Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/usb Be more careful with OHCI_PAGE limitations in oh...



details:   https://anonhg.NetBSD.org/src/rev/d974c67b5891
branches:  trunk
changeset: 933301:d974c67b5891
user:      skrll <skrll%NetBSD.org@localhost>
date:      Sun May 24 07:42:51 2020 +0000

description:
Be more careful with OHCI_PAGE limitations in ohci_reset_std_chain and
ohci_device_isoc_enter

Enable USBMALLOC_MULTISEG

diffstat:

 sys/dev/usb/ohci.c |  86 +++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 59 insertions(+), 27 deletions(-)

diffs (163 lines):

diff -r ed9086426ab9 -r d974c67b5891 sys/dev/usb/ohci.c
--- a/sys/dev/usb/ohci.c        Sun May 24 07:17:34 2020 +0000
+++ b/sys/dev/usb/ohci.c        Sun May 24 07:42:51 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ohci.c,v 1.307 2020/05/19 19:09:43 jakllsch Exp $      */
+/*     $NetBSD: ohci.c,v 1.308 2020/05/24 07:42:51 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.307 2020/05/19 19:09:43 jakllsch Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.308 2020/05/24 07:42:51 skrll Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_usb.h"
@@ -618,26 +618,28 @@
                        next = ox->ox_stds[j++];
                KASSERT(next != cur);
 
-               curlen = 0;
-               const ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs);
-               ohci_physaddr_t edataphys = DMAADDR(dma, curoffs + len - 1);
-
-               const ohci_physaddr_t sphyspg = OHCI_PAGE(sdataphys);
-               ohci_physaddr_t ephyspg = OHCI_PAGE(edataphys);
+               curlen = len;
                /*
-                * The OHCI hardware can handle at most one page
-                * crossing per TD
+                * The OHCI hardware can handle at most one page crossing per
+                * TD.  That is, 2 * OHCI_PAGE_SIZE as a maximum.  Limit the
+                * length in this TD accordingly.
                 */
-               curlen = len;
-               if (sphyspg != ephyspg &&
-                   sphyspg + OHCI_PAGE_SIZE != ephyspg) {
-                       /* must use multiple TDs, fill as much as possible. */
-                       curlen = 2 * OHCI_PAGE_SIZE -
-                           OHCI_PAGE_OFFSET(sdataphys);
-                       /* the length must be a multiple of the max size */
+               const ohci_physaddr_t sdataphys = DMAADDR(dma, curoffs);
+
+               int maxlen = (2 * OHCI_PAGE_SIZE) - OHCI_PAGE_OFFSET(sdataphys);
+               if (curlen > maxlen) {
+                       curlen = maxlen;
+
+                       /*
+                        * the length must be a multiple of
+                        * the max size
+                        */
                        curlen -= curlen % mps;
-                       edataphys = DMAADDR(dma, curoffs + curlen - 1);
                }
+
+               const int edataoffs = curoffs + curlen - 1;
+               const ohci_physaddr_t edataphys = DMAADDR(dma, edataoffs);
+
                KASSERT(curlen != 0);
                DPRINTFN(4, "sdataphys=0x%08jx edataphys=0x%08jx "
                    "len=%jd curlen=%jd", sdataphys, edataphys, len, curlen);
@@ -811,6 +813,7 @@
        }
        sc->sc_bus.ub_revision = USBREV_1_0;
        sc->sc_bus.ub_usedma = true;
+       sc->sc_bus.ub_dmaflags = USBMALLOC_MULTISEG;
 
        /* XXX determine alignment by R/W */
        /* Allocate the HCCA area. */
@@ -3447,8 +3450,9 @@
        ohci_softc_t *sc = OHCI_XFER2SC(xfer);
        ohci_soft_ed_t *sed = opipe->sed;
        ohci_soft_itd_t *sitd, *nsitd, *tail;
-       ohci_physaddr_t buf, offs, noffs, bp0;
+       ohci_physaddr_t buf, offs, bp0, bp1;
        int i, ncur, nframes;
+       size_t boff, frlen;
 
        OHCIHIST_FUNC(); OHCIHIST_CALLED();
        DPRINTFN(5, "xfer=%#jx", (uintptr_t)xfer, 0, 0, 0);
