aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-07-11 11:22:35 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-07-16 19:54:25 -0400
commit55934eb3b9fa52eb53b9d7342267fc73c38206aa (patch)
tree66666fa4f08121a53152cb956a6ef36026edc057 /drivers/usb/host
parentbf6387bcd16975ba8952b094f262a359d74e1c8a (diff)
USB: EHCI: use hrtimer for (s)iTD deallocation
This patch (as1579) adds an hrtimer event to handle deallocation of iTDs and siTDs in ehci-hcd. Because of the frame-oriented approach used by the EHCI periodic schedule, the hardware can continue to access the Transfer Descriptor for isochronous (or split-isochronous) transactions for up to a millisecond after the transaction completes. The iTD (or siTD) must not be reused before then. The strategy currently used involves putting completed iTDs on a list of cached entries and every so often returning them to the endpoint's free list. The new strategy reduces overhead by putting completed iTDs back on the free list immediately, although they are not reused until it is safe to do so. When the isochronous endpoint stops (its queue becomes empty), the iTDs on its free list get moved to a global list, from which they will be deallocated after a minimum of 2 ms. This delay is what the new hrtimer event is for. Overall this may not be a tremendous improvement over the current code, but to me it seems a lot more clear and logical. In addition, it removes the need for each iTD to keep a reference to the ehci_iso_stream it belongs to, since the iTD never needs to be moved back to the stream's free list from the global list. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/ehci-hcd.c1
-rw-r--r--drivers/usb/host/ehci-hub.c1
-rw-r--r--drivers/usb/host/ehci-mem.c1
-rw-r--r--drivers/usb/host/ehci-sched.c137
-rw-r--r--drivers/usb/host/ehci-timer.c50
-rw-r--r--drivers/usb/host/ehci.h5
6 files changed, 90 insertions, 105 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 1676c66b8530..98b945840c9e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -509,6 +509,7 @@ static void ehci_stop (struct usb_hcd *hcd)
509 spin_lock_irq (&ehci->lock); 509 spin_lock_irq (&ehci->lock);
510 if (ehci->async) 510 if (ehci->async)
511 ehci_work (ehci); 511 ehci_work (ehci);
512 end_free_itds(ehci);
512 spin_unlock_irq (&ehci->lock); 513 spin_unlock_irq (&ehci->lock);
513 ehci_mem_cleanup (ehci); 514 ehci_mem_cleanup (ehci);
514 515
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 8aa740dc510d..6ad806bbe468 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -303,6 +303,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
303 if (ehci->async_unlink) 303 if (ehci->async_unlink)
304 end_unlink_async(ehci); 304 end_unlink_async(ehci);
305 ehci_handle_intr_unlinks(ehci); 305 ehci_handle_intr_unlinks(ehci);
306 end_free_itds(ehci);
306 307
307 /* allow remote wakeup */ 308 /* allow remote wakeup */
308 mask = INTR_MASK; 309 mask = INTR_MASK;
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 93132d8ad360..ef2c3a1eca4b 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -118,7 +118,6 @@ fail:
118 118
119static void ehci_mem_cleanup (struct ehci_hcd *ehci) 119static void ehci_mem_cleanup (struct ehci_hcd *ehci)
120{ 120{
121 free_cached_lists(ehci);
122 if (ehci->async) 121 if (ehci->async)
123 qh_destroy(ehci, ehci->async); 122 qh_destroy(ehci, ehci->async);
124 ehci->async = NULL; 123 ehci->async = NULL;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index eec8446f8ded..1e4f13c11b6a 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1045,31 +1045,6 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
1045 if (stream->refcount == 1) { 1045 if (stream->refcount == 1) {
1046 // BUG_ON (!list_empty(&stream->td_list)); 1046 // BUG_ON (!list_empty(&stream->td_list));
1047 1047
1048 while (!list_empty (&stream->free_list)) {
1049 struct list_head *entry;
1050
1051 entry = stream->free_list.next;
1052 list_del (entry);
1053
1054 /* knows about ITD vs SITD */
1055 if (stream->highspeed) {
1056 struct ehci_itd *itd;
1057
1058 itd = list_entry (entry, struct ehci_itd,
1059 itd_list);
1060 dma_pool_free (ehci->itd_pool, itd,
1061 itd->itd_dma);
1062 } else {
1063 struct ehci_sitd *sitd;
1064
1065 sitd = list_entry (entry, struct ehci_sitd,
1066 sitd_list);
1067 dma_pool_free (ehci->sitd_pool, sitd,
1068 sitd->sitd_dma);
1069 }
1070 }
1071
1072 stream->bEndpointAddress &= 0x0f;
1073 if (stream->ep) 1048 if (stream->ep)
1074 stream->ep->hcpriv = NULL; 1049 stream->ep->hcpriv = NULL;
1075 1050
@@ -1230,17 +1205,19 @@ itd_urb_transaction (
1230 spin_lock_irqsave (&ehci->lock, flags); 1205 spin_lock_irqsave (&ehci->lock, flags);
1231 for (i = 0; i < num_itds; i++) { 1206 for (i = 0; i < num_itds; i++) {
1232 1207
1233 /* free_list.next might be cache-hot ... but maybe 1208 /*
1234 * the HC caches it too. avoid that issue for now. 1209 * Use iTDs from the free list, but not iTDs that may
1210 * still be in use by the hardware.
1235 */ 1211 */
1236 1212 if (likely(!list_empty(&stream->free_list))) {
1237 /* prefer previously-allocated itds */ 1213 itd = list_first_entry(&stream->free_list,
1238 if (likely (!list_empty(&stream->free_list))) {
1239 itd = list_entry (stream->free_list.prev,
1240 struct ehci_itd, itd_list); 1214 struct ehci_itd, itd_list);
1215 if (itd->frame == ehci->clock_frame)
1216 goto alloc_itd;
1241 list_del (&itd->itd_list); 1217 list_del (&itd->itd_list);
1242 itd_dma = itd->itd_dma; 1218 itd_dma = itd->itd_dma;
1243 } else { 1219 } else {
1220 alloc_itd:
1244 spin_unlock_irqrestore (&ehci->lock, flags); 1221 spin_unlock_irqrestore (&ehci->lock, flags);
1245 itd = dma_pool_alloc (ehci->itd_pool, mem_flags, 1222 itd = dma_pool_alloc (ehci->itd_pool, mem_flags,
1246 &itd_dma); 1223 &itd_dma);
@@ -1762,24 +1739,18 @@ itd_complete (
1762 1739
1763done: 1740done:
1764 itd->urb = NULL; 1741 itd->urb = NULL;
1765 if (ehci->clock_frame != itd->frame || itd->index[7] != -1) { 1742
1766 /* OK to recycle this ITD now. */ 1743 /* Add to the end of the free list for later reuse */
1767 itd->stream = NULL; 1744 list_move_tail(&itd->itd_list, &stream->free_list);
1768 list_move(&itd->itd_list, &stream->free_list); 1745
1769 iso_stream_put(ehci, stream); 1746 /* Recycle the iTDs when the pipeline is empty (ep no longer in use) */
1770 } else { 1747 if (list_empty(&stream->td_list)) {
1771 /* HW might remember this ITD, so we can't recycle it yet. 1748 list_splice_tail_init(&stream->free_list,
1772 * Move it to a safe place until a new frame starts. 1749 &ehci->cached_itd_list);
1773 */ 1750 start_free_itds(ehci);
1774 list_move(&itd->itd_list, &ehci->cached_itd_list);
1775 if (stream->refcount == 2) {
1776 /* If iso_stream_put() were called here, stream
1777 * would be freed. Instead, just prevent reuse.
1778 */
1779 stream->ep->hcpriv = NULL;
1780 stream->ep = NULL;
1781 }
1782 } 1751 }
1752
1753 iso_stream_put(ehci, stream);
1783 return retval; 1754 return retval;
1784} 1755}
1785 1756
@@ -1930,17 +1901,19 @@ sitd_urb_transaction (
1930 * means we never need two sitds for full speed packets. 1901 * means we never need two sitds for full speed packets.
1931 */ 1902 */
1932 1903
1933 /* free_list.next might be cache-hot ... but maybe 1904 /*
1934 * the HC caches it too. avoid that issue for now. 1905 * Use siTDs from the free list, but not siTDs that may
1906 * still be in use by the hardware.
1935 */ 1907 */
1936 1908 if (likely(!list_empty(&stream->free_list))) {
1937 /* prefer previously-allocated sitds */ 1909 sitd = list_first_entry(&stream->free_list,
1938 if (!list_empty(&stream->free_list)) {
1939 sitd = list_entry (stream->free_list.prev,
1940 struct ehci_sitd, sitd_list); 1910 struct ehci_sitd, sitd_list);
1911 if (sitd->frame == ehci->clock_frame)
1912 goto alloc_sitd;
1941 list_del (&sitd->sitd_list); 1913 list_del (&sitd->sitd_list);
1942 sitd_dma = sitd->sitd_dma; 1914 sitd_dma = sitd->sitd_dma;
1943 } else { 1915 } else {
1916 alloc_sitd:
1944 spin_unlock_irqrestore (&ehci->lock, flags); 1917 spin_unlock_irqrestore (&ehci->lock, flags);
1945 sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags, 1918 sitd = dma_pool_alloc (ehci->sitd_pool, mem_flags,
1946 &sitd_dma); 1919 &sitd_dma);
@@ -2157,24 +2130,18 @@ sitd_complete (
2157 2130
2158done: 2131done:
2159 sitd->urb = NULL; 2132 sitd->urb = NULL;
2160 if (ehci->clock_frame != sitd->frame) { 2133
2161 /* OK to recycle this SITD now. */ 2134 /* Add to the end of the free list for later reuse */
2162 sitd->stream = NULL; 2135 list_move_tail(&sitd->sitd_list, &stream->free_list);
2163 list_move(&sitd->sitd_list, &stream->free_list); 2136
2164 iso_stream_put(ehci, stream); 2137 /* Recycle the siTDs when the pipeline is empty (ep no longer in use) */
2165 } else { 2138 if (list_empty(&stream->td_list)) {
2166 /* HW might remember this SITD, so we can't recycle it yet. 2139 list_splice_tail_init(&stream->free_list,
2167 * Move it to a safe place until a new frame starts. 2140 &ehci->cached_sitd_list);
2168 */ 2141 start_free_itds(ehci);
2169 list_move(&sitd->sitd_list, &ehci->cached_sitd_list);
2170 if (stream->refcount == 2) {
2171 /* If iso_stream_put() were called here, stream
2172 * would be freed. Instead, just prevent reuse.
2173 */
2174 stream->ep->hcpriv = NULL;
2175 stream->ep = NULL;
2176 }
2177 } 2142 }
2143
2144 iso_stream_put(ehci, stream);
2178 return retval; 2145 return retval;
2179} 2146}
2180 2147
@@ -2239,28 +2206,6 @@ done:
2239 2206
2240/*-------------------------------------------------------------------------*/ 2207/*-------------------------------------------------------------------------*/
2241 2208
2242static void free_cached_lists(struct ehci_hcd *ehci)
2243{
2244 struct ehci_itd *itd, *n;
2245 struct ehci_sitd *sitd, *sn;
2246
2247 list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
2248 struct ehci_iso_stream *stream = itd->stream;
2249 itd->stream = NULL;
2250 list_move(&itd->itd_list, &stream->free_list);
2251 iso_stream_put(ehci, stream);
2252 }
2253
2254 list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
2255 struct ehci_iso_stream *stream = sitd->stream;
2256 sitd->stream = NULL;
2257 list_move(&sitd->sitd_list, &stream->free_list);
2258 iso_stream_put(ehci, stream);
2259 }
2260}
2261
2262/*-------------------------------------------------------------------------*/
2263
2264static void 2209static void
2265scan_periodic (struct ehci_hcd *ehci) 2210scan_periodic (struct ehci_hcd *ehci)
2266{ 2211{
@@ -2282,10 +2227,7 @@ scan_periodic (struct ehci_hcd *ehci)
2282 clock = now_uframe + mod - 1; 2227 clock = now_uframe + mod - 1;
2283 clock_frame = -1; 2228 clock_frame = -1;
2284 } 2229 }
2285 if (ehci->clock_frame != clock_frame) { 2230 ehci->clock_frame = clock_frame;
2286 free_cached_lists(ehci);
2287 ehci->clock_frame = clock_frame;
2288 }
2289 clock &= mod - 1; 2231 clock &= mod - 1;
2290 clock_frame = clock >> 3; 2232 clock_frame = clock >> 3;
2291 ++ehci->periodic_stamp; 2233 ++ehci->periodic_stamp;
@@ -2463,7 +2405,6 @@ restart:
2463 clock = now; 2405 clock = now;
2464 clock_frame = clock >> 3; 2406 clock_frame = clock >> 3;
2465 if (ehci->clock_frame != clock_frame) { 2407 if (ehci->clock_frame != clock_frame) {
2466 free_cached_lists(ehci);
2467 ehci->clock_frame = clock_frame; 2408 ehci->clock_frame = clock_frame;
2468 ++ehci->periodic_stamp; 2409 ++ehci->periodic_stamp;
2469 } 2410 }
diff --git a/drivers/usb/host/ehci-timer.c b/drivers/usb/host/ehci-timer.c
index 0c5326a8883c..8feb60ff4228 100644
--- a/drivers/usb/host/ehci-timer.c
+++ b/drivers/usb/host/ehci-timer.c
@@ -71,6 +71,7 @@ static unsigned event_delays_ns[] = {
71 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */ 71 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_PSS */
72 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */ 72 1 * NSEC_PER_MSEC, /* EHCI_HRTIMER_POLL_DEAD */
73 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */ 73 1125 * NSEC_PER_USEC, /* EHCI_HRTIMER_UNLINK_INTR */
74 2 * NSEC_PER_MSEC, /* EHCI_HRTIMER_FREE_ITDS */
74 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 75 10 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_PERIODIC */
75 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */ 76 15 * NSEC_PER_MSEC, /* EHCI_HRTIMER_DISABLE_ASYNC */
76}; 77};
@@ -165,7 +166,6 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
165 166
166 /* The status is up-to-date; restart or stop the schedule as needed */ 167 /* The status is up-to-date; restart or stop the schedule as needed */
167 if (want == 0) { /* Stopped */ 168 if (want == 0) { /* Stopped */
168 free_cached_lists(ehci);
169 if (ehci->periodic_count > 0) { 169 if (ehci->periodic_count > 0) {
170 170
171 /* make sure ehci_work scans these */ 171 /* make sure ehci_work scans these */
@@ -188,9 +188,6 @@ static void ehci_poll_PSS(struct ehci_hcd *ehci)
188static void ehci_disable_PSE(struct ehci_hcd *ehci) 188static void ehci_disable_PSE(struct ehci_hcd *ehci)
189{ 189{
190 ehci_clear_command_bit(ehci, CMD_PSE); 190 ehci_clear_command_bit(ehci, CMD_PSE);
191
192 /* Poll to see when it actually stops */
193 ehci_enable_event(ehci, EHCI_HRTIMER_POLL_PSS, true);
194} 191}
195 192
196 193
@@ -250,6 +247,50 @@ static void ehci_handle_intr_unlinks(struct ehci_hcd *ehci)
250} 247}
251 248
252 249
250/* Start another free-iTDs/siTDs cycle */
251static void start_free_itds(struct ehci_hcd *ehci)
252{
253 if (!(ehci->enabled_hrtimer_events & BIT(EHCI_HRTIMER_FREE_ITDS))) {
254 ehci->last_itd_to_free = list_entry(
255 ehci->cached_itd_list.prev,
256 struct ehci_itd, itd_list);
257 ehci->last_sitd_to_free = list_entry(
258 ehci->cached_sitd_list.prev,
259 struct ehci_sitd, sitd_list);
260 ehci_enable_event(ehci, EHCI_HRTIMER_FREE_ITDS, true);
261 }
262}
263
264/* Wait for controller to stop using old iTDs and siTDs */
265static void end_free_itds(struct ehci_hcd *ehci)
266{
267 struct ehci_itd *itd, *n;
268 struct ehci_sitd *sitd, *sn;
269
270 if (ehci->rh_state < EHCI_RH_RUNNING) {
271 ehci->last_itd_to_free = NULL;
272 ehci->last_sitd_to_free = NULL;
273 }
274
275 list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
276 list_del(&itd->itd_list);
277 dma_pool_free(ehci->itd_pool, itd, itd->itd_dma);
278 if (itd == ehci->last_itd_to_free)
279 break;
280 }
281 list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) {
282 list_del(&sitd->sitd_list);
283 dma_pool_free(ehci->sitd_pool, sitd, sitd->sitd_dma);
284 if (sitd == ehci->last_sitd_to_free)
285 break;
286 }
287
288 if (!list_empty(&ehci->cached_itd_list) ||
289 !list_empty(&ehci->cached_sitd_list))
290 start_free_itds(ehci);
291}
292
293
253/* 294/*
254 * Handler functions for the hrtimer event types. 295 * Handler functions for the hrtimer event types.
255 * Keep this array in the same order as the event types indexed by 296 * Keep this array in the same order as the event types indexed by
@@ -260,6 +301,7 @@ static void (*event_handlers[])(struct ehci_hcd *) = {
260 ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */ 301 ehci_poll_PSS, /* EHCI_HRTIMER_POLL_PSS */
261 ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */ 302 ehci_handle_controller_death, /* EHCI_HRTIMER_POLL_DEAD */
262 ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */ 303 ehci_handle_intr_unlinks, /* EHCI_HRTIMER_UNLINK_INTR */
304 end_free_itds, /* EHCI_HRTIMER_FREE_ITDS */
263 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */ 305 ehci_disable_PSE, /* EHCI_HRTIMER_DISABLE_PERIODIC */
264 ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */ 306 ehci_disable_ASE, /* EHCI_HRTIMER_DISABLE_ASYNC */
265}; 307};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 6874d89b0b64..bcfbb175e2b4 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -83,6 +83,7 @@ enum ehci_hrtimer_event {
83 EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */ 83 EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
84 EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */ 84 EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
85 EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */ 85 EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
86 EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
86 EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */ 87 EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
87 EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */ 88 EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
88 EHCI_HRTIMER_NUM_EVENTS /* Must come last */ 89 EHCI_HRTIMER_NUM_EVENTS /* Must come last */
@@ -139,7 +140,9 @@ struct ehci_hcd { /* one per controller */
139 140
140 /* list of itds & sitds completed while clock_frame was still active */ 141 /* list of itds & sitds completed while clock_frame was still active */
141 struct list_head cached_itd_list; 142 struct list_head cached_itd_list;
143 struct ehci_itd *last_itd_to_free;
142 struct list_head cached_sitd_list; 144 struct list_head cached_sitd_list;
145 struct ehci_sitd *last_sitd_to_free;
143 unsigned clock_frame; 146 unsigned clock_frame;
144 147
145 /* per root hub port */ 148 /* per root hub port */
@@ -250,8 +253,6 @@ timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
250 clear_bit (action, &ehci->actions); 253 clear_bit (action, &ehci->actions);
251} 254}
252 255
253static void free_cached_lists(struct ehci_hcd *ehci);
254
255/*-------------------------------------------------------------------------*/ 256/*-------------------------------------------------------------------------*/
256 257
257#include <linux/usb/ehci_def.h> 258#include <linux/usb/ehci_def.h>