aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2009-03-19 02:53:57 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-19 02:53:57 -0400
commit0702b30dd821ac8a4103ddbe545518713fdca9be (patch)
tree8ce0c9f5e58c5ccb99870505eecd139986caa05e /drivers/usb/host
parent192d7a4667c6d11d1a174ec4cad9a3c5d5f9043c (diff)
parenta1e4ee22863d41a6fbb24310d7951836cb6dafe7 (diff)
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
Diffstat (limited to 'drivers/usb/host')
-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-pci.c1
-rw-r--r--drivers/usb/host/ehci-q.c3
-rw-r--r--drivers/usb/host/ehci-sched.c66
-rw-r--r--drivers/usb/host/ehci.h6
-rw-r--r--drivers/usb/host/ohci-pci.c1
-rw-r--r--drivers/usb/host/uhci-hcd.c1
-rw-r--r--drivers/usb/host/whci/asl.c4
-rw-r--r--drivers/usb/host/whci/pzl.c4
10 files changed, 67 insertions, 22 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-pci.c b/drivers/usb/host/ehci-pci.c
index bb21fb0a4969..abb9a7706ec7 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -432,7 +432,6 @@ static struct pci_driver ehci_pci_driver = {
432 432
433#ifdef CONFIG_PM 433#ifdef CONFIG_PM
434 .suspend = usb_hcd_pci_suspend, 434 .suspend = usb_hcd_pci_suspend,
435 .resume_early = usb_hcd_pci_resume_early,
436 .resume = usb_hcd_pci_resume, 435 .resume = usb_hcd_pci_resume,
437#endif 436#endif
438 .shutdown = usb_hcd_pci_shutdown, 437 .shutdown = usb_hcd_pci_shutdown,
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 3712b925b315..ecc9b66c03cd 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1095,7 +1095,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
1095 prev->qh_next = qh->qh_next; 1095 prev->qh_next = qh->qh_next;
1096 wmb (); 1096 wmb ();
1097 1097
1098 if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) { 1098 /* If the controller isn't running, we don't have to wait for it */
1099 if (unlikely(!HC_IS_RUNNING(ehci_to_hcd(ehci)->state))) {
1099 /* if (unlikely (qh->reclaim != 0)) 1100 /* if (unlikely (qh->reclaim != 0))
1100 * this will recurse, probably not much 1101 * this will recurse, probably not much
1101 */ 1102 */
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index a081ee65bde6..1d0b49e3f192 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 "
@@ -1535,7 +1536,7 @@ itd_link_urb (
1535 struct ehci_itd, itd_list); 1536 struct ehci_itd, itd_list);
1536 list_move_tail (&itd->itd_list, &stream->td_list); 1537 list_move_tail (&itd->itd_list, &stream->td_list);
1537 itd->stream = iso_stream_get (stream); 1538 itd->stream = iso_stream_get (stream);
1538 itd->urb = usb_get_urb (urb); 1539 itd->urb = urb;
1539 itd_init (ehci, stream, itd); 1540 itd_init (ehci, stream, itd);
1540 } 1541 }
1541 1542
@@ -1644,7 +1645,7 @@ itd_complete (
1644 (void) disable_periodic(ehci); 1645 (void) disable_periodic(ehci);
1645 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; 1646 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
1646 1647
1647 if (unlikely (list_empty (&stream->td_list))) { 1648 if (unlikely(list_is_singular(&stream->td_list))) {
1648 ehci_to_hcd(ehci)->self.bandwidth_allocated 1649 ehci_to_hcd(ehci)->self.bandwidth_allocated
1649 -= stream->bandwidth; 1650 -= stream->bandwidth;
1650 ehci_vdbg (ehci, 1651 ehci_vdbg (ehci,
@@ -1653,14 +1654,27 @@ 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 itd->urb = NULL; 1659 itd->urb = NULL;
1660 itd->stream = NULL; 1660 if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
1661 list_move(&itd->itd_list, &stream->free_list); 1661 /* OK to recycle this ITD now. */
1662 iso_stream_put(ehci, stream); 1662 itd->stream = NULL;
1663 1663 list_move(&itd->itd_list, &stream->free_list);
1664 iso_stream_put(ehci, stream);
1665 } else {
1666 /* HW might remember this ITD, so we can't recycle it yet.
1667 * Move it to a safe place until a new frame starts.
1668 */
1669 list_move(&itd->itd_list, &ehci->cached_itd_list);
1670 if (stream->refcount == 2) {
1671 /* If iso_stream_put() were called here, stream
1672 * would be freed. Instead, just prevent reuse.
1673 */
1674 stream->ep->hcpriv = NULL;
1675 stream->ep = NULL;
1676 }
1677 }
1664 return retval; 1678 return retval;
1665} 1679}
1666 1680
@@ -1934,7 +1948,7 @@ sitd_link_urb (
1934 struct ehci_sitd, sitd_list); 1948 struct ehci_sitd, sitd_list);
1935 list_move_tail (&sitd->sitd_list, &stream->td_list); 1949 list_move_tail (&sitd->sitd_list, &stream->td_list);
1936 sitd->stream = iso_stream_get (stream); 1950 sitd->stream = iso_stream_get (stream);
1937 sitd->urb = usb_get_urb (urb); 1951 sitd->urb = urb;
1938 1952
1939 sitd_patch(ehci, stream, sitd, sched, packet); 1953 sitd_patch(ehci, stream, sitd, sched, packet);
1940 sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size, 1954 sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
@@ -2019,7 +2033,7 @@ sitd_complete (
2019 (void) disable_periodic(ehci); 2033 (void) disable_periodic(ehci);
2020 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--; 2034 ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs--;
2021 2035
2022 if (list_empty (&stream->td_list)) { 2036 if (list_is_singular(&stream->td_list)) {
2023 ehci_to_hcd(ehci)->self.bandwidth_allocated 2037 ehci_to_hcd(ehci)->self.bandwidth_allocated
2024 -= stream->bandwidth; 2038 -= stream->bandwidth;
2025 ehci_vdbg (ehci, 2039 ehci_vdbg (ehci,
@@ -2030,7 +2044,6 @@ sitd_complete (
2030 iso_stream_put (ehci, stream); 2044 iso_stream_put (ehci, stream);
2031 /* OK to recycle this SITD now that its completion callback ran. */ 2045 /* OK to recycle this SITD now that its completion callback ran. */
2032done: 2046done:
2033 usb_put_urb(urb);
2034 sitd->urb = NULL; 2047 sitd->urb = NULL;
2035 sitd->stream = NULL; 2048 sitd->stream = NULL;
2036 list_move(&sitd->sitd_list, &stream->free_list); 2049 list_move(&sitd->sitd_list, &stream->free_list);
@@ -2101,6 +2114,20 @@ done:
2101 2114
2102/*-------------------------------------------------------------------------*/ 2115/*-------------------------------------------------------------------------*/
2103 2116
2117static void free_cached_itd_list(struct ehci_hcd *ehci)
2118{
2119 struct ehci_itd *itd, *n;
2120
2121 list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
2122 struct ehci_iso_stream *stream = itd->stream;
2123 itd->stream = NULL;
2124 list_move(&itd->itd_list, &stream->free_list);
2125 iso_stream_put(ehci, stream);
2126 }
2127}
2128
2129/*-------------------------------------------------------------------------*/
2130
2104static void 2131static void
2105scan_periodic (struct ehci_hcd *ehci) 2132scan_periodic (struct ehci_hcd *ehci)
2106{ 2133{
@@ -2115,10 +2142,17 @@ scan_periodic (struct ehci_hcd *ehci)
2115 * Touches as few pages as possible: cache-friendly. 2142 * Touches as few pages as possible: cache-friendly.
2116 */ 2143 */
2117 now_uframe = ehci->next_uframe; 2144 now_uframe = ehci->next_uframe;
2118 if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state)) 2145 if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
2119 clock = ehci_readl(ehci, &ehci->regs->frame_index); 2146 clock = ehci_readl(ehci, &ehci->regs->frame_index);
2120 else 2147 clock_frame = (clock >> 3) % ehci->periodic_size;
2148 } else {
2121 clock = now_uframe + mod - 1; 2149 clock = now_uframe + mod - 1;
2150 clock_frame = -1;
2151 }
2152 if (ehci->clock_frame != clock_frame) {
2153 free_cached_itd_list(ehci);
2154 ehci->clock_frame = clock_frame;
2155 }
2122 clock %= mod; 2156 clock %= mod;
2123 clock_frame = clock >> 3; 2157 clock_frame = clock >> 3;
2124 2158
@@ -2277,6 +2311,10 @@ restart:
2277 /* rescan the rest of this frame, then ... */ 2311 /* rescan the rest of this frame, then ... */
2278 clock = now; 2312 clock = now;
2279 clock_frame = clock >> 3; 2313 clock_frame = clock >> 3;
2314 if (ehci->clock_frame != clock_frame) {
2315 free_cached_itd_list(ehci);
2316 ehci->clock_frame = clock_frame;
2317 }
2280 } else { 2318 } else {
2281 now_uframe++; 2319 now_uframe++;
2282 now_uframe %= mod; 2320 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>
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 5d625c3fd423..f9961b4c0da3 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -487,7 +487,6 @@ static struct pci_driver ohci_pci_driver = {
487 487
488#ifdef CONFIG_PM 488#ifdef CONFIG_PM
489 .suspend = usb_hcd_pci_suspend, 489 .suspend = usb_hcd_pci_suspend,
490 .resume_early = usb_hcd_pci_resume_early,
491 .resume = usb_hcd_pci_resume, 490 .resume = usb_hcd_pci_resume,
492#endif 491#endif
493 492
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 944f7e0ca4df..cf5e4cf7ea42 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -942,7 +942,6 @@ static struct pci_driver uhci_pci_driver = {
942 942
943#ifdef CONFIG_PM 943#ifdef CONFIG_PM
944 .suspend = usb_hcd_pci_suspend, 944 .suspend = usb_hcd_pci_suspend,
945 .resume_early = usb_hcd_pci_resume_early,
946 .resume = usb_hcd_pci_resume, 945 .resume = usb_hcd_pci_resume,
947#endif /* PM */ 946#endif /* PM */
948}; 947};
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c
index 2291c5f5af51..958751ccea43 100644
--- a/drivers/usb/host/whci/asl.c
+++ b/drivers/usb/host/whci/asl.c
@@ -227,13 +227,13 @@ void scan_async_work(struct work_struct *work)
227 * Now that the ASL is updated, complete the removal of any 227 * Now that the ASL is updated, complete the removal of any
228 * removed qsets. 228 * removed qsets.
229 */ 229 */
230 spin_lock(&whc->lock); 230 spin_lock_irq(&whc->lock);
231 231
232 list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) { 232 list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
233 qset_remove_complete(whc, qset); 233 qset_remove_complete(whc, qset);
234 } 234 }
235 235
236 spin_unlock(&whc->lock); 236 spin_unlock_irq(&whc->lock);
237} 237}
238 238
239/** 239/**
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c
index 7dc85a0bee7c..df8b85f07092 100644
--- a/drivers/usb/host/whci/pzl.c
+++ b/drivers/usb/host/whci/pzl.c
@@ -255,13 +255,13 @@ void scan_periodic_work(struct work_struct *work)
255 * Now that the PZL is updated, complete the removal of any 255 * Now that the PZL is updated, complete the removal of any
256 * removed qsets. 256 * removed qsets.
257 */ 257 */
258 spin_lock(&whc->lock); 258 spin_lock_irq(&whc->lock);
259 259
260 list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) { 260 list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
261 qset_remove_complete(whc, qset); 261 qset_remove_complete(whc, qset);
262 } 262 }
263 263
264 spin_unlock(&whc->lock); 264 spin_unlock_irq(&whc->lock);
265} 265}
266 266
267/** 267/**