From: Aristeu Rozanski <aris@redhat.com> Date: Wed, 20 Aug 2008 13:17:02 -0400 Subject: [x86] nmi: introduce do_nmi_callback Message-id: 20080820171650.316226000@redhat.com O-Subject: [RHEL5.3 PATCH 16/25] nmi: introduce do_nmi_callback for i386 Bugzilla: 447618 https://bugzilla.redhat.com/show_bug.cgi?id=447618 Fix setup_apic_nmi_watchdog to use perfctr and introduce do_nmi_callback() to be called to determine if there's a handler catching the NMIs. Upstream: 3adbbcce9a49b900d4cc118cdccfdefa78bf1afb diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index eb91d21..956ac01 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -369,41 +369,21 @@ static void write_watchdog_counter32(const char *descr) void setup_apic_nmi_watchdog (void) { - switch (boot_cpu_data.x86_vendor) { - case X86_VENDOR_AMD: - if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15 && boot_cpu_data.x86 != 16) - return; - setup_k7_watchdog(); - break; - case X86_VENDOR_INTEL: - if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { - if (!setup_intel_arch_watchdog()) - return; - break; - } - switch (boot_cpu_data.x86) { - case 6: - if (boot_cpu_data.x86_model > 0xd) - return; - - setup_p6_watchdog(); - break; - case 15: - if (boot_cpu_data.x86_model > 0x4) - return; - - if (!setup_p4_watchdog()) - return; - break; - default: + if (__get_cpu_var(wd_enabled) == 1) + return; + + switch (nmi_watchdog) { + case NMI_LOCAL_APIC: + __get_cpu_var(wd_enabled) = 1; + if (lapic_watchdog_init(nmi_hz) < 0) { + __get_cpu_var(wd_enabled) = 0; return; } - break; - default: - return; + /* FALL THROUGH */ + case NMI_IO_APIC: + __get_cpu_var(wd_enabled) = 1; + atomic_inc(&nmi_active); } - lapic_nmi_owner = LAPIC_NMI_WATCHDOG; - nmi_active = 1; } /* @@ -499,6 +479,16 @@ void nmi_watchdog_tick (struct pt_regs * regs) } } +static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu); +int do_nmi_callback(struct pt_regs *regs, int cpu) +{ +#ifdef CONFIG_SYSCTL + if (unknown_nmi_panic) + unknown_nmi_panic_callback(regs, cpu); +#endif + return 0; +} + #ifdef CONFIG_SYSCTL static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) @@ -506,10 +496,9 @@ static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu) unsigned char reason = get_nmi_reason(); char buf[64]; - if (!(reason & 0xc0)) { - sprintf(buf, "NMI received for unknown reason %02x\n", reason); - die_nmi(regs, buf); - } + sprintf(buf, "NMI received for unknown reason %02x\n", reason); + die_nmi(regs, buf); + return 0; } @@ -530,12 +519,9 @@ int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file, if (reserve_lapic_nmi() < 0) { unknown_nmi_panic = 0; return -EBUSY; - } else { - set_nmi_callback(unknown_nmi_panic_callback); } } else { release_lapic_nmi(); - unset_nmi_callback(); } return 0; } diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 3217dc3..10fa3ea 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -811,9 +811,10 @@ void die_nmi (struct pt_regs *regs, const char *msg) static void default_do_nmi(struct pt_regs * regs) { unsigned char reason = 0; + int cpu = smp_processor_id(); /* Only the BSP gets external NMIs from the system. */ - if (!smp_processor_id()) + if (!cpu) reason = get_nmi_reason(); if (!(reason & 0xc0)) { @@ -830,7 +831,8 @@ static void default_do_nmi(struct pt_regs * regs) return; } #endif - unknown_nmi_error(reason, regs); + if (!do_nmi_callback(regs, cpu)) + unknown_nmi_error(reason, regs); return; } 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 f127beb..4ff5761 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h @@ -11,6 +11,14 @@ struct pt_regs; typedef int (*nmi_callback_t)(struct pt_regs * regs, int cpu); /** + * do_nmi_callback + * + * Check to see if a callback exists and execute it. Return 1 + * if the handler exists and was handled successfully. + */ +int do_nmi_callback(struct pt_regs *regs, int cpu); + +/** * set_nmi_callback * * Set a handler for an NMI. Only one handler may be