[ 38/89] ath9k: add a better fix for the rx tasklet vs rx flush race

From: Greg Kroah-Hartman
Date: Fri Feb 01 2013 - 08:22:32 EST


3.7-stable review patch. If anyone has any objections, please let me know.

------------------

From: Felix Fietkau <nbd@xxxxxxxxxxx>

commit 7fc00a3054b70b1794c2d64db703eb467ad0365c upstream.

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.

Signed-off-by: Felix Fietkau <nbd@xxxxxxxxxxx>
Signed-off-by: John W. Linville <linville@xxxxxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
drivers/net/wireless/ath/ath9k/ath9k.h | 1 -
drivers/net/wireless/ath/ath9k/debug.c | 1 -
drivers/net/wireless/ath/ath9k/debug.h | 2 --
drivers/net/wireless/ath/ath9k/main.c | 4 ++++
drivers/net/wireless/ath/ath9k/recv.c | 15 ---------------
5 files changed, 4 insertions(+), 19 deletions(-)

--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -630,7 +630,6 @@ void ath_ant_comb_update(struct ath_soft
enum sc_op_flags {
SC_OP_INVALID,
SC_OP_BEACONS,
- SC_OP_RXFLUSH,
SC_OP_ANI_RUN,
SC_OP_PRIM_STA_VIF,
SC_OP_HW_RESET,
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -973,7 +973,6 @@ static ssize_t read_file_recv(struct fil
RXS_ERR("RX-LENGTH-ERR", rx_len_err);
RXS_ERR("RX-OOM-ERR", rx_oom_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);

PHY_ERR("UNDERRUN ERR", ATH9K_PHYERR_UNDERRUN);
--- a/drivers/net/wireless/ath/ath9k/debug.h
+++ b/drivers/net/wireless/ath/ath9k/debug.h
@@ -200,7 +200,6 @@ struct ath_tx_stats {
* @rx_oom_err: No. of frames dropped due to OOM issues.
* @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_drop_rxflush: No. of frames dropped due to RX-FLUSH.
* @rx_beacons: No. of beacons received.
* @rx_frags: No. of rx-fragements received.
*/
@@ -219,7 +218,6 @@ struct ath_rx_stats {
u32 rx_oom_err;
u32 rx_rate_err;
u32 rx_too_many_frags_err;
- u32 rx_drop_rxflush;
u32 rx_beacons;
u32 rx_frags;
};
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -195,6 +195,8 @@ static bool ath_prepare_reset(struct ath
ath9k_debug_samp_bb_mac(sc);
ath9k_hw_disable_interrupts(ah);

+ tasklet_disable(&sc->intr_tq);
+
if (!ath_stoprecv(sc))
ret = false;

@@ -209,6 +211,8 @@ static bool ath_prepare_reset(struct ath
ath_flushrecv(sc);
}

+ tasklet_enable(&sc->intr_tq);
+
return ret;
}

--- 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, in

spin_lock_init(&sc->sc_pcu_lock);
spin_lock_init(&sc->rx.rxbuflock);
- clear_bit(SC_OP_RXFLUSH, &sc->sc_flags);

common->rx_bufsize = IEEE80211_MAX_MPDU_LEN / 2 +
sc->sc_ah->caps.rx_status_len;
@@ -501,11 +500,9 @@ bool ath_stoprecv(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)
ath_rx_tasklet(sc, 1, true);
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)
@@ -1067,9 +1064,6 @@ int ath_rx_tasklet(struct ath_softc *sc,

do {
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));
if (edma)
@@ -1109,15 +1103,6 @@ int ath_rx_tasklet(struct ath_softc *sc,
sc->rx.num_pkts++;
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));

rxs->mactime = (tsf & ~0xffffffffULL) | rs.rs_tstamp;


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/