diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2024-04-22 16:32:16 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2024-04-22 16:32:16 +0200 |
commit | 7cc59868cf5bfc8726c546d1cb21f280056c816b (patch) | |
tree | 1b9a60d54da8b36a9b36049827eb222934f83c76 | |
parent | ef887d030627b02a5ba01f4f941d592b428c4ba9 (diff) | |
parent | cc3c01ee30862eaf3781f8bafd47b6883b360d3c (diff) | |
download | renesas-drivers-7cc59868cf5bfc8726c546d1cb21f280056c816b.tar.gz |
Merge branch 'thermal-core' into linux-next
Notice: this object is not reachable from any branch.
* thermal-core:
thermal: core: Relocate critical and hot trip handling
thermal: core: Drop the .throttle() governor callback
thermal: gov_user_space: Use .trip_crossed() instead of .throttle()
thermal: gov_fair_share: Eliminate unnecessary integer divisions
thermal: gov_fair_share: Use trip thresholds instead of trip temperatures
thermal: gov_fair_share: Use .manage() callback instead of .throttle()
thermal: gov_step_wise: Clean up thermal_zone_trip_update()
thermal: gov_step_wise: Use trip thresholds instead of trip temperatures
thermal: gov_step_wise: Use .manage() callback instead of .throttle()
thermal: gov_power_allocator: Eliminate a redundant variable
thermal: gov_power_allocator: Use .manage() callback instead of .throttle()
thermal: core: Introduce .manage() callback for thermal governors
thermal: gov_bang_bang: Fold thermal_zone_trip_update() into its caller
thermal: gov_bang_bang: Clean up thermal_zone_trip_update()
thermal: gov_bang_bang: Use .trip_crossed() instead of .throttle()
thermal: core: Introduce .trip_crossed() callback for thermal governors
Notice: this object is not reachable from any branch.
-rw-r--r-- | drivers/thermal/gov_bang_bang.c | 97 | ||||
-rw-r--r-- | drivers/thermal/gov_fair_share.c | 81 | ||||
-rw-r--r-- | drivers/thermal/gov_power_allocator.c | 31 | ||||
-rw-r--r-- | drivers/thermal/gov_step_wise.c | 59 | ||||
-rw-r--r-- | drivers/thermal/gov_user_space.c | 10 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.c | 30 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.h | 10 |
7 files changed, 153 insertions, 165 deletions
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c index c3b2943a2db8bf..acb52c9ee10f1a 100644 --- a/drivers/thermal/gov_bang_bang.c +++ b/drivers/thermal/gov_bang_bang.c @@ -13,60 +13,11 @@ #include "thermal_core.h" -static int thermal_zone_trip_update(struct thermal_zone_device *tz, - const struct thermal_trip *trip) -{ - int trip_index = thermal_zone_trip_id(tz, trip); - struct thermal_instance *instance; - - if (!trip->hysteresis) - dev_info_once(&tz->device, - "Zero hysteresis value for thermal zone %s\n", tz->type); - - dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n", - trip_index, trip->temperature, tz->temperature, - trip->hysteresis); - - list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - if (instance->trip != trip) - continue; - - /* in case fan is in initial state, switch the fan off */ - if (instance->target == THERMAL_NO_TARGET) - instance->target = 0; - - /* in case fan is neither on nor off set the fan to active */ - if (instance->target != 0 && instance->target != 1) { - pr_warn("Thermal instance %s controlled by bang-bang has unexpected state: %ld\n", - instance->name, instance->target); - instance->target = 1; - } - - /* - * enable fan when temperature exceeds trip_temp and disable - * the fan in case it falls below trip_temp minus hysteresis - */ - if (instance->target == 0 && tz->temperature >= trip->temperature) - instance->target = 1; - else if (instance->target == 1 && - tz->temperature < trip->temperature - trip->hysteresis) - instance->target = 0; - - dev_dbg(&instance->cdev->device, "target=%d\n", - (int)instance->target); - - mutex_lock(&instance->cdev->lock); - instance->cdev->updated = false; /* cdev needs update */ - mutex_unlock(&instance->cdev->lock); - } - - return 0; -} - /** * bang_bang_control - controls devices associated with the given zone * @tz: thermal_zone_device * @trip: the trip point + * @crossed_up: whether or not the trip has been crossed on the way up * * Regulation Logic: a two point regulation, deliver cooling state depending * on the previous state shown in this diagram: @@ -90,26 +41,54 @@ static int thermal_zone_trip_update(struct thermal_zone_device *tz, * (trip_temp - hyst) so that the fan gets turned off again. * */ -static int bang_bang_control(struct thermal_zone_device *tz, - const struct thermal_trip *trip) +static void bang_bang_control(struct thermal_zone_device *tz, + const struct thermal_trip *trip, + bool crossed_up) { struct thermal_instance *instance; - int ret; lockdep_assert_held(&tz->lock); - ret = thermal_zone_trip_update(tz, trip); - if (ret) - return ret; + dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n", + thermal_zone_trip_id(tz, trip), trip->temperature, + tz->temperature, trip->hysteresis); + + list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + if (instance->trip != trip) + continue; + + if (instance->target == THERMAL_NO_TARGET) + instance->target = 0; + + if (instance->target != 0 && instance->target != 1) { + pr_debug("Unexpected state %ld of thermal instance %s in bang-bang\n", + instance->target, instance->name); + + instance->target = 1; + } + + /* + * Enable the fan when the trip is crossed on the way up and + * disable it when the trip is crossed on the way down. + */ + if (instance->target == 0 && crossed_up) + instance->target = 1; + else if (instance->target == 1 && !crossed_up) + instance->target = 0; + + dev_dbg(&instance->cdev->device, "target=%ld\n", instance->target); + + mutex_lock(&instance->cdev->lock); + instance->cdev->updated = false; /* cdev needs update */ + mutex_unlock(&instance->cdev->lock); + } list_for_each_entry(instance, &tz->thermal_instances, tz_node) thermal_cdev_update(instance->cdev); - - return 0; } static struct thermal_governor thermal_gov_bang_bang = { .name = "bang_bang", - .throttle = bang_bang_control, + .trip_crossed = bang_bang_control, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_bang_bang); diff --git a/drivers/thermal/gov_fair_share.c b/drivers/thermal/gov_fair_share.c index 6ef8cfde7749a9..ce0ea571ed67ab 100644 --- a/drivers/thermal/gov_fair_share.c +++ b/drivers/thermal/gov_fair_share.c @@ -17,100 +17,111 @@ static int get_trip_level(struct thermal_zone_device *tz) { - const struct thermal_trip *level_trip = NULL; + const struct thermal_trip_desc *level_td = NULL; const struct thermal_trip_desc *td; int trip_level = -1; for_each_trip_desc(tz, td) { - const struct thermal_trip *trip = &td->trip; - - if (trip->temperature >= tz->temperature) + if (td->threshold > tz->temperature) continue; trip_level++; - if (!level_trip || trip->temperature > level_trip->temperature) - level_trip = trip; + if (!level_td || td->threshold > level_td->threshold) + level_td = td; } /* Bail out if the temperature is not greater than any trips. */ if (trip_level < 0) return 0; - trace_thermal_zone_trip(tz, thermal_zone_trip_id(tz, level_trip), - level_trip->type); + trace_thermal_zone_trip(tz, thermal_zone_trip_id(tz, &level_td->trip), + level_td->trip.type); return trip_level; } -static long get_target_state(struct thermal_zone_device *tz, - struct thermal_cooling_device *cdev, int percentage, int level) -{ - return (long)(percentage * level * cdev->max_state) / (100 * tz->num_trips); -} - /** * fair_share_throttle - throttles devices associated with the given zone * @tz: thermal_zone_device * @trip: trip point + * @trip_level: number of trips crossed by the zone temperature * * Throttling Logic: This uses three parameters to calculate the new * throttle state of the cooling devices associated with the given zone. * * Parameters used for Throttling: * P1. max_state: Maximum throttle state exposed by the cooling device. - * P2. percentage[i]/100: + * P2. weight[i]/total_weight: * How 'effective' the 'i'th device is, in cooling the given zone. - * P3. cur_trip_level/max_no_of_trips: + * P3. trip_level/max_no_of_trips: * This describes the extent to which the devices should be throttled. * We do not want to throttle too much when we trip a lower temperature, * whereas the throttling is at full swing if we trip critical levels. - * (Heavily assumes the trip points are in ascending order) * new_state of cooling device = P3 * P2 * P1 */ -static int fair_share_throttle(struct thermal_zone_device *tz, - const struct thermal_trip *trip) +static void fair_share_throttle(struct thermal_zone_device *tz, + const struct thermal_trip *trip, + int trip_level) { struct thermal_instance *instance; int total_weight = 0; - int total_instance = 0; - int cur_trip_level = get_trip_level(tz); - - lockdep_assert_held(&tz->lock); + int nr_instances = 0; list_for_each_entry(instance, &tz->thermal_instances, tz_node) { if (instance->trip != trip) continue; total_weight += instance->weight; - total_instance++; + nr_instances++; } list_for_each_entry(instance, &tz->thermal_instances, tz_node) { - int percentage; struct thermal_cooling_device *cdev = instance->cdev; + u64 dividend; + u32 divisor; if (instance->trip != trip) continue; - if (!total_weight) - percentage = 100 / total_instance; - else - percentage = (instance->weight * 100) / total_weight; - - instance->target = get_target_state(tz, cdev, percentage, - cur_trip_level); + dividend = trip_level; + dividend *= cdev->max_state; + divisor = tz->num_trips; + if (total_weight) { + dividend *= instance->weight; + divisor *= total_weight; + } else { + divisor *= nr_instances; + } + instance->target = div_u64(dividend, divisor); mutex_lock(&cdev->lock); __thermal_cdev_update(cdev); mutex_unlock(&cdev->lock); } +} + +static void fair_share_manage(struct thermal_zone_device *tz) +{ + int trip_level = get_trip_level(tz); + const struct thermal_trip_desc *td; + + lockdep_assert_held(&tz->lock); + + for_each_trip_desc(tz, td) { + const struct thermal_trip *trip = &td->trip; - return 0; + if (trip->temperature == THERMAL_TEMP_INVALID || + trip->type == THERMAL_TRIP_CRITICAL || + trip->type == THERMAL_TRIP_HOT) + continue; + + fair_share_throttle(tz, trip, trip_level); + } } static struct thermal_governor thermal_gov_fair_share = { - .name = "fair_share", - .throttle = fair_share_throttle, + .name = "fair_share", + .manage = fair_share_manage, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_fair_share); diff --git a/drivers/thermal/gov_power_allocator.c b/drivers/thermal/gov_power_allocator.c index ac1d02193a1bf1..7450ab77d5f09e 100644 --- a/drivers/thermal/gov_power_allocator.c +++ b/drivers/thermal/gov_power_allocator.c @@ -395,7 +395,7 @@ static void divvy_up_power(struct power_actor *power, int num_actors, } } -static int allocate_power(struct thermal_zone_device *tz, int control_temp) +static void allocate_power(struct thermal_zone_device *tz, int control_temp) { struct power_allocator_params *params = tz->governor_data; unsigned int num_actors = params->num_actors; @@ -410,7 +410,7 @@ static int allocate_power(struct thermal_zone_device *tz, int control_temp) int i = 0, ret; if (!num_actors) - return -ENODEV; + return; /* Clean all buffers for new power estimations */ memset(power, 0, params->buffer_size); @@ -471,8 +471,6 @@ static int allocate_power(struct thermal_zone_device *tz, int control_temp) num_actors, power_range, max_allocatable_power, tz->temperature, control_temp - tz->temperature); - - return 0; } /** @@ -745,40 +743,29 @@ static void power_allocator_unbind(struct thermal_zone_device *tz) tz->governor_data = NULL; } -static int power_allocator_throttle(struct thermal_zone_device *tz, - const struct thermal_trip *trip) +static void power_allocator_manage(struct thermal_zone_device *tz) { struct power_allocator_params *params = tz->governor_data; - bool update; + const struct thermal_trip *trip = params->trip_switch_on; lockdep_assert_held(&tz->lock); - /* - * We get called for every trip point but we only need to do - * our calculations once - */ - if (trip != params->trip_max) - return 0; - - trip = params->trip_switch_on; if (trip && tz->temperature < trip->temperature) { - update = tz->passive; - tz->passive = 0; reset_pid_controller(params); - allow_maximum_power(tz, update); - return 0; + allow_maximum_power(tz, tz->passive); + tz->passive = 0; + return; } + allocate_power(tz, params->trip_max->temperature); tz->passive = 1; - - return allocate_power(tz, params->trip_max->temperature); } static struct thermal_governor thermal_gov_power_allocator = { .name = "power_allocator", .bind_to_tz = power_allocator_bind, .unbind_from_tz = power_allocator_unbind, - .throttle = power_allocator_throttle, + .manage = power_allocator_manage, .update_tz = power_allocator_update_tz, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_power_allocator); diff --git a/drivers/thermal/gov_step_wise.c b/drivers/thermal/gov_step_wise.c index ee2fb4e63d1478..0196a1a02290c9 100644 --- a/drivers/thermal/gov_step_wise.c +++ b/drivers/thermal/gov_step_wise.c @@ -62,32 +62,33 @@ static unsigned long get_target_state(struct thermal_instance *instance, } static void thermal_zone_trip_update(struct thermal_zone_device *tz, - const struct thermal_trip *trip) + const struct thermal_trip *trip, + int trip_threshold) { + enum thermal_trend trend = get_tz_trend(tz, trip); int trip_id = thermal_zone_trip_id(tz, trip); - enum thermal_trend trend; struct thermal_instance *instance; bool throttle = false; - int old_target; - trend = get_tz_trend(tz, trip); - - if (tz->temperature >= trip->temperature) { + if (tz->temperature >= trip_threshold) { throttle = true; trace_thermal_zone_trip(tz, trip_id, trip->type); } dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n", - trip_id, trip->type, trip->temperature, trend, throttle); + trip_id, trip->type, trip_threshold, trend, throttle); list_for_each_entry(instance, &tz->thermal_instances, tz_node) { + int old_target; + if (instance->trip != trip) continue; old_target = instance->target; instance->target = get_target_state(instance, trend, throttle); - dev_dbg(&instance->cdev->device, "old_target=%d, target=%d\n", - old_target, (int)instance->target); + + dev_dbg(&instance->cdev->device, "old_target=%d, target=%ld\n", + old_target, instance->target); if (instance->initialized && old_target == instance->target) continue; @@ -103,40 +104,44 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, } instance->initialized = true; + mutex_lock(&instance->cdev->lock); instance->cdev->updated = false; /* cdev needs update */ mutex_unlock(&instance->cdev->lock); } } -/** - * step_wise_throttle - throttles devices associated with the given zone - * @tz: thermal_zone_device - * @trip: trip point - * - * Throttling Logic: This uses the trend of the thermal zone to throttle. - * If the thermal zone is 'heating up' this throttles all the cooling - * devices associated with the zone and its particular trip point, by one - * step. If the zone is 'cooling down' it brings back the performance of - * the devices by one step. - */ -static int step_wise_throttle(struct thermal_zone_device *tz, - const struct thermal_trip *trip) +static void step_wise_manage(struct thermal_zone_device *tz) { + const struct thermal_trip_desc *td; struct thermal_instance *instance; lockdep_assert_held(&tz->lock); - thermal_zone_trip_update(tz, trip); + /* + * Throttling Logic: Use the trend of the thermal zone to throttle. + * If the thermal zone is 'heating up', throttle all of the cooling + * devices associated with each trip point by one step. If the zone + * is 'cooling down', it brings back the performance of the devices + * by one step. + */ + for_each_trip_desc(tz, td) { + const struct thermal_trip *trip = &td->trip; + + if (trip->temperature == THERMAL_TEMP_INVALID || + trip->type == THERMAL_TRIP_CRITICAL || + trip->type == THERMAL_TRIP_HOT) + continue; + + thermal_zone_trip_update(tz, trip, td->threshold); + } list_for_each_entry(instance, &tz->thermal_instances, tz_node) thermal_cdev_update(instance->cdev); - - return 0; } static struct thermal_governor thermal_gov_step_wise = { - .name = "step_wise", - .throttle = step_wise_throttle, + .name = "step_wise", + .manage = step_wise_manage, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_step_wise); diff --git a/drivers/thermal/gov_user_space.c b/drivers/thermal/gov_user_space.c index 7a1790b7e8f557..75137b419eb239 100644 --- a/drivers/thermal/gov_user_space.c +++ b/drivers/thermal/gov_user_space.c @@ -26,11 +26,13 @@ static int user_space_bind(struct thermal_zone_device *tz) * notify_user_space - Notifies user space about thermal events * @tz: thermal_zone_device * @trip: trip point + * @crossed_up: whether or not the trip has been crossed on the way up * * This function notifies the user space through UEvents. */ -static int notify_user_space(struct thermal_zone_device *tz, - const struct thermal_trip *trip) +static void notify_user_space(struct thermal_zone_device *tz, + const struct thermal_trip *trip, + bool crossed_up) { char *thermal_prop[5]; int i; @@ -46,13 +48,11 @@ static int notify_user_space(struct thermal_zone_device *tz, kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, thermal_prop); for (i = 0; i < 4; ++i) kfree(thermal_prop[i]); - - return 0; } static struct thermal_governor thermal_gov_user_space = { .name = "user_space", - .throttle = notify_user_space, + .trip_crossed = notify_user_space, .bind_to_tz = user_space_bind, }; THERMAL_GOVERNOR_DECLARE(thermal_gov_user_space); diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 58e60bcdc0a58a..87b3cb8679d577 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -302,11 +302,12 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz) thermal_zone_device_set_polling(tz, tz->polling_delay_jiffies); } -static void handle_non_critical_trips(struct thermal_zone_device *tz, - const struct thermal_trip *trip) +static struct thermal_governor *thermal_get_tz_governor(struct thermal_zone_device *tz) { - tz->governor ? tz->governor->throttle(tz, trip) : - def_governor->throttle(tz, trip); + if (tz->governor) + return tz->governor; + + return def_governor; } void thermal_governor_update_tz(struct thermal_zone_device *tz, @@ -349,10 +350,6 @@ void thermal_zone_device_critical_reboot(struct thermal_zone_device *tz) static void handle_critical_trips(struct thermal_zone_device *tz, const struct thermal_trip *trip) { - /* If we have not crossed the trip_temp, we do not care. */ - if (trip->temperature <= 0 || tz->temperature < trip->temperature) - return; - trace_thermal_zone_trip(tz, thermal_zone_trip_id(tz, trip), trip->type); if (trip->type == THERMAL_TRIP_CRITICAL) @@ -404,12 +401,11 @@ static void handle_thermal_trip(struct thermal_zone_device *tz, list_add_tail(&td->notify_list_node, way_up_list); td->notify_temp = trip->temperature; td->threshold -= trip->hysteresis; - } - if (trip->type == THERMAL_TRIP_CRITICAL || trip->type == THERMAL_TRIP_HOT) - handle_critical_trips(tz, trip); - else - handle_non_critical_trips(tz, trip); + if (trip->type == THERMAL_TRIP_CRITICAL || + trip->type == THERMAL_TRIP_HOT) + handle_critical_trips(tz, trip); + } } static void update_temperature(struct thermal_zone_device *tz) @@ -470,6 +466,7 @@ static int thermal_trip_notify_cmp(void *ascending, const struct list_head *a, void __thermal_zone_device_update(struct thermal_zone_device *tz, enum thermal_notify_event event) { + struct thermal_governor *governor = thermal_get_tz_governor(tz); struct thermal_trip_desc *td; LIST_HEAD(way_down_list); LIST_HEAD(way_up_list); @@ -493,14 +490,21 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz, list_for_each_entry(td, &way_up_list, notify_list_node) { thermal_notify_tz_trip_up(tz, &td->trip); thermal_debug_tz_trip_up(tz, &td->trip); + if (governor->trip_crossed) + governor->trip_crossed(tz, &td->trip, true); } list_sort(NULL, &way_down_list, thermal_trip_notify_cmp); list_for_each_entry(td, &way_down_list, notify_list_node) { thermal_notify_tz_trip_down(tz, &td->trip); thermal_debug_tz_trip_down(tz, &td->trip); + if (governor->trip_crossed) + governor->trip_crossed(tz, &td->trip, false); } + if (governor->manage) + governor->manage(tz); + monitor_thermal_zone(tz); } diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h index b461d9583834cf..d9785e5bbb08cd 100644 --- a/drivers/thermal/thermal_core.h +++ b/drivers/thermal/thermal_core.h @@ -30,8 +30,8 @@ struct thermal_trip_desc { * otherwise it fails. * @unbind_from_tz: callback called when a governor is unbound from a * thermal zone. - * @throttle: callback called for every trip point even if temperature is - * below the trip point temperature + * @trip_crossed: called for trip points that have just been crossed + * @manage: called on thermal zone temperature updates * @update_tz: callback called when thermal zone internals have changed, e.g. * thermal cooling instance was added/removed * @governor_list: node in thermal_governor_list (in thermal_core.c) @@ -40,8 +40,10 @@ struct thermal_governor { const char *name; int (*bind_to_tz)(struct thermal_zone_device *tz); void (*unbind_from_tz)(struct thermal_zone_device *tz); - int (*throttle)(struct thermal_zone_device *tz, - const struct thermal_trip *trip); + void (*trip_crossed)(struct thermal_zone_device *tz, + const struct thermal_trip *trip, + bool crossed_up); + void (*manage)(struct thermal_zone_device *tz); void (*update_tz)(struct thermal_zone_device *tz, enum thermal_notify_event reason); struct list_head governor_list; |