]> xenbits.xensource.com Git - people/andrewcoop/seabios.git/commitdiff
xhci: Wait for port enable even for USB3 devices
authorKevin O'Connor <kevin@koconnor.net>
Sun, 13 Dec 2015 19:49:41 +0000 (14:49 -0500)
committerGerd Hoffmann <kraxel@redhat.com>
Fri, 15 Jan 2016 09:47:52 +0000 (10:47 +0100)
Some USB3 controllers (and/or devices) need additional time after the
device is detected to place the port in an enabled state.  Wait for
the controller to report enabled before proceeding.  This fixes
several reports of devices that showed a "stall" error (cc 4) during
set address.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
(cherry picked from commit c01b41c5c68c197fe0124078261b48942f2919bd)

src/hw/usb-xhci.c

index 945b4626b491c4e0c7e828a6ef59db4e9952c20d..654febaad108410d17a2a42c5273c0ceabc68513 100644 (file)
@@ -350,42 +350,41 @@ xhci_hub_reset(struct usbhub_s *hub, u32 port)
 {
     struct usb_xhci_s *xhci = container_of(hub->cntl, struct usb_xhci_s, usb);
     u32 portsc = readl(&xhci->pr[port].portsc);
-    int rc;
     if (!(portsc & XHCI_PORTSC_CCS))
         // Device no longer connected?!
         return -1;
 
     switch (xhci_get_field(portsc, XHCI_PORTSC_PLS)) {
     case PLS_U0:
-        // A USB3 port - no reset necessary.
-        rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+        // A USB3 port - controller automatically performs reset
         break;
     case PLS_POLLING:
-        // A USB2 port - perform device reset and wait for completion
+        // A USB2 port - perform device reset
         xhci_print_port_state(3, __func__, port, portsc);
         writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
-        u32 end = timer_calc(100);
-        for (;;) {
-            portsc = readl(&xhci->pr[port].portsc);
-            if (!(portsc & XHCI_PORTSC_CCS))
-                // Device disconnected during reset
-                return -1;
-            if (portsc & XHCI_PORTSC_PED)
-                // Reset complete
-                break;
-            if (timer_check(end)) {
-                warn_timeout();
-                return -1;
-            }
-            yield();
-        }
-        rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
         break;
     default:
-        rc = -1;
-        break;
+        return -1;
+    }
+
+    // Wait for device to complete reset and be enabled
+    u32 end = timer_calc(100);
+    for (;;) {
+        portsc = readl(&xhci->pr[port].portsc);
+        if (!(portsc & XHCI_PORTSC_CCS))
+            // Device disconnected during reset
+            return -1;
+        if (portsc & XHCI_PORTSC_PED)
+            // Reset complete
+            break;
+        if (timer_check(end)) {
+            warn_timeout();
+            return -1;
+        }
+        yield();
     }
 
+    int rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
     xhci_print_port_state(1, "XHCI", port, portsc);
     return rc;
 }