aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-12-22 17:59:01 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-05 18:35:55 -0500
commit9f6d8f6ab26b42620a914d67f29822f9bba90233 (patch)
treeac243fb6970bf2b870e34e061281f7ad5446ad38
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>
-rw-r--r--Documentation/power/runtime_pm.txt9
-rw-r--r--drivers/base/power/main.c9
2 files changed, 9 insertions, 9 deletions
diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt
index 4abe83e1045a..03591a750f99 100644
--- a/Documentation/power/runtime_pm.txt
+++ b/Documentation/power/runtime_pm.txt
@@ -642,12 +642,13 @@ out the following operations:
642 * During system suspend it calls pm_runtime_get_noresume() and 642 * During system suspend it calls pm_runtime_get_noresume() and
643 pm_runtime_barrier() for every device right before executing the 643 pm_runtime_barrier() for every device right before executing the
644 subsystem-level .suspend() callback for it. In addition to that it calls 644 subsystem-level .suspend() callback for it. In addition to that it calls
645 pm_runtime_disable() for every device right after executing the 645 __pm_runtime_disable() with 'false' as the second argument for every device
646 subsystem-level .suspend() callback for it. 646 right before executing the subsystem-level .suspend_late() callback for it.
647 647
648 * During system resume it calls pm_runtime_enable() and pm_runtime_put_sync() 648 * During system resume it calls pm_runtime_enable() and pm_runtime_put_sync()
649 for every device right before and right after executing the subsystem-level 649 for every device right after executing the subsystem-level .resume_early()
650 .resume() callback for it, respectively. 650 callback and right after executing the subsystem-level .resume() callback
651 for it, respectively.
651 652
6527. Generic subsystem callbacks 6537. Generic subsystem callbacks
653 654
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index a3c1404c7933..2b7f77d3fcb0 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)
513 513
514 Out: 514 Out:
515 TRACE_RESUME(error); 515 TRACE_RESUME(error);
516
517 pm_runtime_enable(dev);
516 return error; 518 return error;
517} 519}
518 520
@@ -589,8 +591,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
589 if (!dev->power.is_suspended) 591 if (!dev->power.is_suspended)
590 goto Unlock; 592 goto Unlock;
591 593
592 pm_runtime_enable(dev);
593
594 if (dev->pm_domain) { 594 if (dev->pm_domain) {
595 info = "power domain "; 595 info = "power domain ";
596 callback = pm_op(&dev->pm_domain->ops, state); 596 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 pm_callback_t callback = NULL; 930 pm_callback_t callback = NULL;
931 char *info = NULL; 931 char *info = NULL;
932 932
933 __pm_runtime_disable(dev, false);
934
933 if (dev->power.syscore) 935 if (dev->power.syscore)
934 return 0; 936 return 0;
935 937
@@ -1133,11 +1135,8 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
1133 1135
1134 Complete: 1136 Complete:
1135 complete_all(&dev->power.completion); 1137 complete_all(&dev->power.completion);
1136
1137 if (error) 1138 if (error)
1138 async_error = error; 1139 async_error = error;
1139 else if (dev->power.is_suspended)
1140 __pm_runtime_disable(dev, false);
1141 1140
1142 return error; 1141 return error;
1143} 1142}