Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ath9k: Improve flush() in mcc mode

The flush timeout in MCC mode is very small, since
we are constrained by the time slice for each
channel context, but since only the HW queues are
flushed when switching contexts, it is acceptable.

Since the SW queues are also emptied in the mac80211 flush()
callback, a larger duration is needed. Add an override
argument to __ath9k_flush() and set it when flush()
is called in MCC mode. This allows the driver to
drain both the SW and HW queues.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Sujith Manoharan and committed by
John W. Linville
25f3bc7d 23aab0c2

+28 -6
+1 -1
drivers/net/wireless/ath/ath9k/ath9k.h
··· 719 719 void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); 720 720 void ath_ps_full_sleep(unsigned long data); 721 721 void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, 722 - bool sw_pending); 722 + bool sw_pending, bool timeout_override); 723 723 724 724 /**********/ 725 725 /* BTCOEX */
+2 -2
drivers/net/wireless/ath/ath9k/channel.c
··· 1232 1232 ath9k_chanctx_stop_queues(sc, sc->cur_chan); 1233 1233 queues_stopped = true; 1234 1234 1235 - __ath9k_flush(sc->hw, ~0, true, false); 1235 + __ath9k_flush(sc->hw, ~0, true, false, false); 1236 1236 1237 1237 if (ath_chanctx_send_ps_frame(sc, true)) 1238 1238 __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), 1239 - false, false); 1239 + false, false, false); 1240 1240 1241 1241 send_ps = true; 1242 1242 spin_lock_bh(&sc->chan_lock);
+25 -3
drivers/net/wireless/ath/ath9k/main.c
··· 2031 2031 u32 queues, bool drop) 2032 2032 { 2033 2033 struct ath_softc *sc = hw->priv; 2034 + struct ath_common *common = ath9k_hw_common(sc->sc_ah); 2034 2035 2036 + if (ath9k_is_chanctx_enabled()) { 2037 + if (!test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) 2038 + goto flush; 2039 + 2040 + /* 2041 + * If MCC is active, extend the flush timeout 2042 + * and wait for the HW/SW queues to become 2043 + * empty. This needs to be done outside the 2044 + * sc->mutex lock to allow the channel scheduler 2045 + * to switch channel contexts. 2046 + * 2047 + * The vif queues have been stopped in mac80211, 2048 + * so there won't be any incoming frames. 2049 + */ 2050 + __ath9k_flush(hw, queues, drop, true, true); 2051 + return; 2052 + } 2053 + flush: 2035 2054 mutex_lock(&sc->mutex); 2036 - __ath9k_flush(hw, queues, drop, true); 2055 + __ath9k_flush(hw, queues, drop, true, false); 2037 2056 mutex_unlock(&sc->mutex); 2038 2057 } 2039 2058 2040 2059 void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop, 2041 - bool sw_pending) 2060 + bool sw_pending, bool timeout_override) 2042 2061 { 2043 2062 struct ath_softc *sc = hw->priv; 2044 2063 struct ath_hw *ah = sc->sc_ah; ··· 2078 2059 } 2079 2060 2080 2061 spin_lock_bh(&sc->chan_lock); 2081 - timeout = sc->cur_chan->flush_timeout; 2062 + if (timeout_override) 2063 + timeout = HZ / 5; 2064 + else 2065 + timeout = sc->cur_chan->flush_timeout; 2082 2066 spin_unlock_bh(&sc->chan_lock); 2083 2067 2084 2068 ath_dbg(common, CHAN_CTX,