diff options
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 33 |
1 files changed, 29 insertions, 4 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 0917e3a..e4cc485 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -289,6 +289,12 @@ __acquires(ehci->lock) urb->actual_length, urb->transfer_buffer_length); #endif +#ifdef CONFIG_HOST_COMPLIANT_TEST + if (likely (urb->transfer_flags == URB_HCD_DRIVER_TEST)) { + ehci_dbg(ehci, "USB_TEST : transfer_flags = URB_HCD_DRIVER_TEST so... return!\n"); + return; + } +#endif /* complete() can reenter this HCD */ usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb); spin_unlock (&ehci->lock); @@ -387,10 +393,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) QTD_CERR(token) == 0 && ++qh->xacterrs < QH_XACTERR_MAX && !urb->unlinked) { - ehci_dbg(ehci, - "detected XactErr len %zu/%zu retry %d\n", - qtd->length - QTD_LENGTH(token), qtd->length, qh->xacterrs); - /* reset the token in the qtd and the * qh overlay (which still contains * the qtd) so that we pick up from @@ -406,6 +408,11 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) token); goto retry_xacterr; } + if (qh->xacterrs >= QH_XACTERR_MAX) + ehci_dbg(ehci, + "detected XactErr len %zu/%zu retry %d\n", + qtd->length - QTD_LENGTH(token), + qtd->length, qh->xacterrs); stopped = 1; /* magic dummy for some short reads; qh won't advance. @@ -995,6 +1002,12 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head->qh_next.qh = qh; head->hw->hw_next = dma; + /* + * flush qh descriptor into memory immediately, + * see comments in qh_append_tds. + * */ + ehci_sync_mem(); + qh_get(qh); qh->xacterrs = 0; qh->qh_state = QH_STATE_LINKED; @@ -1082,6 +1095,18 @@ static struct ehci_qh *qh_append_tds ( wmb (); dummy->hw_token = token; + /* + * Writing to dma coherent buffer on ARM may + * be delayed to reach memory, so HC may not see + * hw_token of dummy qtd in time, which can cause + * the qtd transaction to be executed very late, + * and degrade performance a lot. ehci_sync_mem + * is added to flush 'token' immediatelly into + * memory, so that ehci can execute the transaction + * ASAP. + * */ + ehci_sync_mem(); + urb->hcpriv = qh_get (qh); } } |