Skip to content

Commit

Permalink
USB: EHCI: add software retry for transaction errors
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Alan Stern authored and Greg Kroah-Hartman committed Mar 24, 2009
1 parent 1f4159c commit a2c2706
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
32 changes: 32 additions & 0 deletions drivers/usb/host/ehci-q.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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 */
}
Expand Down
3 changes: 3 additions & 0 deletions drivers/usb/host/ehci.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down

0 comments on commit a2c2706

Please sign in to comment.