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.
         *
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to