aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/nmi.c16
-rw-r--r--arch/i386/kernel/traps.c24
-rw-r--r--arch/x86_64/kernel/nmi.c26
-rw-r--r--arch/x86_64/kernel/traps.c8
-rw-r--r--include/asm-i386/nmi.h2
-rw-r--r--include/asm-x86_64/nmi.h10
6 files changed, 57 insertions, 29 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
782extern void die_nmi(struct pt_regs *, const char *msg); 782extern void die_nmi(struct pt_regs *, const char *msg);
783 783
784void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) 784int 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 }
855done: 865done:
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
709static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
710{
711 return 0;
712}
713
714static nmi_callback_t nmi_callback = dummy_nmi_callback;
715
709static void default_do_nmi(struct pt_regs * regs) 716static 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
747static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
748{
749 return 0;
750}
751
752static nmi_callback_t nmi_callback = dummy_nmi_callback;
753
754fastcall void do_nmi(struct pt_regs * regs, long error_code) 753fastcall 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}
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index d42374a952d7..f6b881b23a70 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -682,16 +682,18 @@ void touch_nmi_watchdog (void)
682 touch_softlockup_watchdog(); 682 touch_softlockup_watchdog();
683} 683}
684 684
685void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) 685int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
686{ 686{
687 int sum; 687 int sum;
688 int touched = 0; 688 int touched = 0;
689 struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); 689 struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk);
690 u64 dummy; 690 u64 dummy;
691 int rc=0;
691 692
692 /* check for other users first */ 693 /* check for other users first */
693 if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) 694 if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT)
694 == NOTIFY_STOP) { 695 == NOTIFY_STOP) {
696 rc = 1;
695 touched = 1; 697 touched = 1;
696 } 698 }
697 699
@@ -746,10 +748,18 @@ void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
746 } 748 }
747 /* start the cycle over again */ 749 /* start the cycle over again */
748 wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz)); 750 wrmsrl(wd->perfctr_msr, -((u64)cpu_khz * 1000 / nmi_hz));
749 } 751 rc = 1;
752 } else if (nmi_watchdog == NMI_IO_APIC) {
753 /* don't know how to accurately check for this.
754 * just assume it was a watchdog timer interrupt
755 * This matches the old behaviour.
756 */
757 rc = 1;
758 } else
759 printk(KERN_WARNING "Unknown enabled NMI hardware?!\n");
750 } 760 }
751done: 761done:
752 return; 762 return rc;
753} 763}
754 764
755static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu) 765static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu)
@@ -761,15 +771,17 @@ static nmi_callback_t nmi_callback = dummy_nmi_callback;
761 771
762asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code) 772asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
763{ 773{
764 int cpu = safe_smp_processor_id();
765
766 nmi_enter(); 774 nmi_enter();
767 add_pda(__nmi_count,1); 775 add_pda(__nmi_count,1);
768 if (!rcu_dereference(nmi_callback)(regs, cpu)) 776 default_do_nmi(regs);
769 default_do_nmi(regs);
770 nmi_exit(); 777 nmi_exit();
771} 778}
772 779
780int do_nmi_callback(struct pt_regs * regs, int cpu)
781{
782 return rcu_dereference(nmi_callback)(regs, cpu);
783}
784
773void set_nmi_callback(nmi_callback_t callback) 785void set_nmi_callback(nmi_callback_t callback)
774{ 786{
775 vmalloc_sync_all(); 787 vmalloc_sync_all();
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index b1249774d1e8..42bc070fdf11 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -781,12 +781,12 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
781 * Ok, so this is none of the documented NMI sources, 781 * Ok, so this is none of the documented NMI sources,
782 * so it must be the NMI watchdog. 782 * so it must be the NMI watchdog.
783 */ 783 */
784 if (nmi_watchdog > 0) { 784 if (nmi_watchdog_tick(regs,reason))
785 nmi_watchdog_tick(regs,reason);
786 return; 785 return;
787 } 786 if (!do_nmi_callback(regs,cpu))
788#endif 787#endif
789 unknown_nmi_error(reason, regs); 788 unknown_nmi_error(reason, regs);
789
790 return; 790 return;
791 } 791 }
792 if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) 792 if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP)
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index 4cda6801ecb8..da0e0b4e9139 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -37,7 +37,7 @@ extern int reserve_lapic_nmi(void);
37extern void release_lapic_nmi(void); 37extern void release_lapic_nmi(void);
38extern void disable_timer_nmi_watchdog(void); 38extern void disable_timer_nmi_watchdog(void);
39extern void enable_timer_nmi_watchdog(void); 39extern void enable_timer_nmi_watchdog(void);
40extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); 40extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
41 41
42extern atomic_t nmi_active; 42extern atomic_t nmi_active;
43extern unsigned int nmi_watchdog; 43extern unsigned int nmi_watchdog;
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index 5918136fd853..8f02a2a416e6 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -26,6 +26,14 @@ void set_nmi_callback(nmi_callback_t callback);
26 */ 26 */
27void unset_nmi_callback(void); 27void unset_nmi_callback(void);
28 28
29/**
30 * do_nmi_callback
31 *
32 * Check to see if a callback exists and execute it. Return 1
33 * if the handler exists and was handled successfully.
34 */
35int do_nmi_callback(struct pt_regs *regs, int cpu);
36
29#ifdef CONFIG_PM 37#ifdef CONFIG_PM
30 38
31/** Replace the PM callback routine for NMI. */ 39/** Replace the PM callback routine for NMI. */
@@ -68,7 +76,7 @@ extern int reserve_lapic_nmi(void);
68extern void release_lapic_nmi(void); 76extern void release_lapic_nmi(void);
69extern void disable_timer_nmi_watchdog(void); 77extern void disable_timer_nmi_watchdog(void);
70extern void enable_timer_nmi_watchdog(void); 78extern void enable_timer_nmi_watchdog(void);
71extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); 79extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason);
72 80
73extern void nmi_watchdog_default(void); 81extern void nmi_watchdog_default(void);
74extern int setup_nmi_watchdog(char *); 82extern int setup_nmi_watchdog(char *);