diff options
author | David Brownell <david-b@pacbell.net> | 2007-05-17 15:21:19 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-12 19:29:47 -0400 |
commit | 9c033e810eef0aff6d4d3bf028aa1e583c074f93 (patch) | |
tree | b7dfa412f7882fa90fd6bb8c5e8cbc2185bd12cf | |
parent | 04d06ad0f1fdb499af84ae3d7969e2136a462f38 (diff) |
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: Steven J. Hill <sjhill1@rockwellcollins.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/host/ehci-mem.c | 11 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 9 |
2 files changed, 14 insertions, 6 deletions
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c index bdb29e618058..8816d09903d0 100644 --- a/drivers/usb/host/ehci-mem.c +++ b/drivers/usb/host/ehci-mem.c | |||
@@ -64,9 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | 66 | ||
67 | static void qh_destroy (struct kref *kref) | 67 | static void qh_destroy(struct ehci_qh *qh) |
68 | { | 68 | { |
69 | struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref); | ||
70 | struct ehci_hcd *ehci = qh->ehci; | 69 | struct ehci_hcd *ehci = qh->ehci; |
71 | 70 | ||
72 | /* clean qtds first, and know this is not linked */ | 71 | /* 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 | return qh; | 89 | return qh; |
91 | 90 | ||
92 | memset (qh, 0, sizeof *qh); | 91 | memset (qh, 0, sizeof *qh); |
93 | kref_init(&qh->kref); | 92 | qh->refcount = 1; |
94 | qh->ehci = ehci; | 93 | qh->ehci = ehci; |
95 | qh->qh_dma = dma; | 94 | qh->qh_dma = dma; |
96 | // INIT_LIST_HEAD (&qh->qh_list); | 95 | // 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 | /* to share a qh (cpu threads, or hc) */ | 111 | /* to share a qh (cpu threads, or hc) */ |
113 | static inline struct ehci_qh *qh_get (struct ehci_qh *qh) | 112 | static inline struct ehci_qh *qh_get (struct ehci_qh *qh) |
114 | { | 113 | { |
115 | kref_get(&qh->kref); | 114 | WARN_ON(!qh->refcount); |
115 | qh->refcount++; | ||
116 | return qh; | 116 | return qh; |
117 | } | 117 | } |
118 | 118 | ||
119 | static inline void qh_put (struct ehci_qh *qh) | 119 | static inline void qh_put (struct ehci_qh *qh) |
120 | { | 120 | { |
121 | kref_put(&qh->kref, qh_destroy); | 121 | if (!--qh->refcount) |
122 | qh_destroy(qh); | ||
122 | } | 123 | } |
123 | 124 | ||
124 | /*-------------------------------------------------------------------------*/ | 125 | /*-------------------------------------------------------------------------*/ |
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 79ad2af5ef6a..6ef9d775775b 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h | |||
@@ -457,7 +457,14 @@ struct ehci_qh { | |||
457 | struct ehci_qh *reclaim; /* next to reclaim */ | 457 | struct ehci_qh *reclaim; /* next to reclaim */ |
458 | 458 | ||
459 | struct ehci_hcd *ehci; | 459 | struct ehci_hcd *ehci; |
460 | struct kref kref; | 460 | |
461 | /* | ||
462 | * Do NOT use atomic operations for QH refcounting. On some CPUs | ||
463 | * (PPC7448 for example), atomic operations cannot be performed on | ||
464 | * memory that is cache-inhibited (i.e. being used for DMA). | ||
465 | * Spinlocks are used to protect all QH fields. | ||
466 | */ | ||
467 | u32 refcount; | ||
461 | unsigned stamp; | 468 | unsigned stamp; |
462 | 469 | ||
463 | u8 qh_state; | 470 | u8 qh_state; |