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) |

Reply via email to