aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2012-09-28 16:01:23 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-10-22 11:57:43 -0400
commitc3ee9b76aa93fbf59727e02fac9914c7355108f3 (patch)
tree6a5456490de55f56b6fa0bf778db6f7f8a764616 /drivers/usb/host/ehci-sched.c
parent6f0c0580b70c89094b3422ba81118c7b959c7556 (diff)
EHCI: improved logic for isochronous scheduling
This patch (as1608) reworks the logic used by ehci-hcd for scheduling isochronous transfers. Now the modular calculations are all based on a window that starts at the last frame scanned for isochronous completions. No transfer descriptors for any earlier frames can possibly remain on the schedule, so there can be no confusion from schedule wrap-around. This removes the need for a "slop" region of arbitrary size. There's no need to check for URBs that are longer than the schedule length. With the old code they could throw things off by wrapping around and appearing to end in the near future rather than the distant future. Now such confusion isn't possible, and the existing test for submissions that extend too far into the future will also catch those that exceed the schedule length. (But there still has to be an initial test to handle the case where the schedule already extends as far into the future as possible.) Delays caused by IRQ latency won't confuse the algorithm unless they are ridiculously long (over 250 ms); they will merely reduce how far into the future new transfers can be scheduled. A few people have reported problems caused by delays of 50 ms or so. Now instead of failing completely, isochronous transfers will experience a brief glitch and then continue normally. (Whether this is truly a good thing is debatable. A latency as large as 50 ms generally indicates a bug is present, and complete failure of audio or video transfers draws people's attention pretty vividly. Making the transfers more robust also makes it easier for such bugs to remain undetected.) Finally, ehci->next_frame is renamed to ehci->last_iso_frame, because that better describes what it is: the last frame to have been scanned for isochronous completions. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c70
1 files changed, 32 insertions, 38 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 7cf3da7babf0..7eb242f27c00 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1361,7 +1361,7 @@ sitd_slot_ok (
1361 * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler! 1361 * given EHCI_TUNE_FLS and the slop). Or, write a smarter scheduler!
1362 */ 1362 */
1363 1363
1364#define SCHEDULE_SLOP 80 /* microframes */ 1364#define SCHEDULING_DELAY 40 /* microframes */
1365 1365
1366static int 1366static int
1367iso_stream_schedule ( 1367iso_stream_schedule (
@@ -1370,7 +1370,7 @@ iso_stream_schedule (
1370 struct ehci_iso_stream *stream 1370 struct ehci_iso_stream *stream
1371) 1371)
1372{ 1372{
1373 u32 now, next, start, period, span; 1373 u32 now, base, next, start, period, span;
1374 int status; 1374 int status;
1375 unsigned mod = ehci->periodic_size << 3; 1375 unsigned mod = ehci->periodic_size << 3;
1376 struct ehci_iso_sched *sched = urb->hcpriv; 1376 struct ehci_iso_sched *sched = urb->hcpriv;
@@ -1382,12 +1382,6 @@ iso_stream_schedule (
1382 span <<= 3; 1382 span <<= 3;
1383 } 1383 }
1384 1384
1385 if (span > mod - SCHEDULE_SLOP) {
1386 ehci_dbg (ehci, "iso request %p too long\n", urb);
1387 status = -EFBIG;
1388 goto fail;
1389 }
1390
1391 now = ehci_read_frame_index(ehci) & (mod - 1); 1385 now = ehci_read_frame_index(ehci) & (mod - 1);
1392 1386
1393 /* Typical case: reuse current schedule, stream is still active. 1387 /* Typical case: reuse current schedule, stream is still active.
@@ -1396,7 +1390,6 @@ iso_stream_schedule (
1396 * slot in the schedule, implicitly assuming URB_ISO_ASAP. 1390 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
1397 */ 1391 */
1398 if (likely (!list_empty (&stream->td_list))) { 1392 if (likely (!list_empty (&stream->td_list))) {
1399 u32 excess;
1400 1393
1401 /* For high speed devices, allow scheduling within the 1394 /* For high speed devices, allow scheduling within the
1402 * isochronous scheduling threshold. For full speed devices 1395 * isochronous scheduling threshold. For full speed devices
@@ -1408,36 +1401,41 @@ iso_stream_schedule (
1408 else 1401 else
1409 next = now; 1402 next = now;
1410 1403
1411 /* Fell behind (by up to twice the slop amount)? 1404 /*
1412 * We decide based on the time of the last currently-scheduled 1405 * Use ehci->last_iso_frame as the base. There can't be any
1413 * slot, not the time of the next available slot. 1406 * TDs scheduled for earlier than that.
1414 */ 1407 */
1415 excess = (stream->next_uframe - period - next) & (mod - 1); 1408 base = ehci->last_iso_frame << 3;
1416 if (excess >= mod - 2 * SCHEDULE_SLOP) 1409 next = (next - base) & (mod - 1);
1417 start = next + excess - mod + period * 1410 start = (stream->next_uframe - base) & (mod - 1);
1418 DIV_ROUND_UP(mod - excess, period); 1411
1419 else 1412 /* Is the schedule already full? */
1420 start = next + excess + period; 1413 if (unlikely(start < period)) {
1421 if (start - now >= mod) { 1414 ehci_dbg(ehci, "iso sched full %p (%u-%u < %u mod %u)\n",
1422 ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", 1415 urb, stream->next_uframe, base,
1423 urb, start - now - period, period, 1416 period, mod);
1424 mod); 1417 status = -ENOSPC;
1425 status = -EFBIG;
1426 goto fail; 1418 goto fail;
1427 } 1419 }
1420
1421 /* Behind the scheduling threshold? Assume URB_ISO_ASAP. */
1422 if (unlikely(start < next))
1423 start += period * DIV_ROUND_UP(next - start, period);
1424
1425 start += base;
1428 } 1426 }
1429 1427
1430 /* need to schedule; when's the next (u)frame we could start? 1428 /* need to schedule; when's the next (u)frame we could start?
1431 * this is bigger than ehci->i_thresh allows; scheduling itself 1429 * this is bigger than ehci->i_thresh allows; scheduling itself
1432 * isn't free, the slop should handle reasonably slow cpus. it 1430 * isn't free, the delay should handle reasonably slow cpus. it
1433 * can also help high bandwidth if the dma and irq loads don't 1431 * can also help high bandwidth if the dma and irq loads don't
1434 * jump until after the queue is primed. 1432 * jump until after the queue is primed.
1435 */ 1433 */
1436 else { 1434 else {
1437 int done = 0; 1435 int done = 0;
1438 start = SCHEDULE_SLOP + (now & ~0x07);
1439 1436
1440 /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ 1437 base = now & ~0x07;
1438 start = base + SCHEDULING_DELAY;
1441 1439
1442 /* find a uframe slot with enough bandwidth. 1440 /* find a uframe slot with enough bandwidth.
1443 * Early uframes are more precious because full-speed 1441 * Early uframes are more precious because full-speed
@@ -1464,19 +1462,16 @@ iso_stream_schedule (
1464 1462
1465 /* no room in the schedule */ 1463 /* no room in the schedule */
1466 if (!done) { 1464 if (!done) {
1467 ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", 1465 ehci_dbg(ehci, "iso sched full %p", urb);
1468 urb, now, now + mod);
1469 status = -ENOSPC; 1466 status = -ENOSPC;
1470 goto fail; 1467 goto fail;
1471 } 1468 }
1472 } 1469 }
1473 1470
1474 /* Tried to schedule too far into the future? */ 1471 /* Tried to schedule too far into the future? */
1475 if (unlikely(start - now + span - period 1472 if (unlikely(start - base + span - period >= mod)) {
1476 >= mod - 2 * SCHEDULE_SLOP)) { 1473 ehci_dbg(ehci, "request %p would overflow (%u+%u >= %u)\n",
1477 ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", 1474 urb, start - base, span - period, mod);
1478 urb, start - now, span - period,
1479 mod - 2 * SCHEDULE_SLOP);
1480 status = -EFBIG; 1475 status = -EFBIG;
1481 goto fail; 1476 goto fail;
1482 } 1477 }
@@ -1490,7 +1485,7 @@ iso_stream_schedule (
1490 1485
1491 /* Make sure scan_isoc() sees these */ 1486 /* Make sure scan_isoc() sees these */
1492 if (ehci->isoc_count == 0) 1487 if (ehci->isoc_count == 0)
1493 ehci->next_frame = now >> 3; 1488 ehci->last_iso_frame = now >> 3;
1494 return 0; 1489 return 0;
1495 1490
1496 fail: 1491 fail:
@@ -2220,16 +2215,16 @@ static void scan_isoc(struct ehci_hcd *ehci)
2220 now_frame = (uf >> 3) & fmask; 2215 now_frame = (uf >> 3) & fmask;
2221 live = true; 2216 live = true;
2222 } else { 2217 } else {
2223 now_frame = (ehci->next_frame - 1) & fmask; 2218 now_frame = (ehci->last_iso_frame - 1) & fmask;
2224 live = false; 2219 live = false;
2225 } 2220 }
2226 ehci->now_frame = now_frame; 2221 ehci->now_frame = now_frame;
2227 2222
2228 frame = ehci->next_frame;
2229 for (;;) { 2223 for (;;) {
2230 union ehci_shadow q, *q_p; 2224 union ehci_shadow q, *q_p;
2231 __hc32 type, *hw_p; 2225 __hc32 type, *hw_p;
2232 2226
2227 frame = ehci->last_iso_frame;
2233restart: 2228restart:
2234 /* scan each element in frame's queue for completions */ 2229 /* scan each element in frame's queue for completions */
2235 q_p = &ehci->pshadow [frame]; 2230 q_p = &ehci->pshadow [frame];
@@ -2334,7 +2329,6 @@ restart:
2334 /* Stop when we have reached the current frame */ 2329 /* Stop when we have reached the current frame */
2335 if (frame == now_frame) 2330 if (frame == now_frame)
2336 break; 2331 break;
2337 frame = (frame + 1) & fmask; 2332 ehci->last_iso_frame = (frame + 1) & fmask;
2338 } 2333 }
2339 ehci->next_frame = now_frame;
2340} 2334}