summaryrefslogtreecommitdiffstats
path: root/sys/dev/iwn/if_iwn.c
diff options
context:
space:
mode:
authoradrian <adrian@FreeBSD.org>2015-07-07 03:51:29 +0000
committeradrian <adrian@FreeBSD.org>2015-07-07 03:51:29 +0000
commit8c71055773dd3fc15837633427bf90def7dd5c80 (patch)
tree214f783604eb7625ba28f909b934280a453378a3 /sys/dev/iwn/if_iwn.c
parentc37111ed64115d4794fd850295c962f62494c930 (diff)
downloadFreeBSD-src-8c71055773dd3fc15837633427bf90def7dd5c80.zip
FreeBSD-src-8c71055773dd3fc15837633427bf90def7dd5c80.tar.gz
Attempt to make 5GHz HT/40 work on the 6xxx series NICs.
The 6205 (Taylor Peak) in the Lenovo X230 works fine in 5GHz 11a and 11n HT20, but not 11n HT40. The NIC goes RX deaf the moment HT40 is configured. It's so RX deaf that it doesn't even hear beacons and the firmware sends "BEACON MISS" events. That's pretty deaf. I tried configuring up the HT40 flags in monitor mode and it worked - so I assumed that doing the transition from 20 -> 40MHz channel configuration when going auth->assoc (ie, after the NIC has been partially configured) is a problem. So for now, let's just always set them if they're available. Tested: * Intel 5300, STA mode, 5GHz HT/40 AP; 2GHz HT/20 AP * Intel 6205, STA mode, 5GHz HT/40, HT20, 11a AP; 2GHz HT/20 AP This was pointed out to me by coworkers trying to use FreeBSD-HEAD in the office on their Thinkpad T420p laptops. TODO: * I don't like how the HT40 flags are configured - the whole interop/ protection config should be re-checked. Notably, I think curhtprotmode is 0 in a lot of cases, which means "no interoperability" and i think that's busted. Sponsored by: Norse Corp, Inc.
Diffstat (limited to 'sys/dev/iwn/if_iwn.c')
-rw-r--r--sys/dev/iwn/if_iwn.c62
1 files changed, 42 insertions, 20 deletions
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index f3cf2ae..3cd5d7b 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -6503,6 +6503,34 @@ iwn5000_runtime_calib(struct iwn_softc *sc)
return iwn_cmd(sc, IWN5000_CMD_CALIB_CONFIG, &cmd, sizeof(cmd), 0);
}
+static uint32_t
+iwn_get_rxon_ht_flags(struct iwn_softc *sc, struct ieee80211_channel *c)
+{
+ uint32_t htflags = 0;
+ struct ifnet *ifp = sc->sc_ifp;
+ struct ieee80211com *ic = ifp->if_l2com;
+
+ if (! IEEE80211_IS_CHAN_HT(c))
+ return (0);
+
+ htflags |= IWN_RXON_HT_PROTMODE(ic->ic_curhtprotmode);
+
+ if (IEEE80211_IS_CHAN_HT40(c)) {
+ switch (ic->ic_curhtprotmode) {
+ case IEEE80211_HTINFO_OPMODE_HT20PR:
+ htflags |= IWN_RXON_HT_MODEPURE40;
+ break;
+ default:
+ htflags |= IWN_RXON_HT_MODEMIXED;
+ break;
+ }
+ }
+ if (IEEE80211_IS_CHAN_HT40D(c))
+ htflags |= IWN_RXON_HT_HT40MINUS;
+
+ return (htflags);
+}
+
static int
iwn_config(struct iwn_softc *sc)
{
@@ -6633,7 +6661,12 @@ iwn_config(struct iwn_softc *sc)
__func__,
sc->rxchainmask,
sc->nrxchains);
- DPRINTF(sc, IWN_DEBUG_RESET, "%s: setting configuration\n", __func__);
+
+ sc->rxon->flags |= htole32(iwn_get_rxon_ht_flags(sc, ic->ic_curchan));
+
+ DPRINTF(sc, IWN_DEBUG_RESET,
+ "%s: setting configuration; flags=0x%08x\n",
+ __func__, le32toh(sc->rxon->flags));
if (sc->sc_is_scanning)
device_printf(sc->sc_dev,
"%s: is_scanning set, before RXON\n",
@@ -7036,6 +7069,10 @@ iwn_auth(struct iwn_softc *sc, struct ieee80211vap *vap)
sc->rxon->cck_mask = 0x03;
sc->rxon->ofdm_mask = 0x15;
}
+
+ /* try HT */
+ sc->rxon->flags |= htole32(iwn_get_rxon_ht_flags(sc, ic->ic_curchan));
+
DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x cck %x ofdm %x\n",
sc->rxon->chan, sc->rxon->flags, sc->rxon->cck_mask,
sc->rxon->ofdm_mask);
@@ -7080,7 +7117,6 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap)
struct ieee80211com *ic = ifp->if_l2com;
struct ieee80211_node *ni = vap->iv_bss;
struct iwn_node_info node;
- uint32_t htflags = 0;
int error;
DPRINTF(sc, IWN_DEBUG_TRACE, "->%s begin\n", __func__);
@@ -7119,25 +7155,11 @@ iwn_run(struct iwn_softc *sc, struct ieee80211vap *vap)
sc->rxon->cck_mask = 0x0f;
sc->rxon->ofdm_mask = 0x15;
}
- if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) {
- htflags |= IWN_RXON_HT_PROTMODE(ic->ic_curhtprotmode);
- if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
- switch (ic->ic_curhtprotmode) {
- case IEEE80211_HTINFO_OPMODE_HT20PR:
- htflags |= IWN_RXON_HT_MODEPURE40;
- break;
- default:
- htflags |= IWN_RXON_HT_MODEMIXED;
- break;
- }
- }
- if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
- htflags |= IWN_RXON_HT_HT40MINUS;
- }
- sc->rxon->flags |= htole32(htflags);
+ /* try HT */
+ sc->rxon->flags |= htole32(iwn_get_rxon_ht_flags(sc, ni->ni_chan));
sc->rxon->filter |= htole32(IWN_FILTER_BSS);
- DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x\n",
- sc->rxon->chan, sc->rxon->flags);
+ DPRINTF(sc, IWN_DEBUG_STATE, "rxon chan %d flags %x, curhtprotmode=%d\n",
+ sc->rxon->chan, le32toh(sc->rxon->flags), ic->ic_curhtprotmode);
if (sc->sc_is_scanning)
device_printf(sc->sc_dev,
"%s: is_scanning set, before RXON\n",
OpenPOWER on IntegriCloud