aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c114
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
1390static int 1392static int
1391iso_stream_schedule ( 1393iso_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
1488fail: 1500fail:
@@ -1553,13 +1565,27 @@ itd_patch(
1553static inline void 1565static inline void
1554itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) 1566itd_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
2117done: 2143done:
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
2188static void free_cached_itd_list(struct ehci_hcd *ehci) 2228static 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 {