Commit 9f6d8f6a authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

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: default avatarJan-Matthias Braun <jan_braun@gmx.net>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Reviewed-by: default avatarKevin Hilman <khilman@deeprootsystems.com>
Cc: 3.4+ <stable@vger.kernel.org>
parent d1c3ed66
...@@ -642,12 +642,13 @@ out the following operations: ...@@ -642,12 +642,13 @@ out the following operations:
* During system suspend it calls pm_runtime_get_noresume() and * During system suspend it calls pm_runtime_get_noresume() and
pm_runtime_barrier() for every device right before executing the pm_runtime_barrier() for every device right before executing the
subsystem-level .suspend() callback for it. In addition to that it calls subsystem-level .suspend() callback for it. In addition to that it calls
pm_runtime_disable() for every device right after executing the __pm_runtime_disable() with 'false' as the second argument for every device
subsystem-level .suspend() callback for it. right before executing the subsystem-level .suspend_late() callback for it.
* During system resume it calls pm_runtime_enable() and pm_runtime_put_sync() * During system resume it calls pm_runtime_enable() and pm_runtime_put_sync()
for every device right before and right after executing the subsystem-level for every device right after executing the subsystem-level .resume_early()
.resume() callback for it, respectively. callback and right after executing the subsystem-level .resume() callback
for it, respectively.
7. Generic subsystem callbacks 7. Generic subsystem callbacks
......
...@@ -513,6 +513,8 @@ static int device_resume_early(struct device *dev, pm_message_t state) ...@@ -513,6 +513,8 @@ static int device_resume_early(struct device *dev, pm_message_t state)
Out: Out:
TRACE_RESUME(error); TRACE_RESUME(error);
pm_runtime_enable(dev);
return error; return error;
} }
...@@ -589,8 +591,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async) ...@@ -589,8 +591,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (!dev->power.is_suspended) if (!dev->power.is_suspended)
goto Unlock; goto Unlock;
pm_runtime_enable(dev);
if (dev->pm_domain) { if (dev->pm_domain) {
info = "power domain "; info = "power domain ";
callback = pm_op(&dev->pm_domain->ops, state); callback = pm_op(&dev->pm_domain->ops, state);
...@@ -930,6 +930,8 @@ static int device_suspend_late(struct device *dev, pm_message_t state) ...@@ -930,6 +930,8 @@ static int device_suspend_late(struct device *dev, pm_message_t state)
pm_callback_t callback = NULL; pm_callback_t callback = NULL;
char *info = NULL; char *info = NULL;
__pm_runtime_disable(dev, false);
if (dev->power.syscore) if (dev->power.syscore)
return 0; return 0;
...@@ -1133,11 +1135,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) ...@@ -1133,11 +1135,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
Complete: Complete:
complete_all(&dev->power.completion); complete_all(&dev->power.completion);
if (error) if (error)
async_error = error; async_error = error;
else if (dev->power.is_suspended)
__pm_runtime_disable(dev, false);
return error; return error;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment