Flush is a prerequisite for proper PS support and ensures we
empty queues before going off channel.  We simply wait up to
200 ms for the tx tasklet to run its course.

Signed-off-by: Bob Copeland <m...@bobcopeland.com>
---
 drivers/net/wireless/ath/ath5k/base.c         |   37 +++++++++++++++++++++++++
 drivers/net/wireless/ath/ath5k/base.h         |    1 +
 drivers/net/wireless/ath/ath5k/mac80211-ops.c |    2 +-
 3 files changed, 39 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ath5k/base.c 
b/drivers/net/wireless/ath/ath5k/base.c
index 8ba3346..b6107e7 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -1055,6 +1055,43 @@ ath5k_drain_tx_buffs(struct ath5k_hw *ah)
        }
 }
 
+static int ath5k_tx_pending(struct ath5k_hw *ah, struct ath5k_txq *txq)
+{
+       int pending;
+       spin_lock_bh(&txq->lock);
+       pending = txq->setup ? txq->txq_len : 0;
+       spin_unlock_bh(&txq->lock);
+       return pending;
+}
+
+/**
+ * ath5k_flush_tx - wait for queued frames to be processed
+ *
+ * @ah: the &struct ath5k_hw
+ * @drop: true if we should drop packets rather than wait
+ */
+void ath5k_flush_tx(struct ath5k_hw *ah, bool drop)
+{
+       int i;
+       bool pending = true;
+       unsigned long timeout = jiffies + msecs_to_jiffies(200);
+
+       if (drop)
+               pending = false;
+
+       /* sleep until timeout or all queues are empty */
+       while (pending && !time_after(jiffies, timeout)) {
+               pending = false;
+               for (i = 0; i < ARRAY_SIZE(ah->txqs); i++)
+                       pending |= ath5k_tx_pending(ah, &ah->txqs[i]);
+
+               if (pending)
+                       msleep(10);
+       }
+       ath5k_hw_stop_tx_dma_all(ah);
+       ath5k_drain_tx_buffs(ah);
+}
+
 static void
 ath5k_txq_release(struct ath5k_hw *ah)
 {
diff --git a/drivers/net/wireless/ath/ath5k/base.h 
b/drivers/net/wireless/ath/ath5k/base.h
index 6c94c7f..47a2c33 100644
--- a/drivers/net/wireless/ath/ath5k/base.h
+++ b/drivers/net/wireless/ath/ath5k/base.h
@@ -104,6 +104,7 @@ void ath5k_txbuf_free_skb(struct ath5k_hw *ah, struct 
ath5k_buf *bf);
 void ath5k_rxbuf_free_skb(struct ath5k_hw *ah, struct ath5k_buf *bf);
 void ath5k_tx_queue(struct ieee80211_hw *hw, struct sk_buff *skb,
                    struct ath5k_txq *txq);
+void ath5k_flush_tx(struct ath5k_hw *ah, bool drop);
 
 const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
 
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c 
b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 0560234..de6a3f3 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -801,7 +801,7 @@ const struct ieee80211_ops ath5k_hw_ops = {
        .get_survey             = ath5k_get_survey,
        .set_coverage_class     = ath5k_set_coverage_class,
        /* .rfkill_poll         = not implemented */
-       /* .flush               = not implemented */
+       .flush                  = ath5k_flush_tx,
        /* .channel_switch      = not implemented */
        /* .napi_poll           = not implemented */
        .set_antenna            = ath5k_set_antenna,
-- 
1.7.6


_______________________________________________
ath5k-devel mailing list
ath5k-devel@lists.ath5k.org
https://lists.ath5k.org/mailman/listinfo/ath5k-devel

Reply via email to