diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 182 |
1 files changed, 85 insertions, 97 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 805ec633a652..a92526d6e5ae 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -880,8 +880,7 @@ static int intr_submit ( | |||
880 | 880 | ||
881 | spin_lock_irqsave (&ehci->lock, flags); | 881 | spin_lock_irqsave (&ehci->lock, flags); |
882 | 882 | ||
883 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, | 883 | if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { |
884 | &ehci_to_hcd(ehci)->flags))) { | ||
885 | status = -ESHUTDOWN; | 884 | status = -ESHUTDOWN; |
886 | goto done_not_linked; | 885 | goto done_not_linked; |
887 | } | 886 | } |
@@ -1075,15 +1074,6 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream) | |||
1075 | if (stream->ep) | 1074 | if (stream->ep) |
1076 | stream->ep->hcpriv = NULL; | 1075 | stream->ep->hcpriv = NULL; |
1077 | 1076 | ||
1078 | if (stream->rescheduled) { | ||
1079 | ehci_info (ehci, "ep%d%s-iso rescheduled " | ||
1080 | "%lu times in %lu seconds\n", | ||
1081 | stream->bEndpointAddress, is_in ? "in" : "out", | ||
1082 | stream->rescheduled, | ||
1083 | ((jiffies - stream->start)/HZ) | ||
1084 | ); | ||
1085 | } | ||
1086 | |||
1087 | kfree(stream); | 1077 | kfree(stream); |
1088 | } | 1078 | } |
1089 | } | 1079 | } |
@@ -1396,30 +1386,25 @@ iso_stream_schedule ( | |||
1396 | struct ehci_iso_stream *stream | 1386 | struct ehci_iso_stream *stream |
1397 | ) | 1387 | ) |
1398 | { | 1388 | { |
1399 | u32 now, next, start, period; | 1389 | u32 now, next, start, period, span; |
1400 | int status; | 1390 | int status; |
1401 | unsigned mod = ehci->periodic_size << 3; | 1391 | unsigned mod = ehci->periodic_size << 3; |
1402 | struct ehci_iso_sched *sched = urb->hcpriv; | 1392 | struct ehci_iso_sched *sched = urb->hcpriv; |
1403 | struct pci_dev *pdev; | ||
1404 | 1393 | ||
1405 | if (sched->span > (mod - SCHEDULE_SLOP)) { | 1394 | period = urb->interval; |
1406 | ehci_dbg (ehci, "iso request %p too long\n", urb); | 1395 | span = sched->span; |
1407 | status = -EFBIG; | 1396 | if (!stream->highspeed) { |
1408 | goto fail; | 1397 | period <<= 3; |
1398 | span <<= 3; | ||
1409 | } | 1399 | } |
1410 | 1400 | ||
1411 | if ((stream->depth + sched->span) > mod) { | 1401 | if (span > mod - SCHEDULE_SLOP) { |
1412 | ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n", | 1402 | ehci_dbg (ehci, "iso request %p too long\n", urb); |
1413 | urb, stream->depth, sched->span, mod); | ||
1414 | status = -EFBIG; | 1403 | status = -EFBIG; |
1415 | goto fail; | 1404 | goto fail; |
1416 | } | 1405 | } |
1417 | 1406 | ||
1418 | period = urb->interval; | 1407 | now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1); |
1419 | if (!stream->highspeed) | ||
1420 | period <<= 3; | ||
1421 | |||
1422 | now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; | ||
1423 | 1408 | ||
1424 | /* Typical case: reuse current schedule, stream is still active. | 1409 | /* Typical case: reuse current schedule, stream is still active. |
1425 | * Hopefully there are no gaps from the host falling behind | 1410 | * Hopefully there are no gaps from the host falling behind |
@@ -1427,34 +1412,35 @@ iso_stream_schedule ( | |||
1427 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. | 1412 | * slot in the schedule, implicitly assuming URB_ISO_ASAP. |
1428 | */ | 1413 | */ |
1429 | if (likely (!list_empty (&stream->td_list))) { | 1414 | if (likely (!list_empty (&stream->td_list))) { |
1430 | pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller); | 1415 | u32 excess; |
1431 | start = stream->next_uframe; | ||
1432 | 1416 | ||
1433 | /* For high speed devices, allow scheduling within the | 1417 | /* For high speed devices, allow scheduling within the |
1434 | * isochronous scheduling threshold. For full speed devices, | 1418 | * isochronous scheduling threshold. For full speed devices |
1435 | * don't. (Work around for Intel ICH9 bug.) | 1419 | * and Intel PCI-based controllers, don't (work around for |
1420 | * Intel ICH9 bug). | ||
1436 | */ | 1421 | */ |
1437 | if (!stream->highspeed && | 1422 | if (!stream->highspeed && ehci->fs_i_thresh) |
1438 | pdev->vendor == PCI_VENDOR_ID_INTEL) | ||
1439 | next = now + ehci->i_thresh; | 1423 | next = now + ehci->i_thresh; |
1440 | else | 1424 | else |
1441 | next = now; | 1425 | next = now; |
1442 | 1426 | ||
1443 | /* Fell behind (by up to twice the slop amount)? */ | 1427 | /* Fell behind (by up to twice the slop amount)? |
1444 | if (((start - next) & (mod - 1)) >= | 1428 | * We decide based on the time of the last currently-scheduled |
1445 | mod - 2 * SCHEDULE_SLOP) | 1429 | * slot, not the time of the next available slot. |
1446 | start += period * DIV_ROUND_UP( | 1430 | */ |
1447 | (next - start) & (mod - 1), | 1431 | excess = (stream->next_uframe - period - next) & (mod - 1); |
1448 | period); | 1432 | if (excess >= mod - 2 * SCHEDULE_SLOP) |
1449 | 1433 | start = next + excess - mod + period * | |
1450 | /* Tried to schedule too far into the future? */ | 1434 | DIV_ROUND_UP(mod - excess, period); |
1451 | if (unlikely(((start - now) & (mod - 1)) + sched->span | 1435 | else |
1452 | >= mod - 2 * SCHEDULE_SLOP)) { | 1436 | start = next + excess + period; |
1437 | if (start - now >= mod) { | ||
1438 | ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", | ||
1439 | urb, start - now - period, period, | ||
1440 | mod); | ||
1453 | status = -EFBIG; | 1441 | status = -EFBIG; |
1454 | goto fail; | 1442 | goto fail; |
1455 | } | 1443 | } |
1456 | stream->next_uframe = start; | ||
1457 | goto ready; | ||
1458 | } | 1444 | } |
1459 | 1445 | ||
1460 | /* need to schedule; when's the next (u)frame we could start? | 1446 | /* need to schedule; when's the next (u)frame we could start? |
@@ -1463,51 +1449,60 @@ iso_stream_schedule ( | |||
1463 | * can also help high bandwidth if the dma and irq loads don't | 1449 | * can also help high bandwidth if the dma and irq loads don't |
1464 | * jump until after the queue is primed. | 1450 | * jump until after the queue is primed. |
1465 | */ | 1451 | */ |
1466 | start = SCHEDULE_SLOP + (now & ~0x07); | 1452 | else { |
1467 | start %= mod; | 1453 | start = SCHEDULE_SLOP + (now & ~0x07); |
1468 | stream->next_uframe = start; | 1454 | |
1469 | 1455 | /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ | |
1470 | /* NOTE: assumes URB_ISO_ASAP, to limit complexity/bugs */ | 1456 | |
1471 | 1457 | /* find a uframe slot with enough bandwidth */ | |
1472 | /* find a uframe slot with enough bandwidth */ | 1458 | next = start + period; |
1473 | for (; start < (stream->next_uframe + period); start++) { | 1459 | for (; start < next; start++) { |
1474 | int enough_space; | 1460 | |
1475 | 1461 | /* check schedule: enough space? */ | |
1476 | /* check schedule: enough space? */ | 1462 | if (stream->highspeed) { |
1477 | if (stream->highspeed) | 1463 | if (itd_slot_ok(ehci, mod, start, |
1478 | enough_space = itd_slot_ok (ehci, mod, start, | 1464 | stream->usecs, period)) |
1479 | stream->usecs, period); | 1465 | break; |
1480 | else { | 1466 | } else { |
1481 | if ((start % 8) >= 6) | 1467 | if ((start % 8) >= 6) |
1482 | continue; | 1468 | continue; |
1483 | enough_space = sitd_slot_ok (ehci, mod, stream, | 1469 | if (sitd_slot_ok(ehci, mod, stream, |
1484 | start, sched, period); | 1470 | start, sched, period)) |
1471 | break; | ||
1472 | } | ||
1485 | } | 1473 | } |
1486 | 1474 | ||
1487 | /* schedule it here if there's enough bandwidth */ | 1475 | /* no room in the schedule */ |
1488 | if (enough_space) { | 1476 | if (start == next) { |
1489 | stream->next_uframe = start % mod; | 1477 | ehci_dbg(ehci, "iso resched full %p (now %d max %d)\n", |
1490 | goto ready; | 1478 | urb, now, now + mod); |
1479 | status = -ENOSPC; | ||
1480 | goto fail; | ||
1491 | } | 1481 | } |
1492 | } | 1482 | } |
1493 | 1483 | ||
1494 | /* no room in the schedule */ | 1484 | /* Tried to schedule too far into the future? */ |
1495 | ehci_dbg (ehci, "iso %ssched full %p (now %d max %d)\n", | 1485 | if (unlikely(start - now + span - period |
1496 | list_empty (&stream->td_list) ? "" : "re", | 1486 | >= mod - 2 * SCHEDULE_SLOP)) { |
1497 | urb, now, now + mod); | 1487 | ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n", |
1498 | status = -ENOSPC; | 1488 | urb, start - now, span - period, |
1489 | mod - 2 * SCHEDULE_SLOP); | ||
1490 | status = -EFBIG; | ||
1491 | goto fail; | ||
1492 | } | ||
1499 | 1493 | ||
1500 | fail: | 1494 | stream->next_uframe = start & (mod - 1); |
1501 | iso_sched_free (stream, sched); | ||
1502 | urb->hcpriv = NULL; | ||
1503 | return status; | ||
1504 | 1495 | ||
1505 | ready: | ||
1506 | /* report high speed start in uframes; full speed, in frames */ | 1496 | /* report high speed start in uframes; full speed, in frames */ |
1507 | urb->start_frame = stream->next_uframe; | 1497 | urb->start_frame = stream->next_uframe; |
1508 | if (!stream->highspeed) | 1498 | if (!stream->highspeed) |
1509 | urb->start_frame >>= 3; | 1499 | urb->start_frame >>= 3; |
1510 | return 0; | 1500 | return 0; |
1501 | |||
1502 | fail: | ||
1503 | iso_sched_free(stream, sched); | ||
1504 | urb->hcpriv = NULL; | ||
1505 | return status; | ||
1511 | } | 1506 | } |
1512 | 1507 | ||
1513 | /*-------------------------------------------------------------------------*/ | 1508 | /*-------------------------------------------------------------------------*/ |
@@ -1602,7 +1597,7 @@ itd_link_urb ( | |||
1602 | struct ehci_iso_sched *iso_sched = urb->hcpriv; | 1597 | struct ehci_iso_sched *iso_sched = urb->hcpriv; |
1603 | struct ehci_itd *itd; | 1598 | struct ehci_itd *itd; |
1604 | 1599 | ||
1605 | next_uframe = stream->next_uframe % mod; | 1600 | next_uframe = stream->next_uframe & (mod - 1); |
1606 | 1601 | ||
1607 | if (unlikely (list_empty(&stream->td_list))) { | 1602 | if (unlikely (list_empty(&stream->td_list))) { |
1608 | ehci_to_hcd(ehci)->self.bandwidth_allocated | 1603 | ehci_to_hcd(ehci)->self.bandwidth_allocated |
@@ -1613,7 +1608,6 @@ itd_link_urb ( | |||
1613 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", | 1608 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", |
1614 | urb->interval, | 1609 | urb->interval, |
1615 | next_uframe >> 3, next_uframe & 0x7); | 1610 | next_uframe >> 3, next_uframe & 0x7); |
1616 | stream->start = jiffies; | ||
1617 | } | 1611 | } |
1618 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; | 1612 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; |
1619 | 1613 | ||
@@ -1639,14 +1633,13 @@ itd_link_urb ( | |||
1639 | itd_patch(ehci, itd, iso_sched, packet, uframe); | 1633 | itd_patch(ehci, itd, iso_sched, packet, uframe); |
1640 | 1634 | ||
1641 | next_uframe += stream->interval; | 1635 | next_uframe += stream->interval; |
1642 | stream->depth += stream->interval; | 1636 | next_uframe &= mod - 1; |
1643 | next_uframe %= mod; | ||
1644 | packet++; | 1637 | packet++; |
1645 | 1638 | ||
1646 | /* link completed itds into the schedule */ | 1639 | /* link completed itds into the schedule */ |
1647 | if (((next_uframe >> 3) != frame) | 1640 | if (((next_uframe >> 3) != frame) |
1648 | || packet == urb->number_of_packets) { | 1641 | || packet == urb->number_of_packets) { |
1649 | itd_link (ehci, frame % ehci->periodic_size, itd); | 1642 | itd_link(ehci, frame & (ehci->periodic_size - 1), itd); |
1650 | itd = NULL; | 1643 | itd = NULL; |
1651 | } | 1644 | } |
1652 | } | 1645 | } |
@@ -1695,7 +1688,6 @@ itd_complete ( | |||
1695 | 1688 | ||
1696 | t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]); | 1689 | t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]); |
1697 | itd->hw_transaction [uframe] = 0; | 1690 | itd->hw_transaction [uframe] = 0; |
1698 | stream->depth -= stream->interval; | ||
1699 | 1691 | ||
1700 | /* report transfer status */ | 1692 | /* report transfer status */ |
1701 | if (unlikely (t & ISO_ERRS)) { | 1693 | if (unlikely (t & ISO_ERRS)) { |
@@ -1815,8 +1807,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, | |||
1815 | 1807 | ||
1816 | /* schedule ... need to lock */ | 1808 | /* schedule ... need to lock */ |
1817 | spin_lock_irqsave (&ehci->lock, flags); | 1809 | spin_lock_irqsave (&ehci->lock, flags); |
1818 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, | 1810 | if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { |
1819 | &ehci_to_hcd(ehci)->flags))) { | ||
1820 | status = -ESHUTDOWN; | 1811 | status = -ESHUTDOWN; |
1821 | goto done_not_linked; | 1812 | goto done_not_linked; |
1822 | } | 1813 | } |
@@ -2024,9 +2015,8 @@ sitd_link_urb ( | |||
2024 | "sched devp %s ep%d%s-iso [%d] %dms/%04x\n", | 2015 | "sched devp %s ep%d%s-iso [%d] %dms/%04x\n", |
2025 | urb->dev->devpath, stream->bEndpointAddress & 0x0f, | 2016 | urb->dev->devpath, stream->bEndpointAddress & 0x0f, |
2026 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", | 2017 | (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out", |
2027 | (next_uframe >> 3) % ehci->periodic_size, | 2018 | (next_uframe >> 3) & (ehci->periodic_size - 1), |
2028 | stream->interval, hc32_to_cpu(ehci, stream->splits)); | 2019 | stream->interval, hc32_to_cpu(ehci, stream->splits)); |
2029 | stream->start = jiffies; | ||
2030 | } | 2020 | } |
2031 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; | 2021 | ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++; |
2032 | 2022 | ||
@@ -2047,13 +2037,12 @@ sitd_link_urb ( | |||
2047 | sitd->urb = urb; | 2037 | sitd->urb = urb; |
2048 | 2038 | ||
2049 | sitd_patch(ehci, stream, sitd, sched, packet); | 2039 | sitd_patch(ehci, stream, sitd, sched, packet); |
2050 | sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size, | 2040 | sitd_link(ehci, (next_uframe >> 3) & (ehci->periodic_size - 1), |
2051 | sitd); | 2041 | sitd); |
2052 | 2042 | ||
2053 | next_uframe += stream->interval << 3; | 2043 | next_uframe += stream->interval << 3; |
2054 | stream->depth += stream->interval << 3; | ||
2055 | } | 2044 | } |
2056 | stream->next_uframe = next_uframe % mod; | 2045 | stream->next_uframe = next_uframe & (mod - 1); |
2057 | 2046 | ||
2058 | /* don't need that schedule data any more */ | 2047 | /* don't need that schedule data any more */ |
2059 | iso_sched_free (stream, sched); | 2048 | iso_sched_free (stream, sched); |
@@ -2111,7 +2100,6 @@ sitd_complete ( | |||
2111 | desc->actual_length = desc->length - SITD_LENGTH(t); | 2100 | desc->actual_length = desc->length - SITD_LENGTH(t); |
2112 | urb->actual_length += desc->actual_length; | 2101 | urb->actual_length += desc->actual_length; |
2113 | } | 2102 | } |
2114 | stream->depth -= stream->interval << 3; | ||
2115 | 2103 | ||
2116 | /* handle completion now? */ | 2104 | /* handle completion now? */ |
2117 | if ((urb_index + 1) != urb->number_of_packets) | 2105 | if ((urb_index + 1) != urb->number_of_packets) |
@@ -2201,8 +2189,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, | |||
2201 | 2189 | ||
2202 | /* schedule ... need to lock */ | 2190 | /* schedule ... need to lock */ |
2203 | spin_lock_irqsave (&ehci->lock, flags); | 2191 | spin_lock_irqsave (&ehci->lock, flags); |
2204 | if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, | 2192 | if (unlikely(!HCD_HW_ACCESSIBLE(ehci_to_hcd(ehci)))) { |
2205 | &ehci_to_hcd(ehci)->flags))) { | ||
2206 | status = -ESHUTDOWN; | 2193 | status = -ESHUTDOWN; |
2207 | goto done_not_linked; | 2194 | goto done_not_linked; |
2208 | } | 2195 | } |
@@ -2263,7 +2250,7 @@ scan_periodic (struct ehci_hcd *ehci) | |||
2263 | now_uframe = ehci->next_uframe; | 2250 | now_uframe = ehci->next_uframe; |
2264 | if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { | 2251 | if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) { |
2265 | clock = ehci_readl(ehci, &ehci->regs->frame_index); | 2252 | clock = ehci_readl(ehci, &ehci->regs->frame_index); |
2266 | clock_frame = (clock >> 3) % ehci->periodic_size; | 2253 | clock_frame = (clock >> 3) & (ehci->periodic_size - 1); |
2267 | } else { | 2254 | } else { |
2268 | clock = now_uframe + mod - 1; | 2255 | clock = now_uframe + mod - 1; |
2269 | clock_frame = -1; | 2256 | clock_frame = -1; |
@@ -2272,7 +2259,7 @@ scan_periodic (struct ehci_hcd *ehci) | |||
2272 | free_cached_lists(ehci); | 2259 | free_cached_lists(ehci); |
2273 | ehci->clock_frame = clock_frame; | 2260 | ehci->clock_frame = clock_frame; |
2274 | } | 2261 | } |
2275 | clock %= mod; | 2262 | clock &= mod - 1; |
2276 | clock_frame = clock >> 3; | 2263 | clock_frame = clock >> 3; |
2277 | 2264 | ||
2278 | for (;;) { | 2265 | for (;;) { |
@@ -2361,7 +2348,7 @@ restart: | |||
2361 | * frame is current. | 2348 | * frame is current. |
2362 | */ | 2349 | */ |
2363 | if (((frame == clock_frame) || | 2350 | if (((frame == clock_frame) || |
2364 | (((frame + 1) % ehci->periodic_size) | 2351 | (((frame + 1) & (ehci->periodic_size - 1)) |
2365 | == clock_frame)) | 2352 | == clock_frame)) |
2366 | && live | 2353 | && live |
2367 | && (q.sitd->hw_results & | 2354 | && (q.sitd->hw_results & |
@@ -2428,7 +2415,8 @@ restart: | |||
2428 | || ehci->periodic_sched == 0) | 2415 | || ehci->periodic_sched == 0) |
2429 | break; | 2416 | break; |
2430 | ehci->next_uframe = now_uframe; | 2417 | ehci->next_uframe = now_uframe; |
2431 | now = ehci_readl(ehci, &ehci->regs->frame_index) % mod; | 2418 | now = ehci_readl(ehci, &ehci->regs->frame_index) & |
2419 | (mod - 1); | ||
2432 | if (now_uframe == now) | 2420 | if (now_uframe == now) |
2433 | break; | 2421 | break; |
2434 | 2422 | ||
@@ -2441,7 +2429,7 @@ restart: | |||
2441 | } | 2429 | } |
2442 | } else { | 2430 | } else { |
2443 | now_uframe++; | 2431 | now_uframe++; |
2444 | now_uframe %= mod; | 2432 | now_uframe &= mod - 1; |
2445 | } | 2433 | } |
2446 | } | 2434 | } |
2447 | } | 2435 | } |