diff options
Diffstat (limited to 'arch/x86/kernel/nmi.c')
-rw-r--r-- | arch/x86/kernel/nmi.c | 43 |
1 files changed, 36 insertions, 7 deletions
diff --git a/arch/x86/kernel/nmi.c b/arch/x86/kernel/nmi.c index 2c97f07f1c2c..13316cf57cdb 100644 --- a/arch/x86/kernel/nmi.c +++ b/arch/x86/kernel/nmi.c | |||
@@ -131,6 +131,11 @@ static void report_broken_nmi(int cpu, int *prev_nmi_count) | |||
131 | atomic_dec(&nmi_active); | 131 | atomic_dec(&nmi_active); |
132 | } | 132 | } |
133 | 133 | ||
134 | static void __acpi_nmi_disable(void *__unused) | ||
135 | { | ||
136 | apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); | ||
137 | } | ||
138 | |||
134 | int __init check_nmi_watchdog(void) | 139 | int __init check_nmi_watchdog(void) |
135 | { | 140 | { |
136 | unsigned int *prev_nmi_count; | 141 | unsigned int *prev_nmi_count; |
@@ -179,8 +184,12 @@ int __init check_nmi_watchdog(void) | |||
179 | kfree(prev_nmi_count); | 184 | kfree(prev_nmi_count); |
180 | return 0; | 185 | return 0; |
181 | error: | 186 | error: |
182 | if (nmi_watchdog == NMI_IO_APIC && !timer_through_8259) | 187 | if (nmi_watchdog == NMI_IO_APIC) { |
183 | disable_8259A_irq(0); | 188 | if (!timer_through_8259) |
189 | disable_8259A_irq(0); | ||
190 | on_each_cpu(__acpi_nmi_disable, NULL, 1); | ||
191 | } | ||
192 | |||
184 | #ifdef CONFIG_X86_32 | 193 | #ifdef CONFIG_X86_32 |
185 | timer_ack = 0; | 194 | timer_ack = 0; |
186 | #endif | 195 | #endif |
@@ -285,11 +294,6 @@ void acpi_nmi_enable(void) | |||
285 | on_each_cpu(__acpi_nmi_enable, NULL, 1); | 294 | on_each_cpu(__acpi_nmi_enable, NULL, 1); |
286 | } | 295 | } |
287 | 296 | ||
288 | static void __acpi_nmi_disable(void *__unused) | ||
289 | { | ||
290 | apic_write(APIC_LVT0, APIC_DM_NMI | APIC_LVT_MASKED); | ||
291 | } | ||
292 | |||
293 | /* | 297 | /* |
294 | * Disable timer based NMIs on all CPUs: | 298 | * Disable timer based NMIs on all CPUs: |
295 | */ | 299 | */ |
@@ -340,6 +344,8 @@ void stop_apic_nmi_watchdog(void *unused) | |||
340 | return; | 344 | return; |
341 | if (nmi_watchdog == NMI_LOCAL_APIC) | 345 | if (nmi_watchdog == NMI_LOCAL_APIC) |
342 | lapic_watchdog_stop(); | 346 | lapic_watchdog_stop(); |
347 | else | ||
348 | __acpi_nmi_disable(NULL); | ||
343 | __get_cpu_var(wd_enabled) = 0; | 349 | __get_cpu_var(wd_enabled) = 0; |
344 | atomic_dec(&nmi_active); | 350 | atomic_dec(&nmi_active); |
345 | } | 351 | } |
@@ -465,6 +471,24 @@ nmi_watchdog_tick(struct pt_regs *regs, unsigned reason) | |||
465 | 471 | ||
466 | #ifdef CONFIG_SYSCTL | 472 | #ifdef CONFIG_SYSCTL |
467 | 473 | ||
474 | static void enable_ioapic_nmi_watchdog_single(void *unused) | ||
475 | { | ||
476 | __get_cpu_var(wd_enabled) = 1; | ||
477 | atomic_inc(&nmi_active); | ||
478 | __acpi_nmi_enable(NULL); | ||
479 | } | ||
480 | |||
481 | static void enable_ioapic_nmi_watchdog(void) | ||
482 | { | ||
483 | on_each_cpu(enable_ioapic_nmi_watchdog_single, NULL, 1); | ||
484 | touch_nmi_watchdog(); | ||
485 | } | ||
486 | |||
487 | static void disable_ioapic_nmi_watchdog(void) | ||
488 | { | ||
489 | on_each_cpu(stop_apic_nmi_watchdog, NULL, 1); | ||
490 | } | ||
491 | |||
468 | static int __init setup_unknown_nmi_panic(char *str) | 492 | static int __init setup_unknown_nmi_panic(char *str) |
469 | { | 493 | { |
470 | unknown_nmi_panic = 1; | 494 | unknown_nmi_panic = 1; |
@@ -507,6 +531,11 @@ int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file, | |||
507 | enable_lapic_nmi_watchdog(); | 531 | enable_lapic_nmi_watchdog(); |
508 | else | 532 | else |
509 | disable_lapic_nmi_watchdog(); | 533 | disable_lapic_nmi_watchdog(); |
534 | } else if (nmi_watchdog == NMI_IO_APIC) { | ||
535 | if (nmi_watchdog_enabled) | ||
536 | enable_ioapic_nmi_watchdog(); | ||
537 | else | ||
538 | disable_ioapic_nmi_watchdog(); | ||
510 | } else { | 539 | } else { |
511 | printk(KERN_WARNING | 540 | printk(KERN_WARNING |
512 | "NMI watchdog doesn't know what hardware to touch\n"); | 541 | "NMI watchdog doesn't know what hardware to touch\n"); |