Diff below converts the three USB controllers to use a pool(9) for
allocating their transfer descriptors instead of maintaining their
own custom free list.

With it uhci(4) and ehci(4) no longer initialized the "isdone" value
to 1 for every new transfer descriptor (if DIAGNOSTIC is defined).
This is done on purpose so that these descriptors don't get ignored
by the abort function in case they were not properly initialized (and
that happens on various code paths).

Comments, ok?


Index: usb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.92
diff -u -p -r1.92 usb.c
--- usb.c       30 May 2013 16:15:02 -0000      1.92
+++ usb.c       1 Nov 2013 21:54:43 -0000
@@ -156,6 +156,8 @@ usb_attach(struct device *parent, struct
        DPRINTF(("usbd_attach\n"));
 
        if (usb_nbuses == 0) {
+               usbd_init();
+
                rw_init(&usbpalock, "usbpalock");
                TAILQ_INIT(&usb_abort_tasks);
                TAILQ_INIT(&usb_explore_tasks);
Index: usbdi.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.63
diff -u -p -r1.63 usbdi.c
--- usbdi.c     31 Oct 2013 20:06:59 -0000      1.63
+++ usbdi.c     1 Nov 2013 21:54:43 -0000
@@ -37,6 +37,7 @@
 #include <sys/kernel.h>
 #include <sys/device.h>
 #include <sys/malloc.h>
+#include <sys/pool.h>
 
 #include <machine/bus.h>
 
@@ -55,12 +56,20 @@ extern int usbdebug;
 #define DPRINTFN(n,x)
 #endif
 
-void usbd_do_request_async_cb(struct usbd_xfer *, void *,
-    usbd_status);
+struct pool usbd_xfer_pool;
+
+void usbd_do_request_async_cb(struct usbd_xfer *, void *, usbd_status);
 void usbd_start_next(struct usbd_pipe *pipe);
 usbd_status usbd_open_pipe_ival(struct usbd_interface *, u_int8_t, u_int8_t,
     struct usbd_pipe **, int);
 
+void
+usbd_init(void)
+{
+       pool_init(&usbd_xfer_pool, USBD_XFER_MAXSIZE, 0, 0, 0, "usbdxfers",
+           NULL);
+}
+
 int
 usbd_is_dying(struct usbd_device *dev)
 {
@@ -402,11 +411,14 @@ usbd_alloc_xfer(struct usbd_device *dev)
 {
        struct usbd_xfer *xfer;
 
-       xfer = dev->bus->methods->allocx(dev->bus);
+       xfer = pool_get(&usbd_xfer_pool, PR_NOWAIT | PR_ZERO);
        if (xfer == NULL)
                return (NULL);
        xfer->device = dev;
        timeout_set(&xfer->timeout_handle, NULL, NULL);
+#ifdef DIAGNOSTIC
+       xfer->busy_free = XFER_BUSY;
+#endif
        DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer));
        return (xfer);
 }
@@ -417,7 +429,7 @@ usbd_free_xfer(struct usbd_xfer *xfer)
        DPRINTFN(5,("usbd_free_xfer: %p\n", xfer));
        if (xfer->rqflags & (URQ_DEV_DMABUF | URQ_AUTO_DMABUF))
                usbd_free_buffer(xfer);
-       xfer->device->bus->methods->freex(xfer->device->bus, xfer);
+       pool_put(&usbd_xfer_pool, xfer);
        return (USBD_NORMAL_COMPLETION);
 }
 
