aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/host/ehci-hcd.c2
-rw-r--r--drivers/usb/host/ehci-mem.c1
-rw-r--r--drivers/usb/host/ehci-sched.c56
-rw-r--r--drivers/usb/host/ehci.h6
4 files changed, 57 insertions, 8 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 4725d15d096f..e551bb38852b 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -485,6 +485,7 @@ static int ehci_init(struct usb_hcd *hcd)
485 * periodic_size can shrink by USBCMD update if hcc_params allows. 485 * periodic_size can shrink by USBCMD update if hcc_params allows.
486 */ 486 */
487 ehci->periodic_size = DEFAULT_I_TDPS; 487 ehci->periodic_size = DEFAULT_I_TDPS;
488 INIT_LIST_HEAD(&ehci->cached_itd_list);
488 if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0) 489 if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
489 return retval; 490 return retval;
490 491
@@ -497,6 +498,7 @@ static int ehci_init(struct usb_hcd *hcd)
497 498
498 ehci->reclaim = NULL; 499 ehci->reclaim = NULL;
499 ehci->next_uframe = -1; 500 ehci->next_uframe = -1;
501 ehci->clock_frame = -1;
500 502
501 /* 503 /*
502 * dedicate a qh for the async ring head, since we couldn't unlink 504 * dedicate a qh for the async ring head, since we couldn't unlink
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 0431397836f6..10d52919abbb 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -128,6 +128,7 @@ static inline void qh_put (struct ehci_qh *qh)
128 128
129static void ehci_mem_cleanup (struct ehci_hcd *ehci) 129static void ehci_mem_cleanup (struct ehci_hcd *ehci)
130{ 130{
131 free_cached_itd_list(ehci);
131 if (ehci->async) 132 if (ehci->async)
132 qh_put (ehci->async); 133 qh_put (ehci->async);
133 ehci->async = NULL; 134 ehci->async = NULL;
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)
1004 1004
1005 is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0; 1005 is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
1006 stream->bEndpointAddress &= 0x0f; 1006 stream->bEndpointAddress &= 0x0f;
1007 stream->ep->hcpriv = NULL; 1007 if (stream->ep)
1008 stream->ep->hcpriv = NULL;
1008 1009
1009 if (stream->rescheduled) { 1010 if (stream->rescheduled) {
1010 ehci_info (ehci, "ep%d%s-iso rescheduled " 1011 ehci_info (ehci, "ep%d%s-iso rescheduled "
@@ -1653,14 +1654,28 @@ itd_complete (
1653 (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); 1654 (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
1654 } 1655 }
1655 iso_stream_put (ehci, stream); 1656 iso_stream_put (ehci, stream);
1656 /* OK to recycle this ITD now that its completion callback ran. */ 1657
1657done: 1658done:
1658 usb_put_urb(urb); 1659 usb_put_urb(urb);
1659 itd->urb = NULL; 1660 itd->urb = NULL;
1660 itd->stream = NULL; 1661 if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
1661 list_move(&itd->itd_list, &stream->free_list); 1662 /* OK to recycle this ITD now. */
1662 iso_stream_put(ehci, stream); 1663 itd->stream = NULL;
1663 1664 list_move(&itd->itd_list, &stream->free_list);
1665 iso_stream_put(ehci, stream);
1666 } else {
1667 /* HW might remember this ITD, so we can't recycle it yet.
1668 * Move it to a safe place until a new frame starts.
1669 */
1670 list_move(&itd->itd_list, &ehci->cached_itd_list);
1671 if (stream->refcount == 2) {
1672 /* If iso_stream_put() were called here, stream
1673 * would be freed. Instead, just prevent reuse.
1674 */
1675 stream->ep->hcpriv = NULL;
1676 stream->ep = NULL;
1677 }
1678 }
1664 return retval; 1679 return retval;
1665} 1680}
1666 1681
@@ -2101,6 +2116,20 @@ done:
2101 2116
2102/*-------------------------------------------------------------------------*/ 2117/*-------------------------------------------------------------------------*/
2103 2118
2119static void free_cached_itd_list(struct ehci_hcd *ehci)
2120{
2121 struct ehci_itd *itd, *n;
2122
2123 list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
2124 struct ehci_iso_stream *stream = itd->stream;
2125 itd->stream = NULL;
2126 list_move(&itd->itd_list, &stream->free_list);
2127 iso_stream_put(ehci, stream);
2128 }
2129}
2130
2131/*-------------------------------------------------------------------------*/
2132
2104static void 2133static void
2105scan_periodic (struct ehci_hcd *ehci) 2134scan_periodic (struct ehci_hcd *ehci)
2106{ 2135{
@@ -2115,10 +2144,17 @@ scan_periodic (struct ehci_hcd *ehci)
2115 * Touches as few pages as possible: cache-friendly. 2144 * Touches as few pages as possible: cache-friendly.
2116 */ 2145 */
2117 now_uframe = ehci->next_uframe; 2146 now_uframe = ehci->next_uframe;
2118 if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) 2147 if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
2119 clock = ehci_readl(ehci, &ehci->regs->frame_index); 2148 clock = ehci_readl(ehci, &ehci->regs->frame_index);
2120 else 2149 clock_frame = (clock >> 3) % ehci->periodic_size;
2150 } else {
2121 clock = now_uframe + mod - 1; 2151 clock = now_uframe + mod - 1;
2152 clock_frame = -1;
2153 }
2154 if (ehci->clock_frame != clock_frame) {
2155 free_cached_itd_list(ehci);
2156 ehci->clock_frame = clock_frame;
2157 }
2122 clock %= mod; 2158 clock %= mod;
2123 clock_frame = clock >> 3; 2159 clock_frame = clock >> 3;
2124 2160
@@ -2277,6 +2313,10 @@ restart:
2277 /* rescan the rest of this frame, then ... */ 2313 /* rescan the rest of this frame, then ... */
2278 clock = now; 2314 clock = now;
2279 clock_frame = clock >> 3; 2315 clock_frame = clock >> 3;
2316 if (ehci->clock_frame != clock_frame) {
2317 free_cached_itd_list(ehci);
2318 ehci->clock_frame = clock_frame;
2319 }
2280 } else { 2320 } else {
2281 now_uframe++; 2321 now_uframe++;
2282 now_uframe %= mod; 2322 now_uframe %= mod;
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index fb7054ccf4fc..262b00c9b334 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -87,6 +87,10 @@ struct ehci_hcd { /* one per controller */
87 int next_uframe; /* scan periodic, start here */ 87 int next_uframe; /* scan periodic, start here */
88 unsigned periodic_sched; /* periodic activity count */ 88 unsigned periodic_sched; /* periodic activity count */
89 89
90 /* list of itds completed while clock_frame was still active */
91 struct list_head cached_itd_list;
92 unsigned clock_frame;
93
90 /* per root hub port */ 94 /* per root hub port */
91 unsigned long reset_done [EHCI_MAX_ROOT_PORTS]; 95 unsigned long reset_done [EHCI_MAX_ROOT_PORTS];
92 96
@@ -220,6 +224,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
220 } 224 }
221} 225}
222 226
227static void free_cached_itd_list(struct ehci_hcd *ehci);
228
223/*-------------------------------------------------------------------------*/ 229/*-------------------------------------------------------------------------*/
224 230
225#include <linux/usb/ehci_def.h> 231#include <linux/usb/ehci_def.h>