From c8b90d418f688acffc718a7172a351bde5b95aae Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Tue, 11 Mar 2025 08:51:19 +0900 Subject: [PATCH] thermal: core: Mark thermal zones as initializing to start with BugLink: https://bugs.launchpad.net/bugs/2101915 [ Upstream commit 7837fa8115e0273d3cfbd3d17b3f7b7291ceac08 ] After thermal_zone_device_register_with_trips() has called device_register() and it has registered the new thermal zone device with the driver core, user space may access its sysfs attributes and, among other things, it may enable the thermal zone before it is ready. To address this, introduce a new thermal zone state flag for initialization and set it before calling device_register() in thermal_zone_device_register_with_trips(). This causes __thermal_zone_device_update() to return early until the new flag is cleared. To clear it when the thermal zone is ready, introduce a new function called thermal_zone_init_complete() that will also invoke __thermal_zone_device_update() after clearing that flag (both under the thernal zone lock) and make thermal_zone_device_register_with_trips() call the new function instead of checking need_update and calling thermal_zone_device_update() when it is set. After this change, if user space enables the thermal zone prematurely, __thermal_zone_device_update() will return early for it until thermal_zone_init_complete() is called. In turn, if the thermal zone is not enabled by user space before thermal_zone_init_complete() is called, the __thermal_zone_device_update() call in it will return early because the thermal zone has not been enabled yet, but that function will be invoked again by thermal_zone_device_set_mode() when the thermal zone is enabled and it will not return early this time. The checking of need_update is not necessary any more because the __thermal_zone_device_update() calls potentially triggered by cooling device binding take place before calling thermal_zone_init_complete(), so they all will return early, which means that thermal_zone_init_complete() must call __thermal_zone_device_update() in case the thermal zone is enabled prematurely by user space. Fixes: 203d3d4aa482 ("the generic thermal sysfs driver") Signed-off-by: Rafael J. Wysocki Link: https://patch.msgid.link/9360231.CDJkKcVGEf@rjwysocki.net Reviewed-by: Lukasz Luba Signed-off-by: Sasha Levin [koichiroden: applied changes for drivers/thermal/thermal_core.h to include/linux/thermal.h due to the missing backport of: b1ae92dcfa8e ("thermal: core: Make struct thermal_zone_device definition internal")] Signed-off-by: Koichiro Den Signed-off-by: Stefan Bader --- drivers/thermal/thermal_core.c | 16 +++++++++++++--- include/linux/thermal.h | 1 + 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 1e6ec3e0c5b0..68c5c96a542d 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1239,6 +1239,16 @@ int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp) } EXPORT_SYMBOL_GPL(thermal_zone_get_crit_temp); +static void thermal_zone_init_complete(struct thermal_zone_device *tz) +{ + mutex_lock(&tz->lock); + + tz->state &= ~TZ_STATE_FLAG_INIT; + __thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + + mutex_unlock(&tz->lock); +} + /** * thermal_zone_device_register_with_trips() - register a new thermal zone device * @type: the thermal zone device type @@ -1354,6 +1364,8 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t tz->polling_delay_jiffies = msecs_to_jiffies(polling_delay); tz->passive_delay_jiffies = msecs_to_jiffies(passive_delay); + tz->state = TZ_STATE_FLAG_INIT; + /* sys I/F */ /* Add nodes that are always present via .groups */ result = thermal_zone_create_device_groups(tz, mask); @@ -1414,9 +1426,7 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t mutex_unlock(&thermal_list_lock); - /* Update the new thermal zone and mark it as already updated. */ - if (atomic_cmpxchg(&tz->need_update, 1, 0)) - thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED); + thermal_zone_init_complete(tz); thermal_notify_tz_create(tz); diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 346b9cdd0b5d..41740bb0d052 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -121,6 +121,7 @@ struct thermal_cooling_device { #define TZ_STATE_FLAG_SUSPENDED BIT(0) #define TZ_STATE_FLAG_RESUMING BIT(1) +#define TZ_STATE_FLAG_INIT BIT(2) #define TZ_STATE_READY 0