summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_iwn.c
diff options
context:
space:
mode:
authorStefan Sperling <stsp@cvs.openbsd.org>2021-11-11 13:36:59 +0000
committerStefan Sperling <stsp@cvs.openbsd.org>2021-11-11 13:36:59 +0000
commit4ff4fb9880eb7462587279a478090e9ddaad8cd4 (patch)
tree7fc35d2bd474bb0154996ce9bd80d17871f665ba /sys/dev/pci/if_iwn.c
parent6f3d89e355d7698c760a647de44edecc2a2922d4 (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.c75
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);
}