Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit d2278f3

Browse files
committed
thermal: core: Synchronize suspend-prepare and post-suspend actions
After commit 5a5efda ("thermal: core: Resume thermal zones asynchronously") it is theoretically possible that, if a system suspend starts immediately after a system resume, thermal_zone_device_resume() spawned by the thermal PM notifier for one of the thermal zones at the end of the system resume will run after the PM thermal notifier for the suspend-prepare action. If that happens, tz->suspended set by the latter will be reset by the former which may lead to unexpected consequences. To avoid that race, synchronize thermal_zone_device_resume() with the suspend-prepare thermal PM notifier with the help of additional bool field and completion in struct thermal_zone_device. Note that this also ensures running __thermal_zone_device_update() at least once for each thermal zone between system resume and the following system suspend in case it is needed to start thermal mitigation. Fixes: 5a5efda ("thermal: core: Resume thermal zones asynchronously") Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 83a7eef commit d2278f3

File tree

2 files changed

+25
-0
lines changed

2 files changed

+25
-0
lines changed

drivers/thermal/thermal_core.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,7 @@ thermal_zone_device_register_with_trips(const char *type,
13971397
ida_init(&tz->ida);
13981398
mutex_init(&tz->lock);
13991399
init_completion(&tz->removal);
1400+
init_completion(&tz->resume);
14001401
id = ida_alloc(&thermal_tz_ida, GFP_KERNEL);
14011402
if (id < 0) {
14021403
result = id;
@@ -1642,6 +1643,9 @@ static void thermal_zone_device_resume(struct work_struct *work)
16421643
thermal_zone_device_init(tz);
16431644
__thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
16441645

1646+
complete(&tz->resume);
1647+
tz->resuming = false;
1648+
16451649
mutex_unlock(&tz->lock);
16461650
}
16471651

@@ -1659,6 +1663,20 @@ static int thermal_pm_notify(struct notifier_block *nb,
16591663
list_for_each_entry(tz, &thermal_tz_list, node) {
16601664
mutex_lock(&tz->lock);
16611665

1666+
if (tz->resuming) {
1667+
/*
1668+
* thermal_zone_device_resume() queued up for
1669+
* this zone has not acquired the lock yet, so
1670+
* release it to let the function run and wait
1671+
* util it has done the work.
1672+
*/
1673+
mutex_unlock(&tz->lock);
1674+
1675+
wait_for_completion(&tz->resume);
1676+
1677+
mutex_lock(&tz->lock);
1678+
}
1679+
16621680
tz->suspended = true;
16631681

16641682
mutex_unlock(&tz->lock);
@@ -1676,6 +1694,9 @@ static int thermal_pm_notify(struct notifier_block *nb,
16761694

16771695
cancel_delayed_work(&tz->poll_queue);
16781696

1697+
reinit_completion(&tz->resume);
1698+
tz->resuming = true;
1699+
16791700
/*
16801701
* Replace the work function with the resume one, which
16811702
* will restore the original work function and schedule

drivers/thermal/thermal_core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ struct thermal_governor {
5555
* @type: the thermal zone device type
5656
* @device: &struct device for this thermal zone
5757
* @removal: removal completion
58+
* @resume: resume completion
5859
* @trip_temp_attrs: attributes for trip points for sysfs: trip temperature
5960
* @trip_type_attrs: attributes for trip points for sysfs: trip type
6061
* @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis
@@ -89,13 +90,15 @@ struct thermal_governor {
8990
* @poll_queue: delayed work for polling
9091
* @notify_event: Last notification event
9192
* @suspended: thermal zone suspend indicator
93+
* @resuming: indicates whether or not thermal zone resume is in progress
9294
* @trips: array of struct thermal_trip objects
9395
*/
9496
struct thermal_zone_device {
9597
int id;
9698
char type[THERMAL_NAME_LENGTH];
9799
struct device device;
98100
struct completion removal;
101+
struct completion resume;
99102
struct attribute_group trips_attribute_group;
100103
struct thermal_attr *trip_temp_attrs;
101104
struct thermal_attr *trip_type_attrs;
@@ -123,6 +126,7 @@ struct thermal_zone_device {
123126
struct delayed_work poll_queue;
124127
enum thermal_notify_event notify_event;
125128
bool suspended;
129+
bool resuming;
126130
#ifdef CONFIG_THERMAL_DEBUGFS
127131
struct thermal_debugfs *debugfs;
128132
#endif

0 commit comments

Comments
 (0)