sparc: implement watchdog_nmi_enable and watchdog_nmi_disable

Implement functions watchdog_nmi_enable and watchdog_nmi_disable to
enable/disable nmi watchdog.  Sparc uses arch specific nmi watchdog
handler.  Currently, we do not have a way to enable/disable nmi watchdog
dynamically.  With these patches we can enable or disable arch specific
nmi watchdogs using proc or sysctl interface.

Example commands.
To enable: echo 1 >  /proc/sys/kernel/nmi_watchdog
To disable: echo 0 >  /proc/sys/kernel/nmi_watchdog

It can also achieved using the sysctl parameter kernel.nmi_watchdog

Link: http://lkml.kernel.org/r/1478034826-43888-4-git-send-email-babu.moger@oracle.com
Signed-off-by: Babu Moger <babu.moger@oracle.com>
Acked-by: Don Zickus <dzickus@redhat.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Kosina <jkosina@suse.cz>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: Yaowei Bai <baiyaowei@cmss.chinamobile.com>
Cc: Aaron Tomlin <atomlin@redhat.com>
Cc: Ulrich Obergfell <uobergfe@redhat.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com>
Cc: Josh Hunt <johunt@akamai.com>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Babu Moger 2016-12-14 15:06:28 -08:00 коммит произвёл Linus Torvalds
Родитель 73ce0511c4
Коммит 7a5c8b57ce
1 изменённых файлов: 43 добавлений и 1 удалений

Просмотреть файл

@ -42,7 +42,7 @@ static int panic_on_timeout;
*/ */
atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */ atomic_t nmi_active = ATOMIC_INIT(0); /* oprofile uses this */
EXPORT_SYMBOL(nmi_active); EXPORT_SYMBOL(nmi_active);
static int nmi_init_done;
static unsigned int nmi_hz = HZ; static unsigned int nmi_hz = HZ;
static DEFINE_PER_CPU(short, wd_enabled); static DEFINE_PER_CPU(short, wd_enabled);
static int endflag __initdata; static int endflag __initdata;
@ -153,6 +153,8 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count)
void stop_nmi_watchdog(void *unused) void stop_nmi_watchdog(void *unused)
{ {
if (!__this_cpu_read(wd_enabled))
return;
pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable); pcr_ops->write_pcr(0, pcr_ops->pcr_nmi_disable);
__this_cpu_write(wd_enabled, 0); __this_cpu_write(wd_enabled, 0);
atomic_dec(&nmi_active); atomic_dec(&nmi_active);
@ -207,6 +209,9 @@ error:
void start_nmi_watchdog(void *unused) void start_nmi_watchdog(void *unused)
{ {
if (__this_cpu_read(wd_enabled))
return;
__this_cpu_write(wd_enabled, 1); __this_cpu_write(wd_enabled, 1);
atomic_inc(&nmi_active); atomic_inc(&nmi_active);
@ -259,6 +264,8 @@ int __init nmi_init(void)
} }
} }
nmi_init_done = 1;
return err; return err;
} }
@ -270,3 +277,38 @@ static int __init setup_nmi_watchdog(char *str)
return 0; return 0;
} }
__setup("nmi_watchdog=", setup_nmi_watchdog); __setup("nmi_watchdog=", setup_nmi_watchdog);
/*
* sparc specific NMI watchdog enable function.
* Enables watchdog if it is not enabled already.
*/
int watchdog_nmi_enable(unsigned int cpu)
{
if (atomic_read(&nmi_active) == -1) {
pr_warn("NMI watchdog cannot be enabled or disabled\n");
return -1;
}
/*
* watchdog thread could start even before nmi_init is called.
* Just Return in that case. Let nmi_init finish the init
* process first.
*/
if (!nmi_init_done)
return 0;
smp_call_function_single(cpu, start_nmi_watchdog, NULL, 1);
return 0;
}
/*
* sparc specific NMI watchdog disable function.
* Disables watchdog if it is not disabled already.
*/
void watchdog_nmi_disable(unsigned int cpu)
{
if (atomic_read(&nmi_active) == -1)
pr_warn_once("NMI watchdog cannot be enabled or disabled\n");
else
smp_call_function_single(cpu, stop_nmi_watchdog, NULL, 1);
}