Module Name:    src
Committed By:   skrll
Date:           Mon Apr  4 07:43:12 UTC 2016

Modified Files:
        src/sys/dev/usb [nick-nhusb]: ehci.c ehcivar.h ohci.c uhci.c

Log Message:
Rework {alloc,reset}_*_chain functions to perform all of TD setup in
reset chain.  The initial motivation for this was to fix ZLP.


To generate a diff of this commit:
cvs rdiff -u -r1.234.2.95 -r1.234.2.96 src/sys/dev/usb/ehci.c
cvs rdiff -u -r1.42.14.24 -r1.42.14.25 src/sys/dev/usb/ehcivar.h
cvs rdiff -u -r1.254.2.69 -r1.254.2.70 src/sys/dev/usb/ohci.c
cvs rdiff -u -r1.264.4.69 -r1.264.4.70 src/sys/dev/usb/uhci.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/ehci.c
diff -u src/sys/dev/usb/ehci.c:1.234.2.95 src/sys/dev/usb/ehci.c:1.234.2.96
--- src/sys/dev/usb/ehci.c:1.234.2.95	Sat Mar 26 11:42:44 2016
+++ src/sys/dev/usb/ehci.c	Mon Apr  4 07:43:12 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehci.c,v 1.234.2.95 2016/03/26 11:42:44 skrll Exp $ */
+/*	$NetBSD: ehci.c,v 1.234.2.96 2016/04/04 07:43:12 skrll Exp $ */
 
 /*
  * Copyright (c) 2004-2012 The NetBSD Foundation, Inc.
@@ -53,7 +53,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.95 2016/03/26 11:42:44 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.96 2016/04/04 07:43:12 skrll Exp $");
 
 #include "ohci.h"
 #include "uhci.h"
@@ -235,12 +235,13 @@ Static void		ehci_free_sqh(ehci_softc_t 
 
 Static ehci_soft_qtd_t *ehci_alloc_sqtd(ehci_softc_t *);
 Static void		ehci_free_sqtd(ehci_softc_t *, ehci_soft_qtd_t *);
-Static usbd_status	ehci_alloc_sqtd_chain(ehci_softc_t *, struct usbd_xfer *,
-			    int, int, ehci_soft_qtd_t **, ehci_soft_qtd_t **);
+Static usbd_status	ehci_alloc_sqtd_chain(ehci_softc_t *,
+			    struct usbd_xfer *, int, int, ehci_soft_qtd_t **);
 Static void		ehci_free_sqtds(ehci_softc_t *, struct ehci_xfer *);
 
 Static void		ehci_reset_sqtd_chain(ehci_softc_t *, struct usbd_xfer *,
 			    int, int, int *, ehci_soft_qtd_t **);
+Static void		ehci_append_sqtd(ehci_soft_qtd_t *, ehci_soft_qtd_t *);
 
 Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *);
 Static ehci_soft_sitd_t *
@@ -2823,130 +2824,38 @@ ehci_free_sqtd(ehci_softc_t *sc, ehci_so
 
 Static usbd_status
 ehci_alloc_sqtd_chain(ehci_softc_t *sc, struct usbd_xfer *xfer,
-    int alen, int rd, ehci_soft_qtd_t **sp, ehci_soft_qtd_t **ep)
+    int alen, int rd, ehci_soft_qtd_t **sp)
 {
 	struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
-	ehci_soft_qtd_t *next, *cur;
-	ehci_physaddr_t nextphys;
-	uint32_t qtdstatus;
-	int len, curlen, mps;
-	int i, tog;
-	int pages, pageoffs;
-	size_t curoffs;
-	vaddr_t va, va_offs;
-	usb_dma_t *dma = &xfer->ux_dmabuf;
 	uint16_t flags = xfer->ux_flags;
-	paddr_t a;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
-	DPRINTF("start len=%d", alen, 0, 0, 0);
 
 	ASSERT_SLEEPABLE();
 	KASSERT(sp);
-	KASSERT(alen != 0 || (flags & USBD_FORCE_SHORT_XFER));
-
-	len = alen;
-	qtdstatus = EHCI_QTD_ACTIVE |
-	    EHCI_QTD_SET_PID(rd ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
-	    EHCI_QTD_SET_CERR(3)
-	    ;
+	KASSERT(alen != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER)));
 
-	size_t nsqtd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0;
-	nsqtd += ((len + EHCI_QTD_MAXTRANSFER - 1) / EHCI_QTD_MAXTRANSFER);
+	size_t nsqtd = (!rd && (flags & USBD_FORCE_SHORT_XFER)) ? 1 : 0;
+	nsqtd += ((alen + EHCI_PAGE_SIZE - 1) / EHCI_PAGE_SIZE);
 	exfer->ex_sqtds = kmem_zalloc(sizeof(ehci_soft_qtd_t *) * nsqtd,
 	    KM_SLEEP);
 	exfer->ex_nsqtd = nsqtd;
 
-	mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
-	cur = ehci_alloc_sqtd(sc);
-	*sp = cur;
-	if (cur == NULL)
-		goto nomem;
-
-	curoffs = 0;
-	for (size_t j = 0;;) {
-		KASSERT(j < nsqtd);
-		exfer->ex_sqtds[j++] = cur;
-
-		/* The EHCI hardware can handle at most 5 pages. */
-		va = (vaddr_t)KERNADDR(dma, curoffs);
-		va_offs = EHCI_PAGE_OFFSET(va);
-		if (len - curoffs < EHCI_QTD_MAXTRANSFER - va_offs) {
-			/* we can handle it in this QTD */
-			curlen = len - curoffs;
-		} else {
-			/* must use multiple TDs, fill as much as possible. */
-			curlen = EHCI_QTD_MAXTRANSFER - va_offs;
+	DPRINTF("xfer %p len %d nsqtd %d flags %x", xfer, alen, nsqtd, flags);
 
-			/* the length must be a multiple of the max size */
-			curlen -= curlen % mps;
-			DPRINTF("multiple QTDs, curlen=%d", curlen, 0, 0, 0);
-			KASSERT(curlen != 0);
-		}
-		DPRINTF("len=%d curlen=%d curoffs=%zu", len, curlen, curoffs,
-		    0);
-
-		/*
-		 * Allocate another transfer if there's more data left,
-		 * or if force last short transfer flag is set and we're
-		 * allocating a multiple of the max packet size.
-		 */
-
-		if (curoffs + curlen != len ||
-		    ((curlen % mps) == 0 && !rd && curlen != 0 &&
-		     (flags & USBD_FORCE_SHORT_XFER))) {
-			next = ehci_alloc_sqtd(sc);
-			if (next == NULL)
-				goto nomem;
-			nextphys = htole32(next->physaddr);
-		} else {
-			next = NULL;
-			nextphys = EHCI_NULL;
-		}
-
-		/* Find number of pages we'll be using, insert dma addresses */
-		pages = EHCI_NPAGES(curlen);
-		KASSERT(pages <= EHCI_QTD_NBUFFERS);
-		pageoffs = EHCI_PAGE(curoffs);
-		for (i = 0; i < pages; i++) {
-			a = DMAADDR(dma, pageoffs + i * EHCI_PAGE_SIZE);
-			cur->qtd.qtd_buffer[i] = htole32(EHCI_PAGE(a));
-			/* Cast up to avoid compiler warnings */
-			cur->qtd.qtd_buffer_hi[i] = htole32((uint64_t)a >> 32);
-		}
+	for (size_t j = 0; j < exfer->ex_nsqtd;) {
+		ehci_soft_qtd_t *cur = ehci_alloc_sqtd(sc);
+		if (cur == NULL)
+			goto nomem;
+		exfer->ex_sqtds[j++] = cur;
 
-		/* First buffer pointer requires a page offset to start at */
-		cur->qtd.qtd_buffer[0] |= htole32(va_offs);
-		cur->qtd.qtd_next = cur->qtd.qtd_altnext = nextphys;
-		cur->qtd.qtd_status = htole32(qtdstatus);
-		cur->nextqtd = next;
 		cur->xfer = xfer;
-		cur->bufoff = curoffs;
-		cur->tdlen = curlen;
 		cur->len = 0;
 
-		DPRINTF("cbp=0x%08zx end=0x%08zx", curoffs, curoffs + curlen,
-		    0, 0);
-
-		/*
-		 * adjust the toggle based on the number of packets in this
-		 * qtd
-		 */
-		if (((curlen + mps - 1) / mps) & 1) {
-			tog ^= 1;
-			qtdstatus ^= EHCI_QTD_TOGGLE_MASK;
-		}
-		if (next == NULL)
-			break;
-		DPRINTF("extend chain", 0, 0, 0, 0);
-		if (len)
-			curoffs += curlen;
-		cur = next;
 	}
