From: Aristeu Rozanski <aris@redhat.com> Date: Wed, 20 Aug 2008 13:16:56 -0400 Subject: [x86_64] nmi: use perfctr functions for probing Message-id: 20080820171648.895079000@redhat.com O-Subject: [RHEL5.3 PATCH 10/25] nmi: use perfctr functions for probing Bugzilla: 447618 https://bugzilla.redhat.com/show_bug.cgi?id=447618 This patch changes lapic_watchdog_init() and creates lapic_watchdog_probe() to allow enabling nmi watchdog as default. upstream: not upstream, only interesting for RHEL-5 which ships NMI enabled by default diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c index 5c13e7f..05db057 100644 --- a/arch/x86_64/kernel/nmi.c +++ b/arch/x86_64/kernel/nmi.c @@ -51,67 +51,14 @@ static DEFINE_PER_CPU(short, wd_enabled); unsigned int nmi_watchdog = NMI_DEFAULT; static unsigned int nmi_hz = HZ; -static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */ -static unsigned int nmi_p4_cccr_val; - -/* Note that these events don't tick when the CPU idles. This means - the frequency varies with CPU load. */ - -#define K7_EVNTSEL_ENABLE (1 << 22) -#define K7_EVNTSEL_INT (1 << 20) -#define K7_EVNTSEL_OS (1 << 17) -#define K7_EVNTSEL_USR (1 << 16) -#define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76 -#define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING - -#define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL -#define ARCH_PERFMON_NMI_EVENT_UMASK ARCH_PERFMON_UNHALTED_CORE_CYCLES_UMASK - -#define MSR_P4_MISC_ENABLE 0x1A0 -#define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7) -#define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12) -#define MSR_P4_PERFCTR0 0x300 -#define MSR_P4_CCCR0 0x360 -#define P4_ESCR_EVENT_SELECT(N) ((N)<<25) -#define P4_ESCR_OS (1<<3) -#define P4_ESCR_USR (1<<2) -#define P4_CCCR_OVF_PMI0 (1<<26) -#define P4_CCCR_OVF_PMI1 (1<<27) -#define P4_CCCR_THRESHOLD(N) ((N)<<20) -#define P4_CCCR_COMPLEMENT (1<<19) -#define P4_CCCR_COMPARE (1<<18) -#define P4_CCCR_REQUIRED (3<<16) -#define P4_CCCR_ESCR_SELECT(N) ((N)<<13) -#define P4_CCCR_ENABLE (1<<12) -/* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter - CRU_ESCR0 (with any non-null event selector) through a complemented - max threshold. [IA32-Vol3, Section 14.9.9] */ -#define MSR_P4_IQ_COUNTER0 0x30C -#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR) -#define P4_NMI_IQ_CCCR0 \ - (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ - P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) - -static __cpuinit inline int nmi_known_cpu(void) -{ - switch (boot_cpu_data.x86_vendor) { - case X86_VENDOR_AMD: - return boot_cpu_data.x86 == 15 || boot_cpu_data.x86 == 16; - case X86_VENDOR_INTEL: - if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) - return 1; - else - return (boot_cpu_data.x86 == 15); - } - return 0; -} /* Run after command line and cpu_init init, but before all other checks */ void __cpuinit nmi_watchdog_default(void) { if (nmi_watchdog != NMI_DEFAULT) return; - if (nmi_known_cpu()) + /* if not specified, probe it */ + if (!lapic_watchdog_probe()) nmi_watchdog = NMI_LOCAL_APIC; else nmi_watchdog = NMI_IO_APIC; @@ -192,7 +139,6 @@ int __init check_nmi_watchdog (void) cpu_pda(cpu)->__nmi_count); if (atomic_dec_and_test(&nmi_watchdog_active)) nmi_active = 0; - nmi_perfctr_msr = 0; per_cpu(wd_enabled, cpu) = 0; kfree(counts); return -1; @@ -209,13 +155,8 @@ int __init check_nmi_watchdog (void) /* now that we know it works we can reduce NMI frequency to something more reasonable; makes a difference in some configs */ - if (nmi_watchdog == NMI_LOCAL_APIC) { - - nmi_hz = 1; - if (nmi_perfctr_msr == MSR_ARCH_PERFMON_PERFCTR0) { - nmi_hz = adjust_for_32bit_ctr(nmi_hz); - } - } + if (nmi_watchdog == NMI_LOCAL_APIC) + nmi_hz = lapic_adjust_nmi_hz(1); kfree(counts); return 0; diff --git a/arch/x86_64/kernel/perfctr-watchdog.c b/arch/x86_64/kernel/perfctr-watchdog.c index 984f2fb..f68e71c 100644 --- a/arch/x86_64/kernel/perfctr-watchdog.c +++ b/arch/x86_64/kernel/perfctr-watchdog.c @@ -668,7 +668,7 @@ static void probe_nmi_watchdog(void) /* Interface to nmi.c */ -int lapic_watchdog_init(unsigned nmi_hz) +int lapic_watchdog_probe(void) { if (!wd_ops) { probe_nmi_watchdog(); @@ -681,6 +681,13 @@ int lapic_watchdog_init(unsigned nmi_hz) return -1; } } + return 0; +} + +int lapic_watchdog_init(unsigned nmi_hz) +{ + if (lapic_watchdog_probe()) + return -1; if (!(wd_ops->setup(nmi_hz))) { printk(KERN_ERR "Cannot setup NMI watchdog on CPU %d\n", diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h index 86b8bcf..7d82b1a 100644 --- a/include/asm-x86_64/nmi.h +++ b/include/asm-x86_64/nmi.h @@ -71,6 +71,7 @@ extern int reserve_evntsel_nmi(unsigned int); extern void release_evntsel_nmi(unsigned int); void lapic_watchdog_stop(void); +int lapic_watchdog_probe(void); int lapic_watchdog_init(unsigned nmi_hz); int lapic_wd_event(unsigned nmi_hz); unsigned lapic_adjust_nmi_hz(unsigned hz);