Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 23 Jan 2009 19:05:59 GMT
From:      Hans Petter Selasky <hselasky@FreeBSD.org>
To:        Perforce Change Reviews <perforce@FreeBSD.org>
Subject:   PERFORCE change 156577 for review
Message-ID:  <200901231905.n0NJ5xaB090658@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=156577

Change 156577 by hselasky@hselasky_laptop001 on 2009/01/23 19:05:38

	
	Fix issues with USB bluetooth negraph node and detach.
	- Cleanup code.
	- Reduce the number of mutexes.
	- Needs review by Maksim.

Affected files ...

.. //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2.c#15 edit
.. //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2_var.h#7 edit

Differences ...

==== //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2.c#15 (text+ko) ====

@@ -37,22 +37,12 @@
  * driver will *NOT* create traditional /dev/ enties, only Netgraph 
  * node.
  *
- * NOTE ON LOCKS USED: ng_ubt2 drives uses 3 locks (mutexes)
+ * NOTE ON LOCKS USED: ng_ubt2 drives uses 1 lock
  *
- * 1) sc_if_mtx[0] - lock for device's interface #0. This lock is used
- *    by USB2 for any USB request going over device's interface #0, i.e.
- *    interrupt, control and bulk transfers.
- * 
- * 2) sc_if_mtx[1] - lock for device's interface #1. This lock is used
- *    by USB2 for any USB request going over device's interface #1, i.e
- *    isoc. transfers.
- * 
- * 3) sc_mbufq_mtx - lock for mbufq and task flags. This lock is used
- *    to protect device's outgoing mbuf queues and task flags. This lock
- *    *SHOULD NOT* be grabbed for a long time. In fact, think of it as a 
- *    spin lock.
+ * The "sc_mtx" lock protects both USB and Netgraph data. The "sc_mtx"
+ * lock should not be grabbed for a long time.
  *
- * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 3 different contexts.
+ * NOTE ON LOCKING STRATEGY: ng_ubt2 driver operates in 2 different contexts.
  *
  * 1) USB context. This is where all the USB related stuff happens. All
  *    callbacks run in this context. All callbacks are called (by USB2) with
@@ -67,26 +57,6 @@
  *    grab any long-sleep lock in the Netgraph context. In fact, the only
  *    lock that is allowed in the Netgraph context is the sc_mbufq_mtx lock.
  *
- * 3) Taskqueue context. This is where ubt_task runs. Since we are NOT allowed
- *    to grab any locks in the Netgraph context, and, USB2 requires us to
- *    grab interface lock before doing things with transfers, we need to
- *    transition from the Netgraph context to the Taskqueue context before
- *    we can call into USB2 subsystem.
- *
- * So, to put everything together, the rules are as follows.
- *	It is OK to call from the USB context or the Taskqueue context into
- * the Netgraph context (i.e. call NG_SEND_xxx functions). In other words
- * it is allowed to call into the Netgraph context with locks held.
- *	Is it *NOT* OK to call from the Netgraph context into the USB context,
- * because USB2 requires us to grab interface locks and we can not do that.
- * To avoid this, we set task flags to indicate which actions we want to
- * perform and schedule ubt_task which would run in the Taskqueue context.
- *	Is is OK to call from the Taskqueue context into the USB context,
- * and, ubt_task does just that (i.e. grabs appropriate interface locks
- * before calling into USB2).
- *	Access to the outgoing queues and task flags is controlled by the
- * sc_mbufq_mtx lock. It is an unavoidable evil. Again, sc_mbufq_mtx should
- * really be a spin lock.
  *	All USB callbacks accept Netgraph node pointer as private data. To
  * ensure that Netgraph node pointer remains valid for the duration of the
  * transfer, we grab a referrence to the node. In other words, if transfer is
@@ -111,7 +81,6 @@
 #include <dev/usb2/core/usb2_transfer.h>
 
 #include <sys/mbuf.h>
-#include <sys/taskqueue.h>
 
 #include <netgraph/ng_message.h>
 #include <netgraph/netgraph.h>
@@ -128,10 +97,6 @@
 static device_attach_t	ubt_attach;
 static device_detach_t	ubt_detach;
 
-static int		ubt_task_schedule(ubt_softc_p, int);
-static task_fn_t	ubt_task;
-static void		ubt_xfer_start(ubt_softc_p, int);
-
 /* Netgraph methods */
 static ng_constructor_t	ng_ubt_constructor;
 static ng_shutdown_t	ng_ubt_shutdown;
@@ -279,6 +244,7 @@
 		.type =		UE_BULK,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_OUT,
