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 so that (close...



details:   https://anonhg.NetBSD.org/src/rev/ab544301e14c
branches:  nick-nhusb
changeset: 804433:ab544301e14c
user:      skrll <skrll%NetBSD.org@localhost>
date:      Sun Oct 25 09:50:06 2015 +0000

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

Addresses kern/48308 for ehci(4), fixes a bunch of locking bugs around the
*TD free lists, and plugs some memory leaks on error conditions.

XXX revisit for isoc caching models (4.7.2.1)

diffstat:

 sys/dev/usb/ehci.c    |  1685 ++++++++++++++++++++++++++++++------------------
 sys/dev/usb/ehcivar.h |    27 +-
 2 files changed, 1062 insertions(+), 650 deletions(-)

diffs (truncated from 2622 to 300 lines):

diff -r 7fe22e9022ef -r ab544301e14c sys/dev/usb/ehci.c
--- a/sys/dev/usb/ehci.c        Sun Oct 25 09:28:41 2015 +0000
+++ b/sys/dev/usb/ehci.c        Sun Oct 25 09:50:06 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ehci.c,v 1.234.2.63 2015/10/25 09:28:41 skrll Exp $ */
+/*     $NetBSD: ehci.c,v 1.234.2.64 2015/10/25 09:50:06 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.63 2015/10/25 09:28:41 skrll Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ehci.c,v 1.234.2.64 2015/10/25 09:50:06 skrll Exp $");
 
 #include "ohci.h"
 #include "uhci.h"
@@ -167,6 +167,7 @@
 Static struct usbd_xfer *
                        ehci_allocx(struct usbd_bus *, unsigned int);
 Static void            ehci_freex(struct usbd_bus *, struct usbd_xfer *);
+
 Static void            ehci_get_lock(struct usbd_bus *, kmutex_t **);
 Static int             ehci_roothub_ctrl(struct usbd_bus *,
                            usb_device_request_t *, void *, int);
@@ -177,30 +178,40 @@
 Static void            ehci_root_intr_close(struct usbd_pipe *);
 Static void            ehci_root_intr_done(struct usbd_xfer *);
 
+Static int             ehci_device_ctrl_init(struct usbd_xfer *);
+Static void            ehci_device_ctrl_fini(struct usbd_xfer *);
 Static usbd_status     ehci_device_ctrl_transfer(struct usbd_xfer *);
 Static usbd_status     ehci_device_ctrl_start(struct usbd_xfer *);
 Static void            ehci_device_ctrl_abort(struct usbd_xfer *);
 Static void            ehci_device_ctrl_close(struct usbd_pipe *);
 Static void            ehci_device_ctrl_done(struct usbd_xfer *);
 
+Static int             ehci_device_bulk_init(struct usbd_xfer *);
+Static void            ehci_device_bulk_fini(struct usbd_xfer *);
 Static usbd_status     ehci_device_bulk_transfer(struct usbd_xfer *);
 Static usbd_status     ehci_device_bulk_start(struct usbd_xfer *);
 Static void            ehci_device_bulk_abort(struct usbd_xfer *);
 Static void            ehci_device_bulk_close(struct usbd_pipe *);
 Static void            ehci_device_bulk_done(struct usbd_xfer *);
 
+Static int             ehci_device_intr_init(struct usbd_xfer *);
+Static void            ehci_device_intr_fini(struct usbd_xfer *);
 Static usbd_status     ehci_device_intr_transfer(struct usbd_xfer *);
 Static usbd_status     ehci_device_intr_start(struct usbd_xfer *);
 Static void            ehci_device_intr_abort(struct usbd_xfer *);
 Static void            ehci_device_intr_close(struct usbd_pipe *);
 Static void            ehci_device_intr_done(struct usbd_xfer *);
 
+Static int             ehci_device_isoc_init(struct usbd_xfer *);
+Static void            ehci_device_isoc_fini(struct usbd_xfer *);
 Static usbd_status     ehci_device_isoc_transfer(struct usbd_xfer *);
 Static usbd_status     ehci_device_isoc_start(struct usbd_xfer *);
 Static void            ehci_device_isoc_abort(struct usbd_xfer *);
 Static void            ehci_device_isoc_close(struct usbd_pipe *);
 Static void            ehci_device_isoc_done(struct usbd_xfer *);
 
+Static int             ehci_device_fs_isoc_init(struct usbd_xfer *);
+Static void            ehci_device_fs_isoc_fini(struct usbd_xfer *);
 Static usbd_status     ehci_device_fs_isoc_transfer(struct usbd_xfer *);
 Static usbd_status     ehci_device_fs_isoc_start(struct usbd_xfer *);
 Static void            ehci_device_fs_isoc_abort(struct usbd_xfer *);
@@ -217,25 +228,37 @@
 
 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(struct ehci_pipe *,
-                           ehci_softc_t *, int, int, struct usbd_xfer *,
-                           ehci_soft_qtd_t **, ehci_soft_qtd_t **);
-Static void            ehci_free_sqtd_chain(ehci_softc_t *, 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 **, 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 *, ehci_soft_qtd_t **);
 
 Static ehci_soft_itd_t *ehci_alloc_itd(ehci_softc_t *);
 Static ehci_soft_sitd_t *
                        ehci_alloc_sitd(ehci_softc_t *);
-Static void            ehci_free_itd(ehci_softc_t *, ehci_soft_itd_t *);
-Static void            ehci_free_sitd(ehci_softc_t *, ehci_soft_sitd_t *);
-Static void            ehci_rem_free_itd_chain(ehci_softc_t *,
-                                               struct ehci_xfer *);
-Static void            ehci_rem_free_sitd_chain(ehci_softc_t *,
-                                                struct ehci_xfer *);
-Static void            ehci_abort_isoc_xfer(struct usbd_xfer *,
-                                               usbd_status);
-
-Static usbd_status     ehci_device_request(struct usbd_xfer *);
+
+Static void            ehci_remove_itd_chain(ehci_softc_t *, ehci_soft_itd_t *);
+Static void            ehci_remove_sitd_chain(ehci_softc_t *, ehci_soft_sitd_t *);
+Static void            ehci_free_itd_chain(ehci_softc_t *, ehci_soft_itd_t *);
+Static void            ehci_free_sitd_chain(ehci_softc_t *, ehci_soft_sitd_t *);
+
+static inline void
+ehci_free_itd_locked(ehci_softc_t *sc, ehci_soft_itd_t *itd)
+{
+
+       LIST_INSERT_HEAD(&sc->sc_freeitds, itd, free_list);
+}
+
+static inline void
+ehci_free_sitd_locked(ehci_softc_t *sc, ehci_soft_sitd_t *sitd)
+{
+
+       LIST_INSERT_HEAD(&sc->sc_freesitds, sitd, free_list);
+}
+
+Static void            ehci_abort_isoc_xfer(struct usbd_xfer *, usbd_status);
 
 Static usbd_status     ehci_device_setintr(ehci_softc_t *, ehci_soft_qh_t *,
                            int);
@@ -262,6 +285,7 @@
 Static void            ehci_dump_qtd(ehci_qtd_t *);
 Static void            ehci_dump_sqh(ehci_soft_qh_t *);
 Static void            ehci_dump_sitd(struct ehci_soft_itd *);
+Static void            ehci_dump_itds(ehci_soft_itd_t *);
 Static void            ehci_dump_itd(struct ehci_soft_itd *);
 Static void            ehci_dump_exfer(struct ehci_xfer *);
 #endif
@@ -297,6 +321,8 @@
 };
 
 Static const struct usbd_pipe_methods ehci_device_ctrl_methods = {
+       .upm_init =     ehci_device_ctrl_init,
+       .upm_fini =     ehci_device_ctrl_fini,
        .upm_transfer = ehci_device_ctrl_transfer,
        .upm_start =    ehci_device_ctrl_start,
        .upm_abort =    ehci_device_ctrl_abort,
@@ -306,6 +332,8 @@
 };
 
 Static const struct usbd_pipe_methods ehci_device_intr_methods = {
+       .upm_init =     ehci_device_intr_init,
+       .upm_fini =     ehci_device_intr_fini,
        .upm_transfer = ehci_device_intr_transfer,
        .upm_start =    ehci_device_intr_start,
        .upm_abort =    ehci_device_intr_abort,
@@ -315,6 +343,8 @@
 };
 
 Static const struct usbd_pipe_methods ehci_device_bulk_methods = {
+       .upm_init =     ehci_device_bulk_init,
+       .upm_fini =     ehci_device_bulk_fini,
        .upm_transfer = ehci_device_bulk_transfer,
        .upm_start =    ehci_device_bulk_start,
        .upm_abort =    ehci_device_bulk_abort,
@@ -324,6 +354,8 @@
 };
 
 Static const struct usbd_pipe_methods ehci_device_isoc_methods = {
+       .upm_init =     ehci_device_isoc_init,
+       .upm_fini =     ehci_device_isoc_fini,
        .upm_transfer = ehci_device_isoc_transfer,
        .upm_start =    ehci_device_isoc_start,
        .upm_abort =    ehci_device_isoc_abort,
@@ -333,6 +365,8 @@
 };
 
 Static const struct usbd_pipe_methods ehci_device_fs_isoc_methods = {
+       .upm_init =     ehci_device_fs_isoc_init,
+       .upm_fini =     ehci_device_fs_isoc_fini,
        .upm_transfer = ehci_device_fs_isoc_transfer,
        .upm_start =    ehci_device_fs_isoc_start,
        .upm_abort =    ehci_device_fs_isoc_abort,
@@ -783,22 +817,27 @@
 Static void
 ehci_check_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
 {
-       struct usbd_device *dev = ex->ex_xfer.ux_pipe->up_dev;
-       int attr;
 
        USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
        USBHIST_LOG(ehcidebug, "ex = %p", ex, 0, 0, 0);
 
        KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
-       attr = ex->ex_xfer.ux_pipe->up_endpoint->ue_edesc->bmAttributes;
-       if (UE_GET_XFERTYPE(attr) == UE_ISOCHRONOUS) {
-               if (dev->ud_speed == USB_SPEED_HIGH)
-                       ehci_check_itd_intr(sc, ex);
-               else
-                       ehci_check_sitd_intr(sc, ex);
-       } else
+       switch (ex->ex_type) {
+       case EX_CTRL:
+       case EX_BULK:
+       case EX_INTR:
                ehci_check_qh_intr(sc, ex);
+               break;
+       case EX_ISOC:
+               ehci_check_itd_intr(sc, ex);
+               break;
+       case EX_FS_ISOC:
+               ehci_check_sitd_intr(sc, ex);
+               break;
+       default:
+               KASSERT(false);
+       }
 
        return;
 }
@@ -806,25 +845,23 @@
 Static void
 ehci_check_qh_intr(ehci_softc_t *sc, struct ehci_xfer *ex)
 {
-       ehci_soft_qtd_t *sqtd, *lsqtd;
+       ehci_soft_qtd_t *sqtd, *fsqtd, *lsqtd;
        uint32_t status;
 
        USBHIST_FUNC(); USBHIST_CALLED(ehcidebug);
 
        KASSERT(sc->sc_bus.ub_usepolling || mutex_owned(&sc->sc_lock));
 
-       if (ex->ex_sqtdstart == NULL) {
-               printf("ehci_check_qh_intr: not valid sqtd\n");
-               return;
+       if (ex->ex_type == EX_CTRL) {
+               fsqtd = ex->ex_setup;
+               lsqtd = ex->ex_status;
+       } else {
+               fsqtd = ex->ex_sqtdstart;
+               lsqtd = ex->ex_sqtdend;
        }
-
-       lsqtd = ex->ex_sqtdend;
-#ifdef DIAGNOSTIC
-       if (lsqtd == NULL) {
-               printf("ehci_check_qh_intr: lsqtd==0\n");
-               return;
-       }
-#endif
+       KASSERTMSG(fsqtd != NULL && lsqtd != NULL,
+           "xfer %p xt %d fsqtd %p lsqtd %p", ex, ex->ex_type, fsqtd, lsqtd);
+
        /*
         * If the last TD is still active we need to check whether there
         * is an error somewhere in the middle, or whether there was a
@@ -840,8 +877,7 @@
            sizeof(lsqtd->qtd.qtd_status), BUS_DMASYNC_PREREAD);
        if (status & EHCI_QTD_ACTIVE) {
                USBHIST_LOGN(ehcidebug, 10, "active ex=%p", ex, 0, 0, 0);
-               for (sqtd = ex->ex_sqtdstart; sqtd != lsqtd;
-                    sqtd = sqtd->nextqtd) {
+               for (sqtd = fsqtd; sqtd != lsqtd; sqtd = sqtd->nextqtd) {
                        usb_syncmem(&sqtd->dma,
                            sqtd->offs + offsetof(ehci_qtd_t, qtd_status),
                            sizeof(sqtd->qtd.qtd_status),
@@ -858,11 +894,6 @@
                                goto done;
                        /* Handle short packets */
                        if (EHCI_QTD_GET_BYTES(status) != 0) {
-                               struct usbd_pipe *pipe = ex->ex_xfer.ux_pipe;
-                               usb_endpoint_descriptor_t *ed =
-                                   pipe->up_endpoint->ue_edesc;
-                               uint8_t xt = UE_GET_XFERTYPE(ed->bmAttributes);
-
                                /*
                                 * If we get here for a control transfer then
                                 * we need to let the hardware complete the
@@ -871,7 +902,7 @@
                                 *
                                 * Otherwise, we're done.
                                 */
-                               if (xt == UE_CONTROL) {
+                               if (ex->ex_type == EX_CTRL) {
                                        break;
                                }
                                goto done;
@@ -907,18 +938,10 @@
        if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue))
                return;
 
-       if (ex->ex_itdstart == NULL) {
-               printf("ehci_check_itd_intr: not valid itd\n");
-               return;
-       }
+       KASSERTMSG(ex->ex_itdstart != NULL && ex->ex_itdend != NULL,
+           "xfer %p fitd %p litd %p", ex, ex->ex_itdstart, ex->ex_itdend);
 
        itd = ex->ex_itdend;
-#ifdef DIAGNOSTIC
-       if (itd == NULL) {
-               printf("ehci_check_itd_intr: itdend == 0\n");
-               return;
-       }
-#endif
 
        /*
         * check no active transfers in last itd, meaning we're finished
@@ -961,18 +984,10 @@
        if (&ex->ex_xfer != SIMPLEQ_FIRST(&ex->ex_xfer.ux_pipe->up_queue))



Home | Main Index | Thread Index | Old Index