From: Mark Kettenis Subject: Re: fix fatal firmware error when forcing iwx to 11a/b/g mode To: Stefan Sperling Cc: tech@openbsd.org Date: Mon, 09 Mar 2026 22:31:41 +0100 > Date: Mon, 9 Mar 2026 13:49:59 +0100 > From: Stefan Sperling > > Forcing iwx(4) into 11a/b/g mode produces a fatal firmware error with > BZ firmware, and possibly other firmware, too. This also happens when > I try to disable mimo with "ifconfig iwx0 nwflag nomimo". > > The driver does not take limitations of 11a/b/g modes into account while > initializing Tx rate selection, which triggers some sanity checks in the > firmware. The patch below fixes this. > > ok? Lightly tested on MA. Seems forcing it into 11a without the diff doesn't produce a fatal firmware error. With or without your diff. Diff doesn't look unreasonable to me, but I fear it goes beyond my understanding of ieee802.11. > M sys/dev/pci/if_iwx.c | 24+ 10- > > 1 file changed, 24 insertions(+), 10 deletions(-) > > path + /usr/src > commit - bf3713f7dfbf19ede85da952a0d01b849aa8a252 > blob - e731cf032ef66ed7a7eab46a3669fc5d80d9e8d3 > file + sys/dev/pci/if_iwx.c > --- sys/dev/pci/if_iwx.c > +++ sys/dev/pci/if_iwx.c > @@ -8483,18 +8483,25 @@ iwx_rs_init_v3(struct iwx_softc *sc, struct iwx_node * > cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT; > > cfg_cmd.sta_id = IWX_STATION_ID; > - if (in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) > + 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 (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA || > - in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB) > + else if ((ni->ni_flags & IEEE80211_NODE_HT) && > + (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA || > + in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)) > cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_40MHZ; > else > cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_20MHZ; > - cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK; > + if ((ni->ni_flags & IEEE80211_NODE_HT) && iwx_mimo_enabled(sc)) > + cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK; > + else > + cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK; > if (ni->ni_flags & IEEE80211_NODE_VHT) > cfg_cmd.max_mpdu_len = htole16(3895); > - else > + else if (ni->ni_flags & IEEE80211_NODE_HT) > cfg_cmd.max_mpdu_len = htole16(3839); > + else > + cfg_cmd.max_mpdu_len = IEEE80211_MAX_LEN; > if (ni->ni_flags & IEEE80211_NODE_HT) { > if (ieee80211_node_supports_ht_sgi20(ni)) { > cfg_cmd.sgi_ch_width_supp |= (1 << > @@ -8551,18 +8558,25 @@ iwx_rs_init_v4(struct iwx_softc *sc, struct iwx_node * > cfg_cmd.mode = IWX_TLC_MNG_MODE_NON_HT; > > cfg_cmd.sta_id = IWX_STATION_ID; > - if (in->in_phyctxt->vht_chan_width == IEEE80211_VHTOP0_CHAN_WIDTH_80) > + 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 (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA || > - in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB) > + else if ((ni->ni_flags & IEEE80211_NODE_HT) && > + (in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCA || > + in->in_phyctxt->sco == IEEE80211_HTOP0_SCO_SCB)) > cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_40MHZ; > else > cfg_cmd.max_ch_width = IWX_TLC_MNG_CH_WIDTH_20MHZ; > - cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK; > + if ((ni->ni_flags & IEEE80211_NODE_HT) && iwx_mimo_enabled(sc)) > + cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK | IWX_TLC_MNG_CHAIN_B_MSK; > + else > + cfg_cmd.chains = IWX_TLC_MNG_CHAIN_A_MSK; > if (ni->ni_flags & IEEE80211_NODE_VHT) > cfg_cmd.max_mpdu_len = htole16(3895); > - else > + else if (ni->ni_flags & IEEE80211_NODE_HT) > cfg_cmd.max_mpdu_len = htole16(3839); > + else > + cfg_cmd.max_mpdu_len = IEEE80211_MAX_LEN; > if (ni->ni_flags & IEEE80211_NODE_HT) { > if (ieee80211_node_supports_ht_sgi20(ni)) { > cfg_cmd.sgi_ch_width_supp |= (1 << > >