summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/xhci.c
diff options
context:
space:
mode:
authormpi <mpi@openbsd.org>2018-04-27 13:25:08 +0000
committermpi <mpi@openbsd.org>2018-04-27 13:25:08 +0000
commit438cc1d7544e78e2eb1f1db810214133e13df8fc (patch)
tree748f417a555177cb89d28b95dce8d182da72e1d9 /sys/dev/usb/xhci.c
parentvmd(8): implement vmd side of ELCR registers (diff)
downloadwireguard-openbsd-438cc1d7544e78e2eb1f1db810214133e13df8fc.tar.xz
wireguard-openbsd-438cc1d7544e78e2eb1f1db810214133e13df8fc.zip
Introduce an helper function to extract endpoint's max burst value.
Use this helper to calculate the Transfer Burst Count (TBC) and Transfer Last Burst Packet Count (TLBPC) required for isochronous support. Note that SS companion descriptors are still not read. While here print the ETE and IST values in debug mode.
Diffstat (limited to 'sys/dev/usb/xhci.c')
-rw-r--r--sys/dev/usb/xhci.c91
1 files changed, 72 insertions, 19 deletions
diff --git a/sys/dev/usb/xhci.c b/sys/dev/usb/xhci.c
index 8a9cd85ef63..715e89a0b1d 100644
--- a/sys/dev/usb/xhci.c
+++ b/sys/dev/usb/xhci.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: xhci.c,v 1.81 2018/04/27 10:16:26 mpi Exp $ */
+/* $OpenBSD: xhci.c,v 1.82 2018/04/27 13:25:08 mpi Exp $ */
/*
* Copyright (c) 2014-2015 Martin Pieuchot
@@ -387,7 +387,8 @@ xhci_init(struct xhci_softc *sc)
/* Get the number of scratch pages and configure them if necessary. */
hcr = XREAD4(sc, XHCI_HCSPARAMS2);
npage = XHCI_HCS2_SPB_MAX(hcr);
- DPRINTF(("%s: %d scratch pages\n", DEVNAME(sc), npage));
+ DPRINTF(("%s: %u scratch pages, ETE=%u, IST=0x%x\n", DEVNAME(sc), npage,
+ XHCI_HCS2_ETE(hcr), XHCI_HCS2_IST(hcr)));
if (npage > 0 && xhci_scratchpad_alloc(sc, npage)) {
printf("%s: could not allocate scratchpad.\n", DEVNAME(sc));
@@ -1147,6 +1148,28 @@ xhci_pipe_interval(struct usbd_pipe *pipe)
return (XHCI_EPCTX_SET_IVAL(ival));
}
+uint32_t
+xhci_pipe_maxburst(struct usbd_pipe *pipe)
+{
+ usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
+ uint32_t mps = UGETW(ed->wMaxPacketSize);
+ uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
+ uint32_t maxb = 0;
+
+ switch (pipe->device->speed) {
+ case USB_SPEED_HIGH:
+ if (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)
+ maxb = UE_GET_TRANS(mps);
+ break;
+ case USB_SPEED_SUPER:
+ /* XXX Read the companion descriptor */
+ default:
+ break;
+ }
+
+ return (maxb);
+}
+
int
xhci_context_setup(struct xhci_softc *sc, struct usbd_pipe *pipe)
{
@@ -1155,7 +1178,7 @@ xhci_context_setup(struct xhci_softc *sc, struct usbd_pipe *pipe)
usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc;
uint32_t mps = UGETW(ed->wMaxPacketSize);
uint8_t xfertype = UE_GET_XFERTYPE(ed->bmAttributes);
- uint8_t speed, cerr = 0, maxb = 0;
+ uint8_t speed, cerr = 0;
uint32_t route = 0, rhport = 0;
struct usbd_device *hub;
@@ -1183,12 +1206,9 @@ xhci_context_setup(struct xhci_softc *sc, struct usbd_pipe *pipe)
break;
case USB_SPEED_HIGH:
speed = XHCI_SPEED_HIGH;
- if (xfertype == UE_ISOCHRONOUS || xfertype == UE_INTERRUPT)
- maxb = UE_GET_TRANS(mps);
break;
case USB_SPEED_SUPER:
speed = XHCI_SPEED_SUPER;
- maxb = 0; /* XXX Read the companion descriptor */
break;
default:
return (USBD_INVAL);
@@ -1203,7 +1223,8 @@ xhci_context_setup(struct xhci_softc *sc, struct usbd_pipe *pipe)
sdev->ep_ctx[xp->dci-1]->info_lo = htole32(xhci_pipe_interval(pipe));
sdev->ep_ctx[xp->dci-1]->info_hi = htole32(
- XHCI_EPCTX_SET_MPS(UE_GET_SIZE(mps)) | XHCI_EPCTX_SET_MAXB(maxb) |
+ XHCI_EPCTX_SET_MPS(UE_GET_SIZE(mps)) |
+ XHCI_EPCTX_SET_MAXB(xhci_pipe_maxburst(pipe)) |
XHCI_EPCTX_SET_EPTYPE(xfertype) | XHCI_EPCTX_SET_CERR(cerr)
);
sdev->ep_ctx[xp->dci-1]->txinfo = htole32(xhci_get_txinfo(sc, pipe));
@@ -2479,7 +2500,11 @@ xhci_root_intr_done(struct usbd_xfer *xfer)
{
}
-/* Number of packets remaining in the TD after the corresponding TRB. */
+/*
+ * Number of packets remaining in the TD after the corresponding TRB.
+ *
+ * Section 4.11.2.4 of xHCI specification r1.1.
+ */
static inline uint32_t
xhci_xfer_tdsize(struct usbd_xfer *xfer, uint32_t remain, uint32_t len)
{
@@ -2495,6 +2520,40 @@ xhci_xfer_tdsize(struct usbd_xfer *xfer, uint32_t remain, uint32_t len)
return XHCI_TRB_TDREM(npkt);
}
+/*
+ * Transfer Burst Count (TBC) and Transfer Last Burst Packet Count (TLBPC).
+ *
+ * Section 4.11.2.3 of xHCI specification r1.1.
+ */
+static inline uint32_t
+xhci_xfer_tbc(struct usbd_xfer *xfer, uint32_t len, uint32_t *tlbpc)
+{
+ uint32_t mps = UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
+ uint32_t maxb, tdpc, residue, tbc;
+
+ /* Transfer Descriptor Packet Count, section 4.14.1. */
+ tdpc = howmany(len, UE_GET_SIZE(mps));
+ if (tdpc == 0)
+ tdpc = 1;
+
+ /* Transfer Burst Count */
+ maxb = xhci_pipe_maxburst(xfer->pipe);
+ tbc = howmany(tdpc, maxb + 1) - 1;
+
+ /* Transfer Last Burst Packet Count */
+ if (xfer->device->speed == USB_SPEED_SUPER) {
+ residue = tdpc % (maxb + 1);
+ if (residue == 0)
+ *tlbpc = maxb;
+ else
+ *tlbpc = residue - 1;
+ } else {
+ *tlbpc = tdpc - 1;
+ }
+
+ return (tbc);
+}
+
usbd_status
xhci_device_ctrl_transfer(struct usbd_xfer *xfer)
{
@@ -2745,15 +2804,13 @@ xhci_device_isoc_start(struct usbd_xfer *xfer)
{
struct xhci_softc *sc = (struct xhci_softc *)xfer->device->bus;
struct xhci_pipe *xp = (struct xhci_pipe *)xfer->pipe;
- usb_endpoint_descriptor_t *ed = xfer->pipe->endpoint->edesc;
struct xhci_xfer *xx = (struct xhci_xfer *)xfer;
struct xhci_trb *trb0, *trb;
uint32_t len, remain, flags;
uint64_t paddr = DMAADDR(&xfer->dmabuf, 0);
- uint32_t len0, mps = UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
+ uint32_t len0, tbc, tlbpc;
uint8_t toggle0, toggle;
- int s, i, ntrb = xfer->nframes, maxb;
- int npkt = xfer->length / mps;
+ int s, i, ntrb = xfer->nframes;
KASSERT(!(xfer->rqflags & URQ_REQUEST));
@@ -2816,18 +2873,14 @@ xhci_device_isoc_start(struct usbd_xfer *xfer)
flags |= XHCI_TRB_ISP;
flags |= (ntrb == 1) ? XHCI_TRB_IOC : XHCI_TRB_CHAIN;
- maxb = UE_GET_TRANS(UGETW(ed->wMaxPacketSize));
- flags |= XHCI_TRB_ISOC_TBC((npkt / (maxb + 1)) - 1);
- if (ntrb > 1 && xfer->frlengths[ntrb - 1] < maxb)
- flags |= XHCI_TRB_ISOC_TLBPC((npkt % (maxb + 1)) - 1);
- else
- flags |= XHCI_TRB_ISOC_TLBPC(maxb);
+ tbc = xhci_xfer_tbc(xfer, len0, &tlbpc);
+ flags |= XHCI_TRB_ISOC_TBC(tbc) | XHCI_TRB_ISOC_TLBPC(tlbpc);
trb0->trb_paddr = htole64(DMAADDR(&xfer->dmabuf, 0));
trb0->trb_status = htole32(
XHCI_TRB_INTR(0) | XHCI_TRB_LEN(len0) |
xhci_xfer_tdsize(xfer, xfer->length, len0)
- );
+ );
trb0->trb_flags = htole32(flags);
bus_dmamap_sync(xp->ring.dma.tag, xp->ring.dma.map,