summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/power/pci.rst5
-rw-r--r--drivers/acpi/acpi_lpss.c6
-rw-r--r--drivers/acpi/device_pm.c15
-rw-r--r--drivers/base/power/main.c85
-rw-r--r--drivers/pci/pci-driver.c18
5 files changed, 62 insertions, 67 deletions
diff --git a/Documentation/power/pci.rst b/Documentation/power/pci.rst
index 0924d29636ad..a39b2461919a 100644
--- a/Documentation/power/pci.rst
+++ b/Documentation/power/pci.rst
@@ -1035,10 +1035,7 @@ This flag is checked by the PM core, but the PCI bus type informs the PM core
which devices may be left in suspend from its perspective (that happens during
the "noirq" phase of system-wide suspend and analogous transitions) and next it
uses the dev_pm_may_skip_resume() helper to decide whether or not to return from
-pci_pm_resume_noirq() early, as the PM core will skip the remaining resume
-callbacks for the device during the transition under way and will set its
-runtime PM status to "suspended" if dev_pm_may_skip_resume() returns "true" for
-it.
+pci_pm_resume_noirq() and pci_pm_resume_early() upfront.
3.2. Device Runtime Power Management
------------------------------------
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index dee999938213..c4a84df6cc98 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -1093,6 +1093,9 @@ static int acpi_lpss_resume_early(struct device *dev)
if (pdata->dev_desc->resume_from_noirq)
return 0;
+ if (dev_pm_may_skip_resume(dev))
+ return 0;
+
return acpi_lpss_do_resume_early(dev);
}
@@ -1105,9 +1108,6 @@ static int acpi_lpss_resume_noirq(struct device *dev)
if (dev_pm_may_skip_resume(dev))
return 0;
- if (dev_pm_smart_suspend_and_suspended(dev))
- pm_runtime_set_active(dev);
-
ret = pm_generic_resume_noirq(dev);
if (ret)
return ret;
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index b2263ec67b43..399684085f85 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1132,14 +1132,6 @@ static int acpi_subsys_resume_noirq(struct device *dev)
if (dev_pm_may_skip_resume(dev))
return 0;
- /*
- * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
- * during system suspend, so update their runtime PM status to "active"
- * as they will be put into D0 going forward.
- */
- if (dev_pm_smart_suspend_and_suspended(dev))
- pm_runtime_set_active(dev);
-
return pm_generic_resume_noirq(dev);
}
@@ -1153,7 +1145,12 @@ static int acpi_subsys_resume_noirq(struct device *dev)
*/
static int acpi_subsys_resume_early(struct device *dev)
{
- int ret = acpi_dev_resume(dev);
+ int ret;
+
+ if (dev_pm_may_skip_resume(dev))
+ return 0;
+
+ ret = acpi_dev_resume(dev);
return ret ? ret : pm_generic_resume_early(dev);
}
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 75d7cdb4de9c..25b0302188d8 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -565,12 +565,22 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd)
* dev_pm_may_skip_resume - System-wide device resume optimization check.
* @dev: Target device.
*
- * Checks whether or not the device may be left in suspend after a system-wide
- * transition to the working state.
+ * Return:
+ * - %false if the transition under way is RESTORE.
+ * - The return value of dev_pm_smart_suspend_and_suspended() if the transition
+ * under way is THAW.
+ * - The logical negation of %power.must_resume otherwise (that is, when the
+ * transition under way is RESUME).
*/
bool dev_pm_may_skip_resume(struct device *dev)
{
- return !dev->power.must_resume && pm_transition.event != PM_EVENT_RESTORE;
+ if (pm_transition.event == PM_EVENT_RESTORE)
+ return false;
+
+ if (pm_transition.event == PM_EVENT_THAW)
+ return dev_pm_smart_suspend_and_suspended(dev);
+
+ return !dev->power.must_resume;
}
/**
@@ -601,6 +611,22 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
if (!dpm_wait_for_superior(dev, async))
goto Out;
+ skip_resume = dev_pm_may_skip_resume(dev);
+ /*
+ * If the driver callback is skipped below or by the middle layer
+ * callback and device_resume_early() also skips the driver callback for
+ * this device later, it needs to appear as "suspended" to PM-runtime,
+ * so change its status accordingly.
+ *
+ * Otherwise, the device is going to be resumed, so set its PM-runtime
+ * status to "active", but do that only if DPM_FLAG_SMART_SUSPEND is set
+ * to avoid confusing drivers that don't use it.
+ */
+ if (skip_resume)
+ pm_runtime_set_suspended(dev);
+ else if (dev_pm_smart_suspend_and_suspended(dev))
+ pm_runtime_set_active(dev);
+
if (dev->pm_domain) {
info = "noirq power domain ";
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
info = "noirq bus ";
callback = pm_noirq_op(dev->bus->pm, state);
}
- if (callback) {
- skip_resume = false;
+ if (callback)
goto Run;
- }
- skip_resume = dev_pm_may_skip_resume(dev);
if (skip_resume)
goto Skip;
- /*
- * If "freeze" driver callbacks have been skipped during hibernation,
- * because the device was runtime-suspended in __device_suspend_late(),
- * the corresponding "thaw" callbacks must be skipped too, because
- * running them for a runtime-suspended device may not be valid.
- */
- if (dev_pm_smart_suspend_and_suspended(dev) &&
- state.event == PM_EVENT_THAW) {
- skip_resume = true;
- goto Skip;
- }
-
- /*
- * The device is going to be resumed, so set its PM-runtime status to
- * "active", but do that only if DPM_FLAG_SMART_SUSPEND is set to avoid
- * confusing drivers that don't use it.
- */
- if (dev_pm_smart_suspend_and_suspended(dev))
- pm_runtime_set_active(dev);
-
if (dev->driver && dev->driver->pm) {
info = "noirq driver ";
callback = pm_noirq_op(dev->driver->pm, state);
@@ -654,20 +657,6 @@ Run:
Skip:
dev->power.is_noirq_suspended = false;
- if (skip_resume) {
- /* Make the next phases of resume skip the device. */
- dev->power.is_late_suspended = false;
- dev->power.is_suspended = false;
- /*
- * The device is going to be left in suspend, but it might not
- * have been in runtime suspend before the system suspended, so
- * its runtime PM status needs to be updated to avoid confusing
- * the runtime PM framework when runtime PM is enabled for the
- * device again.
- */
- pm_runtime_set_suspended(dev);
- }
-
Out:
complete_all(&dev->power.completion);
TRACE_RESUME(error);
@@ -804,15 +793,25 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
} else if (dev->bus && dev->bus->pm) {
info = "early bus ";
callback = pm_late_early_op(dev->bus->pm, state);
- } else if (dev->driver && dev->driver->pm) {
+ }
+ if (callback)
+ goto Run;
+
+ if (dev_pm_may_skip_resume(dev))
+ goto Skip;
+
+ if (dev->driver && dev->driver->pm) {
info = "early driver ";
callback = pm_late_early_op(dev->driver->pm, state);
}
+Run:
error = dpm_run_callback(callback, dev, state, info);
+
+Skip:
dev->power.is_late_suspended = false;
- Out:
+Out:
TRACE_RESUME(error);
pm_runtime_enable(dev);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 0454ca0e4e3f..685fbf044911 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -897,14 +897,6 @@ static int pci_pm_resume_noirq(struct device *dev)
return 0;
/*
- * Devices with DPM_FLAG_SMART_SUSPEND may be left in runtime suspend
- * during system suspend, so update their runtime PM status to "active"
- * as they are going to be put into D0 shortly.
- */
- if (dev_pm_smart_suspend_and_suspended(dev))
- pm_runtime_set_active(dev);
-
- /*
* In the suspend-to-idle case, devices left in D0 during suspend will
* stay in D0, so it is not necessary to restore or update their
* configuration here and attempting to put them into D0 again is
@@ -928,6 +920,14 @@ static int pci_pm_resume_noirq(struct device *dev)
return 0;
}
+static int pci_pm_resume_early(struct device *dev)
+{
+ if (dev_pm_may_skip_resume(dev))
+ return 0;
+
+ return pm_generic_resume_early(dev);
+}
+
static int pci_pm_resume(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -961,6 +961,7 @@ static int pci_pm_resume(struct device *dev)
#define pci_pm_suspend_late NULL
#define pci_pm_suspend_noirq NULL
#define pci_pm_resume NULL
+#define pci_pm_resume_early NULL
#define pci_pm_resume_noirq NULL
#endif /* !CONFIG_SUSPEND */
@@ -1358,6 +1359,7 @@ static const struct dev_pm_ops pci_dev_pm_ops = {
.suspend = pci_pm_suspend,
.suspend_late = pci_pm_suspend_late,
.resume = pci_pm_resume,
+ .resume_early = pci_pm_resume_early,
.freeze = pci_pm_freeze,
.thaw = pci_pm_thaw,
.poweroff = pci_pm_poweroff,