aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2013-01-09 10:16:55 -0500
committerJohn W. Linville <linville@tuxdriver.com>2013-01-11 14:12:02 -0500
commit7fc00a3054b70b1794c2d64db703eb467ad0365c (patch)
tree3a8c6672e339337b16a6e4bb736d3c6f2d3bb238
parent3adcf20afb585993ffee24de36d1975f6b26b120 (diff)
ath9k: add a better fix for the rx tasklet vs rx flush race
Ensure that the rx tasklet is no longer running when entering the reset path. Also remove the distinction between flush and no-flush frame processing. If a frame has been received and ACKed by the hardware, the stack needs to see it, so that the BA receive window does not go out of sync. 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/debug.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.h2
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c15
5 files changed, 4 insertions, 19 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 86e26a19efda..7335e9ef0249 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -646,7 +646,6 @@ void ath_ant_comb_update(struct ath_softc *sc);
646enum sc_op_flags { 646enum sc_op_flags {
647 SC_OP_INVALID, 647 SC_OP_INVALID,
648 SC_OP_BEACONS, 648 SC_OP_BEACONS,
649 SC_OP_RXFLUSH,
650 SC_OP_ANI_RUN, 649 SC_OP_ANI_RUN,
651 SC_OP_PRIM_STA_VIF, 650 SC_OP_PRIM_STA_VIF,
652 SC_OP_HW_RESET, 651 SC_OP_HW_RESET,
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 13ff9edc2401..e585fc827c50 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -861,7 +861,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
861 RXS_ERR("RX-LENGTH-ERR", rx_len_err); 861 RXS_ERR("RX-LENGTH-ERR", rx_len_err);
862 RXS_ERR("RX-OOM-ERR", rx_oom_err); 862 RXS_ERR("RX-OOM-ERR", rx_oom_err);
863 RXS_ERR("RX-RATE-ERR", rx_rate_err); 863 RXS_ERR("RX-RATE-ERR", rx_rate_err);
864 RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush);
865 RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); 864 RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
866 865
867 PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); 866 PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h
index 375c3b46411e..6df2ab62dcb7 100644
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -216,7 +216,6 @@ struct ath_tx_stats {
216 * @rx_oom_err: No. of frames dropped due to OOM issues. 216 * @rx_oom_err: No. of frames dropped due to OOM issues.
217 * @rx_rate_err: No. of frames dropped due to rate errors. 217 * @rx_rate_err: No. of frames dropped due to rate errors.
218 * @rx_too_many_frags_err: Frames dropped due to too-many-frags received. 218 * @rx_too_many_frags_err: Frames dropped due to too-many-frags received.
219 * @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH.
220 * @rx_beacons: No. of beacons received. 219 * @rx_beacons: No. of beacons received.
221 * @rx_frags: No. of rx-fragements received. 220 * @rx_frags: No. of rx-fragements received.
222 */ 221 */
@@ -235,7 +234,6 @@ struct ath_rx_stats {
235 u32 rx_oom_err; 234 u32 rx_oom_err;
236 u32 rx_rate_err; 235 u32 rx_rate_err;
237 u32 rx_too_many_frags_err; 236 u32 rx_too_many_frags_err;
238 u32 rx_drop_rxflush;
239 u32 rx_beacons; 237 u32 rx_beacons;
240 u32 rx_frags; 238 u32 rx_frags;
241}; 239};
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index be30a9af1528..d3cf01ec2d15 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -196,6 +196,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
196 ath9k_debug_samp_bb_mac(sc); 196 ath9k_debug_samp_bb_mac(sc);
197 ath9k_hw_disable_interrupts(ah); 197 ath9k_hw_disable_interrupts(ah);
198 198
199 tasklet_disable(&sc->intr_tq);
200
199 if (!ath_stoprecv(sc)) 201 if (!ath_stoprecv(sc))
200 ret = false; 202 ret = false;
201 203
@@ -210,6 +212,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
210 ath_flushrecv(sc); 212 ath_flushrecv(sc);
211 } 213 }
212 214
215 tasklet_enable(&sc->intr_tq);
216
213 return ret; 217 return ret;
214} 218}
215 219
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 01c3ba47a5b9..6b83b3bbfe8c 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -286,7 +286,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
286 286
287 spin_lock_init(&sc->sc_pcu_lock); 287 spin_lock_init(&sc->sc_pcu_lock);
288 spin_lock_init(&sc->rx.rxbuflock); 288 spin_lock_init(&sc->rx.rxbuflock);
289 clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
290 289
291 common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + 290 common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
292 sc->sc_ah->caps.rx_status_len; 291 sc->sc_ah->caps.rx_status_len;
@@ -501,11 +500,9 @@ bool ath_stoprecv(struct ath_softc *sc)
501 500
502void ath_flushrecv(struct ath_softc *sc) 501void ath_flushrecv(struct ath_softc *sc)
503{ 502{
504 set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
505 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) 503 if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
506 ath_rx_tasklet(sc, 1, true); 504 ath_rx_tasklet(sc, 1, true);
507 ath_rx_tasklet(sc, 1, false); 505 ath_rx_tasklet(sc, 1, false);
508 clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
509} 506}
510 507
511static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) 508static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
@@ -1067,9 +1064,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1067 1064
1068 do { 1065 do {
1069 bool decrypt_error = false; 1066 bool decrypt_error = false;
1070 /* If handling rx interrupt and flush is in progress => exit */
1071 if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
1072 break;
1073 1067
1074 memset(&rs, 0, sizeof(rs)); 1068 memset(&rs, 0, sizeof(rs));
1075 if (edma) 1069 if (edma)
@@ -1112,15 +1106,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
1112 1106
1113 ath_debug_stat_rx(sc, &rs); 1107 ath_debug_stat_rx(sc, &rs);
1114 1108
1115 /*
1116 * If we're asked to flush receive queue, directly
1117 * chain it back at the queue without processing it.
1118 */
1119 if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
1120 RX_STAT_INC(rx_drop_rxflush);
1121 goto requeue_drop_frag;
1122 }
1123
1124 memset(rxs, 0, sizeof(struct ieee80211_rx_status)); 1109 memset(rxs, 0, sizeof(struct ieee80211_rx_status));
1125 1110
1126 rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; 1111 rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;