xref: /kvm-unit-tests/lib/x86/pmu.h (revision dd602b6f79d1343ece1d4522fec9d5f62309b5d9)
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 	bool is_intel;
52 	u8 version;
53 	u8 nr_fixed_counters;
54 	u8 fixed_counter_width;
55 	u8 nr_gp_counters;
56 	u8 gp_counter_width;
57 	u8 gp_counter_mask_length;
58 	u32 gp_counter_available;
59 	u32 msr_gp_counter_base;
60 	u32 msr_gp_event_select_base;
61 
62 	u32 msr_global_status;
63 	u32 msr_global_ctl;
64 	u32 msr_global_status_clr;
65 
66 	u64 perf_cap;
67 };
68 
69 extern struct pmu_caps pmu;
70 
71 void pmu_init(void);
72 
73 static inline u32 MSR_GP_COUNTERx(unsigned int i)
74 {
75 	return pmu.msr_gp_counter_base + i;
76 }
77 
78 static inline u32 MSR_GP_EVENT_SELECTx(unsigned int i)
79 {
80 	return pmu.msr_gp_event_select_base + i;
81 }
82 
83 static inline bool this_cpu_has_pmu(void)
84 {
85 	return !!pmu.version;
86 }
87 
88 static inline bool this_cpu_has_perf_global_ctrl(void)
89 {
90 	return pmu.version > 1;
91 }
92 
93 static inline bool this_cpu_has_perf_global_status(void)
94 {
95 	return pmu.version > 1;
96 }
97 
98 static inline bool pmu_gp_counter_is_available(int i)
99 {
100 	return pmu.gp_counter_available & BIT(i);
101 }
102 
103 static inline u64 pmu_lbr_version(void)
104 {
105 	return pmu.perf_cap & PMU_CAP_LBR_FMT;
106 }
107 
108 static inline bool pmu_has_full_writes(void)
109 {
110 	return pmu.perf_cap & PMU_CAP_FW_WRITES;
111 }
112 
113 static inline void pmu_activate_full_writes(void)
114 {
115 	pmu.msr_gp_counter_base = MSR_IA32_PMC0;
116 }
117 
118 static inline bool pmu_use_full_writes(void)
119 {
120 	return pmu.msr_gp_counter_base == MSR_IA32_PMC0;
121 }
122 
123 static inline u32 MSR_PERF_FIXED_CTRx(unsigned int i)
124 {
125 	return MSR_CORE_PERF_FIXED_CTR0 + i;
126 }
127 
128 static inline void pmu_reset_all_gp_counters(void)
129 {
130 	unsigned int idx;
131 
132 	for (idx = 0; idx < pmu.nr_gp_counters; idx++) {
133 		wrmsr(MSR_GP_EVENT_SELECTx(idx), 0);
134 		wrmsr(MSR_GP_COUNTERx(idx), 0);
135 	}
136 }
137 
138 static inline void pmu_reset_all_fixed_counters(void)
139 {
140 	unsigned int idx;
141 
142 	if (!pmu.nr_fixed_counters)
143 		return;
144 
145 	wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
146 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++)
147 		wrmsr(MSR_PERF_FIXED_CTRx(idx), 0);
148 }
149 
150 static inline void pmu_reset_all_counters(void)
151 {
152 	pmu_reset_all_gp_counters();
153 	pmu_reset_all_fixed_counters();
154 }
155 
156 static inline void pmu_clear_global_status(void)
157 {
158 	wrmsr(pmu.msr_global_status_clr, rdmsr(pmu.msr_global_status));
159 }
160 
161 static inline bool pmu_has_pebs(void)
162 {
163 	return pmu.version > 1;
164 }
165 
166 static inline u8 pmu_pebs_format(void)
167 {
168 	return (pmu.perf_cap & PERF_CAP_PEBS_FORMAT ) >> 8;
169 }
170 
171 static inline bool pmu_has_pebs_baseline(void)
172 {
173 	return pmu.perf_cap & PMU_CAP_PEBS_BASELINE;
174 }
175 
176 #endif /* _X86_PMU_H_ */
177