tech-kern archive

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

Re: bus_dmamap_sync() for uhci(4)



On Fri, Jun 06, 2008 at 09:41:08PM +0200, Manuel Bouyer wrote:
> Hi,
> the attached patch adds bus_dmamap_sync() calls to uhci. I tested
> this on a sparc64 with a via ehci and a umodem device.
> Note that this combination works on sparc64 without the bus_dmamap_sync()
> calls because all memory used for DMA is from bus_dmamem_alloc().
> But bus_dmamap_sync() on this platform is not a nop, and has some
> DIAGNOSTIC checks, so it shows the calls I added are not completely
> brocken. Unfortunably I don't have a device to test the iso
> transfers.
> I'll also look at adding such calls to ehci.

Here is the patch for ehci. Also tested on sparc64, with a umass device.

-- 
Manuel Bouyer <bouyer%antioche.eu.org@localhost>
     NetBSD: 26 ans d'experience feront toujours la difference
--
Index: ehci.c
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehci.c,v
retrieving revision 1.136
diff -u -r1.136 ehci.c
--- ehci.c      21 May 2008 17:19:44 -0000      1.136
+++ ehci.c      8 Jun 2008 19:13:47 -0000
@@ -437,6 +437,8 @@
                sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
                sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
                sqh->sqtd = NULL;
+               usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        }
        /* Point the frame list at the last level (128ms). */
        for (i = 0; i < sc->sc_flsize; i++) {
@@ -448,6 +450,8 @@
                    sc->sc_islots[EHCI_IQHIDX(EHCI_IPOLLRATES - 1,
                    i)].sqh->physaddr);
        }
+       usb_syncmem(&sc->sc_fldma, 0, sc->sc_flsize * sizeof(ehci_link_t),
+           BUS_DMASYNC_PREWRITE);
 
        /* Allocate dummy QH that starts the async list. */
        sqh = ehci_alloc_sqh(sc);
@@ -467,6 +471,8 @@
        sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
        sqh->qh.qh_qtd.qtd_status = htole32(EHCI_QTD_HALTED);
        sqh->sqtd = NULL;
