diff options
author | Adrian Chadd <adrian@FreeBSD.org> | 2011-11-08 19:18:34 +0000 |
---|---|---|
committer | Adrian Chadd <adrian@FreeBSD.org> | 2011-11-08 19:18:34 +0000 |
commit | 16d4de92f92a7fe44920deedb5c2e2a4967ae3ec (patch) | |
tree | aad4937860ba524af8ce9a6d6bfb20c14a76e28d /sys | |
parent | 729bfad6a475d1f71e69c6ee7551983160628dac (diff) | |
download | src-16d4de92f92a7fe44920deedb5c2e2a4967ae3ec.tar.gz src-16d4de92f92a7fe44920deedb5c2e2a4967ae3ec.zip |
Some more various fixes, etc from my 11n branch.
* When doing software TX queue handling and flush, it's possible
that the deletion of a VAP (eg a STA shutdown) will queue a
"STA Disassociate" frame whilst the interface is being deleted.
The VAP is then deleted, and the frame ends up being queued
to a node that is freed before it can be TX'ed. Things go awry
at this point.
There's no way at the present to avoid freeing the underlying node
when the vap is being deleted. It's too late in the game.
I suspect the real fix is to make sure the frame is software
queued with no completion information somehow, so it doesn't
link back to a node whose underlying VAP has been freed.
For now, we'll just have to do this.
* Add some comments showing what's going on.
* Move an instance of the ATH_LOCK() around to protect the interrupt
set. I'll worry about changing that to a PCU lock later on once
the 11n code is in the tree.
Sponsored by: Hobnob, Inc.
Notes
Notes:
svn path=/head/; revision=227356
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ath/if_ath.c | 37 |
1 files changed, 36 insertions, 1 deletions
diff --git a/sys/dev/ath/if_ath.c b/sys/dev/ath/if_ath.c index b4662f5e68eb..12f7261abf29 100644 --- a/sys/dev/ath/if_ath.c +++ b/sys/dev/ath/if_ath.c @@ -1133,6 +1133,26 @@ ath_vap_delete(struct ieee80211vap *vap) } ieee80211_vap_detach(vap); + + /* + * XXX Danger Will Robinson! Danger! + * + * Because ieee80211_vap_detach() can queue a frame (the station + * diassociate message?) after we've drained the TXQ and + * flushed the software TXQ, we will end up with a frame queued + * to a node whose vap is about to be freed. + * + * To work around this, flush the hardware/software again. + * This may be racy - the ath task may be running and the packet + * may be being scheduled between sw->hw txq. Tsk. + * + * TODO: figure out why a new node gets allocated somewhere around + * here (after the ath_tx_swq() call; and after an ath_stop_locked() + * call!) + */ + + ath_draintxq(sc, ATH_RESET_DEFAULT); + ATH_LOCK(sc); /* * Reclaim beacon state. Note this must be done before @@ -1180,7 +1200,6 @@ ath_vap_delete(struct ieee80211vap *vap) sc->sc_swbmiss = 0; } #endif - ATH_UNLOCK(sc); free(avp, M_80211_VAP); if (ifp->if_drv_flags & IFF_DRV_RUNNING) { @@ -1201,6 +1220,7 @@ ath_vap_delete(struct ieee80211vap *vap) } ath_hal_intrset(ah, sc->sc_imask); } + ATH_UNLOCK(sc); } void @@ -1798,6 +1818,7 @@ ath_reset(struct ifnet *ifp, ATH_RESET_TYPE reset_type) HAL_STATUS status; DPRINTF(sc, ATH_DEBUG_RESET, "%s: called\n", __func__); + ath_hal_intrset(ah, 0); /* disable interrupts */ ath_draintxq(sc, reset_type); /* stop xmit side */ /* @@ -2748,10 +2769,18 @@ ath_bstuck_proc(void *arg, int pending) { struct ath_softc *sc = arg; struct ifnet *ifp = sc->sc_ifp; + uint32_t hangs = 0; + + if (ath_hal_gethangstate(sc->sc_ah, 0xff, &hangs) && hangs != 0) + if_printf(ifp, "bb hang detected (0x%x)\n", hangs); if_printf(ifp, "stuck beacon; resetting (bmiss count %u)\n", sc->sc_bmisscount); sc->sc_stats.ast_bstuck++; + /* + * This assumes that there's no simultaneous channel mode change + * occuring. + */ ath_reset(ifp, ATH_RESET_NOLOSS); } @@ -3955,6 +3984,7 @@ ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum) txq->axq_qnum = qnum; txq->axq_ac = 0; txq->axq_depth = 0; + txq->axq_aggr_depth = 0; txq->axq_intrcnt = 0; txq->axq_link = NULL; txq->axq_softc = sc; @@ -4085,6 +4115,10 @@ ath_txq_update(struct ath_softc *sc, int ac) qi.tqi_burstTime = qi.tqi_readyTime; } else { #endif + /* + * XXX shouldn't this just use the default flags + * used in the previous queue setup? + */ qi.tqi_qflags = HAL_TXQ_TXOKINT_ENABLE | HAL_TXQ_TXERRINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE @@ -4430,6 +4464,7 @@ ath_tx_proc(void *arg, int npending) ath_start(ifp); } +#undef TXQACTIVE static void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) |