Commit bfd1e910139be73fb0783a0b3171fc79e6afa031
Committed by
Greg Kroah-Hartman
1 parent
969ddcfc95
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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, |
include/linux/usb.h
... | ... | @@ -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; |