From 3de347c1f83b09f1ac4190a66d53992116fa66d2 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann 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 +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 +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 +--- + 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 +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 +--- + 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 +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 +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 +--- + 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 +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 +--- + 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, + ®_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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +Date: Thu, 9 May 2013 11:56:19 -0700 +Subject: [PATCH] wifi: Warn if cannot add station debugfs entries. + +Signed-off-by: Ben Greear +--- + 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 +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 +--- + 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(®_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 +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 +--- + 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 ++ ++/* ++ * 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 +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 +--- + 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 +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 +--- + 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 +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 +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 +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 +--- + 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 +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 +--- + 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 +Date: Wed, 24 Sep 2014 13:35:55 -0700 +Subject: [PATCH] wireless: better regdomain logging. + +Signed-off-by: Ben Greear +--- + 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 +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 +--- + 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 +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 +--- + 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, + ¶ms->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, ¶ms->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 +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 +--- + 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 +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 +--- + 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<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 +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 +--- + 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 +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 +--- + 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 +Date: Wed, 31 Dec 2014 10:38:09 -0800 +Subject: [PATCH] ath10k: fix typo in logging message + +Signed-off-by: Ben Greear +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +Signed-off-by: Kalle Valo +--- + 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 +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 +Signed-off-by: Kalle Valo +--- + 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 +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 +--- + 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 + #include ++#include + + #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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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, ¶m_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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 + #include ++#include + + #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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +Date: Wed, 24 Sep 2014 13:35:19 -0700 +Subject: [PATCH] ath10k: more regdom debugging information. + +Signed-off-by: Ben Greear +--- + 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 +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 +--- + 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 +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 +--- + 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 + #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 +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 +--- + 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 +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 +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 +--- + 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 +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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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@aoifes.com + +Signed-off-by: Ben Greear +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +Signed-off-by: Ben Greear +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +--- + 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 +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 +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 +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 +--- + 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); + }