Search Linux Wireless

Fwd: CT firmware and linux kernel patches for OpenWRT( ar71xx - Tp-Link 1750AC )

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Sven,

Thank you for your patch.

I applied that patch and tried to test by executing sending deauth
command using aireplay-ng. However, I got following error.

root@OpenWrt:/# aireplay-ng -0 1 -a 10:C3:7B:DF:EA:54 -c 9C:F3:87:49:96:7e wlan0
[  286.183915] device wlan0 entered promiscuous mode
22:15:55  Waiting for beacon frame (BSSID: 10:C3:7B:DF:EA:54) on channel 36
[  286.369861] ------------[ cut here ]------------
[  286.374611] WARNING: CPU: 0 PID: 1150 at
/home/openwrt/ct/openwrt/build_dir/target-mips_34kc_uClibc-0.9.33.2/linux-ar71xx_generic/compat-wireless-2015-06-22/drivers/net/wireless/ath/ath10k/mac.c:3695
0x87204cec()
[  286.393771] Modules linked in: pppoe ppp_async iptable_nat ath9k
pppox ppp_generic nf_nat_ipv4 nf_conntrack_ipv6 nf_conntrack_ipv4
ipt_REJECT ipt_MASQUERADE ath9k_common xt_time xt_tcpudp xt_state
xt_nat xt_multiport xt_mark xt_mac xt_limit xt_id xt_conntrack
xt_comment xt_TCPMSS xt_REDIRECT xt_LOG xt_CT slhc nf_reject_ipv4
nf_nat_redirect nf_nat_masquerade_ipv4 nf_nat_ftp nf_nat nf_log_ipv4
nf_defrag_ipv6 nf_defrag_ipv4 nf_conntrack_rtcache nf_conntrack_ftp
nf_conntrack iptable_raw iptable_mangle iptable_filter ip_tables
crc_ccitt ath9k_hw ath10k_pci ath10k_core ath mac80211 cfg80211 compat
ledtrig_usbdev ip6t_REJECT nf_reject_ipv6 nf_log_ipv6 nf_log_common
ip6table_raw ip6table_mangle ip6table_filter ip6_tables x_tables ipv6
arc4 crypto_blkcipher ohci_platform ohci_hcd ehci_platform ehci_hcd
gpio_button_hotplug usbcore nls_base usb_common
[  286.469918] CPU: 0 PID: 1150 Comm: aireplay-ng Not tainted 4.1.2 #6
[  286.476273] Stack : 803c42b2 00000037 00000000 00000001 80318d80
80371f03 878f5ba0 0000047e
          803c3510 00000001 00000000 00000000 871d0000 800a6564
00000003 8031e0f4
          00000e6f 00000001 8031c608 86623a84 871d0000 800a4b74
803c42b2 000000c8
          00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000
          00000000 00000000 00000000 00000000 00000000 00000000
00000000 00000000
          ...
[  286.512635] Call Trace:
[  286.515127] [<80071be8>] show_stack+0x48/0x70
[  286.519554] [<8008188c>] warn_slowpath_common+0xa0/0xd0
[  286.524867] [<80081944>] warn_slowpath_null+0x18/0x24
[  286.530024] [<87204cec>] 0x87204cec
[  286.533568]
[  286.535076] ---[ end trace d3f6cfc1171daefd ]---

Please let me know if I need to do any.

I need to send De-authentication command in monitor mode.


Thanks and Regards,
S Prasad

---------- Forwarded message ----------
From: Sven Eckelmann <sven@xxxxxxxxxxxxx>
Date: Fri, Aug 28, 2015 at 8:48 AM
Subject: Re: CT firmware and linux kernel patches for OpenWRT( ar71xx
- Tp-Link 1750AC )
To: s prasad <sprasad.kandregula@xxxxxxxxx>


[mailing lists removed - see other mail. please continue discussion
 on mailing list]

On Wednesday 26 August 2015 18:59:51 s prasad wrote:
> Does anybody have patches for CT firmware testing using OpenWRT environment.
> I tried to create patch, however OpenWRT patches supporting only for
> kernel versions 3.18 and 4.1 at the same time CT Kernels supporting
> 3.17_dev, 4.0.4 and 4.2.x. Both are miss matching.
>
> Can somebody help me if they have patches or to create patches.

Attached is the patch with the changes for mac80211. You still have to
select the "Firmware from Candelatech" under ath10k. Don't select
"Firmware optimized for AP operation (v10.1 / API v2)". I know that this
selection should be done more cleanly but I only needed it for testing :)

Also an example patch for the mentioned iw hack is attached.

You just have to checkout openwrt r46435 (in git
113f685179b34015d615530575c73e61fc913039), apply these two patches,
select your device, enable ath10k, enable the Candelatech firmware and
build it.

Kind regards,
        Sven


-- 
S Prasad Kandregula
From 3de347c1f83b09f1ac4190a66d53992116fa66d2 Mon Sep 17 00:00:00 2001
From: Sven Eckelmann <sven@xxxxxxxxxxxxx>
Date: Mon, 16 Mar 2015 17:28:39 +0100
Subject: [PATCH] iw: Hardcode VHT channel 36 in iw for testing

---
diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile
index cc98fb7..57db76f 100644
--- a/package/kernel/mac80211/Makefile
+++ b/package/kernel/mac80211/Makefile
@@ -144,6 +144,16 @@ define Download/ath10k-firmware
 endef
 $(eval $(call Download,ath10k-firmware))
 
+ATH10K_CT_FW:=firmware-2-ct-full-community-14.bin
+
+define Download/ath10k-firmware-ct
+  FILE:=$(ATH10K_CT_FW)
+  URL:=http://www.candelatech.com/downloads/
+  MD5SUM:=800799459c20c1683138c74b3ba58f25
+endef
+$(eval $(call Download,ath10k-firmware-ct))
+
+
 # Prism54 drivers
 P54PCIFW:=2.13.12.0.arm
 P54USBFW:=2.13.24.0.lm87.arm
@@ -630,6 +640,14 @@ define KernelPackage/ath10k/config
 		  Use the ath10k firmware from the 10.1 SDK using API v2 optimized
 		  for access point operation if the default firmware keeps crashing.
 
+	config ATH10K_CT_FW
+		bool "Firmware from Candelatech"
+		default n
+		depends on !ATH10K_STA_FW
+		help
+		  Use the ath10k firmware optimized for IBSS and access point
+		  operation.
+
   endif
 endef
 
@@ -1862,10 +1880,18 @@ ifeq ($(CONFIG_ATH10K_API2_FW),y)
 		$(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/10.1/firmware-2.bin_10.1.467.2-1 \
 		$(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-2.bin
 else
+
+ifeq ($(CONFIG_ATH10K_CT_FW),y)
+	$(INSTALL_DATA) \
+		$(DL_DIR)/$(ATH10K_CT_FW) \
+		$(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-2.bin
+else
 	$(INSTALL_DATA) \
 		$(PKG_BUILD_DIR)/$(PKG_ATH10K_LINUX_FIRMWARE_SUBDIR)/10.2.4/untested/firmware-5.bin_10.2.4.70-2 \
 		$(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-5.bin
 endif
+
+endif
 endef
 
 define KernelPackage/mwl8k/install
diff --git a/package/kernel/mac80211/patches/999-0001-ath-Add-time-stamp-to-debug-messages.patch b/package/kernel/mac80211/patches/999-0001-ath-Add-time-stamp-to-debug-messages.patch
new file mode 100644
index 0000000..a75edcb
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0001-ath-Add-time-stamp-to-debug-messages.patch
@@ -0,0 +1,43 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 13 Nov 2013 10:14:54 -0800
+Subject: [PATCH] ath: Add time-stamp to debug messages.
+
+dmesg has no time-stamps, and var/log/messages doesn't have
+high-precision (at least by default), to explicitly add stamps
+to ath debug messages.
+---
+ drivers/net/wireless/ath/main.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/main.c b/drivers/net/wireless/ath/main.c
+index 338d72337604..0a2cc5bef89e 100644
+--- a/drivers/net/wireless/ath/main.c
++++ b/drivers/net/wireless/ath/main.c
+@@ -71,6 +71,7 @@ EXPORT_SYMBOL(ath_is_mybeacon);
+ void ath_printk(const char *level, const struct ath_common* common,
+ 		const char *fmt, ...)
+ {
++	struct timeval tv;
+ 	struct va_format vaf;
+ 	va_list args;
+ 
+@@ -79,12 +80,16 @@ void ath_printk(const char *level, const struct ath_common* common,
+ 	vaf.fmt = fmt;
+ 	vaf.va = &args;
+ 
++	do_gettimeofday(&tv);
++
+ 	if (common && common->hw && common->hw->wiphy) {
+-		printk("%sath: %s: %pV",
+-		       level, wiphy_name(common->hw->wiphy), &vaf);
++		printk("%sath: %lu.%lu %s: %pV",
++		       level, tv.tv_sec, tv.tv_usec,
++		       wiphy_name(common->hw->wiphy), &vaf);
+ 		trace_ath_log(common->hw->wiphy, &vaf);
+ 	} else {
+-		printk("%sath: %pV", level, &vaf);
++		printk("%sath: %lu.%lu %pV",
++		       level, tv.tv_sec, tv.tv_usec, &vaf);
+ 	}
+ 
+ 	va_end(args);
diff --git a/package/kernel/mac80211/patches/999-0002-ath-make-easier-to-enable-more-verbose-regdom-loggin.patch b/package/kernel/mac80211/patches/999-0002-ath-make-easier-to-enable-more-verbose-regdom-loggin.patch
new file mode 100644
index 0000000..9c3ea21
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0002-ath-make-easier-to-enable-more-verbose-regdom-loggin.patch
@@ -0,0 +1,129 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 24 Sep 2014 13:34:08 -0700
+Subject: [PATCH] ath: make easier to enable more verbose regdom logging.
+
+Good for developers who are debugging regdomain issues.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/regd.c | 29 ++++++++++++++++-------------
+ 1 file changed, 16 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c
+index 06ea6cc9e30a..45e584dd8285 100644
+--- a/drivers/net/wireless/ath/regd.c
++++ b/drivers/net/wireless/ath/regd.c
+@@ -23,6 +23,9 @@
+ #include "regd.h"
+ #include "regd_common.h"
+ 
++#define KERN_DBG_LVL KERN_DEBUG
++/*#define KERN_DBG_LVL KERN_INFO*/
++
+ static int __ath_regd_init(struct ath_regulatory *reg);
+ 
+ /*
+@@ -492,7 +495,7 @@ static void ath_reg_dyn_country(struct wiphy *wiphy,
+ 	if (__ath_reg_dyn_country(wiphy, reg, request))
+ 		return;
+ 
+-	printk(KERN_DEBUG "ath: regdomain 0x%0x "
++	printk(KERN_DBG_LVL "ath: regdomain 0x%0x "
+ 			  "dynamically updated by %s\n",
+ 	       reg->current_rd,
+ 	       reg_initiator_name(request->initiator));
+@@ -549,7 +552,7 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
+ 	if (rd & COUNTRY_ERD_FLAG) {
+ 		/* EEPROM value is a country code */
+ 		u16 cc = rd & ~COUNTRY_ERD_FLAG;
+-		printk(KERN_DEBUG
++		printk(KERN_DBG_LVL
+ 		       "ath: EEPROM indicates we should expect "
+ 			"a country code\n");
+ 		for (i = 0; i < ARRAY_SIZE(allCountries); i++)
+@@ -558,13 +561,13 @@ static bool ath_regd_is_eeprom_valid(struct ath_regulatory *reg)
+ 	} else {
+ 		/* EEPROM value is a regpair value */
+ 		if (rd != CTRY_DEFAULT)
+-			printk(KERN_DEBUG "ath: EEPROM indicates we "
++			printk(KERN_DBG_LVL "ath: EEPROM indicates we "
+ 			       "should expect a direct regpair map\n");
+ 		for (i = 0; i < ARRAY_SIZE(regDomainPairs); i++)
+ 			if (regDomainPairs[i].reg_domain == rd)
+ 				return true;
+ 	}
+-	printk(KERN_DEBUG
++	printk(KERN_DBG_LVL
+ 		 "ath: invalid regulatory domain/country code 0x%x\n", rd);
+ 	return false;
+ }
+@@ -669,7 +672,7 @@ static void ath_regd_sanitize(struct ath_regulatory *reg)
+ {
+ 	if (reg->current_rd != COUNTRY_ERD_FLAG)
+ 		return;
+-	printk(KERN_DEBUG "ath: EEPROM regdomain sanitized\n");
++	printk(KERN_DBG_LVL "ath: EEPROM regdomain sanitized\n");
+ 	reg->current_rd = 0x64;
+ }
+ 
+@@ -683,7 +686,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
+ 
+ 	ath_regd_sanitize(reg);
+ 
+-	printk(KERN_DEBUG "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
++	printk(KERN_DBG_LVL "ath: EEPROM regdomain: 0x%0x\n", reg->current_rd);
+ 
+ 	if (!ath_regd_is_eeprom_valid(reg)) {
+ 		pr_err("Invalid EEPROM contents\n");
+@@ -695,7 +698,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
+ 
+ 	if (reg->country_code == CTRY_DEFAULT &&
+ 	    regdmn == CTRY_DEFAULT) {
+-		printk(KERN_DEBUG "ath: EEPROM indicates default "
++		printk(KERN_DBG_LVL "ath: EEPROM indicates default "
+ 		       "country code should be used\n");
+ 		reg->country_code = CTRY_UNITED_STATES;
+ 	}
+@@ -703,18 +706,18 @@ static int __ath_regd_init(struct ath_regulatory *reg)
+ 	if (reg->country_code == CTRY_DEFAULT) {
+ 		country = NULL;
+ 	} else {
+-		printk(KERN_DEBUG "ath: doing EEPROM country->regdmn "
++		printk(KERN_DBG_LVL "ath: doing EEPROM country->regdmn "
+ 		       "map search\n");
+ 		country = ath_regd_find_country(reg->country_code);
+ 		if (country == NULL) {
+-			printk(KERN_DEBUG
++			printk(KERN_DBG_LVL
+ 				"ath: no valid country maps found for "
+ 				"country code: 0x%0x\n",
+ 				reg->country_code);
+ 			return -EINVAL;
+ 		} else {
+ 			regdmn = country->regDmnEnum;
+-			printk(KERN_DEBUG "ath: country maps to "
++			printk(KERN_DBG_LVL "ath: country maps to "
+ 			       "regdmn code: 0x%0x\n",
+ 			       regdmn);
+ 		}
+@@ -723,7 +726,7 @@ static int __ath_regd_init(struct ath_regulatory *reg)
+ 	reg->regpair = ath_get_regpair(regdmn);
+ 
+ 	if (!reg->regpair) {
+-		printk(KERN_DEBUG "ath: "
++		printk(KERN_DBG_LVL "ath: "
+ 			"No regulatory domain pair found, cannot continue\n");
+ 		return -EINVAL;
+ 	}
+@@ -739,9 +742,9 @@ static int __ath_regd_init(struct ath_regulatory *reg)
+ 		reg->alpha2[1] = '0';
+ 	}
+ 
+-	printk(KERN_DEBUG "ath: Country alpha2 being used: %c%c\n",
++	printk(KERN_DBG_LVL "ath: Country alpha2 being used: %c%c\n",
+ 		reg->alpha2[0], reg->alpha2[1]);
+-	printk(KERN_DEBUG "ath: Regpair used: 0x%0x\n",
++	printk(KERN_DBG_LVL "ath: Regpair used: 0x%0x\n",
+ 		reg->regpair->reg_domain);
+ 
+ 	return 0;
diff --git a/package/kernel/mac80211/patches/999-0003-wireless-Print-error-logs-for-EINVAL-scan-failures.patch b/package/kernel/mac80211/patches/999-0003-wireless-Print-error-logs-for-EINVAL-scan-failures.patch
new file mode 100644
index 0000000..c4a577b
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0003-wireless-Print-error-logs-for-EINVAL-scan-failures.patch
@@ -0,0 +1,103 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 24 Mar 2014 14:02:32 -0700
+Subject: [PATCH] wireless: Print error logs for EINVAL scan failures.
+
+There is no other easy way to tell why scans fail with
+EINVAL since there are so many different errors that
+return the same error code.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/nl80211.c | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index c264effd00a6..9991080c7e62 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -5692,8 +5692,11 @@ static int validate_scan_freqs(struct nlattr *freqs)
+ 		 */
+ 		nla_for_each_nested(attr2, freqs, tmp2)
+ 			if (attr1 != attr2 &&
+-			    nla_get_u32(attr1) == nla_get_u32(attr2))
++			    nla_get_u32(attr1) == nla_get_u32(attr2)) {
++				pr_err("scan:  Duplicate freq requested: %d\n",
++				       nla_get_u32(attr1));
+ 				return 0;
++			}
+ 	}
+ 
+ 	return n_channels;
+@@ -5746,8 +5749,10 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 	int err, tmp, n_ssids = 0, n_channels, i;
+ 	size_t ie_len;
+ 
+-	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
++	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) {
++		pr_err("scan:  Invalid ATTR_IE\n");
+ 		return -EINVAL;
++	}
+ 
+ 	wiphy = &rdev->wiphy;
+ 
+@@ -5763,6 +5768,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 		n_channels = validate_scan_freqs(
+ 				info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
+ 		if (!n_channels) {
++			pr_err("scan:  validate_scan_freqs failed, duplicate freq?\n");
+ 			err = -EINVAL;
+ 			goto unlock;
+ 		}
+@@ -5775,6 +5781,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 			n_ssids++;
+ 
+ 	if (n_ssids > wiphy->max_scan_ssids) {
++		pr_err("scan:  too many ssids, req: %d  supports: %d\n",
++		       n_ssids, wiphy->max_scan_ssids);
+ 		err = -EINVAL;
+ 		goto unlock;
+ 	}
+@@ -5785,6 +5793,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 		ie_len = 0;
+ 
+ 	if (ie_len > wiphy->max_scan_ie_len) {
++		pr_err("scan: ie-len too large: %zd  max: %d\n",
++		       ie_len, wiphy->max_scan_ie_len);
+ 		err = -EINVAL;
+ 		goto unlock;
+ 	}
+@@ -5817,6 +5827,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 			chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+ 
+ 			if (!chan) {
++				pr_err("scan:  Channel %d is not supported.\n",
++				       nla_get_u32(attr));
+ 				err = -EINVAL;
+ 				goto out_free;
+ 			}
+@@ -5851,6 +5863,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 	}
+ 
+ 	if (!i) {
++		pr_err("scan:  No scannable channels found.\n");
+ 		err = -EINVAL;
+ 		goto out_free;
+ 	}
+@@ -5861,6 +5874,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 	if (n_ssids) {
+ 		nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
+ 			if (nla_len(attr) > IEEE80211_MAX_SSID_LEN) {
++				pr_err("scan: ssid-len too large: %d  max: %d\n",
++				       nla_len(attr), IEEE80211_MAX_SSID_LEN);
+ 				err = -EINVAL;
+ 				goto out_free;
+ 			}
+@@ -5889,6 +5904,8 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
+ 			enum ieee80211_band band = nla_type(attr);
+ 
+ 			if (band < 0 || band >= IEEE80211_NUM_BANDS) {
++				pr_err("scan:  band %d out of range, num-bands: %d\n",
++				       band, IEEE80211_NUM_BANDS);
+ 				err = -EINVAL;
+ 				goto out_free;
+ 			}
diff --git a/package/kernel/mac80211/patches/999-0004-mac80211-Extra-debug-info-for-station-cleanup-case.patch b/package/kernel/mac80211/patches/999-0004-mac80211-Extra-debug-info-for-station-cleanup-case.patch
new file mode 100644
index 0000000..8e03884
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0004-mac80211-Extra-debug-info-for-station-cleanup-case.patch
@@ -0,0 +1,22 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 23 Oct 2013 13:54:13 -0700
+Subject: [PATCH] mac80211: Extra debug info for station cleanup case.
+---
+ net/mac80211/sta_info.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
+index 494422729132..69a8a9d0c714 100644
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -924,7 +924,9 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
+ 	if (sta->uploaded) {
+ 		ret = drv_sta_state(local, sdata, sta, IEEE80211_STA_NONE,
+ 				    IEEE80211_STA_NOTEXIST);
+-		WARN_ON_ONCE(ret != 0);
++		if (WARN_ON_ONCE(ret != 0))
++			sdata_info(sdata, "sta-info-destroy: drv-sta-state error: %i, sta: %pM\n",
++				   ret, sta->sta.addr);
+ 	}
+ 
+ 	sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
diff --git a/package/kernel/mac80211/patches/999-0005-wireless-add-pr-err-calls-in-DFS-code.patch b/package/kernel/mac80211/patches/999-0005-wireless-add-pr-err-calls-in-DFS-code.patch
new file mode 100644
index 0000000..b0fcf3d
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0005-wireless-add-pr-err-calls-in-DFS-code.patch
@@ -0,0 +1,84 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 11 Jun 2014 12:48:44 -0700
+Subject: [PATCH] wireless: add pr-err calls in DFS code.
+
+Helps determine why DFS cannot be started.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/nl80211.c | 36 ++++++++++++++++++++++++++++--------
+ 1 file changed, 28 insertions(+), 8 deletions(-)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index 9991080c7e62..4c18c4f0c954 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -6332,32 +6332,48 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+ 	int err;
+ 
+ 	dfs_region = reg_get_dfs_region(wdev->wiphy);
+-	if (dfs_region == NL80211_DFS_UNSET)
++	if (dfs_region == NL80211_DFS_UNSET) {
++		pr_err("start-radar: dfs_region == DFS_UNSET\n");
+ 		return -EINVAL;
++	}
+ 
+ 	err = nl80211_parse_chandef(rdev, info, &chandef);
+-	if (err)
++	if (err) {
++		pr_err("start-radar: parse-chandef failed\n");
+ 		return err;
++	}
+ 
+-	if (netif_carrier_ok(dev))
++	if (netif_carrier_ok(dev)) {
++		pr_err("start-radar: carrier-ok\n");
+ 		return -EBUSY;
++	}
+ 
+-	if (wdev->cac_started)
++	if (wdev->cac_started) {
++		pr_err("start-radar: cac-started\n");
+ 		return -EBUSY;
++	}
+ 
+ 	err = cfg80211_chandef_dfs_required(wdev->wiphy, &chandef,
+ 					    wdev->iftype);
+-	if (err < 0)
++	if (err < 0) {
++		pr_err("start-radar: dfs-required\n");
+ 		return err;
++	}
+ 
+-	if (err == 0)
++	if (err == 0) {
++		pr_err("start-radar: dfs-required (err == 0)\n");
+ 		return -EINVAL;
++	}
+ 
+-	if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef))
++	if (!cfg80211_chandef_dfs_usable(wdev->wiphy, &chandef)) {
++		pr_err("start-radar: dfs not usable\n");
+ 		return -EINVAL;
++	}
+ 
+-	if (!rdev->ops->start_radar_detection)
++	if (!rdev->ops->start_radar_detection) {
++		pr_err("start-radar: ops not available\n");
+ 		return -EOPNOTSUPP;
++	}
+ 
+ 	cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
+ 	if (WARN_ON(!cac_time_ms))
+@@ -6370,7 +6386,11 @@ static int nl80211_start_radar_detection(struct sk_buff *skb,
+ 		wdev->cac_started = true;
+ 		wdev->cac_start_time = jiffies;
+ 		wdev->cac_time_ms = cac_time_ms;
++	} else {
++		pr_err("start-radar: ops->start-radar-detection failed: %i\n",
++		       err);
+ 	}
++
+ 	return err;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0006-wireless-add-pr-info-debugging-related-to-regulatory.patch b/package/kernel/mac80211/patches/999-0006-wireless-add-pr-info-debugging-related-to-regulatory.patch
new file mode 100644
index 0000000..13f3ed7
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0006-wireless-add-pr-info-debugging-related-to-regulatory.patch
@@ -0,0 +1,204 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 11 Jun 2014 13:00:31 -0700
+Subject: [PATCH] wireless: add pr-info debugging related to regulatory domains.
+
+Had all sorts of trouble figuring out why regulatory was acting
+weird on me.  Turns out, probably was bad regulatory.bin,
+but this debug should help next time there are issues.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/reg.c | 70 +++++++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 54 insertions(+), 16 deletions(-)
+
+diff --git a/net/wireless/reg.c b/net/wireless/reg.c
+index d359e0610198..6b1fbb0b8d2d 100644
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -785,6 +785,10 @@ static int reg_rules_intersect(const struct ieee80211_regdomain *rd1,
+ 	struct ieee80211_power_rule *power_rule;
+ 	u32 freq_diff, max_bandwidth1, max_bandwidth2;
+ 
++	pr_info("reg-rules-intersect, %c%c  %c%c\n",
++		rd1->alpha2[0], rd1->alpha2[1],
++		rd2->alpha2[0], rd2->alpha2[1]);
++
+ 	freq_range1 = &rule1->freq_range;
+ 	freq_range2 = &rule2->freq_range;
+ 	freq_range = &intersected_rule->freq_range;
+@@ -917,9 +921,16 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
+ 	struct ieee80211_reg_rule intersected_rule;
+ 	struct ieee80211_regdomain *rd;
+ 
++	pr_info("regdom-intersect, rd1: %p  rd2: %p\n",
++		rd1, rd2);
++
+ 	if (!rd1 || !rd2)
+ 		return NULL;
+ 
++	pr_info("regdom-intersect, rd1: %c%c  rd2: %c%c\n",
++		rd1->alpha2[0], rd1->alpha2[1],
++		rd2->alpha2[0], rd2->alpha2[1]);
++
+ 	/*
+ 	 * First we get a count of the rules we'll need, then we actually
+ 	 * build them. This is to so we can malloc() and free() a
+@@ -938,15 +949,19 @@ regdom_intersect(const struct ieee80211_regdomain *rd1,
+ 		}
+ 	}
+ 
+-	if (!num_rules)
++	if (!num_rules) {
++		pr_info("regdom-intersect: num-rules is zero\n");
+ 		return NULL;
++	}
+ 
+ 	size_of_regd = sizeof(struct ieee80211_regdomain) +
+ 		       num_rules * sizeof(struct ieee80211_reg_rule);
+ 
+ 	rd = kzalloc(size_of_regd, GFP_KERNEL);
+-	if (!rd)
++	if (!rd) {
++		pr_info("regdom-intersect: Could not allocate regd\n");
+ 		return NULL;
++	}
+ 
+ 	for (x = 0; x < rd1->n_reg_rules; x++) {
+ 		rule1 = &rd1->reg_rules[x];
+@@ -2727,8 +2742,8 @@ bool reg_supported_dfs_region(enum nl80211_dfs_regions dfs_region)
+ 	case NL80211_DFS_JP:
+ 		return true;
+ 	default:
+-		REG_DBG_PRINT("Ignoring uknown DFS master region: %d\n",
+-			      dfs_region);
++		pr_info("Ignoring uknown DFS master region: %d\n",
++			dfs_region);
+ 		return false;
+ 	}
+ }
+@@ -2768,10 +2783,12 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
+ 	print_rd_rules(rd);
+ }
+ 
+-static void print_regdomain_info(const struct ieee80211_regdomain *rd)
++static void print_regdomain_info(const struct ieee80211_regdomain *rd, const char* dbg)
+ {
+-	pr_info("Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]);
++	pr_info("Regulatory domain (%s): %c%c  DFS: %s\n",
++		dbg, rd->alpha2[0], rd->alpha2[1], reg_dfs_region_str(rd->dfs_region));
+ 	print_rd_rules(rd);
++	pr_info("Done with reg domain\n\n");
+ }
+ 
+ static int reg_set_rd_core(const struct ieee80211_regdomain *rd)
+@@ -2787,23 +2804,30 @@ static int reg_set_rd_user(const struct ieee80211_regdomain *rd,
+ {
+ 	const struct ieee80211_regdomain *intersected_rd = NULL;
+ 
+-	if (!regdom_changes(rd->alpha2))
++	pr_info("set-rd-user called...\n");
++
++	if (!regdom_changes(rd->alpha2)) {
++		pr_info("set-rd-user:  No change in reg-domain.\n");
+ 		return -EALREADY;
++	}
+ 
+ 	if (!is_valid_rd(rd)) {
+ 		pr_err("Invalid regulatory domain detected:\n");
+-		print_regdomain_info(rd);
++		print_regdomain_info(rd, "set-rd-user, invalid regdomain");
+ 		return -EINVAL;
+ 	}
+ 
+ 	if (!user_request->intersect) {
++		pr_info("set-rd-user:  No intersect requested.\n");
+ 		reset_regdomains(false, rd);
+ 		return 0;
+ 	}
+ 
+ 	intersected_rd = regdom_intersect(rd, get_cfg80211_regdom());
+-	if (!intersected_rd)
++	if (!intersected_rd) {
++		pr_info("set-rd-user:  regdom_intersect returned NULL.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	kfree(rd);
+ 	rd = NULL;
+@@ -2820,32 +2844,42 @@ static int reg_set_rd_driver(const struct ieee80211_regdomain *rd,
+ 	const struct ieee80211_regdomain *tmp;
+ 	struct wiphy *request_wiphy;
+ 
+-	if (is_world_regdom(rd->alpha2))
++	if (is_world_regdom(rd->alpha2)) {
++		pr_info("set-rd-driver, rd is WORLD.\n");
+ 		return -EINVAL;
++	}
+ 
+-	if (!regdom_changes(rd->alpha2))
++	if (!regdom_changes(rd->alpha2)) {
++		pr_info("set-rd-driver, no change.\n");
+ 		return -EALREADY;
++	}
+ 
+ 	if (!is_valid_rd(rd)) {
+ 		pr_err("Invalid regulatory domain detected:\n");
+-		print_regdomain_info(rd);
++		print_regdomain_info(rd, "set-rd-driver, invalid domain");
+ 		return -EINVAL;
+ 	}
+ 
+ 	request_wiphy = wiphy_idx_to_wiphy(driver_request->wiphy_idx);
+ 	if (!request_wiphy) {
++		pr_info("set-rd-driver:  Cannot find request wiphy.\n");
+ 		queue_delayed_work(system_power_efficient_wq,
+ 				   &reg_timeout, 0);
+ 		return -ENODEV;
+ 	}
+ 
+ 	if (!driver_request->intersect) {
+-		if (request_wiphy->regd)
++		pr_info("set-rd-driver, no intersect requested.\n");
++		if (request_wiphy->regd) {
++			pr_info("set-rd-driver, no intersect, has rd already.\n");
+ 			return -EALREADY;
++		}
+ 
+ 		regd = reg_copy_regd(rd);
+-		if (IS_ERR(regd))
++		if (IS_ERR(regd)) {
++			pr_info("set-rd-driver, no intersect, copy failed.\n");
+ 			return PTR_ERR(regd);
++		}
+ 
+ 		rcu_assign_pointer(request_wiphy->regd, regd);
+ 		reset_regdomains(false, rd);
+@@ -2889,7 +2923,7 @@ static int reg_set_rd_country_ie(const struct ieee80211_regdomain *rd,
+ 
+ 	if (!is_valid_rd(rd)) {
+ 		pr_err("Invalid regulatory domain detected:\n");
+-		print_regdomain_info(rd);
++		print_regdomain_info(rd, "set-rd-country-ie, invalid regdomain");
+ 		return -EINVAL;
+ 	}
+ 
+@@ -2929,6 +2963,10 @@ int set_regdom(const struct ieee80211_regdomain *rd,
+ 
+ 	lr = get_last_request();
+ 
++	pr_info("set-regdom, lr->initiator: %d domain: %c%c\n",
++		lr->initiator, rd->alpha2[0], rd->alpha2[1]);
++	print_regdomain_info(rd, "set-regdom");
++
+ 	/* Note that this doesn't update the wiphys, this is done below */
+ 	switch (lr->initiator) {
+ 	case NL80211_REGDOM_SET_BY_CORE:
+@@ -2994,7 +3032,7 @@ static int __regulatory_set_wiphy_regd(struct wiphy *wiphy,
+ 		return -EPERM;
+ 
+ 	if (WARN(!is_valid_rd(rd), "Invalid regulatory domain detected\n")) {
+-		print_regdomain_info(rd);
++		print_regdomain_info(rd, "invalid regulatory detected");
+ 		return -EINVAL;
+ 	}
+ 
diff --git a/package/kernel/mac80211/patches/999-0007-wireless-improve-dfs-region-intersection.patch b/package/kernel/mac80211/patches/999-0007-wireless-improve-dfs-region-intersection.patch
new file mode 100644
index 0000000..ba8633a
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0007-wireless-improve-dfs-region-intersection.patch
@@ -0,0 +1,33 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 11 Jun 2014 13:05:13 -0700
+Subject: [PATCH] wireless: improve dfs-region intersection.
+
+If one is UN-SET, use the other.  Seems this would
+be more correct that what we have now.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/reg.c | 9 ++++++++-
+ 1 file changed, 8 insertions(+), 1 deletion(-)
+
+diff --git a/net/wireless/reg.c b/net/wireless/reg.c
+index 6b1fbb0b8d2d..cad029adf058 100644
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -764,8 +764,15 @@ static enum nl80211_dfs_regions
+ reg_intersect_dfs_region(const enum nl80211_dfs_regions dfs_region1,
+ 			 const enum nl80211_dfs_regions dfs_region2)
+ {
+-	if (dfs_region1 != dfs_region2)
++	if (dfs_region1 != dfs_region2) {
++		pr_info("intersect-dfs-region, region1: %d  region2: %d\n",
++			dfs_region1, dfs_region2);
++		if (dfs_region1 == NL80211_DFS_UNSET)
++			return dfs_region2;
++		if (dfs_region2 == NL80211_DFS_UNSET)
++			return dfs_region1;
+ 		return NL80211_DFS_UNSET;
++	}
+ 	return dfs_region1;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0008-wireless-Allow-dynamic-interface-combinations.patch b/package/kernel/mac80211/patches/999-0008-wireless-Allow-dynamic-interface-combinations.patch
new file mode 100644
index 0000000..e44cc39
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0008-wireless-Allow-dynamic-interface-combinations.patch
@@ -0,0 +1,27 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 26 Jun 2014 11:32:47 -0700
+Subject: [PATCH] wireless: Allow dynamic interface combinations.
+
+Depending on firmware and/or module parameters, the
+number of vdevs supported may change.  Remove const
+modifier so that code can change the values accordingly
+at run-time.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ include/net/cfg80211.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+index a741678f24a2..348c02da1426 100644
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -2858,7 +2858,7 @@ struct ieee80211_iface_limit {
+  *  };
+  */
+ struct ieee80211_iface_combination {
+-	const struct ieee80211_iface_limit *limits;
++	struct ieee80211_iface_limit *limits;
+ 	u32 num_different_channels;
+ 	u16 max_interfaces;
+ 	u8 n_limits;
diff --git a/package/kernel/mac80211/patches/999-0009-mac80211-Make-STA-disconnect-messages-warn-instead-o.patch b/package/kernel/mac80211/patches/999-0009-mac80211-Make-STA-disconnect-messages-warn-instead-o.patch
new file mode 100644
index 0000000..b8cb491
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0009-mac80211-Make-STA-disconnect-messages-warn-instead-o.patch
@@ -0,0 +1,66 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 6 Feb 2013 09:08:30 -0800
+Subject: [PATCH] mac80211: Make STA disconnect messages warn instead of debug.
+
+This makes them more easily seen in /var/log/messages
+and the console, for instance.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/debug.h |  3 +++
+ net/mac80211/mlme.c  | 14 +++++++-------
+ 2 files changed, 10 insertions(+), 7 deletions(-)
+
+diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h
+index 1956b3115dd5..ed8ce2d28408 100644
+--- a/net/mac80211/debug.h
++++ b/net/mac80211/debug.h
+@@ -193,6 +193,9 @@ do {									\
+ 	_sdata_dbg(MAC80211_MLME_DEBUG,					\
+ 		   sdata, fmt, ##__VA_ARGS__)
+ 
++#define mlme_wrn(sdata, fmt, ...)					\
++	_sdata_err(sdata, fmt, ##__VA_ARGS__)
++
+ #define mlme_dbg_ratelimited(sdata, fmt, ...)				\
+ 	_sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(),		\
+ 		   sdata, fmt, ##__VA_ARGS__)
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 6332ff705ec3..d27d96725c2f 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -3930,7 +3930,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
+ 					 max_tries);
+ 				ieee80211_mgd_probe_ap_send(sdata);
+ 			} else {
+-				mlme_dbg(sdata,
++				mlme_wrn(sdata,
+ 					 "No ack for nullfunc frame to AP %pM, disconnecting.\n",
+ 					 bssid);
+ 				ieee80211_sta_connection_lost(sdata, bssid,
+@@ -3940,7 +3940,7 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
+ 		} else if (time_is_after_jiffies(ifmgd->probe_timeout))
+ 			run_again(sdata, ifmgd->probe_timeout);
+ 		else if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+-			mlme_dbg(sdata,
++			mlme_wrn(sdata,
+ 				 "Failed to send nullfunc to AP %pM after %dms, disconnecting\n",
+ 				 bssid, probe_wait_ms);
+ 			ieee80211_sta_connection_lost(sdata, bssid,
+@@ -3956,11 +3956,11 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
+ 			 * We actually lost the connection ... or did we?
+ 			 * Let's make sure!
+ 			 */
+-			wiphy_debug(local->hw.wiphy,
+-				    "%s: No probe response from AP %pM"
+-				    " after %dms, disconnecting.\n",
+-				    sdata->name,
+-				    bssid, probe_wait_ms);
++			wiphy_warn(local->hw.wiphy,
++				   "%s: No probe response from AP %pM"
++				   " after %dms, disconnecting.\n",
++				   sdata->name,
++				   bssid, probe_wait_ms);
+ 
+ 			ieee80211_sta_connection_lost(sdata, bssid,
+ 				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, false);
diff --git a/package/kernel/mac80211/patches/999-0010-wifi-Warn-if-cannot-add-station-debugfs-entries.patch b/package/kernel/mac80211/patches/999-0010-wifi-Warn-if-cannot-add-station-debugfs-entries.patch
new file mode 100644
index 0000000..25a48f2
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0010-wifi-Warn-if-cannot-add-station-debugfs-entries.patch
@@ -0,0 +1,39 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 9 May 2013 11:56:19 -0700
+Subject: [PATCH] wifi: Warn if cannot add station debugfs entries.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/debugfs_sta.c | 10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
+index 06d52935036d..d40d22713908 100644
+--- a/net/mac80211/debugfs_sta.c
++++ b/net/mac80211/debugfs_sta.c
+@@ -342,8 +342,11 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
+ 
+ 	sta->debugfs.add_has_run = true;
+ 
+-	if (!stations_dir)
++	if (!stations_dir) {
++		printk("%s: sta_debugfs_add: stations_dir is NULL\n",
++			sta->sdata->name);
+ 		return;
++	}
+ 
+ 	snprintf(mac, sizeof(mac), "%pM", sta->sta.addr);
+ 
+@@ -357,8 +360,11 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
+ 	 * dir might still be around.
+ 	 */
+ 	sta->debugfs.dir = debugfs_create_dir(mac, stations_dir);
+-	if (!sta->debugfs.dir)
++	if (!sta->debugfs.dir) {
++		printk("%s: sta_debugfs_add: Failed to create sta->debugfs.dir\n",
++			sta->sdata->name);
+ 		return;
++	}
+ 
+ 	DEBUGFS_ADD(flags);
+ 	DEBUGFS_ADD(num_ps_buf_frames);
diff --git a/package/kernel/mac80211/patches/999-0011-wifi-Don-t-spam-logs-with-Found-new-beacon-messages.patch b/package/kernel/mac80211/patches/999-0011-wifi-Don-t-spam-logs-with-Found-new-beacon-messages.patch
new file mode 100644
index 0000000..b91b31d
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0011-wifi-Don-t-spam-logs-with-Found-new-beacon-messages.patch
@@ -0,0 +1,44 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 9 May 2013 11:56:21 -0700
+Subject: [PATCH] wifi: Don't spam logs with 'Found new beacon' messages.
+
+We saw logs fill with this (at very high speeds):
+
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+cfg80211: Found new beacon on frequency: 5745 MHz (Ch 149) on wiphy0
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/reg.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/net/wireless/reg.c b/net/wireless/reg.c
+index cad029adf058..19844fdd0ef9 100644
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -2667,10 +2667,11 @@ int regulatory_hint_found_beacon(struct wiphy *wiphy,
+ 	if (!reg_beacon)
+ 		return -ENOMEM;
+ 
+-	REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
+-		      beacon_chan->center_freq,
+-		      ieee80211_frequency_to_channel(beacon_chan->center_freq),
+-		      wiphy_name(wiphy));
++	if (printk_ratelimit())
++		REG_DBG_PRINT("Found new beacon on frequency: %d MHz (Ch %d) on %s\n",
++			      beacon_chan->center_freq,
++			      ieee80211_frequency_to_channel(beacon_chan->center_freq),
++			      wiphy_name(wiphy));
+ 
+ 	memcpy(&reg_beacon->chan, beacon_chan,
+ 	       sizeof(struct ieee80211_channel));
diff --git a/package/kernel/mac80211/patches/999-0012-mac80211-Limit-number-of-pending-skbs.patch b/package/kernel/mac80211/patches/999-0012-mac80211-Limit-number-of-pending-skbs.patch
new file mode 100644
index 0000000..5f83de7
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0012-mac80211-Limit-number-of-pending-skbs.patch
@@ -0,0 +1,73 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 9 May 2013 11:56:22 -0700
+Subject: [PATCH] mac80211: Limit number of pending skbs.
+
+Current code will allow any number of pending skbs, and
+this can OOM the system when used with something like
+the pktgen tool (which may not back off properly if
+queue is stopped).
+
+Possibly this is just a bug in our version of pktgen,
+but either way, it seems reasonable to add a limit
+so that it is not possible to go OOM in this manner.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/tx.c | 32 ++++++++++++++++++++++++++++----
+ 1 file changed, 28 insertions(+), 4 deletions(-)
+
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index 9489b5da5a46..e3ddf99dc956 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -34,6 +34,17 @@
+ #include "wpa.h"
+ #include "wme.h"
+ #include "rate.h"
++#include <linux/moduleparam.h>
++
++/*
++ * Maximum number of skbs that may be queued in a pending
++ * queue.  After that, packets will just be dropped.
++ */
++static int max_pending_qsize = 1000;
++module_param(max_pending_qsize, int, 0644);
++MODULE_PARM_DESC(max_pending_qsize,
++		 "Maximum number of skbs that may be queued in a pending queue.");
++
+ 
+ /* misc utils */
+ 
+@@ -1368,15 +1379,28 @@ static bool ieee80211_tx_frags(struct ieee80211_local *local,
+ 				 * later transmission from the tx-pending
+ 				 * tasklet when the queue is woken again.
+ 				 */
+-				if (txpending)
++				bool do_free = false;
++				if (txpending) {
+ 					skb_queue_splice_init(skbs,
+ 							      &local->pending[q]);
+-				else
+-					skb_queue_splice_tail_init(skbs,
+-								   &local->pending[q]);
++				} else {
++					u32 len = skb_queue_len(&local->pending[q]);
++					if (len >= max_pending_qsize) {
++						__skb_unlink(skb, skbs);
++						do_free = true;
++					} else {
++						skb_queue_splice_tail_init(skbs,
++									   &local->pending[q]);
++					}
++				}
+ 
+ 				spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+ 						       flags);
++				if (do_free) {
++					dev_kfree_skb_any(skb);
++					/* TODO:  Add counter for this */
++				}
++
+ 				return false;
+ 			}
+ 		}
diff --git a/package/kernel/mac80211/patches/999-0013-mac80211-Make-un-found-rate-splat-a-warn-once.patch b/package/kernel/mac80211/patches/999-0013-mac80211-Make-un-found-rate-splat-a-warn-once.patch
new file mode 100644
index 0000000..4d77f19
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0013-mac80211-Make-un-found-rate-splat-a-warn-once.patch
@@ -0,0 +1,51 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 9 May 2013 11:56:30 -0700
+Subject: [PATCH] mac80211: Make un-found-rate splat a warn-once.
+
+After that, print it out with net_ratelimit.  We saw a system
+continually hit this warning, for reasons unknown, and it
+seems it bogged the system down enough to make it go OOM.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/tx.c | 26 +++++++++++++++++++-------
+ 1 file changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index e3ddf99dc956..93d6be53027d 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -727,14 +727,26 @@ ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx)
+ 	 * Lets not bother rate control if we're associated and cannot
+ 	 * talk to the sta. This should not happen.
+ 	 */
+-	if (WARN(test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
+-		 !rate_usable_index_exists(sband, &tx->sta->sta),
+-		 "%s: Dropped data frame as no usable bitrate found while "
+-		 "scanning and associated. Target station: "
+-		 "%pM on %d GHz band\n",
+-		 tx->sdata->name, hdr->addr1,
+-		 info->band ? 5 : 2))
++	if (test_bit(SCAN_SW_SCANNING, &tx->local->scanning) && assoc &&
++	    !rate_usable_index_exists(sband, &tx->sta->sta)) {
++		static bool do_once = true;
++		if (do_once) {
++			WARN(1, "%s: Dropped data frame as no usable bitrate found while "
++			     "scanning and associated. Target station: "
++			     "%pM on %d GHz band\n",
++			     tx->sdata->name, hdr->addr1,
++			     info->band ? 5 : 2);
++			do_once = false;
++		}
++		else {
++			net_info_ratelimited("%s: Dropped data frame as no usable bitrate found while "
++					     "scanning and associated. Target station: "
++					     "%pM on %d GHz band\n",
++					     tx->sdata->name, hdr->addr1,
++					     info->band ? 5 : 2);
++		}
+ 		return TX_DROP;
++	}
+ 
+ 	/*
+ 	 * If we're associated with the sta at this point we know we can at
diff --git a/package/kernel/mac80211/patches/999-0014-mac80211-Get-ethtool-stats-frequency-more-often.patch b/package/kernel/mac80211/patches/999-0014-mac80211-Get-ethtool-stats-frequency-more-often.patch
new file mode 100644
index 0000000..6d29971
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0014-mac80211-Get-ethtool-stats-frequency-more-often.patch
@@ -0,0 +1,36 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 21 May 2013 16:08:30 -0700
+Subject: [PATCH] mac80211: Get ethtool-stats frequency more often.
+
+Some NICs (ath9k_htc) don't use chanctx_conf, it
+seems, so look at local->hw.conf.channel->center_freq
+in that case.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/ethtool.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/net/mac80211/ethtool.c b/net/mac80211/ethtool.c
+index 188faab11c24..1567eea3fab7 100644
+--- a/net/mac80211/ethtool.c
++++ b/net/mac80211/ethtool.c
+@@ -166,10 +166,14 @@ do_survey:
+ 		} while (channel != survey.channel);
+ 	}
+ 
+-	if (survey.filled)
+-		data[i++] = survey.channel->center_freq;
+-	else
+-		data[i++] = 0;
++	if (channel) {
++		data[i++] = channel->center_freq;
++	} else {
++		if (local->_oper_chandef.chan)
++			data[i++] = local->_oper_chandef.chan->center_freq;
++		else
++			data[i++] = 0;
++	}
+ 	if (survey.filled & SURVEY_INFO_NOISE_DBM)
+ 		data[i++] = (u8)survey.noise;
+ 	else
diff --git a/package/kernel/mac80211/patches/999-0015-mac80211-Debugging-for-chantx-warnings.patch b/package/kernel/mac80211/patches/999-0015-mac80211-Debugging-for-chantx-warnings.patch
new file mode 100644
index 0000000..49fd11f
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0015-mac80211-Debugging-for-chantx-warnings.patch
@@ -0,0 +1,24 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 21 May 2013 16:08:30 -0700
+Subject: [PATCH] mac80211: Debugging for chantx warnings.
+---
+ net/mac80211/chan.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c
+index 1d1b9b7bdefe..4275eeae1b4c 100644
+--- a/net/mac80211/chan.c
++++ b/net/mac80211/chan.c
+@@ -587,8 +587,11 @@ void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
+ 
+ 		compat = cfg80211_chandef_compatible(
+ 				&sdata->vif.bss_conf.chandef, compat);
+-		if (WARN_ON_ONCE(!compat))
++		if (WARN_ON_ONCE(!compat)) {
++			printk("compat was NULL in chanctx_chantype, dev: %s\n",
++			       sdata->name);
+ 			break;
++		}
+ 	}
+ 
+ 	/* TDLS peers can sometimes affect the chandef width */
diff --git a/package/kernel/mac80211/patches/999-0016-mac80211-Fix-pktgen-on-wifi-interfaces.patch b/package/kernel/mac80211/patches/999-0016-mac80211-Fix-pktgen-on-wifi-interfaces.patch
new file mode 100644
index 0000000..71e3385
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0016-mac80211-Fix-pktgen-on-wifi-interfaces.patch
@@ -0,0 +1,33 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 30 May 2013 11:47:23 -0700
+Subject: [PATCH] mac80211: Fix pktgen on wifi interfaces.
+
+Otherwise, you get queue-mismatch splats and stuck
+queues in ath9k.
+---
+ net/mac80211/tx.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
+index 93d6be53027d..2cf05f0317b3 100644
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1699,6 +1699,18 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
+ 		}
+ 	}
+ 
++	/* This check needs to go in before the QoS header is set below. */
++	if (skb->priority > 7 ||
++	    skb->queue_mapping != ieee802_1d_to_ac[skb->priority]) {
++		WARN_ONCE(1, "Invalid queue-mapping, priority: %i  queue-mapping: %i.  This is an expected warning if you are using pktgen, but otherwise may indicate a bug.\n",
++			  (int)(skb->priority), (int)(skb->queue_mapping));
++		/* Adjust queue-mapping to match what the wifi stack expects.
++		 * pktgen will just have to set QoS bits accordingly instead
++		 * of trying to set the queue_mapping directly.
++		 */
++		skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
++	}
++
+ 	ieee80211_set_qos_hdr(sdata, skb);
+ 	ieee80211_tx(sdata, sta, skb, false);
+ }
diff --git a/package/kernel/mac80211/patches/999-0017-mac80211-Tell-user-why-beacons-fail-to-parse.patch b/package/kernel/mac80211/patches/999-0017-mac80211-Tell-user-why-beacons-fail-to-parse.patch
new file mode 100644
index 0000000..f2c02cb
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0017-mac80211-Tell-user-why-beacons-fail-to-parse.patch
@@ -0,0 +1,233 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Sat, 29 Jun 2013 15:29:38 -0700
+Subject: [PATCH] mac80211: Tell user why beacons fail to parse.
+
+Should help better debug dodgy APs and such.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/ieee80211_i.h |  2 ++
+ net/mac80211/mlme.c        |  4 +--
+ net/mac80211/scan.c        |  6 ++++
+ net/mac80211/util.c        | 79 +++++++++++++++++++++++++++++++++++++++++-----
+ 4 files changed, 81 insertions(+), 10 deletions(-)
+
+diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
+index dd131e9b41d7..701b3dcf0db7 100644
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -120,6 +120,7 @@ struct ieee80211_bss {
+ 
+ 	/* Keep track of what bits of information we have valid info for. */
+ 	u8 valid_data;
++	char corrupt_elems_msg[80];
+ };
+ 
+ /**
+@@ -1439,6 +1440,7 @@ struct ieee802_11_elems {
+ 
+ 	/* whether a parse error occurred while retrieving these elements */
+ 	bool parse_error;
++	char parse_err_msg[80];
+ };
+ 
+ static inline struct ieee80211_local *hw_to_local(
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index d27d96725c2f..98500c16b16f 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -4936,8 +4936,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
+ 				corrupt_type = "beacon";
+ 		} else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP)
+ 			corrupt_type = "probe response";
+-		sdata_info(sdata, "associating with AP with corrupt %s\n",
+-			   corrupt_type);
++		sdata_info(sdata, "associating with AP with corrupt %s, reason: %s\n",
++			   corrupt_type, bss->corrupt_elems_msg);
+ 	}
+ 
+ 	return 0;
+diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
+index 11d0901ebb7b..6e857d157592 100644
+--- a/net/mac80211/scan.c
++++ b/net/mac80211/scan.c
+@@ -101,6 +101,8 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
+ 		bss->device_ts_presp = rx_status->device_timestamp;
+ 
+ 	if (elems->parse_error) {
++		strncpy(bss->corrupt_elems_msg, elems->parse_err_msg,
++			sizeof(bss->corrupt_elems_msg));
+ 		if (beacon)
+ 			bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON;
+ 		else
+@@ -110,6 +112,10 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
+ 			bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_BEACON;
+ 		else
+ 			bss->corrupt_data &= ~IEEE80211_BSS_CORRUPT_PROBE_RESP;
++		if (!(bss->corrupt_data &
++		      (IEEE80211_BSS_CORRUPT_BEACON |
++		       IEEE80211_BSS_CORRUPT_PROBE_RESP)))
++			bss->corrupt_elems_msg[0] = 0;
+ 	}
+ 
+ 	/* save the ERP value so that it is available at association time */
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index e54596f95663..bf83413e6061 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -786,6 +786,10 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 
+ 		if (elen > left) {
+ 			elems->parse_error = true;
++			snprintf(elems->parse_err_msg,
++				 sizeof(elems->parse_err_msg),
++				 "elen: %hhu > left: %zu",
++				 elen, left);
+ 			break;
+ 		}
+ 
+@@ -829,6 +833,9 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 		 */
+ 			if (test_bit(id, seen_elems)) {
+ 				elems->parse_error = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "seen id: %i already", id);
+ 				left -= elen;
+ 				pos += elen;
+ 				continue;
+@@ -878,8 +885,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 			if (elen >= sizeof(struct ieee80211_tim_ie)) {
+ 				elems->tim = (void *)pos;
+ 				elems->tim_len = elen;
+-			} else
++			} else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "EID_TIM size wrong, elen: %hhu  sizeof(tim_ie): %zu",
++					 elen,
++					 sizeof(struct ieee80211_tim_ie));
++			}
+ 			break;
+ 		case WLAN_EID_CHALLENGE:
+ 			elems->challenge = pos;
+@@ -922,32 +935,61 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 		case WLAN_EID_HT_CAPABILITY:
+ 			if (elen >= sizeof(struct ieee80211_ht_cap))
+ 				elems->ht_cap_elem = (void *)pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "HT_CAPAB size wrong, elen: %hhu  sizeof(ht_cap): %zu",
++					 elen,
++					 sizeof(struct ieee80211_ht_cap));
++			}
+ 			break;
+ 		case WLAN_EID_HT_OPERATION:
+ 			if (elen >= sizeof(struct ieee80211_ht_operation))
+ 				elems->ht_operation = (void *)pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "HT_OPER size wrong, elen: %hhu  sizeof(ht_oper): %zu",
++					 elen,
++					 sizeof(struct ieee80211_ht_operation));
++			}
+ 			break;
+ 		case WLAN_EID_VHT_CAPABILITY:
+ 			if (elen >= sizeof(struct ieee80211_vht_cap))
+ 				elems->vht_cap_elem = (void *)pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "EID_VHT size wrong, elen: %hhu  sizeof(vht_cap): %zu",
++					 elen,
++					 sizeof(struct ieee80211_vht_cap));
++			}
+ 			break;
+ 		case WLAN_EID_VHT_OPERATION:
+ 			if (elen >= sizeof(struct ieee80211_vht_operation))
+ 				elems->vht_operation = (void *)pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "VHT_OPER size wrong, elen: %hhu  sizeof(vht_oper): %zu",
++					 elen,
++					 sizeof(struct ieee80211_vht_operation));
++			}
+ 			break;
+ 		case WLAN_EID_OPMODE_NOTIF:
+ 			if (elen > 0)
+ 				elems->opmode_notif = pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "OPMODE_NOTIF has elen > 0: %hhu",
++					 elen);
++			}
+ 			break;
+ 		case WLAN_EID_MESH_ID:
+ 			elems->mesh_id = pos;
+@@ -956,8 +998,14 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 		case WLAN_EID_MESH_CONFIG:
+ 			if (elen >= sizeof(struct ieee80211_meshconf_ie))
+ 				elems->mesh_config = (void *)pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "MESH_CONFIG size wrong, elen: %hhu  sizeof(meshconf_ie): %zu",
++					 elen,
++					 sizeof(struct ieee80211_meshconf_ie));
++			}
+ 			break;
+ 		case WLAN_EID_PEER_MGMT:
+ 			elems->peering = pos;
+@@ -982,12 +1030,23 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 		case WLAN_EID_RANN:
+ 			if (elen >= sizeof(struct ieee80211_rann_ie))
+ 				elems->rann = (void *)pos;
+-			else
++			else {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "EID_RANN size wrong, elen: %hhu  sizeof(rann_ie): %zu",
++					 elen,
++					 sizeof(struct ieee80211_rann_ie));
++			}
+ 			break;
+ 		case WLAN_EID_CHANNEL_SWITCH:
+ 			if (elen != sizeof(struct ieee80211_channel_sw_ie)) {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "CH_SWITCH size wrong, elen: %hhu  sizeof(sw_ie): %zu",
++					 elen,
++					 sizeof(struct ieee80211_channel_sw_ie));
+ 				break;
+ 			}
+ 			elems->ch_switch_ie = (void *)pos;
+@@ -1049,6 +1108,10 @@ u32 ieee802_11_parse_elems_crc(const u8 *start, size_t len, bool action,
+ 		case WLAN_EID_PWR_CONSTRAINT:
+ 			if (elen != 1) {
+ 				elem_parse_failed = true;
++				snprintf(elems->parse_err_msg,
++					 sizeof(elems->parse_err_msg),
++					 "PWR_CONSTRAINT size not 1, elen: %hhu",
++					 elen);
+ 				break;
+ 			}
+ 			elems->pwr_constr_elem = pos;
diff --git a/package/kernel/mac80211/patches/999-0018-mac80211-Add-precise-time-stamps-to-association-logg.patch b/package/kernel/mac80211/patches/999-0018-mac80211-Add-precise-time-stamps-to-association-logg.patch
new file mode 100644
index 0000000..bace8aa
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0018-mac80211-Add-precise-time-stamps-to-association-logg.patch
@@ -0,0 +1,116 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 13 Nov 2013 10:15:12 -0800
+Subject: [PATCH] mac80211: Add precise time-stamps to association logging.
+
+This helps understand exactly how long it takes to connect
+to APs.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/mlme.c | 58 +++++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 45 insertions(+), 13 deletions(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 98500c16b16f..68908f81af95 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -2624,7 +2624,14 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
+ 
+ 	event.u.mlme.status = MLME_SUCCESS;
+ 	drv_event_callback(sdata->local, sdata, &event);
+-	sdata_info(sdata, "authenticated\n");
++
++	{
++		struct timeval tv;
++		do_gettimeofday(&tv);
++		sdata_info(sdata, "authenticated at: %lu.%lu\n",
++			   tv.tv_sec, tv.tv_usec);
++	}
++
+ 	ifmgd->auth_data->done = true;
+ 	ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC;
+ 	ifmgd->auth_data->timeout_started = true;
+@@ -3114,10 +3121,16 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+ 	status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code);
+ 	aid = le16_to_cpu(mgmt->u.assoc_resp.aid);
+ 
+-	sdata_info(sdata,
+-		   "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n",
+-		   reassoc ? "Rea" : "A", mgmt->sa,
+-		   capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14))));
++	{
++		struct timeval tv;
++		do_gettimeofday(&tv);
++		sdata_info(sdata,
++			   "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d) at: %lu.%lu\n",
++			   reassoc ? "Rea" : "A", mgmt->sa,
++			   capab_info, status_code,
++			   (u16)(aid & ~(BIT(15) | BIT(14))), tv.tv_sec,
++			   tv.tv_usec);
++	}
+ 
+ 	pos = mgmt->u.assoc_resp.variable;
+ 	ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), false, &elems);
+@@ -3156,7 +3169,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
+ 		}
+ 		event.u.mlme.status = MLME_SUCCESS;
+ 		drv_event_callback(sdata->local, sdata, &event);
+-		sdata_info(sdata, "associated\n");
++		{
++			struct timeval tv;
++			do_gettimeofday(&tv);
++			sdata_info(sdata, "associated at: %lu.%lu\n",
++				   tv.tv_sec, tv.tv_usec);
++		}
+ 
+ 		/*
+ 		 * destroy assoc_data afterwards, as otherwise an idle
+@@ -3715,9 +3733,14 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata)
+ 		u16 trans = 1;
+ 		u16 status = 0;
+ 
+-		sdata_info(sdata, "send auth to %pM (try %d/%d)\n",
+-			   auth_data->bss->bssid, auth_data->tries,
+-			   IEEE80211_AUTH_MAX_TRIES);
++		{
++			struct timeval tv;
++			do_gettimeofday(&tv);
++			sdata_info(sdata, "send auth to %pM (try %d/%d) at: %lu.%lu\n",
++				   auth_data->bss->bssid, auth_data->tries,
++				   IEEE80211_AUTH_MAX_TRIES, tv.tv_sec,
++				   tv.tv_usec);
++		}
+ 
+ 		auth_data->expected_transaction = 2;
+ 
+@@ -3795,9 +3818,13 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata)
+ 		return -ETIMEDOUT;
+ 	}
+ 
+-	sdata_info(sdata, "associate with %pM (try %d/%d)\n",
+-		   assoc_data->bss->bssid, assoc_data->tries,
+-		   IEEE80211_ASSOC_MAX_TRIES);
++	{
++		struct timeval tv;
++		do_gettimeofday(&tv);
++		sdata_info(sdata, "associate with %pM (try %d/%d), at: %lu.%lu\n",
++			   assoc_data->bss->bssid, assoc_data->tries,
++			   IEEE80211_ASSOC_MAX_TRIES, tv.tv_sec, tv.tv_usec);
++	}
+ 	ieee80211_send_assoc(sdata);
+ 
+ 	if (!ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+@@ -4556,7 +4583,12 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+ 					    WLAN_REASON_UNSPECIFIED);
+ 	}
+ 
+-	sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid);
++	{
++		struct timeval tv;
++		do_gettimeofday(&tv);
++		sdata_info(sdata, "authenticate with %pM at: %lu.%lu\n",
++			   req->bss->bssid, tv.tv_sec, tv.tv_usec);
++	}
+ 
+ 	err = ieee80211_prep_connection(sdata, req->bss, false, false);
+ 	if (err)
diff --git a/package/kernel/mac80211/patches/999-0019-wireless-better-regdomain-logging.patch b/package/kernel/mac80211/patches/999-0019-wireless-better-regdomain-logging.patch
new file mode 100644
index 0000000..5084764
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0019-wireless-better-regdomain-logging.patch
@@ -0,0 +1,29 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 24 Sep 2014 13:35:55 -0700
+Subject: [PATCH] wireless: better regdomain logging.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/reg.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/net/wireless/reg.c b/net/wireless/reg.c
+index 19844fdd0ef9..4a1df65f4906 100644
+--- a/net/wireless/reg.c
++++ b/net/wireless/reg.c
+@@ -1683,6 +1683,15 @@ static void wiphy_update_regulatory(struct wiphy *wiphy,
+ 		return;
+ 	}
+ 
++	pr_info("Setting DFS Master region in update_regulatory, was: %c%c %s, new: %c%c %s  lr: %p  regdom: %p\n",
++		lr->alpha2[0],
++		lr->alpha2[1],
++		reg_dfs_region_str(lr->dfs_region),
++		get_cfg80211_regdom()->alpha2[0],
++		get_cfg80211_regdom()->alpha2[1],
++		reg_dfs_region_str(get_cfg80211_regdom()->dfs_region),
++		lr, get_cfg80211_regdom());
++
+ 	lr->dfs_region = get_cfg80211_regdom()->dfs_region;
+ 
+ 	for (band = 0; band < IEEE80211_NUM_BANDS; band++)
diff --git a/package/kernel/mac80211/patches/999-0020-mac80211-print-mac-addr-when-authenticating.patch b/package/kernel/mac80211/patches/999-0020-mac80211-print-mac-addr-when-authenticating.patch
new file mode 100644
index 0000000..d8cf936
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0020-mac80211-print-mac-addr-when-authenticating.patch
@@ -0,0 +1,28 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 4 Nov 2014 15:26:58 -0800
+Subject: [PATCH] mac80211: print mac addr when authenticating.
+
+Helps compare with logging info in drivers when using
+multiple vifs.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/mlme.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
+index 68908f81af95..3847d762ee03 100644
+--- a/net/mac80211/mlme.c
++++ b/net/mac80211/mlme.c
+@@ -4586,8 +4586,9 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata,
+ 	{
+ 		struct timeval tv;
+ 		do_gettimeofday(&tv);
+-		sdata_info(sdata, "authenticate with %pM at: %lu.%lu\n",
+-			   req->bss->bssid, tv.tv_sec, tv.tv_usec);
++		sdata_info(sdata, "%pM authenticate with %pM at: %lu.%lu\n",
++			   sdata->dev->dev_addr, req->bss->bssid,
++			   tv.tv_sec, tv.tv_usec);
+ 	}
+ 
+ 	err = ieee80211_prep_connection(sdata, req->bss, false, false);
diff --git a/package/kernel/mac80211/patches/999-0021-mac80211-print-kernel-logs-for-ibss-join-failures.patch b/package/kernel/mac80211/patches/999-0021-mac80211-print-kernel-logs-for-ibss-join-failures.patch
new file mode 100644
index 0000000..6c0bdc9
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0021-mac80211-print-kernel-logs-for-ibss-join-failures.patch
@@ -0,0 +1,46 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 21 Nov 2014 13:59:45 -0500
+Subject: [PATCH] mac80211: print kernel logs for ibss join failures.
+
+Helps user know what is wrong with config and/or driver.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/ibss.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
+index 7f72bc9bae2e..8773120f0f43 100644
+--- a/net/mac80211/ibss.c
++++ b/net/mac80211/ibss.c
+@@ -1750,12 +1750,16 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
+ 	ret = cfg80211_chandef_dfs_required(local->hw.wiphy,
+ 					    &params->chandef,
+ 					    sdata->wdev.iftype);
+-	if (ret < 0)
++	if (ret < 0) {
++		sdata_info(sdata, "ibss-join: chandef-dfs-required failed.\n");
+ 		return ret;
++	}
+ 
+ 	if (ret > 0) {
+-		if (!params->userspace_handles_dfs)
++		if (!params->userspace_handles_dfs) {
++			sdata_info(sdata, "ibss-join: No userspace-handles-dfs set.\n");
+ 			return -EINVAL;
++		}
+ 		radar_detect_width = BIT(params->chandef.width);
+ 	}
+ 
+@@ -1766,8 +1770,10 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
+ 	ret = ieee80211_check_combinations(sdata, &params->chandef, chanmode,
+ 					   radar_detect_width);
+ 	mutex_unlock(&local->chanctx_mtx);
+-	if (ret < 0)
++	if (ret < 0) {
++		sdata_info(sdata, "ibss-join:  Failed iface combination check.\n");
+ 		return ret;
++	}
+ 
+ 	if (params->bssid) {
+ 		memcpy(sdata->u.ibss.bssid, params->bssid, ETH_ALEN);
diff --git a/package/kernel/mac80211/patches/999-0022-cfg80211-print-reasons-for-ibss-join-failures-to-ker.patch b/package/kernel/mac80211/patches/999-0022-cfg80211-print-reasons-for-ibss-join-failures-to-ker.patch
new file mode 100644
index 0000000..24fd938
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0022-cfg80211-print-reasons-for-ibss-join-failures-to-ker.patch
@@ -0,0 +1,227 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 21 Nov 2014 14:00:29 -0500
+Subject: [PATCH] cfg80211: print reasons for ibss join failures to kernel logs.
+
+Helps users know what is wrong with their supplicant config
+and perhaps why driver fails to properly do an ibss join.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/nl80211.c | 81 +++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 63 insertions(+), 18 deletions(-)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index 4c18c4f0c954..a45e17e4c27d 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -1921,8 +1921,10 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ {
+ 	u32 control_freq;
+ 
+-	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
++	if (!info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
++		pr_err("parse-chandef:  no FREQ defined.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+ 
+@@ -1932,8 +1934,11 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ 	chandef->center_freq2 = 0;
+ 
+ 	/* Primary channel not allowed */
+-	if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
++	if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED) {
++		pr_err("parse-chandef: Primary channel not allowed: chan: %p  freq: %d\n",
++		       chandef->chan, control_freq);
+ 		return -EINVAL;
++	}
+ 
+ 	if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+ 		enum nl80211_channel_type chantype;
+@@ -1950,6 +1955,8 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ 						chantype);
+ 			break;
+ 		default:
++			pr_err("parse-chandef, invalid chantype: %d\n",
++			       chantype);
+ 			return -EINVAL;
+ 		}
+ 	} else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
+@@ -1965,17 +1972,23 @@ static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+ 					info->attrs[NL80211_ATTR_CENTER_FREQ2]);
+ 	}
+ 
+-	if (!cfg80211_chandef_valid(chandef))
++	if (!cfg80211_chandef_valid(chandef)) {
++		pr_err("parse-chandef:  chandef is not valid\n");
+ 		return -EINVAL;
++	}
+ 
+ 	if (!cfg80211_chandef_usable(&rdev->wiphy, chandef,
+-				     IEEE80211_CHAN_DISABLED))
++				     IEEE80211_CHAN_DISABLED)) {
++		pr_err("parse-chandef: chandef is not usable.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	if ((chandef->width == NL80211_CHAN_WIDTH_5 ||
+ 	     chandef->width == NL80211_CHAN_WIDTH_10) &&
+-	    !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ))
++	    !(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_5_10_MHZ)) {
++		pr_err("parse-chandef:  5/10 Mhz is not supported.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	return 0;
+ }
+@@ -7271,35 +7284,49 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	memset(&ibss, 0, sizeof(ibss));
+ 
+-	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
++	if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE])) {
++		pr_err("join-ibss:  ATTR_IE is not valid.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	if (!info->attrs[NL80211_ATTR_SSID] ||
+-	    !nla_len(info->attrs[NL80211_ATTR_SSID]))
++	    !nla_len(info->attrs[NL80211_ATTR_SSID])) {
++		pr_err("join-ibss: ATTR_SSID is not valid.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	ibss.beacon_interval = 100;
+ 
+ 	if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
+ 		ibss.beacon_interval =
+ 			nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+-		if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000)
++		if (ibss.beacon_interval < 1 || ibss.beacon_interval > 10000) {
++			pr_err("join-ibss: Beacon interval is bad: %d\n",
++			       ibss.beacon_interval);
+ 			return -EINVAL;
++		}
+ 	}
+ 
+-	if (!rdev->ops->join_ibss)
++	if (!rdev->ops->join_ibss) {
++		pr_err("join-ibss:  no join_ibss ops in driver.\n");
+ 		return -EOPNOTSUPP;
++	}
+ 
+-	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC)
++	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC) {
++		pr_err("join-ibss: iftype is invalid.\n");
+ 		return -EOPNOTSUPP;
++	}
+ 
+ 	wiphy = &rdev->wiphy;
+ 
+ 	if (info->attrs[NL80211_ATTR_MAC]) {
+ 		ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+ 
+-		if (!is_valid_ether_addr(ibss.bssid))
++		if (!is_valid_ether_addr(ibss.bssid)) {
++			pr_err("join-ibss: ibss bssid is invalid: %pM\n",
++			       ibss.bssid);
+ 			return -EINVAL;
++		}
+ 	}
+ 	ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
+ 	ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
+@@ -7310,12 +7337,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 	}
+ 
+ 	err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
+-	if (err)
++	if (err) {
++		pr_err("join-ibss:  parse-chandef fails.\n");
+ 		return err;
++	}
+ 
+ 	if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef,
+-				     NL80211_IFTYPE_ADHOC))
++				     NL80211_IFTYPE_ADHOC)) {
++		pr_err("join-ibss: adhoc cannot beacon.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	switch (ibss.chandef.width) {
+ 	case NL80211_CHAN_WIDTH_5:
+@@ -7337,6 +7368,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 			return -EINVAL;
+ 		break;
+ 	default:
++		pr_err("join-ibss:  Invalid chandef width: %d (features: 0x%x)\n",
++		       ibss.chandef.width, rdev->wiphy.features);
+ 		return -EINVAL;
+ 	}
+ 
+@@ -7353,8 +7386,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 
+ 		err = ieee80211_get_ratemask(sband, rates, n_rates,
+ 					     &ibss.basic_rates);
+-		if (err)
++		if (err) {
++			pr_err("join-ibss: get-ratemask failed.\n");
+ 			return err;
++		}
+ 	}
+ 
+ 	if (info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
+@@ -7363,8 +7398,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 		       sizeof(ibss.ht_capa_mask));
+ 
+ 	if (info->attrs[NL80211_ATTR_HT_CAPABILITY]) {
+-		if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK])
++		if (!info->attrs[NL80211_ATTR_HT_CAPABILITY_MASK]) {
++			pr_err("join-ibss: no HT capability mask.\n");
+ 			return -EINVAL;
++		}
+ 		memcpy(&ibss.ht_capa,
+ 		       nla_data(info->attrs[NL80211_ATTR_HT_CAPABILITY]),
+ 		       sizeof(ibss.ht_capa));
+@@ -7372,8 +7409,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	if (info->attrs[NL80211_ATTR_MCAST_RATE] &&
+ 	    !nl80211_parse_mcast_rate(rdev, ibss.mcast_rate,
+-			nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE])))
++			nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]))) {
++		pr_err("join-ibss: failure to parse mcast rate.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	if (ibss.privacy && info->attrs[NL80211_ATTR_KEYS]) {
+ 		bool no_ht = false;
+@@ -7381,12 +7420,16 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 		connkeys = nl80211_parse_connkeys(rdev,
+ 					  info->attrs[NL80211_ATTR_KEYS],
+ 					  &no_ht);
+-		if (IS_ERR(connkeys))
++		if (IS_ERR(connkeys)) {
++			pr_err("join-ibss:  connkeys is bad.\n");
+ 			return PTR_ERR(connkeys);
++		}
+ 
+ 		if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
+ 		    no_ht) {
+ 			kfree(connkeys);
++			pr_err("join-ibss: chandef does not match HT: %d no-ht: %d\n",
++			       ibss.chandef.width, (int)(no_ht));
+ 			return -EINVAL;
+ 		}
+ 	}
+@@ -7398,8 +7441,10 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
+ 		nla_get_flag(info->attrs[NL80211_ATTR_HANDLE_DFS]);
+ 
+ 	err = cfg80211_join_ibss(rdev, dev, &ibss, connkeys);
+-	if (err)
++	if (err) {
++		pr_err("join-ibss: cfg-join-ibss failed.\n");
+ 		kzfree(connkeys);
++	}
+ 	return err;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0024-ath9k-Detect-and-work-around-tx-queue-hang.patch b/package/kernel/mac80211/patches/999-0024-ath9k-Detect-and-work-around-tx-queue-hang.patch
new file mode 100644
index 0000000..fddc865
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0024-ath9k-Detect-and-work-around-tx-queue-hang.patch
@@ -0,0 +1,174 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 11 Aug 2014 13:36:23 -0700
+Subject: [PATCH] ath9k: Detect and work-around tx-queue hang.
+
+We see TX lockups on ar9380 NICs when running 32 stations
+each with a 56kbps stream of MTU sized UDP packets.
+We see lockups on the AP and also on the station, seems
+random which hits first.
+
+The test case further involves a programmable attenuator,
+and the attenuation is taken from -30 to -85 signal level
+in steps of 10db.  Each step runs for 1 minute before
+increasing the attenuation.  The problem normally
+shows up around signal level of -70 (noise is reported
+as around -95).
+
+When the lockup hits, it is typically on a single queue
+(BE).  The symptom is that there is no obvious transmit
+activity on that queue, the acq-depth and axq-ampdu-depth
+are zero, the queue is stopped, and the pending-frames is
+at or above the maximum allowed.  The VO queue continues
+to function, and RX logic functions fine.
+
+Just resetting the chip does not fix the problem:  The
+pending-frames usually stays at max.  So, this patch also
+adds hacks to force pending-frames to zero.  It also
+quietens some warnings about pending-frame underruns
+because sometimes, the tx status does appear many seconds
+later.
+
+Finally, the reset fixup code is logged at ath_err because
+I think everyone should be aware of events like this.
+
+We see the same problem with ath9k rate control and
+minstrel-ht.  We have not tested other ath9k chipsets
+in this manner.
+
+Small numbers of high-speed stations do not hit this
+problem, or at least not in our test cases.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath9k/ath9k.h |  3 ++-
+ drivers/net/wireless/ath/ath9k/link.c  | 33 +++++++++++++++++++++++++++++----
+ drivers/net/wireless/ath/ath9k/xmit.c  | 23 ++++++++++++++++++-----
+ 3 files changed, 49 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
+index a7a81b3969ce..2fe1f3d7dcc1 100644
+--- a/drivers/net/wireless/ath/ath9k/ath9k.h
++++ b/drivers/net/wireless/ath/ath9k/ath9k.h
+@@ -163,8 +163,9 @@ struct ath_txq {
+ 	spinlock_t axq_lock;
+ 	u32 axq_depth;
+ 	u32 axq_ampdu_depth;
++	u8 axq_tx_inprogress;
+ 	bool stopped;
+-	bool axq_tx_inprogress;
++	bool clear_pending_frames_on_flush;
+ 	struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
+ 	u8 txq_headidx;
+ 	u8 txq_tailidx;
+diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
+index 90631d768a60..bcfc5510c56d 100644
+--- a/drivers/net/wireless/ath/ath9k/link.c
++++ b/drivers/net/wireless/ath/ath9k/link.c
+@@ -40,20 +40,45 @@ void ath_tx_complete_poll_work(struct work_struct *work)
+ 
+ 		ath_txq_lock(sc, txq);
+ 		if (txq->axq_depth) {
+-			if (txq->axq_tx_inprogress) {
++			if (txq->axq_tx_inprogress > 1) {
+ 				needreset = true;
++				ath_err(ath9k_hw_common(sc->sc_ah),
++                                        "tx hung, queue: %i axq-depth: %i, ampdu-depth: %i resetting the chip\n",
++                                        i, txq->axq_depth,
++                                        txq->axq_ampdu_depth);
+ 				ath_txq_unlock(sc, txq);
+ 				break;
+ 			} else {
+-				txq->axq_tx_inprogress = true;
++				txq->axq_tx_inprogress++;
++			}
++		} else {
++			/* Check for software TX hang.  It seems
++			 * sometimes pending-frames is not properly
++			 * decremented, and the tx queue hangs.
++			 * Considered hung if:  axq-depth is zero,
++			 *  ampdu-depth is zero, queue-is-stopped,
++			 *  and we have pending frames.
++			 */
++			if (txq->stopped &&
++			    (txq->axq_ampdu_depth == 0) &&
++			    (txq->pending_frames > 0)) {
++				if (txq->axq_tx_inprogress > 1) {
++					ath_err(ath9k_hw_common(sc->sc_ah),
++						"soft tx hang: queue: %i pending-frames: %i, resetting chip\n",
++						i, txq->pending_frames);
++					needreset = true;
++					txq->clear_pending_frames_on_flush = true;
++					ath_txq_unlock(sc, txq);
++					break;
++				} else {
++					txq->axq_tx_inprogress++;
++				}
+ 			}
+ 		}
+ 		ath_txq_unlock(sc, txq);
+ 	}
+ 
+ 	if (needreset) {
+-		ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
+-			"tx hung, resetting the chip\n");
+ 		ath9k_queue_reset(sc, RESET_TYPE_TX_HANG);
+ 		return;
+ 	}
+diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
+index 3ad79bb4f2c2..3100cfa76083 100644
+--- a/drivers/net/wireless/ath/ath9k/xmit.c
++++ b/drivers/net/wireless/ath/ath9k/xmit.c
+@@ -163,9 +163,13 @@ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq,
+ 	if (q < 0)
+ 		return;
+ 
+-	txq = sc->tx.txq_map[q];
+-	if (WARN_ON(--txq->pending_frames < 0))
++	if (--txq->pending_frames < 0) {
++		struct ath_common *common = ath9k_hw_common(sc->sc_ah);
++		if (net_ratelimit())
++			ath_err(common, "txq: %p had negative pending_frames, q: %i\n",
++				txq, q);
+ 		txq->pending_frames = 0;
++	}
+ 
+ 	if (txq->stopped &&
+ 	    txq->pending_frames < sc->tx.txq_max_pending[q]) {
+@@ -680,7 +684,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+ 
+ 	txok = !(ts->ts_status & ATH9K_TXERR_MASK);
+ 	flush = !!(ts->ts_status & ATH9K_TX_FLUSH);
+-	txq->axq_tx_inprogress = false;
++	txq->axq_tx_inprogress = 0;
+ 
+ 	txq->axq_depth--;
+ 	if (bf_is_ampdu_not_probing(bf))
+@@ -1751,7 +1755,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
+ 		spin_lock_init(&txq->axq_lock);
+ 		txq->axq_depth = 0;
+ 		txq->axq_ampdu_depth = 0;
+-		txq->axq_tx_inprogress = false;
++		txq->axq_tx_inprogress = 0;
+ 		sc->tx.txqsetup |= 1<<axq_qnum;
+ 
+ 		txq->txq_headidx = txq->txq_tailidx = 0;
+@@ -1852,9 +1856,18 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq)
+ 	}
+ 
+ 	txq->axq_link = NULL;
+-	txq->axq_tx_inprogress = false;
++	txq->axq_tx_inprogress = 0;
+ 	ath_drain_txq_list(sc, txq, &txq->axq_q);
+ 
++	if (txq->clear_pending_frames_on_flush && (txq->pending_frames != 0)) {
++		ath_err(ath9k_hw_common(sc->sc_ah),
++			"Pending frames still exist on txq: %i after drain: %i  axq-depth: %i  ampdu-depth: %i\n",
++			txq->mac80211_qnum, txq->pending_frames, txq->axq_depth,
++			txq->axq_ampdu_depth);
++		txq->pending_frames = 0;
++	}
++	txq->clear_pending_frames_on_flush = false;
++
+ 	ath_txq_unlock_complete(sc, txq);
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0025-ath9k-Patch-from-Eric-Dumazet.might-fix-tcp-collapse.patch b/package/kernel/mac80211/patches/999-0025-ath9k-Patch-from-Eric-Dumazet.might-fix-tcp-collapse.patch
new file mode 100644
index 0000000..3d36d50
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0025-ath9k-Patch-from-Eric-Dumazet.might-fix-tcp-collapse.patch
@@ -0,0 +1,23 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 8 Jul 2013 13:21:07 -0700
+Subject: [PATCH] ath9k: Patch from Eric Dumazet..might fix tcp-collapse issue.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath9k/recv.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
+index 6c75fb1ab77d..b5d53d41014d 100644
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -1107,7 +1107,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
+ 		if (sc->rx.frag) {
+ 			int space = skb->len - skb_tailroom(hdr_skb);
+ 
+-			if (pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
++			if (space > 0 &&
++			    pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
+ 				dev_kfree_skb(skb);
+ 				RX_STAT_INC(rx_oom_err);
+ 				goto requeue_drop_frag;
diff --git a/package/kernel/mac80211/patches/999-0026-ath9k-Another-debugging-patch.patch b/package/kernel/mac80211/patches/999-0026-ath9k-Another-debugging-patch.patch
new file mode 100644
index 0000000..6687237
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0026-ath9k-Another-debugging-patch.patch
@@ -0,0 +1,25 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 8 Jul 2013 15:56:15 -0700
+Subject: [PATCH] ath9k: Another debugging patch.
+
+Harmless, and unlikely to hit I think.  But if it did,
+it might explain the tcp-collapse bug.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath9k/recv.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
+index b5d53d41014d..64e068f39602 100644
+--- a/drivers/net/wireless/ath/ath9k/recv.c
++++ b/drivers/net/wireless/ath/ath9k/recv.c
+@@ -1107,6 +1107,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush, bool hp)
+ 		if (sc->rx.frag) {
+ 			int space = skb->len - skb_tailroom(hdr_skb);
+ 
++			WARN_ON_ONCE(space < 0);
++
+ 			if (space > 0 &&
+ 			    pskb_expand_head(hdr_skb, 0, space, GFP_ATOMIC) < 0) {
+ 				dev_kfree_skb(skb);
diff --git a/package/kernel/mac80211/patches/999-0027-ath10k-fix-typo-in-logging-message.patch b/package/kernel/mac80211/patches/999-0027-ath10k-fix-typo-in-logging-message.patch
new file mode 100644
index 0000000..9c6c20e
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0027-ath10k-fix-typo-in-logging-message.patch
@@ -0,0 +1,22 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 31 Dec 2014 10:38:09 -0800
+Subject: [PATCH] ath10k: fix typo in logging message
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 4f36dbffc9c4..2f4045fca833 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -2665,7 +2665,7 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
+ 
+ 	ret = ath10k_wmi_vdev_down(ar, arvif->vdev_id);
+ 	if (ret)
+-		ath10k_warn(ar, "faield to down vdev %i: %d\n",
++		ath10k_warn(ar, "failed to down vdev %i: %d\n",
+ 			    arvif->vdev_id, ret);
+ 
+ 	arvif->def_wep_key_idx = -1;
diff --git a/package/kernel/mac80211/patches/999-0028-ath10k-support-CT-firmware-flag.patch b/package/kernel/mac80211/patches/999-0028-ath10k-support-CT-firmware-flag.patch
new file mode 100644
index 0000000..c6c91e3
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0028-ath10k-support-CT-firmware-flag.patch
@@ -0,0 +1,26 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 19 Sep 2014 10:03:49 -0700
+Subject: [PATCH] ath10k: support CT firmware flag.
+
+Add placeholder so CT firmware can more easily co-exist with upstream
+kernel.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 78094f23c9dd..611ca76a224d 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -462,6 +462,9 @@ enum ath10k_fw_features {
+ 	/* Firmware supports bypassing PLL setting on init. */
+ 	ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9,
+ 
++	/* Firmware from Candela Technologies, enables more VIFs, etc */
++	ATH10K_FW_FEATURE_WMI_10X_CT = 31,
++
+ 	/* keep last */
+ 	ATH10K_FW_FEATURE_COUNT,
+ };
diff --git a/package/kernel/mac80211/patches/999-0029-ath10k-Support-32-stations.patch b/package/kernel/mac80211/patches/999-0029-ath10k-Support-32-stations.patch
new file mode 100644
index 0000000..06b9029
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0029-ath10k-Support-32-stations.patch
@@ -0,0 +1,162 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 21 Jan 2014 16:23:46 -0800
+Subject: [PATCH] ath10k: Support 32+ stations.
+
+Support up to 32 stations when using CT firmware.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 12 ++++++++++
+ drivers/net/wireless/ath/ath10k/hw.h   |  6 +++++
+ drivers/net/wireless/ath/ath10k/mac.c  | 42 ++++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.c  | 19 +++++++++++----
+ 4 files changed, 74 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 59496a90ad5e..e9070fda7c6e 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1016,6 +1016,18 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
+ 			WMI_STAT_PEER;
+ 		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_1:
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
++			ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
++			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
++			ar->max_num_vdevs = TARGET_10X_NUM_VDEVS_CT;
++		} else {
++			ar->max_num_peers = TARGET_10X_NUM_PEERS;
++			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
++			ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
++		}
++		ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
++		ar->fw_stats_req_mask = WMI_STAT_PEER;
++		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_2:
+ 	case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ 		ar->max_num_peers = TARGET_10X_NUM_PEERS;
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 85cca29375fe..b334ff654238 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -273,6 +273,12 @@ enum ath10k_hw_rate_cck {
+ #define TARGET_10X_NUM_STATIONS			128
+ #define TARGET_10X_NUM_PEERS			((TARGET_10X_NUM_STATIONS) + \
+ 						 (TARGET_10X_NUM_VDEVS))
++
++/* Over-rides for Candela Technologies firmware */
++#define TARGET_10X_NUM_VDEVS_CT			32
++#define TARGET_10X_NUM_PEERS_CT			(32 + (TARGET_10X_NUM_VDEVS_CT))
++#define TARGET_10X_AST_SKID_LIMIT_CT		(TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
++
+ #define TARGET_10X_NUM_OFFLOAD_PEERS		0
+ #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0
+ #define TARGET_10X_NUM_PEER_KEYS		2
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 2f4045fca833..06d5a44cef50 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -6536,6 +6536,22 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
+ 	},
+ };
+ 
++static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
++	{
++	.max	= TARGET_10X_NUM_VDEVS_CT,
++	.types	= BIT(NL80211_IFTYPE_STATION)
++		| BIT(NL80211_IFTYPE_P2P_CLIENT)
++	},
++	{
++	.max	= 3,
++	.types	= BIT(NL80211_IFTYPE_P2P_GO)
++	},
++	{
++	.max	= 7,
++	.types	= BIT(NL80211_IFTYPE_AP)
++	},
++};
++
+ static const struct ieee80211_iface_combination ath10k_if_comb[] = {
+ 	{
+ 		.limits = ath10k_if_limits,
+@@ -6620,6 +6636,22 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {
+ 	},
+ };
+ 
++static const struct ieee80211_iface_combination ath10k_10x_ct_if_comb[] = {
++	{
++		.limits = ath10k_10x_ct_if_limits,
++		.n_limits = ARRAY_SIZE(ath10k_10x_ct_if_limits),
++		.max_interfaces = TARGET_10X_NUM_VDEVS_CT,
++		.num_different_channels = 1,
++		.beacon_int_infra_match = true,
++#ifdef CPTCFG_ATH10K_DFS_CERTIFIED
++		.radar_detect_widths =	BIT(NL80211_CHAN_WIDTH_20_NOHT) |
++					BIT(NL80211_CHAN_WIDTH_20) |
++					BIT(NL80211_CHAN_WIDTH_40) |
++					BIT(NL80211_CHAN_WIDTH_80),
++#endif
++	},
++};
++
+ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar)
+ {
+ 	struct ieee80211_sta_vht_cap vht_cap = {0};
+@@ -6936,6 +6968,16 @@ int ath10k_mac_register(struct ath10k *ar)
+ 		ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+ 		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_1:
++		if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
++			ar->hw->wiphy->iface_combinations = ath10k_10x_ct_if_comb;
++			ar->hw->wiphy->n_iface_combinations =
++				ARRAY_SIZE(ath10k_10x_ct_if_comb);
++		} else {
++			ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
++			ar->hw->wiphy->n_iface_combinations =
++				ARRAY_SIZE(ath10k_10x_if_comb);
++		}
++		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_2:
+ 	case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ 		ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 6c046c244705..77e451cc53a7 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3112,9 +3112,9 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)
+ 			 * peers, 1 extra for self peer on target */
+ 			/* this needs to be tied, host and target
+ 			 * can get out of sync */
+-			num_units = TARGET_10X_NUM_PEERS + 1;
++			num_units = ar->max_num_peers + 1;
+ 		else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS)
+-			num_units = TARGET_10X_NUM_VDEVS + 1;
++			num_units = ar->max_num_vdevs + 1;
+ 
+ 		ath10k_dbg(ar, ATH10K_DBG_WMI,
+ 			   "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n",
+@@ -3819,12 +3819,21 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 	struct sk_buff *buf;
+ 	struct wmi_resource_config_10x config = {};
+ 	u32 len, val;
++	u32 skid_limit;
++
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
++		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS_CT);
++		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS_CT);
++		skid_limit = TARGET_10X_AST_SKID_LIMIT_CT;
++	} else {
++		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
++		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
++		skid_limit = TARGET_10X_AST_SKID_LIMIT;
++	}
++	config.ast_skid_limit = __cpu_to_le32(skid_limit);
+ 
+-	config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+-	config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+ 	config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+ 	config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+-	config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
+ 	config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+ 	config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
+ 	config.rx_timeout_pri_vo = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
diff --git a/package/kernel/mac80211/patches/999-0030-ath10k-add-helper-method-to-grab-debug-stats.patch b/package/kernel/mac80211/patches/999-0030-ath10k-add-helper-method-to-grab-debug-stats.patch
new file mode 100644
index 0000000..87739c3
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0030-ath10k-add-helper-method-to-grab-debug-stats.patch
@@ -0,0 +1,89 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 20 Mar 2014 16:18:32 -0700
+Subject: [PATCH] ath10k: add helper method to grab debug stats.
+
+It can be nice to update the firmware's stats while
+debugging other bits of the driver, so add helper method
+to do this.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.c | 37 +++++++++++++++++++++------------
+ drivers/net/wireless/ath/ath10k/debug.h |  3 +++
+ 2 files changed, 27 insertions(+), 13 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 8fa606a9c4dd..b3d694a37c4e 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -384,7 +384,7 @@ unlock:
+ 
+ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
+ {
+-	unsigned long timeout, time_left;
++	unsigned long timeout;
+ 	int ret;
+ 
+ 	lockdep_assert_held(&ar->conf_mutex);
+@@ -397,19 +397,9 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
+ 		if (time_after(jiffies, timeout))
+ 			return -ETIMEDOUT;
+ 
+-		reinit_completion(&ar->debug.fw_stats_complete);
+-
+-		ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
+-		if (ret) {
+-			ath10k_warn(ar, "could not request stats (%d)\n", ret);
++		ret = ath10k_refresh_peer_stats(ar);
++		if (ret)
+ 			return ret;
+-		}
+-
+-		time_left =
+-		wait_for_completion_timeout(&ar->debug.fw_stats_complete,
+-					    1 * HZ);
+-		if (!time_left)
+-			return -ETIMEDOUT;
+ 
+ 		spin_lock_bh(&ar->data_lock);
+ 		if (ar->debug.fw_stats_done) {
+@@ -702,6 +692,27 @@ static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
+ 	return 0;
+ }
+ 
++int ath10k_refresh_peer_stats(struct ath10k *ar)
++{
++	int ret;
++	unsigned long time_left;
++
++	reinit_completion(&ar->debug.fw_stats_complete);
++	ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
++	if (ret) {
++		ath10k_warn(ar, "could not request stats (%d)\n", ret);
++		return ret;
++	}
++
++	/* ret means 'time-left' here */
++	time_left =
++		wait_for_completion_timeout(&ar->debug.fw_stats_complete, 1*HZ);
++	if (time_left == 0)
++		return -ETIMEDOUT;
++
++	return 0;
++}
++
+ static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
+ 				    size_t count, loff_t *ppos)
+ {
+diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
+index 53bd6a19eab6..f61b2e6d9c5d 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.h
++++ b/drivers/net/wireless/ath/ath10k/debug.h
+@@ -164,4 +164,7 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
+ {
+ }
+ #endif /* CPTCFG_ATH10K_DEBUG */
++
++int ath10k_refresh_peer_stats(struct ath10k *ar);
++
+ #endif /* _DEBUG_H_ */
diff --git a/package/kernel/mac80211/patches/999-0031-ath10k-request-firmware-flush-in-ath10k_flush.patch b/package/kernel/mac80211/patches/999-0031-ath10k-request-firmware-flush-in-ath10k_flush.patch
new file mode 100644
index 0000000..9f08723
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0031-ath10k-request-firmware-flush-in-ath10k_flush.patch
@@ -0,0 +1,38 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 5 Jun 2014 14:20:45 -0700
+Subject: [PATCH] ath10k: request firmware flush in ath10k_flush.
+
+CT firmware now supports flushing all tids for all
+peers for all vdevs.  This appears to help the ath10k_flush
+logic work faster and not cause timeouts.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 06d5a44cef50..80874698d70d 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -5567,6 +5567,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 	struct ath10k *ar = hw->priv;
+ 	bool skip;
+ 	int ret;
++	u8 peer_addr[ETH_ALEN] = {0};
+ 
+ 	/* mac80211 doesn't care if we really xmit queued frames or not
+ 	 * we'll collect those frames either way if we stop/delete vdevs */
+@@ -5578,6 +5579,12 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 	if (ar->state == ATH10K_STATE_WEDGED)
+ 		goto skip;
+ 
++	/* If we are CT firmware, ask it to flush all tids on all peers on
++	 * all vdevs.  Normal firmware will just crash if you do this.
++	 */
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features))
++		ath10k_wmi_peer_flush(ar, 0xFFFFFFFF, peer_addr, 0xFFFFFFFF);
++
+ 	ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
+ 			bool empty;
+ 
diff --git a/package/kernel/mac80211/patches/999-0032-ath10k-save-firmware-debug-log-messages.patch b/package/kernel/mac80211/patches/999-0032-ath10k-save-firmware-debug-log-messages.patch
new file mode 100644
index 0000000..d83321f
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0032-ath10k-save-firmware-debug-log-messages.patch
@@ -0,0 +1,421 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 23 Oct 2013 15:28:54 -0700
+Subject: [PATCH] ath10k: save firmware debug log messages.
+
+They may be dumped through the firmware dump debugfs
+file.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  | 18 ++++++
+ drivers/net/wireless/ath/ath10k/debug.c | 97 +++++++++++++++++++++++++++++++-
+ drivers/net/wireless/ath/ath10k/debug.h |  5 ++
+ drivers/net/wireless/ath/ath10k/hw.h    | 21 +++++++
+ drivers/net/wireless/ath/ath10k/pci.c   | 99 +++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.c   | 13 +++++
+ drivers/net/wireless/ath/ath10k/wmi.h   |  6 ++
+ 7 files changed, 257 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 611ca76a224d..14a179847adb 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -353,6 +353,22 @@ struct ath10k_vif_iter {
+ 	struct ath10k_vif *arvif;
+ };
+ 
++/* This will store at least the last 128 entries.  Each dbglog message
++ * is a max of 7 32-bit integers in length, but the length can be less
++ * than that as well.
++ */
++#define ATH10K_DBGLOG_DATA_LEN (128 * 7)
++struct ath10k_dbglog_entry_storage {
++	u32 head_idx; /* Where to write next chunk of data */
++	u32 tail_idx; /* Index of first msg */
++	__le32 data[ATH10K_DBGLOG_DATA_LEN];
++};
++
++/* Just enough info to decode firmware debug-log argument length */
++#define DBGLOG_NUM_ARGS_OFFSET           26
++#define DBGLOG_NUM_ARGS_MASK             0xFC000000 /* Bit 26-31 */
++#define DBGLOG_NUM_ARGS_MAX              5 /* firmware tool chain limit */
++
+ /* used for crash-dump storage, protected by data-lock */
+ struct ath10k_fw_crash_data {
+ 	bool crashed_since_read;
+@@ -384,6 +400,8 @@ struct ath10k_debug {
+ 	u8 htt_max_amsdu;
+ 	u8 htt_max_ampdu;
+ 
++	struct ath10k_dbglog_entry_storage dbglog_entry_data;
++
+ 	struct ath10k_fw_crash_data *fw_crash_data;
+ };
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index b3d694a37c4e..e672fce58d90 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -33,10 +33,11 @@
+ /**
+  * enum ath10k_fw_crash_dump_type - types of data in the dump file
+  * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
++ * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
+  */
+ enum ath10k_fw_crash_dump_type {
+ 	ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
+-
++	ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
+ 	ATH10K_FW_CRASH_DUMP_MAX,
+ };
+ 
+@@ -107,6 +108,12 @@ struct ath10k_dump_file_data {
+ 	u8 data[0];
+ } __packed;
+ 
++struct ath10k_dbglog_entry_storage_user {
++	__le32 head_idx; /* Where to write next chunk of data */
++	__le32 tail_idx; /* Index of first msg */
++	__le32 data[ATH10K_DBGLOG_DATA_LEN];
++} __packed;
++
+ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
+ {
+ 	struct va_format vaf = {
+@@ -908,7 +915,6 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+ 
+ 	lockdep_assert_held(&ar->data_lock);
+ 
+-	crash_data->crashed_since_read = true;
+ 	uuid_le_gen(&crash_data->uuid);
+ 	getnstimeofday(&crash_data->timestamp);
+ 
+@@ -916,17 +922,87 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
+ }
+ EXPORT_SYMBOL(ath10k_debug_get_new_fw_crash_data);
+ 
++static void ath10k_dbg_drop_dbg_buffer(struct ath10k *ar)
++{
++	/* Find next message boundary */
++	u32 lg_hdr;
++	int acnt;
++	int tail_idx = ar->debug.dbglog_entry_data.tail_idx;
++	int h_idx = (tail_idx + 1) % ATH10K_DBGLOG_DATA_LEN;
++
++	lockdep_assert_held(&ar->data_lock);
++
++	/* Log header is second 32-bit word */
++	lg_hdr = le32_to_cpu(ar->debug.dbglog_entry_data.data[h_idx]);
++
++	acnt = (lg_hdr & DBGLOG_NUM_ARGS_MASK) >> DBGLOG_NUM_ARGS_OFFSET;
++
++	if (acnt > DBGLOG_NUM_ARGS_MAX) {
++		/* Some sort of corruption it seems, recover as best we can. */
++		ath10k_err(ar, "invalid dbglog arg-count: %i %i %i\n",
++			   acnt, ar->debug.dbglog_entry_data.tail_idx,
++			   ar->debug.dbglog_entry_data.head_idx);
++		ar->debug.dbglog_entry_data.tail_idx =
++			ar->debug.dbglog_entry_data.head_idx;
++		return;
++	}
++
++	/* Move forward over the args and the two header fields */
++	ar->debug.dbglog_entry_data.tail_idx =
++		(tail_idx + acnt + 2) % ATH10K_DBGLOG_DATA_LEN;
++}
++
++void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len)
++{
++	int i;
++	int z;
++
++	lockdep_assert_held(&ar->data_lock);
++
++	z = ar->debug.dbglog_entry_data.head_idx;
++
++	/* Don't save any new logs until user-space reads this. */
++	if (ar->debug.fw_crash_data &&
++	    ar->debug.fw_crash_data->crashed_since_read) {
++		ath10k_warn(ar, "dropping dbg buffer due to crash since read\n");
++		return;
++	}
++
++	for (i = 0; i < len; i++) {
++		ar->debug.dbglog_entry_data.data[z] = buffer[i];
++		z++;
++		if (z >= ATH10K_DBGLOG_DATA_LEN)
++			z = 0;
++
++		/* If we are about to over-write an old message, move the
++		 * tail_idx to the next message.  If idx's are same, we
++		 * are empty.
++		 */
++		if (z == ar->debug.dbglog_entry_data.tail_idx)
++			ath10k_dbg_drop_dbg_buffer(ar);
++
++		ar->debug.dbglog_entry_data.head_idx = z;
++	}
++}
++EXPORT_SYMBOL(ath10k_dbg_save_fw_dbg_buffer);
++
+ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ {
+ 	struct ath10k_fw_crash_data *crash_data = ar->debug.fw_crash_data;
+ 	struct ath10k_dump_file_data *dump_data;
+ 	struct ath10k_tlv_dump_data *dump_tlv;
++	struct ath10k_dbglog_entry_storage_user *dbglog_storage;
+ 	int hdr_len = sizeof(*dump_data);
+ 	unsigned int len, sofar = 0;
+ 	unsigned char *buf;
++	int tmp;
++
++	BUILD_BUG_ON(sizeof(struct ath10k_dbglog_entry_storage) !=
++		     sizeof(struct ath10k_dbglog_entry_storage_user));
+ 
+ 	len = hdr_len;
+ 	len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
++	len += sizeof(*dump_tlv) + sizeof(ar->debug.dbglog_entry_data);
+ 
+ 	sofar += hdr_len;
+ 
+@@ -985,8 +1061,25 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 	       sizeof(crash_data->registers));
+ 	sofar += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+ 
++	/* Gather dbg-log */
++	tmp = sizeof(ar->debug.dbglog_entry_data);
++	dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
++	dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_DBGLOG);
++	dump_tlv->tlv_len = cpu_to_le32(tmp);
++	dbglog_storage =
++		(struct ath10k_dbglog_entry_storage_user *)(dump_tlv->tlv_data);
++	memcpy(dbglog_storage->data, ar->debug.dbglog_entry_data.data,
++	       sizeof(dbglog_storage->data));
++	dbglog_storage->head_idx =
++		cpu_to_le32(ar->debug.dbglog_entry_data.head_idx);
++	dbglog_storage->tail_idx =
++		cpu_to_le32(ar->debug.dbglog_entry_data.tail_idx);
++
++	sofar += sizeof(*dump_tlv) + tmp;
++
+ 	ar->debug.fw_crash_data->crashed_since_read = false;
+ 
++	WARN_ON(sofar != len);
+ 	spin_unlock_bh(&ar->data_lock);
+ 
+ 	return dump_data;
+diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
+index f61b2e6d9c5d..6a2e00348bab 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.h
++++ b/drivers/net/wireless/ath/ath10k/debug.h
+@@ -148,6 +148,7 @@ void ath10k_dbg_dump(struct ath10k *ar,
+ 		     enum ath10k_debug_mask mask,
+ 		     const char *msg, const char *prefix,
+ 		     const void *buf, size_t len);
++void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len);
+ #else /* CPTCFG_ATH10K_DEBUG */
+ 
+ static inline int ath10k_dbg(struct ath10k *ar,
+@@ -163,6 +164,10 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
+ 				   const void *buf, size_t len)
+ {
+ }
++static inline void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar,
++						 __le32 *buffer, int len)
++{
++}
+ #endif /* CPTCFG_ATH10K_DEBUG */
+ 
+ int ath10k_refresh_peer_stats(struct ath10k *ar);
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index b334ff654238..3e1180008971 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -541,4 +541,25 @@ enum ath10k_hw_rate_cck {
+ 
+ #define RTC_STATE_V_GET(x) (((x) & RTC_STATE_V_MASK) >> RTC_STATE_V_LSB)
+ 
++/* Target debug log related defines and structs */
++
++/* Target is 32-bit CPU, so we just use u32 for
++ * the pointers.  The memory space is relative to the
++ * target, not the host.  Values are converted to host
++ * byte order when reading from firmware.
++ */
++struct ath10k_fw_dbglog_buf {
++	__le32 next; /* pointer to ath10k_fw_dbglog_buf. */
++	__le32 buffer; /* pointer to u8 buffer */
++	__le32 bufsize;
++	__le32 length;
++	__le32 count;
++	__le32 free;
++} __packed;
++
++struct ath10k_fw_dbglog_hdr {
++	__le32 dbuf; /* pointer to ath10k_fw_dbglog_buf */
++	__le32 dropped;
++} __packed;
++
+ #endif /* _HW_H_ */
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index ea656e011a96..b56d7a949be1 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1183,6 +1183,102 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
+ 		crash_data->registers[i] = reg_dump_values[i];
+ }
+ 
++/**
++ * Read any not-yet-delivered debug-log buffers on the target
++ * and save them to storage in the host driver.  Typically
++ * only done on crash, as firmware will normally deliver
++ * logs periodically on its own if it is functioning
++ * properly.
++ */
++static void ath10k_pci_dump_dbglog(struct ath10k *ar)
++{
++	struct ath10k_fw_dbglog_hdr dbg_hdr;
++	u32 dbufp; /* pointer in target memory space */
++	struct ath10k_fw_dbglog_buf dbuf;
++	u8 *buffer;
++	int ret;
++	int i;
++	int len;
++
++	ret = ath10k_pci_diag_read_hi(ar, &dbg_hdr, hi_dbglog_hdr,
++				      sizeof(dbg_hdr));
++	if (ret != 0) {
++		ath10k_err(ar, "failed to dump debug log area: %d\n", ret);
++		return;
++	}
++
++	ath10k_dbg(ar, ATH10K_DBG_PCI,
++		   "debug log header, dbuf: 0x%x  dropped: %i\n",
++		   le32_to_cpu(dbg_hdr.dbuf), le32_to_cpu(dbg_hdr.dropped));
++	dbufp = le32_to_cpu(dbg_hdr.dbuf);
++
++	/* i is for logging purposes and sanity check in case firmware buffers
++	 * are corrupted and will not properly terminate the list.
++	 * In standard firmware, it appears there are no more than 2
++	 * buffers, so 10 should be safe upper limit even if firmware
++	 * changes quite a bit.
++	 */
++	i = 0;
++	while (dbufp && i < 10) {
++		ret = ath10k_pci_diag_read_mem(ar, dbufp, &dbuf, sizeof(dbuf));
++		if (ret != 0) {
++			ath10k_err(ar, "failed to read debug log area: %d (addr 0x%x)\n",
++				   ret, dbufp);
++			return;
++		}
++
++		len = le32_to_cpu(dbuf.length);
++
++		ath10k_dbg(ar, ATH10K_DBG_PCI,
++			   "[%i] next: 0x%x buf: 0x%x sz: %i len: %i count: %i free: %i\n",
++			   i, le32_to_cpu(dbuf.next), le32_to_cpu(dbuf.buffer),
++			   le32_to_cpu(dbuf.bufsize), len,
++			   le32_to_cpu(dbuf.count), le32_to_cpu(dbuf.free));
++		if (dbuf.buffer == 0 || len == 0)
++			goto next;
++
++		/* Pick arbitrary upper bound in case firmware is corrupted for
++		 * whatever reason.
++		 */
++		if (len > 4096) {
++			ath10k_err(ar,
++				   "debuglog buf length is out of bounds: %d\n",
++				   len);
++			/* Do not trust the next pointer either... */
++			return;
++		}
++
++		buffer = kmalloc(len, GFP_ATOMIC);
++
++		if (!buffer)
++			goto next;
++
++		ret = ath10k_pci_diag_read_mem(ar, le32_to_cpu(dbuf.buffer),
++					       buffer, len);
++		if (ret != 0) {
++			ath10k_err(ar, "failed to read debug log buffer: %d (addr 0x%x)\n",
++				   ret, le32_to_cpu(dbuf.buffer));
++			kfree(buffer);
++			return;
++		}
++
++		WARN_ON(len & 0x3);
++
++		ath10k_dbg_save_fw_dbg_buffer(ar, (__le32 *)(buffer), len >> 2);
++		kfree(buffer);
++
++next:
++		dbufp = le32_to_cpu(dbuf.next);
++		if (dbufp == le32_to_cpu(dbg_hdr.dbuf)) {
++			/* It is a circular buffer it seems, bail if next
++			 * is head
++			 */
++			break;
++		}
++		i++;
++	} /* While we have a debug buffer to read */
++}
++
+ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+ {
+ 	struct ath10k_fw_crash_data *crash_data;
+@@ -1202,6 +1298,9 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+ 	ath10k_err(ar, "firmware crashed! (uuid %s)\n", uuid);
+ 	ath10k_print_driver_info(ar);
+ 	ath10k_pci_dump_registers(ar, crash_data);
++	ath10k_pci_dump_dbglog(ar);
++	if (crash_data)
++		crash_data->crashed_since_read = true;
+ 
+ 	spin_unlock_bh(&ar->data_lock);
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 77e451cc53a7..75e2fd4dedb4 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -1670,10 +1670,23 @@ void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
+ 
+ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
+ {
++	struct ath10k_fw_dbglog_report *ev;
++
+ 	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
+ 		   skb->len);
+ 
+ 	trace_ath10k_wmi_dbglog(ar, skb->data, skb->len);
++	ev = (struct ath10k_fw_dbglog_report *)skb->data;
++
++	spin_lock_bh(&ar->data_lock);
++	/* First 4 bytes are a messages-dropped-due-to-overflow counter,
++	 * and should not be recorded in the dbglog buffer, so we skip
++	 * them.
++	 */
++	WARN_ON(skb->len & 0x3);
++	ath10k_dbg_save_fw_dbg_buffer(ar, ev->messages,
++				      (skb->len - 4)/sizeof(__le32));
++	spin_unlock_bh(&ar->data_lock);
+ 
+ 	return 0;
+ }
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index cf44a3d080a3..1b4b019a8102 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -4884,6 +4884,12 @@ struct wmi_svc_rdy_ev_arg {
+ 	const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
+ };
+ 
++struct ath10k_fw_dbglog_report {
++	__le32 dropped_count;
++	__le32 messages[];
++} __packed;
++
++
+ struct wmi_rdy_ev_arg {
+ 	__le32 sw_version;
+ 	__le32 abi_version;
diff --git a/package/kernel/mac80211/patches/999-0033-ath10k-save-firmware-stacks-upon-firmware-crash.patch b/package/kernel/mac80211/patches/999-0033-ath10k-save-firmware-stacks-upon-firmware-crash.patch
new file mode 100644
index 0000000..4de6635
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0033-ath10k-save-firmware-stacks-upon-firmware-crash.patch
@@ -0,0 +1,202 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 28 Aug 2014 09:25:39 -0700
+Subject: [PATCH] ath10k: save firmware stacks upon firmware crash
+
+Should help debug firmware crashes, and give users a way
+to provide some useful debug reports to firmware developers.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Signed-off-by: Kalle Valo <kvalo@xxxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  |  4 +++
+ drivers/net/wireless/ath/ath10k/debug.c | 29 +++++++++++++++++-
+ drivers/net/wireless/ath/ath10k/hw.h    |  2 ++
+ drivers/net/wireless/ath/ath10k/pci.c   | 52 +++++++++++++++++++++++++++++++++
+ 4 files changed, 86 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 14a179847adb..d504566d34ea 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -376,6 +376,10 @@ struct ath10k_fw_crash_data {
+ 	uuid_le uuid;
+ 	struct timespec timestamp;
+ 	__le32 registers[REG_DUMP_COUNT_QCA988X];
++	__le32 stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
++	__le32 exc_stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
++	__le32 stack_addr;
++	__le32 exc_stack_addr;
+ };
+ 
+ struct ath10k_debug {
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index e672fce58d90..e2b7ea9f3aa8 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -34,10 +34,15 @@
+  * enum ath10k_fw_crash_dump_type - types of data in the dump file
+  * @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
+  * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
++ * @ATH10K_FW_CRASH_DUMP_STACK:   Stack memory contents.
++ * @ATH10K_FW_CRASH_DUMP_EXC_STACK:   Exception stack memory contents.
+  */
+ enum ath10k_fw_crash_dump_type {
+ 	ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
+ 	ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
++	ATH10K_FW_CRASH_DUMP_STACK = 2,
++	ATH10K_FW_CRASH_DUMP_EXC_STACK = 3,
++
+ 	ATH10K_FW_CRASH_DUMP_MAX,
+ };
+ 
+@@ -101,8 +106,11 @@ struct ath10k_dump_file_data {
+ 	/* VERMAGIC_STRING */
+ 	char kernel_ver[64];
+ 
++	__le32 stack_addr;
++	__le32 exc_stack_addr;
++
+ 	/* room for growth w/out changing binary format */
+-	u8 unused[128];
++	u8 unused[120];
+ 
+ 	/* struct ath10k_tlv_dump_data + more */
+ 	u8 data[0];
+@@ -1003,6 +1011,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 	len = hdr_len;
+ 	len += sizeof(*dump_tlv) + sizeof(crash_data->registers);
+ 	len += sizeof(*dump_tlv) + sizeof(ar->debug.dbglog_entry_data);
++	len += sizeof(*dump_tlv) + sizeof(crash_data->stack_buf);
++	len += sizeof(*dump_tlv) + sizeof(crash_data->exc_stack_buf);
+ 
+ 	sofar += hdr_len;
+ 
+@@ -1042,6 +1052,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 	dump_data->ht_cap_info = cpu_to_le32(ar->ht_cap_info);
+ 	dump_data->vht_cap_info = cpu_to_le32(ar->vht_cap_info);
+ 	dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
++	dump_data->stack_addr = cpu_to_le32(crash_data->stack_addr);
++	dump_data->exc_stack_addr = cpu_to_le32(crash_data->exc_stack_addr);
+ 
+ 	strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
+ 		sizeof(dump_data->fw_ver));
+@@ -1074,7 +1086,22 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 		cpu_to_le32(ar->debug.dbglog_entry_data.head_idx);
+ 	dbglog_storage->tail_idx =
+ 		cpu_to_le32(ar->debug.dbglog_entry_data.tail_idx);
++	sofar += sizeof(*dump_tlv) + tmp;
+ 
++	/* Gather firmware stack dump */
++	tmp = sizeof(crash_data->stack_buf);
++	dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
++	dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_STACK);
++	dump_tlv->tlv_len = cpu_to_le32(tmp);
++	memcpy(dump_tlv->tlv_data, crash_data->stack_buf, tmp);
++	sofar += sizeof(*dump_tlv) + tmp;
++
++	/* Gather firmware exception stack dump */
++	tmp = sizeof(crash_data->exc_stack_buf);
++	dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
++	dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_EXC_STACK);
++	dump_tlv->tlv_len = cpu_to_le32(tmp);
++	memcpy(dump_tlv->tlv_data, crash_data->exc_stack_buf, tmp);
+ 	sofar += sizeof(*dump_tlv) + tmp;
+ 
+ 	ar->debug.fw_crash_data->crashed_since_read = false;
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 3e1180008971..b6f31ea5574a 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -90,6 +90,8 @@ enum qca6174_chip_id_rev {
+ 
+ #define QCA988X_CAL_DATA_LEN		2116
+ 
++#define ATH10K_FW_STACK_SIZE 4096
++
+ struct ath10k_fw_ie {
+ 	__le32 id;
+ 	__le32 len;
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index b56d7a949be1..245be9860bda 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -823,6 +823,22 @@ static int ath10k_pci_diag_read32(struct ath10k *ar, u32 address, u32 *value)
+ 	return ret;
+ }
+ 
++static int __ath10k_pci_diag_read_hi_addr(struct ath10k *ar, __le32 *dest,
++					  u32 src)
++{
++	u32 host_addr;
++	int ret;
++
++	host_addr = host_interest_item_address(src);
++
++	ret = ath10k_pci_diag_read32(ar, host_addr, dest);
++	if (ret != 0) {
++		ath10k_warn(ar, "failed to get memcpy hi address for firmware address %d: %d\n",
++			    src, ret);
++	}
++	return ret;
++}
++
+ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
+ 				     u32 src, u32 len)
+ {
+@@ -851,6 +867,9 @@ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
+ #define ath10k_pci_diag_read_hi(ar, dest, src, len)		\
+ 	__ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
+ 
++#define ath10k_pci_diag_read_hi_addr(ar, dest, src)		\
++	__ath10k_pci_diag_read_hi_addr(ar, dest, HI_ITEM(src))
++
+ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
+ 				     const void *data, int nbytes)
+ {
+@@ -1149,6 +1168,37 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
+ 	return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
+ }
+ 
++/* Save the main firmware stack */
++static void ath10k_pci_dump_stack(struct ath10k *ar,
++				  struct ath10k_fw_crash_data *crash_data)
++{
++	if (!crash_data)
++		return;
++
++	lockdep_assert_held(&ar->data_lock);
++	BUILD_BUG_ON(ATH10K_FW_STACK_SIZE % 4);
++
++	ath10k_pci_diag_read_hi(ar, crash_data->stack_buf,
++				hi_stack, ATH10K_FW_STACK_SIZE);
++	ath10k_pci_diag_read_hi_addr(ar, &crash_data->stack_addr, hi_stack);
++}
++
++/* Save the exception firmware stack */
++static void ath10k_pci_dump_exc_stack(struct ath10k *ar,
++				      struct ath10k_fw_crash_data *crash_data)
++{
++	if (!crash_data)
++		return;
++
++	lockdep_assert_held(&ar->data_lock);
++
++	ath10k_pci_diag_read_hi(ar, crash_data->exc_stack_buf,
++				hi_err_stack, ATH10K_FW_STACK_SIZE);
++
++	ath10k_pci_diag_read_hi_addr(ar, &crash_data->exc_stack_addr,
++				     hi_err_stack);
++}
++
+ static void ath10k_pci_dump_registers(struct ath10k *ar,
+ 				      struct ath10k_fw_crash_data *crash_data)
+ {
+@@ -1299,6 +1349,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+ 	ath10k_print_driver_info(ar);
+ 	ath10k_pci_dump_registers(ar, crash_data);
+ 	ath10k_pci_dump_dbglog(ar);
++	ath10k_pci_dump_stack(ar, crash_data);
++	ath10k_pci_dump_exc_stack(ar, crash_data);
+ 	if (crash_data)
+ 		crash_data->crashed_since_read = true;
+ 
diff --git a/package/kernel/mac80211/patches/999-0034-ath10k-save-firmware-RAM-and-ROM-BSS-sections-on-cra.patch b/package/kernel/mac80211/patches/999-0034-ath10k-save-firmware-RAM-and-ROM-BSS-sections-on-cra.patch
new file mode 100644
index 0000000..ba81a8e
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0034-ath10k-save-firmware-RAM-and-ROM-BSS-sections-on-cra.patch
@@ -0,0 +1,307 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 28 Aug 2014 12:22:34 -0700
+Subject: [PATCH] ath10k: save firmware RAM and ROM BSS sections on crash
+
+This can be used to get a useful back trace out of a firmware
+crash that involves an interrupt handler.  For instance, a
+null-pointer-exception would be this kind of trace.  A user-space
+tool can read the debugfs file and decode things as wished.
+
+This requires a packaged firmware with a new IE to describe the
+BSS section starts and length.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Signed-off-by: Kalle Valo <kvalo@xxxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c  | 48 ++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/core.h  | 16 ++++++++++
+ drivers/net/wireless/ath/ath10k/debug.c | 34 ++++++++++++++++++++-
+ drivers/net/wireless/ath/ath10k/hw.h    |  2 ++
+ drivers/net/wireless/ath/ath10k/pci.c   | 52 +++++++++++++++++++++++++++++++++
+ 5 files changed, 151 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index e9070fda7c6e..b6b979bcc669 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -594,6 +594,13 @@ err:
+ 	return ret;
+ }
+ 
++struct ath10k_bss_rom_ie {
++	__le32 ram_addr;
++	__le32 ram_len;
++	__le32 rom_addr;
++	__le32 rom_len;
++} __packed;
++
+ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+ {
+ 	size_t magic_len, len, ie_len;
+@@ -601,6 +608,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+ 	struct ath10k_fw_ie *hdr;
+ 	const u8 *data;
+ 	__le32 *timestamp, *version;
++	struct ath10k_bss_rom_ie *bss;
+ 
+ 	/* first fetch the firmware file (firmware-*.bin) */
+ 	ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
+@@ -716,6 +724,12 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+ 
+ 			break;
+ 		case ATH10K_FW_IE_WMI_OP_VERSION:
++			/* Upstream stole the ID CT firmware was using, so add
++			 * hack-around to deal with backwards-compat. --Ben
++			 */
++			if (ie_len >= sizeof(*bss))
++				goto fw_ie_bss_info_ct;
++
+ 			if (ie_len != sizeof(u32))
+ 				break;
+ 
+@@ -737,6 +751,40 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+ 			ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",
+ 				   ar->htt.op_version);
+ 			break;
++		case ATH10K_FW_IE_BSS_INFO_CT:
++fw_ie_bss_info_ct:
++			if (ie_len < sizeof(*bss)) {
++				ath10k_warn(ar, "invalid ie len for bss-info (%zd)\n",
++					    ie_len);
++				break;
++			}
++			bss = (struct ath10k_bss_rom_ie *)(data);
++
++			ar->fw.ram_bss_addr = le32_to_cpu(bss->ram_addr);
++			ar->fw.ram_bss_len = le32_to_cpu(bss->ram_len);
++			ath10k_dbg(ar, ATH10K_DBG_BOOT,
++				   "found RAM BSS addr 0x%x length %d\n",
++				   ar->fw.ram_bss_addr, ar->fw.ram_bss_len);
++
++			if (ar->fw.ram_bss_len > ATH10K_RAM_BSS_BUF_LEN) {
++				ath10k_warn(ar, "too long firmware RAM BSS length: %d\n",
++					    ar->fw.ram_bss_len);
++				ar->fw.ram_bss_len = 0;
++			}
++
++			ar->fw.rom_bss_addr = le32_to_cpu(bss->rom_addr);
++			ar->fw.rom_bss_len = le32_to_cpu(bss->rom_len);
++			ath10k_dbg(ar, ATH10K_DBG_BOOT,
++				   "found ROM BSS addr 0x%x length %d\n",
++				   ar->fw.rom_bss_addr, ar->fw.rom_bss_len);
++
++			if (ar->fw.rom_bss_len > ATH10K_ROM_BSS_BUF_LEN) {
++				ath10k_warn(ar, "too long firmware ROM BSS length: %d\n",
++					    ar->fw.rom_bss_len);
++				ar->fw.rom_bss_len = 0;
++			}
++
++			break;
+ 		default:
+ 			ath10k_warn(ar, "Unknown FW IE: %u\n",
+ 				    le32_to_cpu(hdr->id));
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index d504566d34ea..cfa2ec7eb24a 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -369,6 +369,10 @@ struct ath10k_dbglog_entry_storage {
+ #define DBGLOG_NUM_ARGS_MASK             0xFC000000 /* Bit 26-31 */
+ #define DBGLOG_NUM_ARGS_MAX              5 /* firmware tool chain limit */
+ 
++/* estimated values, hopefully these are enough */
++#define ATH10K_ROM_BSS_BUF_LEN 30000
++#define ATH10K_RAM_BSS_BUF_LEN 10000
++
+ /* used for crash-dump storage, protected by data-lock */
+ struct ath10k_fw_crash_data {
+ 	bool crashed_since_read;
+@@ -380,6 +384,8 @@ struct ath10k_fw_crash_data {
+ 	__le32 exc_stack_buf[ATH10K_FW_STACK_SIZE / sizeof(__le32)];
+ 	__le32 stack_addr;
+ 	__le32 exc_stack_addr;
++	__le32 rom_bss_buf[ATH10K_ROM_BSS_BUF_LEN / sizeof(__le32)];
++	__le32 ram_bss_buf[ATH10K_RAM_BSS_BUF_LEN / sizeof(__le32)];
+ };
+ 
+ struct ath10k_debug {
+@@ -613,6 +619,16 @@ struct ath10k {
+ 		} fw;
+ 	} hw_params;
+ 
++	/* These are written to only during first firmware load from user
++	 * space so no need for any locking.
++	 */
++	struct {
++		u32 ram_bss_addr;
++		u32 ram_bss_len;
++		u32 rom_bss_addr;
++		u32 rom_bss_len;
++	} fw;
++
+ 	const struct firmware *board;
+ 	const void *board_data;
+ 	size_t board_len;
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index e2b7ea9f3aa8..eff0f39f1384 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -36,12 +36,16 @@
+  * @ATH10K_FW_ERROR_DUMP_DBGLOG:  Recent firmware debug log entries
+  * @ATH10K_FW_CRASH_DUMP_STACK:   Stack memory contents.
+  * @ATH10K_FW_CRASH_DUMP_EXC_STACK:   Exception stack memory contents.
++ * @ATH10K_FW_CRASH_DUMP_RAM_BSS:  BSS area for RAM code
++ * @ATH10K_FW_CRASH_DUMP_ROM_BSS:  BSS area for ROM code
+  */
+ enum ath10k_fw_crash_dump_type {
+ 	ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
+ 	ATH10K_FW_CRASH_DUMP_DBGLOG = 1,
+ 	ATH10K_FW_CRASH_DUMP_STACK = 2,
+ 	ATH10K_FW_CRASH_DUMP_EXC_STACK = 3,
++	ATH10K_FW_CRASH_DUMP_RAM_BSS = 4,
++	ATH10K_FW_CRASH_DUMP_ROM_BSS = 5,
+ 
+ 	ATH10K_FW_CRASH_DUMP_MAX,
+ };
+@@ -108,9 +112,11 @@ struct ath10k_dump_file_data {
+ 
+ 	__le32 stack_addr;
+ 	__le32 exc_stack_addr;
++	__le32 rom_bss_addr;
++	__le32 ram_bss_addr;
+ 
+ 	/* room for growth w/out changing binary format */
+-	u8 unused[120];
++	u8 unused[112];
+ 
+ 	/* struct ath10k_tlv_dump_data + more */
+ 	u8 data[0];
+@@ -1014,6 +1020,12 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 	len += sizeof(*dump_tlv) + sizeof(crash_data->stack_buf);
+ 	len += sizeof(*dump_tlv) + sizeof(crash_data->exc_stack_buf);
+ 
++	if (ar->fw.ram_bss_addr && ar->fw.ram_bss_len)
++		len += sizeof(*dump_tlv) + ar->fw.ram_bss_len;
++
++	if (ar->fw.rom_bss_addr && ar->fw.rom_bss_len)
++		len += sizeof(*dump_tlv) + ar->fw.rom_bss_len;
++
+ 	sofar += hdr_len;
+ 
+ 	/* This is going to get big when we start dumping FW RAM and such,
+@@ -1054,6 +1066,8 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 	dump_data->num_rf_chains = cpu_to_le32(ar->num_rf_chains);
+ 	dump_data->stack_addr = cpu_to_le32(crash_data->stack_addr);
+ 	dump_data->exc_stack_addr = cpu_to_le32(crash_data->exc_stack_addr);
++	dump_data->rom_bss_addr = cpu_to_le32(ar->fw.rom_bss_addr);
++	dump_data->ram_bss_addr = cpu_to_le32(ar->fw.ram_bss_addr);
+ 
+ 	strlcpy(dump_data->fw_ver, ar->hw->wiphy->fw_version,
+ 		sizeof(dump_data->fw_ver));
+@@ -1104,6 +1118,24 @@ static struct ath10k_dump_file_data *ath10k_build_dump_file(struct ath10k *ar)
+ 	memcpy(dump_tlv->tlv_data, crash_data->exc_stack_buf, tmp);
+ 	sofar += sizeof(*dump_tlv) + tmp;
+ 
++	if (ar->fw.ram_bss_addr && ar->fw.ram_bss_len) {
++		tmp = ar->fw.ram_bss_len;
++		dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
++		dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_RAM_BSS);
++		dump_tlv->tlv_len = cpu_to_le32(tmp);
++		memcpy(dump_tlv->tlv_data, crash_data->ram_bss_buf, tmp);
++		sofar += sizeof(*dump_tlv) + tmp;
++	}
++
++	if (ar->fw.rom_bss_addr && ar->fw.rom_bss_len) {
++		tmp = ar->fw.rom_bss_len;
++		dump_tlv = (struct ath10k_tlv_dump_data *)(buf + sofar);
++		dump_tlv->type = cpu_to_le32(ATH10K_FW_CRASH_DUMP_ROM_BSS);
++		dump_tlv->tlv_len = cpu_to_le32(tmp);
++		memcpy(dump_tlv->tlv_data, crash_data->rom_bss_buf, tmp);
++		sofar += sizeof(*dump_tlv) + tmp;
++	}
++
+ 	ar->debug.fw_crash_data->crashed_since_read = false;
+ 
+ 	WARN_ON(sofar != len);
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index b6f31ea5574a..12c5d9c8ca34 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -114,6 +114,8 @@ enum ath10k_fw_ie_type {
+ 	 * FW API 5 and above.
+ 	 */
+ 	ATH10K_FW_IE_HTT_OP_VERSION = 6,
++
++	ATH10K_FW_IE_BSS_INFO_CT = 30,
+ };
+ 
+ enum ath10k_fw_wmi_op_version {
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 245be9860bda..00ae9a1dafb4 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1168,6 +1168,56 @@ static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
+ 	return ath10k_ce_num_free_src_entries(ar_pci->pipe_info[pipe].ce_hdl);
+ }
+ 
++static void ath10k_pci_dump_bss_ram(struct ath10k *ar,
++				    struct ath10k_fw_crash_data *crash_data)
++{
++	int ret;
++
++	if (!crash_data)
++		return;
++
++	lockdep_assert_held(&ar->data_lock);
++
++	if (!ar->fw.ram_bss_addr)
++		return;
++
++	if (!ar->fw.ram_bss_len)
++		return;
++
++	ret = ath10k_pci_diag_read_mem(ar, ar->fw.ram_bss_addr,
++				       crash_data->ram_bss_buf,
++				       ar->fw.ram_bss_len);
++	if (ret)
++		ath10k_warn(ar,
++			    "failed to read firmware RAM BSS memory from %d (%d B): %d\n",
++			    ar->fw.ram_bss_addr, ar->fw.ram_bss_len, ret);
++}
++
++static void ath10k_pci_dump_bss_rom(struct ath10k *ar,
++				    struct ath10k_fw_crash_data *crash_data)
++{
++	int ret;
++
++	if (!crash_data)
++		return;
++
++	lockdep_assert_held(&ar->data_lock);
++
++	if (!ar->fw.rom_bss_addr)
++		return;
++
++	if (!ar->fw.rom_bss_len)
++		return;
++
++	ret = ath10k_pci_diag_read_mem(ar, ar->fw.rom_bss_addr,
++				       crash_data->rom_bss_buf,
++				       ar->fw.rom_bss_len);
++	if (ret)
++		ath10k_warn(ar,
++			    "failed to read firmware ROM BSS memory from %d (%d B): %d\n",
++			    ar->fw.rom_bss_addr, ar->fw.rom_bss_len, ret);
++}
++
+ /* Save the main firmware stack */
+ static void ath10k_pci_dump_stack(struct ath10k *ar,
+ 				  struct ath10k_fw_crash_data *crash_data)
+@@ -1351,6 +1401,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+ 	ath10k_pci_dump_dbglog(ar);
+ 	ath10k_pci_dump_stack(ar, crash_data);
+ 	ath10k_pci_dump_exc_stack(ar, crash_data);
++	ath10k_pci_dump_bss_ram(ar, crash_data);
++	ath10k_pci_dump_bss_rom(ar, crash_data);
+ 	if (crash_data)
+ 		crash_data->crashed_since_read = true;
+ 
diff --git a/package/kernel/mac80211/patches/999-0035-ath10k-support-rx-software-crypt-mode.patch b/package/kernel/mac80211/patches/999-0035-ath10k-support-rx-software-crypt-mode.patch
new file mode 100644
index 0000000..c1ada51
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0035-ath10k-support-rx-software-crypt-mode.patch
@@ -0,0 +1,186 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 5 Aug 2014 13:24:48 -0700
+Subject: [PATCH] ath10k: support rx-software-crypt mode.
+
+With appropriate firmware (only CT firmware at this time)
+this allows enabling rx-software-crypt mode.  This tells the
+firmware to not decrypt any packets received, but do encrypt
+(as needed) any packets on transmit.  This is implemented to get
+around hardware issues that preclude using two stations to
+connect to the same AP while using encryption.
+
+Always have to ignore FCS when actually using encryption since
+firmware marks decrypt errors as FCS errors.  Decrypt logic
+should catch any real problems.
+
+Add firmware feature flag to specify if firmware supports
+this feature.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h   |  6 ++++++
+ drivers/net/wireless/ath/ath10k/htt_rx.c | 12 ++++++++++++
+ drivers/net/wireless/ath/ath10k/mac.c    |  8 ++++++++
+ drivers/net/wireless/ath/ath10k/mac.h    |  2 ++
+ drivers/net/wireless/ath/ath10k/wmi.c    | 16 +++++++++++++++-
+ drivers/net/wireless/ath/ath10k/wmi.h    | 15 +++++++++++++++
+ 6 files changed, 58 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index cfa2ec7eb24a..1089531c91d4 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -493,6 +493,11 @@ enum ath10k_fw_features {
+ 	/* Firmware from Candela Technologies, enables more VIFs, etc */
+ 	ATH10K_FW_FEATURE_WMI_10X_CT = 31,
+ 
++	/* Firmware from Candela Technologies with rx-software-crypt.
++	 * Required for multiple stations connected to same AP when using
++	 * encryption (ie, commercial version of CT firmware) */
++	ATH10K_FW_FEATURE_CT_RXSWCRYPT = 32,
++
+ 	/* keep last */
+ 	ATH10K_FW_FEATURE_COUNT,
+ };
+@@ -566,6 +571,7 @@ struct ath10k {
+ 	u32 chip_id;
+ 	u32 target_version;
+ 	u8 fw_version_major;
++	bool use_swcrypt; /* Firmware (and driver) supports rx-sw-crypt? */
+ 	u32 fw_version_minor;
+ 	u16 fw_version_release;
+ 	u16 fw_version_build;
+diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
+index 89eb16b30fc4..70682ecec1ff 100644
+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
+@@ -1219,6 +1219,12 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar,
+ 	decap = MS(__le32_to_cpu(rxd->msdu_start.info1),
+ 		   RX_MSDU_START_INFO1_DECAP_FORMAT);
+ 
++	/*
++	  ath10k_dbg(ar, ATH10K_DBG_HTT,
++		   "rx-undecap: msdu-len: %d  decap: %d  ip-summed: %d decrypted: %d enctype: %d\n",
++		   msdu->len, decap, msdu->ip_summed, is_decrypted, enctype);
++	*/
++
+ 	switch (decap) {
+ 	case RX_MSDU_DECAP_RAW:
+ 		ath10k_htt_rx_h_undecap_raw(ar, msdu, status, enctype,
+@@ -1352,6 +1358,12 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
+ 				RX_FLAG_IV_STRIPPED |
+ 				RX_FLAG_MMIC_STRIPPED;
+ 
++	/*
++	ath10k_dbg(ar, ATH10K_DBG_HTT,
++		   "rx-mpdu: first-len: %d  fcs-err: %i  tkip-err: %i decrypted: %i crypto-err: %i  peer-idx-inval: %i  enctype: %i\n",
++		   first->len, has_fcs_err, has_tkip_err, is_decrypted, has_crypto_err,
++		   has_peer_idx_invalid, enctype);
++	*/
+ 	skb_queue_walk(amsdu, msdu) {
+ 		ath10k_htt_rx_h_csum_offload(msdu);
+ 		ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 80874698d70d..d760071a5679 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -19,6 +19,7 @@
+ 
+ #include <net/mac80211.h>
+ #include <linux/etherdevice.h>
++#include <linux/module.h>
+ 
+ #include "hif.h"
+ #include "core.h"
+@@ -154,6 +155,13 @@ ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+ 	return 1;
+ }
+ 
++/* 0:  Full hardware crypt
++ * 1:  Tx hardware crypt, but expect rx software crypt (use native wifi tx type)
++ */
++int ath10k_modparam_nohwcrypt;
++module_param_named(nohwcrypt, ath10k_modparam_nohwcrypt, int, 0444);
++MODULE_PARM_DESC(nohwcrypt, "Disable hardware rx decrypt feature");
++
+ /**********/
+ /* Crypto */
+ /**********/
+diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
+index b291f063705c..03852b1f42f1 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.h
++++ b/drivers/net/wireless/ath/ath10k/mac.h
+@@ -26,6 +26,8 @@
+ enum wmi_tlv_tx_pause_id;
+ enum wmi_tlv_tx_pause_action;
+ 
++extern int ath10k_modparam_nohwcrypt;
++
+ struct ath10k_generic_iter {
+ 	struct ath10k *ar;
+ 	int ret;
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 75e2fd4dedb4..43eb48f048cf 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3834,10 +3834,25 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 	u32 len, val;
+ 	u32 skid_limit;
+ 
++	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
++
+ 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
+ 		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS_CT);
+ 		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS_CT);
+ 		skid_limit = TARGET_10X_AST_SKID_LIMIT_CT;
++		if (test_bit(ATH10K_FW_FEATURE_CT_RXSWCRYPT, ar->fw_features) &&
++		    ath10k_modparam_nohwcrypt) {
++			/* This will disable rx decryption in hardware, enable raw
++			 * rx mode, and native-wifi tx mode.  Requires 'CT' firmware.
++			 */
++			config.rx_decap_mode = __cpu_to_le32(ATH10K_HW_TXRX_RAW |
++							     ATH10k_USE_SW_RX_CRYPT);
++			ar->use_swcrypt = true;
++			ath10k_err(ar, "using rx swcrypt\n");
++		}
++		else if (ath10k_modparam_nohwcrypt) {
++			ath10k_err(ar, "module param nohwcrypt enabled, but firmware does not support this feature.  Disabling swcrypt.\n");
++		}
+ 	} else {
+ 		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ 		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+@@ -3853,7 +3868,6 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 	config.rx_timeout_pri_vi = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ 	config.rx_timeout_pri_be = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_LO_PRI);
+ 	config.rx_timeout_pri_bk = __cpu_to_le32(TARGET_10X_RX_TIMEOUT_HI_PRI);
+-	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
+ 
+ 	config.scan_max_pending_reqs =
+ 		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 1b4b019a8102..2cdd36dca529 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -1663,7 +1663,22 @@ struct wmi_resource_config {
+ 	 *   MAC can decap to RAW (no decap), native wifi or Ethernet types
+ 	 *   THis setting also determines the default TX behavior, however TX
+ 	 *   behavior can be modified on a per VAP basis during VAP init
++	 *
++	 *  NOTE:  Stealing some of this field for flags, only usable when
++	 *         running "CT" firmware.
++	 *   first byte: rx_decap_mode
++	 *   second byte:  reserved
+ 	 */
++	#define ATH10K_RX_DECAP_MODE_MASK 0xff
++	/*  Use software rx crypt.  This disables rx checksumming
++	 *  and may turn off some firmware/hardware optimizations for
++	 *  normal use case.  BUT, it does allow us to run multiple
++	 *  stations connected to the same AP.  This flag causes
++	 *  rx encapsulation to be 'raw', and tx mode to be native-wifi.
++	 *  You should probably not enable this unless you need to
++	 *  connect multiple stations to same AP.
++	 */
++	#define ATH10k_USE_SW_RX_CRYPT 0x10000
+ 	__le32 rx_decap_mode;
+ 
+ 	/* what is the maximum number of scan requests that can be queued */
diff --git a/package/kernel/mac80211/patches/999-0036-ath10k-Remove-roaming-offload-for-CT-firmware.patch b/package/kernel/mac80211/patches/999-0036-ath10k-Remove-roaming-offload-for-CT-firmware.patch
new file mode 100644
index 0000000..088ff45
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0036-ath10k-Remove-roaming-offload-for-CT-firmware.patch
@@ -0,0 +1,48 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 28 Jan 2014 14:34:34 -0800
+Subject: [PATCH] ath10k: Remove roaming offload for CT firmware.
+
+Looks like a useless feature to me, let supplicant
+or something else deal with roaming.  Saves some
+memory in firmware if we disable this.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 43eb48f048cf..efde26614669 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3853,10 +3853,17 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		else if (ath10k_modparam_nohwcrypt) {
+ 			ath10k_err(ar, "module param nohwcrypt enabled, but firmware does not support this feature.  Disabling swcrypt.\n");
+ 		}
++		config.roam_offload_max_vdev = 0; /* disable roaming */
++		config.roam_offload_max_ap_profiles = 0; /* disable roaming */
+ 	} else {
+ 		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ 		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+ 		skid_limit = TARGET_10X_AST_SKID_LIMIT;
++		config.roam_offload_max_vdev =
++			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
++
++		config.roam_offload_max_ap_profiles =
++			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+ 	}
+ 	config.ast_skid_limit = __cpu_to_le32(skid_limit);
+ 
+@@ -3875,12 +3882,6 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 	config.bmiss_offload_max_vdev =
+ 		__cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
+ 
+-	config.roam_offload_max_vdev =
+-		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
+-
+-	config.roam_offload_max_ap_profiles =
+-		__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+-
+ 	config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
+ 	config.num_mcast_table_elems =
+ 		__cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
diff --git a/package/kernel/mac80211/patches/999-0037-ath10k-Enable-detecting-failure-to-install-key-in-fi.patch b/package/kernel/mac80211/patches/999-0037-ath10k-Enable-detecting-failure-to-install-key-in-fi.patch
new file mode 100644
index 0000000..c93003a
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0037-ath10k-Enable-detecting-failure-to-install-key-in-fi.patch
@@ -0,0 +1,102 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 13 Feb 2014 10:21:34 -0800
+Subject: [PATCH] ath10k: Enable detecting failure to install key in firmware (CT).
+
+CT firmware has been modified so that it will always return
+a response message when user requests to add a key, even if
+the key could not actually be added.  Upstream firmware may
+assert or just not respond in a failure case.
+
+This change should be compatible with non CT firmware.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h   |  1 +
+ drivers/net/wireless/ath/ath10k/htt.h    |  7 +++++--
+ drivers/net/wireless/ath/ath10k/htt_rx.c | 20 +++++++++++++++++---
+ drivers/net/wireless/ath/ath10k/mac.c    |  3 ++-
+ 4 files changed, 25 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 1089531c91d4..967b9bec2824 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -687,6 +687,7 @@ struct ath10k {
+ 	unsigned int filter_flags;
+ 	unsigned long dev_flags;
+ 	u32 dfs_block_radar_events;
++	int install_key_rv; /* Store error code from key-install */
+ 
+ 	/* protected by conf_mutex */
+ 	bool radar_enabled;
+diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
+index 7e8a0d835663..808c11f4ccc2 100644
+--- a/drivers/net/wireless/ath/ath10k/htt.h
++++ b/drivers/net/wireless/ath/ath10k/htt.h
+@@ -624,8 +624,9 @@ enum htt_security_types {
+ };
+ 
+ enum htt_security_flags {
+-#define HTT_SECURITY_TYPE_MASK 0x7F
++#define HTT_SECURITY_TYPE_MASK 0x3F
+ #define HTT_SECURITY_TYPE_LSB  0
++	HTT_SECURITY_IS_FAILURE = 1 << 6, /* CT firmware only */
+ 	HTT_SECURITY_IS_UNICAST = 1 << 7
+ };
+ 
+@@ -634,7 +635,9 @@ struct htt_security_indication {
+ 		/* dont use bitfields; undefined behaviour */
+ 		u8 flags; /* %htt_security_flags */
+ 		struct {
+-			u8 security_type:7, /* %htt_security_types */
++			u8 security_type:6, /* %htt_security_types */
++			   is_failure:1, /* does this response indicate failure
++					    (CT Firmware) */
+ 			   is_unicast:1;
+ 		} __packed;
+ 	} __packed;
+diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
+index 70682ecec1ff..7454bf5bbdd7 100644
+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
+@@ -2029,9 +2029,23 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
+ 
+ 		ath10k_dbg(ar, ATH10K_DBG_HTT,
+ 			   "sec ind peer_id %d unicast %d type %d\n",
+-			  __le16_to_cpu(ev->peer_id),
+-			  !!(ev->flags & HTT_SECURITY_IS_UNICAST),
+-			  MS(ev->flags, HTT_SECURITY_TYPE));
++			   __le16_to_cpu(ev->peer_id),
++			   !!(ev->flags & HTT_SECURITY_IS_UNICAST),
++			   MS(ev->flags, HTT_SECURITY_TYPE));
++
++		/* CT firmware adds way to determine failure of key set, without
++		 * just timing things out.  Indication of failure is determined
++		 * by the 6th bit of the security-type being set.
++		 */
++		if (ev->flags & HTT_SECURITY_IS_FAILURE) {
++			ath10k_warn(ar, "Firmware failed to set security key, peer_id: %d unicast %d type %d\n",
++				    __le16_to_cpu(ev->peer_id),
++				    !!(ev->flags & HTT_SECURITY_IS_UNICAST),
++				    MS(ev->flags, HTT_SECURITY_TYPE));
++			ar->install_key_rv = -EINVAL;
++		} else {
++			ar->install_key_rv = 0;
++		}
+ 		complete(&ar->install_key_done);
+ 		break;
+ 	}
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index d760071a5679..b0732b9e3537 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -234,7 +234,8 @@ static int ath10k_install_key(struct ath10k_vif *arvif,
+ 	if (time_left == 0)
+ 		return -ETIMEDOUT;
+ 
+-	return 0;
++	ret = ar->install_key_rv;
++	return ret;
+ }
+ 
+ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
diff --git a/package/kernel/mac80211/patches/999-0038-ath10k-make-TARGET_NUM_PEERS-match-WMI_MAX_KEY_INDEX.patch b/package/kernel/mac80211/patches/999-0038-ath10k-make-TARGET_NUM_PEERS-match-WMI_MAX_KEY_INDEX.patch
new file mode 100644
index 0000000..68ab54b
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0038-ath10k-make-TARGET_NUM_PEERS-match-WMI_MAX_KEY_INDEX.patch
@@ -0,0 +1,50 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 18 Feb 2014 08:53:53 -0800
+Subject: [PATCH] ath10k: make TARGET_NUM_PEERS match WMI_MAX_KEY_INDEX.
+
+This appears to fix the problem of running out of keys
+in the firmware.  Possibly it only hides the problem,
+however.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/hw.h  | 1 +
+ drivers/net/wireless/ath/ath10k/wmi.c | 4 ++--
+ 2 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 12c5d9c8ca34..46224d2734c6 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -282,6 +282,7 @@ enum ath10k_hw_rate_cck {
+ #define TARGET_10X_NUM_VDEVS_CT			32
+ #define TARGET_10X_NUM_PEERS_CT			(32 + (TARGET_10X_NUM_VDEVS_CT))
+ #define TARGET_10X_AST_SKID_LIMIT_CT		(TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
++#define TARGET_10X_NUM_PEER_KEYS_CT             (WMI_MAX_KEY_INDEX + 1) /* 4 */
+ 
+ #define TARGET_10X_NUM_OFFLOAD_PEERS		0
+ #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index efde26614669..e91b86d392d8 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3855,6 +3855,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		}
+ 		config.roam_offload_max_vdev = 0; /* disable roaming */
+ 		config.roam_offload_max_ap_profiles = 0; /* disable roaming */
++		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS_CT);
+ 	} else {
+ 		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ 		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+@@ -3864,10 +3865,9 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 
+ 		config.roam_offload_max_ap_profiles =
+ 			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
++		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+ 	}
+ 	config.ast_skid_limit = __cpu_to_le32(skid_limit);
+-
+-	config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+ 	config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+ 	config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+ 	config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
diff --git a/package/kernel/mac80211/patches/999-0039-ath10k-OTP-debugging-for-CT-firmware.patch b/package/kernel/mac80211/patches/999-0039-ath10k-OTP-debugging-for-CT-firmware.patch
new file mode 100644
index 0000000..ae7589c
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0039-ath10k-OTP-debugging-for-CT-firmware.patch
@@ -0,0 +1,144 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 24 Feb 2014 15:48:26 -0800
+Subject: [PATCH] ath10k: OTP debugging for CT firmware.
+
+OTP firmware image does not have any logging support or
+other debugging on normal hardware.
+
+With the CT firmware, the OTP may choose to return a pointer
+to it's memory location that contains debug information.
+
+This patch enables the driver to read this memory after
+the OTP has exited to aid debugging.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 59 ++++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/hif.h  | 10 ++++++
+ drivers/net/wireless/ath/ath10k/pci.c  |  8 +++++
+ 3 files changed, 77 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index b6b979bcc669..9c1efa964d75 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -388,6 +388,65 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
+ 
+ 	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
+ 
++	/* If we are 'CT' firmware, then we have a back-door way to debug
++	 * the OTP binary since it does not have normal debuglog functionality.
++	 * Return code is: 0x8000000 | memory-address-of-debug-struct.
++	 * I doubt this is guaranteed to work..but it appears to work most of
++	 * the time so it's good enough for now.
++	 */
++	if (result & 0x8000000) {
++/*#define DEBUG_OTP */
++#define PRINTF_MSG_BUFLEN 1024
++#define OTP_DBG_BUFLEN 2048
++		struct otp_debug_ct {
++			char debug_msg[PRINTF_MSG_BUFLEN];
++			u32 real_ret_code;
++			u32 msg_len;
++			unsigned char otp[OTP_DBG_BUFLEN];
++			unsigned int otp_len;
++		};
++		struct otp_debug_ct *dbg = kzalloc(sizeof(*dbg), GFP_ATOMIC);
++		u32 targ_addr = result & ~0x8000000;
++#ifdef DEBUG_OTP
++		int ilen;
++		u32 *uiptr;
++		int i;
++#endif
++
++		if (!dbg) {
++			/* Assume real result is OK */
++			result = 0;
++			goto exit;
++		}
++
++		/* ath10k_err("otp debug location: 0x%x\n", targ_addr); */
++
++		ath10k_hif_read_target_mem(ar, targ_addr, dbg, sizeof(*dbg));
++#ifdef DEBUG_OTP
++		uiptr = (u32*)(&(dbg->otp[0]));
++
++		/* Verbose debugging messages from OTP run on firmware */
++		ath10k_err("otp debug: %s\n", dbg->debug_msg);
++		ath10k_err("otp real-ret-code: 0x%x\n", dbg->real_ret_code);
++		ath10k_err("otp msg-len: %i\n", dbg->msg_len);
++		ath10k_err("otp otp-len: %i\n", dbg->otp_len);
++		ath10k_err("otp data:\n");
++
++		ilen = min(dbg->otp_len, (unsigned int)(OTP_DBG_BUFLEN));
++		if (ilen & 0x3)
++			ilen += 4; /* make sure we read that last few bytes */
++		ilen = ilen / 4;
++		for (i = 0; i < ilen; i++) {
++			ath10k_err("otp [%04d]: %08X\n",
++				   i * 4,
++				   uiptr[i]);
++		}
++#endif
++		result = dbg->real_ret_code;
++		kfree(dbg);
++	}
++
++exit:
+ 	if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
+ 				   ar->fw_features))
+ 	    && result != 0) {
+diff --git a/drivers/net/wireless/ath/ath10k/hif.h b/drivers/net/wireless/ath/ath10k/hif.h
+index 0c92e0251e84..62f41f7b79dc 100644
+--- a/drivers/net/wireless/ath/ath10k/hif.h
++++ b/drivers/net/wireless/ath/ath10k/hif.h
+@@ -98,6 +98,10 @@ struct ath10k_hif_ops {
+ 
+ 	int (*suspend)(struct ath10k *ar);
+ 	int (*resume)(struct ath10k *ar);
++
++	/* Read target memory into specified destination.  Used for
++         * debugging currently. */
++        int (*read_target_mem)(struct ath10k *ar, u32 targ_addr, void* dst, int len);
+ };
+ 
+ static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
+@@ -151,6 +155,12 @@ static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
+ 						ul_is_polled, dl_is_polled);
+ }
+ 
++static inline int ath10k_hif_read_target_mem(struct ath10k *ar, u32 targ_addr,
++					     void* dst, int len)
++{
++	return ar->hif.ops->read_target_mem(ar, targ_addr, dst, len);
++}
++
+ static inline void ath10k_hif_get_default_pipe(struct ath10k *ar,
+ 					       u8 *ul_pipe, u8 *dl_pipe)
+ {
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 00ae9a1dafb4..ea74f5b62459 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1411,6 +1411,13 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
+ 	queue_work(ar->workqueue, &ar->restart_work);
+ }
+ 
++static int ath10k_pci_hif_read_target_mem(struct ath10k *ar, u32 targ_addr,
++					  void* dst, int len)
++{
++	ath10k_pci_wake(ar);
++	return ath10k_pci_diag_read_mem(ar, targ_addr, dst, len);
++}
++
+ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
+ 					       int force)
+ {
+@@ -2458,6 +2465,7 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
+ 	.suspend		= ath10k_pci_hif_suspend,
+ 	.resume			= ath10k_pci_hif_resume,
+ #endif
++	.read_target_mem        = ath10k_pci_hif_read_target_mem,
+ };
+ 
+ static void ath10k_pci_ce_tasklet(unsigned long ptr)
diff --git a/package/kernel/mac80211/patches/999-0040-ath10k-report-tx-rate-when-using-CT-firmware.patch b/package/kernel/mac80211/patches/999-0040-ath10k-report-tx-rate-when-using-CT-firmware.patch
new file mode 100644
index 0000000..f67e44e6
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0040-ath10k-report-tx-rate-when-using-CT-firmware.patch
@@ -0,0 +1,273 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 2 Jun 2014 12:02:35 -0700
+Subject: [PATCH] ath10k: report tx-rate when using CT firmware.
+
+This takes the tx-rate-code and tx-rate-flags reported
+by the CT firmware and decodes it.  I suspect the index
+might need special mapping from firmware's idea of the
+rate index to the linux's idea.  But, it seems to at
+least partially work as is.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c   |  3 ++-
+ drivers/net/wireless/ath/ath10k/htt.h    | 37 ++++++++++++++++++++++++++-
+ drivers/net/wireless/ath/ath10k/htt_rx.c | 24 ++++++++++++++---
+ drivers/net/wireless/ath/ath10k/hw.h     |  2 ++
+ drivers/net/wireless/ath/ath10k/txrx.c   | 44 ++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.c    |  8 +++++-
+ drivers/net/wireless/ath/ath10k/wmi.h    |  4 ++-
+ 7 files changed, 114 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 9c1efa964d75..4104fce62af3 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1127,12 +1127,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
+ 			ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
+ 			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ 			ar->max_num_vdevs = TARGET_10X_NUM_VDEVS_CT;
++			ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC_CT;
+ 		} else {
+ 			ar->max_num_peers = TARGET_10X_NUM_PEERS;
+ 			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ 			ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
++			ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+ 		}
+-		ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+ 		ar->fw_stats_req_mask = WMI_STAT_PEER;
+ 		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_2:
+diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
+index 808c11f4ccc2..d9c50f36bf65 100644
+--- a/drivers/net/wireless/ath/ath10k/htt.h
++++ b/drivers/net/wireless/ath/ath10k/htt.h
+@@ -693,6 +693,26 @@ struct htt_data_tx_completion {
+ 	__le16 msdus[0]; /* variable length based on %num_msdus */
+ } __packed;
+ 
++struct msdu_rx_compl_info_ct {
++	__le16 id; /* msdu id */
++	u8 tx_rate_code; /* what rate index the firmware reports transmitting at. */
++	u8 tx_rate_flags; /* what rate flags, See ATH10K_RC_FLAG_SGI, etc */
++};
++
++struct htt_data_tx_completion_ct {
++	union {
++		u8 flags;
++		struct {
++			u8 status:3,
++			   tid:4,
++			   tid_invalid:1;
++		} __packed;
++	} __packed;
++	u8 num_msdus;
++	u8 rsvd0;
++	struct msdu_rx_compl_info_ct msdus[0]; /* variable length based on %num_msdus */
++} __packed;
++
+ struct htt_tx_compl_ind_base {
+ 	u32 hdr;
+ 	u16 payload[1/*or more*/];
+@@ -1276,6 +1296,7 @@ struct htt_resp {
+ 		struct htt_ver_resp ver_resp;
+ 		struct htt_mgmt_tx_completion mgmt_tx_completion;
+ 		struct htt_data_tx_completion data_tx_completion;
++		struct htt_data_tx_completion_ct data_tx_completion_ct;
+ 		struct htt_rx_indication rx_ind;
+ 		struct htt_rx_fragment_indication rx_frag_ind;
+ 		struct htt_rx_peer_map peer_map;
+@@ -1296,8 +1317,22 @@ struct htt_resp {
+ 
+ /*** host side structures follow ***/
+ 
++/* tx-rate flags field definitions */
++#define ATH10K_RC_FLAG_CHAIN_MASK 0x07 /* identifies tx chain config (1,5,7) */
++#define ATH10K_RC_FLAG_ONE_CHAIN     1
++#define ATH10K_RC_FLAG_TWO_CHAIN     5
++#define ATH10K_RC_FLAG_THREE_CHAIN   7
++#define ATH10K_RC_FLAG_SGI        0x08 /* use HT SGI if set */
++#define ATH10K_RC_FLAG_STBC       0x10 /* use HT STBC if set */
++#define ATH10K_RC_FLAG_40MHZ      0x20 /* 40 mhz mode */
++#define ATH10K_RC_FLAG_80MHZ      0x40 /* 80 mhz mode */
++#define ATH10K_RC_FLAG_160MHZ     0x80 /* 160 mhz mode */
++
++
+ struct htt_tx_done {
+-	u32 msdu_id;
++	u16 msdu_id;
++	u8 tx_rate_code; /* CT firmware only */
++	u8 tx_rate_flags; /* CT firmware only */
+ 	bool discard;
+ 	bool no_ack;
+ 	bool success;
+diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
+index 7454bf5bbdd7..953ab340b4b0 100644
+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
+@@ -1668,10 +1668,24 @@ static void ath10k_htt_rx_frm_tx_compl(struct ath10k *ar,
+ 	ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx completion num_msdus %d\n",
+ 		   resp->data_tx_completion.num_msdus);
+ 
+-	for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
+-		msdu_id = resp->data_tx_completion.msdus[i];
+-		tx_done.msdu_id = __le16_to_cpu(msdu_id);
+-		ath10k_txrx_tx_unref(htt, &tx_done);
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
++		/* CT firmware reports tx-rate-kbps as well as the msdu id */
++		for (i = 0; i < resp->data_tx_completion_ct.num_msdus; i++) {
++			msdu_id = resp->data_tx_completion_ct.msdus[i].id;
++			tx_done.msdu_id = __le16_to_cpu(msdu_id);
++			tx_done.tx_rate_code = resp->data_tx_completion_ct.msdus[i].tx_rate_code;
++			tx_done.tx_rate_flags = resp->data_tx_completion_ct.msdus[i].tx_rate_flags;
++			ath10k_txrx_tx_unref(htt, &tx_done);
++		}
++	} else {
++		/* Uptream firmware does not report any tx-rate */
++		tx_done.tx_rate_code = 0;
++		tx_done.tx_rate_flags = 0;
++		for (i = 0; i < resp->data_tx_completion.num_msdus; i++) {
++			msdu_id = resp->data_tx_completion.msdus[i];
++			tx_done.msdu_id = __le16_to_cpu(msdu_id);
++			ath10k_txrx_tx_unref(htt, &tx_done);
++		}
+ 	}
+ }
+ 
+@@ -1999,6 +2013,8 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
+ 
+ 		tx_done.msdu_id =
+ 			__le32_to_cpu(resp->mgmt_tx_completion.desc_id);
++		tx_done.tx_rate_code = 0;
++		tx_done.tx_rate_flags = 0;
+ 
+ 		switch (status) {
+ 		case HTT_MGMT_TX_STATUS_OK:
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 46224d2734c6..92cc575cf00c 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -283,6 +283,8 @@ enum ath10k_hw_rate_cck {
+ #define TARGET_10X_NUM_PEERS_CT			(32 + (TARGET_10X_NUM_VDEVS_CT))
+ #define TARGET_10X_AST_SKID_LIMIT_CT		(TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
+ #define TARGET_10X_NUM_PEER_KEYS_CT             (WMI_MAX_KEY_INDEX + 1) /* 4 */
++/* These eat a fair chunk of memory on the firmware, so decrease it a bit. */
++#define TARGET_10X_NUM_MSDU_DESC_CT		808 /* must be multiple of 8 */
+ 
+ #define TARGET_10X_NUM_OFFLOAD_PEERS		0
+ #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0
+diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
+index 826500bb2b1b..6f0f8c4f19f4 100644
+--- a/drivers/net/wireless/ath/ath10k/txrx.c
++++ b/drivers/net/wireless/ath/ath10k/txrx.c
+@@ -44,6 +44,44 @@ out:
+ 	spin_unlock_bh(&ar->data_lock);
+ }
+ 
++static void ath10k_set_tx_rate_status(struct ieee80211_tx_rate *rate,
++				      const struct htt_tx_done *tx_done)
++{
++	u8 nss = (tx_done->tx_rate_code >> 4) & 0x3;
++	u8 rate_idx = tx_done->tx_rate_code & 0xF;
++
++	rate->count = 1;
++	rate->idx = rate_idx; /* TODO:  Not sure this is correct. */
++
++	if (((tx_done->tx_rate_code >> 6) & 0x3) == 1) {
++		/* CCK */
++		/* TODO:  Not sure about this. */
++		/* rate->flags |= IEEE80211_TX_RC_MCS; */
++	}
++
++	if ((tx_done->tx_rate_code & 0xcc) == 0x44)
++		rate->flags |= IEEE80211_TX_RC_USE_SHORT_PREAMBLE;
++
++	if ((tx_done->tx_rate_code & 0xc0) == 0x80)
++		rate->flags |= IEEE80211_TX_RC_MCS;
++
++	if ((tx_done->tx_rate_code & 0xc0) == 0xc0) {
++		rate->flags |= IEEE80211_TX_RC_VHT_MCS;
++		/* TODO-BEN:  Not sure this is correct. */
++		rate->idx = (nss << 4) | rate_idx;
++	}
++
++	if (tx_done->tx_rate_flags & ATH10K_RC_FLAG_40MHZ)
++		rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
++	if (tx_done->tx_rate_flags & ATH10K_RC_FLAG_80MHZ)
++		rate->flags |= IEEE80211_TX_RC_80_MHZ_WIDTH;
++	if (tx_done->tx_rate_flags & ATH10K_RC_FLAG_160MHZ)
++		rate->flags |= IEEE80211_TX_RC_160_MHZ_WIDTH;
++	if (tx_done->tx_rate_flags & ATH10K_RC_FLAG_SGI)
++		rate->flags |= IEEE80211_TX_RC_SHORT_GI;
++}
++
++
+ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+ 			  const struct htt_tx_done *tx_done)
+ {
+@@ -102,6 +140,12 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+ 	if (tx_done->success && (info->flags & IEEE80211_TX_CTL_NO_ACK))
+ 		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ 
++	if (tx_done->tx_rate_code || tx_done->tx_rate_flags) {
++		ath10k_set_tx_rate_status(&info->status.rates[0], tx_done);
++	} else {
++		info->status.rates[0].idx = -1;
++	}
++
+ 	ieee80211_tx_status(htt->ar->hw, msdu);
+ 	/* we do not own the msdu anymore */
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index e91b86d392d8..632211efee5a 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3853,9 +3853,11 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		else if (ath10k_modparam_nohwcrypt) {
+ 			ath10k_err(ar, "module param nohwcrypt enabled, but firmware does not support this feature.  Disabling swcrypt.\n");
+ 		}
++		config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE);
+ 		config.roam_offload_max_vdev = 0; /* disable roaming */
+ 		config.roam_offload_max_ap_profiles = 0; /* disable roaming */
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS_CT);
++		config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC_CT);
+ 	} else {
+ 		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+ 		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+@@ -3866,8 +3868,13 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		config.roam_offload_max_ap_profiles =
+ 			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
++		config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+ 	}
+ 	config.ast_skid_limit = __cpu_to_le32(skid_limit);
++
++	/* Firmware will crash if this is not even multiple of 8 */
++	BUG_ON(config.num_msdu_desc & 0x7);
++
+ 	config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
+ 	config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
+ 	config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
+@@ -3897,7 +3904,6 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 
+ 	config.vow_config = __cpu_to_le32(TARGET_10X_VOW_CONFIG);
+ 
+-	config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+ 	config.max_frag_entries = __cpu_to_le32(TARGET_10X_MAX_FRAG_ENTRIES);
+ 
+ 	len = sizeof(*cmd) +
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 2cdd36dca529..43ac25ee17ae 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -1678,7 +1678,9 @@ struct wmi_resource_config {
+ 	 *  You should probably not enable this unless you need to
+ 	 *  connect multiple stations to same AP.
+ 	 */
+-	#define ATH10k_USE_SW_RX_CRYPT 0x10000
++	#define ATH10k_USE_SW_RX_CRYPT    0x10000
++	/* Ask firmware to include tx-rate in completion messages. */
++	#define ATH10k_USE_TXCOMPL_TXRATE 0x20000
+ 	__le32 rx_decap_mode;
+ 
+ 	/* what is the maximum number of scan requests that can be queued */
diff --git a/package/kernel/mac80211/patches/999-0041-ath10k-Support-configuring-htc-buffers.patch b/package/kernel/mac80211/patches/999-0041-ath10k-Support-configuring-htc-buffers.patch
new file mode 100644
index 0000000..34aad34
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0041-ath10k-Support-configuring-htc-buffers.patch
@@ -0,0 +1,78 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 17 Apr 2014 11:22:56 -0700
+Subject: [PATCH] ath10k: Support configuring htc buffers.
+
+Some of this is CT firmware only, and in particular,
+even the non CT specific htc settings may not fully
+work as expected on upstream firmware.
+---
+ drivers/net/wireless/ath/ath10k/core.c      | 16 ++++++++++++++++
+ drivers/net/wireless/ath/ath10k/hw.h        | 10 ++++++++++
+ drivers/net/wireless/ath/ath10k/targaddrs.h |  6 ++++++
+ 3 files changed, 32 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 4104fce62af3..103ffa46700e 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -123,6 +123,22 @@ static int ath10k_init_configure_target(struct ath10k *ar)
+ 		return ret;
+ 	}
+ 
++	/* Configure HTC credits logic. */
++	param_host = (TARGET_HTC_MAX_CONTROL_BUFFERS << 16);
++	param_host |= (TARGET_HTC_MAX_PENDING_TXCREDITS_RPTS << 20);
++
++	/* Max tx buffers (tx-credits), CT firmware only.
++	 * but normal .487 firmware will just ignore it fine.
++	 */
++	param_host |= (TARGET_HTC_MAX_TX_CREDITS_CT << 24);
++
++	ret = ath10k_bmi_write32(ar, hi_mbox_io_block_sz,
++				 param_host);
++	if (ret) {
++		ath10k_err(ar, "failed setting HTC mbox-io-block-sz\n");
++		return ret;
++	}
++
+ 	/* set the firmware mode to STA/IBSS/AP */
+ 	ret = ath10k_bmi_read32(ar, hi_option_flag, &param_host);
+ 	if (ret) {
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 92cc575cf00c..22bb8580fc02 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -286,6 +286,16 @@ enum ath10k_hw_rate_cck {
+ /* These eat a fair chunk of memory on the firmware, so decrease it a bit. */
+ #define TARGET_10X_NUM_MSDU_DESC_CT		808 /* must be multiple of 8 */
+ 
++/* Related to HTC buffers */
++ /* return any credit immediately */
++#define TARGET_HTC_MAX_PENDING_TXCREDITS_RPTS   1
++/* 8 ctrl buffers for sending info to host */
++#define TARGET_HTC_MAX_CONTROL_BUFFERS          8
++/* Only CT firmware will actually use this value.  Each buffer is close to 2K
++ * of firmware RAM, so not sure if increasing this is worth the RAM cost.
++ */
++#define TARGET_HTC_MAX_TX_CREDITS_CT            2
++
+ #define TARGET_10X_NUM_OFFLOAD_PEERS		0
+ #define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS	0
+ #define TARGET_10X_NUM_PEER_KEYS		2
+diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h
+index a417aae52623..78e869eb6e33 100644
+--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
++++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
+@@ -109,6 +109,12 @@ struct host_interest {
+ 	u32 hi_desired_baud_rate;			/* 0x60 */
+ 	u32 hi_dbglog_config;				/* 0x64 */
+ 	u32 hi_end_ram_reserve_sz;			/* 0x68 */
++	/* This controls the HTC pipe init setup.
++	 * 0x0F0000 ( x >> 16 & 0xf) is mask of ctrl-buffers-allocated.
++	 * 0xF00000 ( x >> 20 & 0xf) is mask of max-ep-pending-credit-rpts.
++	 * 0xFF000000 (x >> 24 & 0xff) is tx-credits in CT firmware only.
++	 * The rest appears un-used.
++	 */
+ 	u32 hi_mbox_io_block_sz;			/* 0x6c */
+ 
+ 	u32 hi_num_bpatch_streams;			/* 0x70 -- unused */
diff --git a/package/kernel/mac80211/patches/999-0042-ath10k-Support-dumping-certain-target-registers.patch b/package/kernel/mac80211/patches/999-0042-ath10k-Support-dumping-certain-target-registers.patch
new file mode 100644
index 0000000..2c3b24b
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0042-ath10k-Support-dumping-certain-target-registers.patch
@@ -0,0 +1,347 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 31 Dec 2014 13:40:07 -0800
+Subject: [PATCH] ath10k: Support dumping certain target registers.
+
+Helps debug firmware issues.
+
+fw-powerup-fail gives user-space a normal-ish way to detect that
+firmware has failed to start and that a reboot is
+probably required.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  |  21 ++++
+ drivers/net/wireless/ath/ath10k/debug.c | 191 +++++++++++++++++++++++++++++++-
+ drivers/net/wireless/ath/ath10k/wmi.h   |  38 +++++++
+ 3 files changed, 247 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 967b9bec2824..93a08bd3b22c 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -245,6 +245,27 @@ struct ath10k_fw_stats {
+ 	struct list_head pdevs;
+ 	struct list_head vdevs;
+ 	struct list_head peers;
++
++	/* Register and related dump, CT firmware only. */
++	u32 mac_filter_addr_l32;
++	u32 mac_filter_addr_u16;
++	u32 dcu_slot_time;
++	u32 phy_bb_mode_select;
++	u32 pcu_bssid_l32;
++	u32 pcu_bssid_u16;
++	u32 pcu_bssid2_l32;
++	u32 pcu_bssid2_u16;
++	u32 pcu_sta_addr_l32;
++	u32 pcu_sta_addr_u16;
++	u32 mac_dma_cfg;
++	u32 mac_dma_txcfg;
++	u32 pcu_rxfilter;
++	u32 phy_bb_gen_controls;
++	u32 sw_powermode;
++	u16 sw_chainmask_tx;
++	u16 sw_chainmask_rx;
++	u32 sw_opmode;
++	u32 sw_rxfilter;
+ };
+ 
+ struct ath10k_dfs_stats {
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index eff0f39f1384..5a6d59a69e1b 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -327,12 +327,84 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
+ 	size_t num_peers;
+ 	size_t num_vdevs;
+ 	int ret;
++	const struct wmi_stats_event *ev = (void *)skb->data;
+ 
+ 	INIT_LIST_HEAD(&stats.pdevs);
+ 	INIT_LIST_HEAD(&stats.vdevs);
+ 	INIT_LIST_HEAD(&stats.peers);
+ 
+ 	spin_lock_bh(&ar->data_lock);
++
++	/* CT Firmware only */
++	if (__le32_to_cpu(ev->stats_id) == WMI_REQUEST_REGISTER_DUMP) {
++		struct ath10k_reg_dump* regdump = (struct ath10k_reg_dump*)(ev->data);
++		struct ath10k_fw_stats* sptr = &ar->debug.fw_stats;
++		int i;
++		for (i = 0; i < __le16_to_cpu(regdump->count); i++) {
++			switch (__le16_to_cpu(regdump->regpair[i].reg_id)) {
++			case REG_DUMP_NONE:
++				break;
++			case MAC_FILTER_ADDR_L32:
++				sptr->mac_filter_addr_l32 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case MAC_FILTER_ADDR_U16:
++				sptr->mac_filter_addr_u16 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case DCU_SLOT_TIME:
++				sptr->dcu_slot_time = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PHY_BB_MODE_SELECT:
++				sptr->phy_bb_mode_select = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_BSSID_L32:
++				sptr->pcu_bssid_l32 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_BSSID_U16:
++				sptr->pcu_bssid_u16 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_BSSID2_L32:
++				sptr->pcu_bssid_l32 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_BSSID2_U16:
++				sptr->pcu_bssid_u16 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_STA_ADDR_U16:
++				sptr->pcu_sta_addr_u16 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case MAC_DMA_CFG:
++				sptr->mac_dma_cfg = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case MAC_DMA_TXCFG:
++				sptr->mac_dma_txcfg = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_STA_ADDR_L32:
++				sptr->pcu_sta_addr_l32 = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PCU_RXFILTER:
++				sptr->pcu_rxfilter = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case PHY_BB_GEN_CONTROLS:
++				sptr->phy_bb_gen_controls = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case SW_POWERMODE:
++				sptr->sw_powermode = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case SW_CHAINMASK:
++				sptr->sw_chainmask_tx = (__le32_to_cpu(regdump->regpair[i].reg_val) >> 16);
++				sptr->sw_chainmask_rx = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case SW_OPMODE:
++				sptr->sw_opmode = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case SW_RXFILTER:
++				sptr->sw_rxfilter = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			}/* switch */
++		}
++		complete(&ar->debug.fw_stats_complete);
++		goto unlock;
++	}
++
+ 	ret = ath10k_wmi_pull_fw_stats(ar, skb, &stats);
+ 	if (ret) {
+ 		ath10k_warn(ar, "failed to pull fw stats: %d\n", ret);
+@@ -713,15 +785,17 @@ static int ath10k_fw_stats_release(struct inode *inode, struct file *file)
+ 	return 0;
+ }
+ 
+-int ath10k_refresh_peer_stats(struct ath10k *ar)
++int ath10k_refresh_peer_stats_t(struct ath10k *ar, u32 type)
+ {
+ 	int ret;
+ 	unsigned long time_left;
+ 
+ 	reinit_completion(&ar->debug.fw_stats_complete);
+-	ret = ath10k_wmi_request_stats(ar, ar->fw_stats_req_mask);
++	ret = ath10k_wmi_request_stats(ar, type);
++
+ 	if (ret) {
+-		ath10k_warn(ar, "could not request stats (%d)\n", ret);
++		ath10k_warn(ar, "could not request stats (type %d ret %d)\n",
++			    type, ret);
+ 		return ret;
+ 	}
+ 
+@@ -734,6 +808,107 @@ int ath10k_refresh_peer_stats(struct ath10k *ar)
+ 	return 0;
+ }
+ 
++int ath10k_refresh_peer_stats(struct ath10k *ar)
++{
++	return ath10k_refresh_peer_stats_t(ar, ar->fw_stats_req_mask);
++}
++
++int ath10k_refresh_target_regs(struct ath10k *ar)
++{
++	if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT,
++		     ar->fw_features))
++		return ath10k_refresh_peer_stats_t(ar, WMI_REQUEST_REGISTER_DUMP);
++	return 0; /* fail silently if firmware does not support this option. */
++}
++
++
++static ssize_t ath10k_read_fw_regs(struct file *file, char __user *user_buf,
++				   size_t count, loff_t *ppos)
++{
++	struct ath10k *ar = file->private_data;
++	struct ath10k_fw_stats *fw_regs;
++	char *buf = NULL;
++	unsigned int len = 0, buf_len = 8000;
++	ssize_t ret_cnt = 0;
++	int ret;
++
++	fw_regs = &ar->debug.fw_stats;
++
++	mutex_lock(&ar->conf_mutex);
++
++	if (ar->state != ATH10K_STATE_ON)
++		goto exit;
++
++	buf = kzalloc(buf_len, GFP_KERNEL);
++	if (!buf)
++		goto exit;
++
++	ret = ath10k_refresh_target_regs(ar);
++	if (ret)
++		goto exit;
++
++	spin_lock_bh(&ar->data_lock);
++	len += scnprintf(buf + len, buf_len - len, "\n");
++	len += scnprintf(buf + len, buf_len - len, "%30s\n",
++			 "ath10k Target Register Dump");
++	len += scnprintf(buf + len, buf_len - len, "%30s\n\n",
++				 "=================");
++
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "MAC-FILTER-ADDR-L32", fw_regs->mac_filter_addr_l32);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "MAC-FILTER-ADDR-U16", fw_regs->mac_filter_addr_u16);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "DCU-SLOT-TIME", fw_regs->dcu_slot_time);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PHY-MODE-SELECT", fw_regs->phy_bb_mode_select);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PHY-BB-GEN-CONTROLS", fw_regs->phy_bb_gen_controls);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PCU-BSSID-L32", fw_regs->pcu_bssid_l32);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PCU-BSSID-U16", fw_regs->pcu_bssid_u16);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PCU-BSSID2-L32", fw_regs->pcu_bssid2_l32);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PCU-BSSID2-U16", fw_regs->pcu_bssid2_u16);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PCU-STA-ADDR-L32", fw_regs->pcu_sta_addr_l32);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "PCU-STA-ADDR-U16", fw_regs->pcu_sta_addr_u16);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "MAC-DMA-CFG", fw_regs->mac_dma_cfg);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "MAC-DMA-TXCFG", fw_regs->mac_dma_txcfg);
++
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "SW-POWERMODE", fw_regs->sw_powermode);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "SW-CHAINMASK-TX", (u32)(fw_regs->sw_chainmask_tx));
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "SW-CHAINMASK-RX", (u32)(fw_regs->sw_chainmask_rx));
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "SW-OPMODE", fw_regs->sw_opmode);
++
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "MAC-PCU-RXFILTER", fw_regs->pcu_rxfilter);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "SW-RXFILTER", fw_regs->sw_rxfilter);
++
++	spin_unlock_bh(&ar->data_lock);
++
++	if (len > buf_len)
++		len = buf_len;
++
++	ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++exit:
++	mutex_unlock(&ar->conf_mutex);
++	kfree(buf);
++	return ret_cnt;
++}
++
++
+ static ssize_t ath10k_fw_stats_read(struct file *file, char __user *user_buf,
+ 				    size_t count, loff_t *ppos)
+ {
+@@ -812,6 +987,13 @@ static int ath10k_debug_fw_assert(struct ath10k *ar)
+ 				   ar->wmi.cmd->vdev_install_key_cmdid);
+ }
+ 
++static const struct file_operations fops_fw_regs = {
++	.read = ath10k_read_fw_regs,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
+ static ssize_t ath10k_read_simulate_fw_crash(struct file *file,
+ 					     char __user *user_buf,
+ 					     size_t count, loff_t *ppos)
+@@ -2298,6 +2480,9 @@ int ath10k_debug_register(struct ath10k *ar)
+ 	debugfs_create_file("fw_reset_stats", S_IRUSR, ar->debug.debugfs_phy,
+ 			    ar, &fops_fw_reset_stats);
+ 
++	debugfs_create_file("fw_regs", S_IRUSR, ar->debug.debugfs_phy, ar,
++			    &fops_fw_regs);
++
+ 	debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
+ 			    &fops_wmi_services);
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 43ac25ee17ae..b062c362734a 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -3088,6 +3088,43 @@ struct wmi_pdev_stats_peer {
+ 	__le32 dummy;
+ } __packed;
+ 
++
++#define REG_DUMP_NONE         0
++#define MAC_FILTER_ADDR_L32   1
++#define MAC_FILTER_ADDR_U16   2
++#define DCU_SLOT_TIME         3
++#define PHY_BB_MODE_SELECT    4
++#define PCU_BSSID_L32         5
++#define PCU_BSSID_U16         6
++#define PCU_BSSID2_L32        7
++#define PCU_BSSID2_U16        8
++#define PCU_STA_ADDR_U16      9
++#define MAC_DMA_CFG          10
++#define MAC_DMA_TXCFG        11
++#define PCU_STA_ADDR_L32     12
++#define PCU_RXFILTER         13
++#define PHY_BB_GEN_CONTROLS  14
++#define SW_POWERMODE         17
++#define SW_CHAINMASK         18 /* tx is high 16 bits, rx is low 16 bits */
++#define SW_OPMODE            19
++#define SW_RXFILTER          20
++
++#define REG_DUMP_COUNT       20 /* max number of registers to dump at once. */
++
++struct ath10k_reg_dump_pair {
++	__le32 reg_id;
++	__le32 reg_val;
++};
++
++struct ath10k_reg_dump {
++	__le16 count;
++	__le16 unused;
++	struct ath10k_reg_dump_pair regpair[REG_DUMP_COUNT];
++};
++
++/* These values are a bitmap, but 10.1.x (at least) firmware will not properly
++ * handle multiple values OR'd together.
++ */
+ enum wmi_stats_id {
+ 	WMI_STAT_PEER = BIT(0),
+ 	WMI_STAT_AP = BIT(1),
+@@ -3095,6 +3132,7 @@ enum wmi_stats_id {
+ 	WMI_STAT_VDEV = BIT(3),
+ 	WMI_STAT_BCNFLT = BIT(4),
+ 	WMI_STAT_VDEV_RATE = BIT(5),
++	WMI_REQUEST_REGISTER_DUMP = BIT(7), /* 0x80, CT Firmware only, request register dump. */
+ };
+ 
+ struct wlan_inst_rssi_args {
diff --git a/package/kernel/mac80211/patches/999-0043-ath10k-add-fw-powerfup-fail-to-ethtool-stats.patch b/package/kernel/mac80211/patches/999-0043-ath10k-add-fw-powerfup-fail-to-ethtool-stats.patch
new file mode 100644
index 0000000..91f5f1a
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0043-ath10k-add-fw-powerfup-fail-to-ethtool-stats.patch
@@ -0,0 +1,64 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 31 Dec 2014 13:45:55 -0800
+Subject: [PATCH] ath10k: add fw-powerfup-fail to ethtool stats.
+
+This gives user-space a normal-ish way to detect that
+firmware has failed to start and that a reboot is
+probably required.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  | 1 +
+ drivers/net/wireless/ath/ath10k/debug.c | 2 ++
+ drivers/net/wireless/ath/ath10k/pci.c   | 2 ++
+ 3 files changed, 5 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 93a08bd3b22c..dbfbcfffca4c 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -589,6 +589,7 @@ struct ath10k {
+ 	u8 mac_addr[ETH_ALEN];
+ 
+ 	enum ath10k_hw_rev hw_rev;
++	bool fw_powerup_failed; /* If true, might take reboot to recover. */
+ 	u32 chip_id;
+ 	u32 target_version;
+ 	u8 fw_version_major;
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 5a6d59a69e1b..891a29d4ada9 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -1870,6 +1870,7 @@ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
+ 	"d_fw_crash_count",
+ 	"d_fw_warm_reset_count",
+ 	"d_fw_cold_reset_count",
++	"d_fw_powerup_failed", /* boolean */
+ };
+ 
+ #define ATH10K_SSTATS_LEN ARRAY_SIZE(ath10k_gstrings_stats)
+@@ -1969,6 +1970,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ 	data[i++] = ar->stats.fw_crash_counter;
+ 	data[i++] = ar->stats.fw_warm_reset_counter;
+ 	data[i++] = ar->stats.fw_cold_reset_counter;
++	data[i++] = ar->fw_powerup_failed;
+ 
+ 	spin_unlock_bh(&ar->data_lock);
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index ea74f5b62459..96daa35705ba 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -2394,10 +2394,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
+ 		goto err_ce;
+ 	}
+ 
++	ar->fw_powerup_failed = false;
+ 	return 0;
+ 
+ err_ce:
+ 	ath10k_pci_ce_deinit(ar);
++	ar->fw_powerup_failed = true;
+ 
+ err_sleep:
+ 	return ret;
diff --git a/package/kernel/mac80211/patches/999-0044-ath10k-Request-OTP-to-return-debug-code.patch b/package/kernel/mac80211/patches/999-0044-ath10k-Request-OTP-to-return-debug-code.patch
new file mode 100644
index 0000000..5bc8252
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0044-ath10k-Request-OTP-to-return-debug-code.patch
@@ -0,0 +1,25 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 2 May 2014 06:18:18 -0700
+Subject: [PATCH] ath10k: Request OTP to return debug code.
+
+Normal firmware will ignore this, but CT firmware will
+return debugging info in it's return code.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 103ffa46700e..1db9b0aba24f 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -396,7 +396,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
+ 		return ret;
+ 	}
+ 
+-	ret = ath10k_bmi_execute(ar, address, 0, &result);
++	ret = ath10k_bmi_execute(ar, address, 0x88888888, &result);
+ 	if (ret) {
+ 		ath10k_err(ar, "could not execute otp (%d)\n", ret);
+ 		return ret;
diff --git a/package/kernel/mac80211/patches/999-0045-ath10k-Support-up-to-36-station-vifs-with-CT-firmwar.patch b/package/kernel/mac80211/patches/999-0045-ath10k-Support-up-to-36-station-vifs-with-CT-firmwar.patch
new file mode 100644
index 0000000..0c25836
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0045-ath10k-Support-up-to-36-station-vifs-with-CT-firmwar.patch
@@ -0,0 +1,39 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 9 May 2014 14:59:37 -0700
+Subject: [PATCH] ath10k: Support up to 36 station vifs with CT firmware.
+
+Need to somehow free up more memory in main RAM in order to
+increase this further.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/hw.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 22bb8580fc02..0a818e07a330 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -279,18 +279,18 @@ enum ath10k_hw_rate_cck {
+ 						 (TARGET_10X_NUM_VDEVS))
+ 
+ /* Over-rides for Candela Technologies firmware */
+-#define TARGET_10X_NUM_VDEVS_CT			32
+-#define TARGET_10X_NUM_PEERS_CT			(32 + (TARGET_10X_NUM_VDEVS_CT))
++#define TARGET_10X_NUM_VDEVS_CT			36
++#define TARGET_10X_NUM_PEERS_CT			(2 * TARGET_10X_NUM_VDEVS_CT)
+ #define TARGET_10X_AST_SKID_LIMIT_CT		(TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
+ #define TARGET_10X_NUM_PEER_KEYS_CT             (WMI_MAX_KEY_INDEX + 1) /* 4 */
+ /* These eat a fair chunk of memory on the firmware, so decrease it a bit. */
+ #define TARGET_10X_NUM_MSDU_DESC_CT		808 /* must be multiple of 8 */
+ 
+ /* Related to HTC buffers */
+- /* return any credit immediately */
++/* return any credit immediately */
+ #define TARGET_HTC_MAX_PENDING_TXCREDITS_RPTS   1
+ /* 8 ctrl buffers for sending info to host */
+-#define TARGET_HTC_MAX_CONTROL_BUFFERS          8
++#define TARGET_HTC_MAX_CONTROL_BUFFERS          6
+ /* Only CT firmware will actually use this value.  Each buffer is close to 2K
+  * of firmware RAM, so not sure if increasing this is worth the RAM cost.
+  */
diff --git a/package/kernel/mac80211/patches/999-0046-ath10k-Note-limitation-on-beaconing-vdevs.patch b/package/kernel/mac80211/patches/999-0046-ath10k-Note-limitation-on-beaconing-vdevs.patch
new file mode 100644
index 0000000..433a5d6
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0046-ath10k-Note-limitation-on-beaconing-vdevs.patch
@@ -0,0 +1,39 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 13 May 2014 11:44:45 -0700
+Subject: [PATCH] ath10k: Note limitation on beaconing vdevs.
+
+This only pertains to CT firmware, as standard firmware
+can't do anywhere near this many vdevs anyway.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index b0732b9e3537..2cf645f38acf 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -1278,6 +1278,22 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif,
+ 	arg.channel.max_reg_power = chandef->chan->max_reg_power * 2;
+ 	arg.channel.max_antenna_gain = chandef->chan->max_antenna_gain * 2;
+ 
++	/* CT Firmware can support 32+ VDEVS, but can only support
++	 * beacon-ing devs with dev ids 0 - 31 due to firmware limitations.
++	 * Create VAPs first and all should be well...likely most people
++	 * won't ever hit this anyway, but some day the vdev ID allocation
++	 * could be made smarter to make it more likely to work no matter the
++	 * order the vdevs are created. --Ben
++	 */
++	if ((arvif->vdev_type == WMI_VDEV_TYPE_AP) ||
++	    (arvif->vdev_type == WMI_VDEV_TYPE_IBSS)) {
++		if (arg.vdev_id > 31) {
++			ath10k_warn(ar, "failed to start vdev %i  Beaconing VIFS must have IDs <= 31 to work-around firmware limitations.\n",
++				    arg.vdev_id);
++			return -EINVAL;
++		}
++	}
++
+ 	if (arvif->vdev_type == WMI_VDEV_TYPE_AP) {
+ 		arg.ssid = arvif->u.ap.ssid;
+ 		arg.ssid_len = arvif->u.ap.ssid_len;
diff --git a/package/kernel/mac80211/patches/999-0047-ath10k-Allow-over-riding-regulatory-domain.patch b/package/kernel/mac80211/patches/999-0047-ath10k-Allow-over-riding-regulatory-domain.patch
new file mode 100644
index 0000000..72ed04f
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0047-ath10k-Allow-over-riding-regulatory-domain.patch
@@ -0,0 +1,58 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 31 Dec 2014 13:51:29 -0800
+Subject: [PATCH] ath10k: Allow over-riding regulatory domain.
+
+Uses ath10k_core module parameter 'override_eeprom_regdomain'
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi.c | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 632211efee5a..e517eaf970bb 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -17,6 +17,7 @@
+ 
+ #include <linux/skbuff.h>
+ #include <linux/ctype.h>
++#include <linux/module.h>
+ 
+ #include "core.h"
+ #include "htc.h"
+@@ -29,6 +30,12 @@
+ #include "p2p.h"
+ #include "hw.h"
+ 
++static int modparam_override_eeprom_regdomain = -1;
++module_param_named(override_eeprom_regdomain,
++		   modparam_override_eeprom_regdomain, int, 0444);
++MODULE_PARM_DESC(override_eeprom_regdomain, "Override regdomain hardcoded in EEPROM with this value (DANGEROUS).");
++
++
+ /* MAIN WMI cmd track */
+ static struct wmi_cmd_map wmi_cmd_map = {
+ 	.init_cmdid = WMI_INIT_CMDID,
+@@ -3107,6 +3114,21 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)
+ 			 ar->fw_version_build);
+ 	}
+ 
++	if ((modparam_override_eeprom_regdomain != -1) &&
++	    (modparam_override_eeprom_regdomain != ar->ath_common.regulatory.current_rd)) {
++		static int do_once = 1;
++		if (do_once) {
++			ath10k_err(ar, "DANGER! You're overriding EEPROM-defined regulatory domain,"
++				   "\nfrom: 0x%x to 0x%x\n",
++				   ar->ath_common.regulatory.current_rd, modparam_override_eeprom_regdomain);
++			ath10k_err(ar, "Your card was not certified to operate in the domain you chose.\n");
++			ath10k_err(ar, "This might result in a violation of your local regulatory rules.\n");
++			ath10k_err(ar, "Do not ever do this unless you really know what you are doing!\n");
++			do_once = 0;
++		}
++		ar->ath_common.regulatory.current_rd = modparam_override_eeprom_regdomain | COUNTRY_ERD_FLAG;
++	}
++
+ 	num_mem_reqs = __le32_to_cpu(arg.num_mem_reqs);
+ 	if (num_mem_reqs > WMI_MAX_MEM_REQS) {
+ 		ath10k_warn(ar, "requested memory chunks number (%d) exceeds the limit\n",
diff --git a/package/kernel/mac80211/patches/999-0048-ath10k-do-not-ratelimit-ath10k_warn-messages.patch b/package/kernel/mac80211/patches/999-0048-ath10k-do-not-ratelimit-ath10k_warn-messages.patch
new file mode 100644
index 0000000..7149d6d
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0048-ath10k-do-not-ratelimit-ath10k_warn-messages.patch
@@ -0,0 +1,26 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 12 Feb 2014 17:52:56 -0800
+Subject: [PATCH] ath10k: do not ratelimit ath10k_warn messages
+
+These are too important to miss, and if we ever do have some
+that are overly verbose, could ratelimit the call to ath10k_warn
+instead of doing the ratelimit inside of ath10k_warn.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 891a29d4ada9..7a930df51128 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -193,7 +193,7 @@ void ath10k_warn(struct ath10k *ar, const char *fmt, ...)
+ 
+ 	va_start(args, fmt);
+ 	vaf.va = &args;
+-	dev_warn_ratelimited(ar->dev, "%pV", &vaf);
++	dev_warn(ar->dev, "%pV", &vaf);
+ 	trace_ath10k_log_warn(ar, &vaf);
+ 
+ 	va_end(args);
diff --git a/package/kernel/mac80211/patches/999-0049-ath10k-Module-param-to-config-number-of-vdevs.patch b/package/kernel/mac80211/patches/999-0049-ath10k-Module-param-to-config-number-of-vdevs.patch
new file mode 100644
index 0000000..aa893d1
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0049-ath10k-Module-param-to-config-number-of-vdevs.patch
@@ -0,0 +1,181 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 26 Jun 2014 11:34:07 -0700
+Subject: [PATCH] ath10k: Module param to config number of vdevs.
+
+Depending on version of firmware, different numbers
+of vdevs can be supported.  Allow user to over-ride
+defaults for CT firmware.  Other firmware will not
+be affected by this change.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c |  2 +-
+ drivers/net/wireless/ath/ath10k/hw.h   |  5 +++--
+ drivers/net/wireless/ath/ath10k/mac.c  | 23 ++++++++++++++++-------
+ drivers/net/wireless/ath/ath10k/mac.h  |  1 +
+ drivers/net/wireless/ath/ath10k/wmi.c  | 14 ++++++--------
+ 5 files changed, 27 insertions(+), 18 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 1db9b0aba24f..e4987f3e4808 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1142,7 +1142,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
+ 		if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
+ 			ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
+ 			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+-			ar->max_num_vdevs = TARGET_10X_NUM_VDEVS_CT;
++			ar->max_num_vdevs = ath10k_modparam_target_num_vdevs_ct;
+ 			ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC_CT;
+ 		} else {
+ 			ar->max_num_peers = TARGET_10X_NUM_PEERS;
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 0a818e07a330..0077f87060c5 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -279,8 +279,9 @@ enum ath10k_hw_rate_cck {
+ 						 (TARGET_10X_NUM_VDEVS))
+ 
+ /* Over-rides for Candela Technologies firmware */
+-#define TARGET_10X_NUM_VDEVS_CT			36
+-#define TARGET_10X_NUM_PEERS_CT			(2 * TARGET_10X_NUM_VDEVS_CT)
++#define DEF_TARGET_10X_NUM_VDEVS_CT		36 /* newer CT firmware support more,
++						    * override w/module parm */
++#define TARGET_10X_NUM_PEERS_CT			(2 * ath10k_modparam_target_num_vdevs_ct)
+ #define TARGET_10X_AST_SKID_LIMIT_CT		(TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
+ #define TARGET_10X_NUM_PEER_KEYS_CT             (WMI_MAX_KEY_INDEX + 1) /* 4 */
+ /* These eat a fair chunk of memory on the firmware, so decrease it a bit. */
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 2cf645f38acf..90d2458c98c7 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -161,6 +161,9 @@ ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
+ int ath10k_modparam_nohwcrypt;
+ module_param_named(nohwcrypt, ath10k_modparam_nohwcrypt, int, 0444);
+ MODULE_PARM_DESC(nohwcrypt, "Disable hardware rx decrypt feature");
++int ath10k_modparam_target_num_vdevs_ct = DEF_TARGET_10X_NUM_VDEVS_CT;
++module_param_named(num_vdevs_ct, ath10k_modparam_target_num_vdevs_ct, int, 0444);
++MODULE_PARM_DESC(num_vdevs_ct, "Maximum vdevs to request from firmware");
+ 
+ /**********/
+ /* Crypto */
+@@ -6568,9 +6571,9 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = {
+ 	},
+ };
+ 
+-static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
++static struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
+ 	{
+-	.max	= TARGET_10X_NUM_VDEVS_CT,
++	.max	= DEF_TARGET_10X_NUM_VDEVS_CT,
+ 	.types	= BIT(NL80211_IFTYPE_STATION)
+ 		| BIT(NL80211_IFTYPE_P2P_CLIENT)
+ 	},
+@@ -6584,7 +6587,7 @@ static const struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
+ 	},
+ };
+ 
+-static const struct ieee80211_iface_combination ath10k_if_comb[] = {
++static struct ieee80211_iface_combination ath10k_if_comb[] = {
+ 	{
+ 		.limits = ath10k_if_limits,
+ 		.n_limits = ARRAY_SIZE(ath10k_if_limits),
+@@ -6594,7 +6597,7 @@ static const struct ieee80211_iface_combination ath10k_if_comb[] = {
+ 	},
+ };
+ 
+-static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
++static struct ieee80211_iface_combination ath10k_10x_if_comb[] = {
+ 	{
+ 		.limits = ath10k_10x_if_limits,
+ 		.n_limits = ARRAY_SIZE(ath10k_10x_if_limits),
+@@ -6668,11 +6671,11 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = {
+ 	},
+ };
+ 
+-static const struct ieee80211_iface_combination ath10k_10x_ct_if_comb[] = {
++static struct ieee80211_iface_combination ath10k_10x_ct_if_comb[] = {
+ 	{
+ 		.limits = ath10k_10x_ct_if_limits,
+ 		.n_limits = ARRAY_SIZE(ath10k_10x_ct_if_limits),
+-		.max_interfaces = TARGET_10X_NUM_VDEVS_CT,
++		.max_interfaces = DEF_TARGET_10X_NUM_VDEVS_CT,
+ 		.num_different_channels = 1,
+ 		.beacon_int_infra_match = true,
+ #ifdef CPTCFG_ATH10K_DFS_CERTIFIED
+@@ -7001,7 +7004,13 @@ int ath10k_mac_register(struct ath10k *ar)
+ 		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_1:
+ 		if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
+-			ar->hw->wiphy->iface_combinations = ath10k_10x_ct_if_comb;
++			ath10k_10x_ct_if_comb[0].limits[0].max =
++				ar->max_num_vdevs;
++			ath10k_10x_ct_if_comb[0].max_interfaces =
++				ar->max_num_vdevs;
++
++			ar->hw->wiphy->iface_combinations =
++				ath10k_10x_ct_if_comb;
+ 			ar->hw->wiphy->n_iface_combinations =
+ 				ARRAY_SIZE(ath10k_10x_ct_if_comb);
+ 		} else {
+diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
+index 03852b1f42f1..3580417342b3 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.h
++++ b/drivers/net/wireless/ath/ath10k/mac.h
+@@ -27,6 +27,7 @@ enum wmi_tlv_tx_pause_id;
+ enum wmi_tlv_tx_pause_action;
+ 
+ extern int ath10k_modparam_nohwcrypt;
++extern int ath10k_modparam_target_num_vdevs_ct;
+ 
+ struct ath10k_generic_iter {
+ 	struct ath10k *ar;
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index e517eaf970bb..3d5b27cbe286 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3781,8 +3781,8 @@ static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar)
+ 	struct wmi_resource_config config = {};
+ 	u32 len, val;
+ 
+-	config.num_vdevs = __cpu_to_le32(TARGET_NUM_VDEVS);
+-	config.num_peers = __cpu_to_le32(TARGET_NUM_PEERS);
++	config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs);
++	config.num_peers = __cpu_to_le32(ar->max_num_peers);
+ 	config.num_offload_peers = __cpu_to_le32(TARGET_NUM_OFFLOAD_PEERS);
+ 
+ 	config.num_offload_reorder_bufs =
+@@ -3858,9 +3858,10 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 
+ 	config.rx_decap_mode = __cpu_to_le32(TARGET_10X_RX_DECAP_MODE);
+ 
++	config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs);
++	config.num_peers = __cpu_to_le32(ar->max_num_peers);
++
+ 	if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
+-		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS_CT);
+-		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS_CT);
+ 		skid_limit = TARGET_10X_AST_SKID_LIMIT_CT;
+ 		if (test_bit(ATH10K_FW_FEATURE_CT_RXSWCRYPT, ar->fw_features) &&
+ 		    ath10k_modparam_nohwcrypt) {
+@@ -3879,10 +3880,7 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		config.roam_offload_max_vdev = 0; /* disable roaming */
+ 		config.roam_offload_max_ap_profiles = 0; /* disable roaming */
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS_CT);
+-		config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC_CT);
+ 	} else {
+-		config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
+-		config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
+ 		skid_limit = TARGET_10X_AST_SKID_LIMIT;
+ 		config.roam_offload_max_vdev =
+ 			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_VDEV);
+@@ -3890,8 +3888,8 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		config.roam_offload_max_ap_profiles =
+ 			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
+-		config.num_msdu_desc = __cpu_to_le32(TARGET_10X_NUM_MSDU_DESC);
+ 	}
++	config.num_msdu_desc = __cpu_to_le32(ar->htt.max_num_pending_tx);
+ 	config.ast_skid_limit = __cpu_to_le32(skid_limit);
+ 
+ 	/* Firmware will crash if this is not even multiple of 8 */
diff --git a/package/kernel/mac80211/patches/999-0050-ath10k-Allow-disabling-WoW-in-firmware.patch b/package/kernel/mac80211/patches/999-0050-ath10k-Allow-disabling-WoW-in-firmware.patch
new file mode 100644
index 0000000..f7373d6
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0050-ath10k-Allow-disabling-WoW-in-firmware.patch
@@ -0,0 +1,40 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 1 Jul 2014 07:30:38 -0700
+Subject: [PATCH] ath10k: Allow disabling WoW in firmware.
+
+Saves about 2.5k of RAM in firmware.  Requires CT firmware.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi.c | 2 ++
+ drivers/net/wireless/ath/ath10k/wmi.h | 4 ++++
+ 2 files changed, 6 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 3d5b27cbe286..5fc93c4b21d9 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3877,6 +3877,8 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 			ath10k_err(ar, "module param nohwcrypt enabled, but firmware does not support this feature.  Disabling swcrypt.\n");
+ 		}
+ 		config.rx_decap_mode |= __cpu_to_le32(ATH10k_USE_TXCOMPL_TXRATE);
++		/* Disable WoW in firmware, could make this module option perhaps? */
++		config.rx_decap_mode |= __cpu_to_le32(ATH10k_DISABLE_WOW);
+ 		config.roam_offload_max_vdev = 0; /* disable roaming */
+ 		config.roam_offload_max_ap_profiles = 0; /* disable roaming */
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS_CT);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index b062c362734a..3826783b8602 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -1681,6 +1681,10 @@ struct wmi_resource_config {
+ 	#define ATH10k_USE_SW_RX_CRYPT    0x10000
+ 	/* Ask firmware to include tx-rate in completion messages. */
+ 	#define ATH10k_USE_TXCOMPL_TXRATE 0x20000
++	/* Disable Wake-on-Wireless logic.  Saves some RAM, for those
++	 * that do not need WoW.
++	 */
++	#define ATH10k_DISABLE_WOW        0x40000
+ 	__le32 rx_decap_mode;
+ 
+ 	/* what is the maximum number of scan requests that can be queued */
diff --git a/package/kernel/mac80211/patches/999-0051-ath10k-Disable-beacon-miss-firmware-logic.patch b/package/kernel/mac80211/patches/999-0051-ath10k-Disable-beacon-miss-firmware-logic.patch
new file mode 100644
index 0000000..eed8d64
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0051-ath10k-Disable-beacon-miss-firmware-logic.patch
@@ -0,0 +1,51 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Sat, 5 Jul 2014 09:06:38 -0700
+Subject: [PATCH] ath10k: Disable beacon-miss firmware logic.
+
+Not sure it works all that well in multi-vdev
+environments anyway, since it only look at 2 vdevs?
+
+Needs some testing, and maybe further improvements to
+do useful beacon-loss detection with multiple vdevs.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi.c | 11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 5fc93c4b21d9..5f9a552fb049 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -3882,6 +3882,11 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		config.roam_offload_max_vdev = 0; /* disable roaming */
+ 		config.roam_offload_max_ap_profiles = 0; /* disable roaming */
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS_CT);
++
++		/* Disable beacon-miss logic, old code had it at 2 vdevs, which is not
++		 * nearly enough for us anyway..
++		 */
++		config.bmiss_offload_max_vdev = 0;
+ 	} else {
+ 		skid_limit = TARGET_10X_AST_SKID_LIMIT;
+ 		config.roam_offload_max_vdev =
+@@ -3890,6 +3895,9 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 		config.roam_offload_max_ap_profiles =
+ 			__cpu_to_le32(TARGET_10X_ROAM_OFFLOAD_MAX_AP_PROFILES);
+ 		config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
++		config.bmiss_offload_max_vdev =
++			__cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
++
+ 	}
+ 	config.num_msdu_desc = __cpu_to_le32(ar->htt.max_num_pending_tx);
+ 	config.ast_skid_limit = __cpu_to_le32(skid_limit);
+@@ -3908,9 +3916,6 @@ static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
+ 	config.scan_max_pending_reqs =
+ 		__cpu_to_le32(TARGET_10X_SCAN_MAX_PENDING_REQS);
+ 
+-	config.bmiss_offload_max_vdev =
+-		__cpu_to_le32(TARGET_10X_BMISS_OFFLOAD_MAX_VDEV);
+-
+ 	config.num_mcast_groups = __cpu_to_le32(TARGET_10X_NUM_MCAST_GROUPS);
+ 	config.num_mcast_table_elems =
+ 		__cpu_to_le32(TARGET_10X_NUM_MCAST_TABLE_ELEMS);
diff --git a/package/kernel/mac80211/patches/999-0052-ath10k-Support-up-to-64-vdevs.patch b/package/kernel/mac80211/patches/999-0052-ath10k-Support-up-to-64-vdevs.patch
new file mode 100644
index 0000000..5837ea9
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0052-ath10k-Support-up-to-64-vdevs.patch
@@ -0,0 +1,32 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 16 Jul 2014 04:17:01 -0700
+Subject: [PATCH] ath10k: Support up to 64 vdevs.
+
+The (1 << x) - 1 trick won't work when you
+are trying to fill up all 64 bits, so add special
+case for that.
+
+And, move the limits to the per-nic structure instead
+of per-driver to allow better dynamic use of the limits.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index e4987f3e4808..0565b1d82d53 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1363,7 +1363,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
+ 	if (status)
+ 		goto err_hif_stop;
+ 
+-	ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
++	if (ar->max_num_vdevs >= 64)
++		ar->free_vdev_map = 0xFFFFFFFFFFFFFFFFLL;
++	else
++		ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
+ 
+ 	INIT_LIST_HEAD(&ar->arvifs);
+ 
diff --git a/package/kernel/mac80211/patches/999-0053-ath10k-print-fw-debug-messages-in-hex.patch b/package/kernel/mac80211/patches/999-0053-ath10k-print-fw-debug-messages-in-hex.patch
new file mode 100644
index 0000000..85025ed
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0053-ath10k-print-fw-debug-messages-in-hex.patch
@@ -0,0 +1,136 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 22 Sep 2014 10:10:30 -0700
+Subject: [PATCH] ath10k: print fw debug messages in hex.
+
+This allows user-space tools to decode debug-log
+messages by parsing dmesg or /var/log/messages.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.c | 72 +++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/debug.h |  2 +
+ drivers/net/wireless/ath/ath10k/pci.c   |  3 ++
+ drivers/net/wireless/ath/ath10k/wmi.c   |  4 +-
+ 4 files changed, 80 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 7a930df51128..83b7b7b0b448 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -2610,3 +2610,75 @@ void ath10k_dbg_dump(struct ath10k *ar,
+ EXPORT_SYMBOL(ath10k_dbg_dump);
+ 
+ #endif /* CPTCFG_ATH10K_DEBUG */
++
++void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *ibuf, int len,
++				    const char* lvl)
++{
++	/* Print out raw hex, external tools can decode if
++	 * they care.
++	 * TODO:  Add ar identifier to messages.
++	 */
++	int q = 0;
++
++	printk("%sATH10K_DBG_BUFFER:\n", lvl);
++	while (q < len) {
++		if (q + 8 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
++			       ibuf[q+4], ibuf[q+5], ibuf[q+6], ibuf[q+7]);
++			q += 8;
++		}
++		else if (q + 7 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
++			       ibuf[q+4], ibuf[q+5], ibuf[q+6]);
++			q += 7;
++		}
++		else if (q + 6 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
++			       ibuf[q+4], ibuf[q+5]);
++			q += 6;
++		}
++		else if (q + 5 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3],
++			       ibuf[q+4]);
++			q += 5;
++		}
++		else if (q + 4 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1], ibuf[q+2], ibuf[q+3]);
++			q += 4;
++		}
++		else if (q + 3 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1], ibuf[q+2]);
++			q += 3;
++		}
++		else if (q + 2 <= len) {
++			printk("%sath10k: [%04d]: %08X %08X\n",
++			       lvl, q,
++			       ibuf[q], ibuf[q+1]);
++			q += 2;
++		}
++		else if (q + 1 <= len) {
++			printk("%sath10k: [%04d]: %08X\n",
++			       lvl, q,
++			       ibuf[q]);
++			q += 1;
++		}
++		else {
++			break;
++		}
++	}/* while */
++
++	printk("%sATH10K_END\n", lvl);
++}
++EXPORT_SYMBOL(ath10k_dbg_print_fw_dbg_buffer);
+diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
+index 6a2e00348bab..bdae404377c3 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.h
++++ b/drivers/net/wireless/ath/ath10k/debug.h
+@@ -171,5 +171,7 @@ static inline void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar,
+ #endif /* CPTCFG_ATH10K_DEBUG */
+ 
+ int ath10k_refresh_peer_stats(struct ath10k *ar);
++void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer,
++				    int len, const char* lvl);
+ 
+ #endif /* _DEBUG_H_ */
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 96daa35705ba..78469edefc68 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1365,6 +1365,9 @@ static void ath10k_pci_dump_dbglog(struct ath10k *ar)
+ 		WARN_ON(len & 0x3);
+ 
+ 		ath10k_dbg_save_fw_dbg_buffer(ar, (__le32 *)(buffer), len >> 2);
++		ath10k_dbg_print_fw_dbg_buffer(ar, (__le32 *)(buffer),
++					       dbuf.length/sizeof(__le32),
++					       KERN_ERR);
+ 		kfree(buffer);
+ 
+ next:
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 5f9a552fb049..cec29b8d89a9 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -1694,7 +1694,9 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
+ 	ath10k_dbg_save_fw_dbg_buffer(ar, ev->messages,
+ 				      (skb->len - 4)/sizeof(__le32));
+ 	spin_unlock_bh(&ar->data_lock);
+-
++	ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
++				       (skb->len - 4)/sizeof(__le32),
++				       KERN_INFO);
+ 	return 0;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0054-ath10k-make-firmware-text-debug-messages-more-verbos.patch b/package/kernel/mac80211/patches/999-0054-ath10k-make-firmware-text-debug-messages-more-verbos.patch
new file mode 100644
index 0000000..c3a7d82
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0054-ath10k-make-firmware-text-debug-messages-more-verbos.patch
@@ -0,0 +1,26 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 22 Sep 2014 13:46:46 -0700
+Subject: [PATCH] ath10k: make firmware text debug messages more verbose.
+
+There are not many of these messages producted by the
+firmware, but they are generally fairly useful, so print
+them at info level.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index cec29b8d89a9..7c8f40c12459 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -2853,7 +2853,7 @@ void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb)
+ 	/* the last byte is always reserved for the null character */
+ 	buf[i] = '\0';
+ 
+-	ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
++	ath10k_info(ar, "wmi print '%s'\n", buf);
+ }
+ 
+ void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
diff --git a/package/kernel/mac80211/patches/999-0055-ath10k-add-additional-regulatory-domain-debug-messag.patch b/package/kernel/mac80211/patches/999-0055-ath10k-add-additional-regulatory-domain-debug-messag.patch
new file mode 100644
index 0000000..ccad8dd
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0055-ath10k-add-additional-regulatory-domain-debug-messag.patch
@@ -0,0 +1,30 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 24 Sep 2014 13:31:53 -0700
+Subject: [PATCH] ath10k: add additional regulatory domain debug messages.
+
+Might help the next person who has to deal with regdom
+issues find the problem quicker.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 90d2458c98c7..e1a1ef014203 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -2942,8 +2942,13 @@ static void ath10k_regd_update(struct ath10k *ar)
+ 	if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+ 		nl_dfs_reg = ar->dfs_detector->region;
+ 		wmi_dfs_reg = ath10k_mac_get_dfs_region(nl_dfs_reg);
++		ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
++			   "nl_dfs_reg: %i  wmi_dfs_reg: %i\n",
++			    nl_dfs_reg, wmi_dfs_reg);
+ 	} else {
+ 		wmi_dfs_reg = WMI_UNINIT_DFS_DOMAIN;
++		ath10k_dbg(ar, ATH10K_DBG_REGULATORY,
++			   "not DFS_CERTIFIED or no dfs_detector.\n");
+ 	}
+ 
+ 	/* Target allows setting up per-band regdomain but ath_common provides
diff --git a/package/kernel/mac80211/patches/999-0056-ath10k-more-regdom-debugging-information.patch b/package/kernel/mac80211/patches/999-0056-ath10k-more-regdom-debugging-information.patch
new file mode 100644
index 0000000..fa60fa3
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0056-ath10k-more-regdom-debugging-information.patch
@@ -0,0 +1,22 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 24 Sep 2014 13:35:19 -0700
+Subject: [PATCH] ath10k: more regdom debugging information.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index e1a1ef014203..89941cf6a2be 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -2974,7 +2974,7 @@ static void ath10k_reg_notifier(struct wiphy *wiphy,
+ 	ath_reg_notifier_apply(wiphy, request, &ar->ath_common.regulatory);
+ 
+ 	if (config_enabled(CPTCFG_ATH10K_DFS_CERTIFIED) && ar->dfs_detector) {
+-		ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "dfs region 0x%x\n",
++		ath10k_dbg(ar, ATH10K_DBG_REGULATORY, "reg-notifier: dfs region 0x%x\n",
+ 			   request->dfs_region);
+ 		result = ar->dfs_detector->set_dfs_domain(ar->dfs_detector,
+ 							  request->dfs_region);
diff --git a/package/kernel/mac80211/patches/999-0057-ath10k-decrease-console-spamming-for-firmware-debug.patch b/package/kernel/mac80211/patches/999-0057-ath10k-decrease-console-spamming-for-firmware-debug.patch
new file mode 100644
index 0000000..8a481f8
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0057-ath10k-decrease-console-spamming-for-firmware-debug.patch
@@ -0,0 +1,49 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 4 Nov 2014 19:58:36 -0500
+Subject: [PATCH] ath10k: decrease console spamming for firmware debug
+
+Only spam the console if the DBG_FW flag is enabled,
+otherwise just put it to 'dmesg' output.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.h |  1 +
+ drivers/net/wireless/ath/ath10k/wmi.c   | 13 ++++++++++---
+ 2 files changed, 11 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
+index bdae404377c3..431af55b0536 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.h
++++ b/drivers/net/wireless/ath/ath10k/debug.h
+@@ -37,6 +37,7 @@ enum ath10k_debug_mask {
+ 	ATH10K_DBG_TESTMODE	= 0x00001000,
+ 	ATH10K_DBG_WMI_PRINT	= 0x00002000,
+ 	ATH10K_DBG_PCI_PS	= 0x00004000,
++	ATH10K_DBG_FW		= 0x80000000,
+ 	ATH10K_DBG_ANY		= 0xffffffff,
+ };
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 7c8f40c12459..3f05089e2c5a 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -1694,9 +1694,16 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
+ 	ath10k_dbg_save_fw_dbg_buffer(ar, ev->messages,
+ 				      (skb->len - 4)/sizeof(__le32));
+ 	spin_unlock_bh(&ar->data_lock);
+-	ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
+-				       (skb->len - 4)/sizeof(__le32),
+-				       KERN_INFO);
++
++	if (ath10k_debug_mask & ATH10K_DBG_FW)
++		ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
++					       (skb->len - 4)/sizeof(__le32),
++					       KERN_INFO);
++	else
++		ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
++					       (skb->len - 4)/sizeof(__le32),
++					       KERN_DEBUG);
++
+ 	return 0;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0058-ath10k-support-logging-ath10k_info-as-KERN_DEBUG.patch b/package/kernel/mac80211/patches/999-0058-ath10k-support-logging-ath10k_info-as-KERN_DEBUG.patch
new file mode 100644
index 0000000..4aee36e
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0058-ath10k-support-logging-ath10k_info-as-KERN_DEBUG.patch
@@ -0,0 +1,53 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 5 Nov 2014 20:00:12 -0500
+Subject: [PATCH] ath10k: support logging ath10k_info as KERN_DEBUG
+
+Helps keep messages off of (serial) console when
+that is desired.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.c | 5 ++++-
+ drivers/net/wireless/ath/ath10k/debug.h | 6 ++++++
+ 2 files changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 83b7b7b0b448..9ad5885d0e4c 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -137,7 +137,10 @@ void ath10k_info(struct ath10k *ar, const char *fmt, ...)
+ 
+ 	va_start(args, fmt);
+ 	vaf.va = &args;
+-	dev_info(ar->dev, "%pV", &vaf);
++	if (ath10k_debug_mask & ATH10K_DBG_INFO_AS_DBG)
++		dev_printk(KERN_DEBUG, ar->dev, "%pV", &vaf);
++	else
++		dev_info(ar->dev, "%pV", &vaf);
+ 	trace_ath10k_log_info(ar, &vaf);
+ 	va_end(args);
+ }
+diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
+index 431af55b0536..6a6f76b7e44b 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.h
++++ b/drivers/net/wireless/ath/ath10k/debug.h
+@@ -21,6 +21,10 @@
+ #include <linux/types.h>
+ #include "trace.h"
+ 
++/**
++ * ATH10K_DBG_INFO_AS_DBG: use dev_dbg instead of dev_info
++ *       for ath10k_info messages
++ */
+ enum ath10k_debug_mask {
+ 	ATH10K_DBG_PCI		= 0x00000001,
+ 	ATH10K_DBG_WMI		= 0x00000002,
+@@ -37,6 +41,8 @@ enum ath10k_debug_mask {
+ 	ATH10K_DBG_TESTMODE	= 0x00001000,
+ 	ATH10K_DBG_WMI_PRINT	= 0x00002000,
+ 	ATH10K_DBG_PCI_PS	= 0x00004000,
++
++	ATH10K_DBG_INFO_AS_DBG	= 0x40000000,
+ 	ATH10K_DBG_FW		= 0x80000000,
+ 	ATH10K_DBG_ANY		= 0xffffffff,
+ };
diff --git a/package/kernel/mac80211/patches/999-0059-ath10k-support-disabling-ch-resource-reservation.patch b/package/kernel/mac80211/patches/999-0059-ath10k-support-disabling-ch-resource-reservation.patch
new file mode 100644
index 0000000..952b5cf
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0059-ath10k-support-disabling-ch-resource-reservation.patch
@@ -0,0 +1,141 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 31 Dec 2014 13:59:16 -0800
+Subject: [PATCH] ath10k: support disabling ch resource reservation.
+
+CT firmware supports disabling channel resource reservation when
+starting vdevs.  This saves 200+ms when starting a second station
+vdev.
+
+Signed-off-by:  Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi-tlv.c |  4 +--
+ drivers/net/wireless/ath/ath10k/wmi.c     | 41 ++++++++++++++++++++++++++++---
+ drivers/net/wireless/ath/ath10k/wmi.h     | 13 ++++++++--
+ 3 files changed, 50 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+index 8fdba3865c96..a2d5157201a8 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+@@ -1610,7 +1610,7 @@ ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
+ 	tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+ 	tlv->len = __cpu_to_le16(sizeof(*ch));
+ 	ch = (void *)tlv->value;
+-	ath10k_wmi_put_wmi_channel(ch, &arg->channel);
++	ath10k_wmi_put_wmi_channel(ar, ch, &arg->channel, arg->vdev_id);
+ 
+ 	ptr += sizeof(*tlv);
+ 	ptr += sizeof(*ch);
+@@ -2246,7 +2246,7 @@ ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar,
+ 		tlv->len = __cpu_to_le16(sizeof(*ci));
+ 		ci = (void *)tlv->value;
+ 
+-		ath10k_wmi_put_wmi_channel(ci, ch);
++		ath10k_wmi_put_wmi_channel(ar, ci, ch, 0xFFFFFFFF);
+ 
+ 		chans += sizeof(*tlv);
+ 		chans += sizeof(*ci);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 3f05089e2c5a..f73bfc352cd8 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -858,8 +858,37 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
+ 	.pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
+ };
+ 
+-void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+-				const struct wmi_channel_arg *arg)
++static bool ath10k_ok_skip_ch_reservation(struct ath10k *ar, u32 vdev_id)
++{
++	struct ath10k_vif *arvif;
++	bool rv = false;
++
++	if (! test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features))
++		return rv;
++
++	list_for_each_entry(arvif, &ar->arvifs, list) {
++		if (!arvif->is_up)
++			continue;
++
++		if (arvif->vdev_id == vdev_id) {
++			if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
++				return false;
++			continue;
++		}
++
++		/* If there is another station up, then assume
++		 * requested station must use same channel.
++		 */
++		if (arvif->vdev_type == WMI_VDEV_TYPE_STA)
++			rv = true;
++	}
++	return rv;
++}
++
++void ath10k_wmi_put_wmi_channel(struct ath10k *ar,
++				struct wmi_channel *ch,
++				const struct wmi_channel_arg *arg,
++				u32 vdev_id)
+ {
+ 	u32 flags = 0;
+ 
+@@ -878,6 +907,10 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+ 	if (arg->chan_radar)
+ 		flags |= WMI_CHAN_FLAG_DFS;
+ 
++	if (ath10k_ok_skip_ch_reservation(ar, vdev_id))
++		/* Disable having firmware request on-channel reservation */
++		flags |= WMI_CHAN_FLAG_NO_RESERVE_CH;
++
+ 	ch->mhz = __cpu_to_le32(arg->freq);
+ 	ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1);
+ 	ch->band_center_freq2 = 0;
+@@ -4379,7 +4412,7 @@ ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
+ 		memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
+ 	}
+ 
+-	ath10k_wmi_put_wmi_channel(&cmd->chan, &arg->channel);
++	ath10k_wmi_put_wmi_channel(ar, &cmd->chan, &arg->channel, arg->vdev_id);
+ 
+ 	ath10k_dbg(ar, ATH10K_DBG_WMI,
+ 		   "wmi vdev %s id 0x%x flags: 0x%0X, freq %d, mode %d, ch_flags: 0x%0X, max_power: %d\n",
+@@ -4750,7 +4783,7 @@ ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar,
+ 		ch = &arg->channels[i];
+ 		ci = &cmd->chan_info[i];
+ 
+-		ath10k_wmi_put_wmi_channel(ci, ch);
++		ath10k_wmi_put_wmi_channel(ar, ci, ch, -1);
+ 	}
+ 
+ 	return skb;
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 3826783b8602..29dcc114ced9 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -1345,6 +1345,13 @@ enum wmi_channel_change_cause {
+ #define WMI_CHAN_FLAG_DFS            (1 << 10)
+ #define WMI_CHAN_FLAG_ALLOW_HT       (1 << 11)
+ #define WMI_CHAN_FLAG_ALLOW_VHT      (1 << 12)
++#define WMI_CHAN_FLAG_HALF           (1 << 13)
++#define WMI_CHAN_FLAG_QUARTER        (1 << 14)
++#define WMI_CHAN_FLAG_NO_RESERVE_CH  (1 << 31) /* CT firmware only, do not reserve channel.
++						* Takes 200+ms to grab reservation when starting
++						* vdev, and I think it is handled elsewhere by the
++						* stack and/or supplicant anyway. --Ben
++						*/
+ 
+ /* Indicate reason for channel switch */
+ #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13)
+@@ -5185,8 +5192,10 @@ void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+ 				      const struct wmi_start_scan_arg *arg);
+ void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params,
+ 			      const struct wmi_wmm_params_arg *arg);
+-void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+-				const struct wmi_channel_arg *arg);
++void ath10k_wmi_put_wmi_channel(struct ath10k *ar,
++				struct wmi_channel *ch,
++				const struct wmi_channel_arg *arg,
++				u32 vdev_id);
+ int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
+ 
+ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
diff --git a/package/kernel/mac80211/patches/999-0060-ath10k-Enable-adhoc-mode-for-CT-firmware.patch b/package/kernel/mac80211/patches/999-0060-ath10k-Enable-adhoc-mode-for-CT-firmware.patch
new file mode 100644
index 0000000..85d215e
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0060-ath10k-Enable-adhoc-mode-for-CT-firmware.patch
@@ -0,0 +1,32 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 21 Nov 2014 13:55:20 -0500
+Subject: [PATCH] ath10k: Enable adhoc mode for CT firmware.
+
+Doesn't actually work yet, but hopefully it will soon.
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 89941cf6a2be..69a044488da2 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -6590,6 +6590,10 @@ static struct ieee80211_iface_limit ath10k_10x_ct_if_limits[] = {
+ 	.max	= 7,
+ 	.types	= BIT(NL80211_IFTYPE_AP)
+ 	},
++	{
++	.max	= 1,
++	.types	= BIT(NL80211_IFTYPE_ADHOC)
++	},
+ };
+ 
+ static struct ieee80211_iface_combination ath10k_if_comb[] = {
+@@ -7018,6 +7022,7 @@ int ath10k_mac_register(struct ath10k *ar)
+ 				ath10k_10x_ct_if_comb;
+ 			ar->hw->wiphy->n_iface_combinations =
+ 				ARRAY_SIZE(ath10k_10x_ct_if_comb);
++			ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+ 		} else {
+ 			ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
+ 			ar->hw->wiphy->n_iface_combinations =
diff --git a/package/kernel/mac80211/patches/999-0061-ath10k-add-irq-registers-to-register-dump.patch b/package/kernel/mac80211/patches/999-0061-ath10k-add-irq-registers-to-register-dump.patch
new file mode 100644
index 0000000..2f0adec
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0061-ath10k-add-irq-registers-to-register-dump.patch
@@ -0,0 +1,67 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 25 Nov 2014 19:47:50 -0500
+Subject: [PATCH] ath10k: add irq registers to register dump.
+
+Helps to figure out current hardware state.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  |  2 ++
+ drivers/net/wireless/ath/ath10k/debug.c | 10 ++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.h   |  2 ++
+ 3 files changed, 14 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index dbfbcfffca4c..817b32027b9c 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -261,6 +261,8 @@ struct ath10k_fw_stats {
+ 	u32 mac_dma_txcfg;
+ 	u32 pcu_rxfilter;
+ 	u32 phy_bb_gen_controls;
++	u32 dma_imr;
++	u32 dma_txrx_imr;
+ 	u32 sw_powermode;
+ 	u16 sw_chainmask_tx;
+ 	u16 sw_chainmask_rx;
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 9ad5885d0e4c..37e128636a3a 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -389,6 +389,12 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
+ 			case PHY_BB_GEN_CONTROLS:
+ 				sptr->phy_bb_gen_controls = __le32_to_cpu(regdump->regpair[i].reg_val);
+ 				break;
++			case DMA_IMR:
++				sptr->dma_imr = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
++			case DMA_TXRX_IMR:
++				sptr->dma_txrx_imr = __le32_to_cpu(regdump->regpair[i].reg_val);
++				break;
+ 			case SW_POWERMODE:
+ 				sptr->sw_powermode = __le32_to_cpu(regdump->regpair[i].reg_val);
+ 				break;
+@@ -868,6 +874,10 @@ static ssize_t ath10k_read_fw_regs(struct file *file, char __user *user_buf,
+ 	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
+ 			 "PHY-BB-GEN-CONTROLS", fw_regs->phy_bb_gen_controls);
+ 	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "DMA-IMR", fw_regs->dma_imr);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
++			 "DMA-TXRX-IMR", fw_regs->dma_txrx_imr);
++	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
+ 			 "PCU-BSSID-L32", fw_regs->pcu_bssid_l32);
+ 	len += scnprintf(buf + len, buf_len - len, "%30s 0x%08x\n",
+ 			 "PCU-BSSID-U16", fw_regs->pcu_bssid_u16);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 29dcc114ced9..973311b27b4b 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -3115,6 +3115,8 @@ struct wmi_pdev_stats_peer {
+ #define PCU_STA_ADDR_L32     12
+ #define PCU_RXFILTER         13
+ #define PHY_BB_GEN_CONTROLS  14
++#define DMA_IMR              15
++#define DMA_TXRX_IMR         16
+ #define SW_POWERMODE         17
+ #define SW_CHAINMASK         18 /* tx is high 16 bits, rx is low 16 bits */
+ #define SW_OPMODE            19
diff --git a/package/kernel/mac80211/patches/999-0062-ath10k-add-wmi-id-to-htc-credits-debugging.patch b/package/kernel/mac80211/patches/999-0062-ath10k-add-wmi-id-to-htc-credits-debugging.patch
new file mode 100644
index 0000000..5914c8d
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0062-ath10k-add-wmi-id-to-htc-credits-debugging.patch
@@ -0,0 +1,36 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 8 Jan 2015 16:02:59 -0800
+Subject: [PATCH] ath10k: add wmi-id to htc credits debugging.
+
+This helps when trying to figure out exactly which commands
+are consuming credits when trying to debug wmi credit hangs.
+---
+ drivers/net/wireless/ath/ath10k/htc.c | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
+index 85bfa2acb801..ec5f7e5bb0a9 100644
+--- a/drivers/net/wireless/ath/ath10k/htc.c
++++ b/drivers/net/wireless/ath/ath10k/htc.c
+@@ -134,9 +134,18 @@ int ath10k_htc_send(struct ath10k_htc *htc,
+ 			goto err_pull;
+ 		}
+ 		ep->tx_credits -= credits;
+-		ath10k_dbg(ar, ATH10K_DBG_HTC,
+-			   "htc ep %d consumed %d credits (total %d)\n",
+-			   eid, credits, ep->tx_credits);
++		if (eid == ar->wmi.eid) {
++			struct wmi_cmd_hdr* hdr;
++			hdr = (struct wmi_cmd_hdr*)(skb->data + sizeof(struct ath10k_htc_hdr));
++			ath10k_dbg(ar, ATH10K_DBG_HTC,
++				   "htc ep %d consumed %d credits (total %d, wmi-cmd 0x%x)\n",
++				   eid, credits, ep->tx_credits, __le32_to_cpu(hdr->cmd_id));
++		}
++		else {
++			ath10k_dbg(ar, ATH10K_DBG_HTC,
++				   "htc ep %d consumed %d credits (total %d)\n",
++				   eid, credits, ep->tx_credits);
++		}
+ 		spin_unlock_bh(&htc->tx_lock);
+ 	}
+ 
diff --git a/package/kernel/mac80211/patches/999-0063-ath10k-make-dbglog-debug-messages-be-warn-level.patch b/package/kernel/mac80211/patches/999-0063-ath10k-make-dbglog-debug-messages-be-warn-level.patch
new file mode 100644
index 0000000..b0cf397
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0063-ath10k-make-dbglog-debug-messages-be-warn-level.patch
@@ -0,0 +1,45 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 8 Jan 2015 16:06:35 -0800
+Subject: [PATCH] ath10k: make dbglog debug messages be 'warn' level.
+
+This only happens on firmware crash, and it appears this
+logic is not always perfect, so make sure the information
+is printed to logs at higher level.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/pci.c | 14 ++++++--------
+ 1 file changed, 6 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 78469edefc68..3f0c99d3f48e 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1307,9 +1307,8 @@ static void ath10k_pci_dump_dbglog(struct ath10k *ar)
+ 		return;
+ 	}
+ 
+-	ath10k_dbg(ar, ATH10K_DBG_PCI,
+-		   "debug log header, dbuf: 0x%x  dropped: %i\n",
+-		   le32_to_cpu(dbg_hdr.dbuf), le32_to_cpu(dbg_hdr.dropped));
++	ath10k_warn(ar, "debug log header, dbuf: 0x%x  dropped: %i\n",
++		    le32_to_cpu(dbg_hdr.dbuf), le32_to_cpu(dbg_hdr.dropped));
+ 	dbufp = le32_to_cpu(dbg_hdr.dbuf);
+ 
+ 	/* i is for logging purposes and sanity check in case firmware buffers
+@@ -1329,11 +1328,10 @@ static void ath10k_pci_dump_dbglog(struct ath10k *ar)
+ 
+ 		len = le32_to_cpu(dbuf.length);
+ 
+-		ath10k_dbg(ar, ATH10K_DBG_PCI,
+-			   "[%i] next: 0x%x buf: 0x%x sz: %i len: %i count: %i free: %i\n",
+-			   i, le32_to_cpu(dbuf.next), le32_to_cpu(dbuf.buffer),
+-			   le32_to_cpu(dbuf.bufsize), len,
+-			   le32_to_cpu(dbuf.count), le32_to_cpu(dbuf.free));
++		ath10k_warn(ar, "[%i] next: 0x%x buf: 0x%x sz: %i len: %i count: %i free: %i\n",
++			    i, le32_to_cpu(dbuf.next), le32_to_cpu(dbuf.buffer),
++			    le32_to_cpu(dbuf.bufsize), len,
++			    le32_to_cpu(dbuf.count), le32_to_cpu(dbuf.free));
+ 		if (dbuf.buffer == 0 || len == 0)
+ 			goto next;
+ 
diff --git a/package/kernel/mac80211/patches/999-0064-ath10k-add-firmware-wmi-keep-alive-message.patch b/package/kernel/mac80211/patches/999-0064-ath10k-add-firmware-wmi-keep-alive-message.patch
new file mode 100644
index 0000000..17654d9
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0064-ath10k-add-firmware-wmi-keep-alive-message.patch
@@ -0,0 +1,167 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 8 Jan 2015 16:08:41 -0800
+Subject: [PATCH] ath10k: add firmware wmi keep-alive message.
+
+Only useful for CT firmware.
+
+This sends a wmi message to the firmware every 2 seconds or so.
+Once CT firmware receives one of these messages, it will assert
+if it does not receive more within a 10 second window.
+
+This helps debug and work-around wmi transport hangs.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  |  2 ++
+ drivers/net/wireless/ath/ath10k/debug.c | 29 +++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.c   | 32 ++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.h   |  7 +++++++
+ 4 files changed, 70 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 817b32027b9c..e1d85c73d717 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -420,6 +420,7 @@ struct ath10k_debug {
+ 
+ 	unsigned long htt_stats_mask;
+ 	struct delayed_work htt_stats_dwork;
++	struct delayed_work nop_dwork;
+ 	struct ath10k_dfs_stats dfs_stats;
+ 	struct ath_dfs_pool_stats dfs_pool_stats;
+ 
+@@ -429,6 +430,7 @@ struct ath10k_debug {
+ 	u32 pktlog_filter;
+ 	u32 reg_addr;
+ 	u32 nf_cal_period;
++	u32 nop_id;
+ 
+ 	u8 htt_max_amsdu;
+ 	u8 htt_max_ampdu;
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 37e128636a3a..2305649e876a 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -28,6 +28,8 @@
+ /* ms */
+ #define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
+ 
++#define ATH10K_DEBUG_NOP_INTERVAL 2000 /* ms */
++
+ #define ATH10K_FW_CRASH_DUMP_VERSION 1
+ 
+ /**
+@@ -1651,6 +1653,27 @@ static void ath10k_debug_htt_stats_dwork(struct work_struct *work)
+ 	mutex_unlock(&ar->conf_mutex);
+ }
+ 
++static void ath10k_debug_nop_dwork(struct work_struct *work)
++{
++	struct ath10k *ar = container_of(work, struct ath10k,
++					 debug.nop_dwork.work);
++
++	mutex_lock(&ar->conf_mutex);
++
++	if (ar->state == ATH10K_STATE_ON) {
++		int ret = ath10k_wmi_request_nop(ar);
++		if (ret) {
++			ath10k_warn(ar, "failed to send wmi nop: %d\n", ret);
++		}
++	}
++
++	/* Re-arm periodic work. */
++	queue_delayed_work(ar->workqueue, &ar->debug.nop_dwork,
++			   msecs_to_jiffies(ATH10K_DEBUG_NOP_INTERVAL));
++
++	mutex_unlock(&ar->conf_mutex);
++}
++
+ static ssize_t ath10k_read_htt_stats_mask(struct file *file,
+ 					  char __user *user_buf,
+ 					  size_t count, loff_t *ppos)
+@@ -2484,6 +2507,11 @@ int ath10k_debug_register(struct ath10k *ar)
+ 		return -ENOMEM;
+ 	}
+ 
++	INIT_DELAYED_WORK(&ar->debug.nop_dwork, ath10k_debug_nop_dwork);
++
++	queue_delayed_work(ar->workqueue, &ar->debug.nop_dwork,
++			   msecs_to_jiffies(ATH10K_DEBUG_NOP_INTERVAL));
++
+ 	INIT_DELAYED_WORK(&ar->debug.htt_stats_dwork,
+ 			  ath10k_debug_htt_stats_dwork);
+ 
+@@ -2563,6 +2591,7 @@ int ath10k_debug_register(struct ath10k *ar)
+ 
+ void ath10k_debug_unregister(struct ath10k *ar)
+ {
++	cancel_delayed_work_sync(&ar->debug.nop_dwork);
+ 	cancel_delayed_work_sync(&ar->debug.htt_stats_dwork);
+ }
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index f73bfc352cd8..5eb3d785ec8a 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -4423,6 +4423,38 @@ ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
+ 	return skb;
+ }
+ 
++#ifdef CPTCFG_ATH10K_DEBUG
++/* CT firmware only:
++ * (re) start wmi keep-alive timer in firmware.  Once we start
++ * sending these, firmware will assert if it does not receive one
++ * after about 10 seconds.
++ */
++
++struct wmi_request_nop_cmd {
++	u32 nop_id; /* for debugging purposes */
++};
++
++int ath10k_wmi_request_nop(struct ath10k *ar)
++{
++	struct wmi_request_nop_cmd *cmd;
++	struct sk_buff *skb;
++
++	if (! test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features))
++		return 0;
++
++	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
++	if (!skb)
++		return -ENOMEM;
++
++	cmd = (struct wmi_request_nop_cmd *)skb->data;
++	cmd->nop_id = __cpu_to_le32(ar->debug.nop_id++);
++
++	ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request nop (id %d)\n",
++		   ar->debug.nop_id - 1);
++	return ath10k_wmi_cmd_send(ar, skb, WMI_NOP);
++}
++#endif
++
+ static struct sk_buff *
+ ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
+ {
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 973311b27b4b..b1c987035be9 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -994,6 +994,8 @@ enum wmi_10x_cmd_id {
+ 	WMI_10X_GPIO_CPTCFG_CMDID,
+ 	WMI_10X_GPIO_OUTPUT_CMDID,
+ 
++	WMI_NOP = WMI_10X_END_CMDID - 100, /* CT only:  wmi transport keep-alive, basically */
++
+ 	WMI_10X_PDEV_UTF_CMDID = WMI_10X_END_CMDID - 1,
+ };
+ 
+@@ -5244,4 +5246,9 @@ void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb);
+ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);
+ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb);
+ 
++#ifdef CPTCFG_ATH10K_DEBUG
++/* CT Firmware only */
++int ath10k_wmi_request_nop(struct ath10k *ar);
++#endif
++
+ #endif /* _WMI_H_ */
diff --git a/package/kernel/mac80211/patches/999-0065-ath10k-add-module-param-to-configure-number-of-peers.patch b/package/kernel/mac80211/patches/999-0065-ath10k-add-module-param-to-configure-number-of-peers.patch
new file mode 100644
index 0000000..48b53fb
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0065-ath10k-add-module-param-to-configure-number-of-peers.patch
@@ -0,0 +1,72 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 3 Feb 2015 08:32:01 -0800
+Subject: [PATCH] ath10k: add module-param to configure number of peers.
+
+Allow users of CT firmware to adjust peer count to
+to desired value instead of calculating based on number
+of vdevs, etc.
+
+Total supported depends on number of vdevs:  fewer vdevs
+gives more memory for peers.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 2 +-
+ drivers/net/wireless/ath/ath10k/hw.h   | 3 +--
+ drivers/net/wireless/ath/ath10k/mac.c  | 3 +++
+ drivers/net/wireless/ath/ath10k/mac.h  | 1 +
+ 4 files changed, 6 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 0565b1d82d53..1755b222818c 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1140,7 +1140,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
+ 		break;
+ 	case ATH10K_FW_WMI_OP_VERSION_10_1:
+ 		if (test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
+-			ar->max_num_peers = TARGET_10X_NUM_PEERS_CT;
++			ar->max_num_peers = ath10k_modparam_target_num_peers_ct;
+ 			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ 			ar->max_num_vdevs = ath10k_modparam_target_num_vdevs_ct;
+ 			ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC_CT;
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 0077f87060c5..2c6e0127ffd3 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -281,8 +281,7 @@ enum ath10k_hw_rate_cck {
+ /* Over-rides for Candela Technologies firmware */
+ #define DEF_TARGET_10X_NUM_VDEVS_CT		36 /* newer CT firmware support more,
+ 						    * override w/module parm */
+-#define TARGET_10X_NUM_PEERS_CT			(2 * ath10k_modparam_target_num_vdevs_ct)
+-#define TARGET_10X_AST_SKID_LIMIT_CT		(TARGET_10X_NUM_PEERS_CT * TARGET_10X_NUM_PEER_AST)
++#define TARGET_10X_AST_SKID_LIMIT_CT		(ath10k_modparam_target_num_peers_ct * TARGET_10X_NUM_PEER_AST)
+ #define TARGET_10X_NUM_PEER_KEYS_CT             (WMI_MAX_KEY_INDEX + 1) /* 4 */
+ /* These eat a fair chunk of memory on the firmware, so decrease it a bit. */
+ #define TARGET_10X_NUM_MSDU_DESC_CT		808 /* must be multiple of 8 */
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 69a044488da2..3170c1adecd0 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -164,6 +164,9 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware rx decrypt feature");
+ int ath10k_modparam_target_num_vdevs_ct = DEF_TARGET_10X_NUM_VDEVS_CT;
+ module_param_named(num_vdevs_ct, ath10k_modparam_target_num_vdevs_ct, int, 0444);
+ MODULE_PARM_DESC(num_vdevs_ct, "Maximum vdevs to request from firmware");
++int ath10k_modparam_target_num_peers_ct = 128;
++module_param_named(num_peers_ct, ath10k_modparam_target_num_peers_ct, int, 0444);
++MODULE_PARM_DESC(num_peers_ct, "Maximum peers to request from firmware");
+ 
+ /**********/
+ /* Crypto */
+diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
+index 3580417342b3..6db40bd7d098 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.h
++++ b/drivers/net/wireless/ath/ath10k/mac.h
+@@ -28,6 +28,7 @@ enum wmi_tlv_tx_pause_action;
+ 
+ extern int ath10k_modparam_nohwcrypt;
+ extern int ath10k_modparam_target_num_vdevs_ct;
++extern int ath10k_modparam_target_num_peers_ct;
+ 
+ struct ath10k_generic_iter {
+ 	struct ath10k *ar;
diff --git a/package/kernel/mac80211/patches/999-0066-ath10k-rate-limit-packet-tx-errors.patch b/package/kernel/mac80211/patches/999-0066-ath10k-rate-limit-packet-tx-errors.patch
new file mode 100644
index 0000000..f0d18ee
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0066-ath10k-rate-limit-packet-tx-errors.patch
@@ -0,0 +1,44 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 3 Feb 2015 15:10:10 -0800
+Subject: [PATCH] ath10k: rate-limit packet tx errors
+
+When firmware crashes, stack can continue to send packets
+for a bit, and existing code was spamming logs.
+
+So, rate-limit the error message for tx failures.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c     | 5 +++--
+ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 +-
+ 2 files changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 3170c1adecd0..37c13b611d60 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -3348,8 +3348,9 @@ static void ath10k_mac_tx(struct ath10k *ar, struct sk_buff *skb)
+ 	}
+ 
+ 	if (ret) {
+-		ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
+-			    ret);
++		if (net_ratelimit())
++			ath10k_warn(ar, "failed to transmit packet, dropping: %d\n",
++				    ret);
+ 		ieee80211_free_txskb(ar->hw, skb);
+ 	}
+ }
+diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+index a2d5157201a8..e99571b1945f 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c
++++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
+@@ -2780,7 +2780,7 @@ ath10k_wmi_tlv_op_gen_tdls_peer_update(struct ath10k *ar,
+ 		tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+ 		tlv->len = __cpu_to_le16(sizeof(*chan));
+ 		chan = (void *)tlv->value;
+-		ath10k_wmi_put_wmi_channel(chan, &chan_arg[i]);
++		ath10k_wmi_put_wmi_channel(ar, chan, &chan_arg[i], arg->vdev_id);
+ 
+ 		ptr += sizeof(*tlv);
+ 		ptr += sizeof(*chan);
diff --git a/package/kernel/mac80211/patches/999-0067-ath10k-read-firmware-crash-over-ioread32-if-CE-fails.patch b/package/kernel/mac80211/patches/999-0067-ath10k-read-firmware-crash-over-ioread32-if-CE-fails.patch
new file mode 100644
index 0000000..d527ae0
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0067-ath10k-read-firmware-crash-over-ioread32-if-CE-fails.patch
@@ -0,0 +1,112 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 3 Feb 2015 20:14:59 -0800
+Subject: [PATCH] ath10k: read firmware crash over ioread32 if CE fails.
+
+This might work around problem where sometimes host cannot
+access firmware crash over normal CE transport.
+
+Requires CT firmware with matching logic in it's assert
+handler (-13 and higher releases).
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/hw.h  |  5 ++++
+ drivers/net/wireless/ath/ath10k/pci.c | 55 ++++++++++++++++++++++++++++++++++-
+ 2 files changed, 59 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 2c6e0127ffd3..315eed45dd11 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -472,6 +472,7 @@ enum ath10k_hw_rate_cck {
+ #define PCIE_INTR_ENABLE_ADDRESS		0x0008
+ #define PCIE_INTR_CAUSE_ADDRESS			0x000c
+ #define PCIE_INTR_CLR_ADDRESS			0x0014
++#define SCRATCH_2_ADDRESS                       0x002c
+ #define SCRATCH_3_ADDRESS			ar->regs->scratch_3_address
+ #define CPU_INTR_ADDRESS			0x0010
+ 
+@@ -483,6 +484,10 @@ enum ath10k_hw_rate_cck {
+ #define FW_IND_EVENT_PENDING			1
+ #define FW_IND_INITIALIZED			2
+ 
++/* CT firmware only */
++#define FW_IND_SCRATCH2_WR      (1<<14) /* scratch2 has data written to it */
++#define FW_IND_SCRATCH2_RD      (1<<15) /* scratch2 has been read (by host) */
++
+ /* HOST_REG interrupt from firmware */
+ #define PCIE_INTR_FIRMWARE_MASK			0x00000400
+ #define PCIE_INTR_CE_MASK_ALL			0x0007f800
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 3f0c99d3f48e..053162d75733 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1249,6 +1249,53 @@ static void ath10k_pci_dump_exc_stack(struct ath10k *ar,
+ 				     hi_err_stack);
+ }
+ 
++/* Only CT firmware can do this.  Attempt to read crash dump over pci
++ * registers since normal CE transport is not working.
++ */
++static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
++					  __le32 *reg_dump_values,
++					  int len)
++{
++	u32 val;
++	int i;
++	int q;
++#define MAX_SPIN_TRIES 1000000
++
++	if (!test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
++		return -EINVAL;
++	}
++
++	for (i = 0; i<MAX_SPIN_TRIES; i++) {
++		val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
++		if (val & FW_IND_SCRATCH2_WR)
++			goto pingpong;
++	}
++	return -EBUSY;
++
++pingpong:
++	ath10k_warn(ar, "Trying to read crash dump over pingpong registers.\n");
++	/* Firmware is trying to send us info it seems. */
++	for (q = 0; q<len; q++) {
++		reg_dump_values[q] = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + SCRATCH_2_ADDRESS);
++		val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
++		val |= FW_IND_SCRATCH2_RD; /* tell firmware we read it */
++		val &= ~FW_IND_SCRATCH2_WR; /* clear firmware's write flag */
++		ath10k_pci_write32(ar, FW_INDICATOR_ADDRESS, val);
++
++		for (i = 0; i<MAX_SPIN_TRIES; i++) {
++			val = ath10k_pci_read32(ar, FW_INDICATOR_ADDRESS);
++			if (val & FW_IND_SCRATCH2_WR)
++				break;
++		}
++		if (!(val & FW_IND_SCRATCH2_WR)) {
++			ath10k_err(ar, "failed to read reg %i via pingpong method.\n",
++				   q);
++			return 0; // partial read is better than nothing I guess
++		}
++	}
++	return 0;
++}
++
+ static void ath10k_pci_dump_registers(struct ath10k *ar,
+ 				      struct ath10k_fw_crash_data *crash_data)
+ {
+@@ -1262,7 +1309,13 @@ static void ath10k_pci_dump_registers(struct ath10k *ar,
+ 				      REG_DUMP_COUNT_QCA988X * sizeof(__le32));
+ 	if (ret) {
+ 		ath10k_err(ar, "failed to read firmware dump area: %d\n", ret);
+-		return;
++
++		/* Try to read this directly over registers...only works on new
++		 * CT firmware.
++		 */
++		ret = ath10k_ct_fw_crash_regs_harder(ar, reg_dump_values, REG_DUMP_COUNT_QCA988X);
++		if (ret)
++			return;
+ 	}
+ 
+ 	BUILD_BUG_ON(REG_DUMP_COUNT_QCA988X % 4);
diff --git a/package/kernel/mac80211/patches/999-0068-wireless-just-fail-if-user-requests-to-create-with-b.patch b/package/kernel/mac80211/patches/999-0068-wireless-just-fail-if-user-requests-to-create-with-b.patch
new file mode 100644
index 0000000..9725971
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0068-wireless-just-fail-if-user-requests-to-create-with-b.patch
@@ -0,0 +1,76 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 12 Feb 2015 16:43:48 -0800
+Subject: [PATCH] wireless: just fail if user requests to create with bad name.
+
+It is difficult for user-space to deal with failures when the
+kernel just silently creates something named the wrong thing,
+so instead just fail the creation entirely if the name is
+specified and incorrect (bad format, already in use, etc).
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/core.c | 23 +++++++++++------------
+ 1 file changed, 11 insertions(+), 12 deletions(-)
+
+diff --git a/net/wireless/core.c b/net/wireless/core.c
+index 2a0bbd22854b..090835066db0 100644
+--- a/net/wireless/core.c
++++ b/net/wireless/core.c
+@@ -363,12 +363,9 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+ 
+ 	rdev->wiphy_idx = atomic_inc_return(&wiphy_counter);
+ 
+-	if (unlikely(rdev->wiphy_idx < 0)) {
++	if (unlikely(rdev->wiphy_idx < 0))
+ 		/* ugh, wrapped! */
+-		atomic_dec(&wiphy_counter);
+-		kfree(rdev);
+-		return NULL;
+-	}
++		goto err_exit;
+ 
+ 	/* atomic_inc_return makes it start at 1, make it start at 0 */
+ 	rdev->wiphy_idx--;
+@@ -382,15 +379,14 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
+ 
+ 		if (rv < 0) {
+ 			rtnl_unlock();
+-			goto use_default_name;
++			goto err_exit;
+ 		}
+ 
+ 		rv = dev_set_name(&rdev->wiphy.dev, "%s", requested_name);
+ 		rtnl_unlock();
+ 		if (rv)
+-			goto use_default_name;
++			goto err_exit;
+ 	} else {
+-use_default_name:
+ 		/* NOTE:  This is *probably* safe w/out holding rtnl because of
+ 		 * the restrictions on phy names.  Probably this call could
+ 		 * fail if some other part of the kernel (re)named a device
+@@ -433,10 +429,8 @@ use_default_name:
+ 				   &rdev->wiphy.dev, RFKILL_TYPE_WLAN,
+ 				   &rdev->rfkill_ops, rdev);
+ 
+-	if (!rdev->rfkill) {
+-		kfree(rdev);
+-		return NULL;
+-	}
++	if (!rdev->rfkill)
++		goto err_exit;
+ 
+ 	INIT_WORK(&rdev->rfkill_sync, cfg80211_rfkill_sync_work);
+ 	INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
+@@ -458,6 +452,11 @@ use_default_name:
+ 	rdev->wiphy.max_num_csa_counters = 1;
+ 
+ 	return &rdev->wiphy;
++
++err_exit:
++	atomic_dec(&wiphy_counter);
++	kfree(rdev);
++	return NULL;
+ }
+ EXPORT_SYMBOL(wiphy_new_nm);
+ 
diff --git a/package/kernel/mac80211/patches/999-0069-ath10k-Report-tx-retry-failures-when-using-CT-firmwa.patch b/package/kernel/mac80211/patches/999-0069-ath10k-Report-tx-retry-failures-when-using-CT-firmwa.patch
new file mode 100644
index 0000000..e776401
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0069-ath10k-Report-tx-retry-failures-when-using-CT-firmwa.patch
@@ -0,0 +1,104 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 27 Feb 2015 19:15:05 -0800
+Subject: [PATCH] ath10k: Report tx-retry-failures when using CT firmware.
+
+We steal 2 bits from the tx-rate-flags and use that to pass
+back the tx-completion code from the firmware.
+
+Requires version 14 or later of the CT firmware.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/htt.h  | 15 ++++++++-------
+ drivers/net/wireless/ath/ath10k/txrx.c | 15 +++++++++++----
+ drivers/net/wireless/ath/ath10k/txrx.h |  2 +-
+ 3 files changed, 20 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
+index d9c50f36bf65..bb94db59878a 100644
+--- a/drivers/net/wireless/ath/ath10k/htt.h
++++ b/drivers/net/wireless/ath/ath10k/htt.h
+@@ -1317,11 +1317,12 @@ struct htt_resp {
+ 
+ /*** host side structures follow ***/
+ 
+-/* tx-rate flags field definitions */
+-#define ATH10K_RC_FLAG_CHAIN_MASK 0x07 /* identifies tx chain config (1,5,7) */
+-#define ATH10K_RC_FLAG_ONE_CHAIN     1
+-#define ATH10K_RC_FLAG_TWO_CHAIN     5
+-#define ATH10K_RC_FLAG_THREE_CHAIN   7
++/* tx-rate flags field definitions, see firmware whal_desc.h */
++/* First two bits are for tx-completion report. */
++#define ATH10K_RC_FLAG_TXOK       0x00 /* Pkt transmitted OK */
++#define ATH10K_RC_FLAG_XRETRY     0x01 /* Pkt failed to transmit, too many retries. */
++#define ATH10K_RC_FLAG_DROP       0x02 /* Dropped due to tid flush, local buffer exhaustion, etc. */
++
+ #define ATH10K_RC_FLAG_SGI        0x08 /* use HT SGI if set */
+ #define ATH10K_RC_FLAG_STBC       0x10 /* use HT STBC if set */
+ #define ATH10K_RC_FLAG_40MHZ      0x20 /* 40 mhz mode */
+@@ -1331,8 +1332,8 @@ struct htt_resp {
+ 
+ struct htt_tx_done {
+ 	u16 msdu_id;
+-	u8 tx_rate_code; /* CT firmware only */
+-	u8 tx_rate_flags; /* CT firmware only */
++	u8 tx_rate_code; /* CT firmware only, see firmware ar_desc_wifi_ip01.h (search for 0x44) */
++	u8 tx_rate_flags; /* CT firmware only, see flag defs above */
+ 	bool discard;
+ 	bool no_ack;
+ 	bool success;
+diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
+index 6f0f8c4f19f4..08fd5b901f54 100644
+--- a/drivers/net/wireless/ath/ath10k/txrx.c
++++ b/drivers/net/wireless/ath/ath10k/txrx.c
+@@ -83,7 +83,7 @@ static void ath10k_set_tx_rate_status(struct ieee80211_tx_rate *rate,
+ 
+ 
+ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+-			  const struct htt_tx_done *tx_done)
++			  struct htt_tx_done *tx_done)
+ {
+ 	struct ath10k *ar = htt->ar;
+ 	struct device *dev = ar->dev;
+@@ -134,18 +134,25 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+ 	if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
+ 		info->flags |= IEEE80211_TX_STAT_ACK;
+ 
+-	if (tx_done->no_ack)
+-		info->flags &= ~IEEE80211_TX_STAT_ACK;
+-
+ 	if (tx_done->success && (info->flags & IEEE80211_TX_CTL_NO_ACK))
+ 		info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ 
+ 	if (tx_done->tx_rate_code || tx_done->tx_rate_flags) {
+ 		ath10k_set_tx_rate_status(&info->status.rates[0], tx_done);
++
++		/* Deal with tx-completion status */
++		if ((tx_done->tx_rate_flags & 0x3) == ATH10K_RC_FLAG_XRETRY)
++			tx_done->no_ack = true;
++		/* TODO:  Report drops differently. */
++		if ((tx_done->tx_rate_flags & 0x3) == ATH10K_RC_FLAG_DROP)
++			tx_done->no_ack = true;
+ 	} else {
+ 		info->status.rates[0].idx = -1;
+ 	}
+ 
++	if (tx_done->no_ack)
++		info->flags &= ~IEEE80211_TX_STAT_ACK;
++
+ 	ieee80211_tx_status(htt->ar->hw, msdu);
+ 	/* we do not own the msdu anymore */
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/txrx.h b/drivers/net/wireless/ath/ath10k/txrx.h
+index a90e09f5c7f2..8c7151b63a01 100644
+--- a/drivers/net/wireless/ath/ath10k/txrx.h
++++ b/drivers/net/wireless/ath/ath10k/txrx.h
+@@ -20,7 +20,7 @@
+ #include "htt.h"
+ 
+ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+-			  const struct htt_tx_done *tx_done);
++			  struct htt_tx_done *tx_done);
+ 
+ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
+ 				     const u8 *addr);
diff --git a/package/kernel/mac80211/patches/999-0070-ath10k-Fix-compile-when-ATH10K_DEBUG-option-is-not-e.patch b/package/kernel/mac80211/patches/999-0070-ath10k-Fix-compile-when-ATH10K_DEBUG-option-is-not-e.patch
new file mode 100644
index 0000000..6c80fa7
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0070-ath10k-Fix-compile-when-ATH10K_DEBUG-option-is-not-e.patch
@@ -0,0 +1,86 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 5 Mar 2015 17:37:05 -0800
+Subject: [PATCH] ath10k: Fix compile when ATH10K_DEBUG option is not enabled.
+
+Also, add compile time warning if compiling w/out ATH10K_DEBUGFS
+since CT firmware will be missing the WMI keepalive (and ability
+to do useful debugging of crashes) with this disabled.
+
+Based on patches by jose.delgado@xxxxxxxxxx
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.h | 11 ++++++-----
+ drivers/net/wireless/ath/ath10k/wmi.c   |  3 ++-
+ drivers/net/wireless/ath/ath10k/wmi.h   |  5 ++++-
+ 3 files changed, 12 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
+index 6a6f76b7e44b..f85b970e1a10 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.h
++++ b/drivers/net/wireless/ath/ath10k/debug.h
+@@ -91,7 +91,13 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
+ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ 			       struct ieee80211_vif *vif,
+ 			       struct ethtool_stats *stats, u64 *data);
++
++void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len);
+ #else
++static inline void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar,
++						 __le32 *buffer, int len)
++{
++}
+ static inline int ath10k_debug_start(struct ath10k *ar)
+ {
+ 	return 0;
+@@ -155,7 +161,6 @@ void ath10k_dbg_dump(struct ath10k *ar,
+ 		     enum ath10k_debug_mask mask,
+ 		     const char *msg, const char *prefix,
+ 		     const void *buf, size_t len);
+-void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar, __le32 *buffer, int len);
+ #else /* CPTCFG_ATH10K_DEBUG */
+ 
+ static inline int ath10k_dbg(struct ath10k *ar,
+@@ -171,10 +176,6 @@ static inline void ath10k_dbg_dump(struct ath10k *ar,
+ 				   const void *buf, size_t len)
+ {
+ }
+-static inline void ath10k_dbg_save_fw_dbg_buffer(struct ath10k *ar,
+-						 __le32 *buffer, int len)
+-{
+-}
+ #endif /* CPTCFG_ATH10K_DEBUG */
+ 
+ int ath10k_refresh_peer_stats(struct ath10k *ar);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 5eb3d785ec8a..3fd067b3c17a 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -4423,7 +4423,8 @@ ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
+ 	return skb;
+ }
+ 
+-#ifdef CPTCFG_ATH10K_DEBUG
++#ifdef CPTCFG_ATH10K_DEBUGFS
++/* TODO:  Should really enable this all the time, not just when DEBUGFS is enabled. --Ben */
+ /* CT firmware only:
+  * (re) start wmi keep-alive timer in firmware.  Once we start
+  * sending these, firmware will assert if it does not receive one
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index b1c987035be9..224739e92772 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -5246,9 +5246,12 @@ void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb);
+ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);
+ int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb);
+ 
+-#ifdef CPTCFG_ATH10K_DEBUG
++#ifdef CPTCFG_ATH10K_DEBUGFS
++/* TODO:  Should really enable this all the time, not just when DEBUGFS is enabled. --Ben */
+ /* CT Firmware only */
+ int ath10k_wmi_request_nop(struct ath10k *ar);
++#else
++#warning Please enable ATH10K-DEBUGFS kernel option for optimal support for CT firmware.
+ #endif
+ 
+ #endif /* _WMI_H_ */
diff --git a/package/kernel/mac80211/patches/999-0071-ath10k-Use-new-CT-feature-flag-to-enable-no-ack-repo.patch b/package/kernel/mac80211/patches/999-0071-ath10k-Use-new-CT-feature-flag-to-enable-no-ack-repo.patch
new file mode 100644
index 0000000..d6ef796
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0071-ath10k-Use-new-CT-feature-flag-to-enable-no-ack-repo.patch
@@ -0,0 +1,53 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 6 Mar 2015 22:14:23 -0800
+Subject: [PATCH] ath10k: Use new CT feature flag to enable no-ack reporting.
+
+This way, we can be backwards compat with older firmware that
+do not report the tx-status in quite the same way.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h |  3 +++
+ drivers/net/wireless/ath/ath10k/txrx.c | 15 +++++++++------
+ 2 files changed, 12 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index e1d85c73d717..1cd881d48ab6 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -523,6 +523,9 @@ enum ath10k_fw_features {
+ 	 * encryption (ie, commercial version of CT firmware) */
+ 	ATH10K_FW_FEATURE_CT_RXSWCRYPT = 32,
+ 
++	/* tx-status has the noack bits (CT firmware version 14 and higher ) */
++	ATH10K_FW_FEATURE_HAS_TXSTATUS_NOACK = 33,
++
+ 	/* keep last */
+ 	ATH10K_FW_FEATURE_COUNT,
+ };
+diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
+index 08fd5b901f54..0b455ae6acac 100644
+--- a/drivers/net/wireless/ath/ath10k/txrx.c
++++ b/drivers/net/wireless/ath/ath10k/txrx.c
+@@ -140,12 +140,15 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
+ 	if (tx_done->tx_rate_code || tx_done->tx_rate_flags) {
+ 		ath10k_set_tx_rate_status(&info->status.rates[0], tx_done);
+ 
+-		/* Deal with tx-completion status */
+-		if ((tx_done->tx_rate_flags & 0x3) == ATH10K_RC_FLAG_XRETRY)
+-			tx_done->no_ack = true;
+-		/* TODO:  Report drops differently. */
+-		if ((tx_done->tx_rate_flags & 0x3) == ATH10K_RC_FLAG_DROP)
+-			tx_done->no_ack = true;
++		/* Only in version 14 and higher of CT firmware */
++		if (test_bit(ATH10K_FW_FEATURE_HAS_TXSTATUS_NOACK, ar->fw_features)) {
++			/* Deal with tx-completion status */
++			if ((tx_done->tx_rate_flags & 0x3) == ATH10K_RC_FLAG_XRETRY)
++				tx_done->no_ack = true;
++			/* TODO:  Report drops differently. */
++			if ((tx_done->tx_rate_flags & 0x3) == ATH10K_RC_FLAG_DROP)
++				tx_done->no_ack = true;
++		}
+ 	} else {
+ 		info->status.rates[0].idx = -1;
+ 	}
diff --git a/package/kernel/mac80211/patches/999-0072-ath10k-Allow-setting-bcast-mcast-mgt-fixed-tx-rates.patch b/package/kernel/mac80211/patches/999-0072-ath10k-Allow-setting-bcast-mcast-mgt-fixed-tx-rates.patch
new file mode 100644
index 0000000..9f8897e
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0072-ath10k-Allow-setting-bcast-mcast-mgt-fixed-tx-rates.patch
@@ -0,0 +1,194 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 12 Mar 2015 14:41:27 -0700
+Subject: [PATCH] ath10k: Allow setting bcast, mcast, mgt fixed tx rates.
+
+The default behaviour when setting a fixed transmit rate in ath10k
+is to only set the 'ucast' rate.  This does not affect beacons,
+multicast, or broadcast traffic.
+
+In order to allow a back-door way to set these other types of
+traffic as well, provide a debugfs file that can set the
+traffic type.  Then, use can use the normal 'iw' commands to
+set the rate to the desired value.
+
+Upstream firmware *should* support all of this, but at least
+10.1 does NOT have support for the WMI_10X_VDEV_PARAM_MGMT_RATE
+parameter.  I added this to the CT firmware so it works there.
+
+Possibly other upstream firmware have fixed this as well.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h  |   1 +
+ drivers/net/wireless/ath/ath10k/debug.c | 102 ++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/mac.c   |  19 ++++--
+ 3 files changed, 117 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 1cd881d48ab6..68e49cf247dd 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -613,6 +613,7 @@ struct ath10k {
+ 	u32 num_rf_chains;
+ 	/* protected by conf_mutex */
+ 	bool ani_enabled;
++	u32 set_rate_type; /* override for set-rate behaviour */
+ 
+ 	DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 2305649e876a..306b21d31707 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -1100,6 +1100,105 @@ static const struct file_operations fops_simulate_fw_crash = {
+ 	.llseek = default_llseek,
+ };
+ 
++static ssize_t ath10k_read_set_rates(struct file *file,
++				     char __user *user_buf,
++				     size_t count, loff_t *ppos)
++{
++	struct ath10k *ar = file->private_data;
++	const char buf[] =
++		"To set unicast, beacon/mgt, multicast, and broadcast,\n"
++		"select a type below and then use 'iw' as normal to set\n"
++		"the desired rate.\n"
++		"beacon   # Beacons and management frames\n"
++		"bcast    # Broadcast frames\n"
++		"mcast    # Multicast frames\n"
++		"ucast    # Unicast frames (normal traffic, default)\n";
++
++	char tmpbuf[strlen(buf) + 80];
++	char* str = "ucast";
++
++	if (ar->set_rate_type == ar->wmi.vdev_param->mgmt_rate) {
++		str = "beacon";
++	}
++	else if (ar->set_rate_type == ar->wmi.vdev_param->bcast_data_rate) {
++		str = "bcast";
++	}
++	else if (ar->set_rate_type == ar->wmi.vdev_param->mcast_data_rate) {
++		str = "mcast";
++	}
++	sprintf(tmpbuf, "%sCurrent: %s\n", buf, str);
++
++	return simple_read_from_buffer(user_buf, count, ppos, tmpbuf, strlen(tmpbuf));
++}
++
++/* Set the rates for specific types of traffic.
++ */
++static ssize_t ath10k_write_set_rates(struct file *file,
++				      const char __user *user_buf,
++				      size_t count, loff_t *ppos)
++{
++	struct ath10k *ar = file->private_data;
++	char buf[32];
++	int ret;
++
++	mutex_lock(&ar->conf_mutex);
++
++	memset(buf, 0, sizeof(buf));
++
++	simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
++
++	/* make sure that buf is null terminated */
++	buf[sizeof(buf) - 1] = 0;
++
++	/* drop the possible '\n' from the end */
++	if (buf[count - 1] == '\n')
++		buf[count - 1] = 0;
++
++	/* Ignore empty lines, 'echo' appends them sometimes at least. */
++	if (buf[0] == 0) {
++		ret = count;
++		goto exit;
++	}
++
++	if (ar->state != ATH10K_STATE_ON &&
++	    ar->state != ATH10K_STATE_RESTARTED) {
++		ret = -ENETDOWN;
++		goto exit;
++	}
++
++	if (strncmp(buf, "beacon", strlen("beacon")) == 0) {
++		ar->set_rate_type = ar->wmi.vdev_param->mgmt_rate;
++	}
++	else if (strncmp(buf, "bcast", strlen("bcast")) == 0) {
++		ar->set_rate_type = ar->wmi.vdev_param->bcast_data_rate;
++	}
++	else if (strncmp(buf, "mcast", strlen("mcast")) == 0) {
++		ar->set_rate_type = ar->wmi.vdev_param->mcast_data_rate;
++	}
++	else if (strncmp(buf, "ucast", strlen("ucast")) == 0) {
++		ar->set_rate_type = 0;
++	}
++	else {
++		ath10k_warn(ar, "set-rate, invalid rate type: %s  count: %d  %02hx:%02hx:%02hx:%02hx\n",
++			    buf, (int)count, (int)(buf[0]), (int)(buf[1]), (int)(buf[2]), (int)(buf[3]));
++		ret = -EINVAL;
++		goto exit;
++	}
++	ret = count;
++
++exit:
++	mutex_unlock(&ar->conf_mutex);
++	return ret;
++}
++
++static const struct file_operations fops_set_rates = {
++	.read = ath10k_read_set_rates,
++	.write = ath10k_write_set_rates,
++	.open = simple_open,
++	.owner = THIS_MODULE,
++	.llseek = default_llseek,
++};
++
+ static ssize_t ath10k_read_chip_id(struct file *file, char __user *user_buf,
+ 				   size_t count, loff_t *ppos)
+ {
+@@ -2529,6 +2628,9 @@ int ath10k_debug_register(struct ath10k *ar)
+ 	debugfs_create_file("wmi_services", S_IRUSR, ar->debug.debugfs_phy, ar,
+ 			    &fops_wmi_services);
+ 
++	debugfs_create_file("set_rates", S_IRUSR, ar->debug.debugfs_phy,
++			    ar, &fops_set_rates);
++
+ 	debugfs_create_file("simulate_fw_crash", S_IRUSR, ar->debug.debugfs_phy,
+ 			    ar, &fops_simulate_fw_crash);
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 37c13b611d60..8989df5232e9 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -5846,17 +5846,26 @@ static int ath10k_mac_set_fixed_rate_params(struct ath10k_vif *arvif,
+ 
+ 	lockdep_assert_held(&ar->conf_mutex);
+ 
+-	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu\n",
+-		   arvif->vdev_id, rate, nss, sgi);
++	ath10k_dbg(ar, ATH10K_DBG_MAC, "mac set fixed rate params vdev %i rate 0x%02hhx nss %hhu sgi %hhu set-rate-type: %d\n",
++		   arvif->vdev_id, rate, nss, sgi, ar->set_rate_type);
+ 
+-	vdev_param = ar->wmi.vdev_param->fixed_rate;
++	if (ar->set_rate_type)
++		vdev_param = ar->set_rate_type;
++	else
++		vdev_param = ar->wmi.vdev_param->fixed_rate;
+ 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, rate);
+ 	if (ret) {
+-		ath10k_warn(ar, "failed to set fixed rate param 0x%02x: %d\n",
+-			    rate, ret);
++		ath10k_warn(ar, "vdev %i failed to set fixed rate, param 0x%x rate 0x%02x nss %hhu sgi %hhu: %d\n",
++			    arvif->vdev_id, vdev_param, rate, nss, sgi, ret);
+ 		return ret;
+ 	}
+ 
++	/* If we are setting one of the specialized rates (mgmt, ucast, bcast)
++	 * then we do not need to set the other values, so skip to exit.
++	 */
++	if (ar->set_rate_type != 0)
++		return 0;
++
+ 	vdev_param = ar->wmi.vdev_param->nss;
+ 	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param, nss);
+ 	if (ret) {
diff --git a/package/kernel/mac80211/patches/999-0073-ath10k-more-logging-for-crash-over-PCI-registers.patch b/package/kernel/mac80211/patches/999-0073-ath10k-more-logging-for-crash-over-PCI-registers.patch
new file mode 100644
index 0000000..e0f512f
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0073-ath10k-more-logging-for-crash-over-PCI-registers.patch
@@ -0,0 +1,33 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 31 Mar 2015 10:31:21 -0700
+Subject: [PATCH] ath10k: more logging for crash-over-PCI-registers.
+
+Help us know how the logic is failing if it does fail.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/pci.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
+index 053162d75733..23981860518c 100644
+--- a/drivers/net/wireless/ath/ath10k/pci.c
++++ b/drivers/net/wireless/ath/ath10k/pci.c
+@@ -1261,6 +1261,8 @@ static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
+ 	int q;
+ #define MAX_SPIN_TRIES 1000000
+ 
++	ath10k_warn(ar, "in crash-regs-harder\n");
++
+ 	if (!test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
+ 		return -EINVAL;
+ 	}
+@@ -1270,6 +1272,8 @@ static int ath10k_ct_fw_crash_regs_harder(struct ath10k *ar,
+ 		if (val & FW_IND_SCRATCH2_WR)
+ 			goto pingpong;
+ 	}
++
++	ath10k_warn(ar, "in crash-regs-harder, firmware did not provide indicator: 0x%x\n", val);
+ 	return -EBUSY;
+ 
+ pingpong:
diff --git a/package/kernel/mac80211/patches/999-0074-ath10k-Allow-max-msdu-to-be-configured-with-mod-para.patch b/package/kernel/mac80211/patches/999-0074-ath10k-Allow-max-msdu-to-be-configured-with-mod-para.patch
new file mode 100644
index 0000000..30b3f59
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0074-ath10k-Allow-max-msdu-to-be-configured-with-mod-para.patch
@@ -0,0 +1,72 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 31 Mar 2015 14:07:12 -0700
+Subject: [PATCH] ath10k: Allow max-msdu to be configured with mod-param.
+
+The 4.0 kernel is using more firmware RAM, probably because
+of larger htc buffers.  To still support 64 vdevs, I need
+to save a bit of RAM.  Do that by decreasing the default
+value for msdu-desc count.  It may be adjusted with module
+parameter as desired by the user.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 2 +-
+ drivers/net/wireless/ath/ath10k/hw.h   | 2 --
+ drivers/net/wireless/ath/ath10k/mac.c  | 5 +++++
+ drivers/net/wireless/ath/ath10k/mac.h  | 1 +
+ 4 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 1755b222818c..98c139a88b61 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1143,7 +1143,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
+ 			ar->max_num_peers = ath10k_modparam_target_num_peers_ct;
+ 			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ 			ar->max_num_vdevs = ath10k_modparam_target_num_vdevs_ct;
+-			ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC_CT;
++			ar->htt.max_num_pending_tx = ath10k_modparam_target_num_msdu_desc_ct;
+ 		} else {
+ 			ar->max_num_peers = TARGET_10X_NUM_PEERS;
+ 			ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
+index 315eed45dd11..799699c69866 100644
+--- a/drivers/net/wireless/ath/ath10k/hw.h
++++ b/drivers/net/wireless/ath/ath10k/hw.h
+@@ -283,8 +283,6 @@ enum ath10k_hw_rate_cck {
+ 						    * override w/module parm */
+ #define TARGET_10X_AST_SKID_LIMIT_CT		(ath10k_modparam_target_num_peers_ct * TARGET_10X_NUM_PEER_AST)
+ #define TARGET_10X_NUM_PEER_KEYS_CT             (WMI_MAX_KEY_INDEX + 1) /* 4 */
+-/* These eat a fair chunk of memory on the firmware, so decrease it a bit. */
+-#define TARGET_10X_NUM_MSDU_DESC_CT		808 /* must be multiple of 8 */
+ 
+ /* Related to HTC buffers */
+ /* return any credit immediately */
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 8989df5232e9..aed6f008f815 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -168,6 +168,11 @@ int ath10k_modparam_target_num_peers_ct = 128;
+ module_param_named(num_peers_ct, ath10k_modparam_target_num_peers_ct, int, 0444);
+ MODULE_PARM_DESC(num_peers_ct, "Maximum peers to request from firmware");
+ 
++/* These consume a fair bit of RAM on target. */
++int ath10k_modparam_target_num_msdu_desc_ct = 680;
++module_param_named(num_msdu_desc_ct, ath10k_modparam_target_num_msdu_desc_ct, int, 0444);
++MODULE_PARM_DESC(num_msdu_desc_ct, "Maximum MSDU Descriptors in firmware (must be multiple of 8)");
++
+ /**********/
+ /* Crypto */
+ /**********/
+diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h
+index 6db40bd7d098..4497002e9d31 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.h
++++ b/drivers/net/wireless/ath/ath10k/mac.h
+@@ -29,6 +29,7 @@ enum wmi_tlv_tx_pause_action;
+ extern int ath10k_modparam_nohwcrypt;
+ extern int ath10k_modparam_target_num_vdevs_ct;
+ extern int ath10k_modparam_target_num_peers_ct;
++extern int ath10k_modparam_target_num_msdu_desc_ct;
+ 
+ struct ath10k_generic_iter {
+ 	struct ath10k *ar;
diff --git a/package/kernel/mac80211/patches/999-0075-ath10k-register-as-sw-crypt-capable-if-using-proper-.patch b/package/kernel/mac80211/patches/999-0075-ath10k-register-as-sw-crypt-capable-if-using-proper-.patch
new file mode 100644
index 0000000..e5e2028
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0075-ath10k-register-as-sw-crypt-capable-if-using-proper-.patch
@@ -0,0 +1,41 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 31 Mar 2015 15:16:35 -0700
+Subject: [PATCH] ath10k: register as sw-crypt capable if using proper CT firmware.
+
+This lets us do SW-crypt as we could in previous kernels.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index aed6f008f815..804fb445655d 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -4793,8 +4793,12 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ 	if (key->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
+ 		return 1;
+ 
+-	if (key->keyidx > WMI_MAX_KEY_INDEX)
++	if (key->keyidx > WMI_MAX_KEY_INDEX) {
++		if (cmd != DISABLE_KEY)
++			ath10k_warn(ar, "failed to install key, idx out of range: %d > %d, vdev: %d\n",
++				    key->keyidx, WMI_MAX_KEY_INDEX, arvif->vdev_id);
+ 		return -ENOSPC;
++	}
+ 
+ 	mutex_lock(&ar->conf_mutex);
+ 
+@@ -7041,6 +7045,11 @@ int ath10k_mac_register(struct ath10k *ar)
+ 			ar->hw->wiphy->n_iface_combinations =
+ 				ARRAY_SIZE(ath10k_10x_ct_if_comb);
+ 			ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
++
++			/* CT firmware can do tx-sw-crypt if properly configured */
++			if (test_bit(ATH10K_FW_FEATURE_CT_RXSWCRYPT, ar->fw_features) &&
++			    ath10k_modparam_nohwcrypt)
++				__clear_bit(IEEE80211_HW_SW_CRYPTO_CONTROL, ar->hw->flags);
+ 		} else {
+ 			ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
+ 			ar->hw->wiphy->n_iface_combinations =
diff --git a/package/kernel/mac80211/patches/999-0076-wireless-add-pr_info-debugging-for-key-and-if-combo-.patch b/package/kernel/mac80211/patches/999-0076-wireless-add-pr_info-debugging-for-key-and-if-combo-.patch
new file mode 100644
index 0000000..460984b
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0076-wireless-add-pr_info-debugging-for-key-and-if-combo-.patch
@@ -0,0 +1,197 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 10 Apr 2015 09:57:40 -0700
+Subject: [PATCH] wireless: add pr_info debugging for key and if-combo errors.
+
+This makes it easier for users to know why certain API calls
+failed.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/util.c | 82 ++++++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 65 insertions(+), 17 deletions(-)
+
+diff --git a/net/wireless/util.c b/net/wireless/util.c
+index baf7218cec15..4b0215fe830f 100644
+--- a/net/wireless/util.c
++++ b/net/wireless/util.c
+@@ -218,14 +218,21 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ 				   struct key_params *params, int key_idx,
+ 				   bool pairwise, const u8 *mac_addr)
+ {
+-	if (key_idx > 5)
++	if (key_idx > 5) {
++		pr_info("validate-key:  idx is > 5: %d\n", key_idx);
+ 		return -EINVAL;
++	}
+ 
+-	if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN))
++	if (!pairwise && mac_addr && !(rdev->wiphy.flags & WIPHY_FLAG_IBSS_RSN)) {
++		pr_info("validate-key:  pairwise: %d  mac_addr: %pM  rdev->flags: 0x%x\n",
++			(int)pairwise, mac_addr, rdev->wiphy.flags);
+ 		return -EINVAL;
++	}
+ 
+-	if (pairwise && !mac_addr)
++	if (pairwise && !mac_addr) {
++		pr_info("validate-key: pairwise and NOT mac-addr.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	switch (params->cipher) {
+ 	case WLAN_CIPHER_SUITE_TKIP:
+@@ -239,16 +246,20 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ 		 * specific ciphers this should be validated in the driver or
+ 		 * hardware level - but 802.11i clearly specifies to use zero)
+ 		 */
+-		if (pairwise && key_idx)
++		if (pairwise && key_idx) {
++			pr_info("validate-key:  pairwise && key-idx, for TKIP/[CG]CMP*\n");
+ 			return -EINVAL;
++		}
+ 		break;
+ 	case WLAN_CIPHER_SUITE_AES_CMAC:
+ 	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ 		/* Disallow BIP (group-only) cipher as pairwise cipher */
+-		if (pairwise)
++		if (pairwise) {
++			pr_info("validate-key: BIP as pairwise cipher\n");
+ 			return -EINVAL;
++		}
+ 		break;
+ 	default:
+ 		break;
+@@ -315,6 +326,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ 		case WLAN_CIPHER_SUITE_WEP40:
+ 		case WLAN_CIPHER_SUITE_WEP104:
+ 			/* These ciphers do not use key sequence */
++			pr_info("validate-key:  WEP had params->cipher\n");
+ 			return -EINVAL;
+ 		case WLAN_CIPHER_SUITE_TKIP:
+ 		case WLAN_CIPHER_SUITE_CCMP:
+@@ -325,14 +337,18 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
+ 		case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ 		case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ 		case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+-			if (params->seq_len != 6)
++			if (params->seq_len != 6) {
++				pr_info("validate-key:  Invalid seq-len: %d != 6\n", params->seq_len);
+ 				return -EINVAL;
++			}
+ 			break;
+ 		}
+ 	}
+ 
+-	if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))
++	if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher)) {
++		pr_info("validate-key:  cipher suite not supported: %d\n", params->cipher);
+ 		return -EINVAL;
++	}
+ 
+ 	return 0;
+ }
+@@ -1535,6 +1551,10 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
+ 			used_iftypes |= BIT(iftype);
+ 	}
+ 
++	/*pr_info("%s: iter-comb, radar-detect: %d  combinations: %d  num_interfaces: %d\n",
++		wiphy_name(wiphy), radar_detect, wiphy->n_iface_combinations,
++		num_interfaces);
++	*/
+ 	for (i = 0; i < wiphy->n_iface_combinations; i++) {
+ 		const struct ieee80211_iface_combination *c;
+ 		struct ieee80211_iface_limit *limits;
+@@ -1542,10 +1562,17 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
+ 
+ 		c = &wiphy->iface_combinations[i];
+ 
+-		if (num_interfaces > c->max_interfaces)
++		if (num_interfaces > c->max_interfaces) {
++			pr_info("%i: iter-comb, num > max: %d > %d\n",
++			  i, num_interfaces, c->max_interfaces);
+ 			continue;
+-		if (num_different_channels > c->num_different_channels)
++		}
++
++		if (num_different_channels > c->num_different_channels) {
++			pr_info("%i: iter-comb, channels differ: %d > %d\n",
++				i, num_different_channels, c->num_different_channels);
+ 			continue;
++		}
+ 
+ 		limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
+ 				 GFP_KERNEL);
+@@ -1553,32 +1580,49 @@ int cfg80211_iter_combinations(struct wiphy *wiphy,
+ 			return -ENOMEM;
+ 
+ 		for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+-			if (wiphy->software_iftypes & BIT(iftype))
++			if (wiphy->software_iftypes & BIT(iftype)) {
++				/*pr_info("%i: type: %d  sw-iftypes: 0x%x\n",
++				  i, iftype, wiphy->software_iftypes);*/
+ 				continue;
++			}
+ 			for (j = 0; j < c->n_limits; j++) {
+ 				all_iftypes |= limits[j].types;
+-				if (!(limits[j].types & BIT(iftype)))
++				if (!(limits[j].types & BIT(iftype))) {
++					/*pr_info("%i: type: %i %i:  limits-types: 0x%x\n",
++					  i, iftype, j, limits[j].types);*/
+ 					continue;
+-				if (limits[j].max < iftype_num[iftype])
++				}
++				if (limits[j].max < iftype_num[iftype]) {
++					pr_info("%i: %i: limit-max: %d  iftype-num: %d\n",
++						i, j, limits[j].max, iftype_num[iftype]);
+ 					goto cont;
++				}
+ 				limits[j].max -= iftype_num[iftype];
+ 			}
+ 		}
+ 
+-		if (radar_detect != (c->radar_detect_widths & radar_detect))
++		if (radar_detect != (c->radar_detect_widths & radar_detect)) {
++			pr_info("%i: iter-comb radar-detect: %d  %d\n",
++				i, radar_detect, c->radar_detect_widths);
+ 			goto cont;
++		}
+ 
+ 		if (radar_detect && c->radar_detect_regions &&
+-		    !(c->radar_detect_regions & BIT(region)))
++		    !(c->radar_detect_regions & BIT(region))) {
++			pr_info("%i: iter-comb, radar detect regions mismatch\n", i);
+ 			goto cont;
++		}
+ 
+ 		/* Finally check that all iftypes that we're currently
+ 		 * using are actually part of this combination. If they
+ 		 * aren't then we can't use this combination and have
+ 		 * to continue to the next.
+ 		 */
+-		if ((all_iftypes & used_iftypes) != used_iftypes)
++		if ((all_iftypes & used_iftypes) != used_iftypes) {
++			/*pr_info("%i: all-iftypes: %d  used-iftypes: %d\n",
++			  i, all_iftypes, used_iftypes);*/
+ 			goto cont;
++		}
+ 
+ 		/* This combination covered all interface types and
+ 		 * supported the requested numbers, so we're good.
+@@ -1611,10 +1655,14 @@ int cfg80211_check_combinations(struct wiphy *wiphy,
+ 	err = cfg80211_iter_combinations(wiphy, num_different_channels,
+ 					 radar_detect, iftype_num,
+ 					 cfg80211_iter_sum_ifcombs, &num);
+-	if (err)
++	if (err) {
++		pr_info("cfg-comb-check: failed to iterate combinations\n");
+ 		return err;
+-	if (num == 0)
++	}
++	if (num == 0) {
++		pr_info("cfg-comb-check: iter-combinations returned num==0\n");
+ 		return -EBUSY;
++	}
+ 
+ 	return 0;
+ }
diff --git a/package/kernel/mac80211/patches/999-0077-wireless-add-pr_info-debugging-for-keys-and-if-combo.patch b/package/kernel/mac80211/patches/999-0077-wireless-add-pr_info-debugging-for-keys-and-if-combo.patch
new file mode 100644
index 0000000..4841610
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0077-wireless-add-pr_info-debugging-for-keys-and-if-combo.patch
@@ -0,0 +1,142 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 10 Apr 2015 09:59:11 -0700
+Subject: [PATCH] wireless: add pr_info debugging for keys and if-combo issues.
+
+Helps users know why certain API calls fail.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/nl80211.c | 53 ++++++++++++++++++++++++++++++++++++++------------
+ 1 file changed, 41 insertions(+), 12 deletions(-)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index a45e17e4c27d..c63282275833 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -2935,15 +2935,21 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+ 	struct net_device *dev = info->user_ptr[1];
+ 
+ 	err = nl80211_parse_key(info, &key);
+-	if (err)
++	if (err) {
++		pr_info("set-key:  Failed to parse: %d\n", err);
+ 		return err;
++	}
+ 
+-	if (key.idx < 0)
++	if (key.idx < 0) {
++		pr_info("set-key, idx is negative: %d\n", key.idx);
+ 		return -EINVAL;
++	}
+ 
+ 	/* only support setting default key */
+-	if (!key.def && !key.defmgmt)
++	if (!key.def && !key.defmgmt) {
++		pr_info("set-key: tried to set non-default key.\n");
+ 		return -EINVAL;
++	}
+ 
+ 	wdev_lock(dev->ieee80211_ptr);
+ 
+@@ -2954,20 +2960,26 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+ 		}
+ 
+ 		err = nl80211_key_allowed(dev->ieee80211_ptr);
+-		if (err)
++		if (err) {
++			pr_info("set-key:  key is not allowed: %d\n", err);
+ 			goto out;
++		}
+ 
+ 		err = rdev_set_default_key(rdev, dev, key.idx,
+ 						 key.def_uni, key.def_multi);
+ 
+-		if (err)
++		if (err) {
++			pr_info("set-default-key had error: %d\n", err);
+ 			goto out;
++		}
+ 
+ #ifdef CPTCFG_CFG80211_WEXT
+ 		dev->ieee80211_ptr->wext.default_key = key.idx;
+ #endif
+ 	} else {
+ 		if (key.def_uni || !key.def_multi) {
++			pr_info("set-key, uni: %d or not multi: %d\n",
++				key.def_uni, key.def_multi);
+ 			err = -EINVAL;
+ 			goto out;
+ 		}
+@@ -2978,12 +2990,16 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
+ 		}
+ 
+ 		err = nl80211_key_allowed(dev->ieee80211_ptr);
+-		if (err)
++		if (err) {
++			pr_info("set-key: key is not allowed (!key.def), err: %d\n", err);
+ 			goto out;
++		}
+ 
+ 		err = rdev_set_default_mgmt_key(rdev, dev, key.idx);
+-		if (err)
++		if (err) {
++			pr_info("set-key, rdev-set-default-mgt-key had failured: %d\n", err);
+ 			goto out;
++		}
+ 
+ #ifdef CPTCFG_CFG80211_WEXT
+ 		dev->ieee80211_ptr->wext.default_mgmt_key = key.idx;
+@@ -3005,11 +3021,15 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
+ 	const u8 *mac_addr = NULL;
+ 
+ 	err = nl80211_parse_key(info, &key);
+-	if (err)
++	if (err) {
++		pr_info("new-key:  parse failed: %d\n", err);
+ 		return err;
++	}
+ 
+-	if (!key.p.key)
++	if (!key.p.key) {
++		pr_info("new-key:  key.p.key is NULL\n");
+ 		return -EINVAL;
++	}
+ 
+ 	if (info->attrs[NL80211_ATTR_MAC])
+ 		mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+@@ -3023,23 +3043,32 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
+ 
+ 	/* for now */
+ 	if (key.type != NL80211_KEYTYPE_PAIRWISE &&
+-	    key.type != NL80211_KEYTYPE_GROUP)
++	    key.type != NL80211_KEYTYPE_GROUP) {
++		pr_info("new-key: invalid key type: %d\n", key.type);
+ 		return -EINVAL;
++	}
+ 
+ 	if (!rdev->ops->add_key)
+ 		return -EOPNOTSUPP;
+ 
+ 	if (cfg80211_validate_key_settings(rdev, &key.p, key.idx,
+ 					   key.type == NL80211_KEYTYPE_PAIRWISE,
+-					   mac_addr))
++					   mac_addr)) {
++		pr_info("new-key:  validate settings failed\n");
+ 		return -EINVAL;
++	}
+ 
+ 	wdev_lock(dev->ieee80211_ptr);
+ 	err = nl80211_key_allowed(dev->ieee80211_ptr);
+-	if (!err)
++	if (!err) {
+ 		err = rdev_add_key(rdev, dev, key.idx,
+ 				   key.type == NL80211_KEYTYPE_PAIRWISE,
+ 				    mac_addr, &key.p);
++		if (err)
++			pr_info("new-key:  rdev-add-key failed: %d\n", err);
++	} else {
++		pr_info("new-key:  key-allowed failed: %d\n", err);
++	}
+ 	wdev_unlock(dev->ieee80211_ptr);
+ 
+ 	return err;
diff --git a/package/kernel/mac80211/patches/999-0078-ath10k-improve-wmi-debugging.patch b/package/kernel/mac80211/patches/999-0078-ath10k-improve-wmi-debugging.patch
new file mode 100644
index 0000000..04e12df
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0078-ath10k-improve-wmi-debugging.patch
@@ -0,0 +1,41 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 10 Apr 2015 10:04:46 -0700
+Subject: [PATCH] ath10k: improve wmi debugging.
+
+Helps figure out what is going on with keys and some
+related calls.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/wmi.c | 10 ++++++----
+ 1 file changed, 6 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index 3fd067b3c17a..c2f79c0ce9e8 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -4573,8 +4573,9 @@ ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar,
+ 		memcpy(cmd->key_data, arg->key_data, arg->key_len);
+ 
+ 	ath10k_dbg(ar, ATH10K_DBG_WMI,
+-		   "wmi vdev install key idx %d cipher %d len %d\n",
+-		   arg->key_idx, arg->key_cipher, arg->key_len);
++		   "wmi vdev %d install key peer %pM idx %d cipher %d len %d flags 0x%x\n",
++		   arg->vdev_id, arg->macaddr, arg->key_idx, arg->key_cipher, arg->key_len,
++		   arg->key_flags);
+ 	return skb;
+ }
+ 
+@@ -4957,9 +4958,10 @@ ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar,
+ 	ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+ 
+ 	ath10k_dbg(ar, ATH10K_DBG_WMI,
+-		   "wmi peer assoc vdev %d addr %pM (%s)\n",
++		   "wmi peer assoc vdev %d addr %pM (%s) flags 0x%x\n",
+ 		   arg->vdev_id, arg->addr,
+-		   arg->peer_reassoc ? "reassociate" : "new");
++		   arg->peer_reassoc ? "reassociate" : "new",
++		   arg->peer_flags);
+ 	return skb;
+ }
+ 
diff --git a/package/kernel/mac80211/patches/999-0079-mac80211-debug-messages-related-to-if-combinations.patch b/package/kernel/mac80211/patches/999-0079-mac80211-debug-messages-related-to-if-combinations.patch
new file mode 100644
index 0000000..e9ac554
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0079-mac80211-debug-messages-related-to-if-combinations.patch
@@ -0,0 +1,62 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 10 Apr 2015 10:06:46 -0700
+Subject: [PATCH] mac80211: debug messages related to if-combinations.
+
+Helps user understand why API calls are failing.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/mac80211/util.c | 20 ++++++++++++++++----
+ 1 file changed, 16 insertions(+), 4 deletions(-)
+
+diff --git a/net/mac80211/util.c b/net/mac80211/util.c
+index bf83413e6061..17129715bdc0 100644
+--- a/net/mac80211/util.c
++++ b/net/mac80211/util.c
+@@ -3220,23 +3220,33 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
+ 
+ 	lockdep_assert_held(&local->chanctx_mtx);
+ 
+-	if (WARN_ON(hweight32(radar_detect) > 1))
++	if (WARN_ON(hweight32(radar_detect) > 1)) {
++		sdata_info(sdata, "comb-check: failed radar-detect: %d\n",
++			   (int)(radar_detect));
+ 		return -EINVAL;
++	}
+ 
+ 	if (WARN_ON(chandef && chanmode == IEEE80211_CHANCTX_SHARED &&
+-		    !chandef->chan))
++		    !chandef->chan)) {
++		sdata_info(sdata, "comb-check: failed chantx-shared check\n");
+ 		return -EINVAL;
++	}
+ 
+ 	if (chandef)
+ 		num_different_channels = 1;
+ 
+-	if (WARN_ON(iftype >= NUM_NL80211_IFTYPES))
++	if (WARN_ON(iftype >= NUM_NL80211_IFTYPES)) {
++		sdata_info(sdata, "comb-check: failed iftype check: %d\n",
++			   (int)(iftype));
+ 		return -EINVAL;
++	}
+ 
+ 	/* Always allow software iftypes */
+ 	if (local->hw.wiphy->software_iftypes & BIT(iftype)) {
+-		if (radar_detect)
++		if (radar_detect) {
++			sdata_info(sdata, "comb-check: failed software-type + radar-detect\n");
+ 			return -EINVAL;
++		}
+ 		return 0;
+ 	}
+ 
+@@ -3270,6 +3280,8 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata,
+ 		    local->hw.wiphy->software_iftypes & BIT(wdev_iter->iftype))
+ 			continue;
+ 
++		/*sdata_info(sdata, "sdata_iter: %s  type: %d  is active\n",
++		  sdata_iter->name, wdev_iter->iftype);*/
+ 		num[wdev_iter->iftype]++;
+ 		total++;
+ 	}
diff --git a/package/kernel/mac80211/patches/999-0081-ath10k-Add-tx-rx-bytes-counter-to-ethtool-stats.patch b/package/kernel/mac80211/patches/999-0081-ath10k-Add-tx-rx-bytes-counter-to-ethtool-stats.patch
new file mode 100644
index 0000000..a8a0c13
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0081-ath10k-Add-tx-rx-bytes-counter-to-ethtool-stats.patch
@@ -0,0 +1,111 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 8 May 2015 12:18:20 -0700
+Subject: [PATCH] ath10k: Add tx/rx bytes counter to ethtool stats.
+
+The firmware does not offer this counter, so just keep track of
+it in the driver.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h   |  3 +++
+ drivers/net/wireless/ath/ath10k/debug.c  |  8 ++++----
+ drivers/net/wireless/ath/ath10k/htt_rx.c |  3 +++
+ drivers/net/wireless/ath/ath10k/htt_tx.c | 10 ++++++++--
+ 4 files changed, 18 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 68e49cf247dd..784dfa2b93b9 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -438,6 +438,9 @@ struct ath10k_debug {
+ 	struct ath10k_dbglog_entry_storage dbglog_entry_data;
+ 
+ 	struct ath10k_fw_crash_data *fw_crash_data;
++
++	u64 tx_bytes; /* counter, firmware does not offer this stat */
++	u64 rx_bytes; /* counter, firmware does not offer this stat */
+ };
+ 
+ enum ath10k_state {
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 306b21d31707..891a42a8b5d9 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -1960,9 +1960,9 @@ exit:
+ /* This generally cooresponds to the debugfs fw_stats file */
+ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
+ 	"tx_pkts_nic",
+-	"tx_bytes_nic",
++	"tx_bytes_nic", // from driver, firmware does not keep this stat.
+ 	"rx_pkts_nic",
+-	"rx_bytes_nic",
++	"rx_bytes_nic", // from driver, firmware does not keep this stat.
+ 	"d_noise_floor",
+ 	"d_cycle_count",
+ 	"d_phy_error",
+@@ -2060,9 +2060,9 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ 	spin_lock_bh(&ar->data_lock);
+ 
+ 	data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
+-	data[i++] = 0; /* tx bytes */
++	data[i++] = ar->debug.tx_bytes;
+ 	data[i++] = pdev_stats->htt_mpdus;
+-	data[i++] = 0; /* rx bytes */
++	data[i++] = ar->debug.rx_bytes;
+ 	data[i++] = pdev_stats->ch_noise_floor;
+ 	data[i++] = pdev_stats->cycle_count;
+ 	data[i++] = pdev_stats->phy_err_count;
+diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
+index 953ab340b4b0..521f95609345 100644
+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
+@@ -1365,6 +1365,9 @@ static void ath10k_htt_rx_h_mpdu(struct ath10k *ar,
+ 		   has_peer_idx_invalid, enctype);
+ 	*/
+ 	skb_queue_walk(amsdu, msdu) {
++#ifdef CPTCFG_ATH10K_DEBUGFS
++		ar->debug.rx_bytes += msdu->len;
++#endif
+ 		ath10k_htt_rx_h_csum_offload(msdu);
+ 		ath10k_htt_rx_h_undecap(ar, msdu, status, first_hdr, enctype,
+ 					is_decrypted);
+diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
+index a60ef7d1d5fc..396c83176036 100644
+--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
+@@ -422,6 +422,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
+ 	u16 msdu_id, flags1 = 0;
+ 	dma_addr_t paddr = 0;
+ 	u32 frags_paddr = 0;
++	int skb_len;
+ 
+ 	res = ath10k_htt_tx_inc_pending(htt);
+ 	if (res)
+@@ -533,13 +534,14 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
+ 	skb_cb->htt.txbuf->cmd_tx.peerid = __cpu_to_le16(HTT_INVALID_PEERID);
+ 	skb_cb->htt.txbuf->cmd_tx.freq = __cpu_to_le16(skb_cb->htt.freq);
+ 
++	skb_len = msdu->len;
+ 	trace_ath10k_htt_tx(ar, msdu_id, msdu->len, vdev_id, tid);
+ 	ath10k_dbg(ar, ATH10K_DBG_HTT,
+ 		   "htt tx flags0 %hhu flags1 %hu len %d id %hu frags_paddr %08x, msdu_paddr %08x vdev %hhu tid %hhu freq %hu\n",
+-		   flags0, flags1, msdu->len, msdu_id, frags_paddr,
++		   flags0, flags1, skb_len, msdu_id, frags_paddr,
+ 		   (u32)skb_cb->paddr, vdev_id, tid, skb_cb->htt.freq);
+ 	ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt tx msdu: ",
+-			msdu->data, msdu->len);
++			msdu->data, skb_len);
+ 	trace_ath10k_tx_hdr(ar, msdu->data, msdu->len);
+ 	trace_ath10k_tx_payload(ar, msdu->data, msdu->len);
+ 
+@@ -564,6 +566,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
+ 	if (res)
+ 		goto err_unmap_msdu;
+ 
++#ifdef CPTCFG_ATH10K_DEBUGFS
++	ar->debug.tx_bytes += skb_len;
++#endif
++
+ 	return 0;
+ 
+ err_unmap_msdu:
diff --git a/package/kernel/mac80211/patches/999-0082-ath10k-Document-cycle-count-related-counters.patch b/package/kernel/mac80211/patches/999-0082-ath10k-Document-cycle-count-related-counters.patch
new file mode 100644
index 0000000..8f6741c
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0082-ath10k-Document-cycle-count-related-counters.patch
@@ -0,0 +1,31 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 5 Jun 2015 13:42:32 -0700
+Subject: [PATCH] ath10k: Document cycle count related counters.
+
+They are not necessarily named in an intuitive manner,
+so at least add some comments to help the next person.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 784dfa2b93b9..c433754e1ac4 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -187,10 +187,10 @@ struct ath10k_fw_stats_pdev {
+ 
+ 	/* PDEV stats */
+ 	s32 ch_noise_floor;
+-	u32 tx_frame_count;
+-	u32 rx_frame_count;
+-	u32 rx_clear_count;
+-	u32 cycle_count;
++	u32 tx_frame_count; /* cycles spent transmitting frames */
++	u32 rx_frame_count; /* cycles spent receiving frames */
++	u32 rx_clear_count; /* Total channel busy time, evidently */
++	u32 cycle_count; /* Total on-channel time */
+ 	u32 phy_err_count;
+ 	u32 chan_tx_power;
+ 	u32 ack_rx_bad;
diff --git a/package/kernel/mac80211/patches/999-0083-ath10k-Improve-ethtool-stats-to-return-cycle-counter.patch b/package/kernel/mac80211/patches/999-0083-ath10k-Improve-ethtool-stats-to-return-cycle-counter.patch
new file mode 100644
index 0000000..2dcd224
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0083-ath10k-Improve-ethtool-stats-to-return-cycle-counter.patch
@@ -0,0 +1,74 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Fri, 5 Jun 2015 13:43:55 -0700
+Subject: [PATCH] ath10k: Improve ethtool stats to return cycle-counters.
+
+Note these counters are since the chip reset, though the counters
+wrap often.  When cycle-counters counter overflows on
+certain hardware, it will right shift all 4 of the
+related registers to the right by one bit (basically,
+divide by two).  Since you have no idea what the others
+were at when cycle-counter wrapped, you must simply
+ignore any sample where cycle-counter wraps, and set
+new baseline values to calculate diffs against next
+time.
+
+Hardware with this funny wrap logic will cause the
+d_flags 'counter' to have bit 0x1 set, so that is how
+user-space can know how to deal with this.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.c | 18 +++++++++++++++---
+ 1 file changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 891a42a8b5d9..9f840ea9c573 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -1960,11 +1960,15 @@ exit:
+ /* This generally cooresponds to the debugfs fw_stats file */
+ static const char ath10k_gstrings_stats[][ETH_GSTRING_LEN] = {
+ 	"tx_pkts_nic",
+-	"tx_bytes_nic", // from driver, firmware does not keep this stat.
++	"tx_bytes_nic", /* from driver, firmware does not keep this stat. */
+ 	"rx_pkts_nic",
+-	"rx_bytes_nic", // from driver, firmware does not keep this stat.
++	"rx_bytes_nic", /* from driver, firmware does not keep this stat. */
+ 	"d_noise_floor",
+-	"d_cycle_count",
++	"d_cycle_count", /* this is duty cycle counter, basically channel-time. 88MHz clock */
++	"d_tx_cycle_count", /* tx cycle count */
++	"d_rx_cycle_count", /* rx cycle count */
++	"d_busy_count", /* Total channel busy time cycles (called 'clear' by firmware) */
++	"d_flags", /* 0x1:  hw has shifted cycle-count wrap, see ath10k_hw_fill_survey_time */
+ 	"d_phy_error",
+ 	"d_rts_bad",
+ 	"d_rts_good",
+@@ -2036,6 +2040,7 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ 	static const struct ath10k_fw_stats_pdev zero_stats = {};
+ 	const struct ath10k_fw_stats_pdev *pdev_stats;
+ 	int i = 0, ret;
++	u64 d_flags = 0;
+ 
+ 	mutex_lock(&ar->conf_mutex);
+ 
+@@ -2059,12 +2064,19 @@ void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
+ 
+ 	spin_lock_bh(&ar->data_lock);
+ 
++	if (ar->hw_params.has_shifted_cc_wraparound)
++		d_flags |= 0x1;
++
+ 	data[i++] = pdev_stats->hw_reaped; /* ppdu reaped */
+ 	data[i++] = ar->debug.tx_bytes;
+ 	data[i++] = pdev_stats->htt_mpdus;
+ 	data[i++] = ar->debug.rx_bytes;
+ 	data[i++] = pdev_stats->ch_noise_floor;
+ 	data[i++] = pdev_stats->cycle_count;
++	data[i++] = pdev_stats->tx_frame_count;
++	data[i++] = pdev_stats->rx_frame_count;
++	data[i++] = pdev_stats->rx_clear_count; /* yes, this appears to actually be 'busy' count */
++	data[i++] = d_flags; /* give user-space a chance to decode cycle counters */
+ 	data[i++] = pdev_stats->phy_err_count;
+ 	data[i++] = pdev_stats->rts_bad;
+ 	data[i++] = pdev_stats->rts_good;
diff --git a/package/kernel/mac80211/patches/999-0084-wireless-Add-ifname-to-STOP_AP-event.patch b/package/kernel/mac80211/patches/999-0084-wireless-Add-ifname-to-STOP_AP-event.patch
new file mode 100644
index 0000000..9dea63f
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0084-wireless-Add-ifname-to-STOP_AP-event.patch
@@ -0,0 +1,27 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Wed, 10 Jun 2015 15:07:56 -0700
+Subject: [PATCH] wireless: Add ifname to STOP_AP event.
+
+In case user-space wants to know the name of the
+device, this will save a name lookup by index, and
+in case where kernel manages to fully delete the
+interface before user-space can determine the name,
+this will ensure user-space has proper name.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/wireless/nl80211.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+index c63282275833..b1a94c498d11 100644
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -13055,6 +13055,7 @@ void nl80211_send_ap_stopped(struct wireless_dev *wdev)
+ 		goto out;
+ 
+ 	if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
++	    nla_put_string(msg, NL80211_ATTR_IFNAME, wdev->netdev->name) ||
+ 	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, wdev->netdev->ifindex) ||
+ 	    nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)))
+ 		goto out;
diff --git a/package/kernel/mac80211/patches/999-0085-ath10k-Use-non-qos-TID-for-nullfunc-frames.patch b/package/kernel/mac80211/patches/999-0085-ath10k-Use-non-qos-TID-for-nullfunc-frames.patch
new file mode 100644
index 0000000..87e3590
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0085-ath10k-Use-non-qos-TID-for-nullfunc-frames.patch
@@ -0,0 +1,29 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 15 Jun 2015 13:23:06 -0700
+Subject: [PATCH] ath10k: Use non-qos TID for nullfunc frames.
+
+This gives firmware a chance to send the frames as non-qos
+packets.  Otherwise, at least some firmware versions will
+treat this as normal QoS data that can use block-ack, and
+end result is that null-func probes often fail because
+ack is not received in time.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 804fb445655d..6245c53e0521 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -3149,6 +3149,9 @@ static u8 ath10k_tx_h_get_tid(struct ieee80211_hdr *hdr)
+ 	if (ieee80211_is_mgmt(hdr->frame_control))
+ 		return HTT_DATA_TX_EXT_TID_MGMT;
+ 
++	if (ieee80211_is_nullfunc(hdr->frame_control))
++		return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
++
+ 	if (!ieee80211_is_data_qos(hdr->frame_control))
+ 		return HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
+ 
diff --git a/package/kernel/mac80211/patches/999-0086-ath10k-Default-to-127-peers.patch b/package/kernel/mac80211/patches/999-0086-ath10k-Default-to-127-peers.patch
new file mode 100644
index 0000000..dd138fa
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0086-ath10k-Default-to-127-peers.patch
@@ -0,0 +1,31 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Tue, 16 Jun 2015 16:46:32 -0700
+Subject: [PATCH] ath10k: Default to 127 peers.
+
+When using normal hw-crypt, more than 127 stations breaks WPA-1
+communication in station mode with CT firmware.  It most likely
+causes problems with other encryption schemes as well.
+
+So, default to 127.
+
+Reported-by: Severn Tsui <severn@xxxxxxxxxxx>
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 6245c53e0521..b0d1ed58542d 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -164,7 +164,9 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware rx decrypt feature");
+ int ath10k_modparam_target_num_vdevs_ct = DEF_TARGET_10X_NUM_VDEVS_CT;
+ module_param_named(num_vdevs_ct, ath10k_modparam_target_num_vdevs_ct, int, 0444);
+ MODULE_PARM_DESC(num_vdevs_ct, "Maximum vdevs to request from firmware");
+-int ath10k_modparam_target_num_peers_ct = 128;
++
++/* More than 127 seems to cause issues when using HW de-crypt, so default to 127. */
++int ath10k_modparam_target_num_peers_ct = 127;
+ module_param_named(num_peers_ct, ath10k_modparam_target_num_peers_ct, int, 0444);
+ MODULE_PARM_DESC(num_peers_ct, "Maximum peers to request from firmware");
+ 
diff --git a/package/kernel/mac80211/patches/999-0087-ath10k-Support-special-pdev-cmd-id.patch b/package/kernel/mac80211/patches/999-0087-ath10k-Support-special-pdev-cmd-id.patch
new file mode 100644
index 0000000..5c24025
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0087-ath10k-Support-special-pdev-cmd-id.patch
@@ -0,0 +1,188 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Sun, 28 Jun 2015 09:06:56 -0700
+Subject: [PATCH] ath10k: Support 'special' pdev cmd-id.
+
+This is for CT firmware only.  Supports some register
+overrides (thresh62_ext, ack timing, etc).
+
+debugfs interface is added to modify thresh62_ext
+value.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c  |  8 ++++++
+ drivers/net/wireless/ath/ath10k/core.h  |  2 ++
+ drivers/net/wireless/ath/ath10k/debug.c | 44 +++++++++++++++++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.c   | 26 +++++++++++++++++++
+ drivers/net/wireless/ath/ath10k/wmi.h   | 20 +++++++++++++++
+ 5 files changed, 100 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 98c139a88b61..390aa6256239 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -1363,6 +1363,14 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
+ 	if (status)
+ 		goto err_hif_stop;
+ 
++	/* Apply user-supplied configuration changes. */
++	if (ar->ath10k_thresh62_ext) {
++		/* Don't worry about failures..not much we can do, and not worth failing init even
++		 * if this fails.
++		 */
++		ath10k_wmi_pdev_set_special(ar, SET_SPECIAL_ID_THRESH62_EXT, ar->ath10k_thresh62_ext);
++	}
++
+ 	if (ar->max_num_vdevs >= 64)
+ 		ar->free_vdev_map = 0xFFFFFFFFFFFFFFFFLL;
+ 	else
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index c433754e1ac4..306a5c08e4a6 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -821,6 +821,8 @@ struct ath10k {
+ 	struct ath10k_thermal thermal;
+ 	struct ath10k_wow wow;
+ 
++	u8 ath10k_thresh62_ext; /* be sure to flush this to firmware after resets */
++
+ 	/* must be last */
+ 	u8 drv_priv[0] __aligned(sizeof(void *));
+ };
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 9f840ea9c573..0c04338821c9 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -2542,6 +2542,47 @@ static const struct file_operations fops_pktlog_filter = {
+ 	.open = simple_open
+ };
+ 
++static ssize_t ath10k_write_thresh62_ext(struct file *file,
++					 const char __user *ubuf,
++					 size_t count, loff_t *ppos)
++{
++	struct ath10k *ar = file->private_data;
++	u8 enable;
++	int ret = 0;
++
++	if (kstrtou8_from_user(ubuf, count, 0, &enable))
++		return -EINVAL;
++
++	mutex_lock(&ar->conf_mutex);
++	ar->ath10k_thresh62_ext = enable;
++	ret = ath10k_wmi_pdev_set_special(ar, SET_SPECIAL_ID_THRESH62_EXT, enable);
++	mutex_unlock(&ar->conf_mutex);
++
++	return ret ?: count;
++}
++
++static ssize_t ath10k_read_thresh62_ext(struct file *file,
++					char __user *ubuf,
++					size_t count, loff_t *ppos)
++{
++	char buf[32];
++	struct ath10k *ar = file->private_data;
++	int len = 0;
++
++	mutex_lock(&ar->conf_mutex);
++	len = scnprintf(buf, sizeof(buf) - len, "%d\n",
++			ar->ath10k_thresh62_ext);
++	mutex_unlock(&ar->conf_mutex);
++
++	return simple_read_from_buffer(ubuf, count, ppos, buf, len);
++}
++
++static const struct file_operations fops_thresh62_ext = {
++	.read = ath10k_read_thresh62_ext,
++	.write = ath10k_write_thresh62_ext,
++	.open = simple_open
++};
++
+ static ssize_t ath10k_write_quiet_period(struct file *file,
+ 					 const char __user *ubuf,
+ 					 size_t count, loff_t *ppos)
+@@ -2700,6 +2741,9 @@ int ath10k_debug_register(struct ath10k *ar)
+ 	debugfs_create_file("quiet_period", S_IRUGO | S_IWUSR,
+ 			    ar->debug.debugfs_phy, ar, &fops_quiet_period);
+ 
++	debugfs_create_file("thresh62_ext", S_IRUGO | S_IWUSR,
++			    ar->debug.debugfs_phy, ar, &fops_thresh62_ext);
++
+ 	return 0;
+ }
+ 
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index c2f79c0ce9e8..ba0cdb17f468 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -5307,6 +5307,32 @@ ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ 	return skb;
+ }
+ 
++int ath10k_wmi_pdev_set_special(struct ath10k *ar, u32 id, u32 val)
++{
++	struct wmi_pdev_set_special_cmd *cmd;
++	struct sk_buff *skb;
++
++	if (!test_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features)) {
++		ath10k_warn(ar, "Only CT firmware (built after June 26, 2015) supports this method of setting thresh62_ext.\n");
++		return -ENOTSUPP;
++	}
++
++	skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
++	if (!skb)
++		return -ENOMEM;
++
++	cmd = (struct wmi_pdev_set_special_cmd *)skb->data;
++	memset(cmd, 0, sizeof(*cmd));
++
++	cmd->id = __cpu_to_le32(id);
++	cmd->val = __cpu_to_le32(val);
++
++	ath10k_dbg(ar, ATH10K_DBG_WMI,
++		   "wmi pdev set special id:%d val: %d\n",
++		   id, val);
++	return ath10k_wmi_cmd_send(ar, skb, WMI_PDEV_SET_SPECIAL_CMDID);
++}
++
+ static const struct wmi_ops wmi_ops = {
+ 	.rx = ath10k_wmi_op_rx,
+ 	.map_svc = wmi_main_svc_map,
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
+index 224739e92772..633442720bdf 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.h
++++ b/drivers/net/wireless/ath/ath10k/wmi.h
+@@ -994,6 +994,7 @@ enum wmi_10x_cmd_id {
+ 	WMI_10X_GPIO_CPTCFG_CMDID,
+ 	WMI_10X_GPIO_OUTPUT_CMDID,
+ 
++	WMI_PDEV_SET_SPECIAL_CMDID = WMI_10X_END_CMDID - 101, /* CT only:  special hack (cts/slot/cifs/ack timers, etc) */
+ 	WMI_NOP = WMI_10X_END_CMDID - 100, /* CT only:  wmi transport keep-alive, basically */
+ 
+ 	WMI_10X_PDEV_UTF_CMDID = WMI_10X_END_CMDID - 1,
+@@ -4978,6 +4979,25 @@ struct wmi_pdev_temperature_event {
+ 	__le32 temperature;
+ } __packed;
+ 
++/* CT firmware only, and only builds after June 26, 2015 */
++struct wmi_pdev_set_special_cmd {
++#define SET_SPECIAL_ID_ACK_CTS 0 /* set ack-cts-timeout register */
++#define SET_SPECIAL_ID_SLOT    1 /* set slot-duration register */
++#define SET_SPECIAL_ID_SIFS    2 /* set sifs-duration register */
++#define SET_SPECIAL_ID_THRESH62_EXT 3 /* set PHY_BB_EXT_CHAN_PWR_THR_1_THRESH62_EXT register field...
++				       * increasing this to 42 helps at least
++				       * one customer pass regulatory testing, for instance.  This is
++				       * same register/field as: PHY_BB_EXT_CHAN_PWR_THR_1_THR_CCA_EXT40
++				       * this is an 8-bit value.
++				       */
++
++    __le32 id;
++    __le32 val;
++    __le32 extra1;
++    __le32 extra2;
++};
++int ath10k_wmi_pdev_set_special(struct ath10k *ar, u32 id, u32 val);
++
+ /* WOW structures */
+ enum wmi_wow_wakeup_event {
+ 	WOW_BMISS_EVENT = 0,
diff --git a/package/kernel/mac80211/patches/999-0088-ath10k-Add-compatibility-with-older-CT-firmware.patch b/package/kernel/mac80211/patches/999-0088-ath10k-Add-compatibility-with-older-CT-firmware.patch
new file mode 100644
index 0000000..7720270
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0088-ath10k-Add-compatibility-with-older-CT-firmware.patch
@@ -0,0 +1,60 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 3 Aug 2015 16:11:42 -0700
+Subject: [PATCH] ath10k:  Add compatibility with older CT firmware.
+
+And fix a mis-ported FW feature to match existing
+(and future) firmware.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.c | 12 ++++++++++++
+ drivers/net/wireless/ath/ath10k/core.h |  6 +++---
+ 2 files changed, 15 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
+index 390aa6256239..307892b78803 100644
+--- a/drivers/net/wireless/ath/ath10k/core.c
++++ b/drivers/net/wireless/ath/ath10k/core.c
+@@ -880,6 +880,18 @@ fw_ie_bss_info_ct:
+ 		goto err;
+ 	}
+ 
++	/* Only CT firmware has BSS stuff, so we can use this to fix up
++	 * flags for backwards and forwards compat with older/newer CT firmware.
++	 * (upstream stole some bits it was using)
++	 */
++	if (ar->fw.rom_bss_addr) {
++		if (test_bit(5, ar->fw_features))
++			__set_bit(ATH10K_FW_FEATURE_WMI_10X_CT, ar->fw_features);
++
++		if (test_bit(6, ar->fw_features))
++			__set_bit(ATH10K_FW_FEATURE_CT_RXSWCRYPT, ar->fw_features);
++	}
++
+ 	return 0;
+ 
+ err:
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 306a5c08e4a6..4e1996989612 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -518,6 +518,9 @@ enum ath10k_fw_features {
+ 	/* Firmware supports bypassing PLL setting on init. */
+ 	ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT = 9,
+ 
++	/* tx-status has the noack bits (CT firmware version 14 and higher ) */
++	ATH10K_FW_FEATURE_HAS_TXSTATUS_NOACK = 30,
++
+ 	/* Firmware from Candela Technologies, enables more VIFs, etc */
+ 	ATH10K_FW_FEATURE_WMI_10X_CT = 31,
+ 
+@@ -526,9 +529,6 @@ enum ath10k_fw_features {
+ 	 * encryption (ie, commercial version of CT firmware) */
+ 	ATH10K_FW_FEATURE_CT_RXSWCRYPT = 32,
+ 
+-	/* tx-status has the noack bits (CT firmware version 14 and higher ) */
+-	ATH10K_FW_FEATURE_HAS_TXSTATUS_NOACK = 33,
+-
+ 	/* keep last */
+ 	ATH10K_FW_FEATURE_COUNT,
+ };
diff --git a/package/kernel/mac80211/patches/999-0089-ath10k-Support-CT-firmware-management-over-htt.patch b/package/kernel/mac80211/patches/999-0089-ath10k-Support-CT-firmware-management-over-htt.patch
new file mode 100644
index 0000000..0b4ecb9
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0089-ath10k-Support-CT-firmware-management-over-htt.patch
@@ -0,0 +1,75 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 13 Jul 2015 11:58:45 -0700
+Subject: [PATCH] ath10k: Support CT firmware management-over-htt.
+
+CT firmware now also comes in 'htt-mgt' variants.  These bump
+the HTT version to 2.2 (from 2.1) and support management frames
+over normal htt transport.
+
+This patch enables this firmware to work properly.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/core.h   |  1 +
+ drivers/net/wireless/ath/ath10k/htt_rx.c | 10 ++++++++++
+ drivers/net/wireless/ath/ath10k/mac.c    |  7 +++++++
+ 3 files changed, 18 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
+index 4e1996989612..d0b640606d2e 100644
+--- a/drivers/net/wireless/ath/ath10k/core.h
++++ b/drivers/net/wireless/ath/ath10k/core.h
+@@ -621,6 +621,7 @@ struct ath10k {
+ 	DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
+ 
+ 	bool p2p;
++	bool ct_all_pkts_htt; /* CT firmware only: native-wifi for all pkts */
+ 
+ 	struct {
+ 		enum ath10k_bus bus;
+diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
+index 521f95609345..ca3ff1cce53a 100644
+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
+@@ -1985,6 +1985,16 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
+ 	case HTT_T2H_MSG_TYPE_VERSION_CONF: {
+ 		htt->target_version_major = resp->ver_resp.major;
+ 		htt->target_version_minor = resp->ver_resp.minor;
++
++		/* CT firmware with HTT-MGT?  No official firmware has this
++		 * htt version combination as far as I am aware. --Ben
++		 */
++		if ((htt->target_version_major == 2 &&
++		     htt->target_version_minor == 2))
++			ar->ct_all_pkts_htt = true;
++		else
++			ar->ct_all_pkts_htt = false;
++
+ 		complete(&htt->target_version_received);
+ 		break;
+ 	}
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index b0d1ed58542d..d9e416ed188f 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -3185,6 +3185,12 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
+ 	if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
+ 		return ATH10K_HW_TXRX_RAW;
+ 
++	/* CT Firmware with HTT-TX support sends all frames, including
++	 * management frames, over HTT in NATIVE-WIFI format.
++	 */
++	if (ar->ct_all_pkts_htt)
++		goto do_native_mgt_ct;
++
+ 	if (ieee80211_is_mgmt(fc))
+ 		return ATH10K_HW_TXRX_MGMT;
+ 
+@@ -3215,6 +3221,7 @@ ath10k_tx_h_get_txmode(struct ath10k *ar, struct ieee80211_vif *vif,
+ 	 * NativeWifi txmode - it selects AP key instead of peer key. It seems
+ 	 * to work with Ethernet txmode so use it.
+ 	 */
++do_native_mgt_ct:
+ 	if (ieee80211_is_data_present(fc) && sta && sta->tdls)
+ 		return ATH10K_HW_TXRX_ETHERNET;
+ 
diff --git a/package/kernel/mac80211/patches/999-0090-ath10k-firmware-dbglog-now-prints-pci-id.patch b/package/kernel/mac80211/patches/999-0090-ath10k-firmware-dbglog-now-prints-pci-id.patch
new file mode 100644
index 0000000..0f28284
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-0090-ath10k-firmware-dbglog-now-prints-pci-id.patch
@@ -0,0 +1,49 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Thu, 30 Jul 2015 16:14:37 -0700
+Subject: [PATCH] ath10k: firmware dbglog now prints pci-id.
+
+Also, print warning if firmware reports a dropped
+debug-buffer, and fix a compile warning from a previous
+commit.
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ drivers/net/wireless/ath/ath10k/debug.c | 4 ++--
+ drivers/net/wireless/ath/ath10k/wmi.c   | 3 +++
+ 2 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
+index 0c04338821c9..b0262eec1e0e 100644
+--- a/drivers/net/wireless/ath/ath10k/debug.c
++++ b/drivers/net/wireless/ath/ath10k/debug.c
+@@ -2820,7 +2820,7 @@ void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *ibuf, int len,
+ 	 */
+ 	int q = 0;
+ 
+-	printk("%sATH10K_DBG_BUFFER:\n", lvl);
++	dev_printk(lvl, ar->dev, "ath10k_pci ATH10K_DBG_BUFFER:\n");
+ 	while (q < len) {
+ 		if (q + 8 <= len) {
+ 			printk("%sath10k: [%04d]: %08X %08X %08X %08X %08X %08X %08X %08X\n",
+@@ -2879,6 +2879,6 @@ void ath10k_dbg_print_fw_dbg_buffer(struct ath10k *ar, __le32 *ibuf, int len,
+ 		}
+ 	}/* while */
+ 
+-	printk("%sATH10K_END\n", lvl);
++	dev_printk(lvl, ar->dev, "ATH10K_END\n");
+ }
+ EXPORT_SYMBOL(ath10k_dbg_print_fw_dbg_buffer);
+diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
+index ba0cdb17f468..d12dd4ce14d8 100644
+--- a/drivers/net/wireless/ath/ath10k/wmi.c
++++ b/drivers/net/wireless/ath/ath10k/wmi.c
+@@ -1728,6 +1728,9 @@ int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
+ 				      (skb->len - 4)/sizeof(__le32));
+ 	spin_unlock_bh(&ar->data_lock);
+ 
++	if (ev->dropped_count)
++		ath10k_warn(ar, "WARNING: Dropped dbglog buffers: %d\n", __le32_to_cpu(ev->dropped_count));
++
+ 	if (ath10k_debug_mask & ATH10K_DBG_FW)
+ 		ath10k_dbg_print_fw_dbg_buffer(ar, ev->messages,
+ 					       (skb->len - 4)/sizeof(__le32),
diff --git a/package/kernel/mac80211/patches/999-9001-ath10k-Enable-VHT-support-in-IBSS-mode.patch b/package/kernel/mac80211/patches/999-9001-ath10k-Enable-VHT-support-in-IBSS-mode.patch
new file mode 100644
index 0000000..24fecbc
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-9001-ath10k-Enable-VHT-support-in-IBSS-mode.patch
@@ -0,0 +1,20 @@
+From: Sven Eckelmann <sven@xxxxxxxxxxxxx>
+Date: Mon, 16 Mar 2015 16:56:46 +0100
+Subject: [PATCH] ath10k: Enable VHT support in IBSS mode
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index f84f7a918962..244971bf29d5 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -7028,6 +7028,8 @@ int ath10k_mac_register(struct ath10k *ar)
+ 		goto err_free;
+ 	}
+ 
++	wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
++
+ 	/*
+ 	 * on LL hardware queues are managed entirely by the FW
+ 	 * so we only advertise to mac we can do the queues thing
diff --git a/package/kernel/mac80211/patches/999-9002-ath10k-Disable-static-SMPS-for-HT-MCS-7-test-with-at.patch b/package/kernel/mac80211/patches/999-9002-ath10k-Disable-static-SMPS-for-HT-MCS-7-test-with-at.patch
new file mode 100644
index 0000000..7ebc891
--- /dev/null
+++ b/package/kernel/mac80211/patches/999-9002-ath10k-Disable-static-SMPS-for-HT-MCS-7-test-with-at.patch
@@ -0,0 +1,61 @@
+From: Sven Eckelmann <sven@xxxxxxxxxxxxx>
+Date: Tue, 17 Mar 2015 18:10:27 +0100
+Subject: [PATCH] ath10k: Disable static SMPS for HT-MCS > 7 test with ath9k
+
+static SMPS limits rate control (minstrel_ht) to one stream
+---
+ drivers/net/wireless/ath/ath10k/mac.c | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
+index 244971bf29d5..e6de69c2ef84 100644
+--- a/drivers/net/wireless/ath/ath10k/mac.c
++++ b/drivers/net/wireless/ath/ath10k/mac.c
+@@ -6785,7 +6785,9 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
+ 	ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_8;
+ 	ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ 	ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
++#if 0
+ 	ht_cap.cap |= WLAN_HT_CAP_SM_PS_STATIC << IEEE80211_HT_CAP_SM_PS_SHIFT;
++#endif
+ 
+ 	if (ar->ht_cap_info & WMI_HT_CAP_HT20_SGI)
+ 		ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+@@ -6793,14 +6795,20 @@ static struct ieee80211_sta_ht_cap ath10k_get_ht_cap(struct ath10k *ar)
+ 	if (ar->ht_cap_info & WMI_HT_CAP_HT40_SGI)
+ 		ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+ 
++#if 0
+ 	if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS) {
+ 		u32 smps;
+ 
++		/* TODO */
+ 		smps   = WLAN_HT_CAP_SM_PS_DYNAMIC;
+ 		smps <<= IEEE80211_HT_CAP_SM_PS_SHIFT;
+ 
+ 		ht_cap.cap |= smps;
+ 	}
++#else
++	/* disable sm_ps because it limits rates to single stream */
++	ht_cap.cap |= IEEE80211_HT_CAP_SM_PS;
++#endif
+ 
+ 	if (ar->ht_cap_info & WMI_HT_CAP_TX_STBC)
+ 		ht_cap.cap |= IEEE80211_HT_CAP_TX_STBC;
+@@ -6978,11 +6986,16 @@ int ath10k_mac_register(struct ath10k *ar)
+ 	ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
+ 	ieee80211_hw_set(ar->hw, SUPPORT_FAST_XMIT);
+ 
++#if 0
++	/* TODO */
+ 	ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
++#endif
+ 	ar->hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+ 
++#if 0
+ 	if (ar->ht_cap_info & WMI_HT_CAP_DYNAMIC_SMPS)
+ 		ar->hw->wiphy->features |= NL80211_FEATURE_DYNAMIC_SMPS;
++#endif
+ 
+ 	if (ar->ht_cap_info & WMI_HT_CAP_ENABLED) {
+ 		ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
diff --git a/target/linux/generic/patches-4.1/999-bridge-Do-not-enable-PROMISC-mode-when-adding-AP.patch b/target/linux/generic/patches-4.1/999-bridge-Do-not-enable-PROMISC-mode-when-adding-AP.patch
new file mode 100644
index 0000000..a024d42
--- /dev/null
+++ b/target/linux/generic/patches-4.1/999-bridge-Do-not-enable-PROMISC-mode-when-adding-AP.patch
@@ -0,0 +1,53 @@
+From: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+Date: Mon, 13 Jul 2015 16:07:40 -0700
+Subject: [PATCH] bridge: Do not enable PROMISC mode when adding AP.
+
+This fixes ath10k instability in PROMISC mode, and should
+improve bridged AP performance in busy environments.
+
+See this for original idea and description:
+
+http://lists.celinuxforum.org/pipermail/bridge/2008-June/005906.html
+
+Signed-off-by: Ben Greear <greearb@xxxxxxxxxxxxxxx>
+---
+ net/bridge/br_if.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
+index 1849d96b3c91..7ddb1023e9f4 100644
+--- a/net/bridge/br_if.c
++++ b/net/bridge/br_if.c
+@@ -92,7 +92,8 @@ static void br_port_set_promisc(struct net_bridge_port *p)
+ 	if (br_promisc_port(p))
+ 		return;
+ 
+-	err = dev_set_promiscuity(p->dev, 1);
++	if (!p->dev->ieee80211_ptr)
++		err = dev_set_promiscuity(p->dev, 1);
+ 	if (err)
+ 		return;
+ 
+@@ -119,7 +120,8 @@ static void br_port_clear_promisc(struct net_bridge_port *p)
+ 	if (err)
+ 		return;
+ 
+-	dev_set_promiscuity(p->dev, -1);
++	if (!p->dev->ieee80211_ptr)
++		dev_set_promiscuity(p->dev, -1);
+ 	p->flags &= ~BR_PROMISC;
+ }
+ 
+@@ -184,8 +186,10 @@ static void nbp_delete_promisc(struct net_bridge_port *p)
+ 	 * from it.
+ 	 */
+ 	dev_set_allmulti(p->dev, -1);
+-	if (br_promisc_port(p))
+-		dev_set_promiscuity(p->dev, -1);
++	if (br_promisc_port(p)) {
++		if (!p->dev->ieee80211_ptr)
++			dev_set_promiscuity(p->dev, -1);
++	}
+ 	else
+ 		br_fdb_unsync_static(p->br, p);
+ }
From 3de347c1f83b09f1ac4190a66d53992116fa66d2 Mon Sep 17 00:00:00 2001
From: Sven Eckelmann <sven@xxxxxxxxxxxxx>
Date: Mon, 16 Mar 2015 17:28:39 +0100
Subject: [PATCH] iw: Hardcode VHT channel 36 in iw for testing

---
 .../iw/patches/300-hardcode-vht80-chan36.patch     | 27 ++++++++++++++++++++++
 1 file changed, 27 insertions(+)
 create mode 100644 package/network/utils/iw/patches/300-hardcode-vht80-chan36.patch

diff --git a/package/network/utils/iw/patches/300-hardcode-vht80-chan36.patch b/package/network/utils/iw/patches/300-hardcode-vht80-chan36.patch
new file mode 100644
index 0000000..0cc3425
--- /dev/null
+++ b/package/network/utils/iw/patches/300-hardcode-vht80-chan36.patch
@@ -0,0 +1,27 @@
+diff --git a/ibss.c b/ibss.c
+index 1bf1bab..6f332ce 100644
+--- a/ibss.c
++++ b/ibss.c
+@@ -89,10 +89,10 @@ static int join_ibss(struct nl80211_state *state,
+ 		}
+ 		if (chanmode_selected) {
+ 			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
+-				    chanmode_selected->width);
++				   NL80211_CHAN_WIDTH_80);
+ 			NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1,
+-				    freq + chanmode_selected->freq1_diff);
+-			if (chanmode_selected->chantype != -1)
++				    5210);
++			if (chanmode_selected->chantype != -1 && 0)
+ 				NLA_PUT_U32(msg,
+ 					    NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ 					    chanmode_selected->chantype);
+@@ -194,7 +194,7 @@ COMMAND(ibss, leave, NULL,
+ 	NL80211_CMD_LEAVE_IBSS, 0, CIB_NETDEV, leave_ibss,
+ 	"Leave the current IBSS cell.");
+ COMMAND(ibss, join,
+-	"<SSID> <freq in MHz> [HT20|HT40+|HT40-|NOHT|5MHZ|10MHZ] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>]"
++	"<SSID> <freq in MHz> [HT20|HT40+|HT40-|HT80|HT80+80|HT160|NOHT|5MHZ|10MHZ] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>]"
+ 	" [basic-rates <rate in Mbps,rate2,...>] [mcast-rate <rate in Mbps>] "
+ 	"[key d:0:abcde]",
+ 	NL80211_CMD_JOIN_IBSS, 0, CIB_NETDEV, join_ibss,
-- 
2.5.0


[Index of Archives]     [Linux Host AP]     [ATH6KL]     [Linux Wireless Personal Area Network]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Linux Kernel]     [IDE]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite Hiking]     [MIPS Linux]     [ARM Linux]     [Linux RAID]

  Powered by Linux