Date: Tue, 7 Jul 2015 03:51:30 +0000 (UTC) From: Adrian Chadd <adrian@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r285234 - head/sys/dev/iwn Message-ID: <201507070351.t673pUKp099094@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: adrian Date: Tue Jul 7 03:51:29 2015 New Revision: 285234 URL: https://svnweb.freebsd.org/changeset/base/285234 Log: 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. Modified: head/sys/dev/iwn/if_iwn.c head/sys/dev/iwn/if_iwnreg.h Modified: head/sys/dev/iwn/if_iwn.c ============================================================================== --- head/sys/dev/iwn/if_iwn.c Tue Jul 7 03:06:56 2015 (r285233) +++ head/sys/dev/iwn/if_iwn.c Tue Jul 7 03:51:29 2015 (r285234) @@ -6503,6 +6503,34 @@ iwn5000_runtime_calib(struct iwn_softc * 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 ie 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 iee 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 iee 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", Modified: head/sys/dev/iwn/if_iwnreg.h ============================================================================== --- head/sys/dev/iwn/if_iwnreg.h Tue Jul 7 03:06:56 2015 (r285233) +++ head/sys/dev/iwn/if_iwnreg.h Tue Jul 7 03:51:29 2015 (r285234) @@ -586,9 +586,13 @@ struct iwn_rxon { #define IWN_RXON_ANTENNA_B (1 << 9) #define IWN_RXON_TSF (1 << 15) #define IWN_RXON_HT_HT40MINUS (1 << 22) + #define IWN_RXON_HT_PROTMODE(x) (x << 23) + +/* 0=legacy, 1=pure40, 2=mixed */ #define IWN_RXON_HT_MODEPURE40 (1 << 25) #define IWN_RXON_HT_MODEMIXED (2 << 25) + #define IWN_RXON_CTS_TO_SELF (1 << 30) uint32_t filter;
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507070351.t673pUKp099094>