diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2021-11-11 13:36:59 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2021-11-11 13:36:59 +0000 |
commit | 4ff4fb9880eb7462587279a478090e9ddaad8cd4 (patch) | |
tree | 7fc35d2bd474bb0154996ce9bd80d17871f665ba /sys/dev/pci/if_iwn.c | |
parent | 6f3d89e355d7698c760a647de44edecc2a2922d4 (diff) |
Fix iwn(4) with 4965 devices.
Our driver was using the wrong data structure for RXON_ASSOC commands on
4965 devices. This resulted in fatal firmware errors during association.
Problem found and fix tested on 4965 by jsg@.
Patch also tested on 6200 by me.
Diffstat (limited to 'sys/dev/pci/if_iwn.c')
-rw-r--r-- | sys/dev/pci/if_iwn.c | 75 |
1 files changed, 58 insertions, 17 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index aff55acd0f1..594ec004b14 100644 --- a/sys/dev/pci/if_iwn.c +++ b/sys/dev/pci/if_iwn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_iwn.c,v 1.250 2021/10/11 09:01:05 stsp Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.251 2021/11/11 13:36:58 stsp Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> @@ -249,7 +249,9 @@ void iwn_delete_key(struct ieee80211com *, struct ieee80211_node *, struct ieee80211_key *); void iwn_updateprot(struct ieee80211com *); void iwn_updateslot(struct ieee80211com *); -void iwn_update_rxon(struct iwn_softc *); +void iwn_update_rxon_restore_power(struct iwn_softc *); +void iwn5000_update_rxon(struct iwn_softc *); +void iwn4965_update_rxon(struct iwn_softc *); int iwn_ampdu_rx_start(struct ieee80211com *, struct ieee80211_node *, uint8_t); void iwn_ampdu_rx_stop(struct ieee80211com *, @@ -585,6 +587,7 @@ iwn4965_attach(struct iwn_softc *sc, pci_product_id_t pid) ops->nic_config = iwn4965_nic_config; ops->reset_sched = iwn4965_reset_sched; ops->update_sched = iwn4965_update_sched; + ops->update_rxon = iwn4965_update_rxon; ops->get_temperature = iwn4965_get_temperature; ops->get_rssi = iwn4965_get_rssi; ops->set_txpower = iwn4965_set_txpower; @@ -624,6 +627,7 @@ iwn5000_attach(struct iwn_softc *sc, pci_product_id_t pid) ops->nic_config = iwn5000_nic_config; ops->reset_sched = iwn5000_reset_sched; ops->update_sched = iwn5000_update_sched; + ops->update_rxon = iwn5000_update_rxon; ops->get_temperature = iwn5000_get_temperature; ops->get_rssi = iwn5000_get_rssi; ops->set_txpower = iwn5000_set_txpower; @@ -5668,7 +5672,7 @@ iwn_updateprot(struct ieee80211com *ic) sc->rxon.flags &= ~htole32(IWN_RXON_HT_PROTMODE(3)); sc->rxon.flags |= htole32(IWN_RXON_HT_PROTMODE(htprot)); - iwn_update_rxon(sc); + sc->ops.update_rxon(sc); } void @@ -5689,13 +5693,37 @@ iwn_updateslot(struct ieee80211com *ic) else sc->rxon.flags &= ~htole32(IWN_RXON_SHPREAMBLE); - iwn_update_rxon(sc); + sc->ops.update_rxon(sc); } + void -iwn_update_rxon(struct iwn_softc *sc) +iwn_update_rxon_restore_power(struct iwn_softc *sc) { struct ieee80211com *ic = &sc->sc_ic; struct iwn_ops *ops = &sc->ops; + int error; + + DELAY(100); + + /* All RXONs wipe the firmware's txpower table. Restore it. */ + error = ops->set_txpower(sc, 1); + if (error != 0) + printf("%s: could not set TX power\n", sc->sc_dev.dv_xname); + + DELAY(100); + + /* Restore power saving level */ + if (ic->ic_flags & IEEE80211_F_PMGTON) + error = iwn_set_pslevel(sc, 0, 3, 1); + else + error = iwn_set_pslevel(sc, 0, 0, 1); + if (error != 0) + printf("%s: could not set PS level\n", sc->sc_dev.dv_xname); +} + +void +iwn5000_update_rxon(struct iwn_softc *sc) +{ struct iwn_rxon_assoc rxon_assoc; int s, error; @@ -5718,22 +5746,35 @@ iwn_update_rxon(struct iwn_softc *sc) if (error != 0) printf("%s: RXON_ASSOC command failed\n", sc->sc_dev.dv_xname); - DELAY(100); + iwn_update_rxon_restore_power(sc); - /* All RXONs wipe the firmware's txpower table. Restore it. */ - error = ops->set_txpower(sc, 1); - if (error != 0) - printf("%s: could not set TX power\n", sc->sc_dev.dv_xname); + splx(s); +} - DELAY(100); +void +iwn4965_update_rxon(struct iwn_softc *sc) +{ + struct iwn4965_rxon_assoc rxon_assoc; + int s, error; - /* Restore power saving level */ - if (ic->ic_flags & IEEE80211_F_PMGTON) - error = iwn_set_pslevel(sc, 0, 3, 1); - else - error = iwn_set_pslevel(sc, 0, 0, 1); + /* Update RXON config. */ + memset(&rxon_assoc, 0, sizeof(rxon_assoc)); + rxon_assoc.flags = sc->rxon.flags; + rxon_assoc.filter = sc->rxon.filter; + rxon_assoc.ofdm_mask = sc->rxon.ofdm_mask; + rxon_assoc.cck_mask = sc->rxon.cck_mask; + rxon_assoc.ht_single_mask = sc->rxon.ht_single_mask; + rxon_assoc.ht_dual_mask = sc->rxon.ht_dual_mask; + rxon_assoc.rxchain = sc->rxon.rxchain; + + s = splnet(); + + error = iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &rxon_assoc, + sizeof(rxon_assoc), 1); if (error != 0) - printf("%s: could not set PS level\n", sc->sc_dev.dv_xname); + printf("%s: RXON_ASSOC command failed\n", sc->sc_dev.dv_xname); + + iwn_update_rxon_restore_power(sc); splx(s); } |