[PATCH] for ng_ubt2 stalled transfers

Maksim Yevmenkin maksim.yevmenkin at gmail.com
Fri Jan 23 11:14:00 PST 2009


On Fri, Jan 23, 2009 at 11:12 AM, Maksim Yevmenkin
<maksim.yevmenkin at gmail.com> wrote:
> Lars,
>
>> Maksim has made a lot of changes to the Bluetooth driver. Maybe he can look
>> into it?
>>
>> This looks like a NULL-pointer access to me.
>>
>> Maksim:
>>
>> In the ubt_detach routine, make sure that:
>>
>> 0) No further commands are accepted from the Netgraph stack.
>> 1) You drain the task queue!
>> 2) You drain all USB transfers: "usb2_transfer_drain()" called unlocked.
>> 3) Set the "sc_node" to NULL.
>
> please try attached patch for ng_ubt2 that hopefully addresses some of
> the issues with stalled transfers. stalled transfers do not happen on
> my machine, so i can not test it. i briefly kicked the tires and made
> sure other things seems to work fine for me.

sorry, forgot to attach the patch :)

thanks,
max
-------------- next part --------------
Index: ng_ubt2.c
===================================================================
--- ng_ubt2.c	(revision 187505)
+++ ng_ubt2.c	(working copy)
@@ -243,13 +243,11 @@
 /* USB methods */
 static usb2_callback_t	ubt_ctrl_write_callback;
 static usb2_callback_t	ubt_intr_read_callback;
-static usb2_callback_t	ubt_intr_read_clear_stall_callback;
 static usb2_callback_t	ubt_bulk_read_callback;
-static usb2_callback_t	ubt_bulk_read_clear_stall_callback;
 static usb2_callback_t	ubt_bulk_write_callback;
-static usb2_callback_t	ubt_bulk_write_clear_stall_callback;
 static usb2_callback_t	ubt_isoc_read_callback;
 static usb2_callback_t	ubt_isoc_write_callback;
+static usb2_callback_t	ubt_clear_stall_callback;
 
 static int	ubt_isoc_read_one_frame(struct usb2_xfer *, int);
 
@@ -316,7 +314,7 @@
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
 		.mh.bufsize =	sizeof(struct usb2_device_request),
-		.mh.callback =	&ubt_bulk_write_clear_stall_callback,
+		.mh.callback =	&ubt_clear_stall_callback,
 		.mh.timeout =	1000,	/* 1 second */
 		.mh.interval =	50,	/* 50ms */
 	},
@@ -326,7 +324,7 @@
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
 		.mh.bufsize =	sizeof(struct usb2_device_request),
-		.mh.callback =	&ubt_bulk_read_clear_stall_callback,
+		.mh.callback =	&ubt_clear_stall_callback,
 		.mh.timeout =	1000,	/* 1 second */
 		.mh.interval =	50,	/* 50ms */
 	},
@@ -339,7 +337,7 @@
 		.endpoint =	0x00,	/* control pipe */
 		.direction =	UE_DIR_ANY,
 		.mh.bufsize =	sizeof(struct usb2_device_request),
-		.mh.callback =	&ubt_intr_read_clear_stall_callback,
+		.mh.callback =	&ubt_clear_stall_callback,
 		.mh.timeout =	1000,	/* 1 second */
 		.mh.interval =	50,	/* 50ms */
 	},
@@ -623,6 +621,9 @@
 		ng_rmnode_self(node);
 	}
 
+	/* Make sure ubt_task in gone */
+	taskqueue_drain(taskqueue_swi, &sc->sc_task);
+
 	/* Free USB transfers, if any */
 	usb2_transfer_unsetup(sc->sc_xfer, UBT_N_TRANSFER);
 
