Index | Thread | Search

From:
Kirill A. Korinsky <kirill@korins.ky>
Subject:
sys/qwz: add 802.11n with 40Mhz width
To:
OpenBSD tech <tech@openbsd.org>
Date:
Mon, 25 May 2026 23:39:18 +0200

Download raw body.

Thread
tech@,

here support of 40Mhz width for qwz at 802.11n, tested against Unifi
with 2.4Ghz and 5Ghz, and AP reports RX and TX as 300 Mbps.

30 seconds iperf shows ~140 Mbits/sec and with -R ~171 Mbits/sec.

I don't like +/- 10 for channel center, but better apporach is helper in
net80211 which I plan to add as the next step with 11ac and 80Mhz width.

Ok?

Index: sys/dev/ic/qwz.c
===================================================================
RCS file: /home/cvs/src/sys/dev/ic/qwz.c,v
diff -u -p -r1.36 qwz.c
--- sys/dev/ic/qwz.c	25 May 2026 20:33:58 -0000	1.36
+++ sys/dev/ic/qwz.c	25 May 2026 21:27:51 -0000
@@ -10874,6 +10874,7 @@ qwz_init_channels_world(struct qwz_softc
 			    IEEE80211_CHAN_OFDM |
 			    IEEE80211_CHAN_DYN |
 			    IEEE80211_CHAN_2GHZ |
+			    IEEE80211_CHAN_40MHZ |
 			    IEEE80211_CHAN_HT;
 		}
 	}
@@ -10884,6 +10885,7 @@ qwz_init_channels_world(struct qwz_softc
 			chan->ic_freq = ieee80211_ieee2mhz(channels_5ghz[i],
 			    IEEE80211_CHAN_5GHZ);
 			chan->ic_flags = IEEE80211_CHAN_A |
+			    IEEE80211_CHAN_40MHZ |
 			    IEEE80211_CHAN_HT |
 			    IEEE80211_CHAN_PASSIVE;
 		}
@@ -10931,6 +10933,9 @@ qwz_init_channels(struct qwz_softc *sc, 
 				    IEEE80211_CHAN_DYN |
 				    IEEE80211_CHAN_2GHZ |
 				    IEEE80211_CHAN_HT;
+				if ((rule->flags & REGULATORY_CHAN_NO_HT40) == 0)
+					chan->ic_flags |=
+					    IEEE80211_CHAN_40MHZ;
 			}
 			chnum++;
 			freq = ieee80211_ieee2mhz(chnum, IEEE80211_CHAN_2GHZ);
@@ -10966,6 +10971,9 @@ qwz_init_channels(struct qwz_softc *sc, 
 				chan->ic_freq = freq;
 				chan->ic_flags = IEEE80211_CHAN_A |
 				    IEEE80211_CHAN_HT;
+				if ((rule->flags & REGULATORY_CHAN_NO_HT40) == 0)
+					chan->ic_flags |=
+					    IEEE80211_CHAN_40MHZ;
 				if (rule->flags & (REGULATORY_CHAN_RADAR |
 				    REGULATORY_CHAN_NO_IR |
 				    REGULATORY_CHAN_INDOOR_ONLY)) {
@@ -21614,6 +21622,7 @@ qwz_mac_vdev_start_restart(struct qwz_so
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ieee80211_channel *chan = ic->ic_bss->ni_chan;
 	struct wmi_vdev_start_req_arg arg = {};
+	uint8_t sco = IEEE80211_HTOP0_SCO_SCN;
 	int ret = 0;
 #ifdef notyet
 	lockdep_assert_held(&ar->conf_mutex);
@@ -21629,7 +21638,25 @@ qwz_mac_vdev_start_restart(struct qwz_so
 	arg.channel.band_center_freq1 = chan->ic_freq;
 	arg.channel.band_center_freq2 = chan->ic_freq;
 
-	if (IEEE80211_IS_CHAN_5GHZ(chan))
+	if (ieee80211_node_supports_ht(ic->ic_bss) &&
+	    (chan->ic_flags & IEEE80211_CHAN_HT)) {
+		arg.channel.allow_ht = true;
+		if (IEEE80211_CHAN_40MHZ_ALLOWED(chan) &&
+		    ieee80211_node_supports_ht_chan40(ic->ic_bss))
+			sco = ic->ic_bss->ni_htop0 &
+			    IEEE80211_HTOP0_SCO_MASK;
+		if (sco == IEEE80211_HTOP0_SCO_SCA) {
+			arg.channel.band_center_freq1 = chan->ic_freq + 10;
+			arg.channel.mode = IEEE80211_IS_CHAN_5GHZ(chan) ?
+			    MODE_11NA_HT40 : MODE_11NG_HT40;
+		} else if (sco == IEEE80211_HTOP0_SCO_SCB) {
+			arg.channel.band_center_freq1 = chan->ic_freq - 10;
+			arg.channel.mode = IEEE80211_IS_CHAN_5GHZ(chan) ?
+			    MODE_11NA_HT40 : MODE_11NG_HT40;
+		} else
+			arg.channel.mode = IEEE80211_IS_CHAN_5GHZ(chan) ?
+			    MODE_11NA_HT20 : MODE_11NG_HT20;
+	} else if (IEEE80211_IS_CHAN_5GHZ(chan))
 		arg.channel.mode = MODE_11A;
 	else if (ic->ic_bss->ni_flags & IEEE80211_NODE_ERP)
 		arg.channel.mode = MODE_11G;
@@ -24271,6 +24298,7 @@ qwz_peer_assoc_h_phymode(struct qwz_soft
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	enum wmi_phy_mode phymode;
+	uint8_t sco;
 
 	switch (ic->ic_curmode) {
 	case IEEE80211_MODE_11A:
@@ -24283,10 +24311,17 @@ qwz_peer_assoc_h_phymode(struct qwz_soft
 		phymode = MODE_11G;
 		break;
 	case IEEE80211_MODE_11N:
-		if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan))
-			phymode = MODE_11NA_HT20;
+		sco = IEEE80211_HTOP0_SCO_SCN;
+		if (IEEE80211_CHAN_40MHZ_ALLOWED(ni->ni_chan) &&
+		    ieee80211_node_supports_ht_chan40(ni))
+			sco = ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK;
+		if (sco == IEEE80211_HTOP0_SCO_SCA ||
+		    sco == IEEE80211_HTOP0_SCO_SCB)
+			phymode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ?
+			    MODE_11NA_HT40 : MODE_11NG_HT40;
 		else
-			phymode = MODE_11NG_HT20;
+			phymode = IEEE80211_IS_CHAN_5GHZ(ni->ni_chan) ?
+			    MODE_11NA_HT20 : MODE_11NG_HT20;
 		break;
 	default:
 		phymode = MODE_UNKNOWN;
@@ -24328,7 +24363,7 @@ qwz_peer_assoc_h_ht(struct qwz_softc *sc
 {
 	struct ieee80211com *ic = &sc->sc_ic;
 	int i, n;
-	uint8_t max_nss;
+	uint8_t max_nss, sco;
 	uint32_t stbc, aggsize, mpdu_density;
 #ifdef notyet
 	lockdep_assert_held(&ar->conf_mutex);
@@ -24336,6 +24371,11 @@ qwz_peer_assoc_h_ht(struct qwz_softc *sc
 	if ((ni->ni_flags & IEEE80211_NODE_HT) == 0)
 		return;
 
+	sco = IEEE80211_HTOP0_SCO_SCN;
+	if (IEEE80211_CHAN_40MHZ_ALLOWED(ni->ni_chan) &&
+	    ieee80211_node_supports_ht_chan40(ni))
+		sco = ni->ni_htop0 & IEEE80211_HTOP0_SCO_MASK;
+
 	arg->ht_flag = true;
 
 	aggsize = (ni->ni_ampdu_param & IEEE80211_AMPDU_PARAM_LE);
@@ -24349,12 +24389,11 @@ qwz_peer_assoc_h_ht(struct qwz_softc *sc
 
 	if (ni->ni_htcaps & IEEE80211_HTCAP_LDPC)
 		arg->ldpc_flag = true;
-#if 0
-	if (sta->deflink.bandwidth >= IEEE80211_STA_RX_BW_40) {
+	if (sco == IEEE80211_HTOP0_SCO_SCA ||
+	    sco == IEEE80211_HTOP0_SCO_SCB) {
 		arg->bw_40 = true;
 		arg->peer_rate_caps |= WMI_HOST_RC_CW40_FLAG;
 	}
-#endif
 	if (ieee80211_node_supports_ht_sgi20(ni) ||
 	    ieee80211_node_supports_ht_sgi40(ni))
 		arg->peer_rate_caps |= WMI_HOST_RC_SGI_FLAG;
Index: sys/dev/ic/qwzreg.h
===================================================================
RCS file: /home/cvs/src/sys/dev/ic/qwzreg.h,v
diff -u -p -r1.15 qwzreg.h
--- sys/dev/ic/qwzreg.h	18 May 2026 13:47:32 -0000	1.15
+++ sys/dev/ic/qwzreg.h	25 May 2026 20:54:14 -0000
@@ -13252,6 +13252,7 @@ struct htt_rx_full_monitor_mode_cfg_cmd 
 } __packed;
 
 #define WMI_HOST_RC_DS_FLAG			0x01
+#define WMI_HOST_RC_CW40_FLAG			0x02
 #define WMI_HOST_RC_SGI_FLAG			0x04
 #define WMI_HOST_RC_HT_FLAG			0x08
 #define WMI_HOST_RC_TX_STBC_FLAG		0x20
Index: sys/dev/pci/if_qwz_pci.c
===================================================================
RCS file: /home/cvs/src/sys/dev/pci/if_qwz_pci.c,v
diff -u -p -r1.11 if_qwz_pci.c
--- sys/dev/pci/if_qwz_pci.c	18 May 2026 13:47:32 -0000	1.11
+++ sys/dev/pci/if_qwz_pci.c	25 May 2026 20:54:14 -0000
@@ -969,13 +969,14 @@ qwz_pci_attach(struct device *parent, st
 	ic->ic_sup_rates[IEEE80211_MODE_11B] = ieee80211_std_rateset_11b;
 	ic->ic_sup_rates[IEEE80211_MODE_11G] = ieee80211_std_rateset_11g;
 
-	ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_AMSDU7935;
-	ic->ic_htcaps |=
+	ic->ic_htcaps = IEEE80211_HTCAP_SGI20 | IEEE80211_HTCAP_SGI40 |
+	    IEEE80211_HTCAP_CBW20_40 | IEEE80211_HTCAP_AMSDU7935 |
 	    (IEEE80211_HTCAP_SMPS_DIS << IEEE80211_HTCAP_SMPS_SHIFT);
 	ic->ic_htxcaps = 0;
 	ic->ic_txbfcaps = 0;
 	ic->ic_aselcaps = 0;
 	ic->ic_ampdu_params = (IEEE80211_AMPDU_PARAM_SS_NONE | 0x3 /* 64k */);
+	ic->ic_tx_mcs_set = IEEE80211_TX_MCS_SET_DEFINED;
 
 	memset(ic->ic_sup_mcs, 0, sizeof(ic->ic_sup_mcs));
 	ic->ic_sup_mcs[0] = 0xff;		/* MCS 0-7 */



-- 
wbr, Kirill