diff options
author | iedowse <iedowse@FreeBSD.org> | 2006-10-19 01:15:58 +0000 |
---|---|---|
committer | iedowse <iedowse@FreeBSD.org> | 2006-10-19 01:15:58 +0000 |
commit | 89a43922e88de3a41c45f554250ae9164b8e6342 (patch) | |
tree | 5e89e7ff60db7f0744b5caa38587e791445b9e29 /sys/dev/usb | |
parent | 82d986f8fdce6ac777e32dc10660fae1ef67e2ae (diff) | |
download | FreeBSD-src-89a43922e88de3a41c45f554250ae9164b8e6342.zip FreeBSD-src-89a43922e88de3a41c45f554250ae9164b8e6342.tar.gz |
Use a different task queue for host controller and peripheral driver
tasks. Since the host controllers rely on tasks to process transfer
timeouts, if a synchronous transfer from a driver was invoked from
a task and timed out, it would never complete because the single
task thread was stuck performing the synchronous transfer so couldn't
process the timeout.
This affected the axe, udav and ural drivers.
Problem hardware provided by: guido
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/ehci.c | 3 | ||||
-rw-r--r-- | sys/dev/usb/if_axe.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/if_udav.c | 4 | ||||
-rw-r--r-- | sys/dev/usb/if_ural.c | 2 | ||||
-rw-r--r-- | sys/dev/usb/ohci.c | 3 | ||||
-rw-r--r-- | sys/dev/usb/uhci.c | 3 | ||||
-rw-r--r-- | sys/dev/usb/usb.c | 86 | ||||
-rw-r--r-- | sys/dev/usb/usbdi.h | 10 |
8 files changed, 74 insertions, 39 deletions
diff --git a/sys/dev/usb/ehci.c b/sys/dev/usb/ehci.c index ca311ec..6a396b9 100644 --- a/sys/dev/usb/ehci.c +++ b/sys/dev/usb/ehci.c @@ -2735,7 +2735,8 @@ ehci_timeout(void *addr) } /* Execute the abort in a process context. */ - usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task); + usb_add_task(exfer->xfer.pipe->device, &exfer->abort_task, + USB_TASKQ_HC); } void diff --git a/sys/dev/usb/if_axe.c b/sys/dev/usb/if_axe.c index 8921919..94e386c 100644 --- a/sys/dev/usb/if_axe.c +++ b/sys/dev/usb/if_axe.c @@ -742,7 +742,7 @@ axe_tick(void *xsc) return; /* Perform periodic stuff in process context */ - usb_add_task(sc->axe_udev, &sc->axe_tick_task); + usb_add_task(sc->axe_udev, &sc->axe_tick_task, USB_TASKQ_DRIVER); } static void diff --git a/sys/dev/usb/if_udav.c b/sys/dev/usb/if_udav.c index e2a2a24..dbc5ab9 100644 --- a/sys/dev/usb/if_udav.c +++ b/sys/dev/usb/if_udav.c @@ -1244,7 +1244,7 @@ udav_send(struct udav_softc *sc, struct mbuf *m, int idx) printf("%s: udav_send error=%s\n", device_get_nameunit(sc->sc_dev), usbd_errstr(err)); /* Stop the interface */ - usb_add_task(sc->sc_udev, &sc->sc_stop_task); + usb_add_task(sc->sc_udev, &sc->sc_stop_task, USB_TASKQ_DRIVER); return (EIO); } @@ -1714,7 +1714,7 @@ udav_tick(void *xsc) return; /* Perform periodic stuff in process context */ - usb_add_task(sc->sc_udev, &sc->sc_tick_task); + usb_add_task(sc->sc_udev, &sc->sc_tick_task, USB_TASKQ_DRIVER); } static void diff --git a/sys/dev/usb/if_ural.c b/sys/dev/usb/if_ural.c index 4c8e181..9708256 100644 --- a/sys/dev/usb/if_ural.c +++ b/sys/dev/usb/if_ural.c @@ -818,7 +818,7 @@ ural_newstate(struct ieee80211com *ic, enum ieee80211_state nstate, int arg) /* do it in a process context */ sc->sc_state = nstate; - usb_add_task(sc->sc_udev, &sc->sc_task); + usb_add_task(sc->sc_udev, &sc->sc_task, USB_TASKQ_DRIVER); return 0; } diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c index 09c2ad3..6026279 100644 --- a/sys/dev/usb/ohci.c +++ b/sys/dev/usb/ohci.c @@ -1991,7 +1991,8 @@ ohci_timeout(void *addr) } /* Execute the abort in a process context. */ - usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task); + usb_add_task(oxfer->xfer.pipe->device, &oxfer->abort_task, + USB_TASKQ_HC); } void diff --git a/sys/dev/usb/uhci.c b/sys/dev/usb/uhci.c index 577b3c8..69380d9 100644 --- a/sys/dev/usb/uhci.c +++ b/sys/dev/usb/uhci.c @@ -1527,7 +1527,8 @@ uhci_timeout(void *addr) } /* Execute the abort in a process context. */ - usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task); + usb_add_task(uxfer->xfer.pipe->device, &uxfer->abort_task, + USB_TASKQ_HC); } void diff --git a/sys/dev/usb/usb.c b/sys/dev/usb/usb.c index 1930108..0267b63 100644 --- a/sys/dev/usb/usb.c +++ b/sys/dev/usb/usb.c @@ -140,7 +140,14 @@ struct usb_softc { char sc_dying; }; -TAILQ_HEAD(, usb_task) usb_all_tasks; +struct usb_taskq { + TAILQ_HEAD(, usb_task) tasks; + struct proc *task_thread_proc; + const char *name; + int taskcreated; /* task thread exists. */ +}; + +static struct usb_taskq usb_taskq[USB_NUM_TASKQS]; #if defined(__NetBSD__) || defined(__OpenBSD__) cdev_decl(usb); @@ -173,12 +180,10 @@ static bus_child_detached_t usb_child_detached; static void usb_create_event_thread(void *); static void usb_event_thread(void *); static void usb_task_thread(void *); -static struct proc *usb_task_thread_proc = NULL; #ifdef __FreeBSD__ static struct cdev *usb_dev; /* The /dev/usb device. */ static int usb_ndevs; /* Number of /dev/usbN devices. */ -static int usb_taskcreated; /* USB task thread exists. */ /* Busses to explore at the end of boot-time device configuration. */ static TAILQ_HEAD(, usb_softc) usb_coldexplist = TAILQ_HEAD_INITIALIZER(usb_coldexplist); @@ -343,10 +348,14 @@ USB_ATTACH(usb) USB_ATTACH_SUCCESS_RETURN; } +static const char *taskq_names[] = USB_TASKQ_NAMES; + void usb_create_event_thread(void *arg) { struct usb_softc *sc = arg; + struct usb_taskq *taskq; + int i; if (usb_kthread_create1(usb_event_thread, sc, &sc->sc_event_thread, "%s", device_get_nameunit(sc->sc_dev))) { @@ -354,13 +363,18 @@ usb_create_event_thread(void *arg) device_get_nameunit(sc->sc_dev)); panic("usb_create_event_thread"); } - if (usb_taskcreated == 0) { - usb_taskcreated = 1; - TAILQ_INIT(&usb_all_tasks); - if (usb_kthread_create2(usb_task_thread, NULL, - &usb_task_thread_proc, "usbtask")) { - printf("unable to create task thread\n"); - panic("usb_create_event_thread task"); + for (i = 0; i < USB_NUM_TASKQS; i++) { + taskq = &usb_taskq[i]; + + if (taskq->taskcreated == 0) { + taskq->taskcreated = 1; + taskq->name = taskq_names[i]; + TAILQ_INIT(&taskq->tasks); + if (usb_kthread_create2(usb_task_thread, taskq, + &taskq->task_thread_proc, taskq->name)) { + printf("unable to create task thread\n"); + panic("usb_create_event_thread task"); + } } } } @@ -371,31 +385,35 @@ usb_create_event_thread(void *arg) * context ASAP. */ void -usb_add_task(usbd_device_handle dev, struct usb_task *task) +usb_add_task(usbd_device_handle dev, struct usb_task *task, int queue) { + struct usb_taskq *taskq; int s; s = splusb(); - if (!task->onqueue) { + taskq = &usb_taskq[queue]; + if (task->queue == -1) { DPRINTFN(2,("usb_add_task: task=%p\n", task)); - TAILQ_INSERT_TAIL(&usb_all_tasks, task, next); - task->onqueue = 1; + TAILQ_INSERT_TAIL(&taskq->tasks, task, next); + task->queue = queue; } else { DPRINTFN(3,("usb_add_task: task=%p on q\n", task)); } - wakeup(&usb_all_tasks); + wakeup(&taskq->tasks); splx(s); } void usb_rem_task(usbd_device_handle dev, struct usb_task *task) { + struct usb_taskq *taskq; int s; s = splusb(); - if (task->onqueue) { - TAILQ_REMOVE(&usb_all_tasks, task, next); - task->onqueue = 0; + if (task->queue != -1) { + taskq = &usb_taskq[task->queue]; + TAILQ_REMOVE(&taskq->tasks, task, next); + task->queue = -1; } splx(s); } @@ -462,25 +480,27 @@ void usb_task_thread(void *arg) { struct usb_task *task; + struct usb_taskq *taskq; int s; #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 mtx_lock(&Giant); #endif - DPRINTF(("usb_task_thread: start\n")); + taskq = arg; + DPRINTF(("usb_task_thread: start taskq %s\n", taskq->name)); s = splusb(); while (usb_ndevs > 0) { - task = TAILQ_FIRST(&usb_all_tasks); + task = TAILQ_FIRST(&taskq->tasks); if (task == NULL) { - tsleep(&usb_all_tasks, PWAIT, "usbtsk", 0); - task = TAILQ_FIRST(&usb_all_tasks); + tsleep(&taskq->tasks, PWAIT, "usbtsk", 0); + task = TAILQ_FIRST(&taskq->tasks); } DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task)); if (task != NULL) { - TAILQ_REMOVE(&usb_all_tasks, task, next); - task->onqueue = 0; + TAILQ_REMOVE(&taskq->tasks, task, next); + task->queue = -1; splx(s); task->fun(task->arg); s = splusb(); @@ -488,8 +508,8 @@ usb_task_thread(void *arg) } splx(s); - usb_taskcreated = 0; - wakeup(&usb_taskcreated); + taskq->taskcreated = 0; + wakeup(&taskq->taskcreated); DPRINTF(("usb_event_thread: exit\n")); kthread_exit(0); @@ -909,6 +929,8 @@ USB_DETACH(usb) { USB_DETACH_START(usb, sc); struct usb_event ue; + struct usb_taskq *taskq; + int i; DPRINTF(("usb_detach: start\n")); @@ -932,9 +954,15 @@ USB_DETACH(usb) if (--usb_ndevs == 0) { destroy_dev(usb_dev); usb_dev = NULL; - wakeup(&usb_all_tasks); - if (tsleep(&usb_taskcreated, PWAIT, "usbtdt", hz * 60)) - printf("usb task thread didn't die\n"); + for (i = 0; i < USB_NUM_TASKQS; i++) { + taskq = &usb_taskq[i]; + wakeup(&taskq->tasks); + if (tsleep(&taskq->taskcreated, PWAIT, "usbtdt", + hz * 60)) { + printf("usb task thread %s didn't die\n", + taskq->name); + } + } } #endif diff --git a/sys/dev/usb/usbdi.h b/sys/dev/usb/usbdi.h index cedb6d9..fb1af43 100644 --- a/sys/dev/usb/usbdi.h +++ b/sys/dev/usb/usbdi.h @@ -193,12 +193,16 @@ struct usb_task { TAILQ_ENTRY(usb_task) next; void (*fun)(void *); void *arg; - char onqueue; + int queue; }; +#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 *); +void usb_add_task(usbd_device_handle, struct usb_task *, int queue); void usb_rem_task(usbd_device_handle, struct usb_task *); -#define usb_init_task(t, f, a) ((t)->fun = (f), (t)->arg = (a), (t)->onqueue = 0) +#define usb_init_task(t, f, a) ((t)->fun = (f), (t)->arg = (a), (t)->queue = -1) struct usb_devno { u_int16_t ud_vendor; |