Greetings:
I encountered an apparent bug in the OHCI host controller driver in Linux.
This one appears as a hang after I open, close, open, close, and then open a
Belkin USB serial adapter device attached to the USB with a Compaq OHCI USB
host controller chip. I originally discovered this problem while attempting
to spawn gettys on the serial adapter. I subsequently reduced it down to
just this sequence of operations.
The Belkin serial adapter has two bulk endpoints (one in, one out) and one
interrupt endpoint (in). The hang occurs when sohci_submit_urb() in
usb-ohci.c calls ep_link() to link the interrupt endpoint descriptor into
the OHCI interrupt descriptor tree. For some reason, the endpoint
descriptor is linked with hwNextED pointing back at itself, which creates an
infinite loop in the schedule. When the OHCI hardware tries to execute this
schedule, you get the system hang.
I have created a fix which just checks to see if the endpoint descriptor is
already linked into the tree, and if so, then nothing else should happen.
This seems more like a band-aid than a proper fix to me, so I would welcome
any comments as to how this might be improved to better deal with the
situation. I would also like to know if this attempted fix would cause any
unintended breakage that I am not aware of.
The following patch should work against most recent 2.4.x kernels. I used a
2.4.8 tree for this one.
Many thanks in advance,
+chris
Chris Parrott
Linux Software Engineer
EchoStar Technologies Corp.
94 Inverness Terrace East, Englewood, CO 80112
phone: (303) 706-5383
email: [EMAIL PROTECTED]
--- linux/drivers/usb/usb-ohci.c.old Mon Oct 29 14:20:06 2001
+++ linux/drivers/usb/usb-ohci.c Mon Oct 29 14:22:27 2001
@@ -1023,9 +1023,13 @@
inter = 1;
for (ed_p = &(ohci->hcca->int_table[ep_rev (5, i) +
int_branch]);
(*ed_p != 0) && ((dma_to_ed (ohci,
le32_to_cpup (ed_p)))->int_interval >= interval);
- ed_p = &((dma_to_ed (ohci, le32_to_cpup
(ed_p)))->hwNextED))
+ ed_p = &((dma_to_ed (ohci, le32_to_cpup
(ed_p)))->hwNextED)) {
inter = ep_rev (6, (dma_to_ed (ohci,
le32_to_cpup (ed_p)))->int_interval);
- ed->hwNextED = *ed_p;
+ if (*ed_p == ed->dma)
+ break;
+ }
+ if (*ed_p != ed->dma)
+ ed->hwNextED = *ed_p;
*ed_p = cpu_to_le32 (ed->dma);
}
#ifdef DEBUG
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel