Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/nick-nhusb]: src/sys/dev/usb Rework {alloc, reset}_*_chain functions to p...



details:   https://anonhg.NetBSD.org/src/rev/64530b9faa26
branches:  nick-nhusb
changeset: 334469:64530b9faa26
user:      skrll <skrll%NetBSD.org@localhost>
date:      Mon Apr 04 07:43:12 2016 +0000

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

diffstat:

 sys/dev/usb/ehci.c    |  307 ++++++++++++++++++++-----------------------------
 sys/dev/usb/ehcivar.h |    4 +-
 sys/dev/usb/ohci.c    |  166 ++++++++------------------
 sys/dev/usb/uhci.c    |  222 ++++++++++++------------------------
 4 files changed, 256 insertions(+), 443 deletions(-)

diffs (truncated from 1102 to 300 lines):

diff -r 142e6c6c391e -r 64530b9faa26 sys/dev/usb/ehci.c
--- a/sys/dev/usb/ehci.c        Sun Apr 03 08:08:27 2016 +0000
+++ b/sys/dev/usb/ehci.c        Mon Apr 04 07:43:12 2016 +0000
@@ -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 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 @@
 
 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)
-           ;
-
-       size_t nsqtd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0;
-       nsqtd += ((len + EHCI_QTD_MAXTRANSFER - 1) / EHCI_QTD_MAXTRANSFER);
+       KASSERT(alen != 0 || (!rd && (flags & USBD_FORCE_SHORT_XFER)));
+
+       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);
+       DPRINTF("xfer %p len %d nsqtd %d flags %x", xfer, alen, nsqtd, flags);
+
+       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;
 
-               /* 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;
-
-                       /* 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);
-               }
-
-               /* 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 @@
 }
 
 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);
-
-               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) |
+               KASSERT(curlen != 0);
+               DPRINTF("    len=%d curlen=%d curoffs=%zu", len, curlen,
+                   curoffs, 0);
+
+               /* 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),
+               /* 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++) {



Home | Main Index | Thread Index | Old Index