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