From f7a9e5dd03f83cf31a85eadf8666939abe47b739 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:57 +0800 Subject: usb: hub: Update handling connect status/change in usb_scan_port() It was observed that on Intel MinnowMax board, when xHCI is enabled in the BayTrail SoC, with a USB 3.0 device connected to the bottom USB 3.0 port (mapped to xHCI root port #7), its PORTSC register is always 0x201203 (CCS = 1, CSC = 0). The root cause of such behavior is unknown yet. Connect status change bit is set on the same port with a USB 2.0 device (mapped to xHCI port #1, which is a different port on the root hub). With current logic in usb_scan_port(), the enumeration process will abort if it does not detect a connect status change on a hub port. However since a device connection status is correctly reported, the enumeration process can still continue. With this change, USB device connected to the bottom blue port on MinnowMax board can be enumerated under either SS or HS mode. Signed-off-by: Bin Meng Reviewed-by: Stefan Roese Tested-by: Stefan Roese Tested-by: Dinh Nguyen --- common/usb_hub.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index d135526..4fe0daa 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -405,8 +405,15 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) portchange = le16_to_cpu(portsts->wPortChange); debug("Port %d Status %X Change %X\n", i + 1, portstatus, portchange); - /* No connection change happened, wait a bit more. */ - if (!(portchange & USB_PORT_STAT_C_CONNECTION)) { + /* + * No connection change happened, wait a bit more. + * + * For some situation, the hub reports no connection change but a + * device is connected to the port (eg: CCS bit is set but CSC is not + * in the PORTSC register of a root hub), ignore such case. + */ + if (!(portchange & USB_PORT_STAT_C_CONNECTION) && + !(portstatus & USB_PORT_STAT_CONNECTION)) { if (get_timer(0) >= hub->connect_timeout) { debug("devnum=%d port=%d: timeout\n", dev->devnum, i + 1); @@ -418,10 +425,6 @@ static int usb_scan_port(struct usb_device_scan *usb_scan) return 0; } - /* Test if the connection came up, and if not exit */ - if (!(portstatus & USB_PORT_STAT_CONNECTION)) - return 0; - /* A new USB device is ready at this point */ debug("devnum=%d port=%d: USB dev found\n", dev->devnum, i + 1); -- cgit v1.1 From f34211960214290d8b38dab2fbdfb18f07582f45 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:58 +0800 Subject: usb: hub: Send correct wValue to get hub descriptor of a USB 3.0 hub Testing a USB 3.0 hub by connecting it to the xHCI port on Intel MinnowMax, when issuing 'get hub descriptor' to the hub, xHCI reports a transfer event TRB with a completion code 6 which means 'Stall Error'. In fact super speed USB hub descriptor type is 0x2a, not 0x29. Sending correct SETUP packet to the hub makes it not stall anymore. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- common/usb_hub.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index 4fe0daa..48831b5 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -65,11 +65,21 @@ __weak void usb_hub_reset_devices(int port) return; } +static inline bool usb_hub_is_superspeed(struct usb_device *hdev) +{ + return hdev->descriptor.bDeviceProtocol == 3; +} + static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { + unsigned short dtype = USB_DT_HUB; + + if (usb_hub_is_superspeed(dev)) + dtype = USB_DT_SS_HUB; + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, - USB_DT_HUB << 8, 0, data, size, USB_CNTL_TIMEOUT); + dtype << 8, 0, data, size, USB_CNTL_TIMEOUT); } static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) -- cgit v1.1 From 53771a490e05e8be750a6ee50002e30df4776e9b Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:49:59 +0800 Subject: usb: hub: Revise wLength for 'get port status' request For accuracy, we should use 'sizeof(struct usb_port_status)' as the wLength for 'get port status' request, although it happens to be equal to 'sizeof(struct usb_hub_status)'. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- common/usb_hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index 48831b5..83c6767 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -107,7 +107,7 @@ int usb_get_port_status(struct usb_device *dev, int port, void *data) { return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, - data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT); + data, sizeof(struct usb_port_status), USB_CNTL_TIMEOUT); } -- cgit v1.1 From 337fc7e665a20bd0c23da233ffb9e8469d999e72 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:50:00 +0800 Subject: usb: hub: Change USB hub descriptor to match USB 3.0 hubs USB 3.0 hubs have a slightly different hub descriptor than USB 2.0 hubs, with a fixed (rather than variable length) size. Change the host controller drivers that access those last two fields (DeviceRemovable and PortPowerCtrlMask) to use the union. Signed-off-by: Bin Meng Reviewed-by: Simon Glass Reviewed-by: Stefan Roese Tested-by: Stefan Roese --- common/usb_hub.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index 83c6767..a46d26a 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -583,17 +583,19 @@ static int usb_hub_configure(struct usb_device *dev) &descriptor->wHubCharacteristics)), &hub->desc.wHubCharacteristics); /* set the bitmap */ - bitmap = (unsigned char *)&hub->desc.DeviceRemovable[0]; + bitmap = (unsigned char *)&hub->desc.u.hs.DeviceRemovable[0]; /* devices not removable by default */ memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); - bitmap = (unsigned char *)&hub->desc.PortPowerCtrlMask[0]; + bitmap = (unsigned char *)&hub->desc.u.hs.PortPowerCtrlMask[0]; memset(bitmap, 0xff, (USB_MAXCHILDREN+1+7)/8); /* PowerMask = 1B */ for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) - hub->desc.DeviceRemovable[i] = descriptor->DeviceRemovable[i]; + hub->desc.u.hs.DeviceRemovable[i] = + descriptor->u.hs.DeviceRemovable[i]; for (i = 0; i < ((hub->desc.bNbrPorts + 1 + 7)/8); i++) - hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i]; + hub->desc.u.hs.PortPowerCtrlMask[i] = + descriptor->u.hs.PortPowerCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; debug("%d ports detected\n", dev->maxchild); @@ -637,7 +639,7 @@ static int usb_hub_configure(struct usb_device *dev) for (i = 0; i < dev->maxchild; i++) debug("port %d is%s removable\n", i + 1, - hub->desc.DeviceRemovable[(i + 1) / 8] & \ + hub->desc.u.hs.DeviceRemovable[(i + 1) / 8] & \ (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { -- cgit v1.1 From dfa96e06761e223288e59d7a3e1d574f014b5a0d Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:09 +0800 Subject: usb: hub: Use 'struct usb_hub_device' as hub device's uclass_priv Use USB hub device's dev->uclass_priv to point to 'usb_hub_device' so that with driver model usb_hub_reset() and usb_hub_allocate() are no longer needed. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index a46d26a..37b358b 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -55,9 +55,6 @@ struct usb_device_scan { struct list_head list; }; -/* TODO(sjg@chromium.org): Remove this when CONFIG_DM_USB is defined */ -static struct usb_hub_device hub_dev[USB_MAX_HUB]; -static int usb_hub_index; static LIST_HEAD(usb_scan_list); __weak void usb_hub_reset_devices(int port) @@ -164,6 +161,10 @@ static void usb_hub_power_on(struct usb_hub_device *hub) max(100, (int)pgood_delay) + 1000); } +#ifndef CONFIG_DM_USB +static struct usb_hub_device hub_dev[USB_MAX_HUB]; +static int usb_hub_index; + void usb_hub_reset(void) { usb_hub_index = 0; @@ -180,6 +181,7 @@ static struct usb_hub_device *usb_hub_allocate(void) printf("ERROR: USB_MAX_HUB (%d) reached\n", USB_MAX_HUB); return NULL; } +#endif #define MAX_TRIES 5 @@ -543,6 +545,20 @@ out: return ret; } +static struct usb_hub_device *usb_get_hub_device(struct usb_device *dev) +{ + struct usb_hub_device *hub; + +#ifndef CONFIG_DM_USB + /* "allocate" Hub device */ + hub = usb_hub_allocate(); +#else + hub = dev_get_uclass_priv(dev->dev); +#endif + + return hub; +} + static int usb_hub_configure(struct usb_device *dev) { int i, length; @@ -554,11 +570,11 @@ static int usb_hub_configure(struct usb_device *dev) __maybe_unused struct usb_hub_status *hubsts; int ret; - /* "allocate" Hub device */ - hub = usb_hub_allocate(); + hub = usb_get_hub_device(dev); if (hub == NULL) return -ENOMEM; hub->pusb_dev = dev; + /* Get the the hub descriptor */ ret = usb_get_hub_descriptor(dev, buffer, 4); if (ret < 0) { @@ -792,6 +808,7 @@ UCLASS_DRIVER(usb_hub) = { .child_pre_probe = usb_child_pre_probe, .per_child_auto_alloc_size = sizeof(struct usb_device), .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata), + .per_device_auto_alloc_size = sizeof(struct usb_hub_device), }; static const struct usb_device_id hub_id_table[] = { -- cgit v1.1 From a199a7244899f6385035459cbc62409bd9bbcc23 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:10 +0800 Subject: usb: hub: Remove hub_port_reset() At present hub_port_reset() is defined in DM USB, but it is never called hence remove it (removing another ifdefs). While we are here, change legacy_hub_port_reset() name to usb_hub_port_reset() to better match other function names in the same hub module. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index 37b358b..086b155 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -207,8 +207,18 @@ static inline char *portspeed(int portstatus) return speed_str; } -int legacy_hub_port_reset(struct usb_device *dev, int port, - unsigned short *portstat) +/** + * usb_hub_port_reset() - reset a port given its usb_device pointer + * + * Reset a hub port and see if a device is present on that port, providing + * sufficient time for it to show itself. The port status is returned. + * + * @dev: USB device to reset + * @port: Port number to reset (note ports are numbered from 0 here) + * @portstat: Returns port status + */ +static int usb_hub_port_reset(struct usb_device *dev, int port, + unsigned short *portstat) { int err, tries; ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); @@ -281,15 +291,6 @@ int legacy_hub_port_reset(struct usb_device *dev, int port, return 0; } -#ifdef CONFIG_DM_USB -int hub_port_reset(struct udevice *dev, int port, unsigned short *portstat) -{ - struct usb_device *udev = dev_get_parent_priv(dev); - - return legacy_hub_port_reset(udev, port, portstat); -} -#endif - int usb_hub_port_connect_change(struct usb_device *dev, int port) { ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); @@ -323,7 +324,7 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port) } /* Reset the port */ - ret = legacy_hub_port_reset(dev, port, &portstatus); + ret = usb_hub_port_reset(dev, port, &portstatus); if (ret < 0) { if (ret != -ENXIO) printf("cannot reset port %i!?\n", port + 1); -- cgit v1.1 From 46c1d49330fe21b3f9d2f7577ee4268248e7b666 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:11 +0800 Subject: usb: hub: Add a new API to test if a hub device is root hub Sometimes we need know if a given hub device is root hub or not. Add a new API to test this. This removes the xHCI driver's own version is_root_hub() and change to use the new API. While we are here, remove the unused/commented out get_usb_device() in the xHCI driver too. Signed-off-by: Bin Meng --- common/usb_hub.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index 086b155..a8c2f56 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -67,6 +67,16 @@ static inline bool usb_hub_is_superspeed(struct usb_device *hdev) return hdev->descriptor.bDeviceProtocol == 3; } +#ifdef CONFIG_DM_USB +bool usb_hub_is_root_hub(struct udevice *hub) +{ + if (device_get_uclass_id(hub->parent) != UCLASS_USB_HUB) + return true; + + return false; +} +#endif + static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { unsigned short dtype = USB_DT_HUB; -- cgit v1.1 From 74ffc7cbb1d2d1f218b1bd67d1bd3cc1cba8aa79 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:12 +0800 Subject: usb: hub: Translate USB 3.0 hub port status into old version USB 3.0 hub port status field has different bit positions from 2.0 hubs. Since U-Boot only understands the old version, translate the new one into the old one. Since we are going to add USB 3.0 hub support, this feature is only available with driver model USB. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index a8c2f56..b0ff159 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -112,9 +112,40 @@ static int usb_get_hub_status(struct usb_device *dev, void *data) int usb_get_port_status(struct usb_device *dev, int port, void *data) { - return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + int ret; + + ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, sizeof(struct usb_port_status), USB_CNTL_TIMEOUT); + +#ifdef CONFIG_DM_USB + if (ret < 0) + return ret; + + /* + * Translate the USB 3.0 hub port status field into the old version + * that U-Boot understands. Do this only when the hub is not root hub. + * For root hub, the port status field has already been translated + * in the host controller driver (see xhci_submit_root() in xhci.c). + * + * Note: this only supports driver model. + */ + + if (!usb_hub_is_root_hub(dev->dev) && usb_hub_is_superspeed(dev)) { + struct usb_port_status *status = (struct usb_port_status *)data; + u16 tmp = (status->wPortStatus) & USB_SS_PORT_STAT_MASK; + + if (status->wPortStatus & USB_SS_PORT_STAT_POWER) + tmp |= USB_PORT_STAT_POWER; + if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) == + USB_SS_PORT_STAT_SPEED_5GBPS) + tmp |= USB_PORT_STAT_SUPER_SPEED; + + status->wPortStatus = tmp; + } +#endif + + return ret; } -- cgit v1.1 From bbc6f06c0031249bf1983b875e54cb7549bafe60 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:13 +0800 Subject: usb: hub: Support 'set hub depth' request for USB 3.0 hubs USB 3.0 hub uses a hub depth value multiplied by four as an offset into the 'route string' to locate the bits it uses to determine the downstream port number. We shall set the hub depth value of a USB 3.0 hub after it is configured. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index b0ff159..18c366a 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -75,6 +75,16 @@ bool usb_hub_is_root_hub(struct udevice *hub) return false; } + +static int usb_set_hub_depth(struct usb_device *dev, int depth) +{ + if (depth < 0 || depth > 4) + return -EINVAL; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_HUB_DEPTH, USB_DIR_OUT | USB_RT_HUB, + depth, 0, NULL, 0, USB_CNTL_TIMEOUT); +} #endif static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) @@ -726,6 +736,48 @@ static int usb_hub_configure(struct usb_device *dev) debug("%sover-current condition exists\n", (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ "" : "no "); + +#ifdef CONFIG_DM_USB + /* + * A maximum of seven tiers are allowed in a USB topology, and the + * root hub occupies the first tier. The last tier ends with a normal + * USB device. USB 3.0 hubs use a 20-bit field called 'route string' + * to route packets to the designated downstream port. The hub uses a + * hub depth value multiplied by four as an offset into the 'route + * string' to locate the bits it uses to determine the downstream + * port number. + */ + if (usb_hub_is_root_hub(dev->dev)) { + hub->hub_depth = -1; + } else { + struct udevice *hdev; + int depth = 0; + + hdev = dev->dev->parent; + while (!usb_hub_is_root_hub(hdev)) { + depth++; + hdev = hdev->parent; + } + + hub->hub_depth = depth; + + if (usb_hub_is_superspeed(dev)) { + debug("set hub (%p) depth to %d\n", dev, depth); + /* + * This request sets the value that the hub uses to + * determine the index into the 'route string index' + * for this hub. + */ + ret = usb_set_hub_depth(dev, depth); + if (ret < 0) { + debug("%s: failed to set hub depth (%lX)\n", + __func__, dev->status); + return ret; + } + } + } +#endif + usb_hub_power_on(hub); /* -- cgit v1.1 From 5624dfd5aa91c244519ec60b40b4a42b4d9a43ca Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:16 +0800 Subject: usb: hub: Parse and save TT details from device descriptor A high speed hub has a special responsibility to handle full speed/ low speed devices connected on downstream ports. In this case, the hub must isolate the high speed signaling environment from the full speed/low speed signaling environment with the help of Transaction Translator (TT). TT details are provided by hub descriptors and we parse and save it to hub uclass_priv for later use. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index 18c366a..bbb1155 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -700,6 +700,56 @@ static int usb_hub_configure(struct usb_device *dev) break; } + switch (dev->descriptor.bDeviceProtocol) { + case USB_HUB_PR_FS: + break; + case USB_HUB_PR_HS_SINGLE_TT: + debug("Single TT\n"); + break; + case USB_HUB_PR_HS_MULTI_TT: + ret = usb_set_interface(dev, 0, 1); + if (ret == 0) { + debug("TT per port\n"); + hub->tt.multi = true; + } else { + debug("Using single TT (err %d)\n", ret); + } + break; + case USB_HUB_PR_SS: + /* USB 3.0 hubs don't have a TT */ + break; + default: + debug("Unrecognized hub protocol %d\n", + dev->descriptor.bDeviceProtocol); + break; + } + + /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ + switch (hubCharacteristics & HUB_CHAR_TTTT) { + case HUB_TTTT_8_BITS: + if (dev->descriptor.bDeviceProtocol != 0) { + hub->tt.think_time = 666; + debug("TT requires at most %d FS bit times (%d ns)\n", + 8, hub->tt.think_time); + } + break; + case HUB_TTTT_16_BITS: + hub->tt.think_time = 666 * 2; + debug("TT requires at most %d FS bit times (%d ns)\n", + 16, hub->tt.think_time); + break; + case HUB_TTTT_24_BITS: + hub->tt.think_time = 666 * 3; + debug("TT requires at most %d FS bit times (%d ns)\n", + 24, hub->tt.think_time); + break; + case HUB_TTTT_32_BITS: + hub->tt.think_time = 666 * 4; + debug("TT requires at most %d FS bit times (%d ns)\n", + 32, hub->tt.think_time); + break; + } + debug("power on to power good time: %dms\n", descriptor->bPwrOn2PwrGood * 2); debug("hub controller current requirement: %dmA\n", -- cgit v1.1 From 81060bb1c02abb242b73f118ce297dbe483a40f7 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Wed, 19 Jul 2017 21:51:18 +0800 Subject: usb: hub: Call usb_update_hub_device() after hub descriptor is fetched After fetching hub descriptor, we need to call USB uclass operation update_hub_device() to notify HCD to do some preparation work. Signed-off-by: Bin Meng Reviewed-by: Simon Glass --- common/usb_hub.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'common') diff --git a/common/usb_hub.c b/common/usb_hub.c index bbb1155..70bc6e2 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -789,6 +789,17 @@ static int usb_hub_configure(struct usb_device *dev) #ifdef CONFIG_DM_USB /* + * Update USB host controller's internal representation of this hub + * after the hub descriptor is fetched. + */ + ret = usb_update_hub_device(dev); + if (ret < 0 && ret != -ENOSYS) { + debug("%s: failed to update hub device for HCD (%x)\n", + __func__, ret); + return ret; + } + + /* * A maximum of seven tiers are allowed in a USB topology, and the * root hub occupies the first tier. The last tier ends with a normal * USB device. USB 3.0 hubs use a 20-bit field called 'route string' -- cgit v1.1