aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/313-ath9k-Check-for-pending-frames-properly.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/313-ath9k-Check-for-pending-frames-properly.patch')
-rw-r--r--package/kernel/mac80211/patches/313-ath9k-Check-for-pending-frames-properly.patch125
1 files changed, 125 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/313-ath9k-Check-for-pending-frames-properly.patch b/package/kernel/mac80211/patches/313-ath9k-Check-for-pending-frames-properly.patch
new file mode 100644
index 0000000000..c1d8791b9d
--- /dev/null
+++ b/package/kernel/mac80211/patches/313-ath9k-Check-for-pending-frames-properly.patch
@@ -0,0 +1,125 @@
+From: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+Date: Fri, 17 Oct 2014 07:40:18 +0530
+Subject: [PATCH] ath9k: Check for pending frames properly
+
+Pending frames in the driver can be present
+either in the HW queues or SW. ath9k_has_pending_frames()
+currently checks for the HW queues first and then
+checks if any ACs are queued in the driver.
+
+In MCC mode, we need to check the HW queues alone, since
+the SW queues are just marked as 'stopped' - they will
+be processed in the next context switch. But since we
+don't differentiate this now, mention whether we want
+to check if there are frames in the SW queues.
+
+* The flush() callback checks both HW and SW queues.
+* The tx_frames_pending() callback does the same.
+* The call to __ath9k_flush() in MCC mode checks HW queues alone.
+
+Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
+---
+
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -715,7 +715,8 @@ int ath_update_survey_stats(struct ath_s
+ void ath_update_survey_nf(struct ath_softc *sc, int channel);
+ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
+ void ath_ps_full_sleep(unsigned long data);
+-void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop);
++void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
++ bool sw_pending);
+
+ /**********/
+ /* BTCOEX */
+--- a/drivers/net/wireless/ath/ath9k/channel.c
++++ b/drivers/net/wireless/ath/ath9k/channel.c
+@@ -1137,10 +1137,11 @@ void ath_chanctx_set_next(struct ath_sof
+ ath9k_chanctx_stop_queues(sc, sc->cur_chan);
+ queues_stopped = true;
+
+- __ath9k_flush(sc->hw, ~0, true);
++ __ath9k_flush(sc->hw, ~0, true, false);
+
+ if (ath_chanctx_send_ps_frame(sc, true))
+- __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO), false);
++ __ath9k_flush(sc->hw, BIT(IEEE80211_AC_VO),
++ false, false);
+
+ send_ps = true;
+ spin_lock_bh(&sc->chan_lock);
+--- a/drivers/net/wireless/ath/ath9k/main.c
++++ b/drivers/net/wireless/ath/ath9k/main.c
+@@ -54,7 +54,8 @@ u8 ath9k_parse_mpdudensity(u8 mpdudensit
+ }
+ }
+
+-static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
++static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq,
++ bool sw_pending)
+ {
+ bool pending = false;
+
+@@ -65,6 +66,9 @@ static bool ath9k_has_pending_frames(str
+ goto out;
+ }
+
++ if (!sw_pending)
++ goto out;
++
+ if (txq->mac80211_qnum >= 0) {
+ struct list_head *list;
+
+@@ -2003,7 +2007,8 @@ static void ath9k_set_coverage_class(str
+ mutex_unlock(&sc->mutex);
+ }
+
+-static bool ath9k_has_tx_pending(struct ath_softc *sc)
++static bool ath9k_has_tx_pending(struct ath_softc *sc,
++ bool sw_pending)
+ {
+ int i, npend = 0;
+
+@@ -2011,7 +2016,8 @@ static bool ath9k_has_tx_pending(struct
+ if (!ATH_TXQ_SETUP(sc, i))
+ continue;
+
+- npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
++ npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i],
++ sw_pending);
+ if (npend)
+ break;
+ }
+@@ -2025,11 +2031,12 @@ static void ath9k_flush(struct ieee80211
+ struct ath_softc *sc = hw->priv;
+
+ mutex_lock(&sc->mutex);
+- __ath9k_flush(hw, queues, drop);
++ __ath9k_flush(hw, queues, drop, true);
+ mutex_unlock(&sc->mutex);
+ }
+
+-void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
++void __ath9k_flush(struct ieee80211_hw *hw, u32 queues, bool drop,
++ bool sw_pending)
+ {
+ struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+@@ -2056,7 +2063,7 @@ void __ath9k_flush(struct ieee80211_hw *
+ ath_dbg(common, CHAN_CTX,
+ "Flush timeout: %d\n", jiffies_to_msecs(timeout));
+
+- if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc),
++ if (wait_event_timeout(sc->tx_wait, !ath9k_has_tx_pending(sc, sw_pending),
+ timeout) > 0)
+ drop = false;
+
+@@ -2079,7 +2086,7 @@ static bool ath9k_tx_frames_pending(stru
+ {
+ struct ath_softc *sc = hw->priv;
+
+- return ath9k_has_tx_pending(sc);
++ return ath9k_has_tx_pending(sc, true);
+ }
+
+ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)