Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 9 Nov 2011 18:24:20 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r227398 - head/sys/dev/ath
Message-ID:  <201111091824.pA9IOKBK094187@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Wed Nov  9 18:24:20 2011
New Revision: 227398
URL: http://svn.freebsd.org/changeset/base/227398

Log:
  If software retransmit occurs with an ath_buf marked ATH_BUF_BUSY,
  it's cloned and that clone is retransmitted. This means that the
  ath_buf pointer squirreled away on the baw window array is suddenly
  wrong and was causing all kinds of console output.
  
  This updates the pointer in that particular BAW slot to the new
  ath_buf after ensuring that:
  
  * the new and old buffers have the same seqno;
  * the current slot pointer matches the old buffer pointer.
  
  This quietens the debugging output (again), restoring said debugging
  to only signify when a broken condition has occured.
  
  Sponsored by:	Hobnob, Inc.

Modified:
  head/sys/dev/ath/if_ath_tx.c

Modified: head/sys/dev/ath/if_ath_tx.c
==============================================================================
--- head/sys/dev/ath/if_ath_tx.c	Wed Nov  9 18:12:42 2011	(r227397)
+++ head/sys/dev/ath/if_ath_tx.c	Wed Nov  9 18:24:20 2011	(r227398)
@@ -1900,6 +1900,56 @@ ath_tx_addto_baw(struct ath_softc *sc, s
 }
 
 /*
+ * Flip the BAW buffer entry over from the existing one to the new one.
+ *
+ * When software retransmitting a (sub-)frame, it is entirely possible that
+ * the frame ath_buf is marked as BUSY and can't be immediately reused.
+ * In that instance the buffer is cloned and the new buffer is used for
+ * retransmit. We thus need to update the ath_buf slot in the BAW buf
+ * tracking array to maintain consistency.
+ */
+static void
+ath_tx_switch_baw_buf(struct ath_softc *sc, struct ath_node *an,
+    struct ath_tid *tid, struct ath_buf *old_bf, struct ath_buf *new_bf)
+{
+	int index, cindex;
+	struct ieee80211_tx_ampdu *tap;
+	int seqno = SEQNO(old_bf->bf_state.bfs_seqno);
+
+	ATH_TXQ_LOCK_ASSERT(sc->sc_ac2q[tid->ac]);
+
+	tap = ath_tx_get_tx_tid(an, tid->tid);
+	index  = ATH_BA_INDEX(tap->txa_start, seqno);
+	cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
+
+	/*
+	 * Just warn for now; if it happens then we should find out
+	 * about it. It's highly likely the aggregation session will
+	 * soon hang.
+	 */
+	if (old_bf->bf_state.bfs_seqno != new_bf->bf_state.bfs_seqno) {
+		device_printf(sc->sc_dev, "%s: retransmitted buffer"
+		    " has mismatching seqno's, BA session may hang.\n",
+		    __func__);
+		device_printf(sc->sc_dev, "%s: old seqno=%d, new_seqno=%d\n",
+		    __func__,
+		    old_bf->bf_state.bfs_seqno,
+		    new_bf->bf_state.bfs_seqno);
+	}
+
+	if (tid->tx_buf[cindex] != old_bf) {
+		device_printf(sc->sc_dev, "%s: ath_buf pointer incorrect; "
+		    " has m BA session may hang.\n",
+		    __func__);
+		device_printf(sc->sc_dev, "%s: old bf=%p, new bf=%p\n",
+		    __func__,
+		    old_bf, new_bf);
+	}
+
+	tid->tx_buf[cindex] = new_bf;
+}
+
+/*
  * seq_start - left edge of BAW
  * seq_next - current/next sequence number to allocate
  *
@@ -2619,7 +2669,8 @@ ath_tx_set_retry(struct ath_softc *sc, s
 }
 
 static struct ath_buf *
-ath_tx_retry_clone(struct ath_softc *sc, struct ath_buf *bf)
+ath_tx_retry_clone(struct ath_softc *sc, struct ath_node *an,
+    struct ath_tid *tid, struct ath_buf *bf)
 {
 	struct ath_buf *nbf;
 	int error;
@@ -2657,6 +2708,10 @@ ath_tx_retry_clone(struct ath_softc *sc,
 		return NULL;
 	}
 
+	/* Update BAW if required, before we free the original buf */
+	if (bf->bf_state.bfs_dobaw)
+		ath_tx_switch_baw_buf(sc, an, tid, bf, nbf);
+
 	/* Free current buffer; return the older buffer */
 	bf->bf_m = NULL;
 	bf->bf_node = NULL;
@@ -2699,7 +2754,7 @@ ath_tx_aggr_retry_unaggr(struct ath_soft
 	if ((bf->bf_state.bfs_retries < SWMAX_RETRIES) &&
 	    (bf->bf_flags & ATH_BUF_BUSY)) {
 		struct ath_buf *nbf;
-		nbf = ath_tx_retry_clone(sc, bf);
+		nbf = ath_tx_retry_clone(sc, an, atid, bf);
 		if (nbf)
 			/* bf has been freed at this point */
 			bf = nbf;
@@ -2791,7 +2846,7 @@ ath_tx_retry_subframe(struct ath_softc *
 	if ((bf->bf_state.bfs_retries < SWMAX_RETRIES) &&
 	    (bf->bf_flags & ATH_BUF_BUSY)) {
 		struct ath_buf *nbf;
-		nbf = ath_tx_retry_clone(sc, bf);
+		nbf = ath_tx_retry_clone(sc, an, atid, bf);
 		if (nbf)
 			/* bf has been freed at this point */
 			bf = nbf;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201111091824.pA9IOKBK094187>