Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b883f02 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville
Browse files

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: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 7fc00a30
Loading
Loading
Loading
Loading
+0 −1
Original line number Original line Diff line number Diff line
@@ -328,7 +328,6 @@ struct ath_rx {


int ath_startrecv(struct ath_softc *sc);
int ath_startrecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
bool ath_stoprecv(struct ath_softc *sc);
void ath_flushrecv(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
u32 ath_calcrxfilter(struct ath_softc *sc);
int ath_rx_init(struct ath_softc *sc, int nbufs);
int ath_rx_init(struct ath_softc *sc, int nbufs);
void ath_rx_cleanup(struct ath_softc *sc);
void ath_rx_cleanup(struct ath_softc *sc);
+3 −13
Original line number Original line Diff line number Diff line
@@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *sc)
	ath_start_ani(sc);
	ath_start_ani(sc);
}
}


static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx)
{
{
	struct ath_hw *ah = sc->sc_ah;
	struct ath_hw *ah = sc->sc_ah;
	bool ret = true;
	bool ret = true;
@@ -204,14 +204,6 @@ static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush)
	if (!ath_drain_all_txq(sc, retry_tx))
	if (!ath_drain_all_txq(sc, retry_tx))
		ret = false;
		ret = false;


	if (!flush) {
		if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
			ath_rx_tasklet(sc, 1, true);
		ath_rx_tasklet(sc, 1, false);
	} else {
		ath_flushrecv(sc);
	}

	tasklet_enable(&sc->intr_tq);
	tasklet_enable(&sc->intr_tq);


	return ret;
	return ret;
@@ -266,7 +258,6 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
	struct ath_common *common = ath9k_hw_common(ah);
	struct ath_common *common = ath9k_hw_common(ah);
	struct ath9k_hw_cal_data *caldata = NULL;
	struct ath9k_hw_cal_data *caldata = NULL;
	bool fastcc = true;
	bool fastcc = true;
	bool flush = false;
	int r;
	int r;


	__ath_cancel_work(sc);
	__ath_cancel_work(sc);
@@ -280,11 +271,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,


	if (!hchan) {
	if (!hchan) {
		fastcc = false;
		fastcc = false;
		flush = true;
		hchan = ah->curchan;
		hchan = ah->curchan;
	}
	}


	if (!ath_prepare_reset(sc, retry_tx, flush))
	if (!ath_prepare_reset(sc, retry_tx))
		fastcc = false;
		fastcc = false;


	ath_dbg(common, CONFIG, "Reset to %u MHz, HT40: %d fastcc: %d\n",
	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)
		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
		ath9k_hw_cfg_gpio_input(ah, ah->led_pin);
	}
	}


	ath_prepare_reset(sc, false, true);
	ath_prepare_reset(sc, false);


	if (sc->rx.frag) {
	if (sc->rx.frag) {
		dev_kfree_skb_any(sc->rx.frag);
		dev_kfree_skb_any(sc->rx.frag);
+9 −7
Original line number Original line Diff line number Diff line
@@ -472,6 +472,13 @@ start_recv:
	return 0;
	return 0;
}
}


static void ath_flushrecv(struct ath_softc *sc)
{
	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
		ath_rx_tasklet(sc, 1, true);
	ath_rx_tasklet(sc, 1, false);
}

bool ath_stoprecv(struct ath_softc *sc)
bool ath_stoprecv(struct ath_softc *sc)
{
{
	struct ath_hw *ah = sc->sc_ah;
	struct ath_hw *ah = sc->sc_ah;
@@ -482,6 +489,8 @@ bool ath_stoprecv(struct ath_softc *sc)
	ath9k_hw_setrxfilter(ah, 0);
	ath9k_hw_setrxfilter(ah, 0);
	stopped = ath9k_hw_stopdmarecv(ah, &reset);
	stopped = ath9k_hw_stopdmarecv(ah, &reset);


	ath_flushrecv(sc);

	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
		ath_edma_stop_recv(sc);
		ath_edma_stop_recv(sc);
	else
	else
@@ -498,13 +507,6 @@ bool ath_stoprecv(struct ath_softc *sc)
	return stopped && !reset;
	return stopped && !reset;
}
}


void ath_flushrecv(struct ath_softc *sc)
{
	if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
		ath_rx_tasklet(sc, 1, true);
	ath_rx_tasklet(sc, 1, false);
}

static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
static bool ath_beacon_dtim_pending_cab(struct sk_buff *skb)
{
{
	/* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
	/* Check whether the Beacon frame has DTIM indicating buffered bc/mc */