/*
  * 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)
        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.
                if (last) {
                        if (likely (last->urb != urb)) {
                                ehci_urb_done(ehci, last->urb, last_status);
-                               count++;
                                last_status = -EINPROGRESS;
                        }
                        ehci_qtd_free (ehci, last);
        /* 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);
        }
 
                /* otherwise, unlink already started */
        }
 
-       return count;
+       return qh->needs_rescan;
 }
 
 /*-------------------------------------------------------------------------*/
                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);
        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;
                         * 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;
+                       }
                }
        }
 
 
        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) {
 
        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;
                         * 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;
                }
        }
 }