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