Thread (36 messages) flat view 36 messages, 6 authors, 2011-10-13

Re: [PATCH V3] input: Fix USB autosuspend on bcm5974

From: Henrik Rydberg <hidden>
Date: 2011-10-13 17:14:32

quoted
I tried the patch out, unfortunately it did not work. The second
suspend request returns with a -EINPROGRESS, here:

	if (dev->power.runtime_status == RPM_SUSPENDING) {
		DEFINE_WAIT(wait);

		if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
			retval = -EINPROGRESS;
			goto out;
		}

		/* Wait for the other suspend running in parallel with us. */
		for (;;) {

The reason is above my horizon, although RPM_ASYNC looks suspicious.
In general, we are re-entering rpm_suspend from within the driver
handler, so the exit condition of rpm_suspend may not have been
satisfied yet.
Ah yes, I vaguely remember thinking that another part would have to be
fixed.  But it's not just the part you identified; the error actually
occurred higher up.  The patch below ought to help.
Yes, this works nicely, thank you. I attached my tested-by at the end,
presuming there will be a formal patch. :-)
quoted hunk ↗ jump to hunk
 drivers/base/power/runtime.c |   18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

Index: usb-3.1/drivers/base/power/runtime.c
===================================================================
--- usb-3.1.orig/drivers/base/power/runtime.c
+++ usb-3.1/drivers/base/power/runtime.c
@@ -278,8 +278,9 @@ static int rpm_callback(int (*cb)(struct
  * @rpmflags: Flag bits.
  *
  * Check if the device's runtime PM status allows it to be suspended.  If
- * another suspend has been started earlier, either return immediately or wait
- * for it to finish, depending on the RPM_NOWAIT and RPM_ASYNC flags.  Cancel a
+ * another suspend has been started earlier and the RPM_ASYNC flag isn't set,
+ * either return immediately or wait for it to finish, depending on the
+ * RPM_NOWAIT flag.  Cancel a
  * pending idle notification.  If the RPM_ASYNC flag is set then queue a
  * suspend request; otherwise run the ->runtime_suspend() callback directly.
  * If a deferred resume was requested while the callback was running then carry
@@ -311,8 +312,7 @@ static int rpm_suspend(struct device *de
 		goto out;
 
 	/* If the autosuspend_delay time hasn't expired yet, reschedule. */
-	if ((rpmflags & RPM_AUTO)
-	    && dev->power.runtime_status != RPM_SUSPENDING) {
+	if (rpmflags & RPM_AUTO) {
 		unsigned long expires = pm_runtime_autosuspend_expiration(dev);
 
 		if (expires != 0) {
@@ -339,10 +339,16 @@ static int rpm_suspend(struct device *de
 	/* Other scheduled or pending requests need to be canceled. */
 	pm_runtime_cancel_pending(dev);
 
-	if (dev->power.runtime_status == RPM_SUSPENDING) {
+	/*
+	 * If the request is synchronous, wait for a concurrent suspend attempt
+	 * to finish.  Allow asynchronous requests to go through; they will be
+	 * cancelled if the concurrent suspend succeeds.
+	 */
+	if (dev->power.runtime_status == RPM_SUSPENDING &&
+			!(rpmflags & RPM_ASYNC)) {
 		DEFINE_WAIT(wait);
 
-		if (rpmflags & (RPM_ASYNC | RPM_NOWAIT)) {
+		if (rpmflags & RPM_NOWAIT) {
 			retval = -EINPROGRESS;
 			goto out;
 		}
    Tested-by: Henrik Rydberg [off-list ref]

Thanks,
Henrik
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help