? usb.task.compl--broken.diff Index: usb.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usb.c,v retrieving revision 1.130 diff -p -r1.130 usb.c *** usb.c 10 Jun 2012 06:15:54 -0000 1.130 --- usb.c 29 Dec 2012 12:09:09 -0000 *************** __KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.13 *** 73,79 **** #ifdef USB_DEBUG #define DPRINTF(x) if (usbdebug) printf x #define DPRINTFN(n,x) if (usbdebug>(n)) printf x ! int usbdebug = 0; /* * 0 - do usual exploration * 1 - do not use timeout exploration --- 73,79 ---- #ifdef USB_DEBUG #define DPRINTF(x) if (usbdebug) printf x #define DPRINTFN(n,x) if (usbdebug>(n)) printf x ! int usbdebug = 6; /* * 0 - do usual exploration * 1 - do not use timeout exploration *************** const struct cdevsw usb_cdevsw = { *** 122,127 **** --- 122,128 ---- }; Static void usb_discover(struct usb_softc *); + Static void usb_create_task_threads(device_t); Static void usb_create_event_thread(device_t); Static void usb_event_thread(void *); Static void usb_task_thread(void *); *************** usb_attach(device_t parent, device_t sel *** 198,203 **** --- 199,206 ---- } aprint_normal("\n"); + usb_create_task_threads(self); + RUN_ONCE(&init_control, usb_once_init); config_interrupts(self, usb_doattach); } *************** void *** 305,312 **** usb_create_event_thread(device_t self) { struct usb_softc *sc = device_private(self); - struct usb_taskq *taskq; - int i; if (kthread_create(PRI_NONE, sc->sc_bus->lock ? KTHREAD_MPSAFE : 0, NULL, --- 308,313 ---- *************** usb_create_event_thread(device_t self) *** 316,321 **** --- 317,330 ---- device_xname(self)); panic("usb_create_event_thread"); } + } + + void + usb_create_task_threads(device_t self) + { + struct usb_taskq *taskq; + int i; + for (i = 0; i < USB_NUM_TASKQS; i++) { taskq = &usb_taskq[i]; *************** usb_create_event_thread(device_t self) *** 323,328 **** --- 332,338 ---- continue; TAILQ_INIT(&taskq->tasks); + DPRINTFN(2,("%s: taskq=%p\n", __func__, &taskq->tasks)); mutex_init(&taskq->lock, MUTEX_DEFAULT, IPL_NONE); cv_init(&taskq->cv, "usbtsk"); taskq->taskcreated = 1; *************** usb_create_event_thread(device_t self) *** 334,339 **** --- 344,354 ---- panic("usb_create_event_thread task"); } } + #if 0 + printf("XXX: waiting for a couple of seconds\n"); + kpause("usb-start", FALSE, hz * 2, NULL); + printf("XXX: done\n"); + #endif } /* *************** usb_task_thread(void *arg) *** 433,444 **** struct usb_taskq *taskq; taskq = arg; ! DPRINTF(("usb_task_thread: start taskq %s\n", taskq->name)); mutex_enter(&taskq->lock); for (;;) { task = TAILQ_FIRST(&taskq->tasks); if (task == NULL) { cv_wait(&taskq->cv, &taskq->lock); task = TAILQ_FIRST(&taskq->tasks); } --- 448,460 ---- struct usb_taskq *taskq; taskq = arg; ! DPRINTFN(2, ("usb_task_thread: start thread taskq %s\n", taskq->name)); mutex_enter(&taskq->lock); for (;;) { task = TAILQ_FIRST(&taskq->tasks); if (task == NULL) { + DPRINTFN(2,("usb_task_thread: sleeping\n")); cv_wait(&taskq->cv, &taskq->lock); task = TAILQ_FIRST(&taskq->tasks); } *************** usb_task_thread(void *arg) *** 450,455 **** --- 466,472 ---- task->fun(task->arg); mutex_enter(&taskq->lock); } + DPRINTFN(2,("usb_task_thread: done task=%p\n", task)); } mutex_exit(&taskq->lock); } Index: usbdi.c =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdi.c,v retrieving revision 1.138 diff -p -r1.138 usbdi.c *** usbdi.c 10 Jun 2012 06:15:55 -0000 1.138 --- usbdi.c 29 Dec 2012 12:09:09 -0000 *************** Static void usbd_start_next(usbd_pipe_ha *** 71,76 **** --- 71,79 ---- Static usbd_status usbd_open_pipe_ival (usbd_interface_handle, u_int8_t, u_int8_t, usbd_pipe_handle *, int); + static void usb_run_completion_callback_via_task(void *arg); + static void usb_run_completion_callback(usbd_xfer_handle xfer); + static inline int usbd_xfer_isread(usbd_xfer_handle xfer) { *************** usbd_alloc_xfer(usbd_device_handle dev) *** 405,411 **** dev->bus->methods->get_lock ? CALLOUT_MPSAFE : 0); cv_init(&xfer->cv, "usbxfer"); cv_init(&xfer->hccv, "usbhcxfer"); ! DPRINTFN(5,("usbd_alloc_xfer() = %p\n", xfer)); return (xfer); } --- 408,417 ---- dev->bus->methods->get_lock ? CALLOUT_MPSAFE : 0); cv_init(&xfer->cv, "usbxfer"); cv_init(&xfer->hccv, "usbhcxfer"); ! usb_init_task(&xfer->compl_task, ! usb_run_completion_callback_via_task, xfer); ! DPRINTFN(5,("%s: xfer %p fun %p\n", ! __func__, xfer, usb_run_completion_callback_via_task)); return (xfer); } *************** usbd_free_xfer(usbd_xfer_handle xfer) *** 421,426 **** --- 427,433 ---- printf("usbd_free_xfer: timout_handle pending"); } #endif + usb_rem_task(xfer->pipe->device, &xfer->compl_task); cv_destroy(&xfer->cv); cv_destroy(&xfer->hccv); xfer->device->bus->methods->freex(xfer->device->bus, xfer); *************** usb_transfer_complete(usbd_xfer_handle x *** 776,785 **** { usbd_pipe_handle pipe = xfer->pipe; usb_dma_t *dmap = &xfer->dmabuf; - int sync = xfer->flags & USBD_SYNCHRONOUS; - int erred = xfer->status == USBD_CANCELLED || - xfer->status == USBD_TIMEOUT; - int repeat, polling; DPRINTFN(5, ("usb_transfer_complete: pipe=%p xfer=%p status=%d " "actlen=%d\n", pipe, xfer, xfer->status, xfer->actlen)); --- 783,788 ---- *************** usb_transfer_complete(usbd_xfer_handle x *** 799,808 **** return; } #endif - repeat = pipe->repeat; - polling = pipe->device->bus->use_polling; /* XXXX */ ! if (polling) pipe->running = 0; if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 && --- 802,809 ---- return; } #endif /* XXXX */ ! if (pipe->device->bus->use_polling) pipe->running = 0; if (!(xfer->flags & USBD_NO_COPY) && xfer->actlen != 0 && *************** usb_transfer_complete(usbd_xfer_handle x *** 819,832 **** /* if we allocated the buffer in usbd_transfer() we free it here. */ if (xfer->rqflags & URQ_AUTO_DMABUF) { ! if (!repeat) { struct usbd_bus *bus = pipe->device->bus; bus->methods->freem(bus, dmap); xfer->rqflags &= ~URQ_AUTO_DMABUF; } } ! if (!repeat) { /* Remove request from queue. */ #ifdef DIAGNOSTIC if (xfer != SIMPLEQ_FIRST(&pipe->queue)) --- 820,833 ---- /* if we allocated the buffer in usbd_transfer() we free it here. */ if (xfer->rqflags & URQ_AUTO_DMABUF) { ! if (!pipe->repeat) { struct usbd_bus *bus = pipe->device->bus; bus->methods->freem(bus, dmap); xfer->rqflags &= ~URQ_AUTO_DMABUF; } } ! if (!pipe->repeat) { /* Remove request from queue. */ #ifdef DIAGNOSTIC if (xfer != SIMPLEQ_FIRST(&pipe->queue)) *************** usb_transfer_complete(usbd_xfer_handle x *** 837,843 **** SIMPLEQ_REMOVE_HEAD(&pipe->queue, next); } DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", ! repeat, SIMPLEQ_FIRST(&pipe->queue))); /* Count completed transfers. */ ++pipe->device->bus->stats.uds_requests --- 838,844 ---- SIMPLEQ_REMOVE_HEAD(&pipe->queue, next); } DPRINTFN(5,("usb_transfer_complete: repeat=%d new head=%p\n", ! pipe->repeat, SIMPLEQ_FIRST(&pipe->queue))); /* Count completed transfers. */ ++pipe->device->bus->stats.uds_requests *************** usb_transfer_complete(usbd_xfer_handle x *** 851,857 **** xfer->status = USBD_SHORT_XFER; } ! if (repeat) { if (xfer->callback) { if (pipe->device->bus->lock) mutex_exit(pipe->device->bus->lock); --- 852,891 ---- xfer->status = USBD_SHORT_XFER; } ! if (pipe->device->bus->use_polling) ! usb_run_completion_callback(xfer); ! else ! usb_add_task(pipe->device, &xfer->compl_task, USB_TASKQ_COMPLETION); ! } ! ! /* ! * We run completions in the task thread (we might want a special ! * completion thread.) The callback via task needs to take the ! * pipe lock around the callback handling, where as the direct ! * call from usb_transfer_complete() already has it. ! */ ! static void ! usb_run_completion_callback_via_task(void *arg) ! { ! usbd_xfer_handle xfer = arg; ! usbd_pipe_handle pipe = xfer->pipe; ! int s; ! ! DPRINTFN(3,("%s: xfer=%p\n", __func__, xfer)); ! usbd_lock_pipe(pipe); ! usb_run_completion_callback(xfer); ! usbd_unlock_pipe(pipe); ! } ! ! static void ! usb_run_completion_callback(usbd_xfer_handle xfer) ! { ! usbd_pipe_handle pipe = xfer->pipe; ! int sync = xfer->flags & USBD_SYNCHRONOUS; ! int erred = xfer->status == USBD_CANCELLED || ! xfer->status == USBD_TIMEOUT; ! ! if (pipe->repeat) { if (xfer->callback) { if (pipe->device->bus->lock) mutex_exit(pipe->device->bus->lock); *************** usb_transfer_complete(usbd_xfer_handle x *** 871,884 **** } } ! if (sync && !polling) { if (pipe->device->bus->lock) cv_broadcast(&xfer->cv); else wakeup(xfer); /* XXXSMP ok */ } ! if (!repeat) { /* XXX should we stop the queue on all errors? */ if (erred && pipe->iface != NULL) /* not control pipe */ pipe->running = 0; --- 905,918 ---- } } ! if (sync && !pipe->device->bus->use_polling) { if (pipe->device->bus->lock) cv_broadcast(&xfer->cv); else wakeup(xfer); /* XXXSMP ok */ } ! if (!pipe->repeat) { /* XXX should we stop the queue on all errors? */ if (erred && pipe->iface != NULL) /* not control pipe */ pipe->running = 0; Index: usbdi.h =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdi.h,v retrieving revision 1.83 diff -p -r1.83 usbdi.h *** usbdi.h 10 Jun 2012 06:15:55 -0000 1.83 --- usbdi.h 29 Dec 2012 12:09:09 -0000 *************** struct usb_task { *** 202,209 **** }; #define USB_TASKQ_HC 0 #define USB_TASKQ_DRIVER 1 ! #define USB_NUM_TASKQS 2 ! #define USB_TASKQ_NAMES {"usbtask-hc", "usbtask-dr"} void usb_add_task(usbd_device_handle, struct usb_task *, int); void usb_rem_task(usbd_device_handle, struct usb_task *); --- 202,210 ---- }; #define USB_TASKQ_HC 0 #define USB_TASKQ_DRIVER 1 ! #define USB_TASKQ_COMPLETION 2 ! #define USB_NUM_TASKQS 3 ! #define USB_TASKQ_NAMES {"usbtask-hc", "usbtask-dr", "usbtask-cp"} void usb_add_task(usbd_device_handle, struct usb_task *, int); void usb_rem_task(usbd_device_handle, struct usb_task *); Index: usbdivar.h =================================================================== RCS file: /cvsroot/src/sys/dev/usb/usbdivar.h,v retrieving revision 1.97 diff -p -r1.97 usbdivar.h *** usbdivar.h 10 Jun 2012 06:15:55 -0000 1.97 --- usbdivar.h 29 Dec 2012 12:09:09 -0000 *************** struct usbd_xfer { *** 263,268 **** --- 263,270 ---- kcondvar_t hccv; /* private use by the HC driver */ struct callout timeout_handle; + + struct usb_task compl_task; /* completion task */ }; void usbd_init(void);