summary refs log tree commit diff
path: root/drivers/base/power
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-09-24 13:31:38 +0200
committerRafael J. Wysocki <rjw@sisk.pl>2012-09-24 13:31:38 +0200
commit057d51a1268fe4be039db8ff0791fcfcb63a4f1b (patch)
tree50b7395aa526c5be9f3ae75836b5ad364db04877 /drivers/base/power
parent071f58279f274f749c4109aef86d899766014139 (diff)
parent88d26136a256576e444db312179e17af6dd0ea87 (diff)
downloadlinux-057d51a1268fe4be039db8ff0791fcfcb63a4f1b.tar.gz
Merge branch 'pm-sleep'
* pm-sleep:
  PM: Prevent runtime suspend during system resume
  PM / Sleep: use resume event when call dpm_resume_early

Conflicts:
	drivers/base/power/main.c (trivial)
Diffstat (limited to 'drivers/base/power')
-rw-r--r--drivers/base/power/main.c31
1 files changed, 19 insertions, 12 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 57f5814c2732..008e6786ae79 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -570,7 +570,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 	pm_callback_t callback = NULL;
 	char *info = NULL;
 	int error = 0;
-	bool put = false;
 
 	TRACE_DEVICE(dev);
 	TRACE_RESUME(0);
@@ -591,7 +590,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 		goto Unlock;
 
 	pm_runtime_enable(dev);
-	put = true;
 
 	if (dev->pm_domain) {
 		info = "power domain ";
@@ -646,9 +644,6 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
 
 	TRACE_RESUME(error);
 
-	if (put)
-		pm_runtime_put_sync(dev);
-
 	return error;
 }
 
@@ -762,6 +757,8 @@ static void device_complete(struct device *dev, pm_message_t state)
 	}
 
 	device_unlock(dev);
+
+	pm_runtime_put_sync(dev);
 }
 
 /**
@@ -1015,7 +1012,7 @@ int dpm_suspend_end(pm_message_t state)
 
 	error = dpm_suspend_noirq(state);
 	if (error) {
-		dpm_resume_early(state);
+		dpm_resume_early(resume_event(state));
 		return error;
 	}
 
@@ -1062,12 +1059,16 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
 	if (async_error)
 		goto Complete;
 
-	pm_runtime_get_noresume(dev);
+	/*
+	 * If a device configured to wake up the system from sleep states
+	 * has been suspended at run time and there's a resume request pending
+	 * for it, this is equivalent to the device signaling wakeup, so the
+	 * system suspend operation should be aborted.
+	 */
 	if (pm_runtime_barrier(dev) && device_may_wakeup(dev))
 		pm_wakeup_event(dev, 0);
 
 	if (pm_wakeup_pending()) {
-		pm_runtime_put_sync(dev);
 		async_error = -EBUSY;
 		goto Complete;
 	}
@@ -1133,12 +1134,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
  Complete:
 	complete_all(&dev->power.completion);
 
-	if (error) {
-		pm_runtime_put_sync(dev);
+	if (error)
 		async_error = error;
-	} else if (dev->power.is_suspended) {
+	else if (dev->power.is_suspended)
 		__pm_runtime_disable(dev, false);
-	}
 
 	return error;
 }
@@ -1234,6 +1233,14 @@ static int device_prepare(struct device *dev, pm_message_t state)
 	if (dev->power.syscore)
 		return 0;
 
+	/*
+	 * If a device's parent goes into runtime suspend at the wrong time,
+	 * it won't be possible to resume the device.  To prevent this we
+	 * block runtime suspend here, during the prepare phase, and allow
+	 * it again during the complete phase.
+	 */
+	pm_runtime_get_noresume(dev);
+
 	device_lock(dev);
 
 	dev->power.wakeup_path = device_may_wakeup(dev);