path: root/drivers
diff options
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-12-22 23:59:01 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-06 00:35:55 +0100
commit9f6d8f6ab26b42620a914d67f29822f9bba90233 (patch)
treeac243fb6970bf2b870e34e061281f7ad5446ad38 /drivers
parentd1c3ed669a2d452cacfb48c2d171a1f364dae2ed (diff)
PM: Move disabling/enabling runtime PM to late suspend/early resume
Currently, the PM core disables runtime PM for all devices right after executing subsystem/driver .suspend() callbacks for them and re-enables it right before executing subsystem/driver .resume() callbacks for them. This may lead to problems when there are two devices such that the .suspend() callback executed for one of them depends on runtime PM working for the other. In that case, if runtime PM has already been disabled for the second device, the first one's .suspend() won't work correctly (and analogously for resume). To make those issues go away, make the PM core disable runtime PM for devices right before executing subsystem/driver .suspend_late() callbacks for them and enable runtime PM for them right after executing subsystem/driver .resume_early() callbacks for them. This way the potential conflitcs between .suspend_late()/.resume_early() and their runtime PM counterparts are still prevented from happening, but the subtle ordering issues related to disabling/enabling runtime PM for devices during system suspend/resume are much easier to avoid. Reported-and-tested-by: Jan-Matthias Braun <jan_braun@gmx.net> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org> Reviewed-by: Kevin Hilman <khilman@deeprootsystems.com> Cc: 3.4+ <stable@vger.kernel.org>
Diffstat (limited to 'drivers')
1 files changed, 4 insertions, 5 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index a3c1404c793..2b7f77d3fcb 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -513,6 +513,8 @@ static int device_resume_early(struct device *dev, pm_message_t state)
+ pm_runtime_enable(dev);
return error;
@@ -589,8 +591,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (!dev->power.is_suspended)
goto Unlock;
- pm_runtime_enable(dev);
if (dev->pm_domain) {
info = "power domain ";
callback = pm_op(&dev->pm_domain->ops, state);
@@ -930,6 +930,8 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
pm_callback_t callback = NULL;
char *info = NULL;
+ __pm_runtime_disable(dev, false);
if (dev->power.syscore)
return 0;
@@ -1133,11 +1135,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (error)
async_error = error;
- else if (dev->power.is_suspended)
- __pm_runtime_disable(dev, false);
return error;