Snapshot PMU info from CPUID.0xA into "struct pmu_caps pmu" during pmu_init() instead of reading CPUID.0xA every time a test wants to query PMU capabilities. Using pmu_caps to track various properties will also make it easier to hide the differences between AMD and Intel PMUs. Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx> --- lib/x86/pmu.c | 16 ++++++++++++++++ lib/x86/pmu.h | 32 ++++++++++++++------------------ 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/lib/x86/pmu.c b/lib/x86/pmu.c index bb272ab7..9c1034aa 100644 --- a/lib/x86/pmu.c +++ b/lib/x86/pmu.c @@ -4,6 +4,22 @@ struct pmu_caps pmu; void pmu_init(void) { + struct cpuid cpuid_10 = cpuid(10); + + pmu.version = cpuid_10.a & 0xff; + + if (pmu.version > 1) { + pmu.nr_fixed_counters = cpuid_10.d & 0x1f; + pmu.fixed_counter_width = (cpuid_10.d >> 5) & 0xff; + } + + pmu.nr_gp_counters = (cpuid_10.a >> 8) & 0xff; + pmu.gp_counter_width = (cpuid_10.a >> 16) & 0xff; + pmu.gp_counter_mask_length = (cpuid_10.a >> 24) & 0xff; + + /* CPUID.0xA.EBX bit is '1' if a counter is NOT available. */ + pmu.gp_counter_available = ~cpuid_10.b; + 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 4780237c..c7e9d3ae 100644 --- a/lib/x86/pmu.h +++ b/lib/x86/pmu.h @@ -34,6 +34,13 @@ #define EVNTSEL_INV (1 << EVNTSEL_INV_SHIF) struct pmu_caps { + u8 version; + u8 nr_fixed_counters; + u8 fixed_counter_width; + u8 nr_gp_counters; + u8 gp_counter_width; + u8 gp_counter_mask_length; + u32 gp_counter_available; u64 perf_cap; }; @@ -43,7 +50,7 @@ void pmu_init(void); static inline u8 pmu_version(void) { - return cpuid(10).a & 0xff; + return pmu.version; } static inline bool this_cpu_has_pmu(void) @@ -58,43 +65,32 @@ static inline bool this_cpu_has_perf_global_ctrl(void) static inline u8 pmu_nr_gp_counters(void) { - return (cpuid(10).a >> 8) & 0xff; + return pmu.nr_gp_counters; } static inline u8 pmu_gp_counter_width(void) { - return (cpuid(10).a >> 16) & 0xff; + return pmu.gp_counter_width; } static inline u8 pmu_gp_counter_mask_length(void) { - return (cpuid(10).a >> 24) & 0xff; + return pmu.gp_counter_mask_length; } static inline u8 pmu_nr_fixed_counters(void) { - struct cpuid id = cpuid(10); - - if ((id.a & 0xff) > 1) - return id.d & 0x1f; - else - return 0; + return pmu.nr_fixed_counters; } static inline u8 pmu_fixed_counter_width(void) { - struct cpuid id = cpuid(10); - - if ((id.a & 0xff) > 1) - return (id.d >> 5) & 0xff; - else - return 0; + return pmu.fixed_counter_width; } static inline bool pmu_gp_counter_is_available(int i) { - /* CPUID.0xA.EBX bit is '1 if they counter is NOT available. */ - return !(cpuid(10).b & BIT(i)); + return pmu.gp_counter_available & BIT(i); } static inline u64 this_cpu_perf_capabilities(void) -- 2.38.1.431.g37b22c650d-goog