aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-03-13 17:39:37 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-03-16 16:44:48 -0400
commit65533bbf63b4f37723fdfedc73d0653958973323 (patch)
treee2a16b9b0966ae6aea1970fe377c70796a281c31
parentcc85b20780562d404e18a47b9b55b4a5102ae53e (diff)
PM / Domains: Fix hibernation restore of devices, v2
During resume from hibernation pm_genpd_restore_noirq() should only power off domains whose suspend_power_off flags are set once and not every time it is called for a device in the given domain. Moreover, it shouldn't decrement genpd->suspended_count, because that field is not touched during device freezing and therefore it is always equal to 0 when pm_genpd_restore_noirq() runs for the first device in the given domain. This means pm_genpd_restore_noirq() may use genpd->suspended_count to determine whether or not it it has been called for the domain in question already in this cycle (it only needs to increment that field every time it runs for this purpose) and whether or not it should check if the domain needs to be powered off. For that to work, though, pm_genpd_prepare() has to clear genpd->suspended_count when it runs for the first device in the given domain (in which case that flag need not be cleared during domain initialization). Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Cc: stable@vger.kernel.org
-rw-r--r--drivers/base/power/domain.c31
1 files changed, 21 insertions, 10 deletions
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index e79228c597f1..84f4beefa4f8 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -764,8 +764,10 @@ static int pm_genpd_prepare(struct device *dev)
764 764
765 genpd_acquire_lock(genpd); 765 genpd_acquire_lock(genpd);
766 766
767 if (genpd->prepared_count++ == 0) 767 if (genpd->prepared_count++ == 0) {
768 genpd->suspended_count = 0;
768 genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF; 769 genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
770 }
769 771
770 genpd_release_lock(genpd); 772 genpd_release_lock(genpd);
771 773
@@ -1097,20 +1099,30 @@ static int pm_genpd_restore_noirq(struct device *dev)
1097 * Since all of the "noirq" callbacks are executed sequentially, it is 1099 * Since all of the "noirq" callbacks are executed sequentially, it is
1098 * guaranteed that this function will never run twice in parallel for 1100 * guaranteed that this function will never run twice in parallel for
1099 * the same PM domain, so it is not necessary to use locking here. 1101 * the same PM domain, so it is not necessary to use locking here.
1102 *
1103 * At this point suspended_count == 0 means we are being run for the
1104 * first time for the given domain in the present cycle.
1100 */ 1105 */
1101 genpd->status = GPD_STATE_POWER_OFF; 1106 if (genpd->suspended_count++ == 0) {
1102 if (genpd->suspend_power_off) {
1103 /* 1107 /*
1104 * The boot kernel might put the domain into the power on state, 1108 * The boot kernel might put the domain into arbitrary state,
1105 * so make sure it really is powered off. 1109 * so make it appear as powered off to pm_genpd_poweron(), so
1110 * that it tries to power it on in case it was really off.
1106 */ 1111 */
1107 if (genpd->power_off) 1112 genpd->status = GPD_STATE_POWER_OFF;
1108 genpd->power_off(genpd); 1113 if (genpd->suspend_power_off) {
1109 return 0; 1114 /*
1115 * If the domain was off before the hibernation, make
1116 * sure it will be off going forward.
1117 */
1118 if (genpd->power_off)
1119 genpd->power_off(genpd);
1120
1121 return 0;
1122 }
1110 } 1123 }
1111 1124
1112 pm_genpd_poweron(genpd); 1125 pm_genpd_poweron(genpd);
1113 genpd->suspended_count--;
1114 1126
1115 return genpd_start_dev(genpd, dev); 1127 return genpd_start_dev(genpd, dev);
1116} 1128}
@@ -1649,7 +1661,6 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
1649 genpd->poweroff_task = NULL; 1661 genpd->poweroff_task = NULL;
1650 genpd->resume_count = 0; 1662 genpd->resume_count = 0;
1651 genpd->device_count = 0; 1663 genpd->device_count = 0;
1652 genpd->suspended_count = 0;
1653 genpd->max_off_time_ns = -1; 1664 genpd->max_off_time_ns = -1;
1654 genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend; 1665 genpd->domain.ops.runtime_suspend = pm_genpd_runtime_suspend;
1655 genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume; 1666 genpd->domain.ops.runtime_resume = pm_genpd_runtime_resume;