===================================================================
@@ -201,7 +201,7 @@ static int ohci_urb_enqueue (
/* allocate the TDs (deferring hash chain updates) */
for (i = 0; i < size; i++) {
- urb_priv->td [i] = td_alloc (ohci, mem_flags);
+ urb_priv->td [i] = td_alloc (ohci, mem_flags, urb->dev, urb->ep);
if (!urb_priv->td [i]) {
urb_priv->length = i;
urb_free_priv (ohci, urb_priv);
@@ -580,6 +580,7 @@ static int ohci_run (struct ohci_hcd *oh
struct usb_hcd *hcd = ohci_to_hcd(ohci);
disable (ohci);
+ ohci->testing = 1;
/* boot firmware should have set this up (5.1.1.3.1) */
if (first) {
===================================================================
@@ -82,7 +82,8 @@ dma_to_td (struct ohci_hcd *hc, dma_addr
/* TDs ... */
static struct td *
-td_alloc (struct ohci_hcd *hc, gfp_t mem_flags)
+td_alloc (struct ohci_hcd *hc, gfp_t mem_flags, struct usb_device *udev,
+ struct usb_host_endpoint *ep)
{
dma_addr_t dma;
struct td *td;
@@ -94,6 +95,9 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem
td->hwNextTD = cpu_to_hc32 (hc, dma);
td->td_dma = dma;
/* hashed in td_fill */
+ if (hc->testing)
+ ohci_dbg(hc, "td alloc for %s ep%x: %p\n",
+ udev->devpath, ep->desc.bEndpointAddress, td);
}
return td;
}
@@ -101,14 +105,32 @@ td_alloc (struct ohci_hcd *hc, gfp_t mem
static void
td_free (struct ohci_hcd *hc, struct td *td)
{
- struct td **prev = &hc->td_hash [TD_HASH_FUNC (td->td_dma)];
-
- while (*prev && *prev != td)
+ int hash = TD_HASH_FUNC(td->td_dma);
+ struct td **prev = &hc->td_hash[hash];
+ int n = 0;
+
+ if (hc->testing)
+ ohci_dbg(hc, "td free %p\n", td);
+ while (*prev && *prev != td) {
+ if ((unsigned long) *prev == 0xa7a7a7a7) {
+ ohci_dbg(hc, "poisoned hash at %p (%d %d) %p\n", prev,
+ hash, n, hc->td_hash[hash]);
+ return;
+ }
prev = &(*prev)->td_hash;
- if (*prev)
+ ++n;
+ }
+ if (*prev) {
*prev = td->td_hash;
- else if ((td->hwINFO & cpu_to_hc32(hc, TD_DONE)) != 0)
- ohci_dbg (hc, "no hash for td %p\n", td);
+ if (hc->testing) {
+ ohci_dbg(hc, "(%d %d) %p -> %p\n", hash, n, prev, *prev);
+ if (td->td_hash == td)
+ hc->testing = 0;
+ }
+ } else {
+ ohci_dbg(hc, "no hash for td %p: %d %p\n", td,
+ hash, hc->td_hash[hash]);
+ }
dma_pool_free (hc->td_cache, td, td->td_dma);
}
===================================================================
@@ -406,7 +406,7 @@ static struct ed *ed_get (
}
/* dummy td; end of td list for ed */
- td = td_alloc (ohci, GFP_ATOMIC);
+ td = td_alloc (ohci, GFP_ATOMIC, udev, ep);
if (!td) {
/* out of memory */
ed_free (ohci, ed);
@@ -560,6 +560,11 @@ td_fill (struct ohci_hcd *ohci, u32 info
hash = TD_HASH_FUNC (td->td_dma);
td->td_hash = ohci->td_hash [hash];
ohci->td_hash [hash] = td;
+ if (ohci->testing) {
+ ohci_dbg(ohci, "hash %p to %d -> %p\n", td, hash, td->td_hash);
+ if (td->td_hash == td)
+ ohci->testing = 0;
+ }
/* HC might read the TD (or cachelines) right away ... */
wmb ();
===================================================================
@@ -346,6 +346,7 @@ typedef struct urb_priv {
struct ohci_hcd {
spinlock_t lock;
+ int testing;
/*
* I/O memory used to communicate with the HC (dma-consistent)