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

Adrian Chadd adrian at FreeBSD.org
Tue Mar 26 19:46:52 UTC 2013


Author: adrian
Date: Tue Mar 26 19:46:51 2013
New Revision: 248745
URL: http://svnweb.freebsd.org/changeset/base/248745

Log:
  Add per-TXQ EDMA FIFO staging queue support.
  
  Each set of frames pushed into a FIFO is represented by a list of
  ath_bufs - the first ath_buf in the FIFO list is marked with
  ATH_BUF_FIFOPTR; the last ath_buf in the FIFO list is marked with
  ATH_BUF_FIFOEND.
  
  Multiple lists of frames are just glued together in the TAILQ as per
  normal - except that at the end of a FIFO list, the descriptor link
  pointer will be NULL and it'll be tagged with ATH_BUF_FIFOEND.
  
  For non-EDMA chipsets this is a no-op - the ath_txq frame list (axq_q)
  stays the same and is treated the same.
  
  For EDMA chipsets the frames are pushed into axq_q and then when
  the FIFO is to be (re) filled, frames will be moved onto the FIFO
  queue and then pushed into the FIFO.
  
  So:
  
  * Add a new queue in each hardware TXQ (ath_txq) for staging FIFO frame
    lists.  It's a TAILQ (like the normal hardware frame queue) rather than
    the ath9k list-of-lists to represent FIFO entries.
  
  * Add new ath_buf flags - ATH_TX_FIFOPTR and ATH_TX_FIFOEND.
  
  * When allocating ath_buf entries, clear out the flag value before
    returning it or it'll end up having stale flags.
  
  * When cloning ath_buf entries, only clone ATH_BUF_MGMT.  Don't clone
    the FIFO related flags.
  
  * Extend ath_tx_draintxq() to first drain the FIFO staging queue, _then_
    drain the normal hardware queue.
  
  Tested:
  
  * AR9280, hostap
  * AR9280, STA
  * AR9380/AR9580 - hostap
  
  TODO:
  
  * Test on other chipsets, just to be thorough.

