18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support Intel/AMD RAPL energy consumption counters 48c2ecf20Sopenharmony_ci * Copyright (C) 2013 Google, Inc., Stephane Eranian 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Intel RAPL interface is specified in the IA-32 Manual Vol3b 78c2ecf20Sopenharmony_ci * section 14.7.1 (September 2013) 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * AMD RAPL interface for Fam17h is described in the public PPR: 108c2ecf20Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=206537 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * RAPL provides more controls than just reporting energy consumption 138c2ecf20Sopenharmony_ci * however here we only expose the 3 energy consumption free running 148c2ecf20Sopenharmony_ci * counters (pp0, pkg, dram). 158c2ecf20Sopenharmony_ci * 168c2ecf20Sopenharmony_ci * Each of those counters increments in a power unit defined by the 178c2ecf20Sopenharmony_ci * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules 188c2ecf20Sopenharmony_ci * but it can vary. 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Counter to rapl events mappings: 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * pp0 counter: consumption of all physical cores (power plane 0) 238c2ecf20Sopenharmony_ci * event: rapl_energy_cores 248c2ecf20Sopenharmony_ci * perf code: 0x1 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * pkg counter: consumption of the whole processor package 278c2ecf20Sopenharmony_ci * event: rapl_energy_pkg 288c2ecf20Sopenharmony_ci * perf code: 0x2 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * dram counter: consumption of the dram domain (servers only) 318c2ecf20Sopenharmony_ci * event: rapl_energy_dram 328c2ecf20Sopenharmony_ci * perf code: 0x3 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * gpu counter: consumption of the builtin-gpu domain (client only) 358c2ecf20Sopenharmony_ci * event: rapl_energy_gpu 368c2ecf20Sopenharmony_ci * perf code: 0x4 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * psys counter: consumption of the builtin-psys domain (client only) 398c2ecf20Sopenharmony_ci * event: rapl_energy_psys 408c2ecf20Sopenharmony_ci * perf code: 0x5 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * We manage those counters as free running (read-only). They may be 438c2ecf20Sopenharmony_ci * use simultaneously by other tools, such as turbostat. 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * The events only support system-wide mode counting. There is no 468c2ecf20Sopenharmony_ci * sampling support because it does not make sense and is not 478c2ecf20Sopenharmony_ci * supported by the RAPL hardware. 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * Because we want to avoid floating-point operations in the kernel, 508c2ecf20Sopenharmony_ci * the events are all reported in fixed point arithmetic (32.32). 518c2ecf20Sopenharmony_ci * Tools must adjust the counts to convert them to Watts using 528c2ecf20Sopenharmony_ci * the duration of the measurement. Tools may use a function such as 538c2ecf20Sopenharmony_ci * ldexp(raw_count, -32); 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "RAPL PMU: " fmt 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci#include <linux/module.h> 598c2ecf20Sopenharmony_ci#include <linux/slab.h> 608c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 618c2ecf20Sopenharmony_ci#include <linux/nospec.h> 628c2ecf20Sopenharmony_ci#include <asm/cpu_device_id.h> 638c2ecf20Sopenharmony_ci#include <asm/intel-family.h> 648c2ecf20Sopenharmony_ci#include "perf_event.h" 658c2ecf20Sopenharmony_ci#include "probe.h" 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * RAPL energy status counters 718c2ecf20Sopenharmony_ci */ 728c2ecf20Sopenharmony_cienum perf_rapl_events { 738c2ecf20Sopenharmony_ci PERF_RAPL_PP0 = 0, /* all cores */ 748c2ecf20Sopenharmony_ci PERF_RAPL_PKG, /* entire package */ 758c2ecf20Sopenharmony_ci PERF_RAPL_RAM, /* DRAM */ 768c2ecf20Sopenharmony_ci PERF_RAPL_PP1, /* gpu */ 778c2ecf20Sopenharmony_ci PERF_RAPL_PSYS, /* psys */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci PERF_RAPL_MAX, 808c2ecf20Sopenharmony_ci NR_RAPL_DOMAINS = PERF_RAPL_MAX, 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = { 848c2ecf20Sopenharmony_ci "pp0-core", 858c2ecf20Sopenharmony_ci "package", 868c2ecf20Sopenharmony_ci "dram", 878c2ecf20Sopenharmony_ci "pp1-gpu", 888c2ecf20Sopenharmony_ci "psys", 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci/* 928c2ecf20Sopenharmony_ci * event code: LSB 8 bits, passed in attr->config 938c2ecf20Sopenharmony_ci * any other bit is reserved 948c2ecf20Sopenharmony_ci */ 958c2ecf20Sopenharmony_ci#define RAPL_EVENT_MASK 0xFFULL 968c2ecf20Sopenharmony_ci#define RAPL_CNTR_WIDTH 32 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define RAPL_EVENT_ATTR_STR(_name, v, str) \ 998c2ecf20Sopenharmony_cistatic struct perf_pmu_events_attr event_attr_##v = { \ 1008c2ecf20Sopenharmony_ci .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \ 1018c2ecf20Sopenharmony_ci .id = 0, \ 1028c2ecf20Sopenharmony_ci .event_str = str, \ 1038c2ecf20Sopenharmony_ci}; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct rapl_pmu { 1068c2ecf20Sopenharmony_ci raw_spinlock_t lock; 1078c2ecf20Sopenharmony_ci int n_active; 1088c2ecf20Sopenharmony_ci int cpu; 1098c2ecf20Sopenharmony_ci struct list_head active_list; 1108c2ecf20Sopenharmony_ci struct pmu *pmu; 1118c2ecf20Sopenharmony_ci ktime_t timer_interval; 1128c2ecf20Sopenharmony_ci struct hrtimer hrtimer; 1138c2ecf20Sopenharmony_ci}; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistruct rapl_pmus { 1168c2ecf20Sopenharmony_ci struct pmu pmu; 1178c2ecf20Sopenharmony_ci unsigned int maxdie; 1188c2ecf20Sopenharmony_ci struct rapl_pmu *pmus[]; 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cienum rapl_unit_quirk { 1228c2ecf20Sopenharmony_ci RAPL_UNIT_QUIRK_NONE, 1238c2ecf20Sopenharmony_ci RAPL_UNIT_QUIRK_INTEL_HSW, 1248c2ecf20Sopenharmony_ci RAPL_UNIT_QUIRK_INTEL_SPR, 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistruct rapl_model { 1288c2ecf20Sopenharmony_ci struct perf_msr *rapl_msrs; 1298c2ecf20Sopenharmony_ci unsigned long events; 1308c2ecf20Sopenharmony_ci unsigned int msr_power_unit; 1318c2ecf20Sopenharmony_ci enum rapl_unit_quirk unit_quirk; 1328c2ecf20Sopenharmony_ci}; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* 1/2^hw_unit Joule */ 1358c2ecf20Sopenharmony_cistatic int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly; 1368c2ecf20Sopenharmony_cistatic struct rapl_pmus *rapl_pmus; 1378c2ecf20Sopenharmony_cistatic cpumask_t rapl_cpu_mask; 1388c2ecf20Sopenharmony_cistatic unsigned int rapl_cntr_mask; 1398c2ecf20Sopenharmony_cistatic u64 rapl_timer_ms; 1408c2ecf20Sopenharmony_cistatic struct perf_msr *rapl_msrs; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci unsigned int dieid = topology_logical_die_id(cpu); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * The unsigned check also catches the '-1' return value for non 1488c2ecf20Sopenharmony_ci * existent mappings in the topology map. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci return dieid < rapl_pmus->maxdie ? rapl_pmus->pmus[dieid] : NULL; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_cistatic inline u64 rapl_read_counter(struct perf_event *event) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci u64 raw; 1568c2ecf20Sopenharmony_ci rdmsrl(event->hw.event_base, raw); 1578c2ecf20Sopenharmony_ci return raw; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic inline u64 rapl_scale(u64 v, int cfg) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci if (cfg > NR_RAPL_DOMAINS) { 1638c2ecf20Sopenharmony_ci pr_warn("Invalid domain %d, failed to scale data\n", cfg); 1648c2ecf20Sopenharmony_ci return v; 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci /* 1678c2ecf20Sopenharmony_ci * scale delta to smallest unit (1/2^32) 1688c2ecf20Sopenharmony_ci * users must then scale back: count * 1/(1e9*2^32) to get Joules 1698c2ecf20Sopenharmony_ci * or use ldexp(count, -32). 1708c2ecf20Sopenharmony_ci * Watts = Joules/Time delta 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci return v << (32 - rapl_hw_unit[cfg - 1]); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic u64 rapl_event_update(struct perf_event *event) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 1788c2ecf20Sopenharmony_ci u64 prev_raw_count, new_raw_count; 1798c2ecf20Sopenharmony_ci s64 delta, sdelta; 1808c2ecf20Sopenharmony_ci int shift = RAPL_CNTR_WIDTH; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ciagain: 1838c2ecf20Sopenharmony_ci prev_raw_count = local64_read(&hwc->prev_count); 1848c2ecf20Sopenharmony_ci rdmsrl(event->hw.event_base, new_raw_count); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, 1878c2ecf20Sopenharmony_ci new_raw_count) != prev_raw_count) { 1888c2ecf20Sopenharmony_ci cpu_relax(); 1898c2ecf20Sopenharmony_ci goto again; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Now we have the new raw value and have updated the prev 1948c2ecf20Sopenharmony_ci * timestamp already. We can now calculate the elapsed delta 1958c2ecf20Sopenharmony_ci * (event-)time and add that to the generic event. 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * Careful, not all hw sign-extends above the physical width 1988c2ecf20Sopenharmony_ci * of the count. 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci delta = (new_raw_count << shift) - (prev_raw_count << shift); 2018c2ecf20Sopenharmony_ci delta >>= shift; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci sdelta = rapl_scale(delta, event->hw.config); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci local64_add(sdelta, &event->count); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci return new_raw_count; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic void rapl_start_hrtimer(struct rapl_pmu *pmu) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci hrtimer_start(&pmu->hrtimer, pmu->timer_interval, 2138c2ecf20Sopenharmony_ci HRTIMER_MODE_REL_PINNED); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct rapl_pmu *pmu = container_of(hrtimer, struct rapl_pmu, hrtimer); 2198c2ecf20Sopenharmony_ci struct perf_event *event; 2208c2ecf20Sopenharmony_ci unsigned long flags; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci if (!pmu->n_active) 2238c2ecf20Sopenharmony_ci return HRTIMER_NORESTART; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci list_for_each_entry(event, &pmu->active_list, active_entry) 2288c2ecf20Sopenharmony_ci rapl_event_update(event); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci hrtimer_forward_now(hrtimer, pmu->timer_interval); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci return HRTIMER_RESTART; 2358c2ecf20Sopenharmony_ci} 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void rapl_hrtimer_init(struct rapl_pmu *pmu) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct hrtimer *hr = &pmu->hrtimer; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 2428c2ecf20Sopenharmony_ci hr->function = rapl_hrtimer_handle; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic void __rapl_pmu_event_start(struct rapl_pmu *pmu, 2468c2ecf20Sopenharmony_ci struct perf_event *event) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) 2498c2ecf20Sopenharmony_ci return; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci event->hw.state = 0; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci list_add_tail(&event->active_entry, &pmu->active_list); 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci local64_set(&event->hw.prev_count, rapl_read_counter(event)); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci pmu->n_active++; 2588c2ecf20Sopenharmony_ci if (pmu->n_active == 1) 2598c2ecf20Sopenharmony_ci rapl_start_hrtimer(pmu); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic void rapl_pmu_event_start(struct perf_event *event, int mode) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct rapl_pmu *pmu = event->pmu_private; 2658c2ecf20Sopenharmony_ci unsigned long flags; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 2688c2ecf20Sopenharmony_ci __rapl_pmu_event_start(pmu, event); 2698c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic void rapl_pmu_event_stop(struct perf_event *event, int mode) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct rapl_pmu *pmu = event->pmu_private; 2758c2ecf20Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 2768c2ecf20Sopenharmony_ci unsigned long flags; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* mark event as deactivated and stopped */ 2818c2ecf20Sopenharmony_ci if (!(hwc->state & PERF_HES_STOPPED)) { 2828c2ecf20Sopenharmony_ci WARN_ON_ONCE(pmu->n_active <= 0); 2838c2ecf20Sopenharmony_ci pmu->n_active--; 2848c2ecf20Sopenharmony_ci if (pmu->n_active == 0) 2858c2ecf20Sopenharmony_ci hrtimer_cancel(&pmu->hrtimer); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci list_del(&event->active_entry); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); 2908c2ecf20Sopenharmony_ci hwc->state |= PERF_HES_STOPPED; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* check if update of sw counter is necessary */ 2948c2ecf20Sopenharmony_ci if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * Drain the remaining delta count out of a event 2978c2ecf20Sopenharmony_ci * that we are disabling: 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci rapl_event_update(event); 3008c2ecf20Sopenharmony_ci hwc->state |= PERF_HES_UPTODATE; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int rapl_pmu_event_add(struct perf_event *event, int mode) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct rapl_pmu *pmu = event->pmu_private; 3098c2ecf20Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 3108c2ecf20Sopenharmony_ci unsigned long flags; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (mode & PERF_EF_START) 3178c2ecf20Sopenharmony_ci __rapl_pmu_event_start(pmu, event); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci} 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_cistatic void rapl_pmu_event_del(struct perf_event *event, int flags) 3258c2ecf20Sopenharmony_ci{ 3268c2ecf20Sopenharmony_ci rapl_pmu_event_stop(event, PERF_EF_UPDATE); 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int rapl_pmu_event_init(struct perf_event *event) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci u64 cfg = event->attr.config & RAPL_EVENT_MASK; 3328c2ecf20Sopenharmony_ci int bit, ret = 0; 3338c2ecf20Sopenharmony_ci struct rapl_pmu *pmu; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci /* only look at RAPL events */ 3368c2ecf20Sopenharmony_ci if (event->attr.type != rapl_pmus->pmu.type) 3378c2ecf20Sopenharmony_ci return -ENOENT; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* check only supported bits are set */ 3408c2ecf20Sopenharmony_ci if (event->attr.config & ~RAPL_EVENT_MASK) 3418c2ecf20Sopenharmony_ci return -EINVAL; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci if (event->cpu < 0) 3448c2ecf20Sopenharmony_ci return -EINVAL; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci if (!cfg || cfg >= NR_RAPL_DOMAINS + 1) 3498c2ecf20Sopenharmony_ci return -EINVAL; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci cfg = array_index_nospec((long)cfg, NR_RAPL_DOMAINS + 1); 3528c2ecf20Sopenharmony_ci bit = cfg - 1; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* check event supported */ 3558c2ecf20Sopenharmony_ci if (!(rapl_cntr_mask & (1 << bit))) 3568c2ecf20Sopenharmony_ci return -EINVAL; 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci /* unsupported modes and filters */ 3598c2ecf20Sopenharmony_ci if (event->attr.sample_period) /* no sampling */ 3608c2ecf20Sopenharmony_ci return -EINVAL; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci /* must be done before validate_group */ 3638c2ecf20Sopenharmony_ci pmu = cpu_to_rapl_pmu(event->cpu); 3648c2ecf20Sopenharmony_ci if (!pmu) 3658c2ecf20Sopenharmony_ci return -EINVAL; 3668c2ecf20Sopenharmony_ci event->cpu = pmu->cpu; 3678c2ecf20Sopenharmony_ci event->pmu_private = pmu; 3688c2ecf20Sopenharmony_ci event->hw.event_base = rapl_msrs[bit].msr; 3698c2ecf20Sopenharmony_ci event->hw.config = cfg; 3708c2ecf20Sopenharmony_ci event->hw.idx = bit; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci return ret; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void rapl_pmu_event_read(struct perf_event *event) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci rapl_event_update(event); 3788c2ecf20Sopenharmony_ci} 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic ssize_t rapl_get_attr_cpumask(struct device *dev, 3818c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 3828c2ecf20Sopenharmony_ci{ 3838c2ecf20Sopenharmony_ci return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask); 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL); 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_cistatic struct attribute *rapl_pmu_attrs[] = { 3898c2ecf20Sopenharmony_ci &dev_attr_cpumask.attr, 3908c2ecf20Sopenharmony_ci NULL, 3918c2ecf20Sopenharmony_ci}; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic struct attribute_group rapl_pmu_attr_group = { 3948c2ecf20Sopenharmony_ci .attrs = rapl_pmu_attrs, 3958c2ecf20Sopenharmony_ci}; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); 3988c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); 3998c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); 4008c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04"); 4018c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-psys, rapl_psys, "event=0x05"); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); 4048c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules"); 4058c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules"); 4068c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules"); 4078c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-psys.unit, rapl_psys_unit, "Joules"); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci/* 4108c2ecf20Sopenharmony_ci * we compute in 0.23 nJ increments regardless of MSR 4118c2ecf20Sopenharmony_ci */ 4128c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10"); 4138c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10"); 4148c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10"); 4158c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10"); 4168c2ecf20Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10"); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci/* 4198c2ecf20Sopenharmony_ci * There are no default events, but we need to create 4208c2ecf20Sopenharmony_ci * "events" group (with empty attrs) before updating 4218c2ecf20Sopenharmony_ci * it with detected events. 4228c2ecf20Sopenharmony_ci */ 4238c2ecf20Sopenharmony_cistatic struct attribute *attrs_empty[] = { 4248c2ecf20Sopenharmony_ci NULL, 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic struct attribute_group rapl_pmu_events_group = { 4288c2ecf20Sopenharmony_ci .name = "events", 4298c2ecf20Sopenharmony_ci .attrs = attrs_empty, 4308c2ecf20Sopenharmony_ci}; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciPMU_FORMAT_ATTR(event, "config:0-7"); 4338c2ecf20Sopenharmony_cistatic struct attribute *rapl_formats_attr[] = { 4348c2ecf20Sopenharmony_ci &format_attr_event.attr, 4358c2ecf20Sopenharmony_ci NULL, 4368c2ecf20Sopenharmony_ci}; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_cistatic struct attribute_group rapl_pmu_format_group = { 4398c2ecf20Sopenharmony_ci .name = "format", 4408c2ecf20Sopenharmony_ci .attrs = rapl_formats_attr, 4418c2ecf20Sopenharmony_ci}; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_cistatic const struct attribute_group *rapl_attr_groups[] = { 4448c2ecf20Sopenharmony_ci &rapl_pmu_attr_group, 4458c2ecf20Sopenharmony_ci &rapl_pmu_format_group, 4468c2ecf20Sopenharmony_ci &rapl_pmu_events_group, 4478c2ecf20Sopenharmony_ci NULL, 4488c2ecf20Sopenharmony_ci}; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic struct attribute *rapl_events_cores[] = { 4518c2ecf20Sopenharmony_ci EVENT_PTR(rapl_cores), 4528c2ecf20Sopenharmony_ci EVENT_PTR(rapl_cores_unit), 4538c2ecf20Sopenharmony_ci EVENT_PTR(rapl_cores_scale), 4548c2ecf20Sopenharmony_ci NULL, 4558c2ecf20Sopenharmony_ci}; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic umode_t 4588c2ecf20Sopenharmony_cirapl_not_visible(struct kobject *kobj, struct attribute *attr, int i) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci return 0; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic struct attribute_group rapl_events_cores_group = { 4648c2ecf20Sopenharmony_ci .name = "events", 4658c2ecf20Sopenharmony_ci .attrs = rapl_events_cores, 4668c2ecf20Sopenharmony_ci .is_visible = rapl_not_visible, 4678c2ecf20Sopenharmony_ci}; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic struct attribute *rapl_events_pkg[] = { 4708c2ecf20Sopenharmony_ci EVENT_PTR(rapl_pkg), 4718c2ecf20Sopenharmony_ci EVENT_PTR(rapl_pkg_unit), 4728c2ecf20Sopenharmony_ci EVENT_PTR(rapl_pkg_scale), 4738c2ecf20Sopenharmony_ci NULL, 4748c2ecf20Sopenharmony_ci}; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_cistatic struct attribute_group rapl_events_pkg_group = { 4778c2ecf20Sopenharmony_ci .name = "events", 4788c2ecf20Sopenharmony_ci .attrs = rapl_events_pkg, 4798c2ecf20Sopenharmony_ci .is_visible = rapl_not_visible, 4808c2ecf20Sopenharmony_ci}; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic struct attribute *rapl_events_ram[] = { 4838c2ecf20Sopenharmony_ci EVENT_PTR(rapl_ram), 4848c2ecf20Sopenharmony_ci EVENT_PTR(rapl_ram_unit), 4858c2ecf20Sopenharmony_ci EVENT_PTR(rapl_ram_scale), 4868c2ecf20Sopenharmony_ci NULL, 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic struct attribute_group rapl_events_ram_group = { 4908c2ecf20Sopenharmony_ci .name = "events", 4918c2ecf20Sopenharmony_ci .attrs = rapl_events_ram, 4928c2ecf20Sopenharmony_ci .is_visible = rapl_not_visible, 4938c2ecf20Sopenharmony_ci}; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic struct attribute *rapl_events_gpu[] = { 4968c2ecf20Sopenharmony_ci EVENT_PTR(rapl_gpu), 4978c2ecf20Sopenharmony_ci EVENT_PTR(rapl_gpu_unit), 4988c2ecf20Sopenharmony_ci EVENT_PTR(rapl_gpu_scale), 4998c2ecf20Sopenharmony_ci NULL, 5008c2ecf20Sopenharmony_ci}; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_cistatic struct attribute_group rapl_events_gpu_group = { 5038c2ecf20Sopenharmony_ci .name = "events", 5048c2ecf20Sopenharmony_ci .attrs = rapl_events_gpu, 5058c2ecf20Sopenharmony_ci .is_visible = rapl_not_visible, 5068c2ecf20Sopenharmony_ci}; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_cistatic struct attribute *rapl_events_psys[] = { 5098c2ecf20Sopenharmony_ci EVENT_PTR(rapl_psys), 5108c2ecf20Sopenharmony_ci EVENT_PTR(rapl_psys_unit), 5118c2ecf20Sopenharmony_ci EVENT_PTR(rapl_psys_scale), 5128c2ecf20Sopenharmony_ci NULL, 5138c2ecf20Sopenharmony_ci}; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_cistatic struct attribute_group rapl_events_psys_group = { 5168c2ecf20Sopenharmony_ci .name = "events", 5178c2ecf20Sopenharmony_ci .attrs = rapl_events_psys, 5188c2ecf20Sopenharmony_ci .is_visible = rapl_not_visible, 5198c2ecf20Sopenharmony_ci}; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_cistatic bool test_msr(int idx, void *data) 5228c2ecf20Sopenharmony_ci{ 5238c2ecf20Sopenharmony_ci return test_bit(idx, (unsigned long *) data); 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic struct perf_msr intel_rapl_msrs[] = { 5278c2ecf20Sopenharmony_ci [PERF_RAPL_PP0] = { MSR_PP0_ENERGY_STATUS, &rapl_events_cores_group, test_msr }, 5288c2ecf20Sopenharmony_ci [PERF_RAPL_PKG] = { MSR_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr }, 5298c2ecf20Sopenharmony_ci [PERF_RAPL_RAM] = { MSR_DRAM_ENERGY_STATUS, &rapl_events_ram_group, test_msr }, 5308c2ecf20Sopenharmony_ci [PERF_RAPL_PP1] = { MSR_PP1_ENERGY_STATUS, &rapl_events_gpu_group, test_msr }, 5318c2ecf20Sopenharmony_ci [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group, test_msr }, 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/* 5358c2ecf20Sopenharmony_ci * Force to PERF_RAPL_MAX size due to: 5368c2ecf20Sopenharmony_ci * - perf_msr_probe(PERF_RAPL_MAX) 5378c2ecf20Sopenharmony_ci * - want to use same event codes across both architectures 5388c2ecf20Sopenharmony_ci */ 5398c2ecf20Sopenharmony_cistatic struct perf_msr amd_rapl_msrs[PERF_RAPL_MAX] = { 5408c2ecf20Sopenharmony_ci [PERF_RAPL_PKG] = { MSR_AMD_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr }, 5418c2ecf20Sopenharmony_ci}; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic int rapl_cpu_offline(unsigned int cpu) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); 5478c2ecf20Sopenharmony_ci int target; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* Check if exiting cpu is used for collecting rapl events */ 5508c2ecf20Sopenharmony_ci if (!cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask)) 5518c2ecf20Sopenharmony_ci return 0; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci pmu->cpu = -1; 5548c2ecf20Sopenharmony_ci /* Find a new cpu to collect rapl events */ 5558c2ecf20Sopenharmony_ci target = cpumask_any_but(topology_die_cpumask(cpu), cpu); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* Migrate rapl events to the new target */ 5588c2ecf20Sopenharmony_ci if (target < nr_cpu_ids) { 5598c2ecf20Sopenharmony_ci cpumask_set_cpu(target, &rapl_cpu_mask); 5608c2ecf20Sopenharmony_ci pmu->cpu = target; 5618c2ecf20Sopenharmony_ci perf_pmu_migrate_context(pmu->pmu, cpu, target); 5628c2ecf20Sopenharmony_ci } 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic int rapl_cpu_online(unsigned int cpu) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); 5698c2ecf20Sopenharmony_ci int target; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci if (!pmu) { 5728c2ecf20Sopenharmony_ci pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); 5738c2ecf20Sopenharmony_ci if (!pmu) 5748c2ecf20Sopenharmony_ci return -ENOMEM; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci raw_spin_lock_init(&pmu->lock); 5778c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&pmu->active_list); 5788c2ecf20Sopenharmony_ci pmu->pmu = &rapl_pmus->pmu; 5798c2ecf20Sopenharmony_ci pmu->timer_interval = ms_to_ktime(rapl_timer_ms); 5808c2ecf20Sopenharmony_ci rapl_hrtimer_init(pmu); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci rapl_pmus->pmus[topology_logical_die_id(cpu)] = pmu; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * Check if there is an online cpu in the package which collects rapl 5878c2ecf20Sopenharmony_ci * events already. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci target = cpumask_any_and(&rapl_cpu_mask, topology_die_cpumask(cpu)); 5908c2ecf20Sopenharmony_ci if (target < nr_cpu_ids) 5918c2ecf20Sopenharmony_ci return 0; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci cpumask_set_cpu(cpu, &rapl_cpu_mask); 5948c2ecf20Sopenharmony_ci pmu->cpu = cpu; 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic int rapl_check_hw_unit(struct rapl_model *rm) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci u64 msr_rapl_power_unit_bits; 6018c2ecf20Sopenharmony_ci int i; 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci /* protect rdmsrl() to handle virtualization */ 6048c2ecf20Sopenharmony_ci if (rdmsrl_safe(rm->msr_power_unit, &msr_rapl_power_unit_bits)) 6058c2ecf20Sopenharmony_ci return -1; 6068c2ecf20Sopenharmony_ci for (i = 0; i < NR_RAPL_DOMAINS; i++) 6078c2ecf20Sopenharmony_ci rapl_hw_unit[i] = (msr_rapl_power_unit_bits >> 8) & 0x1FULL; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci switch (rm->unit_quirk) { 6108c2ecf20Sopenharmony_ci /* 6118c2ecf20Sopenharmony_ci * DRAM domain on HSW server and KNL has fixed energy unit which can be 6128c2ecf20Sopenharmony_ci * different than the unit from power unit MSR. See 6138c2ecf20Sopenharmony_ci * "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, V2 6148c2ecf20Sopenharmony_ci * of 2. Datasheet, September 2014, Reference Number: 330784-001 " 6158c2ecf20Sopenharmony_ci */ 6168c2ecf20Sopenharmony_ci case RAPL_UNIT_QUIRK_INTEL_HSW: 6178c2ecf20Sopenharmony_ci rapl_hw_unit[PERF_RAPL_RAM] = 16; 6188c2ecf20Sopenharmony_ci break; 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * SPR shares the same DRAM domain energy unit as HSW, plus it 6218c2ecf20Sopenharmony_ci * also has a fixed energy unit for Psys domain. 6228c2ecf20Sopenharmony_ci */ 6238c2ecf20Sopenharmony_ci case RAPL_UNIT_QUIRK_INTEL_SPR: 6248c2ecf20Sopenharmony_ci rapl_hw_unit[PERF_RAPL_RAM] = 16; 6258c2ecf20Sopenharmony_ci rapl_hw_unit[PERF_RAPL_PSYS] = 0; 6268c2ecf20Sopenharmony_ci break; 6278c2ecf20Sopenharmony_ci default: 6288c2ecf20Sopenharmony_ci break; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci /* 6338c2ecf20Sopenharmony_ci * Calculate the timer rate: 6348c2ecf20Sopenharmony_ci * Use reference of 200W for scaling the timeout to avoid counter 6358c2ecf20Sopenharmony_ci * overflows. 200W = 200 Joules/sec 6368c2ecf20Sopenharmony_ci * Divide interval by 2 to avoid lockstep (2 * 100) 6378c2ecf20Sopenharmony_ci * if hw unit is 32, then we use 2 ms 1/200/2 6388c2ecf20Sopenharmony_ci */ 6398c2ecf20Sopenharmony_ci rapl_timer_ms = 2; 6408c2ecf20Sopenharmony_ci if (rapl_hw_unit[0] < 32) { 6418c2ecf20Sopenharmony_ci rapl_timer_ms = (1000 / (2 * 100)); 6428c2ecf20Sopenharmony_ci rapl_timer_ms *= (1ULL << (32 - rapl_hw_unit[0] - 1)); 6438c2ecf20Sopenharmony_ci } 6448c2ecf20Sopenharmony_ci return 0; 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic void __init rapl_advertise(void) 6488c2ecf20Sopenharmony_ci{ 6498c2ecf20Sopenharmony_ci int i; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n", 6528c2ecf20Sopenharmony_ci hweight32(rapl_cntr_mask), rapl_timer_ms); 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_ci for (i = 0; i < NR_RAPL_DOMAINS; i++) { 6558c2ecf20Sopenharmony_ci if (rapl_cntr_mask & (1 << i)) { 6568c2ecf20Sopenharmony_ci pr_info("hw unit of domain %s 2^-%d Joules\n", 6578c2ecf20Sopenharmony_ci rapl_domain_names[i], rapl_hw_unit[i]); 6588c2ecf20Sopenharmony_ci } 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci} 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_cistatic void cleanup_rapl_pmus(void) 6638c2ecf20Sopenharmony_ci{ 6648c2ecf20Sopenharmony_ci int i; 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci for (i = 0; i < rapl_pmus->maxdie; i++) 6678c2ecf20Sopenharmony_ci kfree(rapl_pmus->pmus[i]); 6688c2ecf20Sopenharmony_ci kfree(rapl_pmus); 6698c2ecf20Sopenharmony_ci} 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_cistatic const struct attribute_group *rapl_attr_update[] = { 6728c2ecf20Sopenharmony_ci &rapl_events_cores_group, 6738c2ecf20Sopenharmony_ci &rapl_events_pkg_group, 6748c2ecf20Sopenharmony_ci &rapl_events_ram_group, 6758c2ecf20Sopenharmony_ci &rapl_events_gpu_group, 6768c2ecf20Sopenharmony_ci &rapl_events_psys_group, 6778c2ecf20Sopenharmony_ci NULL, 6788c2ecf20Sopenharmony_ci}; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_cistatic int __init init_rapl_pmus(void) 6818c2ecf20Sopenharmony_ci{ 6828c2ecf20Sopenharmony_ci int maxdie = topology_max_packages() * topology_max_die_per_package(); 6838c2ecf20Sopenharmony_ci size_t size; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *); 6868c2ecf20Sopenharmony_ci rapl_pmus = kzalloc(size, GFP_KERNEL); 6878c2ecf20Sopenharmony_ci if (!rapl_pmus) 6888c2ecf20Sopenharmony_ci return -ENOMEM; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci rapl_pmus->maxdie = maxdie; 6918c2ecf20Sopenharmony_ci rapl_pmus->pmu.attr_groups = rapl_attr_groups; 6928c2ecf20Sopenharmony_ci rapl_pmus->pmu.attr_update = rapl_attr_update; 6938c2ecf20Sopenharmony_ci rapl_pmus->pmu.task_ctx_nr = perf_invalid_context; 6948c2ecf20Sopenharmony_ci rapl_pmus->pmu.event_init = rapl_pmu_event_init; 6958c2ecf20Sopenharmony_ci rapl_pmus->pmu.add = rapl_pmu_event_add; 6968c2ecf20Sopenharmony_ci rapl_pmus->pmu.del = rapl_pmu_event_del; 6978c2ecf20Sopenharmony_ci rapl_pmus->pmu.start = rapl_pmu_event_start; 6988c2ecf20Sopenharmony_ci rapl_pmus->pmu.stop = rapl_pmu_event_stop; 6998c2ecf20Sopenharmony_ci rapl_pmus->pmu.read = rapl_pmu_event_read; 7008c2ecf20Sopenharmony_ci rapl_pmus->pmu.module = THIS_MODULE; 7018c2ecf20Sopenharmony_ci rapl_pmus->pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE; 7028c2ecf20Sopenharmony_ci return 0; 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_cistatic struct rapl_model model_snb = { 7068c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 7078c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PKG) | 7088c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PP1), 7098c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7108c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7118c2ecf20Sopenharmony_ci}; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_cistatic struct rapl_model model_snbep = { 7148c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 7158c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PKG) | 7168c2ecf20Sopenharmony_ci BIT(PERF_RAPL_RAM), 7178c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7188c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7198c2ecf20Sopenharmony_ci}; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_cistatic struct rapl_model model_hsw = { 7228c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 7238c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PKG) | 7248c2ecf20Sopenharmony_ci BIT(PERF_RAPL_RAM) | 7258c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PP1), 7268c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7278c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7288c2ecf20Sopenharmony_ci}; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_cistatic struct rapl_model model_hsx = { 7318c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 7328c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PKG) | 7338c2ecf20Sopenharmony_ci BIT(PERF_RAPL_RAM), 7348c2ecf20Sopenharmony_ci .unit_quirk = RAPL_UNIT_QUIRK_INTEL_HSW, 7358c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7368c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7378c2ecf20Sopenharmony_ci}; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_cistatic struct rapl_model model_knl = { 7408c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PKG) | 7418c2ecf20Sopenharmony_ci BIT(PERF_RAPL_RAM), 7428c2ecf20Sopenharmony_ci .unit_quirk = RAPL_UNIT_QUIRK_INTEL_HSW, 7438c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7448c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7458c2ecf20Sopenharmony_ci}; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_cistatic struct rapl_model model_skl = { 7488c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 7498c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PKG) | 7508c2ecf20Sopenharmony_ci BIT(PERF_RAPL_RAM) | 7518c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PP1) | 7528c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PSYS), 7538c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7548c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7558c2ecf20Sopenharmony_ci}; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic struct rapl_model model_spr = { 7588c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 7598c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PKG) | 7608c2ecf20Sopenharmony_ci BIT(PERF_RAPL_RAM) | 7618c2ecf20Sopenharmony_ci BIT(PERF_RAPL_PSYS), 7628c2ecf20Sopenharmony_ci .unit_quirk = RAPL_UNIT_QUIRK_INTEL_SPR, 7638c2ecf20Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 7648c2ecf20Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 7658c2ecf20Sopenharmony_ci}; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic struct rapl_model model_amd_fam17h = { 7688c2ecf20Sopenharmony_ci .events = BIT(PERF_RAPL_PKG), 7698c2ecf20Sopenharmony_ci .msr_power_unit = MSR_AMD_RAPL_POWER_UNIT, 7708c2ecf20Sopenharmony_ci .rapl_msrs = amd_rapl_msrs, 7718c2ecf20Sopenharmony_ci}; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic const struct x86_cpu_id rapl_model_match[] __initconst = { 7748c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE, &model_snb), 7758c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X, &model_snbep), 7768c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE, &model_snb), 7778c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X, &model_snbep), 7788c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL, &model_hsw), 7798c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X, &model_hsx), 7808c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L, &model_hsw), 7818c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G, &model_hsw), 7828c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, &model_hsw), 7838c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, &model_hsw), 7848c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, &model_hsx), 7858c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, &model_hsx), 7868c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &model_knl), 7878c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &model_knl), 7888c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &model_skl), 7898c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &model_skl), 7908c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &model_hsx), 7918c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &model_skl), 7928c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &model_skl), 7938c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &model_skl), 7948c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &model_hsw), 7958c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, &model_hsw), 7968c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &model_hsw), 7978c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &model_skl), 7988c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, &model_skl), 7998c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &model_hsx), 8008c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &model_hsx), 8018c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &model_skl), 8028c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &model_skl), 8038c2ecf20Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &model_spr), 8048c2ecf20Sopenharmony_ci X86_MATCH_VENDOR_FAM(AMD, 0x17, &model_amd_fam17h), 8058c2ecf20Sopenharmony_ci X86_MATCH_VENDOR_FAM(HYGON, 0x18, &model_amd_fam17h), 8068c2ecf20Sopenharmony_ci X86_MATCH_VENDOR_FAM(AMD, 0x19, &model_amd_fam17h), 8078c2ecf20Sopenharmony_ci {}, 8088c2ecf20Sopenharmony_ci}; 8098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, rapl_model_match); 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_cistatic int __init rapl_pmu_init(void) 8128c2ecf20Sopenharmony_ci{ 8138c2ecf20Sopenharmony_ci const struct x86_cpu_id *id; 8148c2ecf20Sopenharmony_ci struct rapl_model *rm; 8158c2ecf20Sopenharmony_ci int ret; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci id = x86_match_cpu(rapl_model_match); 8188c2ecf20Sopenharmony_ci if (!id) 8198c2ecf20Sopenharmony_ci return -ENODEV; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci rm = (struct rapl_model *) id->driver_data; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci rapl_msrs = rm->rapl_msrs; 8248c2ecf20Sopenharmony_ci 8258c2ecf20Sopenharmony_ci rapl_cntr_mask = perf_msr_probe(rapl_msrs, PERF_RAPL_MAX, 8268c2ecf20Sopenharmony_ci false, (void *) &rm->events); 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_ci ret = rapl_check_hw_unit(rm); 8298c2ecf20Sopenharmony_ci if (ret) 8308c2ecf20Sopenharmony_ci return ret; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci ret = init_rapl_pmus(); 8338c2ecf20Sopenharmony_ci if (ret) 8348c2ecf20Sopenharmony_ci return ret; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci /* 8378c2ecf20Sopenharmony_ci * Install callbacks. Core will call them for each online cpu. 8388c2ecf20Sopenharmony_ci */ 8398c2ecf20Sopenharmony_ci ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE, 8408c2ecf20Sopenharmony_ci "perf/x86/rapl:online", 8418c2ecf20Sopenharmony_ci rapl_cpu_online, rapl_cpu_offline); 8428c2ecf20Sopenharmony_ci if (ret) 8438c2ecf20Sopenharmony_ci goto out; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1); 8468c2ecf20Sopenharmony_ci if (ret) 8478c2ecf20Sopenharmony_ci goto out1; 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci rapl_advertise(); 8508c2ecf20Sopenharmony_ci return 0; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ciout1: 8538c2ecf20Sopenharmony_ci cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE); 8548c2ecf20Sopenharmony_ciout: 8558c2ecf20Sopenharmony_ci pr_warn("Initialization failed (%d), disabled\n", ret); 8568c2ecf20Sopenharmony_ci cleanup_rapl_pmus(); 8578c2ecf20Sopenharmony_ci return ret; 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_cimodule_init(rapl_pmu_init); 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_cistatic void __exit intel_rapl_exit(void) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE); 8648c2ecf20Sopenharmony_ci perf_pmu_unregister(&rapl_pmus->pmu); 8658c2ecf20Sopenharmony_ci cleanup_rapl_pmus(); 8668c2ecf20Sopenharmony_ci} 8678c2ecf20Sopenharmony_cimodule_exit(intel_rapl_exit); 868