* [PATCH v1 0/4] thermal: core: Simplifications and suspend/resume relocation
@ 2026-03-31 19:15 Rafael J. Wysocki
2026-03-31 19:16 ` [PATCH v1 1/4] thermal: core: Drop redundant check from thermal_zone_device_update() Rafael J. Wysocki
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2026-03-31 19:15 UTC (permalink / raw)
To: Linux PM; +Cc: Daniel Lezcano, LKML, Lukasz Luba, Armin Wolf
Hi All,
This series is intended for 7.1 (it applies on top of linux-next).
It removes a redundant check (patch [1/4]), changes the thermal workqueue
to an unbound and non-freezable one (patch [2/4]), relocates the suspend
and resume of thermal zones closer to the suspend and resume of devices,
respectively (patch [3/4]), and changes the allocation of thermal_class to
static (patch [4/4]).
Thanks!
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 1/4] thermal: core: Drop redundant check from thermal_zone_device_update()
2026-03-31 19:15 [PATCH v1 0/4] thermal: core: Simplifications and suspend/resume relocation Rafael J. Wysocki
@ 2026-03-31 19:16 ` Rafael J. Wysocki
2026-03-31 19:17 ` [PATCH v1 2/4] thermal: core: Change thermal_wq to be unbound and not freezable Rafael J. Wysocki
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2026-03-31 19:16 UTC (permalink / raw)
To: Linux PM; +Cc: Daniel Lezcano, LKML, Lukasz Luba, Armin Wolf
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Since __thermal_zone_device_update() checks if tz->state is
TZ_STATE_READY and bails out immediately otherwise, it is not
necessary to check the thermal_zone_is_present() return value in
thermal_zone_device_update(). Namely, tz->state is equal to
TZ_STATE_FLAG_INIT initially and that flag is only cleared in
thermal_zone_init_complete() after adding tz to the list of thermal
zones, and thermal_zone_exit() sets TZ_STATE_FLAG_EXIT in tz->state
while removing tz from that list. Thus tz->state is not TZ_STATE_READY
when tz is not in the list and the check mentioned above is redundant.
Accordingly, drop the redundant thermal_zone_is_present() check from
thermal_zone_device_update() and drop the former altogether because it
has no more users.
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/thermal/thermal_core.c | 8 +-------
1 file changed, 1 insertion(+), 7 deletions(-)
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -702,18 +702,12 @@ int thermal_zone_device_disable(struct t
}
EXPORT_SYMBOL_GPL(thermal_zone_device_disable);
-static bool thermal_zone_is_present(struct thermal_zone_device *tz)
-{
- return !list_empty(&tz->node);
-}
-
void thermal_zone_device_update(struct thermal_zone_device *tz,
enum thermal_notify_event event)
{
guard(thermal_zone)(tz);
- if (thermal_zone_is_present(tz))
- __thermal_zone_device_update(tz, event);
+ __thermal_zone_device_update(tz, event);
}
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 2/4] thermal: core: Change thermal_wq to be unbound and not freezable
2026-03-31 19:15 [PATCH v1 0/4] thermal: core: Simplifications and suspend/resume relocation Rafael J. Wysocki
2026-03-31 19:16 ` [PATCH v1 1/4] thermal: core: Drop redundant check from thermal_zone_device_update() Rafael J. Wysocki
@ 2026-03-31 19:17 ` Rafael J. Wysocki
2026-03-31 19:18 ` [PATCH v1 3/4] thermal: core: Suspend thermal zones later and resume them earlier Rafael J. Wysocki
2026-03-31 19:19 ` [PATCH v1 4/4] thermal: core: Allocate thermal_class statically Rafael J. Wysocki
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2026-03-31 19:17 UTC (permalink / raw)
To: Linux PM; +Cc: Daniel Lezcano, LKML, Lukasz Luba, Armin Wolf
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The thermal workqueue doesn't need to be freezable or per-CPU, so drop
WQ_FREEZABLE and WQ_PERCPU from the flags when allocating it.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/thermal/thermal_core.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1915,8 +1915,7 @@ static int __init thermal_init(void)
if (result)
goto error;
- thermal_wq = alloc_workqueue("thermal_events",
- WQ_FREEZABLE | WQ_POWER_EFFICIENT | WQ_PERCPU, 0);
+ thermal_wq = alloc_workqueue("thermal_events", WQ_POWER_EFFICIENT, 0);
if (!thermal_wq) {
result = -ENOMEM;
goto unregister_netlink;
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 3/4] thermal: core: Suspend thermal zones later and resume them earlier
2026-03-31 19:15 [PATCH v1 0/4] thermal: core: Simplifications and suspend/resume relocation Rafael J. Wysocki
2026-03-31 19:16 ` [PATCH v1 1/4] thermal: core: Drop redundant check from thermal_zone_device_update() Rafael J. Wysocki
2026-03-31 19:17 ` [PATCH v1 2/4] thermal: core: Change thermal_wq to be unbound and not freezable Rafael J. Wysocki
@ 2026-03-31 19:18 ` Rafael J. Wysocki
2026-03-31 19:19 ` [PATCH v1 4/4] thermal: core: Allocate thermal_class statically Rafael J. Wysocki
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2026-03-31 19:18 UTC (permalink / raw)
To: Linux PM; +Cc: Daniel Lezcano, LKML, Lukasz Luba, Armin Wolf
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
To avoid some undesirable interactions between thermal zone suspend
and resume with user space that is running when those operations are
carried out, move them closer to the suspend and resume of devices,
respectively, by updating dpm_prepare() to carry out thermal zone
suspend and dpm_complete() to start thermal zone resume (that will
continue asynchronously).
This also makes the code easier to follow by removing one, arguably
redundant, level of indirection represented by the thermal PM notifier.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/base/power/main.c | 6 ++++
drivers/thermal/thermal_core.c | 54 +++++++++--------------------------------
include/linux/thermal.h | 6 ++++
3 files changed, 24 insertions(+), 42 deletions(-)
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -33,6 +33,7 @@
#include <trace/events/power.h>
#include <linux/cpufreq.h>
#include <linux/devfreq.h>
+#include <linux/thermal.h>
#include <linux/timer.h>
#include <linux/nmi.h>
@@ -1284,6 +1285,8 @@ void dpm_complete(pm_message_t state)
/* Allow device probing and trigger re-probing of deferred devices */
device_unblock_probing();
+ /* Start resuming thermal control */
+ thermal_pm_complete();
trace_suspend_resume(TPS("dpm_complete"), state.event, false);
}
@@ -2212,6 +2215,9 @@ int dpm_prepare(pm_message_t state)
trace_suspend_resume(TPS("dpm_prepare"), state.event, true);
+ /* Suspend thermal control. */
+ thermal_pm_prepare();
+
/*
* Give a chance for the known devices to complete their probes, before
* disable probing of devices. This sync point is important at least
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1830,7 +1830,7 @@ static void thermal_zone_pm_prepare(stru
cancel_delayed_work(&tz->poll_queue);
}
-static void thermal_pm_notify_prepare(void)
+static void __thermal_pm_prepare(void)
{
struct thermal_zone_device *tz;
@@ -1842,6 +1842,16 @@ static void thermal_pm_notify_prepare(vo
thermal_zone_pm_prepare(tz);
}
+void thermal_pm_prepare(void)
+{
+ __thermal_pm_prepare();
+ /*
+ * Allow any leftover thermal work items already on the worqueue to
+ * complete so they don't get in the way later.
+ */
+ flush_workqueue(thermal_wq);
+}
+
static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
{
guard(thermal_zone)(tz);
@@ -1858,7 +1868,7 @@ static void thermal_zone_pm_complete(str
mod_delayed_work(thermal_wq, &tz->poll_queue, 0);
}
-static void thermal_pm_notify_complete(void)
+void thermal_pm_complete(void)
{
struct thermal_zone_device *tz;
@@ -1870,41 +1880,6 @@ static void thermal_pm_notify_complete(v
thermal_zone_pm_complete(tz);
}
-static int thermal_pm_notify(struct notifier_block *nb,
- unsigned long mode, void *_unused)
-{
- switch (mode) {
- case PM_HIBERNATION_PREPARE:
- case PM_RESTORE_PREPARE:
- case PM_SUSPEND_PREPARE:
- thermal_pm_notify_prepare();
- /*
- * Allow any leftover thermal work items already on the
- * worqueue to complete so they don't get in the way later.
- */
- flush_workqueue(thermal_wq);
- break;
- case PM_POST_HIBERNATION:
- case PM_POST_RESTORE:
- case PM_POST_SUSPEND:
- thermal_pm_notify_complete();
- break;
- default:
- break;
- }
- return 0;
-}
-
-static struct notifier_block thermal_pm_nb = {
- .notifier_call = thermal_pm_notify,
- /*
- * Run at the lowest priority to avoid interference between the thermal
- * zone resume work items spawned by thermal_pm_notify() and the other
- * PM notifiers.
- */
- .priority = INT_MIN,
-};
-
static int __init thermal_init(void)
{
int result;
@@ -1941,11 +1916,6 @@ static int __init thermal_init(void)
goto unregister_governors;
}
- result = register_pm_notifier(&thermal_pm_nb);
- if (result)
- pr_warn("Thermal: Can not register suspend notifier, return %d\n",
- result);
-
return 0;
unregister_governors:
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -273,6 +273,9 @@ bool thermal_trip_is_bound_to_cdev(struc
int thermal_zone_device_enable(struct thermal_zone_device *tz);
int thermal_zone_device_disable(struct thermal_zone_device *tz);
void thermal_zone_device_critical(struct thermal_zone_device *tz);
+
+void thermal_pm_prepare(void);
+void thermal_pm_complete(void);
#else
static inline struct thermal_zone_device *thermal_zone_device_register_with_trips(
const char *type,
@@ -350,6 +353,9 @@ static inline int thermal_zone_device_en
static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
{ return -ENODEV; }
+
+static inline void thermal_pm_prepare(void) {}
+static inline void thermal_pm_complete(void) {}
#endif /* CONFIG_THERMAL */
#endif /* __THERMAL_H__ */
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v1 4/4] thermal: core: Allocate thermal_class statically
2026-03-31 19:15 [PATCH v1 0/4] thermal: core: Simplifications and suspend/resume relocation Rafael J. Wysocki
` (2 preceding siblings ...)
2026-03-31 19:18 ` [PATCH v1 3/4] thermal: core: Suspend thermal zones later and resume them earlier Rafael J. Wysocki
@ 2026-03-31 19:19 ` Rafael J. Wysocki
3 siblings, 0 replies; 5+ messages in thread
From: Rafael J. Wysocki @ 2026-03-31 19:19 UTC (permalink / raw)
To: Linux PM; +Cc: Daniel Lezcano, LKML, Lukasz Luba, Armin Wolf
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Define thermal_class as a static structure to simplify thermal_init().
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/thermal/thermal_core.c | 29 ++++++++++-------------------
1 file changed, 10 insertions(+), 19 deletions(-)
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -977,7 +977,10 @@ static void thermal_release(struct devic
}
}
-static struct class *thermal_class;
+static const struct class thermal_class = {
+ .name = "thermal",
+ .dev_release = thermal_release,
+};
static inline
void print_bind_err_msg(struct thermal_zone_device *tz,
@@ -1070,7 +1073,7 @@ __thermal_cooling_device_register(struct
!ops->set_cur_state)
return ERR_PTR(-EINVAL);
- if (!thermal_class)
+ if (!class_is_registered(&thermal_class))
return ERR_PTR(-ENODEV);
cdev = kzalloc_obj(*cdev);
@@ -1094,7 +1097,7 @@ __thermal_cooling_device_register(struct
cdev->np = np;
cdev->ops = ops;
cdev->updated = false;
- cdev->device.class = thermal_class;
+ cdev->device.class = &thermal_class;
cdev->devdata = devdata;
ret = cdev->ops->get_max_state(cdev, &cdev->max_state);
@@ -1542,7 +1545,7 @@ thermal_zone_device_register_with_trips(
if (polling_delay && passive_delay > polling_delay)
return ERR_PTR(-EINVAL);
- if (!thermal_class)
+ if (!class_is_registered(&thermal_class))
return ERR_PTR(-ENODEV);
tz = kzalloc_flex(*tz, trips, num_trips);
@@ -1578,7 +1581,7 @@ thermal_zone_device_register_with_trips(
if (!tz->ops.critical)
tz->ops.critical = thermal_zone_device_critical;
- tz->device.class = thermal_class;
+ tz->device.class = &thermal_class;
tz->devdata = devdata;
tz->num_trips = num_trips;
for_each_trip_desc(tz, td) {
@@ -1900,21 +1903,9 @@ static int __init thermal_init(void)
if (result)
goto destroy_workqueue;
- thermal_class = kzalloc_obj(*thermal_class);
- if (!thermal_class) {
- result = -ENOMEM;
- goto unregister_governors;
- }
-
- thermal_class->name = "thermal";
- thermal_class->dev_release = thermal_release;
-
- result = class_register(thermal_class);
- if (result) {
- kfree(thermal_class);
- thermal_class = NULL;
+ result = class_register(&thermal_class);
+ if (result)
goto unregister_governors;
- }
return 0;
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-03-31 19:19 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-31 19:15 [PATCH v1 0/4] thermal: core: Simplifications and suspend/resume relocation Rafael J. Wysocki
2026-03-31 19:16 ` [PATCH v1 1/4] thermal: core: Drop redundant check from thermal_zone_device_update() Rafael J. Wysocki
2026-03-31 19:17 ` [PATCH v1 2/4] thermal: core: Change thermal_wq to be unbound and not freezable Rafael J. Wysocki
2026-03-31 19:18 ` [PATCH v1 3/4] thermal: core: Suspend thermal zones later and resume them earlier Rafael J. Wysocki
2026-03-31 19:19 ` [PATCH v1 4/4] thermal: core: Allocate thermal_class statically Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox