From: Aristeu Rozanski <aris@redhat.com> Date: Wed, 20 Aug 2008 13:16:51 -0400 Subject: [x86_64] nmi: update nmi_watchdog_tick Message-id: 20080820171647.722271000@redhat.com O-Subject: [RHEL5.3 PATCH 05/25] nmi: update nmi_watchdog_tick() 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/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index effad06..8ddd38f 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -392,10 +392,16 @@ void touch_nmi_watchdog (void) touch_softlockup_watchdog(); } -void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) +int __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) { - int sum; - int touched = 0; + int sum, touched = 0, rc = 0; + + /* check for other users first */ + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) { + rc = 1; + touched = 1; + } sum = read_pda(apic_timer_irqs); if (__get_cpu_var(nmi_touch)) { @@ -418,7 +424,7 @@ void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) { local_set(&__get_cpu_var(alert_counter), 0); - return; + return 1; } die_nmi("NMI Watchdog detected LOCKUP on CPU %d\n", regs); } @@ -426,34 +432,24 @@ void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) __get_cpu_var(last_irq_sum) = sum; local_set(&__get_cpu_var(alert_counter), 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); - wrmsrl(nmi_perfctr_msr, - -((u64)cpu_khz * 1000 / nmi_hz)); - } else if (nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { - /* - * For Intel based architectural perfmon - * - LVTPC is masked on interrupt and must be - * unmasked by the LVTPC handler. - */ - apic_write(APIC_LVTPC, APIC_DM_NMI); - /* ARCH PERFMON has 32 bit counter writes */ - wrmsr(nmi_perfctr_msr, - (u32)(-((u64)cpu_khz * 1000 / nmi_hz)), 0); - } else { - wrmsrl(nmi_perfctr_msr, - -((u64)cpu_khz * 1000 / nmi_hz)); - } - } + + /* 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 __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu) diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 9274241..195c431 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -794,16 +794,14 @@ asmlinkage __kprobes 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 > 0) { - nmi_watchdog_tick(regs,reason); + if (nmi_watchdog_tick(regs, reason)) return; - } -#endif + if (!do_nmi_callback2(regs, cpu)) unknown_nmi_error(reason, regs); return; diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index b5060dd..86b8bcf 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h @@ -85,7 +85,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, unsigned reason); +extern int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); extern void nmi_watchdog_default(void); extern int setup_nmi_watchdog(char *);