svn commit: r223028 - user/adrian/if_ath_tx/sys/dev/ath

Adrian Chadd adrian at FreeBSD.org
Mon Jun 13 00:55:29 UTC 2011


Author: adrian
Date: Mon Jun 13 00:55:29 2011
New Revision: 223028
URL: http://svn.freebsd.org/changeset/base/223028

Log:
  Add new mutexes - one protecting the sc txqueue slist and one for ath_node
  
  Since ath_node now contains useful data that will be accessed concurrently,
  protect it with a mutex.
  
  Migrate the sc->sc_txnodeq out of ATH_LOCK and behind its own lock.
  
  Since the rate control logic uses state in ath_node (ie, "stuff" attached
  after it), add some mutexes to the rate control calls.
  
  It's likely the locking isn't completely correct yet.

Modified:
  user/adrian/if_ath_tx/sys/dev/ath/if_ath.c
  user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
  user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath.c	Sun Jun 12 23:45:46 2011	(r223027)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath.c	Mon Jun 13 00:55:29 2011	(r223028)
@@ -741,6 +741,9 @@ ath_attach(u_int16_t devid, struct ath_s
 
 	/* Setup software TX queue related bits */
 	STAILQ_INIT(&sc->sc_txnodeq);
+	snprintf(sc->sc_txnodeq_name, sizeof(sc->sc_txnodeq_name),
+	    "%s: txnodeq\n", device_get_nameunit(sc->sc_dev));
+	ATH_TXNODE_LOCK_INIT(sc);
 
 	if (bootverbose)
 		ieee80211_announce(ic);
@@ -793,6 +796,7 @@ ath_detach(struct ath_softc *sc)
 	ath_desc_free(sc);
 	ath_tx_cleanup(sc);
 	ath_hal_detach(sc->sc_ah);	/* NB: sets chip in full sleep */
+	ATH_TXNODE_LOCK_DESTROY(sc);
 	if_free(ifp);
 
 	return 0;
@@ -3120,6 +3124,11 @@ ath_node_alloc(struct ieee80211vap *vap,
 	}
 	ath_rate_node_init(sc, an);
 
+	/* Setup the mutex - there's no associd yet so set the name to NULL */
+	snprintf(an->an_name, sizeof(an->an_name), "%s: node %p",
+	    device_get_nameunit(sc->sc_dev), an);
+	mtx_init(&an->an_mtx, an->an_name, NULL, MTX_DEF);
+
 	/* XXX setup ath_tid */
 	ath_tx_tid_init(sc, an);
 
@@ -3139,6 +3148,7 @@ ath_node_free(struct ieee80211_node *ni)
 	ath_tx_tid_cleanup(sc, ATH_NODE(ni));
 
 	ath_rate_node_cleanup(sc, ATH_NODE(ni));
+	mtx_destroy(&ATH_NODE(ni)->an_mtx);
 	sc->sc_node_free(ni);
 }
 

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Sun Jun 12 23:45:46 2011	(r223027)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Mon Jun 13 00:55:29 2011	(r223028)
@@ -649,8 +649,10 @@ ath_tx_normal_setup(struct ath_softc *sc
 				txrate |= rt->info[rix].shortPreamble;
 			try0 = ATH_TXMAXTRY;	/* XXX?too many? */
 		} else {
+			ATH_NODE_LOCK(an);
 			ath_rate_findrate(sc, an, shortPreamble, pktlen,
 				&rix, &try0, &txrate);
+			ATH_NODE_UNLOCK(an);
 			sc->sc_txrix = rix;		/* for LED blinking */
 			sc->sc_lastdatarix = rix;	/* for fast frames */
 			if (try0 != ATH_TXMAXTRY)
@@ -885,10 +887,12 @@ ath_tx_normal_setup(struct ath_softc *sc
 	 * we don't use it.
 	 */
         if (ismrr) {
+		ATH_NODE_LOCK(an);
                 if (ath_tx_is_11n(sc))
                         ath_rate_getxtxrates(sc, an, rix, rate, try);
                 else
                         ath_rate_setupxtxdesc(sc, an, ds, shortPreamble, rix);
+		ATH_NODE_UNLOCK(an);
         }
 
         if (ath_tx_is_11n(sc)) {
@@ -1222,15 +1226,14 @@ bad:
  * This is done to make it easy for the software scheduler to 
  * find which nodes have data to send.
  *
- * This must be called with the ATH lock held.
+ * The node and txnode locks should be held.
  */
 static void
 ath_tx_node_sched(struct ath_softc *sc, struct ath_node *an)
 {
-	/*
-	 * XXX sched is serialised behind the ATH lock; not
-	 * XXX a per-node lock.
-	 */
+	ATH_NODE_LOCK_ASSERT(an);
+	ATH_TXNODE_LOCK_ASSERT(sc);
+
 	if (an->sched)
 		return;		/* already scheduled */
 
@@ -1243,20 +1246,19 @@ ath_tx_node_sched(struct ath_softc *sc, 
  * Mark the current node as no longer needing to be polled for
  * TX packets.
  *
- * This must be called with the ATH lock held.
+ * The node and txnode locks should be held.
  */
 static void
 ath_tx_node_unsched(struct ath_softc *sc, struct ath_node *an)
 {
-	/*
-	 * XXX sched is serialised behind the ATH lock; not
-	 * XXX a per-node lock.
-	 */
+	ATH_NODE_LOCK_ASSERT(an);
+	ATH_TXNODE_LOCK_ASSERT(sc);
+
 	if (an->sched == 0)
 		return;
 
-	STAILQ_REMOVE(&sc->sc_txnodeq, an, ath_node, an_list);
 	an->sched = 0;
+	STAILQ_REMOVE(&sc->sc_txnodeq, an, ath_node, an_list);
 }
 
 /*
@@ -1302,13 +1304,18 @@ ath_tx_swq(struct ath_softc *sc, struct 
 	ATH_TXQ_UNLOCK(atid);
 
 
-	/* Mark the given node/tid as having packets to dequeue */
-	ATH_LOCK(sc);
+	/*
+	 * ATH_TXNODE must be acquired before ATH_NODE is acquired
+	 * if they're both needed.
+	 */
+	ATH_TXNODE_LOCK(sc);
+	ATH_NODE_LOCK(an);
 	/* Bump queued packet counter */
-	/* XXX for now, an_qdepth is behind the ATH lock */
-	atomic_add_int(&an->an_qdepth, 1);
+	an->an_qdepth++;
+	/* Mark the given node as having packets to dequeue */
 	ath_tx_node_sched(sc, an);
-	ATH_UNLOCK(sc);
+	ATH_NODE_UNLOCK(an);
+	ATH_TXNODE_UNLOCK(sc);
 }
 
 /*
@@ -1375,6 +1382,8 @@ ath_tx_tid_txq_unmark(struct ath_softc *
  *
  * It can also be called on an active node during an interface
  * reset or state transition.
+ *
+ * This doesn't update an->an_qdepth!
  */
 static void
 ath_tx_tid_free_pkts(struct ath_softc *sc, struct ath_node *an,
@@ -1383,7 +1392,6 @@ ath_tx_tid_free_pkts(struct ath_softc *s
 	struct ath_tid *atid = &an->an_tid[tid];
 	struct ath_buf *bf;
 
-
 	/* Walk the queue, free frames */
 	for (;;) {
 		ATH_TXQ_LOCK(atid);
@@ -1400,18 +1408,17 @@ ath_tx_tid_free_pkts(struct ath_softc *s
 
 /*
  * Flush all software queued packets for the given node.
- *
- * This protects ath_node behind ATH_LOCK for now.
  */
 void
 ath_tx_node_flush(struct ath_softc *sc, struct ath_node *an)
 {
 	int tid;
 
-	ATH_LOCK(sc);
+	ATH_NODE_LOCK(an);
 	for (tid = 0; tid < IEEE80211_TID_SIZE; tid++)
 		ath_tx_tid_free_pkts(sc, an, tid);
-	ATH_UNLOCK(sc);
+	an->an_qdepth = 0;
+	ATH_NODE_UNLOCK(an);
 }
 
 /*
@@ -1444,7 +1451,11 @@ ath_tx_tid_cleanup(struct ath_softc *sc,
 		ath_tx_tid_txq_unmark(sc, an, i);
 
 		/* Remove any pending hardware TXQ scheduling */
+		ATH_NODE_LOCK(an);
+		ATH_TXNODE_LOCK(sc);
 		ath_tx_node_unsched(sc, an);
+		ATH_TXNODE_UNLOCK(sc);
+		ATH_NODE_UNLOCK(an);
 
 		/* Free mutex */
 		mtx_destroy(&atid->axq_lock);
@@ -1477,7 +1488,9 @@ ath_tx_tid_hw_queue(struct ath_softc *sc
 		ATH_TXQ_UNLOCK(atid);
 
 		/* Remove from queue */
-		atomic_subtract_int(&an->an_qdepth, 1);
+		ATH_NODE_LOCK(an);
+		an->an_qdepth--;
+		ATH_NODE_UNLOCK(an);
 
 		txq = bf->bf_state.bfs_txq;
 		/* Sanity check! */
@@ -1519,6 +1532,7 @@ ath_tx_hw_queue(struct ath_softc *sc, st
 static int
 ath_txq_node_qlen(struct ath_softc *sc, struct ath_node *an)
 {
+	ATH_NODE_LOCK_ASSERT(an);
 	return an->an_qdepth;
 }
 
@@ -1531,17 +1545,17 @@ ath_txq_sched(struct ath_softc *sc)
 {
 	struct ath_node *an, *next;
 
-	/* XXX I'm not happy the ATH lock is held for so long here */
-	ATH_LOCK(sc);
-
+	ATH_TXNODE_LOCK(sc);
 	/* Iterate over the list of active nodes, queuing packets */
 	STAILQ_FOREACH_SAFE(an, &sc->sc_txnodeq, an_list, next) {
 		/* Try dequeueing packets from the current node */
 		ath_tx_hw_queue(sc, an);
 
 		/* Are any packets left on the node software queue? Remove */
+		ATH_NODE_LOCK(an);
 		if (! ath_txq_node_qlen(sc, an))
 			ath_tx_node_unsched(sc, an);
+		ATH_NODE_UNLOCK(an);
 	}
-	ATH_UNLOCK(sc);
+	ATH_TXNODE_UNLOCK(sc);
 } 

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Sun Jun 12 23:45:46 2011	(r223027)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Mon Jun 13 00:55:29 2011	(r223028)
@@ -94,7 +94,7 @@ struct ath_tid {
 	STAILQ_HEAD(,ath_buf) axq_q;		/* pending buffers        */
 	u_int			axq_depth;	/* queue depth (stat only) */
 	struct mtx		axq_lock;	/* lock on queue, tx_buf */
-	char			axq_name[24];	/* e.g. "ath0_a1_t5" */
+	char			axq_name[24];	/* e.g. "wlan0_a1_t5" */
 	struct ath_buf *tx_buf[ATH_TID_MAX_BUFS];	/* active tx buffers, beginning at current BAW */
 };
 
@@ -110,6 +110,8 @@ struct ath_node {
 	struct ath_buf	*an_ff_buf[WME_NUM_AC]; /* ff staging area */
 	struct ath_tid	an_tid[IEEE80211_TID_SIZE];	/* per-TID state */
 	u_int		an_qdepth;	/* Current queue depth of all TIDs */
+	char		an_name[32];	/* eg "wlan0_a1" */
+	struct mtx	an_mtx;		/* protecting the ath_node state */
 	/* variable-length rate control state follows */
 };
 #define	ATH_NODE(ni)	((struct ath_node *)(ni))
@@ -204,6 +206,10 @@ struct ath_txq {
 	char			axq_name[12];	/* e.g. "ath0_txq4" */
 };
 
+#define	ATH_NODE_LOCK(_an)		mtx_lock(&(_an)->an_mtx)
+#define	ATH_NODE_UNLOCK(_an)		mtx_unlock(&(_an)->an_mtx)
+#define	ATH_NODE_LOCK_ASSERT(_an)	mtx_assert(&(_an)->an_mtx, MA_OWNED)
+
 #define	ATH_TXQ_LOCK_INIT(_sc, _tq) do { \
 	snprintf((_tq)->axq_name, sizeof((_tq)->axq_name), "%s_txq%u", \
 		device_get_nameunit((_sc)->sc_dev), (_tq)->axq_qnum); \
@@ -403,7 +409,9 @@ struct ath_softc {
 	struct task		sc_dfstask;	/* DFS processing task */
 
 	/* Software TX queue related state */
+	struct mtx		sc_txnodeq_mtx;	/* mutex protecting the below */
 	STAILQ_HEAD(, ath_node)	sc_txnodeq;	/* Nodes which have traffic to send */
+	char			sc_txnodeq_name[16];	/* mutex name */
 };
 
 #define	ATH_LOCK_INIT(_sc) \
@@ -414,6 +422,14 @@ struct ath_softc {
 #define	ATH_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
 #define	ATH_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->sc_mtx, MA_OWNED)
 
+#define	ATH_TXNODE_LOCK_INIT(_sc) \
+	mtx_init(&(_sc)->sc_txnodeq_mtx, (sc)->sc_txnodeq_name, \
+	NULL, MTX_DEF | MTX_RECURSE)
+#define	ATH_TXNODE_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->sc_txnodeq_mtx)
+#define	ATH_TXNODE_LOCK(_sc)		mtx_lock(&(_sc)->sc_txnodeq_mtx)
+#define	ATH_TXNODE_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_txnodeq_mtx)
+#define	ATH_TXNODE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->sc_txnodeq_mtx, MA_OWNED)
+
 #define	ATH_TXQ_SETUP(sc, i)	((sc)->sc_txqsetup & (1<<i))
 
 #define	ATH_TXBUF_LOCK_INIT(_sc) do { \


More information about the svn-src-user mailing list