aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-01-09 10:16:56 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-01-11 14:12:02 -0500
commit4b883f021b9ccf2df3d14425e6e610281fb6a35e (patch)
treef4df320f27849c070606915d58295ca890878904
parent7fc00a3054b70b1794c2d64db703eb467ad0365c (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.h1
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c16
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
329int ath_startrecv(struct ath_softc *sc); 329int ath_startrecv(struct ath_softc *sc);
330bool ath_stoprecv(struct ath_softc *sc); 330bool ath_stoprecv(struct ath_softc *sc);
331void ath_flushrecv(struct ath_softc *sc);
332u32 ath_calcrxfilter(struct ath_softc *sc); 331u32 ath_calcrxfilter(struct ath_softc *sc);
333int ath_rx_init(struct ath_softc *sc, int nbufs); 332int ath_rx_init(struct ath_softc *sc, int nbufs);
334void ath_rx_cleanup(struct ath_softc *sc); 333void 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
185static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) 185static 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
475static 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
475bool ath_stoprecv(struct ath_softc *sc) 482bool 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
501void 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
508static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) 510static 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 */