From owner-svn-src-all@FreeBSD.ORG Tue Nov 8 17:08:12 2011 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id D7A4C106566B; Tue, 8 Nov 2011 17:08:12 +0000 (UTC) (envelope-from adrian@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id C67EE8FC14; Tue, 8 Nov 2011 17:08:12 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id pA8H8CTB040537; Tue, 8 Nov 2011 17:08:12 GMT (envelope-from adrian@svn.freebsd.org) Received: (from adrian@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id pA8H8CnM040532; Tue, 8 Nov 2011 17:08:12 GMT (envelope-from adrian@svn.freebsd.org) Message-Id: <201111081708.pA8H8CnM040532@svn.freebsd.org> From: Adrian Chadd Date: Tue, 8 Nov 2011 17:08:12 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r227344 - head/sys/dev/ath X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 08 Nov 2011 17:08:13 -0000 Author: adrian Date: Tue Nov 8 17:08:12 2011 New Revision: 227344 URL: http://svn.freebsd.org/changeset/base/227344 Log: 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. Modified: head/sys/dev/ath/if_ath.c head/sys/dev/ath/if_ath_sysctl.c 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 Tue Nov 8 15:38:21 2011 (r227343) +++ head/sys/dev/ath/if_ath.c Tue Nov 8 17:08:12 2011 (r227344) @@ -263,7 +263,7 @@ static int ath_bstuck_threshold = 4; /* SYSCTL_INT(_hw_ath, OID_AUTO, bstuck, CTLFLAG_RW, &ath_bstuck_threshold, 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_HT40 \ @@ -952,7 +952,7 @@ ath_vap_create(struct ieee80211com *ic, /* * 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"); goto bad; } @@ -1014,8 +1014,8 @@ ath_vap_create(struct ieee80211com *ic, * multicast frames. We know a beacon buffer is * available because we checked above. */ - avp->av_bcbuf = STAILQ_FIRST(&sc->sc_bbuf); - STAILQ_REMOVE_HEAD(&sc->sc_bbuf, bf_list); + avp->av_bcbuf = TAILQ_FIRST(&sc->sc_bbuf); + TAILQ_REMOVE(&sc->sc_bbuf, avp->av_bcbuf, bf_list); if (opmode != IEEE80211_M_IBSS || !sc->sc_hasveol) { /* * 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); - bf = STAILQ_FIRST(&sc->sc_txbuf); + bf = TAILQ_FIRST(&sc->sc_txbuf); 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 bf = NULL; if (bf == NULL) { 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"); } return bf; @@ -1849,7 +1849,7 @@ ath_start(struct ifnet *ifp) IFQ_DEQUEUE(&ifp->if_snd, m); if (m == NULL) { 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); break; } @@ -1860,7 +1860,7 @@ ath_start(struct ifnet *ifp) * buffers to send all the fragments so all * go out or none... */ - STAILQ_INIT(&frags); + TAILQ_INIT(&frags); if ((m->m_flags & M_FRAG) && !ath_txfrag_setup(sc, &frags, m, ni)) { DPRINTF(sc, ATH_DEBUG_XMIT, @@ -1892,7 +1892,7 @@ ath_start(struct ifnet *ifp) bf->bf_m = NULL; bf->bf_node = NULL; 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_TXBUF_UNLOCK(sc); if (ni != NULL) @@ -1913,9 +1913,9 @@ ath_start(struct ifnet *ifp) goto reclaim; } m = next; - bf = STAILQ_FIRST(&frags); + bf = TAILQ_FIRST(&frags); KASSERT(bf != NULL, ("no buf for txfrag")); - STAILQ_REMOVE_HEAD(&frags, bf_list); + TAILQ_REMOVE(&frags, bf, bf_list); goto nextfrag; } @@ -2414,7 +2414,7 @@ ath_beacon_update(struct ieee80211vap *v static void 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; src->axq_link = NULL; dst->axq_depth += src->axq_depth; @@ -2609,7 +2609,7 @@ ath_beacon_generate(struct ath_softc *sc * Move frames from the s/w mcast q to the h/w cab q. * 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) { *cabq->axq_link = bfm->bf_daddr; } else @@ -2620,7 +2620,7 @@ ath_beacon_generate(struct ath_softc *sc sc->sc_stats.ast_cabq_xmit += nmcastq; } /* 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_TXQ_UNLOCK(&avp->av_mcastq); ATH_TXQ_UNLOCK(cabq); @@ -2699,7 +2699,7 @@ ath_beacon_return(struct ath_softc *sc, ieee80211_free_node(bf->bf_node); 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; - STAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { + TAILQ_FOREACH(bf, &sc->sc_bbuf, bf_list) { if (bf->bf_m != NULL) { bus_dmamap_unload(sc->sc_dmat, bf->bf_dmamap); m_freem(bf->bf_m); @@ -3029,7 +3029,7 @@ ath_descdma_setup(struct ath_softc *sc, } dd->dd_bufptr = bf; - STAILQ_INIT(head); + TAILQ_INIT(head); for (i = 0; i < nbuf; i++, bf++, ds += (ndesc * desc_len)) { bf->bf_desc = (struct ath_desc *) ds; bf->bf_daddr = DS2PHYS(dd, ds); @@ -3055,7 +3055,7 @@ ath_descdma_setup(struct ath_softc *sc, ath_descdma_cleanup(sc, dd, head); return error; } - STAILQ_INSERT_TAIL(head, bf, bf_list); + TAILQ_INSERT_TAIL(head, bf, bf_list); } return 0; fail3: @@ -3084,7 +3084,7 @@ ath_descdma_cleanup(struct ath_softc *sc bus_dmamap_destroy(dd->dd_dmat, dd->dd_dmamap); bus_dma_tag_destroy(dd->dd_dmat); - STAILQ_FOREACH(bf, head, bf_list) { + TAILQ_FOREACH(bf, head, bf_list) { if (bf->bf_m) { m_freem(bf->bf_m); 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); memset(dd, 0, sizeof(*dd)); } @@ -3485,7 +3485,7 @@ ath_rx_proc(void *arg, int npending) sc->sc_stats.ast_rx_noise = nf; tsf = ath_hal_gettsf64(ah); do { - bf = STAILQ_FIRST(&sc->sc_rxbuf); + bf = TAILQ_FIRST(&sc->sc_rxbuf); if (sc->sc_rxslink && bf == NULL) { /* NB: shouldn't happen */ if_printf(ifp, "%s: no buffer!\n", __func__); break; @@ -3505,7 +3505,7 @@ ath_rx_proc(void *arg, int npending) */ /* XXX make debug msg */ 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; } ds = bf->bf_desc; @@ -3535,7 +3535,8 @@ ath_rx_proc(void *arg, int npending) #endif if (status == HAL_EINPROGRESS) break; - STAILQ_REMOVE_HEAD(&sc->sc_rxbuf, bf_list); + + TAILQ_REMOVE(&sc->sc_rxbuf, bf, bf_list); /* These aren't specifically errors */ if (rs->rs_flags & HAL_RX_GI) @@ -3804,7 +3805,7 @@ rx_accept: ath_led_event(sc, 0); } 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); /* rx signal state monitoring */ @@ -3853,7 +3854,9 @@ ath_txq_init(struct ath_softc *sc, struc txq->axq_depth = 0; txq->axq_intrcnt = 0; 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); } @@ -4088,7 +4091,7 @@ ath_tx_processq(struct ath_softc *sc, st for (;;) { ATH_TXQ_LOCK(txq); txq->axq_intrcnt = 0; /* reset periodic desc intr count */ - bf = STAILQ_FIRST(&txq->axq_q); + bf = TAILQ_FIRST(&txq->axq_q); if (bf == NULL) { ATH_TXQ_UNLOCK(txq); break; @@ -4106,7 +4109,7 @@ ath_tx_processq(struct ath_softc *sc, st ATH_TXQ_UNLOCK(txq); break; } - ATH_TXQ_REMOVE_HEAD(txq, bf_list); + ATH_TXQ_REMOVE(txq, bf, bf_list); #ifdef IEEE80211_SUPPORT_TDMA if (txq->axq_depth > 0) { /* @@ -4199,10 +4202,10 @@ ath_tx_processq(struct ath_softc *sc, st bf->bf_node = NULL; 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) 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); } #ifdef IEEE80211_SUPPORT_SUPERG @@ -4327,19 +4330,19 @@ ath_tx_draintxq(struct ath_softc *sc, st * we do not need to block ath_tx_proc */ 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) bf->bf_flags &= ~ATH_BUF_BUSY; ATH_TXBUF_UNLOCK(sc); for (ix = 0;; ix++) { ATH_TXQ_LOCK(txq); - bf = STAILQ_FIRST(&txq->axq_q); + bf = TAILQ_FIRST(&txq->axq_q); if (bf == NULL) { txq->axq_link = NULL; ATH_TXQ_UNLOCK(txq); break; } - ATH_TXQ_REMOVE_HEAD(txq, bf_list); + ATH_TXQ_REMOVE(txq, bf, bf_list); ATH_TXQ_UNLOCK(txq); #ifdef ATH_DEBUG if (sc->sc_debug & ATH_DEBUG_RESET) { @@ -4368,7 +4371,7 @@ ath_tx_draintxq(struct ath_softc *sc, st bf->bf_flags &= ~ATH_BUF_BUSY; 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); } } @@ -4412,7 +4415,7 @@ ath_draintxq(struct ath_softc *sc) ath_tx_draintxq(sc, &sc->sc_txq[i]); #ifdef ATH_DEBUG 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) { ath_printtxbuf(sc, bf, sc->sc_bhalq, 0, 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__, (caddr_t)(uintptr_t) ath_hal_getrxbuf(ah), sc->sc_rxlink); 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_rx_status *rs = &bf->bf_status.ds_rxstat; HAL_STATUS status = ath_hal_rxprocdesc(ah, ds, @@ -4480,7 +4483,7 @@ ath_startrecv(struct ath_softc *sc) sc->sc_rxlink = 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); if (error != 0) { 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_rxena(ah); /* enable recv descriptors */ ath_mode_init(sc); /* set filters, etc. */ Modified: head/sys/dev/ath/if_ath_sysctl.c ============================================================================== --- head/sys/dev/ath/if_ath_sysctl.c Tue Nov 8 15:38:21 2011 (r227343) +++ head/sys/dev/ath/if_ath_sysctl.c Tue Nov 8 17:08:12 2011 (r227344) @@ -346,7 +346,7 @@ ath_sysctl_txagg(SYSCTL_HANDLER_ARGS) i = t = 0; 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) { printf("Busy: %d\n", t); i++; Modified: head/sys/dev/ath/if_ath_tx.c ============================================================================== --- head/sys/dev/ath/if_ath_tx.c Tue Nov 8 15:38:21 2011 (r227343) +++ head/sys/dev/ath/if_ath_tx.c Tue Nov 8 17:08:12 2011 (r227344) @@ -116,10 +116,10 @@ ath_txfrag_cleanup(struct ath_softc *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 */ - STAILQ_REMOVE_HEAD(frags, bf_list); - STAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); + TAILQ_REMOVE(frags, bf, bf_list); + TAILQ_INSERT_HEAD(&sc->sc_txbuf, bf, bf_list); ieee80211_node_decref(ni); } } @@ -144,11 +144,11 @@ ath_txfrag_setup(struct ath_softc *sc, a break; } ieee80211_node_incref(ni); - STAILQ_INSERT_TAIL(frags, bf, bf_list); + TAILQ_INSERT_TAIL(frags, bf, bf_list); } ATH_TXBUF_UNLOCK(sc); - return !STAILQ_EMPTY(frags); + return !TAILQ_EMPTY(frags); } /* @@ -323,7 +323,7 @@ ath_tx_handoff(struct ath_softc *sc, str * is/was empty. */ 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; DPRINTF(sc, ATH_DEBUG_TDMA | ATH_DEBUG_XMIT, "%s: Q%u restarted\n", __func__, @@ -351,7 +351,7 @@ ath_tx_handoff(struct ath_softc *sc, str ath_hal_txstart(ah, txq->axq_qnum); } else { 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; /* mark previous frame */ @@ -1114,7 +1114,7 @@ ath_raw_xmit(struct ieee80211_node *ni, return 0; bad2: 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); bad: ifp->if_oerrors++; Modified: head/sys/dev/ath/if_athvar.h ============================================================================== --- head/sys/dev/ath/if_athvar.h Tue Nov 8 15:38:21 2011 (r227343) +++ head/sys/dev/ath/if_athvar.h Tue Nov 8 17:08:12 2011 (r227344) @@ -170,7 +170,7 @@ struct ath_node { #define ATH_RSSI(x) ATH_EP_RND(x, HAL_RSSI_EP_MULTIPLIER) 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 */ int bf_nseg; 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 */ } 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 */ @@ -277,9 +277,10 @@ struct ath_txq { u_int axq_aggr_depth; /* how many aggregates are queued */ u_int axq_intrcnt; /* interrupt count */ 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 */ char axq_name[12]; /* e.g. "ath0_txq4" */ + /* Per-TID traffic queue for software -> hardware TX */ 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_IS_LOCKED(_tq) mtx_owned(&(_tq)->axq_lock) +#define ATH_TXQ_INSERT_HEAD(_tq, _elm, _field) do { \ + TAILQ_INSERT_HEAD(&(_tq)->axq_q, (_elm), _field); \ + (_tq)->axq_depth++; \ +} while (0) #define ATH_TXQ_INSERT_TAIL(_tq, _elm, _field) do { \ - STAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \ + TAILQ_INSERT_TAIL(&(_tq)->axq_q, (_elm), _field); \ (_tq)->axq_depth++; \ } while (0) -#define ATH_TXQ_REMOVE_HEAD(_tq, _field) do { \ - STAILQ_REMOVE_HEAD(&(_tq)->axq_q, _field); \ +#define ATH_TXQ_REMOVE(_tq, _elm, _field) do { \ + TAILQ_REMOVE(&(_tq)->axq_q, _elm, _field); \ (_tq)->axq_depth--; \ } while (0) /* NB: this does not do the "head empty check" that STAILQ_LAST does */ -#define ATH_TXQ_LAST(_tq) \ - ((struct ath_buf *)(void *) \ - ((char *)((_tq)->axq_q.stqh_last) - __offsetof(struct ath_buf, bf_list))) +#define ATH_TXQ_LAST(_tq, _field) TAILQ_LAST(&(_tq)->axq_q, _field) struct ath_vap { struct ieee80211vap av_vap; /* base class */