|
@@ -139,6 +139,55 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|
|
|
|
|
/*-------------------------------------------------------------------------*/
|
|
|
|
|
|
+static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
|
|
|
+
|
|
|
+static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
|
|
|
+ struct usb_host_endpoint *ep)
|
|
|
+{
|
|
|
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
|
|
+ struct ehci_qh *qh = ep->hcpriv;
|
|
|
+ unsigned long flags;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&ehci->lock, flags);
|
|
|
+ qh->clearing_tt = 0;
|
|
|
+ if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
|
|
|
+ && HC_IS_RUNNING(hcd->state))
|
|
|
+ qh_link_async(ehci, qh);
|
|
|
+ spin_unlock_irqrestore(&ehci->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
|
|
|
+ struct urb *urb, u32 token)
|
|
|
+{
|
|
|
+
|
|
|
+ /* If an async split transaction gets an error or is unlinked,
|
|
|
+ * the TT buffer may be left in an indeterminate state. We
|
|
|
+ * have to clear the TT buffer.
|
|
|
+ *
|
|
|
+ * Note: this routine is never called for Isochronous transfers.
|
|
|
+ */
|
|
|
+ if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
|
|
|
+#ifdef DEBUG
|
|
|
+ struct usb_device *tt = urb->dev->tt->hub;
|
|
|
+ dev_dbg(&tt->dev,
|
|
|
+ "clear tt buffer port %d, a%d ep%d t%08x\n",
|
|
|
+ urb->dev->ttport, urb->dev->devnum,
|
|
|
+ usb_pipeendpoint(urb->pipe), token);
|
|
|
+#endif /* DEBUG */
|
|
|
+ if (!ehci_is_TDI(ehci)
|
|
|
+ || urb->dev->tt->hub !=
|
|
|
+ ehci_to_hcd(ehci)->self.root_hub) {
|
|
|
+ if (usb_hub_clear_tt_buffer(urb) == 0)
|
|
|
+ qh->clearing_tt = 1;
|
|
|
+ } else {
|
|
|
+
|
|
|
+ /* REVISIT ARC-derived cores don't clear the root
|
|
|
+ * hub TT buffer in this way...
|
|
|
+ */
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static int qtd_copy_status (
|
|
|
struct ehci_hcd *ehci,
|
|
|
struct urb *urb,
|
|
@@ -195,28 +244,6 @@ static int qtd_copy_status (
|
|
|
usb_pipeendpoint (urb->pipe),
|
|
|
usb_pipein (urb->pipe) ? "in" : "out",
|
|
|
token, status);
|
|
|
-
|
|
|
- /* if async CSPLIT failed, try cleaning out the TT buffer */
|
|
|
- if (status != -EPIPE
|
|
|
- && urb->dev->tt
|
|
|
- && !usb_pipeint(urb->pipe)
|
|
|
- && ((token & QTD_STS_MMF) != 0
|
|
|
- || QTD_CERR(token) == 0)
|
|
|
- && (!ehci_is_TDI(ehci)
|
|
|
- || urb->dev->tt->hub !=
|
|
|
- ehci_to_hcd(ehci)->self.root_hub)) {
|
|
|
-#ifdef DEBUG
|
|
|
- struct usb_device *tt = urb->dev->tt->hub;
|
|
|
- dev_dbg (&tt->dev,
|
|
|
- "clear tt buffer port %d, a%d ep%d t%08x\n",
|
|
|
- urb->dev->ttport, urb->dev->devnum,
|
|
|
- usb_pipeendpoint (urb->pipe), token);
|
|
|
-#endif /* DEBUG */
|
|
|
- /* REVISIT ARC-derived cores don't clear the root
|
|
|
- * hub TT buffer in this way...
|
|
|
- */
|
|
|
- usb_hub_clear_tt_buffer(urb);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
return status;
|
|
@@ -407,9 +434,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|
|
/* qh unlinked; token in overlay may be most current */
|
|
|
if (state == QH_STATE_IDLE
|
|
|
&& cpu_to_hc32(ehci, qtd->qtd_dma)
|
|
|
- == qh->hw_current)
|
|
|
+ == qh->hw_current) {
|
|
|
token = hc32_to_cpu(ehci, qh->hw_token);
|
|
|
|
|
|
+ /* An unlink may leave an incomplete
|
|
|
+ * async transaction in the TT buffer.
|
|
|
+ * We have to clear it.
|
|
|
+ */
|
|
|
+ ehci_clear_tt_buffer(ehci, qh, urb, token);
|
|
|
+ }
|
|
|
+
|
|
|
/* force halt for unlinked or blocked qh, so we'll
|
|
|
* patch the qh later and so that completions can't
|
|
|
* activate it while we "know" it's stopped.
|
|
@@ -435,6 +469,13 @@ halt:
|
|
|
&& (qtd->hw_alt_next
|
|
|
& EHCI_LIST_END(ehci)))
|
|
|
last_status = -EINPROGRESS;
|
|
|
+
|
|
|
+ /* As part of low/full-speed endpoint-halt processing
|
|
|
+ * we must clear the TT buffer (11.17.5).
|
|
|
+ */
|
|
|
+ if (unlikely(last_status != -EINPROGRESS &&
|
|
|
+ last_status != -EREMOTEIO))
|
|
|
+ ehci_clear_tt_buffer(ehci, qh, urb, token);
|
|
|
}
|
|
|
|
|
|
/* if we're removing something not at the queue head,
|
|
@@ -864,6 +905,10 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
|
|
|
__hc32 dma = QH_NEXT(ehci, qh->qh_dma);
|
|
|
struct ehci_qh *head;
|
|
|
|
|
|
+ /* Don't link a QH if there's a Clear-TT-Buffer pending */
|
|
|
+ if (unlikely(qh->clearing_tt))
|
|
|
+ return;
|
|
|
+
|
|
|
/* (re)start the async schedule? */
|
|
|
head = ehci->async;
|
|
|
timer_action_done (ehci, TIMER_ASYNC_OFF);
|