diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2010-07-14 11:03:53 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-10 17:35:40 -0400 |
commit | 1fb2e0558781b07d2ecaabf94c81c17ac820d8f0 (patch) | |
tree | b06dfa7e482664070e688d1b8b2e4e2113dc9099 /drivers/usb | |
parent | ffda080353979273e8aa69fc1e6134f20643ae56 (diff) |
USB: EHCI: reorganize isochronous scheduler routine
This patch (as1408) rearranges the scheduling code in ehci-hcd, partly
to improve its structure, but mainly to change the way it works.
Whether or not a transfer exceeds the hardware schedule length will
now be determined by looking at the last frame the transfer would use,
instead of the first available frame following the end of the transfer.
The benefit of this change is that it allows the driver to accept
valid URBs which would otherwise be rejected. For example, suppose
the schedule length is 1024 frames, the endpoint period is 256 frames,
and a four-packet URB is submitted. The four transfers would occupy
slots that are 0, 256, 512, and 768 frames past the current frame
(plus an extra slop factor). These don't exceed the 1024-frame limit,
so the URB should be accepted. But the current code notices that the
next available slot would be 1024 frames (plus slop) in the future,
which is beyond the limit, and so the URB is rejected unnecessarily.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: David Brownell <david-b@pacbell.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-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 | /*-------------------------------------------------------------------------*/ |