[Zrouter-src-freebsd] ZRouter.org: push to FreeBSD HEAD tree

zrouter-src-freebsd at zrouter.org zrouter-src-freebsd at zrouter.org
Wed Aug 15 08:14:47 UTC 2012


details:   http://zrouter.org/hg/FreeBSD/head//rev/7fffa673adcd
changeset: 523:7fffa673adcd
user:      Aleksandr Rybalko <ray at ddteam.net>
date:      Wed Aug 15 11:15:12 2012 +0300
description:
Update dev/ath to r239289.

diffstat:

 head/sys/dev/ath/ath_hal/ah.c                   |   34 +++--
 head/sys/dev/ath/ath_hal/ah.h                   |    8 +-
 head/sys/dev/ath/ath_rate/sample/sample.c       |   42 +++---
 head/sys/dev/ath/ath_rate/sample/sample.h       |    4 +-
 head/sys/dev/ath/ath_rate/sample/tx_schedules.h |   52 +++++++-
 head/sys/dev/ath/if_ath.c                       |  149 ++++++++++++++++-------
 head/sys/dev/ath/if_ath_beacon.c                |   58 ++++++++-
 head/sys/dev/ath/if_ath_beacon.h                |    4 +-
 head/sys/dev/ath/if_ath_debug.c                 |    5 +-
 head/sys/dev/ath/if_ath_misc.h                  |   15 +-
 head/sys/dev/ath/if_ath_sysctl.c                |    7 +-
 head/sys/dev/ath/if_ath_tx.c                    |    9 +-
 head/sys/dev/ath/if_ath_tx.h                    |    8 +-
 head/sys/dev/ath/if_ath_tx_edma.c               |  147 +++++++++++++++++++++--
 head/sys/dev/ath/if_athvar.h                    |   18 +-
 15 files changed, 425 insertions(+), 135 deletions(-)

diffs (1229 lines):

diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/ath_hal/ah.c
--- a/head/sys/dev/ath/ath_hal/ah.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah.c	Wed Aug 15 11:15:12 2012 +0300
@@ -14,7 +14,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 238858 2012-07-28 07:28:08Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah.c 239288 2012-08-15 07:56:48Z adrian $
  */
 #include "opt_ah.h"
 
@@ -275,31 +275,37 @@
 
 	/* 11n frame - extract out the number of spatial streams */
 	numStreams = HT_RC_2_STREAMS(rc);
-	KASSERT(numStreams == 1 || numStreams == 2, ("number of spatial streams needs to be 1 or 2: MCS rate 0x%x!", rateix));
+	KASSERT(numStreams > 0 && numStreams <= 4,
+	    ("number of spatial streams needs to be 1..3: MCS rate 0x%x!",
+	    rateix));
 
 	return ath_computedur_ht(frameLen, rc, numStreams, isht40, shortPreamble);
 }
 
+static const uint16_t ht20_bps[32] = {
+    26, 52, 78, 104, 156, 208, 234, 260,
+    52, 104, 156, 208, 312, 416, 468, 520,
+    78, 156, 234, 312, 468, 624, 702, 780,
+    104, 208, 312, 416, 624, 832, 936, 1040
+};
+static const uint16_t ht40_bps[32] = {
+    54, 108, 162, 216, 324, 432, 486, 540,
+    108, 216, 324, 432, 648, 864, 972, 1080,
+    162, 324, 486, 648, 972, 1296, 1458, 1620,
+    216, 432, 648, 864, 1296, 1728, 1944, 2160
+};
+
 /*
  * Calculate the transmit duration of an 11n frame.
- * This only works for MCS0->MCS15.
  */
 uint32_t
-ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams, HAL_BOOL isht40,
-    HAL_BOOL isShortGI)
+ath_computedur_ht(uint32_t frameLen, uint16_t rate, int streams,
+    HAL_BOOL isht40, HAL_BOOL isShortGI)
 {
-	static const uint16_t ht20_bps[16] = {
-	    26, 52, 78, 104, 156, 208, 234, 260,
-	    52, 104, 156, 208, 312, 416, 468, 520
-	};
-	static const uint16_t ht40_bps[16] = {
-	    54, 108, 162, 216, 324, 432, 486, 540,
-	    108, 216, 324, 432, 648, 864, 972, 1080,
-	};
 	uint32_t bitsPerSymbol, numBits, numSymbols, txTime;
 
 	KASSERT(rate & IEEE80211_RATE_MCS, ("not mcs %d", rate));
-	KASSERT((rate &~ IEEE80211_RATE_MCS) < 16, ("bad mcs 0x%x", rate));
+	KASSERT((rate &~ IEEE80211_RATE_MCS) < 31, ("bad mcs 0x%x", rate));
 
 	if (isht40)
 		bitsPerSymbol = ht40_bps[rate & 0xf];
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/ath_hal/ah.h
--- a/head/sys/dev/ath/ath_hal/ah.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/ath_hal/ah.h	Wed Aug 15 11:15:12 2012 +0300
@@ -14,7 +14,7 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * $FreeBSD: head/sys/dev/ath/ath_hal/ah.h 239053 2012-08-05 11:24:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_hal/ah.h 239289 2012-08-15 08:06:06Z adrian $
  */
 
 #ifndef _ATH_AH_H_
@@ -550,7 +550,7 @@
 
 typedef struct {
 	int		rateCount;		/* NB: for proper padding */
-	uint8_t		rateCodeToIndex[144];	/* back mapping */
+	uint8_t		rateCodeToIndex[256];	/* back mapping */
 	struct {
 		uint8_t		valid;		/* valid for rate control use */
 		uint8_t		phy;		/* CCK/OFDM/XR */
@@ -564,12 +564,12 @@
 						 * rate; used for dur. calcs */
 		uint16_t	lpAckDuration;	/* long preamble ACK duration */
 		uint16_t	spAckDuration;	/* short preamble ACK duration*/
-	} info[32];
+	} info[64];
 } HAL_RATE_TABLE;
 
 typedef struct {
 	u_int		rs_count;		/* number of valid entries */
-	uint8_t	rs_rates[32];		/* rates */
+	uint8_t	rs_rates[64];		/* rates */
 } HAL_RATE_SET;
 
 /*
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/ath_rate/sample/sample.c
--- a/head/sys/dev/ath/ath_rate/sample/sample.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/sample/sample.c	Wed Aug 15 11:15:12 2012 +0300
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.c 238962 2012-08-01 00:18:02Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.c 239284 2012-08-15 07:10:10Z adrian $");
 
 /*
  * John Bicket's SampleRate control algorithm.
@@ -164,7 +164,7 @@
 {
 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
         int best_rate_rix, best_rate_tt, best_rate_pct;
-	uint32_t mask;
+	uint64_t mask;
 	int rix, tt, pct;
 
         best_rate_rix = 0;
@@ -251,7 +251,7 @@
 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
 	int current_rix, rix;
 	unsigned current_tt;
-	uint32_t mask;
+	uint64_t mask;
 	
 	current_rix = sn->current_rix[size_bin];
 	if (current_rix < 0) {
@@ -263,9 +263,9 @@
 	current_tt = sn->stats[size_bin][current_rix].average_tx_time;
 
 	rix = sn->last_sample_rix[size_bin]+1;	/* next sample rate */
