Commit 7fc00a30 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

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: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 3adcf20a
...@@ -646,7 +646,6 @@ void ath_ant_comb_update(struct ath_softc *sc); ...@@ -646,7 +646,6 @@ void ath_ant_comb_update(struct ath_softc *sc);
enum sc_op_flags { enum sc_op_flags {
SC_OP_INVALID, SC_OP_INVALID,
SC_OP_BEACONS, SC_OP_BEACONS,
SC_OP_RXFLUSH,
SC_OP_ANI_RUN, SC_OP_ANI_RUN,
SC_OP_PRIM_STA_VIF, SC_OP_PRIM_STA_VIF,
SC_OP_HW_RESET, SC_OP_HW_RESET,
......
...@@ -861,7 +861,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf, ...@@ -861,7 +861,6 @@ static ssize_t read_file_recv(struct file *file, char __user *user_buf,
RXS_ERR("RX-LENGTH-ERR", rx_len_err); RXS_ERR("RX-LENGTH-ERR", rx_len_err);
RXS_ERR("RX-OOM-ERR", rx_oom_err); RXS_ERR("RX-OOM-ERR", rx_oom_err);
RXS_ERR("RX-RATE-ERR", rx_rate_err); RXS_ERR("RX-RATE-ERR", rx_rate_err);
RXS_ERR("RX-DROP-RXFLUSH", rx_drop_rxflush);
RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err); RXS_ERR("RX-TOO-MANY-FRAGS", rx_too_many_frags_err);
PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN); PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
......
...@@ -216,7 +216,6 @@ struct ath_tx_stats { ...@@ -216,7 +216,6 @@ struct ath_tx_stats {
* @rx_oom_err: No. of frames dropped due to OOM issues. * @rx_oom_err: No. of frames dropped due to OOM issues.
* @rx_rate_err: No. of frames dropped due to rate errors. * @rx_rate_err: No. of frames dropped due to rate errors.
* @rx_too_many_frags_err: Frames dropped due to too-many-frags received. * @rx_too_many_frags_err: Frames dropped due to too-many-frags received.
* @rx_drop_rxflush: No. of frames dropped due to RX-FLUSH.
* @rx_beacons: No. of beacons received. * @rx_beacons: No. of beacons received.
* @rx_frags: No. of rx-fragements received. * @rx_frags: No. of rx-fragements received.
*/ */
...@@ -235,7 +234,6 @@ struct ath_rx_stats { ...@@ -235,7 +234,6 @@ struct ath_rx_stats {
u32 rx_oom_err; u32 rx_oom_err;
u32 rx_rate_err; u32 rx_rate_err;
u32 rx_too_many_frags_err; u32 rx_too_many_frags_err;
u32 rx_drop_rxflush;
u32 rx_beacons; u32 rx_beacons;
u32 rx_frags; u32 rx_frags;
}; };
......
...@@ -196,6 +196,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) ...@@ -196,6 +196,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
ath9k_debug_samp_bb_mac(sc); ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah); ath9k_hw_disable_interrupts(ah);
tasklet_disable(&sc->intr_tq);
if (!ath_stoprecv(sc)) if (!ath_stoprecv(sc))
ret = false; ret = false;
...@@ -210,6 +212,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) ...@@ -210,6 +212,8 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
ath_flushrecv(sc); ath_flushrecv(sc);
} }
tasklet_enable(&sc->intr_tq);
return ret; return ret;
} }
......
...@@ -286,7 +286,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) ...@@ -286,7 +286,6 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
spin_lock_init(&sc->sc_pcu_lock); spin_lock_init(&sc->sc_pcu_lock);
spin_lock_init(&sc->rx.rxbuflock); spin_lock_init(&sc->rx.rxbuflock);
clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 + common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
sc->sc_ah->caps.rx_status_len; sc->sc_ah->caps.rx_status_len;
...@@ -501,11 +500,9 @@ bool ath_stoprecv(struct ath_softc *sc) ...@@ -501,11 +500,9 @@ bool ath_stoprecv(struct ath_softc *sc)
void ath_flushrecv(struct ath_softc *sc) void ath_flushrecv(struct ath_softc *sc)
{ {
set_bit(SC_OP_RXFLUSH, &sc->sc_flags);
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
ath_rx_tasklet(sc, 1, true); ath_rx_tasklet(sc, 1, true);
ath_rx_tasklet(sc, 1, false); ath_rx_tasklet(sc, 1, false);
clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);
} }
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb) 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,9 +1064,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
do { do {
bool decrypt_error = false; bool decrypt_error = false;
/* If handling rx interrupt and flush is in progress => exit */
if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags) && (flush == 0))
break;
memset(&rs, 0, sizeof(rs)); memset(&rs, 0, sizeof(rs));
if (edma) if (edma)
...@@ -1112,15 +1106,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp) ...@@ -1112,15 +1106,6 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
ath_debug_stat_rx(sc, &rs); ath_debug_stat_rx(sc, &rs);
/*
* If we're asked to flush receive queue, directly
* chain it back at the queue without processing it.
*/
if (test_bit(SC_OP_RXFLUSH, &sc->sc_flags)) {
RX_STAT_INC(rx_drop_rxflush);
goto requeue_drop_frag;
}
memset(rxs, 0, sizeof(struct ieee80211_rx_status)); memset(rxs, 0, sizeof(struct ieee80211_rx_status));
rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp; rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment