Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 24 Jan 2019 03:41:09 +0000 (UTC)
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r343373 - head/sys/dev/iwm
Message-ID:  <201901240341.x0O3f9jX022110@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevans
Date: Thu Jan 24 03:41:09 2019
New Revision: 343373
URL: https://svnweb.freebsd.org/changeset/base/343373

Log:
  if_iwm - Update firmware rs table, instead of indexing the table in tx cmds.
  
  * Rather than providing a non-zero index into the firmware RS table,
  we should always use index 0 and update the firmware RS table whenever
  our chosen tx rate for data-frames changes.
  
  * Send IWM_LQ_CMD updates when the tx rate gets updated by the net80211
  rate control (which is after we tell the tx status to the net80211
  rate-control in iwm_mvm_rx_tx_cmd_single()).
  
  * Disregard frames transferred with a different tx rate than the currently
  selected rate for the rate-control calculations. This way we avoid
  counting management frames (which are sent at a slow, and fixed rate),
  as well as frames we added to the tx queue just before a new IWM_LQ_CMD
  update took effect.
  
  Submitted by:	Augustin Cavalier <waddlesplash@gmail.com> (Haiku)
  Obtained from:	DragonFlyBSD (5d6b465e288ac5b52d7115688d4e6516acbbea1c)

Modified:
  head/sys/dev/iwm/if_iwm.c
  head/sys/dev/iwm/if_iwmvar.h

Modified: head/sys/dev/iwm/if_iwm.c
==============================================================================
--- head/sys/dev/iwm/if_iwm.c	Thu Jan 24 01:08:37 2019	(r343372)
+++ head/sys/dev/iwm/if_iwm.c	Thu Jan 24 03:41:09 2019	(r343373)
@@ -353,7 +353,9 @@ static int	iwm_release(struct iwm_softc *, struct iwm_
 static struct ieee80211_node *
 		iwm_node_alloc(struct ieee80211vap *,
 		               const uint8_t[IEEE80211_ADDR_LEN]);
-static void	iwm_setrates(struct iwm_softc *, struct iwm_node *);
+static uint8_t	iwm_rate_from_ucode_rate(uint32_t);
+static int	iwm_rate2ridx(struct iwm_softc *, uint8_t);
+static void	iwm_setrates(struct iwm_softc *, struct iwm_node *, int);
 static int	iwm_media_change(struct ifnet *);
 static int	iwm_newstate(struct ieee80211vap *, enum ieee80211_state, int);
 static void	iwm_endscan_cb(void *, int);
@@ -3317,7 +3319,11 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
 	struct iwm_mvm_tx_resp *tx_resp = (void *)pkt->data;
 	struct ieee80211_ratectl_tx_status *txs = &sc->sc_txs;
 	struct ieee80211_node *ni = &in->in_ni;
+	struct ieee80211vap *vap = ni->ni_vap;
 	int status = le16toh(tx_resp->status.status) & IWM_TX_STATUS_MSK;
+	int new_rate, cur_rate = vap->iv_bss->ni_txrate;
+	boolean_t rate_matched;
+	uint8_t tx_resp_rate;
 
 	KASSERT(tx_resp->frame_count == 1, ("too many frames"));
 
@@ -3333,6 +3339,17 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
 	    le32toh(tx_resp->initial_rate),
 	    (int) le16toh(tx_resp->wireless_media_time));
 
+	tx_resp_rate = iwm_rate_from_ucode_rate(le32toh(tx_resp->initial_rate));
+
+	/* For rate control, ignore frames sent at different initial rate */
+	rate_matched = (tx_resp_rate != 0 && tx_resp_rate == cur_rate);
+
+	if (tx_resp_rate != 0 && cur_rate != 0 && !rate_matched) {
+		IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
+		    "tx_resp_rate doesn't match ni_txrate (tx_resp_rate=%u "
+		    "ni_txrate=%d)\n", tx_resp_rate, cur_rate);
+	}
+
 	txs->flags = IEEE80211_RATECTL_STATUS_SHORT_RETRY |
 		     IEEE80211_RATECTL_STATUS_LONG_RETRY;
 	txs->short_retries = tx_resp->failure_rts;
@@ -3356,8 +3373,19 @@ iwm_mvm_rx_tx_cmd_single(struct iwm_softc *sc, struct 
 	} else {
 		txs->status = IEEE80211_RATECTL_TX_SUCCESS;
 	}
-	ieee80211_ratectl_tx_complete(ni, txs);
 
+	if (rate_matched) {
+		ieee80211_ratectl_tx_complete(ni, txs);
+
+		int rix = ieee80211_ratectl_rate(vap->iv_bss, NULL, 0);
+		new_rate = vap->iv_bss->ni_txrate;
+		if (new_rate != 0 && new_rate != cur_rate) {
+			struct iwm_node *in = IWM_NODE(vap->iv_bss);
+			iwm_setrates(sc, in, rix);
+			iwm_mvm_send_lq_cmd(sc, &in->in_lq, FALSE);
+		}
+ 	}
+
 	return (txs->status != IEEE80211_RATECTL_TX_SUCCESS);
 }
 
@@ -3482,38 +3510,7 @@ iwm_update_sched(struct iwm_softc *sc, int qid, int id
 }
 #endif
 
-/*
- * Take an 802.11 (non-n) rate, find the relevant rate
- * table entry.  return the index into in_ridx[].
- *
- * The caller then uses that index back into in_ridx
- * to figure out the rate index programmed /into/
- * the firmware for this given node.
- */
 static int
-iwm_tx_rateidx_lookup(struct iwm_softc *sc, struct iwm_node *in,
-    uint8_t rate)
-{
-	int i;
-	uint8_t r;
-
-	for (i = 0; i < nitems(in->in_ridx); i++) {
-		r = iwm_rates[in->in_ridx[i]].rate;
-		if (rate == r)
-			return (i);
-	}
-
-	IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
-	    "%s: couldn't find an entry for rate=%d\n",
-	    __func__,
-	    rate);
-
-	/* XXX Return the first */
-	/* XXX TODO: have it return the /lowest/ */
-	return (0);
-}
-
-static int
 iwm_tx_rateidx_global_lookup(struct iwm_softc *sc, uint8_t rate)
 {
 	int i;
@@ -3565,22 +3562,15 @@ iwm_tx_fill_cmd(struct iwm_softc *sc, struct iwm_node 
 		IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
 		    "%s: FIXED_RATE (%d)\n", __func__, tp->ucastrate);
 	} else {
-		int i;
-
 		/* for data frames, use RS table */
 		IWM_DPRINTF(sc, IWM_DEBUG_TXRATE, "%s: DATA\n", __func__);
-		/* XXX pass pktlen */
-		(void) ieee80211_ratectl_rate(ni, NULL, 0);
-		i = iwm_tx_rateidx_lookup(sc, in, ni->ni_txrate);
-		ridx = in->in_ridx[i];
+		ridx = iwm_rate2ridx(sc, ni->ni_txrate);
+		if (ridx == -1)
+			ridx = 0;
 
 		/* This is the index into the programmed table */
-		tx->initial_rate_index = i;
+		tx->initial_rate_index = 0;
 		tx->tx_flags |= htole32(IWM_TX_CMD_FLG_STA_RATE);
-
-		IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
-		    "%s: start with i=%d, txrate %d\n",
-		    __func__, i, iwm_rates[ridx].rate);
 	}
 
 	IWM_DPRINTF(sc, IWM_DEBUG_XMIT | IWM_DEBUG_TXRATE,
@@ -4165,6 +4155,19 @@ iwm_node_alloc(struct ieee80211vap *vap, const uint8_t
 	    M_NOWAIT | M_ZERO);
 }
 
+static uint8_t
+iwm_rate_from_ucode_rate(uint32_t rate_n_flags)
+{
+	uint8_t plcp = rate_n_flags & 0xff;
+	int i;
+
+	for (i = 0; i <= IWM_RIDX_MAX; i++) {
+		if (iwm_rates[i].plcp == plcp)
+			return iwm_rates[i].rate;
+	}
+	return 0;
+}
+
 uint8_t
 iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 {
@@ -4180,15 +4183,36 @@ iwm_ridx2rate(struct ieee80211_rateset *rs, int ridx)
 	return 0;
 }
 
+static int
+iwm_rate2ridx(struct iwm_softc *sc, uint8_t rate)
+{
+	int i;
+
+	for (i = 0; i <= IWM_RIDX_MAX; i++) {
+		if (iwm_rates[i].rate == rate)
+			return i;
+	}
+
+	device_printf(sc->sc_dev,
+	    "%s: WARNING: device rate for %u not found!\n",
+	    __func__, rate);
+
+	return -1;
+}
+
+
 static void
