diff options
| -rw-r--r-- | drivers/usb/host/ehci-sched.c | 110 |
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 | ||
| 1500 | fail: | 1503 | stream->next_uframe = start & (mod - 1); |
| 1501 | iso_sched_free (stream, sched); | ||
| 1502 | urb->hcpriv = NULL; | ||
| 1503 | return status; | ||
| 1504 | 1504 | ||
| 1505 | ready: | ||
| 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 | /*-------------------------------------------------------------------------*/ |