+		.if_index =	0,
 		.mh.bufsize =	UBT_BULK_WRITE_BUFFER_SIZE,
 		.mh.flags =	{ .pipe_bof = 1, },
 		.mh.callback =	&ubt_bulk_write_callback,
@@ -288,6 +254,7 @@
 		.type =		UE_BULK,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_IN,
+		.if_index =	0,
 		.mh.bufsize =	UBT_BULK_READ_BUFFER_SIZE,
 		.mh.flags =	{ .pipe_bof = 1, .short_xfer_ok = 1, },
 		.mh.callback =	&ubt_bulk_read_callback,
@@ -297,6 +264,7 @@
 		.type =		UE_INTERRUPT,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_IN,
+		.if_index =	0,
 		.mh.flags =	{ .pipe_bof = 1, .short_xfer_ok = 1, },
 		.mh.bufsize =	UBT_INTR_BUFFER_SIZE,
 		.mh.callback =	&ubt_intr_read_callback,
@@ -306,6 +274,7 @@
 		.type =		UE_CONTROL,
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
+		.if_index =	0,
 		.mh.bufsize =	UBT_CTRL_BUFFER_SIZE,
 		.mh.callback =	&ubt_ctrl_write_callback,
 		.mh.timeout =	5000,	/* 5 seconds */
@@ -315,6 +284,7 @@
 		.type =		UE_CONTROL,
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
+		.if_index =	0,
 		.mh.bufsize =	sizeof(struct usb2_device_request),
 		.mh.callback =	&ubt_bulk_write_clear_stall_callback,
 		.mh.timeout =	1000,	/* 1 second */
@@ -325,6 +295,7 @@
 		.type =		UE_CONTROL,
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
+		.if_index =	0,
 		.mh.bufsize =	sizeof(struct usb2_device_request),
 		.mh.callback =	&ubt_bulk_read_clear_stall_callback,
 		.mh.timeout =	1000,	/* 1 second */
@@ -338,6 +309,7 @@
 		.type =		UE_CONTROL,
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
+		.if_index =	0,
 		.mh.bufsize =	sizeof(struct usb2_device_request),
 		.mh.callback =	&ubt_intr_read_clear_stall_callback,
 		.mh.timeout =	1000,	/* 1 second */
@@ -353,6 +325,7 @@
 		.type =		UE_ISOCHRONOUS,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_IN,
+		.if_index =	1,
 		.mh.bufsize =	0,	/* use "wMaxPacketSize * frames" */
 		.mh.frames =	UBT_ISOC_NFRAMES,
 		.mh.flags =	{ .short_xfer_ok = 1, },
@@ -363,6 +336,7 @@
 		.type =		UE_ISOCHRONOUS,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_IN,
+		.if_index =	1,
 		.mh.bufsize =	0,	/* use "wMaxPacketSize * frames" */
 		.mh.frames =	UBT_ISOC_NFRAMES,
 		.mh.flags =	{ .short_xfer_ok = 1, },
@@ -373,6 +347,7 @@
 		.type =		UE_ISOCHRONOUS,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_OUT,
+		.if_index =	1,
 		.mh.bufsize =	0,	/* use "wMaxPacketSize * frames" */
 		.mh.frames =	UBT_ISOC_NFRAMES,
 		.mh.flags =	{ .short_xfer_ok = 1, },
@@ -383,6 +358,7 @@
 		.type =		UE_ISOCHRONOUS,
 		.endpoint =	UE_ADDR_ANY,
 		.direction =	UE_DIR_OUT,
+		.if_index =	1,
 		.mh.bufsize =	0,	/* use "wMaxPacketSize * frames" */
 		.mh.frames =	UBT_ISOC_NFRAMES,
 		.mh.flags =	{ .short_xfer_ok = 1, },
@@ -450,7 +426,8 @@
 	struct ubt_softc		*sc = device_get_softc(dev);
 	struct usb2_endpoint_descriptor	*ed;
 	uint16_t			wMaxPacketSize;
-	uint8_t				alt_index, iface_index, i, j;
+	uint8_t				alt_index, i, j;
+	uint8_t				iface_index[2];
 
 	device_set_usb2_desc(dev);
 
@@ -483,28 +460,22 @@
 
 	/* state */
 	sc->sc_debug = NG_UBT_WARN_LEVEL;
-	sc->sc_flags = 0;
+
 	UBT_STAT_RESET(sc);
 
 	/* initialize locks */
