浏览代码

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>
Alan Stern 15 年之前
父节点
当前提交
ffda080353
共有 2 个文件被更改,包括 19 次插入10 次删除
  1. 7 1
      drivers/usb/host/ehci-hcd.c
  2. 12 9
      drivers/usb/host/ehci-sched.c

+ 7 - 1
drivers/usb/host/ehci-hcd.c

@@ -79,7 +79,13 @@ static const char	hcd_name [] = "ehci_hcd";
 #define	EHCI_TUNE_RL_TT		0
 #define	EHCI_TUNE_RL_TT		0
 #define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
 #define	EHCI_TUNE_MULT_HS	1	/* 1-3 transactions/uframe; 4.10.3 */
 #define	EHCI_TUNE_MULT_TT	1
 #define	EHCI_TUNE_MULT_TT	1
-#define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
+/*
+ * Some drivers think it's safe to schedule isochronous transfers more than
+ * 256 ms into the future (partly as a result of an old bug in the scheduling
+ * code).  In an attempt to avoid trouble, we will use a minimum scheduling
+ * length of 512 frames instead of 256.
+ */
+#define	EHCI_TUNE_FLS		1	/* (medium) 512-frame schedule */
 
 
 #define EHCI_IAA_MSECS		10		/* arbitrary */
 #define EHCI_IAA_MSECS		10		/* arbitrary */
 #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
 #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */

+ 12 - 9
drivers/usb/host/ehci-sched.c

@@ -1395,28 +1395,31 @@ iso_stream_schedule (
 	struct ehci_iso_stream	*stream
 	struct ehci_iso_stream	*stream
 )
 )
 {
 {
-	u32			now, next, start, period;
+	u32			now, next, start, period, span;
 	int			status;
 	int			status;
 	unsigned		mod = ehci->periodic_size << 3;
 	unsigned		mod = ehci->periodic_size << 3;
 	struct ehci_iso_sched	*sched = urb->hcpriv;
 	struct ehci_iso_sched	*sched = urb->hcpriv;
 
 
-	if (sched->span > (mod - SCHEDULE_SLOP)) {
+	period = urb->interval;
+	span = sched->span;
+	if (!stream->highspeed) {
+		period <<= 3;
+		span <<= 3;
+	}
+
+	if (span > mod - SCHEDULE_SLOP) {
 		ehci_dbg (ehci, "iso request %p too long\n", urb);
 		ehci_dbg (ehci, "iso request %p too long\n", urb);
 		status = -EFBIG;
 		status = -EFBIG;
 		goto fail;
 		goto fail;
 	}
 	}
 
 
-	if ((stream->depth + sched->span) > mod) {
+	if (stream->depth + span > mod) {
 		ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
 		ehci_dbg (ehci, "request %p would overflow (%d+%d>%d)\n",
-			urb, stream->depth, sched->span, mod);
+			urb, stream->depth, span, mod);
 		status = -EFBIG;
 		status = -EFBIG;
 		goto fail;
 		goto fail;
 	}
 	}
 
 
-	period = urb->interval;
-	if (!stream->highspeed)
-		period <<= 3;
-
 	now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
 	now = ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
 
 
 	/* Typical case: reuse current schedule, stream is still active.
 	/* Typical case: reuse current schedule, stream is still active.
@@ -1445,7 +1448,7 @@ iso_stream_schedule (
 					period);
 					period);
 
 
 		/* Tried to schedule too far into the future? */
 		/* Tried to schedule too far into the future? */
-		if (unlikely(((start - now) & (mod - 1)) + sched->span
+		if (unlikely(((start - now) & (mod - 1)) + span
 					>= mod - 2 * SCHEDULE_SLOP)) {
 					>= mod - 2 * SCHEDULE_SLOP)) {
 			status = -EFBIG;
 			status = -EFBIG;
 			goto fail;
 			goto fail;