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: Felix Fietkau <nbd@openwrt.org> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
7fc00a3054
commit
4b883f021b
|
@ -328,7 +328,6 @@ struct ath_rx {
|
|||
|
||||
int ath_startrecv(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);
|
||||
int ath_rx_init(struct ath_softc *sc, int nbufs);
|
||||
void ath_rx_cleanup(struct ath_softc *sc);
|
||||
|
|
|
@ -182,7 +182,7 @@ static void ath_restart_work(struct ath_softc *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;
|
||||
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))
|
||||
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);
|
||||
|
||||
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 ath9k_hw_cal_data *caldata = NULL;
|
||||
bool fastcc = true;
|
||||
bool flush = false;
|
||||
int r;
|
||||
|
||||
__ath_cancel_work(sc);
|
||||
|
@ -280,11 +271,10 @@ static int ath_reset_internal(struct ath_softc *sc, struct ath9k_channel *hchan,
|
|||
|
||||
if (!hchan) {
|
||||
fastcc = false;
|
||||
flush = true;
|
||||
hchan = ah->curchan;
|
||||
}
|
||||
|
||||
if (!ath_prepare_reset(sc, retry_tx, flush))
|
||||
if (!ath_prepare_reset(sc, retry_tx))
|
||||
fastcc = false;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
ath_prepare_reset(sc, false, true);
|
||||
ath_prepare_reset(sc, false);
|
||||
|
||||
if (sc->rx.frag) {
|
||||
dev_kfree_skb_any(sc->rx.frag);
|
||||
|
|
|
@ -472,6 +472,13 @@ start_recv:
|
|||
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)
|
||||
{
|
||||
struct ath_hw *ah = sc->sc_ah;
|
||||
|
@ -482,6 +489,8 @@ bool ath_stoprecv(struct ath_softc *sc)
|
|||
ath9k_hw_setrxfilter(ah, 0);
|
||||
stopped = ath9k_hw_stopdmarecv(ah, &reset);
|
||||
|
||||
ath_flushrecv(sc);
|
||||
|
||||
if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
|
||||
ath_edma_stop_recv(sc);
|
||||
else
|
||||
|
@ -498,13 +507,6 @@ bool ath_stoprecv(struct ath_softc *sc)
|
|||
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)
|
||||
{
|
||||
/* Check whether the Beacon frame has DTIM indicating buffered bc/mc */
|
||||
|
|
Loading…
Reference in New Issue