]> Pileus Git - ~andy/linux/blobdiff - drivers/usb/host/ehci-sched.c
Merge tag 'please-pull-pstore' of git://git.kernel.org/pub/scm/linux/kernel/git/aegl...
[~andy/linux] / drivers / usb / host / ehci-sched.c
index 010f686d8881fc9796fd3bbee1c1f5c3aa71e878..acff5b8f6e89dd89edf37d30377c2b1b86307c68 100644 (file)
@@ -539,6 +539,7 @@ static void qh_link_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
        }
        qh->qh_state = QH_STATE_LINKED;
        qh->xacterrs = 0;
+       qh->exception = 0;
 
        /* update per-qh bandwidth for usbfs */
        ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
@@ -602,15 +603,9 @@ static void qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       /* 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;
+       /* If the QH isn't linked then there's nothing we can do. */
+       if (qh->qh_state != QH_STATE_LINKED)
                return;
-       }
 
        qh_unlink_periodic (ehci, qh);
 
@@ -625,17 +620,13 @@ static void start_unlink_intr(struct ehci_hcd *ehci, struct ehci_qh *qh)
        qh->unlink_cycle = ehci->intr_unlink_cycle;
 
        /* New entries go at the end of the intr_unlink list */
-       if (ehci->intr_unlink)
-               ehci->intr_unlink_last->unlink_next = qh;
-       else
-               ehci->intr_unlink = qh;
-       ehci->intr_unlink_last = qh;
+       list_add_tail(&qh->unlink_node, &ehci->intr_unlink);
 
        if (ehci->intr_unlinking)
                ;       /* Avoid recursive calls */
        else if (ehci->rh_state < EHCI_RH_RUNNING)
                ehci_handle_intr_unlinks(ehci);
-       else if (ehci->intr_unlink == qh) {
+       else if (ehci->intr_unlink.next == &qh->unlink_node) {
                ehci_enable_event(ehci, EHCI_HRTIMER_UNLINK_INTR, true);
                ++ehci->intr_unlink_cycle;
        }
@@ -649,7 +640,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) {
@@ -792,7 +784,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
        unsigned        frame;          /* 0..(qh->period - 1), or NO_FRAME */
        struct ehci_qh_hw       *hw = qh->hw;
 
-       qh_refresh(ehci, qh);
        hw->hw_next = EHCI_LIST_END(ehci);
        frame = qh->start;
 
@@ -844,8 +835,6 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
        } else
                ehci_dbg (ehci, "reused qh %p schedule\n", qh);
 
-       /* stuff into the periodic schedule */
-       qh_link_periodic(ehci, qh);
 done:
        return status;
 }
@@ -891,6 +880,12 @@ static int intr_submit (
        qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
        BUG_ON (qh == NULL);
 
+       /* stuff into the periodic schedule */
+       if (qh->qh_state == QH_STATE_IDLE) {
+               qh_refresh(ehci, qh);
+               qh_link_periodic(ehci, qh);
+       }
+
        /* ... update usbfs periodic stats */
        ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
@@ -911,7 +906,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;
@@ -924,12 +919,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;
                }
        }
 }