usb: xhci: Don't assume LS/FS devices are always behind a HS hub
authorBin Meng <bmeng.cn@gmail.com>
Mon, 18 Sep 2017 13:40:39 +0000 (06:40 -0700)
committerMarek Vasut <marex@denx.de>
Sun, 1 Oct 2017 14:32:52 +0000 (16:32 +0200)
At present xHCI driver assumes LS/FS devices are attached directly
to a HS hub. If they are connected to a LS/FS hub, the driver will
fail to perform the USB enumeration process on such devices.

This is fixed by looking from the device itself all the way up to
the HS hub where the TT that serves the device is located.

Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
drivers/usb/host/xhci-mem.c

index d5eab3a61545442ae31066e85b4584946bbdf54d..84982a92d6030efbdab5437a94199b3c4c60ab90 100644 (file)
@@ -786,12 +786,22 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
 #ifdef CONFIG_DM_USB
        /* Set up TT fields to support FS/LS devices */
        if (speed == USB_SPEED_LOW || speed == USB_SPEED_FULL) {
-               dev = dev_get_parent_priv(udev->dev);
-               if (dev->speed == USB_SPEED_HIGH) {
-                       hub = dev_get_uclass_priv(udev->dev);
+               struct udevice *parent = udev->dev;
+
+               dev = udev;
+               do {
+                       port_num = dev->portnr;
+                       dev = dev_get_parent_priv(parent);
+                       if (usb_hub_is_root_hub(dev->dev))
+                               break;
+                       parent = dev->dev->parent;
+               } while (dev->speed != USB_SPEED_HIGH);
+
+               if (!usb_hub_is_root_hub(dev->dev)) {
+                       hub = dev_get_uclass_priv(dev->dev);
                        if (hub->tt.multi)
                                slot_ctx->dev_info |= cpu_to_le32(DEV_MTT);
-                       slot_ctx->tt_info |= cpu_to_le32(TT_PORT(udev->portnr));
+                       slot_ctx->tt_info |= cpu_to_le32(TT_PORT(port_num));
                        slot_ctx->tt_info |= cpu_to_le32(TT_SLOT(dev->slot_id));
                }
        }