Skip to content

Commit 107d47b

Browse files
committed
PM: sleep: core: Simplify the SMART_SUSPEND flag handling
The code to handle the SMART_SUSPEND driver PM flag is hard to follow and somewhat inconsistent with respect to devices without middle-layer (subsystem) callbacks. Namely, for those devices the core takes the role of a middle layer in providing the expected ordering of execution of callbacks (under the assumption that the drivers setting SMART_SUSPEND can reuse their PM-runtime callbacks directly for system-wide suspend). To that end, it prevents driver ->suspend_late and ->suspend_noirq callbacks from being executed for devices that are still runtime-suspended in __device_suspend_late(), because running the same callback funtion that was previously run by PM-runtime for them may be invalid. However, it does that only for devices without any middle-layer callbacks for the late/noirq/early suspend/resume phases even though it would be simpler and more consistent to skip the driver-lavel callbacks for all devices with SMART_SUSPEND set that are runtime-suspended in __device_suspend_late(). Simplify the code in accordance with the above observation. Suggested-by: Alan Stern <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]> Acked-by: Alan Stern <[email protected]>
1 parent ae83d0b commit 107d47b

File tree

1 file changed

+39
-79
lines changed

1 file changed

+39
-79
lines changed

drivers/base/power/main.c

Lines changed: 39 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -561,24 +561,6 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
561561

562562
/*------------------------- Resume routines -------------------------*/
563563

564-
/**
565-
* suspend_event - Return a "suspend" message for given "resume" one.
566-
* @resume_msg: PM message representing a system-wide resume transition.
567-
*/
568-
static pm_message_t suspend_event(pm_message_t resume_msg)
569-
{
570-
switch (resume_msg.event) {
571-
case PM_EVENT_RESUME:
572-
return PMSG_SUSPEND;
573-
case PM_EVENT_THAW:
574-
case PM_EVENT_RESTORE:
575-
return PMSG_FREEZE;
576-
case PM_EVENT_RECOVER:
577-
return PMSG_HIBERNATE;
578-
}
579-
return PMSG_ON;
580-
}
581-
582564
/**
583565
* dev_pm_may_skip_resume - System-wide device resume optimization check.
584566
* @dev: Target device.
@@ -656,37 +638,36 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
656638
if (!dpm_wait_for_superior(dev, async))
657639
goto Out;
658640

659-
skip_resume = dev_pm_may_skip_resume(dev);
660-
661641
callback = dpm_subsys_resume_noirq_cb(dev, state, &info);
662-
if (callback)
642+
if (callback) {
643+
skip_resume = false;
663644
goto Run;
645+
}
664646

647+
skip_resume = dev_pm_may_skip_resume(dev);
665648
if (skip_resume)
666649
goto Skip;
667650

668-
if (dev_pm_smart_suspend_and_suspended(dev)) {
669-
pm_message_t suspend_msg = suspend_event(state);
670-
671-
/*
672-
* If "freeze" callbacks have been skipped during a transition
673-
* related to hibernation, the subsequent "thaw" callbacks must
674-
* be skipped too or bad things may happen. Otherwise, resume
675-
* callbacks are going to be run for the device, so its runtime
676-
* PM status must be changed to reflect the new state after the
677-
* transition under way.
678-
*/
679-
if (!dpm_subsys_suspend_late_cb(dev, suspend_msg, NULL) &&
680-
!dpm_subsys_suspend_noirq_cb(dev, suspend_msg, NULL)) {
681-
if (state.event == PM_EVENT_THAW) {
682-
skip_resume = true;
683-
goto Skip;
684-
} else {
685-
pm_runtime_set_active(dev);
686-
}
687-
}
651+
/*
652+
* If "freeze" driver callbacks have been skipped during hibernation,
653+
* because the device was runtime-suspended in __device_suspend_late(),
654+
* the corresponding "thaw" callbacks must be skipped too, because
655+
* running them for a runtime-suspended device may not be valid.
656+
*/
657+
if (dev_pm_smart_suspend_and_suspended(dev) &&
658+
state.event == PM_EVENT_THAW) {
659+
skip_resume = true;
660+
goto Skip;
688661
}
689662

