diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-01-09 10:16:56 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-01-11 14:12:02 -0500 |
commit | 4b883f021b9ccf2df3d14425e6e610281fb6a35e (patch) | |
tree | f4df320f27849c070606915d58295ca890878904 | |
parent | 7fc00a3054b70b1794c2d64db703eb467ad0365c (diff) |
ath9k: fix rx flush handling
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.
Cc: stable@vger.kernel.org
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath/ath9k/ath9k.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 16 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 16 |
3 files changed, 12 insertions, 21 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 7335e9ef0249..32b2d5cd9a5a 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h | |||
@@ -328,7 +328,6 @@ struct ath_rx { | |||
328 | 328 | ||
329 | int ath_startrecv(struct ath_softc *sc); | 329 | int ath_startrecv(struct ath_softc *sc); |
330 | bool ath_stoprecv(struct ath_softc *sc); | 330 | bool ath_stoprecv(struct ath_softc *sc); |
331 | void ath_flushrecv(struct ath_softc *sc); | ||
332 | u32 ath_calcrxfilter(struct ath_softc *sc); | 331 | u32 ath_calcrxfilter(struct ath_softc *sc); |
333 | int ath_rx_init(struct ath_softc *sc, int nbufs); | 332 | int ath_rx_init(struct ath_softc *sc, int nbufs); |
334 | void ath_rx_cleanup(struct ath_softc *sc); | 333 | void ath_rx_cleanup(struct ath_softc *sc); |
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index d3cf01ec2d15..9844b758f81d 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc) | |||
182 | ath_start_ani(sc); | 182 | ath_start_ani(sc); |
183 | } | 183 | } |
184 | 184 | ||
185 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | 185 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx) |
186 | { | 186 | { |
187 | struct ath_hw *ah = sc->sc_ah; | 187 | struct ath_hw *ah = sc->sc_ah; |
188 | bool ret = true; | 188 | bool ret = true; |
@@ -204,14 +204,6 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | |||
204 | if (!ath_drain_all_txq(sc, retry_tx)) | 204 | if (!ath_drain_all_txq(sc, retry_tx)) |
205 | ret = false; | 205 | ret = false; |
206 | 206 | ||
207 | if (!flush) { | ||
208 | if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
209 | ath_rx_tasklet(sc, 1, true); | ||
210 | ath_rx_tasklet(sc, 1, false); | ||
211 | } else { | ||
212 | ath_flushrecv(sc); | ||
213 | } | ||
214 | |||
215 | tasklet_enable(&sc->intr_tq); | 207 | tasklet_enable(&sc->intr_tq); |
216 | 208 | ||
217 | return ret; | 209 | return ret; |
@@ -266,7 +258,6 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | |||
266 | struct ath_common *common = ath9k_hw_common(ah); | 258 | struct ath_common *common = ath9k_hw_common(ah); |
267 | struct ath9k_hw_cal_data *caldata = NULL; | 259 | struct ath9k_hw_cal_data *caldata = NULL; |
268 | bool fastcc = true; | 260 | bool fastcc = true; |
269 | bool flush = false; | ||
270 | int r; | 261 | int r; |
271 | 262 | ||
272 | __ath_cancel_work(sc); | 263 | __ath_cancel_work(sc); |
@@ -280,11 +271,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan, | |||
280 | 271 | ||
281 | if (!hchan) { | 272 | if (!hchan) { |
282 | fastcc = false; | 273 | fastcc = false; |
283 | flush = true; | ||
284 | hchan = ah->curchan; | 274 | hchan = ah->curchan; |
285 | } | 275 | } |
286 | 276 | ||
287 | if (!ath_prepare_reset(sc, retry_tx, flush)) | 277 | if (!ath_prepare_reset(sc, retry_tx)) |
288 | fastcc = false; | 278 | fastcc = false; |
289 | 279 | ||
290 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", | 280 | ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n", |
@@ -808,7 +798,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
808 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); | 798 | ath9k_hw_cfg_gpio_input(ah, ah->led_pin); |
809 | } | 799 | } |
810 | 800 | ||
811 | ath_prepare_reset(sc, false, true); | 801 | ath_prepare_reset(sc, false); |
812 | 802 | ||
813 | if (sc->rx.frag) { | 803 | if (sc->rx.frag) { |
814 | dev_kfree_skb_any(sc->rx.frag); | 804 | dev_kfree_skb_any(sc->rx.frag); |
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6b83b3bbfe8c..67f58d4bb10e 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c | |||
@@ -472,6 +472,13 @@ start_recv: | |||
472 | return 0; | 472 | return 0; |
473 | } | 473 | } |
474 | 474 | ||
475 | static void ath_flushrecv(struct ath_softc *sc) | ||
476 | { | ||
477 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
478 | ath_rx_tasklet(sc, 1, true); | ||
479 | ath_rx_tasklet(sc, 1, false); | ||
480 | } | ||
481 | |||
475 | bool ath_stoprecv(struct ath_softc *sc) | 482 | bool ath_stoprecv(struct ath_softc *sc) |
476 | { | 483 | { |
477 | struct ath_hw *ah = sc->sc_ah; | 484 | struct ath_hw *ah = sc->sc_ah; |
@@ -482,6 +489,8 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
482 | ath9k_hw_setrxfilter(ah, 0); | 489 | ath9k_hw_setrxfilter(ah, 0); |
483 | stopped = ath9k_hw_stopdmarecv(ah, &reset); | 490 | stopped = ath9k_hw_stopdmarecv(ah, &reset); |
484 | 491 | ||
492 | ath_flushrecv(sc); | ||
493 | |||
485 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | 494 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) |
486 | ath_edma_stop_recv(sc); | 495 | ath_edma_stop_recv(sc); |
487 | else | 496 | else |
@@ -498,13 +507,6 @@ bool ath_stoprecv(struct ath_softc *sc) | |||
498 | return stopped && !reset; | 507 | return stopped && !reset; |
499 | } | 508 | } |
500 | 509 | ||
501 | void ath_flushrecv(struct ath_softc *sc) | ||
502 | { | ||
503 | if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) | ||
504 | ath_rx_tasklet(sc, 1, true); | ||
505 | ath_rx_tasklet(sc, 1, false); | ||
506 | } | ||
507 | |||
508 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | 510 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) |
509 | { | 511 | { |
510 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ | 512 | /* Check whether the Beacon frame has DTIM indicating buffered bc/mc */ |