aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/kernel/nmi.c52
-rw-r--r--arch/x86_64/kernel/nmi.c48
-rw-r--r--include/asm-i386/nmi.h1
-rw-r--r--include/asm-x86_64/nmi.h1
-rw-r--r--include/linux/sysctl.h1
-rw-r--r--kernel/sysctl.c11
6 files changed, 114 insertions, 0 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index acd3fdea2a21..28065d0b71a9 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -846,6 +846,58 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
846 return 0; 846 return 0;
847} 847}
848 848
849/*
850 * proc handler for /proc/sys/kernel/nmi_watchdog
851 */
852int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
853 void __user *buffer, size_t *length, loff_t *ppos)
854{
855 int old_state;
856
857 nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
858 old_state = nmi_watchdog_enabled;
859 proc_dointvec(table, write, file, buffer, length, ppos);
860 if (!!old_state == !!nmi_watchdog_enabled)
861 return 0;
862
863 if (atomic_read(&nmi_active) < 0) {
864 printk(KERN_WARNING "NMI watchdog is permanently disabled\n");
865 return -EINVAL;
866 }
867
868 if (nmi_watchdog == NMI_DEFAULT) {
869 if (nmi_known_cpu() > 0)
870 nmi_watchdog = NMI_LOCAL_APIC;
871 else
872 nmi_watchdog = NMI_IO_APIC;
873 }
874
875 if (nmi_watchdog == NMI_LOCAL_APIC)
876 {
877 if (nmi_watchdog_enabled)
878 enable_lapic_nmi_watchdog();
879 else
880 disable_lapic_nmi_watchdog();
881 } else if (nmi_watchdog == NMI_IO_APIC) {
882 /* FIXME
883 * for some reason these functions don't work
884 */
885 printk("Can not enable/disable NMI on IO APIC\n");
886 return -EINVAL;
887#if 0
888 if (nmi_watchdog_enabled)
889 enable_timer_nmi_watchdog();
890 else
891 disable_timer_nmi_watchdog();
892#endif
893 } else {
894 printk( KERN_WARNING
895 "NMI watchdog doesn't know what hardware to touch\n");
896 return -EIO;
897 }
898 return 0;
899}
900
849#endif 901#endif
850 902
851EXPORT_SYMBOL(nmi_active); 903EXPORT_SYMBOL(nmi_active);
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 9d175dcf3a2d..3a17411a9a19 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -750,6 +750,54 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu)
750 return 0; 750 return 0;
751} 751}
752 752
753/*
754 * proc handler for /proc/sys/kernel/nmi
755 */
756int proc_nmi_enabled(struct ctl_table *table, int write, struct file *file,
757 void __user *buffer, size_t *length, loff_t *ppos)
758{
759 int old_state;
760
761 nmi_watchdog_enabled = (atomic_read(&nmi_active) > 0) ? 1 : 0;
762 old_state = nmi_watchdog_enabled;
763 proc_dointvec(table, write, file, buffer, length, ppos);
764 if (!!old_state == !!nmi_watchdog_enabled)
765 return 0;
766
767 if (atomic_read(&nmi_active) < 0) {
768 printk( KERN_WARNING "NMI watchdog is permanently disabled\n");
769 return -EINVAL;
770 }
771
772 /* if nmi_watchdog is not set yet, then set it */
773 nmi_watchdog_default();
774
775 if (nmi_watchdog == NMI_LOCAL_APIC)
776 {
777 if (nmi_watchdog_enabled)
778 enable_lapic_nmi_watchdog();
779 else
780 disable_lapic_nmi_watchdog();
781 } else if (nmi_watchdog == NMI_IO_APIC) {
782 /* FIXME
783 * for some reason these functions don't work
784 */
785 printk("Can not enable/disable NMI on IO APIC\n");
786 return -EIO;
787#if 0
788 if (nmi_watchdog_enabled)
789 enable_timer_nmi_watchdog();
790 else
791 disable_timer_nmi_watchdog();
792#endif
793 } else {
794 printk(KERN_WARNING
795 "NMI watchdog doesn't know what hardware to touch\n");
796 return -EIO;
797 }
798 return 0;
799}
800
753#endif 801#endif
754 802
755EXPORT_SYMBOL(nmi_active); 803EXPORT_SYMBOL(nmi_active);
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index 34d6bf063b6e..13b5d8311bf7 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -14,6 +14,7 @@
14 */ 14 */
15int do_nmi_callback(struct pt_regs *regs, int cpu); 15int do_nmi_callback(struct pt_regs *regs, int cpu);
16 16
17extern int nmi_watchdog_enabled;
17extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); 18extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
18extern int avail_to_resrv_perfctr_nmi(unsigned int); 19extern int avail_to_resrv_perfctr_nmi(unsigned int);
19extern int reserve_perfctr_nmi(unsigned int); 20extern int reserve_perfctr_nmi(unsigned int);
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index 8818c39d34e0..2c23b0df87d2 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -43,6 +43,7 @@ extern void die_nmi(char *str, struct pt_regs *regs);
43 43
44extern int panic_on_timeout; 44extern int panic_on_timeout;
45extern int unknown_nmi_panic; 45extern int unknown_nmi_panic;
46extern int nmi_watchdog_enabled;
46 47
47extern int check_nmi_watchdog(void); 48extern int check_nmi_watchdog(void);
48extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); 49extern int avail_to_resrv_perfctr_nmi_bit(unsigned int);
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 736ed917a4f8..ecb79ba52ae1 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -150,6 +150,7 @@ enum
150 KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */ 150 KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */
151 KERN_COMPAT_LOG=73, /* int: print compat layer messages */ 151 KERN_COMPAT_LOG=73, /* int: print compat layer messages */
152 KERN_MAX_LOCK_DEPTH=74, 152 KERN_MAX_LOCK_DEPTH=74,
153 KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
153}; 154};
154 155
155 156
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 83f168361624..040de6bd74dd 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,9 @@ extern int compat_log;
76 76
77#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) 77#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
78int unknown_nmi_panic; 78int unknown_nmi_panic;
79int nmi_watchdog_enabled;
80extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
81 void __user *, size_t *, loff_t *);
79#endif 82#endif
80 83
81/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ 84/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
@@ -628,6 +631,14 @@ static ctl_table kern_table[] = {
628 .mode = 0644, 631 .mode = 0644,
629 .proc_handler = &proc_dointvec, 632 .proc_handler = &proc_dointvec,
630 }, 633 },
634 {
635 .ctl_name = KERN_NMI_WATCHDOG,
636 .procname = "nmi_watchdog",
637 .data = &nmi_watchdog_enabled,
638 .maxlen = sizeof (int),
639 .mode = 0644,
640 .proc_handler = &proc_nmi_enabled,
641 },
631#endif 642#endif
632#if defined(CONFIG_X86) 643#if defined(CONFIG_X86)
633 { 644 {