From: Stefan Sperling Subject: Re: sys/qwz: add 802.11n with 40Mhz width To: tech@openbsd.org Date: Tue, 26 May 2026 15:42:28 +0200 On Tue, May 26, 2026 at 11:50:30AM +0200, Kirill A. Korinsky wrote: > Here clean diff. Ok to commit? ok by me, thanks! > 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 26 May 2026 09:48:40 -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 26 May 2026 09:48:40 -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 26 May 2026 09:48:40 -0000 > @@ -969,8 +969,8 @@ 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; > > > -- > wbr, Kirill > >