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;
}