[kvm-unit-tests PATCH v5 16/27] x86/pmu: Snapshot CPUID.0xA PMU capabilities during BSP initialization

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux