| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 3 | * Support Intel/AMD RAPL energy consumption counters | 
|---|
| 4 | * Copyright (C) 2013 Google, Inc., Stephane Eranian | 
|---|
| 5 | * | 
|---|
| 6 | * Intel RAPL interface is specified in the IA-32 Manual Vol3b | 
|---|
| 7 | * section 14.7.1 (September 2013) | 
|---|
| 8 | * | 
|---|
| 9 | * AMD RAPL interface for Fam17h is described in the public PPR: | 
|---|
| 10 | * https://bugzilla.kernel.org/show_bug.cgi?id=206537 | 
|---|
| 11 | * | 
|---|
| 12 | * RAPL provides more controls than just reporting energy consumption | 
|---|
| 13 | * however here we only expose the 3 energy consumption free running | 
|---|
| 14 | * counters (pp0, pkg, dram). | 
|---|
| 15 | * | 
|---|
| 16 | * Each of those counters increments in a power unit defined by the | 
|---|
| 17 | * RAPL_POWER_UNIT MSR. On SandyBridge, this unit is 1/(2^16) Joules | 
|---|
| 18 | * but it can vary. | 
|---|
| 19 | * | 
|---|
| 20 | * Counter to rapl events mappings: | 
|---|
| 21 | * | 
|---|
| 22 | *  pp0 counter: consumption of all physical cores (power plane 0) | 
|---|
| 23 | * 	  event: rapl_energy_cores | 
|---|
| 24 | *    perf code: 0x1 | 
|---|
| 25 | * | 
|---|
| 26 | *  pkg counter: consumption of the whole processor package | 
|---|
| 27 | *	  event: rapl_energy_pkg | 
|---|
| 28 | *    perf code: 0x2 | 
|---|
| 29 | * | 
|---|
| 30 | * dram counter: consumption of the dram domain (servers only) | 
|---|
| 31 | *	  event: rapl_energy_dram | 
|---|
| 32 | *    perf code: 0x3 | 
|---|
| 33 | * | 
|---|
| 34 | * gpu counter: consumption of the builtin-gpu domain (client only) | 
|---|
| 35 | *	  event: rapl_energy_gpu | 
|---|
| 36 | *    perf code: 0x4 | 
|---|
| 37 | * | 
|---|
| 38 | *  psys counter: consumption of the builtin-psys domain (client only) | 
|---|
| 39 | *	  event: rapl_energy_psys | 
|---|
| 40 | *    perf code: 0x5 | 
|---|
| 41 | * | 
|---|
| 42 | *  core counter: consumption of a single physical core | 
|---|
| 43 | *	  event: rapl_energy_core (power_core PMU) | 
|---|
| 44 | *    perf code: 0x1 | 
|---|
| 45 | * | 
|---|
| 46 | * We manage those counters as free running (read-only). They may be | 
|---|
| 47 | * use simultaneously by other tools, such as turbostat. | 
|---|
| 48 | * | 
|---|
| 49 | * The events only support system-wide mode counting. There is no | 
|---|
| 50 | * sampling support because it does not make sense and is not | 
|---|
| 51 | * supported by the RAPL hardware. | 
|---|
| 52 | * | 
|---|
| 53 | * Because we want to avoid floating-point operations in the kernel, | 
|---|
| 54 | * the events are all reported in fixed point arithmetic (32.32). | 
|---|
| 55 | * Tools must adjust the counts to convert them to Watts using | 
|---|
| 56 | * the duration of the measurement. Tools may use a function such as | 
|---|
| 57 | * ldexp(raw_count, -32); | 
|---|
| 58 | */ | 
|---|
| 59 |  | 
|---|
| 60 | #define pr_fmt(fmt) "RAPL PMU: " fmt | 
|---|
| 61 |  | 
|---|
| 62 | #include <linux/module.h> | 
|---|
| 63 | #include <linux/slab.h> | 
|---|
| 64 | #include <linux/perf_event.h> | 
|---|
| 65 | #include <linux/nospec.h> | 
|---|
| 66 | #include <asm/cpu_device_id.h> | 
|---|
| 67 | #include <asm/intel-family.h> | 
|---|
| 68 | #include <asm/msr.h> | 
|---|
| 69 | #include "perf_event.h" | 
|---|
| 70 | #include "probe.h" | 
|---|
| 71 |  | 
|---|
| 72 | MODULE_DESCRIPTION( "Support Intel/AMD RAPL energy consumption counters"); | 
|---|
| 73 | MODULE_LICENSE( "GPL"); | 
|---|
| 74 |  | 
|---|
| 75 | /* | 
|---|
| 76 | * RAPL energy status counters | 
|---|
| 77 | */ | 
|---|
| 78 | enum perf_rapl_pkg_events { | 
|---|
| 79 | PERF_RAPL_PP0 = 0,		/* all cores */ | 
|---|
| 80 | PERF_RAPL_PKG,			/* entire package */ | 
|---|
| 81 | PERF_RAPL_RAM,			/* DRAM */ | 
|---|
| 82 | PERF_RAPL_PP1,			/* gpu */ | 
|---|
| 83 | PERF_RAPL_PSYS,			/* psys */ | 
|---|
| 84 |  | 
|---|
| 85 | PERF_RAPL_PKG_EVENTS_MAX, | 
|---|
| 86 | NR_RAPL_PKG_DOMAINS = PERF_RAPL_PKG_EVENTS_MAX, | 
|---|
| 87 | }; | 
|---|
| 88 |  | 
|---|
| 89 | #define PERF_RAPL_CORE			0		/* single core */ | 
|---|
| 90 | #define PERF_RAPL_CORE_EVENTS_MAX	1 | 
|---|
| 91 | #define NR_RAPL_CORE_DOMAINS		PERF_RAPL_CORE_EVENTS_MAX | 
|---|
| 92 |  | 
|---|
| 93 | static const char *const rapl_pkg_domain_names[NR_RAPL_PKG_DOMAINS] __initconst = { | 
|---|
| 94 | "pp0-core", | 
|---|
| 95 | "package", | 
|---|
| 96 | "dram", | 
|---|
| 97 | "pp1-gpu", | 
|---|
| 98 | "psys", | 
|---|
| 99 | }; | 
|---|
| 100 |  | 
|---|
| 101 | static const char *const rapl_core_domain_name __initconst = "core"; | 
|---|
| 102 |  | 
|---|
| 103 | /* | 
|---|
| 104 | * event code: LSB 8 bits, passed in attr->config | 
|---|
| 105 | * any other bit is reserved | 
|---|
| 106 | */ | 
|---|
| 107 | #define RAPL_EVENT_MASK	0xFFULL | 
|---|
| 108 | #define RAPL_CNTR_WIDTH 32 | 
|---|
| 109 |  | 
|---|
| 110 | #define RAPL_EVENT_ATTR_STR(_name, v, str)					\ | 
|---|
| 111 | static struct perf_pmu_events_attr event_attr_##v = {				\ | 
|---|
| 112 | .attr		= __ATTR(_name, 0444, perf_event_sysfs_show, NULL),	\ | 
|---|
| 113 | .id		= 0,							\ | 
|---|
| 114 | .event_str	= str,							\ | 
|---|
| 115 | }; | 
|---|
| 116 |  | 
|---|
| 117 | /* | 
|---|
| 118 | * RAPL Package energy counter scope: | 
|---|
| 119 | * 1. AMD/HYGON platforms have a per-PKG package energy counter | 
|---|
| 120 | * 2. For Intel platforms | 
|---|
| 121 | *	2.1. CLX-AP is multi-die and its RAPL MSRs are die-scope | 
|---|
| 122 | *	2.2. Other Intel platforms are single die systems so the scope can be | 
|---|
| 123 | *	     considered as either pkg-scope or die-scope, and we are considering | 
|---|
| 124 | *	     them as die-scope. | 
|---|
| 125 | */ | 
|---|
| 126 | #define rapl_pkg_pmu_is_pkg_scope()				\ | 
|---|
| 127 | (boot_cpu_data.x86_vendor == X86_VENDOR_AMD ||	\ | 
|---|
| 128 | boot_cpu_data.x86_vendor == X86_VENDOR_HYGON) | 
|---|
| 129 |  | 
|---|
| 130 | struct rapl_pmu { | 
|---|
| 131 | raw_spinlock_t		lock; | 
|---|
| 132 | int			n_active; | 
|---|
| 133 | int			cpu; | 
|---|
| 134 | struct list_head	active_list; | 
|---|
| 135 | struct pmu		*pmu; | 
|---|
| 136 | ktime_t			timer_interval; | 
|---|
| 137 | struct hrtimer		hrtimer; | 
|---|
| 138 | }; | 
|---|
| 139 |  | 
|---|
| 140 | struct rapl_pmus { | 
|---|
| 141 | struct pmu		pmu; | 
|---|
| 142 | unsigned int		nr_rapl_pmu; | 
|---|
| 143 | unsigned int		cntr_mask; | 
|---|
| 144 | struct rapl_pmu		*rapl_pmu[] __counted_by(nr_rapl_pmu); | 
|---|
| 145 | }; | 
|---|
| 146 |  | 
|---|
| 147 | enum rapl_unit_quirk { | 
|---|
| 148 | RAPL_UNIT_QUIRK_NONE, | 
|---|
| 149 | RAPL_UNIT_QUIRK_INTEL_HSW, | 
|---|
| 150 | RAPL_UNIT_QUIRK_INTEL_SPR, | 
|---|
| 151 | }; | 
|---|
| 152 |  | 
|---|
| 153 | struct rapl_model { | 
|---|
| 154 | struct perf_msr *rapl_pkg_msrs; | 
|---|
| 155 | struct perf_msr *rapl_core_msrs; | 
|---|
| 156 | unsigned long	pkg_events; | 
|---|
| 157 | unsigned long	core_events; | 
|---|
| 158 | unsigned int	msr_power_unit; | 
|---|
| 159 | enum rapl_unit_quirk	unit_quirk; | 
|---|
| 160 | }; | 
|---|
| 161 |  | 
|---|
| 162 | /* 1/2^hw_unit Joule */ | 
|---|
| 163 | static int rapl_pkg_hw_unit[NR_RAPL_PKG_DOMAINS] __read_mostly; | 
|---|
| 164 | static int rapl_core_hw_unit __read_mostly; | 
|---|
| 165 | static struct rapl_pmus *rapl_pmus_pkg; | 
|---|
| 166 | static struct rapl_pmus *rapl_pmus_core; | 
|---|
| 167 | static u64 rapl_timer_ms; | 
|---|
| 168 | static struct rapl_model *rapl_model; | 
|---|
| 169 |  | 
|---|
| 170 | /* | 
|---|
| 171 | * Helper function to get the correct topology id according to the | 
|---|
| 172 | * RAPL PMU scope. | 
|---|
| 173 | */ | 
|---|
| 174 | static inline unsigned int get_rapl_pmu_idx(int cpu, int scope) | 
|---|
| 175 | { | 
|---|
| 176 | /* | 
|---|
| 177 | * Returns unsigned int, which converts the '-1' return value | 
|---|
| 178 | * (for non-existent mappings in topology map) to UINT_MAX, so | 
|---|
| 179 | * the error check in the caller is simplified. | 
|---|
| 180 | */ | 
|---|
| 181 | switch (scope) { | 
|---|
| 182 | case PERF_PMU_SCOPE_PKG: | 
|---|
| 183 | return topology_logical_package_id(cpu); | 
|---|
| 184 | case PERF_PMU_SCOPE_DIE: | 
|---|
| 185 | return topology_logical_die_id(cpu); | 
|---|
| 186 | case PERF_PMU_SCOPE_CORE: | 
|---|
| 187 | return topology_logical_core_id(cpu); | 
|---|
| 188 | default: | 
|---|
| 189 | return -EINVAL; | 
|---|
| 190 | } | 
|---|
| 191 | } | 
|---|
| 192 |  | 
|---|
| 193 | static inline u64 rapl_read_counter(struct perf_event *event) | 
|---|
| 194 | { | 
|---|
| 195 | u64 raw; | 
|---|
| 196 | rdmsrq(event->hw.event_base, raw); | 
|---|
| 197 | return raw; | 
|---|
| 198 | } | 
|---|
| 199 |  | 
|---|
| 200 | static inline u64 rapl_scale(u64 v, struct perf_event *event) | 
|---|
| 201 | { | 
|---|
| 202 | int hw_unit = rapl_pkg_hw_unit[event->hw.config - 1]; | 
|---|
| 203 |  | 
|---|
| 204 | if (event->pmu->scope == PERF_PMU_SCOPE_CORE) | 
|---|
| 205 | hw_unit = rapl_core_hw_unit; | 
|---|
| 206 |  | 
|---|
| 207 | /* | 
|---|
| 208 | * scale delta to smallest unit (1/2^32) | 
|---|
| 209 | * users must then scale back: count * 1/(1e9*2^32) to get Joules | 
|---|
| 210 | * or use ldexp(count, -32). | 
|---|
| 211 | * Watts = Joules/Time delta | 
|---|
| 212 | */ | 
|---|
| 213 | return v << (32 - hw_unit); | 
|---|
| 214 | } | 
|---|
| 215 |  | 
|---|
| 216 | static u64 rapl_event_update(struct perf_event *event) | 
|---|
| 217 | { | 
|---|
| 218 | struct hw_perf_event *hwc = &event->hw; | 
|---|
| 219 | u64 prev_raw_count, new_raw_count; | 
|---|
| 220 | s64 delta, sdelta; | 
|---|
| 221 | int shift = RAPL_CNTR_WIDTH; | 
|---|
| 222 |  | 
|---|
| 223 | prev_raw_count = local64_read(&hwc->prev_count); | 
|---|
| 224 | do { | 
|---|
| 225 | rdmsrq(event->hw.event_base, new_raw_count); | 
|---|
| 226 | } while (!local64_try_cmpxchg(l: &hwc->prev_count, | 
|---|
| 227 | old: &prev_raw_count, new: new_raw_count)); | 
|---|
| 228 |  | 
|---|
| 229 | /* | 
|---|
| 230 | * Now we have the new raw value and have updated the prev | 
|---|
| 231 | * timestamp already. We can now calculate the elapsed delta | 
|---|
| 232 | * (event-)time and add that to the generic event. | 
|---|
| 233 | * | 
|---|
| 234 | * Careful, not all hw sign-extends above the physical width | 
|---|
| 235 | * of the count. | 
|---|
| 236 | */ | 
|---|
| 237 | delta = (new_raw_count << shift) - (prev_raw_count << shift); | 
|---|
| 238 | delta >>= shift; | 
|---|
| 239 |  | 
|---|
| 240 | sdelta = rapl_scale(v: delta, event); | 
|---|
| 241 |  | 
|---|
| 242 | local64_add(sdelta, &event->count); | 
|---|
| 243 |  | 
|---|
| 244 | return new_raw_count; | 
|---|
| 245 | } | 
|---|
| 246 |  | 
|---|
| 247 | static void rapl_start_hrtimer(struct rapl_pmu *pmu) | 
|---|
| 248 | { | 
|---|
| 249 | hrtimer_start(timer: &pmu->hrtimer, tim: pmu->timer_interval, | 
|---|
| 250 | mode: HRTIMER_MODE_REL_PINNED); | 
|---|
| 251 | } | 
|---|
| 252 |  | 
|---|
| 253 | static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) | 
|---|
| 254 | { | 
|---|
| 255 | struct rapl_pmu *rapl_pmu = container_of(hrtimer, struct rapl_pmu, hrtimer); | 
|---|
| 256 | struct perf_event *event; | 
|---|
| 257 | unsigned long flags; | 
|---|
| 258 |  | 
|---|
| 259 | if (!rapl_pmu->n_active) | 
|---|
| 260 | return HRTIMER_NORESTART; | 
|---|
| 261 |  | 
|---|
| 262 | raw_spin_lock_irqsave(&rapl_pmu->lock, flags); | 
|---|
| 263 |  | 
|---|
| 264 | list_for_each_entry(event, &rapl_pmu->active_list, active_entry) | 
|---|
| 265 | rapl_event_update(event); | 
|---|
| 266 |  | 
|---|
| 267 | raw_spin_unlock_irqrestore(&rapl_pmu->lock, flags); | 
|---|
| 268 |  | 
|---|
| 269 | hrtimer_forward_now(timer: hrtimer, interval: rapl_pmu->timer_interval); | 
|---|
| 270 |  | 
|---|
| 271 | return HRTIMER_RESTART; | 
|---|
| 272 | } | 
|---|
| 273 |  | 
|---|
| 274 | static void rapl_hrtimer_init(struct rapl_pmu *rapl_pmu) | 
|---|
| 275 | { | 
|---|
| 276 | struct hrtimer *hr = &rapl_pmu->hrtimer; | 
|---|
| 277 |  | 
|---|
| 278 | hrtimer_setup(timer: hr, function: rapl_hrtimer_handle, CLOCK_MONOTONIC, mode: HRTIMER_MODE_REL); | 
|---|
| 279 | } | 
|---|
| 280 |  | 
|---|
| 281 | static void __rapl_pmu_event_start(struct rapl_pmu *rapl_pmu, | 
|---|
| 282 | struct perf_event *event) | 
|---|
| 283 | { | 
|---|
| 284 | if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) | 
|---|
| 285 | return; | 
|---|
| 286 |  | 
|---|
| 287 | event->hw.state = 0; | 
|---|
| 288 |  | 
|---|
| 289 | list_add_tail(new: &event->active_entry, head: &rapl_pmu->active_list); | 
|---|
| 290 |  | 
|---|
| 291 | local64_set(&event->hw.prev_count, rapl_read_counter(event)); | 
|---|
| 292 |  | 
|---|
| 293 | rapl_pmu->n_active++; | 
|---|
| 294 | if (rapl_pmu->n_active == 1) | 
|---|
| 295 | rapl_start_hrtimer(pmu: rapl_pmu); | 
|---|
| 296 | } | 
|---|
| 297 |  | 
|---|
| 298 | static void rapl_pmu_event_start(struct perf_event *event, int mode) | 
|---|
| 299 | { | 
|---|
| 300 | struct rapl_pmu *rapl_pmu = event->pmu_private; | 
|---|
| 301 | unsigned long flags; | 
|---|
| 302 |  | 
|---|
| 303 | raw_spin_lock_irqsave(&rapl_pmu->lock, flags); | 
|---|
| 304 | __rapl_pmu_event_start(rapl_pmu, event); | 
|---|
| 305 | raw_spin_unlock_irqrestore(&rapl_pmu->lock, flags); | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | static void rapl_pmu_event_stop(struct perf_event *event, int mode) | 
|---|
| 309 | { | 
|---|
| 310 | struct rapl_pmu *rapl_pmu = event->pmu_private; | 
|---|
| 311 | struct hw_perf_event *hwc = &event->hw; | 
|---|
| 312 | unsigned long flags; | 
|---|
| 313 |  | 
|---|
| 314 | raw_spin_lock_irqsave(&rapl_pmu->lock, flags); | 
|---|
| 315 |  | 
|---|
| 316 | /* mark event as deactivated and stopped */ | 
|---|
| 317 | if (!(hwc->state & PERF_HES_STOPPED)) { | 
|---|
| 318 | WARN_ON_ONCE(rapl_pmu->n_active <= 0); | 
|---|
| 319 | rapl_pmu->n_active--; | 
|---|
| 320 | if (rapl_pmu->n_active == 0) | 
|---|
| 321 | hrtimer_cancel(timer: &rapl_pmu->hrtimer); | 
|---|
| 322 |  | 
|---|
| 323 | list_del(entry: &event->active_entry); | 
|---|
| 324 |  | 
|---|
| 325 | WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); | 
|---|
| 326 | hwc->state |= PERF_HES_STOPPED; | 
|---|
| 327 | } | 
|---|
| 328 |  | 
|---|
| 329 | /* check if update of sw counter is necessary */ | 
|---|
| 330 | if ((mode & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { | 
|---|
| 331 | /* | 
|---|
| 332 | * Drain the remaining delta count out of a event | 
|---|
| 333 | * that we are disabling: | 
|---|
| 334 | */ | 
|---|
| 335 | rapl_event_update(event); | 
|---|
| 336 | hwc->state |= PERF_HES_UPTODATE; | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | raw_spin_unlock_irqrestore(&rapl_pmu->lock, flags); | 
|---|
| 340 | } | 
|---|
| 341 |  | 
|---|
| 342 | static int rapl_pmu_event_add(struct perf_event *event, int mode) | 
|---|
| 343 | { | 
|---|
| 344 | struct rapl_pmu *rapl_pmu = event->pmu_private; | 
|---|
| 345 | struct hw_perf_event *hwc = &event->hw; | 
|---|
| 346 | unsigned long flags; | 
|---|
| 347 |  | 
|---|
| 348 | raw_spin_lock_irqsave(&rapl_pmu->lock, flags); | 
|---|
| 349 |  | 
|---|
| 350 | hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; | 
|---|
| 351 |  | 
|---|
| 352 | if (mode & PERF_EF_START) | 
|---|
| 353 | __rapl_pmu_event_start(rapl_pmu, event); | 
|---|
| 354 |  | 
|---|
| 355 | raw_spin_unlock_irqrestore(&rapl_pmu->lock, flags); | 
|---|
| 356 |  | 
|---|
| 357 | return 0; | 
|---|
| 358 | } | 
|---|
| 359 |  | 
|---|
| 360 | static void rapl_pmu_event_del(struct perf_event *event, int flags) | 
|---|
| 361 | { | 
|---|
| 362 | rapl_pmu_event_stop(event, PERF_EF_UPDATE); | 
|---|
| 363 | } | 
|---|
| 364 |  | 
|---|
| 365 | static int rapl_pmu_event_init(struct perf_event *event) | 
|---|
| 366 | { | 
|---|
| 367 | u64 cfg = event->attr.config & RAPL_EVENT_MASK; | 
|---|
| 368 | int bit, rapl_pmus_scope, ret = 0; | 
|---|
| 369 | struct rapl_pmu *rapl_pmu; | 
|---|
| 370 | unsigned int rapl_pmu_idx; | 
|---|
| 371 | struct rapl_pmus *rapl_pmus; | 
|---|
| 372 |  | 
|---|
| 373 | /* only look at RAPL events */ | 
|---|
| 374 | if (event->attr.type != event->pmu->type) | 
|---|
| 375 | return -ENOENT; | 
|---|
| 376 |  | 
|---|
| 377 | /* unsupported modes and filters */ | 
|---|
| 378 | if (event->attr.sample_period) /* no sampling */ | 
|---|
| 379 | return -EINVAL; | 
|---|
| 380 |  | 
|---|
| 381 | /* check only supported bits are set */ | 
|---|
| 382 | if (event->attr.config & ~RAPL_EVENT_MASK) | 
|---|
| 383 | return -EINVAL; | 
|---|
| 384 |  | 
|---|
| 385 | if (event->cpu < 0) | 
|---|
| 386 | return -EINVAL; | 
|---|
| 387 |  | 
|---|
| 388 | rapl_pmus = container_of(event->pmu, struct rapl_pmus, pmu); | 
|---|
| 389 | if (!rapl_pmus) | 
|---|
| 390 | return -EINVAL; | 
|---|
| 391 | rapl_pmus_scope = rapl_pmus->pmu.scope; | 
|---|
| 392 |  | 
|---|
| 393 | if (rapl_pmus_scope == PERF_PMU_SCOPE_PKG || rapl_pmus_scope == PERF_PMU_SCOPE_DIE) { | 
|---|
| 394 | cfg = array_index_nospec((long)cfg, NR_RAPL_PKG_DOMAINS + 1); | 
|---|
| 395 | if (!cfg || cfg >= NR_RAPL_PKG_DOMAINS + 1) | 
|---|
| 396 | return -EINVAL; | 
|---|
| 397 |  | 
|---|
| 398 | bit = cfg - 1; | 
|---|
| 399 | event->hw.event_base = rapl_model->rapl_pkg_msrs[bit].msr; | 
|---|
| 400 | } else if (rapl_pmus_scope == PERF_PMU_SCOPE_CORE) { | 
|---|
| 401 | cfg = array_index_nospec((long)cfg, NR_RAPL_CORE_DOMAINS + 1); | 
|---|
| 402 | if (!cfg || cfg >= NR_RAPL_PKG_DOMAINS + 1) | 
|---|
| 403 | return -EINVAL; | 
|---|
| 404 |  | 
|---|
| 405 | bit = cfg - 1; | 
|---|
| 406 | event->hw.event_base = rapl_model->rapl_core_msrs[bit].msr; | 
|---|
| 407 | } else | 
|---|
| 408 | return -EINVAL; | 
|---|
| 409 |  | 
|---|
| 410 | /* check event supported */ | 
|---|
| 411 | if (!(rapl_pmus->cntr_mask & (1 << bit))) | 
|---|
| 412 | return -EINVAL; | 
|---|
| 413 |  | 
|---|
| 414 | rapl_pmu_idx = get_rapl_pmu_idx(cpu: event->cpu, scope: rapl_pmus_scope); | 
|---|
| 415 | if (rapl_pmu_idx >= rapl_pmus->nr_rapl_pmu) | 
|---|
| 416 | return -EINVAL; | 
|---|
| 417 | /* must be done before validate_group */ | 
|---|
| 418 | rapl_pmu = rapl_pmus->rapl_pmu[rapl_pmu_idx]; | 
|---|
| 419 | if (!rapl_pmu) | 
|---|
| 420 | return -EINVAL; | 
|---|
| 421 |  | 
|---|
| 422 | event->pmu_private = rapl_pmu; | 
|---|
| 423 | event->hw.config = cfg; | 
|---|
| 424 | event->hw.idx = bit; | 
|---|
| 425 |  | 
|---|
| 426 | return ret; | 
|---|
| 427 | } | 
|---|
| 428 |  | 
|---|
| 429 | static void rapl_pmu_event_read(struct perf_event *event) | 
|---|
| 430 | { | 
|---|
| 431 | rapl_event_update(event); | 
|---|
| 432 | } | 
|---|
| 433 |  | 
|---|
| 434 | RAPL_EVENT_ATTR_STR(energy-cores, rapl_cores, "event=0x01"); | 
|---|
| 435 | RAPL_EVENT_ATTR_STR(energy-pkg  ,   rapl_pkg, "event=0x02"); | 
|---|
| 436 | RAPL_EVENT_ATTR_STR(energy-ram  ,   rapl_ram, "event=0x03"); | 
|---|
| 437 | RAPL_EVENT_ATTR_STR(energy-gpu  ,   rapl_gpu, "event=0x04"); | 
|---|
| 438 | RAPL_EVENT_ATTR_STR(energy-psys,   rapl_psys, "event=0x05"); | 
|---|
| 439 | RAPL_EVENT_ATTR_STR(energy-core,   rapl_core, "event=0x01"); | 
|---|
| 440 |  | 
|---|
| 441 | RAPL_EVENT_ATTR_STR(energy-cores.unit, rapl_cores_unit, "Joules"); | 
|---|
| 442 | RAPL_EVENT_ATTR_STR(energy-pkg.unit  ,   rapl_pkg_unit, "Joules"); | 
|---|
| 443 | RAPL_EVENT_ATTR_STR(energy-ram.unit  ,   rapl_ram_unit, "Joules"); | 
|---|
| 444 | RAPL_EVENT_ATTR_STR(energy-gpu.unit  ,   rapl_gpu_unit, "Joules"); | 
|---|
| 445 | RAPL_EVENT_ATTR_STR(energy-psys.unit,   rapl_psys_unit, "Joules"); | 
|---|
| 446 | RAPL_EVENT_ATTR_STR(energy-core.unit,   rapl_core_unit, "Joules"); | 
|---|
| 447 |  | 
|---|
| 448 | /* | 
|---|
| 449 | * we compute in 0.23 nJ increments regardless of MSR | 
|---|
| 450 | */ | 
|---|
| 451 | RAPL_EVENT_ATTR_STR(energy-cores.scale, rapl_cores_scale, "2.3283064365386962890625e-10"); | 
|---|
| 452 | RAPL_EVENT_ATTR_STR(energy-pkg.scale,     rapl_pkg_scale, "2.3283064365386962890625e-10"); | 
|---|
| 453 | RAPL_EVENT_ATTR_STR(energy-ram.scale,     rapl_ram_scale, "2.3283064365386962890625e-10"); | 
|---|
| 454 | RAPL_EVENT_ATTR_STR(energy-gpu.scale,     rapl_gpu_scale, "2.3283064365386962890625e-10"); | 
|---|
| 455 | RAPL_EVENT_ATTR_STR(energy-psys.scale,   rapl_psys_scale, "2.3283064365386962890625e-10"); | 
|---|
| 456 | RAPL_EVENT_ATTR_STR(energy-core.scale,   rapl_core_scale, "2.3283064365386962890625e-10"); | 
|---|
| 457 |  | 
|---|
| 458 | /* | 
|---|
| 459 | * There are no default events, but we need to create | 
|---|
| 460 | * "events" group (with empty attrs) before updating | 
|---|
| 461 | * it with detected events. | 
|---|
| 462 | */ | 
|---|
| 463 | static struct attribute *attrs_empty[] = { | 
|---|
| 464 | NULL, | 
|---|
| 465 | }; | 
|---|
| 466 |  | 
|---|
| 467 | static struct attribute_group rapl_pmu_events_group = { | 
|---|
| 468 | .name = "events", | 
|---|
| 469 | .attrs = attrs_empty, | 
|---|
| 470 | }; | 
|---|
| 471 |  | 
|---|
| 472 | PMU_FORMAT_ATTR(event, "config:0-7"); | 
|---|
| 473 | static struct attribute *rapl_formats_attr[] = { | 
|---|
| 474 | &format_attr_event.attr, | 
|---|
| 475 | NULL, | 
|---|
| 476 | }; | 
|---|
| 477 |  | 
|---|
| 478 | static struct attribute_group rapl_pmu_format_group = { | 
|---|
| 479 | .name = "format", | 
|---|
| 480 | .attrs = rapl_formats_attr, | 
|---|
| 481 | }; | 
|---|
| 482 |  | 
|---|
| 483 | static const struct attribute_group *rapl_attr_groups[] = { | 
|---|
| 484 | &rapl_pmu_format_group, | 
|---|
| 485 | &rapl_pmu_events_group, | 
|---|
| 486 | NULL, | 
|---|
| 487 | }; | 
|---|
| 488 |  | 
|---|
| 489 | static const struct attribute_group *rapl_core_attr_groups[] = { | 
|---|
| 490 | &rapl_pmu_format_group, | 
|---|
| 491 | &rapl_pmu_events_group, | 
|---|
| 492 | NULL, | 
|---|
| 493 | }; | 
|---|
| 494 |  | 
|---|
| 495 | static struct attribute *rapl_events_cores[] = { | 
|---|
| 496 | EVENT_PTR(rapl_cores), | 
|---|
| 497 | EVENT_PTR(rapl_cores_unit), | 
|---|
| 498 | EVENT_PTR(rapl_cores_scale), | 
|---|
| 499 | NULL, | 
|---|
| 500 | }; | 
|---|
| 501 |  | 
|---|
| 502 | static struct attribute_group rapl_events_cores_group = { | 
|---|
| 503 | .name  = "events", | 
|---|
| 504 | .attrs = rapl_events_cores, | 
|---|
| 505 | }; | 
|---|
| 506 |  | 
|---|
| 507 | static struct attribute *rapl_events_pkg[] = { | 
|---|
| 508 | EVENT_PTR(rapl_pkg), | 
|---|
| 509 | EVENT_PTR(rapl_pkg_unit), | 
|---|
| 510 | EVENT_PTR(rapl_pkg_scale), | 
|---|
| 511 | NULL, | 
|---|
| 512 | }; | 
|---|
| 513 |  | 
|---|
| 514 | static struct attribute_group rapl_events_pkg_group = { | 
|---|
| 515 | .name  = "events", | 
|---|
| 516 | .attrs = rapl_events_pkg, | 
|---|
| 517 | }; | 
|---|
| 518 |  | 
|---|
| 519 | static struct attribute *rapl_events_ram[] = { | 
|---|
| 520 | EVENT_PTR(rapl_ram), | 
|---|
| 521 | EVENT_PTR(rapl_ram_unit), | 
|---|
| 522 | EVENT_PTR(rapl_ram_scale), | 
|---|
| 523 | NULL, | 
|---|
| 524 | }; | 
|---|
| 525 |  | 
|---|
| 526 | static struct attribute_group rapl_events_ram_group = { | 
|---|
| 527 | .name  = "events", | 
|---|
| 528 | .attrs = rapl_events_ram, | 
|---|
| 529 | }; | 
|---|
| 530 |  | 
|---|
| 531 | static struct attribute *rapl_events_gpu[] = { | 
|---|
| 532 | EVENT_PTR(rapl_gpu), | 
|---|
| 533 | EVENT_PTR(rapl_gpu_unit), | 
|---|
| 534 | EVENT_PTR(rapl_gpu_scale), | 
|---|
| 535 | NULL, | 
|---|
| 536 | }; | 
|---|
| 537 |  | 
|---|
| 538 | static struct attribute_group rapl_events_gpu_group = { | 
|---|
| 539 | .name  = "events", | 
|---|
| 540 | .attrs = rapl_events_gpu, | 
|---|
| 541 | }; | 
|---|
| 542 |  | 
|---|
| 543 | static struct attribute *rapl_events_psys[] = { | 
|---|
| 544 | EVENT_PTR(rapl_psys), | 
|---|
| 545 | EVENT_PTR(rapl_psys_unit), | 
|---|
| 546 | EVENT_PTR(rapl_psys_scale), | 
|---|
| 547 | NULL, | 
|---|
| 548 | }; | 
|---|
| 549 |  | 
|---|
| 550 | static struct attribute_group rapl_events_psys_group = { | 
|---|
| 551 | .name  = "events", | 
|---|
| 552 | .attrs = rapl_events_psys, | 
|---|
| 553 | }; | 
|---|
| 554 |  | 
|---|
| 555 | static struct attribute *rapl_events_core[] = { | 
|---|
| 556 | EVENT_PTR(rapl_core), | 
|---|
| 557 | EVENT_PTR(rapl_core_unit), | 
|---|
| 558 | EVENT_PTR(rapl_core_scale), | 
|---|
| 559 | NULL, | 
|---|
| 560 | }; | 
|---|
| 561 |  | 
|---|
| 562 | static struct attribute_group rapl_events_core_group = { | 
|---|
| 563 | .name  = "events", | 
|---|
| 564 | .attrs = rapl_events_core, | 
|---|
| 565 | }; | 
|---|
| 566 |  | 
|---|
| 567 | static bool test_msr(int idx, void *data) | 
|---|
| 568 | { | 
|---|
| 569 | return test_bit(idx, (unsigned long *) data); | 
|---|
| 570 | } | 
|---|
| 571 |  | 
|---|
| 572 | /* Only lower 32bits of the MSR represents the energy counter */ | 
|---|
| 573 | #define RAPL_MSR_MASK 0xFFFFFFFF | 
|---|
| 574 |  | 
|---|
| 575 | static struct perf_msr intel_rapl_msrs[] = { | 
|---|
| 576 | [PERF_RAPL_PP0]  = { MSR_PP0_ENERGY_STATUS,      &rapl_events_cores_group, test_msr, false, RAPL_MSR_MASK }, | 
|---|
| 577 | [PERF_RAPL_PKG]  = { MSR_PKG_ENERGY_STATUS,      .grp: &rapl_events_pkg_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 578 | [PERF_RAPL_RAM]  = { MSR_DRAM_ENERGY_STATUS,     .grp: &rapl_events_ram_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 579 | [PERF_RAPL_PP1]  = { MSR_PP1_ENERGY_STATUS,      .grp: &rapl_events_gpu_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 580 | [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, .grp: &rapl_events_psys_group,  .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 581 | }; | 
|---|
| 582 |  | 
|---|
| 583 | static struct perf_msr intel_rapl_spr_msrs[] = { | 
|---|
| 584 | [PERF_RAPL_PP0]  = { MSR_PP0_ENERGY_STATUS,      .grp: &rapl_events_cores_group, .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 585 | [PERF_RAPL_PKG]  = { MSR_PKG_ENERGY_STATUS,      .grp: &rapl_events_pkg_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 586 | [PERF_RAPL_RAM]  = { MSR_DRAM_ENERGY_STATUS,     .grp: &rapl_events_ram_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 587 | [PERF_RAPL_PP1]  = { MSR_PP1_ENERGY_STATUS,      .grp: &rapl_events_gpu_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 588 | [PERF_RAPL_PSYS] = { MSR_PLATFORM_ENERGY_STATUS, .grp: &rapl_events_psys_group,  .test: test_msr, .no_check: true, RAPL_MSR_MASK }, | 
|---|
| 589 | }; | 
|---|
| 590 |  | 
|---|
| 591 | /* | 
|---|
| 592 | * Force to PERF_RAPL_PKG_EVENTS_MAX size due to: | 
|---|
| 593 | * - perf_msr_probe(PERF_RAPL_PKG_EVENTS_MAX) | 
|---|
| 594 | * - want to use same event codes across both architectures | 
|---|
| 595 | */ | 
|---|
| 596 | static struct perf_msr amd_rapl_pkg_msrs[] = { | 
|---|
| 597 | [PERF_RAPL_PP0]  = { .msr: 0, .grp: &rapl_events_cores_group, NULL, .no_check: false, .mask: 0 }, | 
|---|
| 598 | [PERF_RAPL_PKG]  = { MSR_AMD_PKG_ENERGY_STATUS,  .grp: &rapl_events_pkg_group,   .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 599 | [PERF_RAPL_RAM]  = { .msr: 0, .grp: &rapl_events_ram_group,   NULL, .no_check: false, .mask: 0 }, | 
|---|
| 600 | [PERF_RAPL_PP1]  = { .msr: 0, .grp: &rapl_events_gpu_group,   NULL, .no_check: false, .mask: 0 }, | 
|---|
| 601 | [PERF_RAPL_PSYS] = { .msr: 0, .grp: &rapl_events_psys_group,  NULL, .no_check: false, .mask: 0 }, | 
|---|
| 602 | }; | 
|---|
| 603 |  | 
|---|
| 604 | static struct perf_msr amd_rapl_core_msrs[] = { | 
|---|
| 605 | [PERF_RAPL_CORE] = { MSR_AMD_CORE_ENERGY_STATUS, .grp: &rapl_events_core_group, | 
|---|
| 606 | .test: test_msr, .no_check: false, RAPL_MSR_MASK }, | 
|---|
| 607 | }; | 
|---|
| 608 |  | 
|---|
| 609 | static int rapl_check_hw_unit(void) | 
|---|
| 610 | { | 
|---|
| 611 | u64 msr_rapl_power_unit_bits; | 
|---|
| 612 | int i; | 
|---|
| 613 |  | 
|---|
| 614 | /* protect rdmsrq() to handle virtualization */ | 
|---|
| 615 | if (rdmsrq_safe(msr: rapl_model->msr_power_unit, p: &msr_rapl_power_unit_bits)) | 
|---|
| 616 | return -1; | 
|---|
| 617 | for (i = 0; i < NR_RAPL_PKG_DOMAINS; i++) | 
|---|
| 618 | rapl_pkg_hw_unit[i] = (msr_rapl_power_unit_bits >> 8) & 0x1FULL; | 
|---|
| 619 |  | 
|---|
| 620 | rapl_core_hw_unit = (msr_rapl_power_unit_bits >> 8) & 0x1FULL; | 
|---|
| 621 |  | 
|---|
| 622 | switch (rapl_model->unit_quirk) { | 
|---|
| 623 | /* | 
|---|
| 624 | * DRAM domain on HSW server and KNL has fixed energy unit which can be | 
|---|
| 625 | * different than the unit from power unit MSR. See | 
|---|
| 626 | * "Intel Xeon Processor E5-1600 and E5-2600 v3 Product Families, V2 | 
|---|
| 627 | * of 2. Datasheet, September 2014, Reference Number: 330784-001 " | 
|---|
| 628 | */ | 
|---|
| 629 | case RAPL_UNIT_QUIRK_INTEL_HSW: | 
|---|
| 630 | rapl_pkg_hw_unit[PERF_RAPL_RAM] = 16; | 
|---|
| 631 | break; | 
|---|
| 632 | /* SPR uses a fixed energy unit for Psys domain. */ | 
|---|
| 633 | case RAPL_UNIT_QUIRK_INTEL_SPR: | 
|---|
| 634 | rapl_pkg_hw_unit[PERF_RAPL_PSYS] = 0; | 
|---|
| 635 | break; | 
|---|
| 636 | default: | 
|---|
| 637 | break; | 
|---|
| 638 | } | 
|---|
| 639 |  | 
|---|
| 640 | /* | 
|---|
| 641 | * Calculate the timer rate: | 
|---|
| 642 | * Use reference of 200W for scaling the timeout to avoid counter | 
|---|
| 643 | * overflows. 200W = 200 Joules/sec | 
|---|
| 644 | * Divide interval by 2 to avoid lockstep (2 * 100) | 
|---|
| 645 | * if hw unit is 32, then we use 2 ms 1/200/2 | 
|---|
| 646 | */ | 
|---|
| 647 | rapl_timer_ms = 2; | 
|---|
| 648 | if (rapl_pkg_hw_unit[0] < 32) { | 
|---|
| 649 | rapl_timer_ms = (1000 / (2 * 100)); | 
|---|
| 650 | rapl_timer_ms *= (1ULL << (32 - rapl_pkg_hw_unit[0] - 1)); | 
|---|
| 651 | } | 
|---|
| 652 | return 0; | 
|---|
| 653 | } | 
|---|
| 654 |  | 
|---|
| 655 | static void __init rapl_advertise(void) | 
|---|
| 656 | { | 
|---|
| 657 | int i; | 
|---|
| 658 | int num_counters = hweight32(rapl_pmus_pkg->cntr_mask); | 
|---|
| 659 |  | 
|---|
| 660 | if (rapl_pmus_core) | 
|---|
| 661 | num_counters += hweight32(rapl_pmus_core->cntr_mask); | 
|---|
| 662 |  | 
|---|
| 663 | pr_info( "API unit is 2^-32 Joules, %d fixed counters, %llu ms ovfl timer\n", | 
|---|
| 664 | num_counters, rapl_timer_ms); | 
|---|
| 665 |  | 
|---|
| 666 | for (i = 0; i < NR_RAPL_PKG_DOMAINS; i++) { | 
|---|
| 667 | if (rapl_pmus_pkg->cntr_mask & (1 << i)) { | 
|---|
| 668 | pr_info( "hw unit of domain %s 2^-%d Joules\n", | 
|---|
| 669 | rapl_pkg_domain_names[i], rapl_pkg_hw_unit[i]); | 
|---|
| 670 | } | 
|---|
| 671 | } | 
|---|
| 672 |  | 
|---|
| 673 | if (rapl_pmus_core && (rapl_pmus_core->cntr_mask & (1 << PERF_RAPL_CORE))) | 
|---|
| 674 | pr_info( "hw unit of domain %s 2^-%d Joules\n", | 
|---|
| 675 | rapl_core_domain_name, rapl_core_hw_unit); | 
|---|
| 676 | } | 
|---|
| 677 |  | 
|---|
| 678 | static void cleanup_rapl_pmus(struct rapl_pmus *rapl_pmus) | 
|---|
| 679 | { | 
|---|
| 680 | int i; | 
|---|
| 681 |  | 
|---|
| 682 | for (i = 0; i < rapl_pmus->nr_rapl_pmu; i++) | 
|---|
| 683 | kfree(objp: rapl_pmus->rapl_pmu[i]); | 
|---|
| 684 | kfree(objp: rapl_pmus); | 
|---|
| 685 | } | 
|---|
| 686 |  | 
|---|
| 687 | static const struct attribute_group *rapl_attr_update[] = { | 
|---|
| 688 | &rapl_events_cores_group, | 
|---|
| 689 | &rapl_events_pkg_group, | 
|---|
| 690 | &rapl_events_ram_group, | 
|---|
| 691 | &rapl_events_gpu_group, | 
|---|
| 692 | &rapl_events_psys_group, | 
|---|
| 693 | NULL, | 
|---|
| 694 | }; | 
|---|
| 695 |  | 
|---|
| 696 | static const struct attribute_group *rapl_core_attr_update[] = { | 
|---|
| 697 | &rapl_events_core_group, | 
|---|
| 698 | NULL, | 
|---|
| 699 | }; | 
|---|
| 700 |  | 
|---|
| 701 | static int __init init_rapl_pmu(struct rapl_pmus *rapl_pmus) | 
|---|
| 702 | { | 
|---|
| 703 | struct rapl_pmu *rapl_pmu; | 
|---|
| 704 | int idx; | 
|---|
| 705 |  | 
|---|
| 706 | for (idx = 0; idx < rapl_pmus->nr_rapl_pmu; idx++) { | 
|---|
| 707 | rapl_pmu = kzalloc(sizeof(*rapl_pmu), GFP_KERNEL); | 
|---|
| 708 | if (!rapl_pmu) | 
|---|
| 709 | goto free; | 
|---|
| 710 |  | 
|---|
| 711 | raw_spin_lock_init(&rapl_pmu->lock); | 
|---|
| 712 | INIT_LIST_HEAD(list: &rapl_pmu->active_list); | 
|---|
| 713 | rapl_pmu->pmu = &rapl_pmus->pmu; | 
|---|
| 714 | rapl_pmu->timer_interval = ms_to_ktime(ms: rapl_timer_ms); | 
|---|
| 715 | rapl_hrtimer_init(rapl_pmu); | 
|---|
| 716 |  | 
|---|
| 717 | rapl_pmus->rapl_pmu[idx] = rapl_pmu; | 
|---|
| 718 | } | 
|---|
| 719 |  | 
|---|
| 720 | return 0; | 
|---|
| 721 | free: | 
|---|
| 722 | for (; idx > 0; idx--) | 
|---|
| 723 | kfree(objp: rapl_pmus->rapl_pmu[idx - 1]); | 
|---|
| 724 | return -ENOMEM; | 
|---|
| 725 | } | 
|---|
| 726 |  | 
|---|
| 727 | static int __init init_rapl_pmus(struct rapl_pmus **rapl_pmus_ptr, int rapl_pmu_scope, | 
|---|
| 728 | const struct attribute_group **rapl_attr_groups, | 
|---|
| 729 | const struct attribute_group **rapl_attr_update) | 
|---|
| 730 | { | 
|---|
| 731 | int nr_rapl_pmu = topology_max_packages(); | 
|---|
| 732 | struct rapl_pmus *rapl_pmus; | 
|---|
| 733 | int ret; | 
|---|
| 734 |  | 
|---|
| 735 | /* | 
|---|
| 736 | * rapl_pmu_scope must be either PKG, DIE or CORE | 
|---|
| 737 | */ | 
|---|
| 738 | if (rapl_pmu_scope == PERF_PMU_SCOPE_DIE) | 
|---|
| 739 | nr_rapl_pmu	*= topology_max_dies_per_package(); | 
|---|
| 740 | else if (rapl_pmu_scope == PERF_PMU_SCOPE_CORE) | 
|---|
| 741 | nr_rapl_pmu	*= topology_num_cores_per_package(); | 
|---|
| 742 | else if (rapl_pmu_scope != PERF_PMU_SCOPE_PKG) | 
|---|
| 743 | return -EINVAL; | 
|---|
| 744 |  | 
|---|
| 745 | rapl_pmus = kzalloc(struct_size(rapl_pmus, rapl_pmu, nr_rapl_pmu), GFP_KERNEL); | 
|---|
| 746 | if (!rapl_pmus) | 
|---|
| 747 | return -ENOMEM; | 
|---|
| 748 |  | 
|---|
| 749 | *rapl_pmus_ptr = rapl_pmus; | 
|---|
| 750 |  | 
|---|
| 751 | rapl_pmus->nr_rapl_pmu		= nr_rapl_pmu; | 
|---|
| 752 | rapl_pmus->pmu.attr_groups	= rapl_attr_groups; | 
|---|
| 753 | rapl_pmus->pmu.attr_update	= rapl_attr_update; | 
|---|
| 754 | rapl_pmus->pmu.task_ctx_nr	= perf_invalid_context; | 
|---|
| 755 | rapl_pmus->pmu.event_init	= rapl_pmu_event_init; | 
|---|
| 756 | rapl_pmus->pmu.add		= rapl_pmu_event_add; | 
|---|
| 757 | rapl_pmus->pmu.del		= rapl_pmu_event_del; | 
|---|
| 758 | rapl_pmus->pmu.start		= rapl_pmu_event_start; | 
|---|
| 759 | rapl_pmus->pmu.stop		= rapl_pmu_event_stop; | 
|---|
| 760 | rapl_pmus->pmu.read		= rapl_pmu_event_read; | 
|---|
| 761 | rapl_pmus->pmu.scope		= rapl_pmu_scope; | 
|---|
| 762 | rapl_pmus->pmu.module		= THIS_MODULE; | 
|---|
| 763 | rapl_pmus->pmu.capabilities	= PERF_PMU_CAP_NO_EXCLUDE; | 
|---|
| 764 |  | 
|---|
| 765 | ret = init_rapl_pmu(rapl_pmus); | 
|---|
| 766 | if (ret) | 
|---|
| 767 | kfree(objp: rapl_pmus); | 
|---|
| 768 |  | 
|---|
| 769 | return ret; | 
|---|
| 770 | } | 
|---|
| 771 |  | 
|---|
| 772 | static struct rapl_model model_snb = { | 
|---|
| 773 | .pkg_events	= BIT(PERF_RAPL_PP0) | | 
|---|
| 774 | BIT(PERF_RAPL_PKG) | | 
|---|
| 775 | BIT(PERF_RAPL_PP1), | 
|---|
| 776 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 777 | .rapl_pkg_msrs	= intel_rapl_msrs, | 
|---|
| 778 | }; | 
|---|
| 779 |  | 
|---|
| 780 | static struct rapl_model model_snbep = { | 
|---|
| 781 | .pkg_events	= BIT(PERF_RAPL_PP0) | | 
|---|
| 782 | BIT(PERF_RAPL_PKG) | | 
|---|
| 783 | BIT(PERF_RAPL_RAM), | 
|---|
| 784 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 785 | .rapl_pkg_msrs	= intel_rapl_msrs, | 
|---|
| 786 | }; | 
|---|
| 787 |  | 
|---|
| 788 | static struct rapl_model model_hsw = { | 
|---|
| 789 | .pkg_events	= BIT(PERF_RAPL_PP0) | | 
|---|
| 790 | BIT(PERF_RAPL_PKG) | | 
|---|
| 791 | BIT(PERF_RAPL_RAM) | | 
|---|
| 792 | BIT(PERF_RAPL_PP1), | 
|---|
| 793 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 794 | .rapl_pkg_msrs	= intel_rapl_msrs, | 
|---|
| 795 | }; | 
|---|
| 796 |  | 
|---|
| 797 | static struct rapl_model model_hsx = { | 
|---|
| 798 | .pkg_events	= BIT(PERF_RAPL_PP0) | | 
|---|
| 799 | BIT(PERF_RAPL_PKG) | | 
|---|
| 800 | BIT(PERF_RAPL_RAM), | 
|---|
| 801 | .unit_quirk	= RAPL_UNIT_QUIRK_INTEL_HSW, | 
|---|
| 802 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 803 | .rapl_pkg_msrs	= intel_rapl_msrs, | 
|---|
| 804 | }; | 
|---|
| 805 |  | 
|---|
| 806 | static struct rapl_model model_knl = { | 
|---|
| 807 | .pkg_events	= BIT(PERF_RAPL_PKG) | | 
|---|
| 808 | BIT(PERF_RAPL_RAM), | 
|---|
| 809 | .unit_quirk	= RAPL_UNIT_QUIRK_INTEL_HSW, | 
|---|
| 810 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 811 | .rapl_pkg_msrs	= intel_rapl_msrs, | 
|---|
| 812 | }; | 
|---|
| 813 |  | 
|---|
| 814 | static struct rapl_model model_skl = { | 
|---|
| 815 | .pkg_events	= BIT(PERF_RAPL_PP0) | | 
|---|
| 816 | BIT(PERF_RAPL_PKG) | | 
|---|
| 817 | BIT(PERF_RAPL_RAM) | | 
|---|
| 818 | BIT(PERF_RAPL_PP1) | | 
|---|
| 819 | BIT(PERF_RAPL_PSYS), | 
|---|
| 820 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 821 | .rapl_pkg_msrs      = intel_rapl_msrs, | 
|---|
| 822 | }; | 
|---|
| 823 |  | 
|---|
| 824 | static struct rapl_model model_spr = { | 
|---|
| 825 | .pkg_events	= BIT(PERF_RAPL_PP0) | | 
|---|
| 826 | BIT(PERF_RAPL_PKG) | | 
|---|
| 827 | BIT(PERF_RAPL_RAM) | | 
|---|
| 828 | BIT(PERF_RAPL_PSYS), | 
|---|
| 829 | .unit_quirk	= RAPL_UNIT_QUIRK_INTEL_SPR, | 
|---|
| 830 | .msr_power_unit = MSR_RAPL_POWER_UNIT, | 
|---|
| 831 | .rapl_pkg_msrs	= intel_rapl_spr_msrs, | 
|---|
| 832 | }; | 
|---|
| 833 |  | 
|---|
| 834 | static struct rapl_model model_amd_hygon = { | 
|---|
| 835 | .pkg_events	= BIT(PERF_RAPL_PKG), | 
|---|
| 836 | .core_events	= BIT(PERF_RAPL_CORE), | 
|---|
| 837 | .msr_power_unit = MSR_AMD_RAPL_POWER_UNIT, | 
|---|
| 838 | .rapl_pkg_msrs	= amd_rapl_pkg_msrs, | 
|---|
| 839 | .rapl_core_msrs	= amd_rapl_core_msrs, | 
|---|
| 840 | }; | 
|---|
| 841 |  | 
|---|
| 842 | static const struct x86_cpu_id rapl_model_match[] __initconst = { | 
|---|
| 843 | X86_MATCH_FEATURE(X86_FEATURE_RAPL,	&model_amd_hygon), | 
|---|
| 844 | X86_MATCH_VFM(INTEL_SANDYBRIDGE,	&model_snb), | 
|---|
| 845 | X86_MATCH_VFM(INTEL_SANDYBRIDGE_X,	&model_snbep), | 
|---|
| 846 | X86_MATCH_VFM(INTEL_IVYBRIDGE,		&model_snb), | 
|---|
| 847 | X86_MATCH_VFM(INTEL_IVYBRIDGE_X,	&model_snbep), | 
|---|
| 848 | X86_MATCH_VFM(INTEL_HASWELL,		&model_hsw), | 
|---|
| 849 | X86_MATCH_VFM(INTEL_HASWELL_X,		&model_hsx), | 
|---|
| 850 | X86_MATCH_VFM(INTEL_HASWELL_L,		&model_hsw), | 
|---|
| 851 | X86_MATCH_VFM(INTEL_HASWELL_G,		&model_hsw), | 
|---|
| 852 | X86_MATCH_VFM(INTEL_BROADWELL,		&model_hsw), | 
|---|
| 853 | X86_MATCH_VFM(INTEL_BROADWELL_G,	&model_hsw), | 
|---|
| 854 | X86_MATCH_VFM(INTEL_BROADWELL_X,	&model_hsx), | 
|---|
| 855 | X86_MATCH_VFM(INTEL_BROADWELL_D,	&model_hsx), | 
|---|
| 856 | X86_MATCH_VFM(INTEL_XEON_PHI_KNL,	&model_knl), | 
|---|
| 857 | X86_MATCH_VFM(INTEL_XEON_PHI_KNM,	&model_knl), | 
|---|
| 858 | X86_MATCH_VFM(INTEL_SKYLAKE_L,		&model_skl), | 
|---|
| 859 | X86_MATCH_VFM(INTEL_SKYLAKE,		&model_skl), | 
|---|
| 860 | X86_MATCH_VFM(INTEL_SKYLAKE_X,		&model_hsx), | 
|---|
| 861 | X86_MATCH_VFM(INTEL_KABYLAKE_L,		&model_skl), | 
|---|
| 862 | X86_MATCH_VFM(INTEL_KABYLAKE,		&model_skl), | 
|---|
| 863 | X86_MATCH_VFM(INTEL_CANNONLAKE_L,	&model_skl), | 
|---|
| 864 | X86_MATCH_VFM(INTEL_ATOM_GOLDMONT,	&model_hsw), | 
|---|
| 865 | X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_D,	&model_hsw), | 
|---|
| 866 | X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS,	&model_hsw), | 
|---|
| 867 | X86_MATCH_VFM(INTEL_ICELAKE_L,		&model_skl), | 
|---|
| 868 | X86_MATCH_VFM(INTEL_ICELAKE,		&model_skl), | 
|---|
| 869 | X86_MATCH_VFM(INTEL_ICELAKE_D,		&model_hsx), | 
|---|
| 870 | X86_MATCH_VFM(INTEL_ICELAKE_X,		&model_hsx), | 
|---|
| 871 | X86_MATCH_VFM(INTEL_COMETLAKE_L,	&model_skl), | 
|---|
| 872 | X86_MATCH_VFM(INTEL_COMETLAKE,		&model_skl), | 
|---|
| 873 | X86_MATCH_VFM(INTEL_TIGERLAKE_L,	&model_skl), | 
|---|
| 874 | X86_MATCH_VFM(INTEL_TIGERLAKE,		&model_skl), | 
|---|
| 875 | X86_MATCH_VFM(INTEL_ALDERLAKE,		&model_skl), | 
|---|
| 876 | X86_MATCH_VFM(INTEL_ALDERLAKE_L,	&model_skl), | 
|---|
| 877 | X86_MATCH_VFM(INTEL_ATOM_GRACEMONT,	&model_skl), | 
|---|
| 878 | X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X,	&model_spr), | 
|---|
| 879 | X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X,	&model_spr), | 
|---|
| 880 | X86_MATCH_VFM(INTEL_RAPTORLAKE,		&model_skl), | 
|---|
| 881 | X86_MATCH_VFM(INTEL_RAPTORLAKE_P,	&model_skl), | 
|---|
| 882 | X86_MATCH_VFM(INTEL_RAPTORLAKE_S,	&model_skl), | 
|---|
| 883 | X86_MATCH_VFM(INTEL_METEORLAKE,		&model_skl), | 
|---|
| 884 | X86_MATCH_VFM(INTEL_METEORLAKE_L,	&model_skl), | 
|---|
| 885 | X86_MATCH_VFM(INTEL_ARROWLAKE_H,	&model_skl), | 
|---|
| 886 | X86_MATCH_VFM(INTEL_ARROWLAKE,		&model_skl), | 
|---|
| 887 | X86_MATCH_VFM(INTEL_ARROWLAKE_U,	&model_skl), | 
|---|
| 888 | X86_MATCH_VFM(INTEL_LUNARLAKE_M,	&model_skl), | 
|---|
| 889 | {}, | 
|---|
| 890 | }; | 
|---|
| 891 | MODULE_DEVICE_TABLE(x86cpu, rapl_model_match); | 
|---|
| 892 |  | 
|---|
| 893 | static int __init rapl_pmu_init(void) | 
|---|
| 894 | { | 
|---|
| 895 | const struct x86_cpu_id *id; | 
|---|
| 896 | int rapl_pkg_pmu_scope = PERF_PMU_SCOPE_DIE; | 
|---|
| 897 | int ret; | 
|---|
| 898 |  | 
|---|
| 899 | if (rapl_pkg_pmu_is_pkg_scope()) | 
|---|
| 900 | rapl_pkg_pmu_scope = PERF_PMU_SCOPE_PKG; | 
|---|
| 901 |  | 
|---|
| 902 | id = x86_match_cpu(match: rapl_model_match); | 
|---|
| 903 | if (!id) | 
|---|
| 904 | return -ENODEV; | 
|---|
| 905 |  | 
|---|
| 906 | rapl_model = (struct rapl_model *) id->driver_data; | 
|---|
| 907 |  | 
|---|
| 908 | ret = rapl_check_hw_unit(); | 
|---|
| 909 | if (ret) | 
|---|
| 910 | return ret; | 
|---|
| 911 |  | 
|---|
| 912 | ret = init_rapl_pmus(rapl_pmus_ptr: &rapl_pmus_pkg, rapl_pmu_scope: rapl_pkg_pmu_scope, rapl_attr_groups, | 
|---|
| 913 | rapl_attr_update); | 
|---|
| 914 | if (ret) | 
|---|
| 915 | return ret; | 
|---|
| 916 |  | 
|---|
| 917 | rapl_pmus_pkg->cntr_mask = perf_msr_probe(msr: rapl_model->rapl_pkg_msrs, | 
|---|
| 918 | cnt: PERF_RAPL_PKG_EVENTS_MAX, no_zero: false, | 
|---|
| 919 | data: (void *) &rapl_model->pkg_events); | 
|---|
| 920 |  | 
|---|
| 921 | ret = perf_pmu_register(pmu: &rapl_pmus_pkg->pmu, name: "power", type: -1); | 
|---|
| 922 | if (ret) | 
|---|
| 923 | goto out; | 
|---|
| 924 |  | 
|---|
| 925 | if (rapl_model->core_events) { | 
|---|
| 926 | ret = init_rapl_pmus(rapl_pmus_ptr: &rapl_pmus_core, rapl_pmu_scope: PERF_PMU_SCOPE_CORE, | 
|---|
| 927 | rapl_attr_groups: rapl_core_attr_groups, | 
|---|
| 928 | rapl_attr_update: rapl_core_attr_update); | 
|---|
| 929 | if (ret) { | 
|---|
| 930 | pr_warn( "power-core PMU initialization failed (%d)\n", ret); | 
|---|
| 931 | goto core_init_failed; | 
|---|
| 932 | } | 
|---|
| 933 |  | 
|---|
| 934 | rapl_pmus_core->cntr_mask = perf_msr_probe(msr: rapl_model->rapl_core_msrs, | 
|---|
| 935 | PERF_RAPL_CORE_EVENTS_MAX, no_zero: false, | 
|---|
| 936 | data: (void *) &rapl_model->core_events); | 
|---|
| 937 |  | 
|---|
| 938 | ret = perf_pmu_register(pmu: &rapl_pmus_core->pmu, name: "power_core", type: -1); | 
|---|
| 939 | if (ret) { | 
|---|
| 940 | pr_warn( "power-core PMU registration failed (%d)\n", ret); | 
|---|
| 941 | cleanup_rapl_pmus(rapl_pmus: rapl_pmus_core); | 
|---|
| 942 | } | 
|---|
| 943 | } | 
|---|
| 944 |  | 
|---|
| 945 | core_init_failed: | 
|---|
| 946 | rapl_advertise(); | 
|---|
| 947 | return 0; | 
|---|
| 948 |  | 
|---|
| 949 | out: | 
|---|
| 950 | pr_warn( "Initialization failed (%d), disabled\n", ret); | 
|---|
| 951 | cleanup_rapl_pmus(rapl_pmus: rapl_pmus_pkg); | 
|---|
| 952 | return ret; | 
|---|
| 953 | } | 
|---|
| 954 | module_init(rapl_pmu_init); | 
|---|
| 955 |  | 
|---|
| 956 | static void __exit intel_rapl_exit(void) | 
|---|
| 957 | { | 
|---|
| 958 | if (rapl_pmus_core) { | 
|---|
| 959 | perf_pmu_unregister(pmu: &rapl_pmus_core->pmu); | 
|---|
| 960 | cleanup_rapl_pmus(rapl_pmus: rapl_pmus_core); | 
|---|
| 961 | } | 
|---|
| 962 | perf_pmu_unregister(pmu: &rapl_pmus_pkg->pmu); | 
|---|
| 963 | cleanup_rapl_pmus(rapl_pmus: rapl_pmus_pkg); | 
|---|
| 964 | } | 
|---|
| 965 | module_exit(intel_rapl_exit); | 
|---|
| 966 |  | 
|---|