-	mtx_init(&sc->sc_mbufq_mtx, "ubt mbufq", NULL, MTX_DEF);
-	mtx_init(&sc->sc_if_mtx[0], "ubt if0", NULL, MTX_DEF | MTX_RECURSE);
-	mtx_init(&sc->sc_if_mtx[1], "ubt if1", NULL, MTX_DEF | MTX_RECURSE);
+	mtx_init(&sc->sc_mtx, "UBT", NULL, MTX_DEF | MTX_RECURSE);
 
 	/* initialize packet queues */
 	NG_BT_MBUFQ_INIT(&sc->sc_cmdq, UBT_DEFAULT_QLEN);
 	NG_BT_MBUFQ_INIT(&sc->sc_aclq, UBT_DEFAULT_QLEN);
 	NG_BT_MBUFQ_INIT(&sc->sc_scoq, UBT_DEFAULT_QLEN);
 
-	/* initialize glue task */
-	sc->sc_task_flags = 0;
-	TASK_INIT(&sc->sc_task, 0, ubt_task, sc->sc_node);
-
 	/*
 	 * Configure Bluetooth USB device. Discover all required USB
 	 * interfaces and endpoints.
 	 *
-	 * Device is expected to be a high-speed device.
+	 * Device is expected to be a full-speed device.
 	 *
 	 * USB device must present two interfaces:
 	 * 1) Interface 0 that has 3 endpoints
@@ -520,20 +491,11 @@
 	 * configurations with different packet size.
 	 */
 
-	bzero(&sc->sc_xfer, sizeof(sc->sc_xfer));
-
 	/*
 	 * Interface 0
 	 */
 
-	iface_index = 0;
-	if (usb2_transfer_setup(uaa->device, &iface_index, sc->sc_xfer,
-			ubt_config, UBT_IF_0_N_TRANSFER,
-			sc->sc_node, &sc->sc_if_mtx[0])) {
-		device_printf(dev, "could not allocate transfers for " \
-			"interface 0!\n");
-		goto detach;
-	}
+	iface_index[0] = 0;
 
 	/*
 	 * Interface 1
@@ -580,13 +542,11 @@
 		goto detach;
 	}
 
-	iface_index = 1;
-	if (usb2_transfer_setup(uaa->device, &iface_index,
-			&sc->sc_xfer[UBT_IF_0_N_TRANSFER],
-			&ubt_config[UBT_IF_0_N_TRANSFER], UBT_IF_1_N_TRANSFER,
-			sc->sc_node, &sc->sc_if_mtx[1])) {
-		device_printf(dev, "could not allocate transfers for " \
-			"interface 1!\n");
+	iface_index[1] = 1;
+	if (usb2_transfer_setup(uaa->device, iface_index,
+			sc->sc_xfer, ubt_config, UBT_N_TRANSFER,
+			sc->sc_node, &sc->sc_mtx)) {
+		device_printf(dev, "could not allocate transfers\n");
 		goto detach;
 	}
 
@@ -594,6 +554,10 @@
 	for (i = 1; usb2_get_iface(uaa->device, i) != NULL; i ++)
 		usb2_set_parent_iface(uaa->device, i, uaa->info.bIfaceIndex);
 
+	UBT_LOCK(sc);
+	sc->sc_flags |= UBT_FLAG_READY;
+	UBT_UNLOCK(sc);
+
 	return (0); /* success */
 
 detach:
@@ -612,17 +576,29 @@
 {
 	struct ubt_softc	*sc = device_get_softc(dev);
 	node_p			node = sc->sc_node;
+	uint8_t			i;
 
+	UBT_LOCK(sc);
+	sc->sc_flags &= ~UBT_FLAG_READY;
+	UBT_UNLOCK(sc);
+
+	/* make sure that all USB transfers are stopped! */
+	for (i = 0; i != UBT_N_TRANSFER; i++)
+		usb2_transfer_drain(sc->sc_xfer[i]);
+
 	/* Destroy Netgraph node */
 	if (node != NULL) {
 		sc->sc_node = NULL;
 
-		NG_NODE_SET_PRIVATE(node, NULL);
 		NG_NODE_REALLY_DIE(node);
-		NG_NODE_REF(node);
 		ng_rmnode_self(node);
+
+		/* Need to wait until Netgraph has shutdown the node! */
+		UBT_LOCK(sc);
+		while (!(sc->sc_flags & UBT_FLAG_SHUTDOWN))
+			usb2_pause_mtx(&sc->sc_mtx, 100);
+		UBT_UNLOCK(sc);
 	}
-
 	/* Free USB transfers, if any */
 	usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER);
 
@@ -630,15 +606,13 @@
 		NG_NODE_UNREF(node);
 
 	/* Destroy queues */
-	UBT_MBUFQ_LOCK(sc);
+	UBT_LOCK(sc);
 	NG_BT_MBUFQ_DESTROY(&sc->sc_cmdq);
 	NG_BT_MBUFQ_DESTROY(&sc->sc_aclq);
 	NG_BT_MBUFQ_DESTROY(&sc->sc_scoq);
