xref: /kvm-unit-tests/lib/x86/pmu.h (revision 879e7f07f0a718619058af8b26aa636f12f345f0)
1 #ifndef _X86_PMU_H_
2 #define _X86_PMU_H_
3 
4 #include "processor.h"
5 #include "libcflat.h"
6 
7 #define FIXED_CNT_INDEX 32
8 #define MAX_NUM_LBR_ENTRY	  32
9 
10 /* Performance Counter Vector for the LVT PC Register */
11 #define PMI_VECTOR	32
12 
13 #define DEBUGCTLMSR_LBR	  (1UL <<  0)
14 
15 #define PMU_CAP_LBR_FMT	  0x3f
16 #define PMU_CAP_FW_WRITES	(1ULL << 13)
17 
18 #define EVNSEL_EVENT_SHIFT	0
19 #define EVNTSEL_UMASK_SHIFT	8
20 #define EVNTSEL_USR_SHIFT	16
21 #define EVNTSEL_OS_SHIFT	17
22 #define EVNTSEL_EDGE_SHIFT	18
23 #define EVNTSEL_PC_SHIFT	19
24 #define EVNTSEL_INT_SHIFT	20
25 #define EVNTSEL_EN_SHIF		22
26 #define EVNTSEL_INV_SHIF	23
27 #define EVNTSEL_CMASK_SHIFT	24
28 
29 #define EVNTSEL_EN	(1 << EVNTSEL_EN_SHIF)
30 #define EVNTSEL_USR	(1 << EVNTSEL_USR_SHIFT)
31 #define EVNTSEL_OS	(1 << EVNTSEL_OS_SHIFT)
32 #define EVNTSEL_PC	(1 << EVNTSEL_PC_SHIFT)
33 #define EVNTSEL_INT	(1 << EVNTSEL_INT_SHIFT)
34 #define EVNTSEL_INV	(1 << EVNTSEL_INV_SHIF)
35 
36 struct pmu_caps {
37 	u64 perf_cap;
38 };
39 
40 extern struct pmu_caps pmu;
41 
42 void pmu_init(void);
43 
44 static inline u8 pmu_version(void)
45 {
46 	return cpuid(10).a & 0xff;
47 }
48 
49 static inline bool this_cpu_has_pmu(void)
50 {
51 	return !!pmu_version();
52 }
53 
54 static inline bool this_cpu_has_perf_global_ctrl(void)
55 {
56 	return pmu_version() > 1;
57 }
58 
59 static inline u8 pmu_nr_gp_counters(void)
60 {
61 	return (cpuid(10).a >> 8) & 0xff;
62 }
63 
64 static inline u8 pmu_gp_counter_width(void)
65 {
66 	return (cpuid(10).a >> 16) & 0xff;
67 }
68 
69 static inline u8 pmu_gp_counter_mask_length(void)
70 {
71 	return (cpuid(10).a >> 24) & 0xff;
72 }
73 
74 static inline u8 pmu_nr_fixed_counters(void)
75 {
76 	struct cpuid id = cpuid(10);
77 
78 	if ((id.a & 0xff) > 1)
79 		return id.d & 0x1f;
80 	else
81 		return 0;
82 }
83 
84 static inline u8 pmu_fixed_counter_width(void)
85 {
86 	struct cpuid id = cpuid(10);
87 
88 	if ((id.a & 0xff) > 1)
89 		return (id.d >> 5) & 0xff;
90 	else
91 		return 0;
92 }
93 
94 static inline bool pmu_gp_counter_is_available(int i)
95 {
96 	/* CPUID.0xA.EBX bit is '1 if they counter is NOT available. */
97 	return !(cpuid(10).b & BIT(i));
98 }
99 
100 static inline u64 this_cpu_perf_capabilities(void)
101 {
102 	return pmu.perf_cap;
103 }
104 
105 static inline u64 pmu_lbr_version(void)
106 {
107 	return this_cpu_perf_capabilities() & PMU_CAP_LBR_FMT;
108 }
109 
110 static inline bool pmu_has_full_writes(void)
111 {
112 	return this_cpu_perf_capabilities() & PMU_CAP_FW_WRITES;
113 }
114 
115 #endif /* _X86_PMU_H_ */
116