xref: /kvm-unit-tests/lib/x86/pmu.c (revision 952cf19c9143e307fe229af8bf909016a02fcc6c)
19f17508dSLike Xu #include "pmu.h"
2879e7f07SLike Xu 
3879e7f07SLike Xu struct pmu_caps pmu;
4879e7f07SLike Xu 
5879e7f07SLike Xu void pmu_init(void)
6879e7f07SLike Xu {
7dd602b6fSSean Christopherson 	pmu.is_intel = is_intel();
8dd602b6fSSean Christopherson 
9b883751aSLike Xu 	if (pmu.is_intel) {
10b883751aSLike Xu 		struct cpuid cpuid_10 = cpuid(10);
11dd602b6fSSean Christopherson 
12f85e94a2SSean Christopherson 		pmu.version = cpuid_10.a & 0xff;
13f85e94a2SSean Christopherson 
14f85e94a2SSean Christopherson 		if (pmu.version > 1) {
15f85e94a2SSean Christopherson 			pmu.nr_fixed_counters = cpuid_10.d & 0x1f;
16f85e94a2SSean Christopherson 			pmu.fixed_counter_width = (cpuid_10.d >> 5) & 0xff;
17f85e94a2SSean Christopherson 		}
18f85e94a2SSean Christopherson 
19b883751aSLike Xu 		if (pmu.version > 1) {
20b883751aSLike Xu 			pmu.nr_fixed_counters = cpuid_10.d & 0x1f;
21b883751aSLike Xu 			pmu.fixed_counter_width = (cpuid_10.d >> 5) & 0xff;
22b883751aSLike Xu 		}
23b883751aSLike Xu 
24f85e94a2SSean Christopherson 		pmu.nr_gp_counters = (cpuid_10.a >> 8) & 0xff;
25f85e94a2SSean Christopherson 		pmu.gp_counter_width = (cpuid_10.a >> 16) & 0xff;
26f85e94a2SSean Christopherson 		pmu.gp_counter_mask_length = (cpuid_10.a >> 24) & 0xff;
27f85e94a2SSean Christopherson 
28f85e94a2SSean Christopherson 		/* CPUID.0xA.EBX bit is '1' if a counter is NOT available. */
29f85e94a2SSean Christopherson 		pmu.gp_counter_available = ~cpuid_10.b;
30f85e94a2SSean Christopherson 
31879e7f07SLike Xu 		if (this_cpu_has(X86_FEATURE_PDCM))
32879e7f07SLike Xu 			pmu.perf_cap = rdmsr(MSR_IA32_PERF_CAPABILITIES);
33cda64e80SLike Xu 		pmu.msr_gp_counter_base = MSR_IA32_PERFCTR0;
34cda64e80SLike Xu 		pmu.msr_gp_event_select_base = MSR_P6_EVNTSEL0;
3562ba5036SLike Xu 
3662ba5036SLike Xu 		if (this_cpu_has_perf_global_status()) {
378a2866d1SLike Xu 			pmu.msr_global_status = MSR_CORE_PERF_GLOBAL_STATUS;
388a2866d1SLike Xu 			pmu.msr_global_ctl = MSR_CORE_PERF_GLOBAL_CTRL;
398a2866d1SLike Xu 			pmu.msr_global_status_clr = MSR_CORE_PERF_GLOBAL_OVF_CTRL;
4062ba5036SLike Xu 		}
41b883751aSLike Xu 	} else {
42b883751aSLike Xu 		if (this_cpu_has(X86_FEATURE_PERFCTR_CORE)) {
43*952cf19cSLike Xu 			/* Performance Monitoring Version 2 Supported */
44*952cf19cSLike Xu 			if (this_cpu_has(X86_FEATURE_AMD_PMU_V2)) {
45*952cf19cSLike Xu 				pmu.version = 2;
46*952cf19cSLike Xu 				pmu.nr_gp_counters = cpuid(0x80000022).b & 0xf;
47*952cf19cSLike Xu 			} else {
48b883751aSLike Xu 				pmu.nr_gp_counters = AMD64_NUM_COUNTERS_CORE;
49*952cf19cSLike Xu 			}
50b883751aSLike Xu 			pmu.msr_gp_counter_base = MSR_F15H_PERF_CTR0;
51b883751aSLike Xu 			pmu.msr_gp_event_select_base = MSR_F15H_PERF_CTL0;
52b883751aSLike Xu 		} else {
53b883751aSLike Xu 			pmu.nr_gp_counters = AMD64_NUM_COUNTERS;
54b883751aSLike Xu 			pmu.msr_gp_counter_base = MSR_K7_PERFCTR0;
55b883751aSLike Xu 			pmu.msr_gp_event_select_base = MSR_K7_EVNTSEL0;
56b883751aSLike Xu 		}
57b883751aSLike Xu 		pmu.gp_counter_width = PMC_DEFAULT_WIDTH;
58b883751aSLike Xu 		pmu.gp_counter_mask_length = pmu.nr_gp_counters;
59b883751aSLike Xu 		pmu.gp_counter_available = (1u << pmu.nr_gp_counters) - 1;
60*952cf19cSLike Xu 
61*952cf19cSLike Xu 		if (this_cpu_has_perf_global_status()) {
62*952cf19cSLike Xu 			pmu.msr_global_status = MSR_AMD64_PERF_CNTR_GLOBAL_STATUS;
63*952cf19cSLike Xu 			pmu.msr_global_ctl = MSR_AMD64_PERF_CNTR_GLOBAL_CTL;
64*952cf19cSLike Xu 			pmu.msr_global_status_clr = MSR_AMD64_PERF_CNTR_GLOBAL_STATUS_CLR;
65*952cf19cSLike Xu 		}
66b883751aSLike Xu 	}
67f33d3946SSean Christopherson 
68f33d3946SSean Christopherson 	pmu_reset_all_counters();
69879e7f07SLike Xu }
70