diff options
Diffstat (limited to 'arch/i386/kernel')
| -rw-r--r-- | arch/i386/kernel/nmi.c | 33 | ||||
| -rw-r--r-- | arch/i386/kernel/smpboot.c | 3 |
2 files changed, 28 insertions, 8 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 6241e4448cab..8e4ed930ce6b 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
| @@ -63,7 +63,6 @@ struct nmi_watchdog_ctlblk { | |||
| 63 | static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk); | 63 | static DEFINE_PER_CPU(struct nmi_watchdog_ctlblk, nmi_watchdog_ctlblk); |
| 64 | 64 | ||
| 65 | /* local prototypes */ | 65 | /* local prototypes */ |
| 66 | static void stop_apic_nmi_watchdog(void *unused); | ||
| 67 | static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu); | 66 | static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu); |
| 68 | 67 | ||
| 69 | extern void show_registers(struct pt_regs *regs); | 68 | extern void show_registers(struct pt_regs *regs); |
| @@ -341,15 +340,20 @@ static int nmi_pm_active; /* nmi_active before suspend */ | |||
| 341 | 340 | ||
| 342 | static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state) | 341 | static int lapic_nmi_suspend(struct sys_device *dev, pm_message_t state) |
| 343 | { | 342 | { |
| 343 | /* only CPU0 goes here, other CPUs should be offline */ | ||
| 344 | nmi_pm_active = atomic_read(&nmi_active); | 344 | nmi_pm_active = atomic_read(&nmi_active); |
| 345 | disable_lapic_nmi_watchdog(); | 345 | stop_apic_nmi_watchdog(NULL); |
| 346 | BUG_ON(atomic_read(&nmi_active) != 0); | ||
| 346 | return 0; | 347 | return 0; |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 349 | static int lapic_nmi_resume(struct sys_device *dev) | 350 | static int lapic_nmi_resume(struct sys_device *dev) |
| 350 | { | 351 | { |
| 351 | if (nmi_pm_active > 0) | 352 | /* only CPU0 goes here, other CPUs should be offline */ |
| 352 | enable_lapic_nmi_watchdog(); | 353 | if (nmi_pm_active > 0) { |
| 354 | setup_apic_nmi_watchdog(NULL); | ||
| 355 | touch_nmi_watchdog(); | ||
| 356 | } | ||
| 353 | return 0; | 357 | return 0; |
| 354 | } | 358 | } |
| 355 | 359 | ||
| @@ -626,11 +630,21 @@ static void stop_p4_watchdog(void) | |||
| 626 | 630 | ||
| 627 | void setup_apic_nmi_watchdog (void *unused) | 631 | void setup_apic_nmi_watchdog (void *unused) |
| 628 | { | 632 | { |
| 633 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); | ||
| 634 | |||
| 629 | /* only support LOCAL and IO APICs for now */ | 635 | /* only support LOCAL and IO APICs for now */ |
| 630 | if ((nmi_watchdog != NMI_LOCAL_APIC) && | 636 | if ((nmi_watchdog != NMI_LOCAL_APIC) && |
| 631 | (nmi_watchdog != NMI_IO_APIC)) | 637 | (nmi_watchdog != NMI_IO_APIC)) |
| 632 | return; | 638 | return; |
| 633 | 639 | ||
| 640 | if (wd->enabled == 1) | ||
| 641 | return; | ||
| 642 | |||
| 643 | /* cheap hack to support suspend/resume */ | ||
| 644 | /* if cpu0 is not active neither should the other cpus */ | ||
| 645 | if ((smp_processor_id() != 0) && (atomic_read(&nmi_active) <= 0)) | ||
| 646 | return; | ||
| 647 | |||
| 634 | if (nmi_watchdog == NMI_LOCAL_APIC) { | 648 | if (nmi_watchdog == NMI_LOCAL_APIC) { |
| 635 | switch (boot_cpu_data.x86_vendor) { | 649 | switch (boot_cpu_data.x86_vendor) { |
| 636 | case X86_VENDOR_AMD: | 650 | case X86_VENDOR_AMD: |
| @@ -663,17 +677,22 @@ void setup_apic_nmi_watchdog (void *unused) | |||
| 663 | return; | 677 | return; |
| 664 | } | 678 | } |
| 665 | } | 679 | } |
| 666 | __get_cpu_var(nmi_watchdog_ctlblk.enabled) = 1; | 680 | wd->enabled = 1; |
| 667 | atomic_inc(&nmi_active); | 681 | atomic_inc(&nmi_active); |
| 668 | } | 682 | } |
| 669 | 683 | ||
| 670 | static void stop_apic_nmi_watchdog(void *unused) | 684 | void stop_apic_nmi_watchdog(void *unused) |
| 671 | { | 685 | { |
| 686 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); | ||
| 687 | |||
| 672 | /* only support LOCAL and IO APICs for now */ | 688 | /* only support LOCAL and IO APICs for now */ |
| 673 | if ((nmi_watchdog != NMI_LOCAL_APIC) && | 689 | if ((nmi_watchdog != NMI_LOCAL_APIC) && |
| 674 | (nmi_watchdog != NMI_IO_APIC)) | 690 | (nmi_watchdog != NMI_IO_APIC)) |
| 675 | return; | 691 | return; |
| 676 | 692 | ||
| 693 | if (wd->enabled == 0) | ||
| 694 | return; | ||
| 695 | |||
| 677 | if (nmi_watchdog == NMI_LOCAL_APIC) { | 696 | if (nmi_watchdog == NMI_LOCAL_APIC) { |
| 678 | switch (boot_cpu_data.x86_vendor) { | 697 | switch (boot_cpu_data.x86_vendor) { |
| 679 | case X86_VENDOR_AMD: | 698 | case X86_VENDOR_AMD: |
| @@ -697,7 +716,7 @@ static void stop_apic_nmi_watchdog(void *unused) | |||
| 697 | return; | 716 | return; |
| 698 | } | 717 | } |
| 699 | } | 718 | } |
| 700 | __get_cpu_var(nmi_watchdog_ctlblk.enabled) = 0; | 719 | wd->enabled = 0; |
| 701 | atomic_dec(&nmi_active); | 720 | atomic_dec(&nmi_active); |
| 702 | } | 721 | } |
| 703 | 722 | ||
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index efe07990e7fc..9367af76ce37 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c | |||
| @@ -1376,7 +1376,8 @@ int __cpu_disable(void) | |||
| 1376 | */ | 1376 | */ |
| 1377 | if (cpu == 0) | 1377 | if (cpu == 0) |
| 1378 | return -EBUSY; | 1378 | return -EBUSY; |
| 1379 | 1379 | if (nmi_watchdog == NMI_LOCAL_APIC) | |
| 1380 | stop_apic_nmi_watchdog(NULL); | ||
| 1380 | clear_local_APIC(); | 1381 | clear_local_APIC(); |
| 1381 | /* Allow any queued timer interrupts to get serviced */ | 1382 | /* Allow any queued timer interrupts to get serviced */ |
| 1382 | local_irq_enable(); | 1383 | local_irq_enable(); |