-	mask = sn->ratemask &~ (1<<current_rix);/* don't sample current rate */
+	mask = sn->ratemask &~ ((uint64_t) 1<<current_rix);/* don't sample current rate */
 	while (mask != 0) {
-		if ((mask & (1<<rix)) == 0) {	/* not a supported rate */
+		if ((mask & ((uint64_t) 1<<rix)) == 0) {	/* not a supported rate */
 	nextrate:
 			if (++rix >= rt->rateCount)
 				rix = 0;
@@ -275,20 +275,20 @@
 		/* if the node is HT and the rate isn't HT, don't bother sample */
 		if ((an->an_node.ni_flags & IEEE80211_NODE_HT) &&
 		    (rt->info[rix].phy != IEEE80211_T_HT)) {
-			mask &= ~(1<<rix);
+			mask &= ~((uint64_t) 1<<rix);
 			goto nextrate;
 		}
 
 		/* this bit-rate is always worse than the current one */
 		if (sn->stats[size_bin][rix].perfect_tx_time > current_tt) {
-			mask &= ~(1<<rix);
+			mask &= ~((uint64_t) 1<<rix);
 			goto nextrate;
 		}
 
 		/* rarely sample bit-rates that fail a lot */
 		if (sn->stats[size_bin][rix].successive_failures > ssc->max_successive_failures &&
 		    ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout) {
-			mask &= ~(1<<rix);
+			mask &= ~((uint64_t) 1<<rix);
 			goto nextrate;
 		}
 
@@ -304,7 +304,7 @@
 			if ((sn->stats[size_bin][rix].average_tx_time * 10 >
 			    sn->stats[size_bin][current_rix].average_tx_time * 9) &&
 			    (ticks - sn->stats[size_bin][rix].last_tx < ssc->stale_failure_timeout)) {
-				mask &= ~(1<<rix);
+				mask &= ~((uint64_t) 1<<rix);
 				goto nextrate;
 			}
 		}
@@ -317,7 +317,7 @@
 		/* Don't sample more than 2 rates higher for rates > 11M for non-HT rates */
 		if (! (an->an_node.ni_flags & IEEE80211_NODE_HT)) {
 			if (DOT11RATE(rix) > 2*11 && rix > current_rix + 2) {
-				mask &= ~(1<<rix);
+				mask &= ~((uint64_t) 1<<rix);
 				goto nextrate;
 			}
 		}
@@ -394,7 +394,7 @@
 
 	/* no packet has been sent successfully yet */
 	for (rix = rt->rateCount-1; rix > 0; rix--) {
-		if ((sn->ratemask & (1<<rix)) == 0)
+		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
 			continue;
 
 		/* Skip HT rates */
@@ -436,7 +436,7 @@
 	/* no packet has been sent successfully yet */
 	for (rix = rt->rateCount-1; rix > 0; rix--) {
 		/* Skip rates we can't use */
-		if ((sn->ratemask & (1<<rix)) == 0)
+		if ((sn->ratemask & ((uint64_t) 1<<rix)) == 0)
 			continue;
 
 		/* Keep a copy of the last seen HT rate index */
@@ -660,7 +660,8 @@
 	struct sample_node *sn = ATH_NODE_SAMPLE(an);
 	const struct txschedule *sched = &sn->sched[rix0];
 
-	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n", rix0, sched->r0));
+	KASSERT(rix0 == sched->r0, ("rix0 (%x) != sched->r0 (%x)!\n",
+	    rix0, sched->r0));
 
 	rc[0].flags = rc[1].flags = rc[2].flags = rc[3].flags = 0;
 
@@ -919,6 +920,8 @@
 
 	if (!mrr || ts->ts_finaltsi == 0) {
 		if (!IS_RATE_DEFINED(sn, final_rix)) {
+			device_printf(sc->sc_dev, "%s: ts_rate=%d ts_finaltsi=%d\n",
+			    __func__, ts->ts_rate, ts->ts_finaltsi);
 			badrate(ifp, 0, ts->ts_rate, long_tries, status);
 			return;
 		}
@@ -1087,6 +1090,7 @@
 
 	KASSERT(sc->sc_curmode < IEEE80211_MODE_MAX+2,
 	    ("curmode %u", sc->sc_curmode));
+
 	sn->sched = mrr_schedules[sc->sc_curmode];
 	KASSERT(sn->sched != NULL,
 	    ("no mrr schedule for mode %u", sc->sc_curmode));
@@ -1113,7 +1117,7 @@
 				continue;
 			KASSERT(rix < SAMPLE_MAXRATES,
 			    ("mcs %u has rix %d", MCS(x), rix));
-			sn->ratemask |= 1<<rix;
+			sn->ratemask |= (uint64_t) 1<<rix;
 		}
 	}
 
@@ -1127,11 +1131,11 @@
 			continue;
 		KASSERT(rix < SAMPLE_MAXRATES,
 		    ("rate %u has rix %d", RATE(x), rix));
-		sn->ratemask |= 1<<rix;
+		sn->ratemask |= (uint64_t) 1<<rix;
 	}
 #ifdef IEEE80211_DEBUG
 	if (ieee80211_msg(ni->ni_vap, IEEE80211_MSG_RATECTL)) {
-		uint32_t mask;
+		uint64_t mask;
 
 		ieee80211_note(ni->ni_vap, "[%6D] %s: size 1600 rate/tt",
 		    ni->ni_macaddr, ":", __func__);
@@ -1147,7 +1151,7 @@
 #endif
 	for (y = 0; y < NUM_PACKET_SIZE_BINS; y++) {
 		int size = bin_to_size(y);
-		uint32_t mask;
+		uint64_t mask;
 
 		sn->packets_sent[y] = 0;
 		sn->current_sample_rix[y] = -1;
@@ -1289,10 +1293,10 @@
 	struct ath_softc *sc = arg;
 	const HAL_RATE_TABLE *rt = sc->sc_currates;
 	struct sample_node *sn = ATH_NODE_SAMPLE(ATH_NODE(ni));
-	uint32_t mask;
+	uint64_t mask;
 	int rix, y;
 
-	printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%x\n",
+	printf("\n[%s] refcnt %d static_rix (%d %s) ratemask 0x%qx\n",
 	    ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni),
 	    dot11rate(rt, sn->static_rix),
 	    dot11rate_label(rt, sn->static_rix),
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/ath_rate/sample/sample.h
--- a/head/sys/dev/ath/ath_rate/sample/sample.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/sample/sample.h	Wed Aug 15 11:15:12 2012 +0300
@@ -33,7 +33,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.h 238636 2012-07-20 01:41:18Z adrian $
+ * $FreeBSD: head/sys/dev/ath/ath_rate/sample/sample.h 239284 2012-08-15 07:10:10Z adrian $
  */
 
 /*
@@ -91,7 +91,7 @@
 struct sample_node {
 	int static_rix;			/* rate index of fixed tx rate */
 #define	SAMPLE_MAXRATES	64		/* NB: corresponds to hal info[32] */
-	uint32_t ratemask;		/* bit mask of valid rate indices */
+	uint64_t ratemask;		/* bit mask of valid rate indices */
 	const struct txschedule *sched;	/* tx schedule table */
 
 	const HAL_RATE_TABLE *currates;
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/ath_rate/sample/tx_schedules.h
--- a/head/sys/dev/ath/ath_rate/sample/tx_schedules.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/ath_rate/sample/tx_schedules.h	Wed Aug 15 11:15:12 2012 +0300
@@ -38,7 +38,7 @@
 #define	__ATH_RATE_SAMPLE_TXSCHEDULES_H__
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/tx_schedules.h 221869 2011-05-14 01:53:38Z attilio $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/ath_rate/sample/tx_schedules.h 239286 2012-08-15 07:50:42Z adrian $");
 
 #define A(_r) \
     (((_r) == 6)   ? 0 : (((_r) == 9)   ? 1 : (((_r) == 12)  ? 2 : \
@@ -63,6 +63,10 @@
 	(((_r) == 13) ? 16 : (((_r) == 26) ? 17 : (((_r) == 39) ? 18 : \
 	(((_r) == 52) ? 19 : (((_r) == 78) ? 20 : (((_r) == 104)? 21 : \
 	(((_r) == 117)? 22 : (((_r) == 130)? 23 : 0))))))))
+#define NA3(_r) \
+	(((_r) == 19.5)  ? 24 : (((_r) == 39) ? 25 : (((_r) == 58.5)  ? 26 : \
+	(((_r) == 78)  ? 27 : (((_r) == 117) ? 28 : (((_r) == 156) ? 29 : \
+	(((_r) == 175.5) ? 30 : (((_r) == 195)? 31 : 0))))))))
 static const struct txschedule series_11na[] = {
 	{ 3,A( 6), 3,A(  6), 0,A(  6), 0,A( 6) },       /*   6Mb/s */
 	{ 4,A( 9), 3,A(  6), 4,A(  6), 0,A( 6) },       /*   9Mb/s */
@@ -72,6 +76,9 @@
 	{ 4,A(36), 3,A( 24), 4,A( 18), 2,A( 6) },       /*  36Mb/s */
 	{ 4,A(48), 3,A( 36), 4,A( 24), 2,A(12) },       /*  48Mb/s */
 	{ 4,A(54), 3,A( 48), 4,A( 36), 2,A(24) },       /*  54Mb/s */
+
+	/* 1 stream rates */
+
 	{ 3,NA1( 6.5), 3,NA1( 6.5), 0,NA1( 6.5), 0,NA1(6.5) },  /* 6.5Mb/s */
 	{ 4,NA1(  13), 3,NA1( 6.5), 4,NA1( 6.5), 0,NA1(6.5) },  /*  13Mb/s */
 	{ 4,NA1(19.5), 3,NA1( 6.5), 4,NA1( 6.5), 0,NA1(6.5) },  /*19.5Mb/s */
@@ -80,6 +87,9 @@
 	{ 4,NA1(  52), 3,NA1(  39), 4,NA1(  26), 2,NA1(6.5) },  /*  52Mb/s */
 	{ 4,NA1(58.5), 3,NA1(  52), 4,NA1(  39), 2,NA1( 13) },  /*58.5Mb/s */
 	{ 4,NA1(  65), 3,NA1(58.5), 4,NA1(  52), 2,NA1( 13) },  /*  65Mb/s */
+
+	/* 2 stream rates */
+
 	{ 3,NA2(  13), 3,NA2(  13), 0,NA2(  13), 0,NA2( 13) },  /*  13Mb/s */
 	{ 4,NA2(  26), 3,NA2(  13), 4,NA2(  13), 0,NA2( 13) },  /*  26Mb/s */
 	{ 4,NA2(  39), 3,NA2(  26), 4,NA2(  13), 2,NA2( 13) },  /*  39Mb/s */
@@ -87,9 +97,21 @@
 	{ 4,NA2(  78), 3,NA2(  52), 4,NA2(  39), 2,NA2( 13) },  /*  78Mb/s */
 	{ 4,NA2( 104), 3,NA2(  78), 4,NA2(  52), 2,NA2( 13) },  /* 104Mb/s */
 	{ 4,NA2( 117), 3,NA2( 104), 4,NA2(  78), 2,NA2( 26) },  /* 117Mb/s */
-	{ 4,NA2( 130), 3,NA2( 117), 4,NA2( 104), 2,NA2( 26) }   /* 130Mb/s */
+	{ 4,NA2( 130), 3,NA2( 117), 4,NA2( 104), 2,NA2( 26) },   /* 130Mb/s */
+
+	/* 3 stream rates */
+
+	{ 3,NA3(19.5), 3,NA3(19.5), 0,NA3(19.5), 0,NA3(19.5) },  /*  19Mb/s */
+	{ 3,NA3(  39), 3,NA3(19.5), 0,NA3(19.5), 0,NA3(19.5) },  /*  39Mb/s */
+	{ 3,NA3(58.5), 3,NA3(  39), 0,NA3(19.5), 0,NA3(19.5) },  /*  58Mb/s */
+	{ 3,NA3(  78), 3,NA3(58.5), 0,NA3(  39), 0,NA3(19.5) },  /*  78Mb/s */
+	{ 3,NA3( 117), 3,NA3(  78), 0,NA3(58.5), 0,NA3(19.5) },  /* 117Mb/s */
+	{ 3,NA3( 156), 3,NA3( 117), 0,NA3(  78), 0,NA3(19.5) },  /*  156Mb/s */
+	{ 3,NA3(175.5), 3,NA3( 156), 0,NA3( 117), 0,NA3(  39) },  /*  175Mb/s */
+	{ 3,NA3( 195), 3,NA3( 195), 0,NA3( 156), 0,NA3(58.5) },  /* 195Mb/s */
 };
 #undef A
+#undef NA3
 #undef NA2
 #undef NA1
 
@@ -121,6 +143,11 @@
 	(((_r) == 13)  ? 20 : (((_r) == 26) ? 21 : (((_r) == 39)  ? 22 : \
 	(((_r) == 52)  ? 23 : (((_r) == 78) ? 24 : (((_r) == 104) ? 25 : \
 	(((_r) == 117) ? 26 : (((_r) == 130)? 27 : 0))))))))
+#define NG3(_r) \
+	(((_r) == 19.5)  ? 28 : (((_r) == 39) ? 29 : (((_r) == 58.5)  ? 30 : \
+	(((_r) == 78)  ? 31 : (((_r) == 117) ? 32 : (((_r) == 156) ? 33 : \
+	(((_r) == 175.5) ? 34 : (((_r) == 195)? 35 : 0))))))))
+
 static const struct txschedule series_11ng[] = {
 	{ 3,G( 1), 3,G(  1), 0,G(  1), 0,G( 1) },       /*   1Mb/s */
 	{ 4,G( 2), 3,G(  1), 4,G(  1), 0,G( 1) },       /*   2Mb/s */
@@ -134,6 +161,9 @@
 	{ 4,G(36), 3,G( 24), 4,G( 18), 2,G( 1) },       /*  36Mb/s */
 	{ 4,G(48), 3,G( 36), 4,G( 24), 2,G( 1) },       /*  48Mb/s */
 	{ 4,G(54), 3,G( 48), 4,G( 36), 2,G( 1) },       /*  54Mb/s */
+
+	/* 1 stream rates */
+
 	{ 3,NG1( 6.5), 3,NG1( 6.5), 0,NG1( 6.5), 0,NG1(6.5) },  /* 6.5Mb/s */
 	{ 4,NG1(  13), 3,NG1( 6.5), 4,NG1( 6.5), 0,NG1(6.5) },  /*  13Mb/s */
 	{ 4,NG1(19.5), 3,NG1( 6.5), 4,NG1( 6.5), 0,NG1(6.5) },  /*19.5Mb/s */
@@ -142,6 +172,9 @@
 	{ 4,NG1(  52), 3,NG1(  39), 4,NG1(  26), 2,NG1(6.5) },  /*  52Mb/s */
 	{ 4,NG1(58.5), 3,NG1(  52), 4,NG1(  39), 2,NG1( 13) },  /*58.5Mb/s */
 	{ 4,NG1(  65), 3,NG1(58.5), 4,NG1(  52), 2,NG1( 13) },  /*  65Mb/s */
+
+	/* 2 stream rates */
+
 	{ 3,NG2(  13), 3,NG2(  13), 0,NG2(  13), 0,NG2( 13) },  /*  13Mb/s */
 	{ 4,NG2(  26), 3,NG2(  13), 4,NG2(  13), 0,NG2( 13) },  /*  26Mb/s */
 	{ 4,NG2(  39), 3,NG2(  26), 4,NG2(  13), 2,NG2( 13) },  /*  39Mb/s */
@@ -149,9 +182,22 @@
 	{ 4,NG2(  78), 3,NG2(  52), 4,NG2(  39), 2,NG2( 13) },  /*  78Mb/s */
 	{ 4,NG2( 104), 3,NG2(  78), 4,NG2(  52), 2,NG2( 13) },  /* 104Mb/s */
 	{ 4,NG2( 117), 3,NG2( 104), 4,NG2(  78), 2,NG2( 26) },  /* 117Mb/s */
-	{ 4,NG2( 130), 3,NG2( 117), 4,NG2( 104), 2,NG2( 26) }   /* 130Mb/s */
+	{ 4,NG2( 130), 3,NG2( 117), 4,NG2( 104), 2,NG2( 26) },  /* 130Mb/s */
+
+	/* 3 stream rates */
+
+	{ 3,NG3(19.5), 3,NG3(19.5), 0,NG3(19.5), 0,NG3(19.5) },  /*  19Mb/s */
+	{ 3,NG3(  39), 3,NG3(19.5), 0,NG3(19.5), 0,NG3(19.5) },  /*  39Mb/s */
+	{ 3,NG3(58.5), 3,NG3(  39), 0,NG3(19.5), 0,NG3(19.5) },  /*  58Mb/s */
+	{ 3,NG3(  78), 3,NG3(58.5), 0,NG3(  39), 0,NG3(19.5) },  /*  78Mb/s */
+	{ 3,NG3( 117), 3,NG3(  78), 0,NG3(58.5), 0,NG3(19.5) },  /* 117Mb/s */
+	{ 3,NG3( 156), 3,NG3( 117), 0,NG3(  78), 0,NG3(19.5) },  /*  156Mb/s */
+	{ 3,NG3(175.5), 3,NG3( 156), 0,NG3( 117), 0,NG3(  39) },  /*  175Mb/s */
+	{ 3,NG3( 195), 3,NG3( 195), 0,NG3( 156), 0,NG3(58.5) },  /* 195Mb/s */
+
 };
 #undef G
+#undef NG3
 #undef NG2
 #undef NG1
 
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath.c
--- a/head/sys/dev/ath/if_ath.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath.c	Wed Aug 15 11:15:12 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath.c 238961 2012-07-31 23:54:15Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath.c 239282 2012-08-15 06:48:34Z adrian $");
 
 /*
  * Driver for the Atheros Wireless LAN controller.
@@ -168,12 +168,13 @@
 static int	ath_tx_setup(struct ath_softc *, int, int);
 static void	ath_tx_cleanupq(struct ath_softc *, struct ath_txq *);
 static void	ath_tx_cleanup(struct ath_softc *);
+static int	ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq,
+		    int dosched);
 static void	ath_tx_proc_q0(void *, int);
 static void	ath_tx_proc_q0123(void *, int);
 static void	ath_tx_proc(void *, int);
 static void	ath_txq_sched_tasklet(void *, int);
 static int	ath_chan_set(struct ath_softc *, struct ieee80211_channel *);
-static void	ath_draintxq(struct ath_softc *, ATH_RESET_TYPE reset_type);
 static void	ath_chan_change(struct ath_softc *, struct ieee80211_channel *);
 static void	ath_scan_start(struct ieee80211com *);
 static void	ath_scan_end(struct ieee80211com *);
@@ -443,7 +444,7 @@
 	 *
 	 * XXX PS-Poll
 	 */
-	sc->sc_bhalq = ath_beaconq_setup(ah);
+	sc->sc_bhalq = ath_beaconq_setup(sc);
 	if (sc->sc_bhalq == (u_int) -1) {
 		if_printf(ifp, "unable to setup a beacon xmit queue!\n");
 		error = EIO;
@@ -1674,12 +1675,14 @@
 			 * and blank them. This is the only place we should be
 			 * doing this.
 			 */
-			ATH_PCU_LOCK(sc);
-			txqs = 0xffffffff;
-			ath_hal_gettxintrtxqs(sc->sc_ah, &txqs);
-			sc->sc_txq_active |= txqs;
+			if (! sc->sc_isedma) {
+				ATH_PCU_LOCK(sc);
+				txqs = 0xffffffff;
+				ath_hal_gettxintrtxqs(sc->sc_ah, &txqs);
+				sc->sc_txq_active |= txqs;
+				ATH_PCU_UNLOCK(sc);
+			}
 			taskqueue_enqueue(sc->sc_tq, &sc->sc_txtask);
-			ATH_PCU_UNLOCK(sc);
 		}
 		if (status & HAL_INT_BMISS) {
 			sc->sc_stats.ast_bmiss++;
@@ -2341,6 +2344,14 @@
 	bf->bf_comp = NULL;	/* XXX again, just to be sure */
 	bzero(&bf->bf_state, sizeof(bf->bf_state));
 
+	/*
+	 * Track the descriptor ID only if doing EDMA
+	 */
+	if (sc->sc_isedma) {
+		bf->bf_descid = sc->sc_txbuf_descid;
+		sc->sc_txbuf_descid++;
+	}
+
 	return bf;
 }
 
@@ -3581,19 +3592,68 @@
 }
 
 /*
+ * Process the completion of the given buffer.
+ *
+ * This calls the rate control update and then the buffer completion.
+ * This will either free the buffer or requeue it.  In any case, the
+ * bf pointer should be treated as invalid after this function is called.
+ */
+void
+ath_tx_process_buf_completion(struct ath_softc *sc, struct ath_txq *txq,
+    struct ath_tx_status *ts, struct ath_buf *bf)
+{
+	struct ieee80211_node *ni = bf->bf_node;
+	struct ath_node *an = NULL;
+
+	ATH_TXQ_UNLOCK_ASSERT(txq);
+
+	/* If unicast frame, update general statistics */
+	if (ni != NULL) {
+		an = ATH_NODE(ni);
+		/* update statistics */
+		ath_tx_update_stats(sc, ts, bf);
+	}
+
+	/*
+	 * Call the completion handler.
+	 * The completion handler is responsible for
+	 * calling the rate control code.
+	 *
+	 * Frames with no completion handler get the
+	 * rate control code called here.
+	 */
+	if (bf->bf_comp == NULL) {
+		if ((ts->ts_status & HAL_TXERR_FILT) == 0 &&
+		    (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0) {
+			/*
+			 * XXX assume this isn't an aggregate
+			 * frame.
+			 */
+			ath_tx_update_ratectrl(sc, ni,
+			     bf->bf_state.bfs_rc, ts,
+			    bf->bf_state.bfs_pktlen, 1,
+			    (ts->ts_status == 0 ? 0 : 1));
+		}
+		ath_tx_default_comp(sc, bf, 0);
+	} else
+		bf->bf_comp(sc, bf, 0);
+}
+
+
+
+/*
  * Process completed xmit descriptors from the specified queue.
  * Kick the packet scheduler if needed. This can occur from this
  * particular task.
  */
-int
-ath_legacy_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
+static int
+ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
 {
 	struct ath_hal *ah = sc->sc_ah;
 	struct ath_buf *bf;
 	struct ath_desc *ds;
 	struct ath_tx_status *ts;
 	struct ieee80211_node *ni;
-	struct ath_node *an;
 #ifdef	IEEE80211_SUPPORT_SUPERG
 	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
 #endif	/* IEEE80211_SUPPORT_SUPERG */
@@ -3665,36 +3725,12 @@
 		}
 		ATH_TXQ_UNLOCK(txq);
 
-		/* If unicast frame, update general statistics */
-		if (ni != NULL) {
-			an = ATH_NODE(ni);
-			/* update statistics */
-			ath_tx_update_stats(sc, ts, bf);
-		}
-
 		/*
-		 * Call the completion handler.
-		 * The completion handler is responsible for
-		 * calling the rate control code.
-		 *
-		 * Frames with no completion handler get the
-		 * rate control code called here.
+		 * Update statistics and call completion
 		 */
-		if (bf->bf_comp == NULL) {
-			if ((ts->ts_status & HAL_TXERR_FILT) == 0 &&
-			    (bf->bf_state.bfs_txflags & HAL_TXDESC_NOACK) == 0) {
-				/*
-				 * XXX assume this isn't an aggregate
-				 * frame.
-				 */
-				ath_tx_update_ratectrl(sc, ni,
-				     bf->bf_state.bfs_rc, ts,
-				    bf->bf_state.bfs_pktlen, 1,
-				    (ts->ts_status == 0 ? 0 : 1));
-			}
-			ath_tx_default_comp(sc, bf, 0);
-		} else
-			bf->bf_comp(sc, bf, 0);
+		ath_tx_process_buf_completion(sc, txq, ts, bf);
+
+
 	}
 #ifdef IEEE80211_SUPPORT_SUPERG
 	/*
@@ -3986,7 +4022,7 @@
 }
 
 void
-ath_legacy_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
 {
 #ifdef ATH_DEBUG
 	struct ath_hal *ah = sc->sc_ah;
@@ -4012,6 +4048,17 @@
 		bf = TAILQ_FIRST(&txq->axq_q);
 		if (bf == NULL) {
 			txq->axq_link = NULL;
+			/*
+			 * There's currently no flag that indicates
+			 * a buffer is on the FIFO.  So until that
+			 * occurs, just clear the FIFO counter here.
+			 *
+			 * Yes, this means that if something in parallel
+			 * is pushing things onto this TXQ and pushing
+			 * _that_ into the hardware, things will get
+			 * very fruity very quickly.
+			 */
+			txq->axq_fifo_depth = 0;
 			ATH_TXQ_UNLOCK(txq);
 			break;
 		}
@@ -4021,10 +4068,20 @@
 #ifdef ATH_DEBUG
 		if (sc->sc_debug & ATH_DEBUG_RESET) {
 			struct ieee80211com *ic = sc->sc_ifp->if_l2com;
-
-			ath_printtxbuf(sc, bf, txq->axq_qnum, ix,
-				ath_hal_txprocdesc(ah, bf->bf_lastds,
+			int status = 0;
+
+			/*
+			 * EDMA operation has a TX completion FIFO
+			 * separate from the TX descriptor, so this
+			 * method of checking the "completion" status
+			 * is wrong.
+			 */
+			if (! sc->sc_isedma) {
+				status = (ath_hal_txprocdesc(ah,
+				    bf->bf_lastds,
 				    &bf->bf_status.ds_txstat) == HAL_OK);
+			}
+			ath_printtxbuf(sc, bf, txq->axq_qnum, ix, status);
 			ieee80211_dump_pkt(ic, mtod(bf->bf_m, const uint8_t *),
 			    bf->bf_m->m_len, 0, -1);
 		}
@@ -4065,7 +4122,7 @@
 	(void) ath_hal_stoptxdma(ah, txq->axq_qnum);
 }
 
-static int
+int
 ath_stoptxdma(struct ath_softc *sc)
 {
 	struct ath_hal *ah = sc->sc_ah;
@@ -4093,8 +4150,8 @@
 /*
  * Drain the transmit queues and reclaim resources.
  */
-static void
-ath_draintxq(struct ath_softc *sc, ATH_RESET_TYPE reset_type)
+void
+ath_legacy_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type)
 {
 #ifdef	ATH_DEBUG
 	struct ath_hal *ah = sc->sc_ah;
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_beacon.c
--- a/head/sys/dev/ath/if_ath_beacon.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_beacon.c	Wed Aug 15 11:15:12 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_beacon.c 239051 2012-08-05 10:12:27Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_beacon.c 239201 2012-08-11 23:26:19Z adrian $");
 
 /*
  * Driver for the Atheros Wireless LAN controller.
@@ -108,8 +108,9 @@
  * Setup a h/w transmit queue for beacons.
  */
 int
-ath_beaconq_setup(struct ath_hal *ah)
+ath_beaconq_setup(struct ath_softc *sc)
 {
+	struct ath_hal *ah = sc->sc_ah;
 	HAL_TXQ_INFO qi;
 
 	memset(&qi, 0, sizeof(qi));
@@ -118,6 +119,10 @@
 	qi.tqi_cwmax = HAL_TXQ_USEDEFAULT;
 	/* NB: for dynamic turbo, don't enable any other interrupts */
 	qi.tqi_qflags = HAL_TXQ_TXDESCINT_ENABLE;
+	if (sc->sc_isedma)
+		qi.tqi_qflags |= HAL_TXQ_TXOKINT_ENABLE |
+		    HAL_TXQ_TXERRINT_ENABLE;
+
 	return ath_hal_setuptxqueue(ah, HAL_TX_QUEUE_BEACON, &qi);
 }
 
@@ -268,6 +273,7 @@
 	u_int8_t rix, rate;
 	HAL_DMA_ADDR bufAddrList[4];
 	uint32_t segLenList[4];
+	HAL_11N_RATE_SERIES rc[4];
 
 	DPRINTF(sc, ATH_DEBUG_BEACON_PROC, "%s: m %p len %u\n",
 		__func__, m, m->m_len);
@@ -324,6 +330,26 @@
 		, 0				/* rts/cts rate */
 		, 0				/* rts/cts duration */
 	);
+
+	/*
+	 * The EDMA HAL currently assumes that _all_ rate control
+	 * settings are done in ath_hal_set11nratescenario(), rather
+	 * than in ath_hal_setuptxdesc().
+	 */
+	if (sc->sc_isedma) {
+		memset(&rc, 0, sizeof(rc));
+
+		rc[0].ChSel = sc->sc_txchainmask;
+		rc[0].Tries = 1;
+		rc[0].Rate = rt->info[rix].rateCode;
+		rc[0].RateIndex = rix;
+		rc[0].tx_power_cap = 0x3f;
+		rc[0].PktDuration =
+		    ath_hal_computetxtime(ah, rt, roundup(m->m_len, 4),
+		        rix, 0);
+		ath_hal_set11nratescenario(ah, ds, 0, 0, rc, 4, flags);
+	}
+
 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
 	segLenList[0] = roundup(m->m_len, 4);
 	segLenList[1] = segLenList[2] = segLenList[3] = 0;
@@ -458,12 +484,15 @@
 		 * This should never fail since we check above that no frames
 		 * are still pending on the queue.
 		 */
-		if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
-			DPRINTF(sc, ATH_DEBUG_ANY,
-				"%s: beacon queue %u did not stop?\n",
-				__func__, sc->sc_bhalq);
+		if (! sc->sc_isedma) {
+			if (!ath_hal_stoptxdma(ah, sc->sc_bhalq)) {
+				DPRINTF(sc, ATH_DEBUG_ANY,
+					"%s: beacon queue %u did not stop?\n",
+					__func__, sc->sc_bhalq);
+			}
 		}
 		/* NB: cabq traffic should already be queued and primed */
+
 		ath_hal_puttxbuf(ah, sc->sc_bhalq, bfaddr);
 		ath_hal_txstart(ah, sc->sc_bhalq);
 
@@ -673,6 +702,7 @@
 	struct ieee80211com *ic = sc->sc_ifp->if_l2com;
 	struct ieee80211_node *ni;
 	u_int32_t nexttbtt, intval, tsftu;
+	u_int32_t nexttbtt_u8, intval_u8;
 	u_int64_t tsf;
 
 	if (vap == NULL)
@@ -836,7 +866,21 @@
 			sc->sc_imask |= HAL_INT_SWBA;	/* beacon prepare */
 			ath_beaconq_config(sc);
 		}
-		ath_hal_beaconinit(ah, nexttbtt, intval);
+
+		/*
+		 * Now dirty things because for now, the EDMA HAL has
+		 * nexttbtt and intval is TU/8.
+		 */
+		if (sc->sc_isedma) {
+			nexttbtt_u8 = (nexttbtt << 3);
+			intval_u8 = (intval << 3);
+			if (intval & HAL_BEACON_ENA)
+				intval_u8 |= HAL_BEACON_ENA;
+			if (intval & HAL_BEACON_RESET_TSF)
+				intval_u8 |= HAL_BEACON_RESET_TSF;
+			ath_hal_beaconinit(ah, nexttbtt_u8, intval_u8);
+		} else
+			ath_hal_beaconinit(ah, nexttbtt, intval);
 		sc->sc_bmisscount = 0;
 		ath_hal_intrset(ah, sc->sc_imask);
 		/*
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_beacon.h
--- a/head/sys/dev/ath/if_ath_beacon.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_beacon.h	Wed Aug 15 11:15:12 2012 +0300
@@ -26,14 +26,14 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: head/sys/dev/ath/if_ath_beacon.h 235680 2012-05-20 04:14:29Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_ath_beacon.h 239201 2012-08-11 23:26:19Z adrian $
  */
 #ifndef	__IF_ATH_BEACON_H__
 #define	__IF_ATH_BEACON_H__
 
 extern	int ath_bstuck_threshold;
 
-extern	int ath_beaconq_setup(struct ath_hal *ah);
+extern	int ath_beaconq_setup(struct ath_softc *sc);
 extern	int ath_beaconq_config(struct ath_softc *sc);
 extern	void ath_beacon_config(struct ath_softc *sc,
 	    struct ieee80211vap *vap);
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_debug.c
--- a/head/sys/dev/ath/if_ath_debug.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_debug.c	Wed Aug 15 11:15:12 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_debug.c 238275 2012-07-09 06:39:46Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_debug.c 239199 2012-08-11 22:39:27Z adrian $");
 
 #include "opt_inet.h"
 #include "opt_ath.h"
@@ -158,7 +158,8 @@
 			    ds->ds_ctl0, ds->ds_ctl1,
 			    ds->ds_hw[0], ds->ds_hw[1],
 			    ds->ds_hw[2], ds->ds_hw[3]);
-			if (ah->ah_magic == 0x20065416) {
+			if (ah->ah_magic == 0x20065416 ||
+			    ah->ah_magic == 0x19741014) {
 				printf("        %08x %08x %08x %08x %08x %08x %08x %08x\n",
 				    ds->ds_hw[4], ds->ds_hw[5], ds->ds_hw[6],
 				    ds->ds_hw[7], ds->ds_hw[8], ds->ds_hw[9],
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_misc.h
--- a/head/sys/dev/ath/if_ath_misc.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_misc.h	Wed Aug 15 11:15:12 2012 +0300
@@ -26,7 +26,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: head/sys/dev/ath/if_ath_misc.h 238931 2012-07-31 03:09:48Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_ath_misc.h 239262 2012-08-14 22:32:20Z adrian $
  */
 #ifndef	__IF_ATH_MISC_H__
 #define	__IF_ATH_MISC_H__
@@ -96,9 +96,16 @@
 	    struct ath_descdma *dd, ath_bufhead *head);
 
 extern	void ath_legacy_attach_comp_func(struct ath_softc *sc);
-extern	void ath_legacy_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq);
-extern	int ath_legacy_tx_processq(struct ath_softc *sc, struct ath_txq *txq,
-	    int dosched);
+
+extern	void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq);
+
+extern	void ath_legacy_tx_drain(struct ath_softc *sc,
+	    ATH_RESET_TYPE reset_type);
+
+extern	void ath_tx_process_buf_completion(struct ath_softc *sc,
+	    struct ath_txq *txq, struct ath_tx_status *ts, struct ath_buf *bf);
+
+extern	int ath_stoptxdma(struct ath_softc *sc);
 
 /*
  * This is only here so that the RX proc function can call it.
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_sysctl.c
--- a/head/sys/dev/ath/if_ath_sysctl.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_sysctl.c	Wed Aug 15 11:15:12 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_sysctl.c 238507 2012-07-15 20:51:41Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_sysctl.c 239263 2012-08-14 22:34:22Z adrian $");
 
 /*
  * Driver for the Atheros Wireless LAN controller.
@@ -357,10 +357,11 @@
 
 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
 		if (ATH_TXQ_SETUP(sc, i)) {
-			printf("HW TXQ %d: axq_depth=%d, axq_aggr_depth=%d\n",
+			printf("HW TXQ %d: axq_depth=%d, axq_aggr_depth=%d, axq_fifo_depth=%d\n",
 			    i,
 			    sc->sc_txq[i].axq_depth,
-			    sc->sc_txq[i].axq_aggr_depth);
+			    sc->sc_txq[i].axq_aggr_depth,
+			    sc->sc_txq[i].axq_fifo_depth);
 		}
 	}
 
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_tx.c
--- a/head/sys/dev/ath/if_ath_tx.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_tx.c	Wed Aug 15 11:15:12 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx.c 239120 2012-08-07 00:42:46Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx.c 239205 2012-08-12 00:46:15Z adrian $");
 
 /*
  * Driver for the Atheros Wireless LAN controller.
@@ -120,7 +120,8 @@
 static inline int
 ath_tx_is_11n(struct ath_softc *sc)
 {
-	return (sc->sc_ah->ah_magic == 0x20065416);
+	return ((sc->sc_ah->ah_magic == 0x20065416) ||
+		    (sc->sc_ah->ah_magic == 0x19741014));
 }
 
 /*
@@ -4570,6 +4571,6 @@
 
 	sc->sc_tx.xmit_dma_restart = ath_legacy_tx_dma_restart;
 	sc->sc_tx.xmit_handoff = ath_legacy_xmit_handoff;
-	sc->sc_tx.xmit_processq = ath_legacy_tx_processq;
-	sc->sc_tx.xmit_drainq = ath_legacy_tx_draintxq;
+
+	sc->sc_tx.xmit_drain = ath_legacy_tx_drain;
 }
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_tx.h
--- a/head/sys/dev/ath/if_ath_tx.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_tx.h	Wed Aug 15 11:15:12 2012 +0300
@@ -26,7 +26,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: head/sys/dev/ath/if_ath_tx.h 238931 2012-07-31 03:09:48Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_ath_tx.h 239205 2012-08-12 00:46:15Z adrian $
  */
 #ifndef	__IF_ATH_TX_H__
 #define	__IF_ATH_TX_H__
@@ -134,10 +134,8 @@
 	(_sc)->sc_tx.xmit_dma_restart((_sc), (_txq))
 #define	ath_tx_handoff(_sc, _txq, _bf)		\
 	(_sc)->sc_tx.xmit_handoff((_sc), (_txq), (_bf))
-#define	ath_tx_draintxq(_sc, _txq)		\
-	(_sc)->sc_tx.xmit_drainq((_sc), (_txq))
-#define	ath_tx_processq(_sc, _txq, _dosched)	\
-	(_sc)->sc_tx.xmit_processq((_sc), (_txq), (_dosched))
+#define	ath_draintxq(_sc, _rtype)		\
+	(_sc)->sc_tx.xmit_drain((_sc), (_rtype))
 
 extern	void ath_xmit_setup_legacy(struct ath_softc *sc);
 
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_ath_tx_edma.c
--- a/head/sys/dev/ath/if_ath_tx_edma.c	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_ath_tx_edma.c	Wed Aug 15 11:15:12 2012 +0300
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_edma.c 238931 2012-07-31 03:09:48Z adrian $");
+__FBSDID("$FreeBSD: head/sys/dev/ath/if_ath_tx_edma.c 239205 2012-08-12 00:46:15Z adrian $");
 
 /*
  * Driver for the Atheros Wireless LAN controller.
@@ -132,7 +132,7 @@
 
 /*
  * Re-initialise the DMA FIFO with the current contents of
- * said FIFO.
+ * said TXQ.
  *
  * This should only be called as part of the chip reset path, as it
  * assumes the FIFO is currently empty.
@@ -152,6 +152,90 @@
 }
 
 /*
+ * Hand off this frame to a hardware queue.
+ *
+ * Things are a bit hairy in the EDMA world.  The TX FIFO is only
+ * 8 entries deep, so we need to keep track of exactly what we've
+ * pushed into the FIFO and what's just sitting in the TX queue,
+ * waiting to go out.
+ *
+ * So this is split into two halves - frames get appended to the
+ * TXQ; then a scheduler is called to push some frames into the
+ * actual TX FIFO.
+ */
+static void
+ath_edma_xmit_handoff_hw(struct ath_softc *sc, struct ath_txq *txq,
+    struct ath_buf *bf)
+{
+	struct ath_hal *ah = sc->sc_ah;
+
+	ATH_TXQ_LOCK_ASSERT(txq);
+
+	KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
+	    ("%s: busy status 0x%x", __func__, bf->bf_flags));
+
+	/*
+	 * XXX TODO: write a hard-coded check to ensure that
+	 * the queue id in the TX descriptor matches txq->axq_qnum.
+	 */
+
+	/* Update aggr stats */
+	if (bf->bf_state.bfs_aggr)
+		txq->axq_aggr_depth++;
+
+	/* Push and update frame stats */
+	ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+
+	/* Only schedule to the FIFO if there's space */
+	if (txq->axq_fifo_depth < HAL_TXFIFO_DEPTH) {
+		ath_hal_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+		ath_hal_txstart(ah, txq->axq_qnum);
+	}
+}
+
+/*
+ * Hand off this frame to a multicast software queue.
+ *
+ * Unlike legacy DMA, this doesn't chain together frames via the
+ * link pointer.  Instead, they're just added to the queue.
+ * When it comes time to populate the CABQ, these frames should
+ * be individually pushed into the FIFO as appropriate.
+ *
+ * Yes, this does mean that I'll eventually have to flesh out some
+ * replacement code to handle populating the CABQ, rather than
+ * what's done in ath_beacon_generate().  It'll have to push each
+ * frame from the HW CABQ to the FIFO rather than just appending
+ * it to the existing TXQ and kicking off DMA.
+ */
+static void
+ath_edma_xmit_handoff_mcast(struct ath_softc *sc, struct ath_txq *txq,
+    struct ath_buf *bf)
+{
+
+	ATH_TXQ_LOCK_ASSERT(txq);
+	KASSERT((bf->bf_flags & ATH_BUF_BUSY) == 0,
+	    ("%s: busy status 0x%x", __func__, bf->bf_flags));
+
+	/*
+	 * XXX this is mostly duplicated in ath_tx_handoff_mcast().
+	 */
+	if (ATH_TXQ_FIRST(txq) != NULL) {
+		struct ath_buf *bf_last = ATH_TXQ_LAST(txq, axq_q_s);
+		struct ieee80211_frame *wh;
+
+		/* mark previous frame */
+		wh = mtod(bf_last->bf_m, struct ieee80211_frame *);
+		wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
+
+		/* sync descriptor to memory */
+		bus_dmamap_sync(sc->sc_dmat, bf_last->bf_dmamap,
+		   BUS_DMASYNC_PREWRITE);
+	}
+
+	ATH_TXQ_INSERT_TAIL(txq, bf, bf_list);
+}
+
+/*
  * Handoff this frame to the hardware.
  *
  * For the multicast queue, this will treat it as a software queue
@@ -173,17 +257,26 @@
     struct ath_buf *bf)
 {
 
+	ATH_TXQ_LOCK_ASSERT(txq);
+
 	device_printf(sc->sc_dev, "%s: called; bf=%p, txq=%p, qnum=%d\n",
 	    __func__,
 	    bf,
 	    txq,
 	    txq->axq_qnum);
 
+	if (txq->axq_qnum == ATH_TXQ_SWQ)
+		ath_edma_xmit_handoff_mcast(sc, txq, bf);
+	else
+		ath_edma_xmit_handoff_hw(sc, txq, bf);
+
+#if 0
 	/*
 	 * XXX For now this is a placeholder; free the buffer
 	 * and inform the stack that the TX failed.
 	 */
 	ath_tx_default_comp(sc, bf, 1);
+#endif
 }
 
 static int
@@ -255,26 +348,55 @@
 	return (0);
 }
 
-static int
-ath_edma_tx_processq(struct ath_softc *sc, struct ath_txq *txq, int dosched)
+/*
+ * Drain all TXQs, potentially after completing the existing completed
+ * frames.
+ */
+static void
+ath_edma_tx_drain(struct ath_softc *sc, ATH_RESET_TYPE reset_type)
 {
 
-	return (0);
+	device_printf(sc->sc_dev, "%s: called\n", __func__);
 }
 
-static void
-ath_edma_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq)
-{
-
-}
-
+/*
+ * Process the TX status queue.
+ */
 static void
 ath_edma_tx_proc(void *arg, int npending)
 {
 	struct ath_softc *sc = (struct ath_softc *) arg;
+	struct ath_hal *ah = sc->sc_ah;
+	HAL_STATUS status;
+	struct ath_tx_status ts;
+	struct ath_txq *txq;
 
 	device_printf(sc->sc_dev, "%s: called, npending=%d\n",
 	    __func__, npending);
+
+	for (;;) {
+		ATH_TXSTATUS_LOCK(sc);
+		status = ath_hal_txprocdesc(ah, NULL, (void *) &ts);
+		ATH_TXSTATUS_UNLOCK(sc);
+
+		if (status != HAL_OK)
+			break;
+
+		/*
+		 * At this point we have a valid status descriptor.
+		 * The QID and descriptor ID (which currently isn't set)
+		 * is part of the status.
+		 *
+		 * We then assume that the descriptor in question is the
+		 * -head- of the given QID.  Eventually we should verify
+		 * this by using the descriptor ID.
+		 */
+		device_printf(sc->sc_dev, "%s: qcuid=%d\n",
+		    __func__,
+		    ts.ts_queue_id);
+
+		txq = &sc->sc_txq[ts.ts_queue_id];
+	}
 }
 
 static void
