aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-07-14 11:03:46 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-08-10 17:35:40 -0400
commitffda080353979273e8aa69fc1e6134f20643ae56 (patch)
tree3d4981380afc2123e906a85948c20a299c4a52bf /drivers/usb/host/ehci-sched.c
parentbccbefaae050186bed3bcc74b1fd1a9b8c6710b2 (diff)
USB: EHCI: add missing frame -> microframe conversion
This patch (as1407) fixes a bug in ehci-hcd's isochronous scheduler. All its calculations should be done in terms of microframes, but for full-speed devices, sched->span is stored in frames. It needs to be converted. This fix is liable to expose problems in other drivers. The old code would accept URBs that should not have been accepted, so drivers have had no reason to avoid submitting URBs that exceeded the maximum schedule length. In an attempt to partially compensate for this, the patch also adjusts the schedule length from a minimum of 256 frames up to a minimum of 512 frames. 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/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 27dd841b9aa2..dd37350170bb 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1395,28 +1395,31 @@ iso_stream_schedule (
1395 struct ehci_iso_stream *stream 1395 struct ehci_iso_stream *stream
1396) 1396)
1397{ 1397{
1398 u32 now, next, start, period; 1398 u32 now, next, start, period, span;
1399 int status; 1399 int status;
1400 unsigned mod = ehci->periodic_size << 3; 1400 unsigned mod = ehci->periodic_size << 3;
1401 struct ehci_iso_sched *sched = urb->hcpriv; 1401 struct ehci_iso_sched *sched = urb->hcpriv;
1402 1402
1403 if (sched->span > (mod - SCHEDULE_SLOP)) { 1403 period = urb->interval;
1404 span = sched->span;
1405 if (!stream->highspeed) {
1406 period <<= 3;
1407 span <<= 3;
1408 }
1409
1410 if (span > mod - SCHEDULE_SLOP) {
1404 ehci_dbg (ehci, "iso request %p too long\n", urb); 1411 ehci_dbg (ehci, "iso request %p too long\n", urb);
1405 status = -EFBIG; 1412 status = -EFBIG;
1406 goto fail; 1413 goto fail;
1407 } 1414 }
1408 1415
1409 if ((stream->depth + sched->span) > mod) { 1416 if (stream->depth + span > mod) {
1410 ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n", 1417 ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
1411 urb, stream->depth, sched->span, mod); 1418 urb, stream->depth, span, mod);
1412 status = -EFBIG; 1419 status = -EFBIG;
1413 goto fail; 1420 goto fail;
1414 } 1421 }
1415 1422
1416 period = urb->interval;
1417 if (!stream->highspeed)
1418 period <<= 3;
1419
1420 now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1); 1423 now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
1421 1424
1422 /* Typical case: reuse current schedule, stream is still active. 1425 /* Typical case: reuse current schedule, stream is still active.
@@ -1445,7 +1448,7 @@ iso_stream_schedule (
1445 period); 1448 period);
1446 1449
1447 /* Tried to schedule too far into the future? */ 1450 /* Tried to schedule too far into the future? */
1448 if (unlikely(((start - now) & (mod - 1)) + sched->span 1451 if (unlikely(((start - now) & (mod - 1)) + span
1449 >= mod - 2 * SCHEDULE_SLOP)) { 1452 >= mod - 2 * SCHEDULE_SLOP)) {
1450 status = -EFBIG; 1453 status = -EFBIG;
1451 goto fail; 1454 goto fail;