-	UBT_MBUFQ_UNLOCK(sc);
+	UBT_UNLOCK(sc);
 
-	mtx_destroy(&sc->sc_if_mtx[0]);
-	mtx_destroy(&sc->sc_if_mtx[1]);
-	mtx_destroy(&sc->sc_mbufq_mtx);
+	mtx_destroy(&sc->sc_mtx);
 
 	return (0);
 } /* ubt_detach */
@@ -657,37 +631,25 @@
 	struct usb2_device_request	req;
 	struct mbuf			*m;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-		if (xfer->error != 0)
-			UBT_STAT_OERROR(sc);
-		else {
-			UBT_INFO(sc, "sent %d bytes to control pipe\n",
-				xfer->actlen);
+		UBT_INFO(sc, "sent %d bytes to control pipe\n",
+		    xfer->actlen);
+
+		UBT_STAT_BYTES_SENT(sc, xfer->actlen);
+		UBT_STAT_PCKTS_SENT(sc);
 
-			UBT_STAT_BYTES_SENT(sc, xfer->actlen);
-			UBT_STAT_PCKTS_SENT(sc);
-		}
 		/* FALLTHROUGH */
 
 	case USB_ST_SETUP:
 send_next:
 		/* Get next command mbuf, if any */
-		UBT_MBUFQ_LOCK(sc);
 		NG_BT_MBUFQ_DEQUEUE(&sc->sc_cmdq, m);
-		UBT_MBUFQ_UNLOCK(sc);
-
 		if (m == NULL) {
 			UBT_INFO(sc, "HCI command queue is empty\n");
-			NG_NODE_UNREF(node);
-			return;
+			break;
 		}
 
 		/* Initialize a USB control request and then schedule it */
@@ -719,8 +681,6 @@
 			UBT_STAT_OERROR(sc);
 			goto send_next;
 		}
-
-		NG_NODE_UNREF(node); /* cancelled */
 		break;
 	}
 } /* ubt_ctrl_write_callback */
@@ -740,19 +700,8 @@
 	ng_hci_event_pkt_t	*hdr;
 	int			error;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 
-	if ((sc->sc_hook == NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) {
-		UBT_INFO(sc, "no upstream hook\n");
-		NG_NODE_UNREF(node);
-		return; /* upstream hook is gone */
-	}
-
 	m = NULL;
 
 	switch (USB_GET_STATE(xfer)) {
@@ -836,8 +785,7 @@
 			/* Try to clear stall first */
 			sc->sc_flags |= UBT_FLAG_INTR_STALL;
 			usb2_transfer_start(sc->sc_xfer[UBT_IF_0_INTR_CS_RD]);
-		} else
-			NG_NODE_UNREF(node); /* cancelled */
+		}
 		break;
 	}
 } /* ubt_intr_read_callback */
@@ -855,11 +803,6 @@
 	struct ubt_softc	*sc;
 	struct usb2_xfer	*xfer_other;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 	xfer_other = sc->sc_xfer[UBT_IF_0_INTR_DT_RD];
 
@@ -867,8 +810,7 @@
 		DPRINTF("stall cleared\n");
 		sc->sc_flags &= ~UBT_FLAG_INTR_STALL;
 		usb2_transfer_start(xfer_other);
-	} else
-		NG_NODE_UNREF(node); /* cant clear stall */
+	}
 } /* ubt_intr_read_clear_stall_callback */
 
 /*
@@ -887,19 +829,7 @@
 	uint16_t		len;
 	int			error;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
-
-	if ((sc->sc_hook == NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) {
-		UBT_INFO(sc, "no upstream hook\n");
-		NG_NODE_UNREF(node);
-		return; /* upstream hook is gone */
-	}
-
 	m = NULL;
 
 	switch (USB_GET_STATE(xfer)) {
@@ -983,8 +913,7 @@
 			/* Try to clear stall first */
 			sc->sc_flags |= UBT_FLAG_READ_STALL;
 			usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_CS_RD]);
-		} else
-			NG_NODE_UNREF(node); /* cancelled */
+		}
 		break;
 	}
 } /* ubt_bulk_read_callback */
@@ -1002,11 +931,6 @@
 	struct ubt_softc	*sc;
 	struct usb2_xfer	*xfer_other;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 	xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_RD];
 
@@ -1014,8 +938,7 @@
 		DPRINTF("stall cleared\n");
 		sc->sc_flags &= ~UBT_FLAG_READ_STALL;
 		usb2_transfer_start(xfer_other);
