From: Aristeu Rozanski <aris@redhat.com> Date: Wed, 20 Aug 2008 13:17:03 -0400 Subject: [x86] nmi: update nmi_watchdog_tick Message-id: 20080820171650.552580000@redhat.com O-Subject: [RHEL5.3 PATCH 17/25] nmi: update nmi_watchdog_tick() on i386 Bugzilla: 447618 https://bugzilla.redhat.com/show_bug.cgi?id=447618 Change nmi_watchdog_tick() to detect if the NMI was generated by the perf counter (local APIC case). upstream: 751521149a05e308d863d01ced61080ce1a2ec99 (and others) diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 956ac01..8b66535 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -24,6 +24,7 @@ #include <asm/smp.h> #include <asm/nmi.h> #include <asm/intel_arch_perfmon.h> +#include <asm/kdebug.h> #include "mach_traps.h" @@ -425,7 +426,7 @@ EXPORT_SYMBOL(touch_nmi_watchdog); extern void die_nmi(struct pt_regs *, const char *msg); -void nmi_watchdog_tick (struct pt_regs * regs) +int nmi_watchdog_tick (struct pt_regs * regs) { /* @@ -433,7 +434,7 @@ void nmi_watchdog_tick (struct pt_regs * regs) * always switch the stack NMI-atomically, it's safe to use * smp_processor_id(). */ - unsigned int sum; + unsigned int sum, rc = 0; int cpu = smp_processor_id(); sum = per_cpu(irq_stat, cpu).apic_timer_irqs; @@ -453,30 +454,24 @@ void nmi_watchdog_tick (struct pt_regs * regs) last_irq_sums[cpu] = sum; alert_counter[cpu] = 0; } - if (nmi_perfctr_msr) { - if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) { - /* - * P4 quirks: - * - An overflown perfctr will assert its interrupt - * until the OVF flag in its CCCR is cleared. - * - LVTPC is masked on interrupt and must be - * unmasked by the LVTPC handler. - */ - wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); - apic_write(APIC_LVTPC, APIC_DM_NMI); - write_watchdog_counter(NULL); - } - else if (nmi_perfctr_msr == MSR_P6_PERFCTR0 || - nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { - /* Only P6 based Pentium M need to re-unmask - * the apic vector but it doesn't hurt - * other P6 variant */ - apic_write(APIC_LVTPC, APIC_DM_NMI); - write_watchdog_counter32(NULL); - } else { - write_watchdog_counter(NULL); - } - } + + /* see if the nmi watchdog went off */ + if (!__get_cpu_var(wd_enabled)) + return rc; + switch (nmi_watchdog) { + case NMI_LOCAL_APIC: + rc |= lapic_wd_event(nmi_hz); + break; + case NMI_IO_APIC: + /* don't know how to accurately check for this. + * just assume it was a watchdog timer interrupt + * This matches the old behaviour. + */ + rc = 1; + break; + } + + return rc; } static int unknown_nmi_panic_callback(struct pt_regs *regs, int cpu); diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 10fa3ea..e0ab3a1 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -821,16 +821,14 @@ static void default_do_nmi(struct pt_regs * regs) if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) == NOTIFY_STOP) return; -#ifdef CONFIG_X86_LOCAL_APIC + /* * Ok, so this is none of the documented NMI sources, * so it must be the NMI watchdog. */ - if (nmi_watchdog) { - nmi_watchdog_tick(regs); + if (nmi_watchdog_tick(regs)) return; - } -#endif + if (!do_nmi_callback(regs, cpu)) unknown_nmi_error(reason, regs); return; diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h index 4ff5761..48edc43 100644 --- a/include/asm-i386/nmi.h +++ b/include/asm-i386/nmi.h @@ -53,7 +53,7 @@ extern int reserve_lapic_nmi(void); extern void release_lapic_nmi(void); extern void disable_timer_nmi_watchdog(void); extern void enable_timer_nmi_watchdog(void); -extern void nmi_watchdog_tick (struct pt_regs * regs); +extern int nmi_watchdog_tick (struct pt_regs * regs); extern unsigned int nmi_watchdog; #define NMI_DEFAULT -1