* !!! trouble starts: bad entry reported from dl_reverse_done_list seems poisoned memory in this case (in many cases it's not 5a5a5a)
ohci_hcd 0000:00:0c.1: bad entry 5a5a5a50
That's really odd. That poison byte is used by mm/slab.c, but this "bad entry" came from a TD or ED, and hence from a dmapool. And drivers/base/dmapool.c uses different poison bytes. (Partly to highlight strangeness like this ... )
THEORY: somebody's abusing some general purpose kmem_cache_t, maybe the one dmapool used for a "struct dma_page" holding TDs ("size-32"?). That holds a dma_addr_t which may get handed to the OHCI controller. That dma_addr_t could be poisoned, and change to 0x5a5a5a5a ... it'd come back from OHCI as 0x5a5a5a50 if it were used as a non-isochronous TD. (16 byte alignment is required, low bits are ignored and written back as zero.) The "bad entry" was supposed to be a TD.
That should give you some ideas for a few patches to try...
Also, for some more info you could try the attached patch, which dump OHCI's TD hashtable at that point. The phys_to_virt() is not appropriate (oopsable) on many non-PC platforms though.
* going on from this point I've seen two different failure modes
--- either the HC dies:
This path is relatively polite. Whatever did what, the HC probably got bad address, then PCI DMA error, then polite hardware shutdown.
--- or things go south like this:
The rude approach. Whatever corruption happened was not blatant enough to make the OHCI silicon die, so things just mysteriously wedge. We hope it didn't use DMA to clobber pagetables or somesuch.
Badness in ohci_endpoint_disable at drivers/usb/host/ohci-hcd.c:340
Maybe someday a better response to that particular "badness" would be to just kill the OHCI controller and try to clean up ... though it's not clear to me that cleaning up would be safe at that point.
- Dave
===== drivers/usb/host/ohci-q.c 1.47 vs edited ===== --- 1.47/drivers/usb/host/ohci-q.c Wed Feb 11 03:42:39 2004 +++ edited/drivers/usb/host/ohci-q.c Sun Feb 29 06:53:33 2004 @@ -860,7 +860,18 @@ td = dma_to_td (ohci, td_dma); if (!td) { + unsigned i; ohci_err (ohci, "bad entry %8x\n", td_dma); + for (i = 0; i < TD_HASH_SIZE; i++) { + td = ohci->td_hash[i]; + if (td) + ohci_err (ohci, "td_hash[%d]\n", i); + while (td) { + ohci_dump_td(ohci, " entry", td); + td = td->td_hash; + } + } + ohci_dump_td(ohci, "bad?", phys_to_virt (td_dma)); break; }