Commit 9c033e81 authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

USB: ehci refcounts work on ppc7448

Remove atomic operations on the reference counter for EHCI queue heads.
On various platforms (including ppc7448), atomic operations are unusable
with dma-coherent memory.
Signed-off-by: default avatarSteven J. Hill <sjhill1@rockwellcollins.com>
Signed-off-by: default avatarDavid Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 04d06ad0
...@@ -64,9 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) ...@@ -64,9 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
} }
static void qh_destroy (struct kref *kref) static void qh_destroy(struct ehci_qh *qh)
{ {
struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
struct ehci_hcd *ehci = qh->ehci; struct ehci_hcd *ehci = qh->ehci;
/* clean qtds first, and know this is not linked */ /* clean qtds first, and know this is not linked */
...@@ -90,7 +89,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) ...@@ -90,7 +89,7 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
return qh; return qh;
memset (qh, 0, sizeof *qh); memset (qh, 0, sizeof *qh);
kref_init(&qh->kref); qh->refcount = 1;
qh->ehci = ehci; qh->ehci = ehci;
qh->qh_dma = dma; qh->qh_dma = dma;
// INIT_LIST_HEAD (&qh->qh_list); // INIT_LIST_HEAD (&qh->qh_list);
...@@ -112,13 +111,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags) ...@@ -112,13 +111,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
/* to share a qh (cpu threads, or hc) */ /* to share a qh (cpu threads, or hc) */
static inline struct ehci_qh *qh_get (struct ehci_qh *qh) static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
{ {
kref_get(&qh->kref); WARN_ON(!qh->refcount);
qh->refcount++;
return qh; return qh;
} }
static inline void qh_put (struct ehci_qh *qh) static inline void qh_put (struct ehci_qh *qh)
{ {
kref_put(&qh->kref, qh_destroy); if (!--qh->refcount)
qh_destroy(qh);
} }
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
......
...@@ -457,7 +457,14 @@ struct ehci_qh { ...@@ -457,7 +457,14 @@ struct ehci_qh {
struct ehci_qh *reclaim; /* next to reclaim */ struct ehci_qh *reclaim; /* next to reclaim */
struct ehci_hcd *ehci; struct ehci_hcd *ehci;
struct kref kref;
/*
* 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 qh_state; u8 qh_state;
......
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