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

Adrian Chadd adrian at FreeBSD.org
Wed Aug 31 04:57:12 UTC 2011


Author: adrian
Date: Wed Aug 31 04:57:11 2011
New Revision: 225279
URL: http://svn.freebsd.org/changeset/base/225279

Log:
  As much as I dislike it, migrate the driver back to doing direct
  dispatch to hardware.
  
  This matches what the Linux/atheros reference code does.
  
  If the hardware txq isn't busy, start filling it with non-aggregate
  frames. If it's sufficiently busy, start aggregating frames in the
  background.
  
  The aim is to massage this code back to match the structure of the
  reference code in order to make porting/debugging easier. I may
  move it back to task-based TX at a later stage, but only once the
  rest of the TX path has been fully debugged.
  
  This drops the CPU use a little but there's still a problem breaking
  > 100mbit on the MIPS dev boards I'm using. (The same dev board
  can do 250mbit RX on the same NIC, so it's not necessarily unable
  to do it.)

Modified:
  user/adrian/if_ath_tx/sys/dev/ath/if_ath.c
  user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c
  user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
  user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h
  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	Wed Aug 31 03:04:56 2011	(r225278)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath.c	Wed Aug 31 04:57:11 2011	(r225279)
@@ -176,7 +176,6 @@ static void	ath_tx_cleanup(struct ath_so
 static void	ath_tx_proc_q0(void *, int);
 static void	ath_tx_proc_q0123(void *, int);
 static void	ath_tx_proc(void *, int);
-static void	ath_tx_sched_proc(void *, int);
 static int	ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
 static void	ath_draintxq(struct ath_softc *);
 static void	ath_stoprecv(struct ath_softc *);
@@ -399,7 +398,6 @@ ath_attach(u_int16_t devid, struct ath_s
 	TASK_INIT(&sc->sc_rxtask, 0, ath_rx_proc, sc);
 	TASK_INIT(&sc->sc_bmisstask, 0, ath_bmiss_proc, sc);
 	TASK_INIT(&sc->sc_bstucktask,0, ath_bstuck_proc, sc);
-	TASK_INIT(&sc->sc_txschedtask, 0, ath_tx_sched_proc, sc);
 
 	/*
 	 * Allocate hardware transmit queues: one queue for
@@ -2044,13 +2042,6 @@ ath_start(struct ifnet *ifp)
 
 		sc->sc_wd_timer = 5;
 	}
-
-	/*
-	 * Schedule the software TX process to occur
-	 * if we transmitted at least one packet.
-	 */
-	if (tx)
-		ath_tx_sched_proc_sched(sc, NULL);
 }
 
 static int
@@ -4523,41 +4514,6 @@ ath_tx_proc(void *arg, int npending)
 }
 
 /*
- * TX scheduling
- *
- * This calls the per-TXQ TX queue packet scheduling code.
- *
- * Note: there's no need to handle the mcastq; it doesn't have
- * a software TID queue attached (as it's a software queue in
- * itself.)
- */
-static void
-ath_tx_sched_proc(void *arg, int npending)
-{
-	struct ath_softc *sc = arg;
-	struct ath_txq *txq;
-	int i;
-
-	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
-		txq = &sc->sc_txq[i];
-		if (ATH_TXQ_SETUP(sc, i)) {
-			ATH_TXQ_LOCK(txq);
-			ath_txq_sched(sc, txq);
-			ATH_TXQ_UNLOCK(txq);
-		}
-	}
-}
-
-/*
- * Schedule a TXQ scheduling task to occur.
- */
-void
-ath_tx_sched_proc_sched(struct ath_softc *sc, struct ath_txq *txq)
-{
-	taskqueue_enqueue(sc->sc_tq, &sc->sc_txschedtask);
-}
-
-/*
  * Return a buffer to the pool.
  * The caller must free the mbuf and recycle the node reference.
  */

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c	Wed Aug 31 03:04:56 2011	(r225278)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_sysctl.c	Wed Aug 31 04:57:11 2011	(r225279)
@@ -321,6 +321,8 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS)
 	    sc->sc_stats.tx_aggr.aggr_nonbaw_pkt);
 	printf("aggr aggregate packet: %d\n",
 	    sc->sc_stats.tx_aggr.aggr_aggr_pkt);
