Re: [RFC 3/3] EHCI: handle late isochronous submissions

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

 



On Wed, 28 Aug 2013 12:23:31 -0400 (EDT)
Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> wrote:

> You must never alter ehci->last_iso_frame like this.  It violates the 
> driver's invariants for time to run "backward".  After all, there may 
> already be other TDs scheduled for the frames you are about to scan 
> again; they mustn't get scanned until the frame pointer has wrapped 
> around.
> 
> This last problem in particular means your proposal can't be accepted.

On Thu, Aug 29, 2013 at 8:43 AM, Ming Lei <tom.leiming@xxxxxxxxx> wrote:
> No, no other TDs scheduled for the frames since the queue is empty
> when iso_stream_rebase is running.

The above isn't true, but no rescan on other TDs introduced:

- suppose URB0 is scheduled via stream0 when underrun without ISO_ASAP

- iso_stream_rebase() find that stream0->next_uframe is behind
  ehci->last_iso_frame but URB0 isn't completed before
  ehci->last_iso_frame, then adjust it as stream0->next_uframe >> 3,
  and record its old value as ehci->last_iso_frame'.

- when next ehci irq comes, scan_isoc() scans from stream0->next_uframe
to 'now', and the extra scan introduced by iso_stream_rebase() is from
stream0->next_uframe to ehci->last_iso_frame' - 1, during this period,
only TDs belonged to undrun URBs without ISO_ASAP will scanned, and no
other TDs scheduled in these frames at all.(ehci->last_iso_frame doesn't
affect schedule, only decides start point of the next scan)

So no sort of run 'backward' things, and URBs are always completed in
time order, aren't they?

Below patch is modified according to your comment.

 drivers/usb/host/ehci-sched.c |   55 ++++++++++++++++++++++++++++++++++++++---
 drivers/usb/host/ehci.h       |    1 +
 2 files changed, 53 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 83be03f..80da5fd 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1370,6 +1370,35 @@ sitd_slot_ok (
 	return 1;
 }
 
+/* rebase in case of underun without ISO_ASAP together */
+static int iso_stream_rebase(struct ehci_hcd *ehci, struct urb *urb,
+		struct ehci_iso_stream	*stream, u32 span, u32 period)
+{
+	u32 start, size;
+	u32 mod = ehci->periodic_size;
+
+	if (ehci->last_base == -1)
+		return 0;
+
+	start = stream->next_uframe >> 3;
+	size = (ehci->last_iso_frame - ehci->last_base) & (mod - 1);
+
+	/* if the URB should have been started */
+	if (size > ((start - ehci->last_base) & (mod - 1))) {
+		/* if the URB should have been completed now */
+		size = (ehci->last_iso_frame - start) & (mod - 1);
+		if (size > ((span - period) & (mod - 1))) {
+			int i;
+			for (i = 0; i < urb->number_of_packets; i++)
+				urb->iso_frame_desc[i].status = -EXDEV;
+			return 1;
+		}
+		ehci->last_iso_frame = start & (mod - 1);
+	}
+
+	return 0;
+}
+
 /*
  * This scheduler plans almost as far into the future as it has actual
  * periodic schedule slots.  (Affected by TUNE_FLS, which defaults to
@@ -1409,7 +1438,9 @@ iso_stream_schedule (
 	 * (irq delays etc).  If there are, the behavior depends on
 	 * whether URB_ISO_ASAP is set.
 	 */
-	if (likely (!list_empty (&stream->td_list))) {
+	if (likely (!list_empty (&stream->td_list) ||
+				hcd_complete_in_progress(
+				ehci_to_hcd(ehci), urb))) {
 
 		/* Take the isochronous scheduling threshold into account */
 		if (ehci->i_thresh)
@@ -1417,6 +1448,14 @@ iso_stream_schedule (
 		else
 			next = (now + 2 + 7) & ~0x07;	/* full frame cache */
 
+		if (list_empty(&stream->td_list) &&
+				!(urb->transfer_flags & URB_ISO_ASAP))
+			if (iso_stream_rebase(ehci, urb, stream, span,
+					period)) {
+				status = 1;
+				goto fail;
+			}
+
 		/*
 		 * Use ehci->last_iso_frame as the base.  There can't be any
 		 * TDs scheduled for earlier than that.
@@ -1517,6 +1556,7 @@ iso_stream_schedule (
 	/* Make sure scan_isoc() sees these */
 	if (ehci->isoc_count == 0)
 		ehci->last_iso_frame = now >> 3;
+	ehci->last_base = -1;
 	return 0;
 
  fail:
@@ -1838,7 +1878,10 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
 	status = iso_stream_schedule(ehci, urb, stream);
 	if (likely (status == 0))
 		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
-	else
+	else if (status > 0) {
+		ehci_urb_done(ehci, urb, 0);
+		status = 0;
+	} else
 		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
  done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
@@ -2224,7 +2267,10 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
 	status = iso_stream_schedule(ehci, urb, stream);
 	if (status == 0)
 		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
-	else
+	else if (status > 0) {
+		ehci_urb_done(ehci, urb, 0);
+		status = 0;
+	} else
 		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
  done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
@@ -2255,6 +2301,9 @@ static void scan_isoc(struct ehci_hcd *ehci)
 	}
 	ehci->now_frame = now_frame;
 
+	if (ehci->last_base == -1)
+		ehci->last_base = ehci->last_iso_frame;
+
 	frame = ehci->last_iso_frame;
 	for (;;) {
 		union ehci_shadow	q, *q_p;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 2822e79..279e182 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -149,6 +149,7 @@ struct ehci_hcd {			/* one per controller */
 	unsigned		intr_unlink_wait_cycle;
 	unsigned		intr_unlink_cycle;
 	unsigned		now_frame;	/* frame from HC hardware */
+	unsigned		last_base;	/* previous 'last_iso_frame' */
 	unsigned		last_iso_frame;	/* last frame scanned for iso */
 	unsigned		intr_count;	/* intr activity count */
 	unsigned		isoc_count;	/* isoc activity count */


Thanks,
-- 
Ming Lei
--
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