From a92bab8919e3fb0dfb58e79d9a452507b389fd77 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Aug 2018 12:38:14 +0530 Subject: of: thermal: Allow multiple devices to share cooling map A cooling map entry may now contain a list of phandles and their arguments representing multiple devices which share the trip point. This patch updates the thermal OF core to parse them properly. The trip point and contribution value is shared by multiple cooling devices now and so a new structure is created, struct __thermal_cooling_bind_param, which represents a cooling device and its min/max states and the existing struct __thermal_bind_params now contains an array of this new cooling device structure. Tested on Hikey960. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 142 +++++++++++++++++++++++++++++++------------ 1 file changed, 103 insertions(+), 39 deletions(-) (limited to 'drivers/thermal/of-thermal.c') diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 977a8307fbb1..89267f42c597 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -19,22 +19,33 @@ /*** Private data structures to represent thermal device tree data ***/ /** - * struct __thermal_bind_param - a match between trip and cooling device + * struct __thermal_cooling_bind_param - a cooling device for a trip point * @cooling_device: a pointer to identify the referred cooling device - * @trip_id: the trip point index - * @usage: the percentage (from 0 to 100) of cooling contribution * @min: minimum cooling state used at this trip point * @max: maximum cooling state used at this trip point */ -struct __thermal_bind_params { +struct __thermal_cooling_bind_param { struct device_node *cooling_device; - unsigned int trip_id; - unsigned int usage; unsigned long min; unsigned long max; }; +/** + * struct __thermal_bind_param - a match between trip and cooling device + * @tcbp: a pointer to an array of cooling devices + * @count: number of elements in array + * @trip_id: the trip point index + * @usage: the percentage (from 0 to 100) of cooling contribution + */ + +struct __thermal_bind_params { + struct __thermal_cooling_bind_param *tcbp; + unsigned int count; + unsigned int trip_id; + unsigned int usage; +}; + /** * struct __thermal_zone - internal representation of a thermal zone * @mode: current thermal zone device mode (enabled/disabled) @@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { struct __thermal_zone *data = thermal->devdata; - int i; + struct __thermal_bind_params *tbp; + struct __thermal_cooling_bind_param *tcbp; + int i, j; if (!data || IS_ERR(data)) return -ENODEV; /* find where to bind */ for (i = 0; i < data->num_tbps; i++) { - struct __thermal_bind_params *tbp = data->tbps + i; + tbp = data->tbps + i; - if (tbp->cooling_device == cdev->np) { - int ret; + for (j = 0; j < tbp->count; j++) { + tcbp = tbp->tcbp + j; - ret = thermal_zone_bind_cooling_device(thermal, + if (tcbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_bind_cooling_device(thermal, tbp->trip_id, cdev, - tbp->max, - tbp->min, + tcbp->max, + tcbp->min, tbp->usage); - if (ret) - return ret; + if (ret) + return ret; + } } } @@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { struct __thermal_zone *data = thermal->devdata; - int i; + struct __thermal_bind_params *tbp; + struct __thermal_cooling_bind_param *tcbp; + int i, j; if (!data || IS_ERR(data)) return -ENODEV; /* find where to unbind */ for (i = 0; i < data->num_tbps; i++) { - struct __thermal_bind_params *tbp = data->tbps + i; + tbp = data->tbps + i; + + for (j = 0; j < tbp->count; j++) { + tcbp = tbp->tcbp + j; - if (tbp->cooling_device == cdev->np) { - int ret; + if (tcbp->cooling_device == cdev->np) { + int ret; - ret = thermal_zone_unbind_cooling_device(thermal, - tbp->trip_id, cdev); - if (ret) - return ret; + ret = thermal_zone_unbind_cooling_device(thermal, + tbp->trip_id, cdev); + if (ret) + return ret; + } } } @@ -652,8 +675,9 @@ static int thermal_of_populate_bind_params(struct device_node *np, int ntrips) { struct of_phandle_args cooling_spec; + struct __thermal_cooling_bind_param *__tcbp; struct device_node *trip; - int ret, i; + int ret, i, count; u32 prop; /* Default weight. Usage is optional */ @@ -680,20 +704,44 @@ static int thermal_of_populate_bind_params(struct device_node *np, goto end; } - ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", - 0, &cooling_spec); - if (ret < 0) { - pr_err("missing cooling_device property\n"); + count = of_count_phandle_with_args(np, "cooling-device", + "#cooling-cells"); + if (!count) { + pr_err("Add a cooling_device property with at least one device\n"); goto end; } - __tbp->cooling_device = cooling_spec.np; - if (cooling_spec.args_count >= 2) { /* at least min and max */ - __tbp->min = cooling_spec.args[0]; - __tbp->max = cooling_spec.args[1]; - } else { - pr_err("wrong reference to cooling device, missing limits\n"); + + __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL); + if (!__tcbp) + goto end; + + for (i = 0; i < count; i++) { + ret = of_parse_phandle_with_args(np, "cooling-device", + "#cooling-cells", i, &cooling_spec); + if (ret < 0) { + pr_err("Invalid cooling-device entry\n"); + goto free_tcbp; + } + + __tcbp[i].cooling_device = cooling_spec.np; + + if (cooling_spec.args_count >= 2) { /* at least min and max */ + __tcbp[i].min = cooling_spec.args[0]; + __tcbp[i].max = cooling_spec.args[1]; + } else { + pr_err("wrong reference to cooling device, missing limits\n"); + } } + __tbp->tcbp = __tcbp; + __tbp->count = count; + + goto end; + +free_tcbp: + for (i = i - 1; i >= 0; i--) + of_node_put(__tcbp[i].cooling_device); + kfree(__tcbp); end: of_node_put(trip); @@ -900,8 +948,16 @@ finish: return tz; free_tbps: - for (i = i - 1; i >= 0; i--) - of_node_put(tz->tbps[i].cooling_device); + for (i = i - 1; i >= 0; i--) { + struct __thermal_bind_params *tbp = tz->tbps + i; + int j; + + for (j = 0; j < tbp->count; j++) + of_node_put(tbp->tcbp[j].cooling_device); + + kfree(tbp->tcbp); + } + kfree(tz->tbps); free_trips: for (i = 0; i < tz->ntrips; i++) @@ -917,10 +973,18 @@ free_tz: static inline void of_thermal_free_zone(struct __thermal_zone *tz) { - int i; + struct __thermal_bind_params *tbp; + int i, j; + + for (i = 0; i < tz->num_tbps; i++) { + tbp = tz->tbps + i; + + for (j = 0; j < tbp->count; j++) + of_node_put(tbp->tcbp[j].cooling_device); + + kfree(tbp->tcbp); + } - for (i = 0; i < tz->num_tbps; i++) - of_node_put(tz->tbps[i].cooling_device); kfree(tz->tbps); for (i = 0; i < tz->ntrips; i++) of_node_put(tz->trips[i].np); -- cgit v1.2.3-59-g8ed1b From 9b96566063c5511982c33df747e239e77cb75f78 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:46 -0500 Subject: thermal: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: linux-pm@vger.kernel.org Signed-off-by: Rob Herring Acked-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 10 +++++----- drivers/thermal/qoriq_thermal.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/thermal/of-thermal.c') diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 89267f42c597..217d25d7e325 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -506,8 +506,8 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, if (sensor_specs.args_count >= 1) { id = sensor_specs.args[0]; WARN(sensor_specs.args_count > 1, - "%s: too many cells in sensor specifier %d\n", - sensor_specs.np->name, sensor_specs.args_count); + "%pOFn: too many cells in sensor specifier %d\n", + sensor_specs.np, sensor_specs.args_count); } else { id = 0; } @@ -1024,8 +1024,8 @@ int __init of_parse_thermal_zones(void) tz = thermal_of_build_thermal_zone(child); if (IS_ERR(tz)) { - pr_err("failed to build thermal zone %s: %ld\n", - child->name, + pr_err("failed to build thermal zone %pOFn: %ld\n", + child, PTR_ERR(tz)); continue; } @@ -1059,7 +1059,7 @@ int __init of_parse_thermal_zones(void) tz->passive_delay, tz->polling_delay); if (IS_ERR(zone)) { - pr_err("Failed to build %s zone %ld\n", child->name, + pr_err("Failed to build %pOFn zone %ld\n", child, PTR_ERR(zone)); kfree(tzp); kfree(ops); diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c index c866cc165960..1fa132fc316b 100644 --- a/drivers/thermal/qoriq_thermal.c +++ b/drivers/thermal/qoriq_thermal.c @@ -129,8 +129,8 @@ static int qoriq_tmu_get_sensor_id(void) if (sensor_specs.args_count >= 1) { id = sensor_specs.args[0]; WARN(sensor_specs.args_count > 1, - "%s: too many cells in sensor specifier %d\n", - sensor_specs.np->name, sensor_specs.args_count); + "%pOFn: too many cells in sensor specifier %d\n", + sensor_specs.np, sensor_specs.args_count); } else { id = 0; } -- cgit v1.2.3-59-g8ed1b