From: Like Xu <likexu@xxxxxxxxxxx> Add a global "struct pmu_caps pmu" to snapshot PMU capabilities during the final stages of BSP initialization. Use the new hooks to snapshot PERF_CAPABILITIES instead of re-reading the MSR every time a test wants to query capabilities. A software-defined struct will also simplify extending support to AMD CPUs, as many of the differences between AMD and Intel can be handled during pmu_init(). Init the PMU caps for all tests so that tests don't need to remember to call pmu_init() before using any of the PMU helpers, e.g. the nVMX test uses this_cpu_has_pmu(), which will be converted to rely on the global struct in a future patch. Suggested-by: Sean Christopherson <seanjc@xxxxxxxxxx> Signed-off-by: Like Xu <likexu@xxxxxxxxxxx> [sean: reword changelog] Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- lib/x86/pmu.c | 8 ++++++++ lib/x86/pmu.h | 21 ++++++++++++++++++--- lib/x86/setup.c | 2 ++ x86/pmu.c | 2 +- x86/pmu_lbr.c | 7 ++----- 5 files changed, 31 insertions(+), 9 deletions(-) diff --git a/lib/x86/pmu.c b/lib/x86/pmu.c index 9d048abc..bb272ab7 100644 --- a/lib/x86/pmu.c +++ b/lib/x86/pmu.c @@ -1 +1,9 @@ #include "pmu.h" + +struct pmu_caps pmu; + +void pmu_init(void) +{ + if (this_cpu_has(X86_FEATURE_PDCM)) + pmu.perf_cap = rdmsr(MSR_IA32_PERF_CAPABILITIES); +} diff --git a/lib/x86/pmu.h b/lib/x86/pmu.h index 078a9747..4780237c 100644 --- a/lib/x86/pmu.h +++ b/lib/x86/pmu.h @@ -33,6 +33,14 @@ #define EVNTSEL_INT (1 << EVNTSEL_INT_SHIFT) #define EVNTSEL_INV (1 << EVNTSEL_INV_SHIF) +struct pmu_caps { + u64 perf_cap; +}; + +extern struct pmu_caps pmu; + +void pmu_init(void); + static inline u8 pmu_version(void) { return cpuid(10).a & 0xff; @@ -91,10 +99,17 @@ static inline bool pmu_gp_counter_is_available(int i) static inline u64 this_cpu_perf_capabilities(void) { - if (!this_cpu_has(X86_FEATURE_PDCM)) - return 0; + return pmu.perf_cap; +} - return rdmsr(MSR_IA32_PERF_CAPABILITIES); +static inline u64 pmu_lbr_version(void) +{ + return this_cpu_perf_capabilities() & PMU_CAP_LBR_FMT; +} + +static inline bool pmu_has_full_writes(void) +{ + return this_cpu_perf_capabilities() & PMU_CAP_FW_WRITES; } #endif /* _X86_PMU_H_ */ diff --git a/lib/x86/setup.c b/lib/x86/setup.c index a7b3edbe..1ebbf58a 100644 --- a/lib/x86/setup.c +++ b/lib/x86/setup.c @@ -15,6 +15,7 @@ #include "apic-defs.h" #include "asm/setup.h" #include "atomic.h" +#include "pmu.h" #include "processor.h" #include "smp.h" @@ -398,4 +399,5 @@ void bsp_rest_init(void) bringup_aps(); enable_x2apic(); smp_init(); + pmu_init(); } diff --git a/x86/pmu.c b/x86/pmu.c index 7d67746e..627fd394 100644 --- a/x86/pmu.c +++ b/x86/pmu.c @@ -669,7 +669,7 @@ int main(int ac, char **av) check_counters(); - if (this_cpu_perf_capabilities() & PMU_CAP_FW_WRITES) { + if (pmu_has_full_writes()) { gp_counter_base = MSR_IA32_PMC0; report_prefix_push("full-width writes"); check_counters(); diff --git a/x86/pmu_lbr.c b/x86/pmu_lbr.c index e6d98236..d0135520 100644 --- a/x86/pmu_lbr.c +++ b/x86/pmu_lbr.c @@ -43,7 +43,6 @@ static bool test_init_lbr_from_exception(u64 index) int main(int ac, char **av) { - u64 perf_cap; int max, i; setup_vm(); @@ -63,15 +62,13 @@ int main(int ac, char **av) return report_summary(); } - perf_cap = this_cpu_perf_capabilities(); - - if (!(perf_cap & PMU_CAP_LBR_FMT)) { + if (!pmu_lbr_version()) { report_skip("(Architectural) LBR is not supported."); return report_summary(); } printf("PMU version: %d\n", pmu_version()); - printf("LBR version: %ld\n", perf_cap & PMU_CAP_LBR_FMT); + printf("LBR version: %ld\n", pmu_lbr_version()); /* Look for LBR from and to MSRs */ lbr_from = MSR_LBR_CORE_FROM; -- 2.38.1.431.g37b22c650d-goog