diff options
Diffstat (limited to 'arch/i386')
-rw-r--r-- | arch/i386/kernel/nmi.c | 16 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 24 |
2 files changed, 24 insertions, 16 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index d88004343034..bd96ea4f2942 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
@@ -781,7 +781,7 @@ EXPORT_SYMBOL(touch_nmi_watchdog); | |||
781 | 781 | ||
782 | extern void die_nmi(struct pt_regs *, const char *msg); | 782 | extern void die_nmi(struct pt_regs *, const char *msg); |
783 | 783 | ||
784 | void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) | 784 | int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) |
785 | { | 785 | { |
786 | 786 | ||
787 | /* | 787 | /* |
@@ -794,10 +794,12 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) | |||
794 | int cpu = smp_processor_id(); | 794 | int cpu = smp_processor_id(); |
795 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); | 795 | struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); |
796 | u64 dummy; | 796 | u64 dummy; |
797 | int rc=0; | ||
797 | 798 | ||
798 | /* check for other users first */ | 799 | /* check for other users first */ |
799 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) | 800 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) |
800 | == NOTIFY_STOP) { | 801 | == NOTIFY_STOP) { |
802 | rc = 1; | ||
801 | touched = 1; | 803 | touched = 1; |
802 | } | 804 | } |
803 | 805 | ||
@@ -850,10 +852,18 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) | |||
850 | } | 852 | } |
851 | /* start the cycle over again */ | 853 | /* start the cycle over again */ |
852 | write_watchdog_counter(wd->perfctr_msr, NULL); | 854 | write_watchdog_counter(wd->perfctr_msr, NULL); |
853 | } | 855 | rc = 1; |
856 | } else if (nmi_watchdog == NMI_IO_APIC) { | ||
857 | /* don't know how to accurately check for this. | ||
858 | * just assume it was a watchdog timer interrupt | ||
859 | * This matches the old behaviour. | ||
860 | */ | ||
861 | rc = 1; | ||
862 | } else | ||
863 | printk(KERN_WARNING "Unknown enabled NMI hardware?!\n"); | ||
854 | } | 864 | } |
855 | done: | 865 | done: |
856 | return; | 866 | return rc; |
857 | } | 867 | } |
858 | 868 | ||
859 | #ifdef CONFIG_SYSCTL | 869 | #ifdef CONFIG_SYSCTL |
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 3a07b2677e2a..282f0bd40dfd 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -706,6 +706,13 @@ void die_nmi (struct pt_regs *regs, const char *msg) | |||
706 | do_exit(SIGSEGV); | 706 | do_exit(SIGSEGV); |
707 | } | 707 | } |
708 | 708 | ||
709 | static int dummy_nmi_callback(struct pt_regs * regs, int cpu) | ||
710 | { | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static nmi_callback_t nmi_callback = dummy_nmi_callback; | ||
715 | |||
709 | static void default_do_nmi(struct pt_regs * regs) | 716 | static void default_do_nmi(struct pt_regs * regs) |
710 | { | 717 | { |
711 | unsigned char reason = 0; | 718 | unsigned char reason = 0; |
@@ -723,12 +730,11 @@ static void default_do_nmi(struct pt_regs * regs) | |||
723 | * Ok, so this is none of the documented NMI sources, | 730 | * Ok, so this is none of the documented NMI sources, |
724 | * so it must be the NMI watchdog. | 731 | * so it must be the NMI watchdog. |
725 | */ | 732 | */ |
726 | if (nmi_watchdog) { | 733 | if (nmi_watchdog_tick(regs, reason)) |
727 | nmi_watchdog_tick(regs, reason); | ||
728 | return; | 734 | return; |
729 | } | ||
730 | #endif | 735 | #endif |
731 | unknown_nmi_error(reason, regs); | 736 | if (!rcu_dereference(nmi_callback)(regs, smp_processor_id())) |
737 | unknown_nmi_error(reason, regs); | ||
732 | return; | 738 | return; |
733 | } | 739 | } |
734 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 740 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) |
@@ -744,13 +750,6 @@ static void default_do_nmi(struct pt_regs * regs) | |||
744 | reassert_nmi(); | 750 | reassert_nmi(); |
745 | } | 751 | } |
746 | 752 | ||
747 | static int dummy_nmi_callback(struct pt_regs * regs, int cpu) | ||
748 | { | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | static nmi_callback_t nmi_callback = dummy_nmi_callback; | ||
753 | |||
754 | fastcall void do_nmi(struct pt_regs * regs, long error_code) | 753 | fastcall void do_nmi(struct pt_regs * regs, long error_code) |
755 | { | 754 | { |
756 | int cpu; | 755 | int cpu; |
@@ -761,8 +760,7 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code) | |||
761 | 760 | ||
762 | ++nmi_count(cpu); | 761 | ++nmi_count(cpu); |
763 | 762 | ||
764 | if (!rcu_dereference(nmi_callback)(regs, cpu)) | 763 | default_do_nmi(regs); |
765 | default_do_nmi(regs); | ||
766 | 764 | ||
767 | nmi_exit(); | 765 | nmi_exit(); |
768 | } | 766 | } |