Skip to content

Commit 8365a89

Browse files
sumeetpawnikarrafaeljw
authored andcommitted
powercap: Add Power Limit4 support
Modern Intel Mobile platforms support power limit4 (PL4), which is the SoC package level maximum power limit (in Watts). It can be used to preemptively limits potential SoC power to prevent power spikes from tripping the power adapter and battery over-current protection. This patch enables this feature by exposing package level peak power capping control to userspace via RAPL sysfs interface. With this, application like DTPF can modify PL4 power limit, the similar way of other package power limit (PL1). As this feature is not tested on previous generations, here it is enabled only for the platform that has been verified to work, for safety concerns. Signed-off-by: Sumeet Pawnikar <[email protected]> Co-developed-by: Zhang Rui <[email protected]> Signed-off-by: Zhang Rui <[email protected]> Reviewed-by: Srinivas Pandruvada <[email protected]> Tested-by: Srinivas Pandruvada <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 0735069 commit 8365a89

File tree

4 files changed

+81
-8
lines changed

4 files changed

+81
-8
lines changed

Documentation/power/powercap/powercap.rst

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,13 @@ For example::
167167
package-0
168168
---------
169169

170-
The Intel RAPL technology allows two constraints, short term and long term,
171-
with two different time windows to be applied to each power zone. Thus for
172-
each zone there are 2 attributes representing the constraint names, 2 power
173-
limits and 2 attributes representing the sizes of the time windows. Such that,
174-
constraint_j_* attributes correspond to the jth constraint (j = 0,1).
170+
Depending on different power zones, the Intel RAPL technology allows
171+
one or multiple constraints like short term, long term and peak power,
172+
with different time windows to be applied to each power zone.
173+
All the zones contain attributes representing the constraint names,
174+
power limits and the sizes of the time windows. Note that time window
175+
is not applicable to peak power. Here, constraint_j_* attributes
176+
correspond to the jth constraint (j = 0,1,2).
175177

176178
For example::
177179

@@ -181,6 +183,9 @@ For example::
181183
constraint_1_name
182184
constraint_1_power_limit_uw
183185
constraint_1_time_window_us
186+
constraint_2_name
187+
constraint_2_power_limit_uw
188+
constraint_2_time_window_us
184189

185190
Power Zone Attributes
186191
=====================

drivers/powercap/intel_rapl_common.c

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
#define POWER_HIGH_LOCK BIT_ULL(63)
4040
#define POWER_LOW_LOCK BIT(31)
4141

42+
#define POWER_LIMIT4_MASK 0x1FFF
43+
4244
#define TIME_WINDOW1_MASK (0x7FULL<<17)
4345
#define TIME_WINDOW2_MASK (0x7FULL<<49)
4446

@@ -82,6 +84,7 @@ enum unit_type {
8284

8385
static const char pl1_name[] = "long_term";
8486
static const char pl2_name[] = "short_term";
87+
static const char pl4_name[] = "peak_power";
8588

8689
#define power_zone_to_rapl_domain(_zone) \
8790
container_of(_zone, struct rapl_domain, power_zone)
@@ -338,6 +341,9 @@ static int set_power_limit(struct powercap_zone *power_zone, int cid,
338341
case PL2_ENABLE:
339342
rapl_write_data_raw(rd, POWER_LIMIT2, power_limit);
340343
break;
344+
case PL4_ENABLE:
345+
rapl_write_data_raw(rd, POWER_LIMIT4, power_limit);
346+
break;
341347
default:
342348
ret = -EINVAL;
343349
}
@@ -372,6 +378,9 @@ static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
372378
case PL2_ENABLE:
373379
prim = POWER_LIMIT2;
374380
break;
381+
case PL4_ENABLE:
382+
prim = POWER_LIMIT4;
383+
break;
375384
default:
376385
put_online_cpus();
377386
return -EINVAL;
@@ -441,6 +450,13 @@ static int get_time_window(struct powercap_zone *power_zone, int cid,
441450
case PL2_ENABLE:
442451
ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val);
443452
break;
453+
case PL4_ENABLE:
454+
/*
455+
* Time window parameter is not applicable for PL4 entry
456+
* so assigining '0' as default value.
457+
*/
458+
val = 0;
459+
break;
444460
default:
445461
put_online_cpus();
446462
return -EINVAL;
@@ -484,6 +500,9 @@ static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
484500
case PL2_ENABLE:
485501
prim = MAX_POWER;
486502
break;
503+
case PL4_ENABLE:
504+
prim = MAX_POWER;
505+
break;
487506
default:
488507
put_online_cpus();
489508
return -EINVAL;
@@ -493,6 +512,10 @@ static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
493512
else
494513
*data = val;
495514

515+
/* As a generalization rule, PL4 would be around two times PL2. */
516+
if (rd->rpl[id].prim_id == PL4_ENABLE)
517+
*data = *data * 2;
518+
496519
put_online_cpus();
497520

498521
return ret;
@@ -525,12 +548,22 @@ static void rapl_init_domains(struct rapl_package *rp)
525548
rd->id = i;
526549
rd->rpl[0].prim_id = PL1_ENABLE;
527550
rd->rpl[0].name = pl1_name;
528-
/* some domain may support two power limits */
529-
if (rp->priv->limits[i] == 2) {
551+
552+
/*
553+
* The PL2 power domain is applicable for limits two
554+
* and limits three
555+
*/
556+
if (rp->priv->limits[i] >= 2) {
530557
rd->rpl[1].prim_id = PL2_ENABLE;
531558
rd->rpl[1].name = pl2_name;
532559
}
533560

561+
/* Enable PL4 domain if the total power limits are three */
562+
if (rp->priv->limits[i] == 3) {
563+
rd->rpl[2].prim_id = PL4_ENABLE;
564+
rd->rpl[2].name = pl4_name;
565+
}
566+
534567
for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
535568
rd->regs[j] = rp->priv->regs[i][j];
536569

@@ -599,6 +632,8 @@ static struct rapl_primitive_info rpi[] = {
599632
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
600633
PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
601634
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
635+
PRIMITIVE_INFO_INIT(POWER_LIMIT4, POWER_LIMIT4_MASK, 0,
636+
RAPL_DOMAIN_REG_PL4, POWER_UNIT, 0),
602637
PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
603638
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
604639
PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
@@ -609,6 +644,8 @@ static struct rapl_primitive_info rpi[] = {
609644
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
610645
PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
611646
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
647+
PRIMITIVE_INFO_INIT(PL4_ENABLE, POWER_LIMIT4_MASK, 0,
648+
RAPL_DOMAIN_REG_PL4, ARBITRARY_UNIT, 0),
612649
PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
613650
RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
614651
PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
@@ -1273,6 +1310,7 @@ void rapl_remove_package(struct rapl_package *rp)
12731310
if (find_nr_power_limit(rd) > 1) {
12741311
rapl_write_data_raw(rd, PL2_ENABLE, 0);
12751312
rapl_write_data_raw(rd, PL2_CLAMP, 0);
1313+
rapl_write_data_raw(rd, PL4_ENABLE, 0);
12761314
}
12771315
if (rd->id == RAPL_DOMAIN_PACKAGE) {
12781316
rd_package = rd;
@@ -1381,6 +1419,13 @@ static void power_limit_state_save(void)
13811419
if (ret)
13821420
rd->rpl[i].last_power_limit = 0;
13831421
break;
1422+
case PL4_ENABLE:
1423+
ret = rapl_read_data_raw(rd,
1424+
POWER_LIMIT4, true,
1425+
&rd->rpl[i].last_power_limit);
1426+
if (ret)
1427+
rd->rpl[i].last_power_limit = 0;
1428+
break;
13841429
}
13851430
}
13861431
}
@@ -1411,6 +1456,11 @@ static void power_limit_state_restore(void)
14111456
rapl_write_data_raw(rd, POWER_LIMIT2,
14121457
rd->rpl[i].last_power_limit);
14131458
break;
1459+
case PL4_ENABLE:
1460+
if (rd->rpl[i].last_power_limit)
1461+
rapl_write_data_raw(rd, POWER_LIMIT4,
1462+
rd->rpl[i].last_power_limit);
1463+
break;
14141464
}
14151465
}
14161466
}

