diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 114 |
1 files changed, 83 insertions, 31 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a5535b5e3fe2..805ec633a652 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -510,6 +510,8 @@ static int disable_periodic (struct ehci_hcd *ehci) | |||
510 | ehci_writel(ehci, cmd, &ehci->regs->command); | 510 | ehci_writel(ehci, cmd, &ehci->regs->command); |
511 | /* posted write ... */ | 511 | /* posted write ... */ |
512 | 512 | ||
513 | free_cached_lists(ehci); | ||
514 | |||
513 | ehci->next_uframe = -1; | 515 | ehci->next_uframe = -1; |
514 | return 0; | 516 | return 0; |
515 | } | 517 | } |
@@ -1121,8 +1123,8 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) | |||
1121 | urb->interval); | 1123 | urb->interval); |
1122 | } | 1124 | } |
1123 | 1125 | ||
1124 | /* if dev->ep [epnum] is a QH, info1.maxpacket is nonzero */ | 1126 | /* if dev->ep [epnum] is a QH, hw is set */ |
1125 | } else if (unlikely (stream->hw_info1 != 0)) { | 1127 | } else if (unlikely (stream->hw != NULL)) { |
1126 | ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n", | 1128 | ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n", |
1127 | urb->dev->devpath, epnum, | 1129 | urb->dev->devpath, epnum, |
1128 | usb_pipein(urb->pipe) ? "in" : "out"); | 1130 | usb_pipein(urb->pipe) ? "in" : "out"); |
@@ -1385,7 +1387,7 @@ sitd_slot_ok ( | |||
1385 | * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! | 1387 | * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! |
1386 | */ | 1388 | */ |
1387 | 1389 | ||
1388 | #define SCHEDULE_SLOP 10 /* frames */ | 1390 | #define SCHEDULE_SLOP 80 /* microframes */ |
1389 | 1391 | ||
1390 | static int | 1392 | static int |
1391 | iso_stream_schedule ( | 1393 | iso_stream_schedule ( |
@@ -1394,12 +1396,13 @@ iso_stream_schedule ( | |||
1394 | struct ehci_iso_stream *stream | 1396 | struct ehci_iso_stream *stream |
1395 | ) | 1397 | ) |
1396 | { | 1398 | { |
1397 | u32 now, start, max, period; | 1399 | u32 now, next, start, period; |
1398 | int status; | 1400 | int status; |
1399 | unsigned mod = ehci->periodic_size << 3; | 1401 | unsigned mod = ehci->periodic_size << 3; |
1400 | struct ehci_iso_sched *sched = urb->hcpriv; | 1402 | struct ehci_iso_sched *sched = urb->hcpriv; |
1403 | struct pci_dev *pdev; | ||
1401 | 1404 | ||
1402 | if (sched->span > (mod - 8 * SCHEDULE_SLOP)) { | 1405 | if (sched->span > (mod - SCHEDULE_SLOP)) { |
1403 | ehci_dbg (ehci, "iso request %p too long\n", urb); | 1406 | ehci_dbg (ehci, "iso request %p too long\n", urb); |
1404 | status = -EFBIG; | 1407 | status = -EFBIG; |
1405 | goto fail; | 1408 | goto fail; |
@@ -1418,26 +1421,35 @@ iso_stream_schedule ( | |||
1418 | 1421 | ||
1419 | now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; | 1422 | now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; |
1420 | 1423 | ||
1421 | /* when's the last uframe this urb could start? */ | ||
1422 | max = now + mod; | ||
1423 | |||
1424 | /* Typical case: reuse current schedule, stream is still active. | 1424 | /* Typical case: reuse current schedule, stream is still active. |
1425 | * Hopefully there are no gaps from the host falling behind | 1425 | * Hopefully there are no gaps from the host falling behind |
1426 | * (irq delays etc), but if there are we'll take the next | 1426 | * (irq delays etc), but if there are we'll take the next |
1427 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. | 1427 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. |
1428 | */ | 1428 | */ |
1429 | if (likely (!list_empty (&stream->td_list))) { | 1429 | if (likely (!list_empty (&stream->td_list))) { |
1430 | pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); | ||
1430 | start = stream->next_uframe; | 1431 | start = stream->next_uframe; |
1431 | if (start < now) | 1432 | |
1432 | start += mod; | 1433 | /* For high speed devices, allow scheduling within the |
1434 | * isochronous scheduling threshold. For full speed devices, | ||
1435 | * don't. (Work around for Intel ICH9 bug.) | ||
1436 | */ | ||
1437 | if (!stream->highspeed && | ||
1438 | pdev->vendor == PCI_VENDOR_ID_INTEL) | ||
1439 | next = now + ehci->i_thresh; | ||
1440 | else | ||
1441 | next = now; | ||
1433 | 1442 | ||
1434 | /* Fell behind (by up to twice the slop amount)? */ | 1443 | /* Fell behind (by up to twice the slop amount)? */ |
1435 | if (start >= max - 2 * 8 * SCHEDULE_SLOP) | 1444 | if (((start - next) & (mod - 1)) >= |
1445 | mod - 2 * SCHEDULE_SLOP) | ||
1436 | start += period * DIV_ROUND_UP( | 1446 | start += period * DIV_ROUND_UP( |
1437 | max - start, period) - mod; | 1447 | (next - start) & (mod - 1), |
1448 | period); | ||
1438 | 1449 | ||
1439 | /* Tried to schedule too far into the future? */ | 1450 | /* Tried to schedule too far into the future? */ |
1440 | if (unlikely((start + sched->span) >= max)) { | 1451 | if (unlikely(((start - now) & (mod - 1)) + sched->span |
1452 | >= mod - 2 * SCHEDULE_SLOP)) { | ||
1441 | status = -EFBIG; | 1453 | status = -EFBIG; |
1442 | goto fail; | 1454 | goto fail; |
1443 | } | 1455 | } |
@@ -1451,7 +1463,7 @@ iso_stream_schedule ( | |||
1451 | * can also help high bandwidth if the dma and irq loads don't | 1463 | * can also help high bandwidth if the dma and irq loads don't |
1452 | * jump until after the queue is primed. | 1464 | * jump until after the queue is primed. |
1453 | */ | 1465 | */ |
1454 | start = SCHEDULE_SLOP * 8 + (now & ~0x07); | 1466 | start = SCHEDULE_SLOP + (now & ~0x07); |
1455 | start %= mod; | 1467 | start %= mod; |
1456 | stream->next_uframe = start; | 1468 | stream->next_uframe = start; |
1457 | 1469 | ||
@@ -1482,7 +1494,7 @@ iso_stream_schedule ( | |||
1482 | /* no room in the schedule */ | 1494 | /* no room in the schedule */ |
1483 | ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", | 1495 | ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", |
1484 | list_empty (&stream->td_list) ? "" : "re", | 1496 | list_empty (&stream->td_list) ? "" : "re", |
1485 | urb, now, max); | 1497 | urb, now, now + mod); |
1486 | status = -ENOSPC; | 1498 | status = -ENOSPC; |
1487 | 1499 | ||
1488 | fail: | 1500 | fail: |
@@ -1553,13 +1565,27 @@ itd_patch( | |||
1553 | static inline void | 1565 | static inline void |
1554 | itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) | 1566 | itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) |
1555 | { | 1567 | { |
1556 | /* always prepend ITD/SITD ... only QH tree is order-sensitive */ | 1568 | union ehci_shadow *prev = &ehci->pshadow[frame]; |
1557 | itd->itd_next = ehci->pshadow [frame]; | 1569 | __hc32 *hw_p = &ehci->periodic[frame]; |
1558 | itd->hw_next = ehci->periodic [frame]; | 1570 | union ehci_shadow here = *prev; |
1559 | ehci->pshadow [frame].itd = itd; | 1571 | __hc32 type = 0; |
1572 | |||
1573 | /* skip any iso nodes which might belong to previous microframes */ | ||
1574 | while (here.ptr) { | ||
1575 | type = Q_NEXT_TYPE(ehci, *hw_p); | ||
1576 | if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) | ||
1577 | break; | ||
1578 | prev = periodic_next_shadow(ehci, prev, type); | ||
1579 | hw_p = shadow_next_periodic(ehci, &here, type); | ||
1580 | here = *prev; | ||
1581 | } | ||
1582 | |||
1583 | itd->itd_next = here; | ||
1584 | itd->hw_next = *hw_p; | ||
1585 | prev->itd = itd; | ||
1560 | itd->frame = frame; | 1586 | itd->frame = frame; |
1561 | wmb (); | 1587 | wmb (); |
1562 | ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); | 1588 | *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); |
1563 | } | 1589 | } |
1564 | 1590 | ||
1565 | /* fit urb's itds into the selected schedule slot; activate as needed */ | 1591 | /* fit urb's itds into the selected schedule slot; activate as needed */ |
@@ -2113,13 +2139,27 @@ sitd_complete ( | |||
2113 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); | 2139 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); |
2114 | } | 2140 | } |
2115 | iso_stream_put (ehci, stream); | 2141 | iso_stream_put (ehci, stream); |
2116 | /* OK to recycle this SITD now that its completion callback ran. */ | 2142 | |
2117 | done: | 2143 | done: |
2118 | sitd->urb = NULL; | 2144 | sitd->urb = NULL; |
2119 | sitd->stream = NULL; | 2145 | if (ehci->clock_frame != sitd->frame) { |
2120 | list_move(&sitd->sitd_list, &stream->free_list); | 2146 | /* OK to recycle this SITD now. */ |
2121 | iso_stream_put(ehci, stream); | 2147 | sitd->stream = NULL; |
2122 | 2148 | list_move(&sitd->sitd_list, &stream->free_list); | |
2149 | iso_stream_put(ehci, stream); | ||
2150 | } else { | ||
2151 | /* HW might remember this SITD, so we can't recycle it yet. | ||
2152 | * Move it to a safe place until a new frame starts. | ||
2153 | */ | ||
2154 | list_move(&sitd->sitd_list, &ehci->cached_sitd_list); | ||
2155 | if (stream->refcount == 2) { | ||
2156 | /* If iso_stream_put() were called here, stream | ||
2157 | * would be freed. Instead, just prevent reuse. | ||
2158 | */ | ||
2159 | stream->ep->hcpriv = NULL; | ||
2160 | stream->ep = NULL; | ||
2161 | } | ||
2162 | } | ||
2123 | return retval; | 2163 | return retval; |
2124 | } | 2164 | } |
2125 | 2165 | ||
@@ -2185,9 +2225,10 @@ done: | |||
2185 | 2225 | ||
2186 | /*-------------------------------------------------------------------------*/ | 2226 | /*-------------------------------------------------------------------------*/ |
2187 | 2227 | ||
2188 | static void free_cached_itd_list(struct ehci_hcd *ehci) | 2228 | static void free_cached_lists(struct ehci_hcd *ehci) |
2189 | { | 2229 | { |
2190 | struct ehci_itd *itd, *n; | 2230 | struct ehci_itd *itd, *n; |
2231 | struct ehci_sitd *sitd, *sn; | ||
2191 | 2232 | ||
2192 | list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { | 2233 | list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) { |
2193 | struct ehci_iso_stream *stream = itd->stream; | 2234 | struct ehci_iso_stream *stream = itd->stream; |
@@ -2195,6 +2236,13 @@ static void free_cached_itd_list(struct ehci_hcd *ehci) | |||
2195 | list_move(&itd->itd_list, &stream->free_list); | 2236 | list_move(&itd->itd_list, &stream->free_list); |
2196 | iso_stream_put(ehci, stream); | 2237 | iso_stream_put(ehci, stream); |
2197 | } | 2238 | } |
2239 | |||
2240 | list_for_each_entry_safe(sitd, sn, &ehci->cached_sitd_list, sitd_list) { | ||
2241 | struct ehci_iso_stream *stream = sitd->stream; | ||
2242 | sitd->stream = NULL; | ||
2243 | list_move(&sitd->sitd_list, &stream->free_list); | ||
2244 | iso_stream_put(ehci, stream); | ||
2245 | } | ||
2198 | } | 2246 | } |
2199 | 2247 | ||
2200 | /*-------------------------------------------------------------------------*/ | 2248 | /*-------------------------------------------------------------------------*/ |
@@ -2221,7 +2269,7 @@ scan_periodic (struct ehci_hcd *ehci) | |||
2221 | clock_frame = -1; | 2269 | clock_frame = -1; |
2222 | } | 2270 | } |
2223 | if (ehci->clock_frame != clock_frame) { | 2271 | if (ehci->clock_frame != clock_frame) { |
2224 | free_cached_itd_list(ehci); | 2272 | free_cached_lists(ehci); |
2225 | ehci->clock_frame = clock_frame; | 2273 | ehci->clock_frame = clock_frame; |
2226 | } | 2274 | } |
2227 | clock %= mod; | 2275 | clock %= mod; |
@@ -2312,9 +2360,13 @@ restart: | |||
2312 | * No need to check for activity unless the | 2360 | * No need to check for activity unless the |
2313 | * frame is current. | 2361 | * frame is current. |
2314 | */ | 2362 | */ |
2315 | if (frame == clock_frame && live && | 2363 | if (((frame == clock_frame) || |
2316 | (q.sitd->hw_results & | 2364 | (((frame + 1) % ehci->periodic_size) |
2317 | SITD_ACTIVE(ehci))) { | 2365 | == clock_frame)) |
2366 | && live | ||
2367 | && (q.sitd->hw_results & | ||
2368 | SITD_ACTIVE(ehci))) { | ||
2369 | |||
2318 | incomplete = true; | 2370 | incomplete = true; |
2319 | q_p = &q.sitd->sitd_next; | 2371 | q_p = &q.sitd->sitd_next; |
2320 | hw_p = &q.sitd->hw_next; | 2372 | hw_p = &q.sitd->hw_next; |
@@ -2384,7 +2436,7 @@ restart: | |||
2384 | clock = now; | 2436 | clock = now; |
2385 | clock_frame = clock >> 3; | 2437 | clock_frame = clock >> 3; |
2386 | if (ehci->clock_frame != clock_frame) { | 2438 | if (ehci->clock_frame != clock_frame) { |
2387 | free_cached_itd_list(ehci); | 2439 | free_cached_lists(ehci); |
2388 | ehci->clock_frame = clock_frame; | 2440 | ehci->clock_frame = clock_frame; |
2389 | } | 2441 | } |
2390 | } else { | 2442 | } else { |