663+
/*
664+
* The device is going to be resumed, so set its PM-runtime status to
665+
* "active", but do that only if DPM_FLAG_SMART_SUSPEND is set to avoid
666+
* confusing drivers that don't use it.
667+
*/
668+
if (dev_pm_smart_suspend_and_suspended(dev))
669+
pm_runtime_set_active(dev);
670+
690671
if (dev->driver && dev->driver->pm) {
691672
info = "noirq driver ";
692673
callback = pm_noirq_op(dev->driver->pm, state);
@@ -1274,32 +1255,6 @@ static pm_callback_t dpm_subsys_suspend_noirq_cb(struct device *dev,
12741255
return callback;
12751256
}
12761257

1277-
static bool device_must_resume(struct device *dev, pm_message_t state,
1278-
bool no_subsys_suspend_noirq)
1279-
{
1280-
pm_message_t resume_msg = resume_event(state);
1281-
1282-
/*
1283-
* If all of the device driver's "noirq", "late" and "early" callbacks
1284-
* are invoked directly by the core, the decision to allow the device to
1285-
* stay in suspend can be based on its current runtime PM status and its
1286-
* wakeup settings.
1287-
*/
1288-
if (no_subsys_suspend_noirq &&
1289-
!dpm_subsys_suspend_late_cb(dev, state, NULL) &&
1290-
!dpm_subsys_resume_early_cb(dev, resume_msg, NULL) &&
1291-
!dpm_subsys_resume_noirq_cb(dev, resume_msg, NULL))
1292-
return !pm_runtime_status_suspended(dev) &&
1293-
(resume_msg.event != PM_EVENT_RESUME ||
1294-
(device_can_wakeup(dev) && !device_may_wakeup(dev)));
1295-
1296-
/*
1297-
* The only safe strategy here is to require that if the device may not
1298-
* be left in suspend, resume callbacks must be invoked for it.
1299-
*/
1300-
return !dev->power.may_skip_resume;
1301-
}
1302-
13031258
/**
13041259
* __device_suspend_noirq - Execute a "noirq suspend" callback for given device.
13051260
* @dev: Device to handle.
@@ -1313,7 +1268,6 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
13131268
{
13141269
pm_callback_t callback;
13151270
const char *info;
1316-
bool no_subsys_cb = false;
13171271
int error = 0;
13181272

13191273
TRACE_DEVICE(dev);
@@ -1331,9 +1285,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
13311285
if (callback)
13321286
goto Run;
13331287

1334-
no_subsys_cb = !dpm_subsys_suspend_late_cb(dev, state, NULL);
1335-
1336-
if (dev_pm_smart_suspend_and_suspended(dev) && no_subsys_cb)
1288+
if (dev_pm_smart_suspend_and_suspended(dev))
13371289
goto Skip;
13381290

13391291
if (dev->driver && dev->driver->pm) {
@@ -1351,13 +1303,16 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
13511303
Skip:
13521304
dev->power.is_noirq_suspended = true;
13531305

1354-
if (dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED)) {
1355-
dev->power.must_resume = dev->power.must_resume ||
1356-
atomic_read(&dev->power.usage_count) > 1 ||
1357-
device_must_resume(dev, state, no_subsys_cb);
1358-
} else {
1306+
/*
1307+
* Skipping the resume of devices that were in use right before the
1308+
* system suspend (as indicated by their PM-runtime usage counters)
1309+
* would be suboptimal. Also resume them if doing that is not allowed
1310+
* to be skipped.
1311+
*/
1312+
if (atomic_read(&dev->power.usage_count) > 1 ||
1313+
!(dev_pm_test_driver_flags(dev, DPM_FLAG_LEAVE_SUSPENDED) &&
1314+
dev->power.may_skip_resume))
13591315
dev->power.must_resume = true;
1360-
}
13611316

13621317
if (dev->power.must_resume)
13631318
dpm_superior_set_must_resume(dev);
@@ -1539,9 +1494,14 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
15391494
if (callback)
15401495
goto Run;
15411496

1542-
if (dev_pm_smart_suspend_and_suspended(dev) &&
1543-
!dpm_subsys_suspend_noirq_cb(dev, state, NULL))
1497+
if (dev_pm_smart_suspend_and_suspended(dev)) {
1498+
/*
1499+
* In principle, the resume of the device may be skippend if it
1500+
* remains in runtime suspend at this point.
1501+
*/
1502+
dev->power.may_skip_resume = true;
15441503
goto Skip;
1504+
}
15451505

15461506
if (dev->driver && dev->driver->pm) {
15471507
info = "late driver ";

0 commit comments

Comments
 (0)