aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorDavid Brownell <dbrownell@users.sourceforge.net>2007-12-17 01:37:40 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-01 17:34:57 -0500
commit30bf54e62a7926a483b4e36015bb4eb1372e6303 (patch)
treefe35de82e631af8f79392028b0f7781ba36a1069 /drivers/usb
parentdc0d5c1e5c7532e800fff6e313cd4af44af99976 (diff)
USB: PS3: Fix EHCI ISO transfer bug
This adds a workaround for an issue reported with ISO transfers on some EHCI controllers, most recently with VIA KT800 and PS3 EHCI silicon. The issue is that the silicon doesn't necessarily seem to be done using ISO DMA descriptors (itd, sitd) when it marks them inactive. (One theory is that the ill-defined mechanism where hardware caches periodic transfer descriptors isn't invalidating their state...) With such silicon, quick re-use of those descriptors makes trouble. Waiting until the next frame seems to be a sufficient workaround. This patch ensures that the relevant descriptors aren't available for immediate re-use. It does so by not recycling them until after issuing the completion callback which would reuse them by enqueueing an URB and thus (re)allocating ISO DMA descriptors. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Acked-by: Geoff Levand <geoffrey.levand@am.sony.com> Cc: Masashi Kimoto <Masashi_Kimoto@hq.scei.sony.co.jp> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/ehci-sched.c58
1 files changed, 42 insertions, 16 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index dce305bd62a5..1c771045ccaa 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1565,6 +1565,16 @@ itd_link_urb (
1565 1565
1566#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR) 1566#define ISO_ERRS (EHCI_ISOC_BUF_ERR | EHCI_ISOC_BABBLE | EHCI_ISOC_XACTERR)
1567 1567
1568/* Process and recycle a completed ITD. Return true iff its urb completed,
1569 * and hence its completion callback probably added things to the hardware
1570 * schedule.
1571 *
1572 * Note that we carefully avoid recycling this descriptor until after any
1573 * completion callback runs, so that it won't be reused quickly. That is,
1574 * assuming (a) no more than two urbs per frame on this endpoint, and also
1575 * (b) only this endpoint's completions submit URBs. It seems some silicon
1576 * corrupts things if you reuse completed descriptors very quickly...
1577 */
1568static unsigned 1578static unsigned
1569itd_complete ( 1579itd_complete (
1570 struct ehci_hcd *ehci, 1580 struct ehci_hcd *ehci,
@@ -1577,6 +1587,7 @@ itd_complete (
1577 int urb_index = -1; 1587 int urb_index = -1;
1578 struct ehci_iso_stream *stream = itd->stream; 1588 struct ehci_iso_stream *stream = itd->stream;
1579 struct usb_device *dev; 1589 struct usb_device *dev;
1590 unsigned retval = false;
1580 1591
1581 /* for each uframe with a packet */ 1592 /* for each uframe with a packet */
1582 for (uframe = 0; uframe < 8; uframe++) { 1593 for (uframe = 0; uframe < 8; uframe++) {
@@ -1610,15 +1621,9 @@ itd_complete (
1610 } 1621 }
1611 } 1622 }
1612 1623
1613 usb_put_urb (urb);
1614 itd->urb = NULL;
1615 itd->stream = NULL;
1616 list_move (&itd->itd_list, &stream->free_list);
1617 iso_stream_put (ehci, stream);
1618
1619 /* handle completion now? */ 1624 /* handle completion now? */
1620 if (likely ((urb_index + 1) != urb->number_of_packets)) 1625 if (likely ((urb_index + 1) != urb->number_of_packets))
1621 return 0; 1626 goto done;
1622 1627
1623 /* ASSERT: it's really the last itd for this urb 1628 /* ASSERT: it's really the last itd for this urb
1624 list_for_each_entry (itd, &stream->td_list, itd_list) 1629 list_for_each_entry (itd, &stream->td_list, itd_list)
@@ -1628,6 +1633,7 @@ itd_complete (
1628 /* give urb back to the driver ... can be out-of-order */ 1633 /* give urb back to the driver ... can be out-of-order */
1629 dev = urb->dev; 1634 dev = urb->dev;
1630 ehci_urb_done(ehci, urb, 0); 1635 ehci_urb_done(ehci, urb, 0);
1636 retval = true;
1631 urb = NULL; 1637 urb = NULL;
1632 1638
1633 /* defer stopping schedule; completion can submit */ 1639 /* defer stopping schedule; completion can submit */
@@ -1645,8 +1651,15 @@ itd_complete (
1645 (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); 1651 (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
1646 } 1652 }
1647 iso_stream_put (ehci, stream); 1653 iso_stream_put (ehci, stream);
1654 /* OK to recycle this ITD now that its completion callback ran. */
1655done:
1656 usb_put_urb(urb);
1657 itd->urb = NULL;
1658 itd->stream = NULL;
1659 list_move(&itd->itd_list, &stream->free_list);
1660 iso_stream_put(ehci, stream);
1648 1661
1649 return 1; 1662 return retval;
1650} 1663}
1651 1664
1652/*-------------------------------------------------------------------------*/ 1665/*-------------------------------------------------------------------------*/
@@ -1950,6 +1963,16 @@ sitd_link_urb (
1950#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \ 1963#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
1951 | SITD_STS_XACT | SITD_STS_MMF) 1964 | SITD_STS_XACT | SITD_STS_MMF)
1952 1965
1966/* Process and recycle a completed SITD. Return true iff its urb completed,
1967 * and hence its completion callback probably added things to the hardware
1968 * schedule.
1969 *
1970 * Note that we carefully avoid recycling this descriptor until after any
1971 * completion callback runs, so that it won't be reused quickly. That is,
1972 * assuming (a) no more than two urbs per frame on this endpoint, and also
1973 * (b) only this endpoint's completions submit URBs. It seems some silicon
1974 * corrupts things if you reuse completed descriptors very quickly...
1975 */
1953static unsigned 1976static unsigned
1954sitd_complete ( 1977sitd_complete (
1955 struct ehci_hcd *ehci, 1978 struct ehci_hcd *ehci,
@@ -1961,6 +1984,7 @@ sitd_complete (
1961 int urb_index = -1; 1984 int urb_index = -1;
1962 struct ehci_iso_stream *stream = sitd->stream; 1985 struct ehci_iso_stream *stream = sitd->stream;
1963 struct usb_device *dev; 1986 struct usb_device *dev;
1987 unsigned retval = false;
1964 1988
1965 urb_index = sitd->index; 1989 urb_index = sitd->index;
1966 desc = &urb->iso_frame_desc [urb_index]; 1990 desc = &urb->iso_frame_desc [urb_index];
@@ -1981,17 +2005,11 @@ sitd_complete (
1981 desc->status = 0; 2005 desc->status = 0;
1982 desc->actual_length = desc->length - SITD_LENGTH (t); 2006 desc->actual_length = desc->length - SITD_LENGTH (t);
1983 } 2007 }
1984
1985 usb_put_urb (urb);
1986 sitd->urb = NULL;
1987 sitd->stream = NULL;
1988 list_move (&sitd->sitd_list, &stream->free_list);
1989 stream->depth -= stream->interval << 3; 2008 stream->depth -= stream->interval << 3;
1990 iso_stream_put (ehci, stream);
1991 2009
1992 /* handle completion now? */ 2010 /* handle completion now? */
1993 if ((urb_index + 1) != urb->number_of_packets) 2011 if ((urb_index + 1) != urb->number_of_packets)
1994 return 0; 2012 goto done;
1995 2013
1996 /* ASSERT: it's really the last sitd for this urb 2014 /* ASSERT: it's really the last sitd for this urb
1997 list_for_each_entry (sitd, &stream->td_list, sitd_list) 2015 list_for_each_entry (sitd, &stream->td_list, sitd_list)
@@ -2001,6 +2019,7 @@ sitd_complete (
2001 /* give urb back to the driver */ 2019 /* give urb back to the driver */
2002 dev = urb->dev; 2020 dev = urb->dev;
2003 ehci_urb_done(ehci, urb, 0); 2021 ehci_urb_done(ehci, urb, 0);
2022 retval = true;
2004 urb = NULL; 2023 urb = NULL;
2005 2024
2006 /* defer stopping schedule; completion can submit */ 2025 /* defer stopping schedule; completion can submit */
@@ -2018,8 +2037,15 @@ sitd_complete (
2018 (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out"); 2037 (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
2019 } 2038 }
2020 iso_stream_put (ehci, stream); 2039 iso_stream_put (ehci, stream);
2040 /* OK to recycle this SITD now that its completion callback ran. */
2041done:
2042 usb_put_urb(urb);
2043 sitd->urb = NULL;
2044 sitd->stream = NULL;
2045 list_move(&sitd->sitd_list, &stream->free_list);
2046 iso_stream_put(ehci, stream);
2021 2047
2022 return 1; 2048 return retval;
2023} 2049}
2024 2050
2025 2051