Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Jun 2011 14:27:30 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r223422 - user/adrian/if_ath_tx/sys/dev/ath
Message-ID:  <201106221427.p5MERUvT053039@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Wed Jun 22 14:27:30 2011
New Revision: 223422
URL: http://svn.freebsd.org/changeset/base/223422

Log:
  Begin fleshing out the aggregate session handling code.
  
  Document what I see as currently missing, so I don't forget to fill in the gaps
  and implement this stuff.

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

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	Wed Jun 22 09:55:28 2011	(r223421)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Wed Jun 22 14:27:30 2011	(r223422)
@@ -939,6 +939,12 @@ ath_tx_start(struct ath_softc *sc, struc
 	ismcast = IEEE80211_IS_MULTICAST(wh->i_addr1);
 
 	/* A-MPDU TX */
+	/*
+	 * XXX This doesn't hold the node lock!
+	 * XXX So it's possible that another TX process can change
+	 * XXX the AMPDU status from underneath us. This needs to be
+	 * XXX further investigated!
+	 */
 	is_ampdu_tx = ath_tx_ampdu_running(sc, ATH_NODE(ni), tid);
 	is_ampdu_pending = ath_tx_ampdu_pending(sc, ATH_NODE(ni), tid);
 	is_ampdu = is_ampdu_tx | is_ampdu_pending;
@@ -1646,15 +1652,90 @@ ath_tx_tid_cleanup(struct ath_softc *sc,
 }
 
 /*
+ * Handle completion of aggregate frames.
+ */
+static void
+ath_tx_aggr_comp(struct ath_softc *sc, struct ath_buf *bf)
+{
+	/* Success? Complete */
+	ath_tx_default_comp(sc, bf);
+
+	/*
+	 * Not success and have retries left?
+	 *
+	 * Mark as retry, requeue at head of queue
+	 */
+
+	/*
+	 * Not success and out of retries?
+	 *
+	 * Need to wait for the hardware TXQ to finish draining,
+	 * then once we know what was successfully TXed and what
+	 * wasn't, we send a BAR to advance the pointer to that
+	 * place.
+	 */
+}
+
+/*
  * 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.)
+ * This is the aggregate version.
+ */
+void
+ath_tx_tid_hw_queue_aggr(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(&atid->axq_q);
+		if (bf == NULL) {
+			ATH_TXQ_UNLOCK(atid);
+			break;
+		}
+
+		/* XXX check if seqno is outside of BAW, if so don't queue it */
+
+		/*
+		 * XXX If the seqno is out of BAW, then we should pause this TID
+		 * XXX until a completion for this TID allows the BAW to be advanced.
+		 * XXX Otherwise it's possible that we'll simply keep getting called
+		 * XXX for this node/TID until some TX completion has occured
+		 * XXX and progress can be made.
+		 */
+		ATH_TXQ_REMOVE_HEAD(atid, bf_list);
+		ATH_TXQ_UNLOCK(atid);
+
+		/* Remove from queue */
+		ATH_NODE_LOCK(an);
+		an->an_qdepth--;
+		ATH_NODE_UNLOCK(an);
+
+		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);
+		}
+
+		/* Set completion handler */
+		bf->bf_comp = ath_tx_aggr_comp;
+
+		/* Punt to hardware or software txq */
+		ath_tx_handoff(sc, txq, bf);
+	}
+}
+
+
+
+/*
+ * Schedule some packets from the given node/TID to the hardware.
  */
 void
-ath_tx_tid_hw_queue(struct ath_softc *sc, struct ath_node *an, int tid)
+ath_tx_tid_hw_queue_norm(struct ath_softc *sc, struct ath_node *an, int tid)
 {
 	struct ath_buf *bf;
 	struct ath_txq *txq;
@@ -1695,29 +1776,28 @@ void
 ath_tx_hw_queue(struct ath_softc *sc, struct ath_node *an)
 {
 	struct ath_tid *atid;
-	int i;
+	int tid;
 
 	/*
 	 * 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];
+	for (tid = 0; tid < IEEE80211_TID_SIZE; tid++) {
+		atid = &an->an_tid[tid];
 		ATH_NODE_LOCK(an);
-		if (ath_tx_ampdu_pending(sc, an, i)) {
+		if (ath_tx_ampdu_pending(sc, an, tid)) {
 			ATH_NODE_UNLOCK(an);
 			continue;
 		}
 		ATH_NODE_UNLOCK(an);
-		ath_tx_tid_hw_queue(sc, an, i);
+		if (ath_tx_ampdu_running(sc, an, tid))
+			ath_tx_tid_hw_queue_aggr(sc, an, tid);
+		else
+			ath_tx_tid_hw_queue_norm(sc, an, tid);
 	}
 }
 
-/*
- * XXX this needs to be atomic or ath_node locked
- * XXX This is currently serialised behind the ATH lock
- */
 static int
 ath_txq_node_qlen(struct ath_softc *sc, struct ath_node *an)
 {
@@ -1783,7 +1863,7 @@ ath_tx_ampdu_running(struct ath_softc *s
 {
 	struct ieee80211_tx_ampdu *tap;
 
-	//ATH_NODE_LOCK_ASSERT(an);
+	ATH_NODE_LOCK_ASSERT(an);
 
 	tap = ath_tx_get_tx_tid(an, tid);
 	if (tap == NULL)
@@ -1802,7 +1882,7 @@ ath_tx_ampdu_pending(struct ath_softc *s
 {
 	struct ieee80211_tx_ampdu *tap;
 
-	//ATH_NODE_LOCK_ASSERT(an);
+	ATH_NODE_LOCK_ASSERT(an);
 
 	tap = ath_tx_get_tx_tid(an, tid);
 	if (tap == NULL)

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	Wed Jun 22 09:55:28 2011	(r223421)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.h	Wed Jun 22 14:27:30 2011	(r223422)
@@ -47,7 +47,9 @@ extern void ath_tx_swq(struct ath_softc 
     struct ath_txq *txq, 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,
+extern void ath_tx_tid_hw_queue_aggr(struct ath_softc *sc, struct ath_node *an,
+    int tid);
+extern void ath_tx_tid_hw_queue_norm(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);



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