-	} else
-		NG_NODE_UNREF(node); /* cant clear stall */
+	}
 } /* ubt_bulk_read_clear_stall_callback */
 
 /*
@@ -1031,36 +954,24 @@
 	struct ubt_softc	*sc;
 	struct mbuf		*m;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-		if (xfer->error != 0)
-			UBT_STAT_OERROR(sc);
-		else {
-			UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n",
-				xfer->actlen);
+		UBT_INFO(sc, "sent %d bytes to bulk-out pipe\n",
+		    xfer->actlen);
+
+		UBT_STAT_BYTES_SENT(sc, xfer->actlen);
+		UBT_STAT_PCKTS_SENT(sc);
 
-			UBT_STAT_BYTES_SENT(sc, xfer->actlen);
-			UBT_STAT_PCKTS_SENT(sc);
-		}
 		/* FALLTHROUGH */
 
 	case USB_ST_SETUP:
 		/* Get next mbuf, if any */
-		UBT_MBUFQ_LOCK(sc);
 		NG_BT_MBUFQ_DEQUEUE(&sc->sc_aclq, m);
-		UBT_MBUFQ_UNLOCK(sc);
-
 		if (m == NULL) {
 			UBT_INFO(sc, "ACL data queue is empty\n");
-			NG_NODE_UNREF(node);
-			return; /* transfer completed */
+			break;
 		}
 
 		/*
@@ -1089,8 +1000,7 @@
 			/* try to clear stall first */
 			sc->sc_flags |= UBT_FLAG_WRITE_STALL;
 			usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_CS_WR]);
-		} else
-			NG_NODE_UNREF(node); /* cancelled */
+		}
 		break;
 	}
 } /* ubt_bulk_write_callback */
@@ -1108,11 +1018,6 @@
 	struct ubt_softc	*sc;
 	struct usb2_xfer	*xfer_other;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 	xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_WR];
 
@@ -1120,8 +1025,7 @@
 		DPRINTF("stall cleared\n");
 		sc->sc_flags &= ~UBT_FLAG_WRITE_STALL;
 		usb2_transfer_start(xfer_other);
-	} else
-		NG_NODE_UNREF(node); /* cant clear stall */
+	}
 } /* ubt_bulk_write_clear_stall_callback */
 
 /*
@@ -1137,19 +1041,8 @@
 	struct ubt_softc	*sc;
 	int			n;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 
-	if ((sc->sc_hook == NULL) || NG_HOOK_NOT_VALID(sc->sc_hook)) {
-		UBT_INFO(sc, "no upstream hook\n");
-		NG_NODE_UNREF(node);
-		return; /* upstream hook is gone */
-	}
-
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
 		for (n = 0; n < xfer->nframes; n ++)
@@ -1171,8 +1064,6 @@
                         goto read_next;
 			/* NOT REACHED */
                 }
-
-		NG_NODE_UNREF(node); /* cancelled */
 		break;
 	}
 } /* ubt_isoc_read_callback */
@@ -1277,24 +1168,16 @@
 	struct mbuf		*m;
 	int			n, space, offset;
 
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
 	sc = NG_NODE_PRIVATE(node);
 
 	switch (USB_GET_STATE(xfer)) {
 	case USB_ST_TRANSFERRED:
-		if (xfer->error)
-			UBT_STAT_OERROR(sc);
-		else {
-			UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n",
-				xfer->actlen);
+		UBT_INFO(sc, "sent %d bytes to isoc-out pipe\n",
+		    xfer->actlen);
+
+		UBT_STAT_BYTES_SENT(sc, xfer->actlen);
+		UBT_STAT_PCKTS_SENT(sc);
 
-			UBT_STAT_BYTES_SENT(sc, xfer->actlen);
-			UBT_STAT_PCKTS_SENT(sc);
-		}
 		/* FALLTHROUGH */
 
 	case USB_ST_SETUP:
@@ -1305,10 +1188,7 @@
 
 		while (space > 0) {
 			if (m == NULL) {
-				UBT_MBUFQ_LOCK(sc);
 				NG_BT_MBUFQ_DEQUEUE(&sc->sc_scoq, m);
-				UBT_MBUFQ_UNLOCK(sc);
-
 				if (m == NULL)
 					break;
 			}
@@ -1328,9 +1208,7 @@
 
 		/* Put whatever is left from mbuf back on queue */
 		if (m != NULL) {
-			UBT_MBUFQ_LOCK(sc);
 			NG_BT_MBUFQ_PREPEND(&sc->sc_scoq, m);
-			UBT_MBUFQ_UNLOCK(sc);
 		}
 
 		/*
@@ -1355,174 +1233,12 @@
 			goto send_next;
 			/* NOT REACHED */
 		}