@@ -306,6 +428,5 @@
 
 	sc->sc_tx.xmit_dma_restart = ath_edma_dma_restart;
 	sc->sc_tx.xmit_handoff = ath_edma_xmit_handoff;
-	sc->sc_tx.xmit_processq = ath_edma_tx_processq;
-	sc->sc_tx.xmit_drainq = ath_edma_tx_draintxq;
+	sc->sc_tx.xmit_drain = ath_edma_tx_drain;
 }
diff -r f9d564d21599 -r 7fffa673adcd head/sys/dev/ath/if_athvar.h
--- a/head/sys/dev/ath/if_athvar.h	Fri Aug 10 16:14:45 2012 +0300
+++ b/head/sys/dev/ath/if_athvar.h	Wed Aug 15 11:15:12 2012 +0300
@@ -26,7 +26,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  * THE POSSIBILITY OF SUCH DAMAGES.
  *
- * $FreeBSD: head/sys/dev/ath/if_athvar.h 239053 2012-08-05 11:24:21Z adrian $
+ * $FreeBSD: head/sys/dev/ath/if_athvar.h 239282 2012-08-15 06:48:34Z adrian $
  */
 
 /*
@@ -191,6 +191,7 @@
 	int			bf_nseg;
 	HAL_STATUS		bf_rxstatus;
 	uint16_t		bf_flags;	/* status flags (below) */
