Author: adrian
Date: Sat May 18 18:27:53 2013
New Revision: 250783
URL: http://svnweb.freebsd.org/changeset/base/250783

Log:
  Be (very) careful about how to add more TX DMA work.
  
  The list-based DMA engine has the following behaviour:
  
  * When the DMA engine is in the init state, you can write the first
    descriptor address to the QCU TxDP register and it will work.
  
  * Then when it hits the end of the list (ie, it either hits a NULL
    link pointer, OR it hits a descriptor with VEOL set) the QCU
    stops, and the TxDP points to the last descriptor that was transmitted.
  
  * Then when you want to transmit a new frame, you can then either:
    + write the head of the new list into TxDP, or
    + you write the head of the new list into the link pointer of the
      last completed descriptor (ie, where TxDP points), then kick
      TxE to restart transmission on that QCU>
  
  * The hardware then will re-read the descriptor to pick up the link
    pointer and then jump to that.
  
  Now, the quirks:
  
  * If you write a TxDP when there's been no previous TxDP (ie, it's 0),
    it works.
  
  * If you write a TxDP in any other instance, the TxDP write may actually
    fail.  Thus, when you start transmission, it will re-read the last
    transmitted descriptor to get the link pointer, NOT just start a new
    transmission.
  
  So the correct thing to do here is:
  
  * ALWAYS use the holding descriptor (ie, the last transmitted descriptor
    that we've kept safe) and use the link pointer in _THAT_ to transmit
    the next frame.
  
  * NEVER write to the TxDP after you've done the initial write.
  
  * .. also, don't do this whilst you're also resetting the NIC.
  
  With this in mind, the following patch does basically the above.
  
  * Since this encapsulates Sam's issues with the QCU behaviour w/ TDMA,
    kill the TDMA special case and replace it with the above.
  
  * Add a new TXQ flag - PUTRUNNING - which indicates that we've started
    DMA.
  
  * Clear that flag when DMA has been shutdown.
  
  * Ensure that we're not restarting DMA with PUTRUNNING enabled.
  
  * Fix the link pointer logic during TXQ drain - we should always ensure
    the link pointer does point to something if there's a list of frames.
    Having it be NULL as an indication that DMA has finished or during
    a reset causes trouble.
  
  Now, given all of this, i want to nuke axq_link from orbit.  There's now HAL
  methods to get and set the link pointer of a descriptor, so what we
  should do instead is to update the right link pointer.
  
  * If there's a holding descriptor and an empty TXQ list, set the
    link pointer of said holding descriptor to the new frame.
  
  * If there's a non-empty TXQ list, set the link pointer of the
    last descriptor in the list to the new frame.
  
  * Nuke axq_link from orbit.
  
  Note:
  
  * The AR9380 doesn't need this.  FIFO TX writes are atomic.  As long as
    we don't append to a list of frames that we've already passed to the
    hardware, all of the above doesn't apply.  The holding descriptor stuff
    is still needed to ensure the hardware can re-read a completed
    descriptor to move onto the next one, but we restart DMA by pushing in
    a new FIFO entry into the TX QCU.  That doesn't require any real
    gymnastics.
  
  Tested:
  
  * AR5210, AR5211, AR5212, AR5416, AR9380 - STA mode.

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

Modified: head/sys/dev/ath/if_ath.c
==============================================================================
--- head/sys/dev/ath/if_ath.c   Sat May 18 18:01:21 2013        (r250782)
+++ head/sys/dev/ath/if_ath.c   Sat May 18 18:27:53 2013        (r250783)
@@ -4620,6 +4620,8 @@ ath_tx_stopdma(struct ath_softc *sc, str
 {
        struct ath_hal *ah = sc->sc_ah;
 
+       ATH_TXQ_LOCK_ASSERT(txq);
+
        DPRINTF(sc, ATH_DEBUG_RESET,
            "%s: tx queue [%u] %p, active=%d, hwpending=%d, flags 0x%08x, "
            "link %p, holdingbf=%p\n",
@@ -4633,6 +4635,8 @@ ath_tx_stopdma(struct ath_softc *sc, str
            txq->axq_holdingbf);
 
        (void) ath_hal_stoptxdma(ah, txq->axq_qnum);
+       /* We've stopped TX DMA, so mark this as stopped. */
+       txq->axq_flags &= ~ATH_TXQ_PUTRUNNING;
 
 #ifdef ATH_DEBUG
        if ((sc->sc_debug & ATH_DEBUG_RESET)
@@ -4658,17 +4662,25 @@ ath_stoptxdma(struct ath_softc *sc)
                    __func__, sc->sc_bhalq,
                    (caddr_t)(uintptr_t) ath_hal_gettxbuf(ah, sc->sc_bhalq),
                    NULL);
+
+               /* stop the beacon queue */
                (void) ath_hal_stoptxdma(ah, sc->sc_bhalq);
-               for (i = 0; i < HAL_NUM_TX_QUEUES; i++)
-                       if (ATH_TXQ_SETUP(sc, i))
+
+               /* Stop the data queues */
+               for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
+                       if (ATH_TXQ_SETUP(sc, i)) {
+                               ATH_TXQ_LOCK(&sc->sc_txq[i]);
                                ath_tx_stopdma(sc, &sc->sc_txq[i]);
+                               ATH_TXQ_UNLOCK(&sc->sc_txq[i]);
+                       }
+               }
        }
 
        return 1;
 }
 
 #ifdef ATH_DEBUG
-static void
+void
 ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq)
 {
        struct ath_hal *ah = sc->sc_ah;
@@ -4702,6 +4714,7 @@ ath_legacy_tx_drain(struct ath_softc *sc
 #endif
        struct ifnet *ifp = sc->sc_ifp;
        int i;
+       struct ath_buf *bf_last;
 
        (void) ath_stoptxdma(sc);
 
@@ -4727,10 +4740,20 @@ ath_legacy_tx_drain(struct ath_softc *sc
                                 */
                                ath_txq_freeholdingbuf(sc, &sc->sc_txq[i]);
                                /*
-                                * Reset the link pointer to NULL; there's
-                                * no frames to chain DMA to.
+                                * Setup the link pointer to be the
+                                * _last_ buffer/descriptor in the list.
+                                * If there's nothing in the list, set it
+                                * to NULL.
                                 */
-                               sc->sc_txq[i].axq_link = NULL;
+                               bf_last = ATH_TXQ_LAST(&sc->sc_txq[i],
+                                   axq_q_s);
+                               if (bf_last != NULL) {
+                                       ath_hal_gettxdesclinkptr(ah,
+                                           bf_last->bf_lastds,
+                                           &sc->sc_txq[i].axq_link);
+                               } else {
+                                       sc->sc_txq[i].axq_link = NULL;
+                               }
                                ATH_TXQ_UNLOCK(&sc->sc_txq[i]);
                        } else
                                ath_tx_draintxq(sc, &sc->sc_txq[i]);

Modified: head/sys/dev/ath/if_ath_beacon.c
==============================================================================
--- head/sys/dev/ath/if_ath_beacon.c    Sat May 18 18:01:21 2013        
(r250782)
+++ head/sys/dev/ath/if_ath_beacon.c    Sat May 18 18:27:53 2013        
(r250783)
@@ -642,6 +642,7 @@ ath_beacon_cabq_start_edma(struct ath_so
 
        /* Push the first entry into the hardware */
        ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr);
+       cabq->axq_flags |= ATH_TXQ_PUTRUNNING;
 
        /* NB: gated by beacon so safe to start here */
        ath_hal_txstart(sc->sc_ah, cabq->axq_qnum);
@@ -661,6 +662,7 @@ ath_beacon_cabq_start_legacy(struct ath_
 
        /* Push the first entry into the hardware */
        ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr);
+       cabq->axq_flags |= ATH_TXQ_PUTRUNNING;
 
        /* NB: gated by beacon so safe to start here */
        ath_hal_txstart(sc->sc_ah, cabq->axq_qnum);
@@ -736,6 +738,16 @@ ath_beacon_generate(struct ath_softc *sc
                         * frames from a different vap.
                         * XXX could be slow causing us to miss DBA
                         */
+                       /*
+                        * XXX TODO: this doesn't stop CABQ DMA - it assumes
+                        * that since we're about to transmit a beacon, we've
+                        * already stopped transmitting on the CABQ.  But this
+                        * doesn't at all mean that the CABQ DMA QCU will
+                        * accept a new TXDP!  So what, should we do a DMA
+                        * stop? What if it fails?
+                        *
+                        * More thought is required here.
+                        */
                        ath_tx_draintxq(sc, cabq);
                }
        }

Modified: head/sys/dev/ath/if_ath_misc.h
==============================================================================
--- head/sys/dev/ath/if_ath_misc.h      Sat May 18 18:01:21 2013        
(r250782)
+++ head/sys/dev/ath/if_ath_misc.h      Sat May 18 18:27:53 2013        
(r250783)
@@ -125,6 +125,8 @@ extern      void ath_tx_update_tim(struct ath
 extern void ath_start(struct ifnet *ifp);
 extern void ath_start_task(void *arg, int npending);
 
+extern void ath_tx_dump(struct ath_softc *sc, struct ath_txq *txq);
+
 /*
  * Kick the frame TX task.
  */

Modified: head/sys/dev/ath/if_ath_tx.c
==============================================================================
--- head/sys/dev/ath/if_ath_tx.c        Sat May 18 18:01:21 2013        
(r250782)
+++ head/sys/dev/ath/if_ath_tx.c        Sat May 18 18:27:53 2013        
(r250783)
@@ -744,6 +744,7 @@ ath_tx_handoff_hw(struct ath_softc *sc, 
     struct ath_buf *bf)
 {
        struct ath_hal *ah = sc->sc_ah;
+       struct ath_buf *bf_first;
 
        /*
         * Insert the frame on the outbound list and pass it on
@@ -759,6 +760,13 @@ ath_tx_handoff_hw(struct ath_softc *sc, 
        KASSERT(txq->axq_qnum != ATH_TXQ_SWQ,
             ("ath_tx_handoff_hw called for mcast queue"));
 
+       /*
+        * XXX racy, should hold the PCU lock when checking this,
+        * and also should ensure that the TX counter is >0!
+        */
+       KASSERT((sc->sc_inreset_cnt == 0),
+           ("%s: TX during reset?\n", __func__));
+
 #if 0
        /*
         * This causes a LOR. Find out where the PCU lock is being
@@ -776,161 +784,141 @@ ath_tx_handoff_hw(struct ath_softc *sc, 
                    __func__, txq->axq_qnum,
                    (caddr_t)bf->bf_daddr, bf->bf_desc,
                    txq->axq_depth);
+               /* XXX axq_link needs to be set and updated! */
                ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
                if (bf->bf_state.bfs_aggr)
                        txq->axq_aggr_depth++;
-               /*
-                * There's no need to update axq_link; the hardware
-                * is in reset and once the reset is complete, any
-                * non-empty queues will simply have DMA restarted.
-                */
                return;
                }
        ATH_PCU_UNLOCK(sc);
 #endif
 
-       /* For now, so not to generate whitespace diffs */
-       if (1) {
-               ATH_TXQ_LOCK(txq);
-#ifdef IEEE80211_SUPPORT_TDMA
-               int qbusy;
+       ATH_TXQ_LOCK(txq);
 
-               ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
-               qbusy = ath_hal_txqenabled(ah, txq->axq_qnum);
+       /*
+        * XXX TODO: if there's a holdingbf, then
+        * ATH_TXQ_PUTRUNNING should be clear.
+        *
+        * If there is a holdingbf and the list is empty,
+        * then axq_link should be pointing to the holdingbf.
+        *
+        * Otherwise it should point to the last descriptor
+        * in the last ath_buf.
+        *
+        * In any case, we should really ensure that we
+        * update the previous descriptor link pointer to
+        * this descriptor, regardless of all of the above state.
+        *
+        * For now this is captured by having axq_link point
+        * to either the holdingbf (if the TXQ list is empty)
+        * or the end of the list (if the TXQ list isn't empty.)
+        * I'd rather just kill axq_link here and do it as above.
+        */
 
-               ATH_KTR(sc, ATH_KTR_TX, 4,
-                   "ath_tx_handoff: txq=%u, add bf=%p, qbusy=%d, depth=%d",
-                   txq->axq_qnum, bf, qbusy, txq->axq_depth);
-               if (txq->axq_link == NULL) {
-                       /*
-                        * Be careful writing the address to TXDP.  If
-                        * the tx q is enabled then this write will be
-                        * ignored.  Normally this is not an issue but
-                        * when tdma is in use and the q is beacon gated
-                        * this race can occur.  If the q is busy then
-                        * defer the work to later--either when another
-                        * packet comes along or when we prepare a beacon
-                        * frame at SWBA.
-                        */
-                       if (!qbusy) {
-                               ath_hal_puttxbuf(ah, txq->axq_qnum,
-                                   bf->bf_daddr);
-                               txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
-                               DPRINTF(sc, ATH_DEBUG_XMIT,
-                                   "%s: TXDP[%u] = %p (%p) lastds=%p depth 
%d\n",
-                                   __func__, txq->axq_qnum,
-                                   (caddr_t)bf->bf_daddr, bf->bf_desc,
-                                   bf->bf_lastds,
-                                   txq->axq_depth);
-                               ATH_KTR(sc, ATH_KTR_TX, 5,
-                                   "ath_tx_handoff: TXDP[%u] = %p (%p) "
-                                   "lastds=%p depth %d",
-                                   txq->axq_qnum,
-                                   (caddr_t)bf->bf_daddr, bf->bf_desc,
-                                   bf->bf_lastds,
-                                   txq->axq_depth);
-                       } else {
-                               txq->axq_flags |= ATH_TXQ_PUTPENDING;
-                               DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
-                                   "%s: Q%u busy, defer enable\n", __func__,
-                                   txq->axq_qnum);
-                               ATH_KTR(sc, ATH_KTR_TX, 0, "defer enable");
-                       }
-               } else {
-                       *txq->axq_link = bf->bf_daddr;
-                       DPRINTF(sc, ATH_DEBUG_XMIT,
-                           "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
-                           txq->axq_qnum, txq->axq_link,
-                           (caddr_t)bf->bf_daddr, bf->bf_desc,
-                           txq->axq_depth);
-                       ATH_KTR(sc, ATH_KTR_TX, 5,
-                           "ath_tx_handoff: link[%u](%p)=%p (%p) lastds=%p",
-                           txq->axq_qnum, txq->axq_link,
-                           (caddr_t)bf->bf_daddr, bf->bf_desc,
-                           bf->bf_lastds);
-
-                       if ((txq->axq_flags & ATH_TXQ_PUTPENDING) && !qbusy) {
-                               /*
-                                * The q was busy when we previously tried
-                                * to write the address of the first buffer
-                                * in the chain.  Since it's not busy now
-                                * handle this chore.  We are certain the
-                                * buffer at the front is the right one since
-                                * axq_link is NULL only when the buffer list
-                                * is/was empty.
-                                */
-                               ath_hal_puttxbuf(ah, txq->axq_qnum,
-                                       TAILQ_FIRST(&txq->axq_q)->bf_daddr);
-                               txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
-                               DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
-                                   "%s: Q%u restarted\n", __func__,
-                                   txq->axq_qnum);
-                               ATH_KTR(sc, ATH_KTR_TX, 4,
-                                 "ath_tx_handoff: txq[%d] restarted, bf=%p "
-                                 "daddr=%p ds=%p",
-                                   txq->axq_qnum,
-                                   bf,
-                                   (caddr_t)bf->bf_daddr,
-                                   bf->bf_desc);
-                       }
-               }
-#else
-               ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
-               ATH_KTR(sc, ATH_KTR_TX, 3,
-                   "ath_tx_handoff: non-tdma: txq=%u, add bf=%p "
-                   "depth=%d",
+       /*
+        * Append the frame to the TX queue.
+        */
+       ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+       ATH_KTR(sc, ATH_KTR_TX, 3,
+           "ath_tx_handoff: non-tdma: txq=%u, add bf=%p "
+           "depth=%d",
+           txq->axq_qnum,
+           bf,
+           txq->axq_depth);
+
+       /*
+        * If there's a link pointer, update it.
+        *
+        * XXX we should replace this with the above logic, just
+        * to kill axq_link with fire.
+        */
+       if (txq->axq_link != NULL) {
+               *txq->axq_link = bf->bf_daddr;
+               DPRINTF(sc, ATH_DEBUG_XMIT,
+                   "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
+                   txq->axq_qnum, txq->axq_link,
+                   (caddr_t)bf->bf_daddr, bf->bf_desc,
+                   txq->axq_depth);
+               ATH_KTR(sc, ATH_KTR_TX, 5,
+                   "ath_tx_handoff: non-tdma: link[%u](%p)=%p (%p) "
+                   "lastds=%d",
+                   txq->axq_qnum, txq->axq_link,
+                   (caddr_t)bf->bf_daddr, bf->bf_desc,
+                   bf->bf_lastds);
+       }
+
+       /*
+        * If we've not pushed anything into the hardware yet,
+        * push the head of the queue into the TxDP.
+        *
+        * Once we've started DMA, there's no guarantee that
+        * updating the TxDP with a new value will actually work.
+        * So we just don't do that - if we hit the end of the list,
+        * we keep that buffer around (the "holding buffer") and
+        * re-start DMA by updating the link pointer of _that_
+        * descriptor and then restart DMA.
+        */
+       if (! (txq->axq_flags & ATH_TXQ_PUTRUNNING)) {
+               bf_first = TAILQ_FIRST(&txq->axq_q);
+               txq->axq_flags |= ATH_TXQ_PUTRUNNING;
+               ath_hal_puttxbuf(ah, txq->axq_qnum, bf_first->bf_daddr);
+               DPRINTF(sc, ATH_DEBUG_XMIT,
+                   "%s: TXDP[%u] = %p (%p) depth %d\n",
+                   __func__, txq->axq_qnum,
+                   (caddr_t)bf_first->bf_daddr, bf_first->bf_desc,
+                   txq->axq_depth);
+               ATH_KTR(sc, ATH_KTR_TX, 5,
+                   "ath_tx_handoff: TXDP[%u] = %p (%p) "
+                   "lastds=%p depth %d",
                    txq->axq_qnum,
-                   bf,
+                   (caddr_t)bf_first->bf_daddr, bf_first->bf_desc,
+                   bf_first->bf_lastds,
                    txq->axq_depth);
-               if (txq->axq_link == NULL) {
-                       ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
-                       DPRINTF(sc, ATH_DEBUG_XMIT,
-                           "%s: TXDP[%u] = %p (%p) depth %d\n",
-                           __func__, txq->axq_qnum,
-                           (caddr_t)bf->bf_daddr, bf->bf_desc,
-                           txq->axq_depth);
-                       ATH_KTR(sc, ATH_KTR_TX, 5,
-                           "ath_tx_handoff: non-tdma: TXDP[%u] = %p (%p) "
-                           "lastds=%p depth %d",
-                           txq->axq_qnum,
-                           (caddr_t)bf->bf_daddr, bf->bf_desc,
-                           bf->bf_lastds,
-                           txq->axq_depth);
+       }
 
-               } else {
-                       *txq->axq_link = bf->bf_daddr;
-                       DPRINTF(sc, ATH_DEBUG_XMIT,
-                           "%s: link[%u](%p)=%p (%p) depth %d\n", __func__,
-                           txq->axq_qnum, txq->axq_link,
-                           (caddr_t)bf->bf_daddr, bf->bf_desc,
-                           txq->axq_depth);
-                       ATH_KTR(sc, ATH_KTR_TX, 5,
-                           "ath_tx_handoff: non-tdma: link[%u](%p)=%p (%p) "
-                           "lastds=%d",
-                           txq->axq_qnum, txq->axq_link,
-                           (caddr_t)bf->bf_daddr, bf->bf_desc,
-                           bf->bf_lastds);
+       /*
+        * Ensure that the bf TXQ matches this TXQ, so later
+        * checking and holding buffer manipulation is sane.
+        */
+       if (bf->bf_state.bfs_tx_queue != txq->axq_qnum) {
+               device_printf(sc->sc_dev,
+                   "%s: bf=%p, bfs_tx_queue=%d, axq_qnum=%d\n",
+                   __func__,
+                   bf,
+                   bf->bf_state.bfs_tx_queue,
+                   txq->axq_qnum);
+       }
 
-               }
-#endif /* IEEE80211_SUPPORT_TDMA */
+       /*
+        * Track aggregate queue depth.
+        */
+       if (bf->bf_state.bfs_aggr)
+               txq->axq_aggr_depth++;
 
-               if (bf->bf_state.bfs_tx_queue != txq->axq_qnum) {
-                       device_printf(sc->sc_dev,
-                           "%s: bf=%p, bfs_tx_queue=%d, axq_qnum=%d\n",
-                           __func__,
-                           bf,
-                           bf->bf_state.bfs_tx_queue,
-                           txq->axq_qnum);
-               }
+       /*
+        * Update the link pointer.
+        */
+       ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
 
-               if (bf->bf_state.bfs_aggr)
-                       txq->axq_aggr_depth++;
-               ath_hal_gettxdesclinkptr(ah, bf->bf_lastds, &txq->axq_link);
-               ath_hal_txstart(ah, txq->axq_qnum);
-               ATH_TXQ_UNLOCK(txq);
-               ATH_KTR(sc, ATH_KTR_TX, 1,
-                   "ath_tx_handoff: txq=%u, txstart", txq->axq_qnum);
-       }
+       /*
+        * Start DMA.
+        *
+        * If we wrote a TxDP above, DMA will start from here.
+        *
+        * If DMA is running, it'll do nothing.
+        *
+        * If the DMA engine hit the end of the QCU list (ie LINK=NULL,
+        * or VEOL) then it stops at the last transmitted write.
+        * We then append a new frame by updating the link pointer
+        * in that descriptor and then kick TxE here; it will re-read
+        * that last descriptor and find the new descriptor to transmit.
+        *
+        * This is why we keep the holding descriptor around.
+        */
+       ath_hal_txstart(ah, txq->axq_qnum);
+       ATH_TXQ_UNLOCK(txq);
+       ATH_KTR(sc, ATH_KTR_TX, 1,
+           "ath_tx_handoff: txq=%u, txstart", txq->axq_qnum);
 }
 
 /*
@@ -945,8 +933,6 @@ ath_legacy_tx_dma_restart(struct ath_sof
        struct ath_buf *bf, *bf_last;
 
        ATH_TXQ_LOCK_ASSERT(txq);
-       /* This is always going to be cleared, empty or not */
-       txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
 
        /* XXX make this ATH_TXQ_FIRST */
        bf = TAILQ_FIRST(&txq->axq_q);
