thermal: remove power allocator from list of default governors
Subsystems (2)
PATCH 1/1 thermal: remove power allocator from list of default governors
As it currently stands the power allocator governor can not handle thermal zones that are not specifically crafted and therefore can not be used as a default governor.
Users need to explicitly enable this governor for thermal zones that do have enough information for its operation.
--- drivers/thermal/Kconfig | 8 -------- 1 file changed, 8 deletions(-)
drivers/thermal/Kconfig +0 -8
@@ -82,14 +82,6 @@ config THERMAL_DEFAULT_GOV_USER_SPACE Select this if you want to let the user space manage the platform thermals. -config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. - endchoice config THERMAL_GOV_FAIR_SHARE
Signature · 5 lines
2.5.0.rc2.392.g76e840b -- Dmitry
Quoted 18 lines · Dmitry Torokhov
As it currently stands the power allocator governor can not handle thermal zones that are not specifically crafted and therefore can not be used as a default governor.
Users need to explicitly enable this governor for thermal zones that do have enough information for its operation.
Signed-off-by Dmitry Torokhov <[email protected]>--- drivers/thermal/Kconfig | 8 -------- 1 file changed, 8 deletions(-)drivers/thermal/Kconfig +0
-0@@ -82,14 +82,6 @@ config THERMAL_DEFAULT_GOV_USER_SPACE Select this if you want to let the user space manage the
drivers/thermal/Kconfig config THERMAL_DEFAULT_GOV_USER_SPACE · line 92
Quoted 10 lines
drivers/thermal/Kconfig +0
-8platform thermals. -config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. -
Currently the only way we have for a thermal zone configured from device tree to use a governor from the kernel boot is by using THERMAL_DEFAULT_GOV_*. If we remove this option some devices won't have a workable thermal framework until userspace is up and running.
Would you rather have the power allocator governor accept every thermal zone?
Cheers,
Javi
Quoted 35 lines · Javi Merino
Quoted 18 lines · Dmitry Torokhov
As it currently stands the power allocator governor can not handle thermal zones that are not specifically crafted and therefore can not be used as a default governor.
Users need to explicitly enable this governor for thermal zones that do have enough information for its operation.
Signed-off-by Dmitry Torokhov <[email protected]>--- drivers/thermal/Kconfig | 8 -------- 1 file changed, 8 deletions(-)drivers/thermal/Kconfig +0
-0@@ -82,14 +82,6 @@ config THERMAL_DEFAULT_GOV_USER_SPACE Select this if you want to let the user space manage thedrivers/thermal/Kconfig config THERMAL_DEFAULT_GOV_USER_SPACE · line 92
Quoted 10 lines
drivers/thermal/Kconfig +0
-8platform thermals. -config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. -Currently the only way we have for a thermal zone configured from device tree to use a governor from the kernel boot is by using THERMAL_DEFAULT_GOV_*. If we remove this option some devices won't have a workable thermal framework until userspace is up and running.
Quoted 2 lines
Would you rather have the power allocator governor accept every thermal zone?
May be allow to select when the binded cooling device can support this governor.
Thanks,
Srinivas
Quoted 6 lines
Cheers,
Javi
--
To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 21 lines · Javi Merino
Quoted 20 lines · Dmitry Torokhov
As it currently stands the power allocator governor can not handle thermal zones that are not specifically crafted and therefore can not be used as a default governor.
Users need to explicitly enable this governor for thermal zones that do have enough information for its operation.
Signed-off-by Dmitry Torokhov <[email protected]>--- drivers/thermal/Kconfig | 8 -------- 1 file changed, 8 deletions(-)drivers/thermal/Kconfig +0
-0@@ -82,14 +82,6 @@ config THERMAL_DEFAULT_GOV_USER_SPACE Select this if you want to let the user space manage the platform thermals.
Quoted 13 lines
drivers/thermal/Kconfig config THERMAL_DEFAULT_GOV_USER_SPACE · line 92
Quoted 8 lines
drivers/thermal/Kconfig +0
-8-config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. -Currently the only way we have for a thermal zone configured from device tree to use a governor from the kernel boot is by using THERMAL_DEFAULT_GOV_*. If we remove this option some devices won't have a workable thermal framework until userspace is up and running.
Why would step wise, or fair share be not workable (even if not optimal) thermal frameworks? It doe snot take that long to get to [early] userspace. Half of the boot time the thermal framework is not working anyway because half of the devices that can act as colling devices are not yet logically there.
Quoted 3 lines
Would you rather have the power allocator governor accept every thermal zone?
If it is to be one of default governors then yes, it needs to be able to manage all thermal zones, the same way as the other 3 governors can, as far as I know.
Thanks.
Signature · 1 line
Dmitry
Quoted 43 lines · Dmitry Torokhov
Quoted 21 lines · Javi Merino
Quoted 20 lines · Dmitry Torokhov
As it currently stands the power allocator governor can not handle thermal zones that are not specifically crafted and therefore can not be used as a default governor.
Users need to explicitly enable this governor for thermal zones that do have enough information for its operation.
Signed-off-by Dmitry Torokhov <[email protected]>--- drivers/thermal/Kconfig | 8 -------- 1 file changed, 8 deletions(-)drivers/thermal/Kconfig +0
-0@@ -82,14 +82,6 @@ config THERMAL_DEFAULT_GOV_USER_SPACE Select this if you want to let the user space manage the platform thermals.Quoted 13 lines
drivers/thermal/Kconfig config THERMAL_DEFAULT_GOV_USER_SPACE · line 92
Quoted 8 lines
drivers/thermal/Kconfig +0
-8-config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. -Currently the only way we have for a thermal zone configured from device tree to use a governor from the kernel boot is by using THERMAL_DEFAULT_GOV_*. If we remove this option some devices won't have a workable thermal framework until userspace is up and running.
Why would step wise, or fair share be not workable (even if not optimal) thermal frameworks? It doe snot take that long to get to [early] userspace. Half of the boot time the thermal framework is not working anyway because half of the devices that can act as colling devices are not yet logically there.
Quoted 1 line
Quoted 6 lines
Quoted 2 lines
Would you rather have the power allocator governor accept every thermal zone?
If it is to be one of default governors then yes, it needs to be able to manage all thermal zones, the same way as the other 3 governors can, as far as I know.
I believe fairshare also relies on platform data to be properly set, otherwise, it would not be functional. That's probably why I overlooked this point. That said, I would say, if we follow this logic, a similar patch is needed for fairshare.
Javi, ideally, the governor would need to have a workable default settings for any thermal zone that miss the platform settings. Do you think it would be doable for power allocator?
BR,
Quoted 5 lines
Thanks.
Signature · 1 line
Dmitry
Quoted 51 lines · Eduardo Valentin
Quoted 43 lines · Dmitry Torokhov
Quoted 21 lines · Javi Merino
Quoted 20 lines · Dmitry Torokhov
As it currently stands the power allocator governor can not handle thermal zones that are not specifically crafted and therefore can not be used as a default governor.
Users need to explicitly enable this governor for thermal zones that do have enough information for its operation.
Signed-off-by Dmitry Torokhov <[email protected]>--- drivers/thermal/Kconfig | 8 -------- 1 file changed, 8 deletions(-)drivers/thermal/Kconfig +0
-0@@ -82,14 +82,6 @@ config THERMAL_DEFAULT_GOV_USER_SPACE Select this if you want to let the user space manage the platform thermals.Quoted 13 lines
drivers/thermal/Kconfig config THERMAL_DEFAULT_GOV_USER_SPACE · line 92
Quoted 8 lines
drivers/thermal/Kconfig +0
-8-config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. -Currently the only way we have for a thermal zone configured from device tree to use a governor from the kernel boot is by using THERMAL_DEFAULT_GOV_*. If we remove this option some devices won't have a workable thermal framework until userspace is up and running.
Why would step wise, or fair share be not workable (even if not optimal) thermal frameworks? It doe snot take that long to get to [early] userspace. Half of the boot time the thermal framework is not working anyway because half of the devices that can act as colling devices are not yet logically there.
Quoted 1 line
Quoted 6 lines
Quoted 2 lines
Would you rather have the power allocator governor accept every thermal zone?
If it is to be one of default governors then yes, it needs to be able to manage all thermal zones, the same way as the other 3 governors can, as far as I know.
Quoted 8 lines
I believe fairshare also relies on platform data to be properly set, otherwise, it would not be functional. That's probably why I overlooked this point. That said, I would say, if we follow this logic, a similar patch is needed for fairshare.
Javi, ideally, the governor would need to have a workable default settings for any thermal zone that miss the platform settings. Do you think it would be doable for power allocator?
Yes, we can come up with something that accepts any thermal zone. I'll send a patch soon.
Cheers,
Javi
cover Let the power allocator thermal governor run on any thermal zone
Relax the thermal governor requirements of sustainable_power and at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.
Javi Merino (3):
thermal: power_allocator: relax the requirement of a sustainable_power
in tzp
thermal: power_allocator: relax the requirement of two passive trip
points
thermal: power_allocator: exit early if there are no cooling devices
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 158 +++++++++++++++++++++--------- drivers/thermal/thermal_core.c | 28 ++++++ include/linux/thermal.h | 6 ++ 4 files changed, 144 insertions(+), 50 deletions(-)
Signature · 1 line
1.9.1
PATCH 1/3 thermal: power_allocator: relax the requirement of a sustainable_power in tzp
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)
drivers/thermal/power_allocator.c +53 -9
@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius
@@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);
@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);
@@ -412,18 +449,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
@@ -442,13 +479,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret) goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can estimate sustainable_power +* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults that setting k_po and k_pu to 0. +*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ; temperature_threshold = control_temp - switch_on_temp; tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold; tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;/* * The default for k_d and integral_cutoff is 0, so we can
drivers/thermal/thermal_core.c +28 -0
@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwats that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update
include/linux/thermal.h +6 -0
@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Signature · 1 line
1.9.1
PATCH 2/3 thermal: power_allocator: relax the requirement of two passive trip points
In reply to Javi MerinoThe power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 91 +++++++++++++++++-------------- 2 files changed, 52 insertions(+), 41 deletions(-)
Documentation/thermal/power_allocator.txt +1 -1
@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive trip
drivers/thermal/power_allocator.c +51 -40
163 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH 3/3 thermal: power_allocator: exit early if there are no cooling devices
In reply to Javi MerinoDon't waste cycles in the power allocator governor's throttle function if there are no cooling devices and exit early.
This commit doesn't change any functionality, but should provide better performance for the odd case of a thermal zone with trip points but without cooling devices.
--- drivers/thermal/power_allocator.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/thermal/power_allocator.c +5 -0
@@ -287,6 +287,11 @@ static int allocate_power(struct thermal_zone_device *tz, } } +if (!num_actors) { + ret = -ENODEV ; + goto unlock; + } +/* * We need to allocate three arrays of the same size: * req_power, max_power and granted_power. They are going to
Signature · 1 line
1.9.1
v2 cover Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoRelax the thermal governor requirements of sustainable_power and at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.
Changes since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih Wang
Javi Merino (4):
thermal: power_allocator: relax the requirement of a sustainable_power
in tzp
thermal: power_allocator: relax the requirement of two passive trip
points
thermal: power_allocator: don't require tzp to be present for the
thermal zone
thermal: power_allocator: exit early if there are no cooling devices
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 178 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 +++++ include/linux/thermal.h | 6 + 4 files changed, 165 insertions(+), 49 deletions(-)
Signature · 1 line
1.9.1
PATCH v2 1/4 thermal: power_allocator: relax the requirement of a sustainable_power in tzp
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)
drivers/thermal/power_allocator.c +53 -9
@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius
@@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);
@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);
@@ -418,18 +455,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
@@ -448,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret) goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can estimate sustainable_power +* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults that setting k_po and k_pu to 0. +*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ; temperature_threshold = control_temp - switch_on_temp; tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold; tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;/* * The default for k_d and integral_cutoff is 0, so we can
drivers/thermal/thermal_core.c +28 -0
@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwats that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update
include/linux/thermal.h +6 -0
@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Signature · 1 line
1.9.1
Re: [PATCH v2 1/4] thermal: power_allocator: relax the requirement of a sustainable_power in tzp
Hi Javi,
A few nitpicks and a comment below.
Quoted 109 lines · Javi Merino
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)drivers/thermal/power_allocator.c +43
-6@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius @@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);@@ -418,18 +455,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 490
Quoted 6 lines
drivers/thermal/power_allocator.c +3
-0@@ -448,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret) goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can estimate sustainable_power
^
can notdrivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 493
Quoted 3 lines
drivers/thermal/power_allocator.c +3
-0+* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults that setting k_po and k_pu to 0.
^
thandrivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 501
Quoted 11 lines
drivers/thermal/power_allocator.c +4
-3+*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ; temperature_threshold = control_temp - switch_on_temp; tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold;
As we are being conservative with our estimation of sustainable power (sum of mins) when it is not explicitly specified, should we be conservative here and let the proportional terms, k_po and k_pu be zero as well?
Quoted 56 lines
drivers/thermal/power_allocator.c +0
-0tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;/* * The default for k_d and integral_cutoff is 0, so we can drivers/thermal/thermal_core.c +28
-0@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwats that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update include/linux/thermal.h +2
-0@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
include/linux/thermal.h static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) · line 427
Quoted 7 lines
include/linux/thermal.h +4
-0@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }
Perhaps return 0 like power_actor_get_max_power just above for consistency.
Quoted 3 lines
include/linux/thermal.h +0
-0static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Re: [PATCH v2 1/4] thermal: power_allocator: relax the requirement of a sustainable_power in tzp
Quoted 123 lines · Punit Agrawal
Hi Javi,
A few nitpicks and a comment below.
Quoted 109 lines · Javi Merino
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)drivers/thermal/power_allocator.c +43
-6@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius @@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);@@ -418,18 +455,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 490
Quoted 6 lines
drivers/thermal/power_allocator.c +3
-0@@ -448,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret) goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can estimate sustainable_power ^ can not
Quoted 5 lines
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 493
Quoted 3 lines
drivers/thermal/power_allocator.c +3
-0+* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults that setting k_po and k_pu to 0. ^ than
Fixed both.
Quoted 4 lines
Quoted 4 lines
drivers/thermal/power_allocator.c +2
-0+*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ; temperature_threshold = control_temp - switch_on_temp;
Quoted 12 lines
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 501
Quoted 7 lines
drivers/thermal/power_allocator.c +2
-3tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold;As we are being conservative with our estimation of sustainable power (sum of mins) when it is not explicitly specified, should we be conservative here and let the proportional terms,
k_poandk_pube zero as well?
Yes, we could do. If we set it to zero, all cooling devices will be set to the maximum cooling state when the governor is active. If we set it to a valid(ish) value, it will do a bit of thermal control. It's not perfect but I think it's better to have a bad estimate than no estimate.
Quoted 58 lines
Quoted 58 lines
drivers/thermal/power_allocator.c +0
-0tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;/* * The default for k_d and integral_cutoff is 0, so we can drivers/thermal/thermal_core.c +28
-0@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwats that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update include/linux/thermal.h +2
-0@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power)
Quoted 8 lines
include/linux/thermal.h static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) · line 427
Quoted 5 lines
include/linux/thermal.h +4
-0{return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }Perhaps return 0 like
power_actor_get_max_powerjust above for consistency.
No, return 0 is not a good idea. If you return 0, you're telling the calling function that everything went all right and you've put the minimum power in @min_power.
What we should do is fix power_actor_get_max_power() and power_actor_set_power() to return an error value if !CONFIG_THERMAL.
Cheers,
Javi
Re: [PATCH v2 1/4] thermal: power_allocator: relax the requirement of a sustainable_power in tzp
In reply to Javi MerinoHi Javi,
One Tiny nit below...
Quoted 14 lines · Javi Merino
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>---
[snip]
drivers/thermal/thermal_core.c int power_actor_get_max_power(struct thermal_cooling_device *cdev, · line 1005
Quoted 12 lines
drivers/thermal/thermal_core.c +6
-0@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwats that the
^
milliwattsThanks,
-Dan
PATCH v2 2/4 thermal: power_allocator: relax the requirement of two passive trip points
In reply to Javi MerinoThe power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 91 +++++++++++++++++-------------- 2 files changed, 52 insertions(+), 41 deletions(-)
Documentation/thermal/power_allocator.txt +1 -1
@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive trip
drivers/thermal/power_allocator.c +51 -40
163 lines not on this page · raw message
Signature · 1 line
1.9.1
Re: [PATCH v2 2/4] thermal: power_allocator: relax the requirement of two passive trip points
Hi Javi,
tiny nits again...
Quoted 51 lines · Javi Merino
The power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 91 +++++++++++++++++-------------- 2 files changed, 52 insertions(+), 41 deletions(-)Documentation/thermal/power_allocator.txt +1
-1@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive tripdrivers/thermal/power_allocator.c +4
-0@@ -24,6 +24,8 @@#include "thermal_core.h" +#define INVALID_TRIP -1 +#define FRAC_BITS 10#define int_to_frac (x) ((x) << FRAC_BITS)#define frac_to_int (x) ((x) >> FRAC_BITS)@@ -61,6 +63,8 @@ static inline s64 div_frac(s64 x, s64 y)* Used to calculate the derivative term. * @trip_switch_on: first passive trip point of the thermal zone. The * governor switches on when this trip point is crossed. +* If the thermal zone only has one passive trip point, +* @trip_switch_on should be INVALID_TRIP. * @trip_max_desired_temperature: last passive trip point of the thermal * zone. The temperature we are * controlling for.
drivers/thermal/power_allocator.c unlock: · line 388
Quoted 9 lines
drivers/thermal/power_allocator.c +4
-2@@ -378,43 +382,66 @@ unlock:return ret; } -static int get_governor_trips (struct thermal_zone_device *tz, -struct power_allocator_params *params) +/** +* get_governor_trips() - get the number of the two trip points that are key for this governor +* @tz: thermal zone to operate on +* @params: pointer the private data for this governor
^
pointer to private data
drivers/thermal/power_allocator.c unlock: · line 398
Quoted 10 lines
drivers/thermal/power_allocator.c +10
-0+* +* The power allocator governor works optimally with two trips points: +* a "switch on" trip point and a "maximum desired temperature". These +* are defined as the first and last passive trip points. +* +* If there is only one trip point, then that's considered to be the +* "maximum desired temperature" trip point and the governor is always +* on. If there are no passive or active trip points, then the +* governor won't do anything. In fact, its throttle function +* shouldn't be called at all.
^
"shouldn't" or "won't" ?[snip]
drivers/thermal/power_allocator.c static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) · line 564
Quoted 13 lines
static void
power_allocator_unbind(struct thermal_zone_device *tz)drivers/thermal/power_allocator.c +1
-7@@ -544,13 +561,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) ret = tz->ops->get_trip_temp (tz, params->trip_switch_on, &switch_on_temp); -if (ret) { -dev_warn (&tz->device, -"Failed to get switch on temperature: %d\n" , ret); -return ret; - } - -if (current_temp < switch_on_temp) { +if ((!ret) && (current_temp < switch_on_temp)) {
nit: I think the inner pair of () are not necessary.
Thanks,
-Dan
Re: [PATCH v2 2/4] thermal: power_allocator: relax the requirement of two passive trip points
Quoted 1 line · Daniel Kurtz
Hi Javi,
Hi Daniel,
Quoted 55 lines · Javi Merino
Quoted 54 lines
The power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 91 +++++++++++++++++-------------- 2 files changed, 52 insertions(+), 41 deletions(-)Documentation/thermal/power_allocator.txt +1
-1@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive tripdrivers/thermal/power_allocator.c +4
-0@@ -24,6 +24,8 @@#include "thermal_core.h" +#define INVALID_TRIP -1 +#define FRAC_BITS 10#define int_to_frac (x) ((x) << FRAC_BITS)#define frac_to_int (x) ((x) >> FRAC_BITS)@@ -61,6 +63,8 @@ static inline s64 div_frac(s64 x, s64 y)* Used to calculate the derivative term. * @trip_switch_on: first passive trip point of the thermal zone. The * governor switches on when this trip point is crossed. +* If the thermal zone only has one passive trip point, +* @trip_switch_on should be INVALID_TRIP. * @trip_max_desired_temperature: last passive trip point of the thermal * zone. The temperature we are * controlling for. @@ -378,43 +382,66 @@ unlock:return ret; }
Quoted 8 lines
drivers/thermal/power_allocator.c unlock: · line 388
Quoted 6 lines
drivers/thermal/power_allocator.c +4
-2-static int get_governor_trips (struct thermal_zone_device *tz, -struct power_allocator_params *params) +/** +* get_governor_trips() - get the number of the two trip points that are key for this governor +* @tz: thermal zone to operate on +* @params: pointer the private data for this governor ^
pointer to private data
Fixed
Quoted 10 lines
drivers/thermal/power_allocator.c unlock: · line 398
Quoted 10 lines
drivers/thermal/power_allocator.c +10
-0+* +* The power allocator governor works optimally with two trips points: +* a "switch on" trip point and a "maximum desired temperature". These +* are defined as the first and last passive trip points. +* +* If there is only one trip point, then that's considered to be the +* "maximum desired temperature" trip point and the governor is always +* on. If there are no passive or active trip points, then the +* governor won't do anything. In fact, its throttle function +* shouldn't be called at all.
Quoted 2 lines
^
"shouldn't" or "won't" ?"won't". Sometimes I'm overly cautious. You know "never say never" ;-)
Quoted 5 lines
[snip]
Quoted 3 lines
static void
power_allocator_unbind(struct thermal_zone_device *tz)drivers/thermal/power_allocator.c +0
-0@@ -544,13 +561,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip)
Quoted 12 lines
drivers/thermal/power_allocator.c static int power_allocator_throttle(struct thermal_zone_device *tz, int trip) · line 564
Quoted 10 lines
drivers/thermal/power_allocator.c +1
-7ret = tz->ops->get_trip_temp (tz, params->trip_switch_on, &switch_on_temp); -if (ret) { -dev_warn (&tz->device, -"Failed to get switch on temperature: %d\n" , ret); -return ret; - } - -if (current_temp < switch_on_temp) { +if ((!ret) && (current_temp < switch_on_temp)) {nit: I think the inner pair of () are not necessary.
They are not necessary, but I prefer the parenthesis around the comparison. It makes it clearer to me. I've dropped the () around !ret.
Thanks for the comments here and in the first patch. Javi
PATCH v2 3/4 thermal: power_allocator: don't require tzp to be present for the thermal zone
In reply to Javi MerinoThermal zones created using thermal_zone_device_create() may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.
---
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a better behavior.
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
drivers/thermal/power_allocator.c +27 -5
@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term.
@@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;
@@ -473,8 +476,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {
@@ -483,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)unsigned long switch_on_temp, control_temp;u32 sustainable_power, temperature_threshold; -if (!tz->tzp) -return -EINVAL ; - params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL ); +if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );
@@ -531,11 +540,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +devm_kfree (&tz->device, params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +devm_kfree (&tz->device, tz->governor_data); tz->governor_data =NULL ; }
Signature · 1 line
1.9.1
PATCH v2 4/4 thermal: power_allocator: exit early if there are no cooling devices
In reply to Javi MerinoDon't waste cycles in the power allocator governor's throttle function if there are no cooling devices and exit early.
This commit doesn't change any functionality, but should provide better performance for the odd case of a thermal zone with trip points but without cooling devices.
--- drivers/thermal/power_allocator.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/thermal/power_allocator.c +5 -0
@@ -291,6 +291,11 @@ static int allocate_power(struct thermal_zone_device *tz, } } +if (!num_actors) { + ret = -ENODEV ; + goto unlock; + } +/* * We need to allocate five arrays of the same size: * req_power, max_power, granted_power, extra_actor_power and
Signature · 1 line
1.9.1
v3 cover Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoRelax the thermal governor requirements of sustainable_power and at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.
Changes since v2:
- Typos suggested by Daniel Kurtz
Changes since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih Wang
Javi Merino (4):
thermal: power_allocator: relax the requirement of a sustainable_power
in tzp
thermal: power_allocator: relax the requirement of two passive trip
points
thermal: power_allocator: don't require tzp to be present for the
thermal zone
thermal: power_allocator: exit early if there are no cooling devices
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 178 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 +++++ include/linux/thermal.h | 6 + 4 files changed, 165 insertions(+), 49 deletions(-)
Signature · 1 line
1.9.1
PATCH v3 1/4 thermal: power_allocator: relax the requirement of a sustainable_power in tzp
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)
drivers/thermal/power_allocator.c +53 -9
@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius
@@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);
@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);
@@ -418,18 +455,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
@@ -448,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret) goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can not estimate sustainable_power +* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults than setting k_po and k_pu to 0. +*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ; temperature_threshold = control_temp - switch_on_temp; tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold; tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;/* * The default for k_d and integral_cutoff is 0, so we can
drivers/thermal/thermal_core.c +28 -0
@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwatts that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update
include/linux/thermal.h +6 -0
@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Signature · 1 line
1.9.1
Re: [PATCH v3 1/4] thermal: power_allocator: relax the requirement of a sustainable_power in tzp
Quoted 110 lines · Javi Merino
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)drivers/thermal/power_allocator.c +43
-6@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius @@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);@@ -418,18 +455,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,@@ -448,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret)
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 495
Quoted 10 lines
drivers/thermal/power_allocator.c +8
-0goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can not estimate sustainable_power +* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults than setting k_po and k_pu to 0. +*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ;
I think having 2500 here may produce constants that are not sane for most thermal zones.
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 502
Quoted 10 lines
drivers/thermal/power_allocator.c +2
-3temperature_threshold = control_temp - switch_on_temp; tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold; tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;
I would prefer you move the constants estimations to where you have a sane sustainable_power.
Quoted 68 lines
drivers/thermal/power_allocator.c +0
-0/* * The default for k_d and integral_cutoff is 0, so we can drivers/thermal/thermal_core.c +28
-0@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwatts that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update include/linux/thermal.h +6
-0@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }Signature · 1 line
1.9.1
Re: [PATCH v3 1/4] thermal: power_allocator: relax the requirement of a sustainable_power in tzp
Quoted 127 lines · Eduardo Valentin
Quoted 110 lines · Javi Merino
The power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>--- drivers/thermal/power_allocator.c | 62 +++++++++++++++++++++++++++++++++------ drivers/thermal/thermal_core.c | 28 ++++++++++++++++++ include/linux/thermal.h | 6 ++++ 3 files changed, 87 insertions(+), 9 deletions(-)drivers/thermal/power_allocator.c +43
-6@@ -73,6 +73,39 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius @@ -98,6 +131,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power);@@ -138,8 +172,11 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d; + sustainable_power = tz->tzp->sustainable_power ?: +estimate_sustainable_power (tz); +/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);@@ -418,18 +455,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz)int ret;struct power_allocator_params *params;unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +u32 sustainable_power, temperature_threshold; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,@@ -448,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)if (ret)drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 495
Quoted 10 lines
drivers/thermal/power_allocator.c +8
-0goto free; +/* +* Provide an arbitrary sustainable_power to set the default +* values of k_po and k_pu. We can not estimate sustainable_power +* at this point because no cooling devices have been +* registered yet. By providing an arbitrary value we get +* better defaults than setting k_po and k_pu to 0. +*/ + sustainable_power = tz->tzp->sustainable_power ?:2500 ;I think having 2500 here may produce constants that are not sane for most thermal zones.
Quoted 2 lines
drivers/thermal/power_allocator.c +0
-0temperature_threshold = control_temp - switch_on_temp;
Quoted 11 lines
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 502
Quoted 8 lines
drivers/thermal/power_allocator.c +2
-3tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; +int_to_frac (sustainable_power) / temperature_threshold; tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; +int_to_frac (2 * sustainable_power) / temperature_threshold; tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ;I would prefer you move the constants estimations to where you have a sane
sustainable_power.
Ok, I'll factor it to a function so that they can be estimated here if you provide sustainable_power or they can be re-estimated in pid_controller() if there is no sustainable_power.
Cheers,
Javi
PATCH v3 2/4 thermal: power_allocator: relax the requirement of two passive trip points
In reply to Javi MerinoThe power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 91 +++++++++++++++++-------------- 2 files changed, 52 insertions(+), 41 deletions(-)
Documentation/thermal/power_allocator.txt +1 -1
@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive trip
drivers/thermal/power_allocator.c +51 -40
163 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v3 3/4 thermal: power_allocator: don't require tzp to be present for the thermal zone
In reply to Javi MerinoThermal zones created using thermal_zone_device_create() may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.
---
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a better behavior.
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
drivers/thermal/power_allocator.c +27 -5
@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term.
@@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;
@@ -473,8 +476,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {
@@ -483,13 +485,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)unsigned long switch_on_temp, control_temp;u32 sustainable_power, temperature_threshold; -if (!tz->tzp) -return -EINVAL ; - params =devm_kzalloc (&tz->device,sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL ); +if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );
@@ -531,11 +540,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +devm_kfree (&tz->device, params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +devm_kfree (&tz->device, tz->governor_data); tz->governor_data =NULL ; }
Signature · 1 line
1.9.1
PATCH v3 4/4 thermal: power_allocator: exit early if there are no cooling devices
In reply to Javi MerinoDon't waste cycles in the power allocator governor's throttle function if there are no cooling devices and exit early.
This commit doesn't change any functionality, but should provide better performance for the odd case of a thermal zone with trip points but without cooling devices.
--- drivers/thermal/power_allocator.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/thermal/power_allocator.c +5 -0
@@ -291,6 +291,11 @@ static int allocate_power(struct thermal_zone_device *tz, } } +if (!num_actors) { + ret = -ENODEV ; + goto unlock; + } +/* * We need to allocate five arrays of the same size: * req_power, max_power, granted_power, extra_actor_power and
Signature · 1 line
1.9.1
v4 cover Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoRelax the thermal governor requirements of sustainable_power and at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.
Changes since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
- power_actor_get_min_power() moved to a patch of its own.
Changes since v2:
- Typos suggested by Daniel Kurtz
Changes since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih Wang
Javi Merino (5):
thermal: Add a function to get the minimum power
thermal: power_allocator: relax the requirement of a sustainable_power
in tzp
thermal: power_allocator: relax the requirement of two passive trip
points
thermal: power_allocator: don't require tzp to be present for the
thermal zone
thermal: power_allocator: exit early if there are no cooling devices
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 241 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 ++++ include/linux/thermal.h | 6 + 4 files changed, 212 insertions(+), 65 deletions(-)
Signature · 1 line
1.9.1
PATCH v4 1/5 thermal: Add a function to get the minimum power
The thermal core already has a function to get the maximum power of a cooling device: power_actor_get_max_power(). Add a function to get the minimum power of a cooling device.
--- drivers/thermal/thermal_core.c | 28 ++++++++++++++++++++++++++++ include/linux/thermal.h | 6 ++++++ 2 files changed, 34 insertions(+)
drivers/thermal/thermal_core.c +28 -0
@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwatts that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update
include/linux/thermal.h +6 -0
@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Signature · 1 line
1.9.1
PATCH v4 2/5 thermal: power_allocator: relax the requirement of a sustainable_power in tzp
In reply to Javi MerinoThe power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
--- drivers/thermal/power_allocator.c | 128 ++++++++++++++++++++++++++++++-------- 1 file changed, 103 insertions(+), 25 deletions(-)
drivers/thermal/power_allocator.c +103 -25
@@ -73,6 +73,90 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** +* estimate_controller_constants() - Estimate the constants for the PID controller +* @tz: thermal zone for which to estimate the constants +* @sustainable_power: sustainable power for the thermal zone +* @trip_switch_on: trip point number for the switch on temperature +* @control_temp: target temperature for the power allocator governor +* @force: whether to force the update of the constants +* +* This function is used to update the estimation of the PID +* controller constants in struct thermal_zone_parameters. +* Sustainable power is provided in case it was estimated. The +* estimated sustainable_power should not be stored in the +* thermal_zone_parameters so it has to be passed explicitly to this +* function. +* +* If @force is not set, the values in the thermal zone's parameters +* are preserved if they are not zero. If @force is set, the values +* in thermal zone's parameters are overwritten. +*/ +static void estimate_controller_constants (struct thermal_zone_device *tz, +u32 sustainable_power, +int trip_switch_on, +unsigned long control_temp, +bool force) +{ +int ret; +unsigned long switch_on_temp; +u32 temperature_threshold; + + ret = tz->ops->get_trip_temp (tz, trip_switch_on, &switch_on_temp); +if (ret) + switch_on_temp =0 ; + + temperature_threshold = control_temp - switch_on_temp; + +if (!tz->tzp->k_po || force) + tz->tzp->k_po =int_to_frac (sustainable_power) / + temperature_threshold; + +if (!tz->tzp->k_pu || force) + tz->tzp->k_pu =int_to_frac (2 * sustainable_power) / + temperature_threshold; + +if (!tz->tzp->k_i || force) + tz->tzp->k_i =int_to_frac (10 ) /1000 ; +/* +* The default for k_d and integral_cutoff is 0, so we can +* leave them as they are. +*/ +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius
@@ -98,10 +182,20 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power); +if (tz->tzp->sustainable_power) { + sustainable_power = tz->tzp->sustainable_power; + }else { + sustainable_power =estimate_sustainable_power (tz); +estimate_controller_constants (tz, sustainable_power, + params->trip_switch_on, + control_temp, true); + } + err = ((s32 )control_temp - (s32 )current_temp); err =int_to_frac (err);
@@ -139,7 +233,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d;/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);
@@ -417,19 +511,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz) {int ret;struct power_allocator_params *params; -unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +unsigned long control_temp; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
@@ -438,29 +531,14 @@ static int power_allocator_bind(struct thermal_zone_device *tz) goto free; } - ret = tz->ops->get_trip_temp (tz, params->trip_switch_on, - &switch_on_temp); -if (ret) - goto free; - ret = tz->ops->get_trip_temp (tz, params->trip_max_desired_temperature, &control_temp);if (ret) goto free; - temperature_threshold = control_temp - switch_on_temp; - - tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; - tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; - tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ; -/* -* The default for k_d and integral_cutoff is 0, so we can -* leave them as they are. -*/ - +estimate_controller_constants (tz, tz->tzp->sustainable_power, + params->trip_switch_on, control_temp, + false);reset_pid_controller (params); tz->governor_data = params;
Signature · 1 line
1.9.1
PATCH v4 3/5 thermal: power_allocator: relax the requirement of two passive trip points
In reply to Javi MerinoThe power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 96 +++++++++++++++++-------------- 2 files changed, 53 insertions(+), 45 deletions(-)
Documentation/thermal/power_allocator.txt +1 -1
@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive trip
drivers/thermal/power_allocator.c +52 -44
162 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v4 4/5 thermal: power_allocator: don't require tzp to be present for the thermal zone
In reply to Javi MerinoThermal zones created using thermal_zone_device_create() may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.
---
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a better behavior.
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
drivers/thermal/power_allocator.c +27 -5
@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term.
@@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;
@@ -530,8 +533,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {
@@ -539,13 +541,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)struct power_allocator_params *params;unsigned long control_temp; -if (!tz->tzp) -return -EINVAL ; - params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL ); +if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );
@@ -562,11 +571,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +kfree (params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +kfree (tz->governor_data); tz->governor_data =NULL ; }
Signature · 1 line
1.9.1
Re: [PATCH v4 4/5] thermal: power_allocator: don't require tzp to be present for the thermal zone
Quoted 6 lines · Javi Merino
Thermal zones created using
thermal_zone_device_create()may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.
Quoted 8 lines
Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>---
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a better behavior.
Why?
Just ignoring the thermal zone seems reasonable and simpler.
Quoted 38 lines
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)drivers/thermal/power_allocator.c +4
-2@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term. @@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;@@ -530,8 +533,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {@@ -539,13 +541,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)struct power_allocator_params *params;unsigned long control_temp;
drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 549
Quoted 10 lines
drivers/thermal/power_allocator.c +2
-3-if (!tz->tzp) -return -EINVAL ; - params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL );
Why bother to allocate this dummy struct?
Can't we just leave tz->tzp as NULL, and do a NULL check where needed?
Quoted 39 lines
drivers/thermal/power_allocator.c +21
-1+if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );@@ -562,11 +571,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +kfree (params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +kfree (tz->governor_data); tz->governor_data =NULL ; } --1.9.1
Re: [PATCH v4 4/5] thermal: power_allocator: don't require tzp to be present for the thermal zone
Quoted 12 lines · Daniel Kurtz
Quoted 11 lines · Javi Merino
Thermal zones created using
thermal_zone_device_create()may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>---
Quoted 8 lines
Quoted 3 lines
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a better behavior.
Why?
Just ignoring the thermal zone seems reasonable and simpler.From the developer point of view, I agree that it's simpler. What I
want to avoid is the system integrator getting different behaviors based on the presence of tzp when the thermal zone was created. If the integrator was to configure this from userspace, they would only be able to do so if the thermal zone was created with tzp. I don't like this distinction, I prefer the consistency from the user point of view that this patch gives.
Cheers,
Javi
Quoted 91 lines
Quoted 37 lines
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)drivers/thermal/power_allocator.c +4
-2@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term. @@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;@@ -530,8 +533,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {@@ -539,13 +541,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)struct power_allocator_params *params;unsigned long control_temp;drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 549
Quoted 10 lines
drivers/thermal/power_allocator.c +2
-3-if (!tz->tzp) -return -EINVAL ; - params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL );Why bother to allocate this dummy struct?
Can't we just leavetz->tzpas NULL, and do a NULL check where needed?Quoted 39 lines
drivers/thermal/power_allocator.c +21
-1+if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );@@ -562,11 +571,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +kfree (params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +kfree (tz->governor_data); tz->governor_data =NULL ; } --1.9.1
Daniel Kurtz
Reviewed-byRe: [PATCH v4 4/5] thermal: power_allocator: don't require tzp to be present for the thermal zone
Hi Javi,
Quoted 20 lines · Javi Merino
Quoted 12 lines · Daniel Kurtz
Quoted 11 lines · Javi Merino
Thermal zones created using
thermal_zone_device_create()may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.Cc Zhang Rui <[email protected]>Cc Eduardo Valentin <[email protected]>Signed-off-by Javi Merino <[email protected]>---
Quoted 6 lines
Quoted 3 lines
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a better behavior.
Why?
Just ignoring the thermal zone seems reasonable and simpler.
Quoted 7 lines
From the developer point of view, I agree that it's simpler. What I want to avoid is the system integrator getting different behaviors based on the presence of tzp when the thermal zone was created. If the integrator was to configure this from userspace, they would only be able to do so if the thermal zone was created with tzp. I don't like this distinction, I prefer the consistency from the user point of view that this patch gives.
Ok, thanks for the answer.
Thanks!
-Dan
Quoted 95 lines
Cheers,
JaviQuoted 91 lines
Quoted 37 lines
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)drivers/thermal/power_allocator.c +4
-2@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term. @@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;@@ -530,8 +533,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {@@ -539,13 +541,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)struct power_allocator_params *params;unsigned long control_temp;drivers/thermal/power_allocator.c static int power_allocator_bind(struct thermal_zone_device *tz) · line 549
Quoted 10 lines
drivers/thermal/power_allocator.c +2
-3-if (!tz->tzp) -return -EINVAL ; - params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL );Why bother to allocate this dummy struct?
Can't we just leavetz->tzpas NULL, and do a NULL check where needed?Quoted 39 lines
drivers/thermal/power_allocator.c +21
-1+if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );@@ -562,11 +571,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +kfree (params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +kfree (tz->governor_data); tz->governor_data =NULL ; } --1.9.1
PATCH v4 5/5 thermal: power_allocator: exit early if there are no cooling devices
In reply to Javi MerinoDon't waste cycles in the power allocator governor's throttle function if there are no cooling devices and exit early.
This commit doesn't change any functionality, but should provide better performance for the odd case of a thermal zone with trip points but without cooling devices.
--- drivers/thermal/power_allocator.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/thermal/power_allocator.c +5 -0
@@ -348,6 +348,11 @@ static int allocate_power(struct thermal_zone_device *tz, } } +if (!num_actors) { + ret = -ENODEV ; + goto unlock; + } +/* * We need to allocate five arrays of the same size: * req_power, max_power, granted_power, extra_actor_power and
Signature · 1 line
1.9.1
Re: [PATCH v4 0/5] Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoQuoted 28 lines · Javi Merino
Relax the thermal governor requirements of
sustainable_powerand at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.Changes since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
-power_actor_get_min_power()moved to a patch of its own.Changes since v2:
- Typos suggested by Daniel KurtzChanges since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih WangJavi Merino (5):
thermal: Add a function to get the minimum power
thermal:power_allocator: relax the requirement of asustainable_power
in tzp
thermal:power_allocator: relax the requirement of two passive trip
points
thermal:power_allocator: don't require tzp to be present for the
thermal zone
thermal:power_allocator: exit early if there are no cooling devices
Quoted 5 lines
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 241 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 ++++ include/linux/thermal.h | 6 + 4 files changed, 212 insertions(+), 65 deletions(-)
Gentle ping.
v5 cover Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoRelax the thermal governor requirements of sustainable_power and at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best possible with the data provided.
Changes since v4:
- Fix crash when a thermal zone with no trip points has no get_trip_point_temp(). Reported by Daniel Kurtz.
- s/estimate_controller_constants()/estimate_pid_constants()/g
Changes since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
- power_actor_get_min_power() moved to a patch of its own.
Changes since v2:
- Typos suggested by Daniel Kurtz
Changes since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih Wang
Javi Merino (5):
thermal: Add a function to get the minimum power
thermal: power_allocator: relax the requirement of a sustainable_power
in tzp
thermal: power_allocator: relax the requirement of two passive trip
points
thermal: power_allocator: don't require tzp to be present for the
thermal zone
thermal: power_allocator: exit early if there are no cooling devices
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 243 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 ++++ include/linux/thermal.h | 6 + 4 files changed, 214 insertions(+), 65 deletions(-)
Signature · 1 line
1.9.1
PATCH v5 1/5 thermal: Add a function to get the minimum power
The thermal core already has a function to get the maximum power of a cooling device: power_actor_get_max_power(). Add a function to get the minimum power of a cooling device.
--- drivers/thermal/thermal_core.c | 28 ++++++++++++++++++++++++++++ include/linux/thermal.h | 6 ++++++ 2 files changed, 34 insertions(+)
drivers/thermal/thermal_core.c +28 -0
@@ -997,6 +997,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwatts that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update
include/linux/thermal.h +6 -0
@@ -384,6 +384,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
@@ -419,6 +421,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Signature · 1 line
1.9.1
PATCH v5 2/5 thermal: power_allocator: relax the requirement of a sustainable_power in tzp
In reply to Javi MerinoThe power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
--- drivers/thermal/power_allocator.c | 125 ++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 25 deletions(-)
drivers/thermal/power_allocator.c +100 -25
@@ -73,6 +73,88 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** +* estimate_pid_constants() - Estimate the constants for the PID controller +* @tz: thermal zone for which to estimate the constants +* @sustainable_power: sustainable power for the thermal zone +* @trip_switch_on: trip point number for the switch on temperature +* @control_temp: target temperature for the power allocator governor +* @force: whether to force the update of the constants +* +* This function is used to update the estimation of the PID +* controller constants in struct thermal_zone_parameters. +* Sustainable power is provided in case it was estimated. The +* estimated sustainable_power should not be stored in the +* thermal_zone_parameters so it has to be passed explicitly to this +* function. +* +* If @force is not set, the values in the thermal zone's parameters +* are preserved if they are not zero. If @force is set, the values +* in thermal zone's parameters are overwritten. +*/ +static void estimate_pid_constants (struct thermal_zone_device *tz, +u32 sustainable_power,int trip_switch_on, +unsigned long control_temp,bool force) +{ +int ret; +unsigned long switch_on_temp; +u32 temperature_threshold; + + ret = tz->ops->get_trip_temp (tz, trip_switch_on, &switch_on_temp); +if (ret) + switch_on_temp =0 ; + + temperature_threshold = control_temp - switch_on_temp; + +if (!tz->tzp->k_po || force) + tz->tzp->k_po =int_to_frac (sustainable_power) / + temperature_threshold; + +if (!tz->tzp->k_pu || force) + tz->tzp->k_pu =int_to_frac (2 * sustainable_power) / + temperature_threshold; + +if (!tz->tzp->k_i || force) + tz->tzp->k_i =int_to_frac (10 ) /1000 ; +/* +* The default for k_d and integral_cutoff is 0, so we can +* leave them as they are. +*/ +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius
@@ -98,10 +180,20 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power); +if (tz->tzp->sustainable_power) { + sustainable_power = tz->tzp->sustainable_power; + }else { + sustainable_power =estimate_sustainable_power (tz); +estimate_pid_constants (tz, sustainable_power, + params->trip_switch_on, control_temp, + true); + } + err = ((s32 )control_temp - (s32 )current_temp); err =int_to_frac (err);
@@ -139,7 +231,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d;/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);
@@ -416,19 +508,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz) {int ret;struct power_allocator_params *params; -unsigned long switch_on_temp, control_temp; -u32 temperature_threshold; +unsigned long control_temp; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
@@ -437,29 +528,13 @@ static int power_allocator_bind(struct thermal_zone_device *tz) goto free; } - ret = tz->ops->get_trip_temp (tz, params->trip_switch_on, - &switch_on_temp); -if (ret) - goto free; - ret = tz->ops->get_trip_temp (tz, params->trip_max_desired_temperature, &control_temp);if (ret) goto free; - temperature_threshold = control_temp - switch_on_temp; - - tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; - tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; - tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ; -/* -* The default for k_d and integral_cutoff is 0, so we can -* leave them as they are. -*/ - +estimate_pid_constants (tz, tz->tzp->sustainable_power, + params->trip_switch_on, control_temp, false);reset_pid_controller (params); tz->governor_data = params;
Signature · 1 line
1.9.1
PATCH v5 3/5 thermal: power_allocator: relax the requirement of two passive trip points
In reply to Javi MerinoThe power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 101 +++++++++++++++++------------- 2 files changed, 58 insertions(+), 45 deletions(-)
Documentation/thermal/power_allocator.txt +1 -1
@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive trip
drivers/thermal/power_allocator.c +57 -44
166 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v5 4/5 thermal: power_allocator: don't require tzp to be present for the thermal zone
In reply to Javi MerinoThermal zones created using thermal_zone_device_create() may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.
---
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a more consistent behavior for the system integrator as it doesn't make a distinction between thermal zones created with tzp and those that don't.
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
drivers/thermal/power_allocator.c +27 -5
@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term.
@@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;
@@ -527,8 +530,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {
@@ -536,13 +538,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)struct power_allocator_params *params;unsigned long control_temp; -if (!tz->tzp) -return -EINVAL ; - params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL ); +if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );
@@ -563,11 +572,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +kfree (params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +kfree (tz->governor_data); tz->governor_data =NULL ; }
Signature · 1 line
1.9.1
PATCH v5 5/5 thermal: power_allocator: exit early if there are no cooling devices
In reply to Javi MerinoDon't waste cycles in the power allocator governor's throttle function if there are no cooling devices and exit early.
This commit doesn't change any functionality, but should provide better performance for the odd case of a thermal zone with trip points but without cooling devices.
--- drivers/thermal/power_allocator.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/thermal/power_allocator.c +5 -0
@@ -346,6 +346,11 @@ static int allocate_power(struct thermal_zone_device *tz, } } +if (!num_actors) { + ret = -ENODEV ; + goto unlock; + } +/* * We need to allocate five arrays of the same size: * req_power, max_power, granted_power, extra_actor_power and
Signature · 1 line
1.9.1
Re: [PATCH v5 0/5] Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoHi Javi,
Quoted 4 lines · Javi Merino
Relax the thermal governor requirements of
sustainable_powerand at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best possible with the data provided.
I tested this whole series on my MT8173 board with a battery thermal zone with no trip points, so, for this whole series (not sure if both are needed, so take your pick):
I am a bit confused by MAINTAINERS for drivers/thermal. Will these patches be picked up by Eduardo or Zhang?
Thanks!
-Dan
Quoted 37 lines
Changes since v4:
- Fix crash when a thermal zone with no trip points has noget_trip_point_temp(). Reported by Daniel Kurtz.
- s/estimate_controller_constants()/estimate_pid_constants()/gChanges since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
-power_actor_get_min_power()moved to a patch of its own.Changes since v2:
- Typos suggested by Daniel KurtzChanges since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih WangJavi Merino (5):
thermal: Add a function to get the minimum power
thermal:power_allocator: relax the requirement of asustainable_power
in tzp
thermal:power_allocator: relax the requirement of two passive trip
points
thermal:power_allocator: don't require tzp to be present for the
thermal zone
thermal:power_allocator: exit early if there are no cooling devicesDocumentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 243 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 ++++ include/linux/thermal.h | 6 + 4 files changed, 214 insertions(+), 65 deletions(-)--
1.9.1
v6 cover Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoRelax the thermal governor requirements of sustainable_power and at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best possible with the data provided.
Changes since v5:
- Rebased on top of v4.3-rc1
Changes since v4:
- Fix crash when a thermal zone with no trip points has no get_trip_point_temp(). Reported by Daniel Kurtz.
- s/estimate_controller_constants()/estimate_pid_constants()/g
Changes since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
- power_actor_get_min_power() moved to a patch of its own.
Changes since v2:
- Typos suggested by Daniel Kurtz
Changes since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih Wang
Javi Merino (5):
thermal: Add a function to get the minimum power
thermal: power_allocator: relax the requirement of a sustainable_power
in tzp
thermal: power_allocator: relax the requirement of two passive trip
points
thermal: power_allocator: don't require tzp to be present for the
thermal zone
thermal: power_allocator: exit early if there are no cooling devices
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 243 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 ++++ include/linux/thermal.h | 6 + 4 files changed, 214 insertions(+), 65 deletions(-)
Signature · 1 line
1.9.1
PATCH v6 1/5 thermal: Add a function to get the minimum power
The thermal core already has a function to get the maximum power of a cooling device: power_actor_get_max_power(). Add a function to get the minimum power of a cooling device.
--- drivers/thermal/thermal_core.c | 28 ++++++++++++++++++++++++++++ include/linux/thermal.h | 6 ++++++ 2 files changed, 34 insertions(+)
drivers/thermal/thermal_core.c +28 -0
@@ -1013,6 +1013,34 @@ int power_actor_get_max_power(struct thermal_cooling_device *cdev, }/** +* power_actor_get_min_power() - get the mainimum power that a cdev can consume +* @cdev: pointer to &thermal_cooling_device +* @tz: a valid thermal zone device pointer +* @min_power: pointer in which to store the minimum power +* +* Calculate the minimum power consumption in milliwatts that the +* cooling device can currently consume and store it in @min_power. +* +* Return: 0 on success, -EINVAL if @cdev doesn't support the +* power_actor API or -E* on other error. +*/ +int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz,u32 *min_power) +{ +unsigned long max_state; +int ret; + +if (!cdev_is_power_actor (cdev)) +return -EINVAL ; + + ret = cdev->ops->get_max_state (cdev, &max_state); +if (ret) +return ret; + +return cdev->ops->state2power (cdev, tz, max_state, min_power); +} + +/** * power_actor_set_power() - limit the maximum power that a cooling device can consume * @cdev: pointer to &thermal_cooling_device * @instance: thermal instance to update
include/linux/thermal.h +6 -0
@@ -380,6 +380,8 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)int power_actor_get_max_power (struct thermal_cooling_device *,struct thermal_zone_device *tz,u32 *max_power); +int power_actor_get_min_power (struct thermal_cooling_device *, +struct thermal_zone_device *tz,u32 *min_power);int power_actor_set_power (struct thermal_cooling_device *,struct thermal_instance *,u32 ); struct thermal_zone_device *thermal_zone_device_register(const char *, int, int,
@@ -415,6 +417,10 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)static inline int power_actor_get_max_power (struct thermal_cooling_device *cdev,struct thermal_zone_device *tz,u32 *max_power) {return 0 ; } +static inline int power_actor_get_min_power (struct thermal_cooling_device *cdev, +struct thermal_zone_device *tz, +u32 *min_power) +{return -ENODEV ; }static inline int power_actor_set_power (struct thermal_cooling_device *cdev,struct thermal_instance *tz,u32 power) {return 0 ; }
Signature · 1 line
1.9.1
PATCH v6 2/5 thermal: power_allocator: relax the requirement of a sustainable_power in tzp
In reply to Javi MerinoThe power allocator governor currently requires that a sustainable power is passed as part of the thermal zone's thermal zone parameters. If that parameter is not provided, it doesn't register with the thermal zone.
While this parameter is strongly recommended for optimal performance, it doesn't need to be mandatory. Relax the requirement and allow the governor to bind to thermal zones that don't provide it by estimating it from the cooling devices' power model.
--- drivers/thermal/power_allocator.c | 125 ++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 25 deletions(-)
drivers/thermal/power_allocator.c +100 -25
@@ -73,6 +73,88 @@ struct power_allocator_params { };/** +* estimate_sustainable_power() - Estimate the sustainable power of a thermal zone +* @tz: thermal zone we are operating in +* +* For thermal zones that don't provide a sustainable_power in their +* thermal_zone_params, estimate one. Calculate it using the minimum +* power of all the cooling devices as that gives a valid value that +* can give some degree of functionality. For optimal performance of +* this governor, provide a sustainable_power in the thermal zone's +* thermal_zone_params. +*/ +static u32 estimate_sustainable_power (struct thermal_zone_device *tz) +{ +u32 sustainable_power =0 ; +struct thermal_instance *instance; +struct power_allocator_params *params = tz->governor_data; + +list_for_each_entry (instance, &tz->thermal_instances, tz_node) { +struct thermal_cooling_device *cdev = instance->cdev; +u32 min_power; + +if (instance->trip != params->trip_max_desired_temperature) +continue ; + +if (power_actor_get_min_power (cdev, tz, &min_power)) +continue ; + + sustainable_power += min_power; + } + +return sustainable_power; +} + +/** +* estimate_pid_constants() - Estimate the constants for the PID controller +* @tz: thermal zone for which to estimate the constants +* @sustainable_power: sustainable power for the thermal zone +* @trip_switch_on: trip point number for the switch on temperature +* @control_temp: target temperature for the power allocator governor +* @force: whether to force the update of the constants +* +* This function is used to update the estimation of the PID +* controller constants in struct thermal_zone_parameters. +* Sustainable power is provided in case it was estimated. The +* estimated sustainable_power should not be stored in the +* thermal_zone_parameters so it has to be passed explicitly to this +* function. +* +* If @force is not set, the values in the thermal zone's parameters +* are preserved if they are not zero. If @force is set, the values +* in thermal zone's parameters are overwritten. +*/ +static void estimate_pid_constants (struct thermal_zone_device *tz, +u32 sustainable_power,int trip_switch_on, +int control_temp,bool force) +{ +int ret; +int switch_on_temp; +u32 temperature_threshold; + + ret = tz->ops->get_trip_temp (tz, trip_switch_on, &switch_on_temp); +if (ret) + switch_on_temp =0 ; + + temperature_threshold = control_temp - switch_on_temp; + +if (!tz->tzp->k_po || force) + tz->tzp->k_po =int_to_frac (sustainable_power) / + temperature_threshold; + +if (!tz->tzp->k_pu || force) + tz->tzp->k_pu =int_to_frac (2 * sustainable_power) / + temperature_threshold; + +if (!tz->tzp->k_i || force) + tz->tzp->k_i =int_to_frac (10 ) /1000 ; +/* +* The default for k_d and integral_cutoff is 0, so we can +* leave them as they are. +*/ +} + +/** * pid_controller() - PID controller * @tz: thermal zone we are operating in * @current_temp: the current temperature in millicelsius
@@ -98,10 +180,20 @@ static u32 pid_controller(struct thermal_zone_device *tz, {s64 p, i, d, power_range;s32 err, max_power_frac; +u32 sustainable_power;struct power_allocator_params *params = tz->governor_data; max_power_frac =int_to_frac (max_allocatable_power); +if (tz->tzp->sustainable_power) { + sustainable_power = tz->tzp->sustainable_power; + }else { + sustainable_power =estimate_sustainable_power (tz); +estimate_pid_constants (tz, sustainable_power, + params->trip_switch_on, control_temp, + true); + } + err = control_temp - current_temp; err =int_to_frac (err);
@@ -139,7 +231,7 @@ static u32 pid_controller(struct thermal_zone_device *tz, power_range = p + i + d;/* feed-forward the known sustainable dissipatable power */ - power_range = tz->tzp->sustainable_power +frac_to_int (power_range); + power_range = sustainable_power +frac_to_int (power_range); power_range =clamp (power_range, (s64 )0 , (s64 )max_allocatable_power);
@@ -416,19 +508,18 @@ static int power_allocator_bind(struct thermal_zone_device *tz) {int ret;struct power_allocator_params *params; -int switch_on_temp, control_temp; -u32 temperature_threshold; +int control_temp; -if (!tz->tzp || !tz->tzp->sustainable_power) { -dev_err (&tz->device, -"power_allocator: missing sustainable_power\n" ); +if (!tz->tzp)return -EINVAL ; - } params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp->sustainable_power) +dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" ); + ret =get_governor_trips (tz, params);if (ret) { dev_err(&tz->device,
@@ -437,29 +528,13 @@ static int power_allocator_bind(struct thermal_zone_device *tz) goto free; } - ret = tz->ops->get_trip_temp (tz, params->trip_switch_on, - &switch_on_temp); -if (ret) - goto free; - ret = tz->ops->get_trip_temp (tz, params->trip_max_desired_temperature, &control_temp);if (ret) goto free; - temperature_threshold = control_temp - switch_on_temp; - - tz->tzp->k_po = tz->tzp->k_po ?: -int_to_frac (tz->tzp->sustainable_power) / temperature_threshold; - tz->tzp->k_pu = tz->tzp->k_pu ?: -int_to_frac (2 * tz->tzp->sustainable_power) / - temperature_threshold; - tz->tzp->k_i = tz->tzp->k_i ?:int_to_frac (10 ) /1000 ; -/* -* The default for k_d and integral_cutoff is 0, so we can -* leave them as they are. -*/ - +estimate_pid_constants (tz, tz->tzp->sustainable_power, + params->trip_switch_on, control_temp, false);reset_pid_controller (params); tz->governor_data = params;
Signature · 1 line
1.9.1
PATCH v6 3/5 thermal: power_allocator: relax the requirement of two passive trip points
In reply to Javi MerinoThe power allocator governor currently requires that the thermal zone has at least two passive trip points. If there aren't, the governor refuses to bind to the thermal zone.
This commit relaxes that requirement. Now the governor will bind to all thermal zones regardless of how many trip points they have.
--- Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 101 +++++++++++++++++------------- 2 files changed, 58 insertions(+), 45 deletions(-)
Documentation/thermal/power_allocator.txt +1 -1
@@ -4,7 +4,7 @@ Power allocator governor tunables Trip points ----------- -The governor requires the following two passive trip points: +The governor works optimally with the following two passive trip points: 1. "switch on" trip point: temperature above which the governor control loop starts operating. This is the first passive trip
drivers/thermal/power_allocator.c +57 -44
166 lines not on this page · raw message
Signature · 1 line
1.9.1
PATCH v6 4/5 thermal: power_allocator: don't require tzp to be present for the thermal zone
In reply to Javi MerinoThermal zones created using thermal_zone_device_create() may not have tzp. As the governor gets its parameters from there, allocate it while the governor is bound to the thermal zone so that it can operate in it. In this case, tzp is freed when the thermal zone switches to another governor.
---
While this would be easier to do by just ignoring the thermal zone if there was no tzp, I think the approach in this patch provides a more consistent behavior for the system integrator as it doesn't make a distinction between thermal zones created with tzp and those that don't.
drivers/thermal/power_allocator.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
drivers/thermal/power_allocator.c +27 -5
@@ -58,6 +58,8 @@ static inline s64 div_frac(s64 x, s64 y)/** * struct power_allocator_params - parameters for the power allocator governor +* @allocated_tzp: whether we have allocated tzp for this thermal zone and +* it needs to be freed on unbind * @err_integral: accumulated error in the PID controller. * @prev_err: error in the previous iteration of the PID controller. * Used to calculate the derivative term.
@@ -70,6 +72,7 @@ static inline s64 div_frac(s64 x, s64 y)* controlling for. */ struct power_allocator_params { +bool allocated_tzp;s64 err_integral;s32 prev_err;int trip_switch_on;
@@ -527,8 +530,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz)* Initialize the PID controller parameters and bind it to the thermal * zone. * -* Return: 0 on success, -EINVAL if the thermal zone doesn't have tzp or -ENOMEM -* if we ran out of memory. +* Return: 0 on success, or -ENOMEM if we ran out of memory. */ static int power_allocator_bind (struct thermal_zone_device *tz) {
@@ -536,13 +538,20 @@ static int power_allocator_bind(struct thermal_zone_device *tz)struct power_allocator_params *params;int control_temp; -if (!tz->tzp) -return -EINVAL ; - params =kzalloc (sizeof (*params),GFP_KERNEL );if (!params)return -ENOMEM ; +if (!tz->tzp) { + tz->tzp =kzalloc (sizeof (*tz->tzp),GFP_KERNEL ); +if (!tz->tzp) { + ret = -ENOMEM ; + goto free_params; + } + + params->allocated_tzp = true; + } +if (!tz->tzp->sustainable_power)dev_warn (&tz->device,"power_allocator: sustainable_power will be estimated\n" );
@@ -563,11 +572,24 @@ static int power_allocator_bind(struct thermal_zone_device *tz) tz->governor_data = params;return 0 ; + +free_params: +kfree (params); + +return ret; }static void power_allocator_unbind (struct thermal_zone_device *tz) { +struct power_allocator_params *params = tz->governor_data; +dev_dbg (&tz->device,"Unbinding from thermal zone %d\n" , tz->id); + +if (params->allocated_tzp) { +kfree (tz->tzp); + tz->tzp =NULL ; + } +kfree (tz->governor_data); tz->governor_data =NULL ; }
Signature · 1 line
1.9.1
PATCH v6 5/5 thermal: power_allocator: exit early if there are no cooling devices
In reply to Javi MerinoDon't waste cycles in the power allocator governor's throttle function if there are no cooling devices and exit early.
This commit doesn't change any functionality, but should provide better performance for the odd case of a thermal zone with trip points but without cooling devices.
--- drivers/thermal/power_allocator.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/thermal/power_allocator.c +5 -0
@@ -346,6 +346,11 @@ static int allocate_power(struct thermal_zone_device *tz, } } +if (!num_actors) { + ret = -ENODEV ; + goto unlock; + } +/* * We need to allocate five arrays of the same size: * req_power, max_power, granted_power, extra_actor_power and
Signature · 1 line
1.9.1
Re: [PATCH v4 0/5] Let the power allocator thermal governor run on any thermal zone
In reply to Javi MerinoJavi,
Quoted 18 lines · Javi Merino
Relax the thermal governor requirements of
sustainable_powerand at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.Changes since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
-power_actor_get_min_power()moved to a patch of its own.Changes since v2:
- Typos suggested by Daniel KurtzChanges since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih Wang
Quoted 9 lines
Javi Merino (5):
thermal: Add a function to get the minimum power
thermal:power_allocator: relax the requirement of asustainable_power
in tzp
thermal:power_allocator: relax the requirement of two passive trip
points
thermal:power_allocator: don't require tzp to be present for the
thermal zone
thermal:power_allocator: exit early if there are no cooling devices
This patch set does not apply clean. Could you please refresh it?
Quoted 10 lines
Documentation/thermal/power_allocator.txt | 2 +- drivers/thermal/power_allocator.c | 241 ++++++++++++++++++++++-------- drivers/thermal/thermal_core.c | 28 ++++ include/linux/thermal.h | 6 + 4 files changed, 212 insertions(+), 65 deletions(-)Signature · 1 line
1.9.1
Re: [PATCH v4 0/5] Let the power allocator thermal governor run on any thermal zone
Quoted 31 lines · Eduardo Valentin
Javi,
Quoted 18 lines · Javi Merino
Relax the thermal governor requirements of
sustainable_powerand at least two trip points so that it can be bound to any thermal zone. Its behavior won't be optimal, it would be the best it can with the data provided.Changes since v3:
- Don't hardcode a value for sustainable power and re-estimate the PID controllers every time if no sustainable power is given as suggested by Eduardo Valentin.
-power_actor_get_min_power()moved to a patch of its own.Changes since v2:
- Typos suggested by Daniel KurtzChanges since v1:
- Let the power allocator governor operate if the thermal zone doesn't have tzp as suggested by Chung-yih WangQuoted 9 lines
Javi Merino (5):
thermal: Add a function to get the minimum power
thermal:power_allocator: relax the requirement of asustainable_power
in tzp
thermal:power_allocator: relax the requirement of two passive trip
points
thermal:power_allocator: don't require tzp to be present for the
thermal zone
thermal:power_allocator: exit early if there are no cooling devices
Quoted 1 line
This patch set does not apply clean. Could you please refresh it?
I've sent a v6 that's rebased on top of v4.3-rc1
Cheers,
Javi