+	uint16_t		bf_descid;	/* 16 bit descriptor ID */
 	struct ath_desc		*bf_desc;	/* virtual addr of desc */
 	struct ath_desc_status	bf_status;	/* tx/rx status */
 	bus_addr_t		bf_daddr;	/* physical addr of desc */
@@ -304,6 +305,7 @@
 #define	ATH_TXQ_PUTPENDING	0x0001		/* ath_hal_puttxbuf pending */
 	u_int			axq_depth;	/* queue depth (stat only) */
 	u_int			axq_aggr_depth;	/* how many aggregates are queued */
+	u_int			axq_fifo_depth;	/* depth of FIFO frames */
 	u_int			axq_intrcnt;	/* interrupt count */
 	u_int32_t		*axq_link;	/* link ptr in last TX desc */
 	TAILQ_HEAD(axq_q_s, ath_buf)	axq_q;		/* transmit queue */
@@ -326,7 +328,10 @@
 #define	ATH_TXQ_LOCK_DESTROY(_tq)	mtx_destroy(&(_tq)->axq_lock)
 #define	ATH_TXQ_LOCK(_tq)		mtx_lock(&(_tq)->axq_lock)
 #define	ATH_TXQ_UNLOCK(_tq)		mtx_unlock(&(_tq)->axq_lock)