drivers/powercap/intel_rapl_msr.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
/* Local defines */
3030
#define MSR_PLATFORM_POWER_LIMIT 0x0000065C
31+
#define MSR_VR_CURRENT_CONFIG 0x00000601
3132

3233
/* private data for RAPL MSR Interface */
3334
static struct rapl_if_priv rapl_msr_priv = {
@@ -123,13 +124,27 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
123124
return ra->err;
124125
}
125126

127+
/* List of verified CPUs. */
128+
static const struct x86_cpu_id pl4_support_ids[] = {
129+
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
130+
{}
131+
};
132+
126133
static int rapl_msr_probe(struct platform_device *pdev)
127134
{
135+
const struct x86_cpu_id *id = x86_match_cpu(pl4_support_ids);
128136
int ret;
129137

130138
rapl_msr_priv.read_raw = rapl_msr_read_raw;
131139
rapl_msr_priv.write_raw = rapl_msr_write_raw;
132140

141+
if (id) {
142+
rapl_msr_priv.limits[RAPL_DOMAIN_PACKAGE] = 3;
143+
rapl_msr_priv.regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4] =
144+
MSR_VR_CURRENT_CONFIG;
145+
pr_info("PL4 support detected.\n");
146+
}
147+
133148
rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
134149
if (IS_ERR(rapl_msr_priv.control_type)) {
135150
pr_debug("failed to register powercap control_type.\n");

include/linux/intel_rapl.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ enum rapl_domain_reg_id {
2929
RAPL_DOMAIN_REG_PERF,
3030
RAPL_DOMAIN_REG_POLICY,
3131
RAPL_DOMAIN_REG_INFO,
32+
RAPL_DOMAIN_REG_PL4,
3233
RAPL_DOMAIN_REG_MAX,
3334
};
3435

@@ -38,12 +39,14 @@ enum rapl_primitives {
3839
ENERGY_COUNTER,
3940
POWER_LIMIT1,
4041
POWER_LIMIT2,
42+
POWER_LIMIT4,
4143
FW_LOCK,
4244

4345
PL1_ENABLE, /* power limit 1, aka long term */
4446
PL1_CLAMP, /* allow frequency to go below OS request */
4547
PL2_ENABLE, /* power limit 2, aka short term, instantaneous */
4648
PL2_CLAMP,
49+
PL4_ENABLE, /* power limit 4, aka max peak power */
4750

4851
TIME_WINDOW1, /* long term */
4952
TIME_WINDOW2, /* short term */
@@ -65,7 +68,7 @@ struct rapl_domain_data {
6568
unsigned long timestamp;
6669
};
6770

68-
#define NR_POWER_LIMITS (2)
71+
#define NR_POWER_LIMITS (3)
6972
struct rapl_power_limit {
7073
struct powercap_zone_constraint *constraint;
7174
int prim_id; /* primitive ID used to enable */

0 commit comments

Comments
 (0)