From 047258c7becbba49f513b8c20bf3e062bc4d7b3a Mon Sep 17 00:00:00 2001
From: Arnaud Lacombe <lacombar@gmail.com>
Date: Thu, 27 May 2010 01:25:42 -0400
Subject: [PATCH 6/6] ath(4) upgrade

---
 sys/dev/ic/ath.c            |  208 +++++++++++++------------------------------
 sys/dev/ic/ath_netbsd.c     |    7 +-
 sys/dev/ic/athrate-sample.c |    5 +-
 sys/dev/ic/athvar.h         |    9 +--
 4 files changed, 72 insertions(+), 157 deletions(-)

diff --git a/sys/dev/ic/ath.c b/sys/dev/ic/ath.c
index ab1e537..39bd18d 100644
--- a/sys/dev/ic/ath.c
+++ b/sys/dev/ic/ath.c
@@ -78,6 +78,7 @@ __KERNEL_RCSID(0, "$NetBSD: ath.c,v 1.108 2010/01/19 22:06:24 pooka Exp $");
 
 #include <net80211/ieee80211_netbsd.h>
 #include <net80211/ieee80211_var.h>
+#include <net80211/ieee80211_regdomain.h>
 
 #include <net/bpf.h>
 
@@ -183,8 +184,7 @@ static void	ath_calibrate(void *);
 static int	ath_newstate(struct ieee80211com *, enum ieee80211_state, int);
 static void	ath_setup_stationkey(struct ieee80211_node *);
 static void	ath_newassoc(struct ieee80211_node *, int);
-static int	ath_getchannels(struct ath_softc *, u_int cc,
-			HAL_BOOL outdoor, HAL_BOOL xchanmode);
+static int	ath_getchannels(struct ath_softc *, u_int cc);
 static void	ath_led_event(struct ath_softc *, int);
 static void	ath_update_txpow(struct ath_softc *);
 static void	ath_freetx(struct mbuf *);
@@ -198,8 +198,6 @@ static void	ath_announce(struct ath_softc *);
 
 int ath_dwelltime = 200;		/* 5 channels/second */
 int ath_calinterval = 30;		/* calibrate every 30 secs */
-int ath_outdoor = AH_TRUE;		/* outdoor operation */
-int ath_xchanmode = AH_TRUE;		/* enable extended channels */
 int ath_countrycode = CTRY_DEFAULT;	/* country code */
 int ath_regdomain = 0;			/* regulatory domain */
 int ath_debug = 0;
@@ -275,13 +273,6 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
 		error = ENXIO;
 		goto bad;
 	}
-	if (ah->ah_abi != HAL_ABI_VERSION) {
-		if_printf(ifp, "HAL ABI mismatch detected "
-			"(HAL:0x%x != driver:0x%x)\n",
-			ah->ah_abi, HAL_ABI_VERSION);
-		error = ENXIO;
-		goto bad;
-	}
 	sc->sc_ah = ah;
 
 	if (!prop_dictionary_set_bool(device_properties(sc->sc_dev),
@@ -339,8 +330,7 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
 	 * is resposible for filtering this list based on settings
 	 * like the phy mode.
 	 */
-	error = ath_getchannels(sc, ath_countrycode,
-			ath_outdoor, ath_xchanmode);
+	error = ath_getchannels(sc, ath_countrycode);
 	if (error != 0)
 		goto bad;
 
@@ -466,7 +456,8 @@ ath_attach(u_int16_t devid, struct ath_softc *sc)
 	 */
 	sc->sc_softled = (devid == AR5212_DEVID_IBM || devid == AR5211_DEVID);
 	if (sc->sc_softled) {
-		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin);
+		ath_hal_gpioCfgOutput(ah, sc->sc_ledpin,
+		    HAL_GPIO_MUX_MAC_NETWORK_LED);
 		ath_hal_gpioset(ah, sc->sc_ledpin, !sc->sc_ledon);
 	}
 
@@ -721,7 +712,8 @@ ath_resume(struct ath_softc *sc)
 			ath_hal_resettxqueue(ah, i);
 
 	if (sc->sc_softled) {
-		ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
+		ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
+		    HAL_GPIO_MUX_MAC_NETWORK_LED);
 		ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin, !sc->sc_ledon);
 	}
 	return true;
