xref: /kvm-unit-tests/lib/x86/pmu.h (revision dcec966ff7423a29dad0e5ffdcf58e8a4095356f)
19f17508dSLike Xu #ifndef _X86_PMU_H_
29f17508dSLike Xu #define _X86_PMU_H_
39f17508dSLike Xu 
49f17508dSLike Xu #include "processor.h"
59f17508dSLike Xu #include "libcflat.h"
69f17508dSLike Xu 
79f17508dSLike Xu #define FIXED_CNT_INDEX 32
89f17508dSLike Xu #define MAX_NUM_LBR_ENTRY	  32
99f17508dSLike Xu 
109f17508dSLike Xu /* Performance Counter Vector for the LVT PC Register */
119f17508dSLike Xu #define PMI_VECTOR	32
129f17508dSLike Xu 
13b883751aSLike Xu #define AMD64_NUM_COUNTERS	4
14b883751aSLike Xu #define AMD64_NUM_COUNTERS_CORE	6
15b883751aSLike Xu 
16b883751aSLike Xu #define PMC_DEFAULT_WIDTH	48
17b883751aSLike Xu 
189f17508dSLike Xu #define DEBUGCTLMSR_LBR	  (1UL <<  0)
199f17508dSLike Xu 
209f17508dSLike Xu #define PMU_CAP_LBR_FMT	  0x3f
219f17508dSLike Xu #define PMU_CAP_FW_WRITES	(1ULL << 13)
222ae41f5dSLike Xu #define PMU_CAP_PEBS_BASELINE	(1ULL << 14)
232ae41f5dSLike Xu #define PERF_CAP_PEBS_FORMAT           0xf00
249f17508dSLike Xu 
259f17508dSLike Xu #define EVNSEL_EVENT_SHIFT	0
269f17508dSLike Xu #define EVNTSEL_UMASK_SHIFT	8
279f17508dSLike Xu #define EVNTSEL_USR_SHIFT	16
289f17508dSLike Xu #define EVNTSEL_OS_SHIFT	17
299f17508dSLike Xu #define EVNTSEL_EDGE_SHIFT	18
309f17508dSLike Xu #define EVNTSEL_PC_SHIFT	19
319f17508dSLike Xu #define EVNTSEL_INT_SHIFT	20
329f17508dSLike Xu #define EVNTSEL_EN_SHIF		22
339f17508dSLike Xu #define EVNTSEL_INV_SHIF	23
349f17508dSLike Xu #define EVNTSEL_CMASK_SHIFT	24
359f17508dSLike Xu 
369f17508dSLike Xu #define EVNTSEL_EN	(1 << EVNTSEL_EN_SHIF)
379f17508dSLike Xu #define EVNTSEL_USR	(1 << EVNTSEL_USR_SHIFT)
389f17508dSLike Xu #define EVNTSEL_OS	(1 << EVNTSEL_OS_SHIFT)
399f17508dSLike Xu #define EVNTSEL_PC	(1 << EVNTSEL_PC_SHIFT)
409f17508dSLike Xu #define EVNTSEL_INT	(1 << EVNTSEL_INT_SHIFT)
419f17508dSLike Xu #define EVNTSEL_INV	(1 << EVNTSEL_INV_SHIF)
429f17508dSLike Xu 
432ae41f5dSLike Xu #define GLOBAL_STATUS_BUFFER_OVF_BIT		62
442ae41f5dSLike Xu #define GLOBAL_STATUS_BUFFER_OVF	BIT_ULL(GLOBAL_STATUS_BUFFER_OVF_BIT)
452ae41f5dSLike Xu 
462ae41f5dSLike Xu #define PEBS_DATACFG_MEMINFO	BIT_ULL(0)
47*fc17d527SSean Christopherson #define PEBS_DATACFG_GPRS	BIT_ULL(1)
482ae41f5dSLike Xu #define PEBS_DATACFG_XMMS	BIT_ULL(2)
492ae41f5dSLike Xu #define PEBS_DATACFG_LBRS	BIT_ULL(3)
50*fc17d527SSean Christopherson #define PEBS_DATACFG_MASK	(PEBS_DATACFG_MEMINFO | \
51*fc17d527SSean Christopherson 				 PEBS_DATACFG_GPRS | \
52*fc17d527SSean Christopherson 				 PEBS_DATACFG_XMMS | \
53*fc17d527SSean Christopherson 				 PEBS_DATACFG_LBRS)
542ae41f5dSLike Xu 
552ae41f5dSLike Xu #define ICL_EVENTSEL_ADAPTIVE				(1ULL << 34)
562ae41f5dSLike Xu #define PEBS_DATACFG_LBR_SHIFT	24
572ae41f5dSLike Xu #define MAX_NUM_LBR_ENTRY	32
582ae41f5dSLike Xu 
59879e7f07SLike Xu struct pmu_caps {
60dd602b6fSSean Christopherson 	bool is_intel;
61f85e94a2SSean Christopherson 	u8 version;
62f85e94a2SSean Christopherson 	u8 nr_fixed_counters;
63f85e94a2SSean Christopherson 	u8 fixed_counter_width;
64f85e94a2SSean Christopherson 	u8 nr_gp_counters;
65f85e94a2SSean Christopherson 	u8 gp_counter_width;
66f85e94a2SSean Christopherson 	u8 gp_counter_mask_length;
67f85e94a2SSean Christopherson 	u32 gp_counter_available;
68cda64e80SLike Xu 	u32 msr_gp_counter_base;
69cda64e80SLike Xu 	u32 msr_gp_event_select_base;
70cda64e80SLike Xu 
718a2866d1SLike Xu 	u32 msr_global_status;
728a2866d1SLike Xu 	u32 msr_global_ctl;
738a2866d1SLike Xu 	u32 msr_global_status_clr;
748a2866d1SLike Xu 
75879e7f07SLike Xu 	u64 perf_cap;
76879e7f07SLike Xu };
77879e7f07SLike Xu 
78879e7f07SLike Xu extern struct pmu_caps pmu;
79879e7f07SLike Xu 
80879e7f07SLike Xu void pmu_init(void);
81879e7f07SLike Xu 
MSR_GP_COUNTERx(unsigned int i)82cda64e80SLike Xu static inline u32 MSR_GP_COUNTERx(unsigned int i)
83cda64e80SLike Xu {
84b883751aSLike Xu 	if (pmu.msr_gp_counter_base == MSR_F15H_PERF_CTR0)
85b883751aSLike Xu 		return pmu.msr_gp_counter_base + 2 * i;
86b883751aSLike Xu 
87cda64e80SLike Xu 	return pmu.msr_gp_counter_base + i;
88cda64e80SLike Xu }
89cda64e80SLike Xu 
MSR_GP_EVENT_SELECTx(unsigned int i)90cda64e80SLike Xu static inline u32 MSR_GP_EVENT_SELECTx(unsigned int i)
91cda64e80SLike Xu {
92b883751aSLike Xu 	if (pmu.msr_gp_event_select_base == MSR_F15H_PERF_CTL0)
93b883751aSLike Xu 		return pmu.msr_gp_event_select_base + 2 * i;
94b883751aSLike Xu 
95cda64e80SLike Xu 	return pmu.msr_gp_event_select_base + i;
96cda64e80SLike Xu }
97cda64e80SLike Xu 
this_cpu_has_pmu(void)989f17508dSLike Xu static inline bool this_cpu_has_pmu(void)
999f17508dSLike Xu {
100b883751aSLike Xu 	return !pmu.is_intel || !!pmu.version;
1019f17508dSLike Xu }
1029f17508dSLike Xu 
this_cpu_has_perf_global_ctrl(void)1039f17508dSLike Xu static inline bool this_cpu_has_perf_global_ctrl(void)
1049f17508dSLike Xu {
105414ee7d1SSean Christopherson 	return pmu.version > 1;
1069f17508dSLike Xu }
1079f17508dSLike Xu 
this_cpu_has_perf_global_status(void)10862ba5036SLike Xu static inline bool this_cpu_has_perf_global_status(void)
10962ba5036SLike Xu {
11062ba5036SLike Xu 	return pmu.version > 1;
11162ba5036SLike Xu }
11262ba5036SLike Xu 
pmu_gp_counter_is_available(int i)1139f17508dSLike Xu static inline bool pmu_gp_counter_is_available(int i)
1149f17508dSLike Xu {
115f85e94a2SSean Christopherson 	return pmu.gp_counter_available & BIT(i);
1169f17508dSLike Xu }
1179f17508dSLike Xu 
pmu_lbr_version(void)118879e7f07SLike Xu static inline u64 pmu_lbr_version(void)
119879e7f07SLike Xu {
120414ee7d1SSean Christopherson 	return pmu.perf_cap & PMU_CAP_LBR_FMT;
121879e7f07SLike Xu }
122879e7f07SLike Xu 
pmu_has_full_writes(void)123879e7f07SLike Xu static inline bool pmu_has_full_writes(void)
124879e7f07SLike Xu {
125414ee7d1SSean Christopherson 	return pmu.perf_cap & PMU_CAP_FW_WRITES;
1269f17508dSLike Xu }
1279f17508dSLike Xu 
pmu_activate_full_writes(void)1282ae41f5dSLike Xu static inline void pmu_activate_full_writes(void)
1292ae41f5dSLike Xu {
1302ae41f5dSLike Xu 	pmu.msr_gp_counter_base = MSR_IA32_PMC0;
1312ae41f5dSLike Xu }
1322ae41f5dSLike Xu 
pmu_use_full_writes(void)133cda64e80SLike Xu static inline bool pmu_use_full_writes(void)
134cda64e80SLike Xu {
135cda64e80SLike Xu 	return pmu.msr_gp_counter_base == MSR_IA32_PMC0;
136cda64e80SLike Xu }
137cda64e80SLike Xu 
MSR_PERF_FIXED_CTRx(unsigned int i)1383f914933SLike Xu static inline u32 MSR_PERF_FIXED_CTRx(unsigned int i)
1393f914933SLike Xu {
1403f914933SLike Xu 	return MSR_CORE_PERF_FIXED_CTR0 + i;
1413f914933SLike Xu }
1423f914933SLike Xu 
pmu_reset_all_gp_counters(void)143f33d3946SSean Christopherson static inline void pmu_reset_all_gp_counters(void)
144f33d3946SSean Christopherson {
145f33d3946SSean Christopherson 	unsigned int idx;
146f33d3946SSean Christopherson 
147f33d3946SSean Christopherson 	for (idx = 0; idx < pmu.nr_gp_counters; idx++) {
148f33d3946SSean Christopherson 		wrmsr(MSR_GP_EVENT_SELECTx(idx), 0);
149f33d3946SSean Christopherson 		wrmsr(MSR_GP_COUNTERx(idx), 0);
150f33d3946SSean Christopherson 	}
151f33d3946SSean Christopherson }
152f33d3946SSean Christopherson 
pmu_reset_all_fixed_counters(void)153f33d3946SSean Christopherson static inline void pmu_reset_all_fixed_counters(void)
154f33d3946SSean Christopherson {
155f33d3946SSean Christopherson 	unsigned int idx;
156f33d3946SSean Christopherson 
157f33d3946SSean Christopherson 	if (!pmu.nr_fixed_counters)
158f33d3946SSean Christopherson 		return;
159f33d3946SSean Christopherson 
160f33d3946SSean Christopherson 	wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, 0);
161f33d3946SSean Christopherson 	for (idx = 0; idx < pmu.nr_fixed_counters; idx++)
162f33d3946SSean Christopherson 		wrmsr(MSR_PERF_FIXED_CTRx(idx), 0);
163f33d3946SSean Christopherson }
164f33d3946SSean Christopherson 
pmu_reset_all_counters(void)165f33d3946SSean Christopherson static inline void pmu_reset_all_counters(void)
166f33d3946SSean Christopherson {
167f33d3946SSean Christopherson 	pmu_reset_all_gp_counters();
168f33d3946SSean Christopherson 	pmu_reset_all_fixed_counters();
169f33d3946SSean Christopherson }
170f33d3946SSean Christopherson 
pmu_clear_global_status(void)1718a2866d1SLike Xu static inline void pmu_clear_global_status(void)
1728a2866d1SLike Xu {
1738a2866d1SLike Xu 	wrmsr(pmu.msr_global_status_clr, rdmsr(pmu.msr_global_status));
1748a2866d1SLike Xu }
1758a2866d1SLike Xu 
pmu_has_pebs(void)1762ae41f5dSLike Xu static inline bool pmu_has_pebs(void)
1772ae41f5dSLike Xu {
1782ae41f5dSLike Xu 	return pmu.version > 1;
1792ae41f5dSLike Xu }
1802ae41f5dSLike Xu 
pmu_pebs_format(void)1812ae41f5dSLike Xu static inline u8 pmu_pebs_format(void)
1822ae41f5dSLike Xu {
1832ae41f5dSLike Xu 	return (pmu.perf_cap & PERF_CAP_PEBS_FORMAT ) >> 8;
1842ae41f5dSLike Xu }
1852ae41f5dSLike Xu 
pmu_has_pebs_baseline(void)1862ae41f5dSLike Xu static inline bool pmu_has_pebs_baseline(void)
1872ae41f5dSLike Xu {
1882ae41f5dSLike Xu 	return pmu.perf_cap & PMU_CAP_PEBS_BASELINE;
1892ae41f5dSLike Xu }
1902ae41f5dSLike Xu 
1919f17508dSLike Xu #endif /* _X86_PMU_H_ */
192