Skip to content

Commit

Permalink
Merge branches 'powercap', 'pm-x86', 'pm-opp' and 'pm-misc'
Browse files Browse the repository at this point in the history
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
  • Loading branch information
rafaeljw committed Dec 12, 2022
5 parents 7680d45 + 98e596f + 9c252ec + 68bf66a + f9b4dc9 commit e0e4451
Show file tree
Hide file tree
Showing 11 changed files with 636 additions and 137 deletions.
6 changes: 3 additions & 3 deletions Documentation/devicetree/bindings/opp/opp-v2-base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Documentation/devicetree/bindings/opp/opp-v2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
};
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
228 changes: 99 additions & 129 deletions drivers/opp/of.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/* 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;
/*
* 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;

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;
}

/* 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);
kfree(out);
return ERR_PTR(-EINVAL);
}

if (!prop) {
/* Search for "opp-microamp" */
sprintf(name, "opp-microamp");
prop = of_find_property(opp->np, name, NULL);
}
if (triplet)
*triplet = count != opp_table->regulator_count;

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);

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;
}
return microvolt;
}

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;
}
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;

microwatt = kmalloc_array(pcount, sizeof(*microwatt),
GFP_KERNEL);
if (!microwatt) {
ret = -EINVAL;
goto free_microamp;
}
microvolt = opp_parse_microvolt(opp, dev, opp_table, &triplet);
if (IS_ERR(microvolt))
return PTR_ERR(microvolt);

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;
}
microamp = _parse_named_prop(opp, dev, opp_table, "microamp", NULL);
if (IS_ERR(microamp)) {
ret = PTR_ERR(microamp);
goto free_microvolt;
}

for (i = 0, j = 0; i < supplies; i++) {
opp->supplies[i].u_volt = microvolt[j++];
microwatt = _parse_named_prop(opp, dev, opp_table, "microwatt", NULL);
if (IS_ERR(microwatt)) {
ret = PTR_ERR(microwatt);
goto free_microamp;
}

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 {
opp->supplies[i].u_volt_min = microvolt[j++];
opp->supplies[i].u_volt_max = microvolt[j++];
/*
* 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 < opp_table->regulator_count; i++) {
if (microvolt) {
opp->supplies[i].u_volt = microvolt[j++];

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)
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
13 changes: 13 additions & 0 deletions drivers/powercap/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/powercap/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading

0 comments on commit e0e4451

Please sign in to comment.