From 487922a8d9b7ac564effe25632fd90e2cb6979b9 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer 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} | 4047 ++++------------- ...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, 1127 insertions(+), 5214 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 04bf2b2d..64eea76e 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 -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 -+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 -+Reviewed-by: Dinan Gunawardena -+--- -+ create mode 100644 include/linux/bitfield.h -+ -+--- /dev/null -++++ b/include/linux/bitfield.h -+@@ -0,0 +1,100 @@ -++/* -++ * Copyright (C) 2014 Felix Fietkau -++ * Copyright (C) 2004 - 2009 Ivo van Doorn -++ * -++ * 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 -++ -++#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,45 +5288,883 @@ 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 -+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?= ++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 ++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 ++Cc: Felix Fietkau ++Signed-off-by: Toke Høiland-Jørgensen +--- + ++--- 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,9 @@ 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_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)) ++ ++ #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 { ++ ++ 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; ++ }; ++ ++ 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 +275,6 @@ struct ath_tx_control { ++ struct ath_node *an; ++ struct ieee80211_sta *sta; ++ u8 paprd; ++- bool force_channel; ++ }; ++ ++ ++@@ -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"); ++ ++- 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; ++ ++ 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 -+@@ -1563,13 +1563,13 @@ static int ath9k_sta_state(struct ieee80 -+ struct ath_common *common = ath9k_hw_common(sc->sc_ah); -+ int ret = 0; ++@@ -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); ++ ++ enum { ++ MCS_HT20, ++@@ -118,6 +120,26 @@ static void ath_tx_queue_tid(struct ath_ ++ list_add_tail(&tid->list, list); ++ } ++ +++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); +++ +++ 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; ++ ++@@ -171,14 +192,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; ++- } ++ } ++ ++ 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); ++ } ++ +++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; +++ +++ if (!tid->has_queued) +++ return NULL; +++ +++ skb = ieee80211_tx_dequeue(hw, container_of((void*)tid, struct ieee80211_txq, drv_priv)); +++ if (!skb) { +++ tid->has_queued = false; +++ return NULL; +++ } +++ +++ 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) ++ { ++- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); +++ return !skb_queue_empty(&tid->retry_q) || tid->has_queued; ++ } ++ ++ static struct sk_buff *ath_tid_dequeue(struct ath_atx_tid *tid) ++@@ -199,46 +250,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; ++ } ++ ++-/* ++- * 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; ++- } ++- } ++- ++-} ++- ++ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ++ { ++ struct ath_txq *txq = tid->txq; ++@@ -873,20 +889,16 @@ static int ath_compute_num_delims(struct ++ ++ 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) ++ { ++ 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; ++ ++@@ -898,7 +910,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; ++@@ -927,8 +938,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 = {}; ++@@ -936,7 +958,6 @@ ath_tx_get_tid_subframe(struct ath_softc ++ ++ 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 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; ++@@ -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; +++ ++ ++ bf = bf_first; ++ aggr_limit = ath_lookup_rate(sc, bf, tid); ++ ++- 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; ++ } ++ ++ /* 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; ++ ++- __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; ++ ++@@ -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) ++ { ++ 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 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; ++@@ -1513,9 +1528,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; ++@@ -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__); ++ ++- 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; ++ } ++ ++- 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); ++ } ++ } ++ ++@@ -1586,19 +1594,16 @@ 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_AN_2_TID(an, tidno); ++ txq = tid->txq; ++ ++ 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); ++ } ++ } ++@@ -1621,11 +1626,6 @@ void ath_tx_aggr_resume(struct ath_softc ++ ++ tid->baw_size = IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; ++ ++- if (ath_tid_has_buffered(tid)) { ++- ath_tx_queue_tid(sc, txq, tid); ++- ath_txq_schedule(sc, txq); ++- } ++- ++ ath_txq_unlock_complete(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; ++ ++@@ -1656,11 +1655,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)) { ++@@ -1675,7 +1673,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); ++@@ -1902,13 +1900,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); ++ } ++ ++@@ -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; ++ ++ if (vif) ++ avp = (void *)vif->drv_priv; ++ ++- if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN) ++- txctl->force_channel = true; ++- ++ ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE); ++ ++ ret = ath_tx_prepare(hw, skb, txctl); ++@@ -2331,63 +2320,13 @@ int ath_tx_start(struct ieee80211_hw *hw ++ ++ q = skb_get_queue_mapping(skb); ++ +++ 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; ++ } ++ ++ 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 */ ++ } ++ } ++ ++@@ -2895,9 +2836,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_AN_2_TID(an, tidno); ++ txq = tid->txq; ++ ++ ath_txq_lock(sc, txq); ++@@ -2909,6 +2849,9 @@ void ath_tx_node_cleanup(struct ath_soft ++ tid->active = false; ++ ++ ath_txq_unlock(sc, txq); +++ +++ if (!an->sta) +++ break; /* just one multicast ath_atx_tid */ ++ } ++ } + -+- 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 @@ -7448,6 +8003,109 @@ index f7f9df9..0000000 - 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 ++Date: Mon, 11 Jul 2016 11:35:55 +0200 ++Subject: [PATCH] ath9k_hw: implement temperature compensation support for ++ AR9003+ ++ ++Signed-off-by: Felix Fietkau ++--- ++ ++--- 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/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 @@ -8146,702 +8804,6 @@ index 1fd016f..0000000 - 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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); -+ -+ return IRQ_HANDLED; -+ } -+@@ -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); -+ -++ init_dummy_netdev(&ar->napi_dev); -++ -+ 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 -++ -+ 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; -++ -+ /* 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) -+ { -+ 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); -+ } -+ -+ 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; -+ } -+ -++ 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); -+ -+- return 0; -++ return num_msdus; -+ } -+ -+ 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) -+-{ -+- atomic_inc(&htt->num_mpdus_ready); -+- -+- 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); -+- -+- while (num_mpdus) { -+- if (ath10k_htt_rx_handle_amsdu(htt)) -+- break; -+- -+- num_mpdus--; -+- atomic_dec(&htt->num_mpdus_ready); -+- } -+- -+- 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); -+- } -+- -++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) -+ { -+ u32 val; -+ -+@@ -1747,7 +1745,7 @@ void ath10k_pci_ce_deinit(struct ath10k -+ -+ void ath10k_pci_flush(struct ath10k *ar) -+ { -+- 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; -+ } -+ -+- if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) { -+- if (!ath10k_pci_irq_pending(ar)) -+- return IRQ_NONE; -+- -+- 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; -+ } -+ -+-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; -+ } -+ -+ ath10k_ce_per_engine_service_any(ar); -+ -+- /* 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); -++ -++ 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; -++ } -+ 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); -+ } -+ -+-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); -+ } -+ -+ 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) -+ { -+- 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 @@ -8870,81 +8832,6 @@ index e414f23..0000000 - 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 -+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 -+--- -+ -+--- 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 @@ -9083,66 +8970,6 @@ index 6e2d0cf..0000000 - 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 -+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 -+--- -+ -+--- a/net/mac80211/cfg.c -++++ b/net/mac80211/cfg.c -+@@ -868,7 +868,7 @@ static int ieee80211_stop_ap(struct wiph -+ -+ /* 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); -+ -+ 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); -+ } -+ 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); -+ } -+ -+ 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 @@ -9185,317 +9012,6 @@ index f8f4f09..0000000 - 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 -+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 -+--- -+ -+--- 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; -++ } -++ -++ 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) -+ { -+@@ -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 ieee80211_hw *hw = sc->hw; -+ struct sk_buff_head q; -+ struct sk_buff *skb; -+ -+@@ -100,7 +119,7 @@ void ath_txq_unlock_complete(struct ath_ -+ spin_unlock_bh(&txq->axq_lock); -+ -+ while ((skb = __skb_dequeue(&q))) -+- ieee80211_tx_status(sc->hw, skb); -++ ath_tx_status(hw, skb); -+ } -+ -+ 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_ -+ } -+ -+ 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 (sendbar) { -+@@ -333,12 +352,12 @@ static void ath_tid_drain(struct ath_sof -+ bf = fi->bf; -+ -+ if (!bf) { -+- ath_tx_complete(sc, skb, ATH_TX_ERROR, txq); -++ ath_tx_complete(sc, skb, ATH_TX_ERROR, txq, NULL); -+ 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); -+ } -+ } -+ -+@@ -441,12 +460,11 @@ 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_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; -+ -+- rcu_read_lock(); -+- -+- sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr1, hdr->addr2); -+ if (!sta) { -+- rcu_read_unlock(); -+- -+ 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); -+ -+ bf = bf_next; -+ } -+@@ -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); -+ } -+@@ -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 -+ -+ 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); -+ -+ 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; -+ } -+ -+@@ -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); -+ -+ 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); -+ -+ ath_txq_unlock_complete(sc, txq); -++ rcu_read_unlock(); -+ } -+ -+ bool ath_drain_all_txq(struct ath_softc *sc) -+@@ -2487,7 +2508,8 @@ void ath_tx_cabq(struct ieee80211_hw *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; -+ } -+ -+- 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); -++ 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); -++ } -+ } -+ -+ 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); -+ -+- __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); -+ } -+ -+ 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; -+ -++ 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(); -+ } -+ -+ 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; -+ -++ 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); -+ } -++ 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 @@ -9563,82 +9079,6 @@ index acaacf7..0000000 - 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 -+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 -+--- -+ -+--- 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 -+ } -+ -+ 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; -+ -+@@ -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; -++ } -+ -+ 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); -+ -+ 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 deleted file mode 100644 index 32a2ad6..0000000 @@ -9676,963 +9116,6 @@ index 32a2ad6..0000000 - } - - 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?= -+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 -+Cc: Felix Fietkau -+Signed-off-by: Toke Høiland-Jørgensen -+--- -+ -+--- 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; -+ -+@@ -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"); -+ -+- 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; -+ } -+@@ -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); -+ } -+ -++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); -++ -++ 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); -+@@ -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; -+- } -+ } -+ -+ 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); -+ } -+ -++static struct sk_buff * -++ath_tid_pull(struct ath_atx_tid *tid) -++{ -++ 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; -++ } -++ -++ 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) -+ { -+- return !skb_queue_empty(&tid->buf_q) || !skb_queue_empty(&tid->retry_q); -++ return !skb_queue_empty(&tid->retry_q) || tid->has_queued; -+ } -+ -+ 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; -+ } -+ -+-/* -+- * 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; -+- } -+- } -+- -+-} -+- -+ 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 -+ -+ 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) -+ { -+ 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 -+ -+ 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; -+ } -+ -+-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; -++ -+ -+ 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 -+ } -+ -+@@ -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; -+ -+ 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; -+@@ -1451,13 +1466,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); -+@@ -1468,34 +1485,33 @@ static bool ath_tx_sched_aggr(struct ath -+ { -+ 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); -+ } -+ -+@@ -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; -+ -+ 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; -+ -+ ath_txq_lock(sc, txq); -+@@ -1592,13 +1602,12 @@ void ath_tx_aggr_sleep(struct ieee80211_ -+ continue; -+ } -+ -+- 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); -+ } -+ } -+ -+@@ -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; -+ -+ 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); -+ } -+ } -+ -+-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; -+- -+- if (ath_tid_has_buffered(tid)) { -+- ath_tx_queue_tid(sc, txq, tid); -+- ath_txq_schedule(sc, txq); -+- } -+- -+- ath_txq_unlock_complete(sc, txq); -+-} -+- -+ 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; -+- -+ 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 -+ -+ q = skb_get_queue_mapping(skb); -+ -+- 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); -++ if (ps_resp) -+ 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); -++ if (txctl->sta) { -++ an = (struct ath_node *) sta->drv_priv; -++ tid = ath_get_skb_tid(sc, an, skb); -++ } -+ -+- 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; -+ } -+ -+ 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; -+ -+- 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 */ -+ } -+ } -+ -+@@ -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; -+ -+ ath_txq_unlock(sc, txq); -++ -++ if (!an->sta) -++ break; /* just one multicast ath_atx_tid */ -+ } -+ } -+ 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 -+Date: Sun, 28 Aug 2016 13:23:27 +0200 -+Subject: [PATCH] ath9k: report tx status on EOSP -+ -+Signed-off-by: Felix Fietkau -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 6328ba4c..00000000 --- a/patches/openwrt/0073-mac80211-fix-packet-loss-on-fq-reordering.patch +++ /dev/null @@ -1,636 +0,0 @@ -From: Matthias Schiffer -Date: Fri, 30 Sep 2016 16:57:44 +0200 -Subject: mac80211: fix packet loss on fq reordering - -Signed-off-by: Felix Fietkau - -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 -+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 -+--- -+ -+--- 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 --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 ----- -- ----- 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 00000000..803db695 --- /dev/null +++ b/patches/openwrt/0074-ath9k-revert-temperature-compensation-support-patch-FS-111.patch @@ -0,0 +1,124 @@ +From: Matthias Schiffer +Date: Tue, 11 Oct 2016 02:54:27 +0200 +Subject: ath9k: revert temperature compensation support patch (FS#111) + +Signed-off-by: Felix Fietkau + +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 +-Date: Mon, 11 Jul 2016 11:35:55 +0200 +-Subject: [PATCH] ath9k_hw: implement temperature compensation support for +- AR9003+ +- +-Signed-off-by: Felix Fietkau +---- +- +---- 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 f464421c..00000000 --- a/patches/openwrt/0074-mac80211-fix-tx-issue-with-CCMP-PN-generated-in-hardware.patch +++ /dev/null @@ -1,21 +0,0 @@ -From: Matthias Schiffer -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 - -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 - 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 ddfb6445..00000000 --- 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 -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 - -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 --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 ----- -- ----- 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 -+Date: Sun, 28 Aug 2016 13:23:27 +0200 -+Subject: [PATCH] ath9k: report tx status on EOSP -+ -+Signed-off-by: Felix Fietkau -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 --Date: Sun, 28 Aug 2016 13:23:27 +0200 --Subject: [PATCH] ath9k: report tx status on EOSP -- --Signed-off-by: Felix Fietkau ----- -- ----- 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 --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 ----- -- ----- 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 -+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 -+--- -+ -+--- 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 -+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 -+--- -+ -+--- 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 --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 ----- -- ----- 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 -+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 -+--- -+ -+--- 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 --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 ----- -- ----- 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 --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 ----- -- ----- 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! */