[PATCH 1/3] USB: fix race between root-hub suspend and remote wakeup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch (as1533) fixes a race between root-hub suspend and remote
wakeup.  If a wakeup event occurs while a root hub is suspending, it
might not cause the suspend to fail.  Although the host controller
drivers check for pending wakeup events at the start of their
bus_suspend routines, they generally do not check for wakeup events
while the routines are running.

In addition, if a wakeup event occurs any time after khubd is frozen
and before the root hub is fully suspended, it might not cause a
system sleep transition to fail.  For example, the host controller
drivers do not fail root-hub suspends when a connect-change event is
pending.

To fix both these issues, this patch causes hcd_bus_suspend() to query
the controller driver's hub_status_data method after a root hub is
suspended, if the root hub is enabled for wakeup.  Any pending status
changes will count as wakeup events, causing the root hub to be
resumed and the overall suspend to fail with -EBUSY.

A significant point is that not all events are reflected immediately
in the status bits.  Both EHCI and UHCI controllers notify the CPU
when remote wakeup begins on a port, but the port's suspend-change
status bit doesn't get set until after the port has completed the
transition out of the suspend state, some 25 milliseconds later.
Consequently, the patch will interpret any nonzero return value from
hub_status_data as indicating a pending event, even if none of the
status bits are set in the data buffer.  Follow-up patches make the
necessary changes to ehci-hcd and uhci-hcd.

Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>
CC: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
CC: Chen Peter-B29397 <B29397@xxxxxxxxxxxxx>
CC: <stable@xxxxxxxxxxxxxxx>

---

 drivers/usb/core/hcd.c |   12 ++++++++++++
 1 file changed, 12 insertions(+)

Index: usb-3.3/drivers/usb/core/hcd.c
===================================================================
--- usb-3.3.orig/drivers/usb/core/hcd.c
+++ usb-3.3/drivers/usb/core/hcd.c
@@ -1978,6 +1978,18 @@ int hcd_bus_suspend(struct usb_device *r
 	if (status == 0) {
 		usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
 		hcd->state = HC_STATE_SUSPENDED;
+
+		/* Did we race with a root-hub wakeup event? */
+		if (rhdev->do_remote_wakeup) {
+			char	buffer[6];
+
+			status = hcd->driver->hub_status_data(hcd, buffer);
+			if (status != 0) {
+				dev_dbg(&rhdev->dev, "suspend raced with wakeup event\n");
+				hcd_bus_resume(rhdev, PMSG_AUTO_RESUME);
+				status = -EBUSY;
+			}
+		}
 	} else {
 		spin_lock_irq(&hcd_root_hub_lock);
 		if (!HCD_DEAD(hcd)) {

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux