summaryrefslogtreecommitdiff
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2013-05-17 12:08:51 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-05-20 11:28:55 -0700
commit9b790915450e2e2eb9a8df7fe32f41e895de9da1 (patch)
tree785b90ea1896347817fc2e43ddfe7eaca6cd6eaa /drivers/usb/host/ehci-hub.c
parentf23eb0ea9a7862263df338896b3ef415ca83ff51 (diff)
usb: ehci: Only sleep for post-resume handover if devices use persist
The current EHCI code sleeps a flat 110ms in the resume path if there was a USB 1.1 device connected to its companion controller during suspend, waiting for the device to reappear and reset so that it can be handed back to the companion. This is necessary if the device uses persist, so that the companion controller can actually see it during its own resume path. However, if the device doesn't use persist, this is entirely unnecessary. We might just as well ignore it and have the normal device detection/reset/handoff code handle it asynchronously when it eventually shows up. As USB 1.1 devices are almost exclusively HIDs these days (for which persist has no value), this can allow distros to shave another tenth of a second off their resume time. In order to enable this optimization, the patch also adds a new usb_for_each_dev() iterator that is exported by the USB core and wraps bus_for_each_dev() with the logic to differentiate between struct usb_device and struct usb_interface on the usb_bus_type bus. Signed-off-by: Julius Werner <jwerner@chromium.org> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 9ab4a4d9768a..b2f64506840b 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -42,6 +42,12 @@ static int ehci_hub_control(
u16 wLength
);
+static int persist_enabled_on_companion(struct usb_device *udev, void *unused)
+{
+ return !udev->maxchild && udev->persist_enabled &&
+ udev->bus->root_hub->speed < USB_SPEED_HIGH;
+}
+
/* After a power loss, ports that were owned by the companion must be
* reset so that the companion can still own them.
*/
@@ -56,6 +62,16 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
if (!ehci->owned_ports)
return;
+ /*
+ * USB 1.1 devices are mostly HIDs, which don't need to persist across
+ * suspends. If we ensure that none of our companion's devices have
+ * persist_enabled (by looking through all USB 1.1 buses in the system),
+ * we can skip this and avoid slowing resume down. Devices without
+ * persist will just get reenumerated shortly after resume anyway.
+ */
+ if (!usb_for_each_dev(NULL, persist_enabled_on_companion))
+ return;
+
/* Make sure the ports are powered */
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {