Date: Sat, 10 May 2014 07:37:32 +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: r265806 - head/sys/dev/usb/controller Message-ID: <201405100737.s4A7bWBp069001@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: hselasky Date: Sat May 10 07:37:32 2014 New Revision: 265806 URL: http://svnweb.freebsd.org/changeset/base/265806 Log: Optimise host channel disabling: - For non-periodic traffic we only need to wait two SOFs before disabling the channel. - Make sure we release the TX FIFO tracking level after the host channel is disabled. - Make sure the host channel state gets reset/disabled initially. - Two minor code style changes. MFC after: 2 weeks Modified: head/sys/dev/usb/controller/dwc_otg.c head/sys/dev/usb/controller/dwc_otg.h Modified: head/sys/dev/usb/controller/dwc_otg.c ============================================================================== --- head/sys/dev/usb/controller/dwc_otg.c Sat May 10 07:26:49 2014 (r265805) +++ head/sys/dev/usb/controller/dwc_otg.c Sat May 10 07:37:32 2014 (r265806) @@ -141,6 +141,7 @@ static void dwc_otg_do_poll(struct usb_b static void dwc_otg_standard_done(struct usb_xfer *); static void dwc_otg_root_intr(struct dwc_otg_softc *); static void dwc_otg_interrupt_poll(struct dwc_otg_softc *); +static void dwc_otg_host_channel_disable(struct dwc_otg_softc *, uint8_t); /* * Here is a configuration that the chip supports. @@ -210,6 +211,13 @@ dwc_otg_init_fifo(struct dwc_otg_softc * return (EINVAL); } + /* disable any leftover host channels */ + for (x = 0; x != sc->sc_host_ch_max; x++) { + if (sc->sc_chan_state[x].wait_sof == 0) + continue; + dwc_otg_host_channel_disable(sc, x); + } + if (mode == DWC_MODE_HOST) { /* reset active endpoints */ @@ -236,6 +244,9 @@ dwc_otg_init_fifo(struct dwc_otg_softc * ((fifo_size / 4) << 16) | (tx_start / 4)); + /* reset host channel state */ + memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state)); + /* reset FIFO TX levels */ sc->sc_tx_cur_p_level = 0; sc->sc_tx_cur_np_level = 0; @@ -326,6 +337,9 @@ dwc_otg_init_fifo(struct dwc_otg_softc * /* reset periodic and non-periodic FIFO TX size */ sc->sc_tx_max_size = fifo_size; + /* reset host channel state */ + memset(sc->sc_chan_state, 0, sizeof(sc->sc_chan_state)); + /* reset FIFO TX levels */ sc->sc_tx_cur_p_level = 0; sc->sc_tx_cur_np_level = 0; @@ -569,7 +583,7 @@ dwc_otg_clear_hcint(struct dwc_otg_softc } static uint8_t -dwc_otg_host_channel_alloc(struct dwc_otg_td *td, uint8_t which) +dwc_otg_host_channel_alloc(struct dwc_otg_td *td, uint8_t which, uint8_t is_out) { struct dwc_otg_softc *sc; uint32_t tx_p_size; @@ -587,11 +601,7 @@ dwc_otg_host_channel_alloc(struct dwc_ot sc = DWC_OTG_PC2SC(td->pc); /* compute needed TX FIFO size */ - if (td->ep_type == UE_CONTROL) { - /* RX and TX transactions */ - tx_p_size = 0; - tx_np_size = td->max_packet_size; - } else if ((td->hcchar & HCCHAR_EPDIR) == HCCHAR_EPDIR_OUT) { + if (is_out != 0) { if (td->ep_type == UE_INTERRUPT || td->ep_type == UE_ISOCHRONOUS) { tx_p_size = td->max_packet_size; @@ -669,12 +679,22 @@ dwc_otg_host_channel_free(struct dwc_otg /* get pointer to softc */ sc = DWC_OTG_PC2SC(td->pc); - sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MAX; - sc->sc_chan_state[x].allocated = 0; - /* keep track of used TX FIFO, if any */ - sc->sc_tx_cur_p_level -= sc->sc_chan_state[x].tx_p_size; - sc->sc_tx_cur_np_level -= sc->sc_chan_state[x].tx_np_size; + /* + * We need to let programmed host channels run till complete + * else the host channel will stop functioning. Assume that + * after a fixed given amount of time the host channel is no + * longer doing any USB traffic: + */ + if (td->ep_type == UE_ISOCHRONOUS || td->ep_type == UE_INTERRUPT) { + /* double buffered */ + sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MAX; + } else { + /* single buffered */ + sc->sc_chan_state[x].wait_sof = DWC_OTG_SLOT_IDLE_MIN; + } + + sc->sc_chan_state[x].allocated = 0; /* ack any pending messages */ if (sc->sc_last_rx_status != 0 && @@ -810,7 +830,7 @@ send_pkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(td, 0)) { + if (dwc_otg_host_channel_alloc(td, 0, 1)) { td->state = DWC_CHAN_ST_START; goto busy; } @@ -863,7 +883,7 @@ send_cpkt: goto complete; } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(td, 0)) { + if (dwc_otg_host_channel_alloc(td, 0, 0)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } @@ -1322,7 +1342,7 @@ receive_pkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(td, td->tt_channel_tog)) { + if (dwc_otg_host_channel_alloc(td, td->tt_channel_tog, 0)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } @@ -1404,7 +1424,7 @@ receive_spkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(td, 0)) { + if (dwc_otg_host_channel_alloc(td, 0, 0)) { td->state = DWC_CHAN_ST_START; goto busy; } @@ -1616,8 +1636,7 @@ check_state: td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; - } - if (hcint & (HCINT_ACK | HCINT_NYET)) { + } else if (hcint & (HCINT_ACK | HCINT_NYET)) { td->offset += td->tx_bytes; td->remainder -= td->tx_bytes; td->toggle ^= 1; @@ -1642,8 +1661,7 @@ check_state: td->did_nak = 1; td->tt_scheduled = 0; goto send_pkt; - } - if (hcint & (HCINT_ACK | HCINT_NYET)) + } else if (hcint & (HCINT_ACK | HCINT_NYET)) goto send_cpkt; break; @@ -1698,7 +1716,7 @@ check_state: /* FALLTHROUGH */ case DWC_CHAN_ST_TX_PKT_ISOC: - if (dwc_otg_host_channel_alloc(td, 0)) + if (dwc_otg_host_channel_alloc(td, 0, 1)) break; channel = td->channel[0]; goto send_isoc_pkt; @@ -1731,7 +1749,7 @@ send_pkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(td, 0)) { + if (dwc_otg_host_channel_alloc(td, 0, 1)) { td->state = DWC_CHAN_ST_START; goto busy; } @@ -1896,7 +1914,7 @@ send_cpkt: } /* allocate a new channel */ - if (dwc_otg_host_channel_alloc(td, td->tt_channel_tog)) { + if (dwc_otg_host_channel_alloc(td, td->tt_channel_tog, 0)) { td->state = DWC_CHAN_ST_WAIT_C_PKT; goto busy; } @@ -2306,6 +2324,31 @@ dwc_otg_timer_stop(struct dwc_otg_softc usb_callout_stop(&sc->sc_timer); } +static void +dwc_otg_host_channel_disable(struct dwc_otg_softc *sc, uint8_t x) +{ + uint32_t hcchar; + + hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); + + /* disable host channel, if any */ + if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) { + /* disable channel */ + DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), + HCCHAR_CHENA | HCCHAR_CHDIS); + /* wait for chip to get its brains in order */ + sc->sc_chan_state[x].wait_sof = 2; + } + + /* release TX FIFO usage, if any */ + sc->sc_tx_cur_p_level -= sc->sc_chan_state[x].tx_p_size; + sc->sc_tx_cur_np_level -= sc->sc_chan_state[x].tx_np_size; + + /* don't release TX FIFO usage twice */ + sc->sc_chan_state[x].tx_p_size = 0; + sc->sc_chan_state[x].tx_np_size = 0; +} + static uint8_t dwc_otg_update_host_transfer_schedule(struct dwc_otg_softc *sc) { @@ -2326,26 +2369,12 @@ dwc_otg_update_host_transfer_schedule(st TAILQ_INIT(&head); for (x = 0; x != sc->sc_host_ch_max; x++) { - uint32_t hcchar; - if (sc->sc_chan_state[x].wait_sof == 0) continue; sc->sc_needsof = 1; - sc->sc_chan_state[x].wait_sof--; - if (sc->sc_chan_state[x].wait_sof != 0) - continue; - - hcchar = DWC_OTG_READ_4(sc, DOTG_HCCHAR(x)); - - /* disable host channel, if any */ - if (hcchar & (HCCHAR_CHENA | HCCHAR_CHDIS)) { - /* disable channel */ - DWC_OTG_WRITE_4(sc, DOTG_HCCHAR(x), - HCCHAR_CHENA | HCCHAR_CHDIS); - /* wait for chip to get its brains in order */ - sc->sc_chan_state[x].wait_sof = 2; - } + if (--(sc->sc_chan_state[x].wait_sof) == 0) + dwc_otg_host_channel_disable(sc, x); } if ((temp & 7) == 0) { Modified: head/sys/dev/usb/controller/dwc_otg.h ============================================================================== --- head/sys/dev/usb/controller/dwc_otg.h Sat May 10 07:26:49 2014 (r265805) +++ head/sys/dev/usb/controller/dwc_otg.h Sat May 10 07:37:32 2014 (r265806) @@ -36,6 +36,7 @@ #define DWC_OTG_HOST_TIMER_RATE 10 /* ms */ #define DWC_OTG_TT_SLOT_MAX 8 #define DWC_OTG_SLOT_IDLE_MAX 4 +#define DWC_OTG_SLOT_IDLE_MIN 2 #define DWC_OTG_READ_4(sc, reg) \ bus_space_read_4((sc)->sc_io_tag, (sc)->sc_io_hdl, reg)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201405100737.s4A7bWBp069001>