| From 4b883f021b9ccf2df3d14425e6e610281fb6a35e Mon Sep 17 00:00:00 2001 |
| From: Felix Fietkau <nbd@openwrt.org> |
| Date: Wed, 9 Jan 2013 16:16:56 +0100 |
| Subject: ath9k: fix rx flush handling |
| |
| From: Felix Fietkau <nbd@openwrt.org> |
| |
| commit 4b883f021b9ccf2df3d14425e6e610281fb6a35e upstream. |
| |
| Right now the rx flush is not doing anything useful on AR9003+, as it only |
| works if the buffers in the rx FIFO have not been purged yet, as is done |
| by ath_stoprecv. |
| |
| To fix this, always call ath_flushrecv from within ath_stoprecv before |
| the FIFO is emptied, but still after the hw receive path has been stopped. |
| |
| This ensures that frames received (and ACKed by the hardware) shortly before |
| a reset will be seen by the software, which should improve A-MPDU session |
| stability. |
| |
| Signed-off-by: Felix Fietkau <nbd@openwrt.org> |
| Signed-off-by: John W. Linville <linville@tuxdriver.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/net/wireless/ath/ath9k/ath9k.h | 1 - |
| drivers/net/wireless/ath/ath9k/main.c | 16 +++------------- |
| drivers/net/wireless/ath/ath9k/recv.c | 16 +++++++++------- |
| 3 files changed, 12 insertions(+), 21 deletions(-) |
| |
| --- a/drivers/net/wireless/ath/ath9k/ath9k.h |
| +++ b/drivers/net/wireless/ath/ath9k/ath9k.h |
| @@ -326,7 +326,6 @@ struct ath_rx { |
| |
| int ath_startrecv(struct ath_softc *sc); |
| bool ath_stoprecv(struct ath_softc *sc); |
| -void ath_flushrecv(struct ath_softc *sc); |
| u32 ath_calcrxfilter(struct ath_softc *sc); |
| int ath_rx_init(struct ath_softc *sc, int nbufs); |
| void ath_rx_cleanup(struct ath_softc *sc); |
| --- a/drivers/net/wireless/ath/ath9k/main.c |
| +++ b/drivers/net/wireless/ath/ath9k/main.c |
| @@ -181,7 +181,7 @@ static void ath_restart_work(struct ath_ |
| ath_start_ani(sc); |
| } |
| |
| -static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) |
| +static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx) |
| { |
| struct ath_hw *ah = sc->sc_ah; |
| bool ret = true; |
| @@ -203,14 +203,6 @@ static bool ath_prepare_reset(struct ath |
| if (!ath_drain_all_txq(sc, retry_tx)) |
| ret = false; |
| |
| - if (!flush) { |
| - if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| - ath_rx_tasklet(sc, 1, true); |
| - ath_rx_tasklet(sc, 1, false); |
| - } else { |
| - ath_flushrecv(sc); |
| - } |
| - |
| tasklet_enable(&sc->intr_tq); |
| |
| return ret; |
| @@ -265,7 +257,6 @@ static int ath_reset_internal(struct ath |
| struct ath_common *common = ath9k_hw_common(ah); |
| struct ath9k_hw_cal_data *caldata = NULL; |
| bool fastcc = true; |
| - bool flush = false; |
| int r; |
| |
| __ath_cancel_work(sc); |
| @@ -279,11 +270,10 @@ static int ath_reset_internal(struct ath |
| |
| if (!hchan) { |
| fastcc = false; |
| - flush = true; |
| hchan = ah->curchan; |
| } |
| |
| - if (!ath_prepare_reset(sc, retry_tx, flush)) |
| + if (!ath_prepare_reset(sc, retry_tx)) |
| fastcc = false; |
| |
| ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", |
| @@ -820,7 +810,7 @@ static void ath9k_stop(struct ieee80211_ |
| ath9k_hw_cfg_gpio_input(ah, ah->led_pin); |
| } |
| |
| - ath_prepare_reset(sc, false, true); |
| + ath_prepare_reset(sc, false); |
| |
| if (sc->rx.frag) { |
| dev_kfree_skb_any(sc->rx.frag); |
| --- a/drivers/net/wireless/ath/ath9k/recv.c |
| +++ b/drivers/net/wireless/ath/ath9k/recv.c |
| @@ -472,6 +472,13 @@ start_recv: |
| return 0; |
| } |
| |
| +static void ath_flushrecv(struct ath_softc *sc) |
| +{ |
| + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| + ath_rx_tasklet(sc, 1, true); |
| + ath_rx_tasklet(sc, 1, false); |
| +} |
| + |
| bool ath_stoprecv(struct ath_softc *sc) |
| { |
| struct ath_hw *ah = sc->sc_ah; |
| @@ -482,6 +489,8 @@ bool ath_stoprecv(struct ath_softc *sc) |
| ath9k_hw_setrxfilter(ah, 0); |
| stopped = ath9k_hw_stopdmarecv(ah, &reset); |
| |
| + ath_flushrecv(sc); |
| + |
| if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| ath_edma_stop_recv(sc); |
| else |
| @@ -498,13 +507,6 @@ bool ath_stoprecv(struct ath_softc *sc) |
| return stopped && !reset; |
| } |
| |
| -void ath_flushrecv(struct ath_softc *sc) |
| -{ |
| - if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
| - ath_rx_tasklet(sc, 1, true); |
| - ath_rx_tasklet(sc, 1, false); |
| -} |
| - |
| static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |
| { |
| /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ |