Commit bfd1e910139be73fb0783a0b3171fc79e6afa031

Authored by Alan Stern
Committed by Greg Kroah-Hartman
1 parent 969ddcfc95

USB: speed up usb_bus_resume()

This patch (as1620) speeds up USB root-hub resumes in the common case
where every enabled port has its suspend feature set (which currently
will be true for every runtime resume of the root hub).  If all the
enabled ports are suspended then resuming the root hub won't resume
any of the downstream devices.  In this case there's no need for a
Resume Recovery delay, because that delay is meant to give devices a
chance to get ready for active use.

To keep track of the port suspend features, the patch adds a
"port_is_suspended" flag to struct usb_device.  This has to be tracked
separately from the device's state; it's entirely possible for a USB-2
device to be suspended while the suspend feature on its parent port is
clear.  The reason is that devices will go into suspend whenever their
parent hub does.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reviewed-by: Peter Chen <peter.chen@freescale.com>
Tested-by: Peter Chen <peter.chen@freescale.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Showing 3 changed files with 21 additions and 2 deletions Side-by-side Diff

drivers/usb/core/hcd.c
... ... @@ -2039,8 +2039,9 @@
2039 2039 status = hcd->driver->bus_resume(hcd);
2040 2040 clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags);
2041 2041 if (status == 0) {
2042   - /* TRSMRCY = 10 msec */
2043   - msleep(10);
  2042 + struct usb_device *udev;
  2043 + int port1;
  2044 +
2044 2045 spin_lock_irq(&hcd_root_hub_lock);
2045 2046 if (!HCD_DEAD(hcd)) {
2046 2047 usb_set_device_state(rhdev, rhdev->actconfig
... ... @@ -2050,6 +2051,20 @@
2050 2051 hcd->state = HC_STATE_RUNNING;
2051 2052 }
2052 2053 spin_unlock_irq(&hcd_root_hub_lock);
  2054 +
  2055 + /*
  2056 + * Check whether any of the enabled ports on the root hub are
  2057 + * unsuspended. If they are then a TRSMRCY delay is needed
  2058 + * (this is what the USB-2 spec calls a "global resume").
  2059 + * Otherwise we can skip the delay.
  2060 + */
  2061 + usb_hub_for_each_child(rhdev, port1, udev) {
  2062 + if (udev->state != USB_STATE_NOTATTACHED &&
  2063 + !udev->port_is_suspended) {
  2064 + usleep_range(10000, 11000); /* TRSMRCY */
  2065 + break;
  2066 + }
  2067 + }
2053 2068 } else {
2054 2069 hcd->state = old_state;
2055 2070 dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
drivers/usb/core/hub.c
... ... @@ -2876,6 +2876,7 @@
2876 2876 (PMSG_IS_AUTO(msg) ? "auto-" : ""),
2877 2877 udev->do_remote_wakeup);
2878 2878 usb_set_device_state(udev, USB_STATE_SUSPENDED);
  2879 + udev->port_is_suspended = 1;
2879 2880 msleep(10);
2880 2881 }
2881 2882 usb_mark_last_busy(hub->hdev);
... ... @@ -3040,6 +3041,7 @@
3040 3041  
3041 3042 SuspendCleared:
3042 3043 if (status == 0) {
  3044 + udev->port_is_suspended = 0;
3043 3045 if (hub_is_superspeed(hub->hdev)) {
3044 3046 if (portchange & USB_PORT_STAT_C_LINK_STATE)
3045 3047 clear_port_feature(hub->hdev, port1,
... ... @@ -482,6 +482,7 @@
482 482 * @connect_time: time device was first connected
483 483 * @do_remote_wakeup: remote wakeup should be enabled
484 484 * @reset_resume: needs reset instead of resume
  485 + * @port_is_suspended: the upstream port is suspended (L2 or U3)
485 486 * @wusb_dev: if this is a Wireless USB device, link to the WUSB
486 487 * specific data for the device.
487 488 * @slot_id: Slot ID assigned by xHCI
... ... @@ -560,6 +561,7 @@
560 561  
561 562 unsigned do_remote_wakeup:1;
562 563 unsigned reset_resume:1;
  564 + unsigned port_is_suspended:1;
563 565 #endif
564 566 struct wusb_dev *wusb_dev;
565 567 int slot_id;