aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/powercap
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/powercap')
-rw-r--r--drivers/powercap/Kconfig2
-rw-r--r--drivers/powercap/idle_inject.c15
-rw-r--r--drivers/powercap/intel_rapl_common.c165
-rw-r--r--drivers/powercap/intel_rapl_msr.c20
4 files changed, 118 insertions, 84 deletions
diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig
index ebc4d4578339..bc228725346b 100644
--- a/drivers/powercap/Kconfig
+++ b/drivers/powercap/Kconfig
@@ -30,7 +30,7 @@ config INTEL_RAPL
In RAPL, the platform level settings are divided into domains for
fine grained control. These domains include processor package, DRAM
- controller, CPU core (Power Plance 0), graphics uncore (Power Plane
+ controller, CPU core (Power Plane 0), graphics uncore (Power Plane
1), etc.
config IDLE_INJECT
diff --git a/drivers/powercap/idle_inject.c b/drivers/powercap/idle_inject.c
index c90f0990968b..6e1a0043c411 100644
--- a/drivers/powercap/idle_inject.c
+++ b/drivers/powercap/idle_inject.c
@@ -19,8 +19,8 @@
* The idle + run duration is specified via separate helpers and that allows
* idle injection to be started.
*
- * The idle injection kthreads will call play_idle() with the idle duration
- * specified as per the above.
+ * The idle injection kthreads will call play_idle_precise() with the idle
+ * duration and max allowed latency specified as per the above.
*
* After all of them have been woken up, a timer is set to start the next idle
* injection cycle.
@@ -43,6 +43,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/smpboot.h>
+#include <linux/idle_inject.h>
#include <uapi/linux/sched/types.h>
@@ -100,7 +101,7 @@ static void idle_inject_wakeup(struct idle_inject_device *ii_dev)
*
* This function is called when the idle injection timer expires. It wakes up
* idle injection tasks associated with the timer and they, in turn, invoke
- * play_idle() to inject a specified amount of CPU idle time.
+ * play_idle_precise() to inject a specified amount of CPU idle time.
*
* Return: HRTIMER_RESTART.
*/
@@ -124,8 +125,8 @@ static enum hrtimer_restart idle_inject_timer_fn(struct hrtimer *timer)
* idle_inject_fn - idle injection work function
* @cpu: the CPU owning the task
*
- * This function calls play_idle() to inject a specified amount of CPU idle
- * time.
+ * This function calls play_idle_precise() to inject a specified amount of CPU
+ * idle time.
*/
static void idle_inject_fn(unsigned int cpu)
{
@@ -268,9 +269,7 @@ void idle_inject_stop(struct idle_inject_device *ii_dev)
*/
static void idle_inject_setup(unsigned int cpu)
{
- struct sched_param param = { .sched_priority = MAX_USER_RT_PRIO / 2 };
-
- sched_setscheduler(current, SCHED_FIFO, &param);
+ sched_set_fifo(current);
}
/**
diff --git a/drivers/powercap/intel_rapl_common.c b/drivers/powercap/intel_rapl_common.c
index 61a63a16b5e7..70d6d52bc1e2 100644
--- a/drivers/powercap/intel_rapl_common.c
+++ b/drivers/powercap/intel_rapl_common.c
@@ -39,6 +39,8 @@
#define POWER_HIGH_LOCK BIT_ULL(63)
#define POWER_LOW_LOCK BIT(31)
+#define POWER_LIMIT4_MASK 0x1FFF
+
#define TIME_WINDOW1_MASK (0x7FULL<<17)
#define TIME_WINDOW2_MASK (0x7FULL<<49)
@@ -82,6 +84,7 @@ enum unit_type {
static const char pl1_name[] = "long_term";
static const char pl2_name[] = "short_term";
+static const char pl4_name[] = "peak_power";
#define power_zone_to_rapl_domain(_zone) \
container_of(_zone, struct rapl_domain, power_zone)
@@ -93,6 +96,7 @@ struct rapl_defaults {
u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
bool to_raw);
unsigned int dram_domain_energy_unit;
+ unsigned int psys_domain_energy_unit;
};
static struct rapl_defaults *rapl_defaults;
@@ -337,6 +341,9 @@ static int set_power_limit(struct powercap_zone *power_zone, int cid,
case PL2_ENABLE:
rapl_write_data_raw(rd, POWER_LIMIT2, power_limit);
break;
+ case PL4_ENABLE:
+ rapl_write_data_raw(rd, POWER_LIMIT4, power_limit);
+ break;
default:
ret = -EINVAL;
}
@@ -371,6 +378,9 @@ static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
case PL2_ENABLE:
prim = POWER_LIMIT2;
break;
+ case PL4_ENABLE:
+ prim = POWER_LIMIT4;
+ break;
default:
put_online_cpus();
return -EINVAL;
@@ -440,6 +450,13 @@ static int get_time_window(struct powercap_zone *power_zone, int cid,
case PL2_ENABLE:
ret = rapl_read_data_raw(rd, TIME_WINDOW2, true, &val);
break;
+ case PL4_ENABLE:
+ /*
+ * Time window parameter is not applicable for PL4 entry
+ * so assigining '0' as default value.
+ */
+ val = 0;
+ break;
default:
put_online_cpus();
return -EINVAL;
@@ -483,6 +500,9 @@ static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
case PL2_ENABLE:
prim = MAX_POWER;
break;
+ case PL4_ENABLE:
+ prim = MAX_POWER;
+ break;
default:
put_online_cpus();
return -EINVAL;
@@ -492,6 +512,10 @@ static int get_max_power(struct powercap_zone *power_zone, int id, u64 *data)
else
*data = val;
+ /* As a generalization rule, PL4 would be around two times PL2. */
+ if (rd->rpl[id].prim_id == PL4_ENABLE)
+ *data = *data * 2;
+
put_online_cpus();
return ret;
@@ -520,25 +544,53 @@ 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;
- /* some domain may support two power limits */
- if (rp->priv->limits[i] == 2) {
+
+ /*
+ * The PL2 power domain is applicable for limits two
+ * and limits three
+ */
+ if (rp->priv->limits[i] >= 2) {
rd->rpl[1].prim_id = PL2_ENABLE;
rd->rpl[1].name = pl2_name;
}
+ /* Enable PL4 domain if the total power limits are three */
+ if (rp->priv->limits[i] == 3) {
+ rd->rpl[2].prim_id = PL4_ENABLE;
+ rd->rpl[2].name = pl4_name;
+ }
+
for (j = 0; j < RAPL_DOMAIN_REG_MAX; j++)
rd->regs[j] = rp->priv->regs[i][j];
- if (i == RAPL_DOMAIN_DRAM) {
+ switch (i) {
+ case RAPL_DOMAIN_DRAM:
rd->domain_energy_unit =
rapl_defaults->dram_domain_energy_unit;
if (rd->domain_energy_unit)
pr_info("DRAM domain energy unit %dpj\n",
rd->domain_energy_unit);
+ break;
+ case RAPL_DOMAIN_PLATFORM:
+ rd->domain_energy_unit =
+ rapl_defaults->psys_domain_energy_unit;
+ if (rd->domain_energy_unit)
+ pr_info("Platform domain energy unit %dpj\n",
+ rd->domain_energy_unit);
+ break;
+ default:
+ break;
}
rd++;
}
@@ -568,7 +620,7 @@ static u64 rapl_unit_xlate(struct rapl_domain *rd, enum unit_type type,
case ARBITRARY_UNIT:
default:
return value;
- };
+ }
if (to_raw)
return div64_u64(value, units) * scale;
@@ -587,6 +639,8 @@ static struct rapl_primitive_info rpi[] = {
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
PRIMITIVE_INFO_INIT(POWER_LIMIT2, POWER_LIMIT2_MASK, 32,
RAPL_DOMAIN_REG_LIMIT, POWER_UNIT, 0),
+ PRIMITIVE_INFO_INIT(POWER_LIMIT4, POWER_LIMIT4_MASK, 0,
+ RAPL_DOMAIN_REG_PL4, POWER_UNIT, 0),
PRIMITIVE_INFO_INIT(FW_LOCK, POWER_LOW_LOCK, 31,
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(PL1_ENABLE, POWER_LIMIT1_ENABLE, 15,
@@ -597,6 +651,8 @@ static struct rapl_primitive_info rpi[] = {
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(PL2_CLAMP, POWER_LIMIT2_CLAMP, 48,
RAPL_DOMAIN_REG_LIMIT, ARBITRARY_UNIT, 0),
+ PRIMITIVE_INFO_INIT(PL4_ENABLE, POWER_LIMIT4_MASK, 0,
+ RAPL_DOMAIN_REG_PL4, ARBITRARY_UNIT, 0),
PRIMITIVE_INFO_INIT(TIME_WINDOW1, TIME_WINDOW1_MASK, 17,
RAPL_DOMAIN_REG_LIMIT, TIME_UNIT, 0),
PRIMITIVE_INFO_INIT(TIME_WINDOW2, TIME_WINDOW2_MASK, 49,
@@ -919,6 +975,14 @@ static const struct rapl_defaults rapl_defaults_hsw_server = {
.dram_domain_energy_unit = 15300,
};
+static const struct rapl_defaults rapl_defaults_spr_server = {
+ .check_unit = rapl_check_unit_core,
+ .set_floor_freq = set_floor_freq_default,
+ .compute_time_window = rapl_compute_time_window_core,
+ .dram_domain_energy_unit = 15300,
+ .psys_domain_energy_unit = 1000000000,
+};
+
static const struct rapl_defaults rapl_defaults_byt = {
.floor_freq_reg_addr = IOSF_CPU_POWER_BUDGET_CTL_BYT,
.check_unit = rapl_check_unit_atom,
@@ -978,6 +1042,11 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE_L, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(COMETLAKE, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE_L, &rapl_defaults_core),
+ X86_MATCH_INTEL_FAM6_MODEL(TIGERLAKE, &rapl_defaults_core),
+ X86_MATCH_INTEL_FAM6_MODEL(ROCKETLAKE, &rapl_defaults_core),
+ X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE, &rapl_defaults_core),
+ X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server),
+ X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT, &rapl_defaults_byt),
X86_MATCH_INTEL_FAM6_MODEL(ATOM_AIRMONT, &rapl_defaults_cht),
@@ -1050,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);
@@ -1083,67 +1156,6 @@ err_cleanup:
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;
@@ -1153,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;
@@ -1166,7 +1176,7 @@ static int rapl_check_domain(int cpu, int domain, struct rapl_package *rp)
* values, otherwise skip it.
*/
- ra.mask = ~0;
+ ra.mask = ENERGY_STATUS_MASK;
if (rp->priv->read_raw(cpu, &ra) || !ra.value)
return -ENODEV;
@@ -1252,6 +1262,7 @@ void rapl_remove_package(struct rapl_package *rp)
if (find_nr_power_limit(rd) > 1) {
rapl_write_data_raw(rd, PL2_ENABLE, 0);
rapl_write_data_raw(rd, PL2_CLAMP, 0);
+ rapl_write_data_raw(rd, PL4_ENABLE, 0);
}
if (rd->id == RAPL_DOMAIN_PACKAGE) {
rd_package = rd;
@@ -1360,6 +1371,13 @@ static void power_limit_state_save(void)
if (ret)
rd->rpl[i].last_power_limit = 0;
break;
+ case PL4_ENABLE:
+ ret = rapl_read_data_raw(rd,
+ POWER_LIMIT4, true,
+ &rd->rpl[i].last_power_limit);
+ if (ret)
+ rd->rpl[i].last_power_limit = 0;
+ break;
}
}
}
@@ -1390,6 +1408,11 @@ static void power_limit_state_restore(void)
rapl_write_data_raw(rd, POWER_LIMIT2,
rd->rpl[i].last_power_limit);
break;
+ case PL4_ENABLE:
+ if (rd->rpl[i].last_power_limit)
+ rapl_write_data_raw(rd, POWER_LIMIT4,
+ rd->rpl[i].last_power_limit);
+ break;
}
}
}
diff --git a/drivers/powercap/intel_rapl_msr.c b/drivers/powercap/intel_rapl_msr.c
index d5487965bdfe..1646808d354c 100644
--- a/drivers/powercap/intel_rapl_msr.c
+++ b/drivers/powercap/intel_rapl_msr.c
@@ -28,6 +28,7 @@
/* Local defines */
#define MSR_PLATFORM_POWER_LIMIT 0x0000065C
+#define MSR_VR_CURRENT_CONFIG 0x00000601
/* private data for RAPL MSR Interface */
static struct rapl_if_priv rapl_msr_priv = {
@@ -43,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.
@@ -123,13 +125,27 @@ static int rapl_msr_write_raw(int cpu, struct reg_action *ra)
return ra->err;
}
+/* List of verified CPUs. */
+static const struct x86_cpu_id pl4_support_ids[] = {
+ { X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
+ {}
+};
+
static int rapl_msr_probe(struct platform_device *pdev)
{
+ const struct x86_cpu_id *id = x86_match_cpu(pl4_support_ids);
int ret;
rapl_msr_priv.read_raw = rapl_msr_read_raw;
rapl_msr_priv.write_raw = rapl_msr_write_raw;
+ if (id) {
+ rapl_msr_priv.limits[RAPL_DOMAIN_PACKAGE] = 3;
+ rapl_msr_priv.regs[RAPL_DOMAIN_PACKAGE][RAPL_DOMAIN_REG_PL4] =
+ MSR_VR_CURRENT_CONFIG;
+ pr_info("PL4 support detected.\n");
+ }
+
rapl_msr_priv.control_type = powercap_register_control_type(NULL, "intel-rapl", NULL);
if (IS_ERR(rapl_msr_priv.control_type)) {
pr_debug("failed to register powercap control_type.\n");
@@ -142,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:
@@ -156,7 +169,6 @@ out:
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;
}