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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to