Index | Thread | Search

From:
Peter Hessler <phessler@theapt.org>
Subject:
Re: sys/iwx: support of 160Mhz window at 5Ghz
To:
tech@openbsd.org
Date:
Sun, 22 Mar 2026 14:49:50 +0100

Download raw body.

Thread
On 2026 Mar 21 (Sat) at 03:06:50 +0100 (+0100), Kirill A. Korinsky wrote:
:tech@,
:
:here a trivial diff which brings supports of 160Mhz windows.
:
:Tested with 80Mhz and 160Mhz windows on
:
:iwx0 at pci0 dev 20 function 3 "Intel Wi-Fi 6 AX201" rev 0x00, msix
:iwx0: hw rev 0x350, fw 77.30b1cbd8.0, address 98:8d:46:21:2b:6d
:
:with unifi nano AP with enabled roaming with firmware 6.7.41.15623
:
:Ok?
:

My AP is only using 40MHz windows, but it reads fine to me.

tested on AX211.

OK


:
:Index: sys/dev/pci/if_iwx.c
:===================================================================
:RCS file: /home/cvs/src/sys/dev/pci/if_iwx.c,v
:diff -u -p -r1.223 if_iwx.c
:--- sys/dev/pci/if_iwx.c	14 Mar 2026 15:37:44 -0000	1.223
:+++ sys/dev/pci/if_iwx.c	20 Mar 2026 23:32:57 -0000
:@@ -3207,6 +3207,8 @@ iwx_init_channel_map(struct iwx_softc *s
: 			    IEEE80211_CHAN_A;
: 		}
: 		channel->ic_freq = ieee80211_ieee2mhz(hw_value, flags);
:+		channel->ic_xflags &= ~(IEEE80211_CHANX_80MHZ |
:+		    IEEE80211_CHANX_160MHZ);
: 
: 		if (!(ch_flags & IWX_NVM_CHANNEL_ACTIVE))
: 			channel->ic_flags |= IEEE80211_CHAN_PASSIVE;
:@@ -3221,6 +3223,8 @@ iwx_init_channel_map(struct iwx_softc *s
: 			channel->ic_flags |= IEEE80211_CHAN_VHT;
: 			if (ch_flags & IWX_NVM_CHANNEL_80MHZ)
: 				channel->ic_xflags |= IEEE80211_CHANX_80MHZ;
:+			if (ch_flags & IWX_NVM_CHANNEL_160MHZ)
:+				channel->ic_xflags |= IEEE80211_CHANX_160MHZ;
: 		}
: 	}
: }
:@@ -3620,6 +3624,10 @@ iwx_phy_ctxt_task(void *arg)
: 	else
: 		sco = IEEE80211_HTOP0_SCO_SCN;
: 	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
:+	    IEEE80211_CHAN_160MHZ_ALLOWED(in->in_ni.ni_chan) &&
:+	    ieee80211_node_supports_vht_chan160(ni))
:+		vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_160;
:+	else if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
: 	    IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) &&
: 	    ieee80211_node_supports_vht_chan80(ni))
: 		vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80;
:@@ -5573,6 +5581,12 @@ iwx_get_vht_ctrl_pos(struct ieee80211com
: 	uint8_t pos = IWX_PHY_VHT_CTRL_POS_1_BELOW;
: 
: 	switch (primary_idx - center_idx) {
:+	case -14:
:+		pos = IWX_PHY_VHT_CTRL_POS_4_BELOW;
:+		break;
:+	case -10:
:+		pos = IWX_PHY_VHT_CTRL_POS_3_BELOW;
:+		break;
: 	case -6:
: 		pos = IWX_PHY_VHT_CTRL_POS_2_BELOW;
: 		break;
:@@ -5585,6 +5599,12 @@ iwx_get_vht_ctrl_pos(struct ieee80211com
: 	case 6:
: 		pos = IWX_PHY_VHT_CTRL_POS_2_ABOVE;
: 		break;
:+	case 10:
:+		pos = IWX_PHY_VHT_CTRL_POS_3_ABOVE;
:+		break;
:+	case 14:
:+		pos = IWX_PHY_VHT_CTRL_POS_4_ABOVE;
:+		break;
: 	default:
: 		break;
: 	}
:@@ -5616,7 +5636,10 @@ iwx_phy_ctxt_cmd_uhb_v3_v4(struct iwx_so
: 	cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
: 	    IWX_PHY_BAND_24 : IWX_PHY_BAND_5;
: 	cmd.ci.channel = htole32(ieee80211_chan2ieee(ic, chan));
:-	if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) {
:+	if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160) {
:+		cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan);
:+		cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE160;
:+	} else if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) {
: 		cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan);
: 		cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE80;
: 	} else if (chan->ic_flags & IEEE80211_CHAN_40MHZ) {
:@@ -5676,7 +5699,10 @@ iwx_phy_ctxt_cmd_v3_v4(struct iwx_softc 
: 	cmd.ci.band = IEEE80211_IS_CHAN_2GHZ(chan) ?
: 	    IWX_PHY_BAND_24 : IWX_PHY_BAND_5;
: 	cmd.ci.channel = ieee80211_chan2ieee(ic, chan);
:-	if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) {
:+	if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160) {
:+		cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan);
:+		cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE160;
:+	} else if (vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) {
: 		cmd.ci.ctrl_pos = iwx_get_vht_ctrl_pos(ic, chan);
: 		cmd.ci.width = IWX_PHY_VHT_CHANNEL_MODE80;
: 	} else if (chan->ic_flags & IEEE80211_CHAN_40MHZ) {
:@@ -6731,7 +6757,11 @@ iwx_add_sta_cmd(struct iwx_softc *sc, st
: 		}
: 
: 		if (in->in_ni.ni_flags & IEEE80211_NODE_VHT) {
:-			if (IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) &&
:+			if (IEEE80211_CHAN_160MHZ_ALLOWED(in->in_ni.ni_chan) &&
:+			    ieee80211_node_supports_vht_chan160(&in->in_ni)) {
:+				add_sta_cmd.station_flags |= htole32(
:+				    IWX_STA_FLG_FAT_EN_160MHZ);
:+			} else if (IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) &&
: 			    ieee80211_node_supports_vht_chan80(&in->in_ni)) {
: 				add_sta_cmd.station_flags |= htole32(
: 				    IWX_STA_FLG_FAT_EN_80MHZ);
:@@ -8433,6 +8463,13 @@ iwx_rs_init_v3(struct iwx_softc *sc, str
: 		    htole16(iwx_rs_vht_rates(sc, ni, 1));
: 		cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
: 		    htole16(iwx_rs_vht_rates(sc, ni, 2));
:+		if (in->in_phyctxt->vht_chan_width ==
:+		    IEEE80211_VHTOP0_CHAN_WIDTH_160) {
:+			cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_160] =
:+			    cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80];
:+			cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_160] =
:+			    cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80];
:+		}
: 	} else if (ni->ni_flags & IEEE80211_NODE_HT) {
: 		cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
: 		cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
:@@ -8446,6 +8483,9 @@ iwx_rs_init_v3(struct iwx_softc *sc, str
: 
: 	cfg_cmd.sta_id = IWX_STATION_ID;
: 	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
:+	    in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160)
:+		cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_160MHZ;
:+	else if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
: 	    in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80)
: 		cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ;
: 	else if ((ni->ni_flags & IEEE80211_NODE_HT) &&
:@@ -8477,6 +8517,10 @@ iwx_rs_init_v3(struct iwx_softc *sc, str
: 	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
: 	    ieee80211_node_supports_vht_sgi80(ni))
: 		cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ);
:+	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
:+	    in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160 &&
:+	    ieee80211_node_supports_vht_sgi160(ni))
:+		cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_160MHZ);
: 
: 	cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0);
: 	return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
:@@ -8508,6 +8552,13 @@ iwx_rs_init_v4(struct iwx_softc *sc, str
: 		    htole16(iwx_rs_vht_rates(sc, ni, 1));
: 		cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80] =
: 		    htole16(iwx_rs_vht_rates(sc, ni, 2));
:+		if (in->in_phyctxt->vht_chan_width ==
:+		    IEEE80211_VHTOP0_CHAN_WIDTH_160) {
:+			cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_160] =
:+			    cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80];
:+			cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_160] =
:+			    cfg_cmd.ht_rates[IWX_TLC_NSS_2][IWX_TLC_MCS_PER_BW_80];
:+		}
: 	} else if (ni->ni_flags & IEEE80211_NODE_HT) {
: 		cfg_cmd.mode = IWX_TLC_MNG_MODE_HT;
: 		cfg_cmd.ht_rates[IWX_TLC_NSS_1][IWX_TLC_MCS_PER_BW_80] =
:@@ -8521,6 +8572,9 @@ iwx_rs_init_v4(struct iwx_softc *sc, str
: 
: 	cfg_cmd.sta_id = IWX_STATION_ID;
: 	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
:+	    in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160)
:+		cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_160MHZ;
:+	else if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
: 	    in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80)
: 		cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_80MHZ;
: 	else if ((ni->ni_flags & IEEE80211_NODE_HT) &&
:@@ -8552,6 +8606,10 @@ iwx_rs_init_v4(struct iwx_softc *sc, str
: 	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
: 	    ieee80211_node_supports_vht_sgi80(ni))
: 		cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_80MHZ);
:+	if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
:+	    in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_160 &&
:+	    ieee80211_node_supports_vht_sgi160(ni))
:+		cfg_cmd.sgi_ch_width_supp |= (1 << IWX_TLC_MNG_CH_WIDTH_160MHZ);
: 
: 	cmd_id = iwx_cmd_id(IWX_TLC_MNG_CONFIG_CMD, IWX_DATA_PATH_GROUP, 0);
: 	return iwx_send_cmd_pdu(sc, cmd_id, IWX_CMD_ASYNC, cmd_size, &cfg_cmd);
:@@ -8936,6 +8994,10 @@ iwx_run(struct iwx_softc *sc)
: 		else
: 			sco = IEEE80211_HTOP0_SCO_SCN;
: 		if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
:+		    IEEE80211_CHAN_160MHZ_ALLOWED(in->in_ni.ni_chan) &&
:+		    ieee80211_node_supports_vht_chan160(ni))
:+			vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_160;
:+		else if ((ni->ni_flags & IEEE80211_NODE_VHT) &&
: 		    IEEE80211_CHAN_80MHZ_ALLOWED(in->in_ni.ni_chan) &&
: 		    ieee80211_node_supports_vht_chan80(ni))
: 			vht_chan_width = IEEE80211_VHTOP0_CHAN_WIDTH_80;
:@@ -12380,8 +12442,9 @@ iwx_attach(struct device *parent, struct
: 	ic->ic_vhtcaps = IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895 |
: 	    (IEEE80211_VHTCAP_MAX_AMPDU_LEN_64K <<
: 	    IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT) |
:-	    (IEEE80211_VHTCAP_CHAN_WIDTH_80 <<
:-	     IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) | IEEE80211_VHTCAP_SGI80 |
:+	    (IEEE80211_VHTCAP_CHAN_WIDTH_160 <<
:+	     IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) |
:+	    IEEE80211_VHTCAP_SGI80 | IEEE80211_VHTCAP_SGI160 |
: 	    IEEE80211_VHTCAP_RX_ANT_PATTERN | IEEE80211_VHTCAP_TX_ANT_PATTERN;
: 
: 	ic->ic_sup_rates[IEEE80211_MODE_11A] = ieee80211_std_rateset_11a;
:
:
:-- 
:wbr, Kirill
:

-- 
That boy's about as sharp as a pound of wet liver
		-- Foghorn Leghorn