]>
Commit | Line | Data |
---|---|---|
f6cc69f1 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
2d281d81 | 2 | /* |
3382388d ZR |
3 | * Common code for Intel Running Average Power Limit (RAPL) support. |
4 | * Copyright (c) 2019, Intel Corporation. | |
2d281d81 JP |
5 | */ |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
7 | ||
8 | #include <linux/kernel.h> | |
9 | #include <linux/module.h> | |
10 | #include <linux/list.h> | |
11 | #include <linux/types.h> | |
12 | #include <linux/device.h> | |
13 | #include <linux/slab.h> | |
14 | #include <linux/log2.h> | |
15 | #include <linux/bitmap.h> | |
16 | #include <linux/delay.h> | |
17 | #include <linux/sysfs.h> | |
18 | #include <linux/cpu.h> | |
19 | #include <linux/powercap.h> | |
52b3672c | 20 | #include <linux/suspend.h> |
ff956826 | 21 | #include <linux/intel_rapl.h> |
3382388d | 22 | #include <linux/processor.h> |
abcfaeb3 ZR |
23 | #include <linux/platform_device.h> |
24 | ||
25 | #include <asm/iosf_mbi.h> | |
2d281d81 | 26 | #include <asm/cpu_device_id.h> |
62d16733 | 27 | #include <asm/intel-family.h> |
2d281d81 JP |
28 | |
29 | /* bitmasks for RAPL MSRs, used by primitive access functions */ | |
30 | #define ENERGY_STATUS_MASK 0xffffffff | |
31 | ||
32 | #define POWER_LIMIT1_MASK 0x7FFF | |
33 | #define POWER_LIMIT1_ENABLE BIT(15) | |
34 | #define POWER_LIMIT1_CLAMP BIT(16) | |
35 | ||
36 | #define POWER_LIMIT2_MASK (0x7FFFULL<<32) | |
37 | #define POWER_LIMIT2_ENABLE BIT_ULL(47) | |
38 | #define POWER_LIMIT2_CLAMP BIT_ULL(48) | |
0c2ddedd ZR |
39 | #define POWER_HIGH_LOCK BIT_ULL(63) |
40 | #define POWER_LOW_LOCK BIT(31) | |
2d281d81 | 41 | |
8365a898 SP |
42 | #define POWER_LIMIT4_MASK 0x1FFF |
43 | ||
2d281d81 JP |
44 | #define TIME_WINDOW1_MASK (0x7FULL<<17) |
45 | #define TIME_WINDOW2_MASK (0x7FULL<<49) | |
46 | ||
47 | #define POWER_UNIT_OFFSET 0 | |
48 | #define POWER_UNIT_MASK 0x0F | |
49 | ||
50 | #define ENERGY_UNIT_OFFSET 0x08 | |
51 | #define ENERGY_UNIT_MASK 0x1F00 | |
52 | ||
53 | #define TIME_UNIT_OFFSET 0x10 | |
54 | #define TIME_UNIT_MASK 0xF0000 | |
55 | ||
56 | #define POWER_INFO_MAX_MASK (0x7fffULL<<32) | |
57 | #define POWER_INFO_MIN_MASK (0x7fffULL<<16) | |
58 | #define POWER_INFO_MAX_TIME_WIN_MASK (0x3fULL<<48) | |
59 | #define POWER_INFO_THERMAL_SPEC_MASK 0x7fff | |
60 | ||
61 | #define PERF_STATUS_THROTTLE_TIME_MASK 0xffffffff | |
62 | #define PP_POLICY_MASK 0x1F | |
63 | ||
931da6a0 ZR |
64 | /* |
65 | * SPR has different layout for Psys Domain PowerLimit registers. | |
66 | * There are 17 bits of PL1 and PL2 instead of 15 bits. | |
67 | * The Enable bits and TimeWindow bits are also shifted as a result. | |
68 | */ | |
69 | #define PSYS_POWER_LIMIT1_MASK 0x1FFFF | |
70 | #define PSYS_POWER_LIMIT1_ENABLE BIT(17) | |
71 | ||
72 | #define PSYS_POWER_LIMIT2_MASK (0x1FFFFULL<<32) | |
73 | #define PSYS_POWER_LIMIT2_ENABLE BIT_ULL(49) | |
74 | ||
75 | #define PSYS_TIME_WINDOW1_MASK (0x7FULL<<19) | |
76 | #define PSYS_TIME_WINDOW2_MASK (0x7FULL<<51) | |
77 | ||
2d281d81 | 78 | /* Non HW constants */ |
3382388d | 79 | #define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */ |
2d281d81 JP |
80 | #define RAPL_PRIMITIVE_DUMMY BIT(2) |
81 | ||
2d281d81 JP |
82 | #define TIME_WINDOW_MAX_MSEC 40000 |
83 | #define TIME_WINDOW_MIN_MSEC 250 | |
3382388d | 84 | #define ENERGY_UNIT_SCALE 1000 /* scale from driver unit to powercap unit */ |
2d281d81 | 85 | enum unit_type { |
3382388d | 86 | ARBITRARY_UNIT, /* no translation */ |
2d281d81 JP |
87 | POWER_UNIT, |
88 | ENERGY_UNIT, | |
89 | TIME_UNIT, | |
90 | }; | |
91 | ||
2d281d81 | 92 | /* per domain data, some are optional */ |
2d281d81 JP |
93 | #define NR_RAW_PRIMITIVES (NR_RAPL_PRIMITIVES - 2) |
94 | ||
2d281d81 JP |
95 | #define DOMAIN_STATE_INACTIVE BIT(0) |
96 | #define DOMAIN_STATE_POWER_LIMIT_SET BIT(1) | |
97 | #define DOMAIN_STATE_BIOS_LOCKED BIT(2) | |
98 | ||
2d281d81 JP |
99 | static const char pl1_name[] = "long_term"; |
100 | static const char pl2_name[] = "short_term"; | |
8365a898 | 101 | static const char pl4_name[] = "peak_power"; |
2d281d81 | 102 | |
2d281d81 JP |
103 | #define power_zone_to_rapl_domain(_zone) \ |
104 | container_of(_zone, struct rapl_domain, power_zone) | |
105 | ||
087e9cba | 106 | struct rapl_defaults { |
51b63409 | 107 | u8 floor_freq_reg_addr; |
cb532e72 | 108 | int (*check_unit)(struct rapl_domain *rd, int cpu); |
087e9cba | 109 | void (*set_floor_freq)(struct rapl_domain *rd, bool mode); |
cb532e72 | 110 | u64 (*compute_time_window)(struct rapl_domain *rd, u64 val, |
3382388d | 111 | bool to_raw); |
d474a4d3 | 112 | unsigned int dram_domain_energy_unit; |
2d798d9f | 113 | unsigned int psys_domain_energy_unit; |
931da6a0 | 114 | bool spr_psys_bits; |
087e9cba JP |
115 | }; |
116 | static struct rapl_defaults *rapl_defaults; | |
117 | ||
e8e28c2a ZR |
118 | static struct rapl_defaults *get_defaults(struct rapl_package *rp) |
119 | { | |
120 | return rp->priv->defaults; | |
121 | } | |
122 | ||
3c2c0845 | 123 | /* Sideband MBI registers */ |
51b63409 AT |
124 | #define IOSF_CPU_POWER_BUDGET_CTL_BYT (0x2) |
125 | #define IOSF_CPU_POWER_BUDGET_CTL_TNG (0xdf) | |
3c2c0845 | 126 | |
2d281d81 JP |
127 | #define PACKAGE_PLN_INT_SAVED BIT(0) |
128 | #define MAX_PRIM_NAME (32) | |
129 | ||
130 | /* per domain data. used to describe individual knobs such that access function | |
131 | * can be consolidated into one instead of many inline functions. | |
132 | */ | |
133 | struct rapl_primitive_info { | |
134 | const char *name; | |
135 | u64 mask; | |
136 | int shift; | |
f7c4e0c8 | 137 | enum rapl_domain_reg_id id; |
2d281d81 JP |
138 | enum unit_type unit; |
139 | u32 flag; | |
140 | }; | |
141 | ||
142 | #define PRIMITIVE_INFO_INIT(p, m, s, i, u, f) { \ | |
143 | .name = #p, \ | |
144 | .mask = m, \ | |
145 | .shift = s, \ | |
146 | .id = i, \ | |
147 | .unit = u, \ | |
148 | .flag = f \ | |
149 | } | |
150 | ||
151 | static void rapl_init_domains(struct rapl_package *rp); | |
152 | static int rapl_read_data_raw(struct rapl_domain *rd, | |
3382388d ZR |
153 | enum rapl_primitives prim, |
154 | bool xlate, u64 *data); | |
2d281d81 | 155 | static int rapl_write_data_raw(struct rapl_domain *rd, |
3382388d ZR |
156 | enum rapl_primitives prim, |
157 | unsigned long long value); | |
309557f5 | 158 | static u64 rapl_unit_xlate(struct rapl_domain *rd, |
3382388d | 159 | enum unit_type type, u64 value, int to_raw); |
309557f5 | 160 | static void package_power_limit_irq_save(struct rapl_package *rp); |
2d281d81 | 161 | |
3382388d | 162 | static LIST_HEAD(rapl_packages); /* guarded by CPU hotplug lock */ |
2d281d81 | 163 | |
3382388d | 164 | static const char *const rapl_domain_names[] = { |
2d281d81 JP |
165 | "package", |
166 | "core", | |
167 | "uncore", | |
168 | "dram", | |
3521ba1c | 169 | "psys", |
2d281d81 JP |
170 | }; |
171 | ||
3382388d ZR |
172 | static int get_energy_counter(struct powercap_zone *power_zone, |
173 | u64 *energy_raw) | |
2d281d81 JP |
174 | { |
175 | struct rapl_domain *rd; | |
176 | u64 energy_now; | |
177 | ||
178 | /* prevent CPU hotplug, make sure the RAPL domain does not go | |
179 | * away while reading the counter. | |
180 | */ | |
5d4c779c | 181 | cpus_read_lock(); |
2d281d81 JP |
182 | rd = power_zone_to_rapl_domain(power_zone); |
183 | ||
184 | if (!rapl_read_data_raw(rd, ENERGY_COUNTER, true, &energy_now)) { | |
185 | *energy_raw = energy_now; | |
5d4c779c | 186 | cpus_read_unlock(); |
2d281d81 JP |
187 | |
188 | return 0; | |
189 | } | |
5d4c779c | 190 | cpus_read_unlock(); |
2d281d81 JP |
191 | |
192 | return -EIO; | |
193 | } | |
194 | ||
195 | static int get_max_energy_counter(struct powercap_zone *pcd_dev, u64 *energy) | |
196 | { | |
d474a4d3 JP |
197 | struct rapl_domain *rd = power_zone_to_rapl_domain(pcd_dev); |
198 | ||
309557f5 | 199 | *energy = rapl_unit_xlate(rd, ENERGY_UNIT, ENERGY_STATUS_MASK, 0); |
2d281d81 JP |
200 | return 0; |
201 | } | |
202 | ||
203 | static int release_zone(struct powercap_zone *power_zone) | |
204 | { | |
205 | struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone); | |
309557f5 | 206 | struct rapl_package *rp = rd->rp; |
2d281d81 JP |
207 | |
208 | /* package zone is the last zone of a package, we can free | |
209 | * memory here since all children has been unregistered. | |
210 | */ | |
211 | if (rd->id == RAPL_DOMAIN_PACKAGE) { | |
2d281d81 JP |
212 | kfree(rd); |
213 | rp->domains = NULL; | |
214 | } | |
215 | ||
216 | return 0; | |
217 | ||
218 | } | |
219 | ||
220 | static int find_nr_power_limit(struct rapl_domain *rd) | |
221 | { | |
e1399ba2 | 222 | int i, nr_pl = 0; |
2d281d81 JP |
223 | |
224 | for (i = 0; i < NR_POWER_LIMITS; i++) { | |
e1399ba2 JP |
225 | if (rd->rpl[i].name) |
226 | nr_pl++; | |
2d281d81 JP |
227 | } |
228 | ||
e1399ba2 | 229 | return nr_pl; |
2d281d81 JP |
230 | } |
231 | ||
232 | static int set_domain_enable(struct powercap_zone *power_zone, bool mode) | |
233 | { | |
234 | struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone); | |
e8e28c2a | 235 | struct rapl_defaults *defaults = get_defaults(rd->rp); |
2d281d81 JP |
236 | |
237 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) | |
238 | return -EACCES; | |
3c2c0845 | 239 | |
5d4c779c | 240 | cpus_read_lock(); |
2d281d81 | 241 | rapl_write_data_raw(rd, PL1_ENABLE, mode); |
e8e28c2a ZR |
242 | if (defaults->set_floor_freq) |
243 | defaults->set_floor_freq(rd, mode); | |
5d4c779c | 244 | cpus_read_unlock(); |
2d281d81 JP |
245 | |
246 | return 0; | |
247 | } | |
248 | ||
249 | static int get_domain_enable(struct powercap_zone *power_zone, bool *mode) | |
250 | { | |
251 | struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone); | |
252 | u64 val; | |
253 | ||
254 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) { | |
255 | *mode = false; | |
256 | return 0; | |
257 | } | |
5d4c779c | 258 | cpus_read_lock(); |
2d281d81 | 259 | if (rapl_read_data_raw(rd, PL1_ENABLE, true, &val)) { |
5d4c779c | 260 | cpus_read_unlock(); |
2d281d81 JP |
261 | return -EIO; |
262 | } | |
263 | *mode = val; | |
5d4c779c | 264 | cpus_read_unlock(); |
2d281d81 JP |
265 | |
266 | return 0; | |
267 | } | |
268 | ||
269 | /* per RAPL domain ops, in the order of rapl_domain_type */ | |
600c395b | 270 | static const struct powercap_zone_ops zone_ops[] = { |
2d281d81 JP |
271 | /* RAPL_DOMAIN_PACKAGE */ |
272 | { | |
3382388d ZR |
273 | .get_energy_uj = get_energy_counter, |
274 | .get_max_energy_range_uj = get_max_energy_counter, | |
275 | .release = release_zone, | |
276 | .set_enable = set_domain_enable, | |
277 | .get_enable = get_domain_enable, | |
278 | }, | |
2d281d81 JP |
279 | /* RAPL_DOMAIN_PP0 */ |
280 | { | |
3382388d ZR |
281 | .get_energy_uj = get_energy_counter, |
282 | .get_max_energy_range_uj = get_max_energy_counter, | |
283 | .release = release_zone, | |
284 | .set_enable = set_domain_enable, | |
285 | .get_enable = get_domain_enable, | |
286 | }, | |
2d281d81 JP |
287 | /* RAPL_DOMAIN_PP1 */ |
288 | { | |
3382388d ZR |
289 | .get_energy_uj = get_energy_counter, |
290 | .get_max_energy_range_uj = get_max_energy_counter, | |
291 | .release = release_zone, | |
292 | .set_enable = set_domain_enable, | |
293 | .get_enable = get_domain_enable, | |
294 | }, | |
2d281d81 JP |
295 | /* RAPL_DOMAIN_DRAM */ |
296 | { | |
3382388d ZR |
297 | .get_energy_uj = get_energy_counter, |
298 | .get_max_energy_range_uj = get_max_energy_counter, | |
299 | .release = release_zone, | |
300 | .set_enable = set_domain_enable, | |
301 | .get_enable = get_domain_enable, | |
302 | }, | |
3521ba1c SP |
303 | /* RAPL_DOMAIN_PLATFORM */ |
304 | { | |
3382388d ZR |
305 | .get_energy_uj = get_energy_counter, |
306 | .get_max_energy_range_uj = get_max_energy_counter, | |
307 | .release = release_zone, | |
308 | .set_enable = set_domain_enable, | |
309 | .get_enable = get_domain_enable, | |
310 | }, | |
2d281d81 JP |
311 | }; |
312 | ||
e1399ba2 JP |
313 | /* |
314 | * Constraint index used by powercap can be different than power limit (PL) | |
3382388d | 315 | * index in that some PLs maybe missing due to non-existent MSRs. So we |
e1399ba2 JP |
316 | * need to convert here by finding the valid PLs only (name populated). |
317 | */ | |
318 | static int contraint_to_pl(struct rapl_domain *rd, int cid) | |
319 | { | |
320 | int i, j; | |
321 | ||
322 | for (i = 0, j = 0; i < NR_POWER_LIMITS; i++) { | |
323 | if ((rd->rpl[i].name) && j++ == cid) { | |
324 | pr_debug("%s: index %d\n", __func__, i); | |
325 | return i; | |
326 | } | |
327 | } | |
cb43f81b | 328 | pr_err("Cannot find matching power limit for constraint %d\n", cid); |
e1399ba2 JP |
329 | |
330 | return -EINVAL; | |
331 | } | |
332 | ||
333 | static int set_power_limit(struct powercap_zone *power_zone, int cid, | |
3382388d | 334 | u64 power_limit) |
2d281d81 JP |
335 | { |
336 | struct rapl_domain *rd; | |
337 | struct rapl_package *rp; | |
338 | int ret = 0; | |
e1399ba2 | 339 | int id; |
2d281d81 | 340 | |
5d4c779c | 341 | cpus_read_lock(); |
2d281d81 | 342 | rd = power_zone_to_rapl_domain(power_zone); |
e1399ba2 | 343 | id = contraint_to_pl(rd, cid); |
cb43f81b JP |
344 | if (id < 0) { |
345 | ret = id; | |
346 | goto set_exit; | |
347 | } | |
e1399ba2 | 348 | |
309557f5 | 349 | rp = rd->rp; |
2d281d81 JP |
350 | |
351 | if (rd->state & DOMAIN_STATE_BIOS_LOCKED) { | |
3382388d ZR |
352 | dev_warn(&power_zone->dev, |
353 | "%s locked by BIOS, monitoring only\n", rd->name); | |
2d281d81 JP |
354 | ret = -EACCES; |
355 | goto set_exit; | |
356 | } | |
357 | ||
358 | switch (rd->rpl[id].prim_id) { | |
359 | case PL1_ENABLE: | |
360 | rapl_write_data_raw(rd, POWER_LIMIT1, power_limit); | |
361 | break; | |
362 | case PL2_ENABLE: | |
363 | rapl_write_data_raw(rd, POWER_LIMIT2, power_limit); | |
364 | break; | |
8365a898 SP |
365 | case PL4_ENABLE: |
366 | rapl_write_data_raw(rd, POWER_LIMIT4, power_limit); | |
367 | break; | |
2d281d81 JP |
368 | default: |
369 | ret = -EINVAL; | |
370 | } | |
371 | if (!ret) | |
309557f5 | 372 | package_power_limit_irq_save(rp); |
2d281d81 | 373 | set_exit: |
5d4c779c | 374 | cpus_read_unlock(); |
2d281d81 JP |
375 | return ret; |
376 | } | |
377 | ||
e1399ba2 | 378 | static int get_current_power_limit(struct powercap_zone *power_zone, int cid, |
3382388d | 379 | u64 *data) |
2d281d81 JP |
380 | { |
381 | struct rapl_domain *rd; | |
382 | u64 val; | |
383 | int prim; | |
384 | int ret = 0; | |
e1399ba2 | 385 | int id; |
2d281d81 | 386 | |
5d4c779c | 387 | cpus_read_lock(); |
2d281d81 | 388 | rd = power_zone_to_rapl_domain(power_zone); |
e1399ba2 | 389 | id = contraint_to_pl(rd, cid); |
cb43f81b JP |
390 | if (id < 0) { |
391 | ret = id; | |
392 | goto get_exit; | |
393 | } | |
394 | ||
2d281d81 JP |
395 | switch (rd->rpl[id].prim_id) { |
396 | case PL1_ENABLE: | |
397 | prim = POWER_LIMIT1; | |
398 | break; | |
399 | case PL2_ENABLE: | |
400 | prim = POWER_LIMIT2; | |
401 | break; | |
8365a898 SP |
402 | case PL4_ENABLE: |
403 | prim = POWER_LIMIT4; | |
404 | break; | |
2d281d81 | 405 | default: |
5d4c779c | 406 | cpus_read_unlock(); |
2d281d81 JP |
407 | return -EINVAL; |
408 | } | |
409 | if (rapl_read_data_raw(rd, prim, true, &val)) | |
410 | ret = -EIO; | |
411 | else | |
412 | *data = val; | |
413 | ||
cb43f81b | 414 | get_exit: |
5d4c779c | 415 | cpus_read_unlock(); |
2d281d81 JP |
416 | |
417 | return ret; | |
418 | } | |
419 | ||
e1399ba2 | 420 | static int set_time_window(struct powercap_zone *power_zone, int cid, |
3382388d | 421 | u64 window) |
2d281d81 JP |
422 | { |
423 | struct rapl_domain *rd; | |
424 | int ret = 0; | |
e1399ba2 | 425 | int id; |
2d281d81 | 426 | |
5d4c779c | 427 | cpus_read_lock(); |
2d281d81 | 428 | rd = power_zone_to_rapl_domain(power_zone); |
e1399ba2 | 429 | id = contraint_to_pl(rd, cid); |
cb43f81b JP |
430 | if (id < 0) { |
431 | ret = id; | |
432 | goto set_time_exit; | |
433 | } | |
e1399ba2 | 434 | |
2d281d81 JP |
435 | switch (rd->rpl[id].prim_id) { |
436 | case PL1_ENABLE: | |
437 | rapl_write_data_raw(rd, TIME_WINDOW1, window); | |
438 | break; | |
439 | case PL2_ENABLE: | |
440 | rapl_write_data_raw(rd, TIME_WINDOW2, window); | |
441 | break; | |
442 | default: | |
443 | ret = -EINVAL; | |
444 | } | |
cb43f81b JP |
445 | |
446 | set_time_exit: | |
5d4c779c | 447 | cpus_read_unlock(); |
2d281d81 JP |
448 | return ret; |
449 | } | |
450 | ||
3382388d ZR |
451 | static int get_time_window(struct powercap_zone *power_zone, int cid, |
452 | u64 *data) | |
2d281d81 JP |
453 | { |
454 | struct rapl_domain *rd; | |
455 | u64 val; | |
456 | int ret = 0; | |
e1399ba2 | 457 | int id; |
2d281d81 | 458 | |
5d4c779c | 459 | cpus_read_lock(); |
2d281d81 | 460 | rd = power_zone_to_rapl_domain(power_zone); |
e1399ba2 | 461 | id = contraint_to_pl(rd, cid); |
cb43f81b JP |
462 | if (id < 0) { |
463 | ret = id; | |
464 | goto get_time_exit; | |
465 | } | |
e1399ba2 | 466 | |
2d281d81 JP |
467 | switch (rd->rpl[id].prim_id) { |
468 | case PL1_ENABLE: | |
469 | ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val); | |
470 | break; | |
471 | case PL2_ENABLE: | |
472 | ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val); | |
473 | break; | |
8365a898 SP |
474 | case PL4_ENABLE: |
475 | /* | |
476 | * Time window parameter is not applicable for PL4 entry | |
477 | * so assigining '0' as default value. | |
478 | */ | |
479 | val = 0; | |
480 | break; | |
2d281d81 | 481 | default: |
5d4c779c | 482 | cpus_read_unlock(); |
2d281d81 JP |
483 | return -EINVAL; |
484 | } | |
485 | if (!ret) | |
486 | *data = val; | |
cb43f81b JP |
487 | |
488 | get_time_exit: | |
5d4c779c | 489 | cpus_read_unlock(); |
2d281d81 JP |
490 | |
491 | return ret; | |
492 | } | |
493 | ||
3382388d ZR |
494 | static const char *get_constraint_name(struct powercap_zone *power_zone, |
495 | int cid) | |
2d281d81 | 496 | { |
2d281d81 | 497 | struct rapl_domain *rd; |
e1399ba2 | 498 | int id; |
2d281d81 JP |
499 | |
500 | rd = power_zone_to_rapl_domain(power_zone); | |
e1399ba2 JP |
501 | id = contraint_to_pl(rd, cid); |
502 | if (id >= 0) | |
503 | return rd->rpl[id].name; | |
2d281d81 | 504 | |
e1399ba2 | 505 | return NULL; |
2d281d81 JP |
506 | } |
507 | ||
3382388d | 508 | static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data) |
2d281d81 JP |
509 | { |
510 | struct rapl_domain *rd; | |
511 | u64 val; | |
512 | int prim; | |
513 | int ret = 0; | |
514 | ||
5d4c779c | 515 | cpus_read_lock(); |
2d281d81 JP |
516 | rd = power_zone_to_rapl_domain(power_zone); |
517 | switch (rd->rpl[id].prim_id) { | |
518 | case PL1_ENABLE: | |
519 | prim = THERMAL_SPEC_POWER; | |
520 | break; | |
521 | case PL2_ENABLE: | |
522 | prim = MAX_POWER; | |
523 | break; | |
8365a898 SP |
524 | case PL4_ENABLE: |
525 | prim = MAX_POWER; | |
526 | break; | |
2d281d81 | 527 | default: |
5d4c779c | 528 | cpus_read_unlock(); |
2d281d81 JP |
529 | return -EINVAL; |
530 | } | |
531 | if (rapl_read_data_raw(rd, prim, true, &val)) | |
532 | ret = -EIO; | |
533 | else | |
534 | *data = val; | |
535 | ||
8365a898 SP |
536 | /* As a generalization rule, PL4 would be around two times PL2. */ |
537 | if (rd->rpl[id].prim_id == PL4_ENABLE) | |
538 | *data = *data * 2; | |
539 | ||
5d4c779c | 540 | cpus_read_unlock(); |
2d281d81 JP |
541 | |
542 | return ret; | |
543 | } | |
544 | ||
600c395b | 545 | static const struct powercap_zone_constraint_ops constraint_ops = { |
2d281d81 JP |
546 | .set_power_limit_uw = set_power_limit, |
547 | .get_power_limit_uw = get_current_power_limit, | |
548 | .set_time_window_us = set_time_window, | |
549 | .get_time_window_us = get_time_window, | |
550 | .get_max_power_uw = get_max_power, | |
551 | .get_name = get_constraint_name, | |
552 | }; | |
553 | ||
554 | /* called after domain detection and package level data are set */ | |
555 | static void rapl_init_domains(struct rapl_package *rp) | |
556 | { | |
0c2ddedd ZR |
557 | enum rapl_domain_type i; |
558 | enum rapl_domain_reg_id j; | |
2d281d81 JP |
559 | struct rapl_domain *rd = rp->domains; |
560 | ||
561 | for (i = 0; i < RAPL_DOMAIN_MAX; i++) { | |
562 | unsigned int mask = rp->domain_map & (1 << i); | |
7fde2712 | 563 | |
0c2ddedd ZR |
564 | if (!mask) |
565 | continue; | |
566 | ||
567 | rd->rp = rp; | |
f1e8d756 ZR |
568 | |
569 | if (i == RAPL_DOMAIN_PLATFORM && rp->id > 0) { | |
570 | snprintf(rd->name, RAPL_DOMAIN_NAME_LENGTH, "psys-%d", | |
65348ba2 | 571 | topology_physical_package_id(rp->lead_cpu)); |
f1e8d756 ZR |
572 | } else |
573 | snprintf(rd->name, RAPL_DOMAIN_NAME_LENGTH, "%s", | |
574 | rapl_domain_names[i]); | |
575 | ||
0c2ddedd ZR |
576 | rd->id = i; |
577 | rd->rpl[0].prim_id = PL1_ENABLE; | |
578 | rd->rpl[0].name = pl1_name; | |
8365a898 SP |
579 | |
580 | /* | |
581 | * The PL2 power domain is applicable for limits two | |
582 | * and limits three | |
583 | */ | |
584 | if (rp->priv->limits[i] >= 2) { | |
2d281d81 JP |
585 | rd->rpl[1].prim_id = PL2_ENABLE; |
586 | rd->rpl[1].name = pl2_name; | |
0c2ddedd ZR |
587 | } |
588 | ||
8365a898 SP |
589 | /* Enable PL4 domain if the total power limits are three */ |
590 | if (rp->priv->limits[i] == 3) { | |
591 | rd->rpl[2].prim_id = PL4_ENABLE; | |
592 | rd->rpl[2].name = pl4_name; | |
593 | } | |
594 | ||
0c2ddedd ZR |
595 | for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++) |
596 | rd->regs[j] = rp->priv->regs[i][j]; | |
597 | ||
0c2ddedd | 598 | rd++; |
2d281d81 JP |
599 | } |
600 | } | |
601 | ||
309557f5 | 602 | static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type, |
3382388d | 603 | u64 value, int to_raw) |
2d281d81 | 604 | { |
3c2c0845 | 605 | u64 units = 1; |
cb532e72 | 606 | struct rapl_defaults *defaults = get_defaults(rd->rp); |
d474a4d3 | 607 | u64 scale = 1; |
2d281d81 | 608 | |
2d281d81 JP |
609 | switch (type) { |
610 | case POWER_UNIT: | |
cb532e72 | 611 | units = rd->power_unit; |
2d281d81 JP |
612 | break; |
613 | case ENERGY_UNIT: | |
d474a4d3 | 614 | scale = ENERGY_UNIT_SCALE; |
cb532e72 | 615 | units = rd->energy_unit; |
2d281d81 JP |
616 | break; |
617 | case TIME_UNIT: | |
cb532e72 | 618 | return defaults->compute_time_window(rd, value, to_raw); |
2d281d81 JP |
619 | case ARBITRARY_UNIT: |
620 | default: | |
621 | return value; | |
a8193af7 | 622 | } |
2d281d81 JP |
623 | |
624 | if (to_raw) | |
d474a4d3 | 625 | return div64_u64(value, units) * scale; |
3c2c0845 JP |
626 | |
627 | value *= units; | |
628 | ||
d474a4d3 | 629 | return div64_u64(value, scale); |
2d281d81 JP |
630 | } |
631 | ||
11edbe5c | 632 | static struct rapl_primitive_info rpi_default[NR_RAPL_PRIMITIVES] = { |
2d281d81 | 633 | /* name, mask, shift, msr index, unit divisor */ |
11edbe5c | 634 | [POWER_LIMIT1] = PRIMITIVE_INFO_INIT(POWER_LIMIT1, POWER_LIMIT1_MASK, 0, |
3382388d | 635 | RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0), |
11edbe5c | 636 | [POWER_LIMIT2] = PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32, |
3382388d | 637 | RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0), |
11edbe5c | 638 | [POWER_LIMIT4] = PRIMITIVE_INFO_INIT(POWER_LIMIT4, POWER_LIMIT4_MASK, 0, |
8365a898 | 639 | RAPL_DOMAIN_REG_PL4, POWER_UNIT, 0), |
045610c3 ZR |
640 | [ENERGY_COUNTER] = PRIMITIVE_INFO_INIT(ENERGY_COUNTER, ENERGY_STATUS_MASK, 0, |
641 | RAPL_DOMAIN_REG_STATUS, ENERGY_UNIT, 0), | |
11edbe5c | 642 | [FW_LOCK] = PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31, |
3382388d | 643 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 644 | [PL1_ENABLE] = PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15, |
3382388d | 645 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 646 | [PL1_CLAMP] = PRIMITIVE_INFO_INIT(PL1_CLAMP, POWER_LIMIT1_CLAMP, 16, |
3382388d | 647 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 648 | [PL2_ENABLE] = PRIMITIVE_INFO_INIT(PL2_ENABLE, POWER_LIMIT2_ENABLE, 47, |
3382388d | 649 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 650 | [PL2_CLAMP] = PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48, |
3382388d | 651 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 652 | [PL4_ENABLE] = PRIMITIVE_INFO_INIT(PL4_ENABLE, POWER_LIMIT4_MASK, 0, |
8365a898 | 653 | RAPL_DOMAIN_REG_PL4, ARBITRARY_UNIT, 0), |
11edbe5c | 654 | [TIME_WINDOW1] = PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17, |
3382388d | 655 | RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0), |
11edbe5c | 656 | [TIME_WINDOW2] = PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49, |
3382388d | 657 | RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0), |
11edbe5c | 658 | [THERMAL_SPEC_POWER] = PRIMITIVE_INFO_INIT(THERMAL_SPEC_POWER, POWER_INFO_THERMAL_SPEC_MASK, |
3382388d | 659 | 0, RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0), |
11edbe5c | 660 | [MAX_POWER] = PRIMITIVE_INFO_INIT(MAX_POWER, POWER_INFO_MAX_MASK, 32, |
3382388d | 661 | RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0), |
11edbe5c | 662 | [MIN_POWER] = PRIMITIVE_INFO_INIT(MIN_POWER, POWER_INFO_MIN_MASK, 16, |
3382388d | 663 | RAPL_DOMAIN_REG_INFO, POWER_UNIT, 0), |
11edbe5c | 664 | [MAX_TIME_WINDOW] = PRIMITIVE_INFO_INIT(MAX_TIME_WINDOW, POWER_INFO_MAX_TIME_WIN_MASK, 48, |
3382388d | 665 | RAPL_DOMAIN_REG_INFO, TIME_UNIT, 0), |
11edbe5c | 666 | [THROTTLED_TIME] = PRIMITIVE_INFO_INIT(THROTTLED_TIME, PERF_STATUS_THROTTLE_TIME_MASK, 0, |
3382388d | 667 | RAPL_DOMAIN_REG_PERF, TIME_UNIT, 0), |
11edbe5c | 668 | [PRIORITY_LEVEL] = PRIMITIVE_INFO_INIT(PRIORITY_LEVEL, PP_POLICY_MASK, 0, |
3382388d | 669 | RAPL_DOMAIN_REG_POLICY, ARBITRARY_UNIT, 0), |
11edbe5c | 670 | [PSYS_POWER_LIMIT1] = PRIMITIVE_INFO_INIT(PSYS_POWER_LIMIT1, PSYS_POWER_LIMIT1_MASK, 0, |
931da6a0 | 671 | RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0), |
11edbe5c | 672 | [PSYS_POWER_LIMIT2] = PRIMITIVE_INFO_INIT(PSYS_POWER_LIMIT2, PSYS_POWER_LIMIT2_MASK, 32, |
931da6a0 | 673 | RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0), |
11edbe5c | 674 | [PSYS_PL1_ENABLE] = PRIMITIVE_INFO_INIT(PSYS_PL1_ENABLE, PSYS_POWER_LIMIT1_ENABLE, 17, |
931da6a0 | 675 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 676 | [PSYS_PL2_ENABLE] = PRIMITIVE_INFO_INIT(PSYS_PL2_ENABLE, PSYS_POWER_LIMIT2_ENABLE, 49, |
931da6a0 | 677 | RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0), |
11edbe5c | 678 | [PSYS_TIME_WINDOW1] = PRIMITIVE_INFO_INIT(PSYS_TIME_WINDOW1, PSYS_TIME_WINDOW1_MASK, 19, |
931da6a0 | 679 | RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0), |
11edbe5c | 680 | [PSYS_TIME_WINDOW2] = PRIMITIVE_INFO_INIT(PSYS_TIME_WINDOW2, PSYS_TIME_WINDOW2_MASK, 51, |
931da6a0 | 681 | RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0), |
2d281d81 | 682 | /* non-hardware */ |
11edbe5c | 683 | [AVERAGE_POWER] = PRIMITIVE_INFO_INIT(AVERAGE_POWER, 0, 0, 0, POWER_UNIT, |
3382388d | 684 | RAPL_PRIMITIVE_DERIVED), |
2d281d81 JP |
685 | }; |
686 | ||
98ff639a ZR |
687 | static struct rapl_primitive_info *get_rpi(struct rapl_package *rp, int prim) |
688 | { | |
689 | struct rapl_primitive_info *rpi = rp->priv->rpi; | |
690 | ||
691 | if (prim < 0 || prim > NR_RAPL_PRIMITIVES || !rpi) | |
692 | return NULL; | |
693 | ||
694 | return &rpi[prim]; | |
695 | } | |
696 | ||
e8e28c2a ZR |
697 | static int rapl_config(struct rapl_package *rp) |
698 | { | |
699 | rp->priv->defaults = (void *)rapl_defaults; | |
98ff639a | 700 | rp->priv->rpi = (void *)rpi_default; |
e8e28c2a ZR |
701 | return 0; |
702 | } | |
703 | ||
931da6a0 ZR |
704 | static enum rapl_primitives |
705 | prim_fixups(struct rapl_domain *rd, enum rapl_primitives prim) | |
706 | { | |
e8e28c2a ZR |
707 | struct rapl_defaults *defaults = get_defaults(rd->rp); |
708 | ||
709 | if (!defaults->spr_psys_bits) | |
931da6a0 ZR |
710 | return prim; |
711 | ||
712 | if (rd->id != RAPL_DOMAIN_PLATFORM) | |
713 | return prim; | |
714 | ||
715 | switch (prim) { | |
716 | case POWER_LIMIT1: | |
717 | return PSYS_POWER_LIMIT1; | |
718 | case POWER_LIMIT2: | |
719 | return PSYS_POWER_LIMIT2; | |
720 | case PL1_ENABLE: | |
721 | return PSYS_PL1_ENABLE; | |
722 | case PL2_ENABLE: | |
723 | return PSYS_PL2_ENABLE; | |
724 | case TIME_WINDOW1: | |
725 | return PSYS_TIME_WINDOW1; | |
726 | case TIME_WINDOW2: | |
727 | return PSYS_TIME_WINDOW2; | |
728 | default: | |
729 | return prim; | |
730 | } | |
731 | } | |
732 | ||
2d281d81 JP |
733 | /* Read primitive data based on its related struct rapl_primitive_info. |
734 | * if xlate flag is set, return translated data based on data units, i.e. | |
735 | * time, energy, and power. | |
736 | * RAPL MSRs are non-architectual and are laid out not consistently across | |
737 | * domains. Here we use primitive info to allow writing consolidated access | |
738 | * functions. | |
739 | * For a given primitive, it is processed by MSR mask and shift. Unit conversion | |
740 | * is pre-assigned based on RAPL unit MSRs read at init time. | |
741 | * 63-------------------------- 31--------------------------- 0 | |
742 | * | xxxxx (mask) | | |
743 | * | |<- shift ----------------| | |
744 | * 63-------------------------- 31--------------------------- 0 | |
745 | */ | |
746 | static int rapl_read_data_raw(struct rapl_domain *rd, | |
3382388d | 747 | enum rapl_primitives prim, bool xlate, u64 *data) |
2d281d81 | 748 | { |
beea8df8 | 749 | u64 value; |
931da6a0 | 750 | enum rapl_primitives prim_fixed = prim_fixups(rd, prim); |
98ff639a | 751 | struct rapl_primitive_info *rpi = get_rpi(rd->rp, prim_fixed); |
beea8df8 | 752 | struct reg_action ra; |
2d281d81 JP |
753 | int cpu; |
754 | ||
98ff639a | 755 | if (!rpi || !rpi->name || rpi->flag & RAPL_PRIMITIVE_DUMMY) |
2d281d81 JP |
756 | return -EINVAL; |
757 | ||
98ff639a | 758 | ra.reg = rd->regs[rpi->id]; |
beea8df8 | 759 | if (!ra.reg) |
2d281d81 | 760 | return -EINVAL; |
323ee64a JP |
761 | |
762 | cpu = rd->rp->lead_cpu; | |
2d281d81 | 763 | |
0c2ddedd ZR |
764 | /* domain with 2 limits has different bit */ |
765 | if (prim == FW_LOCK && rd->rp->priv->limits[rd->id] == 2) { | |
98ff639a ZR |
766 | rpi->mask = POWER_HIGH_LOCK; |
767 | rpi->shift = 63; | |
2d281d81 JP |
768 | } |
769 | /* non-hardware data are collected by the polling thread */ | |
98ff639a | 770 | if (rpi->flag & RAPL_PRIMITIVE_DERIVED) { |
2d281d81 JP |
771 | *data = rd->rdd.primitives[prim]; |
772 | return 0; | |
773 | } | |
774 | ||
98ff639a | 775 | ra.mask = rpi->mask; |
beea8df8 ZR |
776 | |
777 | if (rd->rp->priv->read_raw(cpu, &ra)) { | |
d978e755 | 778 | pr_debug("failed to read reg 0x%llx on cpu %d\n", ra.reg, cpu); |
2d281d81 JP |
779 | return -EIO; |
780 | } | |
781 | ||
98ff639a | 782 | value = ra.value >> rpi->shift; |
beea8df8 | 783 | |
2d281d81 | 784 | if (xlate) |
98ff639a | 785 | *data = rapl_unit_xlate(rd, rpi->unit, value, 0); |
2d281d81 | 786 | else |
beea8df8 | 787 | *data = value; |
2d281d81 JP |
788 | |
789 | return 0; | |
790 | } | |
791 | ||
792 | /* Similar use of primitive info in the read counterpart */ | |
793 | static int rapl_write_data_raw(struct rapl_domain *rd, | |
3382388d ZR |
794 | enum rapl_primitives prim, |
795 | unsigned long long value) | |
2d281d81 | 796 | { |
931da6a0 | 797 | enum rapl_primitives prim_fixed = prim_fixups(rd, prim); |
98ff639a | 798 | struct rapl_primitive_info *rpi = get_rpi(rd->rp, prim_fixed); |
2d281d81 | 799 | int cpu; |
f14a1396 | 800 | u64 bits; |
beea8df8 | 801 | struct reg_action ra; |
f14a1396 | 802 | int ret; |
2d281d81 | 803 | |
98ff639a ZR |
804 | if (!rpi || !rpi->name || rpi->flag & RAPL_PRIMITIVE_DUMMY) |
805 | return -EINVAL; | |
806 | ||
323ee64a | 807 | cpu = rd->rp->lead_cpu; |
98ff639a ZR |
808 | bits = rapl_unit_xlate(rd, rpi->unit, value, 1); |
809 | bits <<= rpi->shift; | |
810 | bits &= rpi->mask; | |
edbdabc6 | 811 | |
beea8df8 | 812 | memset(&ra, 0, sizeof(ra)); |
f14a1396 | 813 | |
98ff639a ZR |
814 | ra.reg = rd->regs[rpi->id]; |
815 | ra.mask = rpi->mask; | |
beea8df8 | 816 | ra.value = bits; |
f14a1396 | 817 | |
beea8df8 | 818 | ret = rd->rp->priv->write_raw(cpu, &ra); |
f14a1396 JP |
819 | |
820 | return ret; | |
2d281d81 JP |
821 | } |
822 | ||
3c2c0845 JP |
823 | /* |
824 | * Raw RAPL data stored in MSRs are in certain scales. We need to | |
825 | * convert them into standard units based on the units reported in | |
826 | * the RAPL unit MSRs. This is specific to CPUs as the method to | |
827 | * calculate units differ on different CPUs. | |
828 | * We convert the units to below format based on CPUs. | |
829 | * i.e. | |
d474a4d3 | 830 | * energy unit: picoJoules : Represented in picoJoules by default |
3c2c0845 JP |
831 | * power unit : microWatts : Represented in milliWatts by default |
832 | * time unit : microseconds: Represented in seconds by default | |
833 | */ | |
cb532e72 | 834 | static int rapl_check_unit_core(struct rapl_domain *rd, int cpu) |
2d281d81 | 835 | { |
1193b165 | 836 | struct reg_action ra; |
2d281d81 JP |
837 | u32 value; |
838 | ||
cb532e72 | 839 | ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT]; |
1193b165 | 840 | ra.mask = ~0; |
cb532e72 | 841 | if (rd->rp->priv->read_raw(cpu, &ra)) { |
d978e755 | 842 | pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n", |
cb532e72 | 843 | ra.reg, cpu); |
2d281d81 JP |
844 | return -ENODEV; |
845 | } | |
846 | ||
1193b165 | 847 | value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; |
cb532e72 | 848 | rd->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value); |
2d281d81 | 849 | |
1193b165 | 850 | value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; |
cb532e72 | 851 | rd->power_unit = 1000000 / (1 << value); |
2d281d81 | 852 | |
1193b165 | 853 | value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; |
cb532e72 | 854 | rd->time_unit = 1000000 / (1 << value); |
2d281d81 | 855 | |
cb532e72 ZR |
856 | pr_debug("Core CPU %s:%s energy=%dpJ, time=%dus, power=%duW\n", |
857 | rd->rp->name, rd->name, rd->energy_unit, rd->time_unit, rd->power_unit); | |
2d281d81 JP |
858 | |
859 | return 0; | |
860 | } | |
861 | ||
cb532e72 | 862 | static int rapl_check_unit_atom(struct rapl_domain *rd, int cpu) |
3c2c0845 | 863 | { |
1193b165 | 864 | struct reg_action ra; |
3c2c0845 JP |
865 | u32 value; |
866 | ||
cb532e72 | 867 | ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT]; |
1193b165 | 868 | ra.mask = ~0; |
cb532e72 | 869 | if (rd->rp->priv->read_raw(cpu, &ra)) { |
d978e755 | 870 | pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n", |
cb532e72 | 871 | ra.reg, cpu); |
3c2c0845 JP |
872 | return -ENODEV; |
873 | } | |
1193b165 ZR |
874 | |
875 | value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET; | |
cb532e72 | 876 | rd->energy_unit = ENERGY_UNIT_SCALE * 1 << value; |
3c2c0845 | 877 | |
1193b165 | 878 | value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET; |
cb532e72 | 879 | rd->power_unit = (1 << value) * 1000; |
3c2c0845 | 880 | |
1193b165 | 881 | value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET; |
cb532e72 | 882 | rd->time_unit = 1000000 / (1 << value); |
3c2c0845 | 883 | |
cb532e72 ZR |
884 | pr_debug("Atom %s:%s energy=%dpJ, time=%dus, power=%duW\n", |
885 | rd->rp->name, rd->name, rd->energy_unit, rd->time_unit, rd->power_unit); | |
3c2c0845 JP |
886 | |
887 | return 0; | |
888 | } | |
889 | ||
f14a1396 JP |
890 | static void power_limit_irq_save_cpu(void *info) |
891 | { | |
892 | u32 l, h = 0; | |
893 | struct rapl_package *rp = (struct rapl_package *)info; | |
894 | ||
895 | /* save the state of PLN irq mask bit before disabling it */ | |
896 | rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); | |
897 | if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) { | |
898 | rp->power_limit_irq = l & PACKAGE_THERM_INT_PLN_ENABLE; | |
899 | rp->power_limit_irq |= PACKAGE_PLN_INT_SAVED; | |
900 | } | |
901 | l &= ~PACKAGE_THERM_INT_PLN_ENABLE; | |
902 | wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | |
903 | } | |
904 | ||
2d281d81 JP |
905 | /* REVISIT: |
906 | * When package power limit is set artificially low by RAPL, LVT | |
907 | * thermal interrupt for package power limit should be ignored | |
908 | * since we are not really exceeding the real limit. The intention | |
909 | * is to avoid excessive interrupts while we are trying to save power. | |
910 | * A useful feature might be routing the package_power_limit interrupt | |
911 | * to userspace via eventfd. once we have a usecase, this is simple | |
912 | * to do by adding an atomic notifier. | |
913 | */ | |
914 | ||
309557f5 | 915 | static void package_power_limit_irq_save(struct rapl_package *rp) |
2d281d81 | 916 | { |
f14a1396 JP |
917 | if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN)) |
918 | return; | |
919 | ||
323ee64a | 920 | smp_call_function_single(rp->lead_cpu, power_limit_irq_save_cpu, rp, 1); |
f14a1396 JP |
921 | } |
922 | ||
58705069 TG |
923 | /* |
924 | * Restore per package power limit interrupt enable state. Called from cpu | |
925 | * hotplug code on package removal. | |
926 | */ | |
927 | static void package_power_limit_irq_restore(struct rapl_package *rp) | |
f14a1396 | 928 | { |
58705069 TG |
929 | u32 l, h; |
930 | ||
931 | if (!boot_cpu_has(X86_FEATURE_PTS) || !boot_cpu_has(X86_FEATURE_PLN)) | |
932 | return; | |
933 | ||
934 | /* irq enable state not saved, nothing to restore */ | |
935 | if (!(rp->power_limit_irq & PACKAGE_PLN_INT_SAVED)) | |
936 | return; | |
f14a1396 JP |
937 | |
938 | rdmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, &l, &h); | |
939 | ||
940 | if (rp->power_limit_irq & PACKAGE_THERM_INT_PLN_ENABLE) | |
941 | l |= PACKAGE_THERM_INT_PLN_ENABLE; | |
942 | else | |
943 | l &= ~PACKAGE_THERM_INT_PLN_ENABLE; | |
944 | ||
945 | wrmsr_safe(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h); | |
2d281d81 JP |
946 | } |
947 | ||
3c2c0845 JP |
948 | static void set_floor_freq_default(struct rapl_domain *rd, bool mode) |
949 | { | |
950 | int nr_powerlimit = find_nr_power_limit(rd); | |
951 | ||
952 | /* always enable clamp such that p-state can go below OS requested | |
953 | * range. power capping priority over guranteed frequency. | |
954 | */ | |
955 | rapl_write_data_raw(rd, PL1_CLAMP, mode); | |
956 | ||
957 | /* some domains have pl2 */ | |
958 | if (nr_powerlimit > 1) { | |
959 | rapl_write_data_raw(rd, PL2_ENABLE, mode); | |
960 | rapl_write_data_raw(rd, PL2_CLAMP, mode); | |
961 | } | |
962 | } | |
963 | ||
964 | static void set_floor_freq_atom(struct rapl_domain *rd, bool enable) | |
965 | { | |
966 | static u32 power_ctrl_orig_val; | |
e8e28c2a | 967 | struct rapl_defaults *defaults = get_defaults(rd->rp); |
3c2c0845 JP |
968 | u32 mdata; |
969 | ||
e8e28c2a | 970 | if (!defaults->floor_freq_reg_addr) { |
51b63409 AT |
971 | pr_err("Invalid floor frequency config register\n"); |
972 | return; | |
973 | } | |
974 | ||
3c2c0845 | 975 | if (!power_ctrl_orig_val) |
4077a387 | 976 | iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_CR_READ, |
e8e28c2a | 977 | defaults->floor_freq_reg_addr, |
4077a387 | 978 | &power_ctrl_orig_val); |
3c2c0845 JP |
979 | mdata = power_ctrl_orig_val; |
980 | if (enable) { | |
981 | mdata &= ~(0x7f << 8); | |
982 | mdata |= 1 << 8; | |
983 | } | |
4077a387 | 984 | iosf_mbi_write(BT_MBI_UNIT_PMC, MBI_CR_WRITE, |
e8e28c2a | 985 | defaults->floor_freq_reg_addr, mdata); |
3c2c0845 JP |
986 | } |
987 | ||
cb532e72 | 988 | static u64 rapl_compute_time_window_core(struct rapl_domain *rd, u64 value, |
3382388d | 989 | bool to_raw) |
3c2c0845 | 990 | { |
3382388d | 991 | u64 f, y; /* fraction and exp. used for time unit */ |
3c2c0845 JP |
992 | |
993 | /* | |
994 | * Special processing based on 2^Y*(1+F/4), refer | |
995 | * to Intel Software Developer's manual Vol.3B: CH 14.9.3. | |
996 | */ | |
997 | if (!to_raw) { | |
998 | f = (value & 0x60) >> 5; | |
999 | y = value & 0x1f; | |
cb532e72 | 1000 | value = (1 << y) * (4 + f) * rd->time_unit / 4; |
3c2c0845 | 1001 | } else { |
cb532e72 | 1002 | if (value < rd->time_unit) |
2d935400 CQ |
1003 | return 0; |
1004 | ||
cb532e72 | 1005 | do_div(value, rd->time_unit); |
3c2c0845 | 1006 | y = ilog2(value); |
cf835b00 ZR |
1007 | |
1008 | /* | |
1009 | * The target hardware field is 7 bits wide, so return all ones | |
1010 | * if the exponent is too large. | |
1011 | */ | |
1012 | if (y > 0x1f) | |
1013 | return 0x7f; | |
1014 | ||
1015 | f = div64_u64(4 * (value - (1ULL << y)), 1ULL << y); | |
3c2c0845 JP |
1016 | value = (y & 0x1f) | ((f & 0x3) << 5); |
1017 | } | |
1018 | return value; | |
1019 | } | |
1020 | ||
cb532e72 | 1021 | static u64 rapl_compute_time_window_atom(struct rapl_domain *rd, u64 value, |
3382388d | 1022 | bool to_raw) |
3c2c0845 JP |
1023 | { |
1024 | /* | |
1025 | * Atom time unit encoding is straight forward val * time_unit, | |
1026 | * where time_unit is default to 1 sec. Never 0. | |
1027 | */ | |
1028 | if (!to_raw) | |
cb532e72 | 1029 | return (value) ? value * rd->time_unit : rd->time_unit; |
3382388d | 1030 | |
cb532e72 | 1031 | value = div64_u64(value, rd->time_unit); |
3c2c0845 JP |
1032 | |
1033 | return value; | |
1034 | } | |
1035 | ||
087e9cba | 1036 | static const struct rapl_defaults rapl_defaults_core = { |
51b63409 | 1037 | .floor_freq_reg_addr = 0, |
3c2c0845 JP |
1038 | .check_unit = rapl_check_unit_core, |
1039 | .set_floor_freq = set_floor_freq_default, | |
1040 | .compute_time_window = rapl_compute_time_window_core, | |
087e9cba JP |
1041 | }; |
1042 | ||
d474a4d3 JP |
1043 | static const struct rapl_defaults rapl_defaults_hsw_server = { |
1044 | .check_unit = rapl_check_unit_core, | |
1045 | .set_floor_freq = set_floor_freq_default, | |
1046 | .compute_time_window = rapl_compute_time_window_core, | |
1047 | .dram_domain_energy_unit = 15300, | |
1048 | }; | |
1049 | ||
2d798d9f ZR |
1050 | static const struct rapl_defaults rapl_defaults_spr_server = { |
1051 | .check_unit = rapl_check_unit_core, | |
1052 | .set_floor_freq = set_floor_freq_default, | |
1053 | .compute_time_window = rapl_compute_time_window_core, | |
2d798d9f | 1054 | .psys_domain_energy_unit = 1000000000, |
931da6a0 | 1055 | .spr_psys_bits = true, |
2d798d9f ZR |
1056 | }; |
1057 | ||
51b63409 AT |
1058 | static const struct rapl_defaults rapl_defaults_byt = { |
1059 | .floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_BYT, | |
1060 | .check_unit = rapl_check_unit_atom, | |
1061 | .set_floor_freq = set_floor_freq_atom, | |
1062 | .compute_time_window = rapl_compute_time_window_atom, | |
1063 | }; | |
1064 | ||
1065 | static const struct rapl_defaults rapl_defaults_tng = { | |
1066 | .floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_TNG, | |
3c2c0845 JP |
1067 | .check_unit = rapl_check_unit_atom, |
1068 | .set_floor_freq = set_floor_freq_atom, | |
1069 | .compute_time_window = rapl_compute_time_window_atom, | |
087e9cba JP |
1070 | }; |
1071 | ||
51b63409 AT |
1072 | static const struct rapl_defaults rapl_defaults_ann = { |
1073 | .floor_freq_reg_addr = 0, | |
1074 | .check_unit = rapl_check_unit_atom, | |
1075 | .set_floor_freq = NULL, | |
1076 | .compute_time_window = rapl_compute_time_window_atom, | |
1077 | }; | |
1078 | ||
1079 | static const struct rapl_defaults rapl_defaults_cht = { | |
1080 | .floor_freq_reg_addr = 0, | |
1081 | .check_unit = rapl_check_unit_atom, | |
1082 | .set_floor_freq = NULL, | |
1083 | .compute_time_window = rapl_compute_time_window_atom, | |
1084 | }; | |
1085 | ||
43756a29 VD |
1086 | static const struct rapl_defaults rapl_defaults_amd = { |
1087 | .check_unit = rapl_check_unit_core, | |
1088 | }; | |
1089 | ||
ea85dbca | 1090 | static const struct x86_cpu_id rapl_ids[] __initconst = { |
f0722512 TG |
1091 | X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE, &rapl_defaults_core), |
1092 | X86_MATCH_INTEL_FAM6_MODEL(SANDYBRIDGE_X, &rapl_defaults_core), | |
1093 | ||
1094 | X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE, &rapl_defaults_core), | |
1095 | X86_MATCH_INTEL_FAM6_MODEL(IVYBRIDGE_X, &rapl_defaults_core), | |
1096 | ||
1097 | X86_MATCH_INTEL_FAM6_MODEL(HASWELL, &rapl_defaults_core), | |
1098 | X86_MATCH_INTEL_FAM6_MODEL(HASWELL_L, &rapl_defaults_core), | |
1099 | X86_MATCH_INTEL_FAM6_MODEL(HASWELL_G, &rapl_defaults_core), | |
1100 | X86_MATCH_INTEL_FAM6_MODEL(HASWELL_X, &rapl_defaults_hsw_server), | |
1101 | ||
1102 | X86_MATCH_INTEL_FAM6_MODEL(BROADWELL, &rapl_defaults_core), | |
1103 | X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_G, &rapl_defaults_core), | |
1104 | X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_D, &rapl_defaults_core), | |
1105 | X86_MATCH_INTEL_FAM6_MODEL(BROADWELL_X, &rapl_defaults_hsw_server), | |
1106 | ||
1107 | X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, &rapl_defaults_core), | |
1108 | X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, &rapl_defaults_core), | |
1109 | X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &rapl_defaults_hsw_server), | |
1110 | X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, &rapl_defaults_core), | |
1111 | X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &rapl_defaults_core), | |
1112 | X86_MATCH_INTEL_FAM6_MODEL(CANNONLAKE_L, &rapl_defaults_core), | |
1113 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_L, &rapl_defaults_core), | |
1114 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE, &rapl_defaults_core), | |
1115 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_NNPI, &rapl_defaults_core), | |
1116 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &rapl_defaults_hsw_server), | |
1117 | X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &rapl_defaults_hsw_server), | |
1118 | X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &rapl_defaults_core), | |
1119 | X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &rapl_defaults_core), | |
1120 | X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &rapl_defaults_core), | |
57a2fb06 | 1121 | X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &rapl_defaults_core), |
64e5f367 | 1122 | X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &rapl_defaults_core), |
ba92a420 | 1123 | X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &rapl_defaults_core), |
cca26b66 | 1124 | X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &rapl_defaults_core), |
f125bdbd | 1125 | X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &rapl_defaults_core), |
ae0dc7ed | 1126 | X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &rapl_defaults_core), |
27557146 | 1127 | X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &rapl_defaults_core), |
0d7a23b5 | 1128 | X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, &rapl_defaults_core), |
bdaad038 ZR |
1129 | X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, &rapl_defaults_core), |
1130 | X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, &rapl_defaults_core), | |
2d798d9f | 1131 | X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server), |
7adc6885 | 1132 | X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, &rapl_defaults_spr_server), |
e1c2d96c | 1133 | X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD, &rapl_defaults_core), |
f0722512 TG |
1134 | |
1135 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, &rapl_defaults_byt), | |
1136 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, &rapl_defaults_cht), | |
1137 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_MID, &rapl_defaults_tng), | |
1138 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT_MID, &rapl_defaults_ann), | |
1139 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &rapl_defaults_core), | |
1140 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_PLUS, &rapl_defaults_core), | |
1141 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, &rapl_defaults_core), | |
33c98003 | 1142 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT, &rapl_defaults_core), |
f0722512 TG |
1143 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_D, &rapl_defaults_core), |
1144 | X86_MATCH_INTEL_FAM6_MODEL(ATOM_TREMONT_L, &rapl_defaults_core), | |
1145 | ||
1146 | X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &rapl_defaults_hsw_server), | |
1147 | X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &rapl_defaults_hsw_server), | |
43756a29 VD |
1148 | |
1149 | X86_MATCH_VENDOR_FAM(AMD, 0x17, &rapl_defaults_amd), | |
8a9d881f | 1150 | X86_MATCH_VENDOR_FAM(AMD, 0x19, &rapl_defaults_amd), |
a7405612 | 1151 | X86_MATCH_VENDOR_FAM(HYGON, 0x18, &rapl_defaults_amd), |
2d281d81 JP |
1152 | {} |
1153 | }; | |
1154 | MODULE_DEVICE_TABLE(x86cpu, rapl_ids); | |
1155 | ||
bed5ab63 TG |
1156 | /* Read once for all raw primitive data for domains */ |
1157 | static void rapl_update_domain_data(struct rapl_package *rp) | |
2d281d81 JP |
1158 | { |
1159 | int dmn, prim; | |
1160 | u64 val; | |
2d281d81 | 1161 | |
bed5ab63 | 1162 | for (dmn = 0; dmn < rp->nr_domains; dmn++) { |
9ea7612c | 1163 | pr_debug("update %s domain %s data\n", rp->name, |
bed5ab63 TG |
1164 | rp->domains[dmn].name); |
1165 | /* exclude non-raw primitives */ | |
1166 | for (prim = 0; prim < NR_RAW_PRIMITIVES; prim++) { | |
98ff639a ZR |
1167 | struct rapl_primitive_info *rpi = get_rpi(rp, prim); |
1168 | ||
bed5ab63 | 1169 | if (!rapl_read_data_raw(&rp->domains[dmn], prim, |
98ff639a | 1170 | rpi->unit, &val)) |
3382388d | 1171 | rp->domains[dmn].rdd.primitives[prim] = val; |
2d281d81 JP |
1172 | } |
1173 | } | |
1174 | ||
1175 | } | |
1176 | ||
2d281d81 JP |
1177 | static int rapl_package_register_powercap(struct rapl_package *rp) |
1178 | { | |
1179 | struct rapl_domain *rd; | |
2d281d81 | 1180 | struct powercap_zone *power_zone = NULL; |
01857cf7 | 1181 | int nr_pl, ret; |
bed5ab63 TG |
1182 | |
1183 | /* Update the domain data of the new package */ | |
1184 | rapl_update_domain_data(rp); | |
2d281d81 | 1185 | |
3382388d | 1186 | /* first we register package domain as the parent zone */ |
2d281d81 JP |
1187 | for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { |
1188 | if (rd->id == RAPL_DOMAIN_PACKAGE) { | |
1189 | nr_pl = find_nr_power_limit(rd); | |
9ea7612c | 1190 | pr_debug("register package domain %s\n", rp->name); |
2d281d81 | 1191 | power_zone = powercap_register_zone(&rd->power_zone, |
3382388d ZR |
1192 | rp->priv->control_type, rp->name, |
1193 | NULL, &zone_ops[rd->id], nr_pl, | |
1194 | &constraint_ops); | |
2d281d81 | 1195 | if (IS_ERR(power_zone)) { |
9ea7612c | 1196 | pr_debug("failed to register power zone %s\n", |
3382388d | 1197 | rp->name); |
bed5ab63 | 1198 | return PTR_ERR(power_zone); |
2d281d81 JP |
1199 | } |
1200 | /* track parent zone in per package/socket data */ | |
1201 | rp->power_zone = power_zone; | |
1202 | /* done, only one package domain per socket */ | |
1203 | break; | |
1204 | } | |
1205 | } | |
1206 | if (!power_zone) { | |
1207 | pr_err("no package domain found, unknown topology!\n"); | |
bed5ab63 | 1208 | return -ENODEV; |
2d281d81 | 1209 | } |
3382388d | 1210 | /* now register domains as children of the socket/package */ |
2d281d81 | 1211 | for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { |
f1e8d756 ZR |
1212 | struct powercap_zone *parent = rp->power_zone; |
1213 | ||
2d281d81 JP |
1214 | if (rd->id == RAPL_DOMAIN_PACKAGE) |
1215 | continue; | |
f1e8d756 ZR |
1216 | if (rd->id == RAPL_DOMAIN_PLATFORM) |
1217 | parent = NULL; | |
2d281d81 JP |
1218 | /* number of power limits per domain varies */ |
1219 | nr_pl = find_nr_power_limit(rd); | |
1220 | power_zone = powercap_register_zone(&rd->power_zone, | |
3382388d | 1221 | rp->priv->control_type, |
f1e8d756 | 1222 | rd->name, parent, |
3382388d ZR |
1223 | &zone_ops[rd->id], nr_pl, |
1224 | &constraint_ops); | |
2d281d81 JP |
1225 | |
1226 | if (IS_ERR(power_zone)) { | |
9ea7612c | 1227 | pr_debug("failed to register power_zone, %s:%s\n", |
3382388d | 1228 | rp->name, rd->name); |
2d281d81 JP |
1229 | ret = PTR_ERR(power_zone); |
1230 | goto err_cleanup; | |
1231 | } | |
1232 | } | |
bed5ab63 | 1233 | return 0; |
2d281d81 | 1234 | |
2d281d81 | 1235 | err_cleanup: |
58705069 TG |
1236 | /* |
1237 | * Clean up previously initialized domains within the package if we | |
2d281d81 JP |
1238 | * failed after the first domain setup. |
1239 | */ | |
1240 | while (--rd >= rp->domains) { | |
9ea7612c | 1241 | pr_debug("unregister %s domain %s\n", rp->name, rd->name); |
3382388d ZR |
1242 | powercap_unregister_zone(rp->priv->control_type, |
1243 | &rd->power_zone); | |
2d281d81 JP |
1244 | } |
1245 | ||
1246 | return ret; | |
1247 | } | |
1248 | ||
7fde2712 | 1249 | static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp) |
2d281d81 | 1250 | { |
1193b165 | 1251 | struct reg_action ra; |
2d281d81 JP |
1252 | |
1253 | switch (domain) { | |
1254 | case RAPL_DOMAIN_PACKAGE: | |
2d281d81 | 1255 | case RAPL_DOMAIN_PP0: |
2d281d81 | 1256 | case RAPL_DOMAIN_PP1: |
2d281d81 | 1257 | case RAPL_DOMAIN_DRAM: |
f1e8d756 | 1258 | case RAPL_DOMAIN_PLATFORM: |
1193b165 | 1259 | ra.reg = rp->priv->regs[domain][RAPL_DOMAIN_REG_STATUS]; |
2d281d81 JP |
1260 | break; |
1261 | default: | |
1262 | pr_err("invalid domain id %d\n", domain); | |
1263 | return -EINVAL; | |
1264 | } | |
9d31c676 JP |
1265 | /* make sure domain counters are available and contains non-zero |
1266 | * values, otherwise skip it. | |
7b874772 | 1267 | */ |
1193b165 | 1268 | |
7a57e9f1 | 1269 | ra.mask = ENERGY_STATUS_MASK; |
1193b165 | 1270 | if (rp->priv->read_raw(cpu, &ra) || !ra.value) |
9d31c676 | 1271 | return -ENODEV; |
2d281d81 | 1272 | |
9d31c676 | 1273 | return 0; |
2d281d81 JP |
1274 | } |
1275 | ||
cb532e72 ZR |
1276 | /* |
1277 | * Get per domain energy/power/time unit. | |
1278 | * RAPL Interfaces without per domain unit register will use the package | |
1279 | * scope unit register to set per domain units. | |
1280 | */ | |
1281 | static int rapl_get_domain_unit(struct rapl_domain *rd) | |
1282 | { | |
1283 | struct rapl_defaults *defaults = get_defaults(rd->rp); | |
1284 | int ret; | |
1285 | ||
1286 | if (!rd->regs[RAPL_DOMAIN_REG_UNIT]) { | |
1287 | if (!rd->rp->priv->reg_unit) { | |
1288 | pr_err("No valid Unit register found\n"); | |
1289 | return -ENODEV; | |
1290 | } | |
1291 | rd->regs[RAPL_DOMAIN_REG_UNIT] = rd->rp->priv->reg_unit; | |
1292 | } | |
1293 | ||
1294 | if (!defaults->check_unit) { | |
1295 | pr_err("missing .check_unit() callback\n"); | |
1296 | return -ENODEV; | |
1297 | } | |
1298 | ||
1299 | ret = defaults->check_unit(rd, rd->rp->lead_cpu); | |
1300 | if (ret) | |
1301 | return ret; | |
1302 | ||
1303 | if (rd->id == RAPL_DOMAIN_DRAM && defaults->dram_domain_energy_unit) | |
1304 | rd->energy_unit = defaults->dram_domain_energy_unit; | |
1305 | if (rd->id == RAPL_DOMAIN_PLATFORM && defaults->psys_domain_energy_unit) | |
1306 | rd->energy_unit = defaults->psys_domain_energy_unit; | |
1307 | return 0; | |
1308 | } | |
1309 | ||
e1399ba2 JP |
1310 | /* |
1311 | * Check if power limits are available. Two cases when they are not available: | |
1312 | * 1. Locked by BIOS, in this case we still provide read-only access so that | |
1313 | * users can see what limit is set by the BIOS. | |
1314 | * 2. Some CPUs make some domains monitoring only which means PLx MSRs may not | |
3382388d | 1315 | * exist at all. In this case, we do not show the constraints in powercap. |
e1399ba2 JP |
1316 | * |
1317 | * Called after domains are detected and initialized. | |
1318 | */ | |
1319 | static void rapl_detect_powerlimit(struct rapl_domain *rd) | |
1320 | { | |
1321 | u64 val64; | |
1322 | int i; | |
1323 | ||
1324 | /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */ | |
1325 | if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) { | |
1326 | if (val64) { | |
9ea7612c ZR |
1327 | pr_info("RAPL %s domain %s locked by BIOS\n", |
1328 | rd->rp->name, rd->name); | |
e1399ba2 JP |
1329 | rd->state |= DOMAIN_STATE_BIOS_LOCKED; |
1330 | } | |
1331 | } | |
3382388d | 1332 | /* check if power limit MSR exists, otherwise domain is monitoring only */ |
e1399ba2 JP |
1333 | for (i = 0; i < NR_POWER_LIMITS; i++) { |
1334 | int prim = rd->rpl[i].prim_id; | |
3382388d | 1335 | |
e1399ba2 JP |
1336 | if (rapl_read_data_raw(rd, prim, false, &val64)) |
1337 | rd->rpl[i].name = NULL; | |
1338 | } | |
1339 | } | |
1340 | ||
2d281d81 JP |
1341 | /* Detect active and valid domains for the given CPU, caller must |
1342 | * ensure the CPU belongs to the targeted package and CPU hotlug is disabled. | |
1343 | */ | |
1344 | static int rapl_detect_domains(struct rapl_package *rp, int cpu) | |
1345 | { | |
2d281d81 | 1346 | struct rapl_domain *rd; |
58705069 | 1347 | int i; |
2d281d81 JP |
1348 | |
1349 | for (i = 0; i < RAPL_DOMAIN_MAX; i++) { | |
1350 | /* use physical package id to read counters */ | |
7fde2712 | 1351 | if (!rapl_check_domain(cpu, i, rp)) { |
2d281d81 | 1352 | rp->domain_map |= 1 << i; |
fcdf1797 JP |
1353 | pr_info("Found RAPL domain %s\n", rapl_domain_names[i]); |
1354 | } | |
2d281d81 | 1355 | } |
3382388d | 1356 | rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX); |
2d281d81 | 1357 | if (!rp->nr_domains) { |
9ea7612c | 1358 | pr_debug("no valid rapl domains found in %s\n", rp->name); |
58705069 | 1359 | return -ENODEV; |
2d281d81 | 1360 | } |
9ea7612c | 1361 | pr_debug("found %d domains on %s\n", rp->nr_domains, rp->name); |
2d281d81 JP |
1362 | |
1363 | rp->domains = kcalloc(rp->nr_domains + 1, sizeof(struct rapl_domain), | |
3382388d | 1364 | GFP_KERNEL); |
58705069 TG |
1365 | if (!rp->domains) |
1366 | return -ENOMEM; | |
1367 | ||
2d281d81 JP |
1368 | rapl_init_domains(rp); |
1369 | ||
cb532e72 ZR |
1370 | for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { |
1371 | rapl_get_domain_unit(rd); | |
e1399ba2 | 1372 | rapl_detect_powerlimit(rd); |
cb532e72 | 1373 | } |
e1399ba2 | 1374 | |
2d281d81 JP |
1375 | return 0; |
1376 | } | |
1377 | ||
1378 | /* called from CPU hotplug notifier, hotplug lock held */ | |
3382388d | 1379 | void rapl_remove_package(struct rapl_package *rp) |
2d281d81 JP |
1380 | { |
1381 | struct rapl_domain *rd, *rd_package = NULL; | |
1382 | ||
58705069 TG |
1383 | package_power_limit_irq_restore(rp); |
1384 | ||
2d281d81 | 1385 | for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { |
58705069 TG |
1386 | rapl_write_data_raw(rd, PL1_ENABLE, 0); |
1387 | rapl_write_data_raw(rd, PL1_CLAMP, 0); | |
1388 | if (find_nr_power_limit(rd) > 1) { | |
1389 | rapl_write_data_raw(rd, PL2_ENABLE, 0); | |
1390 | rapl_write_data_raw(rd, PL2_CLAMP, 0); | |
8365a898 | 1391 | rapl_write_data_raw(rd, PL4_ENABLE, 0); |
58705069 | 1392 | } |
2d281d81 JP |
1393 | if (rd->id == RAPL_DOMAIN_PACKAGE) { |
1394 | rd_package = rd; | |
1395 | continue; | |
1396 | } | |
9ea7612c ZR |
1397 | pr_debug("remove package, undo power limit on %s: %s\n", |
1398 | rp->name, rd->name); | |
3382388d ZR |
1399 | powercap_unregister_zone(rp->priv->control_type, |
1400 | &rd->power_zone); | |
2d281d81 JP |
1401 | } |
1402 | /* do parent zone last */ | |
3382388d ZR |
1403 | powercap_unregister_zone(rp->priv->control_type, |
1404 | &rd_package->power_zone); | |
2d281d81 JP |
1405 | list_del(&rp->plist); |
1406 | kfree(rp); | |
1407 | } | |
3382388d ZR |
1408 | EXPORT_SYMBOL_GPL(rapl_remove_package); |
1409 | ||
1410 | /* caller to ensure CPU hotplug lock is held */ | |
1411 | struct rapl_package *rapl_find_package_domain(int cpu, struct rapl_if_priv *priv) | |
1412 | { | |
1413 | int id = topology_logical_die_id(cpu); | |
1414 | struct rapl_package *rp; | |
1415 | ||
1416 | list_for_each_entry(rp, &rapl_packages, plist) { | |
1417 | if (rp->id == id | |
1418 | && rp->priv->control_type == priv->control_type) | |
1419 | return rp; | |
1420 | } | |
1421 | ||
1422 | return NULL; | |
1423 | } | |
1424 | EXPORT_SYMBOL_GPL(rapl_find_package_domain); | |
2d281d81 JP |
1425 | |
1426 | /* called from CPU hotplug notifier, hotplug lock held */ | |
3382388d | 1427 | struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv) |
2d281d81 | 1428 | { |
32fb480e | 1429 | int id = topology_logical_die_id(cpu); |
2d281d81 | 1430 | struct rapl_package *rp; |
b4005e92 | 1431 | int ret; |
2d281d81 | 1432 | |
2d281d81 JP |
1433 | rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL); |
1434 | if (!rp) | |
b4005e92 | 1435 | return ERR_PTR(-ENOMEM); |
2d281d81 JP |
1436 | |
1437 | /* add the new package to the list */ | |
aadf7b38 | 1438 | rp->id = id; |
323ee64a | 1439 | rp->lead_cpu = cpu; |
7ebf8eff | 1440 | rp->priv = priv; |
323ee64a | 1441 | |
e8e28c2a ZR |
1442 | ret = rapl_config(rp); |
1443 | if (ret) | |
1444 | goto err_free_package; | |
1445 | ||
9ea7612c ZR |
1446 | if (topology_max_die_per_package() > 1) |
1447 | snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, | |
88ffce95 YY |
1448 | "package-%d-die-%d", |
1449 | topology_physical_package_id(cpu), topology_die_id(cpu)); | |
9ea7612c ZR |
1450 | else |
1451 | snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d", | |
88ffce95 | 1452 | topology_physical_package_id(cpu)); |
9ea7612c | 1453 | |
2d281d81 | 1454 | /* check if the package contains valid domains */ |
cb532e72 | 1455 | if (rapl_detect_domains(rp, cpu)) { |
2d281d81 JP |
1456 | ret = -ENODEV; |
1457 | goto err_free_package; | |
1458 | } | |
a74f4367 TG |
1459 | ret = rapl_package_register_powercap(rp); |
1460 | if (!ret) { | |
2d281d81 JP |
1461 | INIT_LIST_HEAD(&rp->plist); |
1462 | list_add(&rp->plist, &rapl_packages); | |
b4005e92 | 1463 | return rp; |
2d281d81 JP |
1464 | } |
1465 | ||
1466 | err_free_package: | |
1467 | kfree(rp->domains); | |
1468 | kfree(rp); | |
b4005e92 | 1469 | return ERR_PTR(ret); |
2d281d81 | 1470 | } |
3382388d | 1471 | EXPORT_SYMBOL_GPL(rapl_add_package); |
2d281d81 | 1472 | |
52b3672c ZH |
1473 | static void power_limit_state_save(void) |
1474 | { | |
1475 | struct rapl_package *rp; | |
1476 | struct rapl_domain *rd; | |
1477 | int nr_pl, ret, i; | |
1478 | ||
5d4c779c | 1479 | cpus_read_lock(); |
52b3672c ZH |
1480 | list_for_each_entry(rp, &rapl_packages, plist) { |
1481 | if (!rp->power_zone) | |
1482 | continue; | |
1483 | rd = power_zone_to_rapl_domain(rp->power_zone); | |
1484 | nr_pl = find_nr_power_limit(rd); | |
1485 | for (i = 0; i < nr_pl; i++) { | |
1486 | switch (rd->rpl[i].prim_id) { | |
1487 | case PL1_ENABLE: | |
1488 | ret = rapl_read_data_raw(rd, | |
3382388d ZR |
1489 | POWER_LIMIT1, true, |
1490 | &rd->rpl[i].last_power_limit); | |
52b3672c ZH |
1491 | if (ret) |
1492 | rd->rpl[i].last_power_limit = 0; | |
1493 | break; | |
1494 | case PL2_ENABLE: | |
1495 | ret = rapl_read_data_raw(rd, | |
3382388d ZR |
1496 | POWER_LIMIT2, true, |
1497 | &rd->rpl[i].last_power_limit); | |
52b3672c ZH |
1498 | if (ret) |
1499 | rd->rpl[i].last_power_limit = 0; | |
1500 | break; | |
8365a898 SP |
1501 | case PL4_ENABLE: |
1502 | ret = rapl_read_data_raw(rd, | |
1503 | POWER_LIMIT4, true, | |
1504 | &rd->rpl[i].last_power_limit); | |
1505 | if (ret) | |
1506 | rd->rpl[i].last_power_limit = 0; | |
1507 | break; | |
52b3672c ZH |
1508 | } |
1509 | } | |
1510 | } | |
5d4c779c | 1511 | cpus_read_unlock(); |
52b3672c ZH |
1512 | } |
1513 | ||
1514 | static void power_limit_state_restore(void) | |
1515 | { | |
1516 | struct rapl_package *rp; | |
1517 | struct rapl_domain *rd; | |
1518 | int nr_pl, i; | |
1519 | ||
5d4c779c | 1520 | cpus_read_lock(); |
52b3672c ZH |
1521 | list_for_each_entry(rp, &rapl_packages, plist) { |
1522 | if (!rp->power_zone) | |
1523 | continue; | |
1524 | rd = power_zone_to_rapl_domain(rp->power_zone); | |
1525 | nr_pl = find_nr_power_limit(rd); | |
1526 | for (i = 0; i < nr_pl; i++) { | |
1527 | switch (rd->rpl[i].prim_id) { | |
1528 | case PL1_ENABLE: | |
1529 | if (rd->rpl[i].last_power_limit) | |
3382388d ZR |
1530 | rapl_write_data_raw(rd, POWER_LIMIT1, |
1531 | rd->rpl[i].last_power_limit); | |
52b3672c ZH |
1532 | break; |
1533 | case PL2_ENABLE: | |
1534 | if (rd->rpl[i].last_power_limit) | |
3382388d ZR |
1535 | rapl_write_data_raw(rd, POWER_LIMIT2, |
1536 | rd->rpl[i].last_power_limit); | |
52b3672c | 1537 | break; |
8365a898 SP |
1538 | case PL4_ENABLE: |
1539 | if (rd->rpl[i].last_power_limit) | |
1540 | rapl_write_data_raw(rd, POWER_LIMIT4, | |
1541 | rd->rpl[i].last_power_limit); | |
1542 | break; | |
52b3672c ZH |
1543 | } |
1544 | } | |
1545 | } | |
5d4c779c | 1546 | cpus_read_unlock(); |
52b3672c ZH |
1547 | } |
1548 | ||
1549 | static int rapl_pm_callback(struct notifier_block *nb, | |
3382388d | 1550 | unsigned long mode, void *_unused) |
52b3672c ZH |
1551 | { |
1552 | switch (mode) { | |
1553 | case PM_SUSPEND_PREPARE: | |
1554 | power_limit_state_save(); | |
1555 | break; | |
1556 | case PM_POST_SUSPEND: | |
1557 | power_limit_state_restore(); | |
1558 | break; | |
1559 | } | |
1560 | return NOTIFY_OK; | |
1561 | } | |
1562 | ||
1563 | static struct notifier_block rapl_pm_notifier = { | |
1564 | .notifier_call = rapl_pm_callback, | |
1565 | }; | |
1566 | ||
abcfaeb3 ZR |
1567 | static struct platform_device *rapl_msr_platdev; |
1568 | ||
1569 | static int __init rapl_init(void) | |
2d281d81 | 1570 | { |
087e9cba | 1571 | const struct x86_cpu_id *id; |
58705069 | 1572 | int ret; |
2d281d81 | 1573 | |
087e9cba | 1574 | id = x86_match_cpu(rapl_ids); |
1488ac99 ZR |
1575 | if (id) { |
1576 | rapl_defaults = (struct rapl_defaults *)id->driver_data; | |
2d281d81 | 1577 | |
1488ac99 ZR |
1578 | rapl_msr_platdev = platform_device_alloc("intel_rapl_msr", 0); |
1579 | if (!rapl_msr_platdev) | |
1580 | return -ENOMEM; | |
52b3672c | 1581 | |
1488ac99 ZR |
1582 | ret = platform_device_add(rapl_msr_platdev); |
1583 | if (ret) { | |
1584 | platform_device_put(rapl_msr_platdev); | |
1585 | return ret; | |
1586 | } | |
abcfaeb3 ZR |
1587 | } |
1588 | ||
1488ac99 ZR |
1589 | ret = register_pm_notifier(&rapl_pm_notifier); |
1590 | if (ret && rapl_msr_platdev) { | |
1591 | platform_device_del(rapl_msr_platdev); | |
abcfaeb3 | 1592 | platform_device_put(rapl_msr_platdev); |
1488ac99 | 1593 | } |
abcfaeb3 ZR |
1594 | |
1595 | return ret; | |
2d281d81 JP |
1596 | } |
1597 | ||
abcfaeb3 | 1598 | static void __exit rapl_exit(void) |
2d281d81 | 1599 | { |
abcfaeb3 | 1600 | platform_device_unregister(rapl_msr_platdev); |
52b3672c | 1601 | unregister_pm_notifier(&rapl_pm_notifier); |
2d281d81 JP |
1602 | } |
1603 | ||
f76cb066 | 1604 | fs_initcall(rapl_init); |
abcfaeb3 ZR |
1605 | module_exit(rapl_exit); |
1606 | ||
3382388d | 1607 | MODULE_DESCRIPTION("Intel Runtime Average Power Limit (RAPL) common code"); |
2d281d81 JP |
1608 | MODULE_AUTHOR("Jacob Pan <[email protected]>"); |
1609 | MODULE_LICENSE("GPL v2"); |