[coreboot-gerrit] New patch to review for coreboot: libpayload: usb: Add support for SuperSpeed hubs

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Thu Jul 16 18:13:29 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/10958

-gerrit

commit e60c821b68cb703536d84dd159db62e57c5144ce
Author: Julius Werner <jwerner at chromium.org>
Date:   Thu Jul 9 16:29:10 2015 -0700

    libpayload: usb: Add support for SuperSpeed hubs
    
    This patch adds support for the SuperSpeed half of USB 3.0 hubs, which
    previously prevented SuperSpeed devices behind those hubs from working.
    
    BRANCH=None
    BUG=chrome-os-partner:39877
    TEST=Played around with multiple hubs and devices on Oak and Falco, can
    no longer find a combination that doesn't work.
    
    Change-Id: I20815be95769e33d399b7ad91c3020687234e059
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: 3db96ece20d2304e7f6f6aa333cf114037c48a3e
    Original-Change-Id: I2dd6c9c3607a24a7d78c308911e3d254d5f8d91d
    Original-Signed-off-by: Julius Werner <jwerner at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/284577
    Original-Reviewed-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Tested-by: chunfeng yun <chunfeng.yun at mediatek.com>
---
 payloads/libpayload/drivers/usb/usb.c          | 12 +++-----
 payloads/libpayload/drivers/usb/usbhub.c       | 42 ++++++++++++++++++++++----
 payloads/libpayload/drivers/usb/xhci_debug.c   |  4 +--
 payloads/libpayload/drivers/usb/xhci_devconf.c |  6 ++--
 4 files changed, 46 insertions(+), 18 deletions(-)

diff --git a/payloads/libpayload/drivers/usb/usb.c b/payloads/libpayload/drivers/usb/usb.c
index e00d92f..69d1c39 100644
--- a/payloads/libpayload/drivers/usb/usb.c
+++ b/payloads/libpayload/drivers/usb/usb.c
@@ -556,17 +556,13 @@ set_address (hci_t *controller, usb_speed speed, int hubport, int hubaddr)
 #endif
 		break;
 	case hub_device:
-		if (speed < SUPER_SPEED) {
-			usb_debug ("hub (2.0)\n");
+		usb_debug ("hub\n");
 #if IS_ENABLED(CONFIG_LP_USB_HUB)
-			dev->init = usb_hub_init;
-			return dev->address;
+		dev->init = usb_hub_init;
+		return dev->address;
 #else
-			usb_debug ("NOTICE: USB hub support not compiled in\n");
+		usb_debug ("NOTICE: USB hub support not compiled in\n");
 #endif
-		} else {
-			usb_debug ("hub (3.0) - not yet supported!\n");
-		}
 		break;
 	case cdc_device:
 		usb_debug("CDC\n");
diff --git a/payloads/libpayload/drivers/usb/usbhub.c b/payloads/libpayload/drivers/usb/usbhub.c
index e12fd92..f75141e 100644
--- a/payloads/libpayload/drivers/usb/usbhub.c
+++ b/payloads/libpayload/drivers/usb/usbhub.c
@@ -42,6 +42,8 @@
 #define SEL_PORT_RESET 0x4
 #define SEL_PORT_POWER 0x8
 #define SEL_C_PORT_CONNECTION 0x10
+/* request type (USB 3.0 hubs only) */
+#define SET_HUB_DEPTH 12
 
 static int
 usb_hub_port_status_changed(usbdev_t *const dev, const int port)
@@ -93,17 +95,21 @@ usb_hub_port_speed(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 && (buf[0] & PORT_ENABLE)) {
-		/* bit  10  9
+		/* SuperSpeed hubs can only have SuperSpeed devices. */
+		if (dev->speed == SUPER_SPEED)
+			return SUPER_SPEED;
+
+		/*[bit] 10  9  (USB 2.0 port status word)
 		 *      0   0  full speed
 		 *      0   1  low speed
 		 *      1   0  high speed
-		 *      1   1  super speed (hack, not in spec!)
+		 *      1   1  invalid
 		 */
 		ret = (buf[0] >> 9) & 0x3;
-	} else {
-		ret = -1;
+		if (ret != 0x3)
+			return ret;
 	}
-	return ret;
+	return -1;
 }
 
 static int
@@ -118,6 +124,27 @@ usb_hub_start_port_reset(usbdev_t *const dev, const int port)
 	return set_feature (dev, port, SEL_PORT_RESET, DR_PORT);
 }
 
+static void usb_hub_set_hub_depth(usbdev_t *const dev)
+{
+	dev_req_t dr = {
+		.bmRequestType = gen_bmRequestType(host_to_device,
+						   class_type, dev_recp),
+		.bRequest = SET_HUB_DEPTH,
+		.wValue = 0,
+		.wIndex = 0,
+		.wLength = 0,
+	};
+	usbdev_t *parent = dev;
+	while (parent->hub > 0) {
+		parent = dev->controller->devices[parent->hub];
+		dr.wValue++;
+	}
+	int ret = dev->controller->control(dev, OUT, sizeof(dr), &dr, 0, NULL);
+	if (ret < 0)
+		usb_debug("Failed SET_HUB_DEPTH(%d) on hub %d: %d\n",
+			  dr.wValue, dev->address, ret);
+}
+
 static const generic_hub_ops_t usb_hub_ops = {
 	.hub_status_changed	= NULL,
 	.port_status_changed	= usb_hub_port_status_changed,
@@ -134,13 +161,16 @@ static const generic_hub_ops_t usb_hub_ops = {
 void
 usb_hub_init(usbdev_t *const dev)
 {
+	int type = dev->speed == SUPER_SPEED ? 0x2a : 0x29; /* similar enough */
 	hub_descriptor_t desc;	/* won't fit the whole thing, we don't care */
 	if (get_descriptor(dev, gen_bmRequestType(device_to_host, class_type,
-		dev_recp), 0x29, 0, &desc, sizeof(desc)) != sizeof(desc)) {
+		dev_recp), type, 0, &desc, sizeof(desc)) != sizeof(desc)) {
 		usb_debug("get_descriptor(HUB) failed\n");
 		usb_detach_device(dev->controller, dev->address);
 		return;
 	}
 
+	if (dev->speed == SUPER_SPEED)
+		usb_hub_set_hub_depth(dev);
 	generic_hub_init(dev, desc.bNbrPorts, &usb_hub_ops);
 }
diff --git a/payloads/libpayload/drivers/usb/xhci_debug.c b/payloads/libpayload/drivers/usb/xhci_debug.c
index d50f6db..f8d2309 100644
--- a/payloads/libpayload/drivers/usb/xhci_debug.c
+++ b/payloads/libpayload/drivers/usb/xhci_debug.c
@@ -80,8 +80,8 @@ xhci_dump_devctx(const devctx_t *const dc, const u32 ctx_mask)
 	int i;
 	if (ctx_mask & 1)
 		xhci_dump_slotctx(dc->slot);
-	for (i = 0; i < SC_GET(CTXENT, dc->slot); ++i) {
-		if (ctx_mask & (2 << i))
+	for (i = 1; i <= SC_GET(CTXENT, dc->slot); ++i) {
+		if (ctx_mask & (1 << i))
 			xhci_dump_epctx(dc->ep[i]);
 	}
 }
diff --git a/payloads/libpayload/drivers/usb/xhci_devconf.c b/payloads/libpayload/drivers/usb/xhci_devconf.c
index 32cd291..ead130e 100644
--- a/payloads/libpayload/drivers/usb/xhci_devconf.c
+++ b/payloads/libpayload/drivers/usb/xhci_devconf.c
@@ -267,10 +267,11 @@ _free_ic_return:
 static int
 xhci_finish_hub_config(usbdev_t *const dev, inputctx_t *const ic)
 {
+	int type = dev->speed == SUPER_SPEED ? 0x2a : 0x29; /* similar enough */
 	hub_descriptor_t desc;
 
 	if (get_descriptor(dev, gen_bmRequestType(device_to_host, class_type,
-		dev_recp), 0x29, 0, &desc, sizeof(desc)) != sizeof(desc)) {
+		dev_recp), type, 0, &desc, sizeof(desc)) != sizeof(desc)) {
 		xhci_debug("Failed to fetch hub descriptor\n");
 		return COMMUNICATION_ERROR;
 	}
@@ -386,8 +387,9 @@ xhci_finish_device_config(usbdev_t *const dev)
 	ic->dev.slot->f1 = di->ctx.slot->f1;
 	ic->dev.slot->f2 = di->ctx.slot->f2;
 	ic->dev.slot->f3 = di->ctx.slot->f3;
+	/* f4 *must* be 0 in the Input Context... yeah, it's weird, I know. */
 
-	if (dev->descriptor->bDeviceClass == 0x09 && dev->speed < SUPER_SPEED) {
+	if (dev->descriptor->bDeviceClass == 0x09) {
 		ret = xhci_finish_hub_config(dev, ic);
 		if (ret)
 			goto _free_return;



More information about the coreboot-gerrit mailing list