Skip to content

Commit 6e176bf

Browse files
committed
PM: sleep: core: Do not skip callbacks in the resume phase
The current code in device_resume_noirq() causes the entire early resume and resume phases of device suspend to be skipped for devices for which the noirq resume phase have been skipped (due to the LEAVE_SUSPENDED flag being set) on the premise that those devices should stay in runtime-suspend after system-wide resume. However, that may not be correct in two situations. First, the middle layer (subsystem) noirq resume callback may be missing for a given device, but its early resume callback may be present and it may need to do something even if it decides to skip the driver callback. Second, if the device's wakeup settings were adjusted in the suspend phase without resuming the device (that was in runtime suspend at that time), they most likely need to be adjusted again in the resume phase and so the driver callback in that phase needs to be run. For the above reason, modify the core to allow the middle layer ->resume_late callback to run even if its ->resume_noirq callback is missing (and the core has skipped the driver-level callback in that phase) and to allow all device callbacks to run in the resume phase. Also make the core set the PM-runtime status of devices with SMART_SUSPEND set whose resume callbacks are not skipped to "active" in the "noirq" resume phase and update the affected subsystems (PCI and ACPI) accordingly. After this change, middle-layer (subsystem) callbacks will always be invoked in all phases of system suspend and resume and driver callbacks will always run in the prepare, suspend, resume, and complete phases for all devices. For devices with SMART_SUSPEND set, driver callbacks will be skipped in the late and noirq phases of system suspend if those devices remain in runtime suspend in __device_suspend_late(). Driver callbacks will also be skipped for them during the noirq and early phases of the "thaw" transition related to hibernation in that case. Setting LEAVE_SUSPENDED means that the driver allows its callbacks to be skipped in the noirq and early phases of system resume, but some additional conditions need to be met for that to happen (among other things, the power.may_skip_resume flag needs to be set for the device during system suspend for the driver callbacks to be skipped during the subsequent resume transition). For all devices with SMART_SUSPEND set whose driver callbacks are invoked during system resume, the PM-runtime status will be set to "active" (by the core). Signed-off-by: Rafael J. Wysocki <[email protected]> Acked-by: Alan Stern <[email protected]> Acked-by: Bjorn Helgaas <[email protected]>
1 parent 3020537 commit 6e176bf

File tree

5 files changed

+62
-67
lines changed

5 files changed

+62
-67
lines changed

Documentation/power/pci.rst

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,10 +1035,7 @@ This flag is checked by the PM core, but the PCI bus type informs the PM core
10351035
which devices may be left in suspend from its perspective (that happens during
10361036
the "noirq" phase of system-wide suspend and analogous transitions) and next it
10371037
uses the dev_pm_may_skip_resume() helper to decide whether or not to return from
1038-
pci_pm_resume_noirq() early, as the PM core will skip the remaining resume
1039-
callbacks for the device during the transition under way and will set its
1040-
runtime PM status to "suspended" if dev_pm_may_skip_resume() returns "true" for
1041-
it.
1038+
pci_pm_resume_noirq() and pci_pm_resume_early() upfront.
10421039

10431040
3.2. Device Runtime Power Management
10441041
------------------------------------

drivers/acpi/acpi_lpss.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,9 @@ static int acpi_lpss_resume_early(struct device *dev)
10931093
if (pdata->dev_desc->resume_from_noirq)
10941094
return 0;
10951095

1096+
if (dev_pm_may_skip_resume(dev))
1097+
return 0;
1098+
10961099
return acpi_lpss_do_resume_early(dev);
10971100
}
10981101

@@ -1105,9 +1108,6 @@ static int acpi_lpss_resume_noirq(struct device *dev)
11051108
if (dev_pm_may_skip_resume(dev))
11061109
return 0;
11071110

1108-
if (dev_pm_smart_suspend_and_suspended(dev))
1109-
pm_runtime_set_active(dev);
1110-
11111111
ret = pm_generic_resume_noirq(dev);
11121112
if (ret)
11131113
return ret;

