* [PATCH 0/5] thermal: multi-sensor aggregation support
@ 2024-11-12 5:19 Nicolas Pitre
2024-11-12 5:19 ` [PATCH 1/5] thermal: of: properly parse coefficients with multiple thermal-sensors entries Nicolas Pitre
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-12 5:19 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
This series provides support for thermal aggregation of multiple sensors.
The "one sensor per zone" model is preserved for all its advantages.
Aggregation is performed via the creation of a special zone whose purpose
consists in aggregating its associated primary zones using a weighted
average.
Motivation for this work stems from use cases where multiple sensors are
contained within the same performance domain. In such case it is preferable
to apply thermal mitigation while considering all such sensors as a whole.
Previous incarnation by Alexandre Bailon can be found here:
https://patchwork.kernel.org/project/linux-pm/cover/20240613132410.161663-1-abailon@baylibre.com/
diffstat:
.../bindings/thermal/thermal-zones.yaml | 5 +-
arch/arm64/boot/dts/mediatek/mt8195.dtsi | 210 +-----
drivers/thermal/Kconfig | 27 +
drivers/thermal/thermal_core.c | 643 ++++++++++++++++++
drivers/thermal/thermal_core.h | 14 +
drivers/thermal/thermal_of.c | 86 ++-
6 files changed, 780 insertions(+), 205 deletions(-)
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/5] thermal: of: properly parse coefficients with multiple thermal-sensors entries
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
@ 2024-11-12 5:19 ` Nicolas Pitre
2024-11-12 5:19 ` [PATCH 2/5] dt-bindings: thermal: Restore the thermal-sensors property Nicolas Pitre
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-12 5:19 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
From: Nicolas Pitre <npitre@baylibre.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@baylibre.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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/5] dt-bindings: thermal: Restore the thermal-sensors property
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
2024-11-12 5:19 ` [PATCH 1/5] thermal: of: properly parse coefficients with multiple thermal-sensors entries Nicolas Pitre
@ 2024-11-12 5:19 ` Nicolas Pitre
2024-11-12 5:19 ` [PATCH 3/5] thermal: aggregation support Nicolas Pitre
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-12 5:19 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
From: Alexandre Bailon <abailon@baylibre.com>
thermal-sensors was defined in thermal.txt but when the yaml binding
has been defined, its definition has changed, dropping support of multi
sensors.
Since we are adding support of multi sensors, use the original definition
for thermal-sensors property.
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
---
Documentation/devicetree/bindings/thermal/thermal-zones.yaml | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml
index 0f435be1db..cc98f87633 100644
--- a/Documentation/devicetree/bindings/thermal/thermal-zones.yaml
+++ b/Documentation/devicetree/bindings/thermal/thermal-zones.yaml
@@ -96,10 +96,9 @@ patternProperties:
thermal-sensors:
$ref: /schemas/types.yaml#/definitions/phandle-array
- maxItems: 1
description:
- The thermal sensor phandle and sensor specifier used to monitor this
- thermal zone.
+ A list of thermal sensor phandles and sensor specifier
+ used while monitoring the thermal zone.
coefficients:
$ref: /schemas/types.yaml#/definitions/uint32-array
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/5] thermal: aggregation support
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
2024-11-12 5:19 ` [PATCH 1/5] thermal: of: properly parse coefficients with multiple thermal-sensors entries Nicolas Pitre
2024-11-12 5:19 ` [PATCH 2/5] dt-bindings: thermal: Restore the thermal-sensors property Nicolas Pitre
@ 2024-11-12 5:19 ` Nicolas Pitre
2024-11-12 5:19 ` [PATCH 4/5] thermal: automatic " Nicolas Pitre
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-12 5:19 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
From: Nicolas Pitre <npitre@baylibre.com>
This provides support for the creation of virtual thermal zone devices
that serve as aggregation point for other devices. Individual primary
thermal devices remain accessible in sysfs but all cooling device bindings
are moved over to the thermal aggregator whose temperature is the weighted
average of its primary devices. Trip points are inherited from the
aggregator but only the aggregator will bind to cooling devices.
Although cooling devices are bound to the aggregator, critical trip
points remain individually accessible, and more importantly triggerable
for each primary device.
Full visibility of primary devices is preserved via the sysfs interface.
Some sysfs symbolic links are created to represent the hierarchical
relationship between the aggregator and its primary devices.
When this is enabled, the aggregation is applied to all entries found in
the device tree's "thermal-sensors" list when it contains more than one
entry. For example, let's consider:
```
thermal_zones: thermal-zones {
cpu0-thermal {
thermal-sensors = <&sensor_mcu 0>;
};
cpu1-thermal {
thermal-sensors = <&sensor_mcu 1>;
};
};
```
The above won't provide any aggregation. However:
```
thermal_zones: thermal-zones {
cluster0-thermal {
thermal-sensors = <&sensor_mcu 0>,
<&sensor_mcu 1>;
coefficients = <6 4>;
};
};
```
The above will create the "cluster0-thermal" aggregator that combines
the "sensor_mcu(0)" and "sensor_mcu(1)" primary zones whose thermal
measurement contributions are 60% and 40% respectively.
In sysfs we have:
```
$ cd /sys/class/thermal
$ ls -l thermal_zone*/aggregator
lrwxrwxrwx 1 root root ... thermal_zone5/aggregator -> ../thermal_zone4
lrwxrwxrwx 1 root root ... thermal_zone6/aggregator -> ../thermal_zone4
$ ls ls -l thermal_zone*/primary_zone*
lrwxrwxrwx 1 root root ... thermal_zone4/primary_zone_0 -> ../thermal_zone5
lrwxrwxrwx 1 root root ... thermal_zone4/primary_zone_1 -> ../thermal_zone6
$ cat thermal_zone4/type
cluster0-thermal
$ cat thermal_zone*/primary_zone*/type
sensor_mcu(0)
sensor_mcu(1)
```
Future work may allow the addition and removal of primary thermal zones
to an aggregadirectly tor within sysfs for added flexibility.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
---
drivers/thermal/Kconfig | 15 ++
drivers/thermal/thermal_core.c | 416 +++++++++++++++++++++++++++++++++
drivers/thermal/thermal_core.h | 14 ++
drivers/thermal/thermal_of.c | 23 +-
4 files changed, 467 insertions(+), 1 deletion(-)
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 61e7ae524b..111f07b52a 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -220,6 +220,21 @@ config DEVFREQ_THERMAL
If you want this support, you should say Y here.
+config THERMAL_AGGREGATION
+ bool "Thermal zone aggregation support"
+ depends on THERMAL_OF
+ help
+ This provides support for the creation of virtual thermal zone
+ devices that serve as aggregation point for other devices.
+ Individual primary thermal devices remain accessible in sysfs
+ but all cooling device bindings are moved over to the thermal
+ aggregator whose temperature is the weighted average of its
+ primary devices.
+
+ When this is enabled, the aggregation is applied to all entries
+ found in the device tree's "thermal-sensors" list when it contains
+ more than one entry.
+
config THERMAL_EMULATION
bool "Thermal emulation mode support"
help
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 8f03985f97..73a1b30081 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -748,6 +748,13 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id)
* binding, and unbinding.
*/
+#ifdef CONFIG_THERMAL_AGGREGATION
+static void thermal_remove_tz_from_aggregator(struct thermal_zone_device *tz);
+#else
+static inline void thermal_remove_tz_from_aggregator(struct thermal_zone_device *tz)
+{}
+#endif /* CONFIG_THERMAL_AGGREGATION */
+
/**
* thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone
* @tz: pointer to struct thermal_zone_device
@@ -1577,6 +1584,8 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
thermal_debug_tz_remove(tz);
+ thermal_remove_tz_from_aggregator(tz);
+
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node)
if (pos == tz)
@@ -1654,6 +1663,413 @@ struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name)
}
EXPORT_SYMBOL_GPL(thermal_zone_get_zone_by_name);
+#ifdef CONFIG_THERMAL_AGGREGATION
+
+static LIST_HEAD(thermal_aggregator_list);
+
+struct thermal_zone_aggregator {
+ struct thermal_zone_device *tz;
+ struct list_head primary_tz_list;
+ struct mutex lock;
+ struct ida ida;
+ struct list_head node;
+};
+
+static bool is_aggregated(struct thermal_zone_device *tz)
+{
+ return tz->aggregator != NULL;
+}
+
+/*
+ * Get weighted average temperature for all aggregated zones.
+ *
+ * A "max temp" variant could also be provided but the end result on the
+ * cooling device would be the same as if no aggregation was done in the
+ * first place.
+ */
+static int thermal_aggr_get_average_temp(struct thermal_zone_device *aggr_tz,
+ int *aggr_temp)
+{
+ struct thermal_zone_aggregator *aggr = aggr_tz->devdata;
+ struct thermal_zone_device *tz;
+ int temp, weight;
+ s64 temp_sum = 0;
+ u32 weight_sum = 0;
+ int ret = -ENODATA;
+
+ mutex_lock(&aggr->lock);
+ list_for_each_entry(tz, &aggr->primary_tz_list, aggregated_node) {
+ mutex_lock(&tz->lock);
+ if (tz->suspended || tz->mode != THERMAL_DEVICE_ENABLED) {
+ mutex_unlock(&tz->lock);
+ continue;
+ }
+ ret = __thermal_zone_get_temp(tz, &temp);
+ if (ret) {
+ mutex_unlock(&tz->lock);
+ break;
+ }
+ if (temp <= THERMAL_TEMP_INVALID) {
+ /*
+ * Invalid temp values are ignored, unless all
+ * primary zones are invalid in which case it is
+ * passed up to accommodate the special case in
+ * __thermal_zone_device_update().
+ */
+ *aggr_temp = temp;
+ } else {
+ weight = tz->tzp->slope;
+ temp_sum += (s64)temp * weight;
+ weight_sum += weight;
+ }
+ mutex_unlock(&tz->lock);
+ }
+ mutex_unlock(&aggr->lock);
+
+ if (weight_sum)
+ *aggr_temp = div_s64(temp_sum, weight_sum);
+
+ return ret;
+}
+
+static int thermal_aggr_set_trips(struct thermal_zone_device *aggr_tz,
+ int low, int high)
+{
+ struct thermal_zone_aggregator *aggr = aggr_tz->devdata;
+ struct thermal_zone_device *tz;
+
+ mutex_lock(&aggr->lock);
+ list_for_each_entry(tz, &aggr->primary_tz_list, aggregated_node) {
+ mutex_lock(&tz->lock);
+ if (!tz->suspended && tz->mode == THERMAL_DEVICE_ENABLED)
+ thermal_zone_set_trips(tz, low, high);
+ mutex_unlock(&tz->lock);
+ }
+ mutex_unlock(&aggr->lock);
+
+ return 0;
+}
+
+static int thermal_aggr_change_mode(struct thermal_zone_device *aggr_tz,
+ enum thermal_device_mode mode)
+{
+ struct thermal_zone_aggregator *aggr = aggr_tz->devdata;
+ struct thermal_zone_device *tz;
+ int ret, err = 0;
+
+ mutex_lock(&aggr->lock);
+ list_for_each_entry(tz, &aggr->primary_tz_list, aggregated_node) {
+ ret = thermal_zone_device_set_mode(tz, mode);
+ if (ret)
+ err = ret;
+ /* cycle through all tz's even if there are errors */
+ }
+ mutex_unlock(&aggr->lock);
+
+ return err;
+}
+
+static const struct thermal_zone_device_ops thermal_aggr_tz_ops = {
+ .get_temp = thermal_aggr_get_average_temp,
+ .set_trips = thermal_aggr_set_trips,
+ .change_mode = thermal_aggr_change_mode,
+};
+
+/**
+ * create_thermal_aggregator - create a tz to be used as an aggregator
+ *
+ * @ref_tz: the tz from which parameters such as trip values are copied
+ * @name: name to identify this aggregator
+ *
+ * This creates a virtual thermal zone to be used as an aggregator for
+ * other zones called "primary" zones. Those primary zones must be added to
+ * the created aggregator with add_tz_to_aggregator().
+ *
+ * Return: a pointer to the created struct thermal_zone_device or an ERR_PTR
+ * value in case of errors.
+ */
+static struct thermal_zone_device *
+create_thermal_aggregator(struct thermal_zone_device *ref_tz, const char *name)
+{
+ struct thermal_zone_aggregator *aggr;
+ struct thermal_zone_device *aggr_tz;
+ struct thermal_trip *trips;
+ int ntrips = ref_tz->num_trips;
+ int ret;
+
+ trips = kcalloc(ntrips, sizeof(*trips), GFP_KERNEL);
+ if (!trips)
+ return ERR_PTR(-ENOMEM);
+ for (int i = 0; i < ntrips; i++)
+ trips[i] = ref_tz->trips[i].trip;
+
+ aggr = kzalloc(sizeof(*aggr), GFP_KERNEL);
+ if (!aggr) {
+ ret = -ENOMEM;
+ goto err_free_trips;
+ }
+ mutex_init(&aggr->lock);
+ INIT_LIST_HEAD(&aggr->primary_tz_list);
+ ida_init(&aggr->ida);
+
+ aggr_tz = thermal_zone_device_register_with_trips(name, trips, ntrips,
+ aggr,
+ &thermal_aggr_tz_ops,
+ ref_tz->tzp, 0, 0);
+ if (IS_ERR(aggr_tz)) {
+ ret = PTR_ERR(aggr_tz);
+ pr_err("Failed to register thermal aggregator zone: %d\n", ret);
+ goto err_free_aggr;
+ }
+ aggr_tz->polling_delay_jiffies = ref_tz->polling_delay_jiffies;
+ aggr_tz->passive_delay_jiffies = ref_tz->passive_delay_jiffies;
+ aggr_tz->ops.should_bind = ref_tz->ops.should_bind;
+ aggr->tz = aggr_tz;
+ kfree(trips);
+
+ ret = thermal_zone_device_enable(aggr_tz);
+ if (ret) {
+ pr_err("Failed to enable thermal aggregator zone: %d\n", ret);
+ goto err_unregister_tz;
+ }
+
+ mutex_lock(&thermal_list_lock);
+ list_add_tail(&aggr->node, &thermal_aggregator_list);
+ mutex_unlock(&thermal_list_lock);
+
+ return aggr_tz;
+
+err_unregister_tz:
+ thermal_zone_device_unregister(aggr_tz);
+err_free_aggr:
+ ida_destroy(&aggr->ida);
+ kfree(aggr);
+err_free_trips:
+ kfree(trips);
+ return ERR_PTR(ret);
+}
+
+/**
+ * add_tz_to_aggregator() - add a primary zone to an aggregator
+ *
+ * @aggr_tz: the aggregator tz to use, as returned by create_thermal_aggregator()
+ * @tz: a primary tz to be added
+ *
+ * This enrolls a primary tz with an aggregator tz. Thermal instances
+ * (bindings) from the primary tz are moved to the aggregator. It is assumed
+ * that all primary tz's added to a given aggregator have the same set of
+ * trip points. This can be called with an already enrolled tz in which case
+ * only new thermal instances from the primary, if any, will be moved over
+ * to the aggregator. Duplicate thermal instances are simply dropped.
+ *
+ * An "aggregator" symlink is created within the primary tz's sysfs directory
+ * to the aggregator tz directory. And a list of "primary_zone_<n>" symlinks
+ * in the aggregator's directory point back to all primary tz's it owns.
+ */
+static void add_tz_to_aggregator(struct thermal_zone_device *aggr_tz,
+ struct thermal_zone_device *tz)
+{
+ struct thermal_zone_aggregator *aggr = aggr_tz->devdata;
+ struct thermal_instance *ti, *next;
+ int ret;
+
+ mutex_lock(&aggr->lock);
+ mutex_lock(&aggr_tz->lock);
+ mutex_lock(&tz->lock);
+
+ /* duplicate thermal instances onto the aggregator */
+ list_for_each_entry(ti, &tz->thermal_instances, tz_node) {
+ int i = thermal_zone_trip_id(tz, ti->trip);
+ struct thermal_trip *aggr_trip = &aggr_tz->trips[i].trip;
+ struct thermal_cooling_device *cdev = ti->cdev;
+ struct cooling_spec c = {
+ .upper = ti->upper_no_limit ? THERMAL_NO_LIMIT : ti->upper,
+ .lower = ti->lower,
+ .weight = ti->weight,
+ };
+ ret = thermal_bind_cdev_to_trip(aggr_tz, aggr_trip, cdev, &c);
+ if (ret == -EEXIST)
+ ret = 0;
+ if (ret) {
+ print_bind_err_msg(aggr_tz, aggr_trip, cdev, ret);
+ goto out;
+ }
+ }
+
+ /* remove thermal instances from the primary tz */
+ list_for_each_entry_safe(ti, next, &tz->thermal_instances, tz_node) {
+ thermal_unbind_cdev_from_trip(tz, ti->trip, ti->cdev);
+ }
+
+ if (!tz->aggregator) {
+ list_add_tail(&tz->aggregated_node, &aggr->primary_tz_list);
+ tz->aggregator = aggr_tz;
+
+ /* add a link from the primary tz to its aggregator */
+ ret = sysfs_create_link(&tz->device.kobj,
+ &aggr_tz->device.kobj,
+ "aggregator");
+ if (ret)
+ dev_err(&tz->device, "linking to aggregator failed: %d\n", ret);
+
+ /* add a link from the aggregator to this primary tz */
+ tz->aggregated_id = ret = ida_alloc(&aggr->ida, GFP_KERNEL);
+ if (ret >= 0) {
+ char name[sizeof("primary_zone_000")];
+
+ snprintf(name, sizeof(name), "primary_zone_%d", ret);
+ ret = sysfs_create_link(&aggr_tz->device.kobj,
+ &tz->device.kobj,
+ name);
+ if (ret) {
+ ida_free(&aggr->ida, tz->aggregated_id);
+ tz->aggregated_id = -1;
+ }
+ }
+ if (ret)
+ dev_err(&aggr_tz->device, "linking to primary failed: %d\n", ret);
+ }
+
+out:
+ mutex_unlock(&tz->lock);
+ mutex_unlock(&aggr_tz->lock);
+ mutex_unlock(&aggr->lock);
+}
+
+/**
+ * free_thermal_aggregator_unlock - unregister and free an aggregator tz
+ *
+ * @aggr_tz: the aggregator to free, as returned by create_thermal_aggregator()
+ *
+ * This unregisters the tz used as an aggregator and frees its associated
+ * memory. This is called by thermal_remove_tz_from_aggregator() when the
+ * last primary tz is removed from the aggregator, or if the aggregator was
+ * created and is no longer needed before any primary tz's have been added
+ * to it.
+ *
+ * Note: To avoid race issues, this is expected to be called with
+ * thermal_list_lock held, but it will be released before returning.
+ */
+static void free_thermal_aggregator_unlock(struct thermal_zone_device *aggr_tz)
+{
+ struct thermal_zone_aggregator *aggr = aggr_tz->devdata;
+
+ lockdep_assert_held(&thermal_list_lock);
+ BUG_ON(!list_empty(&aggr->primary_tz_list));
+
+ list_del(&aggr->node);
+ mutex_unlock(&thermal_list_lock);
+
+ thermal_zone_device_disable(aggr_tz);
+ thermal_zone_device_unregister(aggr_tz);
+ ida_destroy(&aggr->ida);
+ kfree(aggr);
+}
+
+/**
+ * thermal_remove_tz_from_aggregator - remove a primary tz from an aggregator
+ *
+ * @tz: the thermal zone to remove from its aggregator
+ *
+ * This retires a primary tz from its aggregator. If not aggregated, this
+ * is a no-op. Thermal instance bindings are re-established with the primary
+ * tz.
+ *
+ * If given tz was the last one owned by the aggregator, then the aggregator
+ * is destroyed.
+ */
+static void thermal_remove_tz_from_aggregator(struct thermal_zone_device *tz)
+{
+ struct thermal_zone_device *aggr_tz = tz->aggregator;
+ struct thermal_zone_aggregator *aggr = aggr_tz->devdata;
+ struct thermal_cooling_device *cdev;
+
+ if (!is_aggregated(tz))
+ return;
+
+ mutex_lock(&thermal_list_lock);
+
+ /* Bind cooling devices back to this zone */
+ tz->ops.should_bind = aggr_tz->ops.should_bind;
+ list_for_each_entry(cdev, &thermal_cdev_list, node)
+ thermal_zone_cdev_bind(tz, cdev);
+
+ mutex_lock(&aggr->lock);
+ list_del(&tz->aggregated_node);
+ tz->aggregator = NULL;
+ sysfs_remove_link(&tz->device.kobj, "aggregator");
+ if (tz->aggregated_id >= 0) {
+ char name[sizeof("primary_zone_000")];
+
+ snprintf(name, sizeof(name), "primary_zone_%d", tz->aggregated_id);
+ sysfs_remove_link(&aggr_tz->device.kobj, name);
+ ida_free(&aggr->ida, tz->aggregated_id);
+ }
+ mutex_unlock(&aggr->lock);
+
+ if (list_empty(&aggr->primary_tz_list)) {
+ /* no more tz tied to this aggregator */
+ free_thermal_aggregator_unlock(aggr_tz);
+ } else {
+ mutex_unlock(&thermal_list_lock);
+ }
+}
+
+/**
+ * thermal_zone_device_aggregate - aggregate provided thermal zone device
+ *
+ * @tz: the thermal zone to aggregate
+ * @name: the aggregator's name to use
+ *
+ * This adds the provided thermal zone device to the thermal aggregator
+ * identified by @name. If no such aggregator exists it is created.
+ *
+ * In case of any error, the provided thermal zone will remain freestanding
+ * on its own and an error message will be logged. There is no point returning
+ * an error as it would be unwise for the caller to revert registration of
+ * this tz anyway (a suboptimal thermal configuration is better than no
+ * configuration).
+ */
+void thermal_zone_device_aggregate(struct thermal_zone_device *tz,
+ const char *name)
+{
+ struct thermal_zone_aggregator *aggr;
+ struct thermal_zone_device *aggr_tz;
+
+ /* look for an existing aggregator */
+ mutex_lock(&thermal_list_lock);
+ list_for_each_entry(aggr, &thermal_aggregator_list, node) {
+ aggr_tz = aggr->tz;
+ if (strcmp(aggr_tz->type, name) != 0)
+ continue;
+ if (aggr_tz->ops.should_bind != tz->ops.should_bind) {
+ pr_err("%s: same name but ops.should_bind differs\n",
+ __func__);
+ goto out;
+ }
+ goto add;
+ }
+ mutex_unlock(&thermal_list_lock);
+
+ /* no aggregator with specified name exists, create one */
+ aggr_tz = create_thermal_aggregator(tz, name);
+ if (IS_ERR(aggr_tz)) {
+ pr_err("unable to create thermal aggregator (%ld)\n",
+ PTR_ERR(aggr_tz));
+ return;
+ }
+
+ mutex_lock(&thermal_list_lock);
+add:
+ add_tz_to_aggregator(aggr_tz, tz);
+ if (is_aggregated(tz))
+ tz->ops.should_bind = NULL;
+out:
+ mutex_unlock(&thermal_list_lock);
+}
+
+#endif /* CONFIG_THERMAL_AGGREGATION */
+
static void thermal_zone_device_resume(struct work_struct *work)
{
struct thermal_zone_device *tz;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index a64d39b1c8..ff5aa20e82 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -136,6 +136,11 @@ struct thermal_zone_device {
enum thermal_notify_event notify_event;
bool suspended;
bool resuming;
+#ifdef CONFIG_THERMAL_AGGREGATION
+ struct thermal_zone_device *aggregator;
+ struct list_head aggregated_node;
+ int aggregated_id;
+#endif
#ifdef CONFIG_THERMAL_DEBUGFS
struct thermal_debugfs *debugfs;
#endif
@@ -287,4 +292,13 @@ thermal_cooling_device_stats_update(struct thermal_cooling_device *cdev,
unsigned long new_state) {}
#endif /* CONFIG_THERMAL_STATISTICS */
+#ifdef CONFIG_THERMAL_AGGREGATION
+void thermal_zone_device_aggregate(struct thermal_zone_device *tz,
+ const char *aggr_name);
+#else
+static inline void
+thermal_zone_device_aggregate(struct thermal_zone_device *tz, const char *aggr_name)
+{}
+#endif /* CONFIG_THERMAL_AGGREGATION */
+
#endif /* __THERMAL_CORE_H__ */
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index b8ddd41247..1761a60db5 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -451,7 +451,25 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
if (!of_ops.critical && !strcasecmp(action, "reboot"))
of_ops.critical = thermal_zone_device_critical_reboot;
- tz = thermal_zone_device_register_with_trips(np->name, trips, ntrips,
+ /*
+ * The device tree node name is used with single-sensor entries.
+ * When multiple-sensor entries are aggregated, the node name is used
+ * for the aggregator and primary sensors use their compatible alias
+ * name with the id value.
+ */
+ bool multi = (index != -1);
+ char namebuf[THERMAL_NAME_LENGTH];
+ const char *tz_name = namebuf;
+
+ if (!multi)
+ tz_name = np->name;
+ else if (of_alias_from_compatible(sensor, namebuf, sizeof(namebuf)) == 0)
+ snprintf(namebuf + strlen(namebuf), sizeof(namebuf) - strlen(namebuf),
+ "(%d)", id);
+ else
+ snprintf(namebuf, sizeof(namebuf), "%s(%d)", sensor->name, id);
+
+ tz = thermal_zone_device_register_with_trips(tz_name, trips, ntrips,
data, &of_ops, &tzp,
pdelay, delay);
if (IS_ERR(tz)) {
@@ -460,6 +478,9 @@ static struct thermal_zone_device *thermal_of_zone_register(struct device_node *
goto out_kfree_trips;
}
+ if (multi)
+ thermal_zone_device_aggregate(tz, np->name);
+
of_node_put(np);
kfree(trips);
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/5] thermal: automatic aggregation support
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
` (2 preceding siblings ...)
2024-11-12 5:19 ` [PATCH 3/5] thermal: aggregation support Nicolas Pitre
@ 2024-11-12 5:19 ` Nicolas Pitre
2024-11-12 5:19 ` [PATCH 5/5] ARM64: mt8195: Use thermal aggregation for big and little cpu Nicolas Pitre
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-12 5:19 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
From: Nicolas Pitre <npitre@baylibre.com>
Automatically apply thermal aggregation of multiple related thermal zones
into a single one. Here "related" means such zones must have the same trip
points and cooling devices bound to them. This is an alternative to the
device tree's "thermal-sensors" list for testing purpose without actually
modifying the DTB.
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
---
drivers/thermal/Kconfig | 12 ++
drivers/thermal/thermal_core.c | 227 +++++++++++++++++++++++++++++++++
2 files changed, 239 insertions(+)
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 111f07b52a..1b2f319838 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -235,6 +235,18 @@ config THERMAL_AGGREGATION
found in the device tree's "thermal-sensors" list when it contains
more than one entry.
+config THERMAL_AGGREGATION_AUTO
+ bool "Automatic Thermal Aggregation support"
+ depends on THERMAL_AGGREGATION
+ help
+ Automatically apply thermal aggregation of multiple related thermal
+ zones into a single one. Here "related" means such zones must have
+ the same trip points and cooling devices bound to them. This is an
+ alternative to the device tree's "thermal-sensors" list for testing
+ purpose without actually modifying the DTB. It is highly recommended
+ that the device tree method be used in preference to this for actual
+ system deployment.
+
config THERMAL_EMULATION
bool "Thermal emulation mode support"
help
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 73a1b30081..934d248aa9 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -755,6 +755,16 @@ static inline void thermal_remove_tz_from_aggregator(struct thermal_zone_device
{}
#endif /* CONFIG_THERMAL_AGGREGATION */
+#ifdef CONFIG_THERMAL_AGGREGATION_AUTO
+static void thermal_check_zone_for_aggregation(struct thermal_zone_device *target_tz);
+static void thermal_check_cdev_for_aggregation(struct thermal_cooling_device *new_cdev);
+#else
+static inline void thermal_check_zone_for_aggregation(struct thermal_zone_device *target_tz)
+{}
+static inline void thermal_check_cdev_for_aggregation(struct thermal_cooling_device *new_cdev)
+{}
+#endif /* CONFIG_THERMAL_AGGREGATION_AUTO */
+
/**
* thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone
* @tz: pointer to struct thermal_zone_device
@@ -1073,6 +1083,8 @@ __thermal_cooling_device_register(struct device_node *np,
mutex_unlock(&thermal_list_lock);
+ thermal_check_cdev_for_aggregation(cdev);
+
return cdev;
out_cooling_dev:
@@ -1515,6 +1527,8 @@ thermal_zone_device_register_with_trips(const char *type,
if (atomic_cmpxchg(&tz->need_update, 1, 0))
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
+ thermal_check_zone_for_aggregation(tz);
+
thermal_notify_tz_create(tz);
thermal_debug_tz_add(tz);
@@ -2068,6 +2082,219 @@ void thermal_zone_device_aggregate(struct thermal_zone_device *tz,
mutex_unlock(&thermal_list_lock);
}
+#ifdef CONFIG_THERMAL_AGGREGATION_AUTO
+
+static bool is_aggregator(struct thermal_zone_device *tz)
+{
+ return !strcmp(tz->type, "aggregator");
+}
+
+/**
+ * thermal_trip_related - determine if two trips are equivalent
+ *
+ * @tt1, @tt2: thermal trip specs to compare
+ *
+ * Determine if given trips may be candidates for aggregation.
+ *
+ * Return: true if related for aggregation, false otherwise
+ */
+static bool thermal_trip_related(struct thermal_trip *tt1,
+ struct thermal_trip *tt2)
+{
+ return tt1->temperature == tt2->temperature &&
+ tt1->hysteresis == tt2->hysteresis &&
+ tt1->type == tt2->type &&
+ tt1->flags == tt2->flags;
+}
+
+static struct thermal_cooling_device *
+trip_to_cdev(struct thermal_zone_device *tz, int trip_idx)
+{
+ struct thermal_instance *ti;
+
+ list_for_each_entry(ti, &tz->thermal_instances, tz_node)
+ if (trip_to_trip_desc(ti->trip) == &tz->trips[trip_idx])
+ return ti->cdev;
+
+ return NULL;
+}
+
+/**
+ * thermal_zone_related - determine if two tz's are candidates for aggregation
+ *
+ * @tz1, @tz2: thermal zones to compare
+ *
+ * Return: true if related for aggregation, false otherwise
+ */
+static bool thermal_zone_related(struct thermal_zone_device *tz1,
+ struct thermal_zone_device *tz2)
+{
+ /* a tz can't aggregate with itself */
+ if (tz1 == tz2)
+ return false;
+
+ /* no relation possible if ops.should_bind is unset */
+ if (!tz1->ops.should_bind || !tz2->ops.should_bind)
+ return false;
+
+ /* a tz always relates to its aggregator */
+ if (tz1->aggregator == tz2 || tz2->aggregator == tz1)
+ return true;
+
+ /* related tz's must have the same number of trip points */
+ if (tz1->num_trips != tz2->num_trips)
+ return false;
+
+ /* tz's with no cdev bindings are not (yet) considered */
+ if (list_empty(&tz1->thermal_instances) ||
+ list_empty(&tz2->thermal_instances))
+ return false;
+
+ for (int i = 0; i < tz1->num_trips; i++) {
+ /* all trips must be related */
+ if (!thermal_trip_related(&tz1->trips[i].trip, &tz2->trips[i].trip))
+ return false;
+ /* cdevs for given trips must be the same */
+ if (trip_to_cdev(tz1, i) != trip_to_cdev(tz2, i))
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * find_related_tz - look for a tz aggregation candidate
+ *
+ * @target_tz: tz to compare against
+ *
+ * Return: candidate tz for aggregation, or NULL if none
+ */
+static struct thermal_zone_device *
+find_related_tz(struct thermal_zone_device *target_tz)
+{
+ struct thermal_zone_device *tz;
+
+ list_for_each_entry(tz, &thermal_tz_list, node) {
+ if (is_aggregated(tz))
+ continue;
+ if (is_aggregator(tz))
+ continue;
+ if (!thermal_zone_related(tz, target_tz))
+ continue;
+ return tz;
+ }
+
+ return NULL;
+}
+
+/**
+ * thermal_check_zone_for_aggregation - consider tz for aggregation
+ *
+ * @target_tz: tz to compare against
+ *
+ * Adds the provided tz to a compatible aggregator. If none found, look for
+ * the possibility to create a new aggregator if another compatible tz exists.
+ * This is called, notably, when a new tz is registered and potentially bound
+ * to existing cdevs.
+ */
+static void thermal_check_zone_for_aggregation(struct thermal_zone_device *target_tz)
+{
+ struct thermal_zone_aggregator *aggr;
+ struct thermal_zone_device *aggr_tz, *tz;
+
+ if (is_aggregator(target_tz))
+ return;
+
+ mutex_lock(&thermal_list_lock);
+ if (!thermal_zone_is_present(target_tz)) {
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+
+ /* see if existing aggregators can appropriate this zone */
+ list_for_each_entry(aggr, &thermal_aggregator_list, node) {
+ aggr_tz = aggr->tz;
+ if (!thermal_zone_related(aggr_tz, target_tz))
+ continue;
+ pr_debug("aggr %s(%d) and zone %s(%d) are related\n",
+ aggr_tz->type, aggr_tz->id, target_tz->type, target_tz->id);
+ add_tz_to_aggregator(aggr_tz, target_tz);
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+
+ /* see if non-aggregated zones can be aggregated */
+ tz = find_related_tz(target_tz);
+ if (!tz) {
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+
+ pr_debug("zones %s(%d) and %s(%d) are related\n",
+ tz->type, tz->id, target_tz->type, target_tz->id);
+
+ mutex_unlock(&thermal_list_lock);
+ aggr_tz = create_thermal_aggregator(target_tz, "aggregator");
+ if (IS_ERR(aggr_tz)) {
+ pr_err("unable to create thermal aggregator (%ld)\n",
+ PTR_ERR(aggr_tz));
+ return;
+ }
+
+ mutex_lock(&thermal_list_lock);
+
+ /* the lock was momentarily dropped so need to revalide everything */
+ if (thermal_zone_is_present(target_tz)) {
+ tz = find_related_tz(target_tz);
+ if (tz) {
+ add_tz_to_aggregator(aggr_tz, target_tz);
+ add_tz_to_aggregator(aggr_tz, tz);
+ mutex_unlock(&thermal_list_lock);
+ return;
+ }
+ }
+
+ /* our match disappeared in the mean time */
+ free_thermal_aggregator_unlock(aggr_tz);
+}
+
+/**
+ * thermal_check_cdev_for_aggregation - consider aggregation after new cdev registration
+ *
+ * @new_cdev: cdev for which new thermal bindings might create aggregation candidates
+ *
+ * Consider tz's having thermal instance bindings with this new cdev as
+ * candidates for aggregation. This is called when a new cdev is registered
+ * and potentially bound to existing tz's.
+ */
+static void thermal_check_cdev_for_aggregation(struct thermal_cooling_device *new_cdev)
+{
+ struct thermal_zone_device *tz, *last_tz = NULL;
+ struct thermal_instance *ti;
+
+start_over:
+ mutex_lock(&thermal_list_lock);
+
+ list_for_each_entry(tz, &thermal_tz_list, node) {
+ if (tz == last_tz)
+ continue;
+ if (is_aggregator(tz))
+ continue;
+ list_for_each_entry(ti, &tz->thermal_instances, tz_node) {
+ if (ti->cdev == new_cdev) {
+ last_tz = tz;
+ mutex_unlock(&thermal_list_lock);
+ thermal_check_zone_for_aggregation(tz);
+ /* because the lock was dropped ... */
+ goto start_over;
+ }
+ }
+ }
+
+ mutex_unlock(&thermal_list_lock);
+}
+
+#endif /* CONFIG_THERMAL_AGGREGATION_AUTO */
#endif /* CONFIG_THERMAL_AGGREGATION */
static void thermal_zone_device_resume(struct work_struct *work)
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/5] ARM64: mt8195: Use thermal aggregation for big and little cpu
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
` (3 preceding siblings ...)
2024-11-12 5:19 ` [PATCH 4/5] thermal: automatic " Nicolas Pitre
@ 2024-11-12 5:19 ` Nicolas Pitre
2024-11-27 22:05 ` [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
2024-11-29 20:00 ` Daniel Lezcano
6 siblings, 0 replies; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-12 5:19 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
From: Alexandre Bailon <abailon@baylibre.com>
This uses the thermal aggregation for the mt8195 to get the maximal
temperature of big and little cpu clusters.
Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
---
arch/arm64/boot/dts/mediatek/mt8195.dtsi | 210 +++--------------------
1 file changed, 25 insertions(+), 185 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt8195.dtsi b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
index e89ba384c4..a75a56f67e 100644
--- a/arch/arm64/boot/dts/mediatek/mt8195.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt8195.dtsi
@@ -3601,50 +3601,30 @@ dp_tx: dp-tx@1c600000 {
};
thermal_zones: thermal-zones {
- cpu0-thermal {
+ cpu-little {
polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>;
+ polling-delay-passive = <100>;
+ thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU0>,
+ <&lvts_mcu MT8195_MCU_LITTLE_CPU1>,
+ <&lvts_mcu MT8195_MCU_LITTLE_CPU2>,
+ <&lvts_mcu MT8195_MCU_LITTLE_CPU3>;
+ sustainable-power = <1500>;
trips {
- cpu0_alert: trip-alert {
- temperature = <85000>;
+ cpu_little_threshold: trip-point {
+ temperature = <68000>;
hysteresis = <2000>;
type = "passive";
};
- cpu0_crit: trip-crit {
- temperature = <100000>;
- hysteresis = <2000>;
- type = "critical";
- };
- };
-
- cooling-maps {
- map0 {
- trip = <&cpu0_alert>;
- cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-
- cpu1-thermal {
- polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU1>;
-
- trips {
- cpu1_alert: trip-alert {
+ cpu_little_target: target {
temperature = <85000>;
hysteresis = <2000>;
type = "passive";
};
- cpu1_crit: trip-crit {
- temperature = <100000>;
+ cpu_little_soc_max_crit: soc-max-crit {
+ temperature = <115000>;
hysteresis = <2000>;
type = "critical";
};
@@ -3652,7 +3632,7 @@ cpu1_crit: trip-crit {
cooling-maps {
map0 {
- trip = <&cpu1_alert>;
+ trip = <&cpu_little_target>;
cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
@@ -3661,170 +3641,30 @@ map0 {
};
};
- cpu2-thermal {
+ cpu-big {
polling-delay = <1000>;
polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU2>;
+ thermal-sensors = <&lvts_mcu MT8195_MCU_BIG_CPU0>,
+ <&lvts_mcu MT8195_MCU_BIG_CPU1>,
+ <&lvts_mcu MT8195_MCU_BIG_CPU2>,
+ <&lvts_mcu MT8195_MCU_BIG_CPU3>;
+ sustainable-power = <1500>;
trips {
- cpu2_alert: trip-alert {
- temperature = <85000>;
+ cpu_big_threshold: trip-point {
+ temperature = <68000>;
hysteresis = <2000>;
type = "passive";
};
- cpu2_crit: trip-crit {
- temperature = <100000>;
- hysteresis = <2000>;
- type = "critical";
- };
- };
-
- cooling-maps {
- map0 {
- trip = <&cpu2_alert>;
- cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-
- cpu3-thermal {
- polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_LITTLE_CPU3>;
-
- trips {
- cpu3_alert: trip-alert {
- temperature = <85000>;
- hysteresis = <2000>;
- type = "passive";
- };
-
- cpu3_crit: trip-crit {
- temperature = <100000>;
- hysteresis = <2000>;
- type = "critical";
- };
- };
-
- cooling-maps {
- map0 {
- trip = <&cpu3_alert>;
- cooling-device = <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu1 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu2 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu3 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-
- cpu4-thermal {
- polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_BIG_CPU0>;
-
- trips {
- cpu4_alert: trip-alert {
+ cpu_big_target: target {
temperature = <85000>;
hysteresis = <2000>;
type = "passive";
};
- cpu4_crit: trip-crit {
- temperature = <100000>;
- hysteresis = <2000>;
- type = "critical";
- };
- };
-
- cooling-maps {
- map0 {
- trip = <&cpu4_alert>;
- cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-
- cpu5-thermal {
- polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_BIG_CPU1>;
-
- trips {
- cpu5_alert: trip-alert {
- temperature = <85000>;
- hysteresis = <2000>;
- type = "passive";
- };
-
- cpu5_crit: trip-crit {
- temperature = <100000>;
- hysteresis = <2000>;
- type = "critical";
- };
- };
-
- cooling-maps {
- map0 {
- trip = <&cpu5_alert>;
- cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-
- cpu6-thermal {
- polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_BIG_CPU2>;
-
- trips {
- cpu6_alert: trip-alert {
- temperature = <85000>;
- hysteresis = <2000>;
- type = "passive";
- };
-
- cpu6_crit: trip-crit {
- temperature = <100000>;
- hysteresis = <2000>;
- type = "critical";
- };
- };
-
- cooling-maps {
- map0 {
- trip = <&cpu6_alert>;
- cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
- <&cpu7 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
- };
- };
- };
-
- cpu7-thermal {
- polling-delay = <1000>;
- polling-delay-passive = <250>;
- thermal-sensors = <&lvts_mcu MT8195_MCU_BIG_CPU3>;
-
- trips {
- cpu7_alert: trip-alert {
- temperature = <85000>;
- hysteresis = <2000>;
- type = "passive";
- };
-
- cpu7_crit: trip-crit {
- temperature = <100000>;
+ cpu_big_soc_max_crit: soc-max-crit {
+ temperature = <115000>;
hysteresis = <2000>;
type = "critical";
};
@@ -3832,7 +3672,7 @@ cpu7_crit: trip-crit {
cooling-maps {
map0 {
- trip = <&cpu7_alert>;
+ trip = <&cpu_big_target>;
cooling-device = <&cpu4 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu5 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
<&cpu6 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
--
2.47.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 0/5] thermal: multi-sensor aggregation support
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
` (4 preceding siblings ...)
2024-11-12 5:19 ` [PATCH 5/5] ARM64: mt8195: Use thermal aggregation for big and little cpu Nicolas Pitre
@ 2024-11-27 22:05 ` Nicolas Pitre
2024-11-28 17:38 ` Daniel Lezcano
2024-11-29 20:00 ` Daniel Lezcano
6 siblings, 1 reply; 10+ messages in thread
From: Nicolas Pitre @ 2024-11-27 22:05 UTC (permalink / raw)
To: Daniel Lezcano, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Alexandre Bailon
Gentle ping, feedback appreciated.
On Tue, 12 Nov 2024, Nicolas Pitre wrote:
> This series provides support for thermal aggregation of multiple sensors.
> The "one sensor per zone" model is preserved for all its advantages.
> Aggregation is performed via the creation of a special zone whose purpose
> consists in aggregating its associated primary zones using a weighted
> average.
>
> Motivation for this work stems from use cases where multiple sensors are
> contained within the same performance domain. In such case it is preferable
> to apply thermal mitigation while considering all such sensors as a whole.
>
> Previous incarnation by Alexandre Bailon can be found here:
> https://patchwork.kernel.org/project/linux-pm/cover/20240613132410.161663-1-abailon@baylibre.com/
>
> diffstat:
> .../bindings/thermal/thermal-zones.yaml | 5 +-
> arch/arm64/boot/dts/mediatek/mt8195.dtsi | 210 +-----
> drivers/thermal/Kconfig | 27 +
> drivers/thermal/thermal_core.c | 643 ++++++++++++++++++
> drivers/thermal/thermal_core.h | 14 +
> drivers/thermal/thermal_of.c | 86 ++-
> 6 files changed, 780 insertions(+), 205 deletions(-)
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/5] thermal: multi-sensor aggregation support
2024-11-27 22:05 ` [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
@ 2024-11-28 17:38 ` Daniel Lezcano
0 siblings, 0 replies; 10+ messages in thread
From: Daniel Lezcano @ 2024-11-28 17:38 UTC (permalink / raw)
To: Nicolas Pitre, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Alexandre Bailon
Hi Nicolas,
On 27/11/2024 23:05, Nicolas Pitre wrote:
> Gentle ping, feedback appreciated.
I'm currently reviewing the series.
We have been discussing this feature since a long time and multiple
times at different plumbers without any progress since then. So thank
you for proposing an implementation of this feature.
I have some concerns regarding the approach I will raise tomorrow.
Thanks
-- Daniel
> On Tue, 12 Nov 2024, Nicolas Pitre wrote:
>
>> This series provides support for thermal aggregation of multiple sensors.
>> The "one sensor per zone" model is preserved for all its advantages.
>> Aggregation is performed via the creation of a special zone whose purpose
>> consists in aggregating its associated primary zones using a weighted
>> average.
>>
>> Motivation for this work stems from use cases where multiple sensors are
>> contained within the same performance domain. In such case it is preferable
>> to apply thermal mitigation while considering all such sensors as a whole.
>>
>> Previous incarnation by Alexandre Bailon can be found here:
>> https://patchwork.kernel.org/project/linux-pm/cover/20240613132410.161663-1-abailon@baylibre.com/
>>
>> diffstat:
>> .../bindings/thermal/thermal-zones.yaml | 5 +-
>> arch/arm64/boot/dts/mediatek/mt8195.dtsi | 210 +-----
>> drivers/thermal/Kconfig | 27 +
>> drivers/thermal/thermal_core.c | 643 ++++++++++++++++++
>> drivers/thermal/thermal_core.h | 14 +
>> drivers/thermal/thermal_of.c | 86 ++-
>> 6 files changed, 780 insertions(+), 205 deletions(-)
>>
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/5] thermal: multi-sensor aggregation support
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
` (5 preceding siblings ...)
2024-11-27 22:05 ` [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
@ 2024-11-29 20:00 ` Daniel Lezcano
2024-12-02 3:41 ` Chen-Yu Tsai
6 siblings, 1 reply; 10+ messages in thread
From: Daniel Lezcano @ 2024-11-29 20:00 UTC (permalink / raw)
To: Nicolas Pitre, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree
Cc: linux-kernel, Nicolas Pitre, Alexandre Bailon
On 12/11/2024 06:19, Nicolas Pitre wrote:
> This series provides support for thermal aggregation of multiple sensors.
> The "one sensor per zone" model is preserved for all its advantages.
> Aggregation is performed via the creation of a special zone whose purpose
> consists in aggregating its associated primary zones using a weighted
> average.
>
> Motivation for this work stems from use cases where multiple sensors are
> contained within the same performance domain. In such case it is preferable
> to apply thermal mitigation while considering all such sensors as a whole.
Do we have a real use case where we can compare the per sensor vs
aggregated sensors approach ?
> Previous incarnation by Alexandre Bailon can be found here:
> https://patchwork.kernel.org/project/linux-pm/cover/20240613132410.161663-1-abailon@baylibre.com/
>
> diffstat:
> .../bindings/thermal/thermal-zones.yaml | 5 +-
> arch/arm64/boot/dts/mediatek/mt8195.dtsi | 210 +-----
> drivers/thermal/Kconfig | 27 +
> drivers/thermal/thermal_core.c | 643 ++++++++++++++++++
> drivers/thermal/thermal_core.h | 14 +
> drivers/thermal/thermal_of.c | 86 ++-
> 6 files changed, 780 insertions(+), 205 deletions(-)
--
<http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 0/5] thermal: multi-sensor aggregation support
2024-11-29 20:00 ` Daniel Lezcano
@ 2024-12-02 3:41 ` Chen-Yu Tsai
0 siblings, 0 replies; 10+ messages in thread
From: Chen-Yu Tsai @ 2024-12-02 3:41 UTC (permalink / raw)
To: Daniel Lezcano
Cc: Nicolas Pitre, Rafael J . Wysocki, linux-pm, linux-mediatek,
devicetree, linux-kernel, Nicolas Pitre, Alexandre Bailon
On Sat, Nov 30, 2024 at 4:00 AM Daniel Lezcano
<daniel.lezcano@linaro.org> wrote:
>
> On 12/11/2024 06:19, Nicolas Pitre wrote:
> > This series provides support for thermal aggregation of multiple sensors.
> > The "one sensor per zone" model is preserved for all its advantages.
> > Aggregation is performed via the creation of a special zone whose purpose
> > consists in aggregating its associated primary zones using a weighted
> > average.
> >
> > Motivation for this work stems from use cases where multiple sensors are
> > contained within the same performance domain. In such case it is preferable
> > to apply thermal mitigation while considering all such sensors as a whole.
>
> Do we have a real use case where we can compare the per sensor vs
> aggregated sensors approach ?
The MediaTek platforms have one sensor per CPU core, but the cores are
grouped into two clusters, and DVFS is tied together for all the cores
in each cluster, as is commonly seen on ARM systems.
Furthermore, there is a hardware block that does minute OPP voltage
tweaking based on thermal readings, and AFAIK that block wants the
per-cluster aggregate temperature.
ChenYu
> > Previous incarnation by Alexandre Bailon can be found here:
> > https://patchwork.kernel.org/project/linux-pm/cover/20240613132410.161663-1-abailon@baylibre.com/
> >
> > diffstat:
> > .../bindings/thermal/thermal-zones.yaml | 5 +-
> > arch/arm64/boot/dts/mediatek/mt8195.dtsi | 210 +-----
> > drivers/thermal/Kconfig | 27 +
> > drivers/thermal/thermal_core.c | 643 ++++++++++++++++++
> > drivers/thermal/thermal_core.h | 14 +
> > drivers/thermal/thermal_of.c | 86 ++-
> > 6 files changed, 780 insertions(+), 205 deletions(-)
>
>
> --
> <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
>
> Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook |
> <http://twitter.com/#!/linaroorg> Twitter |
> <http://www.linaro.org/linaro-blog/> Blog
>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2024-12-02 3:41 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-11-12 5:19 [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
2024-11-12 5:19 ` [PATCH 1/5] thermal: of: properly parse coefficients with multiple thermal-sensors entries Nicolas Pitre
2024-11-12 5:19 ` [PATCH 2/5] dt-bindings: thermal: Restore the thermal-sensors property Nicolas Pitre
2024-11-12 5:19 ` [PATCH 3/5] thermal: aggregation support Nicolas Pitre
2024-11-12 5:19 ` [PATCH 4/5] thermal: automatic " Nicolas Pitre
2024-11-12 5:19 ` [PATCH 5/5] ARM64: mt8195: Use thermal aggregation for big and little cpu Nicolas Pitre
2024-11-27 22:05 ` [PATCH 0/5] thermal: multi-sensor aggregation support Nicolas Pitre
2024-11-28 17:38 ` Daniel Lezcano
2024-11-29 20:00 ` Daniel Lezcano
2024-12-02 3:41 ` Chen-Yu Tsai
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox