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 Restructure the xfer methods of ohci(4) so ...



details:   https://anonhg.NetBSD.org/src/rev/fc7928a5b1ef
branches:  nick-nhusb
changeset: 334328:fc7928a5b1ef
user:      skrll <skrll%NetBSD.org@localhost>
date:      Sun Dec 06 15:39:35 2015 +0000

description:
Restructure the xfer methods of ohci(4) so that minimal work in done in
softint context.  Now all memory allocation is done in thread context.

Addresses kern/48308 for ohci(4), might fix some locking bugs around the
*TD free lists, and plugs some memory leaks on error conditions.

diffstat:

 sys/dev/usb/ohci.c    |  879 +++++++++++++++++++++++++++++++++++++------------
 sys/dev/usb/ohcivar.h |   24 +-
 2 files changed, 684 insertions(+), 219 deletions(-)

diffs (truncated from 1508 to 300 lines):

diff -r 3ca8bf9236c1 -r fc7928a5b1ef sys/dev/usb/ohci.c
--- a/sys/dev/usb/ohci.c        Wed Dec 02 20:36:50 2015 +0000
+++ b/sys/dev/usb/ohci.c        Sun Dec 06 15:39:35 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ohci.c,v 1.254.2.34 2015/12/02 20:36:50 skrll Exp $    */
+/*     $NetBSD: ohci.c,v 1.254.2.35 2015/12/06 15:39:35 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.34 2015/12/02 20:36:50 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ohci.c,v 1.254.2.35 2015/12/06 15:39:35 skrll Exp $");
 
 #include "opt_usb.h"
 
@@ -129,15 +129,19 @@
 
 Static ohci_soft_td_t  *ohci_alloc_std(ohci_softc_t *);
 Static void            ohci_free_std(ohci_softc_t *, ohci_soft_td_t *);
+Static void            ohci_free_std_locked(ohci_softc_t *, ohci_soft_td_t *);
 
 Static ohci_soft_itd_t *ohci_alloc_sitd(ohci_softc_t *);
 Static void            ohci_free_sitd(ohci_softc_t *,ohci_soft_itd_t *);
-
-Static void            ohci_free_std_chain(ohci_softc_t *, ohci_soft_td_t *,
-                                           ohci_soft_td_t *);
-Static usbd_status     ohci_alloc_std_chain(struct ohci_pipe *,
-                           ohci_softc_t *, int, int, struct usbd_xfer *,
-                           ohci_soft_td_t *, ohci_soft_td_t **);
+Static void            ohci_free_sitd_locked(ohci_softc_t *,
+                           ohci_soft_itd_t *);
+
+Static usbd_status     ohci_alloc_std_chain(ohci_softc_t *, struct usbd_xfer *,
+                           int, int);
+Static void            ohci_free_stds(ohci_softc_t *, struct ohci_xfer *);
+
+Static void            ohci_reset_std_chain(ohci_softc_t *, struct usbd_xfer *,
+                           int, int, ohci_soft_td_t *, ohci_soft_td_t **);
 
 Static usbd_status     ohci_open(struct usbd_pipe *);
 Static void            ohci_poll(struct usbd_bus *);
@@ -174,24 +178,32 @@
 Static void            ohci_root_intr_close(struct usbd_pipe *);
 Static void            ohci_root_intr_done(struct usbd_xfer *);
 
+Static int             ohci_device_ctrl_init(struct usbd_xfer *);
+Static void            ohci_device_ctrl_fini(struct usbd_xfer *);
 Static usbd_status     ohci_device_ctrl_transfer(struct usbd_xfer *);
 Static usbd_status     ohci_device_ctrl_start(struct usbd_xfer *);
 Static void            ohci_device_ctrl_abort(struct usbd_xfer *);
 Static void            ohci_device_ctrl_close(struct usbd_pipe *);
 Static void            ohci_device_ctrl_done(struct usbd_xfer *);
 
+Static int             ohci_device_bulk_init(struct usbd_xfer *);
+Static void            ohci_device_bulk_fini(struct usbd_xfer *);
 Static usbd_status     ohci_device_bulk_transfer(struct usbd_xfer *);
 Static usbd_status     ohci_device_bulk_start(struct usbd_xfer *);
 Static void            ohci_device_bulk_abort(struct usbd_xfer *);
 Static void            ohci_device_bulk_close(struct usbd_pipe *);
 Static void            ohci_device_bulk_done(struct usbd_xfer *);
 
+Static int             ohci_device_intr_init(struct usbd_xfer *);
+Static void            ohci_device_intr_fini(struct usbd_xfer *);
 Static usbd_status     ohci_device_intr_transfer(struct usbd_xfer *);
 Static usbd_status     ohci_device_intr_start(struct usbd_xfer *);
 Static void            ohci_device_intr_abort(struct usbd_xfer *);
 Static void            ohci_device_intr_close(struct usbd_pipe *);
 Static void            ohci_device_intr_done(struct usbd_xfer *);
 
+Static int             ohci_device_isoc_init(struct usbd_xfer *);
+Static void            ohci_device_isoc_fini(struct usbd_xfer *);
 Static usbd_status     ohci_device_isoc_transfer(struct usbd_xfer *);
 Static usbd_status     ohci_device_isoc_start(struct usbd_xfer *);
 Static void            ohci_device_isoc_abort(struct usbd_xfer *);
@@ -289,6 +301,8 @@
 };
 
 Static const struct usbd_pipe_methods ohci_device_ctrl_methods = {
+       .upm_init =     ohci_device_ctrl_init,
+       .upm_fini =     ohci_device_ctrl_fini,
        .upm_transfer = ohci_device_ctrl_transfer,
        .upm_start =    ohci_device_ctrl_start,
        .upm_abort =    ohci_device_ctrl_abort,
@@ -298,6 +312,8 @@
 };
 
 Static const struct usbd_pipe_methods ohci_device_intr_methods = {
+       .upm_init =     ohci_device_intr_init,
+       .upm_fini =     ohci_device_intr_fini,
        .upm_transfer = ohci_device_intr_transfer,
        .upm_start =    ohci_device_intr_start,
        .upm_abort =    ohci_device_intr_abort,
@@ -307,6 +323,8 @@
 };
 
 Static const struct usbd_pipe_methods ohci_device_bulk_methods = {
+       .upm_init =     ohci_device_bulk_init,
+       .upm_fini =     ohci_device_bulk_fini,
        .upm_transfer = ohci_device_bulk_transfer,
        .upm_start =    ohci_device_bulk_start,
        .upm_abort =    ohci_device_bulk_abort,
@@ -316,6 +334,8 @@
 };
 
 Static const struct usbd_pipe_methods ohci_device_isoc_methods = {
+       .upm_init =     ohci_device_isoc_init,
+       .upm_fini =     ohci_device_isoc_fini,
        .upm_transfer = ohci_device_isoc_transfer,
        .upm_start =    ohci_device_isoc_start,
        .upm_abort =    ohci_device_isoc_abort,
@@ -387,12 +407,17 @@
 
        OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
+       mutex_enter(&sc->sc_lock);
        if (sc->sc_freeeds == NULL) {
                DPRINTFN(2, "allocating chunk", 0, 0, 0, 0);
+               mutex_exit(&sc->sc_lock);
+
                err = usb_allocmem(&sc->sc_bus, OHCI_SED_SIZE * OHCI_SED_CHUNK,
                          OHCI_ED_ALIGN, &dma);
                if (err)
                        return 0;
+
+               mutex_enter(&sc->sc_lock);
                for (i = 0; i < OHCI_SED_CHUNK; i++) {
                        offs = i * OHCI_SED_SIZE;
                        sed = KERNADDR(&dma, offs);
@@ -405,16 +430,30 @@
        }
        sed = sc->sc_freeeds;
        sc->sc_freeeds = sed->next;
+       mutex_exit(&sc->sc_lock);
+
        memset(&sed->ed, 0, sizeof(ohci_ed_t));
        sed->next = 0;
        return sed;
 }
 
+static inline void
+ohci_free_sed_locked(ohci_softc_t *sc, ohci_soft_ed_t *sed)
+{
+
+       KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+       sed->next = sc->sc_freeeds;
+       sc->sc_freeeds = sed;
+}
+
 void
 ohci_free_sed(ohci_softc_t *sc, ohci_soft_ed_t *sed)
 {
-       sed->next = sc->sc_freeeds;
-       sc->sc_freeeds = sed;
+
+       mutex_enter(&sc->sc_lock);
+       ohci_free_sed_locked(sc, sed);
+       mutex_exit(&sc->sc_lock);
 }
 
 ohci_soft_td_t *
@@ -427,14 +466,17 @@
 
        OHCIHIST_FUNC(); OHCIHIST_CALLED();
 
-       KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
-
+       mutex_enter(&sc->sc_lock);
        if (sc->sc_freetds == NULL) {
                DPRINTFN(2, "allocating chunk", 0, 0, 0, 0);
+               mutex_exit(&sc->sc_lock);
+
                err = usb_allocmem(&sc->sc_bus, OHCI_STD_SIZE * OHCI_STD_CHUNK,
                          OHCI_TD_ALIGN, &dma);
                if (err)
                        return NULL;
+
+               mutex_enter(&sc->sc_lock);
                for(i = 0; i < OHCI_STD_CHUNK; i++) {
                        offs = i * OHCI_STD_SIZE;
                        std = KERNADDR(&dma, offs);
@@ -448,59 +490,79 @@
 
        std = sc->sc_freetds;
        sc->sc_freetds = std->nexttd;
+       mutex_exit(&sc->sc_lock);
+
        memset(&std->td, 0, sizeof(ohci_td_t));
        std->nexttd = NULL;
        std->xfer = NULL;
-       ohci_hash_add_td(sc, std);
 
        return std;
 }
 
 void
+ohci_free_std_locked(ohci_softc_t *sc, ohci_soft_td_t *std)
+{
+
+       KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
+
+       std->nexttd = sc->sc_freetds;
+       sc->sc_freetds = std;
+}
+
+void
 ohci_free_std(ohci_softc_t *sc, ohci_soft_td_t *std)
 {
 
-       KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
-
-       ohci_hash_rem_td(sc, std);
-       std->nexttd = sc->sc_freetds;
-       sc->sc_freetds = std;
+       mutex_enter(&sc->sc_lock);
+       ohci_free_std_locked(sc, std);
+       mutex_exit(&sc->sc_lock);
 }
 
-usbd_status
-ohci_alloc_std_chain(struct ohci_pipe *opipe, ohci_softc_t *sc,
-                    int alen, int rd, struct usbd_xfer *xfer,
-                    ohci_soft_td_t *sp, ohci_soft_td_t **ep)
+Static usbd_status
+ohci_alloc_std_chain(ohci_softc_t *sc, struct usbd_xfer *xfer, int alen, 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;
        uint32_t tdflags;
-       int len, curlen;
+       int len = alen;
+       int curlen;
        usb_dma_t *dma = &xfer->ux_dmabuf;
        uint16_t flags = xfer->ux_flags;
 
        OHCIHIST_FUNC(); OHCIHIST_CALLED();
-       DPRINTF("start len=%d", alen, 0, 0, 0);
-
-       KASSERT(mutex_owned(&sc->sc_lock));
 
        DPRINTFN(8, "addr=%d endpt=%d len=%d speed=%d",
-           opipe->pipe.up_dev->ud_addr,
-           UE_GET_ADDR(opipe->pipe.up_endpoint->ue_edesc->bEndpointAddress),
-           alen, opipe->pipe.up_dev->ud_speed);
+           pipe->up_dev->ud_addr,
+           UE_GET_ADDR(pipe->up_endpoint->ue_edesc->bEndpointAddress),
+           alen, pipe->up_dev->ud_speed);
+
+       ASSERT_SLEEPABLE();
+
+       size_t nstd = (flags & USBD_FORCE_SHORT_XFER) ? 1 : 0;
+       nstd += ((len + 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);
 
        len = alen;
-       cur = sp;
+       cur = ohci_alloc_std(sc);
+       if (cur == NULL)
+               goto nomem;
+
        dataphys = DMAADDR(dma, 0);
        dataphysend = OHCI_PAGE(dataphys + len - 1);
-       usb_syncmem(dma, 0, len,
-           rd ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
        tdflags = HTOO32(
            (rd ? OHCI_TD_IN : OHCI_TD_OUT) |
            (flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0) |
            OHCI_TD_NOCC | OHCI_TD_TOGGLE_CARRY | OHCI_TD_NOINTR);
 
-       for (;;) {
+       for (size_t j = 0;;) {
+               ox->ox_stds[j++] = cur;
                next = ohci_alloc_std(sc);
                if (next == NULL)
                        goto nomem;
@@ -515,7 +577,7 @@
                        curlen = 2 * OHCI_PAGE_SIZE -
                                 (dataphys & (OHCI_PAGE_SIZE-1));
                        /* the length must be a multiple of the max size */
-                       curlen -= curlen % UGETW(opipe->pipe.up_endpoint->ue_edesc->wMaxPacketSize);
+                       curlen -= curlen % mps;
                        KASSERT(curlen != 0);
                }
                DPRINTFN(4, "dataphys=0x%08x dataphysend=0x%08x "
@@ -530,8 +592,7 @@
                cur->len = curlen;
                cur->flags = OHCI_ADD_LEN;
                cur->xfer = xfer;
-               usb_syncmem(&cur->dma, cur->offs, sizeof(cur->td),
-                   BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);



Home | Main Index | Thread Index | Old Index