+	printf("aggr single packet low hwq: %d\n",
+	    sc->sc_stats.tx_aggr.aggr_low_hwq_single_pkt);
 	for (i = 0; i < 64; i++) {
 		printf("%2d: %10d ", i, sc->sc_stats.tx_aggr.aggr_pkts[i]);
 		if (i % 4 == 3)

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 Aug 31 03:04:56 2011	(r225278)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Wed Aug 31 04:57:11 2011	(r225279)
@@ -872,20 +872,27 @@ ath_tx_set_ratectrl(struct ath_softc *sc
  *
  * The frame must already be setup; rate control must already have
  * been done.
+ *
+ * XXX since the TXQ lock is being held here (and I dislike holding
+ * it for this long when not doing software aggregation), later on
+ * break this function into "setup_normal" and "xmit_normal". The
+ * lock only needs to be held for the ath_tx_handoff call.
  */
 static void
 ath_tx_xmit_normal(struct ath_softc *sc, struct ath_txq *txq,
     struct ath_buf *bf)
 {
+
+	ATH_TXQ_LOCK_ASSERT(txq);
+
 	/* Setup the descriptor before handoff */
 	ath_tx_set_rtscts(sc, bf);
 	ath_tx_setds(sc, bf);
 	ath_tx_set_ratectrl(sc, bf->bf_node, bf);
 	ath_tx_chaindesclist(sc, bf);
 
-	ATH_TXQ_LOCK(txq);
+	/* Hand off to hardware */
 	ath_tx_handoff(sc, txq, bf);
-	ATH_TXQ_UNLOCK(txq);
 }
 
 
@@ -1371,26 +1378,24 @@ ath_tx_start(struct ath_softc *sc, struc
 	 * If it's a BAR frame, do a direct dispatch to the
 	 * destination hardware queue. Don't bother software
 	 * queuing it, as the TID will now be paused.
+	 * Sending a BAR frame can occur from the net80211 txa timer
+	 * (ie, retries) or from the ath txtask (completion call.)
+	 * It queues directly to hardware because the TID is paused
+	 * at this point (and won't be unpaused until the BAR has
+	 * either been TXed successfully or max retries has been
+	 * reached.)
 	 */
 	if (txq == &avp->av_mcastq) {
+		ATH_TXQ_LOCK(txq);
 		ath_tx_xmit_normal(sc, txq, bf);
+		ATH_TXQ_UNLOCK(txq);
 	} else if (type == IEEE80211_FC0_TYPE_CTL &&
 		    subtype == IEEE80211_FC0_SUBTYPE_BAR) {
-		/*
-		 * XXX The following is dirty but needed for now.
-		 *
-		 * Sending a BAR frame can occur from the net80211 txa timer
-		 * (ie, retries) or from the ath txtask (completion call.)
-		 * It queues directly to hardware because the TID is paused
-		 * at this point (and won't be unpaused until the BAR has
-		 * either been TXed successfully or max retries has been
-		 * reached.)
-		 *
-		 * TODO: sending a BAR should be done at the management rate!
-		 */
 		DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
 		    "%s: BAR: TX'ing direct\n", __func__);
+		ATH_TXQ_LOCK(txq);
 		ath_tx_xmit_normal(sc, txq, bf);
+		ATH_TXQ_UNLOCK(txq);
 	} else {
 		/* add to software queue */
 		ath_tx_swq(sc, ni, txq, bf);
@@ -1400,7 +1405,9 @@ ath_tx_start(struct ath_softc *sc, struc
 	 * For now, since there's no software queue,
 	 * direct-dispatch to the hardware.
 	 */
+	ATH_TXQ_LOCK(txq);
 	ath_tx_xmit_normal(sc, txq, bf);
+	ATH_TXQ_UNLOCK(txq);
 #endif
 
 	return 0;
@@ -1603,9 +1610,11 @@ ath_tx_raw_start(struct ath_softc *sc, s
 	DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: dooverride=%d\n",
 	    __func__, do_override);
 
-	if (do_override)
+	if (do_override) {
+		ATH_TXQ_LOCK(sc->sc_ac2q[pri]);
 		ath_tx_xmit_normal(sc, sc->sc_ac2q[pri], bf);
-	else {
+		ATH_TXQ_UNLOCK(sc->sc_ac2q[pri]);
+	} else {
 		/* Queue to software queue */
 		ath_tx_swq(sc, ni, sc->sc_ac2q[pri], bf);
 	}
@@ -1670,9 +1679,6 @@ ath_raw_xmit(struct ieee80211_node *ni, 
 	ifp->if_opackets++;
 	sc->sc_stats.ast_tx_raw++;
 
-	/* Schedule a TX scheduler task call to occur */
-	ath_tx_sched_proc_sched(sc, NULL);
-
 	return 0;
 bad2:
 	ATH_TXBUF_LOCK(sc);
@@ -1965,9 +1971,63 @@ ath_tx_tid_seqno_assign(struct ath_softc
 }
 
 /*
- * Queue the given packet on the relevant software queue.
- *
- * This however doesn't queue the packet to the hardware!
+ * Attempt to direct dispatch an aggregate frame to hardware.
+ * If the frame is out of BAW, queue.
+ * Otherwise, schedule it as a single frame.
+ */
+static void
+ath_tx_xmit_aggr(struct ath_softc *sc, struct ath_node *an, struct ath_buf *bf)
+{
+	struct ath_tid *tid = &an->an_tid[bf->bf_state.bfs_tid];
+	struct ath_txq *txq = bf->bf_state.bfs_txq;
+	struct ieee80211_tx_ampdu *tap;
+
+	ATH_TXQ_LOCK_ASSERT(txq);
+
+	tap = ath_tx_get_tx_tid(an, tid->tid);
+
+	/* paused? queue */
+	if (tid->paused) {
+		ATH_TXQ_INSERT_TAIL(tid, bf, bf_list);
+		return;
+	}
+
+	/* outside baw? queue */
+	if (bf->bf_state.bfs_dobaw &&
+	    (! BAW_WITHIN(tap->txa_start, tap->txa_wnd,
+	    SEQNO(bf->bf_state.bfs_seqno)))) {
+		ATH_TXQ_INSERT_TAIL(tid, bf, bf_list);
+		return;
+	}
+
+	/* Direct dispatch to hardware */
+	ath_tx_set_rtscts(sc, bf);
+	ath_tx_setds(sc, bf);
+	ath_tx_set_ratectrl(sc, bf->bf_node, bf);
+	ath_tx_chaindesclist(sc, bf);
+
+	/* Statistics */
+	sc->sc_stats.tx_aggr.aggr_low_hwq_single_pkt++;
+
+	/* Track per-TID hardware queue depth correctly */
+	tid->hwq_depth++;
+
+	/* Add to BAW */
+	ath_tx_addto_baw(sc, an, tid, bf);
+	bf->bf_state.bfs_addedbaw = 1;
+
+	/* Set completion handler, multi-frame aggregate or not */
+	bf->bf_comp = ath_tx_aggr_comp;
+
+	/* Hand off to hardware */
+	ath_tx_handoff(sc, txq, bf);
+}
+
+/*
+ * Attempt to send the packet.
+ * If the queue isn't busy, direct-dispatch.
+ * If the queue is busy enough, queue the given packet on the
+ *  relevant software queue.
  */
 void
 ath_tx_swq(struct ath_softc *sc, struct ieee80211_node *ni, struct ath_txq *txq,
@@ -1993,10 +2053,31 @@ ath_tx_swq(struct ath_softc *sc, struct 
 	bf->bf_state.bfs_txq = txq;
 	bf->bf_state.bfs_pri = pri;
 
-	/* Queue frame to the tail of the software queue */
+	/*
+	 * If the hardware queue isn't busy, queue it directly.
+	 * If the hardware queue is busy, queue it.
+	 * If the TID is paused or the traffic it outside BAW, software
+	 * queue it.
+	 */
 	ATH_TXQ_LOCK(txq);
-	ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
-	ath_tx_tid_sched(sc, an, tid);
+	if (atid->paused) {
+		/* TID is paused, queue */
+		ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
+	} else if (ath_tx_ampdu_pending(sc, an, tid)) {
+		/* AMPDU pending; queue */
+		ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
+	} else if (txq->axq_depth < sc->sc_hwq_limit &&
+	    ath_tx_ampdu_running(sc, an, tid)) {
+		/* AMPDU running, attempt direct dispatch */
+		ath_tx_xmit_aggr(sc, an, bf);
+	} else if (txq->axq_depth < sc->sc_hwq_limit) {
+		/* AMPDU not running, attempt direct dispatch */
+		ath_tx_xmit_normal(sc, txq, bf);
+	} else {
+		/* Busy; queue */
+		ATH_TXQ_INSERT_TAIL(atid, bf, bf_list);
+		ath_tx_tid_sched(sc, an, tid);
+	}
 	ATH_TXQ_UNLOCK(txq);
 }
 
@@ -2087,7 +2168,6 @@ ath_tx_tid_resume(struct ath_softc *sc, 
 	}
 
 	ath_tx_tid_sched(sc, tid->an, tid->tid);
-	ath_tx_sched_proc_sched(sc, txq);
 }
 
 static void

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h	Wed Aug 31 03:04:56 2011	(r225278)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athioctl.h	Wed Aug 31 04:57:11 2011	(r225279)
@@ -41,6 +41,7 @@ struct ath_tx_aggr_stats {
 	u_int32_t	aggr_nonbaw_pkt;
 	u_int32_t	aggr_aggr_pkt;
 	u_int32_t	aggr_baw_closed_single_pkt;
+	u_int32_t	aggr_low_hwq_single_pkt;
 };
 
 struct ath_stats {

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Wed Aug 31 03:04:56 2011	(r225278)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Wed Aug 31 04:57:11 2011	(r225279)
@@ -445,7 +445,6 @@ struct ath_softc {
 	struct ath_txq		sc_txq[HAL_NUM_TX_QUEUES];
 	struct ath_txq		*sc_ac2q[5];	/* WME AC -> h/w q map */ 
 	struct task		sc_txtask;	/* tx int processing */
-	struct task		sc_txschedtask;	/* tx processing task */
 	int			sc_wd_timer;	/* count down for wd timer */
 	struct callout		sc_wd_ch;	/* tx watchdog timer */
 	struct ath_tx_radiotap_header sc_tx_th;


More information about the svn-src-user mailing list