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.c110
1 files changed, 57 insertions, 53 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index dd37350170bb..3381319a2b3f 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1413,13 +1413,6 @@ iso_stream_schedule (
1413 goto fail; 1413 goto fail;
1414 } 1414 }
1415 1415
1416 if (stream->depth + span > mod) {
1417 ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
1418 urb, stream->depth, span, mod);
1419 status = -EFBIG;
1420 goto fail;
1421 }
1422
1423 now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1); 1416 now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
1424 1417
1425 /* Typical case: reuse current schedule, stream is still active. 1418 /* Typical case: reuse current schedule, stream is still active.
@@ -1428,7 +1421,7 @@ iso_stream_schedule (
1428 * slot in the schedule, implicitly assuming URB_ISO_ASAP. 1421 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
1429 */ 1422 */
1430 if (likely (!list_empty (&stream->td_list))) { 1423 if (likely (!list_empty (&stream->td_list))) {
1431 start = stream->next_uframe; 1424 u32 excess;
1432 1425
1433 /* For high speed devices, allow scheduling within the 1426 /* For high speed devices, allow scheduling within the
1434 * isochronous scheduling threshold. For full speed devices 1427 * isochronous scheduling threshold. For full speed devices
@@ -1440,21 +1433,23 @@ iso_stream_schedule (
1440 else 1433 else
1441 next = now; 1434 next = now;
1442 1435
1443 /* Fell behind (by up to twice the slop amount)? */ 1436 /* Fell behind (by up to twice the slop amount)?
1444 if (((start - next) & (mod - 1)) >= 1437 * We decide based on the time of the last currently-scheduled
1445 mod - 2 * SCHEDULE_SLOP) 1438 * slot, not the time of the next available slot.
1446 start += period * DIV_ROUND_UP( 1439 */
1447 (next - start) & (mod - 1), 1440 excess = (stream->next_uframe - period - next) & (mod - 1);
1448 period); 1441 if (excess >= mod - 2 * SCHEDULE_SLOP)
1449 1442 start = next + excess - mod + period *
1450 /* Tried to schedule too far into the future? */ 1443 DIV_ROUND_UP(mod - excess, period);
1451 if (unlikely(((start - now) & (mod - 1)) + span 1444 else
1452 >= mod - 2 * SCHEDULE_SLOP)) { 1445 start = next + excess + period;
1446 if (start - now >= mod) {
1447 ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n",
1448 urb, start - now - period, period,
1449 mod);
1453 status = -EFBIG; 1450 status = -EFBIG;
1454 goto fail; 1451 goto fail;
1455 } 1452 }
1456 stream->next_uframe = start;
1457 goto ready;
1458 } 1453 }
1459 1454
1460 /* need to schedule; when's the next (u)frame we could start? 1455 /* need to schedule; when's the next (u)frame we could start?
@@ -1463,51 +1458,60 @@ iso_stream_schedule (
1463 * can also help high bandwidth if the dma and irq loads don't 1458 * can also help high bandwidth if the dma and irq loads don't
1464 * jump until after the queue is primed. 1459 * jump until after the queue is primed.
1465 */ 1460 */
1466 start = SCHEDULE_SLOP + (now & ~0x07); 1461 else {
1467 start &= mod - 1; 1462 start = SCHEDULE_SLOP + (now & ~0x07);
1468 stream->next_uframe = start; 1463
1469 1464 /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */
1470 /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ 1465
1471 1466 /* find a uframe slot with enough bandwidth */
1472 /* find a uframe slot with enough bandwidth */ 1467 next = start + period;
1473 for (; start < (stream->next_uframe + period); start++) { 1468 for (; start < next; start++) {
1474 int enough_space; 1469
1475 1470 /* check schedule: enough space? */
1476 /* check schedule: enough space? */ 1471 if (stream->highspeed) {
1477 if (stream->highspeed) 1472 if (itd_slot_ok(ehci, mod, start,
1478 enough_space = itd_slot_ok (ehci, mod, start, 1473 stream->usecs, period))
1479 stream->usecs, period); 1474 break;
1480 else { 1475 } else {
1481 if ((start % 8) >= 6) 1476 if ((start % 8) >= 6)
1482 continue; 1477 continue;
1483 enough_space = sitd_slot_ok (ehci, mod, stream, 1478 if (sitd_slot_ok(ehci, mod, stream,
1484 start, sched, period); 1479 start, sched, period))
1480 break;
1481 }
1485 } 1482 }
1486 1483
1487 /* schedule it here if there's enough bandwidth */ 1484 /* no room in the schedule */
1488 if (enough_space) { 1485 if (start == next) {
1489 stream->next_uframe = start & (mod - 1); 1486 ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n",
1490 goto ready; 1487 urb, now, now + mod);
1488 status = -ENOSPC;
1489 goto fail;
1491 } 1490 }
1492 } 1491 }
1493 1492
1494 /* no room in the schedule */ 1493 /* Tried to schedule too far into the future? */
1495 ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", 1494 if (unlikely(start - now + span - period
1496 list_empty (&stream->td_list) ? "" : "re", 1495 >= mod - 2 * SCHEDULE_SLOP)) {
1497 urb, now, now + mod); 1496 ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n",
1498 status = -ENOSPC; 1497 urb, start - now, span - period,
1498 mod - 2 * SCHEDULE_SLOP);
1499 status = -EFBIG;
1500 goto fail;
1501 }
1499 1502
1500fail: 1503 stream->next_uframe = start & (mod - 1);
1501 iso_sched_free (stream, sched);
1502 urb->hcpriv = NULL;
1503 return status;
1504 1504
1505ready:
1506 /* report high speed start in uframes; full speed, in frames */ 1505 /* report high speed start in uframes; full speed, in frames */
1507 urb->start_frame = stream->next_uframe; 1506 urb->start_frame = stream->next_uframe;
1508 if (!stream->highspeed) 1507 if (!stream->highspeed)
1509 urb->start_frame >>= 3; 1508 urb->start_frame >>= 3;
1510 return 0; 1509 return 0;
1510
1511 fail:
1512 iso_sched_free(stream, sched);
1513 urb->hcpriv = NULL;
1514 return status;
1511} 1515}
1512 1516
1513/*-------------------------------------------------------------------------*/ 1517/*-------------------------------------------------------------------------*/