Modified:
  head/sys/dev/ath/if_ath.c
  head/sys/dev/ath/if_ath_misc.h
  head/sys/dev/ath/if_athvar.h

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c	Tue Mar 26 19:43:18 2013	(r248744)
+++ head/sys/dev/ath/if_ath.c	Tue Mar 26 19:46:51 2013	(r248745)
@@ -2474,6 +2474,7 @@ _ath_getbuf_locked(struct ath_softc *sc,
 
 	/* XXX TODO: should do this at buffer list initialisation */
 	/* XXX (then, ensure the buffer has the right flag set) */
+	bf->bf_flags = 0;
 	if (btype == ATH_BUFTYPE_MGMT)
 		bf->bf_flags |= ATH_BUF_MGMT;
 	else
@@ -2530,7 +2531,7 @@ ath_buf_clone(struct ath_softc *sc, cons
 	/* Copy basics */
 	tbf->bf_next = NULL;
 	tbf->bf_nseg = bf->bf_nseg;
-	tbf->bf_flags = bf->bf_flags & ~ATH_BUF_BUSY;
+	tbf->bf_flags = bf->bf_flags & ATH_BUF_FLAGS_CLONE;
 	tbf->bf_status = bf->bf_status;
 	tbf->bf_m = bf->bf_m;
 	/*
@@ -3410,6 +3411,7 @@ ath_txq_init(struct ath_softc *sc, struc
 	txq->axq_softc = sc;
 	TAILQ_INIT(&txq->axq_q);
 	TAILQ_INIT(&txq->axq_tidq);
+	TAILQ_INIT(&txq->fifo.axq_q);
 	ATH_TXQ_LOCK_INIT(sc, txq);
 }
 
@@ -4169,7 +4171,7 @@ ath_returnbuf_head(struct ath_softc *sc,
 /*
  * Free the holding buffer if it exists
  */
-static void
+void
 ath_txq_freeholdingbuf(struct ath_softc *sc, struct ath_txq *txq)
 {
 	ATH_TXBUF_LOCK_ASSERT(sc);
@@ -4283,6 +4285,61 @@ ath_tx_freebuf(struct ath_softc *sc, str
 	 */
 }
 
+static struct ath_buf *
+ath_tx_draintxq_get_one(struct ath_softc *sc, struct ath_txq *txq)
+{
+	struct ath_buf *bf;
+
+	ATH_TXQ_LOCK_ASSERT(txq);
+
+	/*
+	 * Drain the FIFO queue first, then if it's
+	 * empty, move to the normal frame queue.
+	 */
+	bf = TAILQ_FIRST(&txq->fifo.axq_q);
+	if (bf != NULL) {
+		/*
+		 * Is it the last buffer in this set?
+		 * Decrement the FIFO counter.
+		 */
+		if (bf->bf_flags & ATH_BUF_FIFOEND) {
+			if (txq->axq_fifo_depth == 0) {
+				device_printf(sc->sc_dev,
+				    "%s: Q%d: fifo_depth=0, fifo.axq_depth=%d?\n",
+				    __func__,
+				    txq->axq_qnum,
+				    txq->fifo.axq_depth);
+			} else
+				txq->axq_fifo_depth--;
+		}
+		ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list);
+		return (bf);
+	}
+
+	/*
+	 * Debugging!
+	 */
+	if (txq->axq_fifo_depth != 0 || txq->fifo.axq_depth != 0) {
+		device_printf(sc->sc_dev,
+		    "%s: Q%d: fifo_depth=%d, fifo.axq_depth=%d\n",
+		    __func__,
+		    txq->axq_qnum,
+		    txq->axq_fifo_depth,
+		    txq->fifo.axq_depth);
+	}
+
+	/*
+	 * Now drain the pending queue.
+	 */
+	bf = TAILQ_FIRST(&txq->axq_q);
+	if (bf == NULL) {
+		txq->axq_link = NULL;
+		return (NULL);
+	}
+	ATH_TXQ_REMOVE(txq, bf, bf_list);
+	return (bf);
+}
+
 void
 ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
 {
@@ -4298,24 +4355,11 @@ ath_tx_draintxq(struct ath_softc *sc, st
 	 */
 	for (ix = 0;; ix++) {
 		ATH_TXQ_LOCK(txq);
-		bf = TAILQ_FIRST(&txq->axq_q);
+		bf = ath_tx_draintxq_get_one(sc, txq);
 		if (bf == NULL) {
-			txq->axq_link = NULL;
-			/*
-			 * There's currently no flag that indicates
-			 * a buffer is on the FIFO.  So until that
-			 * occurs, just clear the FIFO counter here.
-			 *
-			 * Yes, this means that if something in parallel
-			 * is pushing things onto this TXQ and pushing
-			 * _that_ into the hardware, things will get
-			 * very fruity very quickly.
-			 */
-			txq->axq_fifo_depth = 0;
 			ATH_TXQ_UNLOCK(txq);
 			break;
 		}
-		ATH_TXQ_REMOVE(txq, bf, bf_list);
 		if (bf->bf_state.bfs_aggr)
 			txq->axq_aggr_depth--;
 #ifdef ATH_DEBUG

Modified: head/sys/dev/ath/if_ath_misc.h
==============================================================================
--- head/sys/dev/ath/if_ath_misc.h	Tue Mar 26 19:43:18 2013	(r248744)
+++ head/sys/dev/ath/if_ath_misc.h	Tue Mar 26 19:46:51 2013	(r248745)
@@ -77,6 +77,8 @@ extern	int ath_hal_gethangstate(struct a
 
 extern void ath_tx_freebuf(struct ath_softc *sc, struct ath_buf *bf,
     int status);
+extern	void ath_txq_freeholdingbuf(struct ath_softc *sc,
+	    struct ath_txq *txq);
 
 extern void ath_txqmove(struct ath_txq *dst, struct ath_txq *src);
 

Modified: head/sys/dev/ath/if_athvar.h
==============================================================================
--- head/sys/dev/ath/if_athvar.h	Tue Mar 26 19:43:18 2013	(r248744)
+++ head/sys/dev/ath/if_athvar.h	Tue Mar 26 19:46:51 2013	(r248745)
@@ -291,6 +291,10 @@ typedef TAILQ_HEAD(ath_bufhead_s, ath_bu
 
 #define	ATH_BUF_MGMT	0x00000001	/* (tx) desc is a mgmt desc */
 #define	ATH_BUF_BUSY	0x00000002	/* (tx) desc owned by h/w */
+#define	ATH_BUF_FIFOEND	0x00000004
+#define	ATH_BUF_FIFOPTR	0x00000008
+
+#define	ATH_BUF_FLAGS_CLONE	(ATH_BUF_MGMT)
 
 /*
  * DMA state for tx/rx descriptors.
@@ -325,13 +329,30 @@ struct ath_txq {
 #define	ATH_TXQ_PUTPENDING	0x0001		/* ath_hal_puttxbuf pending */
 	u_int			axq_depth;	/* queue depth (stat only) */
 	u_int			axq_aggr_depth;	/* how many aggregates are queued */
-	u_int			axq_fifo_depth;	/* depth of FIFO frames */
 	u_int			axq_intrcnt;	/* interrupt count */
 	u_int32_t		*axq_link;	/* link ptr in last TX desc */
 	TAILQ_HEAD(axq_q_s, ath_buf)	axq_q;		/* transmit queue */
 	struct mtx		axq_lock;	/* lock on q and link */
 
 	/*
+	 * This is the FIFO staging buffer when doing EDMA.
+	 *
+	 * For legacy chips, we just push the head pointer to
+	 * the hardware and we ignore this list.
+	 *
+	 * For EDMA, the staging buffer is treated as normal;
+	 * when it's time to push a list of frames to the hardware
+	 * we move that list here and we stamp buffers with
+	 * flags to identify the beginning/end of that particular
+	 * FIFO entry.
+	 */
+	struct {
+		TAILQ_HEAD(axq_q_f_s, ath_buf)	axq_q;
+		u_int				axq_depth;
+	} fifo;
+	u_int			axq_fifo_depth;	/* depth of FIFO frames */
+
+	/*
 	 * XXX the holdingbf field is protected by the TXBUF lock
 	 * for now, NOT the TXQ lock.
 	 *


More information about the svn-src-all mailing list