diff options
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index 1e391e624c8a..a0aaaaff2560 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -510,6 +510,8 @@ static int disable_periodic (struct ehci_hcd *ehci) ehci_writel(ehci, cmd, &ehci->regs->command); /* posted write ... */ + free_cached_itd_list(ehci); + ehci->next_uframe = -1; return 0; } @@ -1121,8 +1123,8 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb) urb->interval); } - /* if dev->ep [epnum] is a QH, info1.maxpacket is nonzero */ - } else if (unlikely (stream->hw_info1 != 0)) { + /* if dev->ep [epnum] is a QH, hw is set */ + } else if (unlikely (stream->hw != NULL)) { ehci_dbg (ehci, "dev %s ep%d%s, not iso??\n", urb->dev->devpath, epnum, usb_pipein(urb->pipe) ? "in" : "out"); @@ -1563,13 +1565,27 @@ itd_patch( static inline void itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd) { - /* always prepend ITD/SITD ... only QH tree is order-sensitive */ - itd->itd_next = ehci->pshadow [frame]; - itd->hw_next = ehci->periodic [frame]; - ehci->pshadow [frame].itd = itd; + union ehci_shadow *prev = &ehci->pshadow[frame]; + __hc32 *hw_p = &ehci->periodic[frame]; + union ehci_shadow here = *prev; + __hc32 type = 0; + + /* skip any iso nodes which might belong to previous microframes */ + while (here.ptr) { + type = Q_NEXT_TYPE(ehci, *hw_p); + if (type == cpu_to_hc32(ehci, Q_TYPE_QH)) + break; + prev = periodic_next_shadow(ehci, prev, type); + hw_p = shadow_next_periodic(ehci, &here, type); + here = *prev; + } + + itd->itd_next = here; + itd->hw_next = *hw_p; + prev->itd = itd; itd->frame = frame; wmb (); - ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); + *hw_p = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD); } /* fit urb's itds into the selected schedule slot; activate as needed */ @@ -2322,9 +2338,13 @@ restart: * No need to check for activity unless the * frame is current. */ - if (frame == clock_frame && live && - (q.sitd->hw_results & - SITD_ACTIVE(ehci))) { + if (((frame == clock_frame) || + (((frame + 1) % ehci->periodic_size) + == clock_frame)) + && live + && (q.sitd->hw_results & + SITD_ACTIVE(ehci))) { + incomplete = true; q_p = &q.sitd->sitd_next; hw_p = &q.sitd->hw_next; |