Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 11 Jun 2011 10:35:54 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r222981 - user/adrian/if_ath_tx/sys/dev/ath
Message-ID:  <201106111035.p5BAZsXQ071747@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Sat Jun 11 10:35:53 2011
New Revision: 222981
URL: http://svn.freebsd.org/changeset/base/222981

Log:
  Flesh out some more software TX queue code
  
  ath_buf's now have both a destination tid and a destination txq.
  (I may end up also storing a destination AC, just to be complete.)
  
  The destination TXQ is pre-calculated at TID TXQ add time
  as that won't change. It's then added to the pre-determined hardware TXQ
  when the packet is ready to be scheduled.
  
  The routine to calculate the ath_node txq length is dirty.
  I shall fix soon.
  
  Packets should now be schedulable via a call to ath_tx_swq() and sit
  in the per-node queue until ath_txq_sched() is called. Packets then
  will be removed from the software queue and added to the relevant
  hardware queue.
  
  Next is writing a completion handler which looks a lot like what
  ath_tx_processq() does, but knows about the ath_node/tid involved.
  Eventually this is where the software aggregation retries will live.
  
  The TX packet scheduler isn't fair. It isn't pretending to be for now.

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

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	Sat Jun 11 09:08:46 2011	(r222980)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Sat Jun 11 10:35:53 2011	(r222981)
@@ -1214,17 +1214,13 @@ bad:
  * Mark the current node/TID as ready to TX.
  *
  * This is done to make it easy for the software scheduler to 
- * find which nodes/TIDs have data to send.
+ * find which nodes have data to send.
  *
  * This must be called with the TX/ATH lock held.
  */
 static void
-ath_tx_node_sched(struct ath_softc *sc, struct ath_node *an, int tid)
+ath_tx_node_sched(struct ath_softc *sc, struct ath_node *an)
 {
-	/*
-	 * For now, the node is marked as ready;
-	 * later code will also maintain a per-TID list.
-	 */
 	if (an->sched)
 		return;		/* already scheduled */
 
@@ -1234,13 +1230,13 @@ ath_tx_node_sched(struct ath_softc *sc, 
 }
 
 /*
- * Mark the current node/TID as no longer needing to be polled for
+ * Mark the current node as no longer needing to be polled for
  * TX packets.
  *
  * This must be called with the TX/ATH lock held.
  */
 static void
-ath_tx_node_unsched(struct ath_softc *sc, struct ath_node *an, int tid)
+ath_tx_node_unsched(struct ath_softc *sc, struct ath_node *an)
 {
 	if (an->sched == 0)
 		return;
@@ -1259,20 +1255,42 @@ ath_tx_swq(struct ath_softc *sc, struct 
     struct mbuf *m0)
 {
 	struct ath_node *an = ATH_NODE(ni);
+	struct ieee80211vap *vap = ni->ni_vap;
 	struct ieee80211_frame *wh;
+	struct ath_vap *avp = ATH_VAP(vap);
 	struct ath_tid *atid;
+	struct ath_txq *txq;	/* eventual destination queue */
 	int tid;
+	int ismcast;
+	u_int pri;
 
 	/* Fetch the TID - non-QoS frames get assigned to TID 16 */
 	wh = mtod(m0, struct ieee80211_frame *);
 	tid = ieee80211_gettid(wh);
 	atid = &an->an_tid[tid];
 
+	/* Fetch the eventual destination queue */
+	pri = M_WME_GETAC(m0);			/* honor classification */
+	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
+	txq = sc->sc_ac2q[pri];
+
+	/* Handle mcast, or PS STA */
+	if (ismcast && (vap->iv_ps_sta || avp->av_mcastq.axq_depth))
+		txq = &avp->av_mcastq;
+
+	/* Set local packet state, used to queue packets to hardware */
+	bf->bf_state.bfs_tid = tid;
+	bf->bf_state.bfs_txq = txq;
+
 	/* Queue frame to the tail of the software queue */
+	ATH_TXQ_LOCK(atid);
 	ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
+	ATH_TXQ_UNLOCK(atid);
 
 	/* Mark the given node/tid as having packets to dequeue */
-	ath_tx_node_sched(sc, an, tid);
+	ATH_LOCK(sc);
+	ath_tx_node_sched(sc, an);
+	ATH_UNLOCK(sc);
 }
 
 /*
@@ -1374,9 +1392,105 @@ ath_tx_tid_cleanup(struct ath_softc *sc,
 		ath_tx_tid_txq_unmark(sc, an, i);
 
 		/* Remove any pending hardware TXQ scheduling */
-		ath_tx_node_unsched(sc, an, i);
+		ath_tx_node_unsched(sc, an);
 
 		/* Free mutex */
 		mtx_destroy(&atid->axq_lock);
 	}
 }
