svn commit: r264708 - head/sys/dev/ath
Adrian Chadd
adrian at FreeBSD.org
Mon Apr 21 01:02:50 UTC 2014
Author: adrian
Date: Mon Apr 21 01:02:49 2014
New Revision: 264708
URL: http://svnweb.freebsd.org/changeset/base/264708
Log:
Fix a cleanup hang if cleanup gets called _during_ an active cleanup.
During power save testing I noticed that the cleanup code is being
called during a RUN->RUN state transition. It's because the net80211
stack is treating that (for reasons I don't quitey know yet) as a
reassociation and this calls the node cleanup code. The reason it's
seeing a RUN->RUN transition is because during active power save
stuff it's possible that the RUN->SLEEP and SLEEP->RUN transitions
happen so quickly that the deferred net80211 vap state code
"loses" a transition, namely the intermediary SLEEP transition.
So, this was causing the node reassociation code to sometimes be called
twice in quick succession and this would result in ath_tx_tid_cleanup()
to be called again. The code calling it would always call pause, and
then only call resume if the TID didn't have "cleanup_inprogress" set.
Unfortunately it didn't check if it was already set on entry, so it
would pause but not call resume. Thus, paused would be called more
than once (once before each entry into ath-tx_tid_cleanup()) but resume
would only be called once when the cleanup state was finished.
This doesn't entirely fix all of the issues seen in the cleanup path
but it's a necessary first step.
Since this is a stability fix, it should be merged to stable/10 at some
point.
Tested:
* AR5416, STA mode
MFC after: 7 days
Modified:
head/sys/dev/ath/if_ath_tx.c
Modified: head/sys/dev/ath/if_ath_tx.c
==============================================================================
--- head/sys/dev/ath/if_ath_tx.c Sun Apr 20 23:01:56 2014 (r264707)
+++ head/sys/dev/ath/if_ath_tx.c Mon Apr 21 01:02:49 2014 (r264708)
@@ -5789,12 +5789,26 @@ ath_addba_stop(struct ieee80211_node *ni
*/
TAILQ_INIT(&bf_cq);
ATH_TX_LOCK(sc);
- ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
+
/*
- * Unpause the TID if no cleanup is required.
+ * In case there's a followup call to this, only call it
+ * if we don't have a cleanup in progress.
+ *
+ * Since we've paused the queue above, we need to make
+ * sure we unpause if there's already a cleanup in
+ * progress - it means something else is also doing
+ * this stuff, so we don't need to also keep it paused.
*/
- if (! atid->cleanup_inprogress)
+ if (atid->cleanup_inprogress) {
ath_tx_tid_resume(sc, atid);
+ } else {
+ ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
+ /*
+ * Unpause the TID if no cleanup is required.
+ */
+ if (! atid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, atid);
+ }
ATH_TX_UNLOCK(sc);
/* Handle completing frames and fail them */
@@ -5828,19 +5842,25 @@ ath_tx_node_reassoc(struct ath_softc *sc
tid = &an->an_tid[i];
if (tid->hwq_depth == 0)
continue;
- ath_tx_tid_pause(sc, tid);
DPRINTF(sc, ATH_DEBUG_NODE,
"%s: %6D: TID %d: cleaning up TID\n",
__func__,
an->an_node.ni_macaddr,
":",
i);
- ath_tx_tid_cleanup(sc, an, i, &bf_cq);
/*
- * Unpause the TID if no cleanup is required.
+ * In case there's a followup call to this, only call it
+ * if we don't have a cleanup in progress.
*/
- if (! tid->cleanup_inprogress)
- ath_tx_tid_resume(sc, tid);
+ if (! tid->cleanup_inprogress) {
+ ath_tx_tid_pause(sc, tid);
+ ath_tx_tid_cleanup(sc, an, i, &bf_cq);
+ /*
+ * Unpause the TID if no cleanup is required.
+ */
+ if (! tid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, tid);
+ }
}
ATH_TX_UNLOCK(sc);
More information about the svn-src-all
mailing list