aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/nmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/nmi.c')
-rw-r--r--arch/x86/kernel/nmi.c61
1 files changed, 47 insertions, 14 deletions
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c
index 2c97f07f1c2c..45a09ccdc214 100644
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -26,11 +26,10 @@
26#include <linux/kernel_stat.h> 26#include <linux/kernel_stat.h>
27#include <linux/kdebug.h> 27#include <linux/kdebug.h>
28#include <linux/smp.h> 28#include <linux/smp.h>
29#include <linux/nmi.h>
29 30
30#include <asm/i8259.h> 31#include <asm/i8259.h>
31#include <asm/io_apic.h> 32#include <asm/io_apic.h>
32#include <asm/smp.h>
33#include <asm/nmi.h>
34#include <asm/proto.h> 33#include <asm/proto.h>
35#include <asm/timer.h> 34#include <asm/timer.h>
36 35
@@ -131,6 +130,11 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count)
131 atomic_dec(&nmi_active); 130 atomic_dec(&nmi_active);
132} 131}
133 132
133static void __acpi_nmi_disable(void *__unused)
134{
135 apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
136}
137
134int __init check_nmi_watchdog(void) 138int __init check_nmi_watchdog(void)
135{ 139{
136 unsigned int *prev_nmi_count; 140 unsigned int *prev_nmi_count;
@@ -179,8 +183,12 @@ int __init check_nmi_watchdog(void)
179 kfree(prev_nmi_count); 183 kfree(prev_nmi_count);
180 return 0; 184 return 0;
181error: 185error:
182 if (nmi_watchdog == NMI_IO_APIC && !timer_through_8259) 186 if (nmi_watchdog == NMI_IO_APIC) {
183 disable_8259A_irq(0); 187 if (!timer_through_8259)
188 disable_8259A_irq(0);
189 on_each_cpu(__acpi_nmi_disable, NULL, 1);
190 }
191
184#ifdef CONFIG_X86_32 192#ifdef CONFIG_X86_32
185 timer_ack = 0; 193 timer_ack = 0;
186#endif 194#endif
@@ -199,12 +207,17 @@ static int __init setup_nmi_watchdog(char *str)
199 ++str; 207 ++str;
200 } 208 }
201 209
202 get_option(&str, &nmi); 210 if (!strncmp(str, "lapic", 5))
203 211 nmi_watchdog = NMI_LOCAL_APIC;
204 if (nmi >= NMI_INVALID) 212 else if (!strncmp(str, "ioapic", 6))
205 return 0; 213 nmi_watchdog = NMI_IO_APIC;
214 else {
215 get_option(&str, &nmi);
216 if (nmi >= NMI_INVALID)
217 return 0;
218 nmi_watchdog = nmi;
219 }
206 220
207 nmi_watchdog = nmi;
208 return 1; 221 return 1;
209} 222}
210__setup("nmi_watchdog=", setup_nmi_watchdog); 223__setup("nmi_watchdog=", setup_nmi_watchdog);
@@ -285,11 +298,6 @@ void acpi_nmi_enable(void)
285 on_each_cpu(__acpi_nmi_enable, NULL, 1); 298 on_each_cpu(__acpi_nmi_enable, NULL, 1);
286} 299}
287 300
288static void __acpi_nmi_disable(void *__unused)
289{
290 apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED);
291}
292
293/* 301/*
294 * Disable timer based NMIs on all CPUs: 302 * Disable timer based NMIs on all CPUs:
295 */ 303 */
@@ -340,6 +348,8 @@ void stop_apic_nmi_watchdog(void *unused)
340 return; 348 return;
341 if (nmi_watchdog == NMI_LOCAL_APIC) 349 if (nmi_watchdog == NMI_LOCAL_APIC)
342 lapic_watchdog_stop(); 350 lapic_watchdog_stop();
351 else
352 __acpi_nmi_disable(NULL);
343 __get_cpu_var(wd_enabled) = 0; 353 __get_cpu_var(wd_enabled) = 0;
344 atomic_dec(&nmi_active); 354 atomic_dec(&nmi_active);
345} 355}
@@ -465,6 +475,24 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason)
465 475
466#ifdef CONFIG_SYSCTL 476#ifdef CONFIG_SYSCTL
467 477
478static void enable_ioapic_nmi_watchdog_single(void *unused)
479{
480 __get_cpu_var(wd_enabled) = 1;
481 atomic_inc(&nmi_active);
482 __acpi_nmi_enable(NULL);
483}
484
485static void enable_ioapic_nmi_watchdog(void)
486{
487 on_each_cpu(enable_ioapic_nmi_watchdog_single, NULL, 1);
488 touch_nmi_watchdog();
489}
490
491static void disable_ioapic_nmi_watchdog(void)
492{
493 on_each_cpu(stop_apic_nmi_watchdog, NULL, 1);
494}
495
468static int __init setup_unknown_nmi_panic(char *str) 496static int __init setup_unknown_nmi_panic(char *str)
469{ 497{
470 unknown_nmi_panic = 1; 498 unknown_nmi_panic = 1;
@@ -507,6 +535,11 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
507 enable_lapic_nmi_watchdog(); 535 enable_lapic_nmi_watchdog();
508 else 536 else
509 disable_lapic_nmi_watchdog(); 537 disable_lapic_nmi_watchdog();
538 } else if (nmi_watchdog == NMI_IO_APIC) {
539 if (nmi_watchdog_enabled)
540 enable_ioapic_nmi_watchdog();
541 else
542 disable_ioapic_nmi_watchdog();
510 } else { 543 } else {
511 printk(KERN_WARNING 544 printk(KERN_WARNING
512 "NMI watchdog doesn't know what hardware to touch\n"); 545 "NMI watchdog doesn't know what hardware to touch\n");