Index: sys/dev/ath/if_ath_tx_edma.c =================================================================== --- sys/dev/ath/if_ath_tx_edma.c (revision 248717) +++ sys/dev/ath/if_ath_tx_edma.c (working copy) @@ -136,19 +136,65 @@ static void ath_edma_tx_processq(struct ath_softc *sc, int dosched); +/* + * Push some frames into the TX FIFO if we have space. + */ static void ath_edma_tx_fifo_fill(struct ath_softc *sc, struct ath_txq *txq) { - struct ath_buf *bf; + struct ath_buf *bf, *bf_last; int i = 0; ATH_TXQ_LOCK_ASSERT(txq); - DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: called\n", __func__); + DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: called\n", + __func__, + txq->axq_qnum); TAILQ_FOREACH(bf, &txq->axq_q, bf_list) { if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) break; + + /* + * We have space in the FIFO - so let's push a frame + * into it. + */ + + /* + * Remove it from the normal list + */ + ATH_TXQ_REMOVE(txq, bf, bf_list); + + /* + * XXX for now, we only dequeue a frame at a time, so + * that's only one buffer. Later on when we just + * push this staging _list_ into the queue, we'll + * set bf_last to the end pointer in the list. + */ + bf_last = bf; + DPRINTF(sc, ATH_DEBUG_TX_PROC, + "%s: Q%d: depth=%d; pushing %p->%p\n", + __func__, + txq->axq_qnum, + txq->axq_fifo_depth, + bf, + bf_last); + + /* + * Append it to the FIFO staging list + */ + ATH_TXQ_INSERT_TAIL(&txq->fifo, bf, bf_list); + + /* + * Set fifo start / fifo end flags appropriately + * + */ + bf->bf_flags |= ATH_BUF_FIFOPTR; + bf_last->bf_flags |= ATH_BUF_FIFOEND; + + /* + * Push _into_ the FIFO. + */ ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr); #ifdef ATH_DEBUG if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) @@ -175,14 +221,109 @@ static void ath_edma_dma_restart(struct ath_softc *sc, struct ath_txq *txq) { + struct ath_buf *bf; + int i = 0; + int fifostart = 1; + int old_fifo_depth; - DPRINTF(sc, ATH_DEBUG_RESET, "%s: called: txq=%p, qnum=%d\n", + DPRINTF(sc, ATH_DEBUG_RESET, "%s: Q%d: called\n", __func__, - txq, txq->axq_qnum); ATH_TXQ_LOCK_ASSERT(txq); - ath_edma_tx_fifo_fill(sc, txq); + + /* + * Let's log if the tracked FIFO depth doesn't match + * what we actually push in. + */ + old_fifo_depth = txq->axq_fifo_depth; + txq->axq_fifo_depth = 0; + + /* + * Walk the FIFO staging list, looking for "head" entries. + * Since we may have a partially completed list of frames, + * we push the first frame we see into the FIFO and re-mark + * it as the head entry. We then skip entries until we see + * FIFO end, at which point we get ready to push another + * entry into the FIFO. + */ + TAILQ_FOREACH(bf, &txq->fifo.axq_q, bf_list) { + /* + * If we're looking for FIFOEND and we haven't found + * it, skip. + * + * If we're looking for FIFOEND and we've found it, + * reset for another descriptor. + */ +#ifdef ATH_DEBUG + if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) + ath_printtxbuf(sc, bf, txq->axq_qnum, i, 0); +#endif/* ATH_DEBUG */ +#ifdef ATH_DEBUG_ALQ + if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) + ath_tx_alq_post(sc, bf); +#endif /* ATH_DEBUG_ALQ */ + + if (fifostart == 0) { + if (bf->bf_flags & ATH_BUF_FIFOEND) + fifostart = 1; + continue; + } + + /* Make sure we're not overflowing the FIFO! */ + if (txq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) { + device_printf(sc->sc_dev, + "%s: Q%d: more frames in the queue; FIFO depth=%d?!\n", + __func__, + txq->axq_qnum, + txq->axq_fifo_depth); + } + +#if 0 + DPRINTF(sc, ATH_DEBUG_RESET, + "%s: Q%d: depth=%d: pushing bf=%p; start=%d, end=%d\n", + __func__, + txq->axq_qnum, + txq->axq_fifo_depth, + bf, + !! (bf->bf_flags & ATH_BUF_FIFOPTR), + !! (bf->bf_flags & ATH_BUF_FIFOEND)); +#endif + + /* + * Set this to be the first buffer in the FIFO + * list - even if it's also the last buffer in + * a FIFO list! + */ + bf->bf_flags |= ATH_BUF_FIFOPTR; + + /* Push it into the FIFO and bump the FIFO count */ + ath_hal_puttxbuf(sc->sc_ah, txq->axq_qnum, bf->bf_daddr); + txq->axq_fifo_depth++; + + /* + * If this isn't the last entry either, let's + * clear fifostart so we continue looking for + * said last entry. + */ + if (! (bf->bf_flags & ATH_BUF_FIFOEND)) + fifostart = 0; + i++; + } + + /* Only bother starting the queue if there's something in it */ + if (i > 0) + ath_hal_txstart(sc->sc_ah, txq->axq_qnum); + + /* And now, let's check! */ + if (txq->axq_fifo_depth != old_fifo_depth) { + device_printf(sc->sc_dev, + "%s: Q%d: FIFO depth should be %d, is %d\n", + __func__, + txq->axq_qnum, + old_fifo_depth, + txq->axq_fifo_depth); + } } /* @@ -201,7 +342,6 @@ ath_edma_xmit_handoff_hw(struct ath_softc *sc, struct ath_txq *txq, struct ath_buf *bf) { - struct ath_hal *ah = sc->sc_ah; ATH_TXQ_LOCK(txq); @@ -220,20 +360,18 @@ /* Push and update frame stats */ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list); - /* Only schedule to the FIFO if there's space */ - if (txq->axq_fifo_depth < HAL_TXFIFO_DEPTH) { -#ifdef ATH_DEBUG - if (sc->sc_debug & ATH_DEBUG_XMIT_DESC) - ath_printtxbuf(sc, bf, txq->axq_qnum, 0, 0); -#endif /* ATH_DEBUG */ -#ifdef ATH_DEBUG_ALQ - if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) - ath_tx_alq_post(sc, bf); -#endif /* ATH_DEBUG_ALQ */ - ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); - txq->axq_fifo_depth++; - ath_hal_txstart(ah, txq->axq_qnum); - } + /* For now, set the link pointer in the last descriptor + * to be NULL. + * + * Later on, when it comes time to handling multiple descriptors + * in one FIFO push, we can link descriptors together this way. + */ + + /* + * Finally, call the FIFO schedule routine to schedule some + * frames to the FIFO. + */ + ath_edma_tx_fifo_fill(sc, txq); ATH_TXQ_UNLOCK(txq); } @@ -274,7 +412,6 @@ bf_last->bf_lastds, bf->bf_daddr); } - #ifdef ATH_DEBUG_ALQ if (if_ath_alq_checkdebug(&sc->sc_alq, ATH_ALQ_EDMA_TXDESC)) ath_tx_alq_post(sc, bf); @@ -434,8 +571,10 @@ { struct ath_softc *sc = (struct ath_softc *) arg; +#if 0 DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: called, npending=%d\n", __func__, npending); +#endif ath_edma_tx_processq(sc, 1); } @@ -469,15 +608,16 @@ status = ath_hal_txprocdesc(ah, NULL, (void *) &ts); ATH_TXSTATUS_UNLOCK(sc); + if (status == HAL_EINPROGRESS) + break; + #ifdef ATH_DEBUG if (sc->sc_debug & ATH_DEBUG_TX_PROC) + if (ts.ts_queue_id != sc->sc_bhalq) ath_printtxstatbuf(sc, NULL, txstatus, ts.ts_queue_id, idx, (status == HAL_OK)); #endif - if (status == HAL_EINPROGRESS) - break; - /* * If there is an error with this descriptor, continue * processing. @@ -519,11 +659,25 @@ txq = &sc->sc_txq[ts.ts_queue_id]; ATH_TXQ_LOCK(txq); - bf = TAILQ_FIRST(&txq->axq_q); + bf = ATH_TXQ_FIRST(&txq->fifo); - DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: qcuid=%d, bf=%p\n", + /* + * Work around the situation where I'm seeing notifications + * for Q1 when no frames are available. That needs to be + * debugged but not by crashing _here_. + */ + if (bf == NULL) { + device_printf(sc->sc_dev, "%s: Q%d: empty?\n", + __func__, + ts.ts_queue_id); + continue; + } + + DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d, bf=%p, start=%d, end=%d\n", __func__, - ts.ts_queue_id, bf); + ts.ts_queue_id, bf, + !! (bf->bf_flags & ATH_BUF_FIFOPTR), + !! (bf->bf_flags & ATH_BUF_FIFOEND)); /* XXX TODO: actually output debugging info about this */ @@ -541,10 +695,22 @@ #endif /* This removes the buffer and decrements the queue depth */ - ATH_TXQ_REMOVE(txq, bf, bf_list); + ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list); if (bf->bf_state.bfs_aggr) txq->axq_aggr_depth--; - txq->axq_fifo_depth --; + + /* + * If this was the end of a FIFO set, decrement FIFO depth + */ + if (bf->bf_flags & ATH_BUF_FIFOEND) + txq->axq_fifo_depth--; + + DPRINTF(sc, ATH_DEBUG_TX_PROC, "%s: Q%d: FIFO depth is now %d (%d)\n", + __func__, + txq->axq_qnum, + txq->axq_fifo_depth, + txq->fifo.axq_depth); + /* XXX assert FIFO depth >= 0 */ ATH_TXQ_UNLOCK(txq); @@ -617,21 +783,10 @@ /* * Now that there's space in the FIFO, let's push some * more frames into it. - * - * Unfortunately for now, the txq has FIFO and non-FIFO - * frames in the same linked list, so there's no way - * to quickly/easily populate frames without walking - * the queue and skipping 'axq_fifo_depth' frames. - * - * So for now, let's only repopulate the FIFO once it - * is empty. It's sucky for performance but it's enough - * to begin validating that things are somewhat - * working. */ ATH_TXQ_LOCK(txq); - if (dosched && txq->axq_fifo_depth == 0) { + if (dosched) ath_edma_tx_fifo_fill(sc, txq); - } ATH_TXQ_UNLOCK(txq); } Index: sys/dev/ath/if_ath_beacon.c =================================================================== --- sys/dev/ath/if_ath_beacon.c (revision 248717) +++ sys/dev/ath/if_ath_beacon.c (working copy) @@ -474,6 +474,10 @@ vap = sc->sc_bslot[slot]; if (vap != NULL && vap->iv_state >= IEEE80211_S_RUN) { bf = ath_beacon_generate(sc, vap); + /* + * XXX TODO: this should use settxdesclinkptr() + * otherwise it won't work for EDMA chipsets! + */ if (bf != NULL) { /* XXX should do this using the ds */ *bflink = bf->bf_daddr; @@ -482,6 +486,10 @@ } } } + /* + * XXX TODO: this should use settxdesclinkptr() + * otherwise it won't work for EDMA chipsets! + */ *bflink = 0; /* terminate list */ } @@ -540,18 +548,100 @@ } } -/* - * Start CABQ transmission - this assumes that all frames are prepped - * and ready in the CABQ. - * - * XXX TODO: methodize this; for the EDMA case it should only push - * into the hardware if the FIFO isn't full _AND_ then it should - * tag the final buffer in the queue as ATH_BUF_FIFOEND so the FIFO - * depth is correctly accounted for. - */ -void -ath_beacon_cabq_start(struct ath_softc *sc) +static void +ath_beacon_cabq_start_edma(struct ath_softc *sc) { + struct ath_buf *bf, *bf_last; + struct ath_txq *cabq = sc->sc_cabq; +#if 0 + struct ath_buf *bfi; + int i = 0; +#endif + + ATH_TXQ_LOCK_ASSERT(cabq); + + if (TAILQ_EMPTY(&cabq->axq_q)) + return; + bf = TAILQ_FIRST(&cabq->axq_q); + bf_last = TAILQ_LAST(&cabq->axq_q, axq_q_s); + + /* + * This is a dirty, dirty hack to push the contents of + * the cabq staging queue into the FIFO. + * + * This ideally should live in the EDMA code file + * and only push things into the CABQ if there's a FIFO + * slot. + * + * We can't treat this like a normal TX queue because + * in the case of multi-VAP traffic, we may have to flush + * the CABQ each new (staggered) beacon that goes out. + * But for non-staggered beacons, we could in theory + * handle multicast traffic for all VAPs in one FIFO + * push. Just keep all of this in mind if you're wondering + * how to correctly/better handle multi-VAP CABQ traffic + * with EDMA. + */ + + /* + * Is the CABQ FIFO free? If not, complain loudly and + * don't queue anything. Maybe we'll flush the CABQ + * traffic, maybe we won't. But that'll happen next + * beacon interval. + */ + if (cabq->axq_fifo_depth >= HAL_TXFIFO_DEPTH) { + device_printf(sc->sc_dev, + "%s: Q%d: CAB FIFO queue=%d?\n", + __func__, + cabq->axq_qnum, + cabq->axq_fifo_depth); + return; + } + + /* + * Ok, so here's the gymnastics reqiured to make this + * all sensible. + */ + + /* + * Tag the first/last buffer appropriately. + */ + bf->bf_flags |= ATH_BUF_FIFOPTR; + bf_last->bf_flags |= ATH_BUF_FIFOEND; + +#if 0 + i = 0; + TAILQ_FOREACH(bfi, &cabq->axq_q, bf_list) { + ath_printtxbuf(sc, bf, cabq->axq_qnum, i, 0); + i++; + } +#endif + + /* + * We now need to push this set of frames onto the tail + * of the FIFO queue. We don't adjust the aggregate + * count, only the queue depth counter(s). + * We also need to blank the link pointer now. + */ + TAILQ_CONCAT(&cabq->fifo.axq_q, &cabq->axq_q, bf_list); + cabq->axq_link = NULL; + cabq->fifo.axq_depth += cabq->axq_depth; + cabq->axq_depth = 0; + + /* Bump FIFO queue */ + cabq->axq_fifo_depth++; + + /* Push the first entry into the hardware */ + ath_hal_puttxbuf(sc->sc_ah, cabq->axq_qnum, bf->bf_daddr); + + /* NB: gated by beacon so safe to start here */ + ath_hal_txstart(sc->sc_ah, cabq->axq_qnum); + +} + +static void +ath_beacon_cabq_start_legacy(struct ath_softc *sc) +{ struct ath_buf *bf; struct ath_txq *cabq = sc->sc_cabq; @@ -567,6 +657,26 @@ ath_hal_txstart(sc->sc_ah, cabq->axq_qnum); } +/* + * Start CABQ transmission - this assumes that all frames are prepped + * and ready in the CABQ. + */ +void +ath_beacon_cabq_start(struct ath_softc *sc) +{ + struct ath_txq *cabq = sc->sc_cabq; + + ATH_TXQ_LOCK_ASSERT(cabq); + + if (TAILQ_EMPTY(&cabq->axq_q)) + return; + + if (sc->sc_isedma) + ath_beacon_cabq_start_edma(sc); + else + ath_beacon_cabq_start_legacy(sc); +} + struct ath_buf * ath_beacon_generate(struct ath_softc *sc, struct ieee80211vap *vap) { @@ -637,9 +747,6 @@ /* * Move frames from the s/w mcast q to the h/w cab q. * - * XXX TODO: This should be methodized - the EDMA - * CABQ setup code may look different! - * * XXX TODO: if we chain together multiple VAPs * worth of CABQ traffic, should we keep the * MORE data bit set on the last frame of each Index: sys/dev/ath/if_athvar.h =================================================================== --- sys/dev/ath/if_athvar.h (revision 248717) +++ sys/dev/ath/if_athvar.h (working copy) @@ -291,7 +291,11 @@ #define ATH_BUF_MGMT 0x00000001 /* (tx) desc is a mgmt desc */ #define ATH_BUF_BUSY 0x00000002 /* (tx) desc owned by h/w */ +#define ATH_BUF_FIFOEND 0x00000004 +#define ATH_BUF_FIFOPTR 0x00000008 +#define ATH_BUF_FLAGS_CLONE (ATH_BUF_MGMT) + /* * DMA state for tx/rx descriptors. */ @@ -325,13 +329,30 @@ #define ATH_TXQ_PUTPENDING 0x0001 /* ath_hal_puttxbuf pending */ u_int axq_depth; /* queue depth (stat only) */ u_int axq_aggr_depth; /* how many aggregates are queued */ - u_int axq_fifo_depth; /* depth of FIFO frames */ u_int axq_intrcnt; /* interrupt count */ u_int32_t *axq_link; /* link ptr in last TX desc */ TAILQ_HEAD(axq_q_s, ath_buf) axq_q; /* transmit queue */ struct mtx axq_lock; /* lock on q and link */ /* + * This is the FIFO staging buffer when doing EDMA. + * + * For legacy chips, we just push the head pointer to + * the hardware and we ignore this list. + * + * For EDMA, the staging buffer is treated as normal; + * when it's time to push a list of frames to the hardware + * we move that list here and we stamp buffers with + * flags to identify the beginning/end of that particular + * FIFO entry. + */ + struct { + TAILQ_HEAD(axq_q_f_s, ath_buf) axq_q; + u_int axq_depth; + } fifo; + u_int axq_fifo_depth; /* depth of FIFO frames */ + + /* * XXX the holdingbf field is protected by the TXBUF lock * for now, NOT the TXQ lock. * Index: sys/dev/ath/if_ath_sysctl.c =================================================================== --- sys/dev/ath/if_ath_sysctl.c (revision 248717) +++ sys/dev/ath/if_ath_sysctl.c (working copy) @@ -754,7 +754,7 @@ &sc->sc_txq_mcastq_maxdepth, 0, "Maximum buffer depth for multicast/broadcast frames"); -#if 0 +#if 1 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "cabq_enable", CTLFLAG_RW, &sc->sc_cabq_enable, 0, Index: sys/dev/ath/if_ath_tx.c =================================================================== --- sys/dev/ath/if_ath_tx.c (revision 248717) +++ sys/dev/ath/if_ath_tx.c (working copy) @@ -1816,7 +1816,8 @@ * XXX duplicated in ath_raw_xmit(). */ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { - if (sc->sc_cabq->axq_depth > sc->sc_txq_mcastq_maxdepth) { + if (sc->sc_cabq->axq_depth + sc->sc_cabq->fifo.axq_depth + > sc->sc_txq_mcastq_maxdepth) { sc->sc_stats.ast_tx_mcastq_overflow++; r = ENOBUFS; } @@ -2219,7 +2220,8 @@ * XXX duplicated in ath_tx_start(). */ if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { - if (sc->sc_cabq->axq_depth > sc->sc_txq_mcastq_maxdepth) { + if (sc->sc_cabq->axq_depth + sc->sc_cabq->fifo.axq_depth + > sc->sc_txq_mcastq_maxdepth) { sc->sc_stats.ast_tx_mcastq_overflow++; error = ENOBUFS; } @@ -2845,7 +2847,7 @@ * * Otherwise, schedule the TID. */ - if (txq->axq_depth < sc->sc_hwq_limit) { + if (txq->axq_depth + txq->fifo.axq_depth < sc->sc_hwq_limit) { bf = ATH_TID_FIRST(atid); ATH_TID_REMOVE(atid, bf, bf_list); @@ -2869,7 +2871,7 @@ ath_tx_tid_sched(sc, atid); } - } else if (txq->axq_depth < sc->sc_hwq_limit) { + } else if (txq->axq_depth + txq->fifo.axq_depth < sc->sc_hwq_limit) { /* AMPDU not running, attempt direct dispatch */ DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: xmit_normal\n", __func__); /* See if clrdmask needs to be set */ Index: sys/dev/ath/if_ath.c =================================================================== --- sys/dev/ath/if_ath.c (revision 248717) +++ sys/dev/ath/if_ath.c (working copy) @@ -2474,6 +2474,7 @@ /* XXX TODO: should do this at buffer list initialisation */ /* XXX (then, ensure the buffer has the right flag set) */ + bf->bf_flags = 0; if (btype == ATH_BUFTYPE_MGMT) bf->bf_flags |= ATH_BUF_MGMT; else @@ -2530,7 +2531,7 @@ /* Copy basics */ tbf->bf_next = NULL; tbf->bf_nseg = bf->bf_nseg; - tbf->bf_flags = bf->bf_flags & ~ATH_BUF_BUSY; + tbf->bf_flags = bf->bf_flags & ATH_BUF_FLAGS_CLONE; tbf->bf_status = bf->bf_status; tbf->bf_m = bf->bf_m; /* @@ -3410,6 +3411,7 @@ txq->axq_softc = sc; TAILQ_INIT(&txq->axq_q); TAILQ_INIT(&txq->axq_tidq); + TAILQ_INIT(&txq->fifo.axq_q); ATH_TXQ_LOCK_INIT(sc, txq); } @@ -4283,6 +4285,61 @@ */ } +static struct ath_buf * +ath_tx_draintxq_get_one(struct ath_softc *sc, struct ath_txq *txq) +{ + struct ath_buf *bf; + + ATH_TXQ_LOCK_ASSERT(txq); + + /* + * Drain the FIFO queue first, then if it's + * empty, move to the normal frame queue. + */ + bf = TAILQ_FIRST(&txq->fifo.axq_q); + if (bf != NULL) { + /* + * Is it the last buffer in this set? + * Decrement the FIFO counter. + */ + if (bf->bf_flags & ATH_BUF_FIFOEND) { + if (txq->axq_fifo_depth == 0) { + device_printf(sc->sc_dev, + "%s: Q%d: fifo_depth=0, fifo.axq_depth=%d?\n", + __func__, + txq->axq_qnum, + txq->fifo.axq_depth); + } else + txq->axq_fifo_depth--; + } + ATH_TXQ_REMOVE(&txq->fifo, bf, bf_list); + return (bf); + } + + /* + * Debugging! + */ + if (txq->axq_fifo_depth != 0 || txq->fifo.axq_depth != 0) { + device_printf(sc->sc_dev, + "%s: Q%d: fifo_depth=%d, fifo.axq_depth=%d\n", + __func__, + txq->axq_qnum, + txq->axq_fifo_depth, + txq->fifo.axq_depth); + } + + /* + * Now drain the pending queue. + */ + bf = TAILQ_FIRST(&txq->axq_q); + if (bf == NULL) { + txq->axq_link = NULL; + return (NULL); + } + ATH_TXQ_REMOVE(txq, bf, bf_list); + return (bf); +} + void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq) { @@ -4298,24 +4355,11 @@ */ for (ix = 0;; ix++) { ATH_TXQ_LOCK(txq); - bf = TAILQ_FIRST(&txq->axq_q); + bf = ath_tx_draintxq_get_one(sc, txq); if (bf == NULL) { - txq->axq_link = NULL; - /* - * There's currently no flag that indicates - * a buffer is on the FIFO. So until that - * occurs, just clear the FIFO counter here. - * - * Yes, this means that if something in parallel - * is pushing things onto this TXQ and pushing - * _that_ into the hardware, things will get - * very fruity very quickly. - */ - txq->axq_fifo_depth = 0; ATH_TXQ_UNLOCK(txq); break; } - ATH_TXQ_REMOVE(txq, bf, bf_list); if (bf->bf_state.bfs_aggr) txq->axq_aggr_depth--; #ifdef ATH_DEBUG