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 */