diff --git a/arch/i386/kernel/cpu/perfctr-watchdog.c b/arch/i386/kernel/cpu/perfctr-watchdog.c index 4be488e73bee11760f9de2b9c8b8acd65e556a38..93fecd4b03de0dd99185362e8a2495d7e5e00ccc 100644 --- a/arch/i386/kernel/cpu/perfctr-watchdog.c +++ b/arch/i386/kernel/cpu/perfctr-watchdog.c @@ -263,8 +263,8 @@ static int setup_k7_watchdog(unsigned nmi_hz) unsigned int evntsel; struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - perfctr_msr = MSR_K7_PERFCTR0; - evntsel_msr = MSR_K7_EVNTSEL0; + perfctr_msr = wd_ops->perfctr; + evntsel_msr = wd_ops->evntsel; wrmsrl(perfctr_msr, 0UL); @@ -343,8 +343,8 @@ static int setup_p6_watchdog(unsigned nmi_hz) unsigned int evntsel; struct nmi_watchdog_ctlblk *wd = &__get_cpu_var(nmi_watchdog_ctlblk); - perfctr_msr = MSR_P6_PERFCTR0; - evntsel_msr = MSR_P6_EVNTSEL0; + perfctr_msr = wd_ops->perfctr; + evntsel_msr = wd_ops->evntsel; /* KVM doesn't implement this MSR */ if (wrmsr_safe(perfctr_msr, 0, 0) < 0) @@ -569,8 +569,8 @@ static int setup_intel_arch_watchdog(unsigned nmi_hz) (ebx & ARCH_PERFMON_UNHALTED_CORE_CYCLES_PRESENT)) return 0; - perfctr_msr = MSR_ARCH_PERFMON_PERFCTR1; - evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL1; + perfctr_msr = wd_ops->perfctr; + evntsel_msr = wd_ops->evntsel; wrmsrl(perfctr_msr, 0UL); @@ -605,6 +605,16 @@ static struct wd_ops intel_arch_wd_ops = { .evntsel = MSR_ARCH_PERFMON_EVENTSEL1, }; +static struct wd_ops coreduo_wd_ops = { + .reserve = single_msr_reserve, + .unreserve = single_msr_unreserve, + .setup = setup_intel_arch_watchdog, + .rearm = p6_rearm, + .stop = single_msr_stop_watchdog, + .perfctr = MSR_ARCH_PERFMON_PERFCTR0, + .evntsel = MSR_ARCH_PERFMON_EVENTSEL0, +}; + static void probe_nmi_watchdog(void) { switch (boot_cpu_data.x86_vendor) { @@ -615,6 +625,12 @@ static void probe_nmi_watchdog(void) wd_ops = &k7_wd_ops; break; case X86_VENDOR_INTEL: + /* Work around Core Duo (Yonah) errata AE49 where perfctr1 + doesn't have a working enable bit. */ + if (boot_cpu_data.x86 == 6 && boot_cpu_data.x86_model == 14) { + wd_ops = &coreduo_wd_ops; + break; + } if (cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { wd_ops = &intel_arch_wd_ops; break;