diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2021-07-18 11:40:32 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2021-07-18 11:40:32 +0000 |
commit | 6f5cf0c305cf76a2e2d713ddaf8d928ff76154bd (patch) | |
tree | f84a6e6f23bb78092e69e23c8114154cc8758d8d /sys/dev | |
parent | 32d95a578d7b819245fe560ffdae3252854a5535 (diff) |
Fix iwx(4) PHY context updates for newer firmware versions.
Firmware which advertises the BINDING_CDB_SUPPORT capability
needs a remove+add dance when the channel band has changed.
See Linux commit 730a18912bcbde0b94ae7f1b554a9908b3424a22
and Linux commit 91109f42d0ad0c0c282d1fa1257a1548977aa895
The same fix was applied to iwm(4) in CVS commit uQ0WjqRUp03vxHg1
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_iwx.c | 85 |
1 files changed, 67 insertions, 18 deletions
diff --git a/sys/dev/pci/if_iwx.c b/sys/dev/pci/if_iwx.c index 73cf9b892c9..406042ab42f 100644 --- a/sys/dev/pci/if_iwx.c +++ b/sys/dev/pci/if_iwx.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwx.c,v 1.63 2021/07/06 15:53:33 stsp Exp $ */ +/* $OpenBSD: if_iwx.c,v 1.64 2021/07/18 11:40:31 stsp Exp $ */ /* * Copyright (c) 2014, 2016 genua gmbh <info@genua.de> @@ -407,6 +407,8 @@ int iwx_rs_rval2idx(uint8_t); uint16_t iwx_rs_ht_rates(struct iwx_softc *, struct ieee80211_node *, int); int iwx_rs_init(struct iwx_softc *, struct iwx_node *); int iwx_enable_data_tx_queues(struct iwx_softc *); +int iwx_phy_ctxt_update(struct iwx_softc *, struct iwx_phy_ctxt *, + struct ieee80211_channel *, uint8_t, uint8_t, uint32_t); int iwx_auth(struct iwx_softc *); int iwx_deauth(struct iwx_softc *); int iwx_assoc(struct iwx_softc *); @@ -6319,6 +6321,47 @@ iwx_rs_update(struct iwx_softc *sc, struct iwx_tlc_update_notif *notif) } int +iwx_phy_ctxt_update(struct iwx_softc *sc, struct iwx_phy_ctxt *phyctxt, + struct ieee80211_channel *chan, uint8_t chains_static, + uint8_t chains_dynamic, uint32_t apply_time) +{ + uint16_t band_flags = (IEEE80211_CHAN_2GHZ | IEEE80211_CHAN_5GHZ); + int err; + + if (isset(sc->sc_enabled_capa, + IWX_UCODE_TLV_CAPA_BINDING_CDB_SUPPORT) && + (phyctxt->channel->ic_flags & band_flags) != + (chan->ic_flags & band_flags)) { + err = iwx_phy_ctxt_cmd(sc, phyctxt, chains_static, + chains_dynamic, IWX_FW_CTXT_ACTION_REMOVE, apply_time); + if (err) { + printf("%s: could not remove PHY context " + "(error %d)\n", DEVNAME(sc), err); + return err; + } + phyctxt->channel = chan; + err = iwx_phy_ctxt_cmd(sc, phyctxt, chains_static, + chains_dynamic, IWX_FW_CTXT_ACTION_ADD, apply_time); + if (err) { + printf("%s: could not remove PHY context " + "(error %d)\n", DEVNAME(sc), err); + return err; + } + } else { + phyctxt->channel = chan; + err = iwx_phy_ctxt_cmd(sc, phyctxt, chains_static, + chains_dynamic, IWX_FW_CTXT_ACTION_MODIFY, apply_time); + if (err) { + printf("%s: could not update PHY context (error %d)\n", + DEVNAME(sc), err); + return err; + } + } + + return 0; +} + +int iwx_auth(struct iwx_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; @@ -6328,16 +6371,16 @@ iwx_auth(struct iwx_softc *sc) splassert(IPL_NET); - if (ic->ic_opmode == IEEE80211_M_MONITOR) - sc->sc_phyctxt[0].channel = ic->ic_ibss_chan; - else - sc->sc_phyctxt[0].channel = in->in_ni.ni_chan; - err = iwx_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0], 1, 1, - IWX_FW_CTXT_ACTION_MODIFY, 0); - if (err) { - printf("%s: could not update PHY context (error %d)\n", - DEVNAME(sc), err); - return err; + if (ic->ic_opmode == IEEE80211_M_MONITOR) { + err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], + ic->ic_ibss_chan, 1, 1, 0); + if (err) + return err; + } else { + err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], + in->in_ni.ni_chan, 1, 1, 0); + if (err) + return err; } in->in_phyctxt = &sc->sc_phyctxt[0]; @@ -6461,6 +6504,12 @@ iwx_deauth(struct iwx_softc *sc) sc->sc_flags &= ~IWX_FLAG_MAC_ACTIVE; } + /* Move unused PHY context to a default channel. */ + err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], + &ic->ic_channels[1], 1, 1, 0); + if (err) + return err; + return 0; } @@ -6535,11 +6584,10 @@ iwx_run(struct iwx_softc *sc) if ((ic->ic_opmode == IEEE80211_M_MONITOR || (in->in_ni.ni_flags & IEEE80211_NODE_HT)) && iwx_mimo_enabled(sc)) { - err = iwx_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0], - 2, 2, IWX_FW_CTXT_ACTION_MODIFY, 0); + err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], + in->in_ni.ni_chan, 2, 2, 0); if (err) { - printf("%s: failed to update PHY\n", - DEVNAME(sc)); + printf("%s: failed to update PHY\n", DEVNAME(sc)); return err; } } @@ -6655,8 +6703,8 @@ iwx_run_stop(struct iwx_softc *sc) /* Reset Tx chains in case MIMO was enabled. */ if ((in->in_ni.ni_flags & IEEE80211_NODE_HT) && iwx_mimo_enabled(sc)) { - err = iwx_phy_ctxt_cmd(sc, &sc->sc_phyctxt[0], 1, 1, - IWX_FW_CTXT_ACTION_MODIFY, 0); + err = iwx_phy_ctxt_update(sc, &sc->sc_phyctxt[0], + in->in_ni.ni_chan, 1, 1, 0); if (err) { printf("%s: failed to update PHY\n", DEVNAME(sc)); return err; @@ -7312,12 +7360,13 @@ iwx_init_hw(struct iwx_softc *sc) goto err; } - for (i = 0; i < 1; i++) { + for (i = 0; i < IWX_NUM_PHY_CTX; i++) { /* * The channel used here isn't relevant as it's * going to be overwritten in the other flows. * For now use the first channel we have. */ + sc->sc_phyctxt[i].id = i; sc->sc_phyctxt[i].channel = &ic->ic_channels[1]; err = iwx_phy_ctxt_cmd(sc, &sc->sc_phyctxt[i], 1, 1, IWX_FW_CTXT_ACTION_ADD, 0); |