-iwm_setrates(struct iwm_softc *sc, struct iwm_node *in)
+iwm_setrates(struct iwm_softc *sc, struct iwm_node *in, int rix)
 {
 	struct ieee80211_node *ni = &in->in_ni;
 	struct iwm_lq_cmd *lq = &in->in_lq;
-	int nrates = ni->ni_rates.rs_nrates;
+	struct ieee80211_rateset *rs = &ni->ni_rates;
+	int nrates = rs->rs_nrates;
 	int i, ridx, tab = 0;
 //	int txant = 0;
 
+	KASSERT(rix >= 0 && rix < nrates, ("invalid rix"));
+
 	if (nrates > nitems(lq->rs_table)) {
 		device_printf(sc->sc_dev,
 		    "%s: node supports %d rates, driver handles "
@@ -4200,45 +4224,11 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 		    "%s: node supports 0 rates, odd!\n", __func__);
 		return;
 	}
+	nrates = imin(rix + 1, nrates);
 
-	/*
-	 * XXX .. and most of iwm_node is not initialised explicitly;
-	 * it's all just 0x0 passed to the firmware.
-	 */
-
-	/* first figure out which rates we should support */
-	/* XXX TODO: this isn't 11n aware /at all/ */
-	memset(&in->in_ridx, -1, sizeof(in->in_ridx));
 	IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
 	    "%s: nrates=%d\n", __func__, nrates);
 
-	/*
-	 * Loop over nrates and populate in_ridx from the highest
-	 * rate to the lowest rate.  Remember, in_ridx[] has
-	 * IEEE80211_RATE_MAXSIZE entries!
-	 */
-	for (i = 0; i < min(nrates, IEEE80211_RATE_MAXSIZE); i++) {
-		int rate = ni->ni_rates.rs_rates[(nrates - 1) - i] & IEEE80211_RATE_VAL;
-
-		/* Map 802.11 rate to HW rate index. */
-		for (ridx = 0; ridx <= IWM_RIDX_MAX; ridx++)
-			if (iwm_rates[ridx].rate == rate)
-				break;
-		if (ridx > IWM_RIDX_MAX) {
-			device_printf(sc->sc_dev,
-			    "%s: WARNING: device rate for %d not found!\n",
-			    __func__, rate);
-		} else {
-			IWM_DPRINTF(sc, IWM_DEBUG_TXRATE,
-			    "%s: rate: i: %d, rate=%d, ridx=%d\n",
-			    __func__,
-			    i,
-			    rate,
-			    ridx);
-			in->in_ridx[i] = ridx;
-		}
-	}
-
 	/* then construct a lq_cmd based on those */
 	memset(lq, 0, sizeof(*lq));
 	lq->sta_id = IWM_STATION_ID;
@@ -4262,13 +4252,15 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 	 * Note that we add the rates in the highest rate first
 	 * (opposite of ni_rates).
 	 */
-	/*
-	 * XXX TODO: this should be looping over the min of nrates
-	 * and LQ_MAX_RETRY_NUM.  Sigh.
-	 */
 	for (i = 0; i < nrates; i++) {
+		int rate = rs->rs_rates[rix - i] & IEEE80211_RATE_VAL;
 		int nextant;
 
+		/* Map 802.11 rate to HW rate index. */
+		ridx = iwm_rate2ridx(sc, rate);
+		if (ridx == -1)
+			continue;
+
 #if 0
 		if (txant == 0)
 			txant = iwm_mvm_get_valid_tx_ant(sc);
@@ -4277,12 +4269,6 @@ iwm_setrates(struct iwm_softc *sc, struct iwm_node *in
 #else
 		nextant = iwm_mvm_get_valid_tx_ant(sc);
 #endif
-		/*
-		 * Map the rate id into a rate index into
-		 * our hardware table containing the
-		 * configuration to use for this rate.
-		 */
-		ridx = in->in_ridx[i];
 		tab = iwm_rates[ridx].plcp;
 		tab |= nextant << IWM_RATE_MCS_ANT_POS;
 		if (IWM_RIDX_IS_CCK(ridx))
@@ -4474,7 +4460,8 @@ iwm_newstate(struct ieee80211vap *vap, enum ieee80211_
 		iwm_mvm_enable_beacon_filter(sc, ivp);
 		iwm_mvm_power_update_mac(sc);
 		iwm_mvm_update_quotas(sc, ivp);
-		iwm_setrates(sc, in);
+		int rix = ieee80211_ratectl_rate(&in->in_ni, NULL, 0);
+		iwm_setrates(sc, in, rix);
 
 		if ((error = iwm_mvm_send_lq_cmd(sc, &in->in_lq, TRUE)) != 0) {
 			device_printf(sc->sc_dev,

Modified: head/sys/dev/iwm/if_iwmvar.h
==============================================================================
--- head/sys/dev/iwm/if_iwmvar.h	Thu Jan 24 01:08:37 2019	(r343372)
+++ head/sys/dev/iwm/if_iwmvar.h	Thu Jan 24 03:41:09 2019	(r343373)
@@ -404,8 +404,6 @@ struct iwm_node {
 	int			in_assoc;
 
 	struct iwm_lq_cmd	in_lq;
-
-	uint8_t			in_ridx[IEEE80211_RATE_MAXSIZE];
 };
 #define IWM_NODE(_ni)		((struct iwm_node *)(_ni))
 



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