diff options
Diffstat (limited to 'drivers/usb/host/ehci-q.c')
-rw-r--r-- | drivers/usb/host/ehci-q.c | 91 |
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 | ||
142 | static void qh_link_async(struct ehci_hcd *ehci, struct ehci_qh *qh); | ||
143 | |||
144 | static 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 | |||
159 | static 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 | |||
142 | static int qtd_copy_status ( | 191 | static 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); |