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

Adrian Chadd adrian at FreeBSD.org
Tue Aug 23 23:33:39 UTC 2011


Author: adrian
Date: Tue Aug 23 23:33:38 2011
New Revision: 225124
URL: http://svn.freebsd.org/changeset/base/225124

Log:
  Try to make the ATH_BUF_BUSY handling work again.
  
  * add bf_last to ath_buf, which points to the last frame in
    an aggregate, or itself for a single frame
  * Set ATH_BUF_BUSY in the last frame in an aggregate - that's
    the ath_buf which the hardware may be currently tinkering
    with.
  * Restore the ATH_BUF_BUSY clearing in ath_tx_processq() -
    clear the ATH_BUF_BUSY flag in the last entry on the free list
    before adding the next buffer - it's assumed the hardware has
    finished with that descriptor.
  
  This should restore the current behaviour that ATH_BUF_BUSY
  protects against, but:
  
  * retries which use ATH_BUF_BUSY buffers need to result in the
    ath_buf being cloned, rather than reused. That buffer then
    needs to be returned to the free list.
  
  * This code seems like it'll only work for a single TX queue.
    As in, if TXQ 0 has been handled and the last buffer is marked
    BUSY, then TXQ 1 runs - the last buffer on the free list will
    be marked as non-busy.
  
    ath9k and the reference code uses a more complicated
    "holding descriptor" setup which keeps the descriptor on the
    TXQ list and frees it when needed. This will be eventually
    needed!

Modified:
  user/adrian/if_ath_tx/sys/dev/ath/if_ath.c
  user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
  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	Tue Aug 23 21:10:23 2011	(r225123)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath.c	Tue Aug 23 23:33:38 2011	(r225124)
@@ -1885,6 +1885,7 @@ _ath_getbuf_locked(struct ath_softc *sc)
 			"out of xmit buffers" : "xmit buffer busy");
 	} else {
 		bf->bf_next = NULL;	/* XXX just to be sure */
+		bf->bf_last = NULL;	/* XXX again, just to be sure */
 		bf->bf_comp = NULL;	/* XXX again, just to be sure */
 	}
 	return bf;
@@ -2433,6 +2434,7 @@ ath_beacon_setup(struct ath_softc *sc, s
 
 	/* setup descriptors */
 	ds = bf->bf_desc;
+	bf->bf_last = bf;
 
 	flags = HAL_TXDESC_NOACK;
 	if (ic->ic_opmode == IEEE80211_M_IBSS && sc->sc_hasveol) {
@@ -4248,7 +4250,7 @@ static int
 ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
 	struct ath_hal *ah = sc->sc_ah;
-	struct ath_buf *bf;
+	struct ath_buf *bf, *last;
 	struct ath_desc *ds, *ds0;
 	struct ath_tx_status *ts;
 	struct ieee80211_node *ni;
@@ -4289,8 +4291,12 @@ ath_tx_processq(struct ath_softc *sc, st
 			 * More frames follow.  Mark the buffer busy
 			 * so it's not re-used while the hardware may
 			 * still re-read the link field in the descriptor.
+			 *
+			 * Use the last buffer in an aggregate as that
+			 * is where the hardware may be - intermediate
+			 * descriptors won't be "busy".
 			 */
-			bf->bf_flags |= ATH_BUF_BUSY;
+			bf->bf_last->bf_flags |= ATH_BUF_BUSY;
 		} else
 #else
 		if (txq->axq_depth == 0)
@@ -4321,6 +4327,20 @@ ath_tx_processq(struct ath_softc *sc, st
 			ath_tx_update_stats(sc, ts, bf);
 		}
 
+		/*
+		 * Since the last frame may still be marked
+		 * as ATH_BUF_BUSY, unmark it here before
+		 * finishing the frame processing.
+		 * Since we've completed a frame (aggregate
+		 * or otherwise), the hardware has moved on
+		 * and is no longer referencing the previous
+		 * descriptor.
+		 */
+		ATH_TXBUF_LOCK(sc);
+		last = TAILQ_LAST(&sc->sc_txbuf, ath_bufhead_s);
+		if (last != NULL)
+			last->bf_flags &= ~ATH_BUF_BUSY;
+		ATH_TXBUF_UNLOCK(sc);
 
 		/*
 		 * Call the completion handler.
@@ -4574,6 +4594,11 @@ ath_tx_draintxq(struct ath_softc *sc, st
 		 * functions, we -must- call it for aggregation
 		 * destinations or BAW tracking will get upset.
 		 */
+		/*
+		 * Clear ATH_BUF_BUSY; the completion handler
+		 * will free the buffer.
+		 */
+		bf->bf_flags &= ~ATH_BUF_BUSY;
 		if (bf->bf_comp)
 			bf->bf_comp(sc, bf, 1);
 		else

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	Tue Aug 23 21:10:23 2011	(r225123)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Tue Aug 23 23:33:38 2011	(r225124)
@@ -444,6 +444,12 @@ ath_tx_setds_11n(struct ath_softc *sc, s
 	 */
 	bf_first->bf_lastds = bf_prev->bf_lastds;
 
+	/*
+	 * And bf_last in the first descriptor points to the end of
+	 * the aggregate list.
+	 */
+	bf_first->bf_last = bf_prev;
+
 	DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR, "%s: end\n", __func__);
 }
 
@@ -739,6 +745,7 @@ ath_tx_setds(struct ath_softc *sc, struc
 	 * This will be overriden when the descriptor chain is written.
 	 */
 	bf->bf_lastds = ds;
+	bf->bf_last = bf;
 
 	/* XXX TODO: Setup descriptor chain */
 }

Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Tue Aug 23 21:10:23 2011	(r225123)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h	Tue Aug 23 23:33:38 2011	(r225124)
@@ -183,6 +183,7 @@ struct ath_buf {
 	struct mbuf		*bf_m;		/* mbuf for buf */
 	struct ieee80211_node	*bf_node;	/* pointer to the node */
 	struct ath_desc		*bf_lastds;	/* last descriptor for comp status */
+	struct ath_buf		*bf_last;	/* last buffer in aggregate, or self for non-aggregate */
 	bus_size_t		bf_mapsize;
 #define	ATH_MAX_SCATTER		ATH_TXDESC	/* max(tx,rx,beacon) desc's */
 	bus_dma_segment_t	bf_segs[ATH_MAX_SCATTER];


More information about the svn-src-user mailing list