summaryrefslogtreecommitdiffstats
path: root/sys/dev/ath/if_ath_tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/ath/if_ath_tx.c')
-rw-r--r--sys/dev/ath/if_ath_tx.c422
1 files changed, 127 insertions, 295 deletions
diff --git a/sys/dev/ath/if_ath_tx.c b/sys/dev/ath/if_ath_tx.c
index 096278e..8bacd92 100644
--- a/sys/dev/ath/if_ath_tx.c
+++ b/sys/dev/ath/if_ath_tx.c
@@ -59,12 +59,10 @@ __FBSDID("$FreeBSD$");
#include <sys/kthread.h>
#include <sys/taskqueue.h>
#include <sys/priv.h>
-#include <sys/ktr.h>
#include <machine/bus.h>
#include <net/if.h>
-#include <net/if_var.h>
#include <net/if_dl.h>
#include <net/if_media.h>
#include <net/if_types.h>
@@ -761,21 +759,37 @@ ath_tx_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
("ath_tx_handoff_hw called for mcast queue"));
/*
- * XXX We should instead just verify that sc_txstart_cnt
- * or ath_txproc_cnt > 0. That would mean that
- * the reset is going to be waiting for us to complete.
+ * XXX racy, should hold the PCU lock when checking this,
+ * and also should ensure that the TX counter is >0!
*/
- if (sc->sc_txproc_cnt == 0 && sc->sc_txstart_cnt == 0) {
- device_printf(sc->sc_dev,
- "%s: TX dispatch without holding txcount/txstart refcnt!\n",
- __func__);
- }
+ KASSERT((sc->sc_inreset_cnt == 0),
+ ("%s: TX during reset?\n", __func__));
+#if 0
/*
- * XXX .. this is going to cause the hardware to get upset;
- * so we really should find some way to drop or queue
- * things.
+ * This causes a LOR. Find out where the PCU lock is being
+ * held whilst the TXQ lock is grabbed - that shouldn't
+ * be occuring.
*/
+ ATH_PCU_LOCK(sc);
+ if (sc->sc_inreset_cnt) {
+ ATH_PCU_UNLOCK(sc);
+ DPRINTF(sc, ATH_DEBUG_RESET,
+ "%s: called with sc_in_reset != 0\n",
+ __func__);
+ DPRINTF(sc, ATH_DEBUG_XMIT,
+ "%s: queued: TXDP[%u] = %p (%p) depth %d\n",
+ __func__, txq->axq_qnum,
+ (caddr_t)bf->bf_daddr, bf->bf_desc,
+ txq->axq_depth);
+ /* XXX axq_link needs to be set and updated! */
+ ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+ if (bf->bf_state.bfs_aggr)
+ txq->axq_aggr_depth++;
+ return;
+ }
+ ATH_PCU_UNLOCK(sc);
+#endif
ATH_TXQ_LOCK(txq);
@@ -1599,7 +1613,6 @@ ath_tx_normal_setup(struct ath_softc *sc, struct ieee80211_node *ni,
error = ath_tx_dmasetup(sc, bf, m0);
if (error != 0)
return error;
- KASSERT((ni != NULL), ("%s: ni=NULL!", __func__));
bf->bf_node = ni; /* NB: held reference */
m0 = bf->bf_m; /* NB: may have changed */
wh = mtod(m0, struct ieee80211_frame *);
@@ -2091,7 +2104,6 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
int do_override;
uint8_t type, subtype;
int queue_to_head;
- struct ath_node *an = ATH_NODE(ni);
ATH_TX_LOCK_ASSERT(sc);
@@ -2151,7 +2163,6 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
return error;
m0 = bf->bf_m; /* NB: may have changed */
wh = mtod(m0, struct ieee80211_frame *);
- KASSERT((ni != NULL), ("%s: ni=NULL!", __func__));
bf->bf_node = ni; /* NB: held reference */
/* Always enable CLRDMASK for raw frames for now.. */
@@ -2170,24 +2181,12 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
rt = sc->sc_currates;
KASSERT(rt != NULL, ("no rate table, mode %u", sc->sc_curmode));
-
- /* Fetch first rate information */
rix = ath_tx_findrix(sc, params->ibp_rate0);
- try0 = params->ibp_try0;
-
- /*
- * Override EAPOL rate as appropriate.
- */
- if (m0->m_flags & M_EAPOL) {
- /* XXX? maybe always use long preamble? */
- rix = an->an_mgmtrix;
- try0 = ATH_TXMAXTRY; /* XXX?too many? */
- }
-
txrate = rt->info[rix].rateCode;
if (params->ibp_flags & IEEE80211_BPF_SHORTPRE)
txrate |= rt->info[rix].shortPreamble;
sc->sc_txrix = rix;
+ try0 = params->ibp_try0;
ismrr = (params->ibp_try1 != 0);
txantenna = params->ibp_pri >> 2;
if (txantenna == 0) /* XXX? */
@@ -2260,7 +2259,8 @@ ath_tx_raw_start(struct ath_softc *sc, struct ieee80211_node *ni,
/* Blank the legacy rate array */
bzero(&bf->bf_state.bfs_rc, sizeof(bf->bf_state.bfs_rc));
- bf->bf_state.bfs_rc[0].rix = rix;
+ bf->bf_state.bfs_rc[0].rix =
+ ath_tx_findrix(sc, params->ibp_rate0);
bf->bf_state.bfs_rc[0].tries = try0;
bf->bf_state.bfs_rc[0].ratecode = txrate;
@@ -2352,16 +2352,11 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
"%s: sc_inreset_cnt > 0; bailing\n", __func__);
error = EIO;
ATH_PCU_UNLOCK(sc);
- goto badbad;
+ goto bad0;
}
sc->sc_txstart_cnt++;
ATH_PCU_UNLOCK(sc);
- /* Wake the hardware up already */
- ATH_LOCK(sc);
- ath_power_set_power_state(sc, HAL_PM_AWAKE);
- ATH_UNLOCK(sc);
-
ATH_TX_LOCK(sc);
if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 || sc->sc_invalid) {
@@ -2424,7 +2419,7 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
}
}
sc->sc_wd_timer = 5;
- if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+ ifp->if_opackets++;
sc->sc_stats.ast_tx_raw++;
/*
@@ -2440,14 +2435,7 @@ ath_raw_xmit(struct ieee80211_node *ni, struct mbuf *m,
sc->sc_txstart_cnt--;
ATH_PCU_UNLOCK(sc);
-
- /* Put the hardware back to sleep if required */
- ATH_LOCK(sc);
- ath_power_restore_power_state(sc);
- ATH_UNLOCK(sc);
-
return 0;
-
bad2:
ATH_KTR(sc, ATH_KTR_TX, 3, "ath_raw_xmit: bad2: m=%p, params=%p, "
"bf=%p",
@@ -2457,23 +2445,17 @@ bad2:
ATH_TXBUF_LOCK(sc);
ath_returnbuf_head(sc, bf);
ATH_TXBUF_UNLOCK(sc);
-
bad:
+
ATH_TX_UNLOCK(sc);
ATH_PCU_LOCK(sc);
sc->sc_txstart_cnt--;
ATH_PCU_UNLOCK(sc);
-
- /* Put the hardware back to sleep if required */
- ATH_LOCK(sc);
- ath_power_restore_power_state(sc);
- ATH_UNLOCK(sc);
-
-badbad:
+bad0:
ATH_KTR(sc, ATH_KTR_TX, 2, "ath_raw_xmit: bad0: m=%p, params=%p",
m, params);
- if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
+ ifp->if_oerrors++;
sc->sc_stats.ast_tx_raw_fail++;
ieee80211_free_node(ni);
@@ -2766,8 +2748,8 @@ ath_tx_update_baw(struct ath_softc *sc, struct ath_node *an,
INCR(tid->baw_head, ATH_TID_MAX_BUFS);
}
DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: tid=%d: baw is now %d:%d, baw head=%d\n",
- __func__, tid->tid, tap->txa_start, tap->txa_wnd, tid->baw_head);
+ "%s: baw is now %d:%d, baw head=%d\n",
+ __func__, tap->txa_start, tap->txa_wnd, tid->baw_head);
}
static void
@@ -3260,11 +3242,8 @@ ath_tx_tid_pause(struct ath_softc *sc, struct ath_tid *tid)
ATH_TX_LOCK_ASSERT(sc);
tid->paused++;
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: [%6D]: tid=%d, paused = %d\n",
- __func__,
- tid->an->an_node.ni_macaddr, ":",
- tid->tid,
- tid->paused);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: paused = %d\n",
+ __func__, tid->paused);
}
/*
@@ -3281,21 +3260,15 @@ ath_tx_tid_resume(struct ath_softc *sc, struct ath_tid *tid)
* until it's actually resolved.
*/
if (tid->paused == 0) {
- device_printf(sc->sc_dev,
- "%s: [%6D]: tid=%d, paused=0?\n",
- __func__,
- tid->an->an_node.ni_macaddr, ":",
- tid->tid);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
+ "%s: %6D: paused=0?\n", __func__,
+ tid->an->an_node.ni_macaddr, ":");
} else {
tid->paused--;
}
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
- "%s: [%6D]: tid=%d, unpaused = %d\n",
- __func__,
- tid->an->an_node.ni_macaddr, ":",
- tid->tid,
- tid->paused);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: unpaused = %d\n",
+ __func__, tid->paused);
if (tid->paused)
return;
@@ -3361,8 +3334,8 @@ ath_tx_tid_filt_comp_buf(struct ath_softc *sc, struct ath_tid *tid,
ATH_TX_LOCK_ASSERT(sc);
if (! tid->isfiltered) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: tid=%d; filter transition\n",
- __func__, tid->tid);
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: filter transition\n",
+ __func__);
tid->isfiltered = 1;
ath_tx_tid_pause(sc, tid);
}
@@ -3382,20 +3355,15 @@ static void
ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
{
struct ath_buf *bf;
- int do_resume = 0;
ATH_TX_LOCK_ASSERT(sc);
if (tid->hwq_depth != 0)
return;
- DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: tid=%d, hwq=0, transition back\n",
- __func__, tid->tid);
- if (tid->isfiltered == 1) {
- tid->isfiltered = 0;
- do_resume = 1;
- }
-
+ DPRINTF(sc, ATH_DEBUG_SW_TX_FILT, "%s: hwq=0, transition back\n",
+ __func__);
+ tid->isfiltered = 0;
/* XXX ath_tx_tid_resume() also calls ath_tx_set_clrdmask()! */
ath_tx_set_clrdmask(sc, tid->an);
@@ -3405,21 +3373,16 @@ ath_tx_tid_filt_comp_complete(struct ath_softc *sc, struct ath_tid *tid)
ATH_TID_INSERT_HEAD(tid, bf, bf_list);
}
- /* And only resume if we had paused before */
- if (do_resume)
- ath_tx_tid_resume(sc, tid);
+ ath_tx_tid_resume(sc, tid);
}
/*
* Called when a single (aggregate or otherwise) frame is completed.
*
- * Returns 0 if the buffer could be added to the filtered list
- * (cloned or otherwise), 1 if the buffer couldn't be added to the
+ * Returns 1 if the buffer could be added to the filtered list
+ * (cloned or otherwise), 0 if the buffer couldn't be added to the
* filtered list (failed clone; expired retry) and the caller should
* free it and handle it like a failure (eg by sending a BAR.)
- *
- * since the buffer may be cloned, bf must be not touched after this
- * if the return value is 0.
*/
static int
ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
@@ -3439,9 +3402,8 @@ ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
"%s: bf=%p, seqno=%d, exceeded retries\n",
__func__,
bf,
- SEQNO(bf->bf_state.bfs_seqno));
- retval = 1; /* error */
- goto finish;
+ bf->bf_state.bfs_seqno);
+ return (0);
}
/*
@@ -3461,12 +3423,11 @@ ath_tx_tid_filt_comp_single(struct ath_softc *sc, struct ath_tid *tid,
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
"%s: busy buffer couldn't be cloned (%p)!\n",
__func__, bf);
- retval = 1; /* error */
+ retval = 1;
} else {
ath_tx_tid_filt_comp_buf(sc, tid, nbf);
- retval = 0; /* ok */
+ retval = 0;
}
-finish:
ath_tx_tid_filt_comp_complete(sc, tid);
return (retval);
@@ -3491,11 +3452,10 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
if (bf->bf_state.bfs_retries > SWMAX_RETRIES) {
sc->sc_stats.ast_tx_swretrymax++;
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
- "%s: tid=%d, bf=%p, seqno=%d, exceeded retries\n",
+ "%s: bf=%p, seqno=%d, exceeded retries\n",
__func__,
- tid->tid,
bf,
- SEQNO(bf->bf_state.bfs_seqno));
+ bf->bf_state.bfs_seqno);
TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
goto next;
}
@@ -3503,8 +3463,8 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
if (bf->bf_flags & ATH_BUF_BUSY) {
nbf = ath_tx_retry_clone(sc, tid->an, tid, bf);
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
- "%s: tid=%d, busy buffer cloned: %p -> %p, seqno=%d\n",
- __func__, tid->tid, bf, nbf, SEQNO(bf->bf_state.bfs_seqno));
+ "%s: busy buffer cloned: %p -> %p",
+ __func__, bf, nbf);
} else {
nbf = bf;
}
@@ -3515,8 +3475,8 @@ ath_tx_tid_filt_comp_aggr(struct ath_softc *sc, struct ath_tid *tid,
*/
if (nbf == NULL) {
DPRINTF(sc, ATH_DEBUG_SW_TX_FILT,
- "%s: tid=%d, buffer couldn't be cloned! (%p) seqno=%d\n",
- __func__, tid->tid, bf, SEQNO(bf->bf_state.bfs_seqno));
+ "%s: buffer couldn't be cloned! (%p)\n",
+ __func__, bf);
TAILQ_INSERT_TAIL(bf_q, bf, bf_list);
} else {
ath_tx_tid_filt_comp_buf(sc, tid, nbf);
@@ -3757,7 +3717,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
txq = sc->sc_ac2q[tid->ac];
tap = ath_tx_get_tx_tid(an, tid->tid);
- DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: %s: %6D: bf=%p: addbaw=%d, dobaw=%d, "
"seqno=%d, retry=%d\n",
__func__,
@@ -3769,7 +3729,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
bf->bf_state.bfs_dobaw,
SEQNO(bf->bf_state.bfs_seqno),
bf->bf_state.bfs_retries);
- DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: %s: %6D: bf=%p: txq[%d] axq_depth=%d, axq_aggr_depth=%d\n",
__func__,
pfx,
@@ -3779,7 +3739,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
txq->axq_qnum,
txq->axq_depth,
txq->axq_aggr_depth);
- DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: %s: %6D: bf=%p: tid txq_depth=%d hwq_depth=%d, bar_wait=%d, "
"isfiltered=%d\n",
__func__,
@@ -3791,7 +3751,7 @@ ath_tx_tid_drain_print(struct ath_softc *sc, struct ath_node *an,
tid->hwq_depth,
tid->bar_wait,
tid->isfiltered);
- DPRINTF(sc, ATH_DEBUG_SW_TX | ATH_DEBUG_RESET,
+ DPRINTF(sc, ATH_DEBUG_SW_TX,
"%s: %s: %6D: tid %d: "
"sched=%d, paused=%d, "
"incomp=%d, baw_head=%d, "
@@ -3851,7 +3811,7 @@ ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an,
if (t == 0) {
ath_tx_tid_drain_print(sc, an, "norm", tid, bf);
-// t = 1;
+ t = 1;
}
ATH_TID_REMOVE(tid, bf, bf_list);
@@ -3867,7 +3827,7 @@ ath_tx_tid_drain(struct ath_softc *sc, struct ath_node *an,
if (t == 0) {
ath_tx_tid_drain_print(sc, an, "filt", tid, bf);
-// t = 1;
+ t = 1;
}
ATH_TID_FILT_REMOVE(tid, bf, bf_list);
@@ -4124,19 +4084,6 @@ ath_tx_normal_comp(struct ath_softc *sc, struct ath_buf *bf, int fail)
DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: hwq_depth < 0: %d\n",
__func__, atid->hwq_depth);
- /* If the TID is being cleaned up, track things */
- /* XXX refactor! */
- if (atid->cleanup_inprogress) {
- atid->incomp--;
- if (atid->incomp == 0) {
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
- "%s: TID %d: cleaned up! resume!\n",
- __func__, tid);
- atid->cleanup_inprogress = 0;
- ath_tx_tid_resume(sc, atid);
- }
- }
-
/*
* If the queue is filtered, potentially mark it as complete
* and reschedule it as needed.
@@ -4184,16 +4131,6 @@ ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf)
ATH_TX_LOCK(sc);
atid->incomp--;
-
- /* XXX refactor! */
- if (bf->bf_state.bfs_dobaw) {
- ath_tx_update_baw(sc, an, atid, bf);
- if (!bf->bf_state.bfs_addedbaw)
- DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: wasn't added: seqno %d\n",
- __func__, SEQNO(bf->bf_state.bfs_seqno));
- }
-
if (atid->incomp == 0) {
DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
"%s: TID %d: cleaned up! resume!\n",
@@ -4206,72 +4143,14 @@ ath_tx_comp_cleanup_unaggr(struct ath_softc *sc, struct ath_buf *bf)
ath_tx_default_comp(sc, bf, 0);
}
-
-/*
- * This as it currently stands is a bit dumb. Ideally we'd just
- * fail the frame the normal way and have it permanently fail
- * via the normal aggregate completion path.
- */
-static void
-ath_tx_tid_cleanup_frame(struct ath_softc *sc, struct ath_node *an,
- int tid, struct ath_buf *bf_head, ath_bufhead *bf_cq)
-{
- struct ath_tid *atid = &an->an_tid[tid];
- struct ath_buf *bf, *bf_next;
-
- ATH_TX_LOCK_ASSERT(sc);
-
- /*
- * Remove this frame from the queue.
- */
- ATH_TID_REMOVE(atid, bf_head, bf_list);
-
- /*
- * Loop over all the frames in the aggregate.
- */
- bf = bf_head;
- while (bf != NULL) {
- bf_next = bf->bf_next; /* next aggregate frame, or NULL */
-
- /*
- * If it's been added to the BAW we need to kick
- * it out of the BAW before we continue.
- *
- * XXX if it's an aggregate, assert that it's in the
- * BAW - we shouldn't have it be in an aggregate
- * otherwise!
- */
- if (bf->bf_state.bfs_addedbaw) {
- ath_tx_update_baw(sc, an, atid, bf);
- bf->bf_state.bfs_dobaw = 0;
- }
-
- /*
- * Give it the default completion handler.
- */
- bf->bf_comp = ath_tx_normal_comp;
- bf->bf_next = NULL;
-
- /*
- * Add it to the list to free.
- */
- TAILQ_INSERT_TAIL(bf_cq, bf, bf_list);
-
- /*
- * Now advance to the next frame in the aggregate.
- */
- bf = bf_next;
- }
-}
-
/*
* Performs transmit side cleanup when TID changes from aggregated to
- * unaggregated and during reassociation.
+ * unaggregated.
*
- * For now, this just tosses everything from the TID software queue
- * whether or not it has been retried and marks the TID as
- * pending completion if there's anything for this TID queued to
- * the hardware.
+ * - Discard all retry frames from the s/w queue.
+ * - Fix the tx completion function for all buffers in s/w queue.
+ * - Count the number of unacked frames, and let transmit completion
+ * handle it later.
*
* The caller is responsible for pausing the TID and unpausing the
* TID if no cleanup was required. Otherwise the cleanup path will
@@ -4282,19 +4161,18 @@ ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid,
ath_bufhead *bf_cq)
{
struct ath_tid *atid = &an->an_tid[tid];
+ struct ieee80211_tx_ampdu *tap;
struct ath_buf *bf, *bf_next;
ATH_TX_LOCK_ASSERT(sc);
DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
- "%s: TID %d: called; inprogress=%d\n", __func__, tid,
- atid->cleanup_inprogress);
+ "%s: TID %d: called\n", __func__, tid);
/*
* Move the filtered frames to the TX queue, before
* we run off and discard/process things.
*/
-
/* XXX this is really quite inefficient */
while ((bf = ATH_TID_FILT_LAST(atid, ath_bufhead_s)) != NULL) {
ATH_TID_FILT_REMOVE(atid, bf, bf_list);
@@ -4309,35 +4187,47 @@ ath_tx_tid_cleanup(struct ath_softc *sc, struct ath_node *an, int tid,
*/
bf = ATH_TID_FIRST(atid);
while (bf) {
- /*
- * Grab the next frame in the list, we may
- * be fiddling with the list.
- */
- bf_next = TAILQ_NEXT(bf, bf_list);
-
- /*
- * Free the frame and all subframes.
- */
- ath_tx_tid_cleanup_frame(sc, an, tid, bf, bf_cq);
-
- /*
- * Next frame!
- */
- bf = bf_next;
+ if (bf->bf_state.bfs_isretried) {
+ bf_next = TAILQ_NEXT(bf, bf_list);
+ ATH_TID_REMOVE(atid, bf, bf_list);
+ if (bf->bf_state.bfs_dobaw) {
+ ath_tx_update_baw(sc, an, atid, bf);
+ if (!bf->bf_state.bfs_addedbaw)
+ DPRINTF(sc, ATH_DEBUG_SW_TX_BAW,
+ "%s: wasn't added: seqno %d\n",
+ __func__,
+ SEQNO(bf->bf_state.bfs_seqno));
+ }
+ bf->bf_state.bfs_dobaw = 0;
+ /*
+ * Call the default completion handler with "fail" just
+ * so upper levels are suitably notified about this.
+ */
+ TAILQ_INSERT_TAIL(bf_cq, bf, bf_list);
+ bf = bf_next;
+ continue;
+ }
+ /* Give these the default completion handler */
+ bf->bf_comp = ath_tx_normal_comp;
+ bf = TAILQ_NEXT(bf, bf_list);
}
/*
- * If there's anything in the hardware queue we wait
- * for the TID HWQ to empty.
+ * Calculate what hardware-queued frames exist based
+ * on the current BAW size. Ie, what frames have been
+ * added to the TX hardware queue for this TID but
+ * not yet ACKed.
*/
- if (atid->hwq_depth > 0) {
- /*
- * XXX how about we kill atid->incomp, and instead
- * replace it with a macro that checks that atid->hwq_depth
- * is 0?
- */
- atid->incomp = atid->hwq_depth;
- atid->cleanup_inprogress = 1;
+ tap = ath_tx_get_tx_tid(an, tid);
+ /* Need the lock - fiddling with BAW */
+ while (atid->baw_head != atid->baw_tail) {
+ if (atid->tx_buf[atid->baw_head]) {
+ atid->incomp++;
+ atid->cleanup_inprogress = 1;
+ atid->tx_buf[atid->baw_head] = NULL;
+ }
+ INCR(atid->baw_head, ATH_TID_MAX_BUFS);
+ INCR(tap->txa_start, IEEE80211_SEQ_RANGE);
}
if (atid->cleanup_inprogress)
@@ -4670,19 +4560,9 @@ ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first)
ATH_TX_LOCK(sc);
/* update incomp */
- atid->incomp--;
-
- /* Update the BAW */
bf = bf_first;
while (bf) {
- /* XXX refactor! */
- if (bf->bf_state.bfs_dobaw) {
- ath_tx_update_baw(sc, an, atid, bf);
- if (!bf->bf_state.bfs_addedbaw)
- DPRINTF(sc, ATH_DEBUG_SW_TX,
- "%s: wasn't added: seqno %d\n",
- __func__, SEQNO(bf->bf_state.bfs_seqno));
- }
+ atid->incomp--;
bf = bf->bf_next;
}
@@ -4705,11 +4585,10 @@ ath_tx_comp_cleanup_aggr(struct ath_softc *sc, struct ath_buf *bf_first)
ATH_TX_UNLOCK(sc);
- /* Handle frame completion as individual frames */
+ /* Handle frame completion */
bf = bf_first;
while (bf) {
bf_next = bf->bf_next;
- bf->bf_next = NULL;
ath_tx_default_comp(sc, bf, 1);
bf = bf_next;
}
@@ -5151,10 +5030,6 @@ ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail)
"%s: isfiltered=1, fail=%d\n",
__func__, fail);
freeframe = ath_tx_tid_filt_comp_single(sc, atid, bf);
- /*
- * If freeframe=0 then bf is no longer ours; don't
- * touch it.
- */
if (freeframe) {
/* Remove from BAW */
if (bf->bf_state.bfs_addedbaw)
@@ -5190,6 +5065,7 @@ ath_tx_aggr_comp_unaggr(struct ath_softc *sc, struct ath_buf *bf, int fail)
if (freeframe)
ath_tx_default_comp(sc, bf, fail);
+
return;
}
/*
@@ -5619,7 +5495,7 @@ ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq)
* a frame; be careful.
*/
if (! ath_tx_tid_can_tx_or_sched(sc, tid)) {
- goto loop_done;
+ continue;
}
if (ath_tx_ampdu_running(sc, tid->an, tid->tid))
ath_tx_tid_hw_queue_aggr(sc, tid->an, tid);
@@ -5642,7 +5518,7 @@ ath_txq_sched(struct ath_softc *sc, struct ath_txq *txq)
if (txq->axq_depth >= sc->sc_hwq_limit_nonaggr) {
break;
}
-loop_done:
+
/*
* If this was the last entry on the original list, stop.
* Otherwise nodes that have been rescheduled onto the end
@@ -5895,26 +5771,12 @@ ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
*/
TAILQ_INIT(&bf_cq);
ATH_TX_LOCK(sc);
-
+ ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
/*
- * In case there's a followup call to this, only call it
- * if we don't have a cleanup in progress.
- *
- * Since we've paused the queue above, we need to make
- * sure we unpause if there's already a cleanup in
- * progress - it means something else is also doing
- * this stuff, so we don't need to also keep it paused.
+ * Unpause the TID if no cleanup is required.
*/
- if (atid->cleanup_inprogress) {
+ if (! atid->cleanup_inprogress)
ath_tx_tid_resume(sc, atid);
- } else {
- ath_tx_tid_cleanup(sc, an, tid, &bf_cq);
- /*
- * Unpause the TID if no cleanup is required.
- */
- if (! atid->cleanup_inprogress)
- ath_tx_tid_resume(sc, atid);
- }
ATH_TX_UNLOCK(sc);
/* Handle completing frames and fail them */
@@ -5948,25 +5810,19 @@ ath_tx_node_reassoc(struct ath_softc *sc, struct ath_node *an)
tid = &an->an_tid[i];
if (tid->hwq_depth == 0)
continue;
+ ath_tx_tid_pause(sc, tid);
DPRINTF(sc, ATH_DEBUG_NODE,
"%s: %6D: TID %d: cleaning up TID\n",
__func__,
an->an_node.ni_macaddr,
":",
i);
+ ath_tx_tid_cleanup(sc, an, i, &bf_cq);
/*
- * In case there's a followup call to this, only call it
- * if we don't have a cleanup in progress.
+ * Unpause the TID if no cleanup is required.
*/
- if (! tid->cleanup_inprogress) {
- ath_tx_tid_pause(sc, tid);
- ath_tx_tid_cleanup(sc, an, i, &bf_cq);
- /*
- * Unpause the TID if no cleanup is required.
- */
- if (! tid->cleanup_inprogress)
- ath_tx_tid_resume(sc, tid);
- }
+ if (! tid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, tid);
}
ATH_TX_UNLOCK(sc);
@@ -5996,43 +5852,19 @@ ath_bar_response(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
struct ath_node *an = ATH_NODE(ni);
struct ath_tid *atid = &an->an_tid[tid];
int attempts = tap->txa_attempts;
- int old_txa_start;
DPRINTF(sc, ATH_DEBUG_SW_TX_BAR,
- "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d, txa_start=%d, txa_seqpending=%d\n",
+ "%s: %6D: called; txa_tid=%d, atid->tid=%d, status=%d, attempts=%d\n",
__func__,
ni->ni_macaddr,
":",
tap->txa_tid,
atid->tid,
status,
- attempts,
- tap->txa_start,
- tap->txa_seqpending);
+ attempts);
/* Note: This may update the BAW details */
- /*
- * XXX What if this does slide the BAW along? We need to somehow
- * XXX either fix things when it does happen, or prevent the
- * XXX seqpending value to be anything other than exactly what
- * XXX the hell we want!
- *
- * XXX So for now, how I do this inside the TX lock for now
- * XXX and just correct it afterwards? The below condition should
- * XXX never happen and if it does I need to fix all kinds of things.
- */
- ATH_TX_LOCK(sc);
- old_txa_start = tap->txa_start;
sc->sc_bar_response(ni, tap, status);
- if (tap->txa_start != old_txa_start) {
- device_printf(sc->sc_dev, "%s: tid=%d; txa_start=%d, old=%d, adjusting\n",
- __func__,
- tid,
- tap->txa_start,
- old_txa_start);
- }
- tap->txa_start = old_txa_start;
- ATH_TX_UNLOCK(sc);
/* Unpause the TID */
/*
OpenPOWER on IntegriCloud