Skip to content

Commit 7585946

Browse files
committed
PM: sleep: core: Restrict power.set_active propagation
Commit 3775fc5 ("PM: sleep: core: Synchronize runtime PM status of parents and children") exposed an issue related to simple_pm_bus_pm_ops that uses pm_runtime_force_suspend() and pm_runtime_force_resume() as bus type PM callbacks for the noirq phases of system-wide suspend and resume. The problem is that pm_runtime_force_suspend() does not distinguish runtime-suspended devices from devices for which runtime PM has never been enabled, so if it sees a device with runtime PM status set to RPM_ACTIVE, it will assume that runtime PM is enabled for that device and so it will attempt to suspend it with the help of its runtime PM callbacks which may not be ready for that. As it turns out, this causes simple_pm_bus_runtime_suspend() to crash due to a NULL pointer dereference. Another problem related to the above commit and simple_pm_bus_pm_ops is that setting runtime PM status of a device handled by the latter to RPM_ACTIVE will actually prevent it from being resumed because pm_runtime_force_resume() only resumes devices with runtime PM status set to RPM_SUSPENDED. To mitigate these issues, do not allow power.set_active to propagate beyond the parent of the device with DPM_FLAG_SMART_SUSPEND set that will need to be resumed, which should be a sufficient stop-gap for the time being, but they will need to be properly addressed in the future because in general during system-wide resume it is necessary to resume all devices in a dependency chain in which at least one device is going to be resumed. Fixes: 3775fc5 ("PM: sleep: core: Synchronize runtime PM status of parents and children") Closes: https://lore.kernel.org/linux-pm/1c2433d4-7e0f-4395-b841-b8eac7c25651@nvidia.com/ Reported-by: Jon Hunter <jonathanh@nvidia.com> Tested-by: Johan Hovold <johan+linaro@kernel.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Link: https://patch.msgid.link/6137505.lOV4Wx5bFT@rjwysocki.net
1 parent 73195be commit 7585946

File tree

1 file changed

+9
-12
lines changed

1 file changed

+9
-12
lines changed

drivers/base/power/main.c

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,24 +1191,18 @@ static pm_message_t resume_event(pm_message_t sleep_state)
11911191
return PMSG_ON;
11921192
}
11931193

1194-
static void dpm_superior_set_must_resume(struct device *dev, bool set_active)
1194+
static void dpm_superior_set_must_resume(struct device *dev)
11951195
{
11961196
struct device_link *link;
11971197
int idx;
11981198

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

12051202
idx = device_links_read_lock();
12061203

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

12131207
device_links_read_unlock(idx);
12141208
}
@@ -1287,9 +1281,12 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state, bool asy
12871281
dev->power.must_resume = true;
12881282

12891283
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);
1284+
if (dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) {
1285+
dev->power.set_active = true;
1286+
if (dev->parent && !dev->parent->power.ignore_children)
1287+
dev->parent->power.set_active = true;
1288+
}
1289+
dpm_superior_set_must_resume(dev);
12931290
}
12941291

12951292
Complete:

0 commit comments

Comments
 (0)