Index: usbdi.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdi.h,v
retrieving revision 1.55
diff -u -p -r1.55 usbdi.h
--- usbdi.h     31 Oct 2013 10:12:19 -0000      1.55
+++ usbdi.h     1 Nov 2013 21:54:43 -0000
@@ -83,6 +83,16 @@ typedef void (*usbd_callback)(struct usb
 
 #define DEVINFOSIZE 1024
 
+/*
+ * Maximum controller xfer length (that is including the usbd_xfer
+ * structure).  Please make sure to update this value when changing the
+ * length of an existing controller xfer type or when adding a new one
+ * that has a larger size than the value below.
+ */
+#define USBD_XFER_MAXSIZE      288
+
+void usbd_init(void);
+
 usbd_status usbd_open_pipe(struct usbd_interface *iface, u_int8_t address,
     u_int8_t flags, struct usbd_pipe **pipe);
 usbd_status usbd_close_pipe(struct usbd_pipe *pipe);
Index: usbdivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.53
diff -u -p -r1.53 usbdivar.h
--- usbdivar.h  1 Nov 2013 12:00:54 -0000       1.53
+++ usbdivar.h  1 Nov 2013 21:54:43 -0000
@@ -54,8 +54,6 @@ struct usbd_bus_methods {
        usbd_status           (*open_pipe)(struct usbd_pipe *pipe);
        void                  (*soft_intr)(void *);
        void                  (*do_poll)(struct usbd_bus *);
-       struct usbd_xfer *    (*allocx)(struct usbd_bus *);
-       void                  (*freex)(struct usbd_bus *, struct usbd_xfer *);
 };
 
 struct usbd_pipe_methods {
@@ -185,7 +183,6 @@ struct usbd_xfer {
        __volatile char         done;
 #ifdef DIAGNOSTIC
        u_int32_t               busy_free;
-#define XFER_FREE 0x46524545
 #define XFER_BUSY 0x42555359
 #define XFER_ONQU 0x4f4e5155
 #endif
Index: ehci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehci.c,v
retrieving revision 1.135
diff -u -p -r1.135 ehci.c
--- ehci.c      1 Nov 2013 12:00:53 -0000       1.135
+++ ehci.c      1 Nov 2013 22:18:10 -0000
@@ -135,9 +135,6 @@ void                ehci_timeout(void *);
 void           ehci_timeout_task(void *);
 void           ehci_intrlist_timeout(void *);
 
-struct usbd_xfer *ehci_allocx(struct usbd_bus *);
-void           ehci_freex(struct usbd_bus *, struct usbd_xfer *);
-
 usbd_status    ehci_root_ctrl_transfer(struct usbd_xfer *);
 usbd_status    ehci_root_ctrl_start(struct usbd_xfer *);
 void           ehci_root_ctrl_abort(struct usbd_xfer *);
@@ -247,8 +244,6 @@ struct usbd_bus_methods ehci_bus_methods
        ehci_open,
        ehci_softintr,
        ehci_poll,
-       ehci_allocx,
-       ehci_freex,
 };
 
 struct usbd_pipe_methods ehci_root_ctrl_methods = {
@@ -1163,56 +1158,6 @@ ehci_reset(struct ehci_softc *sc)
        return (USBD_NORMAL_COMPLETION);
 }
 
-struct usbd_xfer *
-ehci_allocx(struct usbd_bus *bus)
-{
-       struct ehci_softc *sc = (struct ehci_softc *)bus;
-       struct usbd_xfer *xfer;
-
-       xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
-       if (xfer != NULL) {
-               SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
-#ifdef DIAGNOSTIC
-               if (xfer->busy_free != XFER_FREE)
-                       printf("ehci_allocx: xfer=%p not free, 0x%08x\n",
-                           xfer, xfer->busy_free);
-#endif
-       } else
-               xfer = malloc(sizeof(struct ehci_xfer), M_USB, M_NOWAIT);
-
-       if (xfer != NULL) {
-               memset(xfer, 0, sizeof(struct ehci_xfer));
-               usb_init_task(&xfer->abort_task, ehci_timeout_task,
-                   xfer, USB_TASK_TYPE_ABORT);
-               EXFER(xfer)->ehci_xfer_flags = 0;
-#ifdef DIAGNOSTIC
-               EXFER(xfer)->isdone = 1;
-               xfer->busy_free = XFER_BUSY;
-#endif
-       }
-       return (xfer);
-}
-
-void
-ehci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
-{
-       struct ehci_softc *sc = (struct ehci_softc *)bus;
-
-#ifdef DIAGNOSTIC
-       if (xfer->busy_free != XFER_BUSY) {
-               printf("ehci_freex: xfer=%p not busy, 0x%08x\n", xfer,
-                   xfer->busy_free);
-               return;
-       }
-       xfer->busy_free = XFER_FREE;
-       if (!EXFER(xfer)->isdone) {
-               printf("ehci_freex: !isdone\n");
-               return;
-       }
-#endif
-       SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
-}
-
 void
 ehci_device_clear_toggle(struct usbd_pipe *pipe)
 {
@@ -2926,6 +2871,8 @@ ehci_timeout(void *addr)
        }
 
        /* Execute the abort in a process context. */
+       usb_init_task(&exfer->xfer.abort_task, ehci_timeout_task, addr,
+           USB_TASK_TYPE_ABORT);
        usb_add_task(exfer->xfer.pipe->device, &exfer->xfer.abort_task);
 }
 
@@ -3161,9 +3108,6 @@ ehci_device_request(struct usbd_xfer *xf
        exfer->sqtdstart = setup;
        exfer->sqtdend = stat;
 #ifdef DIAGNOSTIC
-       if (!exfer->isdone) {
-               printf("ehci_device_request: not done, exfer=%p\n", exfer);
-       }
        exfer->isdone = 0;
 #endif
 
@@ -3274,9 +3218,6 @@ ehci_device_bulk_start(struct usbd_xfer 
        exfer->sqtdstart = data;
        exfer->sqtdend = dataend;
 #ifdef DIAGNOSTIC
-       if (!exfer->isdone) {
-               printf("ehci_device_bulk_start: not done, ex=%p\n", exfer);
-       }
        exfer->isdone = 0;
 #endif
 
@@ -3447,8 +3388,6 @@ ehci_device_intr_start(struct usbd_xfer 
        exfer->sqtdstart = data;
        exfer->sqtdend = dataend;
 #ifdef DIAGNOSTIC
-       if (!exfer->isdone)
-               printf("ehci_device_intr_start: not done, ex=%p\n", exfer);
        exfer->isdone = 0;
 #endif
 
@@ -3544,10 +3483,6 @@ ehci_device_intr_done(struct usbd_xfer *
                exfer->sqtdstart = data;
                exfer->sqtdend = dataend;
 #ifdef DIAGNOSTIC
-               if (!exfer->isdone) {
-                       printf("ehci_device_intr_done: not done, ex=%p\n",
-                           exfer);
-               }
                exfer->isdone = 0;
 #endif
 
@@ -3639,8 +3574,6 @@ ehci_device_isoc_start(struct usbd_xfer 
        if (xfer->rqflags & URQ_REQUEST)
                panic("ehci_device_isoc_start: request");
 
-       if (!exfer->isdone)
-               printf("ehci_device_isoc_start: not done, ex = %p\n", exfer);
        exfer->isdone = 0;
 #endif
 
Index: ehcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v
retrieving revision 1.27
diff -u -p -r1.27 ehcivar.h
--- ehcivar.h   1 Nov 2013 12:00:54 -0000       1.27
+++ ehcivar.h   1 Nov 2013 21:54:43 -0000
@@ -151,8 +151,6 @@ struct ehci_softc {
        u_int32_t sc_eintrs;
        struct ehci_soft_qh *sc_async_head;
 
-       SIMPLEQ_HEAD(, usbd_xfer) sc_free_xfers; /* free xfers */
-
        struct rwlock sc_doorbell_lock;
 
        struct timeout sc_tmo_intrlist;
Index: ohci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/ohci.c,v
retrieving revision 1.115
diff -u -p -r1.115 ohci.c
--- ohci.c      1 Nov 2013 12:00:54 -0000       1.115
+++ ohci.c      1 Nov 2013 21:54:43 -0000
@@ -118,9 +118,6 @@ struct ohci_soft_itd *ohci_hash_find_itd
 usbd_status    ohci_setup_isoc(struct usbd_pipe *pipe);
 void           ohci_device_isoc_enter(struct usbd_xfer *);
 
-struct usbd_xfer *ohci_allocx(struct usbd_bus *);
-void           ohci_freex(struct usbd_bus *, struct usbd_xfer *);
-
 usbd_status    ohci_root_ctrl_transfer(struct usbd_xfer *);
 usbd_status    ohci_root_ctrl_start(struct usbd_xfer *);
 void           ohci_root_ctrl_abort(struct usbd_xfer *);
@@ -257,8 +254,6 @@ struct usbd_bus_methods ohci_bus_methods
        ohci_open,
        ohci_softintr,
        ohci_poll,
-       ohci_allocx,
-       ohci_freex,
 };
 
 struct usbd_pipe_methods ohci_root_ctrl_methods = {
@@ -736,8 +731,6 @@ ohci_init(struct ohci_softc *sc)
        for (i = 0; i < OHCI_HASH_SIZE; i++)
                LIST_INIT(&sc->sc_hash_itds[i]);
 
-       SIMPLEQ_INIT(&sc->sc_free_xfers);
-
        /* XXX determine alignment by R/W */
        /* Allocate the HCCA area. */
        err = usb_allocmem(&sc->sc_bus, OHCI_HCCA_SIZE,
@@ -943,49 +936,6 @@ ohci_init(struct ohci_softc *sc)
  bad1:
        usb_freemem(&sc->sc_bus, &sc->sc_hccadma);
        return (err);
-}
-
-struct usbd_xfer *
-ohci_allocx(struct usbd_bus *bus)
-{
-       struct ohci_softc *sc = (struct ohci_softc *)bus;
-       struct usbd_xfer *xfer;
-
-       xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
-       if (xfer != NULL) {
-               SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
-#ifdef DIAGNOSTIC
-               if (xfer->busy_free != XFER_FREE) {
-                       printf("ohci_allocx: xfer=%p not free, 0x%08x\n", xfer,
-                              xfer->busy_free);
-               }
-#endif
-       } else {
-               xfer = malloc(sizeof(struct ohci_xfer), M_USB, M_NOWAIT);
-       }
-       if (xfer != NULL) {
-               memset(xfer, 0, sizeof (struct ohci_xfer));
-#ifdef DIAGNOSTIC
-               xfer->busy_free = XFER_BUSY;
-#endif
-       }
-       return (xfer);
-}
-
-void
-ohci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
-{
-       struct ohci_softc *sc = (struct ohci_softc *)bus;
-
-#ifdef DIAGNOSTIC
-       if (xfer->busy_free != XFER_BUSY) {
-               printf("ohci_freex: xfer=%p not busy, 0x%08x\n", xfer,
-                      xfer->busy_free);
-               return;
-       }
-       xfer->busy_free = XFER_FREE;
-#endif
-       SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
 }
 
 #ifdef OHCI_DEBUG
Index: ohcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/ohcivar.h,v
retrieving revision 1.34
diff -u -p -r1.34 ohcivar.h
--- ohcivar.h   1 Nov 2013 12:00:54 -0000       1.34
+++ ohcivar.h   1 Nov 2013 21:54:43 -0000
@@ -106,8 +106,6 @@ struct ohci_softc {
        struct ohci_soft_td *sc_freetds;
        struct ohci_soft_itd *sc_freeitds;
 
-       SIMPLEQ_HEAD(, usbd_xfer) sc_free_xfers; /* free xfers */
-
        struct usbd_xfer *sc_intrxfer;
 
        struct ohci_soft_itd *sc_sidone;
Index: uhci.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhci.c,v
retrieving revision 1.101
diff -u -p -r1.101 uhci.c
--- uhci.c      1 Nov 2013 17:29:01 -0000       1.101
+++ uhci.c      1 Nov 2013 22:03:41 -0000
@@ -161,9 +161,6 @@ void                uhci_rem_loop(struct uhci_softc *s
 usbd_status    uhci_setup_isoc(struct usbd_pipe *pipe);
 void           uhci_device_isoc_enter(struct usbd_xfer *);
 
-struct usbd_xfer *uhci_allocx(struct usbd_bus *);
-void           uhci_freex(struct usbd_bus *, struct usbd_xfer *);
-
 usbd_status    uhci_device_ctrl_transfer(struct usbd_xfer *);
 usbd_status    uhci_device_ctrl_start(struct usbd_xfer *);
 void           uhci_device_ctrl_abort(struct usbd_xfer *);
@@ -274,8 +271,6 @@ struct usbd_bus_methods uhci_bus_methods
        uhci_open,
        uhci_softintr,
        uhci_poll,
-       uhci_allocx,
-       uhci_freex,
 };
 
 struct usbd_pipe_methods uhci_root_ctrl_methods = {
@@ -487,8 +482,6 @@ uhci_init(struct uhci_softc *sc)
 
        LIST_INIT(&sc->sc_intrhead);
 
-       SIMPLEQ_INIT(&sc->sc_free_xfers);
-
        timeout_set(&sc->sc_poll_handle, NULL, NULL);
 
        /* Set up the bus struct. */
@@ -588,7 +581,6 @@ uhci_activate(struct device *self, int a
 int
 uhci_detach(struct uhci_softc *sc, int flags)
 {
-       struct usbd_xfer *xfer;
        int rv = 0;
 
        if (sc->sc_child != NULL)
@@ -602,68 +594,11 @@ uhci_detach(struct uhci_softc *sc, int f
                sc->sc_intr_xfer = NULL;
        }
 
-       /* Free all xfers associated with this HC. */
-       for (;;) {
-               xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
-               if (xfer == NULL)
-                       break;
-               SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
-               free(xfer, M_USB);
-       }
-
        /* XXX free other data structures XXX */
 
        return (rv);
 }
 
-struct usbd_xfer *
-uhci_allocx(struct usbd_bus *bus)
-{
-       struct uhci_softc *sc = (struct uhci_softc *)bus;
-       struct usbd_xfer *xfer;
-
-       xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
-       if (xfer != NULL) {
-               SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
-#ifdef DIAGNOSTIC
-               if (xfer->busy_free != XFER_FREE) {
-                       printf("uhci_allocx: xfer=%p not free, 0x%08x\n", xfer,
-                              xfer->busy_free);
-               }
-#endif
-       } else {
-               xfer = malloc(sizeof(struct uhci_xfer), M_USB, M_NOWAIT);
-       }
-       if (xfer != NULL) {
-               memset(xfer, 0, sizeof (struct uhci_xfer));
-#ifdef DIAGNOSTIC
-               UXFER(xfer)->isdone = 1;
-               xfer->busy_free = XFER_BUSY;
-#endif
-       }
-       return (xfer);
-}
-
-void
-uhci_freex(struct usbd_bus *bus, struct usbd_xfer *xfer)
-{
-       struct uhci_softc *sc = (struct uhci_softc *)bus;
-
-#ifdef DIAGNOSTIC
-       if (xfer->busy_free != XFER_BUSY) {
-               printf("uhci_freex: xfer=%p not busy, 0x%08x\n", xfer,
-                      xfer->busy_free);
-               return;
-       }
-       xfer->busy_free = XFER_FREE;
-       if (!UXFER(xfer)->isdone) {
-               printf("uhci_freex: !isdone\n");
-               return;
-       }
-#endif
-       SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
-}
-
 #ifdef UHCI_DEBUG
 void
 uhci_dumpregs(struct uhci_softc *sc)
@@ -1754,9 +1689,6 @@ uhci_device_bulk_start(struct usbd_xfer 
        ex->stdstart = data;
        ex->stdend = dataend;
 #ifdef DIAGNOSTIC
-       if (!ex->isdone) {
-               printf("uhci_device_bulk_start: not done, ex=%p\n", ex);
-       }
        ex->isdone = 0;
 #endif
 
@@ -1988,9 +1920,6 @@ uhci_device_intr_start(struct usbd_xfer 
        ex->stdstart = data;
        ex->stdend = dataend;
 #ifdef DIAGNOSTIC
-       if (!ex->isdone) {
-               printf("uhci_device_intr_transfer: not done, ex=%p\n", ex);
-       }
        ex->isdone = 0;
 #endif
 
@@ -2150,9 +2079,6 @@ uhci_device_request(struct usbd_xfer *xf
        ex->stdstart = setup;
        ex->stdend = stat;
 #ifdef DIAGNOSTIC
-       if (!ex->isdone) {
-               printf("uhci_device_request: not done, ex=%p\n", ex);
-       }
        ex->isdone = 0;
 #endif
 
@@ -2337,8 +2263,6 @@ uhci_device_isoc_start(struct usbd_xfer 
        ex->stdstart = end;
        ex->stdend = end;
 #ifdef DIAGNOSTIC
-       if (!ex->isdone)
-               printf("uhci_device_isoc_start: not done, ex=%p\n", ex);
        ex->isdone = 0;
 #endif
        uhci_add_intr_list(sc, ex);
@@ -2510,11 +2434,6 @@ uhci_device_isoc_done(struct usbd_xfer *
                return;
 
 #ifdef DIAGNOSTIC
-       if (xfer->busy_free == XFER_FREE) {
-               printf("uhci_device_isoc_done: xfer=%p is free\n", xfer);
-               return;
-       }
-
         if (ex->stdend == NULL) {
                 printf("uhci_device_isoc_done: xfer=%p stdend==NULL\n", xfer);
 #ifdef UHCI_DEBUG
@@ -2572,9 +2491,6 @@ uhci_device_intr_done(struct usbd_xfer *
                ex->stdstart = data;
                ex->stdend = dataend;
 #ifdef DIAGNOSTIC
-               if (!ex->isdone) {
-                       printf("uhci_device_intr_done: not done, ex=%p\n", ex);
-               }
                ex->isdone = 0;
 #endif
                for (i = 0; i < npoll; i++) {
Index: uhcivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/uhcivar.h,v
retrieving revision 1.28
diff -u -p -r1.28 uhcivar.h
--- uhcivar.h   1 Nov 2013 17:29:02 -0000       1.28
+++ uhcivar.h   1 Nov 2013 21:54:43 -0000
@@ -140,8 +140,6 @@ struct uhci_softc {
        struct uhci_soft_td *sc_freetds; /* TD free list */
        struct uhci_soft_qh *sc_freeqhs; /* QH free list */
 
-       SIMPLEQ_HEAD(, usbd_xfer) sc_free_xfers; /* free xfers */
-
        u_int8_t sc_addr;               /* device address */
        u_int8_t sc_conf;               /* device configuration */
 

Reply via email to