ChangeSet 1.850.1.11, 2002/10/30 00:12:42-08:00, david-b@pacbell.net [PATCH] ohci td error cleanup This is a version of a patch I sent out last Friday to help address some of the "bad entry" errors that some folk were seeing, seemingly only with control requests. The fix is just to not try being clever: remove one TD at a time and patch the ED as if that TD had completed normally, then do the next ... don't try to patch just once in this fault case. (And it nukes some debug info I accidently submitted.) I've gotten preliminary feedback that this helps. diff -Nru a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c --- a/drivers/usb/host/ohci-mem.c Wed Oct 30 09:43:28 2002 +++ b/drivers/usb/host/ohci-mem.c Wed Oct 30 09:43:28 2002 @@ -176,13 +176,6 @@ pci_pool_free (hc->td_cache, td, dma); return NULL; } - // DEBUG ONLY want to see if these tds are really getting - // allocated. the last one in a page shouldn't be getting - // allocated during these tests! - if ((dma & 0x0fff) == 0x0fc0) { - dbg ("td = %p", td); - dump_stack (); - } } return td; } diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c --- a/drivers/usb/host/ohci-q.c Wed Oct 30 09:43:28 2002 +++ b/drivers/usb/host/ohci-q.c Wed Oct 30 09:43:28 2002 @@ -736,42 +736,39 @@ */ ed->hwINFO |= ED_SKIP; wmb (); - td->ed->hwHeadP &= ~ED_H; + ed->hwHeadP &= ~ED_H; + /* put any later tds from this urb onto the donelist, after 'td', + * order won't matter here: no errors, and nothing was transferred. + * also patch the ed so it looks as if those tds completed normally. + */ while (tmp != &ed->td_list) { struct td *next; + u32 info; next = list_entry (tmp, struct td, td_list); tmp = next->td_list.next; - /* move other tds from this urb to the donelist, after 'td'. - * order won't matter here: no errors, nothing transferred. - * - * NOTE: this "knows" short control reads won't need fixup: - * hc went from the (one) data TD to the status td. that'll - * change if multi-td control DATA segments are supported, - * and we want to send the status packet. + if (next->urb != urb) + break; + + /* NOTE: if multi-td control DATA segments get supported, + * this urb had one of them, this td wasn't the last td + * in that segment (TD_R clear), this ed halted because + * of a short read, _and_ URB_SHORT_NOT_OK is clear ... + * then we need to leave the control STATUS packet queued + * and clear ED_SKIP. */ - if (next->urb == urb) { - u32 info = next->hwINFO; + info = next->hwINFO; + info |= cpu_to_le32 (TD_DONE); + info &= ~cpu_to_le32 (TD_CC); + next->hwINFO = info; - info |= cpu_to_le32 (TD_DONE); - info &= ~cpu_to_le32 (TD_CC); - next->hwINFO = info; - next->next_dl_td = rev; - rev = next; - continue; - } - - /* restart ed with first td of this next urb */ - ed->hwHeadP = cpu_to_le32 (next->td_dma) | toggle; - tmp = 0; - break; - } + next->next_dl_td = rev; + rev = next; - /* no urbs queued? then ED is empty. */ - if (tmp) - ed->hwHeadP = cpu_to_le32 (ed->dummy->td_dma) | toggle; + ed->hwHeadP = next->hwNextTD | toggle; + } /* help for troubleshooting: */ dbg ("urb %p usb-%s-%s ep-%d-%s cc %d --> status %d",