aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-q.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r--drivers/usb/host/ehci-q.c33
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);
}
}