Skip to content

Commit

Permalink
powercap/intel_rapl: enumerate Psys RAPL domain together with package…
Browse files Browse the repository at this point in the history
… RAPL domain

On multi-package systems, the Psys MSR is only valid for CPUs on
specific package (master package). The current code makes the
assumption that package 0 is the master package, but this is not
true on new platforms like SPR.

Fix the problem by emuerating the Psys RAPL domain for every
package, so CPUs in slave packages will read 0 for the Psys energy
counter and only CPUs in master packages can get a valid reading
and register the Psys RAPL domain.

The sysfs I/F for the Psys RAPL domain is not changed.

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
[ rjw: Subject and changelog edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Zhang Rui authored and Rafael J. Wysocki committed Oct 16, 2020
1 parent 7a57e9f commit f1e8d75
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 74 deletions.
80 changes: 14 additions & 66 deletions drivers/powercap/intel_rapl_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -544,7 +544,14 @@ static void rapl_init_domains(struct rapl_package *rp)
continue;

rd->rp = rp;
rd->name = rapl_domain_names[i];

if (i == RAPL_DOMAIN_PLATFORM && rp->id > 0) {
snprintf(rd->name, RAPL_DOMAIN_NAME_LENGTH, "psys-%d",
cpu_data(rp->lead_cpu).phys_proc_id);
} else
snprintf(rd->name, RAPL_DOMAIN_NAME_LENGTH, "%s",
rapl_domain_names[i]);

rd->id = i;
rd->rpl[0].prim_id = PL1_ENABLE;
rd->rpl[0].name = pl1_name;
Expand Down Expand Up @@ -1112,13 +1119,17 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
}
/* now register domains as children of the socket/package */
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
struct powercap_zone *parent = rp->power_zone;

if (rd->id == RAPL_DOMAIN_PACKAGE)
continue;
if (rd->id == RAPL_DOMAIN_PLATFORM)
parent = NULL;
/* number of power limits per domain varies */
nr_pl = find_nr_power_limit(rd);
power_zone = powercap_register_zone(&rd->power_zone,
rp->priv->control_type,
rd->name, rp->power_zone,
rd->name, parent,
&zone_ops[rd->id], nr_pl,
&constraint_ops);

Expand All @@ -1145,67 +1156,6 @@ static int rapl_package_register_powercap(struct rapl_package *rp)
return ret;
}

int rapl_add_platform_domain(struct rapl_if_priv *priv)
{
struct rapl_domain *rd;
struct powercap_zone *power_zone;
struct reg_action ra;
int ret;

ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
ra.mask = ~0;
ret = priv->read_raw(0, &ra);
if (ret || !ra.value)
return -ENODEV;

ra.reg = priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
ra.mask = ~0;
ret = priv->read_raw(0, &ra);
if (ret || !ra.value)
return -ENODEV;

rd = kzalloc(sizeof(*rd), GFP_KERNEL);
if (!rd)
return -ENOMEM;

rd->name = rapl_domain_names[RAPL_DOMAIN_PLATFORM];
rd->id = RAPL_DOMAIN_PLATFORM;
rd->regs[RAPL_DOMAIN_REG_LIMIT] =
priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_LIMIT];
rd->regs[RAPL_DOMAIN_REG_STATUS] =
priv->regs[RAPL_DOMAIN_PLATFORM][RAPL_DOMAIN_REG_STATUS];
rd->rpl[0].prim_id = PL1_ENABLE;
rd->rpl[0].name = pl1_name;
rd->rpl[1].prim_id = PL2_ENABLE;
rd->rpl[1].name = pl2_name;
rd->rp = rapl_find_package_domain(0, priv);

power_zone = powercap_register_zone(&rd->power_zone, priv->control_type,
"psys", NULL,
&zone_ops[RAPL_DOMAIN_PLATFORM],
2, &constraint_ops);

if (IS_ERR(power_zone)) {
kfree(rd);
return PTR_ERR(power_zone);
}

priv->platform_rapl_domain = rd;

return 0;
}
EXPORT_SYMBOL_GPL(rapl_add_platform_domain);

void rapl_remove_platform_domain(struct rapl_if_priv *priv)
{
if (priv->platform_rapl_domain) {
powercap_unregister_zone(priv->control_type,
&priv->platform_rapl_domain->power_zone);
kfree(priv->platform_rapl_domain);
}
}
EXPORT_SYMBOL_GPL(rapl_remove_platform_domain);

static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
{
struct reg_action ra;
Expand All @@ -1215,11 +1165,9 @@ static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
case RAPL_DOMAIN_PP0:
case RAPL_DOMAIN_PP1:
case RAPL_DOMAIN_DRAM:
case RAPL_DOMAIN_PLATFORM:
ra.reg = rp->priv->regs[domain][RAPL_DOMAIN_REG_STATUS];
break;
case RAPL_DOMAIN_PLATFORM:
/* PSYS(PLATFORM) is not a CPU domain, so avoid printng error */
return -EINVAL;
default:
pr_err("invalid domain id %d\n", domain);
return -EINVAL;
Expand Down
5 changes: 1 addition & 4 deletions drivers/powercap/intel_rapl_msr.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ static struct rapl_if_priv rapl_msr_priv = {
.regs[RAPL_DOMAIN_PLATFORM] = {
MSR_PLATFORM_POWER_LIMIT, MSR_PLATFORM_ENERGY_STATUS, 0, 0, 0},
.limits[RAPL_DOMAIN_PACKAGE] = 2,
.limits[RAPL_DOMAIN_PLATFORM] = 2,
};

/* Handles CPU hotplug on multi-socket systems.
Expand Down Expand Up @@ -157,9 +158,6 @@ static int rapl_msr_probe(struct platform_device *pdev)
goto out;
rapl_msr_priv.pcap_rapl_online = ret;

/* Don't bail out if PSys is not supported */
rapl_add_platform_domain(&rapl_msr_priv);

return 0;

out:
Expand All @@ -171,7 +169,6 @@ static int rapl_msr_probe(struct platform_device *pdev)
static int rapl_msr_remove(struct platform_device *pdev)
{
cpuhp_remove_state(rapl_msr_priv.pcap_rapl_online);
rapl_remove_platform_domain(&rapl_msr_priv);
powercap_unregister_control_type(rapl_msr_priv.control_type);
return 0;
}
Expand Down
7 changes: 3 additions & 4 deletions include/linux/intel_rapl.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ struct rapl_power_limit {

struct rapl_package;

#define RAPL_DOMAIN_NAME_LENGTH 16

struct rapl_domain {
const char *name;
char name[RAPL_DOMAIN_NAME_LENGTH];
enum rapl_domain_type id;
u64 regs[RAPL_DOMAIN_REG_MAX];
struct powercap_zone power_zone;
Expand Down Expand Up @@ -152,7 +154,4 @@ struct rapl_package *rapl_find_package_domain(int cpu, struct rapl_if_priv *priv
struct rapl_package *rapl_add_package(int cpu, struct rapl_if_priv *priv);
void rapl_remove_package(struct rapl_package *rp);

int rapl_add_platform_domain(struct rapl_if_priv *priv);
void rapl_remove_platform_domain(struct rapl_if_priv *priv);

#endif /* __INTEL_RAPL_H__ */

0 comments on commit f1e8d75

Please sign in to comment.