On Mon, 10 Dec 2012, Sarah Sharp wrote: > > > Ok. The hardware devs are asking if this problem is hit on newer > > > hardware. They think that most of the kinks in the EHCI host should > > > have been worked out by the Nehalem generation. Do you have access to a > > > newer EHCI system? If not, I will attempt to find the ez-usb device I > > > have and learn how to program it. > > > > I do have hardware that's newer than ICH5 -- as best I recall, it's > > ICH9. How does that compare with Nehalem? I never figured out the > > relation between Intel's code names and part names. There seem to be > > at least three different ways of describing each piece of hardware. > > Yep. Even at Intel we get confused. > > Nehalem seems to be a particular CPU from 2008. ICH9 came out in 2007. > So I guess your hardware is a year older than what the devs are looking > for. I would suggest you test on the newer box anyway. I just finished the test. The ICH9 system exhibits the same sort of bug. For reference, the test involves applying the patch below (which is based on the 3.7 kernel). Plug in a high-speed g-zero gadget and run testusb -D /dev/bus/usb/BBB/DDD -t 24 (fill in the BBB and DDD values appropriately). If the patch's "Writeback after IAA" debugging messages appear then the bug is present. Alan Stern Index: usb-3.7/drivers/usb/host/ehci-q.c =================================================================== --- usb-3.7.orig/drivers/usb/host/ehci-q.c +++ usb-3.7/drivers/usb/host/ehci-q.c @@ -128,6 +128,19 @@ qh_refresh (struct ehci_hcd *ehci, struc else { qtd = list_entry (qh->qtd_list.next, struct ehci_qtd, qtd_list); + + if (qh->old_qtd && (qh->old_ovtok != qh->hw->hw_token || + qh->old_tdtok != qh->new_tdtok || + (qtd == qh->old_qtd && + qh->old_tdtok != qtd->hw_token))) + ehci_dbg(ehci, "Writeback after IAA: qtd %p %p %c qtd token %x %x qh token %x %x\n", + qh->old_qtd, qtd, + qh->old_qtd == qtd ? ' ' : '*', + hc32_to_cpu(ehci, qh->old_tdtok), + hc32_to_cpu(ehci, qtd == qh->old_qtd ? qtd->hw_token : qh->new_tdtok), + hc32_to_cpu(ehci, qh->old_ovtok), + hc32_to_cpu(ehci, qh->hw->hw_token)); + /* * first qtd may already be partially processed. * If we come here during unlink, the QH overlay region @@ -141,6 +154,7 @@ qh_refresh (struct ehci_hcd *ehci, struc } } + qh->old_qtd = NULL; if (qtd) qh_update (ehci, qh, qtd); } @@ -372,6 +386,8 @@ qh_completions (struct ehci_hcd *ehci, s /* hardware copies qtd out of qh overlay */ rmb (); token = hc32_to_cpu(ehci, qtd->hw_token); + if (qtd == qh->old_qtd) + qh->new_tdtok = qtd->hw_token; /* always clean up qtds the hc de-activated */ retry_xacterr: @@ -552,9 +568,6 @@ qh_completions (struct ehci_hcd *ehci, s */ if (stopped != 0 || hw->hw_qtd_next == EHCI_LIST_END(ehci)) { switch (state) { - case QH_STATE_IDLE: - qh_refresh(ehci, qh); - break; case QH_STATE_LINKED: /* We won't refresh a QH that's linked (after the HC * stopped the queue). That avoids a race: @@ -962,7 +975,6 @@ done: hw->hw_info2 = cpu_to_hc32(ehci, info2); qh->is_out = !is_input; usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1); - qh_refresh (ehci, qh); return qh; } @@ -1226,6 +1238,22 @@ static void start_iaa_cycle(struct ehci_ /* the async qh for the qtds being unlinked are now gone from the HC */ +static void test_qh(struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + struct ehci_qtd *qtd; + __hc32 tok; + + qh->old_ovtok = qh->hw->hw_token; + list_for_each_entry(qtd, &qh->qtd_list, qtd_list) { + tok = ACCESS_ONCE(qtd->hw_token); + if (tok & ACTIVE_BIT(ehci)) { + qh->old_qtd = qtd; + qh->old_tdtok = qh->new_tdtok = tok; + break; + } + } +} + static void end_unlink_async(struct ehci_hcd *ehci) { struct ehci_qh *qh; @@ -1244,6 +1272,7 @@ static void end_unlink_async(struct ehci qh->qh_state = QH_STATE_IDLE; qh->qh_next.qh = NULL; + test_qh(ehci, qh); qh_completions(ehci, qh); if (!list_empty(&qh->qtd_list) && Index: usb-3.7/drivers/usb/host/ehci-timer.c =================================================================== --- usb-3.7.orig/drivers/usb/host/ehci-timer.c +++ usb-3.7/drivers/usb/host/ehci-timer.c @@ -328,7 +328,7 @@ static void ehci_iaa_watchdog(struct ehc ehci_writel(ehci, STS_IAA, &ehci->regs->status); } - ehci_vdbg(ehci, "IAA watchdog: status %x cmd %x\n", + ehci_dbg(ehci, "IAA watchdog: status %x cmd %x\n", status, cmd); end_unlink_async(ehci); } Index: usb-3.7/drivers/usb/host/ehci.h =================================================================== --- usb-3.7.orig/drivers/usb/host/ehci.h +++ usb-3.7/drivers/usb/host/ehci.h @@ -402,6 +402,9 @@ struct ehci_qh { struct usb_device *dev; /* access to TT */ unsigned is_out:1; /* bulk or intr OUT */ unsigned clearing_tt:1; /* Clear-TT-Buf in progress */ + + struct ehci_qtd *old_qtd; + __hc32 old_ovtok, old_tdtok, new_tdtok; }; /*-------------------------------------------------------------------------*/ -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html