@@ -927,12 +919,12 @@ ath_chan2flags(struct ieee80211com *ic, struct ieee80211_channel *chan)
 #define	N(a)	(sizeof(a) / sizeof(a[0]))
 	static const u_int modeflags[] = {
 		0,			/* IEEE80211_MODE_AUTO */
-		CHANNEL_A,		/* IEEE80211_MODE_11A */
-		CHANNEL_B,		/* IEEE80211_MODE_11B */
-		CHANNEL_PUREG,		/* IEEE80211_MODE_11G */
+		IEEE80211_CHAN_A,	/* IEEE80211_MODE_11A */
+		IEEE80211_CHAN_B,	/* IEEE80211_MODE_11B */
+		IEEE80211_CHAN_PUREG,	/* IEEE80211_MODE_11G */
 		0,			/* IEEE80211_MODE_FH */
-		CHANNEL_ST,		/* IEEE80211_MODE_TURBO_A */
-		CHANNEL_108G		/* IEEE80211_MODE_TURBO_G */
+		IEEE80211_CHAN_ST,	/* IEEE80211_MODE_TURBO_A */
+		IEEE80211_CHAN_108G	/* IEEE80211_MODE_TURBO_G */
 	};
 	enum ieee80211_phymode mode = ieee80211_chan2mode(ic, chan);
 
@@ -1002,8 +994,8 @@ ath_init(struct ath_softc *sc)
 	 * and then setup of the interrupt mask.
 	 */
 	ath_settkipmic(sc);
-	sc->sc_curchan.channel = ic->ic_curchan->ic_freq;
-	sc->sc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan);
+	sc->sc_curchan.ic_freq = ic->ic_curchan->ic_freq;
+	sc->sc_curchan.ic_flags = ath_chan2flags(ic, ic->ic_curchan);
 	if (!ath_hal_reset(ah, ic->ic_opmode, &sc->sc_curchan, AH_FALSE, &status)) {
 		if_printf(ifp, "unable to reset hardware; hal status %u\n",
 			status);
@@ -1175,8 +1167,8 @@ ath_reset(struct ifnet *ifp)
 	 * constrained to reflect the current operating mode.
 	 */
 	c = ic->ic_curchan;
-	sc->sc_curchan.channel = c->ic_freq;
-	sc->sc_curchan.channelFlags = ath_chan2flags(ic, c);
+	sc->sc_curchan.ic_freq = c->ic_freq;
+	sc->sc_curchan.ic_flags = ath_chan2flags(ic, c);
 
 	ath_hal_intrset(ah, 0);		/* disable interrupts */
 	ath_draintxq(sc);		/* stop xmit side */
@@ -4105,8 +4097,6 @@ ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 				u_int8_t txant = ds->ds_txstat.ts_antenna;
 				sc->sc_stats.ast_ant_tx[txant]++;
 				sc->sc_ant_tx[txant]++;
-				if (ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)
-					sc->sc_stats.ast_tx_altrate++;
 				sc->sc_stats.ast_tx_rssi =
 					ds->ds_txstat.ts_rssi;
 				ATH_RSSI_LPF(sc->sc_halstats.ns_avgtxrssi,
@@ -4430,7 +4420,7 @@ ath_chan_change(struct ath_softc *sc, struct ieee80211_channel *chan)
 		flags = IEEE80211_CHAN_G;
 	else
 		flags = IEEE80211_CHAN_B;
-	if (IEEE80211_IS_CHAN_T(chan))
+	if (IEEE80211_IS_CHAN_TURBO(chan))
 		flags |= IEEE80211_CHAN_TURBO;
 	sc->sc_tx_th.wt_chan_freq = sc->sc_rx_th.wr_chan_freq =
 		htole16(chan->ic_freq);
@@ -4482,30 +4472,16 @@ ath_dfswait(void *arg)
 static int
 ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
 {
-	struct ath_hal *ah = sc->sc_ah;
 	struct ieee80211com *ic = &sc->sc_ic;
-	HAL_CHANNEL hchan;
+	struct ath_hal *ah = sc->sc_ah;
+	struct ifnet *ifp = &sc->sc_if;
 
-	/*
-	 * Convert to a HAL channel description with
-	 * the flags constrained to reflect the current
-	 * operating mode.
-	 */
-	hchan.channel = chan->ic_freq;
-	hchan.channelFlags = ath_chan2flags(ic, chan);
+	DPRINTF(sc, ATH_DEBUG_RESET, "%s: %u (%u MHz, flags 0x%x)\n",
+	    __func__, ieee80211_chan2ieee(ic, chan),
+	    chan->ic_freq, chan->ic_flags);
 
-	DPRINTF(sc, ATH_DEBUG_RESET,
-	    "%s: %u (%u MHz, hal flags 0x%x) -> %u (%u MHz, hal flags 0x%x)\n",
-	    __func__,
-	    ath_hal_mhz2ieee(ah, sc->sc_curchan.channel,
-		sc->sc_curchan.channelFlags),
-	    	sc->sc_curchan.channel, sc->sc_curchan.channelFlags,
-	    ath_hal_mhz2ieee(ah, hchan.channel, hchan.channelFlags),
-	        hchan.channel, hchan.channelFlags);
-	if (hchan.channel != sc->sc_curchan.channel ||
-	    hchan.channelFlags != sc->sc_curchan.channelFlags) {
+	if (chan != &sc->sc_curchan) {
 		HAL_STATUS status;
-
 		/*
 		 * To switch channels clear any pending DMA operations;
 		 * wait long enough for the RX fifo to drain, reset the
@@ -4515,25 +4491,21 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
 		ath_hal_intrset(ah, 0);		/* disable interrupts */
 		ath_draintxq(sc);		/* clear pending tx frames */
 		ath_stoprecv(sc);		/* turn off frame recv */
-		if (!ath_hal_reset(ah, ic->ic_opmode, &hchan, AH_TRUE, &status)) {
-			if_printf(ic->ic_ifp, "%s: unable to reset "
-			    "channel %u (%u MHz, flags 0x%x hal flags 0x%x)\n",
+		if (!ath_hal_reset(ah, ic->ic_opmode, chan, AH_TRUE, &status)) {
+			if_printf(ifp, "%s: unable to reset "
+			    "channel %u (%u MHz, flags 0x%x), hal status %u\n",
 			    __func__, ieee80211_chan2ieee(ic, chan),
-			    chan->ic_freq, chan->ic_flags, hchan.channelFlags);
+			    chan->ic_freq, chan->ic_flags, status);
 			return EIO;
 		}
-		sc->sc_curchan = hchan;
-		ath_update_txpow(sc);		/* update tx power state */
-		ath_restore_diversity(sc);
-		sc->sc_calinterval = 1;
-		sc->sc_caltries = 0;
+		sc->sc_diversity = ath_hal_getdiversity(ah);
 
 		/*
 		 * Re-enable rx framework.
 		 */
 		if (ath_startrecv(sc) != 0) {
-			if_printf(&sc->sc_if,
-				"%s: unable to restart recv logic\n", __func__);
+			if_printf(ifp, "%s: unable to restart recv logic\n",
+			    __func__);
 			return EIO;
 		}
 
@@ -4541,30 +4513,8 @@ ath_chan_set(struct ath_softc *sc, struct ieee80211_channel *chan)
 		 * Change channels and update the h/w rate map
 		 * if we're switching; e.g. 11a to 11b/g.
 		 */
-		ic->ic_ibss_chan = chan;
 		ath_chan_change(sc, chan);
 
-#if 0
-		/*
-		 * Handle DFS required waiting period to determine
-		 * if channel is clear of radar traffic.
-		 */
-		if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
-#define	DFS_AND_NOT_CLEAR(_c) \
-	(((_c)->privFlags & (CHANNEL_DFS | CHANNEL_DFS_CLEAR)) == CHANNEL_DFS)
-			if (DFS_AND_NOT_CLEAR(&sc->sc_curchan)) {
-				if_printf(&sc->sc_if,
-					"wait for DFS clear channel signal\n");
-				/* XXX stop sndq */
-				sc->sc_if.if_flags |= IFF_OACTIVE;
-				callout_reset(&sc->sc_dfs_ch,
-					2 * hz, ath_dfswait, sc);
-			} else
-				callout_stop(&sc->sc_dfs_ch);
-#undef DFS_NOT_CLEAR
-		}
-#endif
-
 		/*
 		 * Re-enable interrupts.
 		 */
@@ -4616,7 +4566,7 @@ ath_calibrate(void *arg)
 	if (!ath_hal_calibrate(ah, &sc->sc_curchan, &iqCalDone)) {
 		DPRINTF(sc, ATH_DEBUG_ANY,
 			"%s: calibration of channel %u failed\n",
-			__func__, sc->sc_curchan.channel);
+			__func__, sc->sc_curchan.ic_freq);
 		sc->sc_stats.ast_per_calfail++;
 	}
 	/*
@@ -4870,76 +4820,45 @@ ath_newassoc(struct ieee80211_node *ni, int isnew)
 }
 
 static int
-ath_getchannels(struct ath_softc *sc, u_int cc,
-	HAL_BOOL outdoor, HAL_BOOL xchanmode)
+ath_getchannels(struct ath_softc *sc, u_int cc)
 {
-#define	COMPAT	(CHANNEL_ALL_NOTURBO|CHANNEL_PASSIVE)
 	struct ieee80211com *ic = &sc->sc_ic;
 	struct ifnet *ifp = &sc->sc_if;
 	struct ath_hal *ah = sc->sc_ah;
-	HAL_CHANNEL *chans;
-	int i, ix, nchan;
-
-	chans = malloc(IEEE80211_CHAN_MAX * sizeof(HAL_CHANNEL),
-			M_TEMP, M_NOWAIT);
-	if (chans == NULL) {
-		if_printf(ifp, "unable to allocate channel table\n");
-		return ENOMEM;
-	}
-	if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
-	    NULL, 0, NULL,
-	    cc, HAL_MODE_ALL, outdoor, xchanmode)) {
-		u_int32_t rd;
-
-		(void)ath_hal_getregdomain(ah, &rd);
-		if_printf(ifp, "unable to collect channel list from hal; "
-			"regdomain likely %u country code %u\n", rd, cc);
-		free(chans, M_TEMP);
-		return EINVAL;
-	}
+	int nchans;
+	HAL_STATUS status;
 
 	/*
-	 * Convert HAL channels to ieee80211 ones and insert
-	 * them in the table according to their channel number.
+	 * Collect channel set based on EEPROM contents.
 	 */
-	for (i = 0; i < nchan; i++) {
-		HAL_CHANNEL *c = &chans[i];
-		u_int16_t flags;
-
-		ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
-		if (ix > IEEE80211_CHAN_MAX) {
-			if_printf(ifp, "bad hal channel %d (%u/%x) ignored\n",
-				ix, c->channel, c->channelFlags);
-			continue;
-		}
-		if (ix < 0) {
-			/* XXX can't handle stuff <2400 right now */
-			if (bootverbose)
-				if_printf(ifp, "hal channel %d (%u/%x) "
-				    "cannot be handled; ignored\n",
-				    ix, c->channel, c->channelFlags);
-			continue;
-		}
-		/*
-		 * Calculate net80211 flags; most are compatible
-		 * but some need massaging.  Note the static turbo
-		 * conversion can be removed once net80211 is updated
-		 * to understand static vs. dynamic turbo.
-		 */
-		flags = c->channelFlags & COMPAT;
-		if (c->channelFlags & CHANNEL_STURBO)
-			flags |= IEEE80211_CHAN_TURBO;
-		if (ic->ic_channels[ix].ic_freq == 0) {
-			ic->ic_channels[ix].ic_freq = c->channel;
-			ic->ic_channels[ix].ic_flags = flags;
-		} else {
-			/* channels overlap; e.g. 11g and 11b */
-			ic->ic_channels[ix].ic_flags |= flags;
-		}
+	status = ath_hal_init_channels(ah, ic->ic_channels, IEEE80211_CHAN_MAX,
+	    &nchans, HAL_MODE_ALL, CTRY_DEFAULT, SKU_NONE, AH_TRUE);
+	if (status != HAL_OK) {
+		if_printf(ifp, "%s: unable to collect channel list from hal, "
+		    "status %d\n", __func__, status);
+		return EINVAL;
 	}
-	free(chans, M_TEMP);
+#ifdef notyet
+	(void) ath_hal_getregdomain(ah, &sc->sc_eerd);
+	ath_hal_getcountrycode(ah, &sc->sc_eecc);	/* NB: cannot fail */
+	/* XXX map Atheros sku's to net80211 SKU's */
+	/* XXX net80211 types too small */
+	ic->ic_regdomain.regdomain = (uint16_t) sc->sc_eerd;
+	ic->ic_regdomain.country = (uint16_t) sc->sc_eecc;
+	ic->ic_regdomain.isocc[0] = ' ';	/* XXX don't know */
+	ic->ic_regdomain.isocc[1] = ' ';
+
+	ic->ic_regdomain.ecm = 1;
+	ic->ic_regdomain.location = 'I';
+
+	DPRINTF(sc, ATH_DEBUG_REGDOMAIN,
+	    "%s: eeprom rd %u cc %u (mapped rd %u cc %u) location %c%s\n",
+	    __func__, sc->sc_eerd, sc->sc_eecc,
+	    ic->ic_regdomain.regdomain, ic->ic_regdomain.country,
+	    ic->ic_regdomain.location, ic->ic_regdomain.ecm ? " ecm" : "");
+#endif
+
 	return 0;
-#undef COMPAT
 }
 
 static void
@@ -5411,7 +5330,7 @@ ath_announce(struct ath_softc *sc)
 #define	HAL_MODE_DUALBAND	(HAL_MODE_11A|HAL_MODE_11B)
 	struct ifnet *ifp = &sc->sc_if;
 	struct ath_hal *ah = sc->sc_ah;
-	u_int modes, cc;
+	u_int modes;
 
 	if_printf(ifp, "mac %d.%d phy %d.%d",
 		ah->ah_macVersion, ah->ah_macRev,
@@ -5421,8 +5340,7 @@ ath_announce(struct ath_softc *sc)
 	 * to avoid falsely printing revs for inoperable parts.
 	 * Dual-band radio revs are returned in the 5 GHz rev number.
 	 */
-	ath_hal_getcountrycode(ah, &cc);
-	modes = ath_hal_getwirelessmodes(ah, cc);
+	modes = ath_hal_getwirelessmodes(ah);
 	if ((modes & HAL_MODE_DUALBAND) == HAL_MODE_DUALBAND) {
 		if (ah->ah_analog5GhzRev && ah->ah_analog2GhzRev)
 			printf(" 5 GHz radio %d.%d 2 GHz radio %d.%d",
diff --git a/sys/dev/ic/ath_netbsd.c b/sys/dev/ic/ath_netbsd.c
index dbdc1cd..0f8c202 100644
--- a/sys/dev/ic/ath_netbsd.c
+++ b/sys/dev/ic/ath_netbsd.c
@@ -91,10 +91,6 @@ SYSCTL_SETUP(sysctl_ath, "sysctl ath subtree setup")
 	    "chip calibration interval (secs)", calinterval)) != 0)
 		goto err;
 
-	if ((rc = SYSCTL_GLOBAL_INT(CTLFLAG_READWRITE, "outdoor",
-	    "outdoor operation", outdoor)) != 0)
-		goto err;
-
 	/* country code */
 	if ((rc = SYSCTL_GLOBAL_INT(CTLFLAG_READWRITE,
 	    "countrycode", "country code", countrycode)) != 0)
@@ -194,7 +190,8 @@ ath_sysctl_softled(SYSCTLFN_ARGS)
 	if (softled != sc->sc_softled) {
 		if (softled) {
 			/* NB: handle any sc_ledpin change */
-			ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin);
+			ath_hal_gpioCfgOutput(sc->sc_ah, sc->sc_ledpin,
+			    HAL_GPIO_MUX_MAC_NETWORK_LED);
 			ath_hal_gpioset(sc->sc_ah, sc->sc_ledpin,
 				!sc->sc_ledon);
 		}
diff --git a/sys/dev/ic/athrate-sample.c b/sys/dev/ic/athrate-sample.c
index 55e463c..e167e35 100644
--- a/sys/dev/ic/athrate-sample.c
+++ b/sys/dev/ic/athrate-sample.c
@@ -494,7 +494,10 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
 	int ndx = -1;
 	int mrr;
 
+	final_rate = 0;
+#ifdef FIXME
 	final_rate = sc->sc_hwmap[ds->ds_txstat.ts_rate &~ HAL_TXSTAT_ALTRATE].ieeerate;
+#endif
 	short_tries = ds->ds_txstat.ts_shortretry + 1;
 	long_tries = ds->ds_txstat.ts_longretry + 1;
 	frame_size = ds0->ds_ctl0 & 0x0fff; /* low-order 12 bits of ds_ctl0 */
@@ -532,7 +535,7 @@ ath_rate_tx_complete(struct ath_softc *sc, struct ath_node *an,
 			long_tries);
 	}
 
-	if (!mrr || !(ds->ds_txstat.ts_rate & HAL_TXSTAT_ALTRATE)) {
+	if (!mrr || !(ds->ds_txstat.ts_rate /*& HAL_TXSTAT_ALTRATE*/)) {
 		/* only one rate was used */
 		ndx = rate_to_ndx(sn, final_rate);
 		DPRINTF(sc, "%s: %s size %d status %d rate/try %d/%d/%d\n", 
diff --git a/sys/dev/ic/athvar.h b/sys/dev/ic/athvar.h
index 83eb8b5..92bc372 100644
--- a/sys/dev/ic/athvar.h
+++ b/sys/dev/ic/athvar.h
@@ -222,7 +222,7 @@ struct ath_softc {
 	const HAL_RATE_TABLE	*sc_currates;	/* current rate table */
 	enum ieee80211_phymode	sc_curmode;	/* current phy mode */
 	u_int16_t		sc_curtxpow;	/* current tx power limit */
-	HAL_CHANNEL		sc_curchan;	/* current h/w channel */
+	struct ieee80211_channel sc_curchan;	/* current h/w channel */
 	u_int8_t		sc_rixmap[256];	/* IEEE to h/w rate table ix */
 	struct {
 		u_int8_t	ieeerate;	/* IEEE rate */
@@ -324,8 +324,6 @@ void	ath_sysctlattach(struct ath_softc *);
 
 extern int ath_dwelltime;
 extern int ath_calinterval;
-extern int ath_outdoor;
-extern int ath_xchanmode;
 extern int ath_countrycode;
 extern int ath_regdomain;
 extern int ath_debug;
@@ -570,9 +568,8 @@ extern int ath_txbuf;
 	((*(_ah)->ah_procTxDesc)((_ah), (_ds), (_ts)))
 #define	ath_hal_gettxintrtxqs(_ah, _txqs) \
 	((*(_ah)->ah_getTxIntrQueue)((_ah), (_txqs)))
-
-#define ath_hal_gpioCfgOutput(_ah, _gpio) \
-        ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio)))
+#define ath_hal_gpioCfgOutput(_ah, _gpio, _type) \
+        ((*(_ah)->ah_gpioCfgOutput)((_ah), (_gpio), (_type)))
 #define ath_hal_gpioset(_ah, _gpio, _b) \
         ((*(_ah)->ah_gpioSet)((_ah), (_gpio), (_b)))
 
-- 
1.7.1.rc0.7.g02125bc

