svn commit: r227356 - head/sys/dev/ath

Adrian Chadd adrian at FreeBSD.org
Tue Nov 8 19:18:35 UTC 2011


Author: adrian
Date: Tue Nov  8 19:18:34 2011
New Revision: 227356
URL: http://svn.freebsd.org/changeset/base/227356

Log:
  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.

Modified:
  head/sys/dev/ath/if_ath.c

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Tue Nov  8 19:14:15 2011	(r227355)
+++ head/sys/dev/ath/if_ath.c	Tue Nov  8 19:18:34 2011	(r227356)
@@ -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_T
 	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, struc
 	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
 		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)


More information about the svn-src-all mailing list