Commit e0e44513 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branches 'powercap', 'pm-x86', 'pm-opp' and 'pm-misc'

Merge power capping code updates, x86-specific power management pdate,
operating performance points library updates and miscellaneous power
management updates for 6.2-rc1:

 - Fix compiler warnings with make W=1 in the idle_inject power capping
   driver (Srinivas Pandruvada).

 - Use kstrtobool() instead of strtobool() in the power capping sysfs
   interface (Christophe JAILLET).

 - Add SCMI Powercap based power capping driver (Cristian Marussi).

 - Add Emerald Rapids support to the intel-uncore-freq driver (Artem
   Bityutskiy).

 - Repair slips in kernel-doc comments in the generic notifier code
   (Lukas Bulwahn).

 - Fix several DT issues in the OPP library reorganize code around
   opp-microvolt-<named> DT property (Viresh Kumar).

 - Allow any of opp-microvolt, opp-microamp, or opp-microwatt properties
   to be present without the others present (James Calligeros).

 - Fix clock-latency-ns property in DT example (Serge Semin).

* powercap:
  powercap: idle_inject: Fix warnings with make W=1
  powercap: Use kstrtobool() instead of strtobool()
  powercap: arm_scmi: Add SCMI Powercap based driver

* pm-x86:
  platform/x86: intel-uncore-freq: add Emerald Rapids support

* pm-opp:
  dt-bindings: opp-v2: Fix clock-latency-ns prop in example
  OPP: decouple dt properties in opp_parse_supplies()
  OPP: Simplify opp_parse_supplies() by restructuring it
  OPP: Parse named opp-microwatt property too
  dt-bindings: opp: Fix named microwatt property
  dt-bindings: opp: Fix usage of current in microwatt property

* pm-misc:
  notifier: repair slips in kernel-doc comments
