]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/usb/host/ehci-q.c
Merge branch 'stable' of git://git.kernel.org/pub/scm/linux/kernel/git/cmetcalf/linux...
[karo-tx-linux.git] / drivers / usb / host / ehci-q.c
index 7bf2b4eeb9cec93415171b67884788d87d8e6e2c..23d13690428591b3c71d6c10bc9b29a4ffd0c973 100644 (file)
@@ -135,7 +135,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
                 * qtd is updated in qh_completions(). Update the QH
                 * overlay here.
                 */
-               if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw->hw_current) {
+               if (qh->hw->hw_token & ACTIVE_BIT(ehci)) {
                        qh->hw->hw_qtd_next = qtd->hw_next;
                        qtd = NULL;
                }
@@ -449,11 +449,19 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
                        else if (last_status == -EINPROGRESS && !urb->unlinked)
                                continue;
 
-                       /* qh unlinked; token in overlay may be most current */
-                       if (state == QH_STATE_IDLE
-                                       && cpu_to_hc32(ehci, qtd->qtd_dma)
-                                               == hw->hw_current) {
+                       /*
+                        * If this was the active qtd when the qh was unlinked
+                        * and the overlay's token is active, then the overlay
+                        * hasn't been written back to the qtd yet so use its
+                        * token instead of the qtd's.  After the qtd is
+                        * processed and removed, the overlay won't be valid
+                        * any more.
+                        */
+                       if (state == QH_STATE_IDLE &&
+                                       qh->qtd_list.next == &qtd->qtd_list &&
+                                       (hw->hw_token & ACTIVE_BIT(ehci))) {
                                token = hc32_to_cpu(ehci, hw->hw_token);
+                               hw->hw_token &= ~ACTIVE_BIT(ehci);
 
                                /* An unlink may leave an incomplete
                                 * async transaction in the TT buffer.
@@ -1308,6 +1316,19 @@ static void unlink_empty_async(struct ehci_hcd *ehci)
        }
 }
 
+/* The root hub is suspended; unlink all the async QHs */
+static void unlink_empty_async_suspended(struct ehci_hcd *ehci)
+{
+       struct ehci_qh          *qh;
+
+       while (ehci->async->qh_next.qh) {
+               qh = ehci->async->qh_next.qh;
+               WARN_ON(!list_empty(&qh->qtd_list));
+               single_unlink_async(ehci, qh);
+       }
+       start_iaa_cycle(ehci, false);
+}
+
 /* makes sure the async qh will become idle */
 /* caller must own ehci->lock */