lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20241112052211.3087348-2-nico@fluxnic.net>
Date: Tue, 12 Nov 2024 00:19:38 -0500
From: Nicolas Pitre <nico@...xnic.net>
To: Daniel Lezcano <daniel.lezcano@...aro.org>,
	"Rafael J . Wysocki" <rafael@...nel.org>,
	linux-pm@...r.kernel.org,
	linux-mediatek@...ts.infradead.org,
	devicetree@...r.kernel.org
Cc: linux-kernel@...r.kernel.org,
	Nicolas Pitre <npitre@...libre.com>,
	Alexandre Bailon <abailon@...libre.com>
Subject: [PATCH 1/5] thermal: of: properly parse coefficients with multiple thermal-sensors entries

From: Nicolas Pitre <npitre@...libre.com>

The thermal zone DT binding description says:

      coefficients:
        $ref: /schemas/types.yaml#/definitions/uint32-array
        description:
          An array of integers containing the coefficients of a linear
          equation that binds all the sensors listed in this thermal zone.

          The linear equation used is as follows,
            z = c0 * x0 + c1 * x1 + ... + c(n-1) * x(n-1) + cn
          where c0, c1, .., cn are the coefficients.

          Coefficients default to 1 in case this property is not
          specified. The coefficients are ordered and are matched with
          sensors by means of the sensor ID. Additional coefficients are
          interpreted as constant offset.

And the code says:

        /*
         * For now, the thermal framework supports only one sensor per
         * thermal zone. Thus, we are considering only the first two
         * values as slope and offset.
         */

Furthermore, only bcm2711_thermal, bcm2835_thermal and ti-soc-thermal
use these values.

It is not clear how the equation in the bindings documentation should be
interpreted especially in the context of multiple sensors and sensor
aggregation. Assuming x0..xn are temperature values, coefficients have
to be fractional values otherwise the sum won't correspond to a
temperature anymore. So this patch interprets those coefficients as
per-sensor weight for determining the aggregated temperature value
instead. Also, in that context, constant offsets make no sense so they're
always set to 0. Because those weights are integer values, they must all be
provided otherwise they all default to 1.

To preserve backward compatibility, the current behavior is preserved
when "thermal-sensors" contains only one entry. The alternative
interpretation is applied only when "thermal-sensors" holds multiple
entries (which never happened so far).

Signed-off-by: Nicolas Pitre <npitre@...libre.com>
---
 drivers/thermal/thermal_of.c | 63 +++++++++++++++++++++++++++---------
 1 file changed, 47 insertions(+), 16 deletions(-)

diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 07e0989716..b8ddd41247 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -136,7 +136,8 @@ static struct thermal_trip *thermal_of_trips_init(struct device_node *np, int *n
 	return ERR_PTR(ret);
 }
 
-static struct device_node *of_thermal_zone_find(struct device_node *sensor, int id)
+static struct device_node *of_thermal_zone_find(struct device_node *sensor,
+						int id, int *index)
 {
 	struct device_node *np, *tz;
 	struct of_phandle_args sensor_specs;
@@ -179,6 +180,8 @@ static struct device_node *of_thermal_zone_find(struct device_node *sensor, int
 			if ((sensor == sensor_specs.np) && id == (sensor_specs.args_count ?
 								  sensor_specs.args[0] : 0)) {
 				pr_debug("sensor %pOFn id=%d belongs to %pOFn\n", sensor, id, child);
+				/* return index only if multiple entries exist */
+				*index = (count > 1) ? i : -1;
 				tz = no_free_ptr(child);
 				goto out;
 			}
@@ -213,11 +216,10 @@ static int thermal_of_monitor_init(struct device_node *np, int *delay, int *pdel
 	return 0;
 }
 
-static void thermal_of_parameters_init(struct device_node *np,
+static void thermal_of_parameters_init(struct device_node *np, int index,
 				       struct thermal_zone_params *tzp)
 {
-	int coef[2];
-	int ncoef = ARRAY_SIZE(coef);
+	int ncoef, count;
 	int prop, ret;
 
 	tzp->no_hwmon = true;
@@ -226,18 +228,46 @@ static void thermal_of_parameters_init(struct device_node *np,
 		tzp->sustainable_power = prop;
 
 	/*
-	 * For now, the thermal framework supports only one sensor per
-	 * thermal zone. Thus, we are considering only the first two
-	 * values as slope and offset.
+	 * If only one sensor is specified in "thermal-sensors" (index == -1)
+	 * then only the first two "coefficients" values are considered, and
+	 * used as slope and offset (legacy interpretation).
+	 *
+	 * If /thermal-sensors" contains more than one sensor then index
+	 * contains a positive value indicating the "coefficients" value of
+	 * interest. The listed sensors are meant to be aggregated and the
+	 * provided coefficients represent the relative weight among those
+	 * sensors. The slope field is used for that purpose while the offset
+	 * is always 0.
 	 */
-	ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
-	if (ret) {
-		coef[0] = 1;
-		coef[1] = 0;
+	tzp->slope = 1;
+	tzp->offset = 0;
+	if (index == -1) {
+		int coef[2];
+
+		ncoef = ARRAY_SIZE(coef);
+		ret = of_property_read_u32_array(np, "coefficients", coef, ncoef);
+		if (!ret) {
+			tzp->slope = coef[0];
+			tzp->offset = coef[1];
+		}
+	} else {
+		ncoef = of_property_count_u32_elems(np, "coefficients");
+		if (ncoef > 0) {
+			count = of_count_phandle_with_args(np, "thermal-sensors",
+							   "#thermal-sensor-cells");
+			if (ncoef != count) {
+				pr_err("%pOFn: sensors and coefficients mismatch\n", np);
+			} else {
+				int *coef = kmalloc(sizeof(*coef) * (index + 1),
+						    GFP_KERNEL);
+				if (coef &&
+				    of_property_read_u32_array(np, "coefficients",
+							       coef, (index + 1)) == 0)
+					tzp->slope = coef[index];
+				kfree(coef);
+			}
+		}
 	}
-
-	tzp->slope = coef[0];
-	tzp->offset = coef[1];
 }
 
 static struct device_node *thermal_of_zone_get_by_name(struct thermal_zone_device *tz)
@@ -386,9 +416,10 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
 	const char *action;
 	int delay, pdelay;
 	int ntrips;
+	int index;
 	int ret;
 
-	np = of_thermal_zone_find(sensor, id);
+	np = of_thermal_zone_find(sensor, id, &index);
 	if (IS_ERR(np)) {
 		if (PTR_ERR(np) != -ENODEV)
 			pr_err("Failed to find thermal zone for %pOFn id=%d\n", sensor, id);
@@ -411,7 +442,7 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
 		goto out_kfree_trips;
 	}
 
-	thermal_of_parameters_init(np, &tzp);
+	thermal_of_parameters_init(np, index, &tzp);
 
 	of_ops.should_bind = thermal_of_should_bind;
 
-- 
2.47.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