-	if (ep)
-		*ep = cur;
 
-	DPRINTF("return sqtd=%p sqtdend=%p", *sp, cur, 0, 0);
+	*sp = exfer->ex_sqtds[0];
+	DPRINTF("return sqtd=%p", *sp, 0, 0, 0);
 
 	return USBD_NORMAL_COMPLETION;
 
@@ -2976,92 +2885,132 @@ ehci_free_sqtds(ehci_softc_t *sc, struct
 }
 
 Static void
+ehci_append_sqtd(ehci_soft_qtd_t *sqtd, ehci_soft_qtd_t *prev)
+{
+	if (prev) {
+		prev->nextqtd = sqtd;
+		prev->qtd.qtd_next = htole32(sqtd->physaddr);
+		prev->qtd.qtd_altnext = prev->qtd.qtd_next;
+		usb_syncmem(&prev->dma, prev->offs, sizeof(prev->qtd),
+		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+	}
+}
+
+Static void
 ehci_reset_sqtd_chain(ehci_softc_t *sc, struct usbd_xfer *xfer,
     int length, int isread, int *toggle, ehci_soft_qtd_t **lsqtd)
 {
 	struct ehci_xfer *exfer = EHCI_XFER2EXFER(xfer);
+	usb_dma_t *dma = &xfer->ux_dmabuf;
+	uint16_t flags = xfer->ux_flags;
 	ehci_soft_qtd_t *sqtd, *prev;
 	int tog = *toggle;
 	int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
 	int len = length;
-	size_t i;
 
 	EHCIHIST_FUNC(); EHCIHIST_CALLED();
-	DPRINTF("xfer=%p len %d isread %d toggle %d", xfer, len, isread,
-	    *toggle);
+	DPRINTF("xfer=%p len %d isread %d toggle %d", xfer, len, isread, tog);
 	DPRINTF("    VA %p", KERNADDR(&xfer->ux_dmabuf, 0), 0, 0, 0);
 
+	KASSERT(length != 0 || (!isread && (flags & USBD_FORCE_SHORT_XFER)));
+
+	const uint32_t qtdstatus = EHCI_QTD_ACTIVE |
+	    EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
+	    EHCI_QTD_SET_CERR(3)
+	    ;
+
 	sqtd = prev = NULL;
-	for (i = 0; i < exfer->ex_nsqtd; i++, prev = sqtd) {
-		sqtd = exfer->ex_sqtds[i];
-		vaddr_t va = (vaddr_t)KERNADDR(&xfer->ux_dmabuf, sqtd->bufoff);
-		sqtd->len = sqtd->tdlen;
-		if (len < sqtd->len) {
-			sqtd->len = len;
-		}
-
-		DPRINTF("sqtd[%d]=%p prev %p len %d", i, sqtd, prev, sqtd->len);
-		DPRINTF("    va %p bufoff %d pa %p", va, sqtd->bufoff,
-		    DMAADDR(&xfer->ux_dmabuf, sqtd->bufoff), 0);
-
-		if (prev) {
-			prev->nextqtd = sqtd;
-			prev->qtd.qtd_next = htole32(sqtd->physaddr);
-			prev->qtd.qtd_altnext = prev->qtd.qtd_next;
+	size_t curoffs = 0;
+	size_t j = 0;
+	for (; len != 0 && j < exfer->ex_nsqtd; prev = sqtd) {
+		sqtd = exfer->ex_sqtds[j++];
+		DPRINTF("sqtd[%d]=%p prev %p", j, sqtd, prev, 0);
+
+		/*
+		 * The EHCI hardware can handle at most 5 pages and they do
+		 * not have to be contiguous
+		 */
+		vaddr_t va = (vaddr_t)KERNADDR(dma, curoffs);
+		vaddr_t va_offs = EHCI_PAGE_OFFSET(va);
+		size_t curlen = len;
+		if (curlen >= EHCI_QTD_MAXTRANSFER - va_offs) {
+			/* must use multiple TDs, fill as much as possible. */
+			curlen = EHCI_QTD_MAXTRANSFER - va_offs;
+
+			/* the length must be a multiple of the max size */
+			curlen -= curlen % mps;
 		}
-		usb_syncmem(&sqtd->dma,
-		    sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
-		    sizeof(sqtd->qtd.qtd_status),
-		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
-		usb_syncmem(&sqtd->dma,
-		    sqtd->offs + offsetof(ehci_qtd_t, qtd_buffer),
-		    sizeof(sqtd->qtd.qtd_buffer[0]),
-		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
+		KASSERT(curlen != 0);
+		DPRINTF("    len=%d curlen=%d curoffs=%zu", len, curlen,
+		    curoffs, 0);
 
-		sqtd->qtd.qtd_buffer[0] &= ~htole32(EHCI_PAGE_MASK);
-		sqtd->qtd.qtd_buffer[0] |= htole32(EHCI_PAGE_OFFSET(va));
-		/* Reset ... */
-		sqtd->qtd.qtd_status &= ~htole32(
-		    EHCI_QTD_STATUS_MASK |
-		    EHCI_QTD_PID_MASK |
-		    EHCI_QTD_CERR_MASK |
-		    EHCI_QTD_C_PAGE_MASK |
-		    EHCI_QTD_BYTES_MASK |
-		    EHCI_QTD_TOGGLE_MASK);
-		sqtd->qtd.qtd_status |= htole32(
-		    EHCI_QTD_ACTIVE |
-		    EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT) |
-		    EHCI_QTD_SET_BYTES(sqtd->len) |
-		    EHCI_QTD_SET_CERR(3) |
+		/* Fill the qTD */
+		sqtd->qtd.qtd_next = sqtd->qtd.qtd_altnext = EHCI_NULL;
+		sqtd->qtd.qtd_status = htole32(
+		    qtdstatus |
+		    EHCI_QTD_SET_BYTES(curlen) |
 		    EHCI_QTD_SET_TOGGLE(tog));
 
-		usb_syncmem(&sqtd->dma,
-		    sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
-		    sizeof(sqtd->qtd.qtd_status),
-		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-		usb_syncmem(&sqtd->dma,
-		    sqtd->offs + offsetof(ehci_qtd_t, qtd_buffer),
-		    sizeof(sqtd->qtd.qtd_buffer[0]),
+		/* Find number of pages we'll be using, insert dma addresses */
+		size_t pages = EHCI_NPAGES(curlen);
+		KASSERT(pages <= EHCI_QTD_NBUFFERS);
+		size_t pageoffs = EHCI_PAGE(curoffs);
+		for (size_t i = 0; i < pages; i++) {
+			paddr_t a = DMAADDR(dma,
+			    pageoffs + i * EHCI_PAGE_SIZE);
+			sqtd->qtd.qtd_buffer[i] = htole32(EHCI_PAGE(a));
+			/* Cast up to avoid compiler warnings */
+			sqtd->qtd.qtd_buffer_hi[i] = htole32((uint64_t)a >> 32);
+			DPRINTF("      buffer[%d/%d] 0x%08x 0x%08x", i, pages,
+			    le32toh(sqtd->qtd.qtd_buffer_hi[i]),
+			    le32toh(sqtd->qtd.qtd_buffer[i]));
+		}
+		/* First buffer pointer requires a page offset to start at */
+		sqtd->qtd.qtd_buffer[0] |= htole32(va_offs);
+
+		usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd),
 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
-		if (((sqtd->len + mps - 1) / mps) & 1) {
+		sqtd->len = curlen;
+
+		DPRINTF("    va %p pa %p len %d", va,
+		    DMAADDR(&xfer->ux_dmabuf, curoffs), curlen, 0);
+
+		ehci_append_sqtd(sqtd, prev);
+
+		if (((curlen + mps - 1) / mps) & 1) {
 			tog ^= 1;
 		}
 
-		len -= sqtd->len;
-		if (len == 0)
-			break;
+		curoffs += curlen;
+		len -= curlen;
 	}
-	KASSERTMSG(len == 0, "xfer %p olen %d len %d mps %d ex_nsqtd %zu i %zu",
-	    xfer, length, len, mps, exfer->ex_nsqtd, i);
+	KASSERTMSG(len == 0, "xfer %p olen %d len %d mps %d ex_nsqtd %zu j %zu",
+	    xfer, length, len, mps, exfer->ex_nsqtd, j);
 
-	if (i < exfer->ex_nsqtd) {
-		/*
-		 * The full allocation chain wasn't used, so we need to
-		 * terminate it.
-		 */
+	if (!isread &&
+	    (flags & USBD_FORCE_SHORT_XFER) &&
+	    length % mps == 0) {
+		/* Force a 0 length transfer at the end. */
+
+		KASSERTMSG(j < exfer->ex_nsqtd, "j=%zu nsqtd=%zu", j,
+		    exfer->ex_nsqtd);
+		prev = sqtd;
+		sqtd = exfer->ex_sqtds[j++];
+		memset(&sqtd->qtd, 0, sizeof(sqtd->qtd));
 		sqtd->qtd.qtd_next = sqtd->qtd.qtd_altnext = EHCI_NULL;
+		sqtd->qtd.qtd_status = htole32(
+		    qtdstatus |
+		    EHCI_QTD_SET_BYTES(0) |
+		    EHCI_QTD_SET_TOGGLE(tog));
+
+		usb_syncmem(&sqtd->dma, sqtd->offs, sizeof(sqtd->qtd),
+		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+		ehci_append_sqtd(sqtd, prev);
+		tog ^= 1;
 	}
+
 	*lsqtd = sqtd;
 	*toggle = tog;
 }
@@ -3531,9 +3480,8 @@ ehci_device_ctrl_init(struct usbd_xfer *
 	next = status;
 	/* Set up data transaction */
 	if (len != 0) {
-		ehci_soft_qtd_t *end;
 		err = ehci_alloc_sqtd_chain(sc, xfer, len, isread,
-		    &exfer->ex_data, &end);
+		    &exfer->ex_data);
 		if (err)
 			goto bad3;
 		next = exfer->ex_data;
@@ -3550,7 +3498,7 @@ ehci_device_ctrl_init(struct usbd_xfer *
 	setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr);
 	setup->nextqtd = next;
 	setup->xfer = xfer;
-	setup->tdlen = setup->len = sizeof(*req);
+	setup->len = sizeof(*req);
 
 	status->qtd.qtd_status = htole32(
 	    EHCI_QTD_SET_PID(isread ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN) |
@@ -3562,7 +3510,7 @@ ehci_device_ctrl_init(struct usbd_xfer *
 	status->qtd.qtd_next = status->qtd.qtd_altnext = EHCI_NULL;
 	status->nextqtd = NULL;
 	status->xfer = xfer;
-	status->tdlen = status->len = 0;
+	status->len = 0;
 
 	return 0;
 bad3:
@@ -3848,7 +3796,7 @@ ehci_device_bulk_init(struct usbd_xfer *
 	exfer->ex_type = EX_BULK;
 	exfer->ex_nsqtd = 0;
 	err = ehci_alloc_sqtd_chain(sc, xfer, len, isread,
-	    &exfer->ex_sqtdstart, &exfer->ex_sqtdend);
+	    &exfer->ex_sqtdstart);
 
 	return err;
 }
@@ -4063,7 +4011,7 @@ ehci_device_intr_init(struct usbd_xfer *
 	exfer->ex_type = EX_INTR;
 	exfer->ex_nsqtd = 0;
 	err = ehci_alloc_sqtd_chain(sc, xfer, len, isread,
-	    &exfer->ex_sqtdstart, &exfer->ex_sqtdend);
+	    &exfer->ex_sqtdstart);
 
 	return err;
 }
@@ -4134,6 +4082,7 @@ ehci_device_intr_start(struct usbd_xfer 
 
 	/* Take lock to protect nexttoggle */
 	mutex_enter(&sc->sc_lock);
+
 	ehci_reset_sqtd_chain(sc, xfer, len, isread, &epipe->nexttoggle, &end);
 
 	end->qtd.qtd_status |= htole32(EHCI_QTD_IOC);

Index: src/sys/dev/usb/ehcivar.h
diff -u src/sys/dev/usb/ehcivar.h:1.42.14.24 src/sys/dev/usb/ehcivar.h:1.42.14.25
--- src/sys/dev/usb/ehcivar.h:1.42.14.24	Sat Mar 26 11:42:44 2016
+++ src/sys/dev/usb/ehcivar.h	Mon Apr  4 07:43:12 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ehcivar.h,v 1.42.14.24 2016/03/26 11:42:44 skrll Exp $ */
+/*	$NetBSD: ehcivar.h,v 1.42.14.25 2016/04/04 07:43:12 skrll Exp $ */
 
 /*
  * Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -41,9 +41,7 @@ typedef struct ehci_soft_qtd {
 	usb_dma_t dma;			/* qTD's DMA infos */
 	int offs;			/* qTD's offset in usb_dma_t */
 	struct usbd_xfer *xfer;		/* xfer back pointer */
-	size_t bufoff;			/* Offset into xfer buffer */
 	uint16_t len;
-	uint16_t tdlen;
 } ehci_soft_qtd_t;
 #define EHCI_SQTD_ALIGN	MAX(EHCI_QTD_ALIGN, CACHE_LINE_SIZE)
 #define EHCI_SQTD_SIZE ((sizeof(struct ehci_soft_qtd) + EHCI_SQTD_ALIGN - 1) & -EHCI_SQTD_ALIGN)

Index: src/sys/dev/usb/ohci.c
diff -u src/sys/dev/usb/ohci.c:1.254.2.69 src/sys/dev/usb/ohci.c:1.254.2.70
--- src/sys/dev/usb/ohci.c:1.254.2.69	Fri Apr  1 15:13:45 2016
+++ src/sys/dev/usb/ohci.c	Mon Apr  4 07:43:12 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ohci.c,v 1.254.2.69 2016/04/01 15:13:45 skrll Exp $	*/
+/*	$NetBSD: ohci.c,v 1.254.2.70 2016/04/04 07:43:12 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004, 2005, 2012 The NetBSD Foundation, Inc.
@@ -41,7 +41,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.69 2016/04/01 15:13:45 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.70 2016/04/04 07:43:12 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -517,105 +517,37 @@ ohci_free_std(ohci_softc_t *sc, ohci_sof
 }
 
 Static usbd_status
-ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int alen, int rd)
+ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int length, int rd)
 {
 	struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer);
-	struct usbd_pipe *pipe = xfer->ux_pipe;
-	ohci_soft_td_t *next, *cur;
-	ohci_physaddr_t dataphys, dataphysend;
-	int len = alen;
-	int curlen;
-	usb_dma_t *dma = &xfer->ux_dmabuf;
 	uint16_t flags = xfer->ux_flags;
 
 	OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
 	DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d",
-	    pipe->up_dev->ud_addr,
-	    UE_GET_ADDR(pipe->up_endpoint->ue_edesc->bEndpointAddress),
-	    alen, pipe->up_dev->ud_speed);
+	    xfer->ux_pipe->up_dev->ud_addr,
+	    UE_GET_ADDR(xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress),
+	    length, xfer->ux_pipe->up_dev->ud_speed);
 
 	ASSERT_SLEEPABLE();
+	KASSERT(length != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER)));
 
-	size_t nstd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0;
-	nstd += ((len + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE);
+	size_t nstd = (!rd && (flags & USBD_FORCE_SHORT_XFER)) ? 1 : 0;
+	nstd += ((length + OHCI_PAGE_SIZE - 1) / OHCI_PAGE_SIZE);
 	ox->ox_stds = kmem_zalloc(sizeof(ohci_soft_td_t *) * nstd,
 	    KM_SLEEP);
 	ox->ox_nstd = nstd;
-	int mps = UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize);
 
-	DPRINTFN(8, "xfer %p nstd %d mps %d", xfer, nstd, mps, 0);
+	DPRINTFN(8, "xfer %p nstd %d", xfer, nstd, 0, 0);
 
-	len = alen;
-	cur = ohci_alloc_std(sc);
-	if (cur == NULL)
-		goto nomem;
-
-	dataphys = DMAADDR(dma, 0);
-	dataphysend = OHCI_PAGE(dataphys + len - 1);
-	const uint32_t tdflags = HTOO32(
-	    (rd ? OHCI_TD_IN : OHCI_TD_OUT) |
-	    OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
-
-	for (size_t j = 0;;) {
-		ox->ox_stds[j++] = cur;
-		next = ohci_alloc_std(sc);
-		if (next == NULL)
+	for (size_t j = 0; j < ox->ox_nstd;) {
+		ohci_soft_td_t *cur = ohci_alloc_std(sc);
+		if (cur == NULL)
 			goto nomem;
 
-		/* The OHCI hardware can handle at most one page crossing. */
-		if (OHCI_PAGE(dataphys) == dataphysend ||
-		    OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) {
-			/* we can handle it in this TD */
-			curlen = len;
-		} else {
-			/* must use multiple TDs, fill as much as possible. */
-			curlen = 2 * OHCI_PAGE_SIZE -
-			    (dataphys & (OHCI_PAGE_SIZE - 1));
-			/* the length must be a multiple of the max size */
-			curlen -= curlen % mps;
-			KASSERT(curlen != 0);
-		}
-		DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x "
-		    "len=%d curlen=%d", dataphys, dataphysend, len, curlen);
-		len -= curlen;
-
-		cur->td.td_flags = tdflags;
-		cur->td.td_cbp = HTOO32(dataphys);
-		cur->td.td_nexttd = HTOO32(next->physaddr);
-		cur->td.td_be = HTOO32(dataphys + curlen - 1);
-		cur->nexttd = next;
-		cur->len = curlen;
-		cur->flags = OHCI_ADD_LEN;
+		ox->ox_stds[j++] = cur;
 		cur->xfer = xfer;
-
-		DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys,
-		    dataphys + curlen - 1, 0, 0);
-		if (len == 0)
-			break;
-		DPRINTFN(10, "extend chain", 0, 0, 0, 0);
-		dataphys += curlen;
-		cur = next;
-	}
-	if (!rd && (flags & USBD_FORCE_SHORT_XFER) &&
-	    alen % mps == 0) {
-		/* Force a 0 length transfer at the end. */
-
-		cur = next;
-		next = ohci_alloc_std(sc);
-		if (next == NULL)
-			goto nomem;
-
-		cur->td.td_flags = tdflags;
-		cur->td.td_cbp = 0; /* indicate 0 length packet */
-		cur->td.td_nexttd = HTOO32(next->physaddr);
-		cur->td.td_be = ~0;
-		cur->nexttd = next;
-		cur->len = 0;
 		cur->flags = 0;
-		cur->xfer = xfer;
-
-		DPRINTFN(2, "add 0 xfer", 0, 0, 0, 0);
 	}
 
 	return USBD_NORMAL_COMPLETION;
@@ -648,7 +580,6 @@ ohci_reset_std_chain(ohci_softc_t *sc, s
 {
 	struct ohci_xfer *ox = OHCI_XFER2OXFER(xfer);
 	ohci_soft_td_t *next, *cur;
-	ohci_physaddr_t dataphys, dataphysend;
 	int len, curlen;
 	usb_dma_t *dma = &xfer->ux_dmabuf;
 	uint16_t flags = xfer->ux_flags;
@@ -667,44 +598,52 @@ ohci_reset_std_chain(ohci_softc_t *sc, s
 
 	int mps = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
 
+	/*
+	 * Assign next for the len == 0 case where we don't go through the
+	 * main loop.
+	 */
 	len = alen;
-	cur = sp;
+	cur = next = sp;
 
-	dataphys = DMAADDR(dma, 0);
-	dataphysend = OHCI_PAGE(dataphys + len - 1);
 	usb_syncmem(dma, 0, len,
 	    rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
 	const uint32_t tdflags = HTOO32(
 	    (rd ? OHCI_TD_IN : OHCI_TD_OUT) |
 	    OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
 
-	for (size_t j = 1;;) {
+	size_t curoffs = 0;
+	for (size_t j = 1; len != 0;) {
 		if (j == ox->ox_nstd)
 			next = NULL;
 		else
 			next = ox->ox_stds[j++];
 		KASSERT(next != cur);
 
-		/* The OHCI hardware can handle at most one page crossing. */
-		if (OHCI_PAGE(dataphys) == dataphysend ||
-		    OHCI_PAGE(dataphys) + OHCI_PAGE_SIZE == dataphysend) {
-			/* we can handle it in this TD */
-			curlen = len;
-		} else {
+		curlen = 0;
+		ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs);
+		ohci_physaddr_t edataphys = DMAADDR(dma, curoffs + len - 1);
+
+		ohci_physaddr_t sphyspg = OHCI_PAGE(sdataphys);
+		ohci_physaddr_t ephyspg = OHCI_PAGE(edataphys);
+		/*
+		 * The OHCI hardware can handle at most one page
+		 * crossing per TD
+		 */
+		curlen = len;
+		if (!(sphyspg == ephyspg || sphyspg + 1 == ephyspg)) {
 			/* must use multiple TDs, fill as much as possible. */
 			curlen = 2 * OHCI_PAGE_SIZE -
-			    (dataphys & (OHCI_PAGE_SIZE - 1));
+			    (sdataphys & (OHCI_PAGE_SIZE - 1));
 			/* the length must be a multiple of the max size */
 			curlen -= curlen % mps;
-			KASSERT(curlen != 0);
 		}
-		DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x "
-		    "len=%d curlen=%d", dataphys, dataphysend, len, curlen);
-		len -= curlen;
+		KASSERT(curlen != 0);
+		DPRINTFN(4, "sdataphys=0x%08x edataphys=0x%08x "
+		    "len=%d curlen=%d", sdataphys, edataphys, len, curlen);
 
 		cur->td.td_flags = tdflags;
-		cur->td.td_cbp = HTOO32(dataphys);
-		cur->td.td_be = HTOO32(dataphys + curlen - 1);
+		cur->td.td_cbp = HTOO32(sdataphys);
+		cur->td.td_be = HTOO32(edataphys);
 		cur->td.td_nexttd = (next != NULL) ? HTOO32(next->physaddr) : 0;
 		cur->nexttd = next;
 		cur->len = curlen;
@@ -714,14 +653,15 @@ ohci_reset_std_chain(ohci_softc_t *sc, s
 
 		usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td),
 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
-		DPRINTFN(10, "cbp=0x%08x be=0x%08x", dataphys,
-		    dataphys + curlen - 1, 0, 0);
-		if (len == 0)
-			break;
-		KASSERT(next != NULL);
-		DPRINTFN(10, "extend chain", 0, 0, 0, 0);
-		dataphys += curlen;
-		cur = next;
+
+		curoffs += curlen;
+		len -= curlen;
+
+		if (len != 0) {
+			KASSERT(next != NULL);
+			DPRINTFN(10, "extend chain", 0, 0, 0, 0);
+			cur = next;
+		}
 	}
 	cur->td.td_flags |=
 	    (xfer->ux_flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0);
@@ -736,7 +676,7 @@ ohci_reset_std_chain(ohci_softc_t *sc, s
 
 		cur->td.td_flags = tdflags;
 		cur->td.td_cbp = 0; /* indicate 0 length packet */
-		cur->td.td_nexttd = HTOO32(next->physaddr);
+		cur->td.td_nexttd = 0;
 		cur->td.td_be = ~0;
 		cur->nexttd = NULL;
 		cur->len = 0;

Index: src/sys/dev/usb/uhci.c
diff -u src/sys/dev/usb/uhci.c:1.264.4.69 src/sys/dev/usb/uhci.c:1.264.4.70
--- src/sys/dev/usb/uhci.c:1.264.4.69	Fri Mar 25 17:44:00 2016
+++ src/sys/dev/usb/uhci.c	Mon Apr  4 07:43:12 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: uhci.c,v 1.264.4.69 2016/03/25 17:44:00 skrll Exp $	*/
+/*	$NetBSD: uhci.c,v 1.264.4.70 2016/04/04 07:43:12 skrll Exp $	*/
 
 /*
  * Copyright (c) 1998, 2004, 2011, 2012 The NetBSD Foundation, Inc.
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.69 2016/03/25 17:44:00 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uhci.c,v 1.264.4.70 2016/04/04 07:43:12 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -179,7 +179,7 @@ Static void		uhci_exit_ctl_q(uhci_softc_
 Static void		uhci_free_std_chain(uhci_softc_t *, uhci_soft_td_t *,
 			    uhci_soft_td_t *);
 Static usbd_status	uhci_alloc_std_chain(uhci_softc_t *, struct usbd_xfer *,
-			    int, int, uhci_soft_td_t **, uhci_soft_td_t **);
+			    int, int, uhci_soft_td_t **);
 Static void		uhci_free_stds(uhci_softc_t *, struct uhci_xfer *);
 
 Static void		uhci_reset_std_chain(uhci_softc_t *, struct usbd_xfer *,
@@ -2011,95 +2011,53 @@ uhci_free_std_chain(uhci_softc_t *sc, uh
 }
 
 usbd_status
-uhci_alloc_std_chain(uhci_softc_t *sc, struct usbd_xfer *xfer, int alen,
-    int rd, uhci_soft_td_t **sp, uhci_soft_td_t **ep)
+uhci_alloc_std_chain(uhci_softc_t *sc, struct usbd_xfer *xfer, int len,
+    int rd, uhci_soft_td_t **sp)
 {
-	uhci_soft_td_t *p, *lastp;
-	uhci_physaddr_t lastlink;
-	int i, l, maxp;
-	int len;
-	uint32_t status;
 	struct uhci_xfer *uxfer = UHCI_XFER2UXFER(xfer);
-	int addr = xfer->ux_pipe->up_dev->ud_addr;
-	int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
-	usb_dma_t *dma = &xfer->ux_dmabuf;
 	uint16_t flags = xfer->ux_flags;
+	uhci_soft_td_t *p;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
 
 	DPRINTFN(8, "xfer=%p pipe=%p", xfer, xfer->ux_pipe, 0, 0);
-	DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d",
-	    addr, UE_GET_ADDR(endpt), alen, xfer->ux_pipe->up_dev->ud_speed);
 
 	ASSERT_SLEEPABLE();
 	KASSERT(sp);
 
-	len = alen;
-	maxp = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
+	int maxp = UGETW(xfer->ux_pipe->up_endpoint->ue_edesc->wMaxPacketSize);
 	if (maxp == 0) {
 		printf("%s: maxp=0\n", __func__);
 		return USBD_INVAL;
 	}
 	size_t ntd = (len + maxp - 1) / maxp;
-	if ((flags & USBD_FORCE_SHORT_XFER) && len % maxp == 0)
+	if (!rd && (flags & USBD_FORCE_SHORT_XFER)) {
 		ntd++;
+	}
 	DPRINTFN(10, "maxp=%d ntd=%d", maxp, ntd, 0, 0);
 
 	uxfer->ux_stds = NULL;
 	uxfer->ux_nstd = ntd;
+	p = NULL;
 	if (ntd == 0) {
 		*sp = NULL;
-		if (ep)
-			*ep = NULL;
 		DPRINTF("ntd=0", 0, 0, 0, 0);
 		return USBD_NORMAL_COMPLETION;
 	}
 	uxfer->ux_stds = kmem_alloc(sizeof(uhci_soft_td_t *) * ntd,
 	    KM_SLEEP);
 
-	lastp = NULL;
 	ntd--;
-	status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
-	if (xfer->ux_pipe->up_dev->ud_speed == USB_SPEED_LOW)
-		status |= UHCI_TD_LS;
-	if (flags & USBD_SHORT_XFER_OK)
-		status |= UHCI_TD_SPD;
-	for (i = ntd; i >= 0; i--) {
+	for (int i = ntd; i >= 0; i--) {
 		p = uhci_alloc_std(sc);
 		if (p == NULL) {
-			uhci_free_std_chain(sc, lastp, NULL);
+			uhci_free_stds(sc, uxfer);
 			return USBD_NOMEM;
 		}
 		uxfer->ux_stds[i] = p;
-		if (i == ntd) {
-			/* last TD */
-			l = len % maxp;
-			if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER))
-				l = maxp;
-			if (ep)
-				*ep = p;
-			lastlink = UHCI_PTR_T;
-		} else {
-			l = maxp;
-			lastlink = p->physaddr;
-		}
-		p->link.std = lastp;
-		p->td.td_link = htole32(lastlink | UHCI_PTR_VF | UHCI_PTR_TD);
-		p->td.td_status = htole32(status);
-		p->td.td_token = htole32(
-		    (rd ? UHCI_TD_PID_IN : UHCI_TD_PID_OUT) |
-		    UHCI_TD_SET_MAXLEN(l) |
-		    UHCI_TD_SET_ENDPT(UE_GET_ADDR(endpt)) |
-		    UHCI_TD_SET_DEVADDR(addr)
-		    );
-		p->td.td_buffer = htole32(DMAADDR(dma, i * maxp));
-		DPRINTF("std %p link 0x%08x status 0x%08x token 0x%08x",
-		    p, le32toh(p->td.td_link), le32toh(p->td.td_status),
-		    le32toh(p->td.td_token));
-
-		lastp = p;
 	}
-	*sp = lastp;
+
+	*sp = uxfer->ux_stds[0];
 
 	return USBD_NORMAL_COMPLETION;
 }
@@ -2147,11 +2105,14 @@ uhci_reset_std_chain(uhci_softc_t *sc, s
 	DPRINTFN(8, "xfer=%p len %d isread %d toggle %d", xfer,
 	    len, isread, *toggle);
 
-	KASSERT(len != 0 || (flags & USBD_FORCE_SHORT_XFER));
+	KASSERT(len != 0 || (!isread && (flags & USBD_FORCE_SHORT_XFER)));
 
 	maxp = UGETW(pipe->up_endpoint->ue_edesc->wMaxPacketSize);
 	KASSERT(maxp != 0);
 
+	int addr = xfer->ux_pipe->up_dev->ud_addr;
+	int endpt = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
+
 	status = UHCI_TD_ZERO_ACTLEN(UHCI_TD_SET_ERRCNT(3) | UHCI_TD_ACTIVE);
 	if (pipe->up_dev->ud_speed == USB_SPEED_LOW)
 		status |= UHCI_TD_LS;
@@ -2159,15 +2120,12 @@ uhci_reset_std_chain(uhci_softc_t *sc, s
 		status |= UHCI_TD_SPD;
 	usb_syncmem(dma, 0, len,
 	    isread ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
-
 	std = prev = NULL;
-	for (i = 0; i < uxfer->ux_nstd; i++, prev = std) {
+	for (i = 0; len != 0 && i < uxfer->ux_nstd; i++, prev = std) {
 		int l = len;
 		std = uxfer->ux_stds[i];
 		if (l > maxp)
 			l = maxp;
-		if (l == 0 && !(flags & USBD_FORCE_SHORT_XFER))
-			break;
 
 		if (prev) {
 			prev->link.std = std;
@@ -2178,53 +2136,62 @@ uhci_reset_std_chain(uhci_softc_t *sc, s
 			    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 		}
 
-		int addr __diagused = xfer->ux_pipe->up_dev->ud_addr;
-		int endpt __diagused = xfer->ux_pipe->up_endpoint->ue_edesc->bEndpointAddress;
-		KASSERTMSG(UHCI_TD_GET_ENDPT(le32toh(std->td.td_token)) == UE_GET_ADDR(endpt),
-		   "%" __PRIuBIT " vs %d (0x%08x) in %p",
-		   UHCI_TD_GET_ENDPT(le32toh(std->td.td_token)),
-		   UE_GET_ADDR(endpt), le32toh(std->td.td_token), std);
-		KASSERTMSG(UHCI_TD_GET_DEVADDR(le32toh(std->td.td_token)) == addr,
-		    "%" __PRIuBIT " vs %d (0x%08x) in %p",
-		    UHCI_TD_GET_DEVADDR(le32toh(std->td.td_token)), addr,
-		    le32toh(std->td.td_token), std);
-
 		usb_syncmem(&std->dma, std->offs, sizeof(std->td),
 		    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
 
+		std->td.td_link = htole32(UHCI_PTR_T | UHCI_PTR_VF | UHCI_PTR_TD);
 		std->td.td_status = htole32(status);
-		std->td.td_token &= ~htole32(
-		    UHCI_TD_PID_MASK |
-		    UHCI_TD_DT_MASK |
-		    UHCI_TD_MAXLEN_MASK
-		    );
-		std->td.td_token |= htole32(
+		std->td.td_token = htole32(
+		    UHCI_TD_SET_ENDPT(UE_GET_ADDR(endpt)) |
+		    UHCI_TD_SET_DEVADDR(addr) |
 		    UHCI_TD_SET_PID(isread ? UHCI_TD_PID_IN : UHCI_TD_PID_OUT) |
 		    UHCI_TD_SET_DT(tog) |
 		    UHCI_TD_SET_MAXLEN(l)
 		    );
-		std->td.td_link &= ~htole32(UHCI_PTR_T);
+		std->td.td_buffer = htole32(DMAADDR(dma, i * maxp));
+
+		std->link.std = NULL;
 
 		usb_syncmem(&std->dma, std->offs, sizeof(std->td),
 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 		tog ^= 1;
 
 		len -= l;
-		if (len == 0)
-			break;
 	}
 	KASSERTMSG(len == 0, "xfer %p alen %d len %d mps %d ux_nqtd %zu i %zu",
 	    xfer, length, len, maxp, uxfer->ux_nstd, i);
 
-	if (i < uxfer->ux_nstd) {
-		/*
-		 * The full allocation chain wasn't used, so we need to
-		 * terminate it.
-		 */
-		std->link.std = NULL;
-		std->td.td_link = htole32(UHCI_PTR_T);
+	if (!isread &&
+	    (flags & USBD_FORCE_SHORT_XFER) &&
+	    length % maxp == 0) {
+		/* Force a 0 length transfer at the end. */
+		KASSERTMSG(i < uxfer->ux_nstd, "i=%zu nstd=%zu", i,
+		    uxfer->ux_nstd);
+		std = uxfer->ux_stds[i++];
+
+		std->td.td_link = htole32(UHCI_PTR_T | UHCI_PTR_VF | UHCI_PTR_TD);
+		std->td.td_status = htole32(status);
+		std->td.td_token = htole32(
+		    UHCI_TD_SET_ENDPT(UE_GET_ADDR(endpt)) |
+		    UHCI_TD_SET_DEVADDR(addr) |
+		    UHCI_TD_SET_PID(UHCI_TD_PID_OUT) |
+		    UHCI_TD_SET_DT(tog) |
+		    UHCI_TD_SET_MAXLEN(0)
+		    );
+		std->td.td_buffer = 0;
 		usb_syncmem(&std->dma, std->offs, sizeof(std->td),
 		    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+
+		std->link.std = NULL;
+		if (prev) {
+			prev->link.std = std;
+			prev->td.td_link = htole32(
+			    std->physaddr | UHCI_PTR_VF | UHCI_PTR_TD
+			    );
+			usb_syncmem(&prev->dma, prev->offs, sizeof(prev->td),
+			    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
+		}
+		tog ^= 1;
 	}
 	*lstd = std;
 	*toggle = tog;
@@ -2263,8 +2230,7 @@ uhci_device_bulk_init(struct usbd_xfer *
 	KASSERT(!(xfer->ux_rqflags & URQ_REQUEST));
 
 	uxfer->ux_type = UX_BULK;
-	err = uhci_alloc_std_chain(sc, xfer, len, isread, &uxfer->ux_stdstart,
-	    &uxfer->ux_stdend);
+	err = uhci_alloc_std_chain(sc, xfer, len, isread, &uxfer->ux_stdstart);
 	if (err)
 		return err;
 
@@ -2525,68 +2491,30 @@ uhci_device_ctrl_init(struct usbd_xfer *
 	usb_device_request_t *req = &xfer->ux_request;
 	struct usbd_device *dev = upipe->pipe.up_dev;
 	uhci_softc_t *sc = dev->ud_bus->ub_hcpriv;
-	int addr = dev->ud_addr;
 	int endpt = upipe->pipe.up_endpoint->ue_edesc->bEndpointAddress;
-	uhci_soft_td_t *setup, *data, *stat, *next, *dataend;
+	uhci_soft_td_t *data;
 	int len;
-	uint32_t ls;
 	usbd_status err;
 	int isread;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
-	DPRINTFN(3, "len=%d, addr=%d, endpt=%d", xfer->ux_bufsize,
-	    dev->ud_addr, endpt, 0);
+	DPRINTFN(3, "xfer=%p len=%d, addr=%d, endpt=%d", xfer, xfer->ux_bufsize,
+	    dev->ud_addr, endpt);
 
-	ls = dev->ud_speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
 	isread = req->bmRequestType & UT_READ;
 	len = xfer->ux_bufsize;
 
 	uxfer->ux_type = UX_CTRL;
-	setup = upipe->ctrl.setup;
-	stat = upipe->ctrl.stat;
-
 	/* Set up data transaction */
 	if (len != 0) {
-		err = uhci_alloc_std_chain(sc, xfer, len, isread, &data,
-		    &dataend);
+		err = uhci_alloc_std_chain(sc, xfer, len, isread, &data);
 		if (err)
 			return err;
-		next = data;
-		dataend->link.std = stat;
-		dataend->td.td_link = htole32(stat->physaddr | UHCI_PTR_TD);
-	} else {
-		next = stat;
-	}
-
-	setup->link.std = next;
-	setup->td.td_link = htole32(next->physaddr | UHCI_PTR_TD);
-	setup->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
-		UHCI_TD_ACTIVE);
-	setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof(*req), endpt, addr));
-	setup->td.td_buffer = htole32(DMAADDR(&upipe->ctrl.reqdma, 0));
-
-	stat->link.std = NULL;
-	stat->td.td_link = htole32(UHCI_PTR_T);
-	stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
-		UHCI_TD_ACTIVE | UHCI_TD_IOC);
-	stat->td.td_token =
-		htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
-				 UHCI_TD_IN (0, endpt, addr, 1));
-	stat->td.td_buffer = htole32(0);
-
-	DPRINTFN(10, "--- dump start ---", 0, 0, 0, 0);
-#ifdef UHCI_DEBUG
-	if (uhcidebug >= 10) {
-		DPRINTFN(10, "before transfer", 0, 0, 0, 0);
-		uhci_dump_tds(setup);
 	}
-#endif
-	DPRINTFN(10, "--- dump end ---", 0, 0, 0, 0);
-
 	/* Set up interrupt info. */
-	uxfer->ux_setup = setup;
+	uxfer->ux_setup = upipe->ctrl.setup;
+	uxfer->ux_stat = upipe->ctrl.stat;
 	uxfer->ux_data = data;
-	uxfer->ux_stat = stat;
 
 	return 0;
 }
@@ -2637,7 +2565,6 @@ uhci_device_ctrl_start(struct usbd_xfer 
 	uhci_soft_td_t *setup, *stat, *next, *dataend;
 	uhci_soft_qh_t *sqh;
 	int len;
-	uint32_t ls;
 	int isread;
 
 	UHCIHIST_FUNC(); UHCIHIST_CALLED();
@@ -2654,7 +2581,6 @@ uhci_device_ctrl_start(struct usbd_xfer 
 	DPRINTFN(3, "len=%d, addr=%d, endpt=%d",
 	    UGETW(req->wLength), dev->ud_addr, endpt, 0);
 
-	ls = dev->ud_speed == USB_SPEED_LOW ? UHCI_TD_LS : 0;
 	isread = req->bmRequestType & UT_READ;
 	len = UGETW(req->wLength);
 
@@ -2683,22 +2609,23 @@ uhci_device_ctrl_start(struct usbd_xfer 
 		next = stat;
 	}
 
-	setup->link.std = next;
-	setup->td.td_link = htole32(next->physaddr | UHCI_PTR_TD);
-	setup->td.td_status |= htole32(
+	const uint32_t status = UHCI_TD_ZERO_ACTLEN(
 	    UHCI_TD_SET_ERRCNT(3) |
-	    ls |
-	    UHCI_TD_ACTIVE
+	    UHCI_TD_ACTIVE |
+	    (dev->ud_speed == USB_SPEED_LOW ? UHCI_TD_LS : 0)
 	    );
-	setup->td.td_token &= ~htole32(UHCI_TD_MAXLEN_MASK);
-	setup->td.td_token |= htole32(UHCI_TD_SET_MAXLEN(sizeof(*req)));
+	setup->link.std = next;
+	setup->td.td_link = htole32(next->physaddr | UHCI_PTR_TD);
+	setup->td.td_status = htole32(status);
+	setup->td.td_token = htole32(UHCI_TD_SETUP(sizeof(*req), endpt, addr));
+	setup->td.td_buffer = htole32(DMAADDR(&upipe->ctrl.reqdma, 0));
+
 	usb_syncmem(&setup->dma, setup->offs, sizeof(setup->td),
 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
 	stat->link.std = NULL;
 	stat->td.td_link = htole32(UHCI_PTR_T);
-	stat->td.td_status = htole32(UHCI_TD_SET_ERRCNT(3) | ls |
-		UHCI_TD_ACTIVE | UHCI_TD_IOC);
+	stat->td.td_status = htole32(status | UHCI_TD_IOC);
 	stat->td.td_token =
 		htole32(isread ? UHCI_TD_OUT(0, endpt, addr, 1) :
 				 UHCI_TD_IN (0, endpt, addr, 1));
@@ -2795,8 +2722,7 @@ uhci_device_intr_init(struct usbd_xfer *
 
 	ux->ux_type = UX_INTR;
 	ux->ux_nstd = 0;
-	err = uhci_alloc_std_chain(sc, xfer, len, isread,
-	    &ux->ux_stdstart, &ux->ux_stdend);
+	err = uhci_alloc_std_chain(sc, xfer, len, isread, &ux->ux_stdstart);
 
 	return err;
 }

Reply via email to