svn commit: r225131 - user/adrian/if_ath_tx/sys/dev/ath
Adrian Chadd
adrian at FreeBSD.org
Wed Aug 24 06:57:30 UTC 2011
Author: adrian
Date: Wed Aug 24 06:57:29 2011
New Revision: 225131
URL: http://svn.freebsd.org/changeset/base/225131
Log:
Begin fleshing out busy buffer handling in the software retry path.
If the buffer is marked ATH_BUF_BUSY, the hardware may still be
pointing at the link pointer in that descriptor. So the software
retry code can't simply throw the descriptor back into the work
list.
Modified:
user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c
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 Wed Aug 24 06:49:57 2011 (r225130)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c Wed Aug 24 06:57:29 2011 (r225131)
@@ -2345,6 +2345,44 @@ ath_tx_set_retry(struct ath_softc *sc, s
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
}
+static struct ath_buf *
+ath_tx_retry_clone(struct ath_softc *sc, struct ath_buf *bf)
+{
+ struct ath_buf *nbf;
+ int error;
+
+ nbf = ath_buf_clone(sc, bf);
+
+#if 0
+ device_printf(sc->sc_dev, "%s: ATH_BUF_BUSY; cloning\n",
+ __func__);
+#endif
+
+ if (nbf == NULL) {
+ /* Failed to clone */
+ device_printf(sc->sc_dev,
+ "%s: failed to clone a busy buffer\n",
+ __func__);
+ return NULL;
+ }
+
+ /* Setup the dma for the new buffer */
+ error = ath_tx_dmasetup(sc, nbf, nbf->bf_m);
+ if (error != 0) {
+ device_printf(sc->sc_dev,
+ "%s: failed to setup dma for clone\n",
+ __func__);
+ ath_freebuf(sc, nbf);
+ return NULL;
+ }
+
+ /* Free current buffer; return the older buffer */
+ bf->bf_m = NULL;
+ bf->bf_node = NULL;
+ ath_freebuf(sc, bf);
+ return nbf;
+}
+
/*
* Handle retrying an unaggregate frame in an aggregate
* session.
@@ -2366,6 +2404,24 @@ ath_tx_aggr_retry_unaggr(struct ath_soft
tap = ath_tx_get_tx_tid(an, tid);
+ /*
+ * If the buffer is marked as busy, we can't directly
+ * reuse it. Instead, try to clone the buffer.
+ * If the clone is successful, recycle the old buffer.
+ * If the clone is unsuccessful, set bfs_retries to max
+ * to force the next bit of code to free the buffer
+ * for us.
+ */
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ struct ath_buf *nbf;
+ nbf = ath_tx_retry_clone(sc, bf);
+ if (nbf)
+ /* bf has been freed at this point */
+ bf = nbf;
+ else
+ bf->bf_state.bfs_retries = SWMAX_RETRIES + 1;
+ }
+
if (bf->bf_state.bfs_retries >= SWMAX_RETRIES) {
device_printf(sc->sc_dev, "%s: exceeded retries; seqno %d\n",
__func__, SEQNO(bf->bf_state.bfs_seqno));
@@ -2421,28 +2477,6 @@ ath_tx_aggr_retry_unaggr(struct ath_soft
ath_tx_set_retry(sc, bf);
/*
- * XXX Clear the ATH_BUF_BUSY flag. This is likely incorrect
- * XXX and must be revisited before this is merged into -HEAD.
- *
- * This flag is set in ath_tx_processq() if the HW TXQ has
- * further frames on it. The hardware may currently be processing
- * the link field in the descriptor (because for TDMA, the
- * QCU (TX queue DMA engine) can stop until the next TX slot is
- * available and a recycled buffer may still contain a descriptor
- * which the currently-paused QCU still points to.
- *
- * Since I'm not worried about TDMA just for now, I'm going to blank
- * the flag.
- */
- if (bf->bf_flags & ATH_BUF_BUSY) {
- bf->bf_flags &= ~ ATH_BUF_BUSY;
-#if 0
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
- "%s: bf %p: ATH_BUF_BUSY\n", __func__, bf);
-#endif
- }
-
- /*
* Insert this at the head of the queue, so it's
* retried before any current/subsequent frames.
*/
@@ -2475,6 +2509,24 @@ ath_tx_retry_subframe(struct ath_softc *
ath_hal_set11nburstduration(sc->sc_ah, bf->bf_desc, 0);
/* ath_hal_set11n_virtualmorefrag(sc->sc_ah, bf->bf_desc, 0); */
+ /*
+ * If the buffer is marked as busy, we can't directly
+ * reuse it. Instead, try to clone the buffer.
+ * If the clone is successful, recycle the old buffer.
+ * If the clone is unsuccessful, set bfs_retries to max
+ * to force the next bit of code to free the buffer
+ * for us.
+ */
+ if (bf->bf_flags & ATH_BUF_BUSY) {
+ struct ath_buf *nbf;
+ nbf = ath_tx_retry_clone(sc, bf);
+ if (nbf)
+ /* bf has been freed at this point */
+ bf = nbf;
+ else
+ bf->bf_state.bfs_retries = SWMAX_RETRIES + 1;
+ }
+
if (bf->bf_state.bfs_retries >= SWMAX_RETRIES) {
device_printf(sc->sc_dev, "%s: max retries: seqno %d\n",
__func__, SEQNO(bf->bf_state.bfs_seqno));
@@ -2491,14 +2543,6 @@ ath_tx_retry_subframe(struct ath_softc *
return 1;
}
- if (bf->bf_flags & ATH_BUF_BUSY) {
- bf->bf_flags &= ~ ATH_BUF_BUSY;
-#if 0
- DPRINTF(sc, ATH_DEBUG_SW_TX_CTRL,
- "%s: bf %p: ATH_BUF_BUSY\n", __func__, bf);
-#endif
- }
-
ath_tx_set_retry(sc, bf);
bf->bf_next = NULL; /* Just to make sure */
@@ -2935,8 +2979,6 @@ ath_tx_tid_hw_queue_aggr(struct ath_soft
ATH_TXQ_REMOVE(atid, bf, bf_list);
ATH_TXQ_UNLOCK(atid);
bf->bf_state.bfs_aggr = 0;
- /* Ensure the last descriptor link is 0 */
- bf->bf_lastds->ds_link = 0;
ath_tx_setds(sc, bf);
ath_tx_chaindesclist(sc, bf);
ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
@@ -2977,8 +3019,6 @@ ath_tx_tid_hw_queue_aggr(struct ath_soft
DPRINTF(sc, ATH_DEBUG_SW_TX_AGGR,
"%s: single-frame aggregate\n", __func__);
bf->bf_state.bfs_aggr = 0;
- /* Ensure the last descriptor link is 0 */
- bf->bf_lastds->ds_link = 0;
ath_tx_setds(sc, bf);
ath_tx_chaindesclist(sc, bf);
ath_hal_clr11n_aggr(sc->sc_ah, bf->bf_desc);
More information about the svn-src-user
mailing list