Skip to content

Commit d33e89d

Browse files
committed
thermal: core: Suspend thermal zones later and resume them earlier
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> Reviewed-by: Armin Wolf <W_Armin@gmx.de> Link: https://patch.msgid.link/2036875.PYKUYFuaPT@rafael.j.wysocki
1 parent c4c6a86 commit d33e89d

3 files changed

Lines changed: 29 additions & 42 deletions

File tree

drivers/base/power/main.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <trace/events/power.h>
3434
#include <linux/cpufreq.h>
3535
#include <linux/devfreq.h>
36+
#include <linux/thermal.h>
3637
#include <linux/timer.h>
3738
#include <linux/nmi.h>
3839

@@ -1282,6 +1283,8 @@ void dpm_complete(pm_message_t state)
12821283
list_splice(&list, &dpm_list);
12831284
mutex_unlock(&dpm_list_mtx);
12841285

1286+
/* Start resuming thermal control */
1287+
thermal_pm_complete();
12851288
/* Allow device probing and trigger re-probing of deferred devices */
12861289
device_unblock_probing();
12871290
trace_suspend_resume(TPS("dpm_complete"), state.event, false);
@@ -2225,6 +2228,8 @@ int dpm_prepare(pm_message_t state)
22252228
* instead. The normal behavior will be restored in dpm_complete().
22262229
*/
22272230
device_block_probing();
2231+
/* Suspend thermal control. */
2232+
thermal_pm_prepare();
22282233

22292234
mutex_lock(&dpm_list_mtx);
22302235
while (!list_empty(&dpm_list) && !error) {

drivers/thermal/thermal_core.c

Lines changed: 18 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,7 +1823,7 @@ static void thermal_zone_pm_prepare(struct thermal_zone_device *tz)
18231823
cancel_delayed_work(&tz->poll_queue);
18241824
}
18251825

1826-
static void thermal_pm_notify_prepare(void)
1826+
static void __thermal_pm_prepare(void)
18271827
{
18281828
struct thermal_zone_device *tz;
18291829

@@ -1835,6 +1835,19 @@ static void thermal_pm_notify_prepare(void)
18351835
thermal_zone_pm_prepare(tz);
18361836
}
18371837

1838+
void thermal_pm_prepare(void)
1839+
{
1840+
if (thermal_class_unavailable)
1841+
return;
1842+
1843+
__thermal_pm_prepare();
1844+
/*
1845+
* Allow any leftover thermal work items already on the worqueue to
1846+
* complete so they don't get in the way later.
1847+
*/
1848+
flush_workqueue(thermal_wq);
1849+
}
1850+
18381851
static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
18391852
{
18401853
guard(thermal_zone)(tz);
@@ -1851,10 +1864,13 @@ static void thermal_zone_pm_complete(struct thermal_zone_device *tz)
18511864
mod_delayed_work(thermal_wq, &tz->poll_queue, 0);
18521865
}
18531866

1854-
static void thermal_pm_notify_complete(void)
1867+
void thermal_pm_complete(void)
18551868
{
18561869
struct thermal_zone_device *tz;
18571870

1871+
if (thermal_class_unavailable)
1872+
return;
1873+
18581874
guard(mutex)(&thermal_list_lock);
18591875

18601876
thermal_pm_suspended = false;
@@ -1863,41 +1879,6 @@ static void thermal_pm_notify_complete(void)
18631879
thermal_zone_pm_complete(tz);
18641880
}
18651881

1866-
static int thermal_pm_notify(struct notifier_block *nb,
1867-
unsigned long mode, void *_unused)
1868-
{
1869-
switch (mode) {
1870-
case PM_HIBERNATION_PREPARE:
1871-
case PM_RESTORE_PREPARE:
1872-
case PM_SUSPEND_PREPARE:
1873-
thermal_pm_notify_prepare();
1874-
/*
1875-
* Allow any leftover thermal work items already on the
1876-
* worqueue to complete so they don't get in the way later.
1877-
*/
1878-
flush_workqueue(thermal_wq);
1879-
break;
1880-
case PM_POST_HIBERNATION:
1881-
case PM_POST_RESTORE:
1882-
case PM_POST_SUSPEND:
1883-
thermal_pm_notify_complete();
1884-
break;
1885-
default:
1886-
break;
1887-
}
1888-
return 0;
1889-
}
1890-
1891-
static struct notifier_block thermal_pm_nb = {
1892-
.notifier_call = thermal_pm_notify,
1893-
/*
1894-
* Run at the lowest priority to avoid interference between the thermal
1895-
* zone resume work items spawned by thermal_pm_notify() and the other
1896-
* PM notifiers.
1897-
*/
1898-
.priority = INT_MIN,
1899-
};
1900-
19011882
static int __init thermal_init(void)
19021883
{
19031884
int result;
@@ -1924,11 +1905,6 @@ static int __init thermal_init(void)
19241905

19251906
thermal_class_unavailable = false;
19261907

1927-
result = register_pm_notifier(&thermal_pm_nb);
1928-
if (result)
1929-
pr_warn("Thermal: Can not register suspend notifier, return %d\n",
1930-
result);
1931-
19321908
return 0;
19331909

19341910
unregister_governors:

include/linux/thermal.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ bool thermal_trip_is_bound_to_cdev(struct thermal_zone_device *tz,
273273
int thermal_zone_device_enable(struct thermal_zone_device *tz);
274274
int thermal_zone_device_disable(struct thermal_zone_device *tz);
275275
void thermal_zone_device_critical(struct thermal_zone_device *tz);
276+
277+
void thermal_pm_prepare(void);
278+
void thermal_pm_complete(void);
276279
#else
277280
static inline struct thermal_zone_device *thermal_zone_device_register_with_trips(
278281
const char *type,
@@ -350,6 +353,9 @@ static inline int thermal_zone_device_enable(struct thermal_zone_device *tz)
350353

351354
static inline int thermal_zone_device_disable(struct thermal_zone_device *tz)
352355
{ return -ENODEV; }
356+
357+
static inline void thermal_pm_prepare(void) {}
358+
static inline void thermal_pm_complete(void) {}
353359
#endif /* CONFIG_THERMAL */
354360

355361
#endif /* __THERMAL_H__ */

0 commit comments

Comments
 (0)