162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Support Intel/AMD RAPL energy consumption counters 462306a36Sopenharmony_ci * Copyright (C) 2013 Google, Inc., Stephane Eranian 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Intel RAPL interface is specified in the IA-32 Manual Vol3b 762306a36Sopenharmony_ci * section 14.7.1 (September 2013) 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * AMD RAPL interface for Fam17h is described in the public PPR: 1062306a36Sopenharmony_ci * https://bugzilla.kernel.org/show_bug.cgi?id=206537 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * RAPL provides more controls than just reporting energy consumption 1362306a36Sopenharmony_ci * however here we only expose the 3 energy consumption free running 1462306a36Sopenharmony_ci * counters (pp0, pkg, dram). 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Each of those counters increments in a power unit defined by the 1762306a36Sopenharmony_ci * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules 1862306a36Sopenharmony_ci * but it can vary. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Counter to rapl events mappings: 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * pp0 counter: consumption of all physical cores (power plane 0) 2362306a36Sopenharmony_ci * event: rapl_energy_cores 2462306a36Sopenharmony_ci * perf code: 0x1 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * pkg counter: consumption of the whole processor package 2762306a36Sopenharmony_ci * event: rapl_energy_pkg 2862306a36Sopenharmony_ci * perf code: 0x2 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * dram counter: consumption of the dram domain (servers only) 3162306a36Sopenharmony_ci * event: rapl_energy_dram 3262306a36Sopenharmony_ci * perf code: 0x3 3362306a36Sopenharmony_ci * 3462306a36Sopenharmony_ci * gpu counter: consumption of the builtin-gpu domain (client only) 3562306a36Sopenharmony_ci * event: rapl_energy_gpu 3662306a36Sopenharmony_ci * perf code: 0x4 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * psys counter: consumption of the builtin-psys domain (client only) 3962306a36Sopenharmony_ci * event: rapl_energy_psys 4062306a36Sopenharmony_ci * perf code: 0x5 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * We manage those counters as free running (read-only). They may be 4362306a36Sopenharmony_ci * use simultaneously by other tools, such as turbostat. 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * The events only support system-wide mode counting. There is no 4662306a36Sopenharmony_ci * sampling support because it does not make sense and is not 4762306a36Sopenharmony_ci * supported by the RAPL hardware. 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * Because we want to avoid floating-point operations in the kernel, 5062306a36Sopenharmony_ci * the events are all reported in fixed point arithmetic (32.32). 5162306a36Sopenharmony_ci * Tools must adjust the counts to convert them to Watts using 5262306a36Sopenharmony_ci * the duration of the measurement. Tools may use a function such as 5362306a36Sopenharmony_ci * ldexp(raw_count, -32); 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#define pr_fmt(fmt) "RAPL PMU: " fmt 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#include <linux/module.h> 5962306a36Sopenharmony_ci#include <linux/slab.h> 6062306a36Sopenharmony_ci#include <linux/perf_event.h> 6162306a36Sopenharmony_ci#include <linux/nospec.h> 6262306a36Sopenharmony_ci#include <asm/cpu_device_id.h> 6362306a36Sopenharmony_ci#include <asm/intel-family.h> 6462306a36Sopenharmony_ci#include "perf_event.h" 6562306a36Sopenharmony_ci#include "probe.h" 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * RAPL energy status counters 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cienum perf_rapl_events { 7362306a36Sopenharmony_ci PERF_RAPL_PP0 = 0, /* all cores */ 7462306a36Sopenharmony_ci PERF_RAPL_PKG, /* entire package */ 7562306a36Sopenharmony_ci PERF_RAPL_RAM, /* DRAM */ 7662306a36Sopenharmony_ci PERF_RAPL_PP1, /* gpu */ 7762306a36Sopenharmony_ci PERF_RAPL_PSYS, /* psys */ 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci PERF_RAPL_MAX, 8062306a36Sopenharmony_ci NR_RAPL_DOMAINS = PERF_RAPL_MAX, 8162306a36Sopenharmony_ci}; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_cistatic const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = { 8462306a36Sopenharmony_ci "pp0-core", 8562306a36Sopenharmony_ci "package", 8662306a36Sopenharmony_ci "dram", 8762306a36Sopenharmony_ci "pp1-gpu", 8862306a36Sopenharmony_ci "psys", 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * event code: LSB 8 bits, passed in attr->config 9362306a36Sopenharmony_ci * any other bit is reserved 9462306a36Sopenharmony_ci */ 9562306a36Sopenharmony_ci#define RAPL_EVENT_MASK 0xFFULL 9662306a36Sopenharmony_ci#define RAPL_CNTR_WIDTH 32 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci#define RAPL_EVENT_ATTR_STR(_name, v, str) \ 9962306a36Sopenharmony_cistatic struct perf_pmu_events_attr event_attr_##v = { \ 10062306a36Sopenharmony_ci .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \ 10162306a36Sopenharmony_ci .id = 0, \ 10262306a36Sopenharmony_ci .event_str = str, \ 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistruct rapl_pmu { 10662306a36Sopenharmony_ci raw_spinlock_t lock; 10762306a36Sopenharmony_ci int n_active; 10862306a36Sopenharmony_ci int cpu; 10962306a36Sopenharmony_ci struct list_head active_list; 11062306a36Sopenharmony_ci struct pmu *pmu; 11162306a36Sopenharmony_ci ktime_t timer_interval; 11262306a36Sopenharmony_ci struct hrtimer hrtimer; 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistruct rapl_pmus { 11662306a36Sopenharmony_ci struct pmu pmu; 11762306a36Sopenharmony_ci unsigned int maxdie; 11862306a36Sopenharmony_ci struct rapl_pmu *pmus[]; 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cienum rapl_unit_quirk { 12262306a36Sopenharmony_ci RAPL_UNIT_QUIRK_NONE, 12362306a36Sopenharmony_ci RAPL_UNIT_QUIRK_INTEL_HSW, 12462306a36Sopenharmony_ci RAPL_UNIT_QUIRK_INTEL_SPR, 12562306a36Sopenharmony_ci}; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistruct rapl_model { 12862306a36Sopenharmony_ci struct perf_msr *rapl_msrs; 12962306a36Sopenharmony_ci unsigned long events; 13062306a36Sopenharmony_ci unsigned int msr_power_unit; 13162306a36Sopenharmony_ci enum rapl_unit_quirk unit_quirk; 13262306a36Sopenharmony_ci}; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* 1/2^hw_unit Joule */ 13562306a36Sopenharmony_cistatic int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly; 13662306a36Sopenharmony_cistatic struct rapl_pmus *rapl_pmus; 13762306a36Sopenharmony_cistatic cpumask_t rapl_cpu_mask; 13862306a36Sopenharmony_cistatic unsigned int rapl_cntr_mask; 13962306a36Sopenharmony_cistatic u64 rapl_timer_ms; 14062306a36Sopenharmony_cistatic struct perf_msr *rapl_msrs; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_cistatic inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci unsigned int dieid = topology_logical_die_id(cpu); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci /* 14762306a36Sopenharmony_ci * The unsigned check also catches the '-1' return value for non 14862306a36Sopenharmony_ci * existent mappings in the topology map. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci return dieid < rapl_pmus->maxdie ? rapl_pmus->pmus[dieid] : NULL; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic inline u64 rapl_read_counter(struct perf_event *event) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci u64 raw; 15662306a36Sopenharmony_ci rdmsrl(event->hw.event_base, raw); 15762306a36Sopenharmony_ci return raw; 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic inline u64 rapl_scale(u64 v, int cfg) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci if (cfg > NR_RAPL_DOMAINS) { 16362306a36Sopenharmony_ci pr_warn("Invalid domain %d, failed to scale data\n", cfg); 16462306a36Sopenharmony_ci return v; 16562306a36Sopenharmony_ci } 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * scale delta to smallest unit (1/2^32) 16862306a36Sopenharmony_ci * users must then scale back: count * 1/(1e9*2^32) to get Joules 16962306a36Sopenharmony_ci * or use ldexp(count, -32). 17062306a36Sopenharmony_ci * Watts = Joules/Time delta 17162306a36Sopenharmony_ci */ 17262306a36Sopenharmony_ci return v << (32 - rapl_hw_unit[cfg - 1]); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_cistatic u64 rapl_event_update(struct perf_event *event) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 17862306a36Sopenharmony_ci u64 prev_raw_count, new_raw_count; 17962306a36Sopenharmony_ci s64 delta, sdelta; 18062306a36Sopenharmony_ci int shift = RAPL_CNTR_WIDTH; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciagain: 18362306a36Sopenharmony_ci prev_raw_count = local64_read(&hwc->prev_count); 18462306a36Sopenharmony_ci rdmsrl(event->hw.event_base, new_raw_count); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci if (local64_cmpxchg(&hwc->prev_count, prev_raw_count, 18762306a36Sopenharmony_ci new_raw_count) != prev_raw_count) { 18862306a36Sopenharmony_ci cpu_relax(); 18962306a36Sopenharmony_ci goto again; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci /* 19362306a36Sopenharmony_ci * Now we have the new raw value and have updated the prev 19462306a36Sopenharmony_ci * timestamp already. We can now calculate the elapsed delta 19562306a36Sopenharmony_ci * (event-)time and add that to the generic event. 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Careful, not all hw sign-extends above the physical width 19862306a36Sopenharmony_ci * of the count. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci delta = (new_raw_count << shift) - (prev_raw_count << shift); 20162306a36Sopenharmony_ci delta >>= shift; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci sdelta = rapl_scale(delta, event->hw.config); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci local64_add(sdelta, &event->count); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return new_raw_count; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic void rapl_start_hrtimer(struct rapl_pmu *pmu) 21162306a36Sopenharmony_ci{ 21262306a36Sopenharmony_ci hrtimer_start(&pmu->hrtimer, pmu->timer_interval, 21362306a36Sopenharmony_ci HRTIMER_MODE_REL_PINNED); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct rapl_pmu *pmu = container_of(hrtimer, struct rapl_pmu, hrtimer); 21962306a36Sopenharmony_ci struct perf_event *event; 22062306a36Sopenharmony_ci unsigned long flags; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (!pmu->n_active) 22362306a36Sopenharmony_ci return HRTIMER_NORESTART; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci list_for_each_entry(event, &pmu->active_list, active_entry) 22862306a36Sopenharmony_ci rapl_event_update(event); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci hrtimer_forward_now(hrtimer, pmu->timer_interval); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return HRTIMER_RESTART; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void rapl_hrtimer_init(struct rapl_pmu *pmu) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct hrtimer *hr = &pmu->hrtimer; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL); 24262306a36Sopenharmony_ci hr->function = rapl_hrtimer_handle; 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic void __rapl_pmu_event_start(struct rapl_pmu *pmu, 24662306a36Sopenharmony_ci struct perf_event *event) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) 24962306a36Sopenharmony_ci return; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci event->hw.state = 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci list_add_tail(&event->active_entry, &pmu->active_list); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci local64_set(&event->hw.prev_count, rapl_read_counter(event)); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci pmu->n_active++; 25862306a36Sopenharmony_ci if (pmu->n_active == 1) 25962306a36Sopenharmony_ci rapl_start_hrtimer(pmu); 26062306a36Sopenharmony_ci} 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic void rapl_pmu_event_start(struct perf_event *event, int mode) 26362306a36Sopenharmony_ci{ 26462306a36Sopenharmony_ci struct rapl_pmu *pmu = event->pmu_private; 26562306a36Sopenharmony_ci unsigned long flags; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 26862306a36Sopenharmony_ci __rapl_pmu_event_start(pmu, event); 26962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic void rapl_pmu_event_stop(struct perf_event *event, int mode) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct rapl_pmu *pmu = event->pmu_private; 27562306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 27662306a36Sopenharmony_ci unsigned long flags; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* mark event as deactivated and stopped */ 28162306a36Sopenharmony_ci if (!(hwc->state & PERF_HES_STOPPED)) { 28262306a36Sopenharmony_ci WARN_ON_ONCE(pmu->n_active <= 0); 28362306a36Sopenharmony_ci pmu->n_active--; 28462306a36Sopenharmony_ci if (pmu->n_active == 0) 28562306a36Sopenharmony_ci hrtimer_cancel(&pmu->hrtimer); 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci list_del(&event->active_entry); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); 29062306a36Sopenharmony_ci hwc->state |= PERF_HES_STOPPED; 29162306a36Sopenharmony_ci } 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* check if update of sw counter is necessary */ 29462306a36Sopenharmony_ci if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { 29562306a36Sopenharmony_ci /* 29662306a36Sopenharmony_ci * Drain the remaining delta count out of a event 29762306a36Sopenharmony_ci * that we are disabling: 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_ci rapl_event_update(event); 30062306a36Sopenharmony_ci hwc->state |= PERF_HES_UPTODATE; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int rapl_pmu_event_add(struct perf_event *event, int mode) 30762306a36Sopenharmony_ci{ 30862306a36Sopenharmony_ci struct rapl_pmu *pmu = event->pmu_private; 30962306a36Sopenharmony_ci struct hw_perf_event *hwc = &event->hw; 31062306a36Sopenharmony_ci unsigned long flags; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci raw_spin_lock_irqsave(&pmu->lock, flags); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (mode & PERF_EF_START) 31762306a36Sopenharmony_ci __rapl_pmu_event_start(pmu, event); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&pmu->lock, flags); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return 0; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic void rapl_pmu_event_del(struct perf_event *event, int flags) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci rapl_pmu_event_stop(event, PERF_EF_UPDATE); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int rapl_pmu_event_init(struct perf_event *event) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci u64 cfg = event->attr.config & RAPL_EVENT_MASK; 33262306a36Sopenharmony_ci int bit, ret = 0; 33362306a36Sopenharmony_ci struct rapl_pmu *pmu; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* only look at RAPL events */ 33662306a36Sopenharmony_ci if (event->attr.type != rapl_pmus->pmu.type) 33762306a36Sopenharmony_ci return -ENOENT; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* check only supported bits are set */ 34062306a36Sopenharmony_ci if (event->attr.config & ~RAPL_EVENT_MASK) 34162306a36Sopenharmony_ci return -EINVAL; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (event->cpu < 0) 34462306a36Sopenharmony_ci return -EINVAL; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci if (!cfg || cfg >= NR_RAPL_DOMAINS + 1) 34962306a36Sopenharmony_ci return -EINVAL; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci cfg = array_index_nospec((long)cfg, NR_RAPL_DOMAINS + 1); 35262306a36Sopenharmony_ci bit = cfg - 1; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci /* check event supported */ 35562306a36Sopenharmony_ci if (!(rapl_cntr_mask & (1 << bit))) 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* unsupported modes and filters */ 35962306a36Sopenharmony_ci if (event->attr.sample_period) /* no sampling */ 36062306a36Sopenharmony_ci return -EINVAL; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* must be done before validate_group */ 36362306a36Sopenharmony_ci pmu = cpu_to_rapl_pmu(event->cpu); 36462306a36Sopenharmony_ci if (!pmu) 36562306a36Sopenharmony_ci return -EINVAL; 36662306a36Sopenharmony_ci event->cpu = pmu->cpu; 36762306a36Sopenharmony_ci event->pmu_private = pmu; 36862306a36Sopenharmony_ci event->hw.event_base = rapl_msrs[bit].msr; 36962306a36Sopenharmony_ci event->hw.config = cfg; 37062306a36Sopenharmony_ci event->hw.idx = bit; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci return ret; 37362306a36Sopenharmony_ci} 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_cistatic void rapl_pmu_event_read(struct perf_event *event) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci rapl_event_update(event); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic ssize_t rapl_get_attr_cpumask(struct device *dev, 38162306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic struct attribute *rapl_pmu_attrs[] = { 38962306a36Sopenharmony_ci &dev_attr_cpumask.attr, 39062306a36Sopenharmony_ci NULL, 39162306a36Sopenharmony_ci}; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cistatic struct attribute_group rapl_pmu_attr_group = { 39462306a36Sopenharmony_ci .attrs = rapl_pmu_attrs, 39562306a36Sopenharmony_ci}; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); 39862306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02"); 39962306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03"); 40062306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04"); 40162306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-psys, rapl_psys, "event=0x05"); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); 40462306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules"); 40562306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules"); 40662306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules"); 40762306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-psys.unit, rapl_psys_unit, "Joules"); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci/* 41062306a36Sopenharmony_ci * we compute in 0.23 nJ increments regardless of MSR 41162306a36Sopenharmony_ci */ 41262306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10"); 41362306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10"); 41462306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10"); 41562306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10"); 41662306a36Sopenharmony_ciRAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10"); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci/* 41962306a36Sopenharmony_ci * There are no default events, but we need to create 42062306a36Sopenharmony_ci * "events" group (with empty attrs) before updating 42162306a36Sopenharmony_ci * it with detected events. 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_cistatic struct attribute *attrs_empty[] = { 42462306a36Sopenharmony_ci NULL, 42562306a36Sopenharmony_ci}; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_cistatic struct attribute_group rapl_pmu_events_group = { 42862306a36Sopenharmony_ci .name = "events", 42962306a36Sopenharmony_ci .attrs = attrs_empty, 43062306a36Sopenharmony_ci}; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ciPMU_FORMAT_ATTR(event, "config:0-7"); 43362306a36Sopenharmony_cistatic struct attribute *rapl_formats_attr[] = { 43462306a36Sopenharmony_ci &format_attr_event.attr, 43562306a36Sopenharmony_ci NULL, 43662306a36Sopenharmony_ci}; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_cistatic struct attribute_group rapl_pmu_format_group = { 43962306a36Sopenharmony_ci .name = "format", 44062306a36Sopenharmony_ci .attrs = rapl_formats_attr, 44162306a36Sopenharmony_ci}; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic const struct attribute_group *rapl_attr_groups[] = { 44462306a36Sopenharmony_ci &rapl_pmu_attr_group, 44562306a36Sopenharmony_ci &rapl_pmu_format_group, 44662306a36Sopenharmony_ci &rapl_pmu_events_group, 44762306a36Sopenharmony_ci NULL, 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic struct attribute *rapl_events_cores[] = { 45162306a36Sopenharmony_ci EVENT_PTR(rapl_cores), 45262306a36Sopenharmony_ci EVENT_PTR(rapl_cores_unit), 45362306a36Sopenharmony_ci EVENT_PTR(rapl_cores_scale), 45462306a36Sopenharmony_ci NULL, 45562306a36Sopenharmony_ci}; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic struct attribute_group rapl_events_cores_group = { 45862306a36Sopenharmony_ci .name = "events", 45962306a36Sopenharmony_ci .attrs = rapl_events_cores, 46062306a36Sopenharmony_ci}; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic struct attribute *rapl_events_pkg[] = { 46362306a36Sopenharmony_ci EVENT_PTR(rapl_pkg), 46462306a36Sopenharmony_ci EVENT_PTR(rapl_pkg_unit), 46562306a36Sopenharmony_ci EVENT_PTR(rapl_pkg_scale), 46662306a36Sopenharmony_ci NULL, 46762306a36Sopenharmony_ci}; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic struct attribute_group rapl_events_pkg_group = { 47062306a36Sopenharmony_ci .name = "events", 47162306a36Sopenharmony_ci .attrs = rapl_events_pkg, 47262306a36Sopenharmony_ci}; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic struct attribute *rapl_events_ram[] = { 47562306a36Sopenharmony_ci EVENT_PTR(rapl_ram), 47662306a36Sopenharmony_ci EVENT_PTR(rapl_ram_unit), 47762306a36Sopenharmony_ci EVENT_PTR(rapl_ram_scale), 47862306a36Sopenharmony_ci NULL, 47962306a36Sopenharmony_ci}; 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cistatic struct attribute_group rapl_events_ram_group = { 48262306a36Sopenharmony_ci .name = "events", 48362306a36Sopenharmony_ci .attrs = rapl_events_ram, 48462306a36Sopenharmony_ci}; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_cistatic struct attribute *rapl_events_gpu[] = { 48762306a36Sopenharmony_ci EVENT_PTR(rapl_gpu), 48862306a36Sopenharmony_ci EVENT_PTR(rapl_gpu_unit), 48962306a36Sopenharmony_ci EVENT_PTR(rapl_gpu_scale), 49062306a36Sopenharmony_ci NULL, 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic struct attribute_group rapl_events_gpu_group = { 49462306a36Sopenharmony_ci .name = "events", 49562306a36Sopenharmony_ci .attrs = rapl_events_gpu, 49662306a36Sopenharmony_ci}; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic struct attribute *rapl_events_psys[] = { 49962306a36Sopenharmony_ci EVENT_PTR(rapl_psys), 50062306a36Sopenharmony_ci EVENT_PTR(rapl_psys_unit), 50162306a36Sopenharmony_ci EVENT_PTR(rapl_psys_scale), 50262306a36Sopenharmony_ci NULL, 50362306a36Sopenharmony_ci}; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic struct attribute_group rapl_events_psys_group = { 50662306a36Sopenharmony_ci .name = "events", 50762306a36Sopenharmony_ci .attrs = rapl_events_psys, 50862306a36Sopenharmony_ci}; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cistatic bool test_msr(int idx, void *data) 51162306a36Sopenharmony_ci{ 51262306a36Sopenharmony_ci return test_bit(idx, (unsigned long *) data); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci/* Only lower 32bits of the MSR represents the energy counter */ 51662306a36Sopenharmony_ci#define RAPL_MSR_MASK 0xFFFFFFFF 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic struct perf_msr intel_rapl_msrs[] = { 51962306a36Sopenharmony_ci [PERF_RAPL_PP0] = { MSR_PP0_ENERGY_STATUS, &rapl_events_cores_group, test_msr, false, RAPL_MSR_MASK }, 52062306a36Sopenharmony_ci [PERF_RAPL_PKG] = { MSR_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK }, 52162306a36Sopenharmony_ci [PERF_RAPL_RAM] = { MSR_DRAM_ENERGY_STATUS, &rapl_events_ram_group, test_msr, false, RAPL_MSR_MASK }, 52262306a36Sopenharmony_ci [PERF_RAPL_PP1] = { MSR_PP1_ENERGY_STATUS, &rapl_events_gpu_group, test_msr, false, RAPL_MSR_MASK }, 52362306a36Sopenharmony_ci [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group, test_msr, false, RAPL_MSR_MASK }, 52462306a36Sopenharmony_ci}; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic struct perf_msr intel_rapl_spr_msrs[] = { 52762306a36Sopenharmony_ci [PERF_RAPL_PP0] = { MSR_PP0_ENERGY_STATUS, &rapl_events_cores_group, test_msr, false, RAPL_MSR_MASK }, 52862306a36Sopenharmony_ci [PERF_RAPL_PKG] = { MSR_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK }, 52962306a36Sopenharmony_ci [PERF_RAPL_RAM] = { MSR_DRAM_ENERGY_STATUS, &rapl_events_ram_group, test_msr, false, RAPL_MSR_MASK }, 53062306a36Sopenharmony_ci [PERF_RAPL_PP1] = { MSR_PP1_ENERGY_STATUS, &rapl_events_gpu_group, test_msr, false, RAPL_MSR_MASK }, 53162306a36Sopenharmony_ci [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group, test_msr, true, RAPL_MSR_MASK }, 53262306a36Sopenharmony_ci}; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci/* 53562306a36Sopenharmony_ci * Force to PERF_RAPL_MAX size due to: 53662306a36Sopenharmony_ci * - perf_msr_probe(PERF_RAPL_MAX) 53762306a36Sopenharmony_ci * - want to use same event codes across both architectures 53862306a36Sopenharmony_ci */ 53962306a36Sopenharmony_cistatic struct perf_msr amd_rapl_msrs[] = { 54062306a36Sopenharmony_ci [PERF_RAPL_PP0] = { 0, &rapl_events_cores_group, 0, false, 0 }, 54162306a36Sopenharmony_ci [PERF_RAPL_PKG] = { MSR_AMD_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK }, 54262306a36Sopenharmony_ci [PERF_RAPL_RAM] = { 0, &rapl_events_ram_group, 0, false, 0 }, 54362306a36Sopenharmony_ci [PERF_RAPL_PP1] = { 0, &rapl_events_gpu_group, 0, false, 0 }, 54462306a36Sopenharmony_ci [PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group, 0, false, 0 }, 54562306a36Sopenharmony_ci}; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic int rapl_cpu_offline(unsigned int cpu) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); 55062306a36Sopenharmony_ci int target; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci /* Check if exiting cpu is used for collecting rapl events */ 55362306a36Sopenharmony_ci if (!cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask)) 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci pmu->cpu = -1; 55762306a36Sopenharmony_ci /* Find a new cpu to collect rapl events */ 55862306a36Sopenharmony_ci target = cpumask_any_but(topology_die_cpumask(cpu), cpu); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci /* Migrate rapl events to the new target */ 56162306a36Sopenharmony_ci if (target < nr_cpu_ids) { 56262306a36Sopenharmony_ci cpumask_set_cpu(target, &rapl_cpu_mask); 56362306a36Sopenharmony_ci pmu->cpu = target; 56462306a36Sopenharmony_ci perf_pmu_migrate_context(pmu->pmu, cpu, target); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic int rapl_cpu_online(unsigned int cpu) 57062306a36Sopenharmony_ci{ 57162306a36Sopenharmony_ci struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu); 57262306a36Sopenharmony_ci int target; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (!pmu) { 57562306a36Sopenharmony_ci pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu)); 57662306a36Sopenharmony_ci if (!pmu) 57762306a36Sopenharmony_ci return -ENOMEM; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci raw_spin_lock_init(&pmu->lock); 58062306a36Sopenharmony_ci INIT_LIST_HEAD(&pmu->active_list); 58162306a36Sopenharmony_ci pmu->pmu = &rapl_pmus->pmu; 58262306a36Sopenharmony_ci pmu->timer_interval = ms_to_ktime(rapl_timer_ms); 58362306a36Sopenharmony_ci rapl_hrtimer_init(pmu); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci rapl_pmus->pmus[topology_logical_die_id(cpu)] = pmu; 58662306a36Sopenharmony_ci } 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci /* 58962306a36Sopenharmony_ci * Check if there is an online cpu in the package which collects rapl 59062306a36Sopenharmony_ci * events already. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci target = cpumask_any_and(&rapl_cpu_mask, topology_die_cpumask(cpu)); 59362306a36Sopenharmony_ci if (target < nr_cpu_ids) 59462306a36Sopenharmony_ci return 0; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci cpumask_set_cpu(cpu, &rapl_cpu_mask); 59762306a36Sopenharmony_ci pmu->cpu = cpu; 59862306a36Sopenharmony_ci return 0; 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int rapl_check_hw_unit(struct rapl_model *rm) 60262306a36Sopenharmony_ci{ 60362306a36Sopenharmony_ci u64 msr_rapl_power_unit_bits; 60462306a36Sopenharmony_ci int i; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci /* protect rdmsrl() to handle virtualization */ 60762306a36Sopenharmony_ci if (rdmsrl_safe(rm->msr_power_unit, &msr_rapl_power_unit_bits)) 60862306a36Sopenharmony_ci return -1; 60962306a36Sopenharmony_ci for (i = 0; i < NR_RAPL_DOMAINS; i++) 61062306a36Sopenharmony_ci rapl_hw_unit[i] = (msr_rapl_power_unit_bits >> 8) & 0x1FULL; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci switch (rm->unit_quirk) { 61362306a36Sopenharmony_ci /* 61462306a36Sopenharmony_ci * DRAM domain on HSW server and KNL has fixed energy unit which can be 61562306a36Sopenharmony_ci * different than the unit from power unit MSR. See 61662306a36Sopenharmony_ci * "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, V2 61762306a36Sopenharmony_ci * of 2. Datasheet, September 2014, Reference Number: 330784-001 " 61862306a36Sopenharmony_ci */ 61962306a36Sopenharmony_ci case RAPL_UNIT_QUIRK_INTEL_HSW: 62062306a36Sopenharmony_ci rapl_hw_unit[PERF_RAPL_RAM] = 16; 62162306a36Sopenharmony_ci break; 62262306a36Sopenharmony_ci /* SPR uses a fixed energy unit for Psys domain. */ 62362306a36Sopenharmony_ci case RAPL_UNIT_QUIRK_INTEL_SPR: 62462306a36Sopenharmony_ci rapl_hw_unit[PERF_RAPL_PSYS] = 0; 62562306a36Sopenharmony_ci break; 62662306a36Sopenharmony_ci default: 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* 63262306a36Sopenharmony_ci * Calculate the timer rate: 63362306a36Sopenharmony_ci * Use reference of 200W for scaling the timeout to avoid counter 63462306a36Sopenharmony_ci * overflows. 200W = 200 Joules/sec 63562306a36Sopenharmony_ci * Divide interval by 2 to avoid lockstep (2 * 100) 63662306a36Sopenharmony_ci * if hw unit is 32, then we use 2 ms 1/200/2 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_ci rapl_timer_ms = 2; 63962306a36Sopenharmony_ci if (rapl_hw_unit[0] < 32) { 64062306a36Sopenharmony_ci rapl_timer_ms = (1000 / (2 * 100)); 64162306a36Sopenharmony_ci rapl_timer_ms *= (1ULL << (32 - rapl_hw_unit[0] - 1)); 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci return 0; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic void __init rapl_advertise(void) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci int i; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n", 65162306a36Sopenharmony_ci hweight32(rapl_cntr_mask), rapl_timer_ms); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci for (i = 0; i < NR_RAPL_DOMAINS; i++) { 65462306a36Sopenharmony_ci if (rapl_cntr_mask & (1 << i)) { 65562306a36Sopenharmony_ci pr_info("hw unit of domain %s 2^-%d Joules\n", 65662306a36Sopenharmony_ci rapl_domain_names[i], rapl_hw_unit[i]); 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci } 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic void cleanup_rapl_pmus(void) 66262306a36Sopenharmony_ci{ 66362306a36Sopenharmony_ci int i; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci for (i = 0; i < rapl_pmus->maxdie; i++) 66662306a36Sopenharmony_ci kfree(rapl_pmus->pmus[i]); 66762306a36Sopenharmony_ci kfree(rapl_pmus); 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_cistatic const struct attribute_group *rapl_attr_update[] = { 67162306a36Sopenharmony_ci &rapl_events_cores_group, 67262306a36Sopenharmony_ci &rapl_events_pkg_group, 67362306a36Sopenharmony_ci &rapl_events_ram_group, 67462306a36Sopenharmony_ci &rapl_events_gpu_group, 67562306a36Sopenharmony_ci &rapl_events_psys_group, 67662306a36Sopenharmony_ci NULL, 67762306a36Sopenharmony_ci}; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_cistatic int __init init_rapl_pmus(void) 68062306a36Sopenharmony_ci{ 68162306a36Sopenharmony_ci int maxdie = topology_max_packages() * topology_max_die_per_package(); 68262306a36Sopenharmony_ci size_t size; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *); 68562306a36Sopenharmony_ci rapl_pmus = kzalloc(size, GFP_KERNEL); 68662306a36Sopenharmony_ci if (!rapl_pmus) 68762306a36Sopenharmony_ci return -ENOMEM; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci rapl_pmus->maxdie = maxdie; 69062306a36Sopenharmony_ci rapl_pmus->pmu.attr_groups = rapl_attr_groups; 69162306a36Sopenharmony_ci rapl_pmus->pmu.attr_update = rapl_attr_update; 69262306a36Sopenharmony_ci rapl_pmus->pmu.task_ctx_nr = perf_invalid_context; 69362306a36Sopenharmony_ci rapl_pmus->pmu.event_init = rapl_pmu_event_init; 69462306a36Sopenharmony_ci rapl_pmus->pmu.add = rapl_pmu_event_add; 69562306a36Sopenharmony_ci rapl_pmus->pmu.del = rapl_pmu_event_del; 69662306a36Sopenharmony_ci rapl_pmus->pmu.start = rapl_pmu_event_start; 69762306a36Sopenharmony_ci rapl_pmus->pmu.stop = rapl_pmu_event_stop; 69862306a36Sopenharmony_ci rapl_pmus->pmu.read = rapl_pmu_event_read; 69962306a36Sopenharmony_ci rapl_pmus->pmu.module = THIS_MODULE; 70062306a36Sopenharmony_ci rapl_pmus->pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE; 70162306a36Sopenharmony_ci return 0; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_cistatic struct rapl_model model_snb = { 70562306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 70662306a36Sopenharmony_ci BIT(PERF_RAPL_PKG) | 70762306a36Sopenharmony_ci BIT(PERF_RAPL_PP1), 70862306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 70962306a36Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 71062306a36Sopenharmony_ci}; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic struct rapl_model model_snbep = { 71362306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 71462306a36Sopenharmony_ci BIT(PERF_RAPL_PKG) | 71562306a36Sopenharmony_ci BIT(PERF_RAPL_RAM), 71662306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 71762306a36Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 71862306a36Sopenharmony_ci}; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_cistatic struct rapl_model model_hsw = { 72162306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 72262306a36Sopenharmony_ci BIT(PERF_RAPL_PKG) | 72362306a36Sopenharmony_ci BIT(PERF_RAPL_RAM) | 72462306a36Sopenharmony_ci BIT(PERF_RAPL_PP1), 72562306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 72662306a36Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 72762306a36Sopenharmony_ci}; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic struct rapl_model model_hsx = { 73062306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 73162306a36Sopenharmony_ci BIT(PERF_RAPL_PKG) | 73262306a36Sopenharmony_ci BIT(PERF_RAPL_RAM), 73362306a36Sopenharmony_ci .unit_quirk = RAPL_UNIT_QUIRK_INTEL_HSW, 73462306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 73562306a36Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 73662306a36Sopenharmony_ci}; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic struct rapl_model model_knl = { 73962306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PKG) | 74062306a36Sopenharmony_ci BIT(PERF_RAPL_RAM), 74162306a36Sopenharmony_ci .unit_quirk = RAPL_UNIT_QUIRK_INTEL_HSW, 74262306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 74362306a36Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 74462306a36Sopenharmony_ci}; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_cistatic struct rapl_model model_skl = { 74762306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 74862306a36Sopenharmony_ci BIT(PERF_RAPL_PKG) | 74962306a36Sopenharmony_ci BIT(PERF_RAPL_RAM) | 75062306a36Sopenharmony_ci BIT(PERF_RAPL_PP1) | 75162306a36Sopenharmony_ci BIT(PERF_RAPL_PSYS), 75262306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 75362306a36Sopenharmony_ci .rapl_msrs = intel_rapl_msrs, 75462306a36Sopenharmony_ci}; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_cistatic struct rapl_model model_spr = { 75762306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PP0) | 75862306a36Sopenharmony_ci BIT(PERF_RAPL_PKG) | 75962306a36Sopenharmony_ci BIT(PERF_RAPL_RAM) | 76062306a36Sopenharmony_ci BIT(PERF_RAPL_PSYS), 76162306a36Sopenharmony_ci .unit_quirk = RAPL_UNIT_QUIRK_INTEL_SPR, 76262306a36Sopenharmony_ci .msr_power_unit = MSR_RAPL_POWER_UNIT, 76362306a36Sopenharmony_ci .rapl_msrs = intel_rapl_spr_msrs, 76462306a36Sopenharmony_ci}; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_cistatic struct rapl_model model_amd_hygon = { 76762306a36Sopenharmony_ci .events = BIT(PERF_RAPL_PKG), 76862306a36Sopenharmony_ci .msr_power_unit = MSR_AMD_RAPL_POWER_UNIT, 76962306a36Sopenharmony_ci .rapl_msrs = amd_rapl_msrs, 77062306a36Sopenharmony_ci}; 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_cistatic const struct x86_cpu_id rapl_model_match[] __initconst = { 77362306a36Sopenharmony_ci X86_MATCH_FEATURE(X86_FEATURE_RAPL, &model_amd_hygon), 77462306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE, &model_snb), 77562306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X, &model_snbep), 77662306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE, &model_snb), 77762306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X, &model_snbep), 77862306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL, &model_hsw), 77962306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X, &model_hsx), 78062306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L, &model_hsw), 78162306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G, &model_hsw), 78262306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, &model_hsw), 78362306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, &model_hsw), 78462306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, &model_hsx), 78562306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, &model_hsx), 78662306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &model_knl), 78762306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &model_knl), 78862306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &model_skl), 78962306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &model_skl), 79062306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &model_hsx), 79162306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &model_skl), 79262306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &model_skl), 79362306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &model_skl), 79462306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &model_hsw), 79562306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, &model_hsw), 79662306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &model_hsw), 79762306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &model_skl), 79862306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, &model_skl), 79962306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &model_hsx), 80062306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &model_hsx), 80162306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &model_skl), 80262306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &model_skl), 80362306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &model_skl), 80462306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &model_skl), 80562306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &model_skl), 80662306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &model_skl), 80762306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, &model_skl), 80862306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &model_spr), 80962306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &model_spr), 81062306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &model_skl), 81162306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &model_skl), 81262306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, &model_skl), 81362306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, &model_skl), 81462306a36Sopenharmony_ci X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, &model_skl), 81562306a36Sopenharmony_ci {}, 81662306a36Sopenharmony_ci}; 81762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(x86cpu, rapl_model_match); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_cistatic int __init rapl_pmu_init(void) 82062306a36Sopenharmony_ci{ 82162306a36Sopenharmony_ci const struct x86_cpu_id *id; 82262306a36Sopenharmony_ci struct rapl_model *rm; 82362306a36Sopenharmony_ci int ret; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci id = x86_match_cpu(rapl_model_match); 82662306a36Sopenharmony_ci if (!id) 82762306a36Sopenharmony_ci return -ENODEV; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci rm = (struct rapl_model *) id->driver_data; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci rapl_msrs = rm->rapl_msrs; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci rapl_cntr_mask = perf_msr_probe(rapl_msrs, PERF_RAPL_MAX, 83462306a36Sopenharmony_ci false, (void *) &rm->events); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci ret = rapl_check_hw_unit(rm); 83762306a36Sopenharmony_ci if (ret) 83862306a36Sopenharmony_ci return ret; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci ret = init_rapl_pmus(); 84162306a36Sopenharmony_ci if (ret) 84262306a36Sopenharmony_ci return ret; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci /* 84562306a36Sopenharmony_ci * Install callbacks. Core will call them for each online cpu. 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_ci ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE, 84862306a36Sopenharmony_ci "perf/x86/rapl:online", 84962306a36Sopenharmony_ci rapl_cpu_online, rapl_cpu_offline); 85062306a36Sopenharmony_ci if (ret) 85162306a36Sopenharmony_ci goto out; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1); 85462306a36Sopenharmony_ci if (ret) 85562306a36Sopenharmony_ci goto out1; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci rapl_advertise(); 85862306a36Sopenharmony_ci return 0; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ciout1: 86162306a36Sopenharmony_ci cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE); 86262306a36Sopenharmony_ciout: 86362306a36Sopenharmony_ci pr_warn("Initialization failed (%d), disabled\n", ret); 86462306a36Sopenharmony_ci cleanup_rapl_pmus(); 86562306a36Sopenharmony_ci return ret; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_cimodule_init(rapl_pmu_init); 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic void __exit intel_rapl_exit(void) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE); 87262306a36Sopenharmony_ci perf_pmu_unregister(&rapl_pmus->pmu); 87362306a36Sopenharmony_ci cleanup_rapl_pmus(); 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_cimodule_exit(intel_rapl_exit); 876