aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:21:25 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:50:13 -0400
commitc83e1a9ff68a6535b81c40dc8fda99348ab480fb (patch)
treefea3bfe22caed0144933c8b065f2bf16937fd8fb /drivers/usb
parent15be105b4a18c461b95fa683907f6da6deae1b75 (diff)
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>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-mem.c24
-rw-r--r--drivers/usb/host/ehci-q.c12
-rw-r--r--drivers/usb/host/ehci-sched.c5
-rw-r--r--drivers/usb/host/ehci.h9
5 files changed, 8 insertions, 44 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ab7306de8d16..1f8f792eec86 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1179,7 +1179,7 @@ idle_timeout:
1179 if (qh->clearing_tt) 1179 if (qh->clearing_tt)
1180 goto idle_timeout; 1180 goto idle_timeout;
1181 if (list_empty (&qh->qtd_list)) { 1181 if (list_empty (&qh->qtd_list)) {
1182 qh_put (qh); 1182 qh_destroy(ehci, qh);
1183 break; 1183 break;
1184 } 1184 }
1185 /* else FALL THROUGH */ 1185 /* else FALL THROUGH */
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 12f70c302b0b..93132d8ad360 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -64,10 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
64} 64}
65 65
66 66
67static void qh_destroy(struct ehci_qh *qh) 67static void qh_destroy(struct ehci_hcd *ehci, struct ehci_qh *qh)
68{ 68{
69 struct ehci_hcd *ehci = qh->ehci;
70
71 /* clean qtds first, and know this is not linked */ 69 /* clean qtds first, and know this is not linked */
72 if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) { 70 if (!list_empty (&qh->qtd_list) || qh->qh_next.ptr) {
73 ehci_dbg (ehci, "unused qh not empty!\n"); 71 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 if (!qh->hw) 90 if (!qh->hw)
93 goto fail; 91 goto fail;
94 memset(qh->hw, 0, sizeof *qh->hw); 92 memset(qh->hw, 0, sizeof *qh->hw);
95 qh->refcount = 1;
96 qh->ehci = ehci;
97 qh->qh_dma = dma; 93 qh->qh_dma = dma;
98 // INIT_LIST_HEAD (&qh->qh_list); 94 // INIT_LIST_HEAD (&qh->qh_list);
99 INIT_LIST_HEAD (&qh->qtd_list); 95 INIT_LIST_HEAD (&qh->qtd_list);
@@ -113,20 +109,6 @@ fail:
113 return NULL; 109 return NULL;
114} 110}
115 111
116/* to share a qh (cpu threads, or hc) */
117static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
118{
119 WARN_ON(!qh->refcount);
120 qh->refcount++;
121 return qh;
122}
123
124static inline void qh_put (struct ehci_qh *qh)
125{
126 if (!--qh->refcount)
127 qh_destroy(qh);
128}
129
130/*-------------------------------------------------------------------------*/ 112/*-------------------------------------------------------------------------*/
131 113
132/* The queue heads and transfer descriptors are managed from pools tied 114/* 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{ 120{
139 free_cached_lists(ehci); 121 free_cached_lists(ehci);
140 if (ehci->async) 122 if (ehci->async)
141 qh_put (ehci->async); 123 qh_destroy(ehci, ehci->async);
142 ehci->async = NULL; 124 ehci->async = NULL;
143 125
144 if (ehci->dummy) 126 if (ehci->dummy)
145 qh_put(ehci->dummy); 127 qh_destroy(ehci, ehci->dummy);
146 ehci->dummy = NULL; 128 ehci->dummy = NULL;
147 129
148 /* DMA consistent memory and pools */ 130 /* DMA consistent memory and pools */
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 4378bf72bbac..7d117bbffac1 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -265,7 +265,6 @@ __acquires(ehci->lock)
265 /* ... update hc-wide periodic stats (for usbfs) */ 265 /* ... update hc-wide periodic stats (for usbfs) */
266 ehci_to_hcd(ehci)->self.bandwidth_int_reqs--; 266 ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
267 } 267 }
268 qh_put (qh);
269 } 268 }
270 269
271 if (unlikely(urb->unlinked)) { 270 if (unlikely(urb->unlinked)) {
@@ -946,7 +945,7 @@ qh_make (
946 ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev, 945 ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev,
947 urb->dev->speed); 946 urb->dev->speed);
948done: 947done:
949 qh_put (qh); 948 qh_destroy(ehci, qh);
950 return NULL; 949 return NULL;
951 } 950 }
952 951
@@ -1003,7 +1002,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
1003 head->qh_next.qh = qh; 1002 head->qh_next.qh = qh;
1004 head->hw->hw_next = dma; 1003 head->hw->hw_next = dma;
1005 1004
1006 qh_get(qh);
1007 qh->xacterrs = 0; 1005 qh->xacterrs = 0;
1008 qh->qh_state = QH_STATE_LINKED; 1006 qh->qh_state = QH_STATE_LINKED;
1009 /* qtd completions reported later by interrupt */ 1007 /* qtd completions reported later by interrupt */
@@ -1090,7 +1088,7 @@ static struct ehci_qh *qh_append_tds (
1090 wmb (); 1088 wmb ();
1091 dummy->hw_token = token; 1089 dummy->hw_token = token;
1092 1090
1093 urb->hcpriv = qh_get (qh); 1091 urb->hcpriv = qh;
1094 } 1092 }
1095 } 1093 }
1096 return qh; 1094 return qh;
@@ -1167,7 +1165,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
1167 // qh->hw_next = cpu_to_hc32(qh->qh_dma); 1165 // qh->hw_next = cpu_to_hc32(qh->qh_dma);
1168 qh->qh_state = QH_STATE_IDLE; 1166 qh->qh_state = QH_STATE_IDLE;
1169 qh->qh_next.qh = NULL; 1167 qh->qh_next.qh = NULL;
1170 qh_put (qh); // refcount from reclaim
1171 1168
1172 /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */ 1169 /* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
1173 next = qh->reclaim; 1170 next = qh->reclaim;
@@ -1186,7 +1183,6 @@ static void end_unlink_async (struct ehci_hcd *ehci)
1186 && ehci->async->qh_next.qh == NULL) 1183 && ehci->async->qh_next.qh == NULL)
1187 timer_action (ehci, TIMER_ASYNC_OFF); 1184 timer_action (ehci, TIMER_ASYNC_OFF);
1188 } 1185 }
1189 qh_put(qh); /* refcount from async list */
1190 1186
1191 if (next) { 1187 if (next) {
1192 ehci->reclaim = NULL; 1188 ehci->reclaim = NULL;
@@ -1230,7 +1226,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
1230 } 1226 }
1231 1227
1232 qh->qh_state = QH_STATE_UNLINK; 1228 qh->qh_state = QH_STATE_UNLINK;
1233 ehci->reclaim = qh = qh_get (qh); 1229 ehci->reclaim = qh;
1234 1230
1235 prev = ehci->async; 1231 prev = ehci->async;
1236 while (prev->qh_next.qh != qh) 1232 while (prev->qh_next.qh != qh)
@@ -1283,12 +1279,10 @@ static void scan_async (struct ehci_hcd *ehci)
1283 * gets unlinked then ehci->qh_scan_next is adjusted 1279 * gets unlinked then ehci->qh_scan_next is adjusted
1284 * in start_unlink_async(). 1280 * in start_unlink_async().
1285 */ 1281 */
1286 qh = qh_get(qh);
1287 temp = qh_completions(ehci, qh); 1282 temp = qh_completions(ehci, qh);
1288 if (qh->needs_rescan) 1283 if (qh->needs_rescan)
1289 unlink_async(ehci, qh); 1284 unlink_async(ehci, qh);
1290 qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES; 1285 qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
1291 qh_put(qh);
1292 if (temp != 0) 1286 if (temp != 0)
1293 goto rescan; 1287 goto rescan;
1294 } 1288 }
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 33182c6d1ff9..027df3de2dc9 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -606,7 +606,6 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
606 } 606 }
607 qh->qh_state = QH_STATE_LINKED; 607 qh->qh_state = QH_STATE_LINKED;
608 qh->xacterrs = 0; 608 qh->xacterrs = 0;
609 qh_get (qh);
610 609
611 /* update per-qh bandwidth for usbfs */ 610 /* update per-qh bandwidth for usbfs */
612 ehci_to_hcd(ehci)->self.bandwidth_allocated += qh->period 611 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 /* qh->qh_next still "live" to HC */ 649 /* qh->qh_next still "live" to HC */
651 qh->qh_state = QH_STATE_UNLINK; 650 qh->qh_state = QH_STATE_UNLINK;
652 qh->qh_next.ptr = NULL; 651 qh->qh_next.ptr = NULL;
653 qh_put (qh);
654 652
655 /* maybe turn off periodic schedule */ 653 /* maybe turn off periodic schedule */
656 return disable_periodic(ehci); 654 return disable_periodic(ehci);
@@ -2340,7 +2338,7 @@ restart:
2340 switch (hc32_to_cpu(ehci, type)) { 2338 switch (hc32_to_cpu(ehci, type)) {
2341 case Q_TYPE_QH: 2339 case Q_TYPE_QH:
2342 /* handle any completions */ 2340 /* handle any completions */
2343 temp.qh = qh_get (q.qh); 2341 temp.qh = q.qh;
2344 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next); 2342 type = Q_NEXT_TYPE(ehci, q.qh->hw->hw_next);
2345 q = q.qh->qh_next; 2343 q = q.qh->qh_next;
2346 if (temp.qh->stamp != ehci->periodic_stamp) { 2344 if (temp.qh->stamp != ehci->periodic_stamp) {
@@ -2351,7 +2349,6 @@ restart:
2351 temp.qh->needs_rescan)) 2349 temp.qh->needs_rescan))
2352 intr_deschedule(ehci, temp.qh); 2350 intr_deschedule(ehci, temp.qh);
2353 } 2351 }
2354 qh_put (temp.qh);
2355 break; 2352 break;
2356 case Q_TYPE_FSTN: 2353 case Q_TYPE_FSTN:
2357 /* for "save place" FSTNs, look at QH entries 2354 /* for "save place" FSTNs, look at QH entries
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 85c3572155d1..f7a59f5d70c6 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -350,16 +350,7 @@ struct ehci_qh {
350 struct ehci_qtd *dummy; 350 struct ehci_qtd *dummy;
351 struct ehci_qh *reclaim; /* next to reclaim */ 351 struct ehci_qh *reclaim; /* next to reclaim */
352 352
353 struct ehci_hcd *ehci;
354 unsigned long unlink_time; 353 unsigned long unlink_time;
355
356 /*
357 * Do NOT use atomic operations for QH refcounting. On some CPUs
358 * (PPC7448 for example), atomic operations cannot be performed on
359 * memory that is cache-inhibited (i.e. being used for DMA).
360 * Spinlocks are used to protect all QH fields.
361 */
362 u32 refcount;
363 unsigned stamp; 354 unsigned stamp;
364 355
365 u8 needs_rescan; /* Dequeue during giveback */ 356 u8 needs_rescan; /* Dequeue during giveback */