@@ -955,7 +941,29 @@ ath_legacy_tx_dma_restart(struct ath_sof
        if (bf == NULL)
                return;
 
-       ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+       DPRINTF(sc, ATH_DEBUG_RESET,
+           "%s: Q%d: bf=%p, bf_last=%p, daddr=0x%08x\n",
+           __func__,
+           txq->axq_qnum,
+           bf,
+           bf_last,
+           (uint32_t) bf->bf_daddr);
+
+       if (sc->sc_debug & ATH_DEBUG_RESET)
+               ath_tx_dump(sc, txq);
+
+       /*
+        * This is called from a restart, so DMA is known to be
+        * completely stopped.
+        */
+       KASSERT((!(txq->axq_flags & ATH_TXQ_PUTRUNNING)),
+           ("%s: Q%d: called with PUTRUNNING=1\n",
+           __func__,
+           txq->axq_qnum));
+
+       ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr);
+       txq->axq_flags |= ATH_TXQ_PUTRUNNING;
+
        ath_hal_gettxdesclinkptr(ah, bf_last->bf_lastds, &txq->axq_link);
        ath_hal_txstart(ah, txq->axq_qnum);
 }

Modified: head/sys/dev/ath/if_athvar.h
==============================================================================
--- head/sys/dev/ath/if_athvar.h        Sat May 18 18:01:21 2013        
(r250782)
+++ head/sys/dev/ath/if_athvar.h        Sat May 18 18:27:53 2013        
(r250783)
@@ -327,7 +327,8 @@ struct ath_txq {
 #define        ATH_TXQ_SWQ     (HAL_NUM_TX_QUEUES+1)   /* qnum for s/w only 
queue */
        u_int                   axq_ac;         /* WME AC */
        u_int                   axq_flags;
-#define        ATH_TXQ_PUTPENDING      0x0001          /* ath_hal_puttxbuf 
pending */
+//#define      ATH_TXQ_PUTPENDING      0x0001          /* ath_hal_puttxbuf 
pending */
+#define        ATH_TXQ_PUTRUNNING      0x0002          /* ath_hal_puttxbuf has 
been called */
        u_int                   axq_depth;      /* queue depth (stat only) */
        u_int                   axq_aggr_depth; /* how many aggregates are 
queued */
        u_int                   axq_intrcnt;    /* interrupt count */
_______________________________________________
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