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.c30
1 files changed, 20 insertions, 10 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 84079ebbe656..1e391e624c8a 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1394,10 +1394,11 @@ iso_stream_schedule (
1394 struct ehci_iso_stream *stream 1394 struct ehci_iso_stream *stream
1395) 1395)
1396{ 1396{
1397 u32 now, start, max, period; 1397 u32 now, next, start, period;
1398 int status; 1398 int status;
1399 unsigned mod = ehci->periodic_size << 3; 1399 unsigned mod = ehci->periodic_size << 3;
1400 struct ehci_iso_sched *sched = urb->hcpriv; 1400 struct ehci_iso_sched *sched = urb->hcpriv;
1401 struct pci_dev *pdev;
1401 1402
1402 if (sched->span > (mod - SCHEDULE_SLOP)) { 1403 if (sched->span > (mod - SCHEDULE_SLOP)) {
1403 ehci_dbg (ehci, "iso request %p too long\n", urb); 1404 ehci_dbg (ehci, "iso request %p too long\n", urb);
@@ -1418,26 +1419,35 @@ iso_stream_schedule (
1418 1419
1419 now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; 1420 now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
1420 1421
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. 1422 /* Typical case: reuse current schedule, stream is still active.
1425 * Hopefully there are no gaps from the host falling behind 1423 * Hopefully there are no gaps from the host falling behind
1426 * (irq delays etc), but if there are we'll take the next 1424 * (irq delays etc), but if there are we'll take the next
1427 * slot in the schedule, implicitly assuming URB_ISO_ASAP. 1425 * slot in the schedule, implicitly assuming URB_ISO_ASAP.
1428 */ 1426 */
1429 if (likely (!list_empty (&stream->td_list))) { 1427 if (likely (!list_empty (&stream->td_list))) {
1428 pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
1430 start = stream->next_uframe; 1429 start = stream->next_uframe;
1431 if (start < now) 1430
1432 start += mod; 1431 /* For high speed devices, allow scheduling within the
1432 * isochronous scheduling threshold. For full speed devices,
1433 * don't. (Work around for Intel ICH9 bug.)
1434 */
1435 if (!stream->highspeed &&
1436 pdev->vendor == PCI_VENDOR_ID_INTEL)
1437 next = now + ehci->i_thresh;
1438 else
1439 next = now;
1433 1440
1434 /* Fell behind (by up to twice the slop amount)? */ 1441 /* Fell behind (by up to twice the slop amount)? */
1435 if (start >= max - 2 * SCHEDULE_SLOP) 1442 if (((start - next) & (mod - 1)) >=
1443 mod - 2 * SCHEDULE_SLOP)
1436 start += period * DIV_ROUND_UP( 1444 start += period * DIV_ROUND_UP(
1437 max - start, period) - mod; 1445 (next - start) & (mod - 1),
1446 period);
1438 1447
1439 /* Tried to schedule too far into the future? */ 1448 /* Tried to schedule too far into the future? */
1440 if (unlikely((start + sched->span) >= max)) { 1449 if (unlikely(((start - now) & (mod - 1)) + sched->span
1450 >= mod - 2 * SCHEDULE_SLOP)) {
1441 status = -EFBIG; 1451 status = -EFBIG;
1442 goto fail; 1452 goto fail;
1443 } 1453 }
@@ -1482,7 +1492,7 @@ iso_stream_schedule (
1482 /* no room in the schedule */ 1492 /* no room in the schedule */
1483 ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", 1493 ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n",
1484 list_empty (&stream->td_list) ? "" : "re", 1494 list_empty (&stream->td_list) ? "" : "re",
1485 urb, now, max); 1495 urb, now, now + mod);
1486 status = -ENOSPC; 1496 status = -ENOSPC;
1487 1497
1488fail: 1498fail: