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