summaryrefslogtreecommitdiff
path: root/drivers/usb/host/ehci-sched.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-02-28 03:49:26 +0300
committerLinus Torvalds <torvalds@linux-foundation.org>2009-02-28 03:49:26 +0300
commit3c4f1158cd887a1a8c1309fc6d07907160e8e820 (patch)
treeac1916a7940f9659641cd59dcc494ee1bcc7a8e2 /drivers/usb/host/ehci-sched.c
parent7187adbf08336bd69da11d42d2542de7b1cc6957 (diff)
parente747951240b9f820b94fd5582663c66d798c8fd1 (diff)
downloadlinux-3c4f1158cd887a1a8c1309fc6d07907160e8e820.tar.xz
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (21 commits) USB: musb: fix srp sysfs entry deletion USB: musb: resume suspended root hub on disconnect USB: musb: use right poll limit for low speed devices USB: musb: be careful with 64K+ transfer lengths, host side USB: musb: fix data toggle saving with shared FIFO USB: musb: host endpoint_disable() oops fixes USB: musb: fix urb_dequeue() method USB: musb: fix musb_host_tx() for shared endpoint FIFO USB: musb: be careful with 64K+ transfer lengths (gadget side) usb: musb: make Davinci *work* in mainline USB: usb_get_string should check the descriptor type USB: gadget: fix build error in omap_apollon_2420_defconfig USB: g_file_storage: automatically disable stalls under Atmel USB: usb-storage: add IGNORE_RESIDUE flag for Genesys Logic adapters USB: Quirk for Hummingbird huc56s / Conexant ACM modem USB: serial: add support for second revision of Ericsson F3507G WWAN card USB: cdc-acm: add usb id for motomagx phones USB: option: add BenQ 3g modem information usb: gadget: obex: select correct ep descriptors USB: EHCI: slow down ITD reuse ...
Diffstat (limited to 'drivers/usb/host/ehci-sched.c')
-rw-r--r--drivers/usb/host/ehci-sched.c56
1 files changed, 48 insertions, 8 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a081ee65bde6..07bcb931021b 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1004,7 +1004,8 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
stream->bEndpointAddress &= 0x0f;
- stream->ep->hcpriv = NULL;
+ if (stream->ep)
+ stream->ep->hcpriv = NULL;
if (stream->rescheduled) {
ehci_info (ehci, "ep%d%s-iso rescheduled "
@@ -1653,14 +1654,28 @@ itd_complete (
(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
}
iso_stream_put (ehci, stream);
- /* OK to recycle this ITD now that its completion callback ran. */
+
done:
usb_put_urb(urb);
itd->urb = NULL;
- itd->stream = NULL;
- list_move(&itd->itd_list, &stream->free_list);
- iso_stream_put(ehci, stream);
-
+ if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
+ /* OK to recycle this ITD now. */
+ itd->stream = NULL;
+ list_move(&itd->itd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
+ } else {
+ /* HW might remember this ITD, so we can't recycle it yet.
+ * Move it to a safe place until a new frame starts.
+ */
+ list_move(&itd->itd_list, &ehci->cached_itd_list);
+ if (stream->refcount == 2) {
+ /* If iso_stream_put() were called here, stream
+ * would be freed. Instead, just prevent reuse.
+ */
+ stream->ep->hcpriv = NULL;
+ stream->ep = NULL;
+ }
+ }
return retval;
}
@@ -2101,6 +2116,20 @@ done:
/*-------------------------------------------------------------------------*/
+static void free_cached_itd_list(struct ehci_hcd *ehci)
+{
+ struct ehci_itd *itd, *n;
+
+ list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
+ struct ehci_iso_stream *stream = itd->stream;
+ itd->stream = NULL;
+ list_move(&itd->itd_list, &stream->free_list);
+ iso_stream_put(ehci, stream);
+ }
+}
+
+/*-------------------------------------------------------------------------*/
+
static void
scan_periodic (struct ehci_hcd *ehci)
{
@@ -2115,10 +2144,17 @@ scan_periodic (struct ehci_hcd *ehci)
* Touches as few pages as possible: cache-friendly.
*/
now_uframe = ehci->next_uframe;
- if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+ if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
clock = ehci_readl(ehci, &ehci->regs->frame_index);
- else
+ clock_frame = (clock >> 3) % ehci->periodic_size;
+ } else {
clock = now_uframe + mod - 1;
+ clock_frame = -1;
+ }
+ if (ehci->clock_frame != clock_frame) {
+ free_cached_itd_list(ehci);
+ ehci->clock_frame = clock_frame;
+ }
clock %= mod;
clock_frame = clock >> 3;
@@ -2277,6 +2313,10 @@ restart:
/* rescan the rest of this frame, then ... */
clock = now;
clock_frame = clock >> 3;
+ if (ehci->clock_frame != clock_frame) {
+ free_cached_itd_list(ehci);
+ ehci->clock_frame = clock_frame;
+ }
} else {
now_uframe++;
now_uframe %= mod;