From 7974284ed6a2f72effd910ee25a26b53e72bdef3 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 26 Jul 2016 01:12:16 +0200 Subject: [PATCH] mac80211: update to LEDE b47f438d98cd4b731d7f4431448dde973eae4739 --- ...38d98cd4b731d7f4431448dde973eae4739.patch} | 1632 ++++++++--------- 1 file changed, 743 insertions(+), 889 deletions(-) rename patches/openwrt/{0007-mac80211-update-to-LEDE-6c2651566cce8f5b3a3d3b976439dee2bac5e07e.patch => 0007-mac80211-update-to-LEDE-b47f438d98cd4b731d7f4431448dde973eae4739.patch} (94%) diff --git a/patches/openwrt/0007-mac80211-update-to-LEDE-6c2651566cce8f5b3a3d3b976439dee2bac5e07e.patch b/patches/openwrt/0007-mac80211-update-to-LEDE-b47f438d98cd4b731d7f4431448dde973eae4739.patch similarity index 94% rename from patches/openwrt/0007-mac80211-update-to-LEDE-6c2651566cce8f5b3a3d3b976439dee2bac5e07e.patch rename to patches/openwrt/0007-mac80211-update-to-LEDE-b47f438d98cd4b731d7f4431448dde973eae4739.patch index 85b2157a..26b89761 100644 --- a/patches/openwrt/0007-mac80211-update-to-LEDE-6c2651566cce8f5b3a3d3b976439dee2bac5e07e.patch +++ b/patches/openwrt/0007-mac80211-update-to-LEDE-b47f438d98cd4b731d7f4431448dde973eae4739.patch @@ -1,9 +1,9 @@ From: Matthias Schiffer Date: Tue, 7 Jun 2016 14:06:23 +0200 -Subject: mac80211: update to LEDE 6c2651566cce8f5b3a3d3b976439dee2bac5e07e +Subject: mac80211: update to LEDE b47f438d98cd4b731d7f4431448dde973eae4739 diff --git a/package/firmware/ath10k-firmware/Makefile b/package/firmware/ath10k-firmware/Makefile -index b03d644..170a6c9 100644 +index b03d644..e2cf92e 100644 --- a/package/firmware/ath10k-firmware/Makefile +++ b/package/firmware/ath10k-firmware/Makefile @@ -8,7 +8,7 @@ @@ -24,7 +24,7 @@ index b03d644..170a6c9 100644 include $(INCLUDE_DIR)/package.mk -@@ -28,14 +28,18 @@ define Package/ath10k-firmware-default +@@ -28,14 +28,19 @@ define Package/ath10k-firmware-default CATEGORY:=Kernel modules SUBMENU:=$(WMENU) URL:=$(PKG_SOURCE_URL) @@ -38,19 +38,20 @@ index b03d644..170a6c9 100644 endef QCA988X_FIRMWARE_FILE:=firmware-5.bin_10.2.4.97-1 -+QCA988X_FIRMWARE_FILE_CT:=firmware-2-ct-full-community-16.bin-lede ++QCA988X_FIRMWARE_FILE_CT:=firmware-2-ct-full-community-16.1.bin-lede +QCA99X0_FIRMWARE_FILE_CT:=firmware-5-ct-full-community-7.bin-lede.001 ++QCA9984_FIRMWARE_FILE_CT:=firmware-5-ct-full-community-7.bin-lede.001 define Download/ath10k-firmware-qca988x URL:=https://www.codeaurora.org/cgit/quic/qsdk/oss/firmware/ath10k-firmware/plain/10.2.4/ -@@ -44,11 +48,63 @@ define Download/ath10k-firmware-qca988x +@@ -44,11 +49,83 @@ define Download/ath10k-firmware-qca988x endef $(eval $(call Download,ath10k-firmware-qca988x)) +define Download/ath10k-firmware-qca988x-ct + URL:=https://www.candelatech.com/downloads/ + FILE:=$(QCA988X_FIRMWARE_FILE_CT) -+ MD5SUM:=5b651c0458bcf5c20701308b5e519976 ++ MD5SUM:=d7e081e9782936ed544b78994c9133fb +endef +$(eval $(call Download,ath10k-firmware-qca988x-ct)) + @@ -60,6 +61,13 @@ index b03d644..170a6c9 100644 + MD5SUM:=eb710949ff79142954aadae24616169c +endef +$(eval $(call Download,ath10k-firmware-qca99x0-ct)) ++ ++define Download/ath10k-firmware-qca9984-ct ++ URL:=https://www.candelatech.com/downloads/ath10k-9984-10-4/ ++ FILE:=$(QCA9984_FIRMWARE_FILE_CT) ++ MD5SUM:=747cc1394f15aef97b5ea15e4c208e58 ++endef ++$(eval $(call Download,ath10k-firmware-qca9984-ct)) + define Package/ath10k-firmware-qca99x0 $(Package/ath10k-firmware-default) @@ -88,6 +96,14 @@ index b03d644..170a6c9 100644 +one. +endef + ++define Package/ath10k-firmware-qca9984-ct/description ++Alternative ath10k firmware for QCA9984 from Candela Technologies. ++Enables IBSS and other features. See: ++http://www.candelatech.com/ath10k-10.4-9984.php ++This firmware conflicts with the standard 9984 firmware, so select only ++one. ++endef ++ +define Package/ath10k-firmware-qca99x0/description +Standard ath10k firmware for QCA99x0 from QCA +This firmware conflicts with the CT 99x0 firmware, so select only @@ -99,6 +115,11 @@ index b03d644..170a6c9 100644 + TITLE:=ath10k CT 10.4.3 firmware for QCA99x0 devices +endef + ++define Package/ath10k-firmware-qca9984-ct ++$(Package/ath10k-firmware-default) ++ TITLE:=ath10k CT 10.4.3 firmware for QCA9984 devices ++endef ++ +define Package/ath10k-firmware-qca9984 +$(Package/ath10k-firmware-default) + TITLE:=ath10k firmware for QCA9984 devices @@ -107,7 +128,7 @@ index b03d644..170a6c9 100644 define Package/ath10k-firmware-qca6174 $(Package/ath10k-firmware-default) TITLE:=ath10k firmware for QCA6174 devices -@@ -58,8 +114,8 @@ QCA99X0_BOARD_REV:=ddcec9efd245da9365c474f513a855a55f3ac7fe +@@ -58,8 +135,8 @@ QCA99X0_BOARD_REV:=ddcec9efd245da9365c474f513a855a55f3ac7fe QCA99X0_BOARD_FILE:=board-2.bin.$(QCA99X0_BOARD_REV) define Download/qca99x0-board @@ -118,7 +139,7 @@ index b03d644..170a6c9 100644 FILE:=$(QCA99X0_BOARD_FILE) MD5SUM:=a2b3c653c2363a5641200051d6333d0a endef -@@ -79,6 +135,16 @@ define Package/ath10k-firmware-qca988x/install +@@ -79,6 +156,16 @@ define Package/ath10k-firmware-qca988x/install $(1)/lib/firmware/ath10k/QCA988X/hw2.0/firmware-5.bin endef @@ -135,7 +156,7 @@ index b03d644..170a6c9 100644 define Package/ath10k-firmware-qca6174/install $(INSTALL_DIR) $(1)/lib/firmware/ath10k $(CP) $(PKG_BUILD_DIR)/QCA6174 $(1)/lib/firmware/ath10k/ -@@ -97,6 +163,36 @@ define Package/ath10k-firmware-qca99x0/install +@@ -97,6 +184,50 @@ define Package/ath10k-firmware-qca99x0/install $(1)/lib/firmware/ath10k/QCA99X0/hw2.0/firmware-5.bin endef @@ -164,6 +185,19 @@ index b03d644..170a6c9 100644 + $(PKG_BUILD_DIR)/QCA9984/hw1.0/firmware-5.bin_10.4-3.2-00072 \ + $(1)/lib/firmware/ath10k/QCA9984/hw1.0/firmware-5.bin +endef ++ ++define Package/ath10k-firmware-qca9984-ct/install ++ $(INSTALL_DIR) $(1)/lib/firmware/ath10k/QCA9984/hw1.0 ++ ln -s \ ++ ../../cal-pci-0000:01:00.0.bin \ ++ $(1)/lib/firmware/ath10k/QCA9984/hw1.0/board.bin ++ $(INSTALL_DATA) \ ++ $(PKG_BUILD_DIR)/QCA9984/hw1.0/board-2.bin \ ++ $(1)/lib/firmware/ath10k/QCA9984/hw1.0/board-2.bin ++ $(INSTALL_DATA) \ ++ $(DL_DIR)/$(QCA9984_FIRMWARE_FILE_CT) \ ++ $(1)/lib/firmware/ath10k/QCA9984/hw1.0/firmware-5.bin ++endef + $(eval $(call BuildPackage,ath10k-firmware-qca988x)) $(eval $(call BuildPackage,ath10k-firmware-qca99x0)) @@ -172,6 +206,7 @@ index b03d644..170a6c9 100644 + +$(eval $(call BuildPackage,ath10k-firmware-qca988x-ct)) +$(eval $(call BuildPackage,ath10k-firmware-qca99x0-ct)) ++$(eval $(call BuildPackage,ath10k-firmware-qca9984-ct)) diff --git a/package/firmware/linux-firmware/Makefile b/package/firmware/linux-firmware/Makefile index 2fcd93b..7a2e977 100644 --- a/package/firmware/linux-firmware/Makefile @@ -531,14 +566,14 @@ index 0000000..94d6135 + diff --git a/package/kernel/ath10k-ct/Makefile b/package/kernel/ath10k-ct/Makefile new file mode 100644 -index 0000000..adda03c +index 0000000..7a025aa --- /dev/null +++ b/package/kernel/ath10k-ct/Makefile @@ -0,0 +1,80 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ath10k-ct -+PKG_VERSION:=2016-07-09 ++PKG_VERSION:=2016-07-21 +PKG_RELEASE=1 + +PKG_LICENSE:=GPLv2 @@ -547,7 +582,7 @@ index 0000000..adda03c +PKG_SOURCE_URL:=https://github.com/greearb/ath10k-ct.git +PKG_SOURCE_PROTO:=git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) -+PKG_SOURCE_VERSION:=0241aa1d2797ef564bf36fa67888e62289d71e8f ++PKG_SOURCE_VERSION:=a142524abc8eef3ba30b12f9b5ac74385c8ddc39 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION)-$(PKG_SOURCE_VERSION).tar.xz + +PKG_MAINTAINER:=Ben Greear @@ -5190,883 +5225,6 @@ 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-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..f8b8f86 ---- /dev/null -+++ 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 -+ -+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,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 -+@@ -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 */ -+ } -+ } -+ 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 @@ -8706,6 +7864,702 @@ 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