-
-		NG_NODE_UNREF(node); /* cancelled */
 		break;
 	}
 }
 
 /****************************************************************************
  ****************************************************************************
- **                                 Glue 
- ****************************************************************************
- ****************************************************************************/
-
-/*
- * Schedule glue task. Should be called with sc_mbufq_mtx held.
- * Netgraph context.
- */
-
-static int
-ubt_task_schedule(ubt_softc_p sc, int action)
-{
-	mtx_assert(&sc->sc_mbufq_mtx, MA_OWNED);
-
-	if ((sc->sc_task_flags & action) == 0) {
-		/*
-		 * Try to handle corner case when "start all" and "stop all"
-		 * actions can both be set before task is executed.
-		 *
-		 * Assume the following:
-		 * 1) "stop all" after "start all" cancels "start all", and,
-		 *    keeps "stop all"
-		 *
-		 * 2) "start all" after "stop all" is fine because task is
-		 *    executing "stop all" first
-		 */
-
-		if (action == UBT_FLAG_T_STOP_ALL &&
-		    (sc->sc_task_flags & UBT_FLAG_T_START_ALL) != 0)
-			sc->sc_task_flags &= ~UBT_FLAG_T_START_ALL;
-
-		sc->sc_task_flags |= action;
-	}
-
-	if (sc->sc_task_flags & UBT_FLAG_T_PENDING)
-		return (1);
-
-	if (taskqueue_enqueue(taskqueue_swi, &sc->sc_task) == 0) {
-		NG_NODE_REF(sc->sc_node);
-		sc->sc_task_flags |= UBT_FLAG_T_PENDING;
-		return (1);
-	}
-
-	/* XXX: i think this should never happen */
-
-	return (0);
-} /* ubt_task_schedule */
-
-/*
- * Glue task. Examines sc_task_flags and does things depending on it.
- * Taskqueue context.
- */
-
-static void
-ubt_task(void *context, int pending)
-{
-	node_p		node = context;
-	ubt_softc_p	sc;
-	int		task_flags;
-
-	if (NG_NODE_NOT_VALID(node)) {
-		NG_NODE_UNREF(node);
-		return; /* netgraph node is gone */
-	}
-
-	sc = NG_NODE_PRIVATE(node);
-
-	UBT_MBUFQ_LOCK(sc);
-	task_flags = sc->sc_task_flags;
-	sc->sc_task_flags = 0;
-	UBT_MBUFQ_UNLOCK(sc);
-
-	/* Stop all USB transfers */
-	if (task_flags & UBT_FLAG_T_STOP_ALL) {
-		int	i;
-
-		/*
-		 * Interface #0
-		 */
-
-		mtx_lock(&sc->sc_if_mtx[0]);
-
-		for (i = UBT_IF_0_BULK_DT_WR; i < UBT_IF_0_N_TRANSFER; i ++)
-			usb2_transfer_stop(sc->sc_xfer[i]);
-
-		mtx_unlock(&sc->sc_if_mtx[0]);
-
-		/*
-		 * Interface #1
-		 */
-
-		mtx_lock(&sc->sc_if_mtx[1]);
-
-		for (i = UBT_IF_1_ISOC_DT_RD1; i < UBT_N_TRANSFER; i ++) 
-			usb2_transfer_stop(sc->sc_xfer[i]);
-
-		mtx_unlock(&sc->sc_if_mtx[1]);
-	}
-
-	/* Start all incoming USB transfers */
-	if (task_flags & UBT_FLAG_T_START_ALL) {
-		/*
-		 * Interface #0
-		 */
-
-		mtx_lock(&sc->sc_if_mtx[0]);
-		ubt_xfer_start(sc, UBT_IF_0_INTR_DT_RD);
-		ubt_xfer_start(sc, UBT_IF_0_BULK_DT_RD);
-		mtx_unlock(&sc->sc_if_mtx[0]);
-
-		/*
-		 * Interface #1
-		 * Start both read and write isoc. transfers by default.
-		 * Get them going all the time even if we have nothing
-		 * to send to avoid any delays.
-		 */
-
-		mtx_lock(&sc->sc_if_mtx[1]);
-		ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD1);
-		ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_RD2);
-		ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR1);
-		ubt_xfer_start(sc, UBT_IF_1_ISOC_DT_WR2);
-		mtx_unlock(&sc->sc_if_mtx[1]);
-	}
-
- 	/* Start outgoing control transfer */
-	if (task_flags & UBT_FLAG_T_START_CTRL) {
-		mtx_lock(&sc->sc_if_mtx[0]);
-		ubt_xfer_start(sc, UBT_IF_0_CTRL_DT_WR);
-		mtx_unlock(&sc->sc_if_mtx[0]);
-	}
-
-	/* Start outgoing bulk transfer */
-	if (task_flags & UBT_FLAG_T_START_BULK) {
-		mtx_lock(&sc->sc_if_mtx[0]);
-		ubt_xfer_start(sc, UBT_IF_0_BULK_DT_WR);
-		mtx_unlock(&sc->sc_if_mtx[0]);
-	}
-
-	NG_NODE_UNREF(node);
-} /* ubt_task */
-
-/*
- * Start USB transfer.
- * Helper function called from ubt_task. Must be called with appropriate
- * interface lock held.
- * Taskqueue context.
- */
-
-static void
-ubt_xfer_start(ubt_softc_p sc, int transfer)
-{
-	if (!usb2_transfer_pending(sc->sc_xfer[transfer])) {
-		NG_NODE_REF(sc->sc_node);
-		usb2_transfer_start(sc->sc_xfer[transfer]);
-	}
-} /* ubt_xfer_start */
-
-/****************************************************************************
- ****************************************************************************
  **                        Netgraph specific
  ****************************************************************************
  ****************************************************************************/
