diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-02-28 03:49:26 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-02-28 03:49:26 +0300 |
commit | 3c4f1158cd887a1a8c1309fc6d07907160e8e820 (patch) | |
tree | ac1916a7940f9659641cd59dcc494ee1bcc7a8e2 /drivers/usb/host/ehci-sched.c | |
parent | 7187adbf08336bd69da11d42d2542de7b1cc6957 (diff) | |
parent | e747951240b9f820b94fd5582663c66d798c8fd1 (diff) | |
download | linux-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.c | 56 |
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; |