diff options
author | Stefan Sperling <stsp@cvs.openbsd.org> | 2016-07-20 10:26:43 +0000 |
---|---|---|
committer | Stefan Sperling <stsp@cvs.openbsd.org> | 2016-07-20 10:26:43 +0000 |
commit | 5cdde35b81298204f0550369ff00d84823ef57ec (patch) | |
tree | 6843af10b2d7fb4bced021f86cb9cdb55c8a940d /sys | |
parent | c694f6b05682e6db4a1ff01aed7b1f50ed8bf7b6 (diff) |
Bring iwn_update_htprot() back, so iwn(4) will properly keep track
of HT protection changes while associated.
HT protection affects behaviour on Tx but is configured along with Rx settings
(because Intel likes it that way). And our previous iwn_update_htprot()
implementation had a bug where it would accidentally clear bits which enable
CCK rates for Rx. The Intel Wireless-N 2200 chip accordingly stopped receiving
some frames (most notably broadcast frames) and the link broke down.
Also, restore the power-saving level after updating the Rx config (like
Linux does), and add some DELAYs for good measure to ensure the firmware
has time to process asynchronous commands we send.
tested by myself and mlarkin@
ok mlarkin@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/pci/if_iwn.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/sys/dev/pci/if_iwn.c b/sys/dev/pci/if_iwn.c index 1c116dab39e..b67304de00b 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.167 2016/06/27 19:01:02 stsp Exp $ */ +/* $OpenBSD: if_iwn.c,v 1.168 2016/07/20 10:26:42 stsp Exp $ */ /*- * Copyright (c) 2007-2010 Damien Bergamini <damien.bergamini@free.fr> @@ -5046,11 +5046,8 @@ iwn_delete_key(struct ieee80211com *ic, struct ieee80211_node *ni, void iwn_update_htprot(struct ieee80211com *ic, struct ieee80211_node *ni) { - /* XXX Disabled for now. It seems to cause output errors - * (tx status=0x83) and to make block ack sessions degrade - * into a half-working state. */ -#if 0 struct iwn_softc *sc = ic->ic_softc; + struct iwn_ops *ops = &sc->ops; enum ieee80211_htprot htprot; struct iwn_rxon_assoc rxon_assoc; int s, error; @@ -5066,17 +5063,38 @@ iwn_update_htprot(struct ieee80211com *ic, struct ieee80211_node *ni) 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.ht_triple_mask = sc->rxon.ht_triple_mask; rxon_assoc.rxchain = sc->rxon.rxchain; rxon_assoc.acquisition = sc->rxon.acquisition; + s = splnet(); + error = iwn_cmd(sc, IWN_CMD_RXON_ASSOC, &rxon_assoc, sizeof(rxon_assoc), 1); if (error != 0) printf("%s: RXON_ASSOC command failed\n", sc->sc_dev.dv_xname); -#endif + + 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); + + splx(s); } /* |