USB: EHCI: change return value of qh_completions()
authorAlan Stern <stern@rowland.harvard.edu>
Fri, 22 Mar 2013 17:30:56 +0000 (13:30 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 25 Mar 2013 20:35:05 +0000 (13:35 -0700)
This patch (as1658) cleans up the usage of qh_completions() in
ehci-hcd.  Currently the function's return value indicates whether any
URBs were given back; the idea was that the caller can scan the QH
over again to handle any URBs that were dequeued by a completion
handler.  This is not necessary; when qh_completions() is ready to
give back dequeued URBs, it does its own rescanning.

Therefore the new return value will be a flag indicating whether the
caller needs to unlink the QH.  This is more convenient than forcing
the caller to check qh->needs_rescan, and it makes a lot more sense --
why should "needs_rescan" imply that an unlink is needed?  The callers
are also changed to remove the unneeded rescans.

Lastly, the check for whether qh->qtd_list is non-empty is removed
from the start of qh_completions().  Two of the callers have to make
this test anyway, so the same test can simply be added to the other
two callers.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c

index b824cb6748985352917ad0f4f34727781dbd2ebf..c95f60d43b1a9d3603978ae0d1c21c69b0598dcb 100644 (file)
@@ -292,8 +292,8 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
 
 /*
  * Process and free completed qtds for a qh, returning URBs to drivers.
- * Chases up to qh->hw_current.  Returns number of completions called,
- * indicating how much "real" work we did.
+ * Chases up to qh->hw_current.  Returns nonzero if the caller should
+ * unlink qh.
  */
 static unsigned
 qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
@@ -302,13 +302,9 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
        struct list_head        *entry, *tmp;
        int                     last_status;
        int                     stopped;
-       unsigned                count = 0;
        u8                      state;
        struct ehci_qh_hw       *hw = qh->hw;
 
-       if (unlikely (list_empty (&qh->qtd_list)))
-               return count;
-
        /* completions (or tasks on other cpus) must never clobber HALT
         * till we've gone through and cleaned everything up, even when
         * they add urbs to this qh's queue or mark them for unlinking.
@@ -345,7 +341,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                if (last) {
                        if (likely (last->urb != urb)) {
                                ehci_urb_done(ehci, last->urb, last_status);
-                               count++;
                                last_status = -EINPROGRESS;
                        }
                        ehci_qtd_free (ehci, last);
@@ -519,7 +514,6 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* last urb's completion might still need calling */
        if (likely (last != NULL)) {
                ehci_urb_done(ehci, last->urb, last_status);
-               count++;
                ehci_qtd_free (ehci, last);
        }
 
@@ -566,7 +560,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                /* otherwise, unlink already started */
        }
 
-       return count;
+       return qh->needs_rescan;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1254,7 +1248,8 @@ static void end_unlink_async(struct ehci_hcd *ehci)
                qh->qh_state = QH_STATE_IDLE;
                qh->qh_next.qh = NULL;
 
-               qh_completions(ehci, qh);
+               if (!list_empty(&qh->qtd_list))
+                       qh_completions(ehci, qh);
                if (!list_empty(&qh->qtd_list) &&
                                ehci->rh_state == EHCI_RH_RUNNING)
                        qh_link_async(ehci, qh);
@@ -1348,7 +1343,7 @@ static void scan_async (struct ehci_hcd *ehci)
        while (ehci->qh_scan_next) {
                qh = ehci->qh_scan_next;
                ehci->qh_scan_next = qh->qh_next.qh;
- rescan:
+
                /* clean any finished work for this qh */
                if (!list_empty(&qh->qtd_list)) {
                        int temp;
@@ -1361,14 +1356,13 @@ static void scan_async (struct ehci_hcd *ehci)
                         * in single_unlink_async().
                         */
                        temp = qh_completions(ehci, qh);
-                       if (qh->needs_rescan) {
+                       if (unlikely(temp)) {
                                start_unlink_async(ehci, qh);
                        } else if (list_empty(&qh->qtd_list)
                                        && qh->qh_state == QH_STATE_LINKED) {
                                qh->unlink_cycle = ehci->async_unlink_cycle;
                                check_unlinks_later = true;
-                       } else if (temp != 0)
-                               goto rescan;
+                       }
                }
        }
 
index 66259dc7822e90145f7e286ca8ff5213a131829f..5c82bbab9a48976cf1ba27dfadb0f774f44e2a1f 100644 (file)
@@ -649,7 +649,8 @@ static void end_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
        qh->qh_state = QH_STATE_IDLE;
        hw->hw_next = EHCI_LIST_END(ehci);
 
-       qh_completions(ehci, qh);
+       if (!list_empty(&qh->qtd_list))
+               qh_completions(ehci, qh);
 
        /* reschedule QH iff another request is queued */
        if (!list_empty(&qh->qtd_list) && ehci->rh_state == EHCI_RH_RUNNING) {
@@ -914,7 +915,7 @@ static void scan_intr(struct ehci_hcd *ehci)
 
        list_for_each_entry_safe(qh, ehci->qh_scan_next, &ehci->intr_qh_list,
                        intr_node) {
- rescan:
+
                /* clean any finished work for this qh */
                if (!list_empty(&qh->qtd_list)) {
                        int temp;
@@ -927,12 +928,9 @@ static void scan_intr(struct ehci_hcd *ehci)
                         * in qh_unlink_periodic().
                         */
                        temp = qh_completions(ehci, qh);
-                       if (unlikely(qh->needs_rescan ||
-                                       (list_empty(&qh->qtd_list) &&
-                                               qh->qh_state == QH_STATE_LINKED)))
+                       if (unlikely(temp || (list_empty(&qh->qtd_list) &&
+                                       qh->qh_state == QH_STATE_LINKED)))
                                start_unlink_intr(ehci, qh);
-                       else if (temp != 0)
-                               goto rescan;
                }
        }
 }