drivers/acpi/device_pm.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,14 +1132,6 @@ static int acpi_subsys_resume_noirq(struct device *dev)
11321132
if (dev_pm_may_skip_resume(dev))
11331133
return 0;
11341134

1135-
/*
1136-
* Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
1137-
* during system suspend, so update their runtime PM status to "active"
1138-
* as they will be put into D0 going forward.
1139-
*/
1140-
if (dev_pm_smart_suspend_and_suspended(dev))
1141-
pm_runtime_set_active(dev);
1142-
11431135
return pm_generic_resume_noirq(dev);
11441136
}
11451137

@@ -1153,7 +1145,12 @@ static int acpi_subsys_resume_noirq(struct device *dev)
11531145
*/
11541146
static int acpi_subsys_resume_early(struct device *dev)
11551147
{
1156-
int ret = acpi_dev_resume(dev);
1148+
int ret;
1149+
1150+
if (dev_pm_may_skip_resume(dev))
1151+
return 0;
1152+
1153+
ret = acpi_dev_resume(dev);
11571154
return ret ? ret : pm_generic_resume_early(dev);
11581155
}
11591156

drivers/base/power/main.c

Lines changed: 42 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -565,12 +565,22 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
565565
* dev_pm_may_skip_resume - System-wide device resume optimization check.
566566
* @dev: Target device.
567567
*
568-
* Checks whether or not the device may be left in suspend after a system-wide
569-
* transition to the working state.
568+
* Return:
569+
* - %false if the transition under way is RESTORE.
570+
* - The return value of dev_pm_smart_suspend_and_suspended() if the transition
571+
* under way is THAW.
572+
* - The logical negation of %power.must_resume otherwise (that is, when the
573+
* transition under way is RESUME).
570574
*/
571575
bool dev_pm_may_skip_resume(struct device *dev)
572576
{
573-
return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE;
577+
if (pm_transition.event == PM_EVENT_RESTORE)
578+
return false;
579+
580+
if (pm_transition.event == PM_EVENT_THAW)
581+
return dev_pm_smart_suspend_and_suspended(dev);
582+
583+
return !dev->power.must_resume;
574584
}
575585

576586
/**
@@ -601,6 +611,22 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
601611
if (!dpm_wait_for_superior(dev, async))
602612
goto Out;
603613

614+
skip_resume = dev_pm_may_skip_resume(dev);
615+
/*
616+
* If the driver callback is skipped below or by the middle layer
617+
* callback and device_resume_early() also skips the driver callback for
618+
* this device later, it needs to appear as "suspended" to PM-runtime,
619+
* so change its status accordingly.
620+
*
621+
* Otherwise, the device is going to be resumed, so set its PM-runtime
622+
* status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set
623+
* to avoid confusing drivers that don't use it.
624+
*/
625+
if (skip_resume)
626+
pm_runtime_set_suspended(dev);
627+
else if (dev_pm_smart_suspend_and_suspended(dev))
628+
pm_runtime_set_active(dev);
629+
604630
if (dev->pm_domain) {
605631
info = "noirq power domain ";
606632
callback = pm_noirq_op(&dev->pm_domain->ops, state);
@@ -614,35 +640,12 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
614640
info = "noirq bus ";
615641
callback = pm_noirq_op(dev->bus->pm, state);
616642
}
617-
if (callback) {
618-
skip_resume = false;
643+
if (callback)
619644
goto Run;
620-
}
621645

622-
skip_resume = dev_pm_may_skip_resume(dev);
623646
if (skip_resume)
624647
goto Skip;
625648