-#define	ATH_TXQ_LOCK_ASSERT(_tq)	mtx_assert(&(_tq)->axq_lock, MA_OWNED)
+#define	ATH_TXQ_LOCK_ASSERT(_tq)	\
+	    mtx_assert(&(_tq)->axq_lock, MA_OWNED)
+#define	ATH_TXQ_UNLOCK_ASSERT(_tq)	\
+	    mtx_assert(&(_tq)->axq_lock, MA_NOTOWNED)
 #define	ATH_TXQ_IS_LOCKED(_tq)		mtx_owned(&(_tq)->axq_lock)
 
 #define	ATH_TID_LOCK_ASSERT(_sc, _tid)	\
@@ -344,6 +349,7 @@
 	TAILQ_REMOVE(&(_tq)->axq_q, _elm, _field); \
 	(_tq)->axq_depth--; \
 } while (0)
+#define	ATH_TXQ_FIRST(_tq)		TAILQ_FIRST(&(_tq)->axq_q)
 #define	ATH_TXQ_LAST(_tq, _field)	TAILQ_LAST(&(_tq)->axq_q, _field)
 
 struct ath_vap {
@@ -414,11 +420,8 @@
 			    struct ath_txq *txq);
 	void		(*xmit_handoff)(struct ath_softc *sc,
 			    struct ath_txq *txq, struct ath_buf *bf);
-
-	void		(*xmit_drainq)(struct ath_softc *sc,
-			    struct ath_txq *txq);
-	int		(*xmit_processq)(struct ath_softc *sc,
-			    struct ath_txq *txq, int dosched);
+	void		(*xmit_drain)(struct ath_softc *sc,
+			    ATH_RESET_TYPE reset_type);
 };
 
 struct ath_softc {
@@ -574,6 +577,7 @@
 	u_int			sc_monpass;	/* frames to pass in mon.mode */
 
 	struct ath_descdma	sc_txdma;	/* TX descriptors */
+	uint16_t		sc_txbuf_descid;
 	ath_bufhead		sc_txbuf;	/* transmit buffer */
 	int			sc_txbuf_cnt;	/* how many buffers avail */
 	struct ath_descdma	sc_txdma_mgmt;	/* mgmt TX descriptors */


More information about the Zrouter-src-freebsd mailing list