Date: Wed, 3 Dec 2014 21:48:31 +0000 (UTC) From: Hans Petter Selasky <hselasky@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r275467 - head/sys/dev/usb/controller Message-ID: <201412032148.sB3LmVNt038217@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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 */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201412032148.sB3LmVNt038217>