Commit c83e1a9f authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

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: default avatarAlan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 15be105b
...@@ -1179,7 +1179,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep) ...@@ -1179,7 +1179,7 @@ ehci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
if (qh->clearing_tt) if (qh->clearing_tt)
goto idle_timeout; goto idle_timeout;
if (list_empty (&qh->qtd_list)) { if (list_empty (&qh->qtd_list)) {
qh_put (qh); qh_destroy(ehci, qh);
break; break;
} }
/* else FALL THROUGH */ /* else FALL THROUGH */
......
...@@ -64,10 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) ...@@ -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 */ /* clean qtds first, and know this is not linked */
if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
ehci_dbg (ehci, "unused qh not empty!\n"); 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) ...@@ -92,8 +90,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
if (!qh->hw) if (!qh->hw)
goto fail; goto fail;
memset(qh->hw, 0, sizeof *qh->hw); memset(qh->hw, 0, sizeof *qh->hw);
qh->refcount = 1;
qh->ehci = ehci;
qh->qh_dma = dma; qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list); // INIT_LIST_HEAD (&qh->qh_list);
INIT_LIST_HEAD (&qh->qtd_list); INIT_LIST_HEAD (&qh->qtd_list);
...@@ -113,20 +109,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) ...@@ -113,20 +109,6 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
return NULL; 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 /* The queue heads and transfer descriptors are managed from pools tied
...@@ -138,11 +120,11 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci) ...@@ -138,11 +120,11 @@ static void ehci_mem_cleanup (struct ehci_hcd *ehci)
{ {
free_cached_lists(ehci); free_cached_lists(ehci);
if (ehci->async) if (ehci->async)
qh_put (ehci->async); qh_destroy(ehci, ehci->async);
ehci->async = NULL; ehci->async = NULL;
if (ehci->dummy) if (ehci->dummy)
qh_put(ehci->dummy); qh_destroy(ehci, ehci->dummy);
ehci->dummy = NULL; ehci->dummy = NULL;
/* DMA consistent memory and pools */ /* DMA consistent memory and pools */
......
...@@ -265,7 +265,6 @@ __acquires(ehci->lock) ...@@ -265,7 +265,6 @@ __acquires(ehci->lock)
/* ... update hc-wide periodic stats (for usbfs) */ /* ... update hc-wide periodic stats (for usbfs) */
ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
} }
qh_put (qh);
} }
if (unlikely(urb->unlinked)) { if (unlikely(urb->unlinked)) {
...@@ -946,7 +945,7 @@ qh_make ( ...@@ -946,7 +945,7 @@ qh_make (
ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev, ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
urb->dev->speed); urb->dev->speed);
done: done:
qh_put (qh); qh_destroy(ehci, qh);
return NULL; return NULL;
} }
...@@ -1003,7 +1002,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -1003,7 +1002,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
head->qh_next.qh = qh; head->qh_next.qh = qh;
head->hw->hw_next = dma; head->hw->hw_next = dma;
qh_get(qh);
qh->xacterrs = 0; qh->xacterrs = 0;
qh->qh_state = QH_STATE_LINKED; qh->qh_state = QH_STATE_LINKED;
/* qtd completions reported later by interrupt */ /* qtd completions reported later by interrupt */
...@@ -1090,7 +1088,7 @@ static struct ehci_qh *qh_append_tds ( ...@@ -1090,7 +1088,7 @@ static struct ehci_qh *qh_append_tds (
wmb (); wmb ();
dummy->hw_token = token; dummy->hw_token = token;
urb->hcpriv = qh_get (qh); urb->hcpriv = qh;
} }
} }
return qh; return qh;
...@@ -1167,7 +1165,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) ...@@ -1167,7 +1165,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
// qh->hw_next = cpu_to_hc32(qh->qh_dma); // qh->hw_next = cpu_to_hc32(qh->qh_dma);
qh->qh_state = QH_STATE_IDLE; qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL; qh->qh_next.qh = NULL;
qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim; next = qh->reclaim;
...@@ -1186,7 +1183,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) ...@@ -1186,7 +1183,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
&& ehci->async->qh_next.qh == NULL) && ehci->async->qh_next.qh == NULL)
timer_action (ehci, TIMER_ASYNC_OFF); timer_action (ehci, TIMER_ASYNC_OFF);
} }
qh_put(qh); /* refcount from async list */
if (next) { if (next) {
ehci->reclaim = NULL; ehci->reclaim = NULL;
...@@ -1230,7 +1226,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -1230,7 +1226,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
qh->qh_state = QH_STATE_UNLINK; qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_get (qh); ehci->reclaim = qh;
prev = ehci->async; prev = ehci->async;
while (prev->qh_next.qh != qh) while (prev->qh_next.qh != qh)
...@@ -1283,12 +1279,10 @@ static void scan_async (struct ehci_hcd *ehci) ...@@ -1283,12 +1279,10 @@ static void scan_async (struct ehci_hcd *ehci)
* gets unlinked then ehci->qh_scan_next is adjusted * gets unlinked then ehci->qh_scan_next is adjusted
* in start_unlink_async(). * in start_unlink_async().
*/ */
qh = qh_get(qh);
temp = qh_completions(ehci, qh); temp = qh_completions(ehci, qh);
if (qh->needs_rescan) if (qh->needs_rescan)
unlink_async(ehci, qh); unlink_async(ehci, qh);
qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES; qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
qh_put(qh);
if (temp != 0) if (temp != 0)
goto rescan; goto rescan;
} }
......
...@@ -606,7 +606,6 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh) ...@@ -606,7 +606,6 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
} }
qh->qh_state = QH_STATE_LINKED; qh->qh_state = QH_STATE_LINKED;
qh->xacterrs = 0; qh->xacterrs = 0;
qh_get (qh);
/* update per-qh bandwidth for usbfs */ /* update per-qh bandwidth for usbfs */
ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period 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) ...@@ -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_next still "live" to HC */
qh->qh_state = QH_STATE_UNLINK; qh->qh_state = QH_STATE_UNLINK;
qh->qh_next.ptr = NULL; qh->qh_next.ptr = NULL;
qh_put (qh);
/* maybe turn off periodic schedule */ /* maybe turn off periodic schedule */
return disable_periodic(ehci); return disable_periodic(ehci);
...@@ -2340,7 +2338,7 @@ scan_periodic (struct ehci_hcd *ehci) ...@@ -2340,7 +2338,7 @@ scan_periodic (struct ehci_hcd *ehci)
switch (hc32_to_cpu(ehci, type)) { switch (hc32_to_cpu(ehci, type)) {
case Q_TYPE_QH: case Q_TYPE_QH:
/* handle any completions */ /* handle any completions */
temp.qh = qh_get (q.qh); temp.qh = q.qh;
type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
q = q.qh->qh_next; q = q.qh->qh_next;
if (temp.qh->stamp != ehci->periodic_stamp) { if (temp.qh->stamp != ehci->periodic_stamp) {
...@@ -2351,7 +2349,6 @@ scan_periodic (struct ehci_hcd *ehci) ...@@ -2351,7 +2349,6 @@ scan_periodic (struct ehci_hcd *ehci)
temp.qh->needs_rescan)) temp.qh->needs_rescan))
intr_deschedule(ehci, temp.qh); intr_deschedule(ehci, temp.qh);
} }
qh_put (temp.qh);
break; break;
case Q_TYPE_FSTN: case Q_TYPE_FSTN:
/* for "save place" FSTNs, look at QH entries /* for "save place" FSTNs, look at QH entries
......
...@@ -350,16 +350,7 @@ struct ehci_qh { ...@@ -350,16 +350,7 @@ struct ehci_qh {
struct ehci_qtd *dummy; struct ehci_qtd *dummy;
struct ehci_qh *reclaim; /* next to reclaim */ struct ehci_qh *reclaim; /* next to reclaim */
struct ehci_hcd *ehci;
unsigned long unlink_time; 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; unsigned stamp;
u8 needs_rescan; /* Dequeue during giveback */ u8 needs_rescan; /* Dequeue during giveback */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment