svn commit: r275467 - head/sys/dev/usb/controller
Hans Petter Selasky
hselasky at FreeBSD.org
Wed Dec 3 21:48:31 UTC 2014
Author: hselasky
Date: Wed Dec 3 21:48:30 2014
New Revision: 275467
URL: https://svnweb.freebsd.org/changeset/base/275467
Log:
Workaround for possible bug in the SAF1761 chip. Wait 125us before
re-using a hardware propritary transfer descriptor, PTD, in USB host
mode. If the PTD's are recycled too quickly, it has been observed that
the hardware simply fails to schedule the requested job or resets
completely disconnecting all devices.
Modified:
head/sys/dev/usb/controller/saf1761_otg.c
head/sys/dev/usb/controller/saf1761_otg.h
Modified: head/sys/dev/usb/controller/saf1761_otg.c
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg.c Wed Dec 3 19:44:24 2014 (r275466)
+++ head/sys/dev/usb/controller/saf1761_otg.c Wed Dec 3 21:48:30 2014 (r275467)
@@ -130,6 +130,7 @@ static void saf1761_otg_do_poll(struct u
static void saf1761_otg_standard_done(struct usb_xfer *);
static void saf1761_otg_intr_set(struct usb_xfer *, uint8_t);
static void saf1761_otg_root_intr(struct saf1761_otg_softc *);
+static void saf1761_otg_enable_psof(struct saf1761_otg_softc *, uint8_t);
/*
* Here is a list of what the SAF1761 chip can support. The main
@@ -214,6 +215,7 @@ saf1761_otg_wakeup_peer(struct saf1761_o
static uint8_t
saf1761_host_channel_alloc(struct saf1761_otg_softc *sc, struct saf1761_otg_td *td)
{
+ uint32_t map;
uint32_t x;
if (td->channel < SOTG_HOST_CHANNEL_MAX)
@@ -225,8 +227,11 @@ saf1761_host_channel_alloc(struct saf176
switch (td->ep_type) {
case UE_INTERRUPT:
+ map = sc->sc_host_intr_map |
+ sc->sc_host_intr_busy_map[0] |
+ sc->sc_host_intr_busy_map[1];
for (x = 0; x != 32; x++) {
- if (sc->sc_host_intr_map & (1 << x))
+ if (map & (1 << x))
continue;
sc->sc_host_intr_map |= (1 << x);
td->channel = 32 + x;
@@ -234,8 +239,11 @@ saf1761_host_channel_alloc(struct saf176
}
break;
case UE_ISOCHRONOUS:
+ map = sc->sc_host_isoc_map |
+ sc->sc_host_isoc_busy_map[0] |
+ sc->sc_host_isoc_busy_map[1];
for (x = 0; x != 32; x++) {
- if (sc->sc_host_isoc_map & (1 << x))
+ if (map & (1 << x))
continue;
sc->sc_host_isoc_map |= (1 << x);
td->channel = x;
@@ -243,8 +251,11 @@ saf1761_host_channel_alloc(struct saf176
}
break;
default:
+ map = sc->sc_host_async_map |
+ sc->sc_host_async_busy_map[0] |
+ sc->sc_host_async_busy_map[1];
for (x = 0; x != 32; x++) {
- if (sc->sc_host_async_map & (1 << x))
+ if (map & (1 << x))
continue;
sc->sc_host_async_map |= (1 << x);
td->channel = 64 + x;
@@ -269,6 +280,7 @@ saf1761_host_channel_free(struct saf1761
td->channel = SOTG_HOST_CHANNEL_MAX;
sc->sc_host_intr_map &= ~(1 << x);
sc->sc_host_intr_suspend_map &= ~(1 << x);
+ sc->sc_host_intr_busy_map[0] |= (1 << x);
SAF1761_WRITE_LE_4(sc, SOTG_INT_PTD_SKIP_PTD,
(~sc->sc_host_intr_map) | sc->sc_host_intr_suspend_map);
break;
@@ -277,6 +289,7 @@ saf1761_host_channel_free(struct saf1761
td->channel = SOTG_HOST_CHANNEL_MAX;
sc->sc_host_isoc_map &= ~(1 << x);
sc->sc_host_isoc_suspend_map &= ~(1 << x);
+ sc->sc_host_isoc_busy_map[0] |= (1 << x);
SAF1761_WRITE_LE_4(sc, SOTG_ISO_PTD_SKIP_PTD,
(~sc->sc_host_isoc_map) | sc->sc_host_isoc_suspend_map);
break;
@@ -285,10 +298,12 @@ saf1761_host_channel_free(struct saf1761
td->channel = SOTG_HOST_CHANNEL_MAX;
sc->sc_host_async_map &= ~(1 << x);
sc->sc_host_async_suspend_map &= ~(1 << x);
+ sc->sc_host_async_busy_map[0] |= (1 << x);
SAF1761_WRITE_LE_4(sc, SOTG_ATL_PTD_SKIP_PTD,
(~sc->sc_host_async_map) | sc->sc_host_async_suspend_map);
break;
}
+ saf1761_otg_enable_psof(sc, 1);
}
static uint32_t
@@ -1484,6 +1499,17 @@ saf1761_otg_interrupt_poll_locked(struct
}
static void
+saf1761_otg_enable_psof(struct saf1761_otg_softc *sc, uint8_t on)
+{
+ if (on) {
+ sc->sc_intr_enable |= SOTG_DCINTERRUPT_IEPSOF;
+ } else {
+ sc->sc_intr_enable &= ~SOTG_DCINTERRUPT_IEPSOF;
+ }
+ SAF1761_WRITE_LE_4(sc, SOTG_DCINTERRUPT_EN, sc->sc_intr_enable);
+}
+
+static void
saf1761_otg_wait_suspend(struct saf1761_otg_softc *sc, uint8_t on)
{
if (on) {
@@ -1565,6 +1591,27 @@ saf1761_otg_filter_interrupt(void *arg)
(void) SAF1761_READ_LE_4(sc, SOTG_INT_PTD_DONE_PTD);
(void) SAF1761_READ_LE_4(sc, SOTG_ISO_PTD_DONE_PTD);
+ if (status & SOTG_DCINTERRUPT_IEPSOF) {
+ if ((sc->sc_host_async_busy_map[1] | sc->sc_host_async_busy_map[0] |
+ sc->sc_host_intr_busy_map[1] | sc->sc_host_intr_busy_map[0] |
+ sc->sc_host_isoc_busy_map[1] | sc->sc_host_isoc_busy_map[0]) != 0) {
+ /* busy waiting is active */
+ retval = FILTER_SCHEDULE_THREAD;
+
+ sc->sc_host_async_busy_map[1] = sc->sc_host_async_busy_map[0];
+ sc->sc_host_async_busy_map[0] = 0;
+
+ sc->sc_host_intr_busy_map[1] = sc->sc_host_intr_busy_map[0];
+ sc->sc_host_intr_busy_map[0] = 0;
+
+ sc->sc_host_isoc_busy_map[1] = sc->sc_host_isoc_busy_map[0];
+ sc->sc_host_isoc_busy_map[0] = 0;
+ } else {
+ /* busy waiting is not active */
+ saf1761_otg_enable_psof(sc, 0);
+ }
+ }
+
if (status & SAF1761_DCINTERRUPT_THREAD_IRQ)
retval = FILTER_SCHEDULE_THREAD;
Modified: head/sys/dev/usb/controller/saf1761_otg.h
==============================================================================
--- head/sys/dev/usb/controller/saf1761_otg.h Wed Dec 3 19:44:24 2014 (r275466)
+++ head/sys/dev/usb/controller/saf1761_otg.h Wed Dec 3 21:48:30 2014 (r275467)
@@ -139,10 +139,13 @@ struct saf1761_otg_softc {
bus_space_tag_t sc_io_tag;
bus_space_handle_t sc_io_hdl;
+ uint32_t sc_host_async_busy_map[2];
uint32_t sc_host_async_map;
uint32_t sc_host_async_suspend_map;
+ uint32_t sc_host_intr_busy_map[2];
uint32_t sc_host_intr_map;
uint32_t sc_host_intr_suspend_map;
+ uint32_t sc_host_isoc_busy_map[2];
uint32_t sc_host_isoc_map;
uint32_t sc_host_isoc_suspend_map;
uint32_t sc_intr_enable; /* enabled interrupts */
More information about the svn-src-head
mailing list