From 08ba7e86853f67cab5ad87e3da19fed703da8394 Mon Sep 17 00:00:00 2001 From: nbd Date: Thu, 10 Mar 2011 00:53:05 +0000 Subject: ath9k: get rid of most of those annoying dma tx stop issues git-svn-id: svn://svn.openwrt.org/openwrt/trunk@25988 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- .../mac80211/patches/571-ath9k_fix_dma_stop.patch | 75 ++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 package/mac80211/patches/571-ath9k_fix_dma_stop.patch (limited to 'package/mac80211/patches/571-ath9k_fix_dma_stop.patch') diff --git a/package/mac80211/patches/571-ath9k_fix_dma_stop.patch b/package/mac80211/patches/571-ath9k_fix_dma_stop.patch new file mode 100644 index 000000000..698b05bb4 --- /dev/null +++ b/package/mac80211/patches/571-ath9k_fix_dma_stop.patch @@ -0,0 +1,75 @@ +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1271,16 +1271,14 @@ bool ath_drain_all_txq(struct ath_softc + if (sc->sc_flags & SC_OP_INVALID) + return true; + +- /* Stop beacon queue */ +- ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ++ ath9k_hw_abort_tx_dma(ah); + +- /* Stop data queues */ ++ /* Check if any queue remains active */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { +- if (ATH_TXQ_SETUP(sc, i)) { +- txq = &sc->tx.txq[i]; +- ath9k_hw_stoptxdma(ah, txq->axq_qnum); +- npend += ath9k_hw_numtxpending(ah, txq->axq_qnum); +- } ++ if (!ATH_TXQ_SETUP(sc, i)) ++ continue; ++ ++ npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum); + } + + if (npend) +--- a/drivers/net/wireless/ath/ath9k/mac.c ++++ b/drivers/net/wireless/ath/ath9k/mac.c +@@ -143,6 +143,37 @@ bool ath9k_hw_updatetxtriglevel(struct a + } + EXPORT_SYMBOL(ath9k_hw_updatetxtriglevel); + ++bool ath9k_hw_abort_tx_dma(struct ath_hw *ah) ++{ ++ int i, q; ++ ++ REG_WRITE(ah, AR_Q_TXD, AR_Q_TXD_M); ++ ++ REG_SET_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); ++ REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); ++ REG_SET_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); ++ ++ for (q = 0; q < AR_NUM_QCU; q++) { ++ for (i = 1000; i > 0; i--) { ++ if (!ath9k_hw_numtxpending(ah, q)) ++ break; ++ ++ udelay(5); ++ } ++ } ++ if (!i) ++ return false; ++ ++ REG_CLR_BIT(ah, AR_PCU_MISC, AR_PCU_FORCE_QUIET_COLL | AR_PCU_CLEAR_VMF); ++ REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); ++ REG_CLR_BIT(ah, AR_D_GBL_IFS_MISC, AR_D_GBL_IFS_MISC_IGNORE_BACKOFF); ++ ++ REG_WRITE(ah, AR_Q_TXD, 0); ++ ++ return true; ++} ++EXPORT_SYMBOL(ath9k_hw_abort_tx_dma); ++ + bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q) + { + #define ATH9K_TX_STOP_DMA_TIMEOUT 4000 /* usec */ +--- a/drivers/net/wireless/ath/ath9k/mac.h ++++ b/drivers/net/wireless/ath/ath9k/mac.h +@@ -676,6 +676,7 @@ void ath9k_hw_cleartxdesc(struct ath_hw + u32 ath9k_hw_numtxpending(struct ath_hw *ah, u32 q); + bool ath9k_hw_updatetxtriglevel(struct ath_hw *ah, bool bIncTrigLevel); + bool ath9k_hw_stoptxdma(struct ath_hw *ah, u32 q); ++bool ath9k_hw_abort_tx_dma(struct ath_hw *ah); + void ath9k_hw_gettxintrtxqs(struct ath_hw *ah, u32 *txqs); + bool ath9k_hw_set_txq_props(struct ath_hw *ah, int q, + const struct ath9k_tx_queue_info *qinfo); -- cgit v1.2.3