From: Dapeng Mi Starting with Ice Lake, Intel introduced fixed counter 3, which counts TOPDOWN.SLOTS - the number of available slots for an unhalted logical processor. It serves as the denominator for top-level metrics in the Top-down Microarchitecture Analysis method. Emulating this counter on legacy vPMU would require introducing a new generic perf encoding for the Intel-specific TOPDOWN.SLOTS event in order to call perf_get_hw_event_config(). This is undesirable as it would pollute the generic perf event encoding. Moreover, KVM does not intend to emulate IA32_PERF_METRICS in the legacy vPMU model, and without IA32_PERF_METRICS, emulating this counter has little practical value. Therefore, expose fixed counter 3 to guests only when mediated vPMU is enabled. Signed-off-by: Dapeng Mi Co-developed-by: Zide Chen Signed-off-by: Zide Chen --- v3: - Move the non-contiguous counter filter code to pmu.c v2: - Don't advertise fixed counter 3 to userspace if the host doesn't support it. --- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/pmu.c | 18 ++++++++++++++++++ arch/x86/kvm/x86.c | 4 ++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index 3886b536c8a5..754103e7ab4d 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -577,7 +577,7 @@ struct kvm_pmc { #define KVM_MAX_NR_GP_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_GP_COUNTERS, \ KVM_MAX_NR_AMD_GP_COUNTERS) -#define KVM_MAX_NR_INTEL_FIXED_COUNTERS 3 +#define KVM_MAX_NR_INTEL_FIXED_COUNTERS 4 #define KVM_MAX_NR_AMD_FIXED_COUNTERS 0 #define KVM_MAX_NR_FIXED_COUNTERS KVM_MAX(KVM_MAX_NR_INTEL_FIXED_COUNTERS, \ KVM_MAX_NR_AMD_FIXED_COUNTERS) diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c index b92dd2e58335..0faf580782d5 100644 --- a/arch/x86/kvm/pmu.c +++ b/arch/x86/kvm/pmu.c @@ -122,6 +122,8 @@ void kvm_init_pmu_capability(struct kvm_pmu_ops *pmu_ops) { bool is_intel = boot_cpu_data.x86_vendor == X86_VENDOR_INTEL; int min_nr_gp_ctrs = pmu_ops->MIN_NR_GP_COUNTERS; + union cpuid10_edx edx; + u32 eax, ebx, ecx; /* * Hybrid PMUs don't play nice with virtualization without careful @@ -169,6 +171,22 @@ void kvm_init_pmu_capability(struct kvm_pmu_ops *pmu_ops) kvm_pmu_cap.num_counters_fixed = min(kvm_pmu_cap.num_counters_fixed, KVM_MAX_NR_FIXED_COUNTERS); + /* + * Intel platforms may support non-contiguous fixed counters, e.g., some + * E-core based server processors don't implement fixed counter 3. + * + * Before KVM supports non-contiguous fixed counters, make sure only + * contiguous ones are retained in kvm_pmu_cap. + */ + if (kvm_host_pmu.version >= 5) { + cpuid(10, &eax, &ebx, &ecx, &edx.full); + if (kvm_pmu_cap.num_counters_fixed > edx.split.num_counters_fixed) + kvm_pmu_cap.num_counters_fixed = edx.split.num_counters_fixed; + } + + if (!enable_mediated_pmu && kvm_pmu_cap.num_counters_fixed > 3) + kvm_pmu_cap.num_counters_fixed = 3; + kvm_pmu_eventsel.INSTRUCTIONS_RETIRED = perf_get_hw_event_config(PERF_COUNT_HW_INSTRUCTIONS); kvm_pmu_eventsel.BRANCH_INSTRUCTIONS_RETIRED = diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index cf122b8c3210..b9cca855bc10 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -350,7 +350,7 @@ static const u32 msrs_to_save_base[] = { static const u32 msrs_to_save_pmu[] = { MSR_ARCH_PERFMON_FIXED_CTR0, MSR_ARCH_PERFMON_FIXED_CTR1, - MSR_ARCH_PERFMON_FIXED_CTR0 + 2, + MSR_ARCH_PERFMON_FIXED_CTR2, MSR_ARCH_PERFMON_FIXED_CTR3, MSR_CORE_PERF_FIXED_CTR_CTRL, MSR_CORE_PERF_GLOBAL_STATUS, MSR_CORE_PERF_GLOBAL_CTRL, MSR_IA32_PEBS_ENABLE, MSR_IA32_DS_AREA, MSR_PEBS_DATA_CFG, @@ -7742,7 +7742,7 @@ static void kvm_init_msr_lists(void) { unsigned i; - BUILD_BUG_ON_MSG(KVM_MAX_NR_FIXED_COUNTERS != 3, + BUILD_BUG_ON_MSG(KVM_MAX_NR_FIXED_COUNTERS != 4, "Please update the fixed PMCs in msrs_to_save_pmu[]"); num_msrs_to_save = 0; -- 2.54.0