[PATCH] usb: ehci: Only sleep for post-resume handover if devices use persist

From: Julius Werner
Date: Tue Apr 23 2013 - 17:50:49 EST


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.

Signed-off-by: Julius Werner <jwerner@xxxxxxxxxxxx>
---
drivers/usb/host/ehci-hub.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 7d06e77..2507afb 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -29,6 +29,8 @@
/*-------------------------------------------------------------------------*/
#include <linux/usb/otg.h>

+#include "../core/usb.h"
+
#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)

#ifdef CONFIG_PM
@@ -42,6 +44,18 @@ static int ehci_hub_control(
u16 wLength
);

+
+static int companion_persist(struct device *dev, void *unused)
+{
+ struct usb_device *udev = container_of(dev, struct usb_device, dev);
+
+ if (!is_usb_device(dev))
+ return 0; /* Filter out struct usb_interface on the same bus */
+
+ 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 +70,13 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
if (!ehci->owned_ports)
return;

+ /* Check if any USB 1.1 controller in the system uses a non-hub device
+ * with persist enabled. If they don't, the device will get reenumerated
+ * anyway and there is no need to slow resume down to wait for it.
+ */
+ if (!bus_for_each_dev(&usb_bus_type, NULL, NULL, companion_persist))
+ return;
+
/* Make sure the ports are powered */
port = HCS_N_PORTS(ehci->hcs_params);
while (port--) {
--
1.8.2.1

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