Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 4 Oct 2025 03:02:31 GMT
From:      Adrian Chadd <adrian@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 4a5a884c4a77 - main - iwx: rewrite iwx_rs_update() to be VHT aware, refactor it a bit
Message-ID:  <202510040302.59432Vfc014950@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by adrian:

URL: https://cgit.FreeBSD.org/src/commit/?id=4a5a884c4a77e800bb37e1c12db72c724a2220bc

commit 4a5a884c4a77e800bb37e1c12db72c724a2220bc
Author:     Adrian Chadd <adrian@FreeBSD.org>
AuthorDate: 2025-09-28 03:19:57 +0000
Commit:     Adrian Chadd <adrian@FreeBSD.org>
CommitDate: 2025-10-04 02:56:39 +0000

    iwx: rewrite iwx_rs_update() to be VHT aware, refactor it a bit
    
    The current iwx_rs_update() code doesn't handle setting VHT rates
    at all.
    
    So:
    
    * write a routine - iwx_rs_update_node_txrate() - which will update
      the given node txrate info with the given notification
    * .. which is based on the print_ratenflags() logic and decoding
    * migrate iwx_rs_update() to use this routine, only on the STA BSS node.
    
    This only handles decoding the version 2 rate_n_flags format response -
    same as print_ratenflags() - so print if someone somehow sees a version
    1 response.
    
    It's shown a few things that deserve some later follow-up work:
    
    * I really should have net80211 APIs that operate on the txrate struct
      itself, not on the ieee80211_node, but I'll use what I have.
      Changing it later is easy.
    
    * the current net80211 txrate API doesn't include channel width,
      LDPC/STBC and such.  I didn't need it for the earlier tx rate
      representation migration, but it would be nice to add it.
      (The reason is that those choices are currently made in the drivers
      using rate control, rather than the rate control module, which is
      again what the older code did as well.)
    
      This means that the displayed rate isn't EXACTLY what the NIC has
      chosen - eg the NIC could quite happily decide to transmit a 20MHz
      or 40MHz frame to an 80MHz STA if that actually works out better.
      So just add TODOs for those.
    
    Locally tested:
    
    * AX210, STA mode
    
    Differential Revision:  https://reviews.freebsd.org/D52767
    Reviewed by:    thj
---
 sys/dev/iwx/if_iwx.c    | 162 +++++++++++++++++++++++++-----------------------
 sys/dev/iwx/if_iwxreg.h |   4 ++
 2 files changed, 90 insertions(+), 76 deletions(-)

diff --git a/sys/dev/iwx/if_iwx.c b/sys/dev/iwx/if_iwx.c
index d2d435545e27..04ed09f04604 100644
--- a/sys/dev/iwx/if_iwx.c
+++ b/sys/dev/iwx/if_iwx.c
@@ -7323,97 +7323,107 @@ iwx_rs_init(struct iwx_softc *sc, struct iwx_node *in)
 		return iwx_rs_init_v3(sc, in);
 }
 