@@ -1546,13 +1262,18 @@
 static int
 ng_ubt_shutdown(node_p node)
 {
+	struct ubt_softc *sc = NG_NODE_PRIVATE(node);
+
 	if (node->nd_flags & NGF_REALLY_DIE) {
 		/*
                  * We came here because the USB device is being
 		 * detached, so stop being persistant.
                  */
+		UBT_LOCK(sc);
+		sc->sc_flags |= UBT_FLAG_SHUTDOWN;
+		UBT_UNLOCK(sc);
+
 		NG_NODE_SET_PRIVATE(node, NULL);
-		NG_NODE_UNREF(node);
 	} else
 		NG_NODE_REVIVE(node); /* tell ng_rmnode we are persisant */
 
@@ -1592,9 +1313,21 @@
 
 	NG_HOOK_FORCE_QUEUE(NG_HOOK_PEER(hook));
 
-	UBT_MBUFQ_LOCK(sc);
-	ubt_task_schedule(sc, UBT_FLAG_T_START_ALL);
-	UBT_MBUFQ_UNLOCK(sc);
+	if (!(sc->sc_flags & UBT_FLAG_READY)) {
+		/* called too early */
+		return (EINVAL);
+	}
+
+	NG_NODE_REF(sc->sc_node);
+
+	UBT_LOCK(sc);
+	usb2_transfer_start(sc->sc_xfer[UBT_IF_0_INTR_DT_RD]);
+	usb2_transfer_start(sc->sc_xfer[UBT_IF_0_BULK_DT_RD]);
+	usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_RD1]);
+	usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_RD2]);
+	usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_WR1]);
+	usb2_transfer_start(sc->sc_xfer[UBT_IF_1_ISOC_DT_WR2]);
+	UBT_UNLOCK(sc);
 
 	return (0);
 } /* ng_ubt_connect */
@@ -1609,6 +1342,7 @@
 {
 	node_p			node = NG_HOOK_NODE(hook);
 	struct ubt_softc	*sc;
+	uint8_t			i;
 
 	if (NG_NODE_NOT_VALID(node))
 		return (0);
@@ -1618,19 +1352,25 @@
 	if (hook != sc->sc_hook)
 		return (EINVAL);
 
+	/* 
+	 * Synchronously drain all USB transfers:
+	 * Can take some milliseconds!
+	 */
+	for (i = 0; i != UBT_N_TRANSFER; i++)
+		usb2_transfer_drain(sc->sc_xfer[i]);
+
 	sc->sc_hook = NULL;
 
-	UBT_MBUFQ_LOCK(sc);
+	UBT_LOCK(sc);
 
 	/* Drain queues */
 	NG_BT_MBUFQ_DRAIN(&sc->sc_cmdq);
 	NG_BT_MBUFQ_DRAIN(&sc->sc_aclq);
 	NG_BT_MBUFQ_DRAIN(&sc->sc_scoq);
 
-	/* Kick off task to stop all USB xfers */
-	ubt_task_schedule(sc, UBT_FLAG_T_STOP_ALL);
+	UBT_UNLOCK(sc);
 
-	UBT_MBUFQ_UNLOCK(sc);
+	NG_NODE_UNREF(node);
 
 	return (0);
 } /* ng_ubt_disconnect */
@@ -1664,7 +1404,6 @@
 				"Refs: %d\n" \
 				"Hook: %s\n" \
 				"Flags: %#x\n" \
-				"Task flags: %#x\n" \
 				"Debug: %d\n" \
 				"CMD queue: [have:%d,max:%d]\n" \
 				"ACL queue: [have:%d,max:%d]\n" \
@@ -1672,7 +1411,6 @@
 				node->nd_refs,
 				(sc->sc_hook != NULL) ? NG_UBT_HOOK:"",
 				sc->sc_flags,
