diff options
author | Felix Fietkau <nbd@openwrt.org> | 2013-01-09 10:16:55 -0500 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-01-11 14:12:02 -0500 |
commit | 7fc00a3054b70b1794c2d64db703eb467ad0365c (patch) | |
tree | 3a8c6672e339337b16a6e4bb736d3c6f2d3bb238 | |
parent | 3adcf20afb585993ffee24de36d1975f6b26b120 (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.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/debug.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 4 | ||||
-rw-r--r-- | drivers/net/wireless/ath/ath9k/recv.c | 15 |
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); | |||
646 | enum sc_op_flags { | 646 | enum 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 | ||
502 | void ath_flushrecv(struct ath_softc *sc) | 501 | void 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 | ||
511 | static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) | 508 | static 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; |