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.
This commit is contained in:
Adrian Chadd 2015-07-07 03:51:29 +00:00
parent 8265877704
commit 54991f37c9
2 changed files with 46 additions and 20 deletions

View File

@ -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",

View File

@ -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;