-				sc->sc_task_flags,
 				sc->sc_debug,
 				sc->sc_cmdq.len,
 				sc->sc_cmdq.maxlen,
@@ -1823,7 +1561,8 @@
 	struct ubt_softc	*sc = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
 	struct mbuf		*m;
 	struct ng_bt_mbufq	*q;
-	int			action, error = 0;
+	int			error = 0;
+	uint8_t			xfer_action;
 
 	if (hook != sc->sc_hook) {
 		error = EINVAL;
@@ -1853,7 +1592,7 @@
 				UBT_CTRL_BUFFER_SIZE, m->m_pkthdr.len);
 
 		q = &sc->sc_cmdq;
-		action = UBT_FLAG_T_START_CTRL;
+		xfer_action = UBT_IF_0_CTRL_DT_WR;
 		break;
 
 	case NG_HCI_ACL_DATA_PKT:
@@ -1863,12 +1602,12 @@
 				UBT_BULK_WRITE_BUFFER_SIZE, m->m_pkthdr.len);
 
 		q = &sc->sc_aclq;
-		action = UBT_FLAG_T_START_BULK;
+		xfer_action = UBT_IF_0_BULK_DT_WR;
 		break;
 
 	case NG_HCI_SCO_DATA_PKT:
 		q = &sc->sc_scoq;
-		action = 0;
+		xfer_action = 255;
 		break;
 
 	default:
@@ -1881,10 +1620,10 @@
 		/* NOT REACHED */
 	}
 
-	UBT_MBUFQ_LOCK(sc);
+	UBT_LOCK(sc);
 	if (NG_BT_MBUFQ_FULL(q)) {
 		NG_BT_MBUFQ_DROP(q);
-		UBT_MBUFQ_UNLOCK(sc);
+		UBT_UNLOCK(sc);
 		
 		UBT_ERR(sc, "Dropping HCI frame 0x%02x, len=%d. Queue full\n",
 			*mtod(m, uint8_t *), m->m_pkthdr.len);
@@ -1894,9 +1633,9 @@
 		/* Loose HCI packet type, enqueue mbuf and kick off task */
 		m_adj(m, sizeof(uint8_t));
 		NG_BT_MBUFQ_ENQUEUE(q, m);
-		ubt_task_schedule(sc, action);
-
-		UBT_MBUFQ_UNLOCK(sc);
+		if (xfer_action != 255)
+			usb2_transfer_start(sc->sc_xfer[xfer_action]);
+		UBT_UNLOCK(sc);
 	}
 done:
 	NG_FREE_ITEM(item);
@@ -1962,4 +1701,3 @@
 MODULE_DEPEND(ng_ubt, ng_hci, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION, NG_BLUETOOTH_VERSION);
 MODULE_DEPEND(ng_ubt, usb2_bluetooth, 1, 1, 1);
 MODULE_DEPEND(ng_ubt, usb2_core, 1, 1, 1);
-

==== //depot/projects/usb/src/sys/dev/usb2/bluetooth/ng_ubt2_var.h#7 (text+ko) ====

@@ -47,8 +47,8 @@
 #define	UBT_WARN(...)		UBT_DEBUG(NG_UBT_WARN_LEVEL, __VA_ARGS__)
 #define	UBT_INFO(...)		UBT_DEBUG(NG_UBT_INFO_LEVEL, __VA_ARGS__)
 
-#define UBT_MBUFQ_LOCK(sc)	mtx_lock(&(sc)->sc_mbufq_mtx)
-#define UBT_MBUFQ_UNLOCK(sc)	mtx_unlock(&(sc)->sc_mbufq_mtx)
+#define UBT_LOCK(sc)	mtx_lock(&(sc)->sc_mtx)
+#define UBT_UNLOCK(sc)	mtx_unlock(&(sc)->sc_mtx)
 
 /* Bluetooth USB control request type */
 #define	UBT_HCI_REQUEST		0x20
@@ -65,17 +65,14 @@
 	UBT_IF_0_BULK_CS_WR,
 	UBT_IF_0_BULK_CS_RD,
 	UBT_IF_0_INTR_CS_RD,
-	UBT_IF_0_N_TRANSFER,	/* number of interface 0's transfers */
 	
 	/* Interface #1 transfers */
-	UBT_IF_1_ISOC_DT_RD1 = UBT_IF_0_N_TRANSFER,
+	UBT_IF_1_ISOC_DT_RD1,
 	UBT_IF_1_ISOC_DT_RD2,
 	UBT_IF_1_ISOC_DT_WR1,

>>> TRUNCATED FOR MAIL (1000 lines) <<<



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901231905.n0NJ5xaB090658>