......@@ -108,7 +108,7 @@ patternProperties:
The power for the OPP in micro-Watts.
Entries for multiple regulators shall be provided in the same field
separated by angular brackets <>. If current values aren't required
separated by angular brackets <>. If power values aren't required
for a regulator, then it shall be filled with 0. If power values
aren't required for any of the regulators, then this field is not
required. The OPP binding doesn't provide any provisions to relate the
......@@ -230,9 +230,9 @@ patternProperties:
minItems: 1
maxItems: 8 # Should be enough regulators
'^opp-microwatt':
'^opp-microwatt-':
description:
Named opp-microwatt property. Similar to opp-microamp property,
Named opp-microwatt property. Similar to opp-microamp-<name> property,
but for microwatt instead.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 1
......
......@@ -155,7 +155,7 @@ examples:
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <1025000>;
opp-microamp = <90000>;
lock-latency-ns = <290000>;
clock-latency-ns = <290000>;
turbo-mode;
};
};
......
......@@ -20004,6 +20004,7 @@ F: drivers/clk/clk-sc[mp]i.c
F: drivers/cpufreq/sc[mp]i-cpufreq.c
F: drivers/firmware/arm_scmi/
F: drivers/firmware/arm_scpi.c
F: drivers/powercap/arm_scmi_powercap.c
F: drivers/regulator/scmi-regulator.c
F: drivers/reset/reset-scmi.c
F: include/linux/sc[mp]i_protocol.h
......
......@@ -578,169 +578,140 @@ static bool _opp_is_supported(struct device *dev, struct opp_table *opp_table,
return false;
}
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table)
static u32 *_parse_named_prop(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table,
const char *prop_type, bool *triplet)
{
u32 *microvolt, *microamp = NULL, *microwatt = NULL;
int supplies = opp_table->regulator_count;
int vcount, icount, pcount, ret, i, j;
struct property *prop = NULL;
char name[NAME_MAX];
int count, ret;
u32 *out;
/* Search for "opp-microvolt-<name>" */
/* Search for "opp-<prop_type>-<name>" */
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microvolt-%s",
snprintf(name, sizeof(name), "opp-%s-%s", prop_type,
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
if (!prop) {
/* Search for "opp-microvolt" */
sprintf(name, "opp-microvolt");
/* Search for "opp-<prop_type>" */
snprintf(name, sizeof(name), "opp-%s", prop_type);
prop = of_find_property(opp->np, name, NULL);
/* Missing property isn't a problem, but an invalid entry is */
if (!prop) {
if (unlikely(supplies == -1)) {
/* Initialize regulator_count */
opp_table->regulator_count = 0;
return 0;
}
if (!supplies)
return 0;
dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
__func__);
return -EINVAL;
}
if (!prop)
return NULL;
}
if (unlikely(supplies == -1)) {
/* Initialize regulator_count */
supplies = opp_table->regulator_count = 1;
} else if (unlikely(!supplies)) {
dev_err(dev, "%s: opp-microvolt wasn't expected\n", __func__);
return -EINVAL;
count = of_property_count_u32_elems(opp->np, name);
if (count < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__, name,
count);
return ERR_PTR(count);
}
vcount = of_property_count_u32_elems(opp->np, name);
if (vcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n",
__func__, name, vcount);
return vcount;
}
/*
* Initialize regulator_count, if regulator information isn't provided
* by the platform. Now that one of the properties is available, fix the
* regulator_count to 1.
*/
if (unlikely(opp_table->regulator_count == -1))
opp_table->regulator_count = 1;
/* There can be one or three elements per supply */
if (vcount != supplies && vcount != supplies * 3) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, vcount, supplies);
return -EINVAL;
if (count != opp_table->regulator_count &&
(!triplet || count != opp_table->regulator_count * 3)) {
dev_err(dev, "%s: Invalid number of elements in %s property (%u) with supplies (%d)\n",
__func__, prop_type, count, opp_table->regulator_count);
return ERR_PTR(-EINVAL);
}
microvolt = kmalloc_array(vcount, sizeof(*microvolt), GFP_KERNEL);
if (!microvolt)
return -ENOMEM;
out = kmalloc_array(count, sizeof(*out), GFP_KERNEL);
if (!out)
return ERR_PTR(-EINVAL);
ret = of_property_read_u32_array(opp->np, name, microvolt, vcount);
ret = of_property_read_u32_array(opp->np, name, out, count);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__, name, ret);
ret = -EINVAL;
goto free_microvolt;
kfree(out);
return ERR_PTR(-EINVAL);
}
/* Search for "opp-microamp-<name>" */
prop = NULL;
if (opp_table->prop_name) {
snprintf(name, sizeof(name), "opp-microamp-%s",
opp_table->prop_name);
prop = of_find_property(opp->np, name, NULL);
}
if (triplet)
*triplet = count != opp_table->regulator_count;
if (!prop) {
/* Search for "opp-microamp" */
sprintf(name, "opp-microamp");
prop = of_find_property(opp->np, name, NULL);
}
if (prop) {
icount = of_property_count_u32_elems(opp->np, name);
if (icount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
name, icount);
ret = icount;
goto free_microvolt;
}
return out;
}
if (icount != supplies) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, icount, supplies);
ret = -EINVAL;
goto free_microvolt;
}
static u32 *opp_parse_microvolt(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table, bool *triplet)
{
u32 *microvolt;
microamp = kmalloc_array(icount, sizeof(*microamp), GFP_KERNEL);
if (!microamp) {
ret = -EINVAL;
goto free_microvolt;
}
microvolt = _parse_named_prop(opp, dev, opp_table, "microvolt", triplet);
if (IS_ERR(microvolt))
return microvolt;
ret = of_property_read_u32_array(opp->np, name, microamp,
icount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
name, ret);
ret = -EINVAL;
goto free_microamp;
if (!microvolt) {
/*
* Missing property isn't a problem, but an invalid
* entry is. This property isn't optional if regulator
* information is provided. Check only for the first OPP, as
* regulator_count may get initialized after that to a valid
* value.
*/
if (list_empty(&opp_table->opp_list) &&
opp_table->regulator_count > 0) {
dev_err(dev, "%s: opp-microvolt missing although OPP managing regulators\n",
__func__);
return ERR_PTR(-EINVAL);
}
}
/* Search for "opp-microwatt" */
sprintf(name, "opp-microwatt");
prop = of_find_property(opp->np, name, NULL);
return microvolt;
}
if (prop) {
pcount = of_property_count_u32_elems(opp->np, name);
if (pcount < 0) {
dev_err(dev, "%s: Invalid %s property (%d)\n", __func__,
name, pcount);
ret = pcount;
goto free_microamp;
}
static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
struct opp_table *opp_table)
{
u32 *microvolt, *microamp, *microwatt;
int ret = 0, i, j;
bool triplet;
if (pcount != supplies) {
dev_err(dev, "%s: Invalid number of elements in %s property (%d) with supplies (%d)\n",
__func__, name, pcount, supplies);
ret = -EINVAL;
goto free_microamp;
microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
if (IS_ERR(microvolt))
return PTR_ERR(microvolt);
microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
if (IS_ERR(microamp)) {
ret = PTR_ERR(microamp);
goto free_microvolt;
}
microwatt = kmalloc_array(pcount, sizeof(*microwatt),
GFP_KERNEL);
if (!microwatt) {
ret = -EINVAL;
microwatt = _parse_named_prop(opp, dev, opp_table, "microwatt", NULL);
if (IS_ERR(microwatt)) {
ret = PTR_ERR(microwatt);
goto free_microamp;
}
ret = of_property_read_u32_array(opp->np, name, microwatt,
pcount);
if (ret) {
dev_err(dev, "%s: error parsing %s: %d\n", __func__,
name, ret);
ret = -EINVAL;
goto free_microwatt;
}
/*
* Initialize regulator_count if it is uninitialized and no properties
* are found.
*/
if (unlikely(opp_table->regulator_count == -1)) {
opp_table->regulator_count = 0;
return 0;
}
for (i = 0, j = 0; i < supplies; i++) {
for (i = 0, j = 0; i < opp_table->regulator_count; i++) {
if (microvolt) {
opp->supplies[i].u_volt = microvolt[j++];
if (vcount == supplies) {
opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
} else {
if (triplet) {
opp->supplies[i].u_volt_min = microvolt[j++];
opp->supplies[i].u_volt_max = microvolt[j++];
} else {
opp->supplies[i].u_volt_min = opp->supplies[i].u_volt;
opp->supplies[i].u_volt_max = opp->supplies[i].u_volt;
}
}
if (microamp)
......@@ -750,7 +721,6 @@ static int opp_parse_supplies(struct dev_pm_opp *opp, struct device *dev,
opp->supplies[i].u_watt = microwatt[i];
}
free_microwatt:
kfree(microwatt);
free_microamp:
kfree(microamp);
......
......@@ -203,6 +203,7 @@ static const struct x86_cpu_id intel_uncore_cpu_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, NULL),
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, NULL),
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, NULL),
X86_MATCH_INTEL_FAM6_MODEL(EMERALDRAPIDS_X, NULL),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_uncore_cpu_ids);
......
......@@ -44,6 +44,19 @@ config IDLE_INJECT
synchronously on a set of specified CPUs or alternatively
on a per CPU basis.
config ARM_SCMI_POWERCAP
tristate "ARM SCMI Powercap driver"
depends on ARM_SCMI_PROTOCOL
help
This enables support for the ARM Powercap based on ARM SCMI
Powercap protocol.
ARM SCMI Powercap protocol allows power limits to be enforced
and monitored against the SCMI Powercap domains advertised as
available by the SCMI platform firmware.
When compiled as module it will be called arm_scmi_powercap.ko.
config DTPM
bool "Power capping for Dynamic Thermal Power Management (EXPERIMENTAL)"
depends on OF
......
......@@ -6,3 +6,4 @@ obj-$(CONFIG_POWERCAP) += powercap_sys.o
obj-$(CONFIG_INTEL_RAPL_CORE) += intel_rapl_common.o
obj-$(CONFIG_INTEL_RAPL) += intel_rapl_msr.o
obj-$(CONFIG_IDLE_INJECT) += idle_inject.o
obj-$(CONFIG_ARM_SCMI_POWERCAP) += arm_scmi_powercap.o
This diff is collapsed.
......@@ -147,6 +147,7 @@ static void idle_inject_fn(unsigned int cpu)
/**
* idle_inject_set_duration - idle and run duration update helper
* @ii_dev: idle injection control device structure
* @run_duration_us: CPU run time to allow in microseconds
* @idle_duration_us: CPU idle time to inject in microseconds
*/
......@@ -162,6 +163,7 @@ void idle_inject_set_duration(struct idle_inject_device *ii_dev,
/**
* idle_inject_get_duration - idle and run duration retrieval helper
* @ii_dev: idle injection control device structure
* @run_duration_us: memory location to store the current CPU run time
* @idle_duration_us: memory location to store the current CPU idle time
*/
......@@ -175,6 +177,7 @@ void idle_inject_get_duration(struct idle_inject_device *ii_dev,
/**
* idle_inject_set_latency - set the maximum latency allowed
* @ii_dev: idle injection control device structure
* @latency_us: set the latency requirement for the idle state
*/
void idle_inject_set_latency(struct idle_inject_device *ii_dev,
......
......@@ -7,6 +7,7 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kstrtox.h>
#include <linux/slab.h>
#include <linux/powercap.h>
......@@ -446,7 +447,7 @@ static ssize_t enabled_store(struct device *dev,
{
bool mode;
if (strtobool(buf, &mode))
if (kstrtobool(buf, &mode))
return -EINVAL;
if (dev->parent) {
struct powercap_zone *power_zone = to_powercap_zone(dev);
......
......@@ -62,7 +62,7 @@ static int notifier_chain_unregister(struct notifier_block **nl,
* value of this parameter is -1.
* @nr_calls: Records the number of notifications sent. Don't care
* value of this field is NULL.
* @returns: notifier_call_chain returns the value returned by the
* Return: notifier_call_chain returns the value returned by the
* last notifier function called.
*/
static int notifier_call_chain(struct notifier_block **nl,
......@@ -105,13 +105,13 @@ NOKPROBE_SYMBOL(notifier_call_chain);
* @val_up: Value passed unmodified to the notifier function
* @val_down: Value passed unmodified to the notifier function when recovering
* from an error on @val_up
* @v Pointer passed unmodified to the notifier function
* @v: Pointer passed unmodified to the notifier function
*
* NOTE: It is important the @nl chain doesn't change between the two
* invocations of notifier_call_chain() such that we visit the
* exact same notifier callbacks; this rules out any RCU usage.
*
* Returns: the return value of the @val_up call.
* Return: the return value of the @val_up call.
*/
static int notifier_call_chain_robust(struct notifier_block **nl,
unsigned long val_up, unsigned long val_down,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment