Skip site navigation (1)Skip section navigation (2)
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>