thermal/core: Move the mutex inside the thermal_zone_device_update() function

All the different calls inside the thermal_zone_device_update()
function take the mutex.

The previous changes move the mutex out of the different functions,
like the throttling ops. Now that the mutexes are all at the same
level in the call stack for the thermal_zone_device_update() function,
they can be moved inside this one.

That has the benefit of:

1. Simplify the code by not having a plethora of places where the lock is taken

2. Probably closes more race windows because releasing the lock from
one line to another can give the opportunity to the thermal zone to change
its state in the meantime. For example, the thermal zone can be
enabled right after checking it is disabled.

Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Link: https://lore.kernel.org/r/20220805153834.2510142-5-daniel.lezcano@linaro.org
This commit is contained in:
Daniel Lezcano 2022-08-05 17:38:34 +02:00
Родитель 670a5e356c
Коммит a930da9bf5
4 изменённых файлов: 63 добавлений и 54 удалений

Просмотреть файл

@ -297,24 +297,18 @@ static void thermal_zone_device_set_polling(struct thermal_zone_device *tz,
static void monitor_thermal_zone(struct thermal_zone_device *tz) static void monitor_thermal_zone(struct thermal_zone_device *tz)
{ {
mutex_lock(&tz->lock);
if (tz->mode != THERMAL_DEVICE_ENABLED) if (tz->mode != THERMAL_DEVICE_ENABLED)
thermal_zone_device_set_polling(tz, 0); thermal_zone_device_set_polling(tz, 0);
else if (tz->passive) else if (tz->passive)
thermal_zone_device_set_polling(tz, tz->passive_delay_jiffies); thermal_zone_device_set_polling(tz, tz->passive_delay_jiffies);
else if (tz->polling_delay_jiffies) else if (tz->polling_delay_jiffies)
thermal_zone_device_set_polling(tz, tz->polling_delay_jiffies); thermal_zone_device_set_polling(tz, tz->polling_delay_jiffies);
mutex_unlock(&tz->lock);
} }
static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip) static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip)
{ {
mutex_lock(&tz->lock);
tz->governor ? tz->governor->throttle(tz, trip) : tz->governor ? tz->governor->throttle(tz, trip) :
def_governor->throttle(tz, trip); def_governor->throttle(tz, trip);
mutex_unlock(&tz->lock);
} }
void thermal_zone_device_critical(struct thermal_zone_device *tz) void thermal_zone_device_critical(struct thermal_zone_device *tz)
@ -382,7 +376,7 @@ static void update_temperature(struct thermal_zone_device *tz)
{ {
int temp, ret; int temp, ret;
ret = thermal_zone_get_temp(tz, &temp); ret = __thermal_zone_get_temp(tz, &temp);
if (ret) { if (ret) {
if (ret != -EAGAIN) if (ret != -EAGAIN)
dev_warn(&tz->device, dev_warn(&tz->device,
@ -391,10 +385,8 @@ static void update_temperature(struct thermal_zone_device *tz)
return; return;
} }
mutex_lock(&tz->lock);
tz->last_temperature = tz->temperature; tz->last_temperature = tz->temperature;
tz->temperature = temp; tz->temperature = temp;
mutex_unlock(&tz->lock);
trace_thermal_temperature(tz); trace_thermal_temperature(tz);
@ -457,15 +449,9 @@ EXPORT_SYMBOL_GPL(thermal_zone_device_disable);
int thermal_zone_device_is_enabled(struct thermal_zone_device *tz) int thermal_zone_device_is_enabled(struct thermal_zone_device *tz)
{ {
enum thermal_device_mode mode; lockdep_assert_held(&tz->lock);
mutex_lock(&tz->lock); return tz->mode == THERMAL_DEVICE_ENABLED;
mode = tz->mode;
mutex_unlock(&tz->lock);
return mode == THERMAL_DEVICE_ENABLED;
} }
void thermal_zone_device_update(struct thermal_zone_device *tz, void thermal_zone_device_update(struct thermal_zone_device *tz,
@ -473,9 +459,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
{ {
int count; int count;
if (!thermal_zone_device_is_enabled(tz))
return;
if (atomic_read(&in_suspend)) if (atomic_read(&in_suspend))
return; return;
@ -483,9 +466,14 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
"'get_temp' ops set\n", __func__)) "'get_temp' ops set\n", __func__))
return; return;
mutex_lock(&tz->lock);
if (!thermal_zone_device_is_enabled(tz))
goto out;
update_temperature(tz); update_temperature(tz);
thermal_zone_set_trips(tz); __thermal_zone_set_trips(tz);
tz->notify_event = event; tz->notify_event = event;
@ -493,6 +481,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
handle_thermal_trip(tz, count); handle_thermal_trip(tz, count);
monitor_thermal_zone(tz); monitor_thermal_zone(tz);
out:
mutex_unlock(&tz->lock);
} }
EXPORT_SYMBOL_GPL(thermal_zone_device_update); EXPORT_SYMBOL_GPL(thermal_zone_device_update);

Просмотреть файл

@ -112,6 +112,8 @@ int thermal_build_list_of_policies(char *buf);
/* Helpers */ /* Helpers */
void thermal_zone_set_trips(struct thermal_zone_device *tz); void thermal_zone_set_trips(struct thermal_zone_device *tz);
void __thermal_zone_set_trips(struct thermal_zone_device *tz);
int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
/* sysfs I/F */ /* sysfs I/F */
int thermal_zone_create_device_groups(struct thermal_zone_device *, int); int thermal_zone_create_device_groups(struct thermal_zone_device *, int);

Просмотреть файл

@ -64,27 +64,17 @@ get_thermal_instance(struct thermal_zone_device *tz,
} }
EXPORT_SYMBOL(get_thermal_instance); EXPORT_SYMBOL(get_thermal_instance);
/** int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
* 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 ret = -EINVAL; int ret = -EINVAL;
int count; int count;
int crit_temp = INT_MAX; int crit_temp = INT_MAX;
enum thermal_trip_type type; enum thermal_trip_type type;
if (!tz || IS_ERR(tz) || !tz->ops->get_temp) lockdep_assert_held(&tz->lock);
goto exit;
mutex_lock(&tz->lock); if (!tz || IS_ERR(tz) || !tz->ops->get_temp)
return -EINVAL;
ret = tz->ops->get_temp(tz, temp); ret = tz->ops->get_temp(tz, temp);
@ -107,35 +97,42 @@ int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp)
*temp = tz->emul_temperature; *temp = tz->emul_temperature;
} }
return ret;
}
/**
* 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 ret;
mutex_lock(&tz->lock);
ret = __thermal_zone_get_temp(tz, temp);
mutex_unlock(&tz->lock); mutex_unlock(&tz->lock);
exit:
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(thermal_zone_get_temp); EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
/** void __thermal_zone_set_trips(struct thermal_zone_device *tz)
* thermal_zone_set_trips - Computes the next trip points for the driver
* @tz: a pointer to a thermal zone device structure
*
* The function computes the next temperature boundaries by browsing
* the trip points. The result is the closer low and high trip points
* to the current temperature. These values are passed to the backend
* driver to let it set its own notification mechanism (usually an
* interrupt).
*
* It does not return a value
*/
void thermal_zone_set_trips(struct thermal_zone_device *tz)
{ {
int low = -INT_MAX; int low = -INT_MAX;
int high = INT_MAX; int high = INT_MAX;
int trip_temp, hysteresis; int trip_temp, hysteresis;
int i, ret; int i, ret;
mutex_lock(&tz->lock); lockdep_assert_held(&tz->lock);
if (!tz->ops->set_trips || !tz->ops->get_trip_hyst) if (!tz->ops->set_trips || !tz->ops->get_trip_hyst)
goto exit; return;
for (i = 0; i < tz->num_trips; i++) { for (i = 0; i < tz->num_trips; i++) {
int trip_low; int trip_low;
@ -154,7 +151,7 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
/* No need to change trip points */ /* No need to change trip points */
if (tz->prev_low_trip == low && tz->prev_high_trip == high) if (tz->prev_low_trip == low && tz->prev_high_trip == high)
goto exit; return;
tz->prev_low_trip = low; tz->prev_low_trip = low;
tz->prev_high_trip = high; tz->prev_high_trip = high;
@ -169,8 +166,24 @@ void thermal_zone_set_trips(struct thermal_zone_device *tz)
ret = tz->ops->set_trips(tz, low, high); ret = tz->ops->set_trips(tz, low, high);
if (ret) if (ret)
dev_err(&tz->device, "Failed to set trips: %d\n", ret); dev_err(&tz->device, "Failed to set trips: %d\n", ret);
}
exit: /**
* thermal_zone_set_trips - Computes the next trip points for the driver
* @tz: a pointer to a thermal zone device structure
*
* The function computes the next temperature boundaries by browsing
* the trip points. The result is the closer low and high trip points
* to the current temperature. These values are passed to the backend
* driver to let it set its own notification mechanism (usually an
* interrupt).
*
* It does not return a value
*/
void thermal_zone_set_trips(struct thermal_zone_device *tz)
{
mutex_lock(&tz->lock);
__thermal_zone_set_trips(tz);
mutex_unlock(&tz->lock); mutex_unlock(&tz->lock);
} }

Просмотреть файл

@ -49,7 +49,11 @@ static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf) mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{ {
struct thermal_zone_device *tz = to_thermal_zone(dev); struct thermal_zone_device *tz = to_thermal_zone(dev);
int enabled = thermal_zone_device_is_enabled(tz); int enabled;
mutex_lock(&tz->lock);
enabled = thermal_zone_device_is_enabled(tz);
mutex_unlock(&tz->lock);
return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled"); return sprintf(buf, "%s\n", enabled ? "enabled" : "disabled");
} }