Index | Thread | Search

From:
Kevin Lo <kevlo@kevlo.org>
Subject:
Re: fix fatal firmware error when forcing iwx to 11a/b/g mode
To:
tech@openbsd.org
Date:
Tue, 10 Mar 2026 10:31:24 +0800

Download raw body.

Thread
On Mon, Mar 09, 2026 at 10:31:41PM +0100, Mark Kettenis wrote:
> 
> > Date: Mon, 9 Mar 2026 13:49:59 +0100
> > From: Stefan Sperling <stsp@stsp.name>
> > 
> > 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.

Tested on MA and got the same result.

iwx0 at pci1 dev 0 function 0 "Intel Wi-Fi 6 AX210" rev 0x1a, msix
iwx0: hw rev 0x420, fw 77.f92b5fed.0, pnvm 285b3568, address ac:82:47:xx:xx:xx

> 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 <<
> > 
> > 
>