diff options
Diffstat (limited to 'drivers/thermal/thermal_helpers.c')
| -rw-r--r-- | drivers/thermal/thermal_helpers.c | 200 |
1 files changed, 107 insertions, 93 deletions
diff --git a/drivers/thermal/thermal_helpers.c b/drivers/thermal/thermal_helpers.c index 2ba756af76b7..b1152ad7acc9 100644 --- a/drivers/thermal/thermal_helpers.c +++ b/drivers/thermal/thermal_helpers.c @@ -12,22 +12,22 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/sysfs.h> #include <linux/device.h> #include <linux/err.h> +#include <linux/export.h> #include <linux/slab.h> #include <linux/string.h> - -#include <trace/events/thermal.h> +#include <linux/sysfs.h> #include "thermal_core.h" +#include "thermal_trace.h" -int get_tz_trend(struct thermal_zone_device *tz, int trip) +int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip) { enum thermal_trend trend; - if (tz->emul_temperature || !tz->ops->get_trend || - tz->ops->get_trend(tz, trip, &trend)) { + if (tz->emul_temperature || !tz->ops.get_trend || + tz->ops.get_trend(tz, trip, &trend)) { if (tz->temperature > tz->last_temperature) trend = THERMAL_TREND_RAISING; else if (tz->temperature < tz->last_temperature) @@ -38,62 +38,63 @@ int get_tz_trend(struct thermal_zone_device *tz, int trip) return trend; } -EXPORT_SYMBOL(get_tz_trend); -struct thermal_instance * -get_thermal_instance(struct thermal_zone_device *tz, - struct thermal_cooling_device *cdev, int trip) +static bool thermal_instance_present(struct thermal_zone_device *tz, + struct thermal_cooling_device *cdev, + const struct thermal_trip *trip) { - struct thermal_instance *pos = NULL; - struct thermal_instance *target_instance = NULL; - - mutex_lock(&tz->lock); - mutex_lock(&cdev->lock); + const struct thermal_trip_desc *td = trip_to_trip_desc(trip); + struct thermal_instance *ti; - list_for_each_entry(pos, &tz->thermal_instances, tz_node) { - if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) { - target_instance = pos; - break; - } + list_for_each_entry(ti, &td->thermal_instances, trip_node) { + if (ti->cdev == cdev) + return true; } - mutex_unlock(&cdev->lock); - mutex_unlock(&tz->lock); + return false; +} + +bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz, + const struct thermal_trip *trip, + struct thermal_cooling_device *cdev) +{ + guard(thermal_zone)(tz); + guard(cooling_dev)(cdev); - return target_instance; + return thermal_instance_present(tz, cdev, trip); } -EXPORT_SYMBOL(get_thermal_instance); +EXPORT_SYMBOL_GPL(thermal_trip_is_bound_to_cdev); /** - * thermal_zone_get_temp() - returns the temperature of a thermal zone + * __thermal_zone_get_temp() - returns the temperature of a thermal zone * @tz: a valid pointer to a struct thermal_zone_device * @temp: a valid pointer to where to store the resulting temperature. * * When a valid thermal zone reference is passed, it will fetch its * temperature and fill @temp. * + * Both tz and tz->ops must be valid pointers when calling this function, + * and the tz->ops.get_temp callback must be provided. + * The function must be called under tz->lock. + * * Return: On success returns 0, an error code otherwise */ -int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) +int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) { - int ret = -EINVAL; - int count; + const struct thermal_trip_desc *td; int crit_temp = INT_MAX; - enum thermal_trip_type type; - - if (!tz || IS_ERR(tz) || !tz->ops->get_temp) - goto exit; + int ret = -EINVAL; - mutex_lock(&tz->lock); + lockdep_assert_held(&tz->lock); - ret = tz->ops->get_temp(tz, temp); + ret = tz->ops.get_temp(tz, temp); if (IS_ENABLED(CONFIG_THERMAL_EMULATION) && tz->emul_temperature) { - for (count = 0; count < tz->trips; count++) { - ret = tz->ops->get_trip_type(tz, count, &type); - if (!ret && type == THERMAL_TRIP_CRITICAL) { - ret = tz->ops->get_trip_temp(tz, count, - &crit_temp); + for_each_trip_desc(tz, td) { + const struct thermal_trip *trip = &td->trip; + + if (trip->type == THERMAL_TRIP_CRITICAL) { + crit_temp = trip->temperature; break; } } @@ -107,93 +108,106 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) *temp = tz->emul_temperature; } - mutex_unlock(&tz->lock); -exit: + if (ret) + dev_dbg(&tz->device, "Failed to get temperature: %d\n", ret); + return ret; } -EXPORT_SYMBOL_GPL(thermal_zone_get_temp); -void thermal_zone_set_trips(struct thermal_zone_device *tz) +/** + * thermal_zone_get_temp() - returns the temperature of a thermal zone + * @tz: a valid pointer to a struct thermal_zone_device + * @temp: a valid pointer to where to store the resulting temperature. + * + * When a valid thermal zone reference is passed, it will fetch its + * temperature and fill @temp. + * + * Return: On success returns 0, an error code otherwise + */ +int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp) { - int low = -INT_MAX; - int high = INT_MAX; - int trip_temp, hysteresis; - int i, ret; + int ret; - mutex_lock(&tz->lock); + if (IS_ERR_OR_NULL(tz)) + return -EINVAL; - if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) - goto exit; + guard(thermal_zone)(tz); - for (i = 0; i < tz->trips; i++) { - int trip_low; + if (!tz->ops.get_temp) + return -EINVAL; - tz->ops->get_trip_temp(tz, i, &trip_temp); - tz->ops->get_trip_hyst(tz, i, &hysteresis); + ret = __thermal_zone_get_temp(tz, temp); + if (!ret && *temp <= THERMAL_TEMP_INVALID) + return -ENODATA; - trip_low = trip_temp - hysteresis; - - if (trip_low < tz->temperature && trip_low > low) - low = trip_low; - - if (trip_temp > tz->temperature && trip_temp < high) - high = trip_temp; - } - - /* No need to change trip points */ - if (tz->prev_low_trip == low && tz->prev_high_trip == high) - goto exit; - - tz->prev_low_trip = low; - tz->prev_high_trip = high; + return ret; +} +EXPORT_SYMBOL_GPL(thermal_zone_get_temp); - dev_dbg(&tz->device, - "new temperature boundaries: %d < x < %d\n", low, high); +static int thermal_cdev_set_cur_state(struct thermal_cooling_device *cdev, int state) +{ + int ret; /* - * Set a temperature window. When this window is left the driver - * must inform the thermal core via thermal_zone_device_update. + * No check is needed for the ops->set_cur_state as the + * registering function checked the ops are correctly set */ - ret = tz->ops->set_trips(tz, low, high); + ret = cdev->ops->set_cur_state(cdev, state); if (ret) - dev_err(&tz->device, "Failed to set trips: %d\n", ret); + return ret; + + thermal_notify_cdev_state_update(cdev, state); + thermal_cooling_device_stats_update(cdev, state); + thermal_debug_cdev_state_update(cdev, state); -exit: - mutex_unlock(&tz->lock); + return 0; } -EXPORT_SYMBOL_GPL(thermal_zone_set_trips); -void thermal_cdev_update(struct thermal_cooling_device *cdev) +void __thermal_cdev_update(struct thermal_cooling_device *cdev) { struct thermal_instance *instance; unsigned long target = 0; - mutex_lock(&cdev->lock); - /* cooling device is updated*/ - if (cdev->updated) { - mutex_unlock(&cdev->lock); - return; - } - /* Make sure cdev enters the deepest cooling state */ list_for_each_entry(instance, &cdev->thermal_instances, cdev_node) { - dev_dbg(&cdev->device, "zone%d->target=%lu\n", - instance->tz->id, instance->target); if (instance->target == THERMAL_NO_TARGET) continue; if (instance->target > target) target = instance->target; } - if (!cdev->ops->set_cur_state(cdev, target)) - thermal_cooling_device_stats_update(cdev, target); + thermal_cdev_set_cur_state(cdev, target); - cdev->updated = true; - mutex_unlock(&cdev->lock); trace_cdev_update(cdev, target); dev_dbg(&cdev->device, "set to state %lu\n", target); } -EXPORT_SYMBOL(thermal_cdev_update); + +/** + * thermal_cdev_update - update cooling device state if needed + * @cdev: pointer to struct thermal_cooling_device + * + * Update the cooling device state if there is a need. + */ +void thermal_cdev_update(struct thermal_cooling_device *cdev) +{ + guard(cooling_dev)(cdev); + + if (!cdev->updated) { + __thermal_cdev_update(cdev); + cdev->updated = true; + } +} + +/** + * thermal_cdev_update_nocheck() - Unconditionally update cooling device state + * @cdev: Target cooling device. + */ +void thermal_cdev_update_nocheck(struct thermal_cooling_device *cdev) +{ + guard(cooling_dev)(cdev); + + __thermal_cdev_update(cdev); +} /** * thermal_zone_get_slope - return the slope attribute of the thermal zone |