@@ -843,35 +844,6 @@
 } /* ubt_intr_read_callback */
 
 /*
- * Called when outgoing control transfer initiated to clear stall on
- * interrupt pipe has completed.
- * USB context.
- */
-
-static void
-ubt_intr_read_clear_stall_callback(struct usb2_xfer *xfer)
-{
-	node_p			node = xfer->priv_sc;
-	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];
-
-	if (usb2_clear_stall_callback(xfer, xfer_other)) {
-		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 */
-
-/*
  * Called when incoming bulk transfer (ACL packet) has completed, i.e.
  * ACL packet was received from the device.
  * USB context.
@@ -990,35 +962,6 @@
 } /* ubt_bulk_read_callback */
 
 /*
- * Called when outgoing control transfer initiated to clear stall on
- * incoming bulk pipe has completed.
- * USB context.
- */
-
-static void
-ubt_bulk_read_clear_stall_callback(struct usb2_xfer *xfer)
-{
-	node_p			node = xfer->priv_sc;
-	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];
-
-	if (usb2_clear_stall_callback(xfer, xfer_other)) {
-		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 */
-
-/*
  * Called when outgoing bulk transfer (ACL packet) has completed, i.e.
  * ACL packet was sent to the device.
  * USB context.
@@ -1096,35 +1039,6 @@
 } /* ubt_bulk_write_callback */
 
 /*
- * Called when outgoing control transfer initiated to clear stall on
- * outgoing bulk pipe has completed.
- * USB context.
- */
-
-static void
-ubt_bulk_write_clear_stall_callback(struct usb2_xfer *xfer)
-{
-	node_p			node = xfer->priv_sc;
-	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];
-
-	if (usb2_clear_stall_callback(xfer, xfer_other)) {
-		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 */
-
-/*
  * Called when incoming isoc transfer (SCO packet) has completed, i.e.
  * SCO packet was received from the device.
  * USB context.
@@ -1361,6 +1275,80 @@
 	}
 }
 
+/*
+ * Called when an outgoing control transfer to clear stall on another
+ * pipe has been completed. Generic for all clear stall transfers.
+ * USB context.
+ */
+
+static void
+ubt_clear_stall_callback(struct usb2_xfer *xfer)
+{
+	node_p			node = xfer->priv_sc;
+	struct ubt_softc	*sc;
+	struct usb2_xfer	*xfer_other;
+	int			flag;
+
+	if (NG_NODE_NOT_VALID(node)) {
+		NG_NODE_UNREF(node);
+		return; /* netgraph node is gone */
+	}
+
+	sc = NG_NODE_PRIVATE(node);
+
+	/*
+	 * Figure out which clear stall transfer has completed
+	 * and set xfer_other and flag accordingly
+	 */
+
+	if (xfer == sc->sc_xfer[UBT_IF_0_BULK_CS_WR]) {
+		xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_WR];
+		flag = UBT_FLAG_WRITE_STALL;
+	} else if (xfer == sc->sc_xfer[UBT_IF_0_BULK_CS_RD]) {
+		xfer_other = sc->sc_xfer[UBT_IF_0_BULK_DT_RD];
+		flag = UBT_FLAG_READ_STALL;
+	} else if (xfer == sc->sc_xfer[UBT_IF_0_INTR_CS_RD]) {
+		xfer_other = sc->sc_xfer[UBT_IF_0_INTR_DT_RD];
+		flag = UBT_FLAG_INTR_STALL;
+	} else
+		panic("could not set xfer_other! xfer=%p\n", xfer);
+
+	if (xfer_other == NULL) {
+		UBT_WARN(sc, "other transfer is gone. are we dying?!\n");
+		NG_NODE_UNREF(node);
+		return; /* other transfer is gone. are we dying?! */
+	}
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_SETUP:
+		/*
+		 * Ignore return value from usb2_clear_stall_callback()
+		 * as it appears it can not return anything other than
+		 * zero in USB_ST_SETUP case
+		 */
+		(void) usb2_clear_stall_callback(xfer, xfer_other);
+		break;
+
+	case USB_ST_TRANSFERRED:
+		UBT_INFO(sc, "stall cleared, flag=%#x\n", flag);
+submit_other:
+		sc->sc_flags &= ~flag;
+		usb2_transfer_start(xfer_other);
+		break;
+
+	default:
+		if (xfer->error != USB_ERR_CANCELLED) {
+			UBT_WARN(sc, "clear stall transfer failed: %s, " \
+				"flag=%#x\n", usb2_errstr(xfer->error), flag);
+			goto submit_other;
+			/* NOT REACHED */
+		}
+
+		NG_NODE_UNREF(node); /* cancelled */
+		break;
+	}
+} /* ubt_clear_stall_callback */
+
 /****************************************************************************
  ****************************************************************************
  **                                 Glue 


More information about the freebsd-current mailing list