[RFC][PATCH] ehci: make ISO schedule immune to long irq delay

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Ming Lei <tom.leiming@xxxxxxxxx>

The current ehci ISO schedule only supports that the max irq delay
for ehci is 20ms(see 'if (excess >= mod - 2 * SCHEDULE_SLOP)' in
iso_stream_schedule). And if ehci irq is disabled for longer time
than 20ms, ehci ISO schedule will behave badly and cause
failure of "request %p would overflow".

This patch uses kernel time to check if iso schedule was handled
late, and fixes the problem.

Certainly, the problem can be fixed by increasing the allowable
delay, such as:

	if (excess >= mod - N * SCHEDULE_SLOP)	/*iso_stream_schedule*/

and take a larger value of N than 2, but the fix is not feasible
enough, also may decrease the allowable ISO schedule window, especially
for small periodic size case(such as, 256 and 512).

The method in this patch can fix all the above shortcomings, and the
only drawback is that it may introduce extra computation on ktime.

Signed-off-by: Ming Lei <tom.leiming@xxxxxxxxx>
---
 drivers/usb/host/ehci-sched.c |   17 +++++++++++++++--
 drivers/usb/host/ehci.h       |    1 +
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 6c9fbe3..1846cbe 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1432,16 +1432,17 @@ iso_stream_schedule (
 		else
 			next = now;
 
-		/* Fell behind (by up to twice the slop amount)?
+		/* Fell behind (by up to any time)
 		 * We decide based on the time of the last currently-scheduled
 		 * slot, not the time of the next available slot.
 		 */
 		excess = (stream->next_uframe - period - next) & (mod - 1);
-		if (excess >= mod - 2 * SCHEDULE_SLOP)
+		if (ktime_us_delta(stream->next_ktime, ktime_get()) < 0)
 			start = next + excess - mod + period *
 					DIV_ROUND_UP(mod - excess, period);
 		else
 			start = next + excess + period;
+
 		if (start - now >= mod) {
 			ehci_dbg(ehci, "request %p would overflow (%d+%d >= %d)\n",
 					urb, start - now - period, period,
@@ -1591,6 +1592,17 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
 	*hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
 }
 
+static void get_next_uframe_ktime(struct ehci_hcd *ehci,
+	struct ehci_iso_stream	*stream)
+{
+	unsigned	mod = ehci->periodic_size << 3;
+	u32 		now =
+		ehci_readl(ehci, &ehci->regs->frame_index) & (mod - 1);
+
+	stream->next_ktime = ktime_add_us(ktime_get(),
+			((stream->next_uframe - now) & (mod - 1)) * 125);
+}
+
 /* fit urb's itds into the selected schedule slot; activate as needed */
 static int
 itd_link_urb (
@@ -1658,6 +1670,7 @@ itd_link_urb (
 		}
 	}
 	stream->next_uframe = next_uframe;
+	get_next_uframe_ktime(ehci, stream);
 
 	/* don't need that schedule data any more */
 	iso_sched_free (stream, iso_sched);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index bd6ff48..a46054a 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -417,6 +417,7 @@ struct ehci_iso_stream {
 
 	/* output of (re)scheduling */
 	int			next_uframe;
+	ktime_t			next_ktime;
 	__hc32			splits;
 
 	/* the rest is derived from the endpoint descriptor,
-- 
1.7.4.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux