aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
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
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')
-rw-r--r--drivers/usb/host/ehci-hcd.c18
-rw-r--r--drivers/usb/host/ehci-q.c43
-rw-r--r--drivers/usb/host/ehci.h1
3 files changed, 50 insertions, 12 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 6887aac5e73d..d7e85b6231b3 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -863,12 +863,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
863 if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim) 863 if (!HC_IS_RUNNING(ehci_to_hcd(ehci)->state) && ehci->reclaim)
864 end_unlink_async(ehci); 864 end_unlink_async(ehci);
865 865
866 /* if it's not linked then there's nothing to do */ 866 /* If the QH isn't linked then there's nothing we can do
867 if (qh->qh_state != QH_STATE_LINKED) 867 * unless we were called during a giveback, in which case
868 ; 868 * qh_completions() has to deal with it.
869 */
870 if (qh->qh_state != QH_STATE_LINKED) {
871 if (qh->qh_state == QH_STATE_COMPLETING)
872 qh->needs_rescan = 1;
873 return;
874 }
869 875
870 /* defer till later if busy */ 876 /* defer till later if busy */
871 else if (ehci->reclaim) { 877 if (ehci->reclaim) {
872 struct ehci_qh *last; 878 struct ehci_qh *last;
873 879
874 for (last = ehci->reclaim; 880 for (last = ehci->reclaim;
@@ -1001,6 +1007,7 @@ rescan:
1001 qh->qh_state = QH_STATE_IDLE; 1007 qh->qh_state = QH_STATE_IDLE;
1002 switch (qh->qh_state) { 1008 switch (qh->qh_state) {
1003 case QH_STATE_LINKED: 1009 case QH_STATE_LINKED:
1010 case QH_STATE_COMPLETING:
1004 for (tmp = ehci->async->qh_next.qh; 1011 for (tmp = ehci->async->qh_next.qh;
1005 tmp && tmp != qh; 1012 tmp && tmp != qh;
1006 tmp = tmp->qh_next.qh) 1013 tmp = tmp->qh_next.qh)
@@ -1065,7 +1072,8 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1065 usb_settoggle(qh->dev, epnum, is_out, 0); 1072 usb_settoggle(qh->dev, epnum, is_out, 0);
1066 if (!list_empty(&qh->qtd_list)) { 1073 if (!list_empty(&qh->qtd_list)) {
1067 WARN_ONCE(1, "clear_halt for a busy endpoint\n"); 1074 WARN_ONCE(1, "clear_halt for a busy endpoint\n");
1068 } else if (qh->qh_state == QH_STATE_LINKED) { 1075 } else if (qh->qh_state == QH_STATE_LINKED ||
1076 qh->qh_state == QH_STATE_COMPLETING) {
1069 1077
1070 /* The toggle value in the QH can't be updated 1078 /* The toggle value in the QH can't be updated
1071 * while the QH is active. Unlink it now; 1079 * while the QH is active. Unlink it now;
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;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index ec3dba6b8e48..064e76821ff5 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -341,6 +341,7 @@ struct ehci_qh {
341 u32 refcount; 341 u32 refcount;
342 unsigned stamp; 342 unsigned stamp;
343 343
344 u8 needs_rescan; /* Dequeue during giveback */
344 u8 qh_state; 345 u8 qh_state;
345#define QH_STATE_LINKED 1 /* HC sees this */ 346#define QH_STATE_LINKED 1 /* HC sees this */
346#define QH_STATE_UNLINK 2 /* HC may still see this */ 347#define QH_STATE_UNLINK 2 /* HC may still see this */