[U-Boot] [PATCH v2 4/4] usb: Change power-on / scanning timeout handling

Stefan Roese sr at denx.de
Fri Mar 11 15:55:51 CET 2016


This patch changes the USB port scanning procedure and timeout
handling in the following ways:

a)
The power-on delay in usb_hub_power_on() is now reduced to a value of
max(100ms, "hub->desc.bPwrOn2PwrGood * 2"). The total timeout for this
hub, which is 1 second + "hub->desc.bPwrOn2PwrGood * 2" is calculated
and will be used in the following per-port scanning loop as the timeout
to detect active USB devices on this hub.

b)
The ports are now scanned in a quasy parallel way. The current code did
wait for each (unconnected) port to reach its timeout. And only then
continue with the next port. This patch now changes this to scan all
ports of one USB hub quasi simultaniously. Resulting in a faster USB
scan time as the recursive scanning of USB hubs connected to the hub
thats currently being scanned will start earlier.

Without this patch:
starting USB...
USB0:   USB EHCI 1.00
scanning bus 0 for devices... 9 USB Device(s) found

time: 22.266 seconds

With this patch:
starting USB...
USB0:   USB EHCI 1.00
scanning bus 0 for devices... 9 USB Device(s) found

time: 4.606 seconds

So ~17.7 seconds of USB scanning time reduction.

Signed-off-by: Stefan Roese <sr at denx.de>

---

Changes in v2:
- Remove static USB port configuration patch (for now)

 common/usb_hub.c | 98 ++++++++++++++++++++++++++++++++++++++++----------------
 include/usb.h    |  2 ++
 2 files changed, 73 insertions(+), 27 deletions(-)

diff --git a/common/usb_hub.c b/common/usb_hub.c
index 721cfd8..706e7cf 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -120,7 +120,19 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
 		pgood_delay = max(pgood_delay,
 			          (unsigned)simple_strtol(env, NULL, 0));
 	debug("pgood_delay=%dms\n", pgood_delay);
-	mdelay(pgood_delay + 1000);
+
+	/*
+	 * Record the power-on timeout here. The max. delay (timeout)
+	 * will be done based on this value in the USB port loop in
+	 * usb_hub_configure() later.
+	 */
+	dev->poweron_timeout = get_timer(0) + pgood_delay + 1000;
+
+	/*
+	 * Do a minimum delay of the larger value of 100ms or pgood_delay
+	 * so that the power can stablize before the devices are queried
+	 */
+	mdelay(max(100, (int)pgood_delay));
 }
 
 void usb_hub_reset(void)
@@ -342,6 +354,8 @@ static int usb_hub_configure(struct usb_device *dev)
 	struct usb_hub_descriptor *descriptor;
 	struct usb_hub_device *hub;
 	__maybe_unused struct usb_hub_status *hubsts;
+	int device_probed[USB_MAXCHILDREN];
+	int devices_total;
 	int ret;
 
 	/* "allocate" Hub device */
@@ -466,31 +480,44 @@ static int usb_hub_configure(struct usb_device *dev)
 	for (i = 0; i < dev->maxchild; i++)
 		usb_hub_reset_devices(i + 1);
 
-	for (i = 0; i < dev->maxchild; i++) {
-		ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
-		unsigned short portstatus, portchange;
-		int ret;
-		ulong start = get_timer(0);
-		uint delay = CONFIG_SYS_HZ;
-
 #ifdef CONFIG_SANDBOX
-		if (state_get_skip_delays())
-			delay = 0;
+	if (state_get_skip_delays())
+		dev->poweron_timeout = 0;
 #endif
+
+	/*
+	 * Start a loop on this hub which is only exited, once all
+	 * devices (children) of this hub have been probed (either
+	 * detected of timeout)
+	 */
+	devices_total = 0;
+	memset(device_probed, 0,
+	       ARRAY_SIZE(device_probed) * sizeof(device_probed[0]));
+	while (devices_total < dev->maxchild) {
+		ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1);
+		unsigned short portstatus = 0;
+		unsigned short portchange = 0;
+		int ret = 0;
+
+		/*
+		 * Do one loop over all devices on this hub and check if
+		 * either a) a new device is detected or b) a timeout on
+		 * a device has been reached. If either a) or b) occurs,
+		 * mark this device as "probed" and increase the number
+		 * of probed devices of this hub (devices_total).
+		 */
+		for (i = 0; i < dev->maxchild; i++) {
+			/* Skip devices that are already detected */
+			if (device_probed[i])
+				continue;
+
 #ifdef CONFIG_DM_USB
-		debug("\n\nScanning '%s' port %d\n", dev->dev->name, i + 1);
+			debug("\n\nScanning '%s' port %d\n",
+			      dev->dev->name, i + 1);
 #else
-		debug("\n\nScanning port %d\n", i + 1);
+			debug("\n\nScanning port %d\n", i + 1);
 #endif
-		/*
-		 * Wait for (whichever finishes first)
-		 *  - A maximum of 10 seconds
-		 *    This is a purely observational value driven by connecting
-		 *    a few broken pen drives and taking the max * 1.5 approach
-		 *  - connection_change and connection state to report same
-		 *    state
-		 */
-		do {
+
 			ret = usb_get_port_status(dev, i + 1, portsts);
 			if (ret < 0) {
 				debug("get_port_status failed\n");
@@ -501,18 +528,35 @@ static int usb_hub_configure(struct usb_device *dev)
 			portchange = le16_to_cpu(portsts->wPortChange);
 
 			/* No connection change happened, wait a bit more. */
-			if (!(portchange & USB_PORT_STAT_C_CONNECTION))
+			if (!(portchange & USB_PORT_STAT_C_CONNECTION)) {
+				if (get_timer(0) >= dev->poweron_timeout) {
+					device_probed[i] = 1;
+					devices_total++;
+				}
 				continue;
+			}
 
 			/* Test if the connection came up, and if so, exit. */
-			if (portstatus & USB_PORT_STAT_CONNECTION)
+			if (portstatus & USB_PORT_STAT_CONNECTION) {
+				/*
+				 * Mark this device as ready so that it won't be
+				 * scanned in the next loop
+				 */
+				device_probed[i] = 1;
+				devices_total++;
 				break;
+			}
+		}
 
-		} while (get_timer(start) < delay);
-
-		if (ret < 0)
+		/*
+		 * Scan again if either an error has occured, or no new
+		 * USB devices have been detected
+		 */
+		if ((ret < 0) || (i >= dev->maxchild))
 			continue;
 
+		/* A new USB device is ready at this point */
+
 		debug("Port %d Status %X Change %X\n",
 		      i + 1, portstatus, portchange);
 
@@ -561,7 +605,7 @@ static int usb_hub_configure(struct usb_device *dev)
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_RESET);
 		}
-	} /* end for i all ports */
+	}
 
 	return 0;
 }
diff --git a/include/usb.h b/include/usb.h
index 0b410b6..42edab6 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -153,6 +153,8 @@ struct usb_device {
 	struct udevice *dev;		/* Pointer to associated device */
 	struct udevice *controller_dev;	/* Pointer to associated controller */
 #endif
+
+	ulong poweron_timeout;		/* Power-On timeout value in ms */
 };
 
 struct int_queue;
-- 
2.7.3



More information about the U-Boot mailing list