+
+/*
+ * Schedule some packets from the given node/TID to the hardware.
+ *
+ * For non-aggregate packets, all packets can just be queued.
+ * Aggregate destinations will end up having limitations on
+ * what can actually be queued here (ie, not more than the
+ * block-ack window.)
+ */
+void
+ath_tx_tid_hw_queue(struct ath_softc *sc, struct ath_node *an, int tid)
+{
+	struct ath_buf *bf;
+	struct ath_txq *txq;
+	struct ath_tid *atid = &an->an_tid[tid];
+
+	for (;;) {
+		ATH_TXQ_LOCK(atid);
+                bf = STAILQ_FIRST(&txq->axq_q);
+		if (bf == NULL) {
+			ATH_TXQ_UNLOCK(atid);
+			break;
+		}
+		ATH_TXQ_REMOVE_HEAD(atid, bf_list);
+		ATH_TXQ_UNLOCK(atid);
+
+		txq = bf->bf_state.bfs_txq;
+		/* Sanity check! */
+		if (tid != bf->bf_state.bfs_tid) {
+			device_printf(sc->sc_dev, "%s: bfs_tid %d !="
+			    " tid %d\n",
+			    __func__, bf->bf_state.bfs_tid, tid);
+		}
+
+		/* Punt to hardware or software txq */
+		ath_tx_handoff(sc, txq, bf);
+	}
+}
+
+/*
+ * Attempt to schedule packets from the given node to the hardware.
+ */
+void
+ath_tx_hw_queue(struct ath_softc *sc, struct ath_node *an)
+{
+	struct ath_tid *atid;
+	int i;
+
+	/*
+	 * For now, just queue from all TIDs in order.
+	 * This is very likely absolutely wrong from a QoS
+	 * perspective but it'll do for now.
+	 */
+	for (i = 0; i < IEEE80211_TID_SIZE; i++) {
+		atid = &an->an_tid[i];
+		ath_tx_tid_hw_queue(sc, an, i);
+	}
+}
+
+/*
+ * This is pretty disgusting, but again it's just temporary.
+ */
+static int
+ath_txq_node_qlen(struct ath_softc *sc, struct ath_node *an)
+{
+	int qlen = 0;
+	int i;
+	for (i = 0; i < IEEE80211_TID_SIZE; i++) {
+		ATH_TXQ_LOCK(&an->an_tid[i]);
+		qlen += an->an_tid[i].axq_depth;
+		ATH_TXQ_UNLOCK(&an->an_tid[i]);
+	}
+	return qlen;
+}
+
+/*
+ * Handle scheduling some packets from whichever nodes have
+ * signaled they're (potentially) ready.
+ *
+ * This must be called with the ATH lock held.
+ */
+void
+ath_txq_sched(struct ath_softc *sc)
+{
+	struct ath_node *an, *next;
+
+	/* 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 */
+		if (! ath_txq_node_qlen(sc, an))
+			ath_tx_node_unsched(sc, an);
+	}
+} 

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h	Sat Jun 11 09:08:46 2011	(r222980)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h	Sat Jun 11 10:35:53 2011	(r222981)
@@ -46,6 +46,10 @@ extern void ath_tx_swq(struct ath_softc 
     struct ath_buf *bf, struct mbuf *m0);
 extern void ath_tx_tid_init(struct ath_softc *sc, struct ath_node *an);
 extern void ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an);
+extern void ath_tx_tid_hw_queue(struct ath_softc *sc, struct ath_node *an,
+    int tid);
+extern void ath_tx_hw_queue(struct ath_softc *sc, struct ath_node *an);
+extern void ath_txq_sched(struct ath_softc *sc);
 
 
 #endif

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Sat Jun 11 09:08:46 2011	(r222980)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Sat Jun 11 10:35:53 2011	(r222981)
@@ -151,6 +151,7 @@ struct ath_buf {
 		int bfs_seqno;		/* sequence number of this packet */
 		int bfs_retries;	/* retry count */
 		uint16_t bfs_tid;	/* packet TID (or TID_MAX for no QoS) */
+		struct ath_txq *bfs_txq;	/* eventual dest hardware TXQ */
 		uint16_t bfs_al;	/* length of aggregate */
 		uint16_t bfs_pktdur;	/* packet duration (at current rate?) */
 		uint16_t bfs_nframes;	/* number of frames in aggregate */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106111035.p5BAZsXQ071747>