At least some real-world controllers require 64 byte contexts. Detect this case and handle it appropriately.
Signed-off-by: Kevin O'Connor kevin@koconnor.net --- src/hw/usb-xhci.c | 64 ++++++++++++++++++++++++++++++++----------------------- src/hw/usb-xhci.h | 8 ------- 2 files changed, 37 insertions(+), 35 deletions(-)
diff --git a/src/hw/usb-xhci.c b/src/hw/usb-xhci.c index 15fd6a6..21c5ccf 100644 --- a/src/hw/usb-xhci.c +++ b/src/hw/usb-xhci.c @@ -229,6 +229,7 @@ struct usb_xhci_s { u32 xcap; u32 ports; u32 slots; + u8 context64;
/* xhci registers */ struct xhci_caps *caps; @@ -810,12 +811,15 @@ static struct usbhub_op_s xhci_hub_ops = { static struct xhci_inctx * xhci_alloc_inctx(struct usbdevice_s *usbdev) { - struct xhci_inctx *in = memalign_tmphigh(4096, sizeof(*in)); + struct usb_xhci_s *xhci = container_of( + usbdev->hub->cntl, struct usb_xhci_s, usb); + int size = (sizeof(struct xhci_inctx) * 33) << xhci->context64; + struct xhci_inctx *in = memalign_tmphigh(2048 << xhci->context64, size); if (!in) { warn_noalloc(); return NULL; } - memset(in, 0, sizeof(*in)); + memset(in, 0, size);
u32 route = 0; while (usbdev->hub->usbdev) { @@ -825,10 +829,11 @@ xhci_alloc_inctx(struct usbdevice_s *usbdev) }
in->add = 0x01; - in->slot.ctx[0] |= (1 << 27); // context entries - in->slot.ctx[0] |= speed_to_xhci[usbdev->speed] << 20; - in->slot.ctx[0] |= route; - in->slot.ctx[1] |= (usbdev->port+1) << 16; + struct xhci_slotctx *slot = (void*)&in[1 << xhci->context64]; + slot->ctx[0] |= (1 << 27); // context entries + slot->ctx[0] |= speed_to_xhci[usbdev->speed] << 20; + slot->ctx[0] |= route; + slot->ctx[1] |= (usbdev->port+1) << 16; /* TODO ctx0: hub bit */ /* TODO ctx1: hub ports */ return in; @@ -874,7 +879,8 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev usbdev, &pipe->reqs, pipe->slotid, pipe->epid); if (pipe->epid == 1) { // Enable slot and send set_address command. - struct xhci_devctx *dev = memalign_high(2048, sizeof(*dev)); + u32 size = (sizeof(struct xhci_slotctx) * 32) << xhci->context64; + struct xhci_devctx *dev = memalign_high(1024 << xhci->context64, size); if (!dev) { warn_noalloc(); goto fail; @@ -887,7 +893,7 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev } dprintf(3, "%s: enable slot: got slotid %d\n", __func__, slotid);
- memset(dev, 0, sizeof(*dev)); + memset(dev, 0, size); pipe->slotid = usbdev->slotid = slotid; xhci->devs[slotid].ptr_low = (u32)dev; xhci->devs[slotid].ptr_high = 0; @@ -897,14 +903,15 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev goto fail; in->add |= (1 << 1);
- in->ep[0].ctx[0] |= (3 << 16); // interval: 1ms - in->ep[0].ctx[1] |= (4 << 3); // control pipe - in->ep[0].ctx[1] |= (speed_to_ctlsize[usbdev->speed] << 16); + struct xhci_epctx *ep = (void*)&in[2 << xhci->context64]; + ep->ctx[0] |= (3 << 16); // interval: 1ms + ep->ctx[1] |= (4 << 3); // control pipe + ep->ctx[1] |= (speed_to_ctlsize[usbdev->speed] << 16);
- in->ep[0].deq_low = (u32)&pipe->reqs.ring[0]; - in->ep[0].deq_low |= 1; // dcs - in->ep[0].deq_high = 0; - in->ep[0].length = 8; + ep->deq_low = (u32)&pipe->reqs.ring[0]; + ep->deq_low |= 1; // dcs + ep->deq_high = 0; + ep->length = 8;
int cc = xhci_cmd_address_device(xhci, slotid, in); free(in); @@ -918,17 +925,17 @@ xhci_alloc_pipe(struct usbdevice_s *usbdev goto fail; in->add |= (1 << pipe->epid);
- int e = pipe->epid-1; + struct xhci_epctx *ep = (void*)&in[(pipe->epid+1) << xhci->context64]; if (eptype == USB_ENDPOINT_XFER_INT) - in->ep[e].ctx[0] = (usb_getFrameExp(usbdev, epdesc) + 3) << 16; - in->ep[e].ctx[1] |= (eptype << 3); + ep->ctx[0] = (usb_getFrameExp(usbdev, epdesc) + 3) << 16; + ep->ctx[1] |= (eptype << 3); if (epdesc->bEndpointAddress & USB_DIR_IN) - in->ep[e].ctx[1] |= (1 << 5); - in->ep[e].ctx[1] |= (pipe->pipe.maxpacket << 16); - in->ep[e].deq_low = (u32)&pipe->reqs.ring[0]; - in->ep[e].deq_low |= 1; // dcs - in->ep[e].deq_high = 0; - in->ep[e].length = pipe->pipe.maxpacket; + ep->ctx[1] |= (1 << 5); + ep->ctx[1] |= (pipe->pipe.maxpacket << 16); + ep->deq_low = (u32)&pipe->reqs.ring[0]; + ep->deq_low |= 1; // dcs + ep->deq_high = 0; + ep->length = pipe->pipe.maxpacket;
pipe->slotid = usbdev->slotid; int cc = xhci_cmd_configure_endpoint(xhci, pipe->slotid, in); @@ -967,7 +974,8 @@ xhci_update_pipe(struct usbdevice_s *usbdev, struct usb_pipe *upipe if (!in) return upipe; in->add = (1 << 1); - in->ep[0].ctx[1] |= (pipe->pipe.maxpacket << 16); + struct xhci_epctx *ep = (void*)&in[2 << xhci->context64]; + ep->ctx[1] |= (pipe->pipe.maxpacket << 16); int cc = xhci_cmd_evaluate_context(xhci, pipe->slotid, in); if (cc != CC_SUCCESS) { dprintf(1, "%s: reconf ctl endpoint: failed (cc %d)\n", @@ -1083,6 +1091,7 @@ xhci_controller_setup(struct pci_device *pci) xhci->ports = (hcs1 >> 24) & 0xff; xhci->slots = hcs1 & 0xff; xhci->xcap = ((hcc >> 16) & 0xffff) << 2; + xhci->context64 = (hcc & 0x04) ? 1 : 0;
xhci->usb.pci = pci; xhci->usb.type = USB_TYPE_XHCI; @@ -1090,10 +1099,11 @@ xhci_controller_setup(struct pci_device *pci) xhci->hub.portcount = xhci->ports; xhci->hub.op = &xhci_hub_ops;
- dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots\n" + dprintf(1, "XHCI init on dev %02x:%02x.%x: regs @ %p, %d ports, %d slots" + ", %d byte contexts\n" , pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf) , pci_bdf_to_fn(pci->bdf), xhci->caps - , xhci->ports, xhci->slots); + , xhci->ports, xhci->slots, xhci->context64 ? 64 : 32);
if (xhci->xcap) { u32 off, addr = xhci->baseaddr + xhci->xcap; diff --git a/src/hw/usb-xhci.h b/src/hw/usb-xhci.h index be6094c..bd98d17 100644 --- a/src/hw/usb-xhci.h +++ b/src/hw/usb-xhci.h @@ -104,12 +104,6 @@ struct xhci_epctx { u32 reserved_01[3]; } PACKED;
-// device context -struct xhci_devctx { - struct xhci_slotctx slot; - struct xhci_epctx ep[31]; -} PACKED; - // device context array element struct xhci_devlist { u32 ptr_low; @@ -121,8 +115,6 @@ struct xhci_inctx { u32 del; u32 add; u32 reserved_01[6]; - struct xhci_slotctx slot; - struct xhci_epctx ep[31]; } PACKED;
// transfer block (ring element)