diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 137 |
1 files changed, 39 insertions, 98 deletions
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 | ||
1763 | done: | 1740 | done: |
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 | ||
2158 | done: | 2131 | done: |
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 | ||
2242 | static 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 | |||
2264 | static void | 2209 | static void |
2265 | scan_periodic (struct ehci_hcd *ehci) | 2210 | scan_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 | } |