1fd3ae1e1SStephane Eranian // SPDX-License-Identifier: GPL-2.0-only
2fd3ae1e1SStephane Eranian /*
3fd3ae1e1SStephane Eranian * Support Intel/AMD RAPL energy consumption counters
4fd3ae1e1SStephane Eranian * Copyright (C) 2013 Google, Inc., Stephane Eranian
5fd3ae1e1SStephane Eranian *
6fd3ae1e1SStephane Eranian * Intel RAPL interface is specified in the IA-32 Manual Vol3b
7fd3ae1e1SStephane Eranian * section 14.7.1 (September 2013)
8fd3ae1e1SStephane Eranian *
9fd3ae1e1SStephane Eranian * AMD RAPL interface for Fam17h is described in the public PPR:
10fd3ae1e1SStephane Eranian * https://bugzilla.kernel.org/show_bug.cgi?id=206537
11fd3ae1e1SStephane Eranian *
12fd3ae1e1SStephane Eranian * RAPL provides more controls than just reporting energy consumption
13fd3ae1e1SStephane Eranian * however here we only expose the 3 energy consumption free running
14fd3ae1e1SStephane Eranian * counters (pp0, pkg, dram).
15fd3ae1e1SStephane Eranian *
16fd3ae1e1SStephane Eranian * Each of those counters increments in a power unit defined by the
17fd3ae1e1SStephane Eranian * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules
18fd3ae1e1SStephane Eranian * but it can vary.
19fd3ae1e1SStephane Eranian *
20fd3ae1e1SStephane Eranian * Counter to rapl events mappings:
21fd3ae1e1SStephane Eranian *
22fd3ae1e1SStephane Eranian * pp0 counter: consumption of all physical cores (power plane 0)
23fd3ae1e1SStephane Eranian * event: rapl_energy_cores
24fd3ae1e1SStephane Eranian * perf code: 0x1
25fd3ae1e1SStephane Eranian *
26fd3ae1e1SStephane Eranian * pkg counter: consumption of the whole processor package
27fd3ae1e1SStephane Eranian * event: rapl_energy_pkg
28fd3ae1e1SStephane Eranian * perf code: 0x2
29fd3ae1e1SStephane Eranian *
30fd3ae1e1SStephane Eranian * dram counter: consumption of the dram domain (servers only)
31fd3ae1e1SStephane Eranian * event: rapl_energy_dram
32fd3ae1e1SStephane Eranian * perf code: 0x3
33fd3ae1e1SStephane Eranian *
34fd3ae1e1SStephane Eranian * gpu counter: consumption of the builtin-gpu domain (client only)
35fd3ae1e1SStephane Eranian * event: rapl_energy_gpu
36fd3ae1e1SStephane Eranian * perf code: 0x4
37fd3ae1e1SStephane Eranian *
38fd3ae1e1SStephane Eranian * psys counter: consumption of the builtin-psys domain (client only)
39fd3ae1e1SStephane Eranian * event: rapl_energy_psys
40fd3ae1e1SStephane Eranian * perf code: 0x5
41fd3ae1e1SStephane Eranian *
42fd3ae1e1SStephane Eranian * We manage those counters as free running (read-only). They may be
43fd3ae1e1SStephane Eranian * use simultaneously by other tools, such as turbostat.
44fd3ae1e1SStephane Eranian *
45fd3ae1e1SStephane Eranian * The events only support system-wide mode counting. There is no
46fd3ae1e1SStephane Eranian * sampling support because it does not make sense and is not
47fd3ae1e1SStephane Eranian * supported by the RAPL hardware.
48fd3ae1e1SStephane Eranian *
49fd3ae1e1SStephane Eranian * Because we want to avoid floating-point operations in the kernel,
50fd3ae1e1SStephane Eranian * the events are all reported in fixed point arithmetic (32.32).
51fd3ae1e1SStephane Eranian * Tools must adjust the counts to convert them to Watts using
52fd3ae1e1SStephane Eranian * the duration of the measurement. Tools may use a function such as
53fd3ae1e1SStephane Eranian * ldexp(raw_count, -32);
54fd3ae1e1SStephane Eranian */
55fd3ae1e1SStephane Eranian
56fd3ae1e1SStephane Eranian #define pr_fmt(fmt) "RAPL PMU: " fmt
57fd3ae1e1SStephane Eranian
58fd3ae1e1SStephane Eranian #include <linux/module.h>
59fd3ae1e1SStephane Eranian #include <linux/slab.h>
60fd3ae1e1SStephane Eranian #include <linux/perf_event.h>
61fd3ae1e1SStephane Eranian #include <linux/nospec.h>
62fd3ae1e1SStephane Eranian #include <asm/cpu_device_id.h>
63fd3ae1e1SStephane Eranian #include <asm/intel-family.h>
64fd3ae1e1SStephane Eranian #include "perf_event.h"
65fd3ae1e1SStephane Eranian #include "probe.h"
66fd3ae1e1SStephane Eranian
67fd3ae1e1SStephane Eranian MODULE_LICENSE("GPL");
68fd3ae1e1SStephane Eranian
69fd3ae1e1SStephane Eranian /*
70fd3ae1e1SStephane Eranian * RAPL energy status counters
71fd3ae1e1SStephane Eranian */
72fd3ae1e1SStephane Eranian enum perf_rapl_events {
73fd3ae1e1SStephane Eranian PERF_RAPL_PP0 = 0, /* all cores */
74fd3ae1e1SStephane Eranian PERF_RAPL_PKG, /* entire package */
75fd3ae1e1SStephane Eranian PERF_RAPL_RAM, /* DRAM */
76fd3ae1e1SStephane Eranian PERF_RAPL_PP1, /* gpu */
77fd3ae1e1SStephane Eranian PERF_RAPL_PSYS, /* psys */
78fd3ae1e1SStephane Eranian
79fd3ae1e1SStephane Eranian PERF_RAPL_MAX,
80fd3ae1e1SStephane Eranian NR_RAPL_DOMAINS = PERF_RAPL_MAX,
81fd3ae1e1SStephane Eranian };
82fd3ae1e1SStephane Eranian
83fd3ae1e1SStephane Eranian static const char *const rapl_domain_names[NR_RAPL_DOMAINS] __initconst = {
84fd3ae1e1SStephane Eranian "pp0-core",
85fd3ae1e1SStephane Eranian "package",
86fd3ae1e1SStephane Eranian "dram",
87fd3ae1e1SStephane Eranian "pp1-gpu",
88fd3ae1e1SStephane Eranian "psys",
89fd3ae1e1SStephane Eranian };
90fd3ae1e1SStephane Eranian
91fd3ae1e1SStephane Eranian /*
92fd3ae1e1SStephane Eranian * event code: LSB 8 bits, passed in attr->config
93fd3ae1e1SStephane Eranian * any other bit is reserved
94fd3ae1e1SStephane Eranian */
95fd3ae1e1SStephane Eranian #define RAPL_EVENT_MASK 0xFFULL
96fd3ae1e1SStephane Eranian #define RAPL_CNTR_WIDTH 32
97fd3ae1e1SStephane Eranian
98fd3ae1e1SStephane Eranian #define RAPL_EVENT_ATTR_STR(_name, v, str) \
99fd3ae1e1SStephane Eranian static struct perf_pmu_events_attr event_attr_##v = { \
100fd3ae1e1SStephane Eranian .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \
101fd3ae1e1SStephane Eranian .id = 0, \
102fd3ae1e1SStephane Eranian .event_str = str, \
103fd3ae1e1SStephane Eranian };
104fd3ae1e1SStephane Eranian
105fd3ae1e1SStephane Eranian struct rapl_pmu {
106fd3ae1e1SStephane Eranian raw_spinlock_t lock;
107fd3ae1e1SStephane Eranian int n_active;
108fd3ae1e1SStephane Eranian int cpu;
109fd3ae1e1SStephane Eranian struct list_head active_list;
110fd3ae1e1SStephane Eranian struct pmu *pmu;
111fd3ae1e1SStephane Eranian ktime_t timer_interval;
112fd3ae1e1SStephane Eranian struct hrtimer hrtimer;
113fd3ae1e1SStephane Eranian };
114fd3ae1e1SStephane Eranian
115fd3ae1e1SStephane Eranian struct rapl_pmus {
116fd3ae1e1SStephane Eranian struct pmu pmu;
117fd3ae1e1SStephane Eranian unsigned int maxdie;
118fd3ae1e1SStephane Eranian struct rapl_pmu *pmus[];
119fd3ae1e1SStephane Eranian };
120fd3ae1e1SStephane Eranian
12174f41adaSZhang Rui enum rapl_unit_quirk {
12274f41adaSZhang Rui RAPL_UNIT_QUIRK_NONE,
12374f41adaSZhang Rui RAPL_UNIT_QUIRK_INTEL_HSW,
124bcfd218bSZhang Rui RAPL_UNIT_QUIRK_INTEL_SPR,
12574f41adaSZhang Rui };
12674f41adaSZhang Rui
127fd3ae1e1SStephane Eranian struct rapl_model {
1285c95c689SStephane Eranian struct perf_msr *rapl_msrs;
129fd3ae1e1SStephane Eranian unsigned long events;
1305c95c689SStephane Eranian unsigned int msr_power_unit;
13174f41adaSZhang Rui enum rapl_unit_quirk unit_quirk;
132fd3ae1e1SStephane Eranian };
133fd3ae1e1SStephane Eranian
134fd3ae1e1SStephane Eranian /* 1/2^hw_unit Joule */
135fd3ae1e1SStephane Eranian static int rapl_hw_unit[NR_RAPL_DOMAINS] __read_mostly;
136fd3ae1e1SStephane Eranian static struct rapl_pmus *rapl_pmus;
137fd3ae1e1SStephane Eranian static cpumask_t rapl_cpu_mask;
138fd3ae1e1SStephane Eranian static unsigned int rapl_cntr_mask;
139fd3ae1e1SStephane Eranian static u64 rapl_timer_ms;
1405c95c689SStephane Eranian static struct perf_msr *rapl_msrs;
141fd3ae1e1SStephane Eranian
cpu_to_rapl_pmu(unsigned int cpu)142fd3ae1e1SStephane Eranian static inline struct rapl_pmu *cpu_to_rapl_pmu(unsigned int cpu)
143fd3ae1e1SStephane Eranian {
144fd3ae1e1SStephane Eranian unsigned int dieid = topology_logical_die_id(cpu);
145fd3ae1e1SStephane Eranian
146fd3ae1e1SStephane Eranian /*
147fd3ae1e1SStephane Eranian * The unsigned check also catches the '-1' return value for non
148fd3ae1e1SStephane Eranian * existent mappings in the topology map.
149fd3ae1e1SStephane Eranian */
150fd3ae1e1SStephane Eranian return dieid < rapl_pmus->maxdie ? rapl_pmus->pmus[dieid] : NULL;
151fd3ae1e1SStephane Eranian }
152fd3ae1e1SStephane Eranian
rapl_read_counter(struct perf_event * event)153fd3ae1e1SStephane Eranian static inline u64 rapl_read_counter(struct perf_event *event)
154fd3ae1e1SStephane Eranian {
155fd3ae1e1SStephane Eranian u64 raw;
156fd3ae1e1SStephane Eranian rdmsrl(event->hw.event_base, raw);
157fd3ae1e1SStephane Eranian return raw;
158fd3ae1e1SStephane Eranian }
159fd3ae1e1SStephane Eranian
rapl_scale(u64 v,int cfg)160fd3ae1e1SStephane Eranian static inline u64 rapl_scale(u64 v, int cfg)
161fd3ae1e1SStephane Eranian {
162fd3ae1e1SStephane Eranian if (cfg > NR_RAPL_DOMAINS) {
163fd3ae1e1SStephane Eranian pr_warn("Invalid domain %d, failed to scale data\n", cfg);
164fd3ae1e1SStephane Eranian return v;
165fd3ae1e1SStephane Eranian }
166fd3ae1e1SStephane Eranian /*
167fd3ae1e1SStephane Eranian * scale delta to smallest unit (1/2^32)
168fd3ae1e1SStephane Eranian * users must then scale back: count * 1/(1e9*2^32) to get Joules
169fd3ae1e1SStephane Eranian * or use ldexp(count, -32).
170fd3ae1e1SStephane Eranian * Watts = Joules/Time delta
171fd3ae1e1SStephane Eranian */
172fd3ae1e1SStephane Eranian return v << (32 - rapl_hw_unit[cfg - 1]);
173fd3ae1e1SStephane Eranian }
174fd3ae1e1SStephane Eranian
rapl_event_update(struct perf_event * event)175fd3ae1e1SStephane Eranian static u64 rapl_event_update(struct perf_event *event)
176fd3ae1e1SStephane Eranian {
177fd3ae1e1SStephane Eranian struct hw_perf_event *hwc = &event->hw;
178fd3ae1e1SStephane Eranian u64 prev_raw_count, new_raw_count;
179fd3ae1e1SStephane Eranian s64 delta, sdelta;
180fd3ae1e1SStephane Eranian int shift = RAPL_CNTR_WIDTH;
181fd3ae1e1SStephane Eranian
182fd3ae1e1SStephane Eranian again:
183fd3ae1e1SStephane Eranian prev_raw_count = local64_read(&hwc->prev_count);
184fd3ae1e1SStephane Eranian rdmsrl(event->hw.event_base, new_raw_count);
185fd3ae1e1SStephane Eranian
186fd3ae1e1SStephane Eranian if (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
187fd3ae1e1SStephane Eranian new_raw_count) != prev_raw_count) {
188fd3ae1e1SStephane Eranian cpu_relax();
189fd3ae1e1SStephane Eranian goto again;
190fd3ae1e1SStephane Eranian }
191fd3ae1e1SStephane Eranian
192fd3ae1e1SStephane Eranian /*
193fd3ae1e1SStephane Eranian * Now we have the new raw value and have updated the prev
194fd3ae1e1SStephane Eranian * timestamp already. We can now calculate the elapsed delta
195fd3ae1e1SStephane Eranian * (event-)time and add that to the generic event.
196fd3ae1e1SStephane Eranian *
197fd3ae1e1SStephane Eranian * Careful, not all hw sign-extends above the physical width
198fd3ae1e1SStephane Eranian * of the count.
199fd3ae1e1SStephane Eranian */
200fd3ae1e1SStephane Eranian delta = (new_raw_count << shift) - (prev_raw_count << shift);
201fd3ae1e1SStephane Eranian delta >>= shift;
202fd3ae1e1SStephane Eranian
203fd3ae1e1SStephane Eranian sdelta = rapl_scale(delta, event->hw.config);
204fd3ae1e1SStephane Eranian
205fd3ae1e1SStephane Eranian local64_add(sdelta, &event->count);
206fd3ae1e1SStephane Eranian
207fd3ae1e1SStephane Eranian return new_raw_count;
208fd3ae1e1SStephane Eranian }
209fd3ae1e1SStephane Eranian
rapl_start_hrtimer(struct rapl_pmu * pmu)210fd3ae1e1SStephane Eranian static void rapl_start_hrtimer(struct rapl_pmu *pmu)
211fd3ae1e1SStephane Eranian {
212fd3ae1e1SStephane Eranian hrtimer_start(&pmu->hrtimer, pmu->timer_interval,
213fd3ae1e1SStephane Eranian HRTIMER_MODE_REL_PINNED);
214fd3ae1e1SStephane Eranian }
215fd3ae1e1SStephane Eranian
rapl_hrtimer_handle(struct hrtimer * hrtimer)216fd3ae1e1SStephane Eranian static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer)
217fd3ae1e1SStephane Eranian {
218fd3ae1e1SStephane Eranian struct rapl_pmu *pmu = container_of(hrtimer, struct rapl_pmu, hrtimer);
219fd3ae1e1SStephane Eranian struct perf_event *event;
220fd3ae1e1SStephane Eranian unsigned long flags;
221fd3ae1e1SStephane Eranian
222fd3ae1e1SStephane Eranian if (!pmu->n_active)
223fd3ae1e1SStephane Eranian return HRTIMER_NORESTART;
224fd3ae1e1SStephane Eranian
225fd3ae1e1SStephane Eranian raw_spin_lock_irqsave(&pmu->lock, flags);
226fd3ae1e1SStephane Eranian
227fd3ae1e1SStephane Eranian list_for_each_entry(event, &pmu->active_list, active_entry)
228fd3ae1e1SStephane Eranian rapl_event_update(event);
229fd3ae1e1SStephane Eranian
230fd3ae1e1SStephane Eranian raw_spin_unlock_irqrestore(&pmu->lock, flags);
231fd3ae1e1SStephane Eranian
232fd3ae1e1SStephane Eranian hrtimer_forward_now(hrtimer, pmu->timer_interval);
233fd3ae1e1SStephane Eranian
234fd3ae1e1SStephane Eranian return HRTIMER_RESTART;
235fd3ae1e1SStephane Eranian }
236fd3ae1e1SStephane Eranian
rapl_hrtimer_init(struct rapl_pmu * pmu)237fd3ae1e1SStephane Eranian static void rapl_hrtimer_init(struct rapl_pmu *pmu)
238fd3ae1e1SStephane Eranian {
239fd3ae1e1SStephane Eranian struct hrtimer *hr = &pmu->hrtimer;
240fd3ae1e1SStephane Eranian
241fd3ae1e1SStephane Eranian hrtimer_init(hr, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
242fd3ae1e1SStephane Eranian hr->function = rapl_hrtimer_handle;
243fd3ae1e1SStephane Eranian }
244fd3ae1e1SStephane Eranian
__rapl_pmu_event_start(struct rapl_pmu * pmu,struct perf_event * event)245fd3ae1e1SStephane Eranian static void __rapl_pmu_event_start(struct rapl_pmu *pmu,
246fd3ae1e1SStephane Eranian struct perf_event *event)
247fd3ae1e1SStephane Eranian {
248fd3ae1e1SStephane Eranian if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED)))
249fd3ae1e1SStephane Eranian return;
250fd3ae1e1SStephane Eranian
251fd3ae1e1SStephane Eranian event->hw.state = 0;
252fd3ae1e1SStephane Eranian
253fd3ae1e1SStephane Eranian list_add_tail(&event->active_entry, &pmu->active_list);
254fd3ae1e1SStephane Eranian
255fd3ae1e1SStephane Eranian local64_set(&event->hw.prev_count, rapl_read_counter(event));
256fd3ae1e1SStephane Eranian
257fd3ae1e1SStephane Eranian pmu->n_active++;
258fd3ae1e1SStephane Eranian if (pmu->n_active == 1)
259fd3ae1e1SStephane Eranian rapl_start_hrtimer(pmu);
260fd3ae1e1SStephane Eranian }
261fd3ae1e1SStephane Eranian
rapl_pmu_event_start(struct perf_event * event,int mode)262fd3ae1e1SStephane Eranian static void rapl_pmu_event_start(struct perf_event *event, int mode)
263fd3ae1e1SStephane Eranian {
264fd3ae1e1SStephane Eranian struct rapl_pmu *pmu = event->pmu_private;
265fd3ae1e1SStephane Eranian unsigned long flags;
266fd3ae1e1SStephane Eranian
267fd3ae1e1SStephane Eranian raw_spin_lock_irqsave(&pmu->lock, flags);
268fd3ae1e1SStephane Eranian __rapl_pmu_event_start(pmu, event);
269fd3ae1e1SStephane Eranian raw_spin_unlock_irqrestore(&pmu->lock, flags);
270fd3ae1e1SStephane Eranian }
271fd3ae1e1SStephane Eranian
rapl_pmu_event_stop(struct perf_event * event,int mode)272fd3ae1e1SStephane Eranian static void rapl_pmu_event_stop(struct perf_event *event, int mode)
273fd3ae1e1SStephane Eranian {
274fd3ae1e1SStephane Eranian struct rapl_pmu *pmu = event->pmu_private;
275fd3ae1e1SStephane Eranian struct hw_perf_event *hwc = &event->hw;
276fd3ae1e1SStephane Eranian unsigned long flags;
277fd3ae1e1SStephane Eranian
278fd3ae1e1SStephane Eranian raw_spin_lock_irqsave(&pmu->lock, flags);
279fd3ae1e1SStephane Eranian
280fd3ae1e1SStephane Eranian /* mark event as deactivated and stopped */
281fd3ae1e1SStephane Eranian if (!(hwc->state & PERF_HES_STOPPED)) {
282fd3ae1e1SStephane Eranian WARN_ON_ONCE(pmu->n_active <= 0);
283fd3ae1e1SStephane Eranian pmu->n_active--;
284fd3ae1e1SStephane Eranian if (pmu->n_active == 0)
285fd3ae1e1SStephane Eranian hrtimer_cancel(&pmu->hrtimer);
286fd3ae1e1SStephane Eranian
287fd3ae1e1SStephane Eranian list_del(&event->active_entry);
288fd3ae1e1SStephane Eranian
289fd3ae1e1SStephane Eranian WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED);
290fd3ae1e1SStephane Eranian hwc->state |= PERF_HES_STOPPED;
291fd3ae1e1SStephane Eranian }
292fd3ae1e1SStephane Eranian
293fd3ae1e1SStephane Eranian /* check if update of sw counter is necessary */
294fd3ae1e1SStephane Eranian if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) {
295fd3ae1e1SStephane Eranian /*
296fd3ae1e1SStephane Eranian * Drain the remaining delta count out of a event
297fd3ae1e1SStephane Eranian * that we are disabling:
298fd3ae1e1SStephane Eranian */
299fd3ae1e1SStephane Eranian rapl_event_update(event);
300fd3ae1e1SStephane Eranian hwc->state |= PERF_HES_UPTODATE;
301fd3ae1e1SStephane Eranian }
302fd3ae1e1SStephane Eranian
303fd3ae1e1SStephane Eranian raw_spin_unlock_irqrestore(&pmu->lock, flags);
304fd3ae1e1SStephane Eranian }
305fd3ae1e1SStephane Eranian
rapl_pmu_event_add(struct perf_event * event,int mode)306fd3ae1e1SStephane Eranian static int rapl_pmu_event_add(struct perf_event *event, int mode)
307fd3ae1e1SStephane Eranian {
308fd3ae1e1SStephane Eranian struct rapl_pmu *pmu = event->pmu_private;
309fd3ae1e1SStephane Eranian struct hw_perf_event *hwc = &event->hw;
310fd3ae1e1SStephane Eranian unsigned long flags;
311fd3ae1e1SStephane Eranian
312fd3ae1e1SStephane Eranian raw_spin_lock_irqsave(&pmu->lock, flags);
313fd3ae1e1SStephane Eranian
314fd3ae1e1SStephane Eranian hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED;
315fd3ae1e1SStephane Eranian
316fd3ae1e1SStephane Eranian if (mode & PERF_EF_START)
317fd3ae1e1SStephane Eranian __rapl_pmu_event_start(pmu, event);
318fd3ae1e1SStephane Eranian
319fd3ae1e1SStephane Eranian raw_spin_unlock_irqrestore(&pmu->lock, flags);
320fd3ae1e1SStephane Eranian
321fd3ae1e1SStephane Eranian return 0;
322fd3ae1e1SStephane Eranian }
323fd3ae1e1SStephane Eranian
rapl_pmu_event_del(struct perf_event * event,int flags)324fd3ae1e1SStephane Eranian static void rapl_pmu_event_del(struct perf_event *event, int flags)
325fd3ae1e1SStephane Eranian {
326fd3ae1e1SStephane Eranian rapl_pmu_event_stop(event, PERF_EF_UPDATE);
327fd3ae1e1SStephane Eranian }
328fd3ae1e1SStephane Eranian
rapl_pmu_event_init(struct perf_event * event)329fd3ae1e1SStephane Eranian static int rapl_pmu_event_init(struct perf_event *event)
330fd3ae1e1SStephane Eranian {
331fd3ae1e1SStephane Eranian u64 cfg = event->attr.config & RAPL_EVENT_MASK;
332fd3ae1e1SStephane Eranian int bit, ret = 0;
333fd3ae1e1SStephane Eranian struct rapl_pmu *pmu;
334fd3ae1e1SStephane Eranian
335fd3ae1e1SStephane Eranian /* only look at RAPL events */
336fd3ae1e1SStephane Eranian if (event->attr.type != rapl_pmus->pmu.type)
337fd3ae1e1SStephane Eranian return -ENOENT;
338fd3ae1e1SStephane Eranian
339fd3ae1e1SStephane Eranian /* check only supported bits are set */
340fd3ae1e1SStephane Eranian if (event->attr.config & ~RAPL_EVENT_MASK)
341fd3ae1e1SStephane Eranian return -EINVAL;
342fd3ae1e1SStephane Eranian
343fd3ae1e1SStephane Eranian if (event->cpu < 0)
344fd3ae1e1SStephane Eranian return -EINVAL;
345fd3ae1e1SStephane Eranian
346fd3ae1e1SStephane Eranian event->event_caps |= PERF_EV_CAP_READ_ACTIVE_PKG;
347fd3ae1e1SStephane Eranian
348fd3ae1e1SStephane Eranian if (!cfg || cfg >= NR_RAPL_DOMAINS + 1)
349fd3ae1e1SStephane Eranian return -EINVAL;
350fd3ae1e1SStephane Eranian
351fd3ae1e1SStephane Eranian cfg = array_index_nospec((long)cfg, NR_RAPL_DOMAINS + 1);
352fd3ae1e1SStephane Eranian bit = cfg - 1;
353fd3ae1e1SStephane Eranian
354fd3ae1e1SStephane Eranian /* check event supported */
355fd3ae1e1SStephane Eranian if (!(rapl_cntr_mask & (1 << bit)))
356fd3ae1e1SStephane Eranian return -EINVAL;
357fd3ae1e1SStephane Eranian
358fd3ae1e1SStephane Eranian /* unsupported modes and filters */
359fd3ae1e1SStephane Eranian if (event->attr.sample_period) /* no sampling */
360fd3ae1e1SStephane Eranian return -EINVAL;
361fd3ae1e1SStephane Eranian
362fd3ae1e1SStephane Eranian /* must be done before validate_group */
363fd3ae1e1SStephane Eranian pmu = cpu_to_rapl_pmu(event->cpu);
364fd3ae1e1SStephane Eranian if (!pmu)
365fd3ae1e1SStephane Eranian return -EINVAL;
366fd3ae1e1SStephane Eranian event->cpu = pmu->cpu;
367fd3ae1e1SStephane Eranian event->pmu_private = pmu;
368fd3ae1e1SStephane Eranian event->hw.event_base = rapl_msrs[bit].msr;
369fd3ae1e1SStephane Eranian event->hw.config = cfg;
370fd3ae1e1SStephane Eranian event->hw.idx = bit;
371fd3ae1e1SStephane Eranian
372fd3ae1e1SStephane Eranian return ret;
373fd3ae1e1SStephane Eranian }
374fd3ae1e1SStephane Eranian
rapl_pmu_event_read(struct perf_event * event)375fd3ae1e1SStephane Eranian static void rapl_pmu_event_read(struct perf_event *event)
376fd3ae1e1SStephane Eranian {
377fd3ae1e1SStephane Eranian rapl_event_update(event);
378fd3ae1e1SStephane Eranian }
379fd3ae1e1SStephane Eranian
rapl_get_attr_cpumask(struct device * dev,struct device_attribute * attr,char * buf)380fd3ae1e1SStephane Eranian static ssize_t rapl_get_attr_cpumask(struct device *dev,
381fd3ae1e1SStephane Eranian struct device_attribute *attr, char *buf)
382fd3ae1e1SStephane Eranian {
383fd3ae1e1SStephane Eranian return cpumap_print_to_pagebuf(true, buf, &rapl_cpu_mask);
384fd3ae1e1SStephane Eranian }
385fd3ae1e1SStephane Eranian
386fd3ae1e1SStephane Eranian static DEVICE_ATTR(cpumask, S_IRUGO, rapl_get_attr_cpumask, NULL);
387fd3ae1e1SStephane Eranian
388fd3ae1e1SStephane Eranian static struct attribute *rapl_pmu_attrs[] = {
389fd3ae1e1SStephane Eranian &dev_attr_cpumask.attr,
390fd3ae1e1SStephane Eranian NULL,
391fd3ae1e1SStephane Eranian };
392fd3ae1e1SStephane Eranian
393fd3ae1e1SStephane Eranian static struct attribute_group rapl_pmu_attr_group = {
394fd3ae1e1SStephane Eranian .attrs = rapl_pmu_attrs,
395fd3ae1e1SStephane Eranian };
396fd3ae1e1SStephane Eranian
397fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01");
398fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-pkg , rapl_pkg, "event=0x02");
399fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-ram , rapl_ram, "event=0x03");
400fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-gpu , rapl_gpu, "event=0x04");
401fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-psys, rapl_psys, "event=0x05");
402fd3ae1e1SStephane Eranian
403fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules");
404fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-pkg.unit , rapl_pkg_unit, "Joules");
405fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-ram.unit , rapl_ram_unit, "Joules");
406fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-gpu.unit , rapl_gpu_unit, "Joules");
407fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-psys.unit, rapl_psys_unit, "Joules");
408fd3ae1e1SStephane Eranian
409fd3ae1e1SStephane Eranian /*
410fd3ae1e1SStephane Eranian * we compute in 0.23 nJ increments regardless of MSR
411fd3ae1e1SStephane Eranian */
412fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10");
413fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-pkg.scale, rapl_pkg_scale, "2.3283064365386962890625e-10");
414fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-ram.scale, rapl_ram_scale, "2.3283064365386962890625e-10");
415fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-gpu.scale, rapl_gpu_scale, "2.3283064365386962890625e-10");
416fd3ae1e1SStephane Eranian RAPL_EVENT_ATTR_STR(energy-psys.scale, rapl_psys_scale, "2.3283064365386962890625e-10");
417fd3ae1e1SStephane Eranian
418fd3ae1e1SStephane Eranian /*
419fd3ae1e1SStephane Eranian * There are no default events, but we need to create
420fd3ae1e1SStephane Eranian * "events" group (with empty attrs) before updating
421fd3ae1e1SStephane Eranian * it with detected events.
422fd3ae1e1SStephane Eranian */
423fd3ae1e1SStephane Eranian static struct attribute *attrs_empty[] = {
424fd3ae1e1SStephane Eranian NULL,
425fd3ae1e1SStephane Eranian };
426fd3ae1e1SStephane Eranian
427fd3ae1e1SStephane Eranian static struct attribute_group rapl_pmu_events_group = {
428fd3ae1e1SStephane Eranian .name = "events",
429fd3ae1e1SStephane Eranian .attrs = attrs_empty,
430fd3ae1e1SStephane Eranian };
431fd3ae1e1SStephane Eranian
432ebd19fc3SSami Tolvanen PMU_FORMAT_ATTR(event, "config:0-7");
433fd3ae1e1SStephane Eranian static struct attribute *rapl_formats_attr[] = {
434fd3ae1e1SStephane Eranian &format_attr_event.attr,
435fd3ae1e1SStephane Eranian NULL,
436fd3ae1e1SStephane Eranian };
437fd3ae1e1SStephane Eranian
438fd3ae1e1SStephane Eranian static struct attribute_group rapl_pmu_format_group = {
439fd3ae1e1SStephane Eranian .name = "format",
440fd3ae1e1SStephane Eranian .attrs = rapl_formats_attr,
441fd3ae1e1SStephane Eranian };
442fd3ae1e1SStephane Eranian
443fd3ae1e1SStephane Eranian static const struct attribute_group *rapl_attr_groups[] = {
444fd3ae1e1SStephane Eranian &rapl_pmu_attr_group,
445fd3ae1e1SStephane Eranian &rapl_pmu_format_group,
446fd3ae1e1SStephane Eranian &rapl_pmu_events_group,
447fd3ae1e1SStephane Eranian NULL,
448fd3ae1e1SStephane Eranian };
449fd3ae1e1SStephane Eranian
450fd3ae1e1SStephane Eranian static struct attribute *rapl_events_cores[] = {
451fd3ae1e1SStephane Eranian EVENT_PTR(rapl_cores),
452fd3ae1e1SStephane Eranian EVENT_PTR(rapl_cores_unit),
453fd3ae1e1SStephane Eranian EVENT_PTR(rapl_cores_scale),
454fd3ae1e1SStephane Eranian NULL,
455fd3ae1e1SStephane Eranian };
456fd3ae1e1SStephane Eranian
457fd3ae1e1SStephane Eranian static struct attribute_group rapl_events_cores_group = {
458fd3ae1e1SStephane Eranian .name = "events",
459fd3ae1e1SStephane Eranian .attrs = rapl_events_cores,
460fd3ae1e1SStephane Eranian };
461fd3ae1e1SStephane Eranian
462fd3ae1e1SStephane Eranian static struct attribute *rapl_events_pkg[] = {
463fd3ae1e1SStephane Eranian EVENT_PTR(rapl_pkg),
464fd3ae1e1SStephane Eranian EVENT_PTR(rapl_pkg_unit),
465fd3ae1e1SStephane Eranian EVENT_PTR(rapl_pkg_scale),
466fd3ae1e1SStephane Eranian NULL,
467fd3ae1e1SStephane Eranian };
468fd3ae1e1SStephane Eranian
469fd3ae1e1SStephane Eranian static struct attribute_group rapl_events_pkg_group = {
470fd3ae1e1SStephane Eranian .name = "events",
471fd3ae1e1SStephane Eranian .attrs = rapl_events_pkg,
472fd3ae1e1SStephane Eranian };
473fd3ae1e1SStephane Eranian
474fd3ae1e1SStephane Eranian static struct attribute *rapl_events_ram[] = {
475fd3ae1e1SStephane Eranian EVENT_PTR(rapl_ram),
476fd3ae1e1SStephane Eranian EVENT_PTR(rapl_ram_unit),
477fd3ae1e1SStephane Eranian EVENT_PTR(rapl_ram_scale),
478fd3ae1e1SStephane Eranian NULL,
479fd3ae1e1SStephane Eranian };
480fd3ae1e1SStephane Eranian
481fd3ae1e1SStephane Eranian static struct attribute_group rapl_events_ram_group = {
482fd3ae1e1SStephane Eranian .name = "events",
483fd3ae1e1SStephane Eranian .attrs = rapl_events_ram,
484fd3ae1e1SStephane Eranian };
485fd3ae1e1SStephane Eranian
486fd3ae1e1SStephane Eranian static struct attribute *rapl_events_gpu[] = {
487fd3ae1e1SStephane Eranian EVENT_PTR(rapl_gpu),
488fd3ae1e1SStephane Eranian EVENT_PTR(rapl_gpu_unit),
489fd3ae1e1SStephane Eranian EVENT_PTR(rapl_gpu_scale),
490fd3ae1e1SStephane Eranian NULL,
491fd3ae1e1SStephane Eranian };
492fd3ae1e1SStephane Eranian
493fd3ae1e1SStephane Eranian static struct attribute_group rapl_events_gpu_group = {
494fd3ae1e1SStephane Eranian .name = "events",
495fd3ae1e1SStephane Eranian .attrs = rapl_events_gpu,
496fd3ae1e1SStephane Eranian };
497fd3ae1e1SStephane Eranian
498fd3ae1e1SStephane Eranian static struct attribute *rapl_events_psys[] = {
499fd3ae1e1SStephane Eranian EVENT_PTR(rapl_psys),
500fd3ae1e1SStephane Eranian EVENT_PTR(rapl_psys_unit),
501fd3ae1e1SStephane Eranian EVENT_PTR(rapl_psys_scale),
502fd3ae1e1SStephane Eranian NULL,
503fd3ae1e1SStephane Eranian };
504fd3ae1e1SStephane Eranian
505fd3ae1e1SStephane Eranian static struct attribute_group rapl_events_psys_group = {
506fd3ae1e1SStephane Eranian .name = "events",
507fd3ae1e1SStephane Eranian .attrs = rapl_events_psys,
508fd3ae1e1SStephane Eranian };
509fd3ae1e1SStephane Eranian
test_msr(int idx,void * data)510fd3ae1e1SStephane Eranian static bool test_msr(int idx, void *data)
511fd3ae1e1SStephane Eranian {
512fd3ae1e1SStephane Eranian return test_bit(idx, (unsigned long *) data);
513fd3ae1e1SStephane Eranian }
514fd3ae1e1SStephane Eranian
515b6f78d3fSZhang Rui /* Only lower 32bits of the MSR represents the energy counter */
516b6f78d3fSZhang Rui #define RAPL_MSR_MASK 0xFFFFFFFF
517b6f78d3fSZhang Rui
5185c95c689SStephane Eranian static struct perf_msr intel_rapl_msrs[] = {
519b6f78d3fSZhang Rui [PERF_RAPL_PP0] = { MSR_PP0_ENERGY_STATUS, &rapl_events_cores_group, test_msr, false, RAPL_MSR_MASK },
520b6f78d3fSZhang Rui [PERF_RAPL_PKG] = { MSR_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK },
521b6f78d3fSZhang Rui [PERF_RAPL_RAM] = { MSR_DRAM_ENERGY_STATUS, &rapl_events_ram_group, test_msr, false, RAPL_MSR_MASK },
522b6f78d3fSZhang Rui [PERF_RAPL_PP1] = { MSR_PP1_ENERGY_STATUS, &rapl_events_gpu_group, test_msr, false, RAPL_MSR_MASK },
523b6f78d3fSZhang Rui [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group, test_msr, false, RAPL_MSR_MASK },
524fd3ae1e1SStephane Eranian };
525fd3ae1e1SStephane Eranian
526838342a6SZhang Rui static struct perf_msr intel_rapl_spr_msrs[] = {
527838342a6SZhang Rui [PERF_RAPL_PP0] = { MSR_PP0_ENERGY_STATUS, &rapl_events_cores_group, test_msr, false, RAPL_MSR_MASK },
528838342a6SZhang Rui [PERF_RAPL_PKG] = { MSR_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK },
529838342a6SZhang Rui [PERF_RAPL_RAM] = { MSR_DRAM_ENERGY_STATUS, &rapl_events_ram_group, test_msr, false, RAPL_MSR_MASK },
530838342a6SZhang Rui [PERF_RAPL_PP1] = { MSR_PP1_ENERGY_STATUS, &rapl_events_gpu_group, test_msr, false, RAPL_MSR_MASK },
531838342a6SZhang Rui [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, &rapl_events_psys_group, test_msr, true, RAPL_MSR_MASK },
532838342a6SZhang Rui };
533838342a6SZhang Rui
5345cde2653SStephane Eranian /*
5355cde2653SStephane Eranian * Force to PERF_RAPL_MAX size due to:
5365cde2653SStephane Eranian * - perf_msr_probe(PERF_RAPL_MAX)
5375cde2653SStephane Eranian * - want to use same event codes across both architectures
5385cde2653SStephane Eranian */
5390036fb00SStephane Eranian static struct perf_msr amd_rapl_msrs[] = {
5400036fb00SStephane Eranian [PERF_RAPL_PP0] = { 0, &rapl_events_cores_group, 0, false, 0 },
5410036fb00SStephane Eranian [PERF_RAPL_PKG] = { MSR_AMD_PKG_ENERGY_STATUS, &rapl_events_pkg_group, test_msr, false, RAPL_MSR_MASK },
5420036fb00SStephane Eranian [PERF_RAPL_RAM] = { 0, &rapl_events_ram_group, 0, false, 0 },
5430036fb00SStephane Eranian [PERF_RAPL_PP1] = { 0, &rapl_events_gpu_group, 0, false, 0 },
5440036fb00SStephane Eranian [PERF_RAPL_PSYS] = { 0, &rapl_events_psys_group, 0, false, 0 },
5455cde2653SStephane Eranian };
5465cde2653SStephane Eranian
rapl_cpu_offline(unsigned int cpu)547fd3ae1e1SStephane Eranian static int rapl_cpu_offline(unsigned int cpu)
548fd3ae1e1SStephane Eranian {
549fd3ae1e1SStephane Eranian struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
550fd3ae1e1SStephane Eranian int target;
551fd3ae1e1SStephane Eranian
552fd3ae1e1SStephane Eranian /* Check if exiting cpu is used for collecting rapl events */
553fd3ae1e1SStephane Eranian if (!cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask))
554fd3ae1e1SStephane Eranian return 0;
555fd3ae1e1SStephane Eranian
556fd3ae1e1SStephane Eranian pmu->cpu = -1;
557fd3ae1e1SStephane Eranian /* Find a new cpu to collect rapl events */
558fd3ae1e1SStephane Eranian target = cpumask_any_but(topology_die_cpumask(cpu), cpu);
559fd3ae1e1SStephane Eranian
560fd3ae1e1SStephane Eranian /* Migrate rapl events to the new target */
561fd3ae1e1SStephane Eranian if (target < nr_cpu_ids) {
562fd3ae1e1SStephane Eranian cpumask_set_cpu(target, &rapl_cpu_mask);
563fd3ae1e1SStephane Eranian pmu->cpu = target;
564fd3ae1e1SStephane Eranian perf_pmu_migrate_context(pmu->pmu, cpu, target);
565fd3ae1e1SStephane Eranian }
566fd3ae1e1SStephane Eranian return 0;
567fd3ae1e1SStephane Eranian }
568fd3ae1e1SStephane Eranian
rapl_cpu_online(unsigned int cpu)569fd3ae1e1SStephane Eranian static int rapl_cpu_online(unsigned int cpu)
570fd3ae1e1SStephane Eranian {
571fd3ae1e1SStephane Eranian struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
572fd3ae1e1SStephane Eranian int target;
573fd3ae1e1SStephane Eranian
574fd3ae1e1SStephane Eranian if (!pmu) {
575fd3ae1e1SStephane Eranian pmu = kzalloc_node(sizeof(*pmu), GFP_KERNEL, cpu_to_node(cpu));
576fd3ae1e1SStephane Eranian if (!pmu)
577fd3ae1e1SStephane Eranian return -ENOMEM;
578fd3ae1e1SStephane Eranian
579fd3ae1e1SStephane Eranian raw_spin_lock_init(&pmu->lock);
580fd3ae1e1SStephane Eranian INIT_LIST_HEAD(&pmu->active_list);
581fd3ae1e1SStephane Eranian pmu->pmu = &rapl_pmus->pmu;
582fd3ae1e1SStephane Eranian pmu->timer_interval = ms_to_ktime(rapl_timer_ms);
583fd3ae1e1SStephane Eranian rapl_hrtimer_init(pmu);
584fd3ae1e1SStephane Eranian
585fd3ae1e1SStephane Eranian rapl_pmus->pmus[topology_logical_die_id(cpu)] = pmu;
586fd3ae1e1SStephane Eranian }
587fd3ae1e1SStephane Eranian
588fd3ae1e1SStephane Eranian /*
589fd3ae1e1SStephane Eranian * Check if there is an online cpu in the package which collects rapl
590fd3ae1e1SStephane Eranian * events already.
591fd3ae1e1SStephane Eranian */
592fd3ae1e1SStephane Eranian target = cpumask_any_and(&rapl_cpu_mask, topology_die_cpumask(cpu));
593fd3ae1e1SStephane Eranian if (target < nr_cpu_ids)
594fd3ae1e1SStephane Eranian return 0;
595fd3ae1e1SStephane Eranian
596fd3ae1e1SStephane Eranian cpumask_set_cpu(cpu, &rapl_cpu_mask);
597fd3ae1e1SStephane Eranian pmu->cpu = cpu;
598fd3ae1e1SStephane Eranian return 0;
599fd3ae1e1SStephane Eranian }
600fd3ae1e1SStephane Eranian
rapl_check_hw_unit(struct rapl_model * rm)6015c95c689SStephane Eranian static int rapl_check_hw_unit(struct rapl_model *rm)
602fd3ae1e1SStephane Eranian {
603fd3ae1e1SStephane Eranian u64 msr_rapl_power_unit_bits;
604fd3ae1e1SStephane Eranian int i;
605fd3ae1e1SStephane Eranian
606fd3ae1e1SStephane Eranian /* protect rdmsrl() to handle virtualization */
6075c95c689SStephane Eranian if (rdmsrl_safe(rm->msr_power_unit, &msr_rapl_power_unit_bits))
608fd3ae1e1SStephane Eranian return -1;
609fd3ae1e1SStephane Eranian for (i = 0; i < NR_RAPL_DOMAINS; i++)
610fd3ae1e1SStephane Eranian rapl_hw_unit[i] = (msr_rapl_power_unit_bits >> 8) & 0x1FULL;
611fd3ae1e1SStephane Eranian
61274f41adaSZhang Rui switch (rm->unit_quirk) {
613fd3ae1e1SStephane Eranian /*
614fd3ae1e1SStephane Eranian * DRAM domain on HSW server and KNL has fixed energy unit which can be
615fd3ae1e1SStephane Eranian * different than the unit from power unit MSR. See
616fd3ae1e1SStephane Eranian * "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, V2
617fd3ae1e1SStephane Eranian * of 2. Datasheet, September 2014, Reference Number: 330784-001 "
618fd3ae1e1SStephane Eranian */
61974f41adaSZhang Rui case RAPL_UNIT_QUIRK_INTEL_HSW:
620fd3ae1e1SStephane Eranian rapl_hw_unit[PERF_RAPL_RAM] = 16;
62174f41adaSZhang Rui break;
62280275ca9SZhang Rui /* SPR uses a fixed energy unit for Psys domain. */
623bcfd218bSZhang Rui case RAPL_UNIT_QUIRK_INTEL_SPR:
624bcfd218bSZhang Rui rapl_hw_unit[PERF_RAPL_PSYS] = 0;
625bcfd218bSZhang Rui break;
62674f41adaSZhang Rui default:
62774f41adaSZhang Rui break;
62874f41adaSZhang Rui }
62974f41adaSZhang Rui
630fd3ae1e1SStephane Eranian
631fd3ae1e1SStephane Eranian /*
632fd3ae1e1SStephane Eranian * Calculate the timer rate:
633fd3ae1e1SStephane Eranian * Use reference of 200W for scaling the timeout to avoid counter
634fd3ae1e1SStephane Eranian * overflows. 200W = 200 Joules/sec
635fd3ae1e1SStephane Eranian * Divide interval by 2 to avoid lockstep (2 * 100)
636fd3ae1e1SStephane Eranian * if hw unit is 32, then we use 2 ms 1/200/2
637fd3ae1e1SStephane Eranian */
638fd3ae1e1SStephane Eranian rapl_timer_ms = 2;
639fd3ae1e1SStephane Eranian if (rapl_hw_unit[0] < 32) {
640fd3ae1e1SStephane Eranian rapl_timer_ms = (1000 / (2 * 100));
641fd3ae1e1SStephane Eranian rapl_timer_ms *= (1ULL << (32 - rapl_hw_unit[0] - 1));
642fd3ae1e1SStephane Eranian }
643fd3ae1e1SStephane Eranian return 0;
644fd3ae1e1SStephane Eranian }
645fd3ae1e1SStephane Eranian
rapl_advertise(void)646fd3ae1e1SStephane Eranian static void __init rapl_advertise(void)
647fd3ae1e1SStephane Eranian {
648fd3ae1e1SStephane Eranian int i;
649fd3ae1e1SStephane Eranian
650fd3ae1e1SStephane Eranian pr_info("API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n",
651fd3ae1e1SStephane Eranian hweight32(rapl_cntr_mask), rapl_timer_ms);
652fd3ae1e1SStephane Eranian
653fd3ae1e1SStephane Eranian for (i = 0; i < NR_RAPL_DOMAINS; i++) {
654fd3ae1e1SStephane Eranian if (rapl_cntr_mask & (1 << i)) {
655fd3ae1e1SStephane Eranian pr_info("hw unit of domain %s 2^-%d Joules\n",
656fd3ae1e1SStephane Eranian rapl_domain_names[i], rapl_hw_unit[i]);
657fd3ae1e1SStephane Eranian }
658fd3ae1e1SStephane Eranian }
659fd3ae1e1SStephane Eranian }
660fd3ae1e1SStephane Eranian
cleanup_rapl_pmus(void)661fd3ae1e1SStephane Eranian static void cleanup_rapl_pmus(void)
662fd3ae1e1SStephane Eranian {
663fd3ae1e1SStephane Eranian int i;
664fd3ae1e1SStephane Eranian
665fd3ae1e1SStephane Eranian for (i = 0; i < rapl_pmus->maxdie; i++)
666fd3ae1e1SStephane Eranian kfree(rapl_pmus->pmus[i]);
667fd3ae1e1SStephane Eranian kfree(rapl_pmus);
668fd3ae1e1SStephane Eranian }
669fd3ae1e1SStephane Eranian
670fd3ae1e1SStephane Eranian static const struct attribute_group *rapl_attr_update[] = {
671fd3ae1e1SStephane Eranian &rapl_events_cores_group,
672fd3ae1e1SStephane Eranian &rapl_events_pkg_group,
673fd3ae1e1SStephane Eranian &rapl_events_ram_group,
674fd3ae1e1SStephane Eranian &rapl_events_gpu_group,
6754bb5fcb9SZhang Rui &rapl_events_psys_group,
676fd3ae1e1SStephane Eranian NULL,
677fd3ae1e1SStephane Eranian };
678fd3ae1e1SStephane Eranian
init_rapl_pmus(void)679fd3ae1e1SStephane Eranian static int __init init_rapl_pmus(void)
680fd3ae1e1SStephane Eranian {
681fd3ae1e1SStephane Eranian int maxdie = topology_max_packages() * topology_max_die_per_package();
682fd3ae1e1SStephane Eranian size_t size;
683fd3ae1e1SStephane Eranian
684fd3ae1e1SStephane Eranian size = sizeof(*rapl_pmus) + maxdie * sizeof(struct rapl_pmu *);
685fd3ae1e1SStephane Eranian rapl_pmus = kzalloc(size, GFP_KERNEL);
686fd3ae1e1SStephane Eranian if (!rapl_pmus)
687fd3ae1e1SStephane Eranian return -ENOMEM;
688fd3ae1e1SStephane Eranian
689fd3ae1e1SStephane Eranian rapl_pmus->maxdie = maxdie;
690fd3ae1e1SStephane Eranian rapl_pmus->pmu.attr_groups = rapl_attr_groups;
691fd3ae1e1SStephane Eranian rapl_pmus->pmu.attr_update = rapl_attr_update;
692fd3ae1e1SStephane Eranian rapl_pmus->pmu.task_ctx_nr = perf_invalid_context;
693fd3ae1e1SStephane Eranian rapl_pmus->pmu.event_init = rapl_pmu_event_init;
694fd3ae1e1SStephane Eranian rapl_pmus->pmu.add = rapl_pmu_event_add;
695fd3ae1e1SStephane Eranian rapl_pmus->pmu.del = rapl_pmu_event_del;
696fd3ae1e1SStephane Eranian rapl_pmus->pmu.start = rapl_pmu_event_start;
697fd3ae1e1SStephane Eranian rapl_pmus->pmu.stop = rapl_pmu_event_stop;
698fd3ae1e1SStephane Eranian rapl_pmus->pmu.read = rapl_pmu_event_read;
699fd3ae1e1SStephane Eranian rapl_pmus->pmu.module = THIS_MODULE;
700fd3ae1e1SStephane Eranian rapl_pmus->pmu.capabilities = PERF_PMU_CAP_NO_EXCLUDE;
701fd3ae1e1SStephane Eranian return 0;
702fd3ae1e1SStephane Eranian }
703fd3ae1e1SStephane Eranian
704fd3ae1e1SStephane Eranian static struct rapl_model model_snb = {
705fd3ae1e1SStephane Eranian .events = BIT(PERF_RAPL_PP0) |
706fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PKG) |
707fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PP1),
7085c95c689SStephane Eranian .msr_power_unit = MSR_RAPL_POWER_UNIT,
7095c95c689SStephane Eranian .rapl_msrs = intel_rapl_msrs,
710fd3ae1e1SStephane Eranian };
711fd3ae1e1SStephane Eranian
712fd3ae1e1SStephane Eranian static struct rapl_model model_snbep = {
713fd3ae1e1SStephane Eranian .events = BIT(PERF_RAPL_PP0) |
714fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PKG) |
715fd3ae1e1SStephane Eranian BIT(PERF_RAPL_RAM),
7165c95c689SStephane Eranian .msr_power_unit = MSR_RAPL_POWER_UNIT,
7175c95c689SStephane Eranian .rapl_msrs = intel_rapl_msrs,
718fd3ae1e1SStephane Eranian };
719fd3ae1e1SStephane Eranian
720fd3ae1e1SStephane Eranian static struct rapl_model model_hsw = {
721fd3ae1e1SStephane Eranian .events = BIT(PERF_RAPL_PP0) |
722fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PKG) |
723fd3ae1e1SStephane Eranian BIT(PERF_RAPL_RAM) |
724fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PP1),
7255c95c689SStephane Eranian .msr_power_unit = MSR_RAPL_POWER_UNIT,
7265c95c689SStephane Eranian .rapl_msrs = intel_rapl_msrs,
727fd3ae1e1SStephane Eranian };
728fd3ae1e1SStephane Eranian
729fd3ae1e1SStephane Eranian static struct rapl_model model_hsx = {
730fd3ae1e1SStephane Eranian .events = BIT(PERF_RAPL_PP0) |
731fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PKG) |
732fd3ae1e1SStephane Eranian BIT(PERF_RAPL_RAM),
73374f41adaSZhang Rui .unit_quirk = RAPL_UNIT_QUIRK_INTEL_HSW,
7345c95c689SStephane Eranian .msr_power_unit = MSR_RAPL_POWER_UNIT,
7355c95c689SStephane Eranian .rapl_msrs = intel_rapl_msrs,
736fd3ae1e1SStephane Eranian };
737fd3ae1e1SStephane Eranian
738fd3ae1e1SStephane Eranian static struct rapl_model model_knl = {
739fd3ae1e1SStephane Eranian .events = BIT(PERF_RAPL_PKG) |
740fd3ae1e1SStephane Eranian BIT(PERF_RAPL_RAM),
74174f41adaSZhang Rui .unit_quirk = RAPL_UNIT_QUIRK_INTEL_HSW,
7425c95c689SStephane Eranian .msr_power_unit = MSR_RAPL_POWER_UNIT,
7435c95c689SStephane Eranian .rapl_msrs = intel_rapl_msrs,
744fd3ae1e1SStephane Eranian };
745fd3ae1e1SStephane Eranian
746fd3ae1e1SStephane Eranian static struct rapl_model model_skl = {
747fd3ae1e1SStephane Eranian .events = BIT(PERF_RAPL_PP0) |
748fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PKG) |
749fd3ae1e1SStephane Eranian BIT(PERF_RAPL_RAM) |
750fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PP1) |
751fd3ae1e1SStephane Eranian BIT(PERF_RAPL_PSYS),
7525c95c689SStephane Eranian .msr_power_unit = MSR_RAPL_POWER_UNIT,
7535c95c689SStephane Eranian .rapl_msrs = intel_rapl_msrs,
754fd3ae1e1SStephane Eranian };
755fd3ae1e1SStephane Eranian
756bcfd218bSZhang Rui static struct rapl_model model_spr = {
757bcfd218bSZhang Rui .events = BIT(PERF_RAPL_PP0) |
758bcfd218bSZhang Rui BIT(PERF_RAPL_PKG) |
759bcfd218bSZhang Rui BIT(PERF_RAPL_RAM) |
760bcfd218bSZhang Rui BIT(PERF_RAPL_PSYS),
761bcfd218bSZhang Rui .unit_quirk = RAPL_UNIT_QUIRK_INTEL_SPR,
762bcfd218bSZhang Rui .msr_power_unit = MSR_RAPL_POWER_UNIT,
763838342a6SZhang Rui .rapl_msrs = intel_rapl_spr_msrs,
764bcfd218bSZhang Rui };
765bcfd218bSZhang Rui
766cbcddaa3SAndrew Cooper static struct rapl_model model_amd_hygon = {
7675cde2653SStephane Eranian .events = BIT(PERF_RAPL_PKG),
7685cde2653SStephane Eranian .msr_power_unit = MSR_AMD_RAPL_POWER_UNIT,
7695cde2653SStephane Eranian .rapl_msrs = amd_rapl_msrs,
7705cde2653SStephane Eranian };
7715cde2653SStephane Eranian
772fd3ae1e1SStephane Eranian static const struct x86_cpu_id rapl_model_match[] __initconst = {
773cbcddaa3SAndrew Cooper X86_MATCH_FEATURE(X86_FEATURE_RAPL, &model_amd_hygon),
774fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE, &model_snb),
775fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X, &model_snbep),
776fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE, &model_snb),
777fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X, &model_snbep),
778fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(HASWELL, &model_hsw),
779fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X, &model_hsx),
780fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L, &model_hsw),
781fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G, &model_hsw),
782fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, &model_hsw),
783fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, &model_hsw),
784fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, &model_hsx),
785fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, &model_hsx),
786fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &model_knl),
787fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &model_knl),
788fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &model_skl),
789fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &model_skl),
790fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &model_hsx),
791fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &model_skl),
792fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &model_skl),
793fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &model_skl),
794fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &model_hsw),
795fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, &model_hsw),
796fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &model_hsw),
797fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &model_skl),
798fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, &model_skl),
799fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &model_hsx),
800fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &model_hsx),
801fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &model_skl),
802fd3ae1e1SStephane Eranian X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &model_skl),
803c07311b5SChris Wilson X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &model_skl),
804c07311b5SChris Wilson X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &model_skl),
8056a5f4386SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &model_skl),
8066a5f4386SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &model_skl),
807*882cdb06SPeter Zijlstra X86_MATCH_INTEL_FAM6_MODEL(ATOM_GRACEMONT, &model_skl),
808bcfd218bSZhang Rui X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &model_spr),
80957512b57SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &model_spr),
810eff98a74SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &model_skl),
811eff98a74SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &model_skl),
812eff98a74SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, &model_skl),
813f52853a6SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, &model_skl),
814f52853a6SZhang Rui X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, &model_skl),
815fd3ae1e1SStephane Eranian {},
816fd3ae1e1SStephane Eranian };
817fd3ae1e1SStephane Eranian MODULE_DEVICE_TABLE(x86cpu, rapl_model_match);
818fd3ae1e1SStephane Eranian
rapl_pmu_init(void)819fd3ae1e1SStephane Eranian static int __init rapl_pmu_init(void)
820fd3ae1e1SStephane Eranian {
821fd3ae1e1SStephane Eranian const struct x86_cpu_id *id;
822fd3ae1e1SStephane Eranian struct rapl_model *rm;
823fd3ae1e1SStephane Eranian int ret;
824fd3ae1e1SStephane Eranian
825fd3ae1e1SStephane Eranian id = x86_match_cpu(rapl_model_match);
826fd3ae1e1SStephane Eranian if (!id)
827fd3ae1e1SStephane Eranian return -ENODEV;
828fd3ae1e1SStephane Eranian
829fd3ae1e1SStephane Eranian rm = (struct rapl_model *) id->driver_data;
8305c95c689SStephane Eranian
8315c95c689SStephane Eranian rapl_msrs = rm->rapl_msrs;
8325c95c689SStephane Eranian
833fd3ae1e1SStephane Eranian rapl_cntr_mask = perf_msr_probe(rapl_msrs, PERF_RAPL_MAX,
834fd3ae1e1SStephane Eranian false, (void *) &rm->events);
835fd3ae1e1SStephane Eranian
8365c95c689SStephane Eranian ret = rapl_check_hw_unit(rm);
837fd3ae1e1SStephane Eranian if (ret)
838fd3ae1e1SStephane Eranian return ret;
839fd3ae1e1SStephane Eranian
840fd3ae1e1SStephane Eranian ret = init_rapl_pmus();
841fd3ae1e1SStephane Eranian if (ret)
842fd3ae1e1SStephane Eranian return ret;
843fd3ae1e1SStephane Eranian
844fd3ae1e1SStephane Eranian /*
845fd3ae1e1SStephane Eranian * Install callbacks. Core will call them for each online cpu.
846fd3ae1e1SStephane Eranian */
847fd3ae1e1SStephane Eranian ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
848fd3ae1e1SStephane Eranian "perf/x86/rapl:online",
849fd3ae1e1SStephane Eranian rapl_cpu_online, rapl_cpu_offline);
850fd3ae1e1SStephane Eranian if (ret)
851fd3ae1e1SStephane Eranian goto out;
852fd3ae1e1SStephane Eranian
853fd3ae1e1SStephane Eranian ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
854fd3ae1e1SStephane Eranian if (ret)
855fd3ae1e1SStephane Eranian goto out1;
856fd3ae1e1SStephane Eranian
857fd3ae1e1SStephane Eranian rapl_advertise();
858fd3ae1e1SStephane Eranian return 0;
859fd3ae1e1SStephane Eranian
860fd3ae1e1SStephane Eranian out1:
861fd3ae1e1SStephane Eranian cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
862fd3ae1e1SStephane Eranian out:
863fd3ae1e1SStephane Eranian pr_warn("Initialization failed (%d), disabled\n", ret);
864fd3ae1e1SStephane Eranian cleanup_rapl_pmus();
865fd3ae1e1SStephane Eranian return ret;
866fd3ae1e1SStephane Eranian }
867fd3ae1e1SStephane Eranian module_init(rapl_pmu_init);
868fd3ae1e1SStephane Eranian
intel_rapl_exit(void)869fd3ae1e1SStephane Eranian static void __exit intel_rapl_exit(void)
870fd3ae1e1SStephane Eranian {
871fd3ae1e1SStephane Eranian cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
872fd3ae1e1SStephane Eranian perf_pmu_unregister(&rapl_pmus->pmu);
873fd3ae1e1SStephane Eranian cleanup_rapl_pmus();
874fd3ae1e1SStephane Eranian }
875fd3ae1e1SStephane Eranian module_exit(intel_rapl_exit);
876