+       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 #ifdef EHCI_DEBUG
        if (ehcidebug) {
                ehci_dump_sqh(sqh);
@@ -699,9 +705,17 @@
         * is a an error somewhere in the middle, or whether there was a
         * short packet (SPD and not ACTIVE).
         */
+       usb_syncmem(&lsqtd->dma,
+           lsqtd->offs + offsetof(ehci_qtd_t, qtd_status),
+           sizeof(lsqtd->qtd.qtd_status),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        if (le32toh(lsqtd->qtd.qtd_status) & EHCI_QTD_ACTIVE) {
                DPRINTFN(12, ("ehci_check_intr: active ex=%p\n", ex));
                for (sqtd = ex->sqtdstart; sqtd != lsqtd; sqtd=sqtd->nextqtd) {
+                       usb_syncmem(&sqtd->dma,
+                           sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
+                           sizeof(sqtd->qtd.qtd_status),
+                           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
                        status = le32toh(sqtd->qtd.qtd_status);
                        /* If there's an active QTD the xfer isn't done. */
                        if (status & EHCI_QTD_ACTIVE)
@@ -767,6 +781,9 @@
        lsqtd = ex->sqtdend;
        actlen = 0;
        for (sqtd = ex->sqtdstart; sqtd != lsqtd->nextqtd; sqtd=sqtd->nextqtd) {
+               usb_syncmem(&sqtd->dma, sqtd->offs, 
+                   sizeof(sqtd->qtd),
+                   BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
                nstatus = le32toh(sqtd->qtd.qtd_status);
                if (nstatus & EHCI_QTD_ACTIVE)
                        break;
@@ -1232,6 +1249,7 @@
        stop = 0;
        for (i = 0; sqtd && i < 20 && !stop; sqtd = sqtd->nextqtd, i++) {
                ehci_dump_sqtd(sqtd);
+               /* usb_syncmem done by ehci_dump_sqtd() */
                stop = sqtd->qtd.qtd_next & htole32(EHCI_LINK_TERMINATE);
        }
        if (sqtd)
@@ -1241,6 +1259,9 @@
 void
 ehci_dump_sqtd(ehci_soft_qtd_t *sqtd)
 {
+       usb_syncmem(&sqtd->dma, sqtd->offs, 
+           sizeof(sqtd->qtd),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        printf("QTD(%p) at 0x%08x:\n", sqtd, sqtd->physaddr);
        ehci_dump_qtd(&sqtd->qtd);
 }
@@ -1273,6 +1294,9 @@
        ehci_qh_t *qh = &sqh->qh;
        u_int32_t endp, endphub;
 
+       usb_syncmem(&sqh->dma, sqh->offs, 
+           sizeof(sqh->qh),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        printf("QH(%p) at 0x%08x:\n", sqh, sqh->physaddr);
        printf("  link="); ehci_dump_link(qh->qh_link, 1); printf("\n");
        endp = le32toh(qh->qh_endp);
@@ -1393,6 +1417,9 @@
        sqh->qh.qh_qtd.qtd_altnext = EHCI_NULL;
        sqh->qh.qh_qtd.qtd_status = htole32(0);
 
+       usb_syncmem(&sqh->dma, sqh->offs, 
+           sizeof(sqh->qh),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        epipe->sqh = sqh;
 
        switch (xfertype) {
@@ -1459,10 +1486,19 @@
 {
        SPLUSBCHECK;
 
+       usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link),
+           sizeof(head->qh.qh_link),
+           BUS_DMASYNC_POSTWRITE);
        sqh->next = head->next;
        sqh->qh.qh_link = head->qh.qh_link;
+       usb_syncmem(&sqh->dma, sqh->offs + offsetof(ehci_qh_t, qh_link),
+           sizeof(sqh->qh.qh_link),
+           BUS_DMASYNC_PREWRITE);
        head->next = sqh;
        head->qh.qh_link = htole32(sqh->physaddr | EHCI_LINK_QH);
+       usb_syncmem(&head->dma, head->offs + offsetof(ehci_qh_t, qh_link),
+           sizeof(head->qh.qh_link),
+           BUS_DMASYNC_PREWRITE);
 
 #ifdef EHCI_DEBUG
        if (ehcidebug > 5) {
@@ -1486,8 +1522,14 @@
                ;
        if (p == NULL)
                panic("ehci_rem_qh: ED not found");
+       usb_syncmem(&sqh->dma, sqh->offs + offsetof(ehci_qh_t, qh_link),
+           sizeof(sqh->qh.qh_link),
+           BUS_DMASYNC_POSTWRITE);
        p->next = sqh->next;
        p->qh.qh_link = sqh->qh.qh_link;
+       usb_syncmem(&p->dma, p->offs + offsetof(ehci_qh_t, qh_link),
+           sizeof(p->qh.qh_link),
+           BUS_DMASYNC_PREWRITE);
 
        ehci_sync_hc(sc);
 }
@@ -1499,20 +1541,32 @@
        u_int32_t status;
 
        /* Save toggle bit and ping status. */
+       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        status = sqh->qh.qh_qtd.qtd_status &
            htole32(EHCI_QTD_TOGGLE_MASK |
                    EHCI_QTD_SET_STATUS(EHCI_QTD_PINGSTATE));
        /* Set HALTED to make hw leave it alone. */
        sqh->qh.qh_qtd.qtd_status =
            htole32(EHCI_QTD_SET_STATUS(EHCI_QTD_HALTED));
+       usb_syncmem(&sqh->dma,
+           sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
+           sizeof(sqh->qh.qh_qtd.qtd_status),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        sqh->qh.qh_curqtd = 0;
        sqh->qh.qh_qtd.qtd_next = htole32(sqtd->physaddr);
        sqh->qh.qh_qtd.qtd_altnext = 0;
        for (i = 0; i < EHCI_QTD_NBUFFERS; i++)
                sqh->qh.qh_qtd.qtd_buffer[i] = 0;
        sqh->sqtd = sqtd;
+       usb_syncmem(&sqh->dma, sqh->offs, sizeof(sqh->qh),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        /* Set !HALTED && !ACTIVE to start execution, preserve some fields */
        sqh->qh.qh_qtd.qtd_status = status;
+       usb_syncmem(&sqh->dma,
+           sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
+           sizeof(sqh->qh.qh_qtd.qtd_status),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 }
 
 /*
@@ -2171,6 +2225,8 @@
                        offs = i * EHCI_SQH_SIZE;
                        sqh = KERNADDR(&dma, offs);
                        sqh->physaddr = DMAADDR(&dma, offs);
+                       sqh->dma = dma;
+                       sqh->offs = offs;
                        sqh->next = sc->sc_freeqhs;
                        sc->sc_freeqhs = sqh;
                }
@@ -2213,6 +2269,8 @@
                        offs = i * EHCI_SQTD_SIZE;
                        sqtd = KERNADDR(&dma, offs);
                        sqtd->physaddr = DMAADDR(&dma, offs);
+                       sqtd->dma = dma;
+                       sqtd->offs = offs;
                        sqtd->nextqtd = sc->sc_freeqtds;
                        sc->sc_freeqtds = sqtd;
                }
@@ -2273,6 +2331,9 @@
        *sp = cur;
        if (cur == NULL)
                goto nomem;
+
+       usb_syncmem(dma, 0, alen,
+           rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
        for (;;) {
                dataphyspage = EHCI_PAGE(dataphys);
                /* The EHCI hardware can handle at most 5 pages. */
@@ -2347,6 +2408,7 @@
                    htole32(qtdstatus | EHCI_QTD_SET_BYTES(curlen));
                cur->xfer = xfer;
                cur->len = curlen;
+
                DPRINTFN(10,("ehci_alloc_sqtd_chain: cbp=0x%08x end=0x%08x\n",
                            dataphys, dataphys + curlen));
                /* adjust the toggle based on the number of packets in this
@@ -2357,11 +2419,15 @@
                }
                if (next == NULL)
                        break;
+               usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd),
+                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
                DPRINTFN(10,("ehci_alloc_sqtd_chain: extend chain\n"));
                dataphys += curlen;
                cur = next;
        }
        cur->qtd.qtd_status |= htole32(EHCI_QTD_IOC);
+       usb_syncmem(&cur->dma, cur->offs, sizeof(cur->qtd),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        *ep = cur;
        epipe->nexttoggle = tog;
 
@@ -2478,10 +2544,27 @@
        s = splusb();
        xfer->status = status;  /* make software ignore it */
        usb_uncallout(xfer->timeout_handle, ehci_timeout, xfer);
+
+       usb_syncmem(&sqh->dma,
+           sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
+           sizeof(sqh->qh.qh_qtd.qtd_status),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        qhstatus = sqh->qh.qh_qtd.qtd_status;
        sqh->qh.qh_qtd.qtd_status = qhstatus | htole32(EHCI_QTD_HALTED);
+       usb_syncmem(&sqh->dma,
+           sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
+           sizeof(sqh->qh.qh_qtd.qtd_status),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
+               usb_syncmem(&sqtd->dma,
+                   sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
+                   sizeof(sqtd->qtd.qtd_status),
+                   BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
                sqtd->qtd.qtd_status |= htole32(EHCI_QTD_HALTED);
+               usb_syncmem(&sqtd->dma,
+                   sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
+                   sizeof(sqtd->qtd.qtd_status),
+                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
                if (sqtd == exfer->sqtdend)
                        break;
        }
@@ -2511,6 +2594,11 @@
         * any of them.
         */
        s = splusb();           /* XXX why? */
+
+       usb_syncmem(&sqh->dma,
+           sqh->offs + offsetof(ehci_qh_t, qh_curqtd),
+           sizeof(sqh->qh.qh_curqtd),
+           BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
        cur = EHCI_LINK_ADDR(le32toh(sqh->qh.qh_curqtd));
        hit = 0;
        for (sqtd = exfer->sqtdstart; ; sqtd = sqtd->nextqtd) {
@@ -2523,7 +2611,15 @@
        if (hit && sqtd != NULL) {
                DPRINTFN(1,("ehci_abort_xfer: cur=0x%08x\n", sqtd->physaddr));
                sqh->qh.qh_curqtd = htole32(sqtd->physaddr); /* unlink qTDs */
+               usb_syncmem(&sqh->dma,
+                   sqh->offs + offsetof(ehci_qh_t, qh_curqtd),
+                   sizeof(sqh->qh.qh_curqtd),
+                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
                sqh->qh.qh_qtd.qtd_status = qhstatus;
+               usb_syncmem(&sqh->dma,
+                   sqh->offs + offsetof(ehci_qh_t, qh_qtd.qtd_status),
+                   sizeof(sqh->qh.qh_qtd.qtd_status),
+                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        } else {
                DPRINTFN(1,("ehci_abort_xfer: no hit\n"));
        }
@@ -2628,7 +2724,10 @@
 {
        struct ehci_xfer *ex = EXFER(xfer);
        ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
-       /*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/
+       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+       usb_device_request_t *req = &xfer->request;
+       int len = UGETW(req->wLength);
+       int rd = req->bmRequestType & UT_READ;
 
        DPRINTFN(10,("ehci_ctrl_done: xfer=%p\n", xfer));
 
@@ -2641,6 +2740,11 @@
        if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
                ehci_del_intr_list(ex); /* remove from active list */
                ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
+               usb_syncmem(&epipe->u.ctl.reqdma, 0, sizeof *req,
+                   BUS_DMASYNC_POSTWRITE);
+               if (len)
+                       usb_syncmem(&xfer->dmabuf, 0, len,
+                           rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        }
 
        DPRINTFN(5, ("ehci_ctrl_done: length=%d\n", xfer->actlen));
@@ -2729,11 +2833,14 @@
                end->nextqtd = stat;
                end->qtd.qtd_next =
                end->qtd.qtd_altnext = htole32(stat->physaddr);
+               usb_syncmem(&end->dma, end->offs, sizeof(end->qtd),
+                  BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
        } else {
                next = stat;
        }
 
        memcpy(KERNADDR(&epipe->u.ctl.reqdma, 0), req, sizeof *req);
+       usb_syncmem(&epipe->u.ctl.reqdma, 0, sizeof *req, BUS_DMASYNC_PREWRITE);
 
        /* Clear toggle */
        setup->qtd.qtd_status = htole32(
@@ -2749,6 +2856,8 @@
        setup->qtd.qtd_next = setup->qtd.qtd_altnext = htole32(next->physaddr);
        setup->xfer = xfer;
        setup->len = sizeof *req;
+       usb_syncmem(&setup->dma, setup->offs, sizeof(setup->qtd),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
        stat->qtd.qtd_status = htole32(
            EHCI_QTD_ACTIVE |
@@ -2763,6 +2872,8 @@
        stat->qtd.qtd_next = stat->qtd.qtd_altnext = EHCI_NULL;
        stat->xfer = xfer;
        stat->len = 0;
+       usb_syncmem(&stat->dma, stat->offs, sizeof(stat->qtd),
+           BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
 
 #ifdef EHCI_DEBUG
        if (ehcidebug > 5) {
@@ -2783,7 +2894,7 @@
 
        /* Insert qTD in QH list. */
        s = splusb();
-       ehci_set_qh_qtd(sqh, setup);
+       ehci_set_qh_qtd(sqh, setup); /* also does usb_syncmem(sqh) */
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                 usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
                            ehci_timeout, xfer);
@@ -2916,7 +3027,7 @@
 #endif
 
        s = splusb();
-       ehci_set_qh_qtd(sqh, data);
+       ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
                            ehci_timeout, xfer);
@@ -2972,7 +3083,9 @@
 {
        struct ehci_xfer *ex = EXFER(xfer);
        ehci_softc_t *sc = xfer->pipe->device->bus->hci_private;
-       /*struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;*/
+       struct ehci_pipe *epipe = (struct ehci_pipe *)xfer->pipe;
+       int endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
+       int rd = UE_GET_DIR(endpt) == UE_DIR_IN;
 
        DPRINTFN(10,("ehci_bulk_done: xfer=%p, actlen=%d\n",
                     xfer, xfer->actlen));
@@ -2980,6 +3093,8 @@
        if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
                ehci_del_intr_list(ex); /* remove from active list */
                ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
+               usb_syncmem(&xfer->dmabuf, 0, xfer->length,
+                   rd ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        }
 
        DPRINTFN(5, ("ehci_bulk_done: length=%d\n", xfer->actlen));
@@ -3086,7 +3201,7 @@
 #endif
 
        s = splusb();
-       ehci_set_qh_qtd(sqh, data);
+       ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
        if (xfer->timeout && !sc->sc_bus.use_polling) {
                usb_callout(xfer->timeout_handle, mstohz(xfer->timeout),
                    ehci_timeout, xfer);
@@ -3158,6 +3273,8 @@
                xfer->length = len;
                endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
                isread = UE_GET_DIR(endpt) == UE_DIR_IN;
+               usb_syncmem(&xfer->dmabuf, 0, len,
+                   isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
                sqh = epipe->sqh;
 
                err = ehci_alloc_sqtd_chain(epipe, sc, len, isread, xfer,
@@ -3180,7 +3297,7 @@
 #endif
 
                s = splusb();
-               ehci_set_qh_qtd(sqh, data);
+               ehci_set_qh_qtd(sqh, data); /* also does usb_syncmem(sqh) */
                if (xfer->timeout && !sc->sc_bus.use_polling) {
                        usb_callout(xfer->timeout_handle,
                            mstohz(xfer->timeout), ehci_timeout, xfer);
@@ -3191,6 +3308,10 @@
        } else if (xfer->status != USBD_NOMEM && ehci_active_intr_list(ex)) {
                ehci_del_intr_list(ex); /* remove from active list */
                ehci_free_sqtd_chain(sc, ex->sqtdstart, NULL);
+               endpt = epipe->pipe.endpoint->edesc->bEndpointAddress;
+               isread = UE_GET_DIR(endpt) == UE_DIR_IN;
+               usb_syncmem(&xfer->dmabuf, 0, xfer->length,
+                   isread ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
        }
 #undef exfer
 }
Index: ehcivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.30
diff -u -r1.30 ehcivar.h
--- ehcivar.h   28 Apr 2008 20:23:58 -0000      1.30
+++ ehcivar.h   8 Jun 2008 19:13:47 -0000
@@ -33,6 +33,8 @@
        ehci_qtd_t qtd;
        struct ehci_soft_qtd *nextqtd; /* mirrors nextqtd in TD */
        ehci_physaddr_t physaddr;
+       usb_dma_t dma;                  /* qTD's DMA infos */
+       int offs;                       /* qTD's offset in usb_dma_t */
        usbd_xfer_handle xfer;
        LIST_ENTRY(ehci_soft_qtd) hnext;
        u_int16_t len;
@@ -45,6 +47,8 @@
        struct ehci_soft_qh *next;
        struct ehci_soft_qtd *sqtd;
        ehci_physaddr_t physaddr;
+       usb_dma_t dma;                  /* QH's DMA infos */
+       int offs;                       /* QH's offset in usb_dma_t */
        int islot;
 } ehci_soft_qh_t;
 #define EHCI_SQH_SIZE ((sizeof (struct ehci_soft_qh) + EHCI_QH_ALIGN - 1) / 
EHCI_QH_ALIGN * EHCI_QH_ALIGN)


Home | Main Index | Thread Index | Old Index