summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authoriedowse <iedowse@FreeBSD.org>2006-10-19 01:15:58 +0000
committeriedowse <iedowse@FreeBSD.org>2006-10-19 01:15:58 +0000
commit89a43922e88de3a41c45f554250ae9164b8e6342 (patch)
tree5e89e7ff60db7f0744b5caa38587e791445b9e29 /sys/dev/usb
parent82d986f8fdce6ac777e32dc10660fae1ef67e2ae (diff)
downloadFreeBSD-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.c3
-rw-r--r--sys/dev/usb/if_axe.c2
-rw-r--r--sys/dev/usb/if_udav.c4
-rw-r--r--sys/dev/usb/if_ural.c2
-rw-r--r--sys/dev/usb/ohci.c3
-rw-r--r--sys/dev/usb/uhci.c3
-rw-r--r--sys/dev/usb/usb.c86
-rw-r--r--sys/dev/usb/usbdi.h10
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;
OpenPOWER on IntegriCloud