summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-02-26 01:00:19 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-03-04 00:17:48 +0100
commit92858c476ec4e99cf0425f05dee109b6a55eb6f8 (patch)
treef2ab9eff4f07f28bfaf345d8db44f4db7c74cf0e
parent0a9efc4d91df7b18fb3e97c24ee85a1529618899 (diff)
ACPI / PM: Resume runtime-suspended devices later during system suspend
Runtime-suspended devices are resumed during system suspend by acpi_subsys_prepare() for two reasons: First, because they may need to be reprogrammed in order to change their wakeup settings and, second, because they may need to be operatonal for their children to be successfully suspended. That is a problem, though, if there are many runtime-suspended devices that need to be resumed this way during system suspend, because the .prepare() PM callbacks of devices are executed sequentially and the times taken by them accumulate, which may increase the total system suspend time quite a bit. For this reason, move the resume of runtime-suspended devices up to the next phase of device suspend (during system suspend), except for the ones that have power.ignore_children set. The exception is made, because the devices with power.ignore_children set may still be necessary for their children to be successfully suspended (during system suspend) and they won't be resumed automatically as a result of the runtime resume of their children. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/device_pm.c41
1 files changed, 38 insertions, 3 deletions
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index c14a00d3dca..d047739f338 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -901,15 +901,30 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
int acpi_subsys_prepare(struct device *dev)
{
/*
- * Follow PCI and resume devices suspended at run time before running
- * their system suspend callbacks.
+ * Devices having power.ignore_children set may still be necessary for
+ * suspending their children in the next phase of device suspend.
*/
- pm_runtime_resume(dev);
+ if (dev->power.ignore_children)
+ pm_runtime_resume(dev);
+
return pm_generic_prepare(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
/**
+ * acpi_subsys_suspend - Run the device driver's suspend callback.
+ * @dev: Device to handle.
+ *
+ * Follow PCI and resume devices suspended at run time before running their
+ * system suspend callbacks.
+ */
+int acpi_subsys_suspend(struct device *dev)
+{
+ pm_runtime_resume(dev);
+ return pm_generic_suspend(dev);
+}
+
+/**
* acpi_subsys_suspend_late - Suspend device using ACPI.
* @dev: Device to suspend.
*
@@ -937,6 +952,23 @@ int acpi_subsys_resume_early(struct device *dev)
return ret ? ret : pm_generic_resume_early(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_resume_early);
+
+/**
+ * acpi_subsys_freeze - Run the device driver's freeze callback.
+ * @dev: Device to handle.
+ */
+int acpi_subsys_freeze(struct device *dev)
+{
+ /*
+ * This used to be done in acpi_subsys_prepare() for all devices and
+ * some drivers may depend on it, so do it here. Ideally, however,
+ * runtime-suspended devices should not be touched during freeze/thaw
+ * transitions.
+ */
+ pm_runtime_resume(dev);
+ return pm_generic_freeze(dev);
+}
+
#endif /* CONFIG_PM_SLEEP */
static struct dev_pm_domain acpi_general_pm_domain = {
@@ -947,8 +979,11 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
+ .suspend = acpi_subsys_suspend,
.suspend_late = acpi_subsys_suspend_late,
.resume_early = acpi_subsys_resume_early,
+ .freeze = acpi_subsys_freeze,
+ .poweroff = acpi_subsys_suspend,
.poweroff_late = acpi_subsys_suspend_late,
.restore_early = acpi_subsys_resume_early,
#endif