From 3f223a1845337f1d8be7695bb8bff12081acfb92 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 10 Feb 2009 10:16:58 -0500 Subject: [PATCH] --- yaml --- r: 133509 b: refs/heads/master c: a2c2706e1043c17139c2dafd171c4a5cf008ef7e h: refs/heads/master i: 133507: 2addfdc3acc346b8dd29e576399baccac35a2e4d v: v3 --- [refs] | 2 +- trunk/drivers/usb/host/ehci-q.c | 32 ++++++++++++++++++++++++++++++++ trunk/drivers/usb/host/ehci.h | 3 +++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 385cf5f04083..c3eabda69695 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1f4159c1620f74377e26d8a569d10ca5907ef475 +refs/heads/master: a2c2706e1043c17139c2dafd171c4a5cf008ef7e diff --git a/trunk/drivers/usb/host/ehci-q.c b/trunk/drivers/usb/host/ehci-q.c index ecc9b66c03cd..01132ac74eb8 100644 --- a/trunk/drivers/usb/host/ehci-q.c +++ b/trunk/drivers/usb/host/ehci-q.c @@ -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 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) /* 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 */ } diff --git a/trunk/drivers/usb/host/ehci.h b/trunk/drivers/usb/host/ehci.h index 0042deb671dd..9aba560fd569 100644 --- a/trunk/drivers/usb/host/ehci.h +++ b/trunk/drivers/usb/host/ehci.h @@ -342,6 +342,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 */