[coreboot-gerrit] New patch to review for coreboot: libpayload: usbhub: Force enumeration of all connected ports on init

Julius Werner (jwerner@chromium.org) gerrit at coreboot.org
Thu Mar 9 23:21:13 CET 2017


Julius Werner (jwerner at chromium.org) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/18729

-gerrit

commit 05283ef86d4476d46b8157e8f5ab61f86e9ad25e
Author: Julius Werner <jwerner at chromium.org>
Date:   Thu Mar 9 14:14:07 2017 -0800

    libpayload: usbhub: Force enumeration of all connected ports on init
    
    We have found a non-compliant USB hub (RealTek RTS 5413) that does not
    set a port's Connect Status Change bit on its USB 3.0 half if the port
    had already been connected while the hub was being reset. To work around
    this bug, this patch adds code to initially request the status of every
    port after a hub was enumerated, clear the Connect Status Change bit if
    set, and then enumerate the port iff it is currently connected,
    regardless of whether the change bit was set. A similar behavior can
    also be found in the Linux kernel.
    
    BRANCH=oak
    BUG=b:35929438
    TEST=Booted Elm with this change, my USB 3.0 sticks enumerate now even
    if they had been plugged in since boot.
    
    Change-Id: I8a28252eb94f005f04866d06e4fc61ea265cee89
    Signed-off-by: Julius Werner <jwerner at chromium.org>
---
 payloads/libpayload/drivers/usb/usbhub.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c
index f75141e..340e47a 100644
--- a/payloads/libpayload/drivers/usb/usbhub.c
+++ b/payloads/libpayload/drivers/usb/usbhub.c
@@ -158,6 +158,21 @@ static const generic_hub_ops_t usb_hub_ops = {
 	.reset_port		= generic_hub_resetport,
 };
 
+/* Clear CSC if set and enumerate port if it's connected regardless of change
+   bits. Some broken hubs don't set CSC if already connected during reset. */
+static void
+usb_hub_port_initialize(usbdev_t *const dev, const int port)
+{
+	unsigned short buf[2];
+	int ret = get_status(dev, port, DR_PORT, sizeof(buf), buf);
+	if (ret < 0)
+		return;
+	if (buf[1] & PORT_CONNECTION)
+		clear_feature(dev, port, SEL_C_PORT_CONNECTION, DR_PORT);
+	if (buf[0] & PORT_CONNECTION)
+		generic_hub_scanport(dev, port);
+}
+
 void
 usb_hub_init(usbdev_t *const dev)
 {
@@ -172,5 +187,10 @@ usb_hub_init(usbdev_t *const dev)
 
 	if (dev->speed == SUPER_SPEED)
 		usb_hub_set_hub_depth(dev);
-	generic_hub_init(dev, desc.bNbrPorts, &usb_hub_ops);
+	if (generic_hub_init(dev, desc.bNbrPorts, &usb_hub_ops) < 0)
+		return;
+
+	int port;
+	for (port = 1; port <= GEN_HUB(dev)->num_ports; ++port)
+		usb_hub_port_initialize(dev, port);
 }



More information about the coreboot-gerrit mailing list