summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2014-04-08 07:00:43 +0000
committeradrian <adrian@FreeBSD.org>2014-04-08 07:00:43 +0000
commitc0d54a4c69e89f7b81573de8093fae04889a1a2c (patch)
treef8d0a2db70a792ebb3264eff2042ba1d935d3c62 /sys/dev/ath
parent04202d989d7e105705610dc4d3e05ae0c7f76058 (diff)
downloadFreeBSD-src-c0d54a4c69e89f7b81573de8093fae04889a1a2c.zip
FreeBSD-src-c0d54a4c69e89f7b81573de8093fae04889a1a2c.tar.gz
Don't resume a TID on each filtered frame completion - only do it if
we did suspend it. The whole suspend/resume TID queue thing is supposed to be a matched reference count - a subsystem (eg addba negotiation, BAR transmission, filtered frames, etc) is supposed to call pause() once and then resume() once. ath_tx_tid_filt_comp_complete() is called upon the completion of any filtered frame, regardless of whether the driver had aleady seen a filtered frame and called pause(). So only call resume() if tid->isfiltered = 1, which indicates that we had called pause() once. This fixes a seemingly whacked and different problem - traffic hangs. What was actually going on: * There'd be some marginal link with crappy behaviour, causing filtered frames and BAR TXing to occur; * A BAR TX would occur, setting the new BAW (block-ack window) to seqno n; * .. and pause() would be called, blocking further transmission; * A filtered frame completion would occur from the hardware, but with tid->isfiltered = 0 which indiciates we haven't actually marked the queue yet as filtered; * ath_tx_tid_filt_comp_complete() would call resume(), continuing transmission; * Some frames would be queued to the hardware, since the TID is now no longer paused; * .. and if some make it out and ACked successfully, the new BAW may be seqno n+1 or more; * .. then the BAR TX completes and sets the new seqno back to n. At this point the BAW tracking would be loopy because the BAW start was modified but the BAW ring buffer wasn't updated in lock step. Tested: * Routerstation Pro + AR9220 AP
Diffstat (limited to 'sys/dev/ath')
-rw-r--r--sys/dev/ath/if_ath_tx.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c
index 0c3808c..acd1484 100644
--- a/sys/dev/ath/if_ath_tx.c
+++ b/sys/dev/ath/if_ath_tx.c
@@ -3357,6 +3357,7 @@ static void
ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
{
struct ath_buf *bf;
+ int do_resume = 0;
ATH_TX_LOCK_ASSERT(sc);
@@ -3365,7 +3366,11 @@ ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: hwq=0, transition back\n",
__func__);
- tid->isfiltered = 0;
+ if (tid->isfiltered == 1) {
+ tid->isfiltered = 0;
+ do_resume = 1;
+ }
+
/* XXX ath_tx_tid_resume() also calls ath_tx_set_clrdmask()! */
ath_tx_set_clrdmask(sc, tid->an);
@@ -3375,7 +3380,8 @@ ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
ATH_TID_INSERT_HEAD(tid, bf, bf_list);
}
- ath_tx_tid_resume(sc, tid);
+ if (do_resume)
+ ath_tx_tid_resume(sc, tid);
}
/*
OpenPOWER on IntegriCloud