aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-q.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-08-19 12:22:06 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:37 -0400
commit3a44494e233c0fdd818d485cfea8998500543589 (patch)
tree04b66268a2efc1236d3f9e477a04dc2d3ec87582 /drivers/usb/host/ehci-q.c
parent04c4ab17c7c39603c5017bee20d3b8ccb2f19816 (diff)
USB: EHCI: rescan the queue after an unlink
This patch (as1280) fixes an obscure bug in ehci-hcd's dequeuing logic for async URBs. If a later URB is unlinked and the completion routine unlinks an earlier URB, then the earlier URB won't be given back in a timely manner because the endpoint queue isn't rescanned as it should be. Similar bugs occur if an endpoint is reset or a halt is cleared while a completion routine is running, because the subroutines don't test for the COMPLETING state. All these problems are solved by adding a new needs_rescan flag to the ehci_qh structure. If the flag is set while scanning through an idle QH, the scan will be repeated. If the QH isn't idle then an unlink cycle will be initiated, and the proper action will be taken when it becomes idle. Also, an unnecessary test is removed from qh_link_async(): That routine is never called if the QH's state isn't IDLE. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> CC: David Brownell <david-b@pacbell.net> 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.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;