Module Name: src Committed By: dsl Date: Tue Dec 10 19:39:42 UTC 2013
Modified Files: src/sys/dev/usb: xhci.c Log Message: Add a few comments about some perversities of the xhci specification. XXX: I can't see any code that ensures there is space in the rings. XXX: Nothing stops buffer fragments crossing 64kB boundaries. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/sys/dev/usb/xhci.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/usb/xhci.c diff -u src/sys/dev/usb/xhci.c:1.10 src/sys/dev/usb/xhci.c:1.11 --- src/sys/dev/usb/xhci.c:1.10 Sun Nov 17 16:11:35 2013 +++ src/sys/dev/usb/xhci.c Tue Dec 10 19:39:42 2013 @@ -1,4 +1,4 @@ -/* $NetBSD: xhci.c,v 1.10 2013/11/17 16:11:35 skrll Exp $ */ +/* $NetBSD: xhci.c,v 1.11 2013/12/10 19:39:42 dsl Exp $ */ /* * Copyright (c) 2013 Jonathan A. Kollasch @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.10 2013/11/17 16:11:35 skrll Exp $"); +__KERNEL_RCSID(0, "$NetBSD: xhci.c,v 1.11 2013/12/10 19:39:42 dsl Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -1621,6 +1621,15 @@ xhci_ring_put(struct xhci_softc * const ri = xr->xr_ep; cs = xr->xr_cs; + /* + * Although the xhci hardware can do scatter/gather dma from + * arbitrary sized buffers, there is a non-obvious restriction + * that a LINK trb is only allowed at the end of a burst of + * transfers - which might be 16kB. + * Arbitrary aligned LINK trb definitely fail on Ivy bridge. + * The simple solution is not to allow a LINK trb in the middle + * of anything - as here. + */ if (ri + ntrbs >= (xr->xr_ntrb - 1)) { parameter = xhci_ring_trbp(xr, 0); status = 0; @@ -1639,6 +1648,7 @@ xhci_ring_put(struct xhci_softc * const ri++; + /* Write any subsequent TRB first */ for (i = 1; i < ntrbs; i++) { parameter = trbs[i].trb_0; status = trbs[i].trb_2; @@ -1658,6 +1668,7 @@ xhci_ring_put(struct xhci_softc * const ri++; } + /* Write the first TRB last */ i = 0; { parameter = trbs[i].trb_0; @@ -2659,6 +2670,17 @@ xhci_device_bulk_start(usbd_xfer_handle KASSERT((xfer->rqflags & URQ_REQUEST) == 0); parameter = DMAADDR(dma, 0); + /* + * XXX: The physical buffer must not cross a 64k boundary. + * If the user supplied buffer crosses such a boundary then 2 + * (or more) TRB should be used. + * If multiple TRB are used the td_size field must be set correctly. + * For v1.0 devices (like ivy bridge) this is the number of usb data + * blocks needed to complete the transfer. + * Setting it to 1 in the last TRB causes an extra zero-length + * data block be sent. + * The earlier documentation differs, I don't know how it behaves. + */ KASSERT(len <= 0x10000); status = XHCI_TRB_2_IRQ_SET(0) | XHCI_TRB_2_TDSZ_SET(1) |