USB: EHCI: don't refcount QHs
authorAlan Stern <stern@rowland.harvard.edu>
Wed, 11 Jul 2012 15:21:25 +0000 (11:21 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 16 Jul 2012 23:50:13 +0000 (16:50 -0700)
This patch (as1567) removes ehci-hcd's reference counting of QH
structures.  It's not necessary to refcount these things because they
always get deallocated at exactly one spot in ehci_endpoint_disable()
(except for two special QHs, ehci->async and ehci->dummy) and are
never used again.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mem.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h

index ab7306d..1f8f792 100644 (file)
@@ -1179,7 +1179,7 @@ idle_timeout:
                if (qh->clearing_tt)
                        goto idle_timeout;
                if (list_empty (&qh->qtd_list)) {
-                       qh_put (qh);
+                       qh_destroy(ehci, qh);
                        break;
                }
                /* else FALL THROUGH */
index 12f70c3..93132d8 100644 (file)
@@ -64,10 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 }
 
 
-static void qh_destroy(struct ehci_qh *qh)
+static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       struct ehci_hcd *ehci = qh->ehci;
-
        /* clean qtds first, and know this is not linked */
        if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
                ehci_dbg (ehci, "unused qh not empty!\n");
@@ -92,8 +90,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
        if (!qh->hw)
                goto fail;
        memset(qh->hw, 0, sizeof *qh->hw);
-       qh->refcount = 1;
-       qh->ehci = ehci;
        qh->qh_dma = dma;
        // INIT_LIST_HEAD (&qh->qh_list);
        INIT_LIST_HEAD (&qh->qtd_list);
@@ -113,20 +109,6 @@ fail:
        return NULL;
 }
 
-/* to share a qh (cpu threads, or hc) */
-static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
-{
-       WARN_ON(!qh->refcount);
-       qh->refcount++;
-       return qh;
-}
-
-static inline void qh_put (struct ehci_qh *qh)
-{
-       if (!--qh->refcount)
-               qh_destroy(qh);
-}
-
 /*-------------------------------------------------------------------------*/
 
 /* The queue heads and transfer descriptors are managed from pools tied
@@ -138,11 +120,11 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
 {
        free_cached_lists(ehci);
        if (ehci->async)
-               qh_put (ehci->async);
+               qh_destroy(ehci, ehci->async);
        ehci->async = NULL;
 
        if (ehci->dummy)
-               qh_put(ehci->dummy);
+               qh_destroy(ehci, ehci->dummy);
        ehci->dummy = NULL;
 
        /* DMA consistent memory and pools */
index 4378bf7..7d117bb 100644 (file)
@@ -265,7 +265,6 @@ __acquires(ehci->lock)
                        /* ... update hc-wide periodic stats (for usbfs) */
                        ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
                }
-               qh_put (qh);
        }
 
        if (unlikely(urb->unlinked)) {
@@ -946,7 +945,7 @@ qh_make (
                ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
                        urb->dev->speed);
 done:
-               qh_put (qh);
+               qh_destroy(ehci, qh);
                return NULL;
        }
 
@@ -1003,7 +1002,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        head->qh_next.qh = qh;
        head->hw->hw_next = dma;
 
-       qh_get(qh);
        qh->xacterrs = 0;
        qh->qh_state = QH_STATE_LINKED;
        /* qtd completions reported later by interrupt */
@@ -1090,7 +1088,7 @@ static struct ehci_qh *qh_append_tds (
                        wmb ();
                        dummy->hw_token = token;
 
-                       urb->hcpriv = qh_get (qh);
+                       urb->hcpriv = qh;
                }
        }
        return qh;
@@ -1167,7 +1165,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
        // qh->hw_next = cpu_to_hc32(qh->qh_dma);
        qh->qh_state = QH_STATE_IDLE;
        qh->qh_next.qh = NULL;
-       qh_put (qh);                    // refcount from reclaim
 
        /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
        next = qh->reclaim;
@@ -1186,7 +1183,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
                                && ehci->async->qh_next.qh == NULL)
                        timer_action (ehci, TIMER_ASYNC_OFF);
        }
-       qh_put(qh);                     /* refcount from async list */
 
        if (next) {
                ehci->reclaim = NULL;
@@ -1230,7 +1226,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        }
 
        qh->qh_state = QH_STATE_UNLINK;
-       ehci->reclaim = qh = qh_get (qh);
+       ehci->reclaim = qh;
 
        prev = ehci->async;
        while (prev->qh_next.qh != qh)
@@ -1283,12 +1279,10 @@ static void scan_async (struct ehci_hcd *ehci)
                         * gets unlinked then ehci->qh_scan_next is adjusted
                         * in start_unlink_async().
                         */
-                       qh = qh_get(qh);
                        temp = qh_completions(ehci, qh);
                        if (qh->needs_rescan)
                                unlink_async(ehci, qh);
                        qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
-                       qh_put(qh);
                        if (temp != 0)
                                goto rescan;
                }
index 33182c6..027df3d 100644 (file)
@@ -606,7 +606,6 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
        }
        qh->qh_state = QH_STATE_LINKED;
        qh->xacterrs = 0;
-       qh_get (qh);
 
        /* update per-qh bandwidth for usbfs */
        ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period
@@ -650,7 +649,6 @@ static int qh_unlink_periodic(struct ehci_hcd *ehci, struct ehci_qh *qh)
        /* qh->qh_next still "live" to HC */
        qh->qh_state = QH_STATE_UNLINK;
        qh->qh_next.ptr = NULL;
-       qh_put (qh);
 
        /* maybe turn off periodic schedule */
        return disable_periodic(ehci);
@@ -2340,7 +2338,7 @@ restart:
                        switch (hc32_to_cpu(ehci, type)) {
                        case Q_TYPE_QH:
                                /* handle any completions */
-                               temp.qh = qh_get (q.qh);
+                               temp.qh = q.qh;
                                type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
                                q = q.qh->qh_next;
                                if (temp.qh->stamp != ehci->periodic_stamp) {
@@ -2351,7 +2349,6 @@ restart:
                                                        temp.qh->needs_rescan))
                                                intr_deschedule(ehci, temp.qh);
                                }
-                               qh_put (temp.qh);
                                break;
                        case Q_TYPE_FSTN:
                                /* for "save place" FSTNs, look at QH entries
index 85c3572..f7a59f5 100644 (file)
@@ -350,16 +350,7 @@ struct ehci_qh {
        struct ehci_qtd         *dummy;
        struct ehci_qh          *reclaim;       /* next to reclaim */
 
-       struct ehci_hcd         *ehci;
        unsigned long           unlink_time;
-
-       /*
-        * Do NOT use atomic operations for QH refcounting. On some CPUs
-        * (PPC7448 for example), atomic operations cannot be performed on
-        * memory that is cache-inhibited (i.e. being used for DMA).
-        * Spinlocks are used to protect all QH fields.
-        */
-       u32                     refcount;
        unsigned                stamp;
 
        u8                      needs_rescan;   /* Dequeue during giveback */