-static void
-iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif)
+
+/**
+ * @brief Turn the given TX rate control notification into an ieee80211_node_txrate
+ *
+ * This populates the given txrate node with the TX rate control notification.
+ *
+ * @param sc driver softc
+ * @param notif firmware notification
+ * @param ni ieee80211_node update
+ * @returns true if updated, false if not
+ */
+static bool
+iwx_rs_update_node_txrate(struct iwx_softc *sc,
+    const struct iwx_tlc_update_notif *notif, struct ieee80211_node *ni)
 {
 	struct ieee80211com *ic = &sc->sc_ic;
-	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
-	struct ieee80211_node *ni = (void *)vap->iv_bss;
+	/* XXX TODO: create an inline function in if_iwxreg.h? */
+	static int cck_idx_to_rate[] = { 2, 4, 11, 22, 2, 2, 2, 2 };
+	static int ofdm_idx_to_rate[] = { 12, 18, 24, 36, 48, 72, 96, 108 };
 
-	struct ieee80211_rateset *rs = &ni->ni_rates;
 	uint32_t rate_n_flags;
-	uint8_t plcp, rval;
-	int i, cmd_ver, rate_n_flags_ver2 = 0;
-
-	if (notif->sta_id != IWX_STATION_ID ||
-	    (le32toh(notif->flags) & IWX_TLC_NOTIF_FLAG_RATE) == 0)
-		return;
+	uint32_t type;
 
+	/* Extract the rate and command version */
 	rate_n_flags = le32toh(notif->rate);
 
+	if (sc->sc_rate_n_flags_version != 2) {
+		net80211_ic_printf(ic,
+		    "%s: unsupported rate_n_flags version (%d)\n",
+		    __func__,
+		    sc->sc_rate_n_flags_version);
+		return (false);
+	}
+
 	if (sc->sc_debug & IWX_DEBUG_TXRATE)
 		print_ratenflags(__func__, __LINE__,
 		    rate_n_flags, sc->sc_rate_n_flags_version);
 
-	cmd_ver = iwx_lookup_notif_ver(sc, IWX_DATA_PATH_GROUP,
-	    IWX_TLC_MNG_UPDATE_NOTIF);
-	if (cmd_ver != IWX_FW_CMD_VER_UNKNOWN && cmd_ver >= 3)
-		rate_n_flags_ver2 = 1;
-
-	if (rate_n_flags_ver2) {
-		uint32_t mod_type = (rate_n_flags & IWX_RATE_MCS_MOD_TYPE_MSK);
-		if (mod_type == IWX_RATE_MCS_HT_MSK) {
-
-			ieee80211_node_set_txrate_dot11rate(ni,
-				IWX_RATE_HT_MCS_INDEX(rate_n_flags) |
-				IEEE80211_RATE_MCS);
-			IWX_DPRINTF(sc, IWX_DEBUG_TXRATE,
-			    "%s:%d new MCS: %d rate_n_flags: %x\n",
-			    __func__, __LINE__,
-			    ieee80211_node_get_txrate_dot11rate(ni) & ~IEEE80211_RATE_MCS,
-			    rate_n_flags);
-			return;
-		}
-	} else {
-		if (rate_n_flags & IWX_RATE_MCS_HT_MSK_V1) {
-			ieee80211_node_set_txrate_dot11rate(ni,
-			    rate_n_flags & (IWX_RATE_HT_MCS_RATE_CODE_MSK_V1 |
-			    IWX_RATE_HT_MCS_NSS_MSK_V1));
-
-			IWX_DPRINTF(sc, IWX_DEBUG_TXRATE,
-			    "%s:%d new MCS idx: %d rate_n_flags: %x\n",
-			    __func__, __LINE__,
-			    ieee80211_node_get_txrate_dot11rate(ni), rate_n_flags);
-			return;
-		}
+	type = (rate_n_flags & IWX_RATE_MCS_MOD_TYPE_MSK);
+	switch (type) {
+	case IWX_RATE_MCS_CCK_MSK:
+		ieee80211_node_set_txrate_dot11rate(ni,
+		    cck_idx_to_rate[rate_n_flags & IWX_RATE_LEGACY_RATE_MSK]);
+		return (true);
+	case IWX_RATE_MCS_LEGACY_OFDM_MSK:
+		ieee80211_node_set_txrate_dot11rate(ni,
+		    ofdm_idx_to_rate[rate_n_flags & IWX_RATE_LEGACY_RATE_MSK]);
+		return (true);
+	case IWX_RATE_MCS_HT_MSK:
+		/*
+		 * TODO: the current API doesn't include channel width
+		 * and other flags, so we can't accurately store them yet!
+		 *
+		 * channel width: (flags & IWX_RATE_MCS_CHAN_WIDTH_MSK)
+		 *    >> IWX_RATE_MCS_CHAN_WIDTH_POS)
+		 * LDPC: (flags & (1 << 16))
+		 */
+		ieee80211_node_set_txrate_ht_mcsrate(ni,
+		    IWX_RATE_HT_MCS_INDEX(rate_n_flags));
+		return (true);
+	case IWX_RATE_MCS_VHT_MSK:
+		/* TODO: same comment on channel width, etc above */
+		ieee80211_node_set_txrate_vht_rate(ni,
+		    IWX_RATE_VHT_MCS_CODE(rate_n_flags),
+		    IWX_RATE_VHT_MCS_NSS(rate_n_flags));
+		return (true);
+	default:
+		net80211_ic_printf(ic,
+		    "%s: unsupported chosen rate type in "
+		    "IWX_RATE_MCS_MOD_TYPE (%d)\n", __func__,
+		    type >> IWX_RATE_MCS_MOD_TYPE_POS);
+		return (false);
 	}
 
-	if (rate_n_flags_ver2) {
-		const struct ieee80211_rateset *rs;
-		uint32_t ridx = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK);
-		if (rate_n_flags & IWX_RATE_MCS_LEGACY_OFDM_MSK)
-			rs = &ieee80211_std_rateset_11a;
-		else
-			rs = &ieee80211_std_rateset_11b;
-		if (ridx < rs->rs_nrates)
-			rval = (rs->rs_rates[ridx] & IEEE80211_RATE_VAL);
-		else
-			rval = 0;
-	} else {
-		plcp = (rate_n_flags & IWX_RATE_LEGACY_RATE_MSK_V1);
+	/* Default: if we get here, we didn't successfully update anything */
+	return (false);
+}
 
-		rval = 0;
-		for (i = IWX_RATE_1M_INDEX; i < nitems(iwx_rates); i++) {
-			if (iwx_rates[i].plcp == plcp) {
-				rval = iwx_rates[i].rate;
-				break;
-			}
-		}
-	}
+/**
+ * @brief Process a firmware rate control update and update net80211.
+ *
+ * Since firmware is doing rate control, this just needs to update
+ * the txrate in the ieee80211_node entry.
+ */
+static void
+iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif)
+{
+	struct ieee80211com *ic = &sc->sc_ic;
+	struct ieee80211vap *vap = TAILQ_FIRST(&ic->ic_vaps);
+	/* XXX TODO: get a node ref! */
+	struct ieee80211_node *ni = (void *)vap->iv_bss;
 
-	if (rval) {
-		uint8_t rv;
-		for (i = 0; i < rs->rs_nrates; i++) {
-			rv = rs->rs_rates[i] & IEEE80211_RATE_VAL;
-			if (rv == rval) {
-				ieee80211_node_set_txrate_dot11rate(ni, i);
-				break;
-			}
-		}
-		IWX_DPRINTF(sc, IWX_DEBUG_TXRATE,
-		    "%s:%d new rate %d\n", __func__, __LINE__,
-		    ieee80211_node_get_txrate_dot11rate(ni));
-	}
+	/*
+	 * For now the iwx driver only supports a single vdev with a single
+	 * node; it doesn't yet support ibss/hostap/multiple vdevs.
+	 */
+	if (notif->sta_id != IWX_STATION_ID ||
+	    (le32toh(notif->flags) & IWX_TLC_NOTIF_FLAG_RATE) == 0)
+		return;
+
+	iwx_rs_update_node_txrate(sc, notif, ni);
 }
 
 static int
diff --git a/sys/dev/iwx/if_iwxreg.h b/sys/dev/iwx/if_iwxreg.h
index 6755b93fa0ba..f3d1f078b48e 100644
--- a/sys/dev/iwx/if_iwxreg.h
+++ b/sys/dev/iwx/if_iwxreg.h
@@ -5176,6 +5176,10 @@ enum {
 #define IWX_RATE_HT_MCS_INDEX(r)	((((r) & IWX_RATE_MCS_NSS_MSK) >> 1) | \
 					 ((r) & IWX_RATE_HT_MCS_CODE_MSK))
 
+#define IWX_RATE_VHT_MCS_CODE(r)	((r) & IWX_RATE_HT_MCS_CODE_MSK)
+#define IWX_RATE_VHT_MCS_NSS(r)		\
+	    ((((r) & IWX_RATE_MCS_NSS_MSK) == 0) >> IWX_RATE_MCS_NSS_POS)
+
 /* Bits 7-5: reserved */
 
 /*



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