diff options
-rw-r--r-- | arch/i386/kernel/nmi.c | 52 | ||||
-rw-r--r-- | arch/x86_64/kernel/nmi.c | 48 | ||||
-rw-r--r-- | include/asm-i386/nmi.h | 1 | ||||
-rw-r--r-- | include/asm-x86_64/nmi.h | 1 | ||||
-rw-r--r-- | include/linux/sysctl.h | 1 | ||||
-rw-r--r-- | kernel/sysctl.c | 11 |
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 | */ | ||
852 | int 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 | ||
851 | EXPORT_SYMBOL(nmi_active); | 903 | EXPORT_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 | */ | ||
756 | int 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 | ||
755 | EXPORT_SYMBOL(nmi_active); | 803 | EXPORT_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 | */ |
15 | int do_nmi_callback(struct pt_regs *regs, int cpu); | 15 | int do_nmi_callback(struct pt_regs *regs, int cpu); |
16 | 16 | ||
17 | extern int nmi_watchdog_enabled; | ||
17 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); | 18 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); |
18 | extern int avail_to_resrv_perfctr_nmi(unsigned int); | 19 | extern int avail_to_resrv_perfctr_nmi(unsigned int); |
19 | extern int reserve_perfctr_nmi(unsigned int); | 20 | extern 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 | ||
44 | extern int panic_on_timeout; | 44 | extern int panic_on_timeout; |
45 | extern int unknown_nmi_panic; | 45 | extern int unknown_nmi_panic; |
46 | extern int nmi_watchdog_enabled; | ||
46 | 47 | ||
47 | extern int check_nmi_watchdog(void); | 48 | extern int check_nmi_watchdog(void); |
48 | extern int avail_to_resrv_perfctr_nmi_bit(unsigned int); | 49 | extern 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) |
78 | int unknown_nmi_panic; | 78 | int unknown_nmi_panic; |
79 | int nmi_watchdog_enabled; | ||
80 | extern 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 | { |