diff options
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 32 |
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..1976b1b3778c 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 %zu/%zu 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 | } |