Merge back earlier powercap material for v4.8.

This commit is contained in:
Rafael J. Wysocki 2016-06-15 01:37:21 +02:00
commit a8165a21b7
1 changed files with 80 additions and 25 deletions

View File

@ -336,14 +336,14 @@ static int release_zone(struct powercap_zone *power_zone)
static int find_nr_power_limit(struct rapl_domain *rd) static int find_nr_power_limit(struct rapl_domain *rd)
{ {
int i; int i, nr_pl = 0;
for (i = 0; i < NR_POWER_LIMITS; i++) { for (i = 0; i < NR_POWER_LIMITS; i++) {
if (rd->rpl[i].name == NULL) if (rd->rpl[i].name)
break; nr_pl++;
} }
return i; return nr_pl;
} }
static int set_domain_enable(struct powercap_zone *power_zone, bool mode) static int set_domain_enable(struct powercap_zone *power_zone, bool mode)
@ -426,15 +426,38 @@ static const struct powercap_zone_ops zone_ops[] = {
}, },
}; };
static int set_power_limit(struct powercap_zone *power_zone, int id,
/*
* Constraint index used by powercap can be different than power limit (PL)
* index in that some PLs maybe missing due to non-existant MSRs. So we
* need to convert here by finding the valid PLs only (name populated).
*/
static int contraint_to_pl(struct rapl_domain *rd, int cid)
{
int i, j;
for (i = 0, j = 0; i < NR_POWER_LIMITS; i++) {
if ((rd->rpl[i].name) && j++ == cid) {
pr_debug("%s: index %d\n", __func__, i);
return i;
}
}
return -EINVAL;
}
static int set_power_limit(struct powercap_zone *power_zone, int cid,
u64 power_limit) u64 power_limit)
{ {
struct rapl_domain *rd; struct rapl_domain *rd;
struct rapl_package *rp; struct rapl_package *rp;
int ret = 0; int ret = 0;
int id;
get_online_cpus(); get_online_cpus();
rd = power_zone_to_rapl_domain(power_zone); rd = power_zone_to_rapl_domain(power_zone);
id = contraint_to_pl(rd, cid);
rp = rd->rp; rp = rd->rp;
if (rd->state & DOMAIN_STATE_BIOS_LOCKED) { if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
@ -461,16 +484,18 @@ static int set_power_limit(struct powercap_zone *power_zone, int id,
return ret; return ret;
} }
static int get_current_power_limit(struct powercap_zone *power_zone, int id, static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
u64 *data) u64 *data)
{ {
struct rapl_domain *rd; struct rapl_domain *rd;
u64 val; u64 val;
int prim; int prim;
int ret = 0; int ret = 0;
int id;
get_online_cpus(); get_online_cpus();
rd = power_zone_to_rapl_domain(power_zone); rd = power_zone_to_rapl_domain(power_zone);
id = contraint_to_pl(rd, cid);
switch (rd->rpl[id].prim_id) { switch (rd->rpl[id].prim_id) {
case PL1_ENABLE: case PL1_ENABLE:
prim = POWER_LIMIT1; prim = POWER_LIMIT1;
@ -492,14 +517,17 @@ static int get_current_power_limit(struct powercap_zone *power_zone, int id,
return ret; return ret;
} }
static int set_time_window(struct powercap_zone *power_zone, int id, static int set_time_window(struct powercap_zone *power_zone, int cid,
u64 window) u64 window)
{ {
struct rapl_domain *rd; struct rapl_domain *rd;
int ret = 0; int ret = 0;
int id;
get_online_cpus(); get_online_cpus();
rd = power_zone_to_rapl_domain(power_zone); rd = power_zone_to_rapl_domain(power_zone);
id = contraint_to_pl(rd, cid);
switch (rd->rpl[id].prim_id) { switch (rd->rpl[id].prim_id) {
case PL1_ENABLE: case PL1_ENABLE:
rapl_write_data_raw(rd, TIME_WINDOW1, window); rapl_write_data_raw(rd, TIME_WINDOW1, window);
@ -514,14 +542,17 @@ static int set_time_window(struct powercap_zone *power_zone, int id,
return ret; return ret;
} }
static int get_time_window(struct powercap_zone *power_zone, int id, u64 *data) static int get_time_window(struct powercap_zone *power_zone, int cid, u64 *data)
{ {
struct rapl_domain *rd; struct rapl_domain *rd;
u64 val; u64 val;
int ret = 0; int ret = 0;
int id;
get_online_cpus(); get_online_cpus();
rd = power_zone_to_rapl_domain(power_zone); rd = power_zone_to_rapl_domain(power_zone);
id = contraint_to_pl(rd, cid);
switch (rd->rpl[id].prim_id) { switch (rd->rpl[id].prim_id) {
case PL1_ENABLE: case PL1_ENABLE:
ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val); ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val);
@ -540,15 +571,17 @@ static int get_time_window(struct powercap_zone *power_zone, int id, u64 *data)
return ret; return ret;
} }
static const char *get_constraint_name(struct powercap_zone *power_zone, int id) static const char *get_constraint_name(struct powercap_zone *power_zone, int cid)
{ {
struct rapl_power_limit *rpl;
struct rapl_domain *rd; struct rapl_domain *rd;
int id;
rd = power_zone_to_rapl_domain(power_zone); rd = power_zone_to_rapl_domain(power_zone);
rpl = (struct rapl_power_limit *) &rd->rpl[id]; id = contraint_to_pl(rd, cid);
if (id >= 0)
return rd->rpl[id].name;
return rpl->name; return NULL;
} }
@ -1381,6 +1414,37 @@ static int rapl_check_domain(int cpu, int domain)
return 0; return 0;
} }
/*
* Check if power limits are available. Two cases when they are not available:
* 1. Locked by BIOS, in this case we still provide read-only access so that
* users can see what limit is set by the BIOS.
* 2. Some CPUs make some domains monitoring only which means PLx MSRs may not
* exist at all. In this case, we do not show the contraints in powercap.
*
* Called after domains are detected and initialized.
*/
static void rapl_detect_powerlimit(struct rapl_domain *rd)
{
u64 val64;
int i;
/* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
if (val64) {
pr_info("RAPL package %d domain %s locked by BIOS\n",
rd->rp->id, rd->name);
rd->state |= DOMAIN_STATE_BIOS_LOCKED;
}
}
/* check if power limit MSRs exists, otherwise domain is monitoring only */
for (i = 0; i < NR_POWER_LIMITS; i++) {
int prim = rd->rpl[i].prim_id;
if (rapl_read_data_raw(rd, prim, false, &val64))
rd->rpl[i].name = NULL;
}
}
/* Detect active and valid domains for the given CPU, caller must /* Detect active and valid domains for the given CPU, caller must
* ensure the CPU belongs to the targeted package and CPU hotlug is disabled. * ensure the CPU belongs to the targeted package and CPU hotlug is disabled.
*/ */
@ -1389,7 +1453,6 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
int i; int i;
int ret = 0; int ret = 0;
struct rapl_domain *rd; struct rapl_domain *rd;
u64 locked;
for (i = 0; i < RAPL_DOMAIN_MAX; i++) { for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
/* use physical package id to read counters */ /* use physical package id to read counters */
@ -1400,7 +1463,7 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
} }
rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX); rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
if (!rp->nr_domains) { if (!rp->nr_domains) {
pr_err("no valid rapl domains found in package %d\n", rp->id); pr_debug("no valid rapl domains found in package %d\n", rp->id);
ret = -ENODEV; ret = -ENODEV;
goto done; goto done;
} }
@ -1414,17 +1477,9 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
} }
rapl_init_domains(rp); rapl_init_domains(rp);
for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) { for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++)
/* check if the domain is locked by BIOS */ rapl_detect_powerlimit(rd);
ret = rapl_read_data_raw(rd, FW_LOCK, false, &locked);
if (ret)
return ret;
if (locked) {
pr_info("RAPL package %d domain %s locked by BIOS\n",
rp->id, rd->name);
rd->state |= DOMAIN_STATE_BIOS_LOCKED;
}
}
done: done: