These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / seabios / src / hw / usb-xhci.c
index fd58334..654feba 100644 (file)
@@ -350,26 +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:
-        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
         xhci_print_port_state(3, __func__, port, portsc);
-        portsc |= XHCI_PORTSC_PR;
-        writel(&xhci->pr[port].portsc, portsc);
-        if (wait_bit(&xhci->pr[port].portsc, XHCI_PORTSC_PED, XHCI_PORTSC_PED, 100) != 0)
-            return -1;
-        portsc = readl(&xhci->pr[port].portsc);
-        rc = speed_from_xhci[xhci_get_field(portsc, XHCI_PORTSC_SPEED)];
+        writel(&xhci->pr[port].portsc, portsc | XHCI_PORTSC_PR);
         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;
 }
@@ -465,7 +480,7 @@ configure_xhci(void *data)
     xhci->evts->cs = 1;
 
     reg = readl(&xhci->caps->hcsparams2);
-    u32 spb = reg >> 27;
+    u32 spb = (reg >> 21 & 0x1f) << 5 | reg >> 27;
     if (spb) {
         dprintf(3, "%s: setup %d scratch pad buffers\n", __func__, spb);
         u64 *spba = memalign_high(64, sizeof(*spba) * spb);
@@ -921,8 +936,14 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
     usb_desc2pipe(&pipe->pipe, usbdev, epdesc);
     pipe->epid = epid;
     pipe->reqs.cs = 1;
-    if (eptype == USB_ENDPOINT_XFER_INT)
+    if (eptype == USB_ENDPOINT_XFER_INT) {
         pipe->buf = malloc_high(pipe->pipe.maxpacket);
+        if (!pipe->buf) {
+            warn_noalloc();
+            free(pipe);
+            return NULL;
+        }
+    }
 
     // Allocate input context and initialize endpoint info.
     struct xhci_inctx *in = xhci_alloc_inctx(usbdev, epid);
@@ -988,6 +1009,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev
     return &pipe->pipe;
 
 fail:
+    free(pipe->buf);
     free(pipe);
     free(in);
     return NULL;