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