Skip to content

Commit 3775fc5

Browse files
committed
PM: sleep: core: Synchronize runtime PM status of parents and children
Commit 6e176bf ("PM: sleep: core: Do not skip callbacks in the resume phase") overlooked the case in which the parent of a device with DPM_FLAG_SMART_SUSPEND set did not use that flag and could be runtime- suspended before a transition into a system-wide sleep state. In that case, if the child is resumed during the subsequent transition from that state into the working state, its runtime PM status will be set to RPM_ACTIVE, but the runtime PM status of the parent will not be updated accordingly, even though the parent will be resumed too, because of the dev_pm_skip_suspend() check in device_resume_noirq(). Address this problem by tracking the need to set the runtime PM status to RPM_ACTIVE during system-wide resume transitions for devices with DPM_FLAG_SMART_SUSPEND set and all of the devices depended on by them. Fixes: 6e176bf ("PM: sleep: core: Do not skip callbacks in the resume phase") Closes: https://lore.kernel.org/linux-pm/[email protected]/ Reported-by: Johan Hovold <[email protected]> Tested-by: Manivannan Sadhasivam <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]> Reviewed-by: Johan Hovold <[email protected]> Tested-by: Johan Hovold <[email protected]> Link: https://patch.msgid.link/[email protected]
1 parent 4891cd3 commit 3775fc5

File tree

2 files changed

+21
-9
lines changed

2 files changed

+21
-9
lines changed

drivers/base/power/main.c

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -656,13 +656,15 @@ static void device_resume_noirq(struct device *dev, pm_message_t state, bool asy
656656
* so change its status accordingly.
657657
*
658658
* Otherwise, the device is going to be resumed, so set its PM-runtime
659-
* status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set
660-
* to avoid confusing drivers that don't use it.
659+
* status to "active" unless its power.set_active flag is clear, in
660+
* which case it is not necessary to update its PM-runtime status.
661661
*/
662-
if (skip_resume)
662+
if (skip_resume) {
663663
pm_runtime_set_suspended(dev);
664-
else if (dev_pm_skip_suspend(dev))
664+
} else if (dev->power.set_active) {
665665
pm_runtime_set_active(dev);
666+
dev->power.set_active = false;
667+
}
666668

667669
if (dev->pm_domain) {
668670
info = "noirq power domain ";
@@ -1189,18 +1191,24 @@ static pm_message_t resume_event(pm_message_t sleep_state)
11891191
return PMSG_ON;
11901192
}
11911193

1192-
static void dpm_superior_set_must_resume(struct device *dev)
1194+
static void dpm_superior_set_must_resume(struct device *dev, bool set_active)
11931195
{
11941196
struct device_link *link;
11951197
int idx;
11961198

1197-
if (dev->parent)
1199+
if (dev->parent) {
11981200
dev->parent->power.must_resume = true;
1201+
if (set_active)
1202+
dev->parent->power.set_active = true;
1203+
}
11991204

12001205
idx = device_links_read_lock();
12011206

1202-
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node)
1207+
list_for_each_entry_rcu_locked(link, &dev->links.suppliers, c_node) {
12031208
link->supplier->power.must_resume = true;
1209+
if (set_active)
1210+
link->supplier->power.set_active = true;
1211+
}
12041212

12051213
device_links_read_unlock(idx);
12061214
}
@@ -1278,8 +1286,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
12781286
dev->power.may_skip_resume))
12791287
dev->power.must_resume = true;
12801288

1281-
if (dev->power.must_resume)
1282-
dpm_superior_set_must_resume(dev);
1289+
if (dev->power.must_resume) {
1290+
dev->power.set_active = dev->power.set_active ||
1291+
dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND);
1292+
dpm_superior_set_must_resume(dev, dev->power.set_active);
1293+
}
12831294

12841295
Complete:
12851296
complete_all(&dev->power.completion);

include/linux/pm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,7 @@ struct dev_pm_info {
679679
bool no_pm_callbacks:1; /* Owned by the PM core */
680680
bool async_in_progress:1; /* Owned by the PM core */
681681
bool must_resume:1; /* Owned by the PM core */
682+
bool set_active:1; /* Owned by the PM core */
682683
bool may_skip_resume:1; /* Set by subsystems */
683684
#else
684685
bool should_wakeup:1;

0 commit comments

Comments
 (0)