diff options
Diffstat (limited to 'arch/i386/kernel/nmi.c')
| -rw-r--r-- | arch/i386/kernel/nmi.c | 85 |
1 files changed, 11 insertions, 74 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index bd96ea4f2942..acd3fdea2a21 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
| @@ -42,20 +42,6 @@ static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]); | |||
| 42 | */ | 42 | */ |
| 43 | #define NMI_MAX_COUNTER_BITS 66 | 43 | #define NMI_MAX_COUNTER_BITS 66 |
| 44 | 44 | ||
| 45 | /* | ||
| 46 | * lapic_nmi_owner tracks the ownership of the lapic NMI hardware: | ||
| 47 | * - it may be reserved by some other driver, or not | ||
| 48 | * - when not reserved by some other driver, it may be used for | ||
| 49 | * the NMI watchdog, or not | ||
| 50 | * | ||
| 51 | * This is maintained separately from nmi_active because the NMI | ||
| 52 | * watchdog may also be driven from the I/O APIC timer. | ||
| 53 | */ | ||
| 54 | static DEFINE_SPINLOCK(lapic_nmi_owner_lock); | ||
| 55 | static unsigned int lapic_nmi_owner; | ||
| 56 | #define LAPIC_NMI_WATCHDOG (1<<0) | ||
| 57 | #define LAPIC_NMI_RESERVED (1<<1) | ||
| 58 | |||
| 59 | /* nmi_active: | 45 | /* nmi_active: |
| 60 | * >0: the lapic NMI watchdog is active, but can be disabled | 46 | * >0: the lapic NMI watchdog is active, but can be disabled |
| 61 | * <0: the lapic NMI watchdog has not been set up, and cannot | 47 | * <0: the lapic NMI watchdog has not been set up, and cannot |
| @@ -325,33 +311,6 @@ static void enable_lapic_nmi_watchdog(void) | |||
| 325 | touch_nmi_watchdog(); | 311 | touch_nmi_watchdog(); |
| 326 | } | 312 | } |
| 327 | 313 | ||
| 328 | int reserve_lapic_nmi(void) | ||
| 329 | { | ||
| 330 | unsigned int old_owner; | ||
| 331 | |||
| 332 | spin_lock(&lapic_nmi_owner_lock); | ||
| 333 | old_owner = lapic_nmi_owner; | ||
| 334 | lapic_nmi_owner |= LAPIC_NMI_RESERVED; | ||
| 335 | spin_unlock(&lapic_nmi_owner_lock); | ||
| 336 | if (old_owner & LAPIC_NMI_RESERVED) | ||
| 337 | return -EBUSY; | ||
| 338 | if (old_owner & LAPIC_NMI_WATCHDOG) | ||
| 339 | disable_lapic_nmi_watchdog(); | ||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | void release_lapic_nmi(void) | ||
| 344 | { | ||
| 345 | unsigned int new_owner; | ||
| 346 | |||
| 347 | spin_lock(&lapic_nmi_owner_lock); | ||
| 348 | new_owner = lapic_nmi_owner & ~LAPIC_NMI_RESERVED; | ||
| 349 | lapic_nmi_owner = new_owner; | ||
| 350 | spin_unlock(&lapic_nmi_owner_lock); | ||
| 351 | if (new_owner & LAPIC_NMI_WATCHDOG) | ||
| 352 | enable_lapic_nmi_watchdog(); | ||
| 353 | } | ||
| 354 | |||
| 355 | void disable_timer_nmi_watchdog(void) | 314 | void disable_timer_nmi_watchdog(void) |
| 356 | { | 315 | { |
| 357 | BUG_ON(nmi_watchdog != NMI_IO_APIC); | 316 | BUG_ON(nmi_watchdog != NMI_IO_APIC); |
| @@ -866,6 +825,15 @@ done: | |||
| 866 | return rc; | 825 | return rc; |
| 867 | } | 826 | } |
| 868 | 827 | ||
| 828 | int do_nmi_callback(struct pt_regs * regs, int cpu) | ||
| 829 | { | ||
| 830 | #ifdef CONFIG_SYSCTL | ||
| 831 | if (unknown_nmi_panic) | ||
| 832 | return unknown_nmi_panic_callback(regs, cpu); | ||
| 833 | #endif | ||
| 834 | return 0; | ||
| 835 | } | ||
| 836 | |||
| 869 | #ifdef CONFIG_SYSCTL | 837 | #ifdef CONFIG_SYSCTL |
| 870 | 838 | ||
| 871 | static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) | 839 | static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) |
| @@ -873,37 +841,8 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) | |||
| 873 | unsigned char reason = get_nmi_reason(); | 841 | unsigned char reason = get_nmi_reason(); |
| 874 | char buf[64]; | 842 | char buf[64]; |
| 875 | 843 | ||
| 876 | if (!(reason & 0xc0)) { | 844 | sprintf(buf, "NMI received for unknown reason %02x\n", reason); |
| 877 | sprintf(buf, "NMI received for unknown reason %02x\n", reason); | 845 | die_nmi(regs, buf); |
| 878 | die_nmi(regs, buf); | ||
| 879 | } | ||
| 880 | return 0; | ||
| 881 | } | ||
| 882 | |||
| 883 | /* | ||
| 884 | * proc handler for /proc/sys/kernel/unknown_nmi_panic | ||
| 885 | */ | ||
| 886 | int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file, | ||
| 887 | void __user *buffer, size_t *length, loff_t *ppos) | ||
| 888 | { | ||
| 889 | int old_state; | ||
| 890 | |||
| 891 | old_state = unknown_nmi_panic; | ||
| 892 | proc_dointvec(table, write, file, buffer, length, ppos); | ||
| 893 | if (!!old_state == !!unknown_nmi_panic) | ||
| 894 | return 0; | ||
| 895 | |||
| 896 | if (unknown_nmi_panic) { | ||
| 897 | if (reserve_lapic_nmi() < 0) { | ||
| 898 | unknown_nmi_panic = 0; | ||
| 899 | return -EBUSY; | ||
| 900 | } else { | ||
| 901 | set_nmi_callback(unknown_nmi_panic_callback); | ||
| 902 | } | ||
| 903 | } else { | ||
| 904 | release_lapic_nmi(); | ||
| 905 | unset_nmi_callback(); | ||
| 906 | } | ||
| 907 | return 0; | 846 | return 0; |
| 908 | } | 847 | } |
| 909 | 848 | ||
| @@ -917,7 +856,5 @@ EXPORT_SYMBOL(reserve_perfctr_nmi); | |||
| 917 | EXPORT_SYMBOL(release_perfctr_nmi); | 856 | EXPORT_SYMBOL(release_perfctr_nmi); |
| 918 | EXPORT_SYMBOL(reserve_evntsel_nmi); | 857 | EXPORT_SYMBOL(reserve_evntsel_nmi); |
| 919 | EXPORT_SYMBOL(release_evntsel_nmi); | 858 | EXPORT_SYMBOL(release_evntsel_nmi); |
| 920 | EXPORT_SYMBOL(reserve_lapic_nmi); | ||
| 921 | EXPORT_SYMBOL(release_lapic_nmi); | ||
| 922 | EXPORT_SYMBOL(disable_timer_nmi_watchdog); | 859 | EXPORT_SYMBOL(disable_timer_nmi_watchdog); |
| 923 | EXPORT_SYMBOL(enable_timer_nmi_watchdog); | 860 | EXPORT_SYMBOL(enable_timer_nmi_watchdog); |
