Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Aug 2011 20:34:57 +0000 (UTC)
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r224789 - user/adrian/if_ath_tx/sys/dev/ath
Message-ID:  <201108112034.p7BKYvTF007810@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: adrian
Date: Thu Aug 11 20:34:57 2011
New Revision: 224789
URL: http://svn.freebsd.org/changeset/base/224789

Log:
  Implement a very basic software re-transmit algorithm.
  
  If an ADDBA session frame fails, and it's not during some kind
  of queue cleanup, attempt to retransmit the thing.
  
  The retransmit method is very simple - set some bits to indicate
  its a retry, prepend to the front of the queue, and schedule the
  TID for activity in the future. The frame will be rescheduled
  and resubmitted to the hardware for us by the normal TX path.
  
  This doesn't attempt a rate lookup; it re-uses the same rate
  information as the original frame. This means that if TX is
  failing because the rate selection isn't optimal, it's
  likely going to keep failing. I'll investigate that in the
  future.
  
  Use a (currently) hard-coded max of 10 retransmits. This is 10
  retransmits on top of whatever the rate control module attempts,
  which may be 4 or 10 frames. This means a frame could be retried
  from 40 to 100 times.
  
  Finally, a BAR isn't sent if TX does finally fail. I'll worry
  about BAR handling and session teardown handling soon.

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	Thu Aug 11 20:30:22 2011	(r224788)
+++ user/adrian/if_ath_tx/sys/dev/ath/if_ath_tx.c	Thu Aug 11 20:34:57 2011	(r224789)
@@ -119,6 +119,11 @@ __FBSDID("$FreeBSD$");
 #define	BAW_WITHIN(_start, _bawsz, _seqno)	\
 	     ((((_seqno) - (_start)) & 4095) < (_bawsz))
 
+/*
+ * How many retries to perform in software
+ */
+#define	SWMAX_RETRIES		10
+
 static struct ieee80211_tx_ampdu * ath_tx_get_tx_tid(struct ath_node *an,
     int tid);
 static int ath_tx_ampdu_pending(struct ath_softc *sc, struct ath_node *an,
@@ -1910,8 +1915,68 @@ ath_tx_normal_comp(struct ath_softc *sc,
 }
 #endif
 
+static void
+ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf)
+{
+	struct ieee80211_frame *wh;
+
+	sc->sc_stats.ast_tx_swretries++;
+	bf->bf_state.bfs_isretried = 1;
+	bf->bf_state.bfs_retries ++;
+	wh = mtod(bf->bf_m, struct ieee80211_frame *);
+	wh->i_fc[1] |= IEEE80211_FC1_RETRY;
+}
+
+/*
+ * Handle retrying an unaggregate frame in an aggregate
+ * session.
+ *
+ * If too many retries occur, pause the TID, wait for
+ * any further retransmits (as there's no reason why
+ * non-aggregate frames in an aggregate session are
+ * transmitted in-order; they just have to be in-BAW)
+ * and then queue a BAR.
+ */
+static void
+ath_tx_aggr_retry_unaggr(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];
+
+	ATH_TXQ_LOCK_ASSERT(txq);
+
+	if (bf->bf_state.bfs_retries >= SWMAX_RETRIES) {
+		sc->sc_stats.ast_tx_swretrymax++;
+
+		/* Update BAW anyway */
+		ath_tx_update_baw(sc, an, atid, SEQNO(bf->bf_state.bfs_seqno));
+
+		/* Free buffer, bf is free after this call */
+		ath_tx_default_comp(sc, bf, 0);
+		return;
+	}
+
+	/*
+	 * This increments the retry counter as well as
+	 * sets the retry flag in the ath_buf and packet
+	 * body.
+	 */
+	ath_tx_set_retry(sc, bf);
+
+	/*
+	 * Insert this at the head of the queue, so it's
+	 * retried before any current/subsequent frames.
+	 */
+	ATH_TXQ_INSERT_HEAD(atid, bf, bf_list);
+	ath_tx_tid_sched(sc, an, atid->tid);
+}
+
 /*
- * Handle completion of aggregate frames.
+ * Handle completion of unaggregated frames in an ADDBA
+ * session.
  *
  * Fail is set to 1 if the entry is being freed via a call to
  * ath_tx_draintxq().
@@ -1923,6 +1988,7 @@ ath_tx_aggr_comp(struct ath_softc *sc, s
 	struct ath_node *an = ATH_NODE(ni);
 	int tid = bf->bf_state.bfs_tid;
 	struct ath_tid *atid = &an->an_tid[tid];
+	struct ath_tx_status *ts = &bf->bf_status.ds_txstat;
 
 	if (tid == IEEE80211_NONQOS_TID)
 		device_printf(sc->sc_dev, "%s: TID=16!\n", __func__);
@@ -1930,19 +1996,13 @@ ath_tx_aggr_comp(struct ath_softc *sc, s
 	    __func__, bf, bf->bf_state.bfs_tid);
 
 	/*
-	 * Not success and have retries left?
-	 *
-	 * Mark as retry, requeue at head of queue
-	 */
-
-	/*
-	 * Not success and out of retries?
-	 *
-	 * Need to wait for the hardware TXQ to finish draining,
-	 * then once we know what was successfully TXed and what
-	 * wasn't, we send a BAR to advance the pointer to that
-	 * place.
+	 * Don't bother with the retry check if all frames
+	 * are being failed (eg during queue deletion.)
 	 */
+	if (fail == 0 && ts->ts_status & HAL_TXERR_XRETRY) {
+		ath_tx_aggr_retry_unaggr(sc, bf);
+		return;
+	}
 
 	/* Success? Complete */
 	DPRINTF(sc, ATH_DEBUG_SW_TX, "%s: TID=%d, seqno %d\n",



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