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