From 487922a8d9b7ac564effe25632fd90e2cb6979b9 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer <mschiffer@universe-factory.net> Date: Tue, 11 Oct 2016 03:38:53 +0200 Subject: [PATCH] Downgrade mac80211 to LEDE 6c2651566cce8f5b3a3d3b976439dee2bac5e07e In addition, the temperature compensation support patch is reverted. It seems that newer mac80211 version are less stable, so we downgrade it for now. --- ...> 0007-mac80211-hostapd-iw-.-update.patch} | 9389 +++++++---------- ...73-kernel-add-fix-for-CVE-2016-7117.patch} | 0 ...211-fix-packet-loss-on-fq-reordering.patch | 636 -- ...re-compensation-support-patch-FS-111.patch | 124 + ...e-with-CCMP-PN-generated-in-hardware.patch | 21 - ...issues-with-powersave-devices-FS-176.patch | 1513 --- 6 files changed, 3798 insertions(+), 7885 deletions(-) rename patches/openwrt/{0007-mac80211-hostapd-iw-.-update-to-LEDE-42f559ed70897a7b74dd3e6293b42e6d2e511eaa.patch => 0007-mac80211-hostapd-iw-.-update.patch} (92%) rename patches/openwrt/{0076-kernel-add-fix-for-CVE-2016-7117.patch => 0073-kernel-add-fix-for-CVE-2016-7117.patch} (100%) delete mode 100644 patches/openwrt/0073-mac80211-fix-packet-loss-on-fq-reordering.patch create mode 100644 patches/openwrt/0074-ath9k-revert-temperature-compensation-support-patch-FS-111.patch delete mode 100644 patches/openwrt/0074-mac80211-fix-tx-issue-with-CCMP-PN-generated-in-hardware.patch delete mode 100644 patches/openwrt/0075-ath9k-remove-patch-causing-stability-issues-with-powersave-devices-FS-176.patch diff --git a/patches/openwrt/0007-mac80211-hostapd-iw-.-update-to-LEDE-42f559ed70897a7b74dd3e6293b42e6d2e511eaa.patch b/patches/openwrt/0007-mac80211-hostapd-iw-.-update.patch similarity index 92% rename from patches/openwrt/0007-mac80211-hostapd-iw-.-update-to-LEDE-42f559ed70897a7b74dd3e6293b42e6d2e511eaa.patch rename to patches/openwrt/0007-mac80211-hostapd-iw-.-update.patch index 04bf2b2d7..64eea76e5 100644 --- a/patches/openwrt/0007-mac80211-hostapd-iw-.-update-to-LEDE-42f559ed70897a7b74dd3e6293b42e6d2e511eaa.patch +++ b/patches/openwrt/0007-mac80211-hostapd-iw-.-update.patch @@ -1,6 +1,22 @@ From: Matthias Schiffer <mschiffer@universe-factory.net> -Date: Wed, 7 Sep 2016 05:04:06 +0200 -Subject: mac80211, hostapd, iw, ...: update to LEDE 42f559ed70897a7b74dd3e6293b42e6d2e511eaa +Date: Tue, 11 Oct 2016 02:53:43 +0200 +Subject: mac80211, hostapd, iw, ...: update + +The following package is updated to +LEDE 6c2651566cce8f5b3a3d3b976439dee2bac5e07e: + +* mac80211 + +The following packages are updated to +LEDE 42f559ed70897a7b74dd3e6293b42e6d2e511eaa: + +* acx-mac80211 +* ath10k-firmware +* hostapd +* iw +* linux-firmware +* mt76 +* mwlwifi diff --git a/package/firmware/ath10k-firmware/Makefile b/package/firmware/ath10k-firmware/Makefile index b03d644..624da6a 100644 @@ -698,7 +714,7 @@ index 0000000..bbff8d8 + +$(eval $(call KernelPackage,ath10k-ct)) diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile -index 30da1cf..5c0ca3f 100644 +index 30da1cf..f2839cd 100644 --- a/package/kernel/mac80211/Makefile +++ b/package/kernel/mac80211/Makefile @@ -10,20 +10,21 @@ include $(INCLUDE_DIR)/kernel.mk @@ -930,18 +946,15 @@ index 30da1cf..5c0ca3f 100644 WLAN_VENDOR_INTEL \ WLAN_VENDOR_INTERSIL \ WLAN_VENDOR_MARVELL \ -@@ -1491,8 +1491,10 @@ endif +@@ -1491,6 +1491,8 @@ endif config-$(call config_package,lib80211) += LIB80211 LIB80211_CRYPT_WEP LIB80211_CRYPT_CCMP LIB80211_CRYPT_TKIP +config-$(call config_package,airo) += AIRO + config-$(call config_package,ath) += ATH_CARDS ATH_COMMON --config-$(CONFIG_PACKAGE_ATH_DEBUG) += ATH_DEBUG ATH10K_DEBUG -+config-$(CONFIG_PACKAGE_ATH_DEBUG) += ATH_DEBUG ATH10K_DEBUG ATH9K_STATION_STATISTICS + config-$(CONFIG_PACKAGE_ATH_DEBUG) += ATH_DEBUG ATH10K_DEBUG config-$(CONFIG_PACKAGE_ATH_DFS) += ATH9K_DFS_CERTIFIED ATH10K_DFS_CERTIFIED - - config-$(call config_package,ath9k) += ATH9K @@ -1501,6 +1503,7 @@ config-$(CONFIG_TARGET_ar71xx) += ATH9K_AHB config-$(CONFIG_PCI) += ATH9K_PCI config-$(CONFIG_ATH_USER_REGD) += ATH_USER_REGD @@ -1139,151 +1152,6 @@ index ea229d6..06f3b8b 100644 dev_id=" option path '$path'" else dev_id=" option macaddr $(cat /sys/class/ieee80211/${dev}/macaddress)" -diff --git a/package/kernel/mac80211/files/regdb.txt b/package/kernel/mac80211/files/regdb.txt -index 463ace3..c4a9b2d 100644 ---- a/package/kernel/mac80211/files/regdb.txt -+++ b/package/kernel/mac80211/files/regdb.txt -@@ -136,19 +136,35 @@ country BF: DFS-FCC - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -+# Bulgarian rules as defined by the Communications Regulation Commission in the -+# following documents: -+# -+# Rules for carrying out electronic communications through radio equipment using -+# radio spectrum, which does not need to be individually assigned (the Rules): -+# http://www.crc.bg/files/_bg/Pravila_09_06_2015.pdf -+# -+# List of radio equipment that uses harmonized within the European Union bands -+# and electronic communications terminal equipment (the List): -+# http://www.crc.bg/files/_bg/Spisak_2015.pdf -+# -+# Note: The transmit power limits in the 5250-5350 MHz and 5470-5725 MHz bands -+# can be raised by 3 dBm if TPC is enabled. Refer to BDS EN 301 893 for details. - country BG: DFS-ETSI -+ # Wideband data transmission systems (WDTS) in the 2.4GHz ISM band, ref: -+ # I.22 of the List, BDS EN 300 328 - (2402 - 2482 @ 40), (20) -- (5170 - 5250 @ 80), (20), AUTO-BW -+ # 5 GHz Radio Local Area Networks (RLANs), ref: -+ # II.H01 of the List, BDS EN 301 893 -+ (5170 - 5250 @ 80), (23), AUTO-BW - (5250 - 5330 @ 80), (20), DFS, AUTO-BW -+ # II.H01 of the List, I.54 from the List, BDS EN 301 893 - (5490 - 5710 @ 160), (27), DFS -- # 5 GHz Short Range Devices, ref: -- # Etsi EN 300 440-1 -- # Etsi EN 300 440-2 -- # http://crc.bg/files/_bg/Spisak_2015.pdf -- # http://crc.bg/files/_bg/Pravila_2015_resh24.pdf -+ # Short range devices (SRDs) in the 5725-5875 MHz frequency range, ref: -+ # I.43 of the List, BDS EN 300 440-2, BDS EN 300 440-1 - (5725 - 5875 @ 80), (14) -- # 60 GHz band channels 1-4, ref: Etsi En 302 567 -- (57000 - 66000 @ 2160), (40) -+ # 60 GHz Multiple-Gigabit RLAN Systems, ref: -+ # II.H03 of the List, BDS EN 302 567-2 -+ (57000 - 66000 @ 2160), (40), NO-OUTDOOR - - country BH: DFS-JP - (2402 - 2482 @ 40), (20) -@@ -275,6 +291,12 @@ country CR: DFS-FCC - (5490 - 5730 @ 20), (24), DFS - (5735 - 5835 @ 20), (30) - -+# http://www.mincom.gob.cu/?q=marcoregulatorio -+# - Redes Informáticas -+# Resolución 127, 2011 - Reglamento Banda 2,4 GHz. -+country CU: DFS-FCC -+ (2400 - 2483.5 @ 40), (200 mW) -+ - country CX: DFS-FCC - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (24), AUTO-BW -@@ -302,28 +324,41 @@ country CZ: DFS-ETSI - # 60 GHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - --# Data from "Frequenznutzungsplan" (as published in April 2008), downloaded from --# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38448/publicationFile/2659/Frequenznutzungsplan2008_Id17448pdf.pdf --# For the 5GHz range also see --# http://www.bundesnetzagentur.de/cae/servlet/contentblob/38216/publicationFile/6579/WLAN5GHzVfg7_2010_28042010pdf.pdf --# The values have been reduced by a factor of 2 (3db) for non TPC devices --# (in other words: devices with TPC can use twice the tx power of this table). --# Note that the docs do not require TPC for 5150--5250; the reduction to --# 100mW thus is not strictly required -- however the conservative 100mW -+# Allocation for the 2.4 GHz band (Vfg 10 / 2013, Allgemeinzuteilung von -+# Frequenzen für die Nutzung in lokalen Netzwerken; Wireless Local Area -+# Networks (WLAN-Funkanwendungen). -+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2013_10_WLAN_2,4GHz_pdf.pdf -+# -+# Allocation for the 5 GHz band (Vfg. 7 / 2010, Allgemeinzuteilung von -+# Frequenzen in den Bereichen 5150 MHz - 5350 MHz und 5470 MHz - 5725 MHz für -+# Funkanwendungen zur breitbandigen Datenübertragung, WAS/WLAN („Wireless -+# Access Systems including Wireless Local Area Networks“). -+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2010_07_WLAN_5GHz_pdf.pdf -+# The values for the 5 GHz have been reduced by a factor of 2 (3db) for non TPC -+# devices (in other words: devices with TPC can use twice the tx power of this -+# table). Note that the docs do not require TPC for 5150--5250; the reduction -+# to 100mW thus is not strictly required -- however the conservative 100mW - # limit is used here as the non-interference with radar and satellite - # apps relies on the attenuation by the building walls only in the - # absence of DFS; the neighbour countries have 100mW limit here as well. -+# -+# The ETSI EN 300 440-1 standard for short range devices in the 5 GHz band has -+# been implemented in Germany: -+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2014_69_SRD_pdf.pdf -+# -+# Allocation for the 60 GHz band (Allgemeinzuteilung von Frequenzen im -+# Bereich 57 GHz - 66 GHz für Funkanwendungen für weitbandige -+# Datenübertragungssysteme; „Multiple Gigabit WAS/RLAN Systems (MGWS)“). -+# https://www.bundesnetzagentur.de/SharedDocs/Downloads/DE/Sachgebiete/Telekommunikation/Unternehmen_Institutionen/Frequenzen/Allgemeinzuteilungen/2011_08_MGWS_pdf.pdf - - country DE: DFS-ETSI -- # entries 279004 and 280006 - (2400 - 2483.5 @ 40), (100 mW) -- # entry 303005 - (5150 - 5250 @ 80), (100 mW), NO-OUTDOOR, AUTO-BW -- # entries 304002 and 305002 - (5250 - 5350 @ 80), (100 mW), NO-OUTDOOR, DFS, AUTO-BW -- # entries 308002, 309001 and 310003 - (5470 - 5725 @ 160), (500 mW), DFS -- # 60 GHz band channels 1-4, ref: Etsi En 302 567 -+ # short range devices (ETSI EN 300 440-1) -+ (5725 - 5875 @ 80), (25 mW) -+ # 60 GHz band channels 1-4 (ETSI EN 302 567) - (57000 - 66000 @ 2160), (40) - - country DK: DFS-ETSI -@@ -629,6 +664,9 @@ country KR: DFS-JP - (5250 - 5330 @ 80), (20), DFS, AUTO-BW - (5490 - 5710 @ 160), (30), DFS - (5735 - 5835 @ 80), (30) -+ # 60 GHz band channels 1-4, -+ # ref: http://www.law.go.kr/%ED%96%89%EC%A0%95%EA%B7%9C%EC%B9%99/%EB%AC%B4%EC%84%A0%EC%84%A4%EB%B9%84%EA%B7%9C%EC%B9%99 -+ (57000 - 66000 @ 2160), (43) - - country KW: DFS-ETSI - (2402 - 2482 @ 40), (20) -@@ -844,11 +882,18 @@ country NI: DFS-FCC - (5490 - 5730 @ 160), (24), DFS - (5735 - 5835 @ 80), (30) - -+# Regulation on the use of frequency space without a license and -+# without notification 2015 -+# -+# http://wetten.overheid.nl/BWBR0036378/2015-03-05 -+ - country NL: DFS-ETSI - (2402 - 2482 @ 40), (20) - (5170 - 5250 @ 80), (20), NO-OUTDOOR, AUTO-BW - (5250 - 5330 @ 80), (20), NO-OUTDOOR, DFS, AUTO-BW - (5490 - 5710 @ 160), (27), DFS -+ # short range devices (ETSI EN 300 440-1) -+ (5725 - 5875 @ 80), (25 mW) - # 60 GHz band channels 1-4, ref: Etsi En 302 567 - (57000 - 66000 @ 2160), (40) - diff --git a/package/kernel/mac80211/patches/004-backports-add-skb_free_frag.patch b/package/kernel/mac80211/patches/004-backports-add-skb_free_frag.patch deleted file mode 100644 index 9adfd8f..0000000 @@ -1382,157 +1250,6 @@ index 9b672a8..0000000 - /* - * Complicated way of saying: We only backport netdev_rss_key stuff on kernels - * that either already have net_get_random_once() (>= 3.13) or where we've been -diff --git a/package/kernel/mac80211/patches/006-add-basic-register-field-manipulation-macros.patch b/package/kernel/mac80211/patches/006-add-basic-register-field-manipulation-macros.patch -new file mode 100644 -index 0000000..a51edf8 ---- /dev/null -+++ b/package/kernel/mac80211/patches/006-add-basic-register-field-manipulation-macros.patch -@@ -0,0 +1,145 @@ -+From: Jakub Kicinski <jakub.kicinski@netronome.com> -+Date: Wed, 31 Aug 2016 12:46:44 +0100 -+Subject: [PATCH] add basic register-field manipulation macros -+ -+Common approach to accessing register fields is to define -+structures or sets of macros containing mask and shift pair. -+Operations on the register are then performed as follows: -+ -+ field = (reg >> shift) & mask; -+ -+ reg &= ~(mask << shift); -+ reg |= (field & mask) << shift; -+ -+Defining shift and mask separately is tedious. Ivo van Doorn -+came up with an idea of computing them at compilation time -+based on a single shifted mask (later refined by Felix) which -+can be used like this: -+ -+ #define REG_FIELD 0x000ff000 -+ -+ field = FIELD_GET(REG_FIELD, reg); -+ -+ reg &= ~REG_FIELD; -+ reg |= FIELD_PREP(REG_FIELD, field); -+ -+FIELD_{GET,PREP} macros take care of finding out what the -+appropriate shift is based on compilation time ffs operation. -+ -+GENMASK can be used to define registers (which is usually -+less error-prone and easier to match with datasheets). -+ -+This approach is the most convenient I've seen so to limit code -+multiplication let's move the macros to a global header file. -+Attempts to use static inlines instead of macros failed due -+to false positive triggering of BUILD_BUG_ON()s, especially with -+GCC < 6.0. -+ -+Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> -+Reviewed-by: Dinan Gunawardena <dinan.gunawardena@netronome.com> -+--- -+ create mode 100644 include/linux/bitfield.h -+ -+--- /dev/null -++++ b/include/linux/bitfield.h -+@@ -0,0 +1,100 @@ -++/* -++ * Copyright (C) 2014 Felix Fietkau <nbd@nbd.name> -++ * Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> -++ * -++ * This program is free software; you can redistribute it and/or modify -++ * it under the terms of the GNU General Public License version 2 -++ * as published by the Free Software Foundation -++ * -++ * This program is distributed in the hope that it will be useful, -++ * but WITHOUT ANY WARRANTY; without even the implied warranty of -++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -++ * GNU General Public License for more details. -++ */ -++ -++#ifndef _LINUX_BITFIELD_H -++#define _LINUX_BITFIELD_H -++ -++#include <linux/bug.h> -++ -++#ifdef __CHECKER__ -++#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) -++#else -++#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \ -++ BUILD_BUG_ON(((n) & ((n) - 1)) != 0) -++#endif -++ -++/* -++ * Bitfield access macros -++ * -++ * FIELD_{GET,PREP} macros take as first parameter shifted mask -++ * from which they extract the base mask and shift amount. -++ * Mask must be a compilation time constant. -++ * -++ * Example: -++ * -++ * #define REG_FIELD_A GENMASK(6, 0) -++ * #define REG_FIELD_B BIT(7) -++ * #define REG_FIELD_C GENMASK(15, 8) -++ * #define REG_FIELD_D GENMASK(31, 16) -++ * -++ * Get: -++ * a = FIELD_GET(REG_FIELD_A, reg); -++ * b = FIELD_GET(REG_FIELD_B, reg); -++ * -++ * Set: -++ * reg = FIELD_PREP(REG_FIELD_A, 1) | -++ * FIELD_PREP(REG_FIELD_B, 0) | -++ * FIELD_PREP(REG_FIELD_C, c) | -++ * FIELD_PREP(REG_FIELD_D, 0x40); -++ * -++ * Modify: -++ * reg &= ~REG_FIELD_C; -++ * reg |= FIELD_PREP(REG_FIELD_C, c); -++ */ -++ -++#define __bf_shf(x) (__builtin_ffsll(x) - 1) -++ -++#define __BF_FIELD_CHECK(_mask, _reg, _val, _pfx) \ -++ ({ \ -++ BUILD_BUG_ON_MSG(!__builtin_constant_p(_mask), \ -++ _pfx "mask is not constant"); \ -++ BUILD_BUG_ON_MSG(!(_mask), _pfx "mask is zero"); \ -++ BUILD_BUG_ON_MSG(__builtin_constant_p(_val) ? \ -++ ~((_mask) >> __bf_shf(_mask)) & (_val) : 0, \ -++ _pfx "value too large for the field"); \ -++ BUILD_BUG_ON_MSG((_mask) > (typeof(_reg))~0ull, \ -++ _pfx "type of reg too small for mask"); \ -++ __BUILD_BUG_ON_NOT_POWER_OF_2((_mask) + \ -++ (1ULL << __bf_shf(_mask))); \ -++ }) -++ -++/** -++ * FIELD_PREP() - prepare a bitfield element -++ * @_mask: shifted mask defining the field's length and position -++ * @_val: value to put in the field -++ * -++ * FIELD_PREP() masks and shifts up the value. The result should -++ * be combined with other fields of the bitfield using logical OR. -++ */ -++#define FIELD_PREP(_mask, _val) \ -++ ({ \ -++ __BF_FIELD_CHECK(_mask, 0ULL, _val, "FIELD_PREP: "); \ -++ ((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \ -++ }) -++ -++/** -++ * FIELD_GET() - extract a bitfield element -++ * @_mask: shifted mask defining the field's length and position -++ * @_reg: 32bit value of entire bitfield -++ * -++ * FIELD_GET() extracts the field specified by @_mask from the -++ * bitfield passed in as @_reg by masking and shifting it down. -++ */ -++#define FIELD_GET(_mask, _reg) \ -++ ({ \ -++ __BF_FIELD_CHECK(_mask, _reg, 0U, "FIELD_GET: "); \ -++ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \ -++ }) -++ -++#endif diff --git a/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch b/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch index fd1e1cf..8be5fa1 100644 --- a/package/kernel/mac80211/patches/060-no_local_ssb_bcma.patch @@ -5571,5068 +5288,3834 @@ index b646ab3..0000000 - EXPORT_SYMBOL(ieee80211_data_to_8023); - - int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, -diff --git a/package/kernel/mac80211/patches/320-ath9k-fix-using-sta-drv_priv-before-initializing-it.patch b/package/kernel/mac80211/patches/320-ath9k-fix-using-sta-drv_priv-before-initializing-it.patch +diff --git a/package/kernel/mac80211/patches/320-ath9k-Switch-to-using-mac80211-intermediate-software.patch b/package/kernel/mac80211/patches/320-ath9k-Switch-to-using-mac80211-intermediate-software.patch new file mode 100644 -index 0000000..aaa6706 +index 0000000..f8b8f86 --- /dev/null -+++ b/package/kernel/mac80211/patches/320-ath9k-fix-using-sta-drv_priv-before-initializing-it.patch -@@ -0,0 +1,33 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 2 Aug 2016 13:00:01 +0200 -+Subject: [PATCH] ath9k: fix using sta->drv_priv before initializing it ++++ b/package/kernel/mac80211/patches/320-ath9k-Switch-to-using-mac80211-intermediate-software.patch +@@ -0,0 +1,871 @@ ++From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk> ++Date: Wed, 6 Jul 2016 21:34:17 +0200 ++Subject: [PATCH] ath9k: Switch to using mac80211 intermediate software queues. ++MIME-Version: 1.0 ++Content-Type: text/plain; charset=UTF-8 ++Content-Transfer-Encoding: 8bit + -+A station pointer can be passed to the driver on tx, before it has been -+marked as associated. Since ath9k_sta_state was initializing the entry -+too late, it resulted in some spurious crashes. ++This switches ath9k over to using the mac80211 intermediate software ++queueing mechanism for data packets. It removes the queueing inside the ++driver, except for the retry queue, and instead pulls from mac80211 when ++a packet is needed. The retry queue is used to store a packet that was ++pulled but can't be sent immediately. + -+Fixes: df3c6eb34da5 ("ath9k: Use sta_state() callback") -+Cc: stable@vger.kernel.org -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- ++The old code path in ath_tx_start that would queue packets has been ++removed completely, as has the qlen limit tunables (since there's no ++longer a queue in the driver to limit). + -+--- a/drivers/net/wireless/ath/ath9k/main.c -++++ b/drivers/net/wireless/ath/ath9k/main.c -+@@ -1563,13 +1563,13 @@ static int ath9k_sta_state(struct ieee80 -+ struct ath_common *common = ath9k_hw_common(sc->sc_ah); -+ int ret = 0; -+ -+- if (old_state == IEEE80211_STA_AUTH && -+- new_state == IEEE80211_STA_ASSOC) { -++ if (old_state == IEEE80211_STA_NOTEXIST && -++ new_state == IEEE80211_STA_NONE) { -+ ret = ath9k_sta_add(hw, vif, sta); -+ ath_dbg(common, CONFIG, -+ "Add station: %pM\n", sta->addr); -+- } else if (old_state == IEEE80211_STA_ASSOC && -+- new_state == IEEE80211_STA_AUTH) { -++ } else if (old_state == IEEE80211_STA_NONE && -++ new_state == IEEE80211_STA_NOTEXIST) { -+ ret = ath9k_sta_remove(hw, vif, sta); -+ ath_dbg(common, CONFIG, -+ "Remove station: %pM\n", sta->addr); -diff --git a/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch b/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch -deleted file mode 100644 -index 2eeed22..0000000 ---- a/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch -+++ /dev/null -@@ -1,159 +0,0 @@ --From: Felix Fietkau <nbd@openwrt.org> --Date: Tue, 2 Feb 2016 14:39:10 +0100 --Subject: [PATCH] cfg80211: add support for non-linear skbs in -- ieee80211_amsdu_to_8023s -- --Signed-off-by: Felix Fietkau <nbd@openwrt.org> --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/wireless/util.c --+++ b/net/wireless/util.c --@@ -644,73 +644,75 @@ int ieee80211_data_from_8023(struct sk_b -- } -- EXPORT_SYMBOL(ieee80211_data_from_8023); -- --+static struct sk_buff * --+__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, --+ int offset, int len) --+{ --+ struct sk_buff *frame; --+ --+ if (skb->len - offset < len) --+ return NULL; --+ --+ /* --+ * Allocate and reserve two bytes more for payload --+ * alignment since sizeof(struct ethhdr) is 14. --+ */ --+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len); --+ --+ skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); --+ skb_copy_bits(skb, offset, skb_put(frame, len), len); --+ --+ return frame; --+} -- -- void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, -- const u8 *addr, enum nl80211_iftype iftype, -- const unsigned int extra_headroom, -- bool has_80211_header) -- { --+ unsigned int hlen = ALIGN(extra_headroom, 4); -- struct sk_buff *frame = NULL; -- u16 ethertype; -- u8 *payload; --- const struct ethhdr *eth; --- int remaining, err; --- u8 dst[ETH_ALEN], src[ETH_ALEN]; --- --- if (skb_linearize(skb)) --- goto out; --+ int offset = 0, remaining, err; --+ struct ethhdr eth; --+ bool reuse_skb = true; --+ bool last = false; -- -- if (has_80211_header) { --- err = ieee80211_data_to_8023(skb, addr, iftype); --+ err = __ieee80211_data_to_8023(skb, ð, addr, iftype); -- if (err) -- goto out; --- --- /* skip the wrapping header */ --- eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); --- if (!eth) --- goto out; --- } else { --- eth = (struct ethhdr *) skb->data; -- } -- --- while (skb != frame) { --+ while (!last) { --+ unsigned int subframe_len; --+ int len; -- u8 padding; --- __be16 len = eth->h_proto; --- unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); --- --- remaining = skb->len; --- memcpy(dst, eth->h_dest, ETH_ALEN); --- memcpy(src, eth->h_source, ETH_ALEN); -- --+ skb_copy_bits(skb, offset, ð, sizeof(eth)); --+ len = ntohs(eth.h_proto); --+ subframe_len = sizeof(struct ethhdr) + len; -- padding = (4 - subframe_len) & 0x3; --+ -- /* the last MSDU has no padding */ --+ remaining = skb->len - offset; -- if (subframe_len > remaining) -- goto purge; -- --- skb_pull(skb, sizeof(struct ethhdr)); --+ offset += sizeof(struct ethhdr); -- /* reuse skb for the last subframe */ --- if (remaining <= subframe_len + padding) --+ last = remaining <= subframe_len + padding; --+ if (!skb_is_nonlinear(skb) && last) { --+ skb_pull(skb, offset); -- frame = skb; --- else { --- unsigned int hlen = ALIGN(extra_headroom, 4); --- /* --- * Allocate and reserve two bytes more for payload --- * alignment since sizeof(struct ethhdr) is 14. --- */ --- frame = dev_alloc_skb(hlen + subframe_len + 2); --+ reuse_skb = true; --+ } else { --+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len); -- if (!frame) -- goto purge; -- --- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); --- memcpy(skb_put(frame, ntohs(len)), skb->data, --- ntohs(len)); --- --- eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + --- padding); --- if (!eth) { --- dev_kfree_skb(frame); --- goto purge; --- } --+ offset += len + padding; -- } -- -- skb_reset_network_header(frame); --@@ -719,24 +721,20 @@ void ieee80211_amsdu_to_8023s(struct sk_ -- -- payload = frame->data; -- ethertype = (payload[6] << 8) | payload[7]; --- -- if (likely((ether_addr_equal(payload, rfc1042_header) && -- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || -- ether_addr_equal(payload, bridge_tunnel_header))) { --- /* remove RFC1042 or Bridge-Tunnel --- * encapsulation and replace EtherType */ --- skb_pull(frame, 6); --- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); --- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); --- } else { --- memcpy(skb_push(frame, sizeof(__be16)), &len, --- sizeof(__be16)); --- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); --- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); --+ eth.h_proto = htons(ethertype); --+ skb_pull(frame, ETH_ALEN + 2); -- } --+ --+ memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth)); -- __skb_queue_tail(list, frame); -- } -- --+ if (!reuse_skb) --+ dev_kfree_skb(skb); --+ -- return; -- -- purge: -diff --git a/package/kernel/mac80211/patches/321-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch b/package/kernel/mac80211/patches/321-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch -new file mode 100644 -index 0000000..9caa76d ---- /dev/null -+++ b/package/kernel/mac80211/patches/321-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch -@@ -0,0 +1,25 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sat, 9 Jul 2016 15:25:24 +0200 -+Subject: [PATCH] ath9k_hw: reset AHB-WMAC interface on AR91xx ++Based on Tim's original patch set, but reworked quite thoroughly. + -+Should fix a few stability issues -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> ++Cc: Tim Shepard <shep@alum.mit.edu> ++Cc: Felix Fietkau <nbd@nbd.name> ++Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> +--- + -+--- a/drivers/net/wireless/ath/ath9k/hw.c -++++ b/drivers/net/wireless/ath/ath9k/hw.c -+@@ -1398,8 +1398,12 @@ static bool ath9k_hw_set_reset(struct at -+ if (!AR_SREV_9100(ah)) -+ REG_WRITE(ah, AR_RC, 0); -+ -+- if (AR_SREV_9100(ah)) -++ if (AR_SREV_9100(ah)) { -++ /* Reset the AHB-WMAC interface */ -++ if (ah->external_reset) -++ ah->external_reset(); -+ udelay(50); -++ } ++--- a/drivers/net/wireless/ath/ath9k/ath9k.h +++++ b/drivers/net/wireless/ath/ath9k/ath9k.h ++@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc * ++ #define ATH_RXBUF 512 ++ #define ATH_TXBUF 512 ++ #define ATH_TXBUF_RESERVE 5 ++-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) ++ #define ATH_TXMAXTRY 13 ++ #define ATH_MAX_SW_RETRIES 30 + -+ return true; -+ } -diff --git a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch b/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch -deleted file mode 100644 -index c4155a1..0000000 ---- a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch -+++ /dev/null -@@ -1,155 +0,0 @@ --From: Sven Eckelmann <sven@narfation.org> --Date: Tue, 26 Jan 2016 17:11:13 +0100 --Subject: [PATCH] mac80211: Parse legacy and HT rate in injected frames -- --Drivers/devices without their own rate control algorithm can get the --information what rates they should use from either the radiotap header of --injected frames or from the rate control algorithm. But the parsing of the --legacy rate information from the radiotap header was removed in commit --e6a9854b05c1 ("mac80211/drivers: rewrite the rate control API"). -- --The removal of this feature heavily reduced the usefulness of frame --injection when wanting to simulate specific transmission behavior. Having --rate parsing together with MCS rates and retry support allows a fine --grained selection of the tx behavior of injected frames for these kind of --tests. -- --Signed-off-by: Sven Eckelmann <sven@narfation.org> --Cc: Simon Wunderlich <sw@simonwunderlich.de> --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/include/net/mac80211.h --+++ b/include/net/mac80211.h --@@ -708,12 +708,14 @@ enum mac80211_tx_info_flags { -- * protocol frame (e.g. EAP) -- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll -- * frame (PS-Poll or uAPSD). --+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information -- * -- * These flags are used in tx_info->control.flags. -- */ -- enum mac80211_tx_control_flags { -- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), -- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), --+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), -- }; -- -- /* ----- a/net/mac80211/tx.c --+++ b/net/mac80211/tx.c --@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 -- -- info->control.short_preamble = txrc.short_preamble; -- --+ /* don't ask rate control when rate already injected via radiotap */ --+ if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT) --+ return TX_CONTINUE; --+ -- if (tx->sta) -- assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); -- --@@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub -- ieee80211_tx(sdata, sta, skb, false); -- } -- ---static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) --+static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local, --+ struct sk_buff *skb) -- { -- struct ieee80211_radiotap_iterator iterator; -- struct ieee80211_radiotap_header *rthdr = -- (struct ieee80211_radiotap_header *) skb->data; -- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --+ struct ieee80211_supported_band *sband = --+ local->hw.wiphy->bands[info->band]; -- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, -- NULL); -- u16 txflags; --+ u16 rate = 0; --+ bool rate_found = false; --+ u8 rate_retries = 0; --+ u16 rate_flags = 0; --+ u8 mcs_known, mcs_flags; --+ int i; -- -- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | -- IEEE80211_TX_CTL_DONTFRAG; --@@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap( -- info->flags |= IEEE80211_TX_CTL_NO_ACK; -- break; -- --+ case IEEE80211_RADIOTAP_RATE: --+ rate = *iterator.this_arg; --+ rate_flags = 0; --+ rate_found = true; --+ break; --+ --+ case IEEE80211_RADIOTAP_DATA_RETRIES: --+ rate_retries = *iterator.this_arg; --+ break; --+ --+ case IEEE80211_RADIOTAP_MCS: --+ mcs_known = iterator.this_arg[0]; --+ mcs_flags = iterator.this_arg[1]; --+ if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS)) --+ break; --+ --+ rate_found = true; --+ rate = iterator.this_arg[2]; --+ rate_flags = IEEE80211_TX_RC_MCS; --+ --+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI && --+ mcs_flags & IEEE80211_RADIOTAP_MCS_SGI) --+ rate_flags |= IEEE80211_TX_RC_SHORT_GI; --+ --+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW && --+ mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40) --+ rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; --+ break; --+ -- /* -- * Please update the file -- * Documentation/networking/mac80211-injection.txt --@@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap( -- if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ -- return false; -- --+ if (rate_found) { --+ info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT; --+ --+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { --+ info->control.rates[i].idx = -1; --+ info->control.rates[i].flags = 0; --+ info->control.rates[i].count = 0; --+ } --+ --+ if (rate_flags & IEEE80211_TX_RC_MCS) { --+ info->control.rates[0].idx = rate; --+ } else { --+ for (i = 0; i < sband->n_bitrates; i++) { --+ if (rate * 5 != sband->bitrates[i].bitrate) --+ continue; --+ --+ info->control.rates[0].idx = i; --+ break; --+ } --+ } --+ --+ info->control.rates[0].flags = rate_flags; --+ info->control.rates[0].count = min_t(u8, rate_retries + 1, --+ local->hw.max_rate_tries); --+ } --+ -- /* -- * remove the radiotap header -- * iterator->_max_length was sanity-checked against --@@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit -- IEEE80211_TX_CTL_INJECTED; -- -- /* process and remove the injection radiotap header */ --- if (!ieee80211_parse_tx_radiotap(skb)) --+ if (!ieee80211_parse_tx_radiotap(local, skb)) -- goto fail; -- -- rcu_read_lock(); -diff --git a/package/kernel/mac80211/patches/322-ath9k_hw-issue-external-reset-for-QCA9550.patch b/package/kernel/mac80211/patches/322-ath9k_hw-issue-external-reset-for-QCA9550.patch -new file mode 100644 -index 0000000..5d4e849 ---- /dev/null -+++ b/package/kernel/mac80211/patches/322-ath9k_hw-issue-external-reset-for-QCA9550.patch -@@ -0,0 +1,125 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sat, 9 Jul 2016 15:26:44 +0200 -+Subject: [PATCH] ath9k_hw: issue external reset for QCA9550 -+ -+The RTC interface on the SoC needs to be reset along with the rest of -+the WMAC. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/hw.c -++++ b/drivers/net/wireless/ath/ath9k/hw.c -+@@ -1275,39 +1275,56 @@ void ath9k_hw_get_delta_slope_vals(struc -+ *coef_exponent = coef_exp - 16; -+ } ++@@ -145,7 +144,9 @@ int ath_descdma_setup(struct ath_softc * ++ #define BAW_WITHIN(_start, _bawsz, _seqno) \ ++ ((((_seqno) - (_start)) & 4095) < (_bawsz)) + -+-/* AR9330 WAR: -+- * call external reset function to reset WMAC if: -+- * - doing a cold reset -+- * - we have pending frames in the TX queues. -+- */ -+-static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type) -++static bool ath9k_hw_need_external_reset(struct ath_hw *ah, int type) -+ { -+- int i, npend = 0; -++ int i; ++-#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) +++#define ATH_STA_2_TID(_sta, _tidno) ((struct ath_atx_tid *)(_sta)->txq[_tidno]->drv_priv) +++#define ATH_VIF_2_TID(_vif) ((struct ath_atx_tid *)(_vif)->txq->drv_priv) +++#define ATH_AN_2_TID(_an, _tidno) ((_an)->sta ? ATH_STA_2_TID((_an)->sta, _tidno) : ATH_VIF_2_TID((_an)->vif)) + -+- for (i = 0; i < AR_NUM_QCU; i++) { -+- npend = ath9k_hw_numtxpending(ah, i); -+- if (npend) -+- break; -++ if (type == ATH9K_RESET_COLD) -++ return true; -++ -++ if (AR_SREV_9550(ah)) -++ return true; -++ -++ /* AR9330 WAR: -++ * call external reset function to reset WMAC if: -++ * - doing a cold reset -++ * - we have pending frames in the TX queues. -++ */ -++ if (AR_SREV_9330(ah)) { -++ for (i = 0; i < AR_NUM_QCU; i++) { -++ if (ath9k_hw_numtxpending(ah, i)) -++ return true; -++ } -+ } ++ #define IS_HT_RATE(rate) (rate & 0x80) ++ #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) ++@@ -164,7 +165,6 @@ struct ath_txq { ++ spinlock_t axq_lock; ++ u32 axq_depth; ++ u32 axq_ampdu_depth; ++- bool stopped; ++ bool axq_tx_inprogress; ++ struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; ++ u8 txq_headidx; ++@@ -232,7 +232,6 @@ struct ath_buf { + -+- if (ah->external_reset && -+- (npend || type == ATH9K_RESET_COLD)) { -+- int reset_err = 0; -++ return false; -++} ++ struct ath_atx_tid { ++ struct list_head list; ++- struct sk_buff_head buf_q; ++ struct sk_buff_head retry_q; ++ struct ath_node *an; ++ struct ath_txq *txq; ++@@ -247,13 +246,13 @@ struct ath_atx_tid { ++ s8 bar_index; ++ bool active; ++ bool clear_ps_filter; +++ bool has_queued; ++ }; + -+- ath_dbg(ath9k_hw_common(ah), RESET, -+- "reset MAC via external reset\n"); -++static bool ath9k_hw_external_reset(struct ath_hw *ah, int type) -++{ -++ int err; ++ struct ath_node { ++ struct ath_softc *sc; ++ struct ieee80211_sta *sta; /* station struct we're part of */ ++ struct ieee80211_vif *vif; /* interface with which we're associated */ ++- struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; + -+- reset_err = ah->external_reset(); -+- if (reset_err) { -+- ath_err(ath9k_hw_common(ah), -+- "External reset failed, err=%d\n", -+- reset_err); -+- return false; -+- } -++ if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type)) -++ return true; ++ u16 maxampdu; ++ u8 mpdudensity; ++@@ -276,7 +275,6 @@ struct ath_tx_control { ++ struct ath_node *an; ++ struct ieee80211_sta *sta; ++ u8 paprd; ++- bool force_channel; ++ }; + -+- REG_WRITE(ah, AR_RTC_RESET, 1); -++ ath_dbg(ath9k_hw_common(ah), RESET, -++ "reset MAC via external reset\n"); -++ -++ err = ah->external_reset(); -++ if (err) { -++ ath_err(ath9k_hw_common(ah), -++ "External reset failed, err=%d\n", err); -++ return false; -++ } -++ -++ if (AR_SREV_9550(ah)) { -++ REG_WRITE(ah, AR_RTC_RESET, 0); -++ udelay(10); -+ } + -++ REG_WRITE(ah, AR_RTC_RESET, 1); -++ udelay(10); -++ -+ return true; ++@@ -293,7 +291,6 @@ struct ath_tx { ++ struct ath_descdma txdma; ++ struct ath_txq *txq_map[IEEE80211_NUM_ACS]; ++ struct ath_txq *uapsdq; ++- u32 txq_max_pending[IEEE80211_NUM_ACS]; ++ u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32]; ++ }; ++ ++@@ -585,6 +582,7 @@ void ath9k_release_buffered_frames(struc ++ u16 tids, int nframes, ++ enum ieee80211_frame_release_type reason, ++ bool more_data); +++void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue); ++ ++ /********/ ++ /* VIFs */ ++--- a/drivers/net/wireless/ath/ath9k/channel.c +++++ b/drivers/net/wireless/ath/ath9k/channel.c ++@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct a ++ goto error; ++ ++ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; ++- txctl.force_channel = true; ++ if (ath_tx_start(sc->hw, skb, &txctl)) ++ goto error; ++ ++@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath ++ memset(&txctl, 0, sizeof(txctl)); ++ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; ++ txctl.sta = sta; ++- txctl.force_channel = true; ++ if (ath_tx_start(sc->hw, skb, &txctl)) { ++ ieee80211_free_txskb(sc->hw, skb); ++ return false; ++--- a/drivers/net/wireless/ath/ath9k/debug.c +++++ b/drivers/net/wireless/ath/ath9k/debug.c ++@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_fil ++ PR("MPDUs XRetried: ", xretries); ++ PR("Aggregates: ", a_aggr); ++ PR("AMPDUs Queued HW:", a_queued_hw); ++- PR("AMPDUs Queued SW:", a_queued_sw); ++ PR("AMPDUs Completed:", a_completed); ++ PR("AMPDUs Retried: ", a_retries); ++ PR("AMPDUs XRetried: ", a_xretries); ++@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc ++ seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum); ++ seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth); ++ seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth); ++- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames); ++- seq_printf(file, "%s: %d\n", "stopped", txq->stopped); +++ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames); ++ ++ ath_txq_unlock(sc, txq); + } ++@@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[] ++ AMKSTR(d_tx_mpdu_xretries), ++ AMKSTR(d_tx_aggregates), ++ AMKSTR(d_tx_ampdus_queued_hw), ++- AMKSTR(d_tx_ampdus_queued_sw), ++ AMKSTR(d_tx_ampdus_completed), ++ AMKSTR(d_tx_ampdu_retries), ++ AMKSTR(d_tx_ampdu_xretries), ++@@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211 ++ AWDATA(xretries); ++ AWDATA(a_aggr); ++ AWDATA(a_queued_hw); ++- AWDATA(a_queued_sw); ++ AWDATA(a_completed); ++ AWDATA(a_retries); ++ AWDATA(a_xretries); ++@@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah) ++ read_file_xmit); ++ debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy, ++ read_file_queues); ++- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++- &sc->tx.txq_max_pending[IEEE80211_AC_BK]); ++- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++- &sc->tx.txq_max_pending[IEEE80211_AC_BE]); ++- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++- &sc->tx.txq_max_pending[IEEE80211_AC_VI]); ++- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, ++- &sc->tx.txq_max_pending[IEEE80211_AC_VO]); ++ debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, ++ read_file_misc); ++ debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy, ++--- a/drivers/net/wireless/ath/ath9k/debug.h +++++ b/drivers/net/wireless/ath/ath9k/debug.h ++@@ -147,7 +147,6 @@ struct ath_interrupt_stats { ++ * @completed: Total MPDUs (non-aggr) completed ++ * @a_aggr: Total no. of aggregates queued ++ * @a_queued_hw: Total AMPDUs queued to hardware ++- * @a_queued_sw: Total AMPDUs queued to software queues ++ * @a_completed: Total AMPDUs completed ++ * @a_retries: No. of AMPDUs retried (SW) ++ * @a_xretries: No. of AMPDUs dropped due to xretries ++@@ -174,7 +173,6 @@ struct ath_tx_stats { ++ u32 xretries; ++ u32 a_aggr; ++ u32 a_queued_hw; ++- u32 a_queued_sw; ++ u32 a_completed; ++ u32 a_retries; ++ u32 a_xretries; ++--- a/drivers/net/wireless/ath/ath9k/debug_sta.c +++++ b/drivers/net/wireless/ath/ath9k/debug_sta.c ++@@ -52,8 +52,8 @@ static ssize_t read_file_node_aggr(struc ++ "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", ++ "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); + -+@@ -1360,24 +1377,23 @@ static bool ath9k_hw_set_reset(struct at -+ rst_flags |= AR_RTC_RC_MAC_COLD; ++- for (tidno = 0, tid = &an->tid[tidno]; ++- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { +++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { +++ tid = ATH_STA_2_TID(an->sta, tidno); ++ txq = tid->txq; ++ ath_txq_lock(sc, txq); ++ if (tid->active) { ++--- a/drivers/net/wireless/ath/ath9k/init.c +++++ b/drivers/net/wireless/ath/ath9k/init.c ++@@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_ ++ for (i = 0; i < IEEE80211_NUM_ACS; i++) { ++ sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); ++ sc->tx.txq_map[i]->mac80211_qnum = i; ++- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; + } ++ return 0; ++ } ++@@ -873,6 +872,7 @@ static void ath9k_set_hw_capab(struct at ++ hw->max_rate_tries = 10; ++ hw->sta_data_size = sizeof(struct ath_node); ++ hw->vif_data_size = sizeof(struct ath_vif); +++ hw->txq_data_size = sizeof(struct ath_atx_tid); ++ hw->extra_tx_headroom = 4; + -+- if (AR_SREV_9330(ah)) { -+- if (!ath9k_hw_ar9330_reset_war(ah, type)) -+- return false; -+- } -+- -+ if (ath9k_hw_mci_is_enabled(ah)) -+ ar9003_mci_check_gpm_offset(ah); ++ hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; ++--- a/drivers/net/wireless/ath/ath9k/main.c +++++ b/drivers/net/wireless/ath/ath9k/main.c ++@@ -2695,4 +2695,5 @@ struct ieee80211_ops ath9k_ops = { ++ .sw_scan_start = ath9k_sw_scan_start, ++ .sw_scan_complete = ath9k_sw_scan_complete, ++ .get_txpower = ath9k_get_txpower, +++ .wake_tx_queue = ath9k_wake_tx_queue, ++ }; ++--- a/drivers/net/wireless/ath/ath9k/xmit.c +++++ b/drivers/net/wireless/ath/ath9k/xmit.c ++@@ -65,6 +65,8 @@ static struct ath_buf *ath_tx_setup_buff ++ struct ath_txq *txq, ++ struct ath_atx_tid *tid, ++ struct sk_buff *skb); +++static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, +++ struct ath_tx_control *txctl); + -+ /* DMA HALT added to resolve ar9300 and ar9580 bus error during -+- * RTC_RC reg read -++ * RTC_RC reg read. Also needed for AR9550 external reset -+ */ -+- if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { -++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { -+ REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); -+ ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, -+ 20 * AH_WAIT_TIMEOUT); -+- REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); -+ } ++ enum { ++ MCS_HT20, ++@@ -118,6 +120,26 @@ static void ath_tx_queue_tid(struct ath_ ++ list_add_tail(&tid->list, list); ++ } + -++ ath9k_hw_external_reset(ah, type); +++void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) +++{ +++ struct ath_softc *sc = hw->priv; +++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); +++ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; +++ struct ath_txq *txq = tid->txq; ++ -++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) -++ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); +++ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", +++ queue->sta ? queue->sta->addr : queue->vif->addr, +++ tid->tidno); ++ -+ REG_WRITE(ah, AR_RTC_RC, rst_flags); +++ ath_txq_lock(sc, txq); +++ +++ tid->has_queued = true; +++ ath_tx_queue_tid(sc, txq, tid); +++ ath_txq_schedule(sc, txq); +++ +++ ath_txq_unlock(sc, txq); +++} +++ ++ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) ++ { ++ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); ++@@ -160,7 +182,6 @@ static void ath_set_rates(struct ieee802 ++ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, ++ struct sk_buff *skb) ++ { ++- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); ++ struct ath_frame_info *fi = get_frame_info(skb); ++ int q = fi->txq; + -+ REGWRITE_BUFFER_FLUSH(ah); -diff --git a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch b/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch -deleted file mode 100644 -index e7bfb9c..0000000 ---- a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch -+++ /dev/null -@@ -1,317 +0,0 @@ --From: Felix Fietkau <nbd@openwrt.org> --Date: Fri, 5 Feb 2016 01:38:51 +0100 --Subject: [PATCH] mac80211: add A-MSDU tx support -- --Requires software tx queueing support. frag_list support (for zero-copy) --is optional. -- --Signed-off-by: Felix Fietkau <nbd@openwrt.org> ----- -- ----- a/include/net/mac80211.h --+++ b/include/net/mac80211.h --@@ -709,6 +709,7 @@ enum mac80211_tx_info_flags { -- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll -- * frame (PS-Poll or uAPSD). -- * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information --+ * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame -- * -- * These flags are used in tx_info->control.flags. -- */ --@@ -716,6 +717,7 @@ enum mac80211_tx_control_flags { -- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), -- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), -- IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), --+ IEEE80211_TX_CTRL_AMSDU = BIT(3), -- }; -- -- /* --@@ -1728,6 +1730,7 @@ struct ieee80211_sta_rates { -- * size is min(max_amsdu_len, 7935) bytes. -- * Both additional HT limits must be enforced by the low level driver. -- * This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2). --+ * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control. -- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) -- */ -- struct ieee80211_sta { --@@ -1748,6 +1751,7 @@ struct ieee80211_sta { -- bool mfp; -- u8 max_amsdu_subframes; -- u16 max_amsdu_len; --+ u16 max_rc_amsdu_len; -- -- struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; -- --@@ -1961,6 +1965,15 @@ struct ieee80211_txq { -- * order and does not need to manage its own reorder buffer or BA session -- * timeout. -- * --+ * @IEEE80211_HW_TX_AMSDU: Hardware (or driver) supports software aggregated --+ * A-MSDU frames. Requires software tx queueing and fast-xmit support. --+ * When not using minstrel/minstrel_ht rate control, the driver should --+ * limit the maximum A-MSDU size based on the current tx rate by setting --+ * max_rc_amsdu_len in struct ieee80211_sta. --+ * --+ * @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list --+ * skbs, needed for zero-copy software A-MSDU. --+ * -- * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays -- */ -- enum ieee80211_hw_flags { --@@ -1998,6 +2011,8 @@ enum ieee80211_hw_flags { -- IEEE80211_HW_BEACON_TX_STATUS, -- IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR, -- IEEE80211_HW_SUPPORTS_REORDERING_BUFFER, --+ IEEE80211_HW_TX_AMSDU, --+ IEEE80211_HW_TX_FRAG_LIST, -- -- /* keep last, obviously */ -- NUM_IEEE80211_HW_FLAGS --@@ -2070,6 +2085,9 @@ enum ieee80211_hw_flags { -- * size is smaller (an example is LinkSys WRT120N with FW v1.0.07 -- * build 002 Jun 18 2012). -- * --+ * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum --+ * of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list. --+ * -- * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX -- * (if %IEEE80211_HW_QUEUE_CONTROL is set) -- * --@@ -2124,6 +2142,7 @@ struct ieee80211_hw { -- u8 max_rate_tries; -- u8 max_rx_aggregation_subframes; -- u8 max_tx_aggregation_subframes; --+ u8 max_tx_fragments; -- u8 offchannel_tx_hw_queue; -- u8 radiotap_mcs_details; -- u16 radiotap_vht_details; ----- a/net/mac80211/agg-tx.c --+++ b/net/mac80211/agg-tx.c --@@ -935,6 +935,7 @@ void ieee80211_process_addba_resp(struct -- size_t len) -- { -- struct tid_ampdu_tx *tid_tx; --+ struct ieee80211_txq *txq; -- u16 capab, tid; -- u8 buf_size; -- bool amsdu; --@@ -945,6 +946,10 @@ void ieee80211_process_addba_resp(struct -- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; -- buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes); -- --+ txq = sta->sta.txq[tid]; --+ if (!amsdu && txq) --+ set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags); --+ -- mutex_lock(&sta->ampdu_mlme.mtx); -- -- tid_tx = rcu_dereference_protected_tid_tx(sta, tid); ----- a/net/mac80211/debugfs.c --+++ b/net/mac80211/debugfs.c --@@ -127,6 +127,8 @@ static const char *hw_flag_names[NUM_IEE -- FLAG(BEACON_TX_STATUS), -- FLAG(NEEDS_UNIQUE_STA_ADDR), -- FLAG(SUPPORTS_REORDERING_BUFFER), --+ FLAG(TX_AMSDU), --+ FLAG(TX_FRAG_LIST), -- -- /* keep last for the build bug below */ -- (void *)0x1 ----- a/net/mac80211/ieee80211_i.h --+++ b/net/mac80211/ieee80211_i.h --@@ -799,6 +799,7 @@ struct mac80211_qos_map { -- enum txq_info_flags { -- IEEE80211_TXQ_STOP, -- IEEE80211_TXQ_AMPDU, --+ IEEE80211_TXQ_NO_AMSDU, -- }; -- -- struct txq_info { ----- a/net/mac80211/tx.c --+++ b/net/mac80211/tx.c --@@ -1318,6 +1318,10 @@ struct sk_buff *ieee80211_tx_dequeue(str -- out: -- spin_unlock_bh(&txqi->queue.lock); -- --+ if (skb && skb_has_frag_list(skb) && --+ !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) --+ skb_linearize(skb); --+ -- return skb; -- } -- EXPORT_SYMBOL(ieee80211_tx_dequeue); --@@ -2757,6 +2761,163 @@ void ieee80211_clear_fast_xmit(struct st -- kfree_rcu(fast_tx, rcu_head); -- } -- --+static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, --+ struct sk_buff *skb, int headroom, --+ int *subframe_len) --+{ --+ int amsdu_len = *subframe_len + sizeof(struct ethhdr); --+ int padding = (4 - amsdu_len) & 3; --+ --+ if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) { --+ I802_DEBUG_INC(local->tx_expand_skb_head); --+ --+ if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) { --+ wiphy_debug(local->hw.wiphy, --+ "failed to reallocate TX buffer\n"); --+ return false; --+ } --+ } --+ --+ if (padding) { --+ *subframe_len += padding; --+ memset(skb_put(skb, padding), 0, padding); --+ } --+ --+ return true; --+} --+ --+static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata, --+ struct ieee80211_fast_tx *fast_tx, --+ struct sk_buff *skb) --+{ --+ struct ieee80211_local *local = sdata->local; --+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --+ struct ieee80211_hdr *hdr; --+ struct ethhdr amsdu_hdr; --+ int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header); --+ int subframe_len = skb->len - hdr_len; --+ void *data; --+ u8 *qc; --+ --+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) --+ return false; --+ --+ if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) --+ return true; --+ --+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr), --+ &subframe_len)) --+ return false; --+ --+ amsdu_hdr.h_proto = cpu_to_be16(subframe_len); --+ memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN); --+ memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN); --+ --+ data = skb_push(skb, sizeof(amsdu_hdr)); --+ memmove(data, data + sizeof(amsdu_hdr), hdr_len); --+ memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr)); --+ --+ hdr = data; --+ qc = ieee80211_get_qos_ctl(hdr); --+ *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; --+ --+ info->control.flags |= IEEE80211_TX_CTRL_AMSDU; --+ --+ return true; --+} --+ --+static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, --+ struct sta_info *sta, --+ struct ieee80211_fast_tx *fast_tx, --+ struct sk_buff *skb) --+{ --+ struct ieee80211_local *local = sdata->local; --+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; --+ struct ieee80211_txq *txq = sta->sta.txq[tid]; --+ struct txq_info *txqi; --+ struct sk_buff **frag_tail, *head; --+ int subframe_len = skb->len - ETH_ALEN; --+ u8 max_subframes = sta->sta.max_amsdu_subframes; --+ int max_frags = local->hw.max_tx_fragments; --+ int max_amsdu_len = sta->sta.max_amsdu_len; --+ __be16 len; --+ void *data; --+ bool ret = false; --+ int n = 1, nfrags; --+ --+ if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) --+ return false; --+ --+ if (!txq) --+ return false; --+ --+ txqi = to_txq_info(txq); --+ if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags)) --+ return false; --+ --+ if (sta->sta.max_rc_amsdu_len) --+ max_amsdu_len = min_t(int, max_amsdu_len, --+ sta->sta.max_rc_amsdu_len); --+ --+ spin_lock_bh(&txqi->queue.lock); --+ --+ head = skb_peek_tail(&txqi->queue); --+ if (!head) --+ goto out; --+ --+ if (skb->len + head->len > max_amsdu_len) --+ goto out; --+ --+ /* --+ * HT A-MPDU limits maximum MPDU size to 4095 bytes. Since aggregation --+ * sessions are started/stopped without txq flush, use the limit here --+ * to avoid having to de-aggregate later. --+ */ --+ if (skb->len + head->len > 4095 && --+ !sta->sta.vht_cap.vht_supported) --+ goto out; --+ --+ if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head)) --+ goto out; --+ --+ nfrags = 1 + skb_shinfo(skb)->nr_frags; --+ nfrags += 1 + skb_shinfo(head)->nr_frags; --+ frag_tail = &skb_shinfo(head)->frag_list; --+ while (*frag_tail) { --+ nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags; --+ frag_tail = &(*frag_tail)->next; --+ n++; --+ } --+ --+ if (max_subframes && n > max_subframes) --+ goto out; --+ --+ if (max_frags && nfrags > max_frags) --+ goto out; --+ --+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2, --+ &subframe_len)) --+ return false; --+ --+ ret = true; --+ data = skb_push(skb, ETH_ALEN + 2); --+ memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN); --+ --+ data += 2 * ETH_ALEN; --+ len = cpu_to_be16(subframe_len); --+ memcpy(data, &len, 2); --+ memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); --+ --+ head->len += skb->len; --+ head->data_len += skb->len; --+ *frag_tail = skb; --+ --+out: --+ spin_unlock_bh(&txqi->queue.lock); --+ --+ return ret; --+} --+ -- static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -- struct net_device *dev, struct sta_info *sta, -- struct ieee80211_fast_tx *fast_tx, --@@ -2811,6 +2972,10 @@ static bool ieee80211_xmit_fast(struct i -- -- ieee80211_tx_stats(dev, skb->len + extra_head); -- --+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && --+ ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) --+ return true; --+ -- /* will not be crypto-handled beyond what we do here, so use false -- * as the may-encrypt argument for the resize to not account for -- * more room than we already have in 'extra_head' -diff --git a/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch b/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch -deleted file mode 100644 -index 9277b2c..0000000 ---- a/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch -+++ /dev/null -@@ -1,64 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Wed, 20 Jan 2016 16:46:04 +0100 --Subject: [PATCH] brcmfmac: fix setting primary channel for 80 MHz width --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --First of all it changes the way we calculate primary channel offset. If --we use e.g. 80 MHz channel with primary frequency 5180 MHz (which means --center frequency is 5210 MHz) it makes sense to calculate primary offset --as -30 MHz. --Then it fixes values we compare primary_offset with. We were comparing --offset in MHz against -2 or 2 which was resulting in picking a wrong --primary channel. -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c --@@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct br -- brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n", -- ch->chan->center_freq, ch->center_freq1, ch->width); -- ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1); --- primary_offset = ch->center_freq1 - ch->chan->center_freq; --+ primary_offset = ch->chan->center_freq - ch->center_freq1; -- switch (ch->width) { -- case NL80211_CHAN_WIDTH_20: -- case NL80211_CHAN_WIDTH_20_NOHT: --@@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct br -- break; -- case NL80211_CHAN_WIDTH_40: -- ch_inf.bw = BRCMU_CHAN_BW_40; --- if (primary_offset < 0) --+ if (primary_offset > 0) -- ch_inf.sb = BRCMU_CHAN_SB_U; -- else -- ch_inf.sb = BRCMU_CHAN_SB_L; -- break; -- case NL80211_CHAN_WIDTH_80: -- ch_inf.bw = BRCMU_CHAN_BW_80; --- if (primary_offset < 0) { --- if (primary_offset < -CH_10MHZ_APART) --- ch_inf.sb = BRCMU_CHAN_SB_UU; --- else --- ch_inf.sb = BRCMU_CHAN_SB_UL; --- } else { --- if (primary_offset > CH_10MHZ_APART) --- ch_inf.sb = BRCMU_CHAN_SB_LL; --- else --- ch_inf.sb = BRCMU_CHAN_SB_LU; --- } --+ if (primary_offset == -30) --+ ch_inf.sb = BRCMU_CHAN_SB_LL; --+ else if (primary_offset == -10) --+ ch_inf.sb = BRCMU_CHAN_SB_LU; --+ else if (primary_offset == 10) --+ ch_inf.sb = BRCMU_CHAN_SB_UL; --+ else --+ ch_inf.sb = BRCMU_CHAN_SB_UU; -- break; -- case NL80211_CHAN_WIDTH_80P80: -- case NL80211_CHAN_WIDTH_160: -diff --git a/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch b/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch -deleted file mode 100644 -index d7018da..0000000 ---- a/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch -+++ /dev/null -@@ -1,51 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Tue, 26 Jan 2016 17:57:01 +0100 --Subject: [PATCH] brcmfmac: analyze descriptors of current component only --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --So far we were looking for address descriptors without a check for --crossing current component border. In case of dealing with unsupported --descriptor or descriptor missing at all the code would incorrectly get --data from another component. -- --Consider this binary-described component from BCM4366 EROM: --4bf83b01 TAG==CI CID==0x83b --20080201 TAG==CI PORTS==0+1 WRAPPERS==0+1 --18400035 TAG==ADDR SZ_SZD TYPE_SLAVE --00050000 --18107085 TAG==ADDR SZ_4K TYPE_SWRAP -- --Driver was assigning invalid base address to this core: --brcmfmac: [6 ] core 0x83b:32 base 0x18109000 wrap 0x18107000 --which came from totally different component defined in EROM: --43b36701 TAG==CI CID==0x367 --00000201 TAG==CI PORTS==0+1 WRAPPERS==0+0 --18109005 TAG==ADDR SZ_4K TYPE_SLAVE -- --This change will also allow us to support components without wrapper --address in the future. -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --@@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(st -- *eromaddr -= 4; -- return -EFAULT; -- } --- } while (desc != DMP_DESC_ADDRESS); --+ } while (desc != DMP_DESC_ADDRESS && --+ desc != DMP_DESC_COMPONENT); --+ --+ /* stop if we crossed current component border */ --+ if (desc == DMP_DESC_COMPONENT) { --+ *eromaddr -= 4; --+ return 0; --+ } -- -- /* skip upper 32-bit address descriptor */ -- if (val & DMP_DESC_ADDRSIZE_GT32) -diff --git a/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch b/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch -deleted file mode 100644 -index 045ab49..0000000 ---- a/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch -+++ /dev/null -@@ -1,28 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Tue, 26 Jan 2016 17:57:02 +0100 --Subject: [PATCH] brcmfmac: allow storing PMU core without wrapper address --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --Separated PMU core can be found in new devices and should be used for --accessing PMU registers (which were routed through ChipCommon so far). --This core is one of exceptions that doesn't have or need wrapper address --to be still safely accessible. -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --@@ -883,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcm -- rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; -- -- /* need core with ports */ --- if (nmw + nsw == 0) --+ if (nmw + nsw == 0 && --+ id != BCMA_CORE_PMU) -- continue; -- -- /* try to obtain register address info */ -diff --git a/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch b/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch -deleted file mode 100644 -index 7b7ba4f..0000000 ---- a/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch -+++ /dev/null -@@ -1,43 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Tue, 26 Jan 2016 17:57:03 +0100 --Subject: [PATCH] brcmfmac: read extended capabilities of ChipCommon core --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --This is an extra bitfield with info about some present hardware. -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --@@ -1025,6 +1025,9 @@ static int brcmf_chip_setup(struct brcmf -- /* get chipcommon capabilites */ -- pub->cc_caps = chip->ops->read32(chip->ctx, -- CORE_CC_REG(base, capabilities)); --+ pub->cc_caps_ext = chip->ops->read32(chip->ctx, --+ CORE_CC_REG(base, --+ capabilities_ext)); -- -- /* get pmu caps & rev */ -- if (pub->cc_caps & CC_CAP_PMU) { ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h --@@ -27,6 +27,7 @@ -- * @chip: chip identifier. -- * @chiprev: chip revision. -- * @cc_caps: chipcommon core capabilities. --+ * @cc_caps_ext: chipcommon core extended capabilities. -- * @pmucaps: PMU capabilities. -- * @pmurev: PMU revision. -- * @rambase: RAM base address (only applicable for ARM CR4 chips). --@@ -38,6 +39,7 @@ struct brcmf_chip { -- u32 chip; -- u32 chiprev; -- u32 cc_caps; --+ u32 cc_caps_ext; -- u32 pmucaps; -- u32 pmurev; -- u32 rambase; -diff --git a/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch b/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch -deleted file mode 100644 -index 2af6fd9..0000000 ---- a/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch -+++ /dev/null -@@ -1,148 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Tue, 26 Jan 2016 17:57:04 +0100 --Subject: [PATCH] brcmfmac: access PMU registers using standalone PMU core if -- available --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --On recent Broadcom chipsets PMU is present as separated core and it --can't be accessed using ChipCommon anymore as it fails with e.g.: --[ 18.198412] Unhandled fault: imprecise external abort (0x1406) at 0xb6da200f -- --Add a new helper function that will return a proper core that should be --used for accessing PMU registers. -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c --@@ -1014,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf -- { -- struct brcmf_chip *pub; -- struct brcmf_core_priv *cc; --+ struct brcmf_core *pmu; -- u32 base; -- u32 val; -- int ret = 0; --@@ -1030,9 +1031,10 @@ static int brcmf_chip_setup(struct brcmf -- capabilities_ext)); -- -- /* get pmu caps & rev */ --+ pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */ -- if (pub->cc_caps & CC_CAP_PMU) { -- val = chip->ops->read32(chip->ctx, --- CORE_CC_REG(base, pmucapabilities)); --+ CORE_CC_REG(pmu->base, pmucapabilities)); -- pub->pmurev = val & PCAP_REV_MASK; -- pub->pmucaps = val; -- } --@@ -1131,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipco -- return &cc->pub; -- } -- --+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub) --+{ --+ struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub); --+ struct brcmf_core *pmu; --+ --+ /* See if there is separated PMU core available */ --+ if (cc->rev >= 35 && --+ pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) { --+ pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU); --+ if (pmu) --+ return pmu; --+ } --+ --+ /* Fallback to ChipCommon core for older hardware */ --+ return cc; --+} --+ -- bool brcmf_chip_iscoreup(struct brcmf_core *pub) -- { -- struct brcmf_core_priv *core; --@@ -1301,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_ -- { -- u32 base, addr, reg, pmu_cc3_mask = ~0; -- struct brcmf_chip_priv *chip; --+ struct brcmf_core *pmu = brcmf_chip_get_pmu(pub); -- -- brcmf_dbg(TRACE, "Enter\n"); -- --@@ -1320,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_ -- case BRCM_CC_4335_CHIP_ID: -- case BRCM_CC_4339_CHIP_ID: -- /* read PMU chipcontrol register 3 */ --- addr = CORE_CC_REG(base, chipcontrol_addr); --+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr); -- chip->ops->write32(chip->ctx, addr, 3); --- addr = CORE_CC_REG(base, chipcontrol_data); --+ addr = CORE_CC_REG(pmu->base, chipcontrol_data); -- reg = chip->ops->read32(chip->ctx, addr); -- return (reg & pmu_cc3_mask) != 0; -- case BRCM_CC_43430_CHIP_ID: --@@ -1330,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_ -- reg = chip->ops->read32(chip->ctx, addr); -- return reg != 0; -- default: --- addr = CORE_CC_REG(base, pmucapabilities_ext); --+ addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); -- reg = chip->ops->read32(chip->ctx, addr); -- if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) -- return false; -- --- addr = CORE_CC_REG(base, retention_ctl); --+ addr = CORE_CC_REG(pmu->base, retention_ctl); -- reg = chip->ops->read32(chip->ctx, addr); -- return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | -- PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h --@@ -85,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(voi -- void brcmf_chip_detach(struct brcmf_chip *chip); -- struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); -- struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); --+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub); -- bool brcmf_chip_iscoreup(struct brcmf_core *core); -- void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); -- void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c --@@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcm -- const struct sdiod_drive_str *str_tab = NULL; -- u32 str_mask; -- u32 str_shift; --- u32 base; -- u32 i; -- u32 drivestrength_sel = 0; -- u32 cc_data_temp; --@@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcm -- } -- -- if (str_tab != NULL) { --+ struct brcmf_core *pmu = brcmf_chip_get_pmu(ci); --+ -- for (i = 0; str_tab[i].strength != 0; i++) { -- if (drivestrength >= str_tab[i].strength) { -- drivestrength_sel = str_tab[i].sel; -- break; -- } -- } --- base = brcmf_chip_get_chipcommon(ci)->base; --- addr = CORE_CC_REG(base, chipcontrol_addr); --+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr); -- brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); -- cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); -- cc_data_temp &= ~str_mask; --@@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi -- goto fail; -- -- /* set PMUControl so a backplane reset does PMU state reload */ --- reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base, --- pmucontrol); --+ reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); -- reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); -- if (err) -- goto fail; -diff --git a/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch b/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch -deleted file mode 100644 -index 35887fc..0000000 ---- a/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch -+++ /dev/null -@@ -1,38 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Tue, 26 Jan 2016 17:57:05 +0100 --Subject: [PATCH] brcmfmac: add support for 14e4:4365 PCI ID with BCM4366 -- chipset --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --On Broadcom ARM routers BCM4366 cards are available with 14e4:4365 ID. --Unfortunately this ID was already used by Broadcom for cards with --BCM43142, a totally different chipset requiring SoftMAC driver. To avoid --a conflict between brcmfmac and bcma use more specific ID entry with --subvendor and subdevice specified. -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c --@@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pci -- -- #define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ -- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } --+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \ --+ BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ --+ subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } -- -- static struct pci_device_id brcmf_pcie_devid_table[] = { -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), --@@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_d -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID), -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID), -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID), --+ BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365), -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID), -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), -- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), -diff --git a/package/kernel/mac80211/patches/323-ath9k-Fix-programming-of-minCCA-power-threshold.patch b/package/kernel/mac80211/patches/323-ath9k-Fix-programming-of-minCCA-power-threshold.patch -new file mode 100644 -index 0000000..59ac29b ---- /dev/null -+++ b/package/kernel/mac80211/patches/323-ath9k-Fix-programming-of-minCCA-power-threshold.patch -@@ -0,0 +1,26 @@ -+From: Sven Eckelmann <sven@narfation.org> -+Date: Fri, 17 Jun 2016 11:58:20 +0200 -+Subject: [PATCH] ath9k: Fix programming of minCCA power threshold -+ -+The function ar9003_hw_apply_minccapwr_thresh takes as second parameter not -+a pointer to the channel but a boolean value describing whether the channel -+is 2.4GHz or not. This broke (according to the origin commit) the ETSI -+regulatory compliance on 5GHz channels. -+ -+Fixes: 3533bf6b15a0 ("ath9k: Fix regulatory compliance") -+Signed-off-by: Sven Eckelmann <sven@narfation.org> -+Cc: Simon Wunderlich <sw@simonwunderlich.de> -+Cc: Sujith Manoharan <c_manoha@qca.qualcomm.com> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c -++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c -+@@ -4175,7 +4175,7 @@ static void ath9k_hw_ar9300_set_board_va -+ if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah)) -+ ar9003_hw_internal_regulator_apply(ah); -+ ar9003_hw_apply_tuning_caps(ah); -+- ar9003_hw_apply_minccapwr_thresh(ah, chan); -++ ar9003_hw_apply_minccapwr_thresh(ah, is2ghz); -+ ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz); -+ ar9003_hw_thermometer_apply(ah); -+ ar9003_hw_thermo_cal_apply(ah); -diff --git a/package/kernel/mac80211/patches/324-ath9k_hw-fix-spectral-scan-on-AR9285-and-newer.patch b/package/kernel/mac80211/patches/324-ath9k_hw-fix-spectral-scan-on-AR9285-and-newer.patch -new file mode 100644 -index 0000000..b6f4868 ---- /dev/null -+++ b/package/kernel/mac80211/patches/324-ath9k_hw-fix-spectral-scan-on-AR9285-and-newer.patch -@@ -0,0 +1,86 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Mon, 11 Jul 2016 10:34:37 +0200 -+Subject: [PATCH] ath9k_hw: fix spectral scan on AR9285 and newer -+ -+The register layout of AR_PHY_SPECTRAL_SCAN has changed, only AR9280 -+uses the old layout -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c -++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c -+@@ -476,6 +476,7 @@ static void ar9002_hw_set_bt_ant_diversi -+ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, -+ struct ath_spec_scan *param) -+ { -++ u32 repeat_bit; -+ u8 count; -+ -+ if (!param->enabled) { -+@@ -486,12 +487,15 @@ static void ar9002_hw_spectral_scan_conf -+ REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); -+ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); -+ -++ if (AR_SREV_9280(ah)) -++ repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT; -++ else -++ repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI; -++ -+ if (param->short_repeat) -+- REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, -+- AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); -++ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); -+ else -+- REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, -+- AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); -++ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); -+ -+ /* on AR92xx, the highest bit of count will make the the chip send -+ * spectral samples endlessly. Check if this really was intended, -+@@ -499,15 +503,25 @@ static void ar9002_hw_spectral_scan_conf -+ */ -+ count = param->count; -+ if (param->endless) { -+- if (AR_SREV_9271(ah)) -+- count = 0; -+- else -++ if (AR_SREV_9280(ah)) -+ count = 0x80; -++ else -++ count = 0; -+ } else if (count & 0x80) -+ count = 0x7f; -++ else if (!count) -++ count = 1; -++ -++ if (AR_SREV_9280(ah)) { -++ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, -++ AR_PHY_SPECTRAL_SCAN_COUNT, count); -++ } else { -++ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, -++ AR_PHY_SPECTRAL_SCAN_COUNT_KIWI, count); -++ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, -++ AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT); -++ } -+ -+- REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, -+- AR_PHY_SPECTRAL_SCAN_COUNT, count); -+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, -+ AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); -+ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, -+--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h -++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h -+@@ -177,8 +177,11 @@ -+ #define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 -+ #define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ -+ #define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 -++#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000 /* Number of reports, reg 68, bits 16-27*/ -++#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16 -+ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ -+-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ -++#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000 /* Short repeat, reg 68, bit 28*/ -++#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT 0x40000000 -+ -+ #define AR_PHY_RX_DELAY 0x9914 -+ #define AR_PHY_SEARCH_START_DELAY 0x9918 -diff --git a/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch b/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch -deleted file mode 100644 -index 6ce60f1..0000000 ---- a/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch -+++ /dev/null -@@ -1,32 +0,0 @@ --From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> --Date: Sun, 31 Jan 2016 12:14:34 +0100 --Subject: [PATCH] brcmfmac: treat NULL character in NVRAM as separator --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --Platform NVRAM (stored on a flash partition) has entries separated by a --NULL (\0) char. Our parsing code switches from VALUE state to IDLE --whenever it meets a NULL (\0). When that happens our IDLE handler should --simply consume it and analyze whatever is placed ahead. -- --This fixes harmless warnings spamming debugging output: --[ 155.165624] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=20: ignoring invalid character --[ 155.180806] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=44: ignoring invalid character --[ 155.195971] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=63: ignoring invalid character -- --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c --@@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvr -- c = nvp->data[nvp->pos]; -- if (c == '\n') -- return COMMENT; --- if (is_whitespace(c)) --+ if (is_whitespace(c) || c == '\0') -- goto proceed; -- if (c == '#') -- return COMMENT; -diff --git a/package/kernel/mac80211/patches/325-ath9k_hw-fix-duplicate-and-partially-wrong-definitio.patch b/package/kernel/mac80211/patches/325-ath9k_hw-fix-duplicate-and-partially-wrong-definitio.patch -new file mode 100644 -index 0000000..6685f33 ---- /dev/null -+++ b/package/kernel/mac80211/patches/325-ath9k_hw-fix-duplicate-and-partially-wrong-definitio.patch -@@ -0,0 +1,57 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Mon, 11 Jul 2016 11:31:39 +0200 -+Subject: [PATCH] ath9k_hw: fix duplicate (and partially wrong) definition -+ of AR_CH0_THERM -+ -+AR_PHY_65NM_CH0_THERM and AR_CH0_THERM were supposed to refer to the -+same register, however they had different SREV checks. -+ -+Remove the duplicate and use the checks. Since there were other SREV -+checks present in the only place that uses this, this will probaby not -+affect runtime behavior. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h -++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h -+@@ -689,13 +689,6 @@ -+ #define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) -+ #define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) -+ -+-#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ -+- ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) -+-#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 -+-#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 -+-#define AR_CH0_THERM_XPASHORT2GND 0x4 -+-#define AR_CH0_THERM_XPASHORT2GND_S 2 -+- -+ #define AR_SWITCH_TABLE_COM_ALL (0xffff) -+ #define AR_SWITCH_TABLE_COM_ALL_S (0) -+ #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) -+@@ -712,15 +705,17 @@ -+ #define AR_SWITCH_TABLE_ALL (0xfff) -+ #define AR_SWITCH_TABLE_ALL_S (0) -+ -+-#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ -+- ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) -++#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ -++ ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) -++#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 -++#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 -++#define AR_CH0_THERM_XPASHORT2GND 0x4 -++#define AR_CH0_THERM_XPASHORT2GND_S 2 -+ -+-#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 -+-#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 -+-#define AR_PHY_65NM_CH0_THERM_START 0x20000000 -+-#define AR_PHY_65NM_CH0_THERM_START_S 29 -+-#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 -+-#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 -++#define AR_CH0_THERM_LOCAL 0x80000000 -++#define AR_CH0_THERM_START 0x20000000 -++#define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00 -++#define AR_CH0_THERM_SAR_ADC_OUT_S 8 -+ -+ #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ -+ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) -diff --git a/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch b/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch -deleted file mode 100644 -index 012dea1..0000000 ---- a/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch -+++ /dev/null -@@ -1,41 +0,0 @@ --From: Sjoerd Simons <sjoerd.simons@collabora.co.uk> --Date: Mon, 25 Jan 2016 11:47:29 +0100 --Subject: [PATCH] brcmfmac: sdio: Increase the default timeouts a bit -- --On a Radxa Rock2 board with a Ampak AP6335 (Broadcom 4339 core) it seems --the card responds very quickly most of the time, unfortunately during --initialisation it sometimes seems to take just a bit over 2 seconds to --respond. -- --This results intialization failing with message like: -- brcmf_c_preinit_dcmds: Retreiving cur_etheraddr failed, -52 -- brcmf_bus_start: failed: -52 -- brcmf_sdio_firmware_callback: dongle is not responding -- --Increasing the timeout to allow for a bit more headroom allows the --card to initialize reliably. -- --A quick search online after diagnosing/fixing this showed that Google --has a similar patch in their ChromeOS tree, so this doesn't seem --specific to the board I'm using. -- --Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk> --Reviewed-by: Julian Calaby <julian.calaby@gmail.com> --Acked-by: Arend van Spriel <arend@broadcom.com> --Reviewed-by: Douglas Anderson <dianders@chromium.org> --Signed-off-by: Kalle Valo <kvalo@codeaurora.org> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c --@@ -45,8 +45,8 @@ -- #include "chip.h" -- #include "firmware.h" -- ---#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000) ---#define CTL_DONE_TIMEOUT msecs_to_jiffies(2000) --+#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) --+#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) -- -- #ifdef DEBUG -- -diff --git a/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch b/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch -deleted file mode 100644 -index 71f7a40..0000000 ---- a/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch -+++ /dev/null -@@ -1,87 +0,0 @@ --From: Miaoqing Pan <miaoqing@codeaurora.org> --Date: Fri, 5 Feb 2016 09:45:50 +0800 --Subject: [PATCH] ath9k: make NF load complete quickly and reliably -- --Make NF load complete quickly and reliably. NF load execution --is delayed by HW to end of frame if frame Rx or Tx is ongoing. --Increasing timeout to max frame duration. If NF cal is ongoing --before NF load, stop it before load, and restart it afterwards. -- --Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> ----- -- ----- a/drivers/net/wireless/ath/ath9k/calib.c --+++ b/drivers/net/wireless/ath/ath9k/calib.c --@@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s -- u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; -- struct ath_common *common = ath9k_hw_common(ah); -- s16 default_nf = ath9k_hw_get_default_nf(ah, chan); --+ u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL); -- -- if (ah->caldata) -- h = ah->caldata->nfCalHist; --@@ -264,6 +265,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s -- } -- -- /* --+ * stop NF cal if ongoing to ensure NF load completes immediately --+ * (or after end rx/tx frame if ongoing) --+ */ --+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { --+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); --+ REG_RMW_BUFFER_FLUSH(ah); --+ ENABLE_REG_RMW_BUFFER(ah); --+ } --+ --+ /* -- * Load software filtered NF value into baseband internal minCCApwr -- * variable. -- */ --@@ -276,18 +287,33 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s -- -- /* -- * Wait for load to complete, should be fast, a few 10s of us. --- * The max delay was changed from an original 250us to 10000us --- * since 250us often results in NF load timeout and causes deaf --- * condition during stress testing 12/12/2009 --+ * The max delay was changed from an original 250us to 22.2 msec. --+ * This would increase timeout to the longest possible frame --+ * (11n max length 22.1 msec) -- */ --- for (j = 0; j < 10000; j++) { --+ for (j = 0; j < 22200; j++) { -- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & --- AR_PHY_AGC_CONTROL_NF) == 0) --+ AR_PHY_AGC_CONTROL_NF) == 0) -- break; -- udelay(10); -- } -- -- /* --+ * Restart NF so it can continue. --+ */ --+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { --+ ENABLE_REG_RMW_BUFFER(ah); --+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF) --+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, --+ AR_PHY_AGC_CONTROL_ENABLE_NF); --+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF) --+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, --+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF); --+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); --+ REG_RMW_BUFFER_FLUSH(ah); --+ } --+ --+ /* -- * We timed out waiting for the noisefloor to load, probably due to an -- * in-progress rx. Simply return here and allow the load plenty of time -- * to complete before the next calibration interval. We need to avoid --@@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s -- * here, the baseband nf cal will just be capped by our present -- * noisefloor until the next calibration timer. -- */ --- if (j == 10000) { --+ if (j == 22200) { -- ath_dbg(common, ANY, -- "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", -- REG_READ(ah, AR_PHY_AGC_CONTROL)); -diff --git a/package/kernel/mac80211/patches/326-ath9k_hw-simplify-ar9003_hw_per_calibration.patch b/package/kernel/mac80211/patches/326-ath9k_hw-simplify-ar9003_hw_per_calibration.patch -new file mode 100644 -index 0000000..999d993 ---- /dev/null -+++ b/package/kernel/mac80211/patches/326-ath9k_hw-simplify-ar9003_hw_per_calibration.patch -@@ -0,0 +1,88 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Mon, 11 Jul 2016 11:34:47 +0200 -+Subject: [PATCH] ath9k_hw: simplify ar9003_hw_per_calibration -+ -+Reduce indentation, use a variable to save a few pointer dereferences -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c -++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c -+@@ -75,50 +75,49 @@ static bool ar9003_hw_per_calibration(st -+ struct ath9k_cal_list *currCal) -+ { -+ struct ath9k_hw_cal_data *caldata = ah->caldata; -+- /* Cal is assumed not done until explicitly set below */ -+- bool iscaldone = false; -++ const struct ath9k_percal_data *cur_caldata = currCal->calData; -+ -+ /* Calibration in progress. */ -+ if (currCal->calState == CAL_RUNNING) { -+ /* Check to see if it has finished. */ -+- if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { -+- /* -+- * Accumulate cal measures for active chains -+- */ -+- currCal->calData->calCollect(ah); -+- ah->cal_samples++; -++ if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL) -++ return false; -+ -+- if (ah->cal_samples >= -+- currCal->calData->calNumSamples) { -+- unsigned int i, numChains = 0; -+- for (i = 0; i < AR9300_MAX_CHAINS; i++) { -+- if (rxchainmask & (1 << i)) -+- numChains++; -+- } -++ /* -++ * Accumulate cal measures for active chains -++ */ -++ cur_caldata->calCollect(ah); -++ ah->cal_samples++; -+ -+- /* -+- * Process accumulated data -+- */ -+- currCal->calData->calPostProc(ah, numChains); -++ if (ah->cal_samples >= cur_caldata->calNumSamples) { -++ unsigned int i, numChains = 0; -++ for (i = 0; i < AR9300_MAX_CHAINS; i++) { -++ if (rxchainmask & (1 << i)) -++ numChains++; -++ } -+ -+- /* Calibration has finished. */ -+- caldata->CalValid |= currCal->calData->calType; -+- currCal->calState = CAL_DONE; -+- iscaldone = true; -+- } else { -++ /* -++ * Process accumulated data -++ */ -++ cur_caldata->calPostProc(ah, numChains); -++ -++ /* Calibration has finished. */ -++ caldata->CalValid |= cur_caldata->calType; -++ currCal->calState = CAL_DONE; -++ return true; -++ } else { -+ /* -+ * Set-up collection of another sub-sample until we -+ * get desired number -+ */ -+ ar9003_hw_setup_calibration(ah, currCal); -+- } -+ } -+- } else if (!(caldata->CalValid & currCal->calData->calType)) { -++ } else if (!(caldata->CalValid & cur_caldata->calType)) { -+ /* If current cal is marked invalid in channel, kick it off */ -+ ath9k_hw_reset_calibration(ah, currCal); -+ } -+ -+- return iscaldone; -++ return false; -+ } -+ -+ static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, -diff --git a/package/kernel/mac80211/patches/327-ath9k_hw-get-rid-of-some-duplicate-code-in-calibrati.patch b/package/kernel/mac80211/patches/327-ath9k_hw-get-rid-of-some-duplicate-code-in-calibrati.patch -new file mode 100644 -index 0000000..b7f3823 ---- /dev/null -+++ b/package/kernel/mac80211/patches/327-ath9k_hw-get-rid-of-some-duplicate-code-in-calibrati.patch -@@ -0,0 +1,94 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Mon, 11 Jul 2016 11:35:20 +0200 -+Subject: [PATCH] ath9k_hw: get rid of some duplicate code in calibration -+ init -+ -+Remove a misleading debug message as well -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c -++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c -+@@ -1373,6 +1373,26 @@ static void ar9003_hw_cl_cal_post_proc(s -+ } -+ } -+ -++static void ar9003_hw_init_cal_common(struct ath_hw *ah) -++{ -++ struct ath9k_hw_cal_data *caldata = ah->caldata; -++ -++ /* Initialize list pointers */ -++ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; -++ -++ INIT_CAL(&ah->iq_caldata); -++ INSERT_CAL(ah, &ah->iq_caldata); -++ -++ /* Initialize current pointer to first element in list */ -++ ah->cal_list_curr = ah->cal_list; -++ -++ if (ah->cal_list_curr) -++ ath9k_hw_reset_calibration(ah, ah->cal_list_curr); -++ -++ if (caldata) -++ caldata->CalValid = 0; -++} -++ -+ static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, -+ struct ath9k_channel *chan) -+ { -+@@ -1532,21 +1552,7 @@ skip_tx_iqcal: -+ /* Revert chainmask to runtime parameters */ -+ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); -+ -+- /* Initialize list pointers */ -+- ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; -+- -+- INIT_CAL(&ah->iq_caldata); -+- INSERT_CAL(ah, &ah->iq_caldata); -+- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); -+- -+- /* Initialize current pointer to first element in list */ -+- ah->cal_list_curr = ah->cal_list; -+- -+- if (ah->cal_list_curr) -+- ath9k_hw_reset_calibration(ah, ah->cal_list_curr); -+- -+- if (caldata) -+- caldata->CalValid = 0; -++ ar9003_hw_init_cal_common(ah); -+ -+ return true; -+ } -+@@ -1577,8 +1583,6 @@ static bool do_ar9003_agc_cal(struct ath -+ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, -+ struct ath9k_channel *chan) -+ { -+- struct ath_common *common = ath9k_hw_common(ah); -+- struct ath9k_hw_cal_data *caldata = ah->caldata; -+ bool txiqcal_done = false; -+ bool status = true; -+ bool run_agc_cal = false, sep_iq_cal = false; -+@@ -1676,21 +1680,7 @@ skip_tx_iqcal: -+ /* Revert chainmask to runtime parameters */ -+ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); -+ -+- /* Initialize list pointers */ -+- ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; -+- -+- INIT_CAL(&ah->iq_caldata); -+- INSERT_CAL(ah, &ah->iq_caldata); -+- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); -+- -+- /* Initialize current pointer to first element in list */ -+- ah->cal_list_curr = ah->cal_list; -+- -+- if (ah->cal_list_curr) -+- ath9k_hw_reset_calibration(ah, ah->cal_list_curr); -+- -+- if (caldata) -+- caldata->CalValid = 0; -++ ar9003_hw_init_cal_common(ah); -+ -+ return true; -+ } -diff --git a/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch b/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch -deleted file mode 100644 -index f7f9df9..0000000 ---- a/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch -+++ /dev/null -@@ -1,54 +0,0 @@ --From: Henning Rogge <hrogge@gmail.com> --Date: Wed, 3 Feb 2016 13:58:36 +0100 --Subject: [PATCH] mac80211: Remove MPP table entries with MPath -- --Make the mesh_path_del() function remove all mpp table entries --that are proxied by the removed mesh path. -- --Acked-by: Bob Copeland <me@bobcopeland.com> --Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/mac80211/mesh_pathtbl.c --+++ b/net/mac80211/mesh_pathtbl.c --@@ -835,6 +835,29 @@ void mesh_path_flush_by_nexthop(struct s -- rcu_read_unlock(); -- } -- --+static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, --+ const u8 *proxy) --+{ --+ struct mesh_table *tbl; --+ struct mesh_path *mpp; --+ struct mpath_node *node; --+ int i; --+ --+ rcu_read_lock(); --+ read_lock_bh(&pathtbl_resize_lock); --+ tbl = resize_dereference_mpp_paths(); --+ for_each_mesh_entry(tbl, node, i) { --+ mpp = node->mpath; --+ if (ether_addr_equal(mpp->mpp, proxy)) { --+ spin_lock(&tbl->hashwlock[i]); --+ __mesh_path_del(tbl, node); --+ spin_unlock(&tbl->hashwlock[i]); --+ } --+ } --+ read_unlock_bh(&pathtbl_resize_lock); --+ rcu_read_unlock(); --+} --+ -- static void table_flush_by_iface(struct mesh_table *tbl, -- struct ieee80211_sub_if_data *sdata) -- { --@@ -892,6 +915,9 @@ int mesh_path_del(struct ieee80211_sub_i -- int hash_idx; -- int err = 0; -- --+ /* flush relevant mpp entries first */ --+ mpp_flush_by_proxy(sdata, addr); --+ -- read_lock_bh(&pathtbl_resize_lock); -- tbl = resize_dereference_mesh_paths(); -- hash_idx = mesh_table_hash(addr, sdata, tbl); -diff --git a/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch b/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch -deleted file mode 100644 -index 740993c..0000000 ---- a/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch -+++ /dev/null -@@ -1,104 +0,0 @@ --From: Henning Rogge <hrogge@gmail.com> --Date: Wed, 3 Feb 2016 13:58:37 +0100 --Subject: [PATCH] mac80211: let unused MPP table entries timeout -- --Remember the last time when a mpp table entry is used for --rx or tx and remove them after MESH_PATH_EXPIRE time. -- --Acked-by: Bob Copeland <me@bobcopeland.com> --Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/mac80211/mesh_pathtbl.c --+++ b/net/mac80211/mesh_pathtbl.c --@@ -942,6 +942,46 @@ enddel: -- } -- -- /** --+ * mpp_path_del - delete a mesh proxy path from the table --+ * --+ * @addr: addr address (ETH_ALEN length) --+ * @sdata: local subif --+ * --+ * Returns: 0 if successful --+ */ --+static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) --+{ --+ struct mesh_table *tbl; --+ struct mesh_path *mpath; --+ struct mpath_node *node; --+ struct hlist_head *bucket; --+ int hash_idx; --+ int err = 0; --+ --+ read_lock_bh(&pathtbl_resize_lock); --+ tbl = resize_dereference_mpp_paths(); --+ hash_idx = mesh_table_hash(addr, sdata, tbl); --+ bucket = &tbl->hash_buckets[hash_idx]; --+ --+ spin_lock(&tbl->hashwlock[hash_idx]); --+ hlist_for_each_entry(node, bucket, list) { --+ mpath = node->mpath; --+ if (mpath->sdata == sdata && --+ ether_addr_equal(addr, mpath->dst)) { --+ __mesh_path_del(tbl, node); --+ goto enddel; --+ } --+ } --+ --+ err = -ENXIO; --+enddel: --+ mesh_paths_generation++; --+ spin_unlock(&tbl->hashwlock[hash_idx]); --+ read_unlock_bh(&pathtbl_resize_lock); --+ return err; --+} --+ --+/** -- * mesh_path_tx_pending - sends pending frames in a mesh path queue -- * -- * @mpath: mesh path to activate --@@ -1157,6 +1197,17 @@ void mesh_path_expire(struct ieee80211_s -- time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) -- mesh_path_del(mpath->sdata, mpath->dst); -- } --+ --+ tbl = rcu_dereference(mpp_paths); --+ for_each_mesh_entry(tbl, node, i) { --+ if (node->mpath->sdata != sdata) --+ continue; --+ mpath = node->mpath; --+ if ((!(mpath->flags & MESH_PATH_FIXED)) && --+ time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) --+ mpp_path_del(mpath->sdata, mpath->dst); --+ } --+ -- rcu_read_unlock(); -- } -- ----- a/net/mac80211/rx.c --+++ b/net/mac80211/rx.c --@@ -2291,6 +2291,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 -- spin_lock_bh(&mppath->state_lock); -- if (!ether_addr_equal(mppath->mpp, mpp_addr)) -- memcpy(mppath->mpp, mpp_addr, ETH_ALEN); --+ mppath->exp_time = jiffies; -- spin_unlock_bh(&mppath->state_lock); -- } -- rcu_read_unlock(); ----- a/net/mac80211/tx.c --+++ b/net/mac80211/tx.c --@@ -2171,8 +2171,11 @@ static struct sk_buff *ieee80211_build_h -- mpp_lookup = true; -- } -- --- if (mpp_lookup) --+ if (mpp_lookup) { -- mppath = mpp_path_lookup(sdata, skb->data); --+ if (mppath) --+ mppath->exp_time = jiffies; --+ } -- -- if (mppath && mpath) -- mesh_path_del(mpath->sdata, mpath->dst); -diff --git a/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch b/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch -deleted file mode 100644 -index 0c36b1d..0000000 ---- a/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch -+++ /dev/null -@@ -1,143 +0,0 @@ --From: Henning Rogge <hrogge@gmail.com> --Date: Wed, 3 Feb 2016 13:58:38 +0100 --Subject: [PATCH] mac80211: Unify mesh and mpp path removal function -- --mpp_path_del() and mesh_path_del() are mostly the same function. --Move common code into a new static function. -- --Acked-by: Bob Copeland <me@bobcopeland.com> --Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/mac80211/mesh_pathtbl.c --+++ b/net/mac80211/mesh_pathtbl.c --@@ -55,16 +55,21 @@ int mpp_paths_generation; -- static DEFINE_RWLOCK(pathtbl_resize_lock); -- -- --+static inline struct mesh_table *resize_dereference_paths( --+ struct mesh_table __rcu *table) --+{ --+ return rcu_dereference_protected(table, --+ lockdep_is_held(&pathtbl_resize_lock)); --+} --+ -- static inline struct mesh_table *resize_dereference_mesh_paths(void) -- { --- return rcu_dereference_protected(mesh_paths, --- lockdep_is_held(&pathtbl_resize_lock)); --+ return resize_dereference_paths(mesh_paths); -- } -- -- static inline struct mesh_table *resize_dereference_mpp_paths(void) -- { --- return rcu_dereference_protected(mpp_paths, --- lockdep_is_held(&pathtbl_resize_lock)); --+ return resize_dereference_paths(mpp_paths); -- } -- -- /* --@@ -899,14 +904,17 @@ void mesh_path_flush_by_iface(struct iee -- } -- -- /** --- * mesh_path_del - delete a mesh path from the table --+ * table_path_del - delete a path from the mesh or mpp table -- * --- * @addr: dst address (ETH_ALEN length) --+ * @tbl: mesh or mpp path table -- * @sdata: local subif --+ * @addr: dst address (ETH_ALEN length) -- * -- * Returns: 0 if successful -- */ ---int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) --+static int table_path_del(struct mesh_table __rcu *rcu_tbl, --+ struct ieee80211_sub_if_data *sdata, --+ const u8 *addr) -- { -- struct mesh_table *tbl; -- struct mesh_path *mpath; --@@ -915,11 +923,7 @@ int mesh_path_del(struct ieee80211_sub_i -- int hash_idx; -- int err = 0; -- --- /* flush relevant mpp entries first */ --- mpp_flush_by_proxy(sdata, addr); --- --- read_lock_bh(&pathtbl_resize_lock); --- tbl = resize_dereference_mesh_paths(); --+ tbl = resize_dereference_paths(rcu_tbl); -- hash_idx = mesh_table_hash(addr, sdata, tbl); -- bucket = &tbl->hash_buckets[hash_idx]; -- --@@ -935,9 +939,30 @@ int mesh_path_del(struct ieee80211_sub_i -- -- err = -ENXIO; -- enddel: --- mesh_paths_generation++; -- spin_unlock(&tbl->hashwlock[hash_idx]); --+ return err; --+} --+ --+/** --+ * mesh_path_del - delete a mesh path from the table --+ * --+ * @addr: dst address (ETH_ALEN length) --+ * @sdata: local subif --+ * --+ * Returns: 0 if successful --+ */ --+int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) --+{ --+ int err = 0; --+ --+ /* flush relevant mpp entries first */ --+ mpp_flush_by_proxy(sdata, addr); --+ --+ read_lock_bh(&pathtbl_resize_lock); --+ err = table_path_del(mesh_paths, sdata, addr); --+ mesh_paths_generation++; -- read_unlock_bh(&pathtbl_resize_lock); --+ -- return err; -- } -- --@@ -951,33 +976,13 @@ enddel: -- */ -- static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) -- { --- struct mesh_table *tbl; --- struct mesh_path *mpath; --- struct mpath_node *node; --- struct hlist_head *bucket; --- int hash_idx; -- int err = 0; -- -- read_lock_bh(&pathtbl_resize_lock); --- tbl = resize_dereference_mpp_paths(); --- hash_idx = mesh_table_hash(addr, sdata, tbl); --- bucket = &tbl->hash_buckets[hash_idx]; --- --- spin_lock(&tbl->hashwlock[hash_idx]); --- hlist_for_each_entry(node, bucket, list) { --- mpath = node->mpath; --- if (mpath->sdata == sdata && --- ether_addr_equal(addr, mpath->dst)) { --- __mesh_path_del(tbl, node); --- goto enddel; --- } --- } --- --- err = -ENXIO; ---enddel: --- mesh_paths_generation++; --- spin_unlock(&tbl->hashwlock[hash_idx]); --+ err = table_path_del(mpp_paths, sdata, addr); --+ mpp_paths_generation++; -- read_unlock_bh(&pathtbl_resize_lock); --+ -- return err; -- } -- -diff --git a/package/kernel/mac80211/patches/329-mac80211-fix-check-for-buffered-powersave-frames-wit.patch b/package/kernel/mac80211/patches/329-mac80211-fix-check-for-buffered-powersave-frames-wit.patch -new file mode 100644 -index 0000000..38e541c ---- /dev/null -+++ b/package/kernel/mac80211/patches/329-mac80211-fix-check-for-buffered-powersave-frames-wit.patch -@@ -0,0 +1,21 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Mon, 11 Jul 2016 15:07:06 +0200 -+Subject: [PATCH] mac80211: fix check for buffered powersave frames with txq -+ -+The logic was inverted here, set the bit if frames are pending. -+ -+Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation") -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/net/mac80211/rx.c -++++ b/net/mac80211/rx.c -+@@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info -+ for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { -+ struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); -+ -+- if (!txqi->tin.backlog_packets) -++ if (txqi->tin.backlog_packets) -+ set_bit(tid, &sta->txq_buffered_tids); -+ else -+ clear_bit(tid, &sta->txq_buffered_tids); -diff --git a/package/kernel/mac80211/patches/330-ath10k-fix-rx-status-reporting-for-A-MSDU-subframes.patch b/package/kernel/mac80211/patches/330-ath10k-fix-rx-status-reporting-for-A-MSDU-subframes.patch -new file mode 100644 -index 0000000..a6031b9 ---- /dev/null -+++ b/package/kernel/mac80211/patches/330-ath10k-fix-rx-status-reporting-for-A-MSDU-subframes.patch -@@ -0,0 +1,36 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 17 Jul 2016 12:49:59 +0200 -+Subject: [PATCH] ath10k: fix rx status reporting for A-MSDU subframes -+ -+Patch by Nagarajan, Ashok Raj <arnagara@qti.qualcomm.com> -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c -++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c -+@@ -1525,7 +1525,7 @@ static void ath10k_htt_rx_h_filter(struc -+ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) -+ { -+ struct ath10k *ar = htt->ar; -+- static struct ieee80211_rx_status rx_status; -++ struct ieee80211_rx_status *rx_status = &htt->rx_status; -+ struct sk_buff_head amsdu; -+ int ret; -+ -+@@ -1549,11 +1549,11 @@ static int ath10k_htt_rx_handle_amsdu(st -+ return ret; -+ } -+ -+- ath10k_htt_rx_h_ppdu(ar, &amsdu, &rx_status, 0xffff); -++ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); -+ ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); -+- ath10k_htt_rx_h_filter(ar, &amsdu, &rx_status); -+- ath10k_htt_rx_h_mpdu(ar, &amsdu, &rx_status); -+- ath10k_htt_rx_h_deliver(ar, &amsdu, &rx_status); -++ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); -++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); -++ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); -+ -+ return 0; -+ } -diff --git a/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch b/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch -deleted file mode 100644 -index 4dc6d66..0000000 ---- a/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch -+++ /dev/null -@@ -1,51 +0,0 @@ --From: Sven Eckelmann <sven.eckelmann@open-mesh.com> --Date: Tue, 2 Feb 2016 08:12:26 +0100 --Subject: [PATCH] mac80211: minstrel: Change expected throughput unit back to -- Kbps -- --The change from cur_tp to the function --minstrel_get_tp_avg/minstrel_ht_get_tp_avg changed the unit used for the --current throughput. For example in minstrel_ht the correct --conversion between them would be: -- -- mrs->cur_tp / 10 == minstrel_ht_get_tp_avg(..). -- --This factor 10 must also be included in the calculation of --minstrel_get_expected_throughput and minstrel_ht_get_expected_throughput to --return values with the unit [Kbps] instead of [10Kbps]. Otherwise routing --algorithms like B.A.T.M.A.N. V will make incorrect decision based on these --values. Its kernel based implementation expects expected_throughput always --to have the unit [Kbps] and not sometimes [10Kbps] and sometimes [Kbps]. -- --The same requirement has iw or olsrdv2's nl80211 based statistics module --which retrieve the same data via NL80211_STA_INFO_TX_BITRATE. -- --Cc: stable@vger.kernel.org --Fixes: 6a27b2c40b48 ("mac80211: restructure per-rate throughput calculation into function") --Signed-off-by: Sven Eckelmann <sven@open-mesh.com> --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/mac80211/rc80211_minstrel.c --+++ b/net/mac80211/rc80211_minstrel.c --@@ -711,7 +711,7 @@ static u32 minstrel_get_expected_through -- * computing cur_tp -- */ -- tmp_mrs = &mi->r[idx].stats; --- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma); --+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10; -- tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; -- -- return tmp_cur_tp; ----- a/net/mac80211/rc80211_minstrel_ht.c --+++ b/net/mac80211/rc80211_minstrel_ht.c --@@ -1335,7 +1335,8 @@ static u32 minstrel_ht_get_expected_thro -- prob = mi->groups[i].rates[j].prob_ewma; -- -- /* convert tp_avg from pkt per second in kbps */ --- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024; --+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10; --+ tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024; -- -- return tp_avg; -- } -diff --git a/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch b/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch -deleted file mode 100644 -index 1fd016f..0000000 ---- a/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch -+++ /dev/null -@@ -1,307 +0,0 @@ --From: Hante Meuleman <meuleman@broadcom.com> --Date: Sun, 7 Feb 2016 18:08:24 +0100 --Subject: [PATCH] brcmfmac: Increase nr of supported flowrings. --MIME-Version: 1.0 --Content-Type: text/plain; charset=UTF-8 --Content-Transfer-Encoding: 8bit -- --New generation devices have firmware which has more than 256 flowrings. --E.g. following debugging message comes from 14e4:4365 BCM4366: --[ 194.606245] brcmfmac: brcmf_pcie_init_ringbuffers Nr of flowrings is 264 -- --At various code places (related to flowrings) we were using u8 which --could lead to storing wrong number or infinite loops when indexing with --this type. This issue was quite easy to spot in brcmf_flowring_detach --where it led to infinite loop e.g. on failed initialization. -- --This patch switches code to proper types and increases the maximum --number of supported flowrings to 512. -- --Originally this change was sent in September 2015, but back it was --causing a regression on BCM43602 resulting in: --Unable to handle kernel NULL pointer dereference at virtual address ... -- --The reason for this regression was missing update (s/u8/u16) of struct --brcmf_flowring_ring. This problem was handled in 9f64df9 ("brcmfmac: Fix --bug in flowring management."). Starting with that it's safe to apply --this original patch as it doesn't cause a regression anymore. -- --This patch fixes an infinite loop on BCM4366 which is supported since --4.4 so it makes sense to apply it to stable 4.4+. -- --Cc: <stable@vger.kernel.org> # 4.4+ --Reviewed-by: Arend Van Spriel <arend@broadcom.com> --Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> --Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> --Signed-off-by: Hante Meuleman <meuleman@broadcom.com> --Signed-off-by: Arend van Spriel <arend@broadcom.com> --Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> ----- -- ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c --@@ -32,7 +32,7 @@ -- #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256) -- #define BRCMF_FLOWRING_INVALID_IFIDX 0xff -- ---#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) --+#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16) -- #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) -- -- static const u8 brcmf_flowring_prio2fifo[] = { --@@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f -- u8 prio, u8 ifidx) -- { -- struct brcmf_flowring_hash *hash; --- u8 hash_idx; --+ u16 hash_idx; -- u32 i; -- bool found; -- bool sta; --@@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f -- } -- hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : -- BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); --+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); -- found = false; -- hash = flow->hash; -- for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { --@@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f -- break; -- } -- hash_idx++; --+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); -- } -- if (found) -- return hash[hash_idx].flowid; --@@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_f -- { -- struct brcmf_flowring_ring *ring; -- struct brcmf_flowring_hash *hash; --- u8 hash_idx; --+ u16 hash_idx; -- u32 i; -- bool found; -- u8 fifo; --@@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_f -- } -- hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : -- BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); --+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); -- found = false; -- hash = flow->hash; -- for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { --@@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_f -- break; -- } -- hash_idx++; --+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); -- } -- if (found) { -- for (i = 0; i < flow->nrofrings; i++) { --@@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_f -- } -- -- ---u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) --+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid) -- { -- struct brcmf_flowring_ring *ring; -- --@@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowr -- } -- -- ---static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, --+static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid, -- bool blocked) -- { -- struct brcmf_flowring_ring *ring; --@@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct -- } -- -- ---void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) --+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid) -- { -- struct brcmf_flowring_ring *ring; --- u8 hash_idx; --+ u16 hash_idx; -- struct sk_buff *skb; -- -- ring = flow->rings[flowid]; --@@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_ -- } -- -- ---u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, --+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, -- struct sk_buff *skb) -- { -- struct brcmf_flowring_ring *ring; --@@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_ -- } -- -- ---struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) --+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid) -- { -- struct brcmf_flowring_ring *ring; -- struct sk_buff *skb; --@@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(s -- } -- -- ---void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, --+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, -- struct sk_buff *skb) -- { -- struct brcmf_flowring_ring *ring; --@@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcm -- } -- -- ---u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid) --+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid) -- { -- struct brcmf_flowring_ring *ring; -- --@@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flo -- } -- -- ---void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid) --+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid) -- { -- struct brcmf_flowring_ring *ring; -- --@@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_fl -- } -- -- ---u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid) --+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid) -- { -- struct brcmf_flowring_ring *ring; --- u8 hash_idx; --+ u16 hash_idx; -- -- ring = flow->rings[flowid]; -- hash_idx = ring->hash_id; --@@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_ -- struct brcmf_pub *drvr = bus_if->drvr; -- struct brcmf_flowring_tdls_entry *search; -- struct brcmf_flowring_tdls_entry *remove; --- u8 flowid; --+ u16 flowid; -- -- for (flowid = 0; flowid < flow->nrofrings; flowid++) { -- if (flow->rings[flowid]) --@@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode( -- struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); -- struct brcmf_pub *drvr = bus_if->drvr; -- u32 i; --- u8 flowid; --+ u16 flowid; -- -- if (flow->addr_mode[ifidx] != addr_mode) { -- for (i = 0; i < ARRAY_SIZE(flow->hash); i++) { --@@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct b -- struct brcmf_flowring_tdls_entry *prev; -- struct brcmf_flowring_tdls_entry *search; -- u32 i; --- u8 flowid; --+ u16 flowid; -- bool sta; -- -- sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h --@@ -16,7 +16,7 @@ -- #define BRCMFMAC_FLOWRING_H -- -- ---#define BRCMF_FLOWRING_HASHSIZE 256 --+#define BRCMF_FLOWRING_HASHSIZE 512 /* has to be 2^x */ -- #define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF -- -- --@@ -24,7 +24,7 @@ struct brcmf_flowring_hash { -- u8 mac[ETH_ALEN]; -- u8 fifo; -- u8 ifidx; --- u8 flowid; --+ u16 flowid; -- }; -- -- enum ring_status { --@@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_f -- u8 prio, u8 ifidx); -- u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], -- u8 prio, u8 ifidx); ---void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid); ---void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid); ---u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid); ---u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, --+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid); --+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid); --+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid); --+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, -- struct sk_buff *skb); ---struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid); ---void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, --+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid); --+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, -- struct sk_buff *skb); ---u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid); ---u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid); --+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid); --+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid); -- struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings); -- void brcmf_flowring_detach(struct brcmf_flowring *flow); -- void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c --@@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create( -- } -- -- ---static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) --+static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid) -- { -- struct brcmf_flowring *flow = msgbuf->flow; -- struct brcmf_commonring *commonring; --@@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct -- } -- -- ---void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) --+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) -- { -- struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; -- struct msgbuf_tx_flowring_delete_req *delete; --@@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brc -- u32 count; -- -- if_msgbuf = drvr->bus_if->msgbuf; --+ --+ if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) { --+ brcmf_err("driver not configured for this many flowrings %d\n", --+ if_msgbuf->nrof_flowrings); --+ if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; --+ } --+ -- msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL); -- if (!msgbuf) -- goto fail; ----- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h --+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h --@@ -33,7 +33,7 @@ -- -- -- int brcmf_proto_msgbuf_rx_trigger(struct device *dev); ---void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid); --+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid); -- int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr); -- void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr); -- #else -diff --git a/package/kernel/mac80211/patches/331-mac80211-End-the-MPSP-even-if-EOSP-frame-was-not-rec.patch b/package/kernel/mac80211/patches/331-mac80211-End-the-MPSP-even-if-EOSP-frame-was-not-rec.patch -new file mode 100644 -index 0000000..5d8a8fb ---- /dev/null -+++ b/package/kernel/mac80211/patches/331-mac80211-End-the-MPSP-even-if-EOSP-frame-was-not-rec.patch -@@ -0,0 +1,42 @@ -+From: Masashi Honma <masashi.honma@gmail.com> -+Date: Wed, 13 Jul 2016 16:04:35 +0900 -+Subject: [PATCH] mac80211: End the MPSP even if EOSP frame was not received -+ -+The mesh STA sends QoS frame with EOSP (end of service period) -+subfiled=1 to end the MPSP(mesh peer service period). Previously, if -+the frame was not acked by peer, the mesh STA did not end the MPSP. -+This patch ends the MPSP even if the QoS frame was no acked. -+ -+Signed-off-by: Masashi Honma <masashi.honma@gmail.com> -+--- -+ -+--- a/net/mac80211/status.c -++++ b/net/mac80211/status.c -+@@ -784,6 +784,13 @@ void ieee80211_tx_status(struct ieee8021 -+ clear_sta_flag(sta, WLAN_STA_SP); -+ -+ acked = !!(info->flags & IEEE80211_TX_STAT_ACK); -++ -++ /* mesh Peer Service Period support */ -++ if (ieee80211_vif_is_mesh(&sta->sdata->vif) && -++ ieee80211_is_data_qos(fc)) -++ ieee80211_mpsp_trigger_process( -++ ieee80211_get_qos_ctl(hdr), sta, true, acked); -++ -+ if (!acked && test_sta_flag(sta, WLAN_STA_PS_STA)) { -+ /* -+ * The STA is in power save mode, so assume -+@@ -794,13 +801,6 @@ void ieee80211_tx_status(struct ieee8021 -+ return; -+ } -+ -+- /* mesh Peer Service Period support */ -+- if (ieee80211_vif_is_mesh(&sta->sdata->vif) && -+- ieee80211_is_data_qos(fc)) -+- ieee80211_mpsp_trigger_process( -+- ieee80211_get_qos_ctl(hdr), -+- sta, true, acked); -+- -+ if (ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL) && -+ (ieee80211_is_data(hdr->frame_control)) && -+ (rates_idx != -1)) -diff --git a/package/kernel/mac80211/patches/332-ath10k-implement-NAPI-support.patch b/package/kernel/mac80211/patches/332-ath10k-implement-NAPI-support.patch -new file mode 100644 -index 0000000..c6cc145 ---- /dev/null -+++ b/package/kernel/mac80211/patches/332-ath10k-implement-NAPI-support.patch -@@ -0,0 +1,642 @@ -+From: Rajkumar Manoharan <rmanohar@qti.qualcomm.com> -+Date: Thu, 21 Jul 2016 11:50:00 +0530 -+Subject: [PATCH] ath10k: implement NAPI support -+ -+Add NAPI support for rx and tx completion. NAPI poll is scheduled -+from interrupt handler. The design is as below -+ -+ - on interrupt -+ - schedule napi and mask interrupts -+ - on poll -+ - process all pipes (no actual Tx/Rx) -+ - process Rx within budget -+ - if quota exceeds budget reschedule napi poll by returning budget -+ - process Tx completions and update budget if necessary -+ - process Tx fetch indications (pull-push) -+ - push any other pending Tx (if possible) -+ - before resched or napi completion replenish htt rx ring buffer -+ - if work done < budget, complete napi poll and unmask interrupts -+ -+This change also get rid of two tasklets (intr_tq and txrx_compl_task). -+ -+Measured peak throughput with NAPI on IPQ4019 platform in controlled -+environment. No noticeable reduction in throughput is seen and also -+observed improvements in CPU usage. Approx. 15% CPU usage got reduced -+in UDP uplink case. -+ -+DL: AP DUT Tx -+UL: AP DUT Rx -+ -+IPQ4019 (avg. cpu usage %) -+======== -+ TOT +NAPI -+ =========== ============= -+TCP DL 644 Mbps (42%) 645 Mbps (36%) -+TCP UL 673 Mbps (30%) 675 Mbps (26%) -+UDP DL 682 Mbps (49%) 680 Mbps (49%) -+UDP UL 720 Mbps (28%) 717 Mbps (11%) -+ -+Signed-off-by: Rajkumar Manoharan <rmanohar@qti.qualcomm.com> -+--- -+ -+--- a/drivers/net/wireless/ath/ath10k/ahb.c -++++ b/drivers/net/wireless/ath/ath10k/ahb.c -+@@ -462,13 +462,13 @@ static void ath10k_ahb_halt_chip(struct -+ static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg) -+ { -+ struct ath10k *ar = arg; -+- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -+ -+ if (!ath10k_pci_irq_pending(ar)) -+ return IRQ_NONE; -+ -+ ath10k_pci_disable_and_clear_legacy_irq(ar); -+- tasklet_schedule(&ar_pci->intr_tq); -++ ath10k_pci_irq_msi_fw_mask(ar); -++ napi_schedule(&ar->napi); ++@@ -171,14 +192,6 @@ static void ath_txq_skb_done(struct ath_ ++ if (WARN_ON(--txq->pending_frames < 0)) ++ txq->pending_frames = 0; + -+ return IRQ_HANDLED; ++- if (txq->stopped && ++- txq->pending_frames < sc->tx.txq_max_pending[q]) { ++- if (ath9k_is_chanctx_enabled()) ++- ieee80211_wake_queue(sc->hw, info->hw_queue); ++- else ++- ieee80211_wake_queue(sc->hw, q); ++- txq->stopped = false; ++- } + } -+@@ -831,7 +831,7 @@ static int ath10k_ahb_probe(struct platf -+ goto err_resource_deinit; -+ } -+ -+- ath10k_pci_init_irq_tasklets(ar); -++ ath10k_pci_init_napi(ar); + -+ ret = ath10k_ahb_request_irq_legacy(ar); -+ if (ret) -+--- a/drivers/net/wireless/ath/ath10k/core.c -++++ b/drivers/net/wireless/ath/ath10k/core.c -+@@ -2226,6 +2226,8 @@ struct ath10k *ath10k_core_create(size_t -+ INIT_WORK(&ar->register_work, ath10k_core_register_work); -+ INIT_WORK(&ar->restart_work, ath10k_core_restart); ++ static struct ath_atx_tid * ++@@ -188,9 +201,47 @@ ath_get_skb_tid(struct ath_softc *sc, st ++ return ATH_AN_2_TID(an, tidno); ++ } + -++ init_dummy_netdev(&ar->napi_dev); +++static struct sk_buff * +++ath_tid_pull(struct ath_atx_tid *tid) +++{ +++ struct ath_softc *sc = tid->an->sc; +++ struct ieee80211_hw *hw = sc->hw; +++ struct ath_tx_control txctl = { +++ .txq = tid->txq, +++ .sta = tid->an->sta, +++ }; +++ struct sk_buff *skb; +++ struct ath_frame_info *fi; +++ int q; ++ -+ ret = ath10k_debug_create(ar); -+ if (ret) -+ goto err_free_aux_wq; -+--- a/drivers/net/wireless/ath/ath10k/core.h -++++ b/drivers/net/wireless/ath/ath10k/core.h -+@@ -65,6 +65,10 @@ -+ #define ATH10K_KEEPALIVE_MAX_IDLE 3895 -+ #define ATH10K_KEEPALIVE_MAX_UNRESPONSIVE 3900 -+ -++/* NAPI poll budget */ -++#define ATH10K_NAPI_BUDGET 64 -++#define ATH10K_NAPI_QUOTA_LIMIT 60 +++ if (!tid->has_queued) +++ return NULL; ++ -+ struct ath10k; -+ -+ enum ath10k_bus { -+@@ -933,6 +937,10 @@ struct ath10k { -+ struct ath10k_thermal thermal; -+ struct ath10k_wow wow; -+ -++ /* NAPI */ -++ struct net_device napi_dev; -++ struct napi_struct napi; +++ skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv)); +++ if (!skb) { +++ tid->has_queued = false; +++ return NULL; +++ } ++ -+ /* must be last */ -+ u8 drv_priv[0] __aligned(sizeof(void *)); -+ }; -+--- a/drivers/net/wireless/ath/ath10k/htt.h -++++ b/drivers/net/wireless/ath/ath10k/htt.h -+@@ -1666,7 +1666,6 @@ struct ath10k_htt { -+ -+ /* This is used to group tx/rx completions separately and process them -+ * in batches to reduce cache stalls */ -+- struct tasklet_struct txrx_compl_task; -+ struct sk_buff_head rx_compl_q; -+ struct sk_buff_head rx_in_ord_compl_q; -+ struct sk_buff_head tx_fetch_ind_q; -+@@ -1799,5 +1798,6 @@ int ath10k_htt_tx(struct ath10k_htt *htt -+ struct sk_buff *msdu); -+ void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar, -+ struct sk_buff *skb); -++int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget); -+ -+ #endif -+--- a/drivers/net/wireless/ath/ath10k/htt_rx.c -++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c -+@@ -34,7 +34,6 @@ -+ #define HTT_RX_RING_REFILL_RESCHED_MS 5 -+ -+ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb); -+-static void ath10k_htt_txrx_compl_task(unsigned long ptr); -+ -+ static struct sk_buff * -+ ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr) -+@@ -226,7 +225,6 @@ int ath10k_htt_rx_ring_refill(struct ath -+ void ath10k_htt_rx_free(struct ath10k_htt *htt) +++ if (ath_tx_prepare(hw, skb, &txctl)) { +++ ieee80211_free_txskb(hw, skb); +++ return NULL; +++ } +++ +++ q = skb_get_queue_mapping(skb); +++ if (tid->txq == sc->tx.txq_map[q]) { +++ fi = get_frame_info(skb); +++ fi->txq = q; +++ ++tid->txq->pending_frames; +++ } +++ +++ return skb; +++ } +++ +++ ++ static bool ath_tid_has_buffered(struct ath_atx_tid *tid) + { -+ del_timer_sync(&htt->rx_ring.refill_retry_timer); -+- tasklet_kill(&htt->txrx_compl_task); -+ -+ skb_queue_purge(&htt->rx_compl_q); -+ skb_queue_purge(&htt->rx_in_ord_compl_q); -+@@ -520,9 +518,6 @@ int ath10k_htt_rx_alloc(struct ath10k_ht -+ skb_queue_head_init(&htt->tx_fetch_ind_q); -+ atomic_set(&htt->num_mpdus_ready, 0); -+ -+- tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task, -+- (unsigned long)htt); -+- -+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt rx ring size %d fill_level %d\n", -+ htt->rx_ring.size, htt->rx_ring.fill_level); -+ return 0; -+@@ -958,7 +953,7 @@ static void ath10k_process_rx(struct ath -+ trace_ath10k_rx_hdr(ar, skb->data, skb->len); -+ trace_ath10k_rx_payload(ar, skb->data, skb->len); -+ -+- ieee80211_rx(ar->hw, skb); -++ ieee80211_rx_napi(ar->hw, NULL, skb, &ar->napi); ++- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); +++ return !skb_queue_empty(&tid->retry_q) || tid->has_queued; + } + -+ static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar, -+@@ -1527,7 +1522,7 @@ static int ath10k_htt_rx_handle_amsdu(st -+ struct ath10k *ar = htt->ar; -+ struct ieee80211_rx_status *rx_status = &htt->rx_status; -+ struct sk_buff_head amsdu; -+- int ret; -++ int ret, num_msdus; -+ -+ __skb_queue_head_init(&amsdu); -+ -+@@ -1549,13 +1544,14 @@ static int ath10k_htt_rx_handle_amsdu(st -+ return ret; -+ } ++ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) ++@@ -199,46 +250,11 @@ static struct sk_buff *ath_tid_dequeue(s + -++ num_msdus = skb_queue_len(&amsdu); -+ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); -+ ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); -+ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); -+ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); -+ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); ++ skb = __skb_dequeue(&tid->retry_q); ++ if (!skb) ++- skb = __skb_dequeue(&tid->buf_q); +++ skb = ath_tid_pull(tid); + -+- return 0; -++ return num_msdus; ++ return skb; + } + -+ static void ath10k_htt_rx_proc_rx_ind(struct ath10k_htt *htt, -+@@ -1579,15 +1575,6 @@ static void ath10k_htt_rx_proc_rx_ind(st -+ mpdu_count += mpdu_ranges[i].mpdu_count; -+ -+ atomic_add(mpdu_count, &htt->num_mpdus_ready); -+- -+- tasklet_schedule(&htt->txrx_compl_task); -+-} -+- -+-static void ath10k_htt_rx_frag_handler(struct ath10k_htt *htt) ++-/* ++- * ath_tx_tid_change_state: ++- * - clears a-mpdu flag of previous session ++- * - force sequence number allocation to fix next BlockAck Window ++- */ ++-static void ++-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) +-{ -+- atomic_inc(&htt->num_mpdus_ready); ++- struct ath_txq *txq = tid->txq; ++- struct ieee80211_tx_info *tx_info; ++- struct sk_buff *skb, *tskb; ++- struct ath_buf *bf; ++- struct ath_frame_info *fi; +- -+- tasklet_schedule(&htt->txrx_compl_task); -+ } -+ -+ static void ath10k_htt_rx_tx_compl_ind(struct ath10k *ar, -+@@ -1772,14 +1759,15 @@ static void ath10k_htt_rx_h_rx_offload_p -+ RX_FLAG_MMIC_STRIPPED; -+ } -+ -+-static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar, -+- struct sk_buff_head *list) -++static int ath10k_htt_rx_h_rx_offload(struct ath10k *ar, -++ struct sk_buff_head *list) -+ { -+ struct ath10k_htt *htt = &ar->htt; -+ struct ieee80211_rx_status *status = &htt->rx_status; -+ struct htt_rx_offload_msdu *rx; -+ struct sk_buff *msdu; -+ size_t offset; -++ int num_msdu = 0; -+ -+ while ((msdu = __skb_dequeue(list))) { -+ /* Offloaded frames don't have Rx descriptor. Instead they have -+@@ -1819,10 +1807,12 @@ static void ath10k_htt_rx_h_rx_offload(s -+ ath10k_htt_rx_h_rx_offload_prot(status, msdu); -+ ath10k_htt_rx_h_channel(ar, status, NULL, rx->vdev_id); -+ ath10k_process_rx(ar, status, msdu); -++ num_msdu++; -+ } -++ return num_msdu; -+ } -+ -+-static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) -++static int ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb) -+ { -+ struct ath10k_htt *htt = &ar->htt; -+ struct htt_resp *resp = (void *)skb->data; -+@@ -1835,12 +1825,12 @@ static void ath10k_htt_rx_in_ord_ind(str -+ u8 tid; -+ bool offload; -+ bool frag; -+- int ret; -++ int ret, num_msdus = 0; -+ -+ lockdep_assert_held(&htt->rx_ring.lock); -+ -+ if (htt->rx_confused) -+- return; -++ return -EIO; -+ -+ skb_pull(skb, sizeof(resp->hdr)); -+ skb_pull(skb, sizeof(resp->rx_in_ord_ind)); -+@@ -1859,7 +1849,7 @@ static void ath10k_htt_rx_in_ord_ind(str -+ -+ if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) { -+ ath10k_warn(ar, "dropping invalid in order rx indication\n"); -+- return; -++ return -EINVAL; -+ } -+ -+ /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later -+@@ -1870,14 +1860,14 @@ static void ath10k_htt_rx_in_ord_ind(str -+ if (ret < 0) { -+ ath10k_warn(ar, "failed to pop paddr list: %d\n", ret); -+ htt->rx_confused = true; -+- return; -++ return -EIO; -+ } -+ -+ /* Offloaded frames are very different and need to be handled -+ * separately. -+ */ -+ if (offload) -+- ath10k_htt_rx_h_rx_offload(ar, &list); -++ num_msdus = ath10k_htt_rx_h_rx_offload(ar, &list); -+ -+ while (!skb_queue_empty(&list)) { -+ __skb_queue_head_init(&amsdu); -+@@ -1890,6 +1880,7 @@ static void ath10k_htt_rx_in_ord_ind(str -+ * better to report something than nothing though. This -+ * should still give an idea about rx rate to the user. -+ */ -++ num_msdus += skb_queue_len(&amsdu); -+ ath10k_htt_rx_h_ppdu(ar, &amsdu, status, vdev_id); -+ ath10k_htt_rx_h_filter(ar, &amsdu, status); -+ ath10k_htt_rx_h_mpdu(ar, &amsdu, status); -+@@ -1902,9 +1893,10 @@ static void ath10k_htt_rx_in_ord_ind(str -+ ath10k_warn(ar, "failed to extract amsdu: %d\n", ret); -+ htt->rx_confused = true; -+ __skb_queue_purge(&list); -+- return; -++ return -EIO; -+ } -+ } -++ return num_msdus; -+ } -+ -+ static void ath10k_htt_rx_tx_fetch_resp_id_confirm(struct ath10k *ar, -+@@ -2267,7 +2259,6 @@ bool ath10k_htt_t2h_msg_handler(struct a -+ } -+ case HTT_T2H_MSG_TYPE_TX_COMPL_IND: -+ ath10k_htt_rx_tx_compl_ind(htt->ar, skb); -+- tasklet_schedule(&htt->txrx_compl_task); -+ break; -+ case HTT_T2H_MSG_TYPE_SEC_IND: { -+ struct ath10k *ar = htt->ar; -+@@ -2284,7 +2275,7 @@ bool ath10k_htt_t2h_msg_handler(struct a -+ case HTT_T2H_MSG_TYPE_RX_FRAG_IND: { -+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt event: ", -+ skb->data, skb->len); -+- ath10k_htt_rx_frag_handler(htt); -++ atomic_inc(&htt->num_mpdus_ready); -+ break; -+ } -+ case HTT_T2H_MSG_TYPE_TEST: -+@@ -2322,8 +2313,7 @@ bool ath10k_htt_t2h_msg_handler(struct a -+ break; -+ } -+ case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: { -+- skb_queue_tail(&htt->rx_in_ord_compl_q, skb); -+- tasklet_schedule(&htt->txrx_compl_task); -++ __skb_queue_tail(&htt->rx_in_ord_compl_q, skb); -+ return false; -+ } -+ case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND: -+@@ -2349,7 +2339,6 @@ bool ath10k_htt_t2h_msg_handler(struct a -+ break; -+ } -+ skb_queue_tail(&htt->tx_fetch_ind_q, tx_fetch_ind); -+- tasklet_schedule(&htt->txrx_compl_task); -+ break; -+ } -+ case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM: -+@@ -2378,27 +2367,77 @@ void ath10k_htt_rx_pktlog_completion_han -+ } -+ EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler); -+ -+-static void ath10k_htt_txrx_compl_task(unsigned long ptr) -++int ath10k_htt_txrx_compl_task(struct ath10k *ar, int budget) -+ { -+- struct ath10k_htt *htt = (struct ath10k_htt *)ptr; -+- struct ath10k *ar = htt->ar; -++ struct ath10k_htt *htt = &ar->htt; -+ struct htt_tx_done tx_done = {}; -+- struct sk_buff_head rx_ind_q; -+ struct sk_buff_head tx_ind_q; -+ struct sk_buff *skb; -+ unsigned long flags; -+- int num_mpdus; -++ int quota = 0, done, num_rx_msdus; -++ bool resched_napi = false; -+ -+- __skb_queue_head_init(&rx_ind_q); -+ __skb_queue_head_init(&tx_ind_q); -+ -+- spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags); -+- skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q); -+- spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags); -++ /* Since in-ord-ind can deliver more than 1 A-MSDU in single event, -++ * process it first to utilize full available quota. -++ */ -++ while (quota < budget) { -++ if (skb_queue_empty(&htt->rx_in_ord_compl_q)) -++ break; -+ -+- spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags); -+- skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q); -+- spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags); -++ skb = __skb_dequeue(&htt->rx_in_ord_compl_q); -++ if (!skb) { -++ resched_napi = true; -++ goto exit; -++ } -++ -++ spin_lock_bh(&htt->rx_ring.lock); -++ num_rx_msdus = ath10k_htt_rx_in_ord_ind(ar, skb); -++ spin_unlock_bh(&htt->rx_ring.lock); -++ if (num_rx_msdus < 0) { -++ resched_napi = true; -++ goto exit; -++ } -++ -++ dev_kfree_skb_any(skb); -++ if (num_rx_msdus > 0) -++ quota += num_rx_msdus; -++ -++ if ((quota > ATH10K_NAPI_QUOTA_LIMIT) && -++ !skb_queue_empty(&htt->rx_in_ord_compl_q)) { -++ resched_napi = true; -++ goto exit; -++ } -++ } -++ -++ while (quota < budget) { -++ /* no more data to receive */ -++ if (!atomic_read(&htt->num_mpdus_ready)) -++ break; -++ -++ num_rx_msdus = ath10k_htt_rx_handle_amsdu(htt); -++ if (num_rx_msdus < 0) { -++ resched_napi = true; -++ goto exit; -++ } -++ -++ quota += num_rx_msdus; -++ atomic_dec(&htt->num_mpdus_ready); -++ if ((quota > ATH10K_NAPI_QUOTA_LIMIT) && -++ atomic_read(&htt->num_mpdus_ready)) { -++ resched_napi = true; -++ goto exit; -++ } -++ } -++ -++ /* From NAPI documentation: -++ * The napi poll() function may also process TX completions, in which -++ * case if it processes the entire TX ring then it should count that -++ * work as the rest of the budget. -++ */ -++ if ((quota < budget) && !kfifo_is_empty(&htt->txdone_fifo)) -++ quota = budget; -+ -+ /* kfifo_get: called only within txrx_tasklet so it's neatly serialized. -+ * From kfifo_get() documentation: -+@@ -2408,27 +2447,22 @@ static void ath10k_htt_txrx_compl_task(u -+ while (kfifo_get(&htt->txdone_fifo, &tx_done)) -+ ath10k_txrx_tx_unref(htt, &tx_done); -+ -++ spin_lock_irqsave(&htt->tx_fetch_ind_q.lock, flags); -++ skb_queue_splice_init(&htt->tx_fetch_ind_q, &tx_ind_q); -++ spin_unlock_irqrestore(&htt->tx_fetch_ind_q.lock, flags); -++ -+ while ((skb = __skb_dequeue(&tx_ind_q))) { -+ ath10k_htt_rx_tx_fetch_ind(ar, skb); -+ dev_kfree_skb_any(skb); -+ } -+ -+- num_mpdus = atomic_read(&htt->num_mpdus_ready); ++- skb_queue_walk_safe(&tid->buf_q, skb, tskb) { ++- fi = get_frame_info(skb); ++- bf = fi->bf; +- -+- while (num_mpdus) { -+- if (ath10k_htt_rx_handle_amsdu(htt)) -+- break; ++- tx_info = IEEE80211_SKB_CB(skb); ++- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; +- -+- num_mpdus--; -+- atomic_dec(&htt->num_mpdus_ready); -+- } ++- if (bf) ++- continue; +- -+- while ((skb = __skb_dequeue(&rx_ind_q))) { -+- spin_lock_bh(&htt->rx_ring.lock); -+- ath10k_htt_rx_in_ord_ind(ar, skb); -+- spin_unlock_bh(&htt->rx_ring.lock); -+- dev_kfree_skb_any(skb); ++- bf = ath_tx_setup_buffer(sc, txq, tid, skb); ++- if (!bf) { ++- __skb_unlink(skb, &tid->buf_q); ++- ath_txq_skb_done(sc, txq, skb); ++- ieee80211_free_txskb(sc->hw, skb); ++- continue; ++- } +- } +- -++exit: -+ ath10k_htt_rx_msdu_buff_replenish(htt); -++ /* In case of rx failure or more data to read, report budget -++ * to reschedule NAPI poll -++ */ -++ done = resched_napi ? budget : quota; -++ -++ return done; -+ } -++EXPORT_SYMBOL(ath10k_htt_txrx_compl_task); -+--- a/drivers/net/wireless/ath/ath10k/htt_tx.c -++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c -+@@ -388,8 +388,6 @@ void ath10k_htt_tx_free(struct ath10k_ht -+ { -+ int size; -+ -+- tasklet_kill(&htt->txrx_compl_task); -+- -+ idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); -+ idr_destroy(&htt->pending_tx); -+ -+--- a/drivers/net/wireless/ath/ath10k/pci.c -++++ b/drivers/net/wireless/ath/ath10k/pci.c -+@@ -1502,12 +1502,10 @@ void ath10k_pci_hif_send_complete_check( -+ ath10k_ce_per_engine_service(ar, pipe); -+ } -+ -+-void ath10k_pci_kill_tasklet(struct ath10k *ar) -++static void ath10k_pci_rx_retry_sync(struct ath10k *ar) -+ { -+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -+ -+- tasklet_kill(&ar_pci->intr_tq); ++-} +- -+ del_timer_sync(&ar_pci->rx_post_retry); -+ } -+ -+@@ -1566,7 +1564,7 @@ void ath10k_pci_hif_get_default_pipe(str -+ ul_pipe, dl_pipe); -+ } -+ -+-static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) -++void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) ++ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) + { -+ u32 val; -+ -+@@ -1747,7 +1745,7 @@ void ath10k_pci_ce_deinit(struct ath10k ++ struct ath_txq *txq = tid->txq; ++@@ -873,20 +889,16 @@ static int ath_compute_num_delims(struct + -+ void ath10k_pci_flush(struct ath10k *ar) ++ static struct ath_buf * ++ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, ++- struct ath_atx_tid *tid, struct sk_buff_head **q) +++ struct ath_atx_tid *tid) + { -+- ath10k_pci_kill_tasklet(ar); -++ ath10k_pci_rx_retry_sync(ar); -+ ath10k_pci_buffer_cleanup(ar); -+ } -+ -+@@ -2754,35 +2752,53 @@ static irqreturn_t ath10k_pci_interrupt_ -+ return IRQ_NONE; -+ } ++ struct ieee80211_tx_info *tx_info; ++ struct ath_frame_info *fi; ++- struct sk_buff *skb; +++ struct sk_buff *skb, *first_skb = NULL; ++ struct ath_buf *bf; ++ u16 seqno; + -+- if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) { -+- if (!ath10k_pci_irq_pending(ar)) -+- return IRQ_NONE; ++ while (1) { ++- *q = &tid->retry_q; ++- if (skb_queue_empty(*q)) ++- *q = &tid->buf_q; +- -+- ath10k_pci_disable_and_clear_legacy_irq(ar); -+- } -++ if ((ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) && -++ !ath10k_pci_irq_pending(ar)) -++ return IRQ_NONE; -+ -+- tasklet_schedule(&ar_pci->intr_tq); -++ ath10k_pci_disable_and_clear_legacy_irq(ar); -++ ath10k_pci_irq_msi_fw_mask(ar); -++ napi_schedule(&ar->napi); -+ -+ return IRQ_HANDLED; -+ } ++- skb = skb_peek(*q); +++ skb = ath_tid_dequeue(tid); ++ if (!skb) ++ break; + -+-static void ath10k_pci_tasklet(unsigned long data) -++static int ath10k_pci_napi_poll(struct napi_struct *ctx, int budget) -+ { -+- struct ath10k *ar = (struct ath10k *)data; -+- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -++ struct ath10k *ar = container_of(ctx, struct ath10k, napi); -++ int done = 0; -+ -+ if (ath10k_pci_has_fw_crashed(ar)) { -+- ath10k_pci_irq_disable(ar); -+ ath10k_pci_fw_crashed_clear(ar); -+ ath10k_pci_fw_crashed_dump(ar); -+- return; -++ napi_complete(ctx); -++ return done; -+ } ++@@ -898,7 +910,6 @@ ath_tx_get_tid_subframe(struct ath_softc ++ bf->bf_state.stale = false; + -+ ath10k_ce_per_engine_service_any(ar); ++ if (!bf) { ++- __skb_unlink(skb, *q); ++ ath_txq_skb_done(sc, txq, skb); ++ ieee80211_free_txskb(sc->hw, skb); ++ continue; ++@@ -927,8 +938,19 @@ ath_tx_get_tid_subframe(struct ath_softc ++ seqno = bf->bf_state.seqno; + -+- /* Re-enable legacy irq that was disabled in the irq handler */ -+- if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) -++ done = ath10k_htt_txrx_compl_task(ar, budget); ++ /* do not step over block-ack window */ ++- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) +++ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { +++ __skb_queue_tail(&tid->retry_q, skb); ++ -++ if (done < budget) { -++ napi_complete(ctx); -++ /* In case of MSI, it is possible that interrupts are received -++ * while NAPI poll is inprogress. So pending interrupts that are -++ * received after processing all copy engine pipes by NAPI poll -++ * will not be handled again. This is causing failure to -++ * complete boot sequence in x86 platform. So before enabling -++ * interrupts safer to check for pending interrupts for -++ * immediate servicing. -++ */ -++ if (CE_INTERRUPT_SUMMARY(ar)) { -++ napi_reschedule(&ar->napi); -++ goto out; +++ /* If there are other skbs in the retry q, they are +++ * probably within the BAW, so loop immediately to get +++ * one of them. Otherwise the queue can get stuck. */ +++ if (!skb_queue_is_first(&tid->retry_q, skb) && skb != first_skb) { +++ if(!first_skb) /* infinite loop prevention */ +++ first_skb = skb; +++ continue; +++ } ++ break; ++ } -+ ath10k_pci_enable_legacy_irq(ar); -++ ath10k_pci_irq_msi_fw_unmask(ar); -++ } -++ -++out: -++ return done; -+ } + -+ static int ath10k_pci_request_irq_msi(struct ath10k *ar) -+@@ -2840,11 +2856,11 @@ static void ath10k_pci_free_irq(struct a -+ free_irq(ar_pci->pdev->irq, ar); -+ } ++ if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { ++ struct ath_tx_status ts = {}; ++@@ -936,7 +958,6 @@ ath_tx_get_tid_subframe(struct ath_softc + -+-void ath10k_pci_init_irq_tasklets(struct ath10k *ar) -++void ath10k_pci_init_napi(struct ath10k *ar) -+ { -+- struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -+- -+- tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar); -++ netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_pci_napi_poll, -++ ATH10K_NAPI_BUDGET); -++ napi_enable(&ar->napi); ++ INIT_LIST_HEAD(&bf_head); ++ list_add(&bf->list, &bf_head); ++- __skb_unlink(skb, *q); ++ ath_tx_update_baw(sc, tid, seqno); ++ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); ++ continue; ++@@ -948,11 +969,10 @@ ath_tx_get_tid_subframe(struct ath_softc ++ return NULL; + } + -+ static int ath10k_pci_init_irq(struct ath10k *ar) -+@@ -2852,7 +2868,7 @@ static int ath10k_pci_init_irq(struct at -+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); -+ int ret; -+ -+- ath10k_pci_init_irq_tasklets(ar); -++ ath10k_pci_init_napi(ar); -+ -+ if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_AUTO) -+ ath10k_info(ar, "limiting irq mode to: %d\n", -+@@ -3113,7 +3129,8 @@ int ath10k_pci_setup_resource(struct ath -+ -+ void ath10k_pci_release_resource(struct ath10k *ar) ++-static bool +++static int ++ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, ++ struct ath_atx_tid *tid, struct list_head *bf_q, ++- struct ath_buf *bf_first, struct sk_buff_head *tid_q, ++- int *aggr_len) +++ struct ath_buf *bf_first) + { -+- ath10k_pci_kill_tasklet(ar); -++ ath10k_pci_rx_retry_sync(ar); -++ netif_napi_del(&ar->napi); -+ ath10k_pci_ce_deinit(ar); -+ ath10k_pci_free_pipes(ar); -+ } -+@@ -3274,7 +3291,7 @@ static int ath10k_pci_probe(struct pci_d -+ -+ err_free_irq: -+ ath10k_pci_free_irq(ar); -+- ath10k_pci_kill_tasklet(ar); -++ ath10k_pci_rx_retry_sync(ar); -+ -+ err_deinit_irq: -+ ath10k_pci_deinit_irq(ar); -+--- a/drivers/net/wireless/ath/ath10k/pci.h -++++ b/drivers/net/wireless/ath/ath10k/pci.h -+@@ -177,8 +177,6 @@ struct ath10k_pci { -+ /* Operating interrupt mode */ -+ enum ath10k_pci_irq_mode oper_irq_mode; -+ -+- struct tasklet_struct intr_tq; -+- -+ struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX]; -+ -+ /* Copy Engine used for Diagnostic Accesses */ -+@@ -294,8 +292,7 @@ void ath10k_pci_free_pipes(struct ath10k -+ void ath10k_pci_free_pipes(struct ath10k *ar); -+ void ath10k_pci_rx_replenish_retry(unsigned long ptr); -+ void ath10k_pci_ce_deinit(struct ath10k *ar); -+-void ath10k_pci_init_irq_tasklets(struct ath10k *ar); -+-void ath10k_pci_kill_tasklet(struct ath10k *ar); -++void ath10k_pci_init_napi(struct ath10k *ar); -+ int ath10k_pci_init_pipes(struct ath10k *ar); -+ int ath10k_pci_init_config(struct ath10k *ar); -+ void ath10k_pci_rx_post(struct ath10k *ar); -+@@ -303,6 +300,7 @@ void ath10k_pci_flush(struct ath10k *ar) -+ void ath10k_pci_enable_legacy_irq(struct ath10k *ar); -+ bool ath10k_pci_irq_pending(struct ath10k *ar); -+ void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar); -++void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar); -+ int ath10k_pci_wait_for_target_init(struct ath10k *ar); -+ int ath10k_pci_setup_resource(struct ath10k *ar); -+ void ath10k_pci_release_resource(struct ath10k *ar); -diff --git a/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch b/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch -deleted file mode 100644 -index e414f23..0000000 ---- a/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch -+++ /dev/null -@@ -1,22 +0,0 @@ --From: Felix Fietkau <nbd@openwrt.org> --Date: Mon, 8 Feb 2016 14:24:36 +0100 --Subject: [PATCH] cfg80211: fix faulty variable initialization in -- ieee80211_amsdu_to_8023s -- --reuse_skb is set to true if the code decides to use the last segment. --Fixes a memory leak -- --Signed-off-by: Felix Fietkau <nbd@openwrt.org> ----- -- ----- a/net/wireless/util.c --+++ b/net/wireless/util.c --@@ -676,7 +676,7 @@ void ieee80211_amsdu_to_8023s(struct sk_ -- u8 *payload; -- int offset = 0, remaining, err; -- struct ethhdr eth; --- bool reuse_skb = true; --+ bool reuse_skb = false; -- bool last = false; -- -- if (has_80211_header) { -diff --git a/package/kernel/mac80211/patches/333-ath9k-fix-client-mode-beacon-configuration.patch b/package/kernel/mac80211/patches/333-ath9k-fix-client-mode-beacon-configuration.patch -new file mode 100644 -index 0000000..d008ceb ---- /dev/null -+++ b/package/kernel/mac80211/patches/333-ath9k-fix-client-mode-beacon-configuration.patch -@@ -0,0 +1,69 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 26 Jul 2016 08:05:10 +0200 -+Subject: [PATCH] ath9k: fix client mode beacon configuration -+ -+For pure station mode, iter_data.primary_beacon_vif was used and passed -+to ath_beacon_config, but not set to the station vif. -+This was causing the following warning: -+ -+[ 100.310919] ------------[ cut here ]------------ -+[ 100.315683] WARNING: CPU: 0 PID: 7 at compat-wireless-2016-06-20/drivers/net/wireless/ath/ath9k/beacon.c:642 ath9k_calculate_summary_state+0x250/0x60c [ath9k]() -+[ 100.402028] CPU: 0 PID: 7 Comm: kworker/u2:1 Tainted: G W 4.4.15 #5 -+[ 100.409676] Workqueue: phy0 ieee80211_ibss_leave [mac80211] -+[ 100.415351] Stack : 8736e98c 870b4b20 87a25b54 800a6800 8782a080 80400d63 8039b96c 00000007 -+[ 100.415351] 803c5edc 87875914 80400000 800a47cc 87a25b54 800a6800 803a0fd8 80400000 -+[ 100.415351] 00000003 87875914 80400000 80094ae0 87a25b54 8787594c 00000000 801ef308 -+[ 100.415351] 803ffe70 801ef300 87193d58 87b3a400 87b3ad00 70687930 00000000 00000000 -+[ 100.415351] 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 -+[ 100.415351] ... -+[ 100.451703] Call Trace: -+[ 100.454235] [<800a6800>] vprintk_default+0x24/0x30 -+[ 100.459110] [<800a47cc>] printk+0x2c/0x38 -+[ 100.463190] [<800a6800>] vprintk_default+0x24/0x30 -+[ 100.468072] [<80094ae0>] print_worker_info+0x148/0x174 -+[ 100.473378] [<801ef308>] serial8250_console_putchar+0x0/0x44 -+[ 100.479122] [<801ef300>] wait_for_xmitr+0xc4/0xcc -+[ 100.484014] [<87193d58>] ieee80211_ibss_leave+0xb90/0x1900 [mac80211] -+[ 100.490590] [<80081604>] warn_slowpath_common+0xa0/0xd0 -+[ 100.495922] [<801a359c>] dump_stack+0x14/0x28 -+[ 100.500350] [<80071a00>] show_stack+0x50/0x84 -+[ 100.504784] [<80081604>] warn_slowpath_common+0xa0/0xd0 -+[ 100.510106] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k] -+[ 100.517105] [<800816b8>] warn_slowpath_null+0x18/0x24 -+[ 100.522256] [<87024c60>] ath9k_calculate_summary_state+0x250/0x60c [ath9k] -+[ 100.529273] [<87025418>] ath9k_set_txpower+0x148/0x498 [ath9k] -+[ 100.535302] [<871d2c64>] cleanup_module+0xa74/0xd4c [mac80211] -+[ 100.541237] [<801ef308>] serial8250_console_putchar+0x0/0x44 -+[ 100.547042] [<800a5d18>] wake_up_klogd+0x54/0x68 -+[ 100.551730] [<800a6650>] vprintk_emit+0x404/0x43c -+[ 100.556623] [<871b9db8>] ieee80211_sta_rx_notify+0x258/0x32c [mac80211] -+[ 100.563475] [<871ba6a4>] ieee80211_sta_rx_queued_mgmt+0x63c/0x734 [mac80211] -+[ 100.570693] [<871aa49c>] ieee80211_tx_prepare_skb+0x210/0x230 [mac80211] -+[ 100.577609] [<800af5d4>] mod_timer+0x15c/0x190 -+[ 100.582220] [<871ba8b8>] ieee80211_sta_work+0xfc/0xe1c [mac80211] -+[ 100.588539] [<871940b4>] ieee80211_ibss_leave+0xeec/0x1900 [mac80211] -+[ 100.595122] [<8009ec84>] dequeue_task_fair+0x44/0x130 -+[ 100.600281] [<80092a34>] process_one_work+0x1f8/0x334 -+[ 100.605454] [<80093830>] worker_thread+0x2b4/0x408 -+[ 100.610317] [<8009357c>] worker_thread+0x0/0x408 -+[ 100.615019] [<8009357c>] worker_thread+0x0/0x408 -+[ 100.619705] [<80097b68>] kthread+0xdc/0xe8 -+[ 100.623886] [<80097a8c>] kthread+0x0/0xe8 -+[ 100.627961] [<80060878>] ret_from_kernel_thread+0x14/0x1c -+[ 100.633448] -+[ 100.634956] ---[ end trace aafbe57e9ae6862f ]--- -+ -+Fixes: cfda2d8e2314 ("ath9k: Fix beacon configuration for addition/removal of interfaces") -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/main.c -++++ b/drivers/net/wireless/ath/ath9k/main.c -+@@ -1154,6 +1154,7 @@ void ath9k_calculate_summary_state(struc -+ bool changed = (iter_data.primary_sta != ctx->primary_sta); -+ -+ if (iter_data.primary_sta) { -++ iter_data.primary_beacon_vif = iter_data.primary_sta; -+ iter_data.beacons = true; -+ ath9k_set_assoc_state(sc, iter_data.primary_sta, -+ changed); -diff --git a/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch b/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch -deleted file mode 100644 -index 6e2d0cf..0000000 ---- a/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch -+++ /dev/null -@@ -1,132 +0,0 @@ --From: Felix Fietkau <nbd@openwrt.org> --Date: Mon, 8 Feb 2016 14:33:19 +0100 --Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx -- --This massively reduces data copying and thus improves rx performance -- --Signed-off-by: Felix Fietkau <nbd@openwrt.org> ----- -- ----- a/net/wireless/util.c --+++ b/net/wireless/util.c --@@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b -- } -- EXPORT_SYMBOL(ieee80211_data_from_8023); -- --+static void --+__frame_add_frag(struct sk_buff *skb, struct page *page, --+ void *ptr, int len, int size) --+{ --+ struct skb_shared_info *sh = skb_shinfo(skb); --+ int page_offset; --+ --+ atomic_inc(&page->_count); --+ page_offset = ptr - page_address(page); --+ skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); --+} --+ --+static void --+__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, --+ int offset, int len) --+{ --+ struct skb_shared_info *sh = skb_shinfo(skb); --+ const skb_frag_t *frag = &sh->frags[-1]; --+ struct page *frag_page; --+ void *frag_ptr; --+ int frag_len, frag_size; --+ int head_size = skb->len - skb->data_len; --+ int cur_len; --+ --+ frag_page = virt_to_head_page(skb->head); --+ frag_ptr = skb->data; --+ frag_size = head_size; --+ --+ while (offset >= frag_size) { --+ offset -= frag_size; --+ frag++; --+ frag_page = skb_frag_page(frag); --+ frag_ptr = skb_frag_address(frag); --+ frag_size = skb_frag_size(frag); --+ } --+ --+ frag_ptr += offset; --+ frag_len = frag_size - offset; --+ --+ cur_len = min(len, frag_len); --+ --+ __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size); --+ len -= cur_len; --+ --+ while (len > 0) { --+ frag++; --+ frag_len = skb_frag_size(frag); --+ cur_len = min(len, frag_len); --+ __frame_add_frag(frame, skb_frag_page(frag), --+ skb_frag_address(frag), cur_len, frag_len); --+ len -= cur_len; --+ } --+} --+ -- static struct sk_buff * -- __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, --- int offset, int len) --+ int offset, int len, bool reuse_frag) -- { -- struct sk_buff *frame; --+ int cur_len = len; -- -- if (skb->len - offset < len) -- return NULL; -- -- /* --+ * When reusing framents, copy some data to the head to simplify --+ * ethernet header handling and speed up protocol header processing --+ * in the stack later. --+ */ --+ if (reuse_frag) --+ cur_len = min_t(int, len, 32); --+ --+ /* -- * Allocate and reserve two bytes more for payload -- * alignment since sizeof(struct ethhdr) is 14. -- */ --- frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len); --+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len); -- -- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); --- skb_copy_bits(skb, offset, skb_put(frame, len), len); --+ skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len); --+ --+ len -= cur_len; --+ if (!len) --+ return frame; --+ --+ offset += cur_len; --+ __ieee80211_amsdu_copy_frag(skb, frame, offset, len); -- -- return frame; -- } --@@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_ -- u8 *payload; -- int offset = 0, remaining, err; -- struct ethhdr eth; --+ bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); -- bool reuse_skb = false; -- bool last = false; -- --@@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_ -- offset += sizeof(struct ethhdr); -- /* reuse skb for the last subframe */ -- last = remaining <= subframe_len + padding; --- if (!skb_is_nonlinear(skb) && last) { --+ if (!skb_is_nonlinear(skb) && !reuse_frag && last) { -- skb_pull(skb, offset); -- frame = skb; -- reuse_skb = true; -- } else { --- frame = __ieee80211_amsdu_copy(skb, hlen, offset, len); --+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len, --+ reuse_frag); -- if (!frame) -- goto purge; -- -diff --git a/package/kernel/mac80211/patches/334-mac80211-fix-purging-multicast-PS-buffer-queue.patch b/package/kernel/mac80211/patches/334-mac80211-fix-purging-multicast-PS-buffer-queue.patch -new file mode 100644 -index 0000000..dfcc6e4 ---- /dev/null -+++ b/package/kernel/mac80211/patches/334-mac80211-fix-purging-multicast-PS-buffer-queue.patch -@@ -0,0 +1,54 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 2 Aug 2016 11:11:13 +0200 -+Subject: [PATCH] mac80211: fix purging multicast PS buffer queue -+ -+The code currently assumes that buffered multicast PS frames don't have -+a pending ACK frame for tx status reporting. -+However, hostapd sends a broadcast deauth frame on teardown for which tx -+status is requested. This can lead to the "Have pending ack frames" -+warning on module reload. -+Fix this by using ieee80211_free_txskb/ieee80211_purge_tx_queue. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/net/mac80211/cfg.c -++++ b/net/mac80211/cfg.c -+@@ -868,7 +868,7 @@ static int ieee80211_stop_ap(struct wiph ++ #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) ++ struct ath_buf *bf = bf_first, *bf_prev = NULL; ++@@ -962,12 +982,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s ++ struct ieee80211_tx_info *tx_info; ++ struct ath_frame_info *fi; ++ struct sk_buff *skb; ++- bool closed = false; +++ + -+ /* free all potentially still buffered bcast frames */ -+ local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf); -+- skb_queue_purge(&sdata->u.ap.ps.bc_buf); -++ ieee80211_purge_tx_queue(&local->hw, &sdata->u.ap.ps.bc_buf); ++ bf = bf_first; ++ aggr_limit = ath_lookup_rate(sc, bf, tid); + -+ mutex_lock(&local->mtx); -+ ieee80211_vif_copy_chanctx_to_vlans(sdata, true); -+--- a/net/mac80211/tx.c -++++ b/net/mac80211/tx.c -+@@ -368,7 +368,7 @@ static void purge_old_ps_buffers(struct -+ skb = skb_dequeue(&ps->bc_buf); -+ if (skb) { -+ purged++; -+- dev_kfree_skb(skb); -++ ieee80211_free_txskb(&local->hw, skb); ++- do { +++ while (bf) +++ { ++ skb = bf->bf_mpdu; ++ fi = get_frame_info(skb); ++ ++@@ -976,12 +997,12 @@ ath_tx_form_aggr(struct ath_softc *sc, s ++ if (nframes) { ++ if (aggr_limit < al + bpad + al_delta || ++ ath_lookup_legacy(bf) || nframes >= h_baw) ++- break; +++ goto stop; ++ ++ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); ++ if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || ++ !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ++- break; +++ goto stop; + } -+ total += skb_queue_len(&ps->bc_buf); -+ } -+@@ -451,7 +451,7 @@ ieee80211_tx_h_multicast_ps_buf(struct i -+ if (skb_queue_len(&ps->bc_buf) >= AP_MAX_BC_BUFFER) { -+ ps_dbg(tx->sdata, -+ "BC TX buffer full - dropping the oldest frame\n"); -+- dev_kfree_skb(skb_dequeue(&ps->bc_buf)); -++ ieee80211_free_txskb(&tx->local->hw, skb_dequeue(&ps->bc_buf)); -+ } else -+ tx->local->total_ps_buffered++; + -+@@ -4276,7 +4276,7 @@ ieee80211_get_buffered_bc(struct ieee802 -+ sdata = IEEE80211_DEV_TO_SUB_IF(skb->dev); -+ if (!ieee80211_tx_prepare(sdata, &tx, NULL, skb)) -+ break; -+- dev_kfree_skb_any(skb); -++ ieee80211_free_txskb(hw, skb); -+ } ++ /* add padding for previous frame to aggregation length */ ++@@ -1003,20 +1024,18 @@ ath_tx_form_aggr(struct ath_softc *sc, s ++ ath_tx_addto_baw(sc, tid, bf); ++ bf->bf_state.ndelim = ndelim; + -+ info = IEEE80211_SKB_CB(skb); -diff --git a/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch b/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch -deleted file mode 100644 -index f8f4f09..0000000 ---- a/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch -+++ /dev/null -@@ -1,36 +0,0 @@ --From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> --Date: Wed, 10 Feb 2016 16:08:17 +0100 --Subject: [PATCH] mac80211: fix wiphy supported_band access -- --Fix wiphy supported_band access in tx radiotap parsing. In particular, --info->band is always set to 0 (IEEE80211_BAND_2GHZ) since it has not --assigned yet. This cause a kernel crash on 5GHz only devices. --Move ieee80211_parse_tx_radiotap() after info->band assignment -- --Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> ----- -- ----- a/net/mac80211/tx.c --+++ b/net/mac80211/tx.c --@@ -1890,10 +1890,6 @@ netdev_tx_t ieee80211_monitor_start_xmit -- info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | -- IEEE80211_TX_CTL_INJECTED; -- --- /* process and remove the injection radiotap header */ --- if (!ieee80211_parse_tx_radiotap(local, skb)) --- goto fail; --- -- rcu_read_lock(); -- -- /* --@@ -1955,6 +1951,10 @@ netdev_tx_t ieee80211_monitor_start_xmit -- goto fail_rcu; -- -- info->band = chandef->chan->band; --+ /* process and remove the injection radiotap header */ --+ if (!ieee80211_parse_tx_radiotap(local, skb)) --+ goto fail_rcu; --+ -- ieee80211_xmit(sdata, NULL, skb); -- rcu_read_unlock(); -- -diff --git a/package/kernel/mac80211/patches/335-ath9k-use-ieee80211_tx_status_noskb-where-possible.patch b/package/kernel/mac80211/patches/335-ath9k-use-ieee80211_tx_status_noskb-where-possible.patch -new file mode 100644 -index 0000000..dbb5b90 ---- /dev/null -+++ b/package/kernel/mac80211/patches/335-ath9k-use-ieee80211_tx_status_noskb-where-possible.patch -@@ -0,0 +1,305 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 2 Aug 2016 12:12:18 +0200 -+Subject: [PATCH] ath9k: use ieee80211_tx_status_noskb where possible -+ -+It removes the need for undoing the padding changes to skb->data and it -+improves performance by eliminating one tx status lookup per MPDU in the -+status path. It is also useful for preparing a follow-up fix to better -+handle powersave filtering. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -50,9 +50,11 @@ static u16 bits_per_symbol[][2] = { -+ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, -+ struct ath_atx_tid *tid, struct sk_buff *skb); -+ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, -+- int tx_flags, struct ath_txq *txq); -++ int tx_flags, struct ath_txq *txq, -++ struct ieee80211_sta *sta); -+ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, -+ struct ath_txq *txq, struct list_head *bf_q, -++ struct ieee80211_sta *sta, -+ struct ath_tx_status *ts, int txok); -+ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, -+ struct list_head *head, bool internal); -+@@ -77,6 +79,22 @@ enum { -+ /* Aggregation logic */ -+ /*********************/ -+ -++static void ath_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ struct ieee80211_sta *sta = info->status.status_driver_data[0]; -++ -++ if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { -++ ieee80211_tx_status(hw, skb); -++ return; ++- __skb_unlink(skb, tid_q); ++ list_add_tail(&bf->list, bf_q); ++ if (bf_prev) ++ bf_prev->bf_next = bf; ++ ++ bf_prev = bf; ++ ++- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); ++- if (!bf) { ++- closed = true; ++- break; ++- } ++- } while (ath_tid_has_buffered(tid)); ++- +++ bf = ath_tx_get_tid_subframe(sc, txq, tid); ++ } -++ -++ if (sta) -++ ieee80211_tx_status_noskb(hw, sta, info); -++ -++ dev_kfree_skb(skb); -++} -++ -+ void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq) -+ __acquires(&txq->axq_lock) +++ goto finish; +++stop: +++ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); +++finish: ++ bf = bf_first; ++ bf->bf_lastbf = bf_prev; ++ ++@@ -1027,9 +1046,7 @@ ath_tx_form_aggr(struct ath_softc *sc, s ++ TX_STAT_INC(txq->axq_qnum, a_aggr); ++ } ++ ++- *aggr_len = al; ++- ++- return closed; +++ return al; ++ #undef PADBYTES ++ } ++ ++@@ -1406,18 +1423,15 @@ static void ath_tx_fill_desc(struct ath_ ++ static void ++ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, ++ struct ath_atx_tid *tid, struct list_head *bf_q, ++- struct ath_buf *bf_first, struct sk_buff_head *tid_q) +++ struct ath_buf *bf_first) + { -+@@ -92,6 +110,7 @@ void ath_txq_unlock(struct ath_softc *sc -+ void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq) -+ __releases(&txq->axq_lock) ++ struct ath_buf *bf = bf_first, *bf_prev = NULL; ++- struct sk_buff *skb; ++ int nframes = 0; ++ ++ do { ++ struct ieee80211_tx_info *tx_info; ++- skb = bf->bf_mpdu; ++ ++ nframes++; ++- __skb_unlink(skb, tid_q); ++ list_add_tail(&bf->list, bf_q); ++ if (bf_prev) ++ bf_prev->bf_next = bf; ++@@ -1426,13 +1440,15 @@ ath_tx_form_burst(struct ath_softc *sc, ++ if (nframes >= 2) ++ break; ++ ++- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); +++ bf = ath_tx_get_tid_subframe(sc, txq, tid); ++ if (!bf) ++ break; ++ ++ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); ++- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) +++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { +++ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); ++ break; +++ } ++ ++ ath_set_rates(tid->an->vif, tid->an->sta, bf, false); ++ } while (1); ++@@ -1443,34 +1459,33 @@ static bool ath_tx_sched_aggr(struct ath + { -++ struct ieee80211_hw *hw = sc->hw; -+ struct sk_buff_head q; -+ struct sk_buff *skb; ++ struct ath_buf *bf; ++ struct ieee80211_tx_info *tx_info; ++- struct sk_buff_head *tid_q; ++ struct list_head bf_q; ++ int aggr_len = 0; ++- bool aggr, last = true; +++ bool aggr; + -+@@ -100,7 +119,7 @@ void ath_txq_unlock_complete(struct ath_ -+ spin_unlock_bh(&txq->axq_lock); ++ if (!ath_tid_has_buffered(tid)) ++ return false; + -+ while ((skb = __skb_dequeue(&q))) -+- ieee80211_tx_status(sc->hw, skb); -++ ath_tx_status(hw, skb); -+ } ++ INIT_LIST_HEAD(&bf_q); + -+ static void ath_tx_queue_tid(struct ath_softc *sc, struct ath_txq *txq, -+@@ -268,7 +287,7 @@ static void ath_tx_flush_tid(struct ath_ -+ } ++- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); +++ bf = ath_tx_get_tid_subframe(sc, txq, tid); ++ if (!bf) ++ return false; ++ ++ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); ++ aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); ++ if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || ++- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { +++ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { +++ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); ++ *stop = true; ++ return false; ++ } ++ ++ ath_set_rates(tid->an->vif, tid->an->sta, bf, false); ++ if (aggr) ++- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, ++- tid_q, &aggr_len); +++ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf); ++ else ++- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); +++ ath_tx_form_burst(sc, txq, tid, &bf_q, bf); + -+ list_add_tail(&bf->list, &bf_head); -+- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); -++ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); ++ if (list_empty(&bf_q)) ++ return false; ++@@ -1513,9 +1528,6 @@ int ath_tx_aggr_start(struct ath_softc * ++ an->mpdudensity = density; + } + -+ if (sendbar) { -+@@ -333,12 +352,12 @@ static void ath_tid_drain(struct ath_sof -+ bf = fi->bf; ++- /* force sequence number allocation for pending frames */ ++- ath_tx_tid_change_state(sc, txtid); ++- ++ txtid->active = true; ++ *ssn = txtid->seq_start = txtid->seq_next; ++ txtid->bar_index = -1; ++@@ -1540,7 +1552,6 @@ void ath_tx_aggr_stop(struct ath_softc * ++ ath_txq_lock(sc, txq); ++ txtid->active = false; ++ ath_tx_flush_tid(sc, txtid); ++- ath_tx_tid_change_state(sc, txtid); ++ ath_txq_unlock_complete(sc, txq); ++ } ++ ++@@ -1550,14 +1561,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ ++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); ++ struct ath_atx_tid *tid; ++ struct ath_txq *txq; ++- bool buffered; ++ int tidno; ++ ++ ath_dbg(common, XMIT, "%s called\n", __func__); + -+ if (!bf) { -+- ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); -++ ath_tx_complete(sc, skb, ATH_TX_ERROR, txq, NULL); ++- for (tidno = 0, tid = &an->tid[tidno]; ++- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ++- +++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { +++ tid = ATH_AN_2_TID(an, tidno); ++ txq = tid->txq; ++ ++ ath_txq_lock(sc, txq); ++@@ -1567,13 +1576,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ + continue; + } + -+ list_add_tail(&bf->list, &bf_head); -+- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); -++ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); ++- buffered = ath_tid_has_buffered(tid); +++ if (!skb_queue_empty(&tid->retry_q)) +++ ieee80211_sta_set_buffered(sta, tid->tidno, true); ++ ++ list_del_init(&tid->list); ++ ++ ath_txq_unlock(sc, txq); ++- ++- ieee80211_sta_set_buffered(sta, tidno, buffered); + } + } + -+@@ -441,12 +460,11 @@ static void ath_tx_count_frames(struct a ++@@ -1586,19 +1594,16 @@ void ath_tx_aggr_wakeup(struct ath_softc + -+ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, -+ struct ath_buf *bf, struct list_head *bf_q, -++ struct ieee80211_sta *sta, -+ struct ath_tx_status *ts, int txok) -+ { -+ struct ath_node *an = NULL; -+ struct sk_buff *skb; -+- struct ieee80211_sta *sta; -+- struct ieee80211_hw *hw = sc->hw; -+ struct ieee80211_hdr *hdr; -+ struct ieee80211_tx_info *tx_info; -+ struct ath_atx_tid *tid = NULL; -+@@ -475,12 +493,7 @@ static void ath_tx_complete_aggr(struct -+ for (i = 0; i < ts->ts_rateindex; i++) -+ retries += rates[i].count; ++ ath_dbg(common, XMIT, "%s called\n", __func__); + -+- rcu_read_lock(); -+- -+- sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); -+ if (!sta) { -+- rcu_read_unlock(); ++- for (tidno = 0, tid = &an->tid[tidno]; ++- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { +- -+ INIT_LIST_HEAD(&bf_head); -+ while (bf) { -+ bf_next = bf->bf_next; -+@@ -488,7 +501,7 @@ static void ath_tx_complete_aggr(struct -+ if (!bf->bf_state.stale || bf_next != NULL) -+ list_move_tail(&bf->list, &bf_head); -+ -+- ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0); -++ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, ts, 0); +++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { +++ tid = ATH_AN_2_TID(an, tidno); ++ txq = tid->txq; + -+ bf = bf_next; ++ ath_txq_lock(sc, txq); ++ tid->clear_ps_filter = true; ++- ++ if (ath_tid_has_buffered(tid)) { ++ ath_tx_queue_tid(sc, txq, tid); ++ ath_txq_schedule(sc, txq); + } -+@@ -598,7 +611,7 @@ static void ath_tx_complete_aggr(struct -+ ts); -+ } -+ -+- ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, -++ ath_tx_complete_buf(sc, bf, txq, &bf_head, sta, ts, -+ !txfail); -+ } else { -+ if (tx_info->flags & IEEE80211_TX_STATUS_EOSP) { -+@@ -619,7 +632,8 @@ static void ath_tx_complete_aggr(struct -+ ath_tx_update_baw(sc, tid, seqno); -+ -+ ath_tx_complete_buf(sc, bf, txq, -+- &bf_head, ts, 0); -++ &bf_head, NULL, ts, -++ 0); -+ bar_index = max_t(int, bar_index, -+ ATH_BA_INDEX(seq_first, seqno)); -+ break; -+@@ -663,8 +677,6 @@ static void ath_tx_complete_aggr(struct -+ ath_txq_lock(sc, txq); -+ } -+ -+- rcu_read_unlock(); +- -+ if (needreset) -+ ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR); ++ ath_txq_unlock_complete(sc, txq); ++ } + } -+@@ -679,7 +691,10 @@ static void ath_tx_process_buffer(struct -+ struct ath_tx_status *ts, struct ath_buf *bf, -+ struct list_head *bf_head) -+ { -++ struct ieee80211_hw *hw = sc->hw; -+ struct ieee80211_tx_info *info; -++ struct ieee80211_sta *sta; -++ struct ieee80211_hdr *hdr; -+ bool txok, flush; -+ -+ txok = !(ts->ts_status & ATH9K_TXERR_MASK); -+@@ -692,6 +707,10 @@ static void ath_tx_process_buffer(struct ++@@ -1621,11 +1626,6 @@ void ath_tx_aggr_resume(struct ath_softc + -+ ts->duration = ath9k_hw_get_duration(sc->sc_ah, bf->bf_desc, -+ ts->ts_rateindex); -++ -++ hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; -++ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); -++ -+ if (!bf_isampdu(bf)) { -+ if (!flush) { -+ info = IEEE80211_SKB_CB(bf->bf_mpdu); -+@@ -700,9 +719,9 @@ static void ath_tx_process_buffer(struct -+ ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok); -+ ath_dynack_sample_tx_ts(sc->sc_ah, bf->bf_mpdu, ts); -+ } -+- ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok); -++ ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok); -+ } else -+- ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok); -++ ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, ts, txok); ++ tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + -+ if (!flush) -+ ath_txq_schedule(sc, txq); -+@@ -938,7 +957,7 @@ ath_tx_get_tid_subframe(struct ath_softc -+ list_add(&bf->list, &bf_head); -+ __skb_unlink(skb, *q); -+ ath_tx_update_baw(sc, tid, seqno); -+- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0); -++ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); -+ continue; -+ } ++- if (ath_tid_has_buffered(tid)) { ++- ath_tx_queue_tid(sc, txq, tid); ++- ath_txq_schedule(sc, txq); ++- } ++- ++ ath_txq_unlock_complete(sc, txq); ++ } + -+@@ -1847,6 +1866,7 @@ static void ath_drain_txq_list(struct at -+ */ -+ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq) -+ { -++ rcu_read_lock(); -+ ath_txq_lock(sc, txq); ++@@ -1641,7 +1641,6 @@ void ath9k_release_buffered_frames(struc ++ struct ieee80211_tx_info *info; ++ struct list_head bf_q; ++ struct ath_buf *bf_tail = NULL, *bf; ++- struct sk_buff_head *tid_q; ++ int sent = 0; ++ int i; + -+ if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) { -+@@ -1865,6 +1885,7 @@ void ath_draintxq(struct ath_softc *sc, -+ ath_drain_txq_list(sc, txq, &txq->axq_q); ++@@ -1656,11 +1655,10 @@ void ath9k_release_buffered_frames(struc + -+ ath_txq_unlock_complete(sc, txq); -++ rcu_read_unlock(); -+ } ++ ath_txq_lock(sc, tid->txq); ++ while (nframes > 0) { ++- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); +++ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid); ++ if (!bf) ++ break; + -+ bool ath_drain_all_txq(struct ath_softc *sc) -+@@ -2487,7 +2508,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw -+ /*****************/ ++- __skb_unlink(bf->bf_mpdu, tid_q); ++ list_add_tail(&bf->list, &bf_q); ++ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); ++ if (bf_isampdu(bf)) { ++@@ -1675,7 +1673,7 @@ void ath9k_release_buffered_frames(struc ++ sent++; ++ TX_STAT_INC(txq->axq_qnum, a_queued_hw); + -+ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, -+- int tx_flags, struct ath_txq *txq) -++ int tx_flags, struct ath_txq *txq, -++ struct ieee80211_sta *sta) -+ { -+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -+ struct ath_common *common = ath9k_hw_common(sc->sc_ah); -+@@ -2507,15 +2529,17 @@ static void ath_tx_complete(struct ath_s -+ tx_info->flags |= IEEE80211_TX_STAT_ACK; -+ } ++- if (an->sta && !ath_tid_has_buffered(tid)) +++ if (an->sta && skb_queue_empty(&tid->retry_q)) ++ ieee80211_sta_set_buffered(an->sta, i, false); ++ } ++ ath_txq_unlock_complete(sc, tid->txq); ++@@ -1902,13 +1900,7 @@ bool ath_drain_all_txq(struct ath_softc ++ if (!ATH_TXQ_SETUP(sc, i)) ++ continue; + -+- padpos = ieee80211_hdrlen(hdr->frame_control); -+- padsize = padpos & 3; -+- if (padsize && skb->len>padpos+padsize) { +- /* -+- * Remove MAC header padding before giving the frame back to -+- * mac80211. ++- * The caller will resume queues with ieee80211_wake_queues. ++- * Mark the queue as not stopped to prevent ath_tx_complete ++- * from waking the queue too early. +- */ -+- memmove(skb->data + padsize, skb->data, padpos); -+- skb_pull(skb, padsize); -++ if (tx_info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { -++ padpos = ieee80211_hdrlen(hdr->frame_control); -++ padsize = padpos & 3; -++ if (padsize && skb->len>padpos+padsize) { -++ /* -++ * Remove MAC header padding before giving the frame back to -++ * mac80211. -++ */ -++ memmove(skb->data + padsize, skb->data, padpos); -++ skb_pull(skb, padsize); -++ } ++ txq = &sc->tx.txq[i]; ++- txq->stopped = false; ++ ath_draintxq(sc, txq); + } + -+ spin_lock_irqsave(&sc->sc_pm_lock, flags); -+@@ -2530,12 +2554,14 @@ static void ath_tx_complete(struct ath_s -+ } -+ spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ++@@ -2308,15 +2300,12 @@ int ath_tx_start(struct ieee80211_hw *hw ++ struct ath_txq *txq = txctl->txq; ++ struct ath_atx_tid *tid = NULL; ++ struct ath_buf *bf; ++- bool queue, ps_resp; +++ bool ps_resp; ++ int q, ret; + -+- __skb_queue_tail(&txq->complete_q, skb); -+ ath_txq_skb_done(sc, txq, skb); -++ tx_info->status.status_driver_data[0] = sta; -++ __skb_queue_tail(&txq->complete_q, skb); -+ } ++ if (vif) ++ avp = (void *)vif->drv_priv; + -+ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, -+ struct ath_txq *txq, struct list_head *bf_q, -++ struct ieee80211_sta *sta, -+ struct ath_tx_status *ts, int txok) -+ { -+ struct sk_buff *skb = bf->bf_mpdu; -+@@ -2563,7 +2589,7 @@ static void ath_tx_complete_buf(struct a -+ complete(&sc->paprd_complete); -+ } else { -+ ath_debug_stat_tx(sc, bf, ts, txq, tx_flags); -+- ath_tx_complete(sc, skb, tx_flags, txq); -++ ath_tx_complete(sc, skb, tx_flags, txq, sta); -+ } -+ skip_tx_complete: -+ /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't -+@@ -2715,10 +2741,12 @@ void ath_tx_tasklet(struct ath_softc *sc -+ u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1) & ah->intr_txqs; -+ int i; ++- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ++- txctl->force_channel = true; ++- ++ ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); + -++ rcu_read_lock(); -+ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { -+ if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) -+ ath_tx_processq(sc, &sc->tx.txq[i]); -+ } -++ rcu_read_unlock(); -+ } ++ ret = ath_tx_prepare(hw, skb, txctl); ++@@ -2331,63 +2320,13 @@ int ath_tx_start(struct ieee80211_hw *hw + -+ void ath_tx_edma_tasklet(struct ath_softc *sc) -+@@ -2732,6 +2760,7 @@ void ath_tx_edma_tasklet(struct ath_soft -+ struct list_head *fifo_list; -+ int status; ++ q = skb_get_queue_mapping(skb); + -++ rcu_read_lock(); -+ for (;;) { -+ if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) -+ break; -+@@ -2802,6 +2831,7 @@ void ath_tx_edma_tasklet(struct ath_soft -+ ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head); -+ ath_txq_unlock_complete(sc, txq); +++ if (ps_resp) +++ txq = sc->tx.uapsdq; +++ ++ ath_txq_lock(sc, txq); ++ if (txq == sc->tx.txq_map[q]) { ++ fi->txq = q; ++- if (++txq->pending_frames > sc->tx.txq_max_pending[q] && ++- !txq->stopped) { ++- if (ath9k_is_chanctx_enabled()) ++- ieee80211_stop_queue(sc->hw, info->hw_queue); ++- else ++- ieee80211_stop_queue(sc->hw, q); ++- txq->stopped = true; ++- } ++- } ++- ++- queue = ieee80211_is_data_present(hdr->frame_control); ++- ++- /* If chanctx, queue all null frames while NOA could be there */ ++- if (ath9k_is_chanctx_enabled() && ++- ieee80211_is_nullfunc(hdr->frame_control) && ++- !txctl->force_channel) ++- queue = true; ++- ++- /* Force queueing of all frames that belong to a virtual interface on ++- * a different channel context, to ensure that they are sent on the ++- * correct channel. ++- */ ++- if (((avp && avp->chanctx != sc->cur_chan) || ++- sc->cur_chan->stopped) && !txctl->force_channel) { ++- if (!txctl->an) ++- txctl->an = &avp->mcast_node; ++- queue = true; ++- ps_resp = false; ++- } ++- ++- if (txctl->an && queue) ++- tid = ath_get_skb_tid(sc, txctl->an, skb); ++- ++- if (ps_resp) { ++- ath_txq_unlock(sc, txq); ++- txq = sc->tx.uapsdq; ++- ath_txq_lock(sc, txq); ++- } else if (txctl->an && queue) { ++- WARN_ON(tid->txq != txctl->txq); ++- ++- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) ++- tid->clear_ps_filter = true; ++- ++- /* ++- * Add this frame to software queue for scheduling later ++- * for aggregation. ++- */ ++- TX_STAT_INC(txq->axq_qnum, a_queued_sw); ++- __skb_queue_tail(&tid->buf_q, skb); ++- if (!txctl->an->sleeping) ++- ath_tx_queue_tid(sc, txq, tid); ++- ++- ath_txq_schedule(sc, txq); ++- goto out; +++ ++txq->pending_frames; + } -++ rcu_read_unlock(); -+ } + -+ /*****************/ -diff --git a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch b/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch -deleted file mode 100644 -index acaacf7..0000000 ---- a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch -+++ /dev/null -@@ -1,61 +0,0 @@ --From: Felix Fietkau <nbd@openwrt.org> --Date: Thu, 18 Feb 2016 19:30:05 +0100 --Subject: [PATCH] mac80211: minstrel_ht: set A-MSDU tx limits based on selected -- max_prob_rate -- --Prevents excessive A-MSDU aggregation at low data rates or bad --conditions. -- --Signed-off-by: Felix Fietkau <nbd@openwrt.org> ----- -- ----- a/net/mac80211/rc80211_minstrel_ht.c --+++ b/net/mac80211/rc80211_minstrel_ht.c --@@ -883,6 +883,39 @@ minstrel_ht_set_rate(struct minstrel_pri -- ratetbl->rate[offset].flags = flags; -- } -- --+static int --+minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) --+{ --+ int group = mi->max_prob_rate / MCS_GROUP_RATES; --+ const struct mcs_group *g = &minstrel_mcs_groups[group]; --+ int rate = mi->max_prob_rate % MCS_GROUP_RATES; --+ --+ /* Disable A-MSDU if max_prob_rate is bad */ --+ if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) --+ return 1; --+ --+ /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ --+ if (g->duration[rate] > MCS_DURATION(1, 0, 52)) --+ return 500; --+ --+ /* --+ * If the rate is slower than single-stream MCS4, limit A-MSDU to usual --+ * data packet size --+ */ --+ if (g->duration[rate] > MCS_DURATION(1, 0, 104)) --+ return 1500; --+ --+ /* --+ * If the rate is slower than single-stream MCS7, limit A-MSDU to twice --+ * the usual data packet size --+ */ --+ if (g->duration[rate] > MCS_DURATION(1, 0, 260)) --+ return 3000; --+ --+ /* unlimited */ --+ return 0; --+} --+ -- static void -- minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) -- { --@@ -907,6 +940,7 @@ minstrel_ht_update_rates(struct minstrel -- minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); -- } -- --+ mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi); -- rates->rate[i].idx = -1; -- rate_control_set_rates(mp->hw, mi->sta, rates); -- } -diff --git a/package/kernel/mac80211/patches/336-ath9k-improve-powersave-filter-handling.patch b/package/kernel/mac80211/patches/336-ath9k-improve-powersave-filter-handling.patch -new file mode 100644 -index 0000000..67a6c63 ---- /dev/null -+++ b/package/kernel/mac80211/patches/336-ath9k-improve-powersave-filter-handling.patch -@@ -0,0 +1,70 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 2 Aug 2016 12:13:35 +0200 -+Subject: [PATCH] ath9k: improve powersave filter handling -+ -+For non-aggregated frames, ath9k was leaving handling of powersave -+filtered packets to mac80211. This can be too slow if the intermediate -+queue is already filled with packets and mac80211 does not immediately -+send a new packet via drv_tx(). -+ -+Improve response time with filtered frames by triggering clearing the -+powersave filter internally. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -461,13 +461,13 @@ static void ath_tx_count_frames(struct a -+ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, -+ struct ath_buf *bf, struct list_head *bf_q, -+ struct ieee80211_sta *sta, -++ struct ath_atx_tid *tid, -+ struct ath_tx_status *ts, int txok) -+ { -+ struct ath_node *an = NULL; -+ struct sk_buff *skb; -+ struct ieee80211_hdr *hdr; -+ struct ieee80211_tx_info *tx_info; -+- struct ath_atx_tid *tid = NULL; -+ struct ath_buf *bf_next, *bf_last = bf->bf_lastbf; -+ struct list_head bf_head; -+ struct sk_buff_head bf_pending; -+@@ -509,7 +509,6 @@ static void ath_tx_complete_aggr(struct ++ bf = ath_tx_setup_buffer(sc, txq, tid, skb); ++@@ -2871,9 +2810,8 @@ void ath_tx_node_init(struct ath_softc * ++ struct ath_atx_tid *tid; ++ int tidno, acno; ++ ++- for (tidno = 0, tid = &an->tid[tidno]; ++- tidno < IEEE80211_NUM_TIDS; ++- tidno++, tid++) { +++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { +++ tid = ATH_AN_2_TID(an, tidno); ++ tid->an = an; ++ tid->tidno = tidno; ++ tid->seq_start = tid->seq_next = 0; ++@@ -2881,11 +2819,14 @@ void ath_tx_node_init(struct ath_softc * ++ tid->baw_head = tid->baw_tail = 0; ++ tid->active = false; ++ tid->clear_ps_filter = true; ++- __skb_queue_head_init(&tid->buf_q); +++ tid->has_queued = false; ++ __skb_queue_head_init(&tid->retry_q); ++ INIT_LIST_HEAD(&tid->list); ++ acno = TID_TO_WME_AC(tidno); ++ tid->txq = sc->tx.txq_map[acno]; +++ +++ if (!an->sta) +++ break; /* just one multicast ath_atx_tid */ + } ++ } + -+ an = (struct ath_node *)sta->drv_priv; -+- tid = ath_get_skb_tid(sc, an, skb); -+ seq_first = tid->seq_start; -+ isba = ts->ts_flags & ATH9K_TX_BA; ++@@ -2895,9 +2836,8 @@ void ath_tx_node_cleanup(struct ath_soft ++ struct ath_txq *txq; ++ int tidno; + -+@@ -695,6 +694,7 @@ static void ath_tx_process_buffer(struct -+ struct ieee80211_tx_info *info; -+ struct ieee80211_sta *sta; -+ struct ieee80211_hdr *hdr; -++ struct ath_atx_tid *tid = NULL; -+ bool txok, flush; -+ -+ txok = !(ts->ts_status & ATH9K_TXERR_MASK); -+@@ -710,6 +710,12 @@ static void ath_tx_process_buffer(struct -+ -+ hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; -+ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); -++ if (sta) { -++ struct ath_node *an = (struct ath_node *)sta->drv_priv; -++ tid = ath_get_skb_tid(sc, an, bf->bf_mpdu); -++ if (ts->ts_status & (ATH9K_TXERR_FILT | ATH9K_TXERR_XRETRY)) -++ tid->clear_ps_filter = true; -++ } ++- for (tidno = 0, tid = &an->tid[tidno]; ++- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { ++- +++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { +++ tid = ATH_AN_2_TID(an, tidno); ++ txq = tid->txq; + -+ if (!bf_isampdu(bf)) { -+ if (!flush) { -+@@ -721,7 +727,7 @@ static void ath_tx_process_buffer(struct -+ } -+ ath_tx_complete_buf(sc, bf, txq, bf_head, sta, ts, txok); -+ } else -+- ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, ts, txok); -++ ath_tx_complete_aggr(sc, txq, bf, bf_head, sta, tid, ts, txok); ++ ath_txq_lock(sc, txq); ++@@ -2909,6 +2849,9 @@ void ath_tx_node_cleanup(struct ath_soft ++ tid->active = false; + -+ if (!flush) -+ ath_txq_schedule(sc, txq); -diff --git a/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch b/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch ++ ath_txq_unlock(sc, txq); +++ +++ if (!an->sta) +++ break; /* just one multicast ath_atx_tid */ ++ } ++ } ++ +diff --git a/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch b/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch deleted file mode 100644 -index 32a2ad6..0000000 ---- a/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch +index 2eeed22..0000000 +--- a/package/kernel/mac80211/patches/320-cfg80211-add-support-for-non-linear-skbs-in-ieee8021.patch +++ /dev/null -@@ -1,31 +0,0 @@ +@@ -1,159 +0,0 @@ -From: Felix Fietkau <nbd@openwrt.org> --Date: Thu, 18 Feb 2016 19:45:33 +0100 --Subject: [PATCH] mac80211: minstrel_ht: set default tx aggregation timeout to -- 0 -- --The value 5000 was put here with the addition of the timeout field to --ieee80211_start_tx_ba_session. It was originally added in mac80211 to --save resources for drivers like iwlwifi, which only supports a limited --number of concurrent aggregation sessions. -- --Since iwlwifi does not use minstrel_ht and other drivers don't need --this, 0 is a better default - especially since there have been --recent reports of aggregation setup related issues reproduced with --ath9k. This should improve stability without causing any adverse --effects. +-Date: Tue, 2 Feb 2016 14:39:10 +0100 +-Subject: [PATCH] cfg80211: add support for non-linear skbs in +- ieee80211_amsdu_to_8023s - --Cc: stable@vger.kernel.org -Signed-off-by: Felix Fietkau <nbd@openwrt.org> +-Signed-off-by: Johannes Berg <johannes.berg@intel.com> ---- - ----- a/net/mac80211/rc80211_minstrel_ht.c --+++ b/net/mac80211/rc80211_minstrel_ht.c --@@ -692,7 +692,7 @@ minstrel_aggr_check(struct ieee80211_sta -- if (likely(sta->ampdu_mlme.tid_tx[tid])) -- return; -- --- ieee80211_start_tx_ba_session(pubsta, tid, 5000); --+ ieee80211_start_tx_ba_session(pubsta, tid, 0); +---- a/net/wireless/util.c +-+++ b/net/wireless/util.c +-@@ -644,73 +644,75 @@ int ieee80211_data_from_8023(struct sk_b - } +- EXPORT_SYMBOL(ieee80211_data_from_8023); - -- static void -diff --git a/package/kernel/mac80211/patches/337-ath9k-Switch-to-using-mac80211-intermediate-software.patch b/package/kernel/mac80211/patches/337-ath9k-Switch-to-using-mac80211-intermediate-software.patch -new file mode 100644 -index 0000000..adfd6df ---- /dev/null -+++ b/package/kernel/mac80211/patches/337-ath9k-Switch-to-using-mac80211-intermediate-software.patch -@@ -0,0 +1,951 @@ -+From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk> -+Date: Wed, 6 Jul 2016 21:34:17 +0200 -+Subject: [PATCH] ath9k: Switch to using mac80211 intermediate software queues. -+MIME-Version: 1.0 -+Content-Type: text/plain; charset=UTF-8 -+Content-Transfer-Encoding: 8bit -+ -+This switches ath9k over to using the mac80211 intermediate software -+queueing mechanism for data packets. It removes the queueing inside the -+driver, except for the retry queue, and instead pulls from mac80211 when -+a packet is needed. The retry queue is used to store a packet that was -+pulled but can't be sent immediately. -+ -+The old code path in ath_tx_start that would queue packets has been -+removed completely, as has the qlen limit tunables (since there's no -+longer a queue in the driver to limit). -+ -+Based on Tim's original patch set, but reworked quite thoroughly. -+ -+Cc: Tim Shepard <shep@alum.mit.edu> -+Cc: Felix Fietkau <nbd@nbd.name> -+Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/ath9k.h -++++ b/drivers/net/wireless/ath/ath9k/ath9k.h -+@@ -91,7 +91,6 @@ int ath_descdma_setup(struct ath_softc * -+ #define ATH_RXBUF 512 -+ #define ATH_TXBUF 512 -+ #define ATH_TXBUF_RESERVE 5 -+-#define ATH_MAX_QDEPTH (ATH_TXBUF / 4 - ATH_TXBUF_RESERVE) -+ #define ATH_TXMAXTRY 13 -+ #define ATH_MAX_SW_RETRIES 30 -+ -+@@ -145,7 +144,7 @@ int ath_descdma_setup(struct ath_softc * -+ #define BAW_WITHIN(_start, _bawsz, _seqno) \ -+ ((((_seqno) - (_start)) & 4095) < (_bawsz)) -+ -+-#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) -++#define ATH_AN_2_TID(_an, _tidno) ath_node_to_tid(_an, _tidno) -+ -+ #define IS_HT_RATE(rate) (rate & 0x80) -+ #define IS_CCK_RATE(rate) ((rate >= 0x18) && (rate <= 0x1e)) -+@@ -164,7 +163,6 @@ struct ath_txq { -+ spinlock_t axq_lock; -+ u32 axq_depth; -+ u32 axq_ampdu_depth; -+- bool stopped; -+ bool axq_tx_inprogress; -+ struct list_head txq_fifo[ATH_TXFIFO_DEPTH]; -+ u8 txq_headidx; -+@@ -232,7 +230,6 @@ struct ath_buf { -+ -+ struct ath_atx_tid { -+ struct list_head list; -+- struct sk_buff_head buf_q; -+ struct sk_buff_head retry_q; -+ struct ath_node *an; -+ struct ath_txq *txq; -+@@ -247,13 +244,13 @@ struct ath_atx_tid { -+ s8 bar_index; -+ bool active; -+ bool clear_ps_filter; -++ bool has_queued; -+ }; -+ -+ struct ath_node { -+ struct ath_softc *sc; -+ struct ieee80211_sta *sta; /* station struct we're part of */ -+ struct ieee80211_vif *vif; /* interface with which we're associated */ -+- struct ath_atx_tid tid[IEEE80211_NUM_TIDS]; -+ -+ u16 maxampdu; -+ u8 mpdudensity; -+@@ -276,7 +273,6 @@ struct ath_tx_control { -+ struct ath_node *an; -+ struct ieee80211_sta *sta; -+ u8 paprd; -+- bool force_channel; -+ }; -+ -+ -+@@ -293,7 +289,6 @@ struct ath_tx { -+ struct ath_descdma txdma; -+ struct ath_txq *txq_map[IEEE80211_NUM_ACS]; -+ struct ath_txq *uapsdq; -+- u32 txq_max_pending[IEEE80211_NUM_ACS]; -+ u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32]; -+ }; -+ -+@@ -421,6 +416,22 @@ struct ath_offchannel { -+ int duration; -+ }; -+ -++static inline struct ath_atx_tid * -++ath_node_to_tid(struct ath_node *an, u8 tidno) -++{ -++ struct ieee80211_sta *sta = an->sta; -++ struct ieee80211_vif *vif = an->vif; -++ struct ieee80211_txq *txq; -++ -++ BUG_ON(!vif); -++ if (sta) -++ txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)]; -++ else -++ txq = vif->txq; -++ -++ return (struct ath_atx_tid *) txq->drv_priv; -++} -++ -+ #define case_rtn_string(val) case val: return #val -+ -+ #define ath_for_each_chanctx(_sc, _ctx) \ -+@@ -575,7 +586,6 @@ void ath_tx_edma_tasklet(struct ath_soft -+ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, -+ u16 tid, u16 *ssn); -+ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -+-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -+ -+ void ath_tx_aggr_wakeup(struct ath_softc *sc, struct ath_node *an); -+ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, -+@@ -585,6 +595,7 @@ void ath9k_release_buffered_frames(struc -+ u16 tids, int nframes, -+ enum ieee80211_frame_release_type reason, -+ bool more_data); -++void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue); -+ -+ /********/ -+ /* VIFs */ -+--- a/drivers/net/wireless/ath/ath9k/channel.c -++++ b/drivers/net/wireless/ath/ath9k/channel.c -+@@ -1007,7 +1007,6 @@ static void ath_scan_send_probe(struct a -+ goto error; -+ -+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; -+- txctl.force_channel = true; -+ if (ath_tx_start(sc->hw, skb, &txctl)) -+ goto error; +-+static struct sk_buff * +-+__ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, +-+ int offset, int len) +-+{ +-+ struct sk_buff *frame; +-+ +-+ if (skb->len - offset < len) +-+ return NULL; +-+ +-+ /* +-+ * Allocate and reserve two bytes more for payload +-+ * alignment since sizeof(struct ethhdr) is 14. +-+ */ +-+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len); +-+ +-+ skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); +-+ skb_copy_bits(skb, offset, skb_put(frame, len), len); +-+ +-+ return frame; +-+} +- +- void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list, +- const u8 *addr, enum nl80211_iftype iftype, +- const unsigned int extra_headroom, +- bool has_80211_header) +- { +-+ unsigned int hlen = ALIGN(extra_headroom, 4); +- struct sk_buff *frame = NULL; +- u16 ethertype; +- u8 *payload; +-- const struct ethhdr *eth; +-- int remaining, err; +-- u8 dst[ETH_ALEN], src[ETH_ALEN]; +-- +-- if (skb_linearize(skb)) +-- goto out; +-+ int offset = 0, remaining, err; +-+ struct ethhdr eth; +-+ bool reuse_skb = true; +-+ bool last = false; +- +- if (has_80211_header) { +-- err = ieee80211_data_to_8023(skb, addr, iftype); +-+ err = __ieee80211_data_to_8023(skb, ð, addr, iftype); +- if (err) +- goto out; +-- +-- /* skip the wrapping header */ +-- eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr)); +-- if (!eth) +-- goto out; +-- } else { +-- eth = (struct ethhdr *) skb->data; +- } +- +-- while (skb != frame) { +-+ while (!last) { +-+ unsigned int subframe_len; +-+ int len; +- u8 padding; +-- __be16 len = eth->h_proto; +-- unsigned int subframe_len = sizeof(struct ethhdr) + ntohs(len); +-- +-- remaining = skb->len; +-- memcpy(dst, eth->h_dest, ETH_ALEN); +-- memcpy(src, eth->h_source, ETH_ALEN); +- +-+ skb_copy_bits(skb, offset, ð, sizeof(eth)); +-+ len = ntohs(eth.h_proto); +-+ subframe_len = sizeof(struct ethhdr) + len; +- padding = (4 - subframe_len) & 0x3; +-+ +- /* the last MSDU has no padding */ +-+ remaining = skb->len - offset; +- if (subframe_len > remaining) +- goto purge; +- +-- skb_pull(skb, sizeof(struct ethhdr)); +-+ offset += sizeof(struct ethhdr); +- /* reuse skb for the last subframe */ +-- if (remaining <= subframe_len + padding) +-+ last = remaining <= subframe_len + padding; +-+ if (!skb_is_nonlinear(skb) && last) { +-+ skb_pull(skb, offset); +- frame = skb; +-- else { +-- unsigned int hlen = ALIGN(extra_headroom, 4); +-- /* +-- * Allocate and reserve two bytes more for payload +-- * alignment since sizeof(struct ethhdr) is 14. +-- */ +-- frame = dev_alloc_skb(hlen + subframe_len + 2); +-+ reuse_skb = true; +-+ } else { +-+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len); +- if (!frame) +- goto purge; +- +-- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); +-- memcpy(skb_put(frame, ntohs(len)), skb->data, +-- ntohs(len)); +-- +-- eth = (struct ethhdr *)skb_pull(skb, ntohs(len) + +-- padding); +-- if (!eth) { +-- dev_kfree_skb(frame); +-- goto purge; +-- } +-+ offset += len + padding; +- } +- +- skb_reset_network_header(frame); +-@@ -719,24 +721,20 @@ void ieee80211_amsdu_to_8023s(struct sk_ +- +- payload = frame->data; +- ethertype = (payload[6] << 8) | payload[7]; +-- +- if (likely((ether_addr_equal(payload, rfc1042_header) && +- ethertype != ETH_P_AARP && ethertype != ETH_P_IPX) || +- ether_addr_equal(payload, bridge_tunnel_header))) { +-- /* remove RFC1042 or Bridge-Tunnel +-- * encapsulation and replace EtherType */ +-- skb_pull(frame, 6); +-- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); +-- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); +-- } else { +-- memcpy(skb_push(frame, sizeof(__be16)), &len, +-- sizeof(__be16)); +-- memcpy(skb_push(frame, ETH_ALEN), src, ETH_ALEN); +-- memcpy(skb_push(frame, ETH_ALEN), dst, ETH_ALEN); +-+ eth.h_proto = htons(ethertype); +-+ skb_pull(frame, ETH_ALEN + 2); +- } +-+ +-+ memcpy(skb_push(frame, sizeof(eth)), ð, sizeof(eth)); +- __skb_queue_tail(list, frame); +- } +- +-+ if (!reuse_skb) +-+ dev_kfree_skb(skb); +-+ +- return; +- +- purge: +diff --git a/package/kernel/mac80211/patches/321-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch b/package/kernel/mac80211/patches/321-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch +new file mode 100644 +index 0000000..9caa76d +--- /dev/null ++++ b/package/kernel/mac80211/patches/321-ath9k_hw-reset-AHB-WMAC-interface-on-AR91xx.patch +@@ -0,0 +1,25 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Sat, 9 Jul 2016 15:25:24 +0200 ++Subject: [PATCH] ath9k_hw: reset AHB-WMAC interface on AR91xx ++ ++Should fix a few stability issues ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/hw.c +++++ b/drivers/net/wireless/ath/ath9k/hw.c ++@@ -1398,8 +1398,12 @@ static bool ath9k_hw_set_reset(struct at ++ if (!AR_SREV_9100(ah)) ++ REG_WRITE(ah, AR_RC, 0); + -+@@ -1130,7 +1129,6 @@ ath_chanctx_send_vif_ps_frame(struct ath -+ memset(&txctl, 0, sizeof(txctl)); -+ txctl.txq = sc->tx.txq_map[IEEE80211_AC_VO]; -+ txctl.sta = sta; -+- txctl.force_channel = true; -+ if (ath_tx_start(sc->hw, skb, &txctl)) { -+ ieee80211_free_txskb(sc->hw, skb); -+ return false; -+--- a/drivers/net/wireless/ath/ath9k/debug.c -++++ b/drivers/net/wireless/ath/ath9k/debug.c -+@@ -600,7 +600,6 @@ static int read_file_xmit(struct seq_fil -+ PR("MPDUs XRetried: ", xretries); -+ PR("Aggregates: ", a_aggr); -+ PR("AMPDUs Queued HW:", a_queued_hw); -+- PR("AMPDUs Queued SW:", a_queued_sw); -+ PR("AMPDUs Completed:", a_completed); -+ PR("AMPDUs Retried: ", a_retries); -+ PR("AMPDUs XRetried: ", a_xretries); -+@@ -629,8 +628,7 @@ static void print_queue(struct ath_softc -+ seq_printf(file, "%s: %d ", "qnum", txq->axq_qnum); -+ seq_printf(file, "%s: %2d ", "qdepth", txq->axq_depth); -+ seq_printf(file, "%s: %2d ", "ampdu-depth", txq->axq_ampdu_depth); -+- seq_printf(file, "%s: %3d ", "pending", txq->pending_frames); -+- seq_printf(file, "%s: %d\n", "stopped", txq->stopped); -++ seq_printf(file, "%s: %3d\n", "pending", txq->pending_frames); ++- if (AR_SREV_9100(ah)) +++ if (AR_SREV_9100(ah)) { +++ /* Reset the AHB-WMAC interface */ +++ if (ah->external_reset) +++ ah->external_reset(); ++ udelay(50); +++ } + -+ ath_txq_unlock(sc, txq); ++ return true; + } -+@@ -1208,7 +1206,6 @@ static const char ath9k_gstrings_stats[] -+ AMKSTR(d_tx_mpdu_xretries), -+ AMKSTR(d_tx_aggregates), -+ AMKSTR(d_tx_ampdus_queued_hw), -+- AMKSTR(d_tx_ampdus_queued_sw), -+ AMKSTR(d_tx_ampdus_completed), -+ AMKSTR(d_tx_ampdu_retries), -+ AMKSTR(d_tx_ampdu_xretries), -+@@ -1288,7 +1285,6 @@ void ath9k_get_et_stats(struct ieee80211 -+ AWDATA(xretries); -+ AWDATA(a_aggr); -+ AWDATA(a_queued_hw); -+- AWDATA(a_queued_sw); -+ AWDATA(a_completed); -+ AWDATA(a_retries); -+ AWDATA(a_xretries); -+@@ -1346,14 +1342,6 @@ int ath9k_init_debug(struct ath_hw *ah) -+ read_file_xmit); -+ debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy, -+ read_file_queues); -+- debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, -+- &sc->tx.txq_max_pending[IEEE80211_AC_BK]); -+- debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, -+- &sc->tx.txq_max_pending[IEEE80211_AC_BE]); -+- debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, -+- &sc->tx.txq_max_pending[IEEE80211_AC_VI]); -+- debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, -+- &sc->tx.txq_max_pending[IEEE80211_AC_VO]); -+ debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy, -+ read_file_misc); -+ debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy, -+--- a/drivers/net/wireless/ath/ath9k/debug.h -++++ b/drivers/net/wireless/ath/ath9k/debug.h -+@@ -147,7 +147,6 @@ struct ath_interrupt_stats { -+ * @completed: Total MPDUs (non-aggr) completed -+ * @a_aggr: Total no. of aggregates queued -+ * @a_queued_hw: Total AMPDUs queued to hardware -+- * @a_queued_sw: Total AMPDUs queued to software queues -+ * @a_completed: Total AMPDUs completed -+ * @a_retries: No. of AMPDUs retried (SW) -+ * @a_xretries: No. of AMPDUs dropped due to xretries -+@@ -174,7 +173,6 @@ struct ath_tx_stats { -+ u32 xretries; -+ u32 a_aggr; -+ u32 a_queued_hw; -+- u32 a_queued_sw; -+ u32 a_completed; -+ u32 a_retries; -+ u32 a_xretries; -+--- a/drivers/net/wireless/ath/ath9k/debug_sta.c -++++ b/drivers/net/wireless/ath/ath9k/debug_sta.c -+@@ -52,8 +52,8 @@ static ssize_t read_file_node_aggr(struc -+ "TID", "SEQ_START", "SEQ_NEXT", "BAW_SIZE", -+ "BAW_HEAD", "BAW_TAIL", "BAR_IDX", "SCHED", "PAUSED"); -+ -+- for (tidno = 0, tid = &an->tid[tidno]; -+- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { -++ tid = ath_node_to_tid(an, tidno); -+ txq = tid->txq; -+ ath_txq_lock(sc, txq); -+ if (tid->active) { -+--- a/drivers/net/wireless/ath/ath9k/init.c -++++ b/drivers/net/wireless/ath/ath9k/init.c -+@@ -358,7 +358,6 @@ static int ath9k_init_queues(struct ath_ -+ for (i = 0; i < IEEE80211_NUM_ACS; i++) { -+ sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); -+ sc->tx.txq_map[i]->mac80211_qnum = i; -+- sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; -+ } -+ return 0; +diff --git a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch b/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch +deleted file mode 100644 +index c4155a1..0000000 +--- a/package/kernel/mac80211/patches/321-mac80211-Parse-legacy-and-HT-rate-in-injected-frames.patch ++++ /dev/null +@@ -1,155 +0,0 @@ +-From: Sven Eckelmann <sven@narfation.org> +-Date: Tue, 26 Jan 2016 17:11:13 +0100 +-Subject: [PATCH] mac80211: Parse legacy and HT rate in injected frames +- +-Drivers/devices without their own rate control algorithm can get the +-information what rates they should use from either the radiotap header of +-injected frames or from the rate control algorithm. But the parsing of the +-legacy rate information from the radiotap header was removed in commit +-e6a9854b05c1 ("mac80211/drivers: rewrite the rate control API"). +- +-The removal of this feature heavily reduced the usefulness of frame +-injection when wanting to simulate specific transmission behavior. Having +-rate parsing together with MCS rates and retry support allows a fine +-grained selection of the tx behavior of injected frames for these kind of +-tests. +- +-Signed-off-by: Sven Eckelmann <sven@narfation.org> +-Cc: Simon Wunderlich <sw@simonwunderlich.de> +-Signed-off-by: Johannes Berg <johannes.berg@intel.com> +---- +- +---- a/include/net/mac80211.h +-+++ b/include/net/mac80211.h +-@@ -708,12 +708,14 @@ enum mac80211_tx_info_flags { +- * protocol frame (e.g. EAP) +- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll +- * frame (PS-Poll or uAPSD). +-+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information +- * +- * These flags are used in tx_info->control.flags. +- */ +- enum mac80211_tx_control_flags { +- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), +- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), +-+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), +- }; +- +- /* +---- a/net/mac80211/tx.c +-+++ b/net/mac80211/tx.c +-@@ -710,6 +710,10 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021 +- +- info->control.short_preamble = txrc.short_preamble; +- +-+ /* don't ask rate control when rate already injected via radiotap */ +-+ if (info->control.flags & IEEE80211_TX_CTRL_RATE_INJECT) +-+ return TX_CONTINUE; +-+ +- if (tx->sta) +- assoc = test_sta_flag(tx->sta, WLAN_STA_ASSOC); +- +-@@ -1665,15 +1669,24 @@ void ieee80211_xmit(struct ieee80211_sub +- ieee80211_tx(sdata, sta, skb, false); +- } +- +--static bool ieee80211_parse_tx_radiotap(struct sk_buff *skb) +-+static bool ieee80211_parse_tx_radiotap(struct ieee80211_local *local, +-+ struct sk_buff *skb) +- { +- struct ieee80211_radiotap_iterator iterator; +- struct ieee80211_radiotap_header *rthdr = +- (struct ieee80211_radiotap_header *) skb->data; +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +-+ struct ieee80211_supported_band *sband = +-+ local->hw.wiphy->bands[info->band]; +- int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len, +- NULL); +- u16 txflags; +-+ u16 rate = 0; +-+ bool rate_found = false; +-+ u8 rate_retries = 0; +-+ u16 rate_flags = 0; +-+ u8 mcs_known, mcs_flags; +-+ int i; +- +- info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | +- IEEE80211_TX_CTL_DONTFRAG; +-@@ -1724,6 +1737,35 @@ static bool ieee80211_parse_tx_radiotap( +- info->flags |= IEEE80211_TX_CTL_NO_ACK; +- break; +- +-+ case IEEE80211_RADIOTAP_RATE: +-+ rate = *iterator.this_arg; +-+ rate_flags = 0; +-+ rate_found = true; +-+ break; +-+ +-+ case IEEE80211_RADIOTAP_DATA_RETRIES: +-+ rate_retries = *iterator.this_arg; +-+ break; +-+ +-+ case IEEE80211_RADIOTAP_MCS: +-+ mcs_known = iterator.this_arg[0]; +-+ mcs_flags = iterator.this_arg[1]; +-+ if (!(mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_MCS)) +-+ break; +-+ +-+ rate_found = true; +-+ rate = iterator.this_arg[2]; +-+ rate_flags = IEEE80211_TX_RC_MCS; +-+ +-+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_GI && +-+ mcs_flags & IEEE80211_RADIOTAP_MCS_SGI) +-+ rate_flags |= IEEE80211_TX_RC_SHORT_GI; +-+ +-+ if (mcs_known & IEEE80211_RADIOTAP_MCS_HAVE_BW && +-+ mcs_flags & IEEE80211_RADIOTAP_MCS_BW_40) +-+ rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; +-+ break; +-+ +- /* +- * Please update the file +- * Documentation/networking/mac80211-injection.txt +-@@ -1738,6 +1780,32 @@ static bool ieee80211_parse_tx_radiotap( +- if (ret != -ENOENT) /* ie, if we didn't simply run out of fields */ +- return false; +- +-+ if (rate_found) { +-+ info->control.flags |= IEEE80211_TX_CTRL_RATE_INJECT; +-+ +-+ for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { +-+ info->control.rates[i].idx = -1; +-+ info->control.rates[i].flags = 0; +-+ info->control.rates[i].count = 0; +-+ } +-+ +-+ if (rate_flags & IEEE80211_TX_RC_MCS) { +-+ info->control.rates[0].idx = rate; +-+ } else { +-+ for (i = 0; i < sband->n_bitrates; i++) { +-+ if (rate * 5 != sband->bitrates[i].bitrate) +-+ continue; +-+ +-+ info->control.rates[0].idx = i; +-+ break; +-+ } +-+ } +-+ +-+ info->control.rates[0].flags = rate_flags; +-+ info->control.rates[0].count = min_t(u8, rate_retries + 1, +-+ local->hw.max_rate_tries); +-+ } +-+ +- /* +- * remove the radiotap header +- * iterator->_max_length was sanity-checked against +-@@ -1819,7 +1887,7 @@ netdev_tx_t ieee80211_monitor_start_xmit +- IEEE80211_TX_CTL_INJECTED; +- +- /* process and remove the injection radiotap header */ +-- if (!ieee80211_parse_tx_radiotap(skb)) +-+ if (!ieee80211_parse_tx_radiotap(local, skb)) +- goto fail; +- +- rcu_read_lock(); +diff --git a/package/kernel/mac80211/patches/322-ath9k_hw-issue-external-reset-for-QCA9550.patch b/package/kernel/mac80211/patches/322-ath9k_hw-issue-external-reset-for-QCA9550.patch +new file mode 100644 +index 0000000..5d4e849 +--- /dev/null ++++ b/package/kernel/mac80211/patches/322-ath9k_hw-issue-external-reset-for-QCA9550.patch +@@ -0,0 +1,125 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Sat, 9 Jul 2016 15:26:44 +0200 ++Subject: [PATCH] ath9k_hw: issue external reset for QCA9550 ++ ++The RTC interface on the SoC needs to be reset along with the rest of ++the WMAC. ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/hw.c +++++ b/drivers/net/wireless/ath/ath9k/hw.c ++@@ -1275,39 +1275,56 @@ void ath9k_hw_get_delta_slope_vals(struc ++ *coef_exponent = coef_exp - 16; + } -+@@ -873,6 +872,7 @@ static void ath9k_set_hw_capab(struct at -+ hw->max_rate_tries = 10; -+ hw->sta_data_size = sizeof(struct ath_node); -+ hw->vif_data_size = sizeof(struct ath_vif); -++ hw->txq_data_size = sizeof(struct ath_atx_tid); -+ hw->extra_tx_headroom = 4; -+ -+ hw->wiphy->available_antennas_rx = BIT(ah->caps.max_rxchains) - 1; -+--- a/drivers/net/wireless/ath/ath9k/main.c -++++ b/drivers/net/wireless/ath/ath9k/main.c -+@@ -1897,9 +1897,11 @@ static int ath9k_ampdu_action(struct iee -+ bool flush = false; -+ int ret = 0; -+ struct ieee80211_sta *sta = params->sta; -++ struct ath_node *an = (struct ath_node *)sta->drv_priv; -+ enum ieee80211_ampdu_mlme_action action = params->action; -+ u16 tid = params->tid; -+ u16 *ssn = ¶ms->ssn; -++ struct ath_atx_tid *atid; -+ -+ mutex_lock(&sc->mutex); -+ -+@@ -1932,9 +1934,9 @@ static int ath9k_ampdu_action(struct iee -+ ath9k_ps_restore(sc); -+ break; -+ case IEEE80211_AMPDU_TX_OPERATIONAL: -+- ath9k_ps_wakeup(sc); -+- ath_tx_aggr_resume(sc, sta, tid); -+- ath9k_ps_restore(sc); -++ atid = ath_node_to_tid(an, tid); -++ atid->baw_size = IEEE80211_MIN_AMPDU_BUF << -++ sta->ht_cap.ampdu_factor; -+ break; -+ default: -+ ath_err(ath9k_hw_common(sc->sc_ah), "Unknown AMPDU action\n"); -+@@ -2696,4 +2698,5 @@ struct ieee80211_ops ath9k_ops = { -+ .sw_scan_start = ath9k_sw_scan_start, -+ .sw_scan_complete = ath9k_sw_scan_complete, -+ .get_txpower = ath9k_get_txpower, -++ .wake_tx_queue = ath9k_wake_tx_queue, -+ }; -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -67,6 +67,8 @@ static struct ath_buf *ath_tx_setup_buff -+ struct ath_txq *txq, -+ struct ath_atx_tid *tid, -+ struct sk_buff *skb); -++static int ath_tx_prepare(struct ieee80211_hw *hw, struct sk_buff *skb, -++ struct ath_tx_control *txctl); + -+ enum { -+ MCS_HT20, -+@@ -137,6 +139,26 @@ static void ath_tx_queue_tid(struct ath_ -+ list_add_tail(&tid->list, list); -+ } ++-/* AR9330 WAR: ++- * call external reset function to reset WMAC if: ++- * - doing a cold reset ++- * - we have pending frames in the TX queues. ++- */ ++-static bool ath9k_hw_ar9330_reset_war(struct ath_hw *ah, int type) +++static bool ath9k_hw_need_external_reset(struct ath_hw *ah, int type) ++ { ++- int i, npend = 0; +++ int i; + -++void ath9k_wake_tx_queue(struct ieee80211_hw *hw, struct ieee80211_txq *queue) -++{ -++ struct ath_softc *sc = hw->priv; -++ struct ath_common *common = ath9k_hw_common(sc->sc_ah); -++ struct ath_atx_tid *tid = (struct ath_atx_tid *) queue->drv_priv; -++ struct ath_txq *txq = tid->txq; -++ -++ ath_dbg(common, QUEUE, "Waking TX queue: %pM (%d)\n", -++ queue->sta ? queue->sta->addr : queue->vif->addr, -++ tid->tidno); -++ -++ ath_txq_lock(sc, txq); -++ -++ tid->has_queued = true; -++ ath_tx_queue_tid(sc, txq, tid); -++ ath_txq_schedule(sc, txq); ++- for (i = 0; i < AR_NUM_QCU; i++) { ++- npend = ath9k_hw_numtxpending(ah, i); ++- if (npend) ++- break; +++ if (type == ATH9K_RESET_COLD) +++ return true; ++ -++ ath_txq_unlock(sc, txq); -++} +++ if (AR_SREV_9550(ah)) +++ return true; ++ -+ static struct ath_frame_info *get_frame_info(struct sk_buff *skb) -+ { -+ struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); -+@@ -179,7 +201,6 @@ static void ath_set_rates(struct ieee802 -+ static void ath_txq_skb_done(struct ath_softc *sc, struct ath_txq *txq, -+ struct sk_buff *skb) -+ { -+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ struct ath_frame_info *fi = get_frame_info(skb); -+ int q = fi->txq; -+ -+@@ -190,14 +211,6 @@ static void ath_txq_skb_done(struct ath_ -+ if (WARN_ON(--txq->pending_frames < 0)) -+ txq->pending_frames = 0; -+ -+- if (txq->stopped && -+- txq->pending_frames < sc->tx.txq_max_pending[q]) { -+- if (ath9k_is_chanctx_enabled()) -+- ieee80211_wake_queue(sc->hw, info->hw_queue); -+- else -+- ieee80211_wake_queue(sc->hw, q); -+- txq->stopped = false; -+- } -+ } +++ /* AR9330 WAR: +++ * call external reset function to reset WMAC if: +++ * - doing a cold reset +++ * - we have pending frames in the TX queues. +++ */ +++ if (AR_SREV_9330(ah)) { +++ for (i = 0; i < AR_NUM_QCU; i++) { +++ if (ath9k_hw_numtxpending(ah, i)) +++ return true; +++ } ++ } + -+ static struct ath_atx_tid * -+@@ -207,9 +220,48 @@ ath_get_skb_tid(struct ath_softc *sc, st -+ return ATH_AN_2_TID(an, tidno); -+ } ++- if (ah->external_reset && ++- (npend || type == ATH9K_RESET_COLD)) { ++- int reset_err = 0; +++ return false; +++} + -++static struct sk_buff * -++ath_tid_pull(struct ath_atx_tid *tid) ++- ath_dbg(ath9k_hw_common(ah), RESET, ++- "reset MAC via external reset\n"); +++static bool ath9k_hw_external_reset(struct ath_hw *ah, int type) ++{ -++ struct ieee80211_txq *txq = container_of((void*)tid, struct ieee80211_txq, drv_priv); -++ struct ath_softc *sc = tid->an->sc; -++ struct ieee80211_hw *hw = sc->hw; -++ struct ath_tx_control txctl = { -++ .txq = tid->txq, -++ .sta = tid->an->sta, -++ }; -++ struct sk_buff *skb; -++ struct ath_frame_info *fi; -++ int q; -++ -++ if (!tid->has_queued) -++ return NULL; -++ -++ skb = ieee80211_tx_dequeue(hw, txq); -++ if (!skb) { -++ tid->has_queued = false; -++ return NULL; -++ } -++ -++ if (ath_tx_prepare(hw, skb, &txctl)) { -++ ieee80211_free_txskb(hw, skb); -++ return NULL; -++ } +++ int err; ++ ++- reset_err = ah->external_reset(); ++- if (reset_err) { ++- ath_err(ath9k_hw_common(ah), ++- "External reset failed, err=%d\n", ++- reset_err); ++- return false; ++- } +++ if (!ah->external_reset || !ath9k_hw_need_external_reset(ah, type)) +++ return true; ++ ++- REG_WRITE(ah, AR_RTC_RESET, 1); +++ ath_dbg(ath9k_hw_common(ah), RESET, +++ "reset MAC via external reset\n"); ++ -++ q = skb_get_queue_mapping(skb); -++ if (tid->txq == sc->tx.txq_map[q]) { -++ fi = get_frame_info(skb); -++ fi->txq = q; -++ ++tid->txq->pending_frames; +++ err = ah->external_reset(); +++ if (err) { +++ ath_err(ath9k_hw_common(ah), +++ "External reset failed, err=%d\n", err); +++ return false; ++ } ++ -++ return skb; -++ } -++ +++ if (AR_SREV_9550(ah)) { +++ REG_WRITE(ah, AR_RTC_RESET, 0); +++ udelay(10); ++ } ++ +++ REG_WRITE(ah, AR_RTC_RESET, 1); +++ udelay(10); ++ -+ static bool ath_tid_has_buffered(struct ath_atx_tid *tid) -+ { -+- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); -++ return !skb_queue_empty(&tid->retry_q) || tid->has_queued; ++ return true; + } + -+ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) -+@@ -218,46 +270,11 @@ static struct sk_buff *ath_tid_dequeue(s -+ -+ skb = __skb_dequeue(&tid->retry_q); -+ if (!skb) -+- skb = __skb_dequeue(&tid->buf_q); -++ skb = ath_tid_pull(tid); -+ -+ return skb; -+ } ++@@ -1360,24 +1377,23 @@ static bool ath9k_hw_set_reset(struct at ++ rst_flags |= AR_RTC_RC_MAC_COLD; ++ } + -+-/* -+- * ath_tx_tid_change_state: -+- * - clears a-mpdu flag of previous session -+- * - force sequence number allocation to fix next BlockAck Window -+- */ -+-static void -+-ath_tx_tid_change_state(struct ath_softc *sc, struct ath_atx_tid *tid) -+-{ -+- struct ath_txq *txq = tid->txq; -+- struct ieee80211_tx_info *tx_info; -+- struct sk_buff *skb, *tskb; -+- struct ath_buf *bf; -+- struct ath_frame_info *fi; -+- -+- skb_queue_walk_safe(&tid->buf_q, skb, tskb) { -+- fi = get_frame_info(skb); -+- bf = fi->bf; -+- -+- tx_info = IEEE80211_SKB_CB(skb); -+- tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU; -+- -+- if (bf) -+- continue; -+- -+- bf = ath_tx_setup_buffer(sc, txq, tid, skb); -+- if (!bf) { -+- __skb_unlink(skb, &tid->buf_q); -+- ath_txq_skb_done(sc, txq, skb); -+- ieee80211_free_txskb(sc->hw, skb); -+- continue; -+- } ++- if (AR_SREV_9330(ah)) { ++- if (!ath9k_hw_ar9330_reset_war(ah, type)) ++- return false; +- } +- -+-} -+- -+ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) -+ { -+ struct ath_txq *txq = tid->txq; -+@@ -898,20 +915,16 @@ static int ath_compute_num_delims(struct ++ if (ath9k_hw_mci_is_enabled(ah)) ++ ar9003_mci_check_gpm_offset(ah); + -+ static struct ath_buf * -+ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq, -+- struct ath_atx_tid *tid, struct sk_buff_head **q) -++ struct ath_atx_tid *tid) ++ /* DMA HALT added to resolve ar9300 and ar9580 bus error during ++- * RTC_RC reg read +++ * RTC_RC reg read. Also needed for AR9550 external reset ++ */ ++- if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) { +++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) { ++ REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); ++ ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK, ++ 20 * AH_WAIT_TIMEOUT); ++- REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); ++ } ++ +++ ath9k_hw_external_reset(ah, type); +++ +++ if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) +++ REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ); +++ ++ REG_WRITE(ah, AR_RTC_RC, rst_flags); ++ ++ REGWRITE_BUFFER_FLUSH(ah); +diff --git a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch b/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch +deleted file mode 100644 +index e7bfb9c..0000000 +--- a/package/kernel/mac80211/patches/322-mac80211-add-A-MSDU-tx-support.patch ++++ /dev/null +@@ -1,317 +0,0 @@ +-From: Felix Fietkau <nbd@openwrt.org> +-Date: Fri, 5 Feb 2016 01:38:51 +0100 +-Subject: [PATCH] mac80211: add A-MSDU tx support +- +-Requires software tx queueing support. frag_list support (for zero-copy) +-is optional. +- +-Signed-off-by: Felix Fietkau <nbd@openwrt.org> +---- +- +---- a/include/net/mac80211.h +-+++ b/include/net/mac80211.h +-@@ -709,6 +709,7 @@ enum mac80211_tx_info_flags { +- * @IEEE80211_TX_CTRL_PS_RESPONSE: This frame is a response to a poll +- * frame (PS-Poll or uAPSD). +- * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information +-+ * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame +- * +- * These flags are used in tx_info->control.flags. +- */ +-@@ -716,6 +717,7 @@ enum mac80211_tx_control_flags { +- IEEE80211_TX_CTRL_PORT_CTRL_PROTO = BIT(0), +- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), +- IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), +-+ IEEE80211_TX_CTRL_AMSDU = BIT(3), +- }; +- +- /* +-@@ -1728,6 +1730,7 @@ struct ieee80211_sta_rates { +- * size is min(max_amsdu_len, 7935) bytes. +- * Both additional HT limits must be enforced by the low level driver. +- * This is defined by the spec (IEEE 802.11-2012 section 8.3.2.2 NOTE 2). +-+ * @max_rc_amsdu_len: Maximum A-MSDU size in bytes recommended by rate control. +- * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) +- */ +- struct ieee80211_sta { +-@@ -1748,6 +1751,7 @@ struct ieee80211_sta { +- bool mfp; +- u8 max_amsdu_subframes; +- u16 max_amsdu_len; +-+ u16 max_rc_amsdu_len; +- +- struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; +- +-@@ -1961,6 +1965,15 @@ struct ieee80211_txq { +- * order and does not need to manage its own reorder buffer or BA session +- * timeout. +- * +-+ * @IEEE80211_HW_TX_AMSDU: Hardware (or driver) supports software aggregated +-+ * A-MSDU frames. Requires software tx queueing and fast-xmit support. +-+ * When not using minstrel/minstrel_ht rate control, the driver should +-+ * limit the maximum A-MSDU size based on the current tx rate by setting +-+ * max_rc_amsdu_len in struct ieee80211_sta. +-+ * +-+ * @IEEE80211_HW_TX_FRAG_LIST: Hardware (or driver) supports sending frag_list +-+ * skbs, needed for zero-copy software A-MSDU. +-+ * +- * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays +- */ +- enum ieee80211_hw_flags { +-@@ -1998,6 +2011,8 @@ enum ieee80211_hw_flags { +- IEEE80211_HW_BEACON_TX_STATUS, +- IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR, +- IEEE80211_HW_SUPPORTS_REORDERING_BUFFER, +-+ IEEE80211_HW_TX_AMSDU, +-+ IEEE80211_HW_TX_FRAG_LIST, +- +- /* keep last, obviously */ +- NUM_IEEE80211_HW_FLAGS +-@@ -2070,6 +2085,9 @@ enum ieee80211_hw_flags { +- * size is smaller (an example is LinkSys WRT120N with FW v1.0.07 +- * build 002 Jun 18 2012). +- * +-+ * @max_tx_fragments: maximum number of tx buffers per (A)-MSDU, sum +-+ * of 1 + skb_shinfo(skb)->nr_frags for each skb in the frag_list. +-+ * +- * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX +- * (if %IEEE80211_HW_QUEUE_CONTROL is set) +- * +-@@ -2124,6 +2142,7 @@ struct ieee80211_hw { +- u8 max_rate_tries; +- u8 max_rx_aggregation_subframes; +- u8 max_tx_aggregation_subframes; +-+ u8 max_tx_fragments; +- u8 offchannel_tx_hw_queue; +- u8 radiotap_mcs_details; +- u16 radiotap_vht_details; +---- a/net/mac80211/agg-tx.c +-+++ b/net/mac80211/agg-tx.c +-@@ -935,6 +935,7 @@ void ieee80211_process_addba_resp(struct +- size_t len) +- { +- struct tid_ampdu_tx *tid_tx; +-+ struct ieee80211_txq *txq; +- u16 capab, tid; +- u8 buf_size; +- bool amsdu; +-@@ -945,6 +946,10 @@ void ieee80211_process_addba_resp(struct +- buf_size = (capab & IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK) >> 6; +- buf_size = min(buf_size, local->hw.max_tx_aggregation_subframes); +- +-+ txq = sta->sta.txq[tid]; +-+ if (!amsdu && txq) +-+ set_bit(IEEE80211_TXQ_NO_AMSDU, &to_txq_info(txq)->flags); +-+ +- mutex_lock(&sta->ampdu_mlme.mtx); +- +- tid_tx = rcu_dereference_protected_tid_tx(sta, tid); +---- a/net/mac80211/debugfs.c +-+++ b/net/mac80211/debugfs.c +-@@ -127,6 +127,8 @@ static const char *hw_flag_names[NUM_IEE +- FLAG(BEACON_TX_STATUS), +- FLAG(NEEDS_UNIQUE_STA_ADDR), +- FLAG(SUPPORTS_REORDERING_BUFFER), +-+ FLAG(TX_AMSDU), +-+ FLAG(TX_FRAG_LIST), +- +- /* keep last for the build bug below */ +- (void *)0x1 +---- a/net/mac80211/ieee80211_i.h +-+++ b/net/mac80211/ieee80211_i.h +-@@ -799,6 +799,7 @@ struct mac80211_qos_map { +- enum txq_info_flags { +- IEEE80211_TXQ_STOP, +- IEEE80211_TXQ_AMPDU, +-+ IEEE80211_TXQ_NO_AMSDU, +- }; +- +- struct txq_info { +---- a/net/mac80211/tx.c +-+++ b/net/mac80211/tx.c +-@@ -1318,6 +1318,10 @@ struct sk_buff *ieee80211_tx_dequeue(str +- out: +- spin_unlock_bh(&txqi->queue.lock); +- +-+ if (skb && skb_has_frag_list(skb) && +-+ !ieee80211_hw_check(&local->hw, TX_FRAG_LIST)) +-+ skb_linearize(skb); +-+ +- return skb; +- } +- EXPORT_SYMBOL(ieee80211_tx_dequeue); +-@@ -2757,6 +2761,163 @@ void ieee80211_clear_fast_xmit(struct st +- kfree_rcu(fast_tx, rcu_head); +- } +- +-+static bool ieee80211_amsdu_realloc_pad(struct ieee80211_local *local, +-+ struct sk_buff *skb, int headroom, +-+ int *subframe_len) +-+{ +-+ int amsdu_len = *subframe_len + sizeof(struct ethhdr); +-+ int padding = (4 - amsdu_len) & 3; +-+ +-+ if (skb_headroom(skb) < headroom || skb_tailroom(skb) < padding) { +-+ I802_DEBUG_INC(local->tx_expand_skb_head); +-+ +-+ if (pskb_expand_head(skb, headroom, padding, GFP_ATOMIC)) { +-+ wiphy_debug(local->hw.wiphy, +-+ "failed to reallocate TX buffer\n"); +-+ return false; +-+ } +-+ } +-+ +-+ if (padding) { +-+ *subframe_len += padding; +-+ memset(skb_put(skb, padding), 0, padding); +-+ } +-+ +-+ return true; +-+} +-+ +-+static bool ieee80211_amsdu_prepare_head(struct ieee80211_sub_if_data *sdata, +-+ struct ieee80211_fast_tx *fast_tx, +-+ struct sk_buff *skb) +-+{ +-+ struct ieee80211_local *local = sdata->local; +-+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +-+ struct ieee80211_hdr *hdr; +-+ struct ethhdr amsdu_hdr; +-+ int hdr_len = fast_tx->hdr_len - sizeof(rfc1042_header); +-+ int subframe_len = skb->len - hdr_len; +-+ void *data; +-+ u8 *qc; +-+ +-+ if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) +-+ return false; +-+ +-+ if (info->control.flags & IEEE80211_TX_CTRL_AMSDU) +-+ return true; +-+ +-+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(amsdu_hdr), +-+ &subframe_len)) +-+ return false; +-+ +-+ amsdu_hdr.h_proto = cpu_to_be16(subframe_len); +-+ memcpy(amsdu_hdr.h_source, skb->data + fast_tx->sa_offs, ETH_ALEN); +-+ memcpy(amsdu_hdr.h_dest, skb->data + fast_tx->da_offs, ETH_ALEN); +-+ +-+ data = skb_push(skb, sizeof(amsdu_hdr)); +-+ memmove(data, data + sizeof(amsdu_hdr), hdr_len); +-+ memcpy(data + hdr_len, &amsdu_hdr, sizeof(amsdu_hdr)); +-+ +-+ hdr = data; +-+ qc = ieee80211_get_qos_ctl(hdr); +-+ *qc |= IEEE80211_QOS_CTL_A_MSDU_PRESENT; +-+ +-+ info->control.flags |= IEEE80211_TX_CTRL_AMSDU; +-+ +-+ return true; +-+} +-+ +-+static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, +-+ struct sta_info *sta, +-+ struct ieee80211_fast_tx *fast_tx, +-+ struct sk_buff *skb) +-+{ +-+ struct ieee80211_local *local = sdata->local; +-+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; +-+ struct ieee80211_txq *txq = sta->sta.txq[tid]; +-+ struct txq_info *txqi; +-+ struct sk_buff **frag_tail, *head; +-+ int subframe_len = skb->len - ETH_ALEN; +-+ u8 max_subframes = sta->sta.max_amsdu_subframes; +-+ int max_frags = local->hw.max_tx_fragments; +-+ int max_amsdu_len = sta->sta.max_amsdu_len; +-+ __be16 len; +-+ void *data; +-+ bool ret = false; +-+ int n = 1, nfrags; +-+ +-+ if (!ieee80211_hw_check(&local->hw, TX_AMSDU)) +-+ return false; +-+ +-+ if (!txq) +-+ return false; +-+ +-+ txqi = to_txq_info(txq); +-+ if (test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags)) +-+ return false; +-+ +-+ if (sta->sta.max_rc_amsdu_len) +-+ max_amsdu_len = min_t(int, max_amsdu_len, +-+ sta->sta.max_rc_amsdu_len); +-+ +-+ spin_lock_bh(&txqi->queue.lock); +-+ +-+ head = skb_peek_tail(&txqi->queue); +-+ if (!head) +-+ goto out; +-+ +-+ if (skb->len + head->len > max_amsdu_len) +-+ goto out; +-+ +-+ /* +-+ * HT A-MPDU limits maximum MPDU size to 4095 bytes. Since aggregation +-+ * sessions are started/stopped without txq flush, use the limit here +-+ * to avoid having to de-aggregate later. +-+ */ +-+ if (skb->len + head->len > 4095 && +-+ !sta->sta.vht_cap.vht_supported) +-+ goto out; +-+ +-+ if (!ieee80211_amsdu_prepare_head(sdata, fast_tx, head)) +-+ goto out; +-+ +-+ nfrags = 1 + skb_shinfo(skb)->nr_frags; +-+ nfrags += 1 + skb_shinfo(head)->nr_frags; +-+ frag_tail = &skb_shinfo(head)->frag_list; +-+ while (*frag_tail) { +-+ nfrags += 1 + skb_shinfo(*frag_tail)->nr_frags; +-+ frag_tail = &(*frag_tail)->next; +-+ n++; +-+ } +-+ +-+ if (max_subframes && n > max_subframes) +-+ goto out; +-+ +-+ if (max_frags && nfrags > max_frags) +-+ goto out; +-+ +-+ if (!ieee80211_amsdu_realloc_pad(local, skb, sizeof(rfc1042_header) + 2, +-+ &subframe_len)) +-+ return false; +-+ +-+ ret = true; +-+ data = skb_push(skb, ETH_ALEN + 2); +-+ memmove(data, data + ETH_ALEN + 2, 2 * ETH_ALEN); +-+ +-+ data += 2 * ETH_ALEN; +-+ len = cpu_to_be16(subframe_len); +-+ memcpy(data, &len, 2); +-+ memcpy(data + 2, rfc1042_header, sizeof(rfc1042_header)); +-+ +-+ head->len += skb->len; +-+ head->data_len += skb->len; +-+ *frag_tail = skb; +-+ +-+out: +-+ spin_unlock_bh(&txqi->queue.lock); +-+ +-+ return ret; +-+} +-+ +- static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, +- struct net_device *dev, struct sta_info *sta, +- struct ieee80211_fast_tx *fast_tx, +-@@ -2811,6 +2972,10 @@ static bool ieee80211_xmit_fast(struct i +- +- ieee80211_tx_stats(dev, skb->len + extra_head); +- +-+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && +-+ ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) +-+ return true; +-+ +- /* will not be crypto-handled beyond what we do here, so use false +- * as the may-encrypt argument for the resize to not account for +- * more room than we already have in 'extra_head' +diff --git a/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch b/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch +deleted file mode 100644 +index 9277b2c..0000000 +--- a/package/kernel/mac80211/patches/323-0000-brcmfmac-fix-setting-primary-channel-for-80-MHz-widt.patch ++++ /dev/null +@@ -1,64 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Wed, 20 Jan 2016 16:46:04 +0100 +-Subject: [PATCH] brcmfmac: fix setting primary channel for 80 MHz width +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-First of all it changes the way we calculate primary channel offset. If +-we use e.g. 80 MHz channel with primary frequency 5180 MHz (which means +-center frequency is 5210 MHz) it makes sense to calculate primary offset +-as -30 MHz. +-Then it fixes values we compare primary_offset with. We were comparing +-offset in MHz against -2 or 2 which was resulting in picking a wrong +-primary channel. +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +-@@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct br +- brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n", +- ch->chan->center_freq, ch->center_freq1, ch->width); +- ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1); +-- primary_offset = ch->center_freq1 - ch->chan->center_freq; +-+ primary_offset = ch->chan->center_freq - ch->center_freq1; +- switch (ch->width) { +- case NL80211_CHAN_WIDTH_20: +- case NL80211_CHAN_WIDTH_20_NOHT: +-@@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct br +- break; +- case NL80211_CHAN_WIDTH_40: +- ch_inf.bw = BRCMU_CHAN_BW_40; +-- if (primary_offset < 0) +-+ if (primary_offset > 0) +- ch_inf.sb = BRCMU_CHAN_SB_U; +- else +- ch_inf.sb = BRCMU_CHAN_SB_L; +- break; +- case NL80211_CHAN_WIDTH_80: +- ch_inf.bw = BRCMU_CHAN_BW_80; +-- if (primary_offset < 0) { +-- if (primary_offset < -CH_10MHZ_APART) +-- ch_inf.sb = BRCMU_CHAN_SB_UU; +-- else +-- ch_inf.sb = BRCMU_CHAN_SB_UL; +-- } else { +-- if (primary_offset > CH_10MHZ_APART) +-- ch_inf.sb = BRCMU_CHAN_SB_LL; +-- else +-- ch_inf.sb = BRCMU_CHAN_SB_LU; +-- } +-+ if (primary_offset == -30) +-+ ch_inf.sb = BRCMU_CHAN_SB_LL; +-+ else if (primary_offset == -10) +-+ ch_inf.sb = BRCMU_CHAN_SB_LU; +-+ else if (primary_offset == 10) +-+ ch_inf.sb = BRCMU_CHAN_SB_UL; +-+ else +-+ ch_inf.sb = BRCMU_CHAN_SB_UU; +- break; +- case NL80211_CHAN_WIDTH_80P80: +- case NL80211_CHAN_WIDTH_160: +diff --git a/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch b/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch +deleted file mode 100644 +index d7018da..0000000 +--- a/package/kernel/mac80211/patches/323-0001-brcmfmac-analyze-descriptors-of-current-component-on.patch ++++ /dev/null +@@ -1,51 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Tue, 26 Jan 2016 17:57:01 +0100 +-Subject: [PATCH] brcmfmac: analyze descriptors of current component only +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-So far we were looking for address descriptors without a check for +-crossing current component border. In case of dealing with unsupported +-descriptor or descriptor missing at all the code would incorrectly get +-data from another component. +- +-Consider this binary-described component from BCM4366 EROM: +-4bf83b01 TAG==CI CID==0x83b +-20080201 TAG==CI PORTS==0+1 WRAPPERS==0+1 +-18400035 TAG==ADDR SZ_SZD TYPE_SLAVE +-00050000 +-18107085 TAG==ADDR SZ_4K TYPE_SWRAP +- +-Driver was assigning invalid base address to this core: +-brcmfmac: [6 ] core 0x83b:32 base 0x18109000 wrap 0x18107000 +-which came from totally different component defined in EROM: +-43b36701 TAG==CI CID==0x367 +-00000201 TAG==CI PORTS==0+1 WRAPPERS==0+0 +-18109005 TAG==ADDR SZ_4K TYPE_SLAVE +- +-This change will also allow us to support components without wrapper +-address in the future. +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-@@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(st +- *eromaddr -= 4; +- return -EFAULT; +- } +-- } while (desc != DMP_DESC_ADDRESS); +-+ } while (desc != DMP_DESC_ADDRESS && +-+ desc != DMP_DESC_COMPONENT); +-+ +-+ /* stop if we crossed current component border */ +-+ if (desc == DMP_DESC_COMPONENT) { +-+ *eromaddr -= 4; +-+ return 0; +-+ } +- +- /* skip upper 32-bit address descriptor */ +- if (val & DMP_DESC_ADDRSIZE_GT32) +diff --git a/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch b/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch +deleted file mode 100644 +index 045ab49..0000000 +--- a/package/kernel/mac80211/patches/323-0002-brcmfmac-allow-storing-PMU-core-without-wrapper-addr.patch ++++ /dev/null +@@ -1,28 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Tue, 26 Jan 2016 17:57:02 +0100 +-Subject: [PATCH] brcmfmac: allow storing PMU core without wrapper address +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-Separated PMU core can be found in new devices and should be used for +-accessing PMU registers (which were routed through ChipCommon so far). +-This core is one of exceptions that doesn't have or need wrapper address +-to be still safely accessible. +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-@@ -883,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcm +- rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; +- +- /* need core with ports */ +-- if (nmw + nsw == 0) +-+ if (nmw + nsw == 0 && +-+ id != BCMA_CORE_PMU) +- continue; +- +- /* try to obtain register address info */ +diff --git a/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch b/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch +deleted file mode 100644 +index 7b7ba4f..0000000 +--- a/package/kernel/mac80211/patches/323-0003-brcmfmac-read-extended-capabilities-of-ChipCommon-co.patch ++++ /dev/null +@@ -1,43 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Tue, 26 Jan 2016 17:57:03 +0100 +-Subject: [PATCH] brcmfmac: read extended capabilities of ChipCommon core +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-This is an extra bitfield with info about some present hardware. +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-@@ -1025,6 +1025,9 @@ static int brcmf_chip_setup(struct brcmf +- /* get chipcommon capabilites */ +- pub->cc_caps = chip->ops->read32(chip->ctx, +- CORE_CC_REG(base, capabilities)); +-+ pub->cc_caps_ext = chip->ops->read32(chip->ctx, +-+ CORE_CC_REG(base, +-+ capabilities_ext)); +- +- /* get pmu caps & rev */ +- if (pub->cc_caps & CC_CAP_PMU) { +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +-@@ -27,6 +27,7 @@ +- * @chip: chip identifier. +- * @chiprev: chip revision. +- * @cc_caps: chipcommon core capabilities. +-+ * @cc_caps_ext: chipcommon core extended capabilities. +- * @pmucaps: PMU capabilities. +- * @pmurev: PMU revision. +- * @rambase: RAM base address (only applicable for ARM CR4 chips). +-@@ -38,6 +39,7 @@ struct brcmf_chip { +- u32 chip; +- u32 chiprev; +- u32 cc_caps; +-+ u32 cc_caps_ext; +- u32 pmucaps; +- u32 pmurev; +- u32 rambase; +diff --git a/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch b/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch +deleted file mode 100644 +index 2af6fd9..0000000 +--- a/package/kernel/mac80211/patches/323-0004-brcmfmac-access-PMU-registers-using-standalone-PMU-c.patch ++++ /dev/null +@@ -1,148 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Tue, 26 Jan 2016 17:57:04 +0100 +-Subject: [PATCH] brcmfmac: access PMU registers using standalone PMU core if +- available +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-On recent Broadcom chipsets PMU is present as separated core and it +-can't be accessed using ChipCommon anymore as it fails with e.g.: +-[ 18.198412] Unhandled fault: imprecise external abort (0x1406) at 0xb6da200f +- +-Add a new helper function that will return a proper core that should be +-used for accessing PMU registers. +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c +-@@ -1014,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf +- { +- struct brcmf_chip *pub; +- struct brcmf_core_priv *cc; +-+ struct brcmf_core *pmu; +- u32 base; +- u32 val; +- int ret = 0; +-@@ -1030,9 +1031,10 @@ static int brcmf_chip_setup(struct brcmf +- capabilities_ext)); +- +- /* get pmu caps & rev */ +-+ pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */ +- if (pub->cc_caps & CC_CAP_PMU) { +- val = chip->ops->read32(chip->ctx, +-- CORE_CC_REG(base, pmucapabilities)); +-+ CORE_CC_REG(pmu->base, pmucapabilities)); +- pub->pmurev = val & PCAP_REV_MASK; +- pub->pmucaps = val; +- } +-@@ -1131,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipco +- return &cc->pub; +- } +- +-+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub) +-+{ +-+ struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub); +-+ struct brcmf_core *pmu; +-+ +-+ /* See if there is separated PMU core available */ +-+ if (cc->rev >= 35 && +-+ pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) { +-+ pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU); +-+ if (pmu) +-+ return pmu; +-+ } +-+ +-+ /* Fallback to ChipCommon core for older hardware */ +-+ return cc; +-+} +-+ +- bool brcmf_chip_iscoreup(struct brcmf_core *pub) +- { +- struct brcmf_core_priv *core; +-@@ -1301,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_ +- { +- u32 base, addr, reg, pmu_cc3_mask = ~0; +- struct brcmf_chip_priv *chip; +-+ struct brcmf_core *pmu = brcmf_chip_get_pmu(pub); +- +- brcmf_dbg(TRACE, "Enter\n"); +- +-@@ -1320,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_ +- case BRCM_CC_4335_CHIP_ID: +- case BRCM_CC_4339_CHIP_ID: +- /* read PMU chipcontrol register 3 */ +-- addr = CORE_CC_REG(base, chipcontrol_addr); +-+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr); +- chip->ops->write32(chip->ctx, addr, 3); +-- addr = CORE_CC_REG(base, chipcontrol_data); +-+ addr = CORE_CC_REG(pmu->base, chipcontrol_data); +- reg = chip->ops->read32(chip->ctx, addr); +- return (reg & pmu_cc3_mask) != 0; +- case BRCM_CC_43430_CHIP_ID: +-@@ -1330,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_ +- reg = chip->ops->read32(chip->ctx, addr); +- return reg != 0; +- default: +-- addr = CORE_CC_REG(base, pmucapabilities_ext); +-+ addr = CORE_CC_REG(pmu->base, pmucapabilities_ext); +- reg = chip->ops->read32(chip->ctx, addr); +- if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) +- return false; +- +-- addr = CORE_CC_REG(base, retention_ctl); +-+ addr = CORE_CC_REG(pmu->base, retention_ctl); +- reg = chip->ops->read32(chip->ctx, addr); +- return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | +- PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h +-@@ -85,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(voi +- void brcmf_chip_detach(struct brcmf_chip *chip); +- struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); +- struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); +-+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub); +- bool brcmf_chip_iscoreup(struct brcmf_core *core); +- void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset); +- void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset, +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +-@@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcm +- const struct sdiod_drive_str *str_tab = NULL; +- u32 str_mask; +- u32 str_shift; +-- u32 base; +- u32 i; +- u32 drivestrength_sel = 0; +- u32 cc_data_temp; +-@@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcm +- } +- +- if (str_tab != NULL) { +-+ struct brcmf_core *pmu = brcmf_chip_get_pmu(ci); +-+ +- for (i = 0; str_tab[i].strength != 0; i++) { +- if (drivestrength >= str_tab[i].strength) { +- drivestrength_sel = str_tab[i].sel; +- break; +- } +- } +-- base = brcmf_chip_get_chipcommon(ci)->base; +-- addr = CORE_CC_REG(base, chipcontrol_addr); +-+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr); +- brcmf_sdiod_regwl(sdiodev, addr, 1, NULL); +- cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL); +- cc_data_temp &= ~str_mask; +-@@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdi +- goto fail; +- +- /* set PMUControl so a backplane reset does PMU state reload */ +-- reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base, +-- pmucontrol); +-+ reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol); +- reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err); +- if (err) +- goto fail; +diff --git a/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch b/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch +deleted file mode 100644 +index 35887fc..0000000 +--- a/package/kernel/mac80211/patches/323-0005-brcmfmac-add-support-for-14e4-4365-PCI-ID-with-BCM43.patch ++++ /dev/null +@@ -1,38 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Tue, 26 Jan 2016 17:57:05 +0100 +-Subject: [PATCH] brcmfmac: add support for 14e4:4365 PCI ID with BCM4366 +- chipset +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-On Broadcom ARM routers BCM4366 cards are available with 14e4:4365 ID. +-Unfortunately this ID was already used by Broadcom for cards with +-BCM43142, a totally different chipset requiring SoftMAC driver. To avoid +-a conflict between brcmfmac and bcma use more specific ID entry with +-subvendor and subdevice specified. +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +-@@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pci +- +- #define BRCMF_PCIE_DEVICE(dev_id) { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ +- PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } +-+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \ +-+ BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\ +-+ subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 } +- +- static struct pci_device_id brcmf_pcie_devid_table[] = { +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID), +-@@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_d +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID), +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID), +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID), +-+ BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365), +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID), +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID), +- BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID), +diff --git a/package/kernel/mac80211/patches/323-ath9k-Fix-programming-of-minCCA-power-threshold.patch b/package/kernel/mac80211/patches/323-ath9k-Fix-programming-of-minCCA-power-threshold.patch +new file mode 100644 +index 0000000..59ac29b +--- /dev/null ++++ b/package/kernel/mac80211/patches/323-ath9k-Fix-programming-of-minCCA-power-threshold.patch +@@ -0,0 +1,26 @@ ++From: Sven Eckelmann <sven@narfation.org> ++Date: Fri, 17 Jun 2016 11:58:20 +0200 ++Subject: [PATCH] ath9k: Fix programming of minCCA power threshold ++ ++The function ar9003_hw_apply_minccapwr_thresh takes as second parameter not ++a pointer to the channel but a boolean value describing whether the channel ++is 2.4GHz or not. This broke (according to the origin commit) the ETSI ++regulatory compliance on 5GHz channels. ++ ++Fixes: 3533bf6b15a0 ("ath9k: Fix regulatory compliance") ++Signed-off-by: Sven Eckelmann <sven@narfation.org> ++Cc: Simon Wunderlich <sw@simonwunderlich.de> ++Cc: Sujith Manoharan <c_manoha@qca.qualcomm.com> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c ++@@ -4175,7 +4175,7 @@ static void ath9k_hw_ar9300_set_board_va ++ if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah)) ++ ar9003_hw_internal_regulator_apply(ah); ++ ar9003_hw_apply_tuning_caps(ah); ++- ar9003_hw_apply_minccapwr_thresh(ah, chan); +++ ar9003_hw_apply_minccapwr_thresh(ah, is2ghz); ++ ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz); ++ ar9003_hw_thermometer_apply(ah); ++ ar9003_hw_thermo_cal_apply(ah); +diff --git a/package/kernel/mac80211/patches/324-ath9k_hw-fix-spectral-scan-on-AR9285-and-newer.patch b/package/kernel/mac80211/patches/324-ath9k_hw-fix-spectral-scan-on-AR9285-and-newer.patch +new file mode 100644 +index 0000000..b6f4868 +--- /dev/null ++++ b/package/kernel/mac80211/patches/324-ath9k_hw-fix-spectral-scan-on-AR9285-and-newer.patch +@@ -0,0 +1,86 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Mon, 11 Jul 2016 10:34:37 +0200 ++Subject: [PATCH] ath9k_hw: fix spectral scan on AR9285 and newer ++ ++The register layout of AR_PHY_SPECTRAL_SCAN has changed, only AR9280 ++uses the old layout ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c +++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c ++@@ -476,6 +476,7 @@ static void ar9002_hw_set_bt_ant_diversi ++ static void ar9002_hw_spectral_scan_config(struct ath_hw *ah, ++ struct ath_spec_scan *param) + { -+ struct ieee80211_tx_info *tx_info; -+ struct ath_frame_info *fi; -+- struct sk_buff *skb; -++ struct sk_buff *skb, *first_skb = NULL; -+ struct ath_buf *bf; -+ u16 seqno; -+ -+ while (1) { -+- *q = &tid->retry_q; -+- if (skb_queue_empty(*q)) -+- *q = &tid->buf_q; -+- -+- skb = skb_peek(*q); -++ skb = ath_tid_dequeue(tid); -+ if (!skb) -+ break; -+ -+@@ -923,7 +936,6 @@ ath_tx_get_tid_subframe(struct ath_softc -+ bf->bf_state.stale = false; -+ -+ if (!bf) { -+- __skb_unlink(skb, *q); -+ ath_txq_skb_done(sc, txq, skb); -+ ieee80211_free_txskb(sc->hw, skb); -+ continue; -+@@ -952,8 +964,19 @@ ath_tx_get_tid_subframe(struct ath_softc -+ seqno = bf->bf_state.seqno; -+ -+ /* do not step over block-ack window */ -+- if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) -++ if (!BAW_WITHIN(tid->seq_start, tid->baw_size, seqno)) { -++ __skb_queue_tail(&tid->retry_q, skb); -++ -++ /* If there are other skbs in the retry q, they are -++ * probably within the BAW, so loop immediately to get -++ * one of them. Otherwise the queue can get stuck. */ -++ if (!skb_queue_is_first(&tid->retry_q, skb) && skb != first_skb) { -++ if(!first_skb) /* infinite loop prevention */ -++ first_skb = skb; -++ continue; -++ } -+ break; -++ } -+ -+ if (tid->bar_index > ATH_BA_INDEX(tid->seq_start, seqno)) { -+ struct ath_tx_status ts = {}; -+@@ -961,7 +984,6 @@ ath_tx_get_tid_subframe(struct ath_softc +++ u32 repeat_bit; ++ u8 count; + -+ INIT_LIST_HEAD(&bf_head); -+ list_add(&bf->list, &bf_head); -+- __skb_unlink(skb, *q); -+ ath_tx_update_baw(sc, tid, seqno); -+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); -+ continue; -+@@ -973,11 +995,10 @@ ath_tx_get_tid_subframe(struct ath_softc -+ return NULL; -+ } ++ if (!param->enabled) { ++@@ -486,12 +487,15 @@ static void ar9002_hw_spectral_scan_conf ++ REG_SET_BIT(ah, AR_PHY_RADAR_0, AR_PHY_RADAR_0_FFT_ENA); ++ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, AR_PHY_SPECTRAL_SCAN_ENABLE); + -+-static bool -++static int -+ ath_tx_form_aggr(struct ath_softc *sc, struct ath_txq *txq, -+ struct ath_atx_tid *tid, struct list_head *bf_q, -+- struct ath_buf *bf_first, struct sk_buff_head *tid_q, -+- int *aggr_len) -++ struct ath_buf *bf_first) -+ { -+ #define PADBYTES(_len) ((4 - ((_len) % 4)) % 4) -+ struct ath_buf *bf = bf_first, *bf_prev = NULL; -+@@ -987,12 +1008,13 @@ ath_tx_form_aggr(struct ath_softc *sc, s -+ struct ieee80211_tx_info *tx_info; -+ struct ath_frame_info *fi; -+ struct sk_buff *skb; -+- bool closed = false; +++ if (AR_SREV_9280(ah)) +++ repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT; +++ else +++ repeat_bit = AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI; ++ ++ if (param->short_repeat) ++- REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, ++- AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); +++ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); ++ else ++- REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, ++- AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT); +++ REG_CLR_BIT(ah, AR_PHY_SPECTRAL_SCAN, repeat_bit); + -+ bf = bf_first; -+ aggr_limit = ath_lookup_rate(sc, bf, tid); -+ -+- do { -++ while (bf) -++ { -+ skb = bf->bf_mpdu; -+ fi = get_frame_info(skb); -+ -+@@ -1001,12 +1023,12 @@ ath_tx_form_aggr(struct ath_softc *sc, s -+ if (nframes) { -+ if (aggr_limit < al + bpad + al_delta || -+ ath_lookup_legacy(bf) || nframes >= h_baw) -+- break; -++ goto stop; -+ -+ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); -+ if ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) || -+ !(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) -+- break; -++ goto stop; -+ } -+ -+ /* add padding for previous frame to aggregation length */ -+@@ -1028,20 +1050,18 @@ ath_tx_form_aggr(struct ath_softc *sc, s -+ ath_tx_addto_baw(sc, tid, bf); -+ bf->bf_state.ndelim = ndelim; -+ -+- __skb_unlink(skb, tid_q); -+ list_add_tail(&bf->list, bf_q); -+ if (bf_prev) -+ bf_prev->bf_next = bf; -+ -+ bf_prev = bf; -+ -+- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); -+- if (!bf) { -+- closed = true; -+- break; -+- } -+- } while (ath_tid_has_buffered(tid)); -+- -++ bf = ath_tx_get_tid_subframe(sc, txq, tid); -++ } -++ goto finish; -++stop: -++ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); -++finish: -+ bf = bf_first; -+ bf->bf_lastbf = bf_prev; -+ -+@@ -1052,9 +1072,7 @@ ath_tx_form_aggr(struct ath_softc *sc, s -+ TX_STAT_INC(txq->axq_qnum, a_aggr); -+ } -+ -+- *aggr_len = al; -+- -+- return closed; -++ return al; -+ #undef PADBYTES -+ } ++ /* on AR92xx, the highest bit of count will make the the chip send ++ * spectral samples endlessly. Check if this really was intended, ++@@ -499,15 +503,25 @@ static void ar9002_hw_spectral_scan_conf ++ */ ++ count = param->count; ++ if (param->endless) { ++- if (AR_SREV_9271(ah)) ++- count = 0; ++- else +++ if (AR_SREV_9280(ah)) ++ count = 0x80; +++ else +++ count = 0; ++ } else if (count & 0x80) ++ count = 0x7f; +++ else if (!count) +++ count = 1; +++ +++ if (AR_SREV_9280(ah)) { +++ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, +++ AR_PHY_SPECTRAL_SCAN_COUNT, count); +++ } else { +++ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, +++ AR_PHY_SPECTRAL_SCAN_COUNT_KIWI, count); +++ REG_SET_BIT(ah, AR_PHY_SPECTRAL_SCAN, +++ AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT); +++ } + -+@@ -1431,18 +1449,15 @@ static void ath_tx_fill_desc(struct ath_ -+ static void -+ ath_tx_form_burst(struct ath_softc *sc, struct ath_txq *txq, -+ struct ath_atx_tid *tid, struct list_head *bf_q, -+- struct ath_buf *bf_first, struct sk_buff_head *tid_q) -++ struct ath_buf *bf_first) -+ { -+ struct ath_buf *bf = bf_first, *bf_prev = NULL; -+- struct sk_buff *skb; -+ int nframes = 0; ++- REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, ++- AR_PHY_SPECTRAL_SCAN_COUNT, count); ++ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, ++ AR_PHY_SPECTRAL_SCAN_PERIOD, param->period); ++ REG_RMW_FIELD(ah, AR_PHY_SPECTRAL_SCAN, ++--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.h +++++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.h ++@@ -177,8 +177,11 @@ ++ #define AR_PHY_SPECTRAL_SCAN_PERIOD_S 8 ++ #define AR_PHY_SPECTRAL_SCAN_COUNT 0x00FF0000 /* Number of reports, reg 68, bits 16-23*/ ++ #define AR_PHY_SPECTRAL_SCAN_COUNT_S 16 +++#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI 0x0FFF0000 /* Number of reports, reg 68, bits 16-27*/ +++#define AR_PHY_SPECTRAL_SCAN_COUNT_KIWI_S 16 ++ #define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT 0x01000000 /* Short repeat, reg 68, bit 24*/ ++-#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_S 24 /* Short repeat, reg 68, bit 24*/ +++#define AR_PHY_SPECTRAL_SCAN_SHORT_REPEAT_KIWI 0x10000000 /* Short repeat, reg 68, bit 28*/ +++#define AR_PHY_SPECTRAL_SCAN_PHYERR_MASK_SELECT 0x40000000 + -+ do { -+ struct ieee80211_tx_info *tx_info; -+- skb = bf->bf_mpdu; ++ #define AR_PHY_RX_DELAY 0x9914 ++ #define AR_PHY_SEARCH_START_DELAY 0x9918 +diff --git a/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch b/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch +deleted file mode 100644 +index 6ce60f1..0000000 +--- a/package/kernel/mac80211/patches/324-brcmfmac-treat-NULL-character-in-NVRAM-as-separator.patch ++++ /dev/null +@@ -1,32 +0,0 @@ +-From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com> +-Date: Sun, 31 Jan 2016 12:14:34 +0100 +-Subject: [PATCH] brcmfmac: treat NULL character in NVRAM as separator +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-Platform NVRAM (stored on a flash partition) has entries separated by a +-NULL (\0) char. Our parsing code switches from VALUE state to IDLE +-whenever it meets a NULL (\0). When that happens our IDLE handler should +-simply consume it and analyze whatever is placed ahead. +- +-This fixes harmless warnings spamming debugging output: +-[ 155.165624] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=20: ignoring invalid character +-[ 155.180806] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=44: ignoring invalid character +-[ 155.195971] brcmfmac: brcmf_nvram_handle_idle warning: ln=1:col=63: ignoring invalid character +- +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +-@@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvr +- c = nvp->data[nvp->pos]; +- if (c == '\n') +- return COMMENT; +-- if (is_whitespace(c)) +-+ if (is_whitespace(c) || c == '\0') +- goto proceed; +- if (c == '#') +- return COMMENT; +diff --git a/package/kernel/mac80211/patches/325-ath9k_hw-fix-duplicate-and-partially-wrong-definitio.patch b/package/kernel/mac80211/patches/325-ath9k_hw-fix-duplicate-and-partially-wrong-definitio.patch +new file mode 100644 +index 0000000..6685f33 +--- /dev/null ++++ b/package/kernel/mac80211/patches/325-ath9k_hw-fix-duplicate-and-partially-wrong-definitio.patch +@@ -0,0 +1,57 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Mon, 11 Jul 2016 11:31:39 +0200 ++Subject: [PATCH] ath9k_hw: fix duplicate (and partially wrong) definition ++ of AR_CH0_THERM ++ ++AR_PHY_65NM_CH0_THERM and AR_CH0_THERM were supposed to refer to the ++same register, however they had different SREV checks. ++ ++Remove the duplicate and use the checks. Since there were other SREV ++checks present in the only place that uses this, this will probaby not ++affect runtime behavior. ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h ++@@ -689,13 +689,6 @@ ++ #define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) ++ #define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) + -+ nframes++; -+- __skb_unlink(skb, tid_q); -+ list_add_tail(&bf->list, bf_q); -+ if (bf_prev) -+ bf_prev->bf_next = bf; -+@@ -1451,13 +1466,15 @@ ath_tx_form_burst(struct ath_softc *sc, -+ if (nframes >= 2) -+ break; ++-#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ ++- ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) ++-#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 ++-#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 ++-#define AR_CH0_THERM_XPASHORT2GND 0x4 ++-#define AR_CH0_THERM_XPASHORT2GND_S 2 ++- ++ #define AR_SWITCH_TABLE_COM_ALL (0xffff) ++ #define AR_SWITCH_TABLE_COM_ALL_S (0) ++ #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) ++@@ -712,15 +705,17 @@ ++ #define AR_SWITCH_TABLE_ALL (0xfff) ++ #define AR_SWITCH_TABLE_ALL_S (0) + -+- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); -++ bf = ath_tx_get_tid_subframe(sc, txq, tid); -+ if (!bf) -+ break; ++-#define AR_PHY_65NM_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ ++- ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) +++#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 :\ +++ ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16294 : 0x1628c)) +++#define AR_CH0_THERM_XPABIASLVL_MSB 0x3 +++#define AR_CH0_THERM_XPABIASLVL_MSB_S 0 +++#define AR_CH0_THERM_XPASHORT2GND 0x4 +++#define AR_CH0_THERM_XPASHORT2GND_S 2 + -+ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); -+- if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) -++ if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { -++ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); -+ break; -++ } ++-#define AR_PHY_65NM_CH0_THERM_LOCAL 0x80000000 ++-#define AR_PHY_65NM_CH0_THERM_LOCAL_S 31 ++-#define AR_PHY_65NM_CH0_THERM_START 0x20000000 ++-#define AR_PHY_65NM_CH0_THERM_START_S 29 ++-#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT 0x0000ff00 ++-#define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8 +++#define AR_CH0_THERM_LOCAL 0x80000000 +++#define AR_CH0_THERM_START 0x20000000 +++#define AR_CH0_THERM_SAR_ADC_OUT 0x0000ff00 +++#define AR_CH0_THERM_SAR_ADC_OUT_S 8 + -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false); -+ } while (1); -+@@ -1468,34 +1485,33 @@ static bool ath_tx_sched_aggr(struct ath ++ #define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \ ++ (AR_SREV_9462(ah) ? 0x16290 : 0x16284)) +diff --git a/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch b/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch +deleted file mode 100644 +index 012dea1..0000000 +--- a/package/kernel/mac80211/patches/325-brcmfmac-sdio-Increase-the-default-timeouts-a-bit.patch ++++ /dev/null +@@ -1,41 +0,0 @@ +-From: Sjoerd Simons <sjoerd.simons@collabora.co.uk> +-Date: Mon, 25 Jan 2016 11:47:29 +0100 +-Subject: [PATCH] brcmfmac: sdio: Increase the default timeouts a bit +- +-On a Radxa Rock2 board with a Ampak AP6335 (Broadcom 4339 core) it seems +-the card responds very quickly most of the time, unfortunately during +-initialisation it sometimes seems to take just a bit over 2 seconds to +-respond. +- +-This results intialization failing with message like: +- brcmf_c_preinit_dcmds: Retreiving cur_etheraddr failed, -52 +- brcmf_bus_start: failed: -52 +- brcmf_sdio_firmware_callback: dongle is not responding +- +-Increasing the timeout to allow for a bit more headroom allows the +-card to initialize reliably. +- +-A quick search online after diagnosing/fixing this showed that Google +-has a similar patch in their ChromeOS tree, so this doesn't seem +-specific to the board I'm using. +- +-Signed-off-by: Sjoerd Simons <sjoerd.simons@collabora.co.uk> +-Reviewed-by: Julian Calaby <julian.calaby@gmail.com> +-Acked-by: Arend van Spriel <arend@broadcom.com> +-Reviewed-by: Douglas Anderson <dianders@chromium.org> +-Signed-off-by: Kalle Valo <kvalo@codeaurora.org> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +-@@ -45,8 +45,8 @@ +- #include "chip.h" +- #include "firmware.h" +- +--#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000) +--#define CTL_DONE_TIMEOUT msecs_to_jiffies(2000) +-+#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500) +-+#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500) +- +- #ifdef DEBUG +- +diff --git a/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch b/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch +deleted file mode 100644 +index 71f7a40..0000000 +--- a/package/kernel/mac80211/patches/326-ath9k-make-NF-load-complete-quickly-and-reliably.patch ++++ /dev/null +@@ -1,87 +0,0 @@ +-From: Miaoqing Pan <miaoqing@codeaurora.org> +-Date: Fri, 5 Feb 2016 09:45:50 +0800 +-Subject: [PATCH] ath9k: make NF load complete quickly and reliably +- +-Make NF load complete quickly and reliably. NF load execution +-is delayed by HW to end of frame if frame Rx or Tx is ongoing. +-Increasing timeout to max frame duration. If NF cal is ongoing +-before NF load, stop it before load, and restart it afterwards. +- +-Signed-off-by: Miaoqing Pan <miaoqing@codeaurora.org> +---- +- +---- a/drivers/net/wireless/ath/ath9k/calib.c +-+++ b/drivers/net/wireless/ath/ath9k/calib.c +-@@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s +- u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask; +- struct ath_common *common = ath9k_hw_common(ah); +- s16 default_nf = ath9k_hw_get_default_nf(ah, chan); +-+ u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL); +- +- if (ah->caldata) +- h = ah->caldata->nfCalHist; +-@@ -264,6 +265,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s +- } +- +- /* +-+ * stop NF cal if ongoing to ensure NF load completes immediately +-+ * (or after end rx/tx frame if ongoing) +-+ */ +-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { +-+ REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); +-+ REG_RMW_BUFFER_FLUSH(ah); +-+ ENABLE_REG_RMW_BUFFER(ah); +-+ } +-+ +-+ /* +- * Load software filtered NF value into baseband internal minCCApwr +- * variable. +- */ +-@@ -276,18 +287,33 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s +- +- /* +- * Wait for load to complete, should be fast, a few 10s of us. +-- * The max delay was changed from an original 250us to 10000us +-- * since 250us often results in NF load timeout and causes deaf +-- * condition during stress testing 12/12/2009 +-+ * The max delay was changed from an original 250us to 22.2 msec. +-+ * This would increase timeout to the longest possible frame +-+ * (11n max length 22.1 msec) +- */ +-- for (j = 0; j < 10000; j++) { +-+ for (j = 0; j < 22200; j++) { +- if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & +-- AR_PHY_AGC_CONTROL_NF) == 0) +-+ AR_PHY_AGC_CONTROL_NF) == 0) +- break; +- udelay(10); +- } +- +- /* +-+ * Restart NF so it can continue. +-+ */ +-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) { +-+ ENABLE_REG_RMW_BUFFER(ah); +-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF) +-+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, +-+ AR_PHY_AGC_CONTROL_ENABLE_NF); +-+ if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF) +-+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, +-+ AR_PHY_AGC_CONTROL_NO_UPDATE_NF); +-+ REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); +-+ REG_RMW_BUFFER_FLUSH(ah); +-+ } +-+ +-+ /* +- * We timed out waiting for the noisefloor to load, probably due to an +- * in-progress rx. Simply return here and allow the load plenty of time +- * to complete before the next calibration interval. We need to avoid +-@@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, s +- * here, the baseband nf cal will just be capped by our present +- * noisefloor until the next calibration timer. +- */ +-- if (j == 10000) { +-+ if (j == 22200) { +- ath_dbg(common, ANY, +- "Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n", +- REG_READ(ah, AR_PHY_AGC_CONTROL)); +diff --git a/package/kernel/mac80211/patches/326-ath9k_hw-simplify-ar9003_hw_per_calibration.patch b/package/kernel/mac80211/patches/326-ath9k_hw-simplify-ar9003_hw_per_calibration.patch +new file mode 100644 +index 0000000..999d993 +--- /dev/null ++++ b/package/kernel/mac80211/patches/326-ath9k_hw-simplify-ar9003_hw_per_calibration.patch +@@ -0,0 +1,88 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Mon, 11 Jul 2016 11:34:47 +0200 ++Subject: [PATCH] ath9k_hw: simplify ar9003_hw_per_calibration ++ ++Reduce indentation, use a variable to save a few pointer dereferences ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c ++@@ -75,50 +75,49 @@ static bool ar9003_hw_per_calibration(st ++ struct ath9k_cal_list *currCal) + { -+ struct ath_buf *bf; -+ struct ieee80211_tx_info *tx_info; -+- struct sk_buff_head *tid_q; -+ struct list_head bf_q; -+ int aggr_len = 0; -+- bool aggr, last = true; -++ bool aggr; -+ -+ if (!ath_tid_has_buffered(tid)) -+ return false; -+ -+ INIT_LIST_HEAD(&bf_q); -+ -+- bf = ath_tx_get_tid_subframe(sc, txq, tid, &tid_q); -++ bf = ath_tx_get_tid_subframe(sc, txq, tid); -+ if (!bf) -+ return false; -+ -+ tx_info = IEEE80211_SKB_CB(bf->bf_mpdu); -+ aggr = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU); -+ if ((aggr && txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) || -+- (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { -++ (!aggr && txq->axq_depth >= ATH_NON_AGGR_MIN_QDEPTH)) { -++ __skb_queue_tail(&tid->retry_q, bf->bf_mpdu); -+ *stop = true; -+ return false; -+ } -+ -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, false); -+ if (aggr) -+- last = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf, -+- tid_q, &aggr_len); -++ aggr_len = ath_tx_form_aggr(sc, txq, tid, &bf_q, bf); -+ else -+- ath_tx_form_burst(sc, txq, tid, &bf_q, bf, tid_q); -++ ath_tx_form_burst(sc, txq, tid, &bf_q, bf); -+ -+ if (list_empty(&bf_q)) -+ return false; -+@@ -1538,9 +1554,6 @@ int ath_tx_aggr_start(struct ath_softc * -+ an->mpdudensity = density; -+ } -+ -+- /* force sequence number allocation for pending frames */ -+- ath_tx_tid_change_state(sc, txtid); -+- -+ txtid->active = true; -+ *ssn = txtid->seq_start = txtid->seq_next; -+ txtid->bar_index = -1; -+@@ -1565,7 +1578,6 @@ void ath_tx_aggr_stop(struct ath_softc * -+ ath_txq_lock(sc, txq); -+ txtid->active = false; -+ ath_tx_flush_tid(sc, txtid); -+- ath_tx_tid_change_state(sc, txtid); -+ ath_txq_unlock_complete(sc, txq); -+ } ++ struct ath9k_hw_cal_data *caldata = ah->caldata; ++- /* Cal is assumed not done until explicitly set below */ ++- bool iscaldone = false; +++ const struct ath9k_percal_data *cur_caldata = currCal->calData; + -+@@ -1575,14 +1587,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ -+ struct ath_common *common = ath9k_hw_common(sc->sc_ah); -+ struct ath_atx_tid *tid; -+ struct ath_txq *txq; -+- bool buffered; -+ int tidno; ++ /* Calibration in progress. */ ++ if (currCal->calState == CAL_RUNNING) { ++ /* Check to see if it has finished. */ ++- if (!(REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL)) { ++- /* ++- * Accumulate cal measures for active chains ++- */ ++- currCal->calData->calCollect(ah); ++- ah->cal_samples++; +++ if (REG_READ(ah, AR_PHY_TIMING4) & AR_PHY_TIMING4_DO_CAL) +++ return false; + -+ ath_dbg(common, XMIT, "%s called\n", __func__); ++- if (ah->cal_samples >= ++- currCal->calData->calNumSamples) { ++- unsigned int i, numChains = 0; ++- for (i = 0; i < AR9300_MAX_CHAINS; i++) { ++- if (rxchainmask & (1 << i)) ++- numChains++; ++- } +++ /* +++ * Accumulate cal measures for active chains +++ */ +++ cur_caldata->calCollect(ah); +++ ah->cal_samples++; + -+- for (tidno = 0, tid = &an->tid[tidno]; -+- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -+- -++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { -++ tid = ath_node_to_tid(an, tidno); -+ txq = tid->txq; ++- /* ++- * Process accumulated data ++- */ ++- currCal->calData->calPostProc(ah, numChains); +++ if (ah->cal_samples >= cur_caldata->calNumSamples) { +++ unsigned int i, numChains = 0; +++ for (i = 0; i < AR9300_MAX_CHAINS; i++) { +++ if (rxchainmask & (1 << i)) +++ numChains++; +++ } + -+ ath_txq_lock(sc, txq); -+@@ -1592,13 +1602,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ -+ continue; ++- /* Calibration has finished. */ ++- caldata->CalValid |= currCal->calData->calType; ++- currCal->calState = CAL_DONE; ++- iscaldone = true; ++- } else { +++ /* +++ * Process accumulated data +++ */ +++ cur_caldata->calPostProc(ah, numChains); +++ +++ /* Calibration has finished. */ +++ caldata->CalValid |= cur_caldata->calType; +++ currCal->calState = CAL_DONE; +++ return true; +++ } else { ++ /* ++ * Set-up collection of another sub-sample until we ++ * get desired number ++ */ ++ ar9003_hw_setup_calibration(ah, currCal); ++- } + } -+ -+- buffered = ath_tid_has_buffered(tid); -++ if (!skb_queue_empty(&tid->retry_q)) -++ ieee80211_sta_set_buffered(sta, tid->tidno, true); -+ -+ list_del_init(&tid->list); -+ -+ ath_txq_unlock(sc, txq); -+- -+- ieee80211_sta_set_buffered(sta, tidno, buffered); ++- } else if (!(caldata->CalValid & currCal->calData->calType)) { +++ } else if (!(caldata->CalValid & cur_caldata->calType)) { ++ /* If current cal is marked invalid in channel, kick it off */ ++ ath9k_hw_reset_calibration(ah, currCal); + } -+ } -+ -+@@ -1611,49 +1620,20 @@ void ath_tx_aggr_wakeup(struct ath_softc -+ -+ ath_dbg(common, XMIT, "%s called\n", __func__); + -+- for (tidno = 0, tid = &an->tid[tidno]; -+- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -+- -++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { -++ tid = ath_node_to_tid(an, tidno); -+ txq = tid->txq; ++- return iscaldone; +++ return false; ++ } + -+ ath_txq_lock(sc, txq); -+ tid->clear_ps_filter = true; -+- -+ if (ath_tid_has_buffered(tid)) { -+ ath_tx_queue_tid(sc, txq, tid); -+ ath_txq_schedule(sc, txq); -+ } -+- -+ ath_txq_unlock_complete(sc, txq); ++ static int ar9003_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan, +diff --git a/package/kernel/mac80211/patches/327-ath9k_hw-get-rid-of-some-duplicate-code-in-calibrati.patch b/package/kernel/mac80211/patches/327-ath9k_hw-get-rid-of-some-duplicate-code-in-calibrati.patch +new file mode 100644 +index 0000000..b7f3823 +--- /dev/null ++++ b/package/kernel/mac80211/patches/327-ath9k_hw-get-rid-of-some-duplicate-code-in-calibrati.patch +@@ -0,0 +1,94 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Mon, 11 Jul 2016 11:35:20 +0200 ++Subject: [PATCH] ath9k_hw: get rid of some duplicate code in calibration ++ init ++ ++Remove a misleading debug message as well ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c ++@@ -1373,6 +1373,26 @@ static void ar9003_hw_cl_cal_post_proc(s + } + } + -+-void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, -+- u16 tidno) -+-{ -+- struct ath_common *common = ath9k_hw_common(sc->sc_ah); -+- struct ath_atx_tid *tid; -+- struct ath_node *an; -+- struct ath_txq *txq; -+- -+- ath_dbg(common, XMIT, "%s called\n", __func__); -+- -+- an = (struct ath_node *)sta->drv_priv; -+- tid = ATH_AN_2_TID(an, tidno); -+- txq = tid->txq; -+- -+- ath_txq_lock(sc, txq); -+- -+- tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; +++static void ar9003_hw_init_cal_common(struct ath_hw *ah) +++{ +++ struct ath9k_hw_cal_data *caldata = ah->caldata; +++ +++ /* Initialize list pointers */ +++ ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; +++ +++ INIT_CAL(&ah->iq_caldata); +++ INSERT_CAL(ah, &ah->iq_caldata); +++ +++ /* Initialize current pointer to first element in list */ +++ ah->cal_list_curr = ah->cal_list; +++ +++ if (ah->cal_list_curr) +++ ath9k_hw_reset_calibration(ah, ah->cal_list_curr); +++ +++ if (caldata) +++ caldata->CalValid = 0; +++} +++ ++ static bool ar9003_hw_init_cal_pcoem(struct ath_hw *ah, ++ struct ath9k_channel *chan) ++ { ++@@ -1532,21 +1552,7 @@ skip_tx_iqcal: ++ /* Revert chainmask to runtime parameters */ ++ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); ++ ++- /* Initialize list pointers */ ++- ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; +- -+- if (ath_tid_has_buffered(tid)) { -+- ath_tx_queue_tid(sc, txq, tid); -+- ath_txq_schedule(sc, txq); -+- } ++- INIT_CAL(&ah->iq_caldata); ++- INSERT_CAL(ah, &ah->iq_caldata); ++- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); +- -+- ath_txq_unlock_complete(sc, txq); -+-} ++- /* Initialize current pointer to first element in list */ ++- ah->cal_list_curr = ah->cal_list; +- -+ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, -+ struct ieee80211_sta *sta, -+ u16 tids, int nframes, -+@@ -1666,7 +1646,6 @@ void ath9k_release_buffered_frames(struc -+ struct ieee80211_tx_info *info; -+ struct list_head bf_q; -+ struct ath_buf *bf_tail = NULL, *bf; -+- struct sk_buff_head *tid_q; -+ int sent = 0; -+ int i; -+ -+@@ -1681,11 +1660,10 @@ void ath9k_release_buffered_frames(struc -+ -+ ath_txq_lock(sc, tid->txq); -+ while (nframes > 0) { -+- bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid, &tid_q); -++ bf = ath_tx_get_tid_subframe(sc, sc->tx.uapsdq, tid); -+ if (!bf) -+ break; -+ -+- __skb_unlink(bf->bf_mpdu, tid_q); -+ list_add_tail(&bf->list, &bf_q); -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); -+ if (bf_isampdu(bf)) { -+@@ -1700,7 +1678,7 @@ void ath9k_release_buffered_frames(struc -+ sent++; -+ TX_STAT_INC(txq->axq_qnum, a_queued_hw); -+ -+- if (an->sta && !ath_tid_has_buffered(tid)) -++ if (an->sta && skb_queue_empty(&tid->retry_q)) -+ ieee80211_sta_set_buffered(an->sta, i, false); -+ } -+ ath_txq_unlock_complete(sc, tid->txq); -+@@ -1929,13 +1907,7 @@ bool ath_drain_all_txq(struct ath_softc -+ if (!ATH_TXQ_SETUP(sc, i)) -+ continue; -+ -+- /* -+- * The caller will resume queues with ieee80211_wake_queues. -+- * Mark the queue as not stopped to prevent ath_tx_complete -+- * from waking the queue too early. -+- */ -+ txq = &sc->tx.txq[i]; -+- txq->stopped = false; -+ ath_draintxq(sc, txq); -+ } -+ -+@@ -2334,16 +2306,14 @@ int ath_tx_start(struct ieee80211_hw *hw -+ struct ath_softc *sc = hw->priv; -+ struct ath_txq *txq = txctl->txq; -+ struct ath_atx_tid *tid = NULL; -++ struct ath_node *an = NULL; -+ struct ath_buf *bf; -+- bool queue, ps_resp; -++ bool ps_resp; -+ int q, ret; -+ -+ if (vif) -+ avp = (void *)vif->drv_priv; -+ -+- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) -+- txctl->force_channel = true; ++- if (ah->cal_list_curr) ++- ath9k_hw_reset_calibration(ah, ah->cal_list_curr); +- -+ ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); -+ -+ ret = ath_tx_prepare(hw, skb, txctl); -+@@ -2358,63 +2328,18 @@ int ath_tx_start(struct ieee80211_hw *hw ++- if (caldata) ++- caldata->CalValid = 0; +++ ar9003_hw_init_cal_common(ah); + -+ q = skb_get_queue_mapping(skb); ++ return true; ++ } ++@@ -1577,8 +1583,6 @@ static bool do_ar9003_agc_cal(struct ath ++ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, ++ struct ath9k_channel *chan) ++ { ++- struct ath_common *common = ath9k_hw_common(ah); ++- struct ath9k_hw_cal_data *caldata = ah->caldata; ++ bool txiqcal_done = false; ++ bool status = true; ++ bool run_agc_cal = false, sep_iq_cal = false; ++@@ -1676,21 +1680,7 @@ skip_tx_iqcal: ++ /* Revert chainmask to runtime parameters */ ++ ar9003_hw_set_chain_masks(ah, ah->rxchainmask, ah->txchainmask); + -+- ath_txq_lock(sc, txq); -+- if (txq == sc->tx.txq_map[q]) { -+- fi->txq = q; -+- if (++txq->pending_frames > sc->tx.txq_max_pending[q] && -+- !txq->stopped) { -+- if (ath9k_is_chanctx_enabled()) -+- ieee80211_stop_queue(sc->hw, info->hw_queue); -+- else -+- ieee80211_stop_queue(sc->hw, q); -+- txq->stopped = true; -+- } -+- } -+- -+- queue = ieee80211_is_data_present(hdr->frame_control); -+- -+- /* If chanctx, queue all null frames while NOA could be there */ -+- if (ath9k_is_chanctx_enabled() && -+- ieee80211_is_nullfunc(hdr->frame_control) && -+- !txctl->force_channel) -+- queue = true; ++- /* Initialize list pointers */ ++- ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL; +- -+- /* Force queueing of all frames that belong to a virtual interface on -+- * a different channel context, to ensure that they are sent on the -+- * correct channel. -+- */ -+- if (((avp && avp->chanctx != sc->cur_chan) || -+- sc->cur_chan->stopped) && !txctl->force_channel) { -+- if (!txctl->an) -+- txctl->an = &avp->mcast_node; -+- queue = true; -+- ps_resp = false; -+- } ++- INIT_CAL(&ah->iq_caldata); ++- INSERT_CAL(ah, &ah->iq_caldata); ++- ath_dbg(common, CALIBRATE, "enabling IQ Calibration\n"); +- -+- if (txctl->an && queue) -+- tid = ath_get_skb_tid(sc, txctl->an, skb); ++- /* Initialize current pointer to first element in list */ ++- ah->cal_list_curr = ah->cal_list; +- -+- if (ps_resp) { -+- ath_txq_unlock(sc, txq); -++ if (ps_resp) -+ txq = sc->tx.uapsdq; -+- ath_txq_lock(sc, txq); -+- } else if (txctl->an && queue) { -+- WARN_ON(tid->txq != txctl->txq); ++- if (ah->cal_list_curr) ++- ath9k_hw_reset_calibration(ah, ah->cal_list_curr); +- -+- if (info->flags & IEEE80211_TX_CTL_CLEAR_PS_FILT) -+- tid->clear_ps_filter = true; ++- if (caldata) ++- caldata->CalValid = 0; +++ ar9003_hw_init_cal_common(ah); ++ ++ return true; ++ } +diff --git a/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch b/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch +deleted file mode 100644 +index f7f9df9..0000000 +--- a/package/kernel/mac80211/patches/327-mac80211-Remove-MPP-table-entries-with-MPath.patch ++++ /dev/null +@@ -1,54 +0,0 @@ +-From: Henning Rogge <hrogge@gmail.com> +-Date: Wed, 3 Feb 2016 13:58:36 +0100 +-Subject: [PATCH] mac80211: Remove MPP table entries with MPath +- +-Make the mesh_path_del() function remove all mpp table entries +-that are proxied by the removed mesh path. +- +-Acked-by: Bob Copeland <me@bobcopeland.com> +-Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> +-Signed-off-by: Johannes Berg <johannes.berg@intel.com> +---- +- +---- a/net/mac80211/mesh_pathtbl.c +-+++ b/net/mac80211/mesh_pathtbl.c +-@@ -835,6 +835,29 @@ void mesh_path_flush_by_nexthop(struct s +- rcu_read_unlock(); +- } +- +-+static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, +-+ const u8 *proxy) +-+{ +-+ struct mesh_table *tbl; +-+ struct mesh_path *mpp; +-+ struct mpath_node *node; +-+ int i; +-+ +-+ rcu_read_lock(); +-+ read_lock_bh(&pathtbl_resize_lock); +-+ tbl = resize_dereference_mpp_paths(); +-+ for_each_mesh_entry(tbl, node, i) { +-+ mpp = node->mpath; +-+ if (ether_addr_equal(mpp->mpp, proxy)) { +-+ spin_lock(&tbl->hashwlock[i]); +-+ __mesh_path_del(tbl, node); +-+ spin_unlock(&tbl->hashwlock[i]); +-+ } +-+ } +-+ read_unlock_bh(&pathtbl_resize_lock); +-+ rcu_read_unlock(); +-+} +-+ +- static void table_flush_by_iface(struct mesh_table *tbl, +- struct ieee80211_sub_if_data *sdata) +- { +-@@ -892,6 +915,9 @@ int mesh_path_del(struct ieee80211_sub_i +- int hash_idx; +- int err = 0; +- +-+ /* flush relevant mpp entries first */ +-+ mpp_flush_by_proxy(sdata, addr); +-+ +- read_lock_bh(&pathtbl_resize_lock); +- tbl = resize_dereference_mesh_paths(); +- hash_idx = mesh_table_hash(addr, sdata, tbl); +diff --git a/package/kernel/mac80211/patches/328-ath9k_hw-implement-temperature-compensation-support-.patch b/package/kernel/mac80211/patches/328-ath9k_hw-implement-temperature-compensation-support-.patch +new file mode 100644 +index 0000000..cff32ad +--- /dev/null ++++ b/package/kernel/mac80211/patches/328-ath9k_hw-implement-temperature-compensation-support-.patch +@@ -0,0 +1,97 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Mon, 11 Jul 2016 11:35:55 +0200 ++Subject: [PATCH] ath9k_hw: implement temperature compensation support for ++ AR9003+ ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c ++@@ -33,6 +33,7 @@ struct coeff { ++ ++ enum ar9003_cal_types { ++ IQ_MISMATCH_CAL = BIT(0), +++ TEMP_COMP_CAL = BIT(1), ++ }; + -+- /* -+- * Add this frame to software queue for scheduling later -+- * for aggregation. -+- */ -+- TX_STAT_INC(txq->axq_qnum, a_queued_sw); -+- __skb_queue_tail(&tid->buf_q, skb); -+- if (!txctl->an->sleeping) -+- ath_tx_queue_tid(sc, txq, tid); -++ if (txctl->sta) { -++ an = (struct ath_node *) sta->drv_priv; -++ tid = ath_get_skb_tid(sc, an, skb); -++ } ++ static void ar9003_hw_setup_calibration(struct ath_hw *ah, ++@@ -58,6 +59,12 @@ static void ar9003_hw_setup_calibration( ++ /* Kick-off cal */ ++ REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); ++ break; +++ case TEMP_COMP_CAL: +++ ath_dbg(common, CALIBRATE, +++ "starting Temperature Compensation Calibration\n"); +++ REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL); +++ REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START); +++ break; ++ default: ++ ath_err(common, "Invalid calibration type\n"); ++ break; ++@@ -86,7 +93,8 @@ static bool ar9003_hw_per_calibration(st ++ /* ++ * Accumulate cal measures for active chains ++ */ ++- cur_caldata->calCollect(ah); +++ if (cur_caldata->calCollect) +++ cur_caldata->calCollect(ah); ++ ah->cal_samples++; ++ ++ if (ah->cal_samples >= cur_caldata->calNumSamples) { ++@@ -99,7 +107,8 @@ static bool ar9003_hw_per_calibration(st ++ /* ++ * Process accumulated data ++ */ ++- cur_caldata->calPostProc(ah, numChains); +++ if (cur_caldata->calPostProc) +++ cur_caldata->calPostProc(ah, numChains); ++ ++ /* Calibration has finished. */ ++ caldata->CalValid |= cur_caldata->calType; ++@@ -314,9 +323,16 @@ static const struct ath9k_percal_data iq ++ ar9003_hw_iqcalibrate ++ }; + -+- ath_txq_schedule(sc, txq); -+- goto out; -++ ath_txq_lock(sc, txq); -++ if (txq == sc->tx.txq_map[q]) { -++ fi->txq = q; -++ ++txq->pending_frames; +++static const struct ath9k_percal_data temp_cal_single_sample = { +++ TEMP_COMP_CAL, +++ MIN_CAL_SAMPLES, +++ PER_MAX_LOG_COUNT, +++}; +++ ++ static void ar9003_hw_init_cal_settings(struct ath_hw *ah) ++ { ++ ah->iq_caldata.calData = &iq_cal_single_sample; +++ ah->temp_caldata.calData = &temp_cal_single_sample; ++ ++ if (AR_SREV_9300_20_OR_LATER(ah)) { ++ ah->enabled_cals |= TX_IQ_CAL; ++@@ -324,7 +340,7 @@ static void ar9003_hw_init_cal_settings( ++ ah->enabled_cals |= TX_IQ_ON_AGC_CAL; + } + -+ bf = ath_tx_setup_buffer(sc, txq, tid, skb); -+@@ -2907,9 +2832,8 @@ void ath_tx_node_init(struct ath_softc * -+ struct ath_atx_tid *tid; -+ int tidno, acno; ++- ah->supp_cals = IQ_MISMATCH_CAL; +++ ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL; ++ } ++ ++ #define OFF_UPPER_LT 24 ++@@ -1383,6 +1399,9 @@ static void ar9003_hw_init_cal_common(st ++ INIT_CAL(&ah->iq_caldata); ++ INSERT_CAL(ah, &ah->iq_caldata); ++ +++ INIT_CAL(&ah->temp_caldata); +++ INSERT_CAL(ah, &ah->temp_caldata); +++ ++ /* Initialize current pointer to first element in list */ ++ ah->cal_list_curr = ah->cal_list; ++ ++--- a/drivers/net/wireless/ath/ath9k/hw.h +++++ b/drivers/net/wireless/ath/ath9k/hw.h ++@@ -830,6 +830,7 @@ struct ath_hw { ++ /* Calibration */ ++ u32 supp_cals; ++ struct ath9k_cal_list iq_caldata; +++ struct ath9k_cal_list temp_caldata; ++ struct ath9k_cal_list adcgain_caldata; ++ struct ath9k_cal_list adcdc_caldata; ++ struct ath9k_cal_list *cal_list; +diff --git a/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch b/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch +deleted file mode 100644 +index 740993c..0000000 +--- a/package/kernel/mac80211/patches/328-mac80211-let-unused-MPP-table-entries-timeout.patch ++++ /dev/null +@@ -1,104 +0,0 @@ +-From: Henning Rogge <hrogge@gmail.com> +-Date: Wed, 3 Feb 2016 13:58:37 +0100 +-Subject: [PATCH] mac80211: let unused MPP table entries timeout +- +-Remember the last time when a mpp table entry is used for +-rx or tx and remove them after MESH_PATH_EXPIRE time. +- +-Acked-by: Bob Copeland <me@bobcopeland.com> +-Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> +-Signed-off-by: Johannes Berg <johannes.berg@intel.com> +---- +- +---- a/net/mac80211/mesh_pathtbl.c +-+++ b/net/mac80211/mesh_pathtbl.c +-@@ -942,6 +942,46 @@ enddel: +- } +- +- /** +-+ * mpp_path_del - delete a mesh proxy path from the table +-+ * +-+ * @addr: addr address (ETH_ALEN length) +-+ * @sdata: local subif +-+ * +-+ * Returns: 0 if successful +-+ */ +-+static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) +-+{ +-+ struct mesh_table *tbl; +-+ struct mesh_path *mpath; +-+ struct mpath_node *node; +-+ struct hlist_head *bucket; +-+ int hash_idx; +-+ int err = 0; +-+ +-+ read_lock_bh(&pathtbl_resize_lock); +-+ tbl = resize_dereference_mpp_paths(); +-+ hash_idx = mesh_table_hash(addr, sdata, tbl); +-+ bucket = &tbl->hash_buckets[hash_idx]; +-+ +-+ spin_lock(&tbl->hashwlock[hash_idx]); +-+ hlist_for_each_entry(node, bucket, list) { +-+ mpath = node->mpath; +-+ if (mpath->sdata == sdata && +-+ ether_addr_equal(addr, mpath->dst)) { +-+ __mesh_path_del(tbl, node); +-+ goto enddel; +-+ } +-+ } +-+ +-+ err = -ENXIO; +-+enddel: +-+ mesh_paths_generation++; +-+ spin_unlock(&tbl->hashwlock[hash_idx]); +-+ read_unlock_bh(&pathtbl_resize_lock); +-+ return err; +-+} +-+ +-+/** +- * mesh_path_tx_pending - sends pending frames in a mesh path queue +- * +- * @mpath: mesh path to activate +-@@ -1157,6 +1197,17 @@ void mesh_path_expire(struct ieee80211_s +- time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) +- mesh_path_del(mpath->sdata, mpath->dst); +- } +-+ +-+ tbl = rcu_dereference(mpp_paths); +-+ for_each_mesh_entry(tbl, node, i) { +-+ if (node->mpath->sdata != sdata) +-+ continue; +-+ mpath = node->mpath; +-+ if ((!(mpath->flags & MESH_PATH_FIXED)) && +-+ time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) +-+ mpp_path_del(mpath->sdata, mpath->dst); +-+ } +-+ +- rcu_read_unlock(); +- } +- +---- a/net/mac80211/rx.c +-+++ b/net/mac80211/rx.c +-@@ -2291,6 +2291,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80 +- spin_lock_bh(&mppath->state_lock); +- if (!ether_addr_equal(mppath->mpp, mpp_addr)) +- memcpy(mppath->mpp, mpp_addr, ETH_ALEN); +-+ mppath->exp_time = jiffies; +- spin_unlock_bh(&mppath->state_lock); +- } +- rcu_read_unlock(); +---- a/net/mac80211/tx.c +-+++ b/net/mac80211/tx.c +-@@ -2171,8 +2171,11 @@ static struct sk_buff *ieee80211_build_h +- mpp_lookup = true; +- } +- +-- if (mpp_lookup) +-+ if (mpp_lookup) { +- mppath = mpp_path_lookup(sdata, skb->data); +-+ if (mppath) +-+ mppath->exp_time = jiffies; +-+ } +- +- if (mppath && mpath) +- mesh_path_del(mpath->sdata, mpath->dst); +diff --git a/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch b/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch +deleted file mode 100644 +index 0c36b1d..0000000 +--- a/package/kernel/mac80211/patches/329-mac80211-Unify-mesh-and-mpp-path-removal-function.patch ++++ /dev/null +@@ -1,143 +0,0 @@ +-From: Henning Rogge <hrogge@gmail.com> +-Date: Wed, 3 Feb 2016 13:58:38 +0100 +-Subject: [PATCH] mac80211: Unify mesh and mpp path removal function +- +-mpp_path_del() and mesh_path_del() are mostly the same function. +-Move common code into a new static function. +- +-Acked-by: Bob Copeland <me@bobcopeland.com> +-Signed-off-by: Henning Rogge <henning.rogge@fkie.fraunhofer.de> +-Signed-off-by: Johannes Berg <johannes.berg@intel.com> +---- +- +---- a/net/mac80211/mesh_pathtbl.c +-+++ b/net/mac80211/mesh_pathtbl.c +-@@ -55,16 +55,21 @@ int mpp_paths_generation; +- static DEFINE_RWLOCK(pathtbl_resize_lock); +- +- +-+static inline struct mesh_table *resize_dereference_paths( +-+ struct mesh_table __rcu *table) +-+{ +-+ return rcu_dereference_protected(table, +-+ lockdep_is_held(&pathtbl_resize_lock)); +-+} +-+ +- static inline struct mesh_table *resize_dereference_mesh_paths(void) +- { +-- return rcu_dereference_protected(mesh_paths, +-- lockdep_is_held(&pathtbl_resize_lock)); +-+ return resize_dereference_paths(mesh_paths); +- } +- +- static inline struct mesh_table *resize_dereference_mpp_paths(void) +- { +-- return rcu_dereference_protected(mpp_paths, +-- lockdep_is_held(&pathtbl_resize_lock)); +-+ return resize_dereference_paths(mpp_paths); +- } +- +- /* +-@@ -899,14 +904,17 @@ void mesh_path_flush_by_iface(struct iee +- } +- +- /** +-- * mesh_path_del - delete a mesh path from the table +-+ * table_path_del - delete a path from the mesh or mpp table +- * +-- * @addr: dst address (ETH_ALEN length) +-+ * @tbl: mesh or mpp path table +- * @sdata: local subif +-+ * @addr: dst address (ETH_ALEN length) +- * +- * Returns: 0 if successful +- */ +--int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) +-+static int table_path_del(struct mesh_table __rcu *rcu_tbl, +-+ struct ieee80211_sub_if_data *sdata, +-+ const u8 *addr) +- { +- struct mesh_table *tbl; +- struct mesh_path *mpath; +-@@ -915,11 +923,7 @@ int mesh_path_del(struct ieee80211_sub_i +- int hash_idx; +- int err = 0; +- +-- /* flush relevant mpp entries first */ +-- mpp_flush_by_proxy(sdata, addr); +-- +-- read_lock_bh(&pathtbl_resize_lock); +-- tbl = resize_dereference_mesh_paths(); +-+ tbl = resize_dereference_paths(rcu_tbl); +- hash_idx = mesh_table_hash(addr, sdata, tbl); +- bucket = &tbl->hash_buckets[hash_idx]; +- +-@@ -935,9 +939,30 @@ int mesh_path_del(struct ieee80211_sub_i +- +- err = -ENXIO; +- enddel: +-- mesh_paths_generation++; +- spin_unlock(&tbl->hashwlock[hash_idx]); +-+ return err; +-+} +-+ +-+/** +-+ * mesh_path_del - delete a mesh path from the table +-+ * +-+ * @addr: dst address (ETH_ALEN length) +-+ * @sdata: local subif +-+ * +-+ * Returns: 0 if successful +-+ */ +-+int mesh_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) +-+{ +-+ int err = 0; +-+ +-+ /* flush relevant mpp entries first */ +-+ mpp_flush_by_proxy(sdata, addr); +-+ +-+ read_lock_bh(&pathtbl_resize_lock); +-+ err = table_path_del(mesh_paths, sdata, addr); +-+ mesh_paths_generation++; +- read_unlock_bh(&pathtbl_resize_lock); +-+ +- return err; +- } +- +-@@ -951,33 +976,13 @@ enddel: +- */ +- static int mpp_path_del(struct ieee80211_sub_if_data *sdata, const u8 *addr) +- { +-- struct mesh_table *tbl; +-- struct mesh_path *mpath; +-- struct mpath_node *node; +-- struct hlist_head *bucket; +-- int hash_idx; +- int err = 0; +- +- read_lock_bh(&pathtbl_resize_lock); +-- tbl = resize_dereference_mpp_paths(); +-- hash_idx = mesh_table_hash(addr, sdata, tbl); +-- bucket = &tbl->hash_buckets[hash_idx]; +-- +-- spin_lock(&tbl->hashwlock[hash_idx]); +-- hlist_for_each_entry(node, bucket, list) { +-- mpath = node->mpath; +-- if (mpath->sdata == sdata && +-- ether_addr_equal(addr, mpath->dst)) { +-- __mesh_path_del(tbl, node); +-- goto enddel; +-- } +-- } +-- +-- err = -ENXIO; +--enddel: +-- mesh_paths_generation++; +-- spin_unlock(&tbl->hashwlock[hash_idx]); +-+ err = table_path_del(mpp_paths, sdata, addr); +-+ mpp_paths_generation++; +- read_unlock_bh(&pathtbl_resize_lock); +-+ +- return err; +- } +- +diff --git a/package/kernel/mac80211/patches/329-mac80211-fix-check-for-buffered-powersave-frames-wit.patch b/package/kernel/mac80211/patches/329-mac80211-fix-check-for-buffered-powersave-frames-wit.patch +new file mode 100644 +index 0000000..38e541c +--- /dev/null ++++ b/package/kernel/mac80211/patches/329-mac80211-fix-check-for-buffered-powersave-frames-wit.patch +@@ -0,0 +1,21 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Mon, 11 Jul 2016 15:07:06 +0200 ++Subject: [PATCH] mac80211: fix check for buffered powersave frames with txq ++ ++The logic was inverted here, set the bit if frames are pending. ++ ++Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation") ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/net/mac80211/rx.c +++++ b/net/mac80211/rx.c ++@@ -1268,7 +1268,7 @@ static void sta_ps_start(struct sta_info ++ for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { ++ struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); ++ ++- if (!txqi->tin.backlog_packets) +++ if (txqi->tin.backlog_packets) ++ set_bit(tid, &sta->txq_buffered_tids); ++ else ++ clear_bit(tid, &sta->txq_buffered_tids); +diff --git a/package/kernel/mac80211/patches/330-ath10k-fix-rx-status-reporting-for-A-MSDU-subframes.patch b/package/kernel/mac80211/patches/330-ath10k-fix-rx-status-reporting-for-A-MSDU-subframes.patch +new file mode 100644 +index 0000000..a6031b9 +--- /dev/null ++++ b/package/kernel/mac80211/patches/330-ath10k-fix-rx-status-reporting-for-A-MSDU-subframes.patch +@@ -0,0 +1,36 @@ ++From: Felix Fietkau <nbd@nbd.name> ++Date: Sun, 17 Jul 2016 12:49:59 +0200 ++Subject: [PATCH] ath10k: fix rx status reporting for A-MSDU subframes ++ ++Patch by Nagarajan, Ashok Raj <arnagara@qti.qualcomm.com> ++ ++Signed-off-by: Felix Fietkau <nbd@nbd.name> ++--- ++ ++--- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c ++@@ -1525,7 +1525,7 @@ static void ath10k_htt_rx_h_filter(struc ++ static int ath10k_htt_rx_handle_amsdu(struct ath10k_htt *htt) ++ { ++ struct ath10k *ar = htt->ar; ++- static struct ieee80211_rx_status rx_status; +++ struct ieee80211_rx_status *rx_status = &htt->rx_status; ++ struct sk_buff_head amsdu; ++ int ret; + -+- for (tidno = 0, tid = &an->tid[tidno]; -+- tidno < IEEE80211_NUM_TIDS; -+- tidno++, tid++) { -++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { -++ tid = ath_node_to_tid(an, tidno); -+ tid->an = an; -+ tid->tidno = tidno; -+ tid->seq_start = tid->seq_next = 0; -+@@ -2917,11 +2841,14 @@ void ath_tx_node_init(struct ath_softc * -+ tid->baw_head = tid->baw_tail = 0; -+ tid->active = false; -+ tid->clear_ps_filter = true; -+- __skb_queue_head_init(&tid->buf_q); -++ tid->has_queued = false; -+ __skb_queue_head_init(&tid->retry_q); -+ INIT_LIST_HEAD(&tid->list); -+ acno = TID_TO_WME_AC(tidno); -+ tid->txq = sc->tx.txq_map[acno]; -++ -++ if (!an->sta) -++ break; /* just one multicast ath_atx_tid */ ++@@ -1549,11 +1549,11 @@ static int ath10k_htt_rx_handle_amsdu(st ++ return ret; + } -+ } -+ -+@@ -2931,9 +2858,8 @@ void ath_tx_node_cleanup(struct ath_soft -+ struct ath_txq *txq; -+ int tidno; + -+- for (tidno = 0, tid = &an->tid[tidno]; -+- tidno < IEEE80211_NUM_TIDS; tidno++, tid++) { -+- -++ for (tidno = 0; tidno < IEEE80211_NUM_TIDS; tidno++) { -++ tid = ath_node_to_tid(an, tidno); -+ txq = tid->txq; -+ -+ ath_txq_lock(sc, txq); -+@@ -2945,6 +2871,9 @@ void ath_tx_node_cleanup(struct ath_soft -+ tid->active = false; ++- ath10k_htt_rx_h_ppdu(ar, &amsdu, &rx_status, 0xffff); +++ ath10k_htt_rx_h_ppdu(ar, &amsdu, rx_status, 0xffff); ++ ath10k_htt_rx_h_unchain(ar, &amsdu, ret > 0); ++- ath10k_htt_rx_h_filter(ar, &amsdu, &rx_status); ++- ath10k_htt_rx_h_mpdu(ar, &amsdu, &rx_status); ++- ath10k_htt_rx_h_deliver(ar, &amsdu, &rx_status); +++ ath10k_htt_rx_h_filter(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_mpdu(ar, &amsdu, rx_status); +++ ath10k_htt_rx_h_deliver(ar, &amsdu, rx_status); + -+ ath_txq_unlock(sc, txq); -++ -++ if (!an->sta) -++ break; /* just one multicast ath_atx_tid */ -+ } ++ return 0; + } -+ +diff --git a/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch b/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch +deleted file mode 100644 +index 4dc6d66..0000000 +--- a/package/kernel/mac80211/patches/330-mac80211-minstrel-Change-expected-throughput-unit-ba.patch ++++ /dev/null +@@ -1,51 +0,0 @@ +-From: Sven Eckelmann <sven.eckelmann@open-mesh.com> +-Date: Tue, 2 Feb 2016 08:12:26 +0100 +-Subject: [PATCH] mac80211: minstrel: Change expected throughput unit back to +- Kbps +- +-The change from cur_tp to the function +-minstrel_get_tp_avg/minstrel_ht_get_tp_avg changed the unit used for the +-current throughput. For example in minstrel_ht the correct +-conversion between them would be: +- +- mrs->cur_tp / 10 == minstrel_ht_get_tp_avg(..). +- +-This factor 10 must also be included in the calculation of +-minstrel_get_expected_throughput and minstrel_ht_get_expected_throughput to +-return values with the unit [Kbps] instead of [10Kbps]. Otherwise routing +-algorithms like B.A.T.M.A.N. V will make incorrect decision based on these +-values. Its kernel based implementation expects expected_throughput always +-to have the unit [Kbps] and not sometimes [10Kbps] and sometimes [Kbps]. +- +-The same requirement has iw or olsrdv2's nl80211 based statistics module +-which retrieve the same data via NL80211_STA_INFO_TX_BITRATE. +- +-Cc: stable@vger.kernel.org +-Fixes: 6a27b2c40b48 ("mac80211: restructure per-rate throughput calculation into function") +-Signed-off-by: Sven Eckelmann <sven@open-mesh.com> +-Signed-off-by: Johannes Berg <johannes.berg@intel.com> +---- +- +---- a/net/mac80211/rc80211_minstrel.c +-+++ b/net/mac80211/rc80211_minstrel.c +-@@ -711,7 +711,7 @@ static u32 minstrel_get_expected_through +- * computing cur_tp +- */ +- tmp_mrs = &mi->r[idx].stats; +-- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma); +-+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10; +- tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; +- +- return tmp_cur_tp; +---- a/net/mac80211/rc80211_minstrel_ht.c +-+++ b/net/mac80211/rc80211_minstrel_ht.c +-@@ -1335,7 +1335,8 @@ static u32 minstrel_ht_get_expected_thro +- prob = mi->groups[i].rates[j].prob_ewma; +- +- /* convert tp_avg from pkt per second in kbps */ +-- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * AVG_PKT_SIZE * 8 / 1024; +-+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10; +-+ tp_avg = tp_avg * AVG_PKT_SIZE * 8 / 1024; +- +- return tp_avg; +- } +diff --git a/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch b/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch +deleted file mode 100644 +index 1fd016f..0000000 +--- a/package/kernel/mac80211/patches/331-brcmfmac-Increase-nr-of-supported-flowrings.patch ++++ /dev/null +@@ -1,307 +0,0 @@ +-From: Hante Meuleman <meuleman@broadcom.com> +-Date: Sun, 7 Feb 2016 18:08:24 +0100 +-Subject: [PATCH] brcmfmac: Increase nr of supported flowrings. +-MIME-Version: 1.0 +-Content-Type: text/plain; charset=UTF-8 +-Content-Transfer-Encoding: 8bit +- +-New generation devices have firmware which has more than 256 flowrings. +-E.g. following debugging message comes from 14e4:4365 BCM4366: +-[ 194.606245] brcmfmac: brcmf_pcie_init_ringbuffers Nr of flowrings is 264 +- +-At various code places (related to flowrings) we were using u8 which +-could lead to storing wrong number or infinite loops when indexing with +-this type. This issue was quite easy to spot in brcmf_flowring_detach +-where it led to infinite loop e.g. on failed initialization. +- +-This patch switches code to proper types and increases the maximum +-number of supported flowrings to 512. +- +-Originally this change was sent in September 2015, but back it was +-causing a regression on BCM43602 resulting in: +-Unable to handle kernel NULL pointer dereference at virtual address ... +- +-The reason for this regression was missing update (s/u8/u16) of struct +-brcmf_flowring_ring. This problem was handled in 9f64df9 ("brcmfmac: Fix +-bug in flowring management."). Starting with that it's safe to apply +-this original patch as it doesn't cause a regression anymore. +- +-This patch fixes an infinite loop on BCM4366 which is supported since +-4.4 so it makes sense to apply it to stable 4.4+. +- +-Cc: <stable@vger.kernel.org> # 4.4+ +-Reviewed-by: Arend Van Spriel <arend@broadcom.com> +-Reviewed-by: Franky (Zhenhui) Lin <frankyl@broadcom.com> +-Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> +-Signed-off-by: Hante Meuleman <meuleman@broadcom.com> +-Signed-off-by: Arend van Spriel <arend@broadcom.com> +-Signed-off-by: RafaÅ‚ MiÅ‚ecki <zajec5@gmail.com> +---- +- +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c +-@@ -32,7 +32,7 @@ +- #define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256) +- #define BRCMF_FLOWRING_INVALID_IFIDX 0xff +- +--#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16) +-+#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16) +- #define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16) +- +- static const u8 brcmf_flowring_prio2fifo[] = { +-@@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f +- u8 prio, u8 ifidx) +- { +- struct brcmf_flowring_hash *hash; +-- u8 hash_idx; +-+ u16 hash_idx; +- u32 i; +- bool found; +- bool sta; +-@@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f +- } +- hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : +- BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); +-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); +- found = false; +- hash = flow->hash; +- for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { +-@@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_f +- break; +- } +- hash_idx++; +-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); +- } +- if (found) +- return hash[hash_idx].flowid; +-@@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_f +- { +- struct brcmf_flowring_ring *ring; +- struct brcmf_flowring_hash *hash; +-- u8 hash_idx; +-+ u16 hash_idx; +- u32 i; +- bool found; +- u8 fifo; +-@@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_f +- } +- hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) : +- BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx); +-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); +- found = false; +- hash = flow->hash; +- for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) { +-@@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_f +- break; +- } +- hash_idx++; +-+ hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1); +- } +- if (found) { +- for (i = 0; i < flow->nrofrings; i++) { +-@@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_f +- } +- +- +--u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid) +-+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid) +- { +- struct brcmf_flowring_ring *ring; +- +-@@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowr +- } +- +- +--static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, +-+static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid, +- bool blocked) +- { +- struct brcmf_flowring_ring *ring; +-@@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct +- } +- +- +--void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid) +-+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid) +- { +- struct brcmf_flowring_ring *ring; +-- u8 hash_idx; +-+ u16 hash_idx; +- struct sk_buff *skb; +- +- ring = flow->rings[flowid]; +-@@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_ +- } +- +- +--u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, +-+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, +- struct sk_buff *skb) +- { +- struct brcmf_flowring_ring *ring; +-@@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_ +- } +- +- +--struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid) +-+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid) +- { +- struct brcmf_flowring_ring *ring; +- struct sk_buff *skb; +-@@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(s +- } +- +- +--void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, +-+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, +- struct sk_buff *skb) +- { +- struct brcmf_flowring_ring *ring; +-@@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcm +- } +- +- +--u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid) +-+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid) +- { +- struct brcmf_flowring_ring *ring; +- +-@@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flo +- } +- +- +--void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid) +-+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid) +- { +- struct brcmf_flowring_ring *ring; +- +-@@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_fl +- } +- +- +--u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid) +-+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid) +- { +- struct brcmf_flowring_ring *ring; +-- u8 hash_idx; +-+ u16 hash_idx; +- +- ring = flow->rings[flowid]; +- hash_idx = ring->hash_id; +-@@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_ +- struct brcmf_pub *drvr = bus_if->drvr; +- struct brcmf_flowring_tdls_entry *search; +- struct brcmf_flowring_tdls_entry *remove; +-- u8 flowid; +-+ u16 flowid; +- +- for (flowid = 0; flowid < flow->nrofrings; flowid++) { +- if (flow->rings[flowid]) +-@@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode( +- struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev); +- struct brcmf_pub *drvr = bus_if->drvr; +- u32 i; +-- u8 flowid; +-+ u16 flowid; +- +- if (flow->addr_mode[ifidx] != addr_mode) { +- for (i = 0; i < ARRAY_SIZE(flow->hash); i++) { +-@@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct b +- struct brcmf_flowring_tdls_entry *prev; +- struct brcmf_flowring_tdls_entry *search; +- u32 i; +-- u8 flowid; +-+ u16 flowid; +- bool sta; +- +- sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT); +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.h +-@@ -16,7 +16,7 @@ +- #define BRCMFMAC_FLOWRING_H +- +- +--#define BRCMF_FLOWRING_HASHSIZE 256 +-+#define BRCMF_FLOWRING_HASHSIZE 512 /* has to be 2^x */ +- #define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF +- +- +-@@ -24,7 +24,7 @@ struct brcmf_flowring_hash { +- u8 mac[ETH_ALEN]; +- u8 fifo; +- u8 ifidx; +-- u8 flowid; +-+ u16 flowid; +- }; +- +- enum ring_status { +-@@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_f +- u8 prio, u8 ifidx); +- u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN], +- u8 prio, u8 ifidx); +--void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid); +--void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid); +--u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid); +--u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid, +-+void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid); +-+void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid); +-+u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid); +-+u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid, +- struct sk_buff *skb); +--struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid); +--void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid, +-+struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid); +-+void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid, +- struct sk_buff *skb); +--u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid); +--u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid); +-+u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid); +-+u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid); +- struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings); +- void brcmf_flowring_detach(struct brcmf_flowring *flow); +- void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +-@@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create( +- } +- +- +--static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid) +-+static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid) +- { +- struct brcmf_flowring *flow = msgbuf->flow; +- struct brcmf_commonring *commonring; +-@@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct +- } +- +- +--void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) +-+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) +- { +- struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; +- struct msgbuf_tx_flowring_delete_req *delete; +-@@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brc +- u32 count; +- +- if_msgbuf = drvr->bus_if->msgbuf; +-+ +-+ if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) { +-+ brcmf_err("driver not configured for this many flowrings %d\n", +-+ if_msgbuf->nrof_flowrings); +-+ if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1; +-+ } +-+ +- msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL); +- if (!msgbuf) +- goto fail; +---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +-+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h +-@@ -33,7 +33,7 @@ +- +- +- int brcmf_proto_msgbuf_rx_trigger(struct device *dev); +--void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid); +-+void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid); +- int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr); +- void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr); +- #else +diff --git a/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch b/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch +deleted file mode 100644 +index e414f23..0000000 +--- a/package/kernel/mac80211/patches/332-cfg80211-fix-faulty-variable-initialization-in-ieee8.patch ++++ /dev/null +@@ -1,22 +0,0 @@ +-From: Felix Fietkau <nbd@openwrt.org> +-Date: Mon, 8 Feb 2016 14:24:36 +0100 +-Subject: [PATCH] cfg80211: fix faulty variable initialization in +- ieee80211_amsdu_to_8023s +- +-reuse_skb is set to true if the code decides to use the last segment. +-Fixes a memory leak +- +-Signed-off-by: Felix Fietkau <nbd@openwrt.org> +---- +- +---- a/net/wireless/util.c +-+++ b/net/wireless/util.c +-@@ -676,7 +676,7 @@ void ieee80211_amsdu_to_8023s(struct sk_ +- u8 *payload; +- int offset = 0, remaining, err; +- struct ethhdr eth; +-- bool reuse_skb = true; +-+ bool reuse_skb = false; +- bool last = false; +- +- if (has_80211_header) { +diff --git a/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch b/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch +deleted file mode 100644 +index 6e2d0cf..0000000 +--- a/package/kernel/mac80211/patches/333-cfg80211-reuse-existing-page-fragments-in-A-MSDU-rx.patch ++++ /dev/null +@@ -1,132 +0,0 @@ +-From: Felix Fietkau <nbd@openwrt.org> +-Date: Mon, 8 Feb 2016 14:33:19 +0100 +-Subject: [PATCH] cfg80211: reuse existing page fragments in A-MSDU rx +- +-This massively reduces data copying and thus improves rx performance +- +-Signed-off-by: Felix Fietkau <nbd@openwrt.org> +---- +- +---- a/net/wireless/util.c +-+++ b/net/wireless/util.c +-@@ -644,23 +644,93 @@ int ieee80211_data_from_8023(struct sk_b +- } +- EXPORT_SYMBOL(ieee80211_data_from_8023); +- +-+static void +-+__frame_add_frag(struct sk_buff *skb, struct page *page, +-+ void *ptr, int len, int size) +-+{ +-+ struct skb_shared_info *sh = skb_shinfo(skb); +-+ int page_offset; +-+ +-+ atomic_inc(&page->_count); +-+ page_offset = ptr - page_address(page); +-+ skb_add_rx_frag(skb, sh->nr_frags, page, page_offset, len, size); +-+} +-+ +-+static void +-+__ieee80211_amsdu_copy_frag(struct sk_buff *skb, struct sk_buff *frame, +-+ int offset, int len) +-+{ +-+ struct skb_shared_info *sh = skb_shinfo(skb); +-+ const skb_frag_t *frag = &sh->frags[-1]; +-+ struct page *frag_page; +-+ void *frag_ptr; +-+ int frag_len, frag_size; +-+ int head_size = skb->len - skb->data_len; +-+ int cur_len; +-+ +-+ frag_page = virt_to_head_page(skb->head); +-+ frag_ptr = skb->data; +-+ frag_size = head_size; +-+ +-+ while (offset >= frag_size) { +-+ offset -= frag_size; +-+ frag++; +-+ frag_page = skb_frag_page(frag); +-+ frag_ptr = skb_frag_address(frag); +-+ frag_size = skb_frag_size(frag); +-+ } +-+ +-+ frag_ptr += offset; +-+ frag_len = frag_size - offset; +-+ +-+ cur_len = min(len, frag_len); +-+ +-+ __frame_add_frag(frame, frag_page, frag_ptr, cur_len, frag_size); +-+ len -= cur_len; +-+ +-+ while (len > 0) { +-+ frag++; +-+ frag_len = skb_frag_size(frag); +-+ cur_len = min(len, frag_len); +-+ __frame_add_frag(frame, skb_frag_page(frag), +-+ skb_frag_address(frag), cur_len, frag_len); +-+ len -= cur_len; +-+ } +-+} +-+ +- static struct sk_buff * +- __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen, +-- int offset, int len) +-+ int offset, int len, bool reuse_frag) +- { +- struct sk_buff *frame; +-+ int cur_len = len; +- +- if (skb->len - offset < len) +- return NULL; +- +- /* +-+ * When reusing framents, copy some data to the head to simplify +-+ * ethernet header handling and speed up protocol header processing +-+ * in the stack later. +-+ */ +-+ if (reuse_frag) +-+ cur_len = min_t(int, len, 32); +-+ +-+ /* +- * Allocate and reserve two bytes more for payload +- * alignment since sizeof(struct ethhdr) is 14. +- */ +-- frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + len); +-+ frame = dev_alloc_skb(hlen + sizeof(struct ethhdr) + 2 + cur_len); +- +- skb_reserve(frame, hlen + sizeof(struct ethhdr) + 2); +-- skb_copy_bits(skb, offset, skb_put(frame, len), len); +-+ skb_copy_bits(skb, offset, skb_put(frame, cur_len), cur_len); +-+ +-+ len -= cur_len; +-+ if (!len) +-+ return frame; +-+ +-+ offset += cur_len; +-+ __ieee80211_amsdu_copy_frag(skb, frame, offset, len); +- +- return frame; +- } +-@@ -676,6 +746,7 @@ void ieee80211_amsdu_to_8023s(struct sk_ +- u8 *payload; +- int offset = 0, remaining, err; +- struct ethhdr eth; +-+ bool reuse_frag = skb->head_frag && !skb_has_frag_list(skb); +- bool reuse_skb = false; +- bool last = false; +- +-@@ -703,12 +774,13 @@ void ieee80211_amsdu_to_8023s(struct sk_ +- offset += sizeof(struct ethhdr); +- /* reuse skb for the last subframe */ +- last = remaining <= subframe_len + padding; +-- if (!skb_is_nonlinear(skb) && last) { +-+ if (!skb_is_nonlinear(skb) && !reuse_frag && last) { +- skb_pull(skb, offset); +- frame = skb; +- reuse_skb = true; +- } else { +-- frame = __ieee80211_amsdu_copy(skb, hlen, offset, len); +-+ frame = __ieee80211_amsdu_copy(skb, hlen, offset, len, +-+ reuse_frag); +- if (!frame) +- goto purge; +- +diff --git a/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch b/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch +deleted file mode 100644 +index f8f4f09..0000000 +--- a/package/kernel/mac80211/patches/334-mac80211-fix-wiphy-supported_band-access.patch ++++ /dev/null +@@ -1,36 +0,0 @@ +-From: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> +-Date: Wed, 10 Feb 2016 16:08:17 +0100 +-Subject: [PATCH] mac80211: fix wiphy supported_band access +- +-Fix wiphy supported_band access in tx radiotap parsing. In particular, +-info->band is always set to 0 (IEEE80211_BAND_2GHZ) since it has not +-assigned yet. This cause a kernel crash on 5GHz only devices. +-Move ieee80211_parse_tx_radiotap() after info->band assignment +- +-Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi83@gmail.com> +---- +- +---- a/net/mac80211/tx.c +-+++ b/net/mac80211/tx.c +-@@ -1890,10 +1890,6 @@ netdev_tx_t ieee80211_monitor_start_xmit +- info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS | +- IEEE80211_TX_CTL_INJECTED; +- +-- /* process and remove the injection radiotap header */ +-- if (!ieee80211_parse_tx_radiotap(local, skb)) +-- goto fail; +-- +- rcu_read_lock(); +- +- /* +-@@ -1955,6 +1951,10 @@ netdev_tx_t ieee80211_monitor_start_xmit +- goto fail_rcu; +- +- info->band = chandef->chan->band; +-+ /* process and remove the injection radiotap header */ +-+ if (!ieee80211_parse_tx_radiotap(local, skb)) +-+ goto fail_rcu; +-+ +- ieee80211_xmit(sdata, NULL, skb); +- rcu_read_unlock(); +- +diff --git a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch b/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch +deleted file mode 100644 +index acaacf7..0000000 +--- a/package/kernel/mac80211/patches/335-mac80211-minstrel_ht-set-A-MSDU-tx-limits-based-on-s.patch ++++ /dev/null +@@ -1,61 +0,0 @@ +-From: Felix Fietkau <nbd@openwrt.org> +-Date: Thu, 18 Feb 2016 19:30:05 +0100 +-Subject: [PATCH] mac80211: minstrel_ht: set A-MSDU tx limits based on selected +- max_prob_rate +- +-Prevents excessive A-MSDU aggregation at low data rates or bad +-conditions. +- +-Signed-off-by: Felix Fietkau <nbd@openwrt.org> +---- +- +---- a/net/mac80211/rc80211_minstrel_ht.c +-+++ b/net/mac80211/rc80211_minstrel_ht.c +-@@ -883,6 +883,39 @@ minstrel_ht_set_rate(struct minstrel_pri +- ratetbl->rate[offset].flags = flags; +- } +- +-+static int +-+minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) +-+{ +-+ int group = mi->max_prob_rate / MCS_GROUP_RATES; +-+ const struct mcs_group *g = &minstrel_mcs_groups[group]; +-+ int rate = mi->max_prob_rate % MCS_GROUP_RATES; +-+ +-+ /* Disable A-MSDU if max_prob_rate is bad */ +-+ if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) +-+ return 1; +-+ +-+ /* If the rate is slower than single-stream MCS1, make A-MSDU limit small */ +-+ if (g->duration[rate] > MCS_DURATION(1, 0, 52)) +-+ return 500; +-+ +-+ /* +-+ * If the rate is slower than single-stream MCS4, limit A-MSDU to usual +-+ * data packet size +-+ */ +-+ if (g->duration[rate] > MCS_DURATION(1, 0, 104)) +-+ return 1500; +-+ +-+ /* +-+ * If the rate is slower than single-stream MCS7, limit A-MSDU to twice +-+ * the usual data packet size +-+ */ +-+ if (g->duration[rate] > MCS_DURATION(1, 0, 260)) +-+ return 3000; +-+ +-+ /* unlimited */ +-+ return 0; +-+} +-+ +- static void +- minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) +- { +-@@ -907,6 +940,7 @@ minstrel_ht_update_rates(struct minstrel +- minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_prob_rate); +- } +- +-+ mi->sta->max_rc_amsdu_len = minstrel_ht_get_max_amsdu_len(mi); +- rates->rate[i].idx = -1; +- rate_control_set_rates(mp->hw, mi->sta, rates); +- } +diff --git a/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch b/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch +deleted file mode 100644 +index 32a2ad6..0000000 +--- a/package/kernel/mac80211/patches/336-mac80211-minstrel_ht-set-default-tx-aggregation-time.patch ++++ /dev/null +@@ -1,31 +0,0 @@ +-From: Felix Fietkau <nbd@openwrt.org> +-Date: Thu, 18 Feb 2016 19:45:33 +0100 +-Subject: [PATCH] mac80211: minstrel_ht: set default tx aggregation timeout to +- 0 +- +-The value 5000 was put here with the addition of the timeout field to +-ieee80211_start_tx_ba_session. It was originally added in mac80211 to +-save resources for drivers like iwlwifi, which only supports a limited +-number of concurrent aggregation sessions. +- +-Since iwlwifi does not use minstrel_ht and other drivers don't need +-this, 0 is a better default - especially since there have been +-recent reports of aggregation setup related issues reproduced with +-ath9k. This should improve stability without causing any adverse +-effects. +- +-Cc: stable@vger.kernel.org +-Signed-off-by: Felix Fietkau <nbd@openwrt.org> +---- +- +---- a/net/mac80211/rc80211_minstrel_ht.c +-+++ b/net/mac80211/rc80211_minstrel_ht.c +-@@ -692,7 +692,7 @@ minstrel_aggr_check(struct ieee80211_sta +- if (likely(sta->ampdu_mlme.tid_tx[tid])) +- return; +- +-- ieee80211_start_tx_ba_session(pubsta, tid, 5000); +-+ ieee80211_start_tx_ba_session(pubsta, tid, 0); +- } +- +- static void diff --git a/package/kernel/mac80211/patches/337-mac80211-minstrel_ht-fix-a-logic-error-in-RTS-CTS-ha.patch b/package/kernel/mac80211/patches/337-mac80211-minstrel_ht-fix-a-logic-error-in-RTS-CTS-ha.patch deleted file mode 100644 index 229351b..0000000 @@ -10706,98 +9189,6 @@ index 56cd94a..0000000 - !ether_addr_equal(bssid, hdr->addr1)) - return false; - } -diff --git a/package/kernel/mac80211/patches/338-mac80211-fix-tim-recalculation-after-PS-response.patch b/package/kernel/mac80211/patches/338-mac80211-fix-tim-recalculation-after-PS-response.patch -new file mode 100644 -index 0000000..6c0852e ---- /dev/null -+++ b/package/kernel/mac80211/patches/338-mac80211-fix-tim-recalculation-after-PS-response.patch -@@ -0,0 +1,31 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Fri, 26 Aug 2016 21:57:16 +0200 -+Subject: [PATCH] mac80211: fix tim recalculation after PS response -+ -+Handle the case where the mac80211 intermediate queues are empty and the -+driver has buffered frames -+ -+Fixes: ba8c3d6f16a1 ("mac80211: add an intermediate software queue implementation") -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/net/mac80211/sta_info.c -++++ b/net/mac80211/sta_info.c -+@@ -1616,7 +1616,6 @@ ieee80211_sta_ps_deliver_response(struct -+ -+ sta_info_recalc_tim(sta); -+ } else { -+- unsigned long tids = sta->txq_buffered_tids & driver_release_tids; -+ int tid; -+ -+ /* -+@@ -1648,7 +1647,8 @@ ieee80211_sta_ps_deliver_response(struct -+ for (tid = 0; tid < ARRAY_SIZE(sta->sta.txq); tid++) { -+ struct txq_info *txqi = to_txq_info(sta->sta.txq[tid]); -+ -+- if (!(tids & BIT(tid)) || txqi->tin.backlog_packets) -++ if (!(driver_release_tids & BIT(tid)) || -++ txqi->tin.backlog_packets) -+ continue; -+ -+ sta_info_recalc_tim(sta); -diff --git a/package/kernel/mac80211/patches/339-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch b/package/kernel/mac80211/patches/339-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch -new file mode 100644 -index 0000000..49b37e4 ---- /dev/null -+++ b/package/kernel/mac80211/patches/339-ath9k-fix-moredata-bit-in-PS-buffered-frame-release.patch -@@ -0,0 +1,49 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 28 Aug 2016 13:13:01 +0200 -+Subject: [PATCH] ath9k: fix moredata bit in PS buffered frame release -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -1634,6 +1634,21 @@ void ath_tx_aggr_wakeup(struct ath_softc -+ } -+ } -+ -++static void -++ath9k_set_moredata(struct ath_softc *sc, struct ath_buf *bf, bool val) -++{ -++ struct ieee80211_hdr *hdr; -++ u16 mask = cpu_to_le16(IEEE80211_FCTL_MOREDATA); -++ u16 mask_val = mask * val; -++ -++ hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; -++ if ((hdr->frame_control & mask) != mask_val) { -++ hdr->frame_control = (hdr->frame_control & ~mask) | mask_val; -++ dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, -++ sizeof(*hdr), DMA_TO_DEVICE); -++ } -++} -++ -+ void ath9k_release_buffered_frames(struct ieee80211_hw *hw, -+ struct ieee80211_sta *sta, -+ u16 tids, int nframes, -+@@ -1664,6 +1679,7 @@ void ath9k_release_buffered_frames(struc -+ if (!bf) -+ break; -+ -++ ath9k_set_moredata(sc, bf, true); -+ list_add_tail(&bf->list, &bf_q); -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); -+ if (bf_isampdu(bf)) { -+@@ -1687,6 +1703,9 @@ void ath9k_release_buffered_frames(struc -+ if (list_empty(&bf_q)) -+ return; -+ -++ if (!more_data) -++ ath9k_set_moredata(sc, bf_tail, false); -++ -+ info = IEEE80211_SKB_CB(bf_tail->bf_mpdu); -+ info->flags |= IEEE80211_TX_STATUS_EOSP; -+ diff --git a/package/kernel/mac80211/patches/339-cfg80211-add-radiotap-VHT-info-to-rtap_namespace_siz.patch b/package/kernel/mac80211/patches/339-cfg80211-add-radiotap-VHT-info-to-rtap_namespace_siz.patch deleted file mode 100644 index 15d6cd0..0000000 @@ -10825,34 +9216,6 @@ index 15d6cd0..0000000 - /* - * add more here as they are defined in radiotap.h - */ -diff --git a/package/kernel/mac80211/patches/340-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch b/package/kernel/mac80211/patches/340-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch -new file mode 100644 -index 0000000..929da25 ---- /dev/null -+++ b/package/kernel/mac80211/patches/340-ath9k-clear-potentially-stale-EOSP-status-bit-in-int.patch -@@ -0,0 +1,22 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 28 Aug 2016 13:13:42 +0200 -+Subject: [PATCH] ath9k: clear potentially stale EOSP status bit in -+ intermediate queues -+ -+Prevents spurious ieee80211_sta_eosp calls. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -945,7 +945,8 @@ ath_tx_get_tid_subframe(struct ath_softc -+ bf->bf_lastbf = bf; -+ -+ tx_info = IEEE80211_SKB_CB(skb); -+- tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT; -++ tx_info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | -++ IEEE80211_TX_STATUS_EOSP); -+ -+ /* -+ * No aggregation session is running, but there may be frames diff --git a/package/kernel/mac80211/patches/340-mac80211-fix-parsing-of-40Mhz-in-injected-radiotap-h.patch b/package/kernel/mac80211/patches/340-mac80211-fix-parsing-of-40Mhz-in-injected-radiotap-h.patch deleted file mode 100644 index de1b386..0000000 @@ -10895,52 +9258,6 @@ index de1b386..0000000 - rate_flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; - break; - -diff --git a/package/kernel/mac80211/patches/341-ath9k-release-PS-buffered-frames-as-A-MPDU-if-enable.patch b/package/kernel/mac80211/patches/341-ath9k-release-PS-buffered-frames-as-A-MPDU-if-enable.patch -new file mode 100644 -index 0000000..1cc1667 ---- /dev/null -+++ b/package/kernel/mac80211/patches/341-ath9k-release-PS-buffered-frames-as-A-MPDU-if-enable.patch -@@ -0,0 +1,40 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 28 Aug 2016 13:15:10 +0200 -+Subject: [PATCH] ath9k: release PS buffered frames as A-MPDU if enabled -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -1660,10 +1660,11 @@ void ath9k_release_buffered_frames(struc -+ struct ath_node *an = (struct ath_node *)sta->drv_priv; -+ struct ath_txq *txq = sc->tx.uapsdq; -+ struct ieee80211_tx_info *info; -++ struct ath_frame_info *fi; -+ struct list_head bf_q; -+ struct ath_buf *bf_tail = NULL, *bf; -+ int sent = 0; -+- int i; -++ int n, i; -+ -+ INIT_LIST_HEAD(&bf_q); -+ for (i = 0; tids && nframes; i++, tids >>= 1) { -+@@ -1683,10 +1684,15 @@ void ath9k_release_buffered_frames(struc -+ ath9k_set_moredata(sc, bf, true); -+ list_add_tail(&bf->list, &bf_q); -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); -+- if (bf_isampdu(bf)) { -++ if (bf_isampdu(bf)) -+ ath_tx_addto_baw(sc, tid, bf); -+- bf->bf_state.bf_type &= ~BUF_AGGR; -++ if (bf_isaggr(bf)) { -++ fi = get_frame_info(bf->bf_mpdu); -++ n = ath_compute_num_delims(sc, tid, bf, -++ fi->framelen, true); -++ bf->bf_state.ndelim = n; -+ } -++ -+ if (bf_tail) -+ bf_tail->bf_next = bf; -+ diff --git a/package/kernel/mac80211/patches/341-mac80211-parse-VHT-info-in-injected-frames.patch b/package/kernel/mac80211/patches/341-mac80211-parse-VHT-info-in-injected-frames.patch deleted file mode 100644 index ac1f251..0000000 @@ -11012,31 +9329,6 @@ index ac1f251..0000000 - } else { - for (i = 0; i < sband->n_bitrates; i++) { - if (rate * 5 != sband->bitrates[i].bitrate) -diff --git a/package/kernel/mac80211/patches/342-ath9k-report-tx-status-on-EOSP.patch b/package/kernel/mac80211/patches/342-ath9k-report-tx-status-on-EOSP.patch -new file mode 100644 -index 0000000..80a3074 ---- /dev/null -+++ b/package/kernel/mac80211/patches/342-ath9k-report-tx-status-on-EOSP.patch -@@ -0,0 +1,19 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 28 Aug 2016 13:23:27 +0200 -+Subject: [PATCH] ath9k: report tx status on EOSP -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee802 -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ struct ieee80211_sta *sta = info->status.status_driver_data[0]; -+ -+- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { -++ if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | -++ IEEE80211_TX_STATUS_EOSP)) { -+ ieee80211_tx_status(hw, skb); -+ return; -+ } diff --git a/package/kernel/mac80211/patches/342-mac80211-do-not-pass-injected-frames-without-a-valid.patch b/package/kernel/mac80211/patches/342-mac80211-do-not-pass-injected-frames-without-a-valid.patch deleted file mode 100644 index d7452c2..0000000 @@ -11066,123 +9358,6 @@ index d7452c2..0000000 - info->control.rates[0].flags = rate_flags; - info->control.rates[0].count = min_t(u8, rate_retries + 1, - local->hw.max_rate_tries); -diff --git a/package/kernel/mac80211/patches/343-ath9k-fix-block-ack-window-tracking-issues.patch b/package/kernel/mac80211/patches/343-ath9k-fix-block-ack-window-tracking-issues.patch -new file mode 100644 -index 0000000..007a8d7d ---- /dev/null -+++ b/package/kernel/mac80211/patches/343-ath9k-fix-block-ack-window-tracking-issues.patch -@@ -0,0 +1,111 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 30 Aug 2016 12:44:08 +0200 -+Subject: [PATCH] ath9k: fix block-ack window tracking issues -+ -+Ensure that a buffer gets tracked as part of the block-ack window as -+soon as it's dequeued from the tid for the first time. Ensure that -+double calls to ath_tx_addto_baw (e.g. on retransmission) don't cause -+any issues. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -62,7 +62,7 @@ static void ath_tx_rc_status(struct ath_ -+ struct ath_tx_status *ts, int nframes, int nbad, -+ int txok); -+ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, -+- int seqno); -++ struct ath_buf *bf); -+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, -+ struct ath_txq *txq, -+ struct ath_atx_tid *tid, -+@@ -300,7 +300,7 @@ static void ath_tx_flush_tid(struct ath_ -+ } -+ -+ if (fi->baw_tracked) { -+- ath_tx_update_baw(sc, tid, bf->bf_state.seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ sendbar = true; -+ } -+ -+@@ -316,10 +316,15 @@ static void ath_tx_flush_tid(struct ath_ -+ } -+ -+ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, -+- int seqno) -++ struct ath_buf *bf) -+ { -++ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); -++ u16 seqno = bf->bf_state.seqno; -+ int index, cindex; -+ -++ if (!fi->baw_tracked) -++ return; -++ -+ index = ATH_BA_INDEX(tid->seq_start, seqno); -+ cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -+ -+@@ -340,6 +345,9 @@ static void ath_tx_addto_baw(struct ath_ -+ u16 seqno = bf->bf_state.seqno; -+ int index, cindex; -+ -++ if (fi->baw_tracked) -++ return; -++ -+ index = ATH_BA_INDEX(tid->seq_start, seqno); -+ cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -+ __set_bit(cindex, tid->tx_buf); -+@@ -616,7 +624,7 @@ static void ath_tx_complete_aggr(struct -+ * complete the acked-ones/xretried ones; update -+ * block-ack window -+ */ -+- ath_tx_update_baw(sc, tid, seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ -+ if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { -+ memcpy(tx_info->control.rates, rates, sizeof(rates)); -+@@ -646,7 +654,7 @@ static void ath_tx_complete_aggr(struct -+ * run out of tx buf. -+ */ -+ if (!tbf) { -+- ath_tx_update_baw(sc, tid, seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ -+ ath_tx_complete_buf(sc, bf, txq, -+ &bf_head, NULL, ts, -+@@ -986,11 +994,14 @@ ath_tx_get_tid_subframe(struct ath_softc -+ -+ INIT_LIST_HEAD(&bf_head); -+ list_add(&bf->list, &bf_head); -+- ath_tx_update_baw(sc, tid, seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); -+ continue; -+ } -+ -++ if (bf_isampdu(bf)) -++ ath_tx_addto_baw(sc, tid, bf); -++ -+ return bf; -+ } -+ -+@@ -1048,8 +1059,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s -+ bf->bf_next = NULL; -+ -+ /* link buffers of this frame to the aggregate */ -+- if (!fi->baw_tracked) -+- ath_tx_addto_baw(sc, tid, bf); -+ bf->bf_state.ndelim = ndelim; -+ -+ list_add_tail(&bf->list, bf_q); -+@@ -1685,8 +1694,6 @@ void ath9k_release_buffered_frames(struc -+ ath9k_set_moredata(sc, bf, true); -+ list_add_tail(&bf->list, &bf_q); -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); -+- if (bf_isampdu(bf)) -+- ath_tx_addto_baw(sc, tid, bf); -+ if (bf_isaggr(bf)) { -+ fi = get_frame_info(bf->bf_mpdu); -+ n = ath_compute_num_delims(sc, tid, bf, diff --git a/package/kernel/mac80211/patches/343-mac80211-minstrel_ht-improve-sample-rate-skip-logic.patch b/package/kernel/mac80211/patches/343-mac80211-minstrel_ht-improve-sample-rate-skip-logic.patch deleted file mode 100644 index 55ff817..0000000 @@ -15851,76 +14026,6 @@ index c20d40c..0000000 - - #define DOT11_DEFAULT_RTS_LEN 2347 - #define DOT11_DEFAULT_FRAG_LEN 2346 -diff --git a/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch b/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch -new file mode 100644 -index 0000000..3bbca22 ---- /dev/null -+++ b/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch -@@ -0,0 +1,64 @@ -+From: Johannes Berg <johannes.berg@intel.com> -+Date: Mon, 29 Aug 2016 23:25:18 +0300 -+Subject: [PATCH] mac80211: send delBA on unexpected BlockAck data frames -+ -+When we receive data frames with ACK policy BlockAck, send -+delBA as requested by the 802.11 spec. Since this would be -+happening for every frame inside an A-MPDU if it's really -+received outside a session, limit it to a single attempt. -+ -+Signed-off-by: Johannes Berg <johannes.berg@intel.com> -+--- -+ -+--- a/net/mac80211/agg-rx.c -++++ b/net/mac80211/agg-rx.c -+@@ -388,8 +388,10 @@ void __ieee80211_start_rx_ba_session(str -+ } -+ -+ end: -+- if (status == WLAN_STATUS_SUCCESS) -++ if (status == WLAN_STATUS_SUCCESS) { -+ __set_bit(tid, sta->ampdu_mlme.agg_session_valid); -++ __clear_bit(tid, sta->ampdu_mlme.unexpected_agg); -++ } -+ mutex_unlock(&sta->ampdu_mlme.mtx); -+ -+ end_no_lock: -+--- a/net/mac80211/rx.c -++++ b/net/mac80211/rx.c -+@@ -1072,8 +1072,15 @@ static void ieee80211_rx_reorder_ampdu(s -+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; -+ -+ tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); -+- if (!tid_agg_rx) -++ if (!tid_agg_rx) { -++ if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && -++ !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && -++ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) -++ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, -++ WLAN_BACK_RECIPIENT, -++ WLAN_REASON_QSTA_REQUIRE_SETUP); -+ goto dont_reorder; -++ } -+ -+ /* qos null data frames are excluded */ -+ if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) -+--- a/net/mac80211/sta_info.h -++++ b/net/mac80211/sta_info.h -+@@ -230,6 +230,8 @@ struct tid_ampdu_rx { -+ * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the -+ * driver requested to close until the work for it runs -+ * @agg_session_valid: bitmap indicating which TID has a rx BA session open on -++ * @unexpected_agg: bitmap indicating which TID already sent a delBA due to -++ * unexpected aggregation related frames outside a session -+ * @work: work struct for starting/stopping aggregation -+ * @tid_tx: aggregation info for Tx per TID -+ * @tid_start_tx: sessions where start was requested -+@@ -244,6 +246,7 @@ struct sta_ampdu_mlme { -+ unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -+ unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -+ unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -++ unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -+ /* tx */ -+ struct work_struct work; -+ struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; diff --git a/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch b/package/kernel/mac80211/patches/345-brcmfmac-Remove-waitqueue_active-check.patch deleted file mode 100644 index 39f4383..0000000 @@ -15981,38 +14086,6 @@ index 39f4383..0000000 - } - } - -diff --git a/package/kernel/mac80211/patches/345-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch b/package/kernel/mac80211/patches/345-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch -new file mode 100644 -index 0000000..c3d3118 ---- /dev/null -+++ b/package/kernel/mac80211/patches/345-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch -@@ -0,0 +1,26 @@ -+From: Johannes Berg <johannes.berg@intel.com> -+Date: Mon, 29 Aug 2016 23:25:19 +0300 -+Subject: [PATCH] mac80211: send delBA on unexpected BlockAck Request -+ -+If we don't have a BA session, send delBA, as requested by the -+IEEE 802.11 spec. Apply the same limit of sending such a delBA -+only once as in the previous patch. -+ -+Signed-off-by: Johannes Berg <johannes.berg@intel.com> -+--- -+ -+--- a/net/mac80211/rx.c -++++ b/net/mac80211/rx.c -+@@ -2537,6 +2537,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_ -+ -+ tid = le16_to_cpu(bar_data.control) >> 12; -+ -++ if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && -++ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) -++ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, -++ WLAN_BACK_RECIPIENT, -++ WLAN_REASON_QSTA_REQUIRE_SETUP); -++ -+ tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); -+ if (!tid_agg_rx) -+ return RX_DROP_MONITOR; diff --git a/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch b/package/kernel/mac80211/patches/346-brcmfmac-uninitialized-ret-variable.patch deleted file mode 100644 index 3c9ed42..0000000 @@ -16040,119 +14113,6 @@ index 3c9ed42..0000000 - - brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", - write, fn, addr, regsz); -diff --git a/package/kernel/mac80211/patches/346-mac80211-fix-sequence-number-assignment-for-PS-respo.patch b/package/kernel/mac80211/patches/346-mac80211-fix-sequence-number-assignment-for-PS-respo.patch -new file mode 100644 -index 0000000..a82d12f ---- /dev/null -+++ b/package/kernel/mac80211/patches/346-mac80211-fix-sequence-number-assignment-for-PS-respo.patch -@@ -0,0 +1,107 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 4 Sep 2016 17:46:24 +0200 -+Subject: [PATCH] mac80211: fix sequence number assignment for PS response -+ frames -+ -+When using intermediate queues, sequence number allocation is deferred -+until dequeue. This doesn't work for PS response frames, which bypass -+those queues. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/net/mac80211/tx.c -++++ b/net/mac80211/tx.c -+@@ -792,6 +792,36 @@ static __le16 ieee80211_tx_next_seq(stru -+ return ret; -+ } -+ -++static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, -++ struct ieee80211_vif *vif, -++ struct ieee80211_sta *pubsta, -++ struct sk_buff *skb) -++{ -++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ struct ieee80211_txq *txq = NULL; -++ -++ if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) || -++ (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) -++ return NULL; -++ -++ if (!ieee80211_is_data(hdr->frame_control)) -++ return NULL; -++ -++ if (pubsta) { -++ u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; -++ -++ txq = pubsta->txq[tid]; -++ } else if (vif) { -++ txq = vif->txq; -++ } -++ -++ if (!txq) -++ return NULL; -++ -++ return to_txq_info(txq); -++} -++ -+ static ieee80211_tx_result debug_noinline -+ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) -+ { -+@@ -849,7 +879,8 @@ ieee80211_tx_h_sequence(struct ieee80211 -+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; -+ tx->sta->tx_stats.msdu[tid]++; -+ -+- if (!tx->sta->sta.txq[0]) -++ if (!ieee80211_get_txq(tx->local, info->control.vif, &tx->sta->sta, -++ tx->skb)) -+ hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -+ -+ return TX_CONTINUE; -+@@ -1238,36 +1269,6 @@ ieee80211_tx_prepare(struct ieee80211_su -+ return TX_CONTINUE; -+ } -+ -+-static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, -+- struct ieee80211_vif *vif, -+- struct ieee80211_sta *pubsta, -+- struct sk_buff *skb) -+-{ -+- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; -+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+- struct ieee80211_txq *txq = NULL; -+- -+- if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) || -+- (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) -+- return NULL; -+- -+- if (!ieee80211_is_data(hdr->frame_control)) -+- return NULL; -+- -+- if (pubsta) { -+- u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; -+- -+- txq = pubsta->txq[tid]; -+- } else if (vif) { -+- txq = vif->txq; -+- } -+- -+- if (!txq) -+- return NULL; -+- -+- return to_txq_info(txq); -+-} -+- -+ static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb) -+ { -+ IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time(); -+@@ -3265,7 +3266,7 @@ static bool ieee80211_xmit_fast(struct i -+ -+ if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -+ *ieee80211_get_qos_ctl(hdr) = tid; -+- if (!sta->sta.txq[0]) -++ if (!ieee80211_get_txq(local, &sdata->vif, &sta->sta, skb)) -+ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); -+ } else { -+ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; diff --git a/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch b/package/kernel/mac80211/patches/347-brcmfmac-sdio-remove-unused-variable-retry_limit.patch deleted file mode 100644 index d1deb6e..0000000 @@ -20836,14 +18796,13 @@ index e151a12..c40598d 100644 return result; } diff --git a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch -index 5a5e464..69147f6 100644 +index 5a5e464..0b25749 100644 --- a/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch +++ b/package/kernel/mac80211/patches/530-ath9k_extra_leds.patch @@ -1,16 +1,16 @@ --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h --@@ -814,6 +814,9 @@ static inline int ath9k_dump_btcoex(stru -+@@ -827,6 +827,9 @@ static inline int ath9k_dump_btcoex(stru + @@ -814,6 +814,9 @@ static inline int ath9k_dump_btcoex(stru + #ifdef CPTCFG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); void ath_deinit_leds(struct ath_softc *sc); @@ -20856,7 +18815,7 @@ index 5a5e464..69147f6 100644 static inline void ath_init_leds(struct ath_softc *sc) { -@@ -953,6 +956,13 @@ void ath_ant_comb_scan(struct ath_softc -+@@ -963,6 +966,13 @@ void ath_ant_comb_scan(struct ath_softc ++@@ -950,6 +953,13 @@ void ath_ant_comb_scan(struct ath_softc #define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ @@ -20865,7 +18824,7 @@ index 5a5e464..69147f6 100644 struct ieee80211_hw *hw; struct device *dev; -@@ -1005,9 +1015,8 @@ struct ath_softc { -+@@ -1015,9 +1025,8 @@ struct ath_softc { ++@@ -1002,9 +1012,8 @@ struct ath_softc { spinlock_t chan_lock; #ifdef CPTCFG_MAC80211_LEDS @@ -21124,7 +19083,7 @@ index 3c5e9f5..c2d2781 100644 if (i == 0) { diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch -index e83c6bf..6edef09 100644 +index e83c6bf..4615643 100644 --- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch +++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch @@ -1,6 +1,6 @@ @@ -21167,7 +19126,7 @@ index e83c6bf..6edef09 100644 bool htc_reset_init; -@@ -1066,6 +1074,7 @@ void ath9k_hw_check_nav(struct ath_hw *a -+@@ -1067,6 +1075,7 @@ void ath9k_hw_check_nav(struct ath_hw *a ++@@ -1068,6 +1076,7 @@ void ath9k_hw_check_nav(struct ath_hw *a bool ath9k_hw_check_alive(struct ath_hw *ah); bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); @@ -21449,7 +19408,7 @@ index 0000000..5d84cf0 + } diff --git a/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch new file mode 100644 -index 0000000..1330dfe +index 0000000..de7c0ac --- /dev/null +++ b/package/kernel/mac80211/patches/548-ath9k_enable_gpio_chip.patch @@ -0,0 +1,234 @@ @@ -21473,7 +19432,7 @@ index 0000000..1330dfe + + #include "common.h" + #include "debug.h" -+@@ -973,6 +974,14 @@ struct ath_led { ++@@ -960,6 +961,14 @@ struct ath_led { + struct led_classdev cdev; + }; + @@ -21488,7 +19447,7 @@ index 0000000..1330dfe + struct ath_softc { + struct ieee80211_hw *hw; + struct device *dev; -+@@ -1027,6 +1036,9 @@ struct ath_softc { ++@@ -1014,6 +1023,9 @@ struct ath_softc { + #ifdef CPTCFG_MAC80211_LEDS + const char *led_default_trigger; + struct list_head leds; @@ -21689,7 +19648,7 @@ index 0000000..1330dfe + /*******************/ diff --git a/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch new file mode 100644 -index 0000000..f86b015 +index 0000000..b9d1883 --- /dev/null +++ b/package/kernel/mac80211/patches/549-ath9k_enable_gpio_buttons.patch @@ -0,0 +1,149 @@ @@ -21705,7 +19664,7 @@ index 0000000..f86b015 +--- +--- a/drivers/net/wireless/ath/ath9k/ath9k.h ++++ b/drivers/net/wireless/ath/ath9k/ath9k.h -+@@ -1038,6 +1038,7 @@ struct ath_softc { ++@@ -1025,6 +1025,7 @@ struct ath_softc { + struct list_head leds; + #ifdef CONFIG_GPIOLIB + struct ath9k_gpio_chip *gpiochip; diff --git a/patches/openwrt/0076-kernel-add-fix-for-CVE-2016-7117.patch b/patches/openwrt/0073-kernel-add-fix-for-CVE-2016-7117.patch similarity index 100% rename from patches/openwrt/0076-kernel-add-fix-for-CVE-2016-7117.patch rename to patches/openwrt/0073-kernel-add-fix-for-CVE-2016-7117.patch diff --git a/patches/openwrt/0073-mac80211-fix-packet-loss-on-fq-reordering.patch b/patches/openwrt/0073-mac80211-fix-packet-loss-on-fq-reordering.patch deleted file mode 100644 index 6328ba4ce..000000000 --- a/patches/openwrt/0073-mac80211-fix-packet-loss-on-fq-reordering.patch +++ /dev/null @@ -1,636 +0,0 @@ -From: Matthias Schiffer <mschiffer@universe-factory.net> -Date: Fri, 30 Sep 2016 16:57:44 +0200 -Subject: mac80211: fix packet loss on fq reordering - -Signed-off-by: Felix Fietkau <nbd@nbd.name> - -Backport of LEDE a194ffd4a89588bc75aeb9a27f59c36afd3d24bd - -diff --git a/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch b/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -new file mode 100644 -index 0000000..8ceed51 ---- /dev/null -+++ b/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -@@ -0,0 +1,478 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 4 Sep 2016 17:46:24 +0200 -+Subject: [PATCH] mac80211: fix sequence number assignment for PS response -+ frames -+ -+When using intermediate queues, sequence number allocation is deferred -+until dequeue. This doesn't work for PS response frames, which bypass -+those queues. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/net/mac80211/tx.c -++++ b/net/mac80211/tx.c -+@@ -38,6 +38,12 @@ -+ #include "wme.h" -+ #include "rate.h" -+ -++static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx); -++static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, -++ struct sta_info *sta, u8 pn_offs, -++ struct ieee80211_key_conf *key_conf, -++ struct sk_buff *skb); -++ -+ /* misc utils */ -+ -+ static inline void ieee80211_tx_stats(struct net_device *dev, u32 len) -+@@ -849,8 +855,7 @@ ieee80211_tx_h_sequence(struct ieee80211 -+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; -+ tx->sta->tx_stats.msdu[tid]++; -+ -+- if (!tx->sta->sta.txq[0]) -+- hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -++ hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -+ -+ return TX_CONTINUE; -+ } -+@@ -1398,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211 -+ fq_tin_init(&txqi->tin); -+ fq_flow_init(&txqi->def_flow); -+ codel_vars_init(&txqi->def_cvars); -++ __skb_queue_head_init(&txqi->frags); -+ -+ txqi->txq.vif = &sdata->vif; -+ -+@@ -1420,6 +1426,7 @@ void ieee80211_txq_purge(struct ieee8021 -+ struct fq_tin *tin = &txqi->tin; -+ -+ fq_tin_reset(fq, tin, fq_skb_free_func); -++ ieee80211_purge_tx_queue(&local->hw, &txqi->frags); -+ } -+ -+ int ieee80211_txq_setup_flows(struct ieee80211_local *local) -+@@ -1476,12 +1483,19 @@ struct sk_buff *ieee80211_tx_dequeue(str -+ struct sk_buff *skb = NULL; -+ struct fq *fq = &local->fq; -+ struct fq_tin *tin = &txqi->tin; -++ struct ieee80211_tx_info *info; -+ -+ spin_lock_bh(&fq->lock); -+ -+ if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) -+ goto out; -+ -++ /* Make sure fragments stay together. */ -++ skb = __skb_dequeue(&txqi->frags); -++ if (skb) -++ goto out; -++ -++begin: -+ skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); -+ if (!skb) -+ goto out; -+@@ -1489,16 +1503,38 @@ struct sk_buff *ieee80211_tx_dequeue(str -+ ieee80211_set_skb_vif(skb, txqi); -+ -+ hdr = (struct ieee80211_hdr *)skb->data; -+- if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) { -++ info = IEEE80211_SKB_CB(skb); -++ if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { -+ struct sta_info *sta = container_of(txq->sta, struct sta_info, -+ sta); -+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ u8 pn_offs = 0; -+ -+- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid); -+- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags)) -+- info->flags |= IEEE80211_TX_CTL_AMPDU; -+- else -+- info->flags &= ~IEEE80211_TX_CTL_AMPDU; -++ if (info->control.hw_key) -++ pn_offs = ieee80211_padded_hdrlen(hw, hdr->frame_control); -++ -++ ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, -++ info->control.hw_key, skb); -++ } else { -++ struct ieee80211_tx_data tx = { }; -++ -++ __skb_queue_head_init(&tx.skbs); -++ tx.local = local; -++ tx.skb = skb; -++ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control); -++ if (txq->sta) { -++ tx.sta = container_of(txq->sta, struct sta_info, sta); -++ tx.sdata = tx.sta->sdata; -++ } else { -++ tx.sdata = vif_to_sdata(info->control.vif); -++ } -++ -++ if (invoke_tx_handlers_late(&tx)) -++ goto begin; -++ -++ skb = __skb_dequeue(&tx.skbs); -++ -++ if (!skb_queue_empty(&tx.skbs)) -++ skb_queue_splice_tail(&tx.skbs, &txqi->frags); -+ } -+ -+ out: -+@@ -1512,6 +1548,47 @@ out: -+ } -+ EXPORT_SYMBOL(ieee80211_tx_dequeue); -+ -++static bool ieee80211_queue_skb(struct ieee80211_local *local, -++ struct ieee80211_sub_if_data *sdata, -++ struct sta_info *sta, -++ struct sk_buff *skb) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ struct fq *fq = &local->fq; -++ struct ieee80211_vif *vif; -++ struct txq_info *txqi; -++ struct ieee80211_sta *pubsta; -++ -++ if (!local->ops->wake_tx_queue || -++ sdata->vif.type == NL80211_IFTYPE_MONITOR) -++ return false; -++ -++ if (sta && sta->uploaded) -++ pubsta = &sta->sta; -++ else -++ pubsta = NULL; -++ -++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -++ sdata = container_of(sdata->bss, -++ struct ieee80211_sub_if_data, u.ap); -++ -++ vif = &sdata->vif; -++ txqi = ieee80211_get_txq(local, vif, pubsta, skb); -++ -++ if (!txqi) -++ return false; -++ -++ info->control.vif = vif; -++ -++ spin_lock_bh(&fq->lock); -++ ieee80211_txq_enqueue(local, txqi, skb); -++ spin_unlock_bh(&fq->lock); -++ -++ drv_wake_tx_queue(local, txqi); -++ -++ return true; -++} -++ -+ static bool ieee80211_tx_frags(struct ieee80211_local *local, -+ struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta, -+@@ -1519,9 +1596,7 @@ static bool ieee80211_tx_frags(struct ie -+ bool txpending) -+ { -+ struct ieee80211_tx_control control = {}; -+- struct fq *fq = &local->fq; -+ struct sk_buff *skb, *tmp; -+- struct txq_info *txqi; -+ unsigned long flags; -+ -+ skb_queue_walk_safe(skbs, skb, tmp) { -+@@ -1536,21 +1611,6 @@ static bool ieee80211_tx_frags(struct ie -+ } -+ #endif -+ -+- txqi = ieee80211_get_txq(local, vif, sta, skb); -+- if (txqi) { -+- info->control.vif = vif; -+- -+- __skb_unlink(skb, skbs); -+- -+- spin_lock_bh(&fq->lock); -+- ieee80211_txq_enqueue(local, txqi, skb); -+- spin_unlock_bh(&fq->lock); -+- -+- drv_wake_tx_queue(local, txqi); -+- -+- continue; -+- } -+- -+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags); -+ if (local->queue_stop_reasons[q] || -+ (!txpending && !skb_queue_empty(&local->pending[q]))) { -+@@ -1671,10 +1731,13 @@ static bool __ieee80211_tx(struct ieee80 -+ /* -+ * Invoke TX handlers, return 0 on success and non-zero if the -+ * frame was dropped or queued. -++ * -++ * The handlers are split into an early and late part. The latter is everything -++ * that can be sensitive to reordering, and will be deferred to after packets -++ * are dequeued from the intermediate queues (when they are enabled). -+ */ -+-static int invoke_tx_handlers(struct ieee80211_tx_data *tx) -++static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx) -+ { -+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); -+ ieee80211_tx_result res = TX_DROP; -+ -+ #define CALL_TXH(txh) \ -+@@ -1688,16 +1751,42 @@ static int invoke_tx_handlers(struct iee -+ CALL_TXH(ieee80211_tx_h_check_assoc); -+ CALL_TXH(ieee80211_tx_h_ps_buf); -+ CALL_TXH(ieee80211_tx_h_check_control_port_protocol); -+- CALL_TXH(ieee80211_tx_h_select_key); -++ -+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) -+ CALL_TXH(ieee80211_tx_h_rate_ctrl); -+ -++ txh_done: -++ if (unlikely(res == TX_DROP)) { -++ I802_DEBUG_INC(tx->local->tx_handlers_drop); -++ if (tx->skb) -++ ieee80211_free_txskb(&tx->local->hw, tx->skb); -++ else -++ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs); -++ return -1; -++ } else if (unlikely(res == TX_QUEUED)) { -++ I802_DEBUG_INC(tx->local->tx_handlers_queued); -++ return -1; -++ } -++ -++ return 0; -++} -++ -++/* -++ * Late handlers can be called while the sta lock is held. Handlers that can -++ * cause packets to be generated will cause deadlock! -++ */ -++static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); -++ ieee80211_tx_result res = TX_CONTINUE; -++ -+ if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) { -+ __skb_queue_tail(&tx->skbs, tx->skb); -+ tx->skb = NULL; -+ goto txh_done; -+ } -+ -++ CALL_TXH(ieee80211_tx_h_select_key); -+ CALL_TXH(ieee80211_tx_h_michael_mic_add); -+ CALL_TXH(ieee80211_tx_h_sequence); -+ CALL_TXH(ieee80211_tx_h_fragment); -+@@ -1724,6 +1813,15 @@ static int invoke_tx_handlers(struct iee -+ return 0; -+ } -+ -++static int invoke_tx_handlers(struct ieee80211_tx_data *tx) -++{ -++ int r = invoke_tx_handlers_early(tx); -++ if (r) -++ return r; -++ -++ return invoke_tx_handlers_late(tx); -++} -++ -+ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, struct sk_buff *skb, -+ int band, struct ieee80211_sta **sta) -+@@ -1798,7 +1896,13 @@ static bool ieee80211_tx(struct ieee8021 -+ info->hw_queue = -+ sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -+ -+- if (!invoke_tx_handlers(&tx)) -++ if (invoke_tx_handlers_early(&tx)) -++ return false; -++ -++ if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb)) -++ return true; -++ -++ if (!invoke_tx_handlers_late(&tx)) -+ result = __ieee80211_tx(local, &tx.skbs, led_len, -+ tx.sta, txpending); -+ -+@@ -3181,7 +3285,7 @@ out: -+ } -+ -+ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -+- struct net_device *dev, struct sta_info *sta, -++ struct sta_info *sta, -+ struct ieee80211_fast_tx *fast_tx, -+ struct sk_buff *skb) -+ { -+@@ -3192,9 +3296,9 @@ static bool ieee80211_xmit_fast(struct i -+ struct ethhdr eth; -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; -+- struct ieee80211_tx_data tx; -+- ieee80211_tx_result r; -+ struct tid_ampdu_tx *tid_tx = NULL; -++ ieee80211_tx_result r; -++ struct ieee80211_tx_data tx; -+ u8 tid = IEEE80211_NUM_TIDS; -+ -+ /* control port protocol needs a lot of special handling */ -+@@ -3232,8 +3336,6 @@ static bool ieee80211_xmit_fast(struct i -+ return true; -+ } -+ -+- ieee80211_tx_stats(dev, skb->len + extra_head); -+- -+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && -+ ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) -+ return true; -+@@ -3262,24 +3364,7 @@ static bool ieee80211_xmit_fast(struct i -+ info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | -+ IEEE80211_TX_CTL_DONTFRAG | -+ (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); -+- -+- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -+- *ieee80211_get_qos_ctl(hdr) = tid; -+- if (!sta->sta.txq[0]) -+- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); -+- } else { -+- info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; -+- hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); -+- sdata->sequence_number += 0x10; -+- } -+- -+- if (skb_shinfo(skb)->gso_size) -+- sta->tx_stats.msdu[tid] += -+- DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); -+- else -+- sta->tx_stats.msdu[tid]++; -+- -+- info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -++ info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; -+ -+ __skb_queue_head_init(&tx.skbs); -+ -+@@ -3305,22 +3390,71 @@ static bool ieee80211_xmit_fast(struct i -+ } -+ } -+ -++ if (ieee80211_queue_skb(local, sdata, sta, skb)) -++ return true; -++ -++ ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, -++ &fast_tx->key->conf, skb); -++ -++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -++ sdata = container_of(sdata->bss, -++ struct ieee80211_sub_if_data, u.ap); -++ -++ __skb_queue_tail(&tx.skbs, skb); -++ ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false); -++ -++ return true; -++} -++ -++/* -++ * Can be called while the sta lock is held. Anything that can cause packets to -++ * be generated will cause deadlock! -++ */ -++static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, -++ struct sta_info *sta, u8 pn_offs, -++ struct ieee80211_key_conf *key_conf, -++ struct sk_buff *skb) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ struct ieee80211_hdr *hdr = (void *)skb->data; -++ u8 tid = IEEE80211_NUM_TIDS; -++ -++ ieee80211_tx_stats(skb->dev, skb->len); -++ -++ if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -++ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -++ *ieee80211_get_qos_ctl(hdr) = tid; -++ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); -++ } else { -++ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; -++ hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); -++ sdata->sequence_number += 0x10; -++ } -++ -++ if (skb_shinfo(skb)->gso_size) -++ sta->tx_stats.msdu[tid] += -++ DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); -++ else -++ sta->tx_stats.msdu[tid]++; -++ -++ info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -++ -+ /* statistics normally done by ieee80211_tx_h_stats (but that -+ * has to consider fragmentation, so is more complex) -+ */ -+ sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; -+ sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; -+ -+- if (fast_tx->pn_offs) { -++ if (pn_offs) { -+ u64 pn; -+- u8 *crypto_hdr = skb->data + fast_tx->pn_offs; -++ u8 *crypto_hdr = skb->data + pn_offs; -+ -+- switch (fast_tx->key->conf.cipher) { -++ switch (key_conf->cipher) { -+ case WLAN_CIPHER_SUITE_CCMP: -+ case WLAN_CIPHER_SUITE_CCMP_256: -+ case WLAN_CIPHER_SUITE_GCMP: -+ case WLAN_CIPHER_SUITE_GCMP_256: -+- pn = atomic64_inc_return(&fast_tx->key->conf.tx_pn); -++ pn = atomic64_inc_return(&key_conf->tx_pn); -+ crypto_hdr[0] = pn; -+ crypto_hdr[1] = pn >> 8; -+ crypto_hdr[4] = pn >> 16; -+@@ -3331,12 +3465,6 @@ static bool ieee80211_xmit_fast(struct i -+ } -+ } -+ -+- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -+- sdata = container_of(sdata->bss, -+- struct ieee80211_sub_if_data, u.ap); -+- -+- __skb_queue_tail(&tx.skbs, skb); -+- ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false); -+ return true; -+ } -+ -+@@ -3364,7 +3492,7 @@ void __ieee80211_subif_start_xmit(struct -+ fast_tx = rcu_dereference(sta->fast_tx); -+ -+ if (fast_tx && -+- ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb)) -++ ieee80211_xmit_fast(sdata, sta, fast_tx, skb)) -+ goto out; -+ } -+ -+--- a/include/net/mac80211.h -++++ b/include/net/mac80211.h -+@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags { -+ * frame (PS-Poll or uAPSD). -+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information -+ * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame -++ * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path -+ * -+ * These flags are used in tx_info->control.flags. -+ */ -+@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags { -+ IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), -+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), -+ IEEE80211_TX_CTRL_AMSDU = BIT(3), -++ IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), -+ }; -+ -+ /* -+--- a/net/mac80211/ieee80211_i.h -++++ b/net/mac80211/ieee80211_i.h -+@@ -814,11 +814,13 @@ enum txq_info_flags { -+ * @def_flow: used as a fallback flow when a packet destined to @tin hashes to -+ * a fq_flow which is already owned by a different tin -+ * @def_cvars: codel vars for @def_flow -++ * @frags: used to keep fragments created after dequeue -+ */ -+ struct txq_info { -+ struct fq_tin tin; -+ struct fq_flow def_flow; -+ struct codel_vars def_cvars; -++ struct sk_buff_head frags; -+ unsigned long flags; -+ -+ /* keep last! */ -diff --git a/package/kernel/mac80211/patches/346-mac80211-fix-sequence-number-assignment-for-PS-respo.patch b/package/kernel/mac80211/patches/346-mac80211-fix-sequence-number-assignment-for-PS-respo.patch -deleted file mode 100644 -index a82d12f..0000000 ---- a/package/kernel/mac80211/patches/346-mac80211-fix-sequence-number-assignment-for-PS-respo.patch -+++ /dev/null -@@ -1,107 +0,0 @@ --From: Felix Fietkau <nbd@nbd.name> --Date: Sun, 4 Sep 2016 17:46:24 +0200 --Subject: [PATCH] mac80211: fix sequence number assignment for PS response -- frames -- --When using intermediate queues, sequence number allocation is deferred --until dequeue. This doesn't work for PS response frames, which bypass --those queues. -- --Signed-off-by: Felix Fietkau <nbd@nbd.name> ----- -- ----- a/net/mac80211/tx.c --+++ b/net/mac80211/tx.c --@@ -792,6 +792,36 @@ static __le16 ieee80211_tx_next_seq(stru -- return ret; -- } -- --+static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, --+ struct ieee80211_vif *vif, --+ struct ieee80211_sta *pubsta, --+ struct sk_buff *skb) --+{ --+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; --+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --+ struct ieee80211_txq *txq = NULL; --+ --+ if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) || --+ (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) --+ return NULL; --+ --+ if (!ieee80211_is_data(hdr->frame_control)) --+ return NULL; --+ --+ if (pubsta) { --+ u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; --+ --+ txq = pubsta->txq[tid]; --+ } else if (vif) { --+ txq = vif->txq; --+ } --+ --+ if (!txq) --+ return NULL; --+ --+ return to_txq_info(txq); --+} --+ -- static ieee80211_tx_result debug_noinline -- ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) -- { --@@ -849,7 +879,8 @@ ieee80211_tx_h_sequence(struct ieee80211 -- tid = *qc & IEEE80211_QOS_CTL_TID_MASK; -- tx->sta->tx_stats.msdu[tid]++; -- --- if (!tx->sta->sta.txq[0]) --+ if (!ieee80211_get_txq(tx->local, info->control.vif, &tx->sta->sta, --+ tx->skb)) -- hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -- -- return TX_CONTINUE; --@@ -1238,36 +1269,6 @@ ieee80211_tx_prepare(struct ieee80211_su -- return TX_CONTINUE; -- } -- ---static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local, --- struct ieee80211_vif *vif, --- struct ieee80211_sta *pubsta, --- struct sk_buff *skb) ---{ --- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; --- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --- struct ieee80211_txq *txq = NULL; --- --- if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) || --- (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE)) --- return NULL; --- --- if (!ieee80211_is_data(hdr->frame_control)) --- return NULL; --- --- if (pubsta) { --- u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK; --- --- txq = pubsta->txq[tid]; --- } else if (vif) { --- txq = vif->txq; --- } --- --- if (!txq) --- return NULL; --- --- return to_txq_info(txq); ---} --- -- static void ieee80211_set_skb_enqueue_time(struct sk_buff *skb) -- { -- IEEE80211_SKB_CB(skb)->control.enqueue_time = codel_get_time(); --@@ -3265,7 +3266,7 @@ static bool ieee80211_xmit_fast(struct i -- -- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -- *ieee80211_get_qos_ctl(hdr) = tid; --- if (!sta->sta.txq[0]) --+ if (!ieee80211_get_txq(local, &sdata->vif, &sta->sta, skb)) -- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); -- } else { -- info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; -diff --git a/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch -index c40598d..aba065e 100644 ---- a/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch -+++ b/package/kernel/mac80211/patches/522-mac80211_configure_antenna_gain.patch -@@ -18,7 +18,7 @@ - const u8 *addr); - --- a/include/net/mac80211.h - +++ b/include/net/mac80211.h --@@ -1317,6 +1317,7 @@ enum ieee80211_smps_mode { -+@@ -1319,6 +1319,7 @@ enum ieee80211_smps_mode { - * - * @power_level: requested transmit power (in dBm), backward compatibility - * value only that is set to the minimum of all interfaces -@@ -26,7 +26,7 @@ - * - * @chandef: the channel definition to tune to - * @radar_enabled: whether radar detection is enabled --@@ -1337,6 +1338,7 @@ enum ieee80211_smps_mode { -+@@ -1339,6 +1340,7 @@ enum ieee80211_smps_mode { - struct ieee80211_conf { - u32 flags; - int power_level, dynamic_ps_timeout; -@@ -87,7 +87,7 @@ - CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) - --- a/net/mac80211/ieee80211_i.h - +++ b/net/mac80211/ieee80211_i.h --@@ -1338,6 +1338,7 @@ struct ieee80211_local { -+@@ -1340,6 +1340,7 @@ struct ieee80211_local { - int dynamic_ps_forced_timeout; - - int user_power_level; /* in dBm, for all interfaces */ diff --git a/patches/openwrt/0074-ath9k-revert-temperature-compensation-support-patch-FS-111.patch b/patches/openwrt/0074-ath9k-revert-temperature-compensation-support-patch-FS-111.patch new file mode 100644 index 000000000..803db695c --- /dev/null +++ b/patches/openwrt/0074-ath9k-revert-temperature-compensation-support-patch-FS-111.patch @@ -0,0 +1,124 @@ +From: Matthias Schiffer <mschiffer@universe-factory.net> +Date: Tue, 11 Oct 2016 02:54:27 +0200 +Subject: ath9k: revert temperature compensation support patch (FS#111) + +Signed-off-by: Felix Fietkau <nbd@nbd.name> + +Backport of LEDE 3e4d0e3e77dcf9b2116e5ed53f30e2bf53b1c6b7 + +diff --git a/package/kernel/mac80211/patches/328-ath9k_hw-implement-temperature-compensation-support-.patch b/package/kernel/mac80211/patches/328-ath9k_hw-implement-temperature-compensation-support-.patch +deleted file mode 100644 +index cff32ad..0000000 +--- a/package/kernel/mac80211/patches/328-ath9k_hw-implement-temperature-compensation-support-.patch ++++ /dev/null +@@ -1,97 +0,0 @@ +-From: Felix Fietkau <nbd@nbd.name> +-Date: Mon, 11 Jul 2016 11:35:55 +0200 +-Subject: [PATCH] ath9k_hw: implement temperature compensation support for +- AR9003+ +- +-Signed-off-by: Felix Fietkau <nbd@nbd.name> +---- +- +---- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +-+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c +-@@ -33,6 +33,7 @@ struct coeff { +- +- enum ar9003_cal_types { +- IQ_MISMATCH_CAL = BIT(0), +-+ TEMP_COMP_CAL = BIT(1), +- }; +- +- static void ar9003_hw_setup_calibration(struct ath_hw *ah, +-@@ -58,6 +59,12 @@ static void ar9003_hw_setup_calibration( +- /* Kick-off cal */ +- REG_SET_BIT(ah, AR_PHY_TIMING4, AR_PHY_TIMING4_DO_CAL); +- break; +-+ case TEMP_COMP_CAL: +-+ ath_dbg(common, CALIBRATE, +-+ "starting Temperature Compensation Calibration\n"); +-+ REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_LOCAL); +-+ REG_SET_BIT(ah, AR_CH0_THERM, AR_CH0_THERM_START); +-+ break; +- default: +- ath_err(common, "Invalid calibration type\n"); +- break; +-@@ -86,7 +93,8 @@ static bool ar9003_hw_per_calibration(st +- /* +- * Accumulate cal measures for active chains +- */ +-- cur_caldata->calCollect(ah); +-+ if (cur_caldata->calCollect) +-+ cur_caldata->calCollect(ah); +- ah->cal_samples++; +- +- if (ah->cal_samples >= cur_caldata->calNumSamples) { +-@@ -99,7 +107,8 @@ static bool ar9003_hw_per_calibration(st +- /* +- * Process accumulated data +- */ +-- cur_caldata->calPostProc(ah, numChains); +-+ if (cur_caldata->calPostProc) +-+ cur_caldata->calPostProc(ah, numChains); +- +- /* Calibration has finished. */ +- caldata->CalValid |= cur_caldata->calType; +-@@ -314,9 +323,16 @@ static const struct ath9k_percal_data iq +- ar9003_hw_iqcalibrate +- }; +- +-+static const struct ath9k_percal_data temp_cal_single_sample = { +-+ TEMP_COMP_CAL, +-+ MIN_CAL_SAMPLES, +-+ PER_MAX_LOG_COUNT, +-+}; +-+ +- static void ar9003_hw_init_cal_settings(struct ath_hw *ah) +- { +- ah->iq_caldata.calData = &iq_cal_single_sample; +-+ ah->temp_caldata.calData = &temp_cal_single_sample; +- +- if (AR_SREV_9300_20_OR_LATER(ah)) { +- ah->enabled_cals |= TX_IQ_CAL; +-@@ -324,7 +340,7 @@ static void ar9003_hw_init_cal_settings( +- ah->enabled_cals |= TX_IQ_ON_AGC_CAL; +- } +- +-- ah->supp_cals = IQ_MISMATCH_CAL; +-+ ah->supp_cals = IQ_MISMATCH_CAL | TEMP_COMP_CAL; +- } +- +- #define OFF_UPPER_LT 24 +-@@ -1383,6 +1399,9 @@ static void ar9003_hw_init_cal_common(st +- INIT_CAL(&ah->iq_caldata); +- INSERT_CAL(ah, &ah->iq_caldata); +- +-+ INIT_CAL(&ah->temp_caldata); +-+ INSERT_CAL(ah, &ah->temp_caldata); +-+ +- /* Initialize current pointer to first element in list */ +- ah->cal_list_curr = ah->cal_list; +- +---- a/drivers/net/wireless/ath/ath9k/hw.h +-+++ b/drivers/net/wireless/ath/ath9k/hw.h +-@@ -830,6 +830,7 @@ struct ath_hw { +- /* Calibration */ +- u32 supp_cals; +- struct ath9k_cal_list iq_caldata; +-+ struct ath9k_cal_list temp_caldata; +- struct ath9k_cal_list adcgain_caldata; +- struct ath9k_cal_list adcdc_caldata; +- struct ath9k_cal_list *cal_list; +diff --git a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch +index 4615643..6edef09 100644 +--- a/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch ++++ b/package/kernel/mac80211/patches/542-ath9k_debugfs_diag.patch +@@ -84,7 +84,7 @@ + bool reset_power_on; + bool htc_reset_init; + +-@@ -1068,6 +1076,7 @@ void ath9k_hw_check_nav(struct ath_hw *a ++@@ -1067,6 +1075,7 @@ void ath9k_hw_check_nav(struct ath_hw *a + bool ath9k_hw_check_alive(struct ath_hw *ah); + + bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); diff --git a/patches/openwrt/0074-mac80211-fix-tx-issue-with-CCMP-PN-generated-in-hardware.patch b/patches/openwrt/0074-mac80211-fix-tx-issue-with-CCMP-PN-generated-in-hardware.patch deleted file mode 100644 index f464421c7..000000000 --- a/patches/openwrt/0074-mac80211-fix-tx-issue-with-CCMP-PN-generated-in-hardware.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Matthias Schiffer <mschiffer@universe-factory.net> -Date: Fri, 30 Sep 2016 16:57:57 +0200 -Subject: mac80211: fix tx issue with CCMP PN generated in hardware - -Signed-off-by: Felix Fietkau <nbd@nbd.name> - -Backport of LEDE f3747020e202883a43729fc245986f9e36289d6c - -diff --git a/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch b/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -index 8ceed51..aba1ff4 100644 ---- a/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -+++ b/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -@@ -404,7 +404,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name> - sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; - - - if (fast_tx->pn_offs) { --+ if (pn_offs) { -++ if (pn_offs && (key_conf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { - u64 pn; - - u8 *crypto_hdr = skb->data + fast_tx->pn_offs; - + u8 *crypto_hdr = skb->data + pn_offs; diff --git a/patches/openwrt/0075-ath9k-remove-patch-causing-stability-issues-with-powersave-devices-FS-176.patch b/patches/openwrt/0075-ath9k-remove-patch-causing-stability-issues-with-powersave-devices-FS-176.patch deleted file mode 100644 index ddfb64459..000000000 --- a/patches/openwrt/0075-ath9k-remove-patch-causing-stability-issues-with-powersave-devices-FS-176.patch +++ /dev/null @@ -1,1513 +0,0 @@ -From: Matthias Schiffer <mschiffer@universe-factory.net> -Date: Fri, 30 Sep 2016 16:58:01 +0200 -Subject: ath9k: remove patch causing stability issues with powersave devices (FS#176) - -Signed-off-by: Felix Fietkau <nbd@nbd.name> - -Backport of LEDE fc88eb3fdfce6d39b4c62158cf6f42605a360a1e - -diff --git a/package/kernel/mac80211/patches/341-ath9k-release-PS-buffered-frames-as-A-MPDU-if-enable.patch b/package/kernel/mac80211/patches/341-ath9k-release-PS-buffered-frames-as-A-MPDU-if-enable.patch -deleted file mode 100644 -index 1cc1667..0000000 ---- a/package/kernel/mac80211/patches/341-ath9k-release-PS-buffered-frames-as-A-MPDU-if-enable.patch -+++ /dev/null -@@ -1,40 +0,0 @@ --From: Felix Fietkau <nbd@nbd.name> --Date: Sun, 28 Aug 2016 13:15:10 +0200 --Subject: [PATCH] ath9k: release PS buffered frames as A-MPDU if enabled -- --Signed-off-by: Felix Fietkau <nbd@nbd.name> ----- -- ----- a/drivers/net/wireless/ath/ath9k/xmit.c --+++ b/drivers/net/wireless/ath/ath9k/xmit.c --@@ -1660,10 +1660,11 @@ void ath9k_release_buffered_frames(struc -- struct ath_node *an = (struct ath_node *)sta->drv_priv; -- struct ath_txq *txq = sc->tx.uapsdq; -- struct ieee80211_tx_info *info; --+ struct ath_frame_info *fi; -- struct list_head bf_q; -- struct ath_buf *bf_tail = NULL, *bf; -- int sent = 0; --- int i; --+ int n, i; -- -- INIT_LIST_HEAD(&bf_q); -- for (i = 0; tids && nframes; i++, tids >>= 1) { --@@ -1683,10 +1684,15 @@ void ath9k_release_buffered_frames(struc -- ath9k_set_moredata(sc, bf, true); -- list_add_tail(&bf->list, &bf_q); -- ath_set_rates(tid->an->vif, tid->an->sta, bf, true); --- if (bf_isampdu(bf)) { --+ if (bf_isampdu(bf)) -- ath_tx_addto_baw(sc, tid, bf); --- bf->bf_state.bf_type &= ~BUF_AGGR; --+ if (bf_isaggr(bf)) { --+ fi = get_frame_info(bf->bf_mpdu); --+ n = ath_compute_num_delims(sc, tid, bf, --+ fi->framelen, true); --+ bf->bf_state.ndelim = n; -- } --+ -- if (bf_tail) -- bf_tail->bf_next = bf; -- -diff --git a/package/kernel/mac80211/patches/341-ath9k-report-tx-status-on-EOSP.patch b/package/kernel/mac80211/patches/341-ath9k-report-tx-status-on-EOSP.patch -new file mode 100644 -index 0000000..80a3074 ---- /dev/null -+++ b/package/kernel/mac80211/patches/341-ath9k-report-tx-status-on-EOSP.patch -@@ -0,0 +1,19 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 28 Aug 2016 13:23:27 +0200 -+Subject: [PATCH] ath9k: report tx status on EOSP -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee802 -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ struct ieee80211_sta *sta = info->status.status_driver_data[0]; -+ -+- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { -++ if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | -++ IEEE80211_TX_STATUS_EOSP)) { -+ ieee80211_tx_status(hw, skb); -+ return; -+ } -diff --git a/package/kernel/mac80211/patches/342-ath9k-fix-block-ack-window-tracking-issues.patch b/package/kernel/mac80211/patches/342-ath9k-fix-block-ack-window-tracking-issues.patch -new file mode 100644 -index 0000000..fea147b ---- /dev/null -+++ b/package/kernel/mac80211/patches/342-ath9k-fix-block-ack-window-tracking-issues.patch -@@ -0,0 +1,114 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Tue, 30 Aug 2016 12:44:08 +0200 -+Subject: [PATCH] ath9k: fix block-ack window tracking issues -+ -+Ensure that a buffer gets tracked as part of the block-ack window as -+soon as it's dequeued from the tid for the first time. Ensure that -+double calls to ath_tx_addto_baw (e.g. on retransmission) don't cause -+any issues. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/drivers/net/wireless/ath/ath9k/xmit.c -++++ b/drivers/net/wireless/ath/ath9k/xmit.c -+@@ -62,7 +62,7 @@ static void ath_tx_rc_status(struct ath_ -+ struct ath_tx_status *ts, int nframes, int nbad, -+ int txok); -+ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, -+- int seqno); -++ struct ath_buf *bf); -+ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, -+ struct ath_txq *txq, -+ struct ath_atx_tid *tid, -+@@ -300,7 +300,7 @@ static void ath_tx_flush_tid(struct ath_ -+ } -+ -+ if (fi->baw_tracked) { -+- ath_tx_update_baw(sc, tid, bf->bf_state.seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ sendbar = true; -+ } -+ -+@@ -316,10 +316,15 @@ static void ath_tx_flush_tid(struct ath_ -+ } -+ -+ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, -+- int seqno) -++ struct ath_buf *bf) -+ { -++ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); -++ u16 seqno = bf->bf_state.seqno; -+ int index, cindex; -+ -++ if (!fi->baw_tracked) -++ return; -++ -+ index = ATH_BA_INDEX(tid->seq_start, seqno); -+ cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -+ -+@@ -340,6 +345,9 @@ static void ath_tx_addto_baw(struct ath_ -+ u16 seqno = bf->bf_state.seqno; -+ int index, cindex; -+ -++ if (fi->baw_tracked) -++ return; -++ -+ index = ATH_BA_INDEX(tid->seq_start, seqno); -+ cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -+ __set_bit(cindex, tid->tx_buf); -+@@ -616,7 +624,7 @@ static void ath_tx_complete_aggr(struct -+ * complete the acked-ones/xretried ones; update -+ * block-ack window -+ */ -+- ath_tx_update_baw(sc, tid, seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ -+ if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { -+ memcpy(tx_info->control.rates, rates, sizeof(rates)); -+@@ -646,7 +654,7 @@ static void ath_tx_complete_aggr(struct -+ * run out of tx buf. -+ */ -+ if (!tbf) { -+- ath_tx_update_baw(sc, tid, seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ -+ ath_tx_complete_buf(sc, bf, txq, -+ &bf_head, NULL, ts, -+@@ -986,11 +994,14 @@ ath_tx_get_tid_subframe(struct ath_softc -+ -+ INIT_LIST_HEAD(&bf_head); -+ list_add(&bf->list, &bf_head); -+- ath_tx_update_baw(sc, tid, seqno); -++ ath_tx_update_baw(sc, tid, bf); -+ ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); -+ continue; -+ } -+ -++ if (bf_isampdu(bf)) -++ ath_tx_addto_baw(sc, tid, bf); -++ -+ return bf; -+ } -+ -+@@ -1048,8 +1059,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s -+ bf->bf_next = NULL; -+ -+ /* link buffers of this frame to the aggregate */ -+- if (!fi->baw_tracked) -+- ath_tx_addto_baw(sc, tid, bf); -+ bf->bf_state.ndelim = ndelim; -+ -+ list_add_tail(&bf->list, bf_q); -+@@ -1684,10 +1693,8 @@ void ath9k_release_buffered_frames(struc -+ ath9k_set_moredata(sc, bf, true); -+ list_add_tail(&bf->list, &bf_q); -+ ath_set_rates(tid->an->vif, tid->an->sta, bf, true); -+- if (bf_isampdu(bf)) { -+- ath_tx_addto_baw(sc, tid, bf); -++ if (bf_isampdu(bf)) -+ bf->bf_state.bf_type &= ~BUF_AGGR; -+- } -+ if (bf_tail) -+ bf_tail->bf_next = bf; -+ -diff --git a/package/kernel/mac80211/patches/342-ath9k-report-tx-status-on-EOSP.patch b/package/kernel/mac80211/patches/342-ath9k-report-tx-status-on-EOSP.patch -deleted file mode 100644 -index 80a3074..0000000 ---- a/package/kernel/mac80211/patches/342-ath9k-report-tx-status-on-EOSP.patch -+++ /dev/null -@@ -1,19 +0,0 @@ --From: Felix Fietkau <nbd@nbd.name> --Date: Sun, 28 Aug 2016 13:23:27 +0200 --Subject: [PATCH] ath9k: report tx status on EOSP -- --Signed-off-by: Felix Fietkau <nbd@nbd.name> ----- -- ----- a/drivers/net/wireless/ath/ath9k/xmit.c --+++ b/drivers/net/wireless/ath/ath9k/xmit.c --@@ -86,7 +86,8 @@ static void ath_tx_status(struct ieee802 -- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -- struct ieee80211_sta *sta = info->status.status_driver_data[0]; -- --- if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS) { --+ if (info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS | --+ IEEE80211_TX_STATUS_EOSP)) { -- ieee80211_tx_status(hw, skb); -- return; -- } -diff --git a/package/kernel/mac80211/patches/343-ath9k-fix-block-ack-window-tracking-issues.patch b/package/kernel/mac80211/patches/343-ath9k-fix-block-ack-window-tracking-issues.patch -deleted file mode 100644 -index 007a8d7d..0000000 ---- a/package/kernel/mac80211/patches/343-ath9k-fix-block-ack-window-tracking-issues.patch -+++ /dev/null -@@ -1,111 +0,0 @@ --From: Felix Fietkau <nbd@nbd.name> --Date: Tue, 30 Aug 2016 12:44:08 +0200 --Subject: [PATCH] ath9k: fix block-ack window tracking issues -- --Ensure that a buffer gets tracked as part of the block-ack window as --soon as it's dequeued from the tid for the first time. Ensure that --double calls to ath_tx_addto_baw (e.g. on retransmission) don't cause --any issues. -- --Signed-off-by: Felix Fietkau <nbd@nbd.name> ----- -- ----- a/drivers/net/wireless/ath/ath9k/xmit.c --+++ b/drivers/net/wireless/ath/ath9k/xmit.c --@@ -62,7 +62,7 @@ static void ath_tx_rc_status(struct ath_ -- struct ath_tx_status *ts, int nframes, int nbad, -- int txok); -- static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, --- int seqno); --+ struct ath_buf *bf); -- static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc, -- struct ath_txq *txq, -- struct ath_atx_tid *tid, --@@ -300,7 +300,7 @@ static void ath_tx_flush_tid(struct ath_ -- } -- -- if (fi->baw_tracked) { --- ath_tx_update_baw(sc, tid, bf->bf_state.seqno); --+ ath_tx_update_baw(sc, tid, bf); -- sendbar = true; -- } -- --@@ -316,10 +316,15 @@ static void ath_tx_flush_tid(struct ath_ -- } -- -- static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, --- int seqno) --+ struct ath_buf *bf) -- { --+ struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); --+ u16 seqno = bf->bf_state.seqno; -- int index, cindex; -- --+ if (!fi->baw_tracked) --+ return; --+ -- index = ATH_BA_INDEX(tid->seq_start, seqno); -- cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -- --@@ -340,6 +345,9 @@ static void ath_tx_addto_baw(struct ath_ -- u16 seqno = bf->bf_state.seqno; -- int index, cindex; -- --+ if (fi->baw_tracked) --+ return; --+ -- index = ATH_BA_INDEX(tid->seq_start, seqno); -- cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); -- __set_bit(cindex, tid->tx_buf); --@@ -616,7 +624,7 @@ static void ath_tx_complete_aggr(struct -- * complete the acked-ones/xretried ones; update -- * block-ack window -- */ --- ath_tx_update_baw(sc, tid, seqno); --+ ath_tx_update_baw(sc, tid, bf); -- -- if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { -- memcpy(tx_info->control.rates, rates, sizeof(rates)); --@@ -646,7 +654,7 @@ static void ath_tx_complete_aggr(struct -- * run out of tx buf. -- */ -- if (!tbf) { --- ath_tx_update_baw(sc, tid, seqno); --+ ath_tx_update_baw(sc, tid, bf); -- -- ath_tx_complete_buf(sc, bf, txq, -- &bf_head, NULL, ts, --@@ -986,11 +994,14 @@ ath_tx_get_tid_subframe(struct ath_softc -- -- INIT_LIST_HEAD(&bf_head); -- list_add(&bf->list, &bf_head); --- ath_tx_update_baw(sc, tid, seqno); --+ ath_tx_update_baw(sc, tid, bf); -- ath_tx_complete_buf(sc, bf, txq, &bf_head, NULL, &ts, 0); -- continue; -- } -- --+ if (bf_isampdu(bf)) --+ ath_tx_addto_baw(sc, tid, bf); --+ -- return bf; -- } -- --@@ -1048,8 +1059,6 @@ ath_tx_form_aggr(struct ath_softc *sc, s -- bf->bf_next = NULL; -- -- /* link buffers of this frame to the aggregate */ --- if (!fi->baw_tracked) --- ath_tx_addto_baw(sc, tid, bf); -- bf->bf_state.ndelim = ndelim; -- -- list_add_tail(&bf->list, bf_q); --@@ -1685,8 +1694,6 @@ void ath9k_release_buffered_frames(struc -- ath9k_set_moredata(sc, bf, true); -- list_add_tail(&bf->list, &bf_q); -- ath_set_rates(tid->an->vif, tid->an->sta, bf, true); --- if (bf_isampdu(bf)) --- ath_tx_addto_baw(sc, tid, bf); -- if (bf_isaggr(bf)) { -- fi = get_frame_info(bf->bf_mpdu); -- n = ath_compute_num_delims(sc, tid, bf, -diff --git a/package/kernel/mac80211/patches/343-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch b/package/kernel/mac80211/patches/343-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch -new file mode 100644 -index 0000000..3bbca22 ---- /dev/null -+++ b/package/kernel/mac80211/patches/343-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch -@@ -0,0 +1,64 @@ -+From: Johannes Berg <johannes.berg@intel.com> -+Date: Mon, 29 Aug 2016 23:25:18 +0300 -+Subject: [PATCH] mac80211: send delBA on unexpected BlockAck data frames -+ -+When we receive data frames with ACK policy BlockAck, send -+delBA as requested by the 802.11 spec. Since this would be -+happening for every frame inside an A-MPDU if it's really -+received outside a session, limit it to a single attempt. -+ -+Signed-off-by: Johannes Berg <johannes.berg@intel.com> -+--- -+ -+--- a/net/mac80211/agg-rx.c -++++ b/net/mac80211/agg-rx.c -+@@ -388,8 +388,10 @@ void __ieee80211_start_rx_ba_session(str -+ } -+ -+ end: -+- if (status == WLAN_STATUS_SUCCESS) -++ if (status == WLAN_STATUS_SUCCESS) { -+ __set_bit(tid, sta->ampdu_mlme.agg_session_valid); -++ __clear_bit(tid, sta->ampdu_mlme.unexpected_agg); -++ } -+ mutex_unlock(&sta->ampdu_mlme.mtx); -+ -+ end_no_lock: -+--- a/net/mac80211/rx.c -++++ b/net/mac80211/rx.c -+@@ -1072,8 +1072,15 @@ static void ieee80211_rx_reorder_ampdu(s -+ tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; -+ -+ tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); -+- if (!tid_agg_rx) -++ if (!tid_agg_rx) { -++ if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && -++ !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && -++ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) -++ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, -++ WLAN_BACK_RECIPIENT, -++ WLAN_REASON_QSTA_REQUIRE_SETUP); -+ goto dont_reorder; -++ } -+ -+ /* qos null data frames are excluded */ -+ if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) -+--- a/net/mac80211/sta_info.h -++++ b/net/mac80211/sta_info.h -+@@ -230,6 +230,8 @@ struct tid_ampdu_rx { -+ * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the -+ * driver requested to close until the work for it runs -+ * @agg_session_valid: bitmap indicating which TID has a rx BA session open on -++ * @unexpected_agg: bitmap indicating which TID already sent a delBA due to -++ * unexpected aggregation related frames outside a session -+ * @work: work struct for starting/stopping aggregation -+ * @tid_tx: aggregation info for Tx per TID -+ * @tid_start_tx: sessions where start was requested -+@@ -244,6 +246,7 @@ struct sta_ampdu_mlme { -+ unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -+ unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -+ unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -++ unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -+ /* tx */ -+ struct work_struct work; -+ struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; -diff --git a/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch b/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch -new file mode 100644 -index 0000000..c3d3118 ---- /dev/null -+++ b/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch -@@ -0,0 +1,26 @@ -+From: Johannes Berg <johannes.berg@intel.com> -+Date: Mon, 29 Aug 2016 23:25:19 +0300 -+Subject: [PATCH] mac80211: send delBA on unexpected BlockAck Request -+ -+If we don't have a BA session, send delBA, as requested by the -+IEEE 802.11 spec. Apply the same limit of sending such a delBA -+only once as in the previous patch. -+ -+Signed-off-by: Johannes Berg <johannes.berg@intel.com> -+--- -+ -+--- a/net/mac80211/rx.c -++++ b/net/mac80211/rx.c -+@@ -2537,6 +2537,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_ -+ -+ tid = le16_to_cpu(bar_data.control) >> 12; -+ -++ if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && -++ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) -++ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, -++ WLAN_BACK_RECIPIENT, -++ WLAN_REASON_QSTA_REQUIRE_SETUP); -++ -+ tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); -+ if (!tid_agg_rx) -+ return RX_DROP_MONITOR; -diff --git a/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch b/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch -deleted file mode 100644 -index 3bbca22..0000000 ---- a/package/kernel/mac80211/patches/344-mac80211-send-delBA-on-unexpected-BlockAck-data-fram.patch -+++ /dev/null -@@ -1,64 +0,0 @@ --From: Johannes Berg <johannes.berg@intel.com> --Date: Mon, 29 Aug 2016 23:25:18 +0300 --Subject: [PATCH] mac80211: send delBA on unexpected BlockAck data frames -- --When we receive data frames with ACK policy BlockAck, send --delBA as requested by the 802.11 spec. Since this would be --happening for every frame inside an A-MPDU if it's really --received outside a session, limit it to a single attempt. -- --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/mac80211/agg-rx.c --+++ b/net/mac80211/agg-rx.c --@@ -388,8 +388,10 @@ void __ieee80211_start_rx_ba_session(str -- } -- -- end: --- if (status == WLAN_STATUS_SUCCESS) --+ if (status == WLAN_STATUS_SUCCESS) { -- __set_bit(tid, sta->ampdu_mlme.agg_session_valid); --+ __clear_bit(tid, sta->ampdu_mlme.unexpected_agg); --+ } -- mutex_unlock(&sta->ampdu_mlme.mtx); -- -- end_no_lock: ----- a/net/mac80211/rx.c --+++ b/net/mac80211/rx.c --@@ -1072,8 +1072,15 @@ static void ieee80211_rx_reorder_ampdu(s -- tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK; -- -- tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]); --- if (!tid_agg_rx) --+ if (!tid_agg_rx) { --+ if (ack_policy == IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK && --+ !test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && --+ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) --+ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, --+ WLAN_BACK_RECIPIENT, --+ WLAN_REASON_QSTA_REQUIRE_SETUP); -- goto dont_reorder; --+ } -- -- /* qos null data frames are excluded */ -- if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC))) ----- a/net/mac80211/sta_info.h --+++ b/net/mac80211/sta_info.h --@@ -230,6 +230,8 @@ struct tid_ampdu_rx { -- * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the -- * driver requested to close until the work for it runs -- * @agg_session_valid: bitmap indicating which TID has a rx BA session open on --+ * @unexpected_agg: bitmap indicating which TID already sent a delBA due to --+ * unexpected aggregation related frames outside a session -- * @work: work struct for starting/stopping aggregation -- * @tid_tx: aggregation info for Tx per TID -- * @tid_start_tx: sessions where start was requested --@@ -244,6 +246,7 @@ struct sta_ampdu_mlme { -- unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -- unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -- unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; --+ unsigned long unexpected_agg[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; -- /* tx */ -- struct work_struct work; -- struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; -diff --git a/package/kernel/mac80211/patches/345-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch b/package/kernel/mac80211/patches/345-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -new file mode 100644 -index 0000000..aba1ff4 ---- /dev/null -+++ b/package/kernel/mac80211/patches/345-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -@@ -0,0 +1,478 @@ -+From: Felix Fietkau <nbd@nbd.name> -+Date: Sun, 4 Sep 2016 17:46:24 +0200 -+Subject: [PATCH] mac80211: fix sequence number assignment for PS response -+ frames -+ -+When using intermediate queues, sequence number allocation is deferred -+until dequeue. This doesn't work for PS response frames, which bypass -+those queues. -+ -+Signed-off-by: Felix Fietkau <nbd@nbd.name> -+--- -+ -+--- a/net/mac80211/tx.c -++++ b/net/mac80211/tx.c -+@@ -38,6 +38,12 @@ -+ #include "wme.h" -+ #include "rate.h" -+ -++static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx); -++static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, -++ struct sta_info *sta, u8 pn_offs, -++ struct ieee80211_key_conf *key_conf, -++ struct sk_buff *skb); -++ -+ /* misc utils */ -+ -+ static inline void ieee80211_tx_stats(struct net_device *dev, u32 len) -+@@ -849,8 +855,7 @@ ieee80211_tx_h_sequence(struct ieee80211 -+ tid = *qc & IEEE80211_QOS_CTL_TID_MASK; -+ tx->sta->tx_stats.msdu[tid]++; -+ -+- if (!tx->sta->sta.txq[0]) -+- hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -++ hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -+ -+ return TX_CONTINUE; -+ } -+@@ -1398,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211 -+ fq_tin_init(&txqi->tin); -+ fq_flow_init(&txqi->def_flow); -+ codel_vars_init(&txqi->def_cvars); -++ __skb_queue_head_init(&txqi->frags); -+ -+ txqi->txq.vif = &sdata->vif; -+ -+@@ -1420,6 +1426,7 @@ void ieee80211_txq_purge(struct ieee8021 -+ struct fq_tin *tin = &txqi->tin; -+ -+ fq_tin_reset(fq, tin, fq_skb_free_func); -++ ieee80211_purge_tx_queue(&local->hw, &txqi->frags); -+ } -+ -+ int ieee80211_txq_setup_flows(struct ieee80211_local *local) -+@@ -1476,12 +1483,19 @@ struct sk_buff *ieee80211_tx_dequeue(str -+ struct sk_buff *skb = NULL; -+ struct fq *fq = &local->fq; -+ struct fq_tin *tin = &txqi->tin; -++ struct ieee80211_tx_info *info; -+ -+ spin_lock_bh(&fq->lock); -+ -+ if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) -+ goto out; -+ -++ /* Make sure fragments stay together. */ -++ skb = __skb_dequeue(&txqi->frags); -++ if (skb) -++ goto out; -++ -++begin: -+ skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); -+ if (!skb) -+ goto out; -+@@ -1489,16 +1503,38 @@ struct sk_buff *ieee80211_tx_dequeue(str -+ ieee80211_set_skb_vif(skb, txqi); -+ -+ hdr = (struct ieee80211_hdr *)skb->data; -+- if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) { -++ info = IEEE80211_SKB_CB(skb); -++ if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { -+ struct sta_info *sta = container_of(txq->sta, struct sta_info, -+ sta); -+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ u8 pn_offs = 0; -+ -+- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid); -+- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags)) -+- info->flags |= IEEE80211_TX_CTL_AMPDU; -+- else -+- info->flags &= ~IEEE80211_TX_CTL_AMPDU; -++ if (info->control.hw_key) -++ pn_offs = ieee80211_padded_hdrlen(hw, hdr->frame_control); -++ -++ ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, -++ info->control.hw_key, skb); -++ } else { -++ struct ieee80211_tx_data tx = { }; -++ -++ __skb_queue_head_init(&tx.skbs); -++ tx.local = local; -++ tx.skb = skb; -++ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control); -++ if (txq->sta) { -++ tx.sta = container_of(txq->sta, struct sta_info, sta); -++ tx.sdata = tx.sta->sdata; -++ } else { -++ tx.sdata = vif_to_sdata(info->control.vif); -++ } -++ -++ if (invoke_tx_handlers_late(&tx)) -++ goto begin; -++ -++ skb = __skb_dequeue(&tx.skbs); -++ -++ if (!skb_queue_empty(&tx.skbs)) -++ skb_queue_splice_tail(&tx.skbs, &txqi->frags); -+ } -+ -+ out: -+@@ -1512,6 +1548,47 @@ out: -+ } -+ EXPORT_SYMBOL(ieee80211_tx_dequeue); -+ -++static bool ieee80211_queue_skb(struct ieee80211_local *local, -++ struct ieee80211_sub_if_data *sdata, -++ struct sta_info *sta, -++ struct sk_buff *skb) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ struct fq *fq = &local->fq; -++ struct ieee80211_vif *vif; -++ struct txq_info *txqi; -++ struct ieee80211_sta *pubsta; -++ -++ if (!local->ops->wake_tx_queue || -++ sdata->vif.type == NL80211_IFTYPE_MONITOR) -++ return false; -++ -++ if (sta && sta->uploaded) -++ pubsta = &sta->sta; -++ else -++ pubsta = NULL; -++ -++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -++ sdata = container_of(sdata->bss, -++ struct ieee80211_sub_if_data, u.ap); -++ -++ vif = &sdata->vif; -++ txqi = ieee80211_get_txq(local, vif, pubsta, skb); -++ -++ if (!txqi) -++ return false; -++ -++ info->control.vif = vif; -++ -++ spin_lock_bh(&fq->lock); -++ ieee80211_txq_enqueue(local, txqi, skb); -++ spin_unlock_bh(&fq->lock); -++ -++ drv_wake_tx_queue(local, txqi); -++ -++ return true; -++} -++ -+ static bool ieee80211_tx_frags(struct ieee80211_local *local, -+ struct ieee80211_vif *vif, -+ struct ieee80211_sta *sta, -+@@ -1519,9 +1596,7 @@ static bool ieee80211_tx_frags(struct ie -+ bool txpending) -+ { -+ struct ieee80211_tx_control control = {}; -+- struct fq *fq = &local->fq; -+ struct sk_buff *skb, *tmp; -+- struct txq_info *txqi; -+ unsigned long flags; -+ -+ skb_queue_walk_safe(skbs, skb, tmp) { -+@@ -1536,21 +1611,6 @@ static bool ieee80211_tx_frags(struct ie -+ } -+ #endif -+ -+- txqi = ieee80211_get_txq(local, vif, sta, skb); -+- if (txqi) { -+- info->control.vif = vif; -+- -+- __skb_unlink(skb, skbs); -+- -+- spin_lock_bh(&fq->lock); -+- ieee80211_txq_enqueue(local, txqi, skb); -+- spin_unlock_bh(&fq->lock); -+- -+- drv_wake_tx_queue(local, txqi); -+- -+- continue; -+- } -+- -+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags); -+ if (local->queue_stop_reasons[q] || -+ (!txpending && !skb_queue_empty(&local->pending[q]))) { -+@@ -1671,10 +1731,13 @@ static bool __ieee80211_tx(struct ieee80 -+ /* -+ * Invoke TX handlers, return 0 on success and non-zero if the -+ * frame was dropped or queued. -++ * -++ * The handlers are split into an early and late part. The latter is everything -++ * that can be sensitive to reordering, and will be deferred to after packets -++ * are dequeued from the intermediate queues (when they are enabled). -+ */ -+-static int invoke_tx_handlers(struct ieee80211_tx_data *tx) -++static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx) -+ { -+- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); -+ ieee80211_tx_result res = TX_DROP; -+ -+ #define CALL_TXH(txh) \ -+@@ -1688,16 +1751,42 @@ static int invoke_tx_handlers(struct iee -+ CALL_TXH(ieee80211_tx_h_check_assoc); -+ CALL_TXH(ieee80211_tx_h_ps_buf); -+ CALL_TXH(ieee80211_tx_h_check_control_port_protocol); -+- CALL_TXH(ieee80211_tx_h_select_key); -++ -+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) -+ CALL_TXH(ieee80211_tx_h_rate_ctrl); -+ -++ txh_done: -++ if (unlikely(res == TX_DROP)) { -++ I802_DEBUG_INC(tx->local->tx_handlers_drop); -++ if (tx->skb) -++ ieee80211_free_txskb(&tx->local->hw, tx->skb); -++ else -++ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs); -++ return -1; -++ } else if (unlikely(res == TX_QUEUED)) { -++ I802_DEBUG_INC(tx->local->tx_handlers_queued); -++ return -1; -++ } -++ -++ return 0; -++} -++ -++/* -++ * Late handlers can be called while the sta lock is held. Handlers that can -++ * cause packets to be generated will cause deadlock! -++ */ -++static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); -++ ieee80211_tx_result res = TX_CONTINUE; -++ -+ if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) { -+ __skb_queue_tail(&tx->skbs, tx->skb); -+ tx->skb = NULL; -+ goto txh_done; -+ } -+ -++ CALL_TXH(ieee80211_tx_h_select_key); -+ CALL_TXH(ieee80211_tx_h_michael_mic_add); -+ CALL_TXH(ieee80211_tx_h_sequence); -+ CALL_TXH(ieee80211_tx_h_fragment); -+@@ -1724,6 +1813,15 @@ static int invoke_tx_handlers(struct iee -+ return 0; -+ } -+ -++static int invoke_tx_handlers(struct ieee80211_tx_data *tx) -++{ -++ int r = invoke_tx_handlers_early(tx); -++ if (r) -++ return r; -++ -++ return invoke_tx_handlers_late(tx); -++} -++ -+ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, struct sk_buff *skb, -+ int band, struct ieee80211_sta **sta) -+@@ -1798,7 +1896,13 @@ static bool ieee80211_tx(struct ieee8021 -+ info->hw_queue = -+ sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -+ -+- if (!invoke_tx_handlers(&tx)) -++ if (invoke_tx_handlers_early(&tx)) -++ return false; -++ -++ if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb)) -++ return true; -++ -++ if (!invoke_tx_handlers_late(&tx)) -+ result = __ieee80211_tx(local, &tx.skbs, led_len, -+ tx.sta, txpending); -+ -+@@ -3181,7 +3285,7 @@ out: -+ } -+ -+ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, -+- struct net_device *dev, struct sta_info *sta, -++ struct sta_info *sta, -+ struct ieee80211_fast_tx *fast_tx, -+ struct sk_buff *skb) -+ { -+@@ -3192,9 +3296,9 @@ static bool ieee80211_xmit_fast(struct i -+ struct ethhdr eth; -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; -+- struct ieee80211_tx_data tx; -+- ieee80211_tx_result r; -+ struct tid_ampdu_tx *tid_tx = NULL; -++ ieee80211_tx_result r; -++ struct ieee80211_tx_data tx; -+ u8 tid = IEEE80211_NUM_TIDS; -+ -+ /* control port protocol needs a lot of special handling */ -+@@ -3232,8 +3336,6 @@ static bool ieee80211_xmit_fast(struct i -+ return true; -+ } -+ -+- ieee80211_tx_stats(dev, skb->len + extra_head); -+- -+ if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && -+ ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) -+ return true; -+@@ -3262,24 +3364,7 @@ static bool ieee80211_xmit_fast(struct i -+ info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | -+ IEEE80211_TX_CTL_DONTFRAG | -+ (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); -+- -+- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -+- *ieee80211_get_qos_ctl(hdr) = tid; -+- if (!sta->sta.txq[0]) -+- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); -+- } else { -+- info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; -+- hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); -+- sdata->sequence_number += 0x10; -+- } -+- -+- if (skb_shinfo(skb)->gso_size) -+- sta->tx_stats.msdu[tid] += -+- DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); -+- else -+- sta->tx_stats.msdu[tid]++; -+- -+- info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -++ info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; -+ -+ __skb_queue_head_init(&tx.skbs); -+ -+@@ -3305,22 +3390,71 @@ static bool ieee80211_xmit_fast(struct i -+ } -+ } -+ -++ if (ieee80211_queue_skb(local, sdata, sta, skb)) -++ return true; -++ -++ ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, -++ &fast_tx->key->conf, skb); -++ -++ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -++ sdata = container_of(sdata->bss, -++ struct ieee80211_sub_if_data, u.ap); -++ -++ __skb_queue_tail(&tx.skbs, skb); -++ ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false); -++ -++ return true; -++} -++ -++/* -++ * Can be called while the sta lock is held. Anything that can cause packets to -++ * be generated will cause deadlock! -++ */ -++static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, -++ struct sta_info *sta, u8 pn_offs, -++ struct ieee80211_key_conf *key_conf, -++ struct sk_buff *skb) -++{ -++ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -++ struct ieee80211_hdr *hdr = (void *)skb->data; -++ u8 tid = IEEE80211_NUM_TIDS; -++ -++ ieee80211_tx_stats(skb->dev, skb->len); -++ -++ if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { -++ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; -++ *ieee80211_get_qos_ctl(hdr) = tid; -++ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); -++ } else { -++ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; -++ hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); -++ sdata->sequence_number += 0x10; -++ } -++ -++ if (skb_shinfo(skb)->gso_size) -++ sta->tx_stats.msdu[tid] += -++ DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); -++ else -++ sta->tx_stats.msdu[tid]++; -++ -++ info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -++ -+ /* statistics normally done by ieee80211_tx_h_stats (but that -+ * has to consider fragmentation, so is more complex) -+ */ -+ sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; -+ sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; -+ -+- if (fast_tx->pn_offs) { -++ if (pn_offs && (key_conf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { -+ u64 pn; -+- u8 *crypto_hdr = skb->data + fast_tx->pn_offs; -++ u8 *crypto_hdr = skb->data + pn_offs; -+ -+- switch (fast_tx->key->conf.cipher) { -++ switch (key_conf->cipher) { -+ case WLAN_CIPHER_SUITE_CCMP: -+ case WLAN_CIPHER_SUITE_CCMP_256: -+ case WLAN_CIPHER_SUITE_GCMP: -+ case WLAN_CIPHER_SUITE_GCMP_256: -+- pn = atomic64_inc_return(&fast_tx->key->conf.tx_pn); -++ pn = atomic64_inc_return(&key_conf->tx_pn); -+ crypto_hdr[0] = pn; -+ crypto_hdr[1] = pn >> 8; -+ crypto_hdr[4] = pn >> 16; -+@@ -3331,12 +3465,6 @@ static bool ieee80211_xmit_fast(struct i -+ } -+ } -+ -+- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) -+- sdata = container_of(sdata->bss, -+- struct ieee80211_sub_if_data, u.ap); -+- -+- __skb_queue_tail(&tx.skbs, skb); -+- ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false); -+ return true; -+ } -+ -+@@ -3364,7 +3492,7 @@ void __ieee80211_subif_start_xmit(struct -+ fast_tx = rcu_dereference(sta->fast_tx); -+ -+ if (fast_tx && -+- ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb)) -++ ieee80211_xmit_fast(sdata, sta, fast_tx, skb)) -+ goto out; -+ } -+ -+--- a/include/net/mac80211.h -++++ b/include/net/mac80211.h -+@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags { -+ * frame (PS-Poll or uAPSD). -+ * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information -+ * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame -++ * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path -+ * -+ * These flags are used in tx_info->control.flags. -+ */ -+@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags { -+ IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), -+ IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), -+ IEEE80211_TX_CTRL_AMSDU = BIT(3), -++ IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), -+ }; -+ -+ /* -+--- a/net/mac80211/ieee80211_i.h -++++ b/net/mac80211/ieee80211_i.h -+@@ -814,11 +814,13 @@ enum txq_info_flags { -+ * @def_flow: used as a fallback flow when a packet destined to @tin hashes to -+ * a fq_flow which is already owned by a different tin -+ * @def_cvars: codel vars for @def_flow -++ * @frags: used to keep fragments created after dequeue -+ */ -+ struct txq_info { -+ struct fq_tin tin; -+ struct fq_flow def_flow; -+ struct codel_vars def_cvars; -++ struct sk_buff_head frags; -+ unsigned long flags; -+ -+ /* keep last! */ -diff --git a/package/kernel/mac80211/patches/345-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch b/package/kernel/mac80211/patches/345-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch -deleted file mode 100644 -index c3d3118..0000000 ---- a/package/kernel/mac80211/patches/345-mac80211-send-delBA-on-unexpected-BlockAck-Request.patch -+++ /dev/null -@@ -1,26 +0,0 @@ --From: Johannes Berg <johannes.berg@intel.com> --Date: Mon, 29 Aug 2016 23:25:19 +0300 --Subject: [PATCH] mac80211: send delBA on unexpected BlockAck Request -- --If we don't have a BA session, send delBA, as requested by the --IEEE 802.11 spec. Apply the same limit of sending such a delBA --only once as in the previous patch. -- --Signed-off-by: Johannes Berg <johannes.berg@intel.com> ----- -- ----- a/net/mac80211/rx.c --+++ b/net/mac80211/rx.c --@@ -2537,6 +2537,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_ -- -- tid = le16_to_cpu(bar_data.control) >> 12; -- --+ if (!test_bit(tid, rx->sta->ampdu_mlme.agg_session_valid) && --+ !test_and_set_bit(tid, rx->sta->ampdu_mlme.unexpected_agg)) --+ ieee80211_send_delba(rx->sdata, rx->sta->sta.addr, tid, --+ WLAN_BACK_RECIPIENT, --+ WLAN_REASON_QSTA_REQUIRE_SETUP); --+ -- tid_agg_rx = rcu_dereference(rx->sta->ampdu_mlme.tid_rx[tid]); -- if (!tid_agg_rx) -- return RX_DROP_MONITOR; -diff --git a/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch b/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -deleted file mode 100644 -index aba1ff4..0000000 ---- a/package/kernel/mac80211/patches/346-mac80211-Move-reorder-sensitive-TX-handlers-to-after.patch -+++ /dev/null -@@ -1,478 +0,0 @@ --From: Felix Fietkau <nbd@nbd.name> --Date: Sun, 4 Sep 2016 17:46:24 +0200 --Subject: [PATCH] mac80211: fix sequence number assignment for PS response -- frames -- --When using intermediate queues, sequence number allocation is deferred --until dequeue. This doesn't work for PS response frames, which bypass --those queues. -- --Signed-off-by: Felix Fietkau <nbd@nbd.name> ----- -- ----- a/net/mac80211/tx.c --+++ b/net/mac80211/tx.c --@@ -38,6 +38,12 @@ -- #include "wme.h" -- #include "rate.h" -- --+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx); --+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, --+ struct sta_info *sta, u8 pn_offs, --+ struct ieee80211_key_conf *key_conf, --+ struct sk_buff *skb); --+ -- /* misc utils */ -- -- static inline void ieee80211_tx_stats(struct net_device *dev, u32 len) --@@ -849,8 +855,7 @@ ieee80211_tx_h_sequence(struct ieee80211 -- tid = *qc & IEEE80211_QOS_CTL_TID_MASK; -- tx->sta->tx_stats.msdu[tid]++; -- --- if (!tx->sta->sta.txq[0]) --- hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); --+ hdr->seq_ctrl = ieee80211_tx_next_seq(tx->sta, tid); -- -- return TX_CONTINUE; -- } --@@ -1398,6 +1403,7 @@ void ieee80211_txq_init(struct ieee80211 -- fq_tin_init(&txqi->tin); -- fq_flow_init(&txqi->def_flow); -- codel_vars_init(&txqi->def_cvars); --+ __skb_queue_head_init(&txqi->frags); -- -- txqi->txq.vif = &sdata->vif; -- --@@ -1420,6 +1426,7 @@ void ieee80211_txq_purge(struct ieee8021 -- struct fq_tin *tin = &txqi->tin; -- -- fq_tin_reset(fq, tin, fq_skb_free_func); --+ ieee80211_purge_tx_queue(&local->hw, &txqi->frags); -- } -- -- int ieee80211_txq_setup_flows(struct ieee80211_local *local) --@@ -1476,12 +1483,19 @@ struct sk_buff *ieee80211_tx_dequeue(str -- struct sk_buff *skb = NULL; -- struct fq *fq = &local->fq; -- struct fq_tin *tin = &txqi->tin; --+ struct ieee80211_tx_info *info; -- -- spin_lock_bh(&fq->lock); -- -- if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags)) -- goto out; -- --+ /* Make sure fragments stay together. */ --+ skb = __skb_dequeue(&txqi->frags); --+ if (skb) --+ goto out; --+ --+begin: -- skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func); -- if (!skb) -- goto out; --@@ -1489,16 +1503,38 @@ struct sk_buff *ieee80211_tx_dequeue(str -- ieee80211_set_skb_vif(skb, txqi); -- -- hdr = (struct ieee80211_hdr *)skb->data; --- if (txq->sta && ieee80211_is_data_qos(hdr->frame_control)) { --+ info = IEEE80211_SKB_CB(skb); --+ if (txq->sta && info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) { -- struct sta_info *sta = container_of(txq->sta, struct sta_info, -- sta); --- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --+ u8 pn_offs = 0; -- --- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, txq->tid); --- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags)) --- info->flags |= IEEE80211_TX_CTL_AMPDU; --- else --- info->flags &= ~IEEE80211_TX_CTL_AMPDU; --+ if (info->control.hw_key) --+ pn_offs = ieee80211_padded_hdrlen(hw, hdr->frame_control); --+ --+ ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs, --+ info->control.hw_key, skb); --+ } else { --+ struct ieee80211_tx_data tx = { }; --+ --+ __skb_queue_head_init(&tx.skbs); --+ tx.local = local; --+ tx.skb = skb; --+ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control); --+ if (txq->sta) { --+ tx.sta = container_of(txq->sta, struct sta_info, sta); --+ tx.sdata = tx.sta->sdata; --+ } else { --+ tx.sdata = vif_to_sdata(info->control.vif); --+ } --+ --+ if (invoke_tx_handlers_late(&tx)) --+ goto begin; --+ --+ skb = __skb_dequeue(&tx.skbs); --+ --+ if (!skb_queue_empty(&tx.skbs)) --+ skb_queue_splice_tail(&tx.skbs, &txqi->frags); -- } -- -- out: --@@ -1512,6 +1548,47 @@ out: -- } -- EXPORT_SYMBOL(ieee80211_tx_dequeue); -- --+static bool ieee80211_queue_skb(struct ieee80211_local *local, --+ struct ieee80211_sub_if_data *sdata, --+ struct sta_info *sta, --+ struct sk_buff *skb) --+{ --+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --+ struct fq *fq = &local->fq; --+ struct ieee80211_vif *vif; --+ struct txq_info *txqi; --+ struct ieee80211_sta *pubsta; --+ --+ if (!local->ops->wake_tx_queue || --+ sdata->vif.type == NL80211_IFTYPE_MONITOR) --+ return false; --+ --+ if (sta && sta->uploaded) --+ pubsta = &sta->sta; --+ else --+ pubsta = NULL; --+ --+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) --+ sdata = container_of(sdata->bss, --+ struct ieee80211_sub_if_data, u.ap); --+ --+ vif = &sdata->vif; --+ txqi = ieee80211_get_txq(local, vif, pubsta, skb); --+ --+ if (!txqi) --+ return false; --+ --+ info->control.vif = vif; --+ --+ spin_lock_bh(&fq->lock); --+ ieee80211_txq_enqueue(local, txqi, skb); --+ spin_unlock_bh(&fq->lock); --+ --+ drv_wake_tx_queue(local, txqi); --+ --+ return true; --+} --+ -- static bool ieee80211_tx_frags(struct ieee80211_local *local, -- struct ieee80211_vif *vif, -- struct ieee80211_sta *sta, --@@ -1519,9 +1596,7 @@ static bool ieee80211_tx_frags(struct ie -- bool txpending) -- { -- struct ieee80211_tx_control control = {}; --- struct fq *fq = &local->fq; -- struct sk_buff *skb, *tmp; --- struct txq_info *txqi; -- unsigned long flags; -- -- skb_queue_walk_safe(skbs, skb, tmp) { --@@ -1536,21 +1611,6 @@ static bool ieee80211_tx_frags(struct ie -- } -- #endif -- --- txqi = ieee80211_get_txq(local, vif, sta, skb); --- if (txqi) { --- info->control.vif = vif; --- --- __skb_unlink(skb, skbs); --- --- spin_lock_bh(&fq->lock); --- ieee80211_txq_enqueue(local, txqi, skb); --- spin_unlock_bh(&fq->lock); --- --- drv_wake_tx_queue(local, txqi); --- --- continue; --- } --- -- spin_lock_irqsave(&local->queue_stop_reason_lock, flags); -- if (local->queue_stop_reasons[q] || -- (!txpending && !skb_queue_empty(&local->pending[q]))) { --@@ -1671,10 +1731,13 @@ static bool __ieee80211_tx(struct ieee80 -- /* -- * Invoke TX handlers, return 0 on success and non-zero if the -- * frame was dropped or queued. --+ * --+ * The handlers are split into an early and late part. The latter is everything --+ * that can be sensitive to reordering, and will be deferred to after packets --+ * are dequeued from the intermediate queues (when they are enabled). -- */ ---static int invoke_tx_handlers(struct ieee80211_tx_data *tx) --+static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx) -- { --- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); -- ieee80211_tx_result res = TX_DROP; -- -- #define CALL_TXH(txh) \ --@@ -1688,16 +1751,42 @@ static int invoke_tx_handlers(struct iee -- CALL_TXH(ieee80211_tx_h_check_assoc); -- CALL_TXH(ieee80211_tx_h_ps_buf); -- CALL_TXH(ieee80211_tx_h_check_control_port_protocol); --- CALL_TXH(ieee80211_tx_h_select_key); --+ -- if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL)) -- CALL_TXH(ieee80211_tx_h_rate_ctrl); -- --+ txh_done: --+ if (unlikely(res == TX_DROP)) { --+ I802_DEBUG_INC(tx->local->tx_handlers_drop); --+ if (tx->skb) --+ ieee80211_free_txskb(&tx->local->hw, tx->skb); --+ else --+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs); --+ return -1; --+ } else if (unlikely(res == TX_QUEUED)) { --+ I802_DEBUG_INC(tx->local->tx_handlers_queued); --+ return -1; --+ } --+ --+ return 0; --+} --+ --+/* --+ * Late handlers can be called while the sta lock is held. Handlers that can --+ * cause packets to be generated will cause deadlock! --+ */ --+static int invoke_tx_handlers_late(struct ieee80211_tx_data *tx) --+{ --+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); --+ ieee80211_tx_result res = TX_CONTINUE; --+ -- if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) { -- __skb_queue_tail(&tx->skbs, tx->skb); -- tx->skb = NULL; -- goto txh_done; -- } -- --+ CALL_TXH(ieee80211_tx_h_select_key); -- CALL_TXH(ieee80211_tx_h_michael_mic_add); -- CALL_TXH(ieee80211_tx_h_sequence); -- CALL_TXH(ieee80211_tx_h_fragment); --@@ -1724,6 +1813,15 @@ static int invoke_tx_handlers(struct iee -- return 0; -- } -- --+static int invoke_tx_handlers(struct ieee80211_tx_data *tx) --+{ --+ int r = invoke_tx_handlers_early(tx); --+ if (r) --+ return r; --+ --+ return invoke_tx_handlers_late(tx); --+} --+ -- bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw, -- struct ieee80211_vif *vif, struct sk_buff *skb, -- int band, struct ieee80211_sta **sta) --@@ -1798,7 +1896,13 @@ static bool ieee80211_tx(struct ieee8021 -- info->hw_queue = -- sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -- --- if (!invoke_tx_handlers(&tx)) --+ if (invoke_tx_handlers_early(&tx)) --+ return false; --+ --+ if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb)) --+ return true; --+ --+ if (!invoke_tx_handlers_late(&tx)) -- result = __ieee80211_tx(local, &tx.skbs, led_len, -- tx.sta, txpending); -- --@@ -3181,7 +3285,7 @@ out: -- } -- -- static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, --- struct net_device *dev, struct sta_info *sta, --+ struct sta_info *sta, -- struct ieee80211_fast_tx *fast_tx, -- struct sk_buff *skb) -- { --@@ -3192,9 +3296,9 @@ static bool ieee80211_xmit_fast(struct i -- struct ethhdr eth; -- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -- struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; --- struct ieee80211_tx_data tx; --- ieee80211_tx_result r; -- struct tid_ampdu_tx *tid_tx = NULL; --+ ieee80211_tx_result r; --+ struct ieee80211_tx_data tx; -- u8 tid = IEEE80211_NUM_TIDS; -- -- /* control port protocol needs a lot of special handling */ --@@ -3232,8 +3336,6 @@ static bool ieee80211_xmit_fast(struct i -- return true; -- } -- --- ieee80211_tx_stats(dev, skb->len + extra_head); --- -- if ((hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) && -- ieee80211_amsdu_aggregate(sdata, sta, fast_tx, skb)) -- return true; --@@ -3262,24 +3364,7 @@ static bool ieee80211_xmit_fast(struct i -- info->flags = IEEE80211_TX_CTL_FIRST_FRAGMENT | -- IEEE80211_TX_CTL_DONTFRAG | -- (tid_tx ? IEEE80211_TX_CTL_AMPDU : 0); --- --- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { --- *ieee80211_get_qos_ctl(hdr) = tid; --- if (!sta->sta.txq[0]) --- hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); --- } else { --- info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; --- hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); --- sdata->sequence_number += 0x10; --- } --- --- if (skb_shinfo(skb)->gso_size) --- sta->tx_stats.msdu[tid] += --- DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); --- else --- sta->tx_stats.msdu[tid]++; --- --- info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; --+ info->control.flags = IEEE80211_TX_CTRL_FAST_XMIT; -- -- __skb_queue_head_init(&tx.skbs); -- --@@ -3305,22 +3390,71 @@ static bool ieee80211_xmit_fast(struct i -- } -- } -- --+ if (ieee80211_queue_skb(local, sdata, sta, skb)) --+ return true; --+ --+ ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs, --+ &fast_tx->key->conf, skb); --+ --+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) --+ sdata = container_of(sdata->bss, --+ struct ieee80211_sub_if_data, u.ap); --+ --+ __skb_queue_tail(&tx.skbs, skb); --+ ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false); --+ --+ return true; --+} --+ --+/* --+ * Can be called while the sta lock is held. Anything that can cause packets to --+ * be generated will cause deadlock! --+ */ --+static bool ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata, --+ struct sta_info *sta, u8 pn_offs, --+ struct ieee80211_key_conf *key_conf, --+ struct sk_buff *skb) --+{ --+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); --+ struct ieee80211_hdr *hdr = (void *)skb->data; --+ u8 tid = IEEE80211_NUM_TIDS; --+ --+ ieee80211_tx_stats(skb->dev, skb->len); --+ --+ if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) { --+ tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; --+ *ieee80211_get_qos_ctl(hdr) = tid; --+ hdr->seq_ctrl = ieee80211_tx_next_seq(sta, tid); --+ } else { --+ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; --+ hdr->seq_ctrl = cpu_to_le16(sdata->sequence_number); --+ sdata->sequence_number += 0x10; --+ } --+ --+ if (skb_shinfo(skb)->gso_size) --+ sta->tx_stats.msdu[tid] += --+ DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); --+ else --+ sta->tx_stats.msdu[tid]++; --+ --+ info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; --+ -- /* statistics normally done by ieee80211_tx_h_stats (but that -- * has to consider fragmentation, so is more complex) -- */ -- sta->tx_stats.bytes[skb_get_queue_mapping(skb)] += skb->len; -- sta->tx_stats.packets[skb_get_queue_mapping(skb)]++; -- --- if (fast_tx->pn_offs) { --+ if (pn_offs && (key_conf->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { -- u64 pn; --- u8 *crypto_hdr = skb->data + fast_tx->pn_offs; --+ u8 *crypto_hdr = skb->data + pn_offs; -- --- switch (fast_tx->key->conf.cipher) { --+ switch (key_conf->cipher) { -- case WLAN_CIPHER_SUITE_CCMP: -- case WLAN_CIPHER_SUITE_CCMP_256: -- case WLAN_CIPHER_SUITE_GCMP: -- case WLAN_CIPHER_SUITE_GCMP_256: --- pn = atomic64_inc_return(&fast_tx->key->conf.tx_pn); --+ pn = atomic64_inc_return(&key_conf->tx_pn); -- crypto_hdr[0] = pn; -- crypto_hdr[1] = pn >> 8; -- crypto_hdr[4] = pn >> 16; --@@ -3331,12 +3465,6 @@ static bool ieee80211_xmit_fast(struct i -- } -- } -- --- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) --- sdata = container_of(sdata->bss, --- struct ieee80211_sub_if_data, u.ap); --- --- __skb_queue_tail(&tx.skbs, skb); --- ieee80211_tx_frags(local, &sdata->vif, &sta->sta, &tx.skbs, false); -- return true; -- } -- --@@ -3364,7 +3492,7 @@ void __ieee80211_subif_start_xmit(struct -- fast_tx = rcu_dereference(sta->fast_tx); -- -- if (fast_tx && --- ieee80211_xmit_fast(sdata, dev, sta, fast_tx, skb)) --+ ieee80211_xmit_fast(sdata, sta, fast_tx, skb)) -- goto out; -- } -- ----- a/include/net/mac80211.h --+++ b/include/net/mac80211.h --@@ -715,6 +715,7 @@ enum mac80211_tx_info_flags { -- * frame (PS-Poll or uAPSD). -- * @IEEE80211_TX_CTRL_RATE_INJECT: This frame is injected with rate information -- * @IEEE80211_TX_CTRL_AMSDU: This frame is an A-MSDU frame --+ * @IEEE80211_TX_CTRL_FAST_XMIT: This frame is going through the fast_xmit path -- * -- * These flags are used in tx_info->control.flags. -- */ --@@ -723,6 +724,7 @@ enum mac80211_tx_control_flags { -- IEEE80211_TX_CTRL_PS_RESPONSE = BIT(1), -- IEEE80211_TX_CTRL_RATE_INJECT = BIT(2), -- IEEE80211_TX_CTRL_AMSDU = BIT(3), --+ IEEE80211_TX_CTRL_FAST_XMIT = BIT(4), -- }; -- -- /* ----- a/net/mac80211/ieee80211_i.h --+++ b/net/mac80211/ieee80211_i.h --@@ -814,11 +814,13 @@ enum txq_info_flags { -- * @def_flow: used as a fallback flow when a packet destined to @tin hashes to -- * a fq_flow which is already owned by a different tin -- * @def_cvars: codel vars for @def_flow --+ * @frags: used to keep fragments created after dequeue -- */ -- struct txq_info { -- struct fq_tin tin; -- struct fq_flow def_flow; -- struct codel_vars def_cvars; --+ struct sk_buff_head frags; -- unsigned long flags; -- -- /* keep last! */ -- GitLab