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.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 377ed530b920..57a84795c43f 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -310,13 +310,13 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
310static unsigned 310static unsigned
311qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh) 311qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
312{ 312{
313 struct ehci_qtd *last = NULL, *end = qh->dummy; 313 struct ehci_qtd *last, *end = qh->dummy;
314 struct list_head *entry, *tmp; 314 struct list_head *entry, *tmp;
315 int last_status = -EINPROGRESS; 315 int last_status;
316 int stopped; 316 int stopped;
317 unsigned count = 0; 317 unsigned count = 0;
318 u8 state; 318 u8 state;
319 __le32 halt = HALT_BIT(ehci); 319 const __le32 halt = HALT_BIT(ehci);
320 struct ehci_qh_hw *hw = qh->hw; 320 struct ehci_qh_hw *hw = qh->hw;
321 321
322 if (unlikely (list_empty (&qh->qtd_list))) 322 if (unlikely (list_empty (&qh->qtd_list)))
@@ -327,11 +327,20 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
327 * they add urbs to this qh's queue or mark them for unlinking. 327 * they add urbs to this qh's queue or mark them for unlinking.
328 * 328 *
329 * NOTE: unlinking expects to be done in queue order. 329 * NOTE: unlinking expects to be done in queue order.
330 *
331 * It's a bug for qh->qh_state to be anything other than
332 * QH_STATE_IDLE, unless our caller is scan_async() or
333 * scan_periodic().
330 */ 334 */
331 state = qh->qh_state; 335 state = qh->qh_state;
332 qh->qh_state = QH_STATE_COMPLETING; 336 qh->qh_state = QH_STATE_COMPLETING;
333 stopped = (state == QH_STATE_IDLE); 337 stopped = (state == QH_STATE_IDLE);
334 338
339 rescan:
340 last = NULL;
341 last_status = -EINPROGRESS;
342 qh->needs_rescan = 0;
343
335 /* remove de-activated QTDs from front of queue. 344 /* remove de-activated QTDs from front of queue.
336 * after faults (including short reads), cleanup this urb 345 * after faults (including short reads), cleanup this urb
337 * then let the queue advance. 346 * then let the queue advance.
@@ -507,6 +516,21 @@ halt:
507 ehci_qtd_free (ehci, last); 516 ehci_qtd_free (ehci, last);
508 } 517 }
509 518
519 /* Do we need to rescan for URBs dequeued during a giveback? */
520 if (unlikely(qh->needs_rescan)) {
521 /* If the QH is already unlinked, do the rescan now. */
522 if (state == QH_STATE_IDLE)
523 goto rescan;
524
525 /* Otherwise we have to wait until the QH is fully unlinked.
526 * Our caller will start an unlink if qh->needs_rescan is
527 * set. But if an unlink has already started, nothing needs
528 * to be done.
529 */
530 if (state != QH_STATE_LINKED)
531 qh->needs_rescan = 0;
532 }
533
510 /* restore original state; caller must unlink or relink */ 534 /* restore original state; caller must unlink or relink */
511 qh->qh_state = state; 535 qh->qh_state = state;
512 536
@@ -535,8 +559,10 @@ halt:
535 & hw->hw_info2) != 0) { 559 & hw->hw_info2) != 0) {
536 intr_deschedule (ehci, qh); 560 intr_deschedule (ehci, qh);
537 (void) qh_schedule (ehci, qh); 561 (void) qh_schedule (ehci, qh);
538 } else 562 } else {
539 unlink_async (ehci, qh); 563 /* Tell the caller to start an unlink */
564 qh->needs_rescan = 1;
565 }
540 break; 566 break;
541 /* otherwise, unlink already started */ 567 /* otherwise, unlink already started */
542 } 568 }
@@ -916,6 +942,8 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
916 if (unlikely(qh->clearing_tt)) 942 if (unlikely(qh->clearing_tt))
917 return; 943 return;
918 944
945 WARN_ON(qh->qh_state != QH_STATE_IDLE);
946
919 /* (re)start the async schedule? */ 947 /* (re)start the async schedule? */
920 head = ehci->async; 948 head = ehci->async;
921 timer_action_done (ehci, TIMER_ASYNC_OFF); 949 timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -934,8 +962,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
934 } 962 }
935 963
936 /* clear halt and/or toggle; and maybe recover from silicon quirk */ 964 /* clear halt and/or toggle; and maybe recover from silicon quirk */
937 if (qh->qh_state == QH_STATE_IDLE) 965 qh_refresh(ehci, qh);
938 qh_refresh (ehci, qh);
939 966
940 /* splice right after start */ 967 /* splice right after start */
941 qh->qh_next = head->qh_next; 968 qh->qh_next = head->qh_next;
@@ -1220,6 +1247,8 @@ rescan:
1220 qh = qh_get (qh); 1247 qh = qh_get (qh);
1221 qh->stamp = ehci->stamp; 1248 qh->stamp = ehci->stamp;
1222 temp = qh_completions (ehci, qh); 1249 temp = qh_completions (ehci, qh);
1250 if (qh->needs_rescan)
1251 unlink_async(ehci, qh);
1223 qh_put (qh); 1252 qh_put (qh);
1224 if (temp != 0) { 1253 if (temp != 0) {
1225 goto rescan; 1254 goto rescan;