626-
/*
627-
* If "freeze" driver callbacks have been skipped during hibernation,
628-
* because the device was runtime-suspended in __device_suspend_late(),
629-
* the corresponding "thaw" callbacks must be skipped too, because
630-
* running them for a runtime-suspended device may not be valid.
631-
*/
632-
if (dev_pm_smart_suspend_and_suspended(dev) &&
633-
state.event == PM_EVENT_THAW) {
634-
skip_resume = true;
635-
goto Skip;
636-
}
637-
638-
/*
639-
* The device is going to be resumed, so set its PM-runtime status to
640-
* "active", but do that only if DPM_FLAG_SMART_SUSPEND is set to avoid
641-
* confusing drivers that don't use it.
642-
*/
643-
if (dev_pm_smart_suspend_and_suspended(dev))
644-
pm_runtime_set_active(dev);
645-
646649
if (dev->driver && dev->driver->pm) {
647650
info = "noirq driver ";
648651
callback = pm_noirq_op(dev->driver->pm, state);
@@ -654,20 +657,6 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
654657
Skip:
655658
dev->power.is_noirq_suspended = false;
656659

657-
if (skip_resume) {
658-
/* Make the next phases of resume skip the device. */
659-
dev->power.is_late_suspended = false;
660-
dev->power.is_suspended = false;
661-
/*
662-
* The device is going to be left in suspend, but it might not
663-
* have been in runtime suspend before the system suspended, so
664-
* its runtime PM status needs to be updated to avoid confusing
665-
* the runtime PM framework when runtime PM is enabled for the
666-
* device again.
667-
*/
668-
pm_runtime_set_suspended(dev);
669-
}
670-
671660
Out:
672661
complete_all(&dev->power.completion);
673662
TRACE_RESUME(error);
@@ -804,15 +793,25 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
804793
} else if (dev->bus && dev->bus->pm) {
805794
info = "early bus ";
806795
callback = pm_late_early_op(dev->bus->pm, state);
807-
} else if (dev->driver && dev->driver->pm) {
796+
}
797+
if (callback)
798+
goto Run;
799+
800+
if (dev_pm_may_skip_resume(dev))
801+
goto Skip;
802+
803+
if (dev->driver && dev->driver->pm) {
808804
info = "early driver ";
809805
callback = pm_late_early_op(dev->driver->pm, state);
810806
}
811807

808+
Run:
812809
error = dpm_run_callback(callback, dev, state, info);
810+
811+
Skip:
813812
dev->power.is_late_suspended = false;
814813

815-
Out:
814+
Out:
816815
TRACE_RESUME(error);
817816

818817
pm_runtime_enable(dev);

drivers/pci/pci-driver.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -896,14 +896,6 @@ static int pci_pm_resume_noirq(struct device *dev)
896896
if (dev_pm_may_skip_resume(dev))
897897
return 0;
898898

899-
/*
900-
* Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
901-
* during system suspend, so update their runtime PM status to "active"
902-
* as they are going to be put into D0 shortly.
903-
*/
904-
if (dev_pm_smart_suspend_and_suspended(dev))
905-
pm_runtime_set_active(dev);
906-
907899
/*
908900
* In the suspend-to-idle case, devices left in D0 during suspend will
909901
* stay in D0, so it is not necessary to restore or update their
@@ -928,6 +920,14 @@ static int pci_pm_resume_noirq(struct device *dev)
928920
return 0;
929921
}
930922

923+
static int pci_pm_resume_early(struct device *dev)
924+
{
925+
if (dev_pm_may_skip_resume(dev))
926+
return 0;
927+
928+
return pm_generic_resume_early(dev);
929+
}
930+
931931
static int pci_pm_resume(struct device *dev)
932932
{
933933
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -961,6 +961,7 @@ static int pci_pm_resume(struct device *dev)
961961
#define pci_pm_suspend_late NULL
962962
#define pci_pm_suspend_noirq NULL
963963
#define pci_pm_resume NULL
964+
#define pci_pm_resume_early NULL
964965
#define pci_pm_resume_noirq NULL
965966

966967
#endif /* !CONFIG_SUSPEND */
@@ -1358,6 +1359,7 @@ static const struct dev_pm_ops pci_dev_pm_ops = {
13581359
.suspend = pci_pm_suspend,
13591360
.suspend_late = pci_pm_suspend_late,
13601361
.resume = pci_pm_resume,
1362+
.resume_early = pci_pm_resume_early,
13611363
.freeze = pci_pm_freeze,
13621364
.thaw = pci_pm_thaw,
13631365
.poweroff = pci_pm_poweroff,

0 commit comments

Comments
 (0)