@@ -3486,17 +3490,44 @@
        opipe->tail.itd = ox->ox_sitds[0];
        ox->ox_sitds[0] = sitd;
 
+       boff = 0;
        buf = DMAADDR(&xfer->ux_dmabuf, 0);
-       bp0 = OHCI_PAGE(buf);
+       bp0 = bp1 = OHCI_PAGE(buf);
        offs = OHCI_PAGE_OFFSET(buf);
+
+       ohci_physaddr_t end = bp0;      /* XXX stupid GCC */
+
        nframes = xfer->ux_nframes;
        xfer->ux_hcpriv = sitd;
        size_t j = 1;
        for (i = ncur = 0; i < nframes; i++, ncur++) {
-               noffs = offs + xfer->ux_frlengths[i];
-               if (ncur == OHCI_ITD_NOFFSET || /* all offsets used */
-                   OHCI_PAGE(buf + noffs) > bp0 + OHCI_PAGE_SIZE) { /* too many page crossings */
-
+               frlen = xfer->ux_frlengths[i];
+
+               DPRINTFN(1, "frame=%jd ux_frlengths[%jd]=%jd", i, i,
+                   xfer->ux_frlengths[i], 0);
+               /*
+                * XXXNH: The loop assumes this is never true, because
+                * incrementing 'i' assumes all the ux_frlengths[i] is covered.
+                */
+               if (frlen > 2 * OHCI_PAGE_SIZE - offs)
+                       frlen = 2 * OHCI_PAGE_SIZE - offs;
+
+               boff += frlen;
+               buf = DMAADDR(&xfer->ux_dmabuf, boff);
+               ohci_physaddr_t noffs = OHCI_PAGE_OFFSET(buf);
+
+               ohci_physaddr_t nend = DMAADDR(&xfer->ux_dmabuf, boff - 1);
+               const ohci_physaddr_t nep = OHCI_PAGE(nend);
+
+               /* Note the first page crossing in bp1 */
+               if (bp0 == bp1 && bp1 != nep)
+                       bp1 = nep;
+
+               DPRINTFN(1, "ncur=%jd bp0=%#jx bp1=%#jx nend=%#jx",
+                   ncur, bp0, bp1, nend);
+
+               /* all offsets used or too many page crossings */
+               if (ncur == OHCI_ITD_NOFFSET || (bp0 != bp1 && bp1 != nep)) {
                        /* Allocate next ITD */
                        nsitd = ox->ox_sitds[j++];
                        KASSERT(nsitd != NULL);
@@ -3510,7 +3541,7 @@
                                OHCI_ITD_SET_FC(ncur));
                        sitd->itd.itd_bp0 = HTOO32(bp0);
                        sitd->itd.itd_nextitd = HTOO32(nsitd->physaddr);
-                       sitd->itd.itd_be = HTOO32(bp0 + offs - 1);
+                       sitd->itd.itd_be = HTOO32(end);
                        sitd->nextitd = nsitd;
                        sitd->xfer = xfer;
                        sitd->flags = 0;
@@ -3523,10 +3554,11 @@
 
                        sitd = nsitd;
                        isoc->next = isoc->next + ncur;
-                       bp0 = OHCI_PAGE(buf + offs);
+                       bp0 = bp1 = OHCI_PAGE(buf);
                        ncur = 0;
                }
                sitd->itd.itd_offset[ncur] = HTOO16(OHCI_ITD_MK_OFFS(offs));
+               end = nend;
                offs = noffs;
        }
        KASSERT(j <= ox->ox_nsitd);
@@ -3547,7 +3579,7 @@
                OHCI_ITD_SET_FC(ncur));
        sitd->itd.itd_bp0 = HTOO32(bp0);
        sitd->itd.itd_nextitd = HTOO32(tail->physaddr);
-       sitd->itd.itd_be = HTOO32(bp0 + offs - 1);
+       sitd->itd.itd_be = HTOO32(end);
        sitd->nextitd = tail;
        sitd->xfer = xfer;
        sitd->flags = OHCI_CALL_DONE;



Home | Main Index | Thread Index | Old Index