break;
                switch (qh->qh_state) {
                case QH_STATE_LINKED:
+               case QH_STATE_COMPLETING:
                        intr_deschedule (ehci, qh);
-                       /* FALL THROUGH */
+                       break;
                case QH_STATE_IDLE:
                        qh_completions (ehci, qh);
                        break;
                                        qh, qh->qh_state);
                        goto done;
                }
-
-               /* reschedule QH iff another request is queued */
-               if (!list_empty (&qh->qtd_list)
-                               && HC_IS_RUNNING (hcd->state)) {
-                       rc = qh_schedule(ehci, qh);
-
-                       /* An error here likely indicates handshake failure
-                        * or no space left in the schedule.  Neither fault
-                        * should happen often ...
-                        *
-                        * FIXME kill the now-dysfunctional queued urbs
-                        */
-                       if (rc != 0)
-                               ehci_err(ehci,
-                                       "can't reschedule qh %p, err %d",
-                                       qh, rc);
-               }
                break;
 
        case PIPE_ISOCHRONOUS:
                         * while the QH is active.  Unlink it now;
                         * re-linking will call qh_refresh().
                         */
-                       if (eptype == USB_ENDPOINT_XFER_BULK) {
+                       if (eptype == USB_ENDPOINT_XFER_BULK)
                                unlink_async(ehci, qh);
-                       } else {
+                       else
                                intr_deschedule(ehci, qh);
-                               (void) qh_schedule(ehci, qh);
-                       }
                }
        }
        spin_unlock_irqrestore(&ehci->lock, flags);
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
 static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh);
 
-static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
 static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
 
 /*
                         * That should be rare for interrupt transfers,
                         * except maybe high bandwidth ...
                         */
-                       if ((cpu_to_hc32(ehci, QH_SMASK)
-                                       & hw->hw_info2) != 0) {
-                               intr_deschedule (ehci, qh);
-                               (void) qh_schedule (ehci, qh);
-                       } else {
-                               /* Tell the caller to start an unlink */
-                               qh->needs_rescan = 1;
-                       }
+
+                       /* Tell the caller to start an unlink */
+                       qh->needs_rescan = 1;
                        break;
                /* otherwise, unlink already started */
                }
 
 
 static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       unsigned        wait;
-       struct ehci_qh_hw *hw = qh->hw;
+       unsigned                wait;
+       struct ehci_qh_hw       *hw = qh->hw;
+       int                     rc;
+
+       /* If the QH isn't linked then there's nothing we can do
+        * unless we were called during a giveback, in which case
+        * qh_completions() has to deal with it.
+        */
+       if (qh->qh_state != QH_STATE_LINKED) {
+               if (qh->qh_state == QH_STATE_COMPLETING)
+                       qh->needs_rescan = 1;
+               return;
+       }
 
        qh_unlink_periodic (ehci, qh);
 
        qh->qh_state = QH_STATE_IDLE;
        hw->hw_next = EHCI_LIST_END(ehci);
        wmb ();
+
+       qh_completions(ehci, qh);
+
+       /* reschedule QH iff another request is queued */
+       if (!list_empty(&qh->qtd_list) &&
+                       HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
+               rc = qh_schedule(ehci, qh);
+
+               /* An error here likely indicates handshake failure
+                * or no space left in the schedule.  Neither fault
+                * should happen often ...
+                *
+                * FIXME kill the now-dysfunctional queued urbs
+                */
+               if (rc != 0)
+                       ehci_err(ehci, "can't reschedule qh %p, err %d\n",
+                                       qh, rc);
+       }
 }
 
 /*-------------------------------------------------------------------------*/
                                type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
                                q = q.qh->qh_next;
                                modified = qh_completions (ehci, temp.qh);
-                               if (unlikely (list_empty (&temp.qh->qtd_list)))
+                               if (unlikely(list_empty(&temp.qh->qtd_list) ||
+                                               temp.qh->needs_rescan))
                                        intr_deschedule (ehci, temp.qh);
                                qh_put (temp.qh);
                                break;