Re: Need help for hardware bug in Intel's EHCI implementation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux