kernel panic trying to utilize a da(4)/umass(4) device with
ohci(4)
Ian Dowse
iedowse at maths.tcd.ie
Thu Nov 20 01:12:04 PST 2003
In message <200311200326.hAK3Qqvf024651 at green.bikeshed.org>, "Brian F. Feldman"
writes:
>Jeez, it's been broken a year and it's almost 5.2-RELEASE now. Does anyone
>have ANY leads on these problems? I know precisely nothing about how my USB
>hardware is supposed to work, but this OHCI+EHCI stuff definitely doesn't,
>and it's really not uncommon at all. Is it unbroken in NetBSD currently?
I had some success with this patch:
Index: usb_mem.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/usb/usb_mem.c,v
retrieving revision 1.5
diff -u -r1.5 usb_mem.c
--- usb_mem.c 4 Oct 2003 22:13:21 -0000 1.5
+++ usb_mem.c 27 Oct 2003 15:39:03 -0000
@@ -142,7 +142,8 @@
s = splusb();
/* First check the free list. */
for (p = LIST_FIRST(&usb_blk_freelist); p; p = LIST_NEXT(p, next)) {
- if (p->tag == tag && p->size >= size && p->align >= align) {
+ if (p->tag == tag && p->size >= size && p->size < size * 2 &&
+ p->align >= align) {
LIST_REMOVE(p, next);
usb_blk_nfree--;
splx(s);
It seems that since the conversion to busdma, the USB code can end
up attempting to use contigmalloc() to allocate multi-page regions
from an interrupt thread(!). The above doesn't fix that; it just
prevents successful large (e.g 64k) contiguous allocations from
being wasted when a much smaller amount of space is needed.
With the above, I was able to use ohci+ehci fairly reliably on a
Soekris box with a large USB2 disk attached via a cardbus USB2
adaptor. I also have a few other local patches that may help too -
some of them are below:
Ian
Index: ohci.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/usb/ohci.c,v
retrieving revision 1.132
diff -u -r1.132 ohci.c
--- ohci.c 24 Aug 2003 17:55:54 -0000 1.132
+++ ohci.c 21 Sep 2003 15:28:27 -0000
@@ -1405,12 +1405,13 @@
if (std->flags & OHCI_ADD_LEN)
xfer->actlen += len;
if (std->flags & OHCI_CALL_DONE) {
+ ohci_free_std(sc, std); /* XXX */
xfer->status = USBD_NORMAL_COMPLETION;
s = splusb();
usb_transfer_complete(xfer);
splx(s);
- }
- ohci_free_std(sc, std);
+ } else
+ ohci_free_std(sc, std);
} else {
/*
* Endpoint is halted. First unlink all the TDs
@@ -2246,6 +2247,7 @@
usb_uncallout(xfer->timeout_handle, ohci_timeout, xfer);
usb_transfer_complete(xfer);
splx(s);
+ return;
}
if (xfer->device->bus->intr_context || !curproc)
Index: usbdi.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/usb/usbdi.c,v
retrieving revision 1.82
diff -u -r1.82 usbdi.c
--- usbdi.c 24 Aug 2003 17:55:55 -0000 1.82
+++ usbdi.c 21 Sep 2003 15:28:29 -0000
@@ -751,6 +751,7 @@
pipe, xfer, pipe->methods));
/* Make the HC abort it (and invoke the callback). */
pipe->methods->abort(xfer);
+ KASSERT(SIMPLEQ_FIRST(&pipe->queue) != xfer, ("usbd_ar_pipe"));
/* XXX only for non-0 usbd_clear_endpoint_stall(pipe); */
}
pipe->aborting = 0;
@@ -763,8 +764,9 @@
{
usbd_pipe_handle pipe = xfer->pipe;
usb_dma_t *dmap = &xfer->dmabuf;
+ usbd_status status;
int repeat = pipe->repeat;
- int polling;
+ int polling, xfer_flags;
SPLUSBCHECK;
@@ -835,30 +837,33 @@
xfer->status = USBD_SHORT_XFER;
}
- if (xfer->callback)
- xfer->callback(xfer, xfer->priv, xfer->status);
-
-#ifdef DIAGNOSTIC
- if (pipe->methods->done != NULL)
+ /* Copy any xfer fields in case the xfer goes away in the callback. */
+ status = xfer->status;
+ xfer_flags = xfer->flags;
+ /*
+ * For repeat operations, call the callback first, as the xfer
+ * will not go away and the "done" method may modify it. Otherwise
+ * reverse the order in case the callback wants to free or reuse
+ * the xfer.
+ */
+ if (repeat) {
+ if (xfer->callback)
+ xfer->callback(xfer, xfer->priv, status);
pipe->methods->done(xfer);
- else
- printf("usb_transfer_complete: pipe->methods->done == NULL\n");
-#else
- pipe->methods->done(xfer);
-#endif
-
- if ((xfer->flags & USBD_SYNCHRONOUS) && !polling)
- wakeup(xfer);
+ } else {
+ pipe->methods->done(xfer);
+ if (xfer->callback)
+ xfer->callback(xfer, xfer->priv, status);
- if (!repeat) {
/* XXX should we stop the queue on all errors? */
- if ((xfer->status == USBD_CANCELLED ||
- xfer->status == USBD_TIMEOUT) &&
+ if ((status == USBD_CANCELLED || status == USBD_TIMEOUT) &&
pipe->iface != NULL) /* not control pipe */
pipe->running = 0;
else
usbd_start_next(pipe);
}
+ if ((xfer_flags & USBD_SYNCHRONOUS) && !polling)
+ wakeup(xfer);
}
usbd_status
@@ -879,6 +884,7 @@
xfer->busy_free = XFER_ONQU;
#endif
s = splusb();
+ KASSERT(SIMPLEQ_FIRST(&pipe->queue) != xfer, ("usb_insert_transfer"));
SIMPLEQ_INSERT_TAIL(&pipe->queue, xfer, next);
if (pipe->running)
err = USBD_IN_PROGRESS;
Index: usbdi_util.c
===================================================================
RCS file: /dump/FreeBSD-CVS/src/sys/dev/usb/usbdi_util.c,v
retrieving revision 1.31
diff -u -r1.31 usbdi_util.c
--- usbdi_util.c 24 Aug 2003 17:55:55 -0000 1.31
+++ usbdi_util.c 21 Sep 2003 15:28:30 -0000
@@ -440,7 +440,7 @@
}
usbd_get_xfer_status(xfer, NULL, NULL, size, &err);
DPRINTFN(1,("usbd_bulk_transfer: transferred %d\n", *size));
- if (err) {
+ if (err == USBD_STALLED) {
DPRINTF(("usbd_bulk_transfer: error=%d\n", err));
usbd_clear_endpoint_stall(pipe);
}
More information about the freebsd-current
mailing list