aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-02-10 10:16:58 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2009-03-24 19:20:31 -0400
commita2c2706e1043c17139c2dafd171c4a5cf008ef7e (patch)
tree59d6519004eb562ebee5df5f1a4394290dec16ff /drivers/usb/host/ehci-q.c
parent1f4159c1620f74377e26d8a569d10ca5907ef475 (diff)
USB: EHCI: add software retry for transaction errors
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>
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r--drivers/usb/host/ehci-q.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index ecc9b66c03cd..01132ac74eb8 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -333,12 +333,40 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
333 token = hc32_to_cpu(ehci, qtd->hw_token); 333 token = hc32_to_cpu(ehci, qtd->hw_token);
334 334
335 /* always clean up qtds the hc de-activated */ 335 /* always clean up qtds the hc de-activated */
336 retry_xacterr:
336 if ((token & QTD_STS_ACTIVE) == 0) { 337 if ((token & QTD_STS_ACTIVE) == 0) {
337 338
338 /* on STALL, error, and short reads this urb must 339 /* on STALL, error, and short reads this urb must
339 * complete and all its qtds must be recycled. 340 * complete and all its qtds must be recycled.
340 */ 341 */
341 if ((token & QTD_STS_HALT) != 0) { 342 if ((token & QTD_STS_HALT) != 0) {
343
344 /* retry transaction errors until we
345 * reach the software xacterr limit
346 */
347 if ((token & QTD_STS_XACT) &&
348 QTD_CERR(token) == 0 &&
349 --qh->xacterrs > 0 &&
350 !urb->unlinked) {
351 ehci_dbg(ehci,
352 "detected XactErr len %d/%d retry %d\n",
353 qtd->length - QTD_LENGTH(token), qtd->length,
354 QH_XACTERR_MAX - qh->xacterrs);
355
356 /* reset the token in the qtd and the
357 * qh overlay (which still contains
358 * the qtd) so that we pick up from
359 * where we left off
360 */
361 token &= ~QTD_STS_HALT;
362 token |= QTD_STS_ACTIVE |
363 (EHCI_TUNE_CERR << 10);
364 qtd->hw_token = cpu_to_hc32(ehci,
365 token);
366 wmb();
367 qh->hw_token = cpu_to_hc32(ehci, token);
368 goto retry_xacterr;
369 }
342 stopped = 1; 370 stopped = 1;
343 371
344 /* magic dummy for some short reads; qh won't advance. 372 /* magic dummy for some short reads; qh won't advance.
@@ -421,6 +449,9 @@ halt:
421 /* remove qtd; it's recycled after possible urb completion */ 449 /* remove qtd; it's recycled after possible urb completion */
422 list_del (&qtd->qtd_list); 450 list_del (&qtd->qtd_list);
423 last = qtd; 451 last = qtd;
452
453 /* reinit the xacterr counter for the next qtd */
454 qh->xacterrs = QH_XACTERR_MAX;
424 } 455 }
425 456
426 /* last urb's completion might still need calling */ 457 /* 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)
862 head->qh_next.qh = qh; 893 head->qh_next.qh = qh;
863 head->hw_next = dma; 894 head->hw_next = dma;
864 895
896 qh->xacterrs = QH_XACTERR_MAX;
865 qh->qh_state = QH_STATE_LINKED; 897 qh->qh_state = QH_STATE_LINKED;
866 /* qtd completions reported later by interrupt */ 898 /* qtd completions reported later by interrupt */
867} 899}