aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-06-29 10:47:30 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-07-12 18:16:39 -0400
commit914b701280a76f96890ad63eb0fa99bf204b961c (patch)
tree9373723da74f660aa667da000301c191b1929bd8 /drivers/usb/host/ehci-q.c
parentcb88a1b887bb8908f6e00ce29e893ea52b074940 (diff)
USB: EHCI: use the new clear_tt_buffer interface
This patch (as1256) changes ehci-hcd and all the other drivers in the EHCI family to make use of the new clear_tt_buffer callbacks. When a Clear-TT-Buffer request is in progress for a QH, the QH is not allowed to be linked into the async schedule until the request is finished. At that time, if there are any URBs queued for the QH, it is linked into the async schedule. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> 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.c91
1 files changed, 68 insertions, 23 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 68bf81e982d2..e3d2b627bfb3 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -139,6 +139,55 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
139 139
140/*-------------------------------------------------------------------------*/ 140/*-------------------------------------------------------------------------*/
141 141
142static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh);
143
144static void ehci_clear_tt_buffer_complete(struct usb_hcd *hcd,
145 struct usb_host_endpoint *ep)
146{
147 struct ehci_hcd *ehci = hcd_to_ehci(hcd);
148 struct ehci_qh *qh = ep->hcpriv;
149 unsigned long flags;
150
151 spin_lock_irqsave(&ehci->lock, flags);
152 qh->clearing_tt = 0;
153 if (qh->qh_state == QH_STATE_IDLE && !list_empty(&qh->qtd_list)
154 && HC_IS_RUNNING(hcd->state))
155 qh_link_async(ehci, qh);
156 spin_unlock_irqrestore(&ehci->lock, flags);
157}
158
159static void ehci_clear_tt_buffer(struct ehci_hcd *ehci, struct ehci_qh *qh,
160 struct urb *urb, u32 token)
161{
162
163 /* If an async split transaction gets an error or is unlinked,
164 * the TT buffer may be left in an indeterminate state. We
165 * have to clear the TT buffer.
166 *
167 * Note: this routine is never called for Isochronous transfers.
168 */
169 if (urb->dev->tt && !usb_pipeint(urb->pipe) && !qh->clearing_tt) {
170#ifdef DEBUG
171 struct usb_device *tt = urb->dev->tt->hub;
172 dev_dbg(&tt->dev,
173 "clear tt buffer port %d, a%d ep%d t%08x\n",
174 urb->dev->ttport, urb->dev->devnum,
175 usb_pipeendpoint(urb->pipe), token);
176#endif /* DEBUG */
177 if (!ehci_is_TDI(ehci)
178 || urb->dev->tt->hub !=
179 ehci_to_hcd(ehci)->self.root_hub) {
180 if (usb_hub_clear_tt_buffer(urb) == 0)
181 qh->clearing_tt = 1;
182 } else {
183
184 /* REVISIT ARC-derived cores don't clear the root
185 * hub TT buffer in this way...
186 */
187 }
188 }
189}
190
142static int qtd_copy_status ( 191static int qtd_copy_status (
143 struct ehci_hcd *ehci, 192 struct ehci_hcd *ehci,
144 struct urb *urb, 193 struct urb *urb,
@@ -195,28 +244,6 @@ static int qtd_copy_status (
195 usb_pipeendpoint (urb->pipe), 244 usb_pipeendpoint (urb->pipe),
196 usb_pipein (urb->pipe) ? "in" : "out", 245 usb_pipein (urb->pipe) ? "in" : "out",
197 token, status); 246 token, status);
198
199 /* if async CSPLIT failed, try cleaning out the TT buffer */
200 if (status != -EPIPE
201 && urb->dev->tt
202 && !usb_pipeint(urb->pipe)
203 && ((token & QTD_STS_MMF) != 0
204 || QTD_CERR(token) == 0)
205 && (!ehci_is_TDI(ehci)
206 || urb->dev->tt->hub !=
207 ehci_to_hcd(ehci)->self.root_hub)) {
208#ifdef DEBUG
209 struct usb_device *tt = urb->dev->tt->hub;
210 dev_dbg (&tt->dev,
211 "clear tt buffer port %d, a%d ep%d t%08x\n",
212 urb->dev->ttport, urb->dev->devnum,
213 usb_pipeendpoint (urb->pipe), token);
214#endif /* DEBUG */
215 /* REVISIT ARC-derived cores don't clear the root
216 * hub TT buffer in this way...
217 */
218 usb_hub_clear_tt_buffer(urb);
219 }
220 } 247 }
221 248
222 return status; 249 return status;
@@ -407,9 +434,16 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
407 /* qh unlinked; token in overlay may be most current */ 434 /* qh unlinked; token in overlay may be most current */
408 if (state == QH_STATE_IDLE 435 if (state == QH_STATE_IDLE
409 && cpu_to_hc32(ehci, qtd->qtd_dma) 436 && cpu_to_hc32(ehci, qtd->qtd_dma)
410 == qh->hw_current) 437 == qh->hw_current) {
411 token = hc32_to_cpu(ehci, qh->hw_token); 438 token = hc32_to_cpu(ehci, qh->hw_token);
412 439
440 /* An unlink may leave an incomplete
441 * async transaction in the TT buffer.
442 * We have to clear it.
443 */
444 ehci_clear_tt_buffer(ehci, qh, urb, token);
445 }
446
413 /* force halt for unlinked or blocked qh, so we'll 447 /* force halt for unlinked or blocked qh, so we'll
414 * patch the qh later and so that completions can't 448 * patch the qh later and so that completions can't
415 * activate it while we "know" it's stopped. 449 * activate it while we "know" it's stopped.
@@ -435,6 +469,13 @@ halt:
435 && (qtd->hw_alt_next 469 && (qtd->hw_alt_next
436 & EHCI_LIST_END(ehci))) 470 & EHCI_LIST_END(ehci)))
437 last_status = -EINPROGRESS; 471 last_status = -EINPROGRESS;
472
473 /* As part of low/full-speed endpoint-halt processing
474 * we must clear the TT buffer (11.17.5).
475 */
476 if (unlikely(last_status != -EINPROGRESS &&
477 last_status != -EREMOTEIO))
478 ehci_clear_tt_buffer(ehci, qh, urb, token);
438 } 479 }
439 480
440 /* if we're removing something not at the queue head, 481 /* 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)
864 __hc32 dma = QH_NEXT(ehci, qh->qh_dma); 905 __hc32 dma = QH_NEXT(ehci, qh->qh_dma);
865 struct ehci_qh *head; 906 struct ehci_qh *head;
866 907
908 /* Don't link a QH if there's a Clear-TT-Buffer pending */
909 if (unlikely(qh->clearing_tt))
910 return;
911
867 /* (re)start the async schedule? */ 912 /* (re)start the async schedule? */
868 head = ehci->async; 913 head = ehci->async;
869 timer_action_done (ehci, TIMER_ASYNC_OFF); 914 timer_action_done (ehci, TIMER_ASYNC_OFF);