/* When no queues need Full-Speed Bandwidth Reclamation,
  * delay this long before turning FSBR off */
-#define FSBR_OFF_DELAY         msecs_to_jiffies(400)
+#define FSBR_OFF_DELAY         msecs_to_jiffies(10)
 
 /* If a queue hasn't advanced after this much time, assume it is stuck */
 #define QH_WAIT_TIMEOUT                msecs_to_jiffies(200)
        __le32 *frame;
        void **frame_cpu;               /* CPU's frame list */
 
-       unsigned long fsbr_jiffies;     /* Time when FSBR was last wanted */
-
        enum uhci_rh_state rh_state;
        unsigned long auto_stop_time;           /* When to AUTO_STOP */
 
                                                   need to be polled */
        unsigned int is_initialized:1;          /* Data structure is usable */
        unsigned int fsbr_is_on:1;              /* FSBR is turned on */
+       unsigned int fsbr_is_wanted:1;          /* Does any URB want FSBR? */
+       unsigned int fsbr_expiring:1;           /* FSBR is timing out */
+
+       struct timer_list fsbr_timer;           /* For turning off FBSR */
 
        /* Support for port suspend/resume/reset */
        unsigned long port_c_suspend;           /* Bit-arrays of ports */
 
                urbp->fsbr = 1;
 }
 
-static void uhci_qh_wants_fsbr(struct uhci_hcd *uhci, struct uhci_qh *qh)
+static void uhci_urbp_wants_fsbr(struct uhci_hcd *uhci, struct urb_priv *urbp)
 {
-       struct urb_priv *urbp =
-                       list_entry(qh->queue.next, struct urb_priv, node);
-
        if (urbp->fsbr) {
-               uhci->fsbr_jiffies = jiffies;
+               uhci->fsbr_is_wanted = 1;
                if (!uhci->fsbr_is_on)
                        uhci_fsbr_on(uhci);
+               else if (uhci->fsbr_expiring) {
+                       uhci->fsbr_expiring = 0;
+                       del_timer(&uhci->fsbr_timer);
+               }
+       }
+}
+
+static void uhci_fsbr_timeout(unsigned long _uhci)
+{
+       struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
+       unsigned long flags;
+
+       spin_lock_irqsave(&uhci->lock, flags);
+       if (uhci->fsbr_expiring) {
+               uhci->fsbr_expiring = 0;
+               uhci_fsbr_off(uhci);
        }
+       spin_unlock_irqrestore(&uhci->lock, flags);
 }
 
 
        if (qh->type == USB_ENDPOINT_XFER_ISOC) {
                ret = (uhci->frame_number + uhci->is_stopped !=
                                qh->unlink_frame);
-               return ret;
+               goto done;
        }
 
        /* If the URB isn't first on its queue, adjust the link pointer
                td = list_entry(urbp->td_list.prev, struct uhci_td,
                                list);
                ptd->link = td->link;
-               return ret;
+               goto done;
        }
 
        /* If the QH element pointer is UHCI_PTR_TERM then then currently
         * executing URB has already been unlinked, so this one isn't it. */
        if (qh_element(qh) == UHCI_PTR_TERM)
-               return ret;
+               goto done;
        qh->element = UHCI_PTR_TERM;
 
        /* Control pipes have to worry about toggles */
        if (qh->type == USB_ENDPOINT_XFER_CONTROL)
-               return ret;
+               goto done;
 
        /* Save the next toggle value */
        WARN_ON(list_empty(&urbp->td_list));
        td = list_entry(urbp->td_list.next, struct uhci_td, list);
        qh->needs_fixup = 1;
        qh->initial_toggle = uhci_toggle(td_token(td));
+
+done:
        return ret;
 }
 
         * queue isn't stopped. */
        if (qh->queue.next == &urbp->node && !qh->is_stopped) {
                uhci_activate_qh(uhci, qh);
-               uhci_qh_wants_fsbr(uhci, qh);
+               uhci_urbp_wants_fsbr(uhci, urbp);
        }
        goto done;
 
        unsigned status;
 
        if (qh->type == USB_ENDPOINT_XFER_ISOC)
-               return ret;
+               goto done;
 
        /* Treat an UNLINKING queue as though it hasn't advanced.
         * This is okay because reactivation will treat it as though
                        /* We're okay, the queue has advanced */
                        qh->wait_expired = 0;
                        qh->advance_jiffies = jiffies;
-                       return ret;
+                       goto done;
                }
                ret = 0;
        }
 
        /* The queue hasn't advanced; check for timeout */
-       if (!qh->wait_expired && time_after(jiffies,
-                       qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
+       if (qh->wait_expired)
+               goto done;
+
+       if (time_after(jiffies, qh->advance_jiffies + QH_WAIT_TIMEOUT)) {
 
                /* Detect the Intel bug and work around it */
                if (qh->post_td && qh_element(qh) ==
                                cpu_to_le32(qh->post_td->dma_handle)) {
                        qh->element = qh->post_td->link;
                        qh->advance_jiffies = jiffies;
-                       return 1;
+                       ret = 1;
+                       goto done;
                }
 
                qh->wait_expired = 1;
                 * starts moving again. */
                if (urbp && urbp->fsbr && !(status & TD_CTRL_IOC))
                        uhci_unlink_qh(uhci, qh);
+
+       } else {
+               /* Unmoving but not-yet-expired queues keep FSBR alive */
+               if (urbp)
+                       uhci_urbp_wants_fsbr(uhci, urbp);
        }
+
+done:
        return ret;
 }
 
        uhci->scan_in_progress = 1;
 rescan:
        uhci->need_rescan = 0;
+       uhci->fsbr_is_wanted = 0;
 
        uhci_clear_next_interrupt(uhci);
        uhci_get_current_frame_number(uhci);
 
                        if (uhci_advance_check(uhci, qh)) {
                                uhci_scan_qh(uhci, qh, regs);
-                               if (qh->state == QH_STATE_ACTIVE)
-                                       uhci_qh_wants_fsbr(uhci, qh);
+                               if (qh->state == QH_STATE_ACTIVE) {
+                                       uhci_urbp_wants_fsbr(uhci,
+       list_entry(qh->queue.next, struct urb_priv, node));
+                               }
                        }
                }
        }
                goto rescan;
        uhci->scan_in_progress = 0;
 
-       if (uhci->fsbr_is_on && time_after(jiffies,
-                       uhci->fsbr_jiffies + FSBR_OFF_DELAY))
-               uhci_fsbr_off(uhci);
+       if (uhci->fsbr_is_on && !uhci->fsbr_is_wanted &&
+                       !uhci->fsbr_expiring) {
+               uhci->fsbr_expiring = 1;
+               mod_timer(&uhci->fsbr_timer, jiffies + FSBR_OFF_DELAY);
+       }
 
        if (list_empty(&uhci->skel_unlink_qh->node))
                uhci_clear_next_interrupt(uhci);