On Sunday 12 June 2005 7:49 am, Matthias Urlichs wrote: > Hi, > > I am seeing this problem with the OHCI driver: > > Occasionally, this test in finish_unlinks() ... > > > /* INTR_WDH may need to clean up first */ > > if (td->td_dma != head) > > goto skip_ed; > > triggers. The problem is that when this statement is hit, the problem > doesn't go away (I verified that with a debug printf which subsequently > triggered 2000 times per second), and communication gets blocked because > finish_unlinks() now becomes a no-op and the driver has a finite number of > outstanding URBs. :-/
The complication there is the OHCI "donelist" mechanism. That's triggered by WDH. The problem scenario is this: - Several TDs queued for an endpoint - The hardware finished some of them ("head" points to a later TD) - Those uncompleted TDs are in the donelist, maybe not yet reported (that is, the TDs are "partially retired" -- done, but not yet in a state the HCD can touch them) - Device river unlinks an URB (one or more TDs) - HCD must wait for donelist processing (WDH) before unlink can finish (because touching the partially retired TDs is trouble) Basically there's an invariant in that code: the donelist processing must finish first, so every TD the hardware completed has been processed on the normal/completion path, thus the hardware "head" pointer will get to match the front of the software's list before very long. And another one: while finish_unlinks() is running, nobody should be putting that endpoint back on a hardware schedule. That's done based on HCD-internal endpoint state. Clearly a tricky combination of events, there could be a bug lurking, but likewise not straightforward to find and fix without breaking something else... touching partially retired TDs is a great way to oops things later on, especially when those TDs get reused before the controller hands them back through the donelist! The question in this case would seem to be why the donelist processing wasn't catching the TD at the list head. You might add a debug check calling ohci_dump_td() on the TD triggering that skip_ed branch; or maybe even ohci_dump_ed(verbose) to see the whole queue there. If that's called a lot, then just dump it the first three or four times. - Dave ------------------------------------------------------- SF.Net email is sponsored by: Discover Easy Linux Migration Strategies from IBM. Find simple to follow Roadmaps, straightforward articles, informative Webcasts and more! Get everything you need to get up to speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click _______________________________________________ linux-usb-devel@lists.sourceforge.net To unsubscribe, use the last form field at: https://lists.sourceforge.net/lists/listinfo/linux-usb-devel