aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeir Fraser <keir@xen.org>2010-11-22 19:18:10 +0000
committerKeir Fraser <keir@xen.org>2010-11-22 19:18:10 +0000
commit7de79b35023a8767b9e017dcb890adc472748b7e (patch)
treec9289355b0076392f646c6ba075883e0a3faf2b0
parent6a1a3b5845ba23627cc367888306ece8e9f41f15 (diff)
downloadxen-7de79b35023a8767b9e017dcb890adc472748b7e.tar.gz
xen-7de79b35023a8767b9e017dcb890adc472748b7e.tar.bz2
xen-7de79b35023a8767b9e017dcb890adc472748b7e.zip
x86 hvm: Fix VPMU issue on Nehalem cpus
Fix an issue on Nehalem cpus where performance counter overflows may lead to endless interrupt loops on this cpu. Signed-off-by: Dietmar Hahn <dietmar.hahn@ts.fujitsu.com> xen-unstable changeset: 22417:c0c1f5f0745e xen-unstable date: Mon Nov 22 19:16:34 2010 +0000
-rw-r--r--xen/arch/x86/hvm/vmx/vpmu_core2.c67
1 files changed, 67 insertions, 0 deletions
diff --git a/xen/arch/x86/hvm/vmx/vpmu_core2.c b/xen/arch/x86/hvm/vmx/vpmu_core2.c
index dd72580091..31aa1170c6 100644
--- a/xen/arch/x86/hvm/vmx/vpmu_core2.c
+++ b/xen/arch/x86/hvm/vmx/vpmu_core2.c
@@ -35,6 +35,68 @@
#include <asm/hvm/vmx/vpmu.h>
#include <asm/hvm/vmx/vpmu_core2.h>
+/*
+ * QUIRK to workaround an issue on Nehalem processors currently seen
+ * on family 6 cpus E5520 (model 26) and X7542 (model 46).
+ * The issue leads to endless PMC interrupt loops on the processor.
+ * If the interrupt handler is running and a pmc reaches the value 0, this
+ * value remains forever and it triggers immediately a new interrupt after
+ * finishing the handler.
+ * A workaround is to read all flagged counters and if the value is 0 write
+ * 1 (or another value != 0) into it.
+ * There exist no errata and the real cause of this behaviour is unknown.
+ */
+bool_t __read_mostly is_pmc_quirk;
+
+static void check_pmc_quirk(void)
+{
+ u8 family = current_cpu_data.x86;
+ u8 cpu_model = current_cpu_data.x86_model;
+ is_pmc_quirk = 0;
+ if ( family == 6 )
+ {
+ if ( cpu_model == 46 || cpu_model == 26 )
+ is_pmc_quirk = 1;
+ }
+}
+
+static int core2_get_pmc_count(void);
+static void handle_pmc_quirk(u64 msr_content)
+{
+ int num_gen_pmc = core2_get_pmc_count();
+ int num_fix_pmc = 3;
+ int i;
+ u64 val;
+
+ if ( !is_pmc_quirk )
+ return;
+
+ val = msr_content;
+ for ( i = 0; i < num_gen_pmc; i++ )
+ {
+ if ( val & 0x1 )
+ {
+ u64 cnt;
+ rdmsrl(MSR_P6_PERFCTR0 + i, cnt);
+ if ( cnt == 0 )
+ wrmsrl(MSR_P6_PERFCTR0 + i, 1);
+ }
+ val >>= 1;
+ }
+ val = msr_content >> 32;
+ for ( i = 0; i < num_fix_pmc; i++ )
+ {
+ if ( val & 0x1 )
+ {
+ u64 cnt;
+ rdmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, cnt);
+ if ( cnt == 0 )
+ wrmsrl(MSR_CORE_PERF_FIXED_CTR0 + i, 1);
+ }
+ val >>= 1;
+ }
+}
+
u32 core2_counters_msr[] = {
MSR_CORE_PERF_FIXED_CTR0,
MSR_CORE_PERF_FIXED_CTR1,
@@ -497,6 +559,10 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
rdmsrl(MSR_CORE_PERF_GLOBAL_STATUS, msr_content);
if ( !msr_content )
return 0;
+
+ if ( is_pmc_quirk )
+ handle_pmc_quirk(msr_content);
+
core2_vpmu_cxt->global_ovf_status |= msr_content;
msr_content = 0xC000000700000000 | ((1 << core2_get_pmc_count()) - 1);
wrmsrl(MSR_CORE_PERF_GLOBAL_OVF_CTRL, msr_content);
@@ -518,6 +584,7 @@ static int core2_vpmu_do_interrupt(struct cpu_user_regs *regs)
static void core2_vpmu_initialise(struct vcpu *v)
{
+ check_pmc_quirk();
}
static void core2_vpmu_destroy(struct vcpu *v)