svn commit: r224792 - user/adrian/if_ath_tx/sys/dev/ath
Adrian Chadd
adrian at FreeBSD.org
Fri Aug 12 09:18:02 UTC 2011
Author: adrian
Date: Fri Aug 12 09:18:02 2011
New Revision: 224792
URL: http://svn.freebsd.org/changeset/base/224792
Log:
Commit some (very untested) initial code to clean up after
a DELBA.
Once a DELBA is received, there may be:
* packets in the software TX TID queue
* packets in the hardware queue (aggregate or individual frames)
The software TX queue is fine - those packets don't yet have a
personality as they haven't been "scheduled".
The packets in the hardware TX queues need to be completed or
deleted.
So the logic here is:
* packets in the SWQ which are retries are discarded;
* packets in the SWQ which aren't retries are modified to have their
completion handler be the default, non-aggregate one
* if there are any packets left in the hardware queue,
mark the TID as "cleanup" and keep track of how many are outstanding
* if the TID is "cleanup", pause the TID so no further traffic
is scheduled.
Then, when the packets are completed, the "incomplete" packet count
is updated and when it hits 0 (ie, all packets on the hardware queue)
it'll be unpaused and will begin running as a non-aggregate TID.
To avoid races, pause the TID in the addba handler before disabling the
addba state and calling ath_tx_cleanup(). Since the TXQ lock is held for
the duration of queue operations, any packets that snuck in before
the TID was paused will be downgraded to non-aggregate status by
ath_tx_cleanup().
Obtained from: Atheros
Modified:
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_tx.c
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Fri Aug 12 07:04:16 2011 (r224791)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Fri Aug 12 09:18:02 2011 (r224792)
@@ -1916,53 +1916,121 @@ ath_tx_normal_comp(struct ath_softc *sc,
}
#endif
-#ifdef notyet
/*
- * Handle cleanup of aggregate state packets that aren't
+ * Handle cleanup of aggregate session packets that aren't
* an A-MPDU.
*/
static void
ath_tx_comp_cleanup(struct ath_softc *sc, struct ath_buf *bf)
{
+ struct ieee80211_node *ni = bf->bf_node;
+ struct ath_node *an = ATH_NODE(ni);
+ int tid = bf->bf_state.bfs_tid;
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ath_txq *txq = sc->sc_ac2q[atid->ac];
+
+ device_printf(sc->sc_dev, "%s: TID %d: incomp=%d\n",
+ __func__, tid, atid->incomp);
+
+ ATH_TXQ_LOCK_ASSERT(txq);
+
+ atid->incomp--;
+ if (atid->incomp == 0) {
+ device_printf(sc->sc_dev, "%s: TID %d: cleaned up! resume!\n",
+ __func__, tid);
+ atid->cleanup_inprogress = 0;
+ ath_tx_tid_resume(sc, atid);
+ }
+ ath_tx_default_comp(sc, bf, 0);
}
-#endif
/*
* Performs transmit side cleanup when TID changes from aggregated to
* unaggregated.
+ *
* - 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.
+ * The caller is responsible for locking TXQ.
*/
static void
ath_tx_cleanup(struct ath_softc *sc, struct ath_node *an, int tid)
{
struct ath_tid *atid = &an->an_tid[tid];
struct ath_txq *txq = sc->sc_ac2q[atid->ac];
+ struct ieee80211_tx_ampdu *tap;
+ struct ath_buf *bf, *bf_next;
- ATH_TXQ_LOCK(txq);
+ device_printf(sc->sc_dev, "%s: TID %d: called\n", __func__, tid);
+
+ ATH_TXQ_LOCK_ASSERT(txq);
/*
+ * Update the frames in the software TX queue:
+ *
* + Discard retry frames in the queue
* + Fix the completion function to be non-aggregate
*/
+ bf = STAILQ_FIRST(&atid->axq_q);
+ while (bf) {
+ if (bf->bf_state.bfs_isretried) {
+ bf_next = STAILQ_NEXT(bf, bf_list);
+ STAILQ_REMOVE(&atid->axq_q, bf, ath_buf, bf_list);
+ atid->axq_depth--;
+ ath_tx_update_baw(sc, an, atid,
+ SEQNO(bf->bf_state.bfs_seqno));
+ /*
+ * Call the default completion handler with "fail" just
+ * so upper levels are suitably notified about this.
+ */
+ ath_tx_default_comp(sc, bf, 1);
+ bf = bf_next;
+ continue;
+ }
+ /* Give these the default completion handler */
+ bf->bf_comp = NULL;
+ bf = STAILQ_NEXT(bf, bf_list);
+ }
+ /* The caller is required to pause the TID */
+#if 0
/* Pause the TID */
+ ath_tx_tid_pause(sc, atid);
+#endif
/*
- * Calculate what incomplete frames exist, based on
- * the current BAW size. Ie, what frames have been
+ * 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.
*/
+ tap = ath_tx_get_tx_tid(an, tid);
+ 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 cleanup is required, defer TID scheduling
* until all the HW queued packets have been
* sent.
*/
+ if (! atid->cleanup_inprogress)
+ ath_tx_tid_resume(sc, atid);
+
+ if (atid->cleanup_inprogress)
+ device_printf(sc->sc_dev,
+ "%s: TID %d: cleanup needed: %d packets\n",
+ __func__, tid, atid->incomp);
ATH_TXQ_UNLOCK(txq);
}
@@ -2051,15 +2119,13 @@ ath_tx_aggr_comp(struct ath_softc *sc, s
/*
* If a cleanup is in progress, punt to comp_cleanup;
* rather than handling it here. It's thus their
- * responsibility to do the BAW update, track the
- * incomplete packet count, etc.
+ * responsibility to clean up, call the completion
+ * function in net80211, update rate control, etc.
*/
-#ifdef notyet
if (atid->cleanup_inprogress) {
ath_tx_comp_cleanup(sc, bf);
return;
}
-#endif
/*
* Don't bother with the retry check if all frames
@@ -2363,10 +2429,6 @@ ath_addba_response(struct ieee80211_node
/*
* Stop ADDBA on a queue.
- *
- * In theory, queued ath_bufs should be turned back into non-aggregate
- * buffers. I'm not sure what to do about packets currently queued
- * to the hardware.
*/
void
ath_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
@@ -2374,10 +2436,20 @@ ath_addba_stop(struct ieee80211_node *ni
struct ath_softc *sc = ni->ni_ic->ic_ifp->if_softc;
int tid = WME_AC_TO_TID(tap->txa_ac);
struct ath_node *an = ATH_NODE(ni);
-#if 0
- struct ath_tid *atid = an->an_tid[tid];
-#endif
+ struct ath_tid *atid = &an->an_tid[tid];
+ struct ath_txq *txq = sc->sc_ac2q[atid->ac];
+
DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL, "%s: called\n", __func__);
+
+ /* Pause TID traffic early, so there aren't any races */
+ ATH_TXQ_LOCK(txq);
+ ath_tx_tid_pause(sc, atid);
+ ATH_TXQ_UNLOCK(txq);
+
+ /* There's no need to hold the TXQ lock here */
sc->sc_addba_stop(ni, tap);
+
+ ATH_TXQ_LOCK(txq);
ath_tx_cleanup(sc, an, tid);
+ ATH_TXQ_UNLOCK(txq);
}
Modified: user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h
==============================================================================
--- user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Fri Aug 12 07:04:16 2011 (r224791)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_athvar.h Fri Aug 12 09:18:02 2011 (r224792)
@@ -115,6 +115,12 @@ struct ath_tid {
* traffic will resume being TXed.
*/
int cleanup_inprogress;
+ /*
+ * How many hardware-queued packets are
+ * waiting to be cleaned up.
+ * This is only valid if cleanup_inprogress is 1.
+ */
+ int incomp;
/*
* The following implements a ring representing
More information about the svn-src-user
mailing list