diff --git a/xen/arch/x86/cpu/intel.c b/xen/arch/x86/cpu/intel.c index dfee64689f..b5490eb06e 100644 --- a/xen/arch/x86/cpu/intel.c +++ b/xen/arch/x86/cpu/intel.c @@ -533,9 +533,30 @@ static void cf_check init_intel(struct cpuinfo_x86 *c) init_intel_cacheinfo(c); if (c->cpuid_level > 9) { unsigned eax = cpuid_eax(10); + unsigned int cnt = (eax >> 8) & 0xff; + /* Check for version and the number of counters */ - if ((eax & 0xff) && (((eax>>8) & 0xff) > 1)) + if ((eax & 0xff) && (cnt > 1) && (cnt <= 32)) { + uint64_t global_ctrl; + unsigned int cnt_mask = (1UL << cnt) - 1; + + /* + * On (some?) Sapphire/Emerald Rapids platforms each + * package-BSP starts with all the enable bits for the + * general-purpose PMCs cleared. Adjust so counters + * can be enabled from EVNTSEL. + */ + rdmsrl(MSR_CORE_PERF_GLOBAL_CTRL, global_ctrl); + if ((global_ctrl & cnt_mask) != cnt_mask) { + printk("CPU%u: invalid PERF_GLOBAL_CTRL: %#" + PRIx64 " adjusting to %#" PRIx64 "\n", + smp_processor_id(), global_ctrl, + global_ctrl | cnt_mask); + wrmsrl(MSR_CORE_PERF_GLOBAL_CTRL, + global_ctrl | cnt_mask); + } __set_bit(X86_FEATURE_ARCH_PERFMON, c->x86_capability); + } } if ( !cpu_has(c, X86_FEATURE_XTOPOLOGY) )