summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2010-01-08 11:17:55 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-01-28 15:20:34 -0800
commit5b3363926eed5839fdc84055d20f9153980d4b5f (patch)
treecf5efcde79ac42a5d5325a3946337dd15c2c3b8d
parent29691f9ead70fb43b39defe6503e2a8e1de12dad (diff)
USB: EHCI: fix handling of unusual interrupt intervals
commit 1b9a38bfa6e664ff02511314f5586d711c83cc91 upstream. This patch (as1320) fixes two problems related to interrupt-URB scheduling in ehci-hcd. URBs with an interval of 2 or 4 microframes aren't handled. For the time being, the patch reduces to interval to 1 uframe. URBs are constrained to have an interval no larger than 1024 frames by usb_submit_urb(). But some EHCI controllers allow use of a schedule as short as 256 frames; for these controllers we may have to decrease the interval to the actual schedule length. The second problem isn't very significant since few devices expose interrupt endpoints with an interval larger than 256 frames. But the first problem is critical; it will prevent the kernel from working with devices having interrupt intervals of 2 or 4 uframes. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Tested-by: Glynn Farrow <farrowg@sg.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/ehci-q.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 01132ac74eb8..097dd557a929 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -748,9 +748,10 @@ qh_make (
* But interval 1 scheduling is simpler, and
* includes high bandwidth.
*/
- dbg ("intr period %d uframes, NYET!",
- urb->interval);
- goto done;
+ urb->interval = 1;
+ } else if (qh->period > ehci->periodic_size) {
+ qh->period = ehci->periodic_size;
+ urb->interval = qh->period << 3;
}
} else {
int think_time;
@@ -773,6 +774,10 @@ qh_make (
usb_calc_bus_time (urb->dev->speed,
is_input, 0, max_packet (maxp)));
qh->period = urb->interval;
+ if (qh->period > ehci->periodic_size) {
+ qh->period = ehci->periodic_size;
+ urb->interval = qh->period;
+ }
}
}