aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2009-08-19 12:22:44 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:37 -0400
commita448c9d8c58ff7d3f8cc2a8f835065460099b22d (patch)
tree418610891b8dc271bbd798ff5c47d921be5f806d /drivers/usb/host
parent3a44494e233c0fdd818d485cfea8998500543589 (diff)
USB: EHCI: change deschedule logic for interrupt QHs
This patch (as1281) changes the way ehci-hcd deschedules interrupt QHs, copying the approach used for async QHs. The caller is no longer responsible for rescheduling the QH if its queue is non-empty; instead the reschedule is done directly by intr_deschedule(), after calling qh_completions(). This is exactly the same as how end_unlink_async() works. ehci_urb_dequeue() and intr_deschedule() now correctly handle the case where they are called while another interrupt URB for the same QH is being given back. This was a surprisingly large blind spot. And scan_periodic() now respects the new needs_rescan flag. 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')
-rw-r--r--drivers/usb/host/ehci-hcd.c26
-rw-r--r--drivers/usb/host/ehci-q.c12
-rw-r--r--drivers/usb/host/ehci-sched.c36
3 files changed, 40 insertions, 34 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d7e85b6231b3..4f89d7ffd53a 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -934,8 +934,9 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
934 break; 934 break;
935 switch (qh->qh_state) { 935 switch (qh->qh_state) {
936 case QH_STATE_LINKED: 936 case QH_STATE_LINKED:
937 case QH_STATE_COMPLETING:
937 intr_deschedule (ehci, qh); 938 intr_deschedule (ehci, qh);
938 /* FALL THROUGH */ 939 break;
939 case QH_STATE_IDLE: 940 case QH_STATE_IDLE:
940 qh_completions (ehci, qh); 941 qh_completions (ehci, qh);
941 break; 942 break;
@@ -944,23 +945,6 @@ static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
944 qh, qh->qh_state); 945 qh, qh->qh_state);
945 goto done; 946 goto done;
946 } 947 }
947
948 /* reschedule QH iff another request is queued */
949 if (!list_empty (&qh->qtd_list)
950 && HC_IS_RUNNING (hcd->state)) {
951 rc = qh_schedule(ehci, qh);
952
953 /* An error here likely indicates handshake failure
954 * or no space left in the schedule. Neither fault
955 * should happen often ...
956 *
957 * FIXME kill the now-dysfunctional queued urbs
958 */
959 if (rc != 0)
960 ehci_err(ehci,
961 "can't reschedule qh %p, err %d",
962 qh, rc);
963 }
964 break; 948 break;
965 949
966 case PIPE_ISOCHRONOUS: 950 case PIPE_ISOCHRONOUS:
@@ -1079,12 +1063,10 @@ ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
1079 * while the QH is active. Unlink it now; 1063 * while the QH is active. Unlink it now;
1080 * re-linking will call qh_refresh(). 1064 * re-linking will call qh_refresh().
1081 */ 1065 */
1082 if (eptype == USB_ENDPOINT_XFER_BULK) { 1066 if (eptype == USB_ENDPOINT_XFER_BULK)
1083 unlink_async(ehci, qh); 1067 unlink_async(ehci, qh);
1084 } else { 1068 else
1085 intr_deschedule(ehci, qh); 1069 intr_deschedule(ehci, qh);
1086 (void) qh_schedule(ehci, qh);
1087 }
1088 } 1070 }
1089 } 1071 }
1090 spin_unlock_irqrestore(&ehci->lock, flags); 1072 spin_unlock_irqrestore(&ehci->lock, flags);
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 57a84795c43f..00ad9ce392ed 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -299,7 +299,6 @@ __acquires(ehci->lock)
299static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); 299static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
300static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); 300static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
301 301
302static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
303static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh); 302static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
304 303
305/* 304/*
@@ -555,14 +554,9 @@ halt:
555 * That should be rare for interrupt transfers, 554 * That should be rare for interrupt transfers,
556 * except maybe high bandwidth ... 555 * except maybe high bandwidth ...
557 */ 556 */
558 if ((cpu_to_hc32(ehci, QH_SMASK) 557
559 & hw->hw_info2) != 0) { 558 /* Tell the caller to start an unlink */
560 intr_deschedule (ehci, qh); 559 qh->needs_rescan = 1;
561 (void) qh_schedule (ehci, qh);
562 } else {
563 /* Tell the caller to start an unlink */
564 qh->needs_rescan = 1;
565 }
566 break; 560 break;
567 /* otherwise, unlink already started */ 561 /* otherwise, unlink already started */
568 } 562 }
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 327437af2122..3ea05936851f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -615,8 +615,19 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
615 615
616static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh) 616static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
617{ 617{
618 unsigned wait; 618 unsigned wait;
619 struct ehci_qh_hw *hw = qh->hw; 619 struct ehci_qh_hw *hw = qh->hw;
620 int rc;
621
622 /* If the QH isn't linked then there's nothing we can do
623 * unless we were called during a giveback, in which case
624 * qh_completions() has to deal with it.
625 */
626 if (qh->qh_state != QH_STATE_LINKED) {
627 if (qh->qh_state == QH_STATE_COMPLETING)
628 qh->needs_rescan = 1;
629 return;
630 }
620 631
621 qh_unlink_periodic (ehci, qh); 632 qh_unlink_periodic (ehci, qh);
622 633
@@ -636,6 +647,24 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
636 qh->qh_state = QH_STATE_IDLE; 647 qh->qh_state = QH_STATE_IDLE;
637 hw->hw_next = EHCI_LIST_END(ehci); 648 hw->hw_next = EHCI_LIST_END(ehci);
638 wmb (); 649 wmb ();
650
651 qh_completions(ehci, qh);
652
653 /* reschedule QH iff another request is queued */
654 if (!list_empty(&qh->qtd_list) &&
655 HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
656 rc = qh_schedule(ehci, qh);
657
658 /* An error here likely indicates handshake failure
659 * or no space left in the schedule. Neither fault
660 * should happen often ...
661 *
662 * FIXME kill the now-dysfunctional queued urbs
663 */
664 if (rc != 0)
665 ehci_err(ehci, "can't reschedule qh %p, err %d\n",
666 qh, rc);
667 }
639} 668}
640 669
641/*-------------------------------------------------------------------------*/ 670/*-------------------------------------------------------------------------*/
@@ -2213,7 +2242,8 @@ restart:
2213 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); 2242 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
2214 q = q.qh->qh_next; 2243 q = q.qh->qh_next;
2215 modified = qh_completions (ehci, temp.qh); 2244 modified = qh_completions (ehci, temp.qh);
2216 if (unlikely (list_empty (&temp.qh->qtd_list))) 2245 if (unlikely(list_empty(&temp.qh->qtd_list) ||
2246 temp.qh->needs_rescan))
2217 intr_deschedule (ehci, temp.qh); 2247 intr_deschedule (ehci, temp.qh);
2218 qh_put (temp.qh); 2248 qh_put (temp.qh);
2219 break; 2249 break;