From 4005ad4390bf698e3bdae9567e79242ec0584097 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Mon, 1 Oct 2012 10:32:01 -0400 Subject: [PATCH] EHCI: implement new semantics for URB_ISO_ASAP This patch (as1612) updates the isochronous scheduling and processing in ehci-hcd to match the new semantics for URB_ISO_ASAP. It also adds a missing "unlikely" in sitd_complete() to match the corresponding statement in itd_complete(), and it increments urb->error_count in a couple of places that had been overlooked. Signed-off-by: Alan Stern Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-sched.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index e08e65d8e004..b538a4d62d5e 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -1386,8 +1386,8 @@ iso_stream_schedule ( /* Typical case: reuse current schedule, stream is still active. * Hopefully there are no gaps from the host falling behind - * (irq delays etc), but if there are we'll take the next - * slot in the schedule, implicitly assuming URB_ISO_ASAP. + * (irq delays etc). If there are, the behavior depends on + * whether URB_ISO_ASAP is set. */ if (likely (!list_empty (&stream->td_list))) { @@ -1414,9 +1414,25 @@ iso_stream_schedule ( goto fail; } - /* Behind the scheduling threshold? Assume URB_ISO_ASAP. */ - if (unlikely(start < next)) - start += (next - start + period - 1) & (- period); + /* Behind the scheduling threshold? */ + if (unlikely(start < next)) { + + /* USB_ISO_ASAP: Round up to the first available slot */ + if (urb->transfer_flags & URB_ISO_ASAP) + start += (next - start + period - 1) & -period; + + /* + * Not ASAP: Use the next slot in the stream. If + * the entire URB falls before the threshold, fail. + */ + else if (start + span - period < next) { + ehci_dbg(ehci, "iso urb late %p (%u+%u < %u)\n", + urb, start + base, + span - period, next + base); + status = -EXDEV; + goto fail; + } + } start += base; } @@ -1699,7 +1715,7 @@ static bool itd_complete(struct ehci_hcd *ehci, struct ehci_itd *itd) urb->actual_length += desc->actual_length; } else { /* URB was too late */ - desc->status = -EXDEV; + urb->error_count++; } } @@ -2072,7 +2088,7 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) t = hc32_to_cpup(ehci, &sitd->hw_results); /* report transfer status */ - if (t & SITD_ERRS) { + if (unlikely(t & SITD_ERRS)) { urb->error_count++; if (t & SITD_STS_DBE) desc->status = usb_pipein (urb->pipe) @@ -2082,6 +2098,9 @@ static bool sitd_complete(struct ehci_hcd *ehci, struct ehci_sitd *sitd) desc->status = -EOVERFLOW; else /* XACT, MMF, etc */ desc->status = -EPROTO; + } else if (unlikely(t & SITD_STS_ACTIVE)) { + /* URB was too late */ + urb->error_count++; } else { desc->status = 0; desc->actual_length = desc->length - SITD_LENGTH(t); -- 2.39.5