summaryrefslogtreecommitdiffstats
path: root/qemu/roms/seabios/src/hw/usb-xhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'qemu/roms/seabios/src/hw/usb-xhci.c')
-rw-r--r--qemu/roms/seabios/src/hw/usb-xhci.c46
1 files changed, 34 insertions, 12 deletions
diff --git a/qemu/roms/seabios/src/hw/usb-xhci.c b/qemu/roms/seabios/src/hw/usb-xhci.c
index fd58334dc..654febaad 100644
--- a/qemu/roms/seabios/src/hw/usb-xhci.c
+++ b/qemu/roms/seabios/src/hw/usb-xhci.c
@@ -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;