]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
USB: EHCI: add software retry for transaction errors
authorAlan Stern <stern@rowland.harvard.edu>
Thu, 26 Mar 2009 18:25:05 +0000 (18:25 +0000)
committerChris Wright <chrisw@sous-sol.org>
Thu, 2 Apr 2009 20:55:15 +0000 (13:55 -0700)
upstream commit: a2c2706e1043c17139c2dafd171c4a5cf008ef7e

This patch (as1204) adds a software retry mechanism to ehci-hcd.  It
gets invoked when the driver encounters transaction errors on an
asynchronous endpoint.  On many systems, hardware deficiencies cause
such errors to occur if one device is unplugged while the host is
communicating with another device.  With the patch, the failed
transactions are retried and generally succeed the second or third
time through.

This is based on code originally written by Koichiro Saito.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Tested by: Koichiro Saito <Saito.Koichiro@adniss.jp>
CC: David Brownell <david-b@pacbell.net>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci.h

index ecc9b66c03cd38323377c6f3f6b27275d02d58e5..01132ac74eb878817144f37af81794dcca4dafb1 100644 (file)
@@ -333,12 +333,40 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                token = hc32_to_cpu(ehci, qtd->hw_token);
 
                /* always clean up qtds the hc de-activated */
+ retry_xacterr:
                if ((token & QTD_STS_ACTIVE) == 0) {
 
                        /* on STALL, error, and short reads this urb must
                         * complete and all its qtds must be recycled.
                         */
                        if ((token & QTD_STS_HALT) != 0) {
+
+                               /* retry transaction errors until we
+                                * reach the software xacterr limit
+                                */
+                               if ((token & QTD_STS_XACT) &&
+                                               QTD_CERR(token) == 0 &&
+                                               --qh->xacterrs > 0 &&
+                                               !urb->unlinked) {
+                                       ehci_dbg(ehci,
+       "detected XactErr len %d/%d retry %d\n",
+       qtd->length - QTD_LENGTH(token), qtd->length,
+       QH_XACTERR_MAX - qh->xacterrs);
+
+                                       /* reset the token in the qtd and the
+                                        * qh overlay (which still contains
+                                        * the qtd) so that we pick up from
+                                        * where we left off
+                                        */
+                                       token &= ~QTD_STS_HALT;
+                                       token |= QTD_STS_ACTIVE |
+                                                       (EHCI_TUNE_CERR << 10);
+                                       qtd->hw_token = cpu_to_hc32(ehci,
+                                                       token);
+                                       wmb();
+                                       qh->hw_token = cpu_to_hc32(ehci, token);
+                                       goto retry_xacterr;
+                               }
                                stopped = 1;
 
                        /* magic dummy for some short reads; qh won't advance.
@@ -421,6 +449,9 @@ halt:
                /* remove qtd; it's recycled after possible urb completion */
                list_del (&qtd->qtd_list);
                last = qtd;
+
+               /* reinit the xacterr counter for the next qtd */
+               qh->xacterrs = QH_XACTERR_MAX;
        }
 
        /* last urb's completion might still need calling */
@@ -862,6 +893,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        head->qh_next.qh = qh;
        head->hw_next = dma;
 
+       qh->xacterrs = QH_XACTERR_MAX;
        qh->qh_state = QH_STATE_LINKED;
        /* qtd completions reported later by interrupt */
 }
index 262b00c9b334286583d8fb84d394bac07a86a304..c7385f249bd77e0b8fbc502d84b3a49e16c28e40 100644 (file)
@@ -376,6 +376,9 @@ struct ehci_qh {
 #define        QH_STATE_UNLINK_WAIT    4               /* LINKED and on reclaim q */
 #define        QH_STATE_COMPLETING     5               /* don't touch token.HALT */
 
+       u8                      xacterrs;       /* XactErr retry counter */
+#define        QH_XACTERR_MAX          32              /* XactErr retry limit */
+
        /* periodic schedule info */
        u8                      usecs;          /* intr bandwidth */
        u8                      gap_uf;         /* uframes split/csplit gap */