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.
This commit is contained in:
parent
258c6e3d7a
commit
e93086d0bf
@ -130,6 +130,7 @@ static void saf1761_otg_do_poll(struct usb_bus *);
|
||||
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_otg_softc *sc)
|
||||
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 saf1761_otg_softc *sc, struct saf1761_otg_td *
|
||||
|
||||
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 saf1761_otg_softc *sc, struct saf1761_otg_td *
|
||||
}
|
||||
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 saf1761_otg_softc *sc, struct saf1761_otg_td *
|
||||
}
|
||||
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_otg_softc *sc, struct saf1761_otg_td *t
|
||||
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_otg_softc *sc, struct saf1761_otg_td *t
|
||||
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_otg_softc *sc, struct saf1761_otg_td *t
|
||||
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
|
||||
@ -1483,6 +1498,17 @@ saf1761_otg_interrupt_poll_locked(struct saf1761_otg_softc *sc)
|
||||
saf1761_otg_xfer_do_fifo(sc, xfer);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -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;
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user