From 34938c3085e5b56c40091d58ac43f922c27d7258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Imre=20Vad=C3=A1sz?= Date: Wed, 27 Jul 2016 20:51:31 +0000 Subject: [PATCH] [iwm] When stopping TX DMA, wait for all channels at once. * Makes the TX DMA stopping more similar to Linux code, and potentially a bit faster. Also, output an error message when TX DMA idling fails. Taken-From: Linux iwlwifi Tested: * AC3165, STA mode Approved by: adrian (mentor) Obtained from: DragonFlyBSD git 2ee486ddff973ac552ff787c17e8d83e8ae0f24c Differential Revision: https://reviews.freebsd.org/D7325 --- sys/dev/iwm/if_iwm.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/sys/dev/iwm/if_iwm.c b/sys/dev/iwm/if_iwm.c index efe9050d7844..e611ddee3183 100644 --- a/sys/dev/iwm/if_iwm.c +++ b/sys/dev/iwm/if_iwm.c @@ -911,12 +911,9 @@ iwm_free_fwmem(struct iwm_softc *sc) static int iwm_alloc_sched(struct iwm_softc *sc) { - int rv; - /* TX scheduler rings must be aligned on a 1KB boundary. */ - rv = iwm_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma, + return iwm_dma_contig_alloc(sc->sc_dmat, &sc->sched_dma, nitems(sc->txq) * sizeof(struct iwm_agn_scd_bc_tbl), 1024); - return rv; } static void @@ -1281,8 +1278,8 @@ iwm_stop_device(struct iwm_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps); - int chnl, ntries; - int qid; + int chnl, qid; + uint32_t mask = 0; /* tell the device to stop sending interrupts */ iwm_disable_interrupts(sc); @@ -1304,20 +1301,20 @@ iwm_stop_device(struct iwm_softc *sc) iwm_write_prph(sc, IWM_SCD_TXFACT, 0); - /* Stop all DMA channels. */ if (iwm_nic_lock(sc)) { + /* Stop each Tx DMA channel */ for (chnl = 0; chnl < IWM_FH_TCSR_CHNL_NUM; chnl++) { IWM_WRITE(sc, IWM_FH_TCSR_CHNL_TX_CONFIG_REG(chnl), 0); - for (ntries = 0; ntries < 200; ntries++) { - uint32_t r; + mask |= IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(chnl); + } - r = IWM_READ(sc, IWM_FH_TSSR_TX_STATUS_REG); - if (r & IWM_FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE( - chnl)) - break; - DELAY(20); - } + /* Wait for DMA channels to be idle */ + if (iwm_poll_bit(sc, IWM_FH_TSSR_TX_STATUS_REG, mask, mask, + 5000) < 0) { + device_printf(sc->sc_dev, + "Failing on timeout while stopping DMA channel: [0x%08x]\n", + IWM_READ(sc, IWM_FH_TSSR_TX_STATUS_REG)); } iwm_nic_unlock(sc); }