Migrate the STAILQ lists to TAILQs.

A bunch of the 11n TX aggregation logic wants to traverse lists of buffers
in various ways. In order to provide O(1) behaviour in this instance,
use TAILQs.

This does blow out the memory footprint and CPU cycles slightly for some
of these operations. I may convert some of these back to STAILQs once
the rest of the software transmit queue handling has been stabilised.

Sponsored by:	Hobnob, Inc.
This commit is contained in:
Adrian Chadd 2011-11-08 17:08:12 +00:00
parent 3f3f6bc302
commit 6b349e5a86
4 changed files with 63 additions and 57 deletions

View File

@ -263,7 +263,7 @@ static int ath_bstuck_threshold = 4; /* max missed beacons */
SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold, SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold,
0, "max missed beacon xmits before chip reset"); 0, "max missed beacon xmits before chip reset");
static MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers"); MALLOC_DEFINE(M_ATHDEV, "athdev", "ath driver dma buffers");
#define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20) #define HAL_MODE_HT20 (HAL_MODE_11NG_HT20 | HAL_MODE_11NA_HT20)
#define HAL_MODE_HT40 \ #define HAL_MODE_HT40 \
@ -952,7 +952,7 @@ ath_vap_create(struct ieee80211com *ic,
/* /*
* Check that a beacon buffer is available; the code below assumes it. * Check that a beacon buffer is available; the code below assumes it.
*/ */
if (needbeacon & STAILQ_EMPTY(&sc->sc_bbuf)) { if (needbeacon & TAILQ_EMPTY(&sc->sc_bbuf)) {
device_printf(sc->sc_dev, "no beacon buffer available\n"); device_printf(sc->sc_dev, "no beacon buffer available\n");
goto bad; goto bad;
} }
@ -1014,8 +1014,8 @@ ath_vap_create(struct ieee80211com *ic,
* multicast frames. We know a beacon buffer is * multicast frames. We know a beacon buffer is
* available because we checked above. * available because we checked above.
*/ */
avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf); avp->av_bcbuf = TAILQ_FIRST(&sc->sc_bbuf);
STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list); TAILQ_REMOVE(&sc->sc_bbuf, avp->av_bcbuf, bf_list);
if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) { if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) {
/* /*
* Assign the vap to a beacon xmit slot. As above * Assign the vap to a beacon xmit slot. As above
@ -1796,14 +1796,14 @@ _ath_getbuf_locked(struct ath_softc *sc)
ATH_TXBUF_LOCK_ASSERT(sc); ATH_TXBUF_LOCK_ASSERT(sc);
bf = STAILQ_FIRST(&sc->sc_txbuf); bf = TAILQ_FIRST(&sc->sc_txbuf);
if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0) if (bf != NULL && (bf->bf_flags & ATH_BUF_BUSY) == 0)
STAILQ_REMOVE_HEAD(&sc->sc_txbuf, bf_list); TAILQ_REMOVE(&sc->sc_txbuf, bf, bf_list);
else else
bf = NULL; bf = NULL;
if (bf == NULL) { if (bf == NULL) {
DPRINTF(sc, ATH_DEBUG_XMIT, "%s: %s\n", __func__, DPRINTF(sc, ATH_DEBUG_XMIT, "%s: %s\n", __func__,
STAILQ_FIRST(&sc->sc_txbuf) == NULL ? TAILQ_FIRST(&sc->sc_txbuf) == NULL ?
"out of xmit buffers" : "xmit buffer busy"); "out of xmit buffers" : "xmit buffer busy");
} }
return bf; return bf;
@ -1849,7 +1849,7 @@ ath_start(struct ifnet *ifp)
IFQ_DEQUEUE(&ifp->if_snd, m); IFQ_DEQUEUE(&ifp->if_snd, m);
if (m == NULL) { if (m == NULL) {
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
break; break;
} }
@ -1860,7 +1860,7 @@ ath_start(struct ifnet *ifp)
* buffers to send all the fragments so all * buffers to send all the fragments so all
* go out or none... * go out or none...
*/ */
STAILQ_INIT(&frags); TAILQ_INIT(&frags);
if ((m->m_flags & M_FRAG) && if ((m->m_flags & M_FRAG) &&
!ath_txfrag_setup(sc, &frags, m, ni)) { !ath_txfrag_setup(sc, &frags, m, ni)) {
DPRINTF(sc, ATH_DEBUG_XMIT, DPRINTF(sc, ATH_DEBUG_XMIT,
@ -1892,7 +1892,7 @@ ath_start(struct ifnet *ifp)
bf->bf_m = NULL; bf->bf_m = NULL;
bf->bf_node = NULL; bf->bf_node = NULL;
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
ath_txfrag_cleanup(sc, &frags, ni); ath_txfrag_cleanup(sc, &frags, ni);
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
if (ni != NULL) if (ni != NULL)
@ -1913,9 +1913,9 @@ ath_start(struct ifnet *ifp)
goto reclaim; goto reclaim;
} }
m = next; m = next;
bf = STAILQ_FIRST(&frags); bf = TAILQ_FIRST(&frags);
KASSERT(bf != NULL, ("no buf for txfrag")); KASSERT(bf != NULL, ("no buf for txfrag"));
STAILQ_REMOVE_HEAD(&frags, bf_list); TAILQ_REMOVE(&frags, bf, bf_list);
goto nextfrag; goto nextfrag;
} }
@ -2414,7 +2414,7 @@ ath_beacon_update(struct ieee80211vap *vap, int item)
static void static void
ath_txqmove(struct ath_txq *dst, struct ath_txq *src) ath_txqmove(struct ath_txq *dst, struct ath_txq *src)
{ {
STAILQ_CONCAT(&dst->axq_q, &src->axq_q); TAILQ_CONCAT(&dst->axq_q, &src->axq_q, bf_list);
dst->axq_link = src->axq_link; dst->axq_link = src->axq_link;
src->axq_link = NULL; src->axq_link = NULL;
dst->axq_depth += src->axq_depth; dst->axq_depth += src->axq_depth;
@ -2609,7 +2609,7 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
* Move frames from the s/w mcast q to the h/w cab q. * Move frames from the s/w mcast q to the h/w cab q.
* XXX MORE_DATA bit * XXX MORE_DATA bit
*/ */
bfm = STAILQ_FIRST(&avp->av_mcastq.axq_q); bfm = TAILQ_FIRST(&avp->av_mcastq.axq_q);
if (cabq->axq_link != NULL) { if (cabq->axq_link != NULL) {
*cabq->axq_link = bfm->bf_daddr; *cabq->axq_link = bfm->bf_daddr;
} else } else
@ -2620,7 +2620,7 @@ ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap)
sc->sc_stats.ast_cabq_xmit += nmcastq; sc->sc_stats.ast_cabq_xmit += nmcastq;
} }
/* NB: gated by beacon so safe to start here */ /* NB: gated by beacon so safe to start here */
if (! STAILQ_EMPTY(&(cabq->axq_q))) if (! TAILQ_EMPTY(&(cabq->axq_q)))
ath_hal_txstart(ah, cabq->axq_qnum); ath_hal_txstart(ah, cabq->axq_qnum);
ATH_TXQ_UNLOCK(&avp->av_mcastq); ATH_TXQ_UNLOCK(&avp->av_mcastq);
ATH_TXQ_UNLOCK(cabq); ATH_TXQ_UNLOCK(cabq);
@ -2699,7 +2699,7 @@ ath_beacon_return(struct ath_softc *sc, struct ath_buf *bf)
ieee80211_free_node(bf->bf_node); ieee80211_free_node(bf->bf_node);
bf->bf_node = NULL; bf->bf_node = NULL;
} }
STAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list); TAILQ_INSERT_TAIL(&sc->sc_bbuf, bf, bf_list);
} }
/* /*
@ -2710,7 +2710,7 @@ ath_beacon_free(struct ath_softc *sc)
{ {
struct ath_buf *bf; struct ath_buf *bf;
STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { TAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) {
if (bf->bf_m != NULL) { if (bf->bf_m != NULL) {
bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap);
m_freem(bf->bf_m); m_freem(bf->bf_m);
@ -3029,7 +3029,7 @@ ath_descdma_setup(struct ath_softc *sc,
} }
dd->dd_bufptr = bf; dd->dd_bufptr = bf;
STAILQ_INIT(head); TAILQ_INIT(head);
for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) { for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) {
bf->bf_desc = (struct ath_desc *) ds; bf->bf_desc = (struct ath_desc *) ds;
bf->bf_daddr = DS2PHYS(dd, ds); bf->bf_daddr = DS2PHYS(dd, ds);
@ -3055,7 +3055,7 @@ ath_descdma_setup(struct ath_softc *sc,
ath_descdma_cleanup(sc, dd, head); ath_descdma_cleanup(sc, dd, head);
return error; return error;
} }
STAILQ_INSERT_TAIL(head, bf, bf_list); TAILQ_INSERT_TAIL(head, bf, bf_list);
} }
return 0; return 0;
fail3: fail3:
@ -3084,7 +3084,7 @@ ath_descdma_cleanup(struct ath_softc *sc,
bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap);
bus_dma_tag_destroy(dd->dd_dmat); bus_dma_tag_destroy(dd->dd_dmat);
STAILQ_FOREACH(bf, head, bf_list) { TAILQ_FOREACH(bf, head, bf_list) {
if (bf->bf_m) { if (bf->bf_m) {
m_freem(bf->bf_m); m_freem(bf->bf_m);
bf->bf_m = NULL; bf->bf_m = NULL;
@ -3103,7 +3103,7 @@ ath_descdma_cleanup(struct ath_softc *sc,
} }
} }
STAILQ_INIT(head); TAILQ_INIT(head);
free(dd->dd_bufptr, M_ATHDEV); free(dd->dd_bufptr, M_ATHDEV);
memset(dd, 0, sizeof(*dd)); memset(dd, 0, sizeof(*dd));
} }
@ -3485,7 +3485,7 @@ ath_rx_proc(void *arg, int npending)
sc->sc_stats.ast_rx_noise = nf; sc->sc_stats.ast_rx_noise = nf;
tsf = ath_hal_gettsf64(ah); tsf = ath_hal_gettsf64(ah);
do { do {
bf = STAILQ_FIRST(&sc->sc_rxbuf); bf = TAILQ_FIRST(&sc->sc_rxbuf);
if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */ if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */
if_printf(ifp, "%s: no buffer!\n", __func__); if_printf(ifp, "%s: no buffer!\n", __func__);
break; break;
@ -3505,7 +3505,7 @@ ath_rx_proc(void *arg, int npending)
*/ */
/* XXX make debug msg */ /* XXX make debug msg */
if_printf(ifp, "%s: no mbuf!\n", __func__); if_printf(ifp, "%s: no mbuf!\n", __func__);
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
goto rx_next; goto rx_next;
} }
ds = bf->bf_desc; ds = bf->bf_desc;
@ -3535,7 +3535,8 @@ ath_rx_proc(void *arg, int npending)
#endif #endif
if (status == HAL_EINPROGRESS) if (status == HAL_EINPROGRESS)
break; break;
STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list);
TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list);
/* These aren't specifically errors */ /* These aren't specifically errors */
if (rs->rs_flags & HAL_RX_GI) if (rs->rs_flags & HAL_RX_GI)
@ -3804,7 +3805,7 @@ rx_accept:
ath_led_event(sc, 0); ath_led_event(sc, 0);
} }
rx_next: rx_next:
STAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list); TAILQ_INSERT_TAIL(&sc->sc_rxbuf, bf, bf_list);
} while (ath_rxbuf_init(sc, bf) == 0); } while (ath_rxbuf_init(sc, bf) == 0);
/* rx signal state monitoring */ /* rx signal state monitoring */
@ -3853,7 +3854,9 @@ ath_txq_init(struct ath_softc *sc, struct ath_txq *txq, int qnum)
txq->axq_depth = 0; txq->axq_depth = 0;
txq->axq_intrcnt = 0; txq->axq_intrcnt = 0;
txq->axq_link = NULL; txq->axq_link = NULL;
STAILQ_INIT(&txq->axq_q); txq->axq_softc = sc;
TAILQ_INIT(&txq->axq_q);
TAILQ_INIT(&txq->axq_tidq);
ATH_TXQ_LOCK_INIT(sc, txq); ATH_TXQ_LOCK_INIT(sc, txq);
} }
@ -4088,7 +4091,7 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
for (;;) { for (;;) {
ATH_TXQ_LOCK(txq); ATH_TXQ_LOCK(txq);
txq->axq_intrcnt = 0; /* reset periodic desc intr count */ txq->axq_intrcnt = 0; /* reset periodic desc intr count */
bf = STAILQ_FIRST(&txq->axq_q); bf = TAILQ_FIRST(&txq->axq_q);
if (bf == NULL) { if (bf == NULL) {
ATH_TXQ_UNLOCK(txq); ATH_TXQ_UNLOCK(txq);
break; break;
@ -4106,7 +4109,7 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
ATH_TXQ_UNLOCK(txq); ATH_TXQ_UNLOCK(txq);
break; break;
} }
ATH_TXQ_REMOVE_HEAD(txq, bf_list); ATH_TXQ_REMOVE(txq, bf, bf_list);
#ifdef IEEE80211_SUPPORT_TDMA #ifdef IEEE80211_SUPPORT_TDMA
if (txq->axq_depth > 0) { if (txq->axq_depth > 0) {
/* /*
@ -4199,10 +4202,10 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
bf->bf_node = NULL; bf->bf_node = NULL;
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
last = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list); last = TAILQ_LAST(&sc->sc_txbuf, ath_bufhead_s);
if (last != NULL) if (last != NULL)
last->bf_flags &= ~ATH_BUF_BUSY; last->bf_flags &= ~ATH_BUF_BUSY;
STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
} }
#ifdef IEEE80211_SUPPORT_SUPERG #ifdef IEEE80211_SUPPORT_SUPERG
@ -4327,19 +4330,19 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
* we do not need to block ath_tx_proc * we do not need to block ath_tx_proc
*/ */
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
bf = STAILQ_LAST(&sc->sc_txbuf, ath_buf, bf_list); bf = TAILQ_LAST(&sc->sc_txbuf, ath_bufhead_s);
if (bf != NULL) if (bf != NULL)
bf->bf_flags &= ~ATH_BUF_BUSY; bf->bf_flags &= ~ATH_BUF_BUSY;
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
for (ix = 0;; ix++) { for (ix = 0;; ix++) {
ATH_TXQ_LOCK(txq); ATH_TXQ_LOCK(txq);
bf = STAILQ_FIRST(&txq->axq_q); bf = TAILQ_FIRST(&txq->axq_q);
if (bf == NULL) { if (bf == NULL) {
txq->axq_link = NULL; txq->axq_link = NULL;
ATH_TXQ_UNLOCK(txq); ATH_TXQ_UNLOCK(txq);
break; break;
} }
ATH_TXQ_REMOVE_HEAD(txq, bf_list); ATH_TXQ_REMOVE(txq, bf, bf_list);
ATH_TXQ_UNLOCK(txq); ATH_TXQ_UNLOCK(txq);
#ifdef ATH_DEBUG #ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RESET) { if (sc->sc_debug & ATH_DEBUG_RESET) {
@ -4368,7 +4371,7 @@ ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
bf->bf_flags &= ~ATH_BUF_BUSY; bf->bf_flags &= ~ATH_BUF_BUSY;
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
STAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list); TAILQ_INSERT_TAIL(&sc->sc_txbuf, bf, bf_list);
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
} }
} }
@ -4412,7 +4415,7 @@ ath_draintxq(struct ath_softc *sc)
ath_tx_draintxq(sc, &sc->sc_txq[i]); ath_tx_draintxq(sc, &sc->sc_txq[i]);
#ifdef ATH_DEBUG #ifdef ATH_DEBUG
if (sc->sc_debug & ATH_DEBUG_RESET) { if (sc->sc_debug & ATH_DEBUG_RESET) {
struct ath_buf *bf = STAILQ_FIRST(&sc->sc_bbuf); struct ath_buf *bf = TAILQ_FIRST(&sc->sc_bbuf);
if (bf != NULL && bf->bf_m != NULL) { if (bf != NULL && bf->bf_m != NULL) {
ath_printtxbuf(sc, bf, sc->sc_bhalq, 0, ath_printtxbuf(sc, bf, sc->sc_bhalq, 0,
ath_hal_txprocdesc(ah, bf->bf_desc, ath_hal_txprocdesc(ah, bf->bf_desc,
@ -4450,7 +4453,7 @@ ath_stoprecv(struct ath_softc *sc)
printf("%s: rx queue %p, link %p\n", __func__, printf("%s: rx queue %p, link %p\n", __func__,
(caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink);
ix = 0; ix = 0;
STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
struct ath_desc *ds = bf->bf_desc; struct ath_desc *ds = bf->bf_desc;
struct ath_rx_status *rs = &bf->bf_status.ds_rxstat; struct ath_rx_status *rs = &bf->bf_status.ds_rxstat;
HAL_STATUS status = ath_hal_rxprocdesc(ah, ds, HAL_STATUS status = ath_hal_rxprocdesc(ah, ds,
@ -4480,7 +4483,7 @@ ath_startrecv(struct ath_softc *sc)
sc->sc_rxlink = NULL; sc->sc_rxlink = NULL;
sc->sc_rxpending = NULL; sc->sc_rxpending = NULL;
STAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) { TAILQ_FOREACH(bf, &sc->sc_rxbuf, bf_list) {
int error = ath_rxbuf_init(sc, bf); int error = ath_rxbuf_init(sc, bf);
if (error != 0) { if (error != 0) {
DPRINTF(sc, ATH_DEBUG_RECV, DPRINTF(sc, ATH_DEBUG_RECV,
@ -4490,7 +4493,7 @@ ath_startrecv(struct ath_softc *sc)
} }
} }
bf = STAILQ_FIRST(&sc->sc_rxbuf); bf = TAILQ_FIRST(&sc->sc_rxbuf);
ath_hal_putrxbuf(ah, bf->bf_daddr); ath_hal_putrxbuf(ah, bf->bf_daddr);
ath_hal_rxena(ah); /* enable recv descriptors */ ath_hal_rxena(ah); /* enable recv descriptors */
ath_mode_init(sc); /* set filters, etc. */ ath_mode_init(sc); /* set filters, etc. */

View File

@ -346,7 +346,7 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS)
i = t = 0; i = t = 0;
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
STAILQ_FOREACH(bf, &sc->sc_txbuf, bf_list) { TAILQ_FOREACH(bf, &sc->sc_txbuf, bf_list) {
if (bf->bf_flags & ATH_BUF_BUSY) { if (bf->bf_flags & ATH_BUF_BUSY) {
printf("Busy: %d\n", t); printf("Busy: %d\n", t);
i++; i++;

View File

@ -116,10 +116,10 @@ ath_txfrag_cleanup(struct ath_softc *sc,
ATH_TXBUF_LOCK_ASSERT(sc); ATH_TXBUF_LOCK_ASSERT(sc);
STAILQ_FOREACH_SAFE(bf, frags, bf_list, next) { TAILQ_FOREACH_SAFE(bf, frags, bf_list, next) {
/* NB: bf assumed clean */ /* NB: bf assumed clean */
STAILQ_REMOVE_HEAD(frags, bf_list); TAILQ_REMOVE(frags, bf, bf_list);
STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
ieee80211_node_decref(ni); ieee80211_node_decref(ni);
} }
} }
@ -144,11 +144,11 @@ ath_txfrag_setup(struct ath_softc *sc, ath_bufhead *frags,
break; break;
} }
ieee80211_node_incref(ni); ieee80211_node_incref(ni);
STAILQ_INSERT_TAIL(frags, bf, bf_list); TAILQ_INSERT_TAIL(frags, bf, bf_list);
} }
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
return !STAILQ_EMPTY(frags); return !TAILQ_EMPTY(frags);
} }
/* /*
@ -323,7 +323,7 @@ ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
* is/was empty. * is/was empty.
*/ */
ath_hal_puttxbuf(ah, txq->axq_qnum, ath_hal_puttxbuf(ah, txq->axq_qnum,
STAILQ_FIRST(&txq->axq_q)->bf_daddr); TAILQ_FIRST(&txq->axq_q)->bf_daddr);
txq->axq_flags &= ~ATH_TXQ_PUTPENDING; txq->axq_flags &= ~ATH_TXQ_PUTPENDING;
DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT, DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT,
"%s: Q%u restarted\n", __func__, "%s: Q%u restarted\n", __func__,
@ -351,7 +351,7 @@ ath_tx_handoff(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf)
ath_hal_txstart(ah, txq->axq_qnum); ath_hal_txstart(ah, txq->axq_qnum);
} else { } else {
if (txq->axq_link != NULL) { if (txq->axq_link != NULL) {
struct ath_buf *last = ATH_TXQ_LAST(txq); struct ath_buf *last = ATH_TXQ_LAST(txq, axq_q_s);
struct ieee80211_frame *wh; struct ieee80211_frame *wh;
/* mark previous frame */ /* mark previous frame */
@ -1114,7 +1114,7 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
return 0; return 0;
bad2: bad2:
ATH_TXBUF_LOCK(sc); ATH_TXBUF_LOCK(sc);
STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list);
ATH_TXBUF_UNLOCK(sc); ATH_TXBUF_UNLOCK(sc);
bad: bad:
ifp->if_oerrors++; ifp->if_oerrors++;

View File

@ -170,7 +170,7 @@ struct ath_node {
#define ATH_RSSI(x) ATH_EP_RND(x, HAL_RSSI_EP_MULTIPLIER) #define ATH_RSSI(x) ATH_EP_RND(x, HAL_RSSI_EP_MULTIPLIER)
struct ath_buf { struct ath_buf {
STAILQ_ENTRY(ath_buf) bf_list; TAILQ_ENTRY(ath_buf) bf_list;
struct ath_buf * bf_next; /* next buffer in the aggregate */ struct ath_buf * bf_next; /* next buffer in the aggregate */
int bf_nseg; int bf_nseg;
uint16_t bf_txflags; /* tx descriptor flags */ uint16_t bf_txflags; /* tx descriptor flags */
@ -239,7 +239,7 @@ struct ath_buf {
struct ath_rc_series bfs_rc[ATH_RC_NUM]; /* non-11n TX series */ struct ath_rc_series bfs_rc[ATH_RC_NUM]; /* non-11n TX series */
} bf_state; } bf_state;
}; };
typedef STAILQ_HEAD(, ath_buf) ath_bufhead; typedef TAILQ_HEAD(ath_bufhead_s, ath_buf) ath_bufhead;
#define ATH_BUF_BUSY 0x00000002 /* (tx) desc owned by h/w */ #define ATH_BUF_BUSY 0x00000002 /* (tx) desc owned by h/w */
@ -277,9 +277,10 @@ struct ath_txq {
u_int axq_aggr_depth; /* how many aggregates are queued */ u_int axq_aggr_depth; /* how many aggregates are queued */
u_int axq_intrcnt; /* interrupt count */ u_int axq_intrcnt; /* interrupt count */
u_int32_t *axq_link; /* link ptr in last TX desc */ u_int32_t *axq_link; /* link ptr in last TX desc */
STAILQ_HEAD(, ath_buf) axq_q; /* transmit queue */ TAILQ_HEAD(axq_q_s, ath_buf) axq_q; /* transmit queue */
struct mtx axq_lock; /* lock on q and link */ struct mtx axq_lock; /* lock on q and link */
char axq_name[12]; /* e.g. "ath0_txq4" */ char axq_name[12]; /* e.g. "ath0_txq4" */
/* Per-TID traffic queue for software -> hardware TX */ /* Per-TID traffic queue for software -> hardware TX */
TAILQ_HEAD(axq_t_s,ath_tid) axq_tidq; TAILQ_HEAD(axq_t_s,ath_tid) axq_tidq;
}; };
@ -299,18 +300,20 @@ struct ath_txq {
#define ATH_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, MA_OWNED) #define ATH_TXQ_LOCK_ASSERT(_tq) mtx_assert(&(_tq)->axq_lock, MA_OWNED)
#define ATH_TXQ_IS_LOCKED(_tq) mtx_owned(&(_tq)->axq_lock) #define ATH_TXQ_IS_LOCKED(_tq) mtx_owned(&(_tq)->axq_lock)
#define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \ #define ATH_TXQ_INSERT_HEAD(_tq, _elm, _field) do { \
STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \ TAILQ_INSERT_HEAD(&(_tq)->axq_q, (_elm), _field); \
(_tq)->axq_depth++; \ (_tq)->axq_depth++; \
} while (0) } while (0)
#define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \ #define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \
STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \ TAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \
(_tq)->axq_depth++; \
} while (0)
#define ATH_TXQ_REMOVE(_tq, _elm, _field) do { \
TAILQ_REMOVE(&(_tq)->axq_q, _elm, _field); \
(_tq)->axq_depth--; \ (_tq)->axq_depth--; \
} while (0) } while (0)
/* NB: this does not do the "head empty check" that STAILQ_LAST does */ /* NB: this does not do the "head empty check" that STAILQ_LAST does */
#define ATH_TXQ_LAST(_tq) \ #define ATH_TXQ_LAST(_tq, _field) TAILQ_LAST(&(_tq)->axq_q, _field)
((struct ath_buf *)(void *) \
((char *)((_tq)->axq_q.stqh_last) - __offsetof(struct ath_buf, bf_list)))
struct ath_vap { struct ath_vap {
struct ieee80211vap av_vap; /* base class */ struct ieee80211vap av_vap; /* base class */