Skip to content

Commit cb532e7

Browse files
zhang-ruirafaeljw
authored andcommitted
powercap: intel_rapl: Support per domain energy/power/time unit
RAPL MSR/MMIO Interface has package scope unit register but some RAPL domains like Dram/Psys may use a fixed energy unit value instead of the default unit value on certain platforms. RAPL TPMI Interface supports per domain unit register. For the above reasons, add support for per domain unit register and per domain energy/power/time unit. When per domain unit register is not available, use the package scope unit register as the per domain unit register for each RAPL domain so that this change is transparent to MSR/MMIO Interface. No functional change intended. Signed-off-by: Zhang Rui <[email protected]> Tested-by: Wang Wendy <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent 98ff639 commit cb532e7

File tree

2 files changed

+73
-63
lines changed

2 files changed

+73
-63
lines changed

drivers/powercap/intel_rapl_common.c

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ static const char pl4_name[] = "peak_power";
105105

106106
struct rapl_defaults {
107107
u8 floor_freq_reg_addr;
108-
int (*check_unit)(struct rapl_package *rp, int cpu);
108+
int (*check_unit)(struct rapl_domain *rd, int cpu);
109109
void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
110-
u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
110+
u64 (*compute_time_window)(struct rapl_domain *rd, u64 val,
111111
bool to_raw);
112112
unsigned int dram_domain_energy_unit;
113113
unsigned int psys_domain_energy_unit;
@@ -557,7 +557,6 @@ static void rapl_init_domains(struct rapl_package *rp)
557557
enum rapl_domain_type i;
558558
enum rapl_domain_reg_id j;
559559
struct rapl_domain *rd = rp->domains;
560-
struct rapl_defaults *defaults = get_defaults(rp);
561560

562561
for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
563562
unsigned int mask = rp->domain_map & (1 << i);
@@ -596,24 +595,6 @@ static void rapl_init_domains(struct rapl_package *rp)
596595
for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
597596
rd->regs[j] = rp->priv->regs[i][j];
598597

599-
switch (i) {
600-
case RAPL_DOMAIN_DRAM:
601-
rd->domain_energy_unit =
602-
defaults->dram_domain_energy_unit;
603-
if (rd->domain_energy_unit)
604-
pr_info("DRAM domain energy unit %dpj\n",
605-
rd->domain_energy_unit);
606-
break;
607-
case RAPL_DOMAIN_PLATFORM:
608-
rd->domain_energy_unit =
609-
defaults->psys_domain_energy_unit;
610-
if (rd->domain_energy_unit)
611-
pr_info("Platform domain energy unit %dpj\n",
612-
rd->domain_energy_unit);
613-
break;
614-
default:
615-
break;
616-
}
617598
rd++;
618599
}
619600
}
@@ -622,24 +603,19 @@ static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
622603
u64 value, int to_raw)
623604
{
624605
u64 units = 1;
625-
struct rapl_package *rp = rd->rp;
626-
struct rapl_defaults *defaults = get_defaults(rp);
606+
struct rapl_defaults *defaults = get_defaults(rd->rp);
627607
u64 scale = 1;
628608

629609
switch (type) {
630610
case POWER_UNIT:
631-
units = rp->power_unit;
611+
units = rd->power_unit;
632612
break;
633613
case ENERGY_UNIT:
634614
scale = ENERGY_UNIT_SCALE;
635-
/* per domain unit takes precedence */
636-
if (rd->domain_energy_unit)
637-
units = rd->domain_energy_unit;
638-
else
639-
units = rp->energy_unit;
615+
units = rd->energy_unit;
640616
break;
641617
case TIME_UNIT:
642-
return defaults->compute_time_window(rp, value, to_raw);
618+
return defaults->compute_time_window(rd, value, to_raw);
643619
case ARBITRARY_UNIT:
644620
default:
645621
return value;
@@ -857,58 +833,58 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
857833
* power unit : microWatts : Represented in milliWatts by default
858834
* time unit : microseconds: Represented in seconds by default
859835
*/
860-
static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
836+
static int rapl_check_unit_core(struct rapl_domain *rd, int cpu)
861837
{
862838
struct reg_action ra;
863839
u32 value;
864840

865-
ra.reg = rp->priv->reg_unit;
841+
ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT];
866842
ra.mask = ~0;
867-
if (rp->priv->read_raw(cpu, &ra)) {
843+
if (rd->rp->priv->read_raw(cpu, &ra)) {
868844
pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n",
869-
rp->priv->reg_unit, cpu);
845+
ra.reg, cpu);
870846
return -ENODEV;
871847
}
872848

873849
value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
874-
rp->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
850+
rd->energy_unit = ENERGY_UNIT_SCALE * 1000000 / (1 << value);
875851

876852
value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
877-
rp->power_unit = 1000000 / (1 << value);
853+
rd->power_unit = 1000000 / (1 << value);
878854

879855
value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
880-
rp->time_unit = 1000000 / (1 << value);
856+
rd->time_unit = 1000000 / (1 << value);
881857

882-
pr_debug("Core CPU %s energy=%dpJ, time=%dus, power=%duW\n",
883-
rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
858+
pr_debug("Core CPU %s:%s energy=%dpJ, time=%dus, power=%duW\n",
859+
rd->rp->name, rd->name, rd->energy_unit, rd->time_unit, rd->power_unit);
884860

885861
return 0;
886862
}
887863

888-
static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
864+
static int rapl_check_unit_atom(struct rapl_domain *rd, int cpu)
889865
{
890866
struct reg_action ra;
891867
u32 value;
892868

893-
ra.reg = rp->priv->reg_unit;
869+
ra.reg = rd->regs[RAPL_DOMAIN_REG_UNIT];
894870
ra.mask = ~0;
895-
if (rp->priv->read_raw(cpu, &ra)) {
871+
if (rd->rp->priv->read_raw(cpu, &ra)) {
896872
pr_err("Failed to read power unit REG 0x%llx on CPU %d, exit.\n",
897-
rp->priv->reg_unit, cpu);
873+
ra.reg, cpu);
898874
return -ENODEV;
899875
}
900876

901877
value = (ra.value & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
902-
rp->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
878+
rd->energy_unit = ENERGY_UNIT_SCALE * 1 << value;
903879

904880
value = (ra.value & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
905-
rp->power_unit = (1 << value) * 1000;
881+
rd->power_unit = (1 << value) * 1000;
906882

907883
value = (ra.value & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
908-
rp->time_unit = 1000000 / (1 << value);
884+
rd->time_unit = 1000000 / (1 << value);
909885

910-
pr_debug("Atom %s energy=%dpJ, time=%dus, power=%duW\n",
911-
rp->name, rp->energy_unit, rp->time_unit, rp->power_unit);
886+
pr_debug("Atom %s:%s energy=%dpJ, time=%dus, power=%duW\n",
887+
rd->rp->name, rd->name, rd->energy_unit, rd->time_unit, rd->power_unit);
912888

913889
return 0;
914890
}
@@ -1011,7 +987,7 @@ static void set_floor_freq_atom(struct rapl_domain *rd, bool enable)
1011987
defaults->floor_freq_reg_addr, mdata);
1012988
}
1013989

1014-
static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
990+
static u64 rapl_compute_time_window_core(struct rapl_domain *rd, u64 value,
1015991
bool to_raw)
1016992
{
1017993
u64 f, y; /* fraction and exp. used for time unit */
@@ -1023,12 +999,12 @@ static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
1023999
if (!to_raw) {
10241000
f = (value & 0x60) >> 5;
10251001
y = value & 0x1f;
1026-
value = (1 << y) * (4 + f) * rp->time_unit / 4;
1002+
value = (1 << y) * (4 + f) * rd->time_unit / 4;
10271003
} else {
1028-
if (value < rp->time_unit)
1004+
if (value < rd->time_unit)
10291005
return 0;
10301006

1031-
do_div(value, rp->time_unit);
1007+
do_div(value, rd->time_unit);
10321008
y = ilog2(value);
10331009

10341010
/*
@@ -1044,17 +1020,17 @@ static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
10441020
return value;
10451021
}
10461022

1047-
static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
1023+
static u64 rapl_compute_time_window_atom(struct rapl_domain *rd, u64 value,
10481024
bool to_raw)
10491025
{
10501026
/*
10511027
* Atom time unit encoding is straight forward val * time_unit,
10521028
* where time_unit is default to 1 sec. Never 0.
10531029
*/
10541030
if (!to_raw)
1055-
return (value) ? value * rp->time_unit : rp->time_unit;
1031+
return (value) ? value * rd->time_unit : rd->time_unit;
10561032

1057-
value = div64_u64(value, rp->time_unit);
1033+
value = div64_u64(value, rd->time_unit);
10581034

10591035
return value;
10601036
}
@@ -1299,6 +1275,40 @@ static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
12991275
return 0;
13001276
}
13011277

1278+
/*
1279+
* Get per domain energy/power/time unit.
1280+
* RAPL Interfaces without per domain unit register will use the package
1281+
* scope unit register to set per domain units.
1282+
*/
1283+
static int rapl_get_domain_unit(struct rapl_domain *rd)
1284+
{
1285+
struct rapl_defaults *defaults = get_defaults(rd->rp);
1286+
int ret;
1287+
1288+
if (!rd->regs[RAPL_DOMAIN_REG_UNIT]) {
1289+
if (!rd->rp->priv->reg_unit) {
1290+
pr_err("No valid Unit register found\n");
1291+
return -ENODEV;
1292+
}
1293+
rd->regs[RAPL_DOMAIN_REG_UNIT] = rd->rp->priv->reg_unit;
1294+
}
1295+
1296+
if (!defaults->check_unit) {
1297+
pr_err("missing .check_unit() callback\n");
1298+
return -ENODEV;
1299+
}
1300+
1301+
ret = defaults->check_unit(rd, rd->rp->lead_cpu);
1302+
if (ret)
1303+
return ret;
1304+
1305+
if (rd->id == RAPL_DOMAIN_DRAM && defaults->dram_domain_energy_unit)
1306+
rd->energy_unit = defaults->dram_domain_energy_unit;
1307+
if (rd->id == RAPL_DOMAIN_PLATFORM && defaults->psys_domain_energy_unit)
1308+
rd->energy_unit = defaults->psys_domain_energy_unit;
1309+
return 0;
1310+
}
1311+
13021312
/*
13031313
* Check if power limits are available. Two cases when they are not available:
13041314
* 1. Locked by BIOS, in this case we still provide read-only access so that
@@ -1359,8 +1369,10 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
13591369

13601370
rapl_init_domains(rp);
13611371

1362-
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++)
1372+
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
1373+
rapl_get_domain_unit(rd);
13631374
rapl_detect_powerlimit(rd);
1375+
}
13641376

13651377
return 0;
13661378
}
@@ -1418,7 +1430,6 @@ struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv)
14181430
{
14191431
int id = topology_logical_die_id(cpu);
14201432
struct rapl_package *rp;
1421-
struct rapl_defaults *defaults;
14221433
int ret;
14231434

14241435
rp = kzalloc(sizeof(struct rapl_package), GFP_KERNEL);
@@ -1442,9 +1453,8 @@ struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv)
14421453
snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d",
14431454
topology_physical_package_id(cpu));
14441455

1445-
defaults = get_defaults(rp);
14461456
/* check if the package contains valid domains */
1447-
if (rapl_detect_domains(rp, cpu) || defaults->check_unit(rp, cpu)) {
1457+
if (rapl_detect_domains(rp, cpu)) {
14481458
ret = -ENODEV;
14491459
goto err_free_package;
14501460
}

include/linux/intel_rapl.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum rapl_domain_reg_id {
3030
RAPL_DOMAIN_REG_POLICY,
3131
RAPL_DOMAIN_REG_INFO,
3232
RAPL_DOMAIN_REG_PL4,
33+
RAPL_DOMAIN_REG_UNIT,
3334
RAPL_DOMAIN_REG_MAX,
3435
};
3536

@@ -96,7 +97,9 @@ struct rapl_domain {
9697
struct rapl_power_limit rpl[NR_POWER_LIMITS];
9798
u64 attr_map; /* track capabilities */
9899
unsigned int state;
99-
unsigned int domain_energy_unit;
100+
unsigned int power_unit;
101+
unsigned int energy_unit;
102+
unsigned int time_unit;
100103
struct rapl_package *rp;
101104
};
102105

@@ -143,9 +146,6 @@ struct rapl_package {
143146
unsigned int id; /* logical die id, equals physical 1-die systems */
144147
unsigned int nr_domains;
145148
unsigned long domain_map; /* bit map of active domains */
146-
unsigned int power_unit;
147-
unsigned int energy_unit;
148-
unsigned int time_unit;
149149
struct rapl_domain *domains; /* array of domains, sized at runtime */
150150
struct powercap_zone *power_zone; /* keep track of parent zone */
151151
unsigned long power_limit_irq; /* keep track of package power limit

0 commit comments

Comments
 (0)