[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