USB: EHCI: don't refcount QHs
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>
This commit is contained in:
parent
15be105b4a
commit
c83e1a9ff6
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue