Module Name:    src
Committed By:   riastradh
Date:           Thu Jul 17 18:42:38 UTC 2014

Modified Files:
        src/sys/dev/usb: usb.c usbdi.h

Log Message:
Fix usb task queue locking.


To generate a diff of this commit:
cvs rdiff -u -r1.149 -r1.150 src/sys/dev/usb/usb.c
cvs rdiff -u -r1.89 -r1.90 src/sys/dev/usb/usbdi.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/usb/usb.c
diff -u src/sys/dev/usb/usb.c:1.149 src/sys/dev/usb/usb.c:1.150
--- src/sys/dev/usb/usb.c:1.149	Sun Mar 16 05:20:29 2014
+++ src/sys/dev/usb/usb.c	Thu Jul 17 18:42:37 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: usb.c,v 1.149 2014/03/16 05:20:29 dholland Exp $	*/
+/*	$NetBSD: usb.c,v 1.150 2014/07/17 18:42:37 riastradh Exp $	*/
 
 /*
  * Copyright (c) 1998, 2002, 2008, 2012 The NetBSD Foundation, Inc.
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.149 2014/03/16 05:20:29 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: usb.c,v 1.150 2014/07/17 18:42:37 riastradh Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_compat_netbsd.h"
@@ -355,28 +355,40 @@ usb_add_task(usbd_device_handle dev, str
 {
 	struct usb_taskq *taskq;
 
+	KASSERT(0 <= queue);
+	KASSERT(queue < USB_NUM_TASKQS);
 	taskq = &usb_taskq[queue];
 	mutex_enter(&taskq->lock);
-	if (task->queue == -1) {
+	if (atomic_cas_uint(&task->queue, USB_NUM_TASKQS, queue) ==
+	    USB_NUM_TASKQS) {
 		DPRINTFN(2,("usb_add_task: task=%p\n", task));
 		TAILQ_INSERT_TAIL(&taskq->tasks, task, next);
 		task->queue = queue;
+		cv_signal(&taskq->cv);
 	} else {
 		DPRINTFN(3,("usb_add_task: task=%p on q\n", task));
 	}
-	cv_signal(&taskq->cv);
 	mutex_exit(&taskq->lock);
 }
 
+/*
+ * XXX This does not wait for completion!  Most uses need such an
+ * operation.  Urgh...
+ */
 void
 usb_rem_task(usbd_device_handle dev, struct usb_task *task)
 {
+	unsigned queue;
 
-	if (task->queue != -1) {
-		struct usb_taskq *taskq = &usb_taskq[task->queue];
+	while ((queue = task->queue) != USB_NUM_TASKQS) {
+		struct usb_taskq *taskq = &usb_taskq[queue];
 		mutex_enter(&taskq->lock);
-		TAILQ_REMOVE(&taskq->tasks, task, next);
-		task->queue = -1;
+		if (__predict_true(task->queue == queue)) {
+			TAILQ_REMOVE(&taskq->tasks, task, next);
+			task->queue = USB_NUM_TASKQS;
+			mutex_exit(&taskq->lock);
+			break;
+		}
 		mutex_exit(&taskq->lock);
 	}
 }
@@ -444,7 +456,7 @@ usb_task_thread(void *arg)
 		DPRINTFN(2,("usb_task_thread: woke up task=%p\n", task));
 		if (task != NULL) {
 			TAILQ_REMOVE(&taskq->tasks, task, next);
-			task->queue = -1;
+			task->queue = USB_NUM_TASKQS;
 			mutex_exit(&taskq->lock);
 
 			if (!(task->flags & USB_TASKQ_MPSAFE))

Index: src/sys/dev/usb/usbdi.h
diff -u src/sys/dev/usb/usbdi.h:1.89 src/sys/dev/usb/usbdi.h:1.90
--- src/sys/dev/usb/usbdi.h:1.89	Thu Sep 26 07:25:31 2013
+++ src/sys/dev/usb/usbdi.h	Thu Jul 17 18:42:37 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: usbdi.h,v 1.89 2013/09/26 07:25:31 skrll Exp $	*/
+/*	$NetBSD: usbdi.h,v 1.90 2014/07/17 18:42:37 riastradh Exp $	*/
 /*	$FreeBSD: src/sys/dev/usb/usbdi.h,v 1.18 1999/11/17 22:33:49 n_hibma Exp $	*/
 
 /*
@@ -202,7 +202,7 @@ struct usb_task {
 	TAILQ_ENTRY(usb_task) next;
 	void (*fun)(void *);
 	void *arg;
-	int queue;
+	volatile unsigned queue;
 	int flags;
 };
 #define	USB_TASKQ_HC		0
@@ -213,7 +213,7 @@ struct usb_task {
 
 void usb_add_task(usbd_device_handle, struct usb_task *, int);
 void usb_rem_task(usbd_device_handle, struct usb_task *);
-#define usb_init_task(t, f, a, fl) ((t)->fun = (f), (t)->arg = (a), (t)->queue = -1, (t)->flags = (fl))
+#define usb_init_task(t, f, a, fl) ((t)->fun = (f), (t)->arg = (a), (t)->queue = USB_NUM_TASKQS, (t)->flags = (fl))
 
 struct usb_devno {
 	u_int16_t ud_vendor;

Reply via email to