xref: /kvm-unit-tests/lib/x86/pmu.h (revision 62ba50365a989ea84fd0158f3c309aca5839cfe9)
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 #define PMU_CAP_PEBS_BASELINE	(1ULL << 14)
18 #define PERF_CAP_PEBS_FORMAT           0xf00
19 
20 #define EVNSEL_EVENT_SHIFT	0
21 #define EVNTSEL_UMASK_SHIFT	8
22 #define EVNTSEL_USR_SHIFT	16
23 #define EVNTSEL_OS_SHIFT	17
24 #define EVNTSEL_EDGE_SHIFT	18
25 #define EVNTSEL_PC_SHIFT	19
26 #define EVNTSEL_INT_SHIFT	20
27 #define EVNTSEL_EN_SHIF		22
28 #define EVNTSEL_INV_SHIF	23
29 #define EVNTSEL_CMASK_SHIFT	24
30 
31 #define EVNTSEL_EN	(1 << EVNTSEL_EN_SHIF)
32 #define EVNTSEL_USR	(1 << EVNTSEL_USR_SHIFT)
33 #define EVNTSEL_OS	(1 << EVNTSEL_OS_SHIFT)
34 #define EVNTSEL_PC	(1 << EVNTSEL_PC_SHIFT)
35 #define EVNTSEL_INT	(1 << EVNTSEL_INT_SHIFT)
36 #define EVNTSEL_INV	(1 << EVNTSEL_INV_SHIF)
37 
38 #define GLOBAL_STATUS_BUFFER_OVF_BIT		62
39 #define GLOBAL_STATUS_BUFFER_OVF	BIT_ULL(GLOBAL_STATUS_BUFFER_OVF_BIT)
40 
41 #define PEBS_DATACFG_MEMINFO	BIT_ULL(0)
42 #define PEBS_DATACFG_GP	BIT_ULL(1)
43 #define PEBS_DATACFG_XMMS	BIT_ULL(2)
44 #define PEBS_DATACFG_LBRS	BIT_ULL(3)
45 
46 #define ICL_EVENTSEL_ADAPTIVE				(1ULL << 34)
47 #define PEBS_DATACFG_LBR_SHIFT	24
48 #define MAX_NUM_LBR_ENTRY	32
49 
50 struct pmu_caps {
51 	u8 version;
52 	u8 nr_fixed_counters;
53 	u8 fixed_counter_width;
54 	u8 nr_gp_counters;
55 	u8 gp_counter_width;
56 	u8 gp_counter_mask_length;
57 	u32 gp_counter_available;
58 	u32 msr_gp_counter_base;
59 	u32 msr_gp_event_select_base;
60 
61 	u32 msr_global_status;
62 	u32 msr_global_ctl;
63 	u32 msr_global_status_clr;
64 
65 	u64 perf_cap;
66 };
67 
68 extern struct pmu_caps pmu;
69 
70 void pmu_init(void);
71 
72 static inline u32 MSR_GP_COUNTERx(unsigned int i)
73 {
74 	return pmu.msr_gp_counter_base + i;
75 }
76 
77 static inline u32 MSR_GP_EVENT_SELECTx(unsigned int i)
78 {
79 	return pmu.msr_gp_event_select_base + i;
80 }
81 
82 static inline bool this_cpu_has_pmu(void)
83 {
84 	return !!pmu.version;
85 }
86 
87 static inline bool this_cpu_has_perf_global_ctrl(void)
88 {
89 	return pmu.version > 1;
90 }
91 
92 static inline bool this_cpu_has_perf_global_status(void)
93 {
94 	return pmu.version > 1;
95 }
96 
97 static inline bool pmu_gp_counter_is_available(int i)
98 {
99 	return pmu.gp_counter_available & BIT(i);
100 }
101 
102 static inline u64 pmu_lbr_version(void)
103 {
104 	return pmu.perf_cap & PMU_CAP_LBR_FMT;
105 }
106 
107 static inline bool pmu_has_full_writes(void)
108 {
109 	return pmu.perf_cap & PMU_CAP_FW_WRITES;
110 }
111 
112 static inline void pmu_activate_full_writes(void)
113 {
114 	pmu.msr_gp_counter_base = MSR_IA32_PMC0;
115 }
116 
117 static inline bool pmu_use_full_writes(void)
118 {
119 	return pmu.msr_gp_counter_base == MSR_IA32_PMC0;
120 }
121 
122 static inline u32 MSR_PERF_FIXED_CTRx(unsigned int i)
123 {
124 	return MSR_CORE_PERF_FIXED_CTR0 + i;
125 }
126 
127 static inline void pmu_reset_all_gp_counters(void)
128 {
129 	unsigned int idx;
130 
131 	for (idx = 0; idx < pmu.nr_gp_counters; idx++) {
132 		wrmsr(MSR_GP_EVENT_SELECTx(idx), 0);
133 		wrmsr(MSR_GP_COUNTERx(idx), 0);
134 	}
135 }
136 
137 static inline void pmu_reset_all_fixed_counters(void)
138 {
139 	unsigned int idx;
140 
141 	if (!pmu.nr_fixed_counters)
142 		return;
143 
144 	wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
145 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++)
146 		wrmsr(MSR_PERF_FIXED_CTRx(idx), 0);
147 }
148 
149 static inline void pmu_reset_all_counters(void)
150 {
151 	pmu_reset_all_gp_counters();
152 	pmu_reset_all_fixed_counters();
153 }
154 
155 static inline void pmu_clear_global_status(void)
156 {
157 	wrmsr(pmu.msr_global_status_clr, rdmsr(pmu.msr_global_status));
158 }
159 
160 static inline bool pmu_has_pebs(void)
161 {
162 	return pmu.version > 1;
163 }
164 
165 static inline u8 pmu_pebs_format(void)
166 {
167 	return (pmu.perf_cap & PERF_CAP_PEBS_FORMAT ) >> 8;
168 }
169 
170 static inline bool pmu_has_pebs_baseline(void)
171 {
172 	return pmu.perf_cap & PMU_CAP_PEBS_BASELINE;
173 }
174 
175 #endif /* _X86_PMU_H_ */
176