[openwrt/openwrt] mac80211: Update to version 5.14.13-1

LEDE Commits lede-commits at lists.infradead.org
Sat Oct 23 15:59:09 PDT 2021


hauke pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/cfe0eb7485d82dd3acf2ba2b95a31e63557d59bd

commit cfe0eb7485d82dd3acf2ba2b95a31e63557d59bd
Author: Hauke Mehrtens <hauke at hauke-m.de>
AuthorDate: Sun Oct 10 21:24:14 2021 +0200

    mac80211: Update to version 5.14.13-1
    
    The removed patches were applied upstream.
    
    Signed-off-by: Hauke Mehrtens <hauke at hauke-m.de>
---
 package/kernel/mac80211/Makefile                   |    6 +-
 .../862-brcmfmac-Disable-power-management.patch    |    2 +-
 ...c-add-in-driver-tables-with-country-codes.patch |   12 +-
 .../kernel/mac80211/patches/brcm/998-survey.patch  |   10 +-
 .../patches/subsys/150-disable_addr_notifier.patch |    6 +-
 .../mac80211/patches/subsys/210-ap_scan.patch      |    2 +-
 ...mac80211_hwsim-make-6-GHz-channels-usable.patch |    8 +-
 ...nstrel_ht-rework-rate-downgrade-code-and-.patch |    4 +-
 ...ve-A-MPDU-session-check-from-minstrel_ht-.patch |  126 --
 ...all-ieee80211_tx_h_rate_ctrl-when-dequeue.patch |  114 --
 ...dd-rate-control-support-for-encap-offload.patch |  126 --
 ...x-starting-aggregation-sessions-on-mesh-i.patch |  112 --
 ...rearrange-struct-txq_info-for-fewer-holes.patch |   39 -
 ...itch-to-a-virtual-time-based-airtime-sche.patch | 1277 --------------------
 ...11-check-per-vif-offload_flags-in-Tx-path.patch |   26 -
 .../387-nl80211-add-support-for-BSS-coloring.patch |   24 +-
 ...mac80211-add-support-for-BSS-color-change.patch |   30 +-
 ...389-ieee80211-add-TWT-element-definitions.patch |    6 +-
 ...troduce-individual-TWT-support-in-AP-mode.patch |   82 +-
 .../patches/subsys/400-allow-ibss-mixed.patch      |    2 +-
 .../500-mac80211_configure_antenna_gain.patch      |   14 +-
 .../utils/iw/patches/001-nl80211_h_sync.patch      |   42 +-
 22 files changed, 154 insertions(+), 1916 deletions(-)

diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile
index b3a8960fe8..1fc9dc4c48 100644
--- a/package/kernel/mac80211/Makefile
+++ b/package/kernel/mac80211/Makefile
@@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
 
 PKG_NAME:=mac80211
 
-PKG_VERSION:=5.13.19-1
+PKG_VERSION:=5.14.13-1
 PKG_RELEASE:=1
-PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.13.19/
-PKG_HASH:=1eb761c1664d59a0a2d52847f240c9d02fc2e56fb27d862d2949bfb275187eef
+PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.14.13/
+PKG_HASH:=042aef20caf17ef649502d5f2e744a7676abe7faed18de83c96f37bc029635fe
 
 PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
 PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
diff --git a/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch b/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch
index 774656f1fd..2e22ec793b 100644
--- a/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch
+++ b/package/kernel/mac80211/patches/brcm/862-brcmfmac-Disable-power-management.patch
@@ -14,7 +14,7 @@ Signed-off-by: Phil Elwell <phil at raspberrypi.org>
 
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
-@@ -2961,6 +2961,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
+@@ -2966,6 +2966,10 @@ brcmf_cfg80211_set_power_mgmt(struct wip
  	 * preference in cfg struct to apply this to
  	 * FW later while initializing the dongle
  	 */
diff --git a/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch b/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch
index 9658bda1c1..835c870a65 100644
--- a/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch
+++ b/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch
@@ -12,9 +12,9 @@ Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
 
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
-@@ -12,6 +12,36 @@
- #include "common.h"
- #include "of.h"
+@@ -58,6 +58,36 @@ static int brcmf_of_get_country_codes(st
+ 	return 0;
+ }
  
 +/* TODO: FIXME: Use DT */
 +static void brcmf_of_probe_cc(struct device *dev,
@@ -49,12 +49,12 @@ Signed-off-by: Rafał Miłecki <rafal at milecki.pl>
  void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
  		    struct brcmf_mp_device *settings)
  {
-@@ -43,6 +73,8 @@ void brcmf_of_probe(struct device *dev,
+@@ -90,6 +120,8 @@ void brcmf_of_probe(struct device *dev,
  		of_node_put(root);
  	}
  
 +	brcmf_of_probe_cc(dev, settings);
 +
- 	if (!np || bus_type != BRCMF_BUSTYPE_SDIO ||
- 	    !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
+ 	if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
  		return;
+ 
diff --git a/package/kernel/mac80211/patches/brcm/998-survey.patch b/package/kernel/mac80211/patches/brcm/998-survey.patch
index 2c11ed696d..1479c67156 100644
--- a/package/kernel/mac80211/patches/brcm/998-survey.patch
+++ b/package/kernel/mac80211/patches/brcm/998-survey.patch
@@ -64,7 +64,7 @@
  brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev,
  			    int idx, u8 *mac, struct station_info *sinfo)
  {
-@@ -3008,6 +3065,7 @@ static s32 brcmf_inform_single_bss(struc
+@@ -3013,6 +3070,7 @@ static s32 brcmf_inform_single_bss(struc
  	struct brcmu_chan ch;
  	u16 channel;
  	u32 freq;
@@ -72,7 +72,7 @@
  	u16 notify_capability;
  	u16 notify_interval;
  	u8 *notify_ie;
-@@ -3032,6 +3090,17 @@ static s32 brcmf_inform_single_bss(struc
+@@ -3037,6 +3095,17 @@ static s32 brcmf_inform_single_bss(struc
  		band = NL80211_BAND_5GHZ;
  
  	freq = ieee80211_channel_to_frequency(channel, band);
@@ -90,7 +90,7 @@
  	bss_data.chan = ieee80211_get_channel(wiphy, freq);
  	bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20;
  	bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime());
-@@ -5560,6 +5629,7 @@ static struct cfg80211_ops brcmf_cfg8021
+@@ -5565,6 +5634,7 @@ static struct cfg80211_ops brcmf_cfg8021
  	.leave_ibss = brcmf_cfg80211_leave_ibss,
  	.get_station = brcmf_cfg80211_get_station,
  	.dump_station = brcmf_cfg80211_dump_station,
@@ -100,7 +100,7 @@
  	.add_key = brcmf_cfg80211_add_key,
 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
 +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
-@@ -1356,6 +1356,8 @@ int brcmf_attach(struct device *dev)
+@@ -1361,6 +1361,8 @@ int brcmf_attach(struct device *dev)
  
  	/* Link to bus module */
  	drvr->hdrlen = 0;
@@ -109,7 +109,7 @@
  
  	/* Attach and link in the protocol */
  	ret = brcmf_proto_attach(drvr);
-@@ -1438,6 +1440,12 @@ void brcmf_detach(struct device *dev)
+@@ -1443,6 +1445,12 @@ void brcmf_detach(struct device *dev)
  	if (drvr == NULL)
  		return;
  
diff --git a/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch b/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch
index 0cd1cfdd31..e93efa4429 100644
--- a/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch
+++ b/package/kernel/mac80211/patches/subsys/150-disable_addr_notifier.patch
@@ -18,7 +18,7 @@
  static int ieee80211_ifa6_changed(struct notifier_block *nb,
  				  unsigned long data, void *arg)
  {
-@@ -1319,14 +1319,14 @@ int ieee80211_register_hw(struct ieee802
+@@ -1324,14 +1324,14 @@ int ieee80211_register_hw(struct ieee802
  	wiphy_unlock(hw->wiphy);
  	rtnl_unlock();
  
@@ -35,7 +35,7 @@
  	local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed;
  	result = register_inet6addr_notifier(&local->ifa6_notifier);
  	if (result)
-@@ -1335,13 +1335,13 @@ int ieee80211_register_hw(struct ieee802
+@@ -1340,13 +1340,13 @@ int ieee80211_register_hw(struct ieee802
  
  	return 0;
  
@@ -52,7 +52,7 @@
   fail_ifa:
  #endif
  	wiphy_unregister(local->hw.wiphy);
-@@ -1369,10 +1369,10 @@ void ieee80211_unregister_hw(struct ieee
+@@ -1374,10 +1374,10 @@ void ieee80211_unregister_hw(struct ieee
  	tasklet_kill(&local->tx_pending_tasklet);
  	tasklet_kill(&local->tasklet);
  
diff --git a/package/kernel/mac80211/patches/subsys/210-ap_scan.patch b/package/kernel/mac80211/patches/subsys/210-ap_scan.patch
index 708cf7b0d5..1efa336d0c 100644
--- a/package/kernel/mac80211/patches/subsys/210-ap_scan.patch
+++ b/package/kernel/mac80211/patches/subsys/210-ap_scan.patch
@@ -1,6 +1,6 @@
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -2462,7 +2462,7 @@ static int ieee80211_scan(struct wiphy *
+@@ -2487,7 +2487,7 @@ static int ieee80211_scan(struct wiphy *
  		 * the  frames sent while scanning on other channel will be
  		 * lost)
  		 */
diff --git a/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch b/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch
index c21d4446ab..9c7417e5fc 100644
--- a/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch
+++ b/package/kernel/mac80211/patches/subsys/321-mac80211_hwsim-make-6-GHz-channels-usable.patch
@@ -11,7 +11,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
 
 --- a/drivers/net/wireless/mac80211_hwsim.c
 +++ b/drivers/net/wireless/mac80211_hwsim.c
-@@ -2990,15 +2990,19 @@ static void mac80211_hwsim_he_capab(stru
+@@ -2992,15 +2992,19 @@ static void mac80211_hwsim_he_capab(stru
  {
  	u16 n_iftype_data;
  
@@ -34,7 +34,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
  		return;
  	}
  
-@@ -3288,6 +3292,12 @@ static int mac80211_hwsim_new_radio(stru
+@@ -3290,6 +3294,12 @@ static int mac80211_hwsim_new_radio(stru
  			sband->vht_cap.vht_mcs.tx_mcs_map =
  				sband->vht_cap.vht_mcs.rx_mcs_map;
  			break;
@@ -47,7 +47,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
  		case NL80211_BAND_S1GHZ:
  			memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
  			       sizeof(sband->s1g_cap));
-@@ -3298,6 +3308,13 @@ static int mac80211_hwsim_new_radio(stru
+@@ -3300,6 +3310,13 @@ static int mac80211_hwsim_new_radio(stru
  			continue;
  		}
  
@@ -61,7 +61,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
  		sband->ht_cap.ht_supported = true;
  		sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
  				    IEEE80211_HT_CAP_GRN_FLD |
-@@ -3311,10 +3328,6 @@ static int mac80211_hwsim_new_radio(stru
+@@ -3313,10 +3330,6 @@ static int mac80211_hwsim_new_radio(stru
  		sband->ht_cap.mcs.rx_mask[0] = 0xff;
  		sband->ht_cap.mcs.rx_mask[1] = 0xff;
  		sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
diff --git a/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch b/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
index 7cbc8c01d0..a6817bd4a6 100644
--- a/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
+++ b/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
@@ -117,7 +117,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
  	}
  }
  
-@@ -1206,7 +1169,7 @@ minstrel_ht_tx_status(void *priv, struct
+@@ -1183,7 +1146,7 @@ minstrel_ht_tx_status(void *priv, struct
  	struct ieee80211_tx_info *info = st->info;
  	struct minstrel_ht_sta *mi = priv_sta;
  	struct ieee80211_tx_rate *ar = info->status.rates;
@@ -126,7 +126,7 @@ Signed-off-by: Felix Fietkau <nbd at nbd.name>
  	struct minstrel_priv *mp = priv;
  	u32 update_interval = mp->update_interval;
  	bool last, update = false;
-@@ -1252,18 +1215,13 @@ minstrel_ht_tx_status(void *priv, struct
+@@ -1233,18 +1196,13 @@ minstrel_ht_tx_status(void *priv, struct
  		/*
  		 * check for sudden death of spatial multiplexing,
  		 * downgrade to a lower number of streams if necessary.
diff --git a/package/kernel/mac80211/patches/subsys/374-mac80211-move-A-MPDU-session-check-from-minstrel_ht-.patch b/package/kernel/mac80211/patches/subsys/374-mac80211-move-A-MPDU-session-check-from-minstrel_ht-.patch
deleted file mode 100644
index dc511880e5..0000000000
--- a/package/kernel/mac80211/patches/subsys/374-mac80211-move-A-MPDU-session-check-from-minstrel_ht-.patch
+++ /dev/null
@@ -1,126 +0,0 @@
-From: Felix Fietkau <nbd at nbd.name>
-Date: Thu, 17 Jun 2021 17:56:54 +0200
-Subject: [PATCH] mac80211: move A-MPDU session check from minstrel_ht to
- mac80211
-
-This avoids calling back into tx handlers from within the rate control module.
-Preparation for deferring rate control until tx dequeue
-
-Signed-off-by: Felix Fietkau <nbd at nbd.name>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -6192,6 +6192,11 @@ enum rate_control_capabilities {
- 	 * otherwise the NSS difference doesn't bother us.
- 	 */
- 	RATE_CTRL_CAPA_VHT_EXT_NSS_BW = BIT(0),
-+	/**
-+	 * @RATE_CTRL_CAPA_AMPDU_TRIGGER:
-+	 * mac80211 should start A-MPDU sessions on tx
-+	 */
-+	RATE_CTRL_CAPA_AMPDU_TRIGGER = BIT(1),
- };
- 
- struct rate_control_ops {
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -1140,29 +1140,6 @@ minstrel_downgrade_prob_rate(struct mins
- }
- 
- static void
--minstrel_aggr_check(struct ieee80211_sta *pubsta, struct sk_buff *skb)
--{
--	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
--	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
--	u16 tid;
--
--	if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
--		return;
--
--	if (unlikely(!ieee80211_is_data_qos(hdr->frame_control)))
--		return;
--
--	if (unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE)))
--		return;
--
--	tid = ieee80211_get_tid(hdr);
--	if (likely(sta->ampdu_mlme.tid_tx[tid]))
--		return;
--
--	ieee80211_start_tx_ba_session(pubsta, tid, 0);
--}
--
--static void
- minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband,
-                       void *priv_sta, struct ieee80211_tx_status *st)
- {
-@@ -1457,10 +1434,6 @@ minstrel_ht_get_rate(void *priv, struct
- 	struct minstrel_priv *mp = priv;
- 	u16 sample_idx;
- 
--	if (!(info->flags & IEEE80211_TX_CTL_AMPDU) &&
--	    !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate)))
--		minstrel_aggr_check(sta, txrc->skb);
--
- 	info->flags |= mi->tx_flags;
- 
- #ifdef CPTCFG_MAC80211_DEBUGFS
-@@ -1866,6 +1839,7 @@ static u32 minstrel_ht_get_expected_thro
- 
- static const struct rate_control_ops mac80211_minstrel_ht = {
- 	.name = "minstrel_ht",
-+	.capa = RATE_CTRL_CAPA_AMPDU_TRIGGER,
- 	.tx_status_ext = minstrel_ht_tx_status,
- 	.get_rate = minstrel_ht_get_rate,
- 	.rate_init = minstrel_ht_rate_init,
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3951,6 +3951,29 @@ void ieee80211_txq_schedule_start(struct
- }
- EXPORT_SYMBOL(ieee80211_txq_schedule_start);
- 
-+static void
-+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
-+		     struct sta_info *sta,
-+		     struct sk_buff *skb)
-+{
-+	struct rate_control_ref *ref = sdata->local->rate_ctrl;
-+	u16 tid;
-+
-+	if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
-+		return;
-+
-+	if (!sta || !sta->sta.ht_cap.ht_supported ||
-+	    !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
-+	    skb->protocol == sdata->control_port_protocol)
-+		return;
-+
-+	tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
-+	if (likely(sta->ampdu_mlme.tid_tx[tid]))
-+		return;
-+
-+	ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
-+}
-+
- void __ieee80211_subif_start_xmit(struct sk_buff *skb,
- 				  struct net_device *dev,
- 				  u32 info_flags,
-@@ -3981,6 +4004,8 @@ void __ieee80211_subif_start_xmit(struct
- 		skb_get_hash(skb);
- 	}
- 
-+	ieee80211_aggr_check(sdata, sta, skb);
-+
- 	if (sta) {
- 		struct ieee80211_fast_tx *fast_tx;
- 
-@@ -4244,6 +4269,8 @@ static void ieee80211_8023_xmit(struct i
- 
- 	memset(info, 0, sizeof(*info));
- 
-+	ieee80211_aggr_check(sdata, sta, skb);
-+
- 	tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- 	tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
- 	if (tid_tx) {
diff --git a/package/kernel/mac80211/patches/subsys/375-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch b/package/kernel/mac80211/patches/subsys/375-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch
deleted file mode 100644
index 346c6468f8..0000000000
--- a/package/kernel/mac80211/patches/subsys/375-mac80211-call-ieee80211_tx_h_rate_ctrl-when-dequeue.patch
+++ /dev/null
@@ -1,114 +0,0 @@
-From: Ryder Lee <ryder.lee at mediatek.com>
-Date: Fri, 28 May 2021 14:05:41 +0800
-Subject: [PATCH] mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue
-
-Make ieee80211_tx_h_rate_ctrl() get called on dequeue to improve
-performance since it reduces the turnaround time for rate control.
-
-Signed-off-by: Ryder Lee <ryder.lee at mediatek.com>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1768,8 +1768,6 @@ static int invoke_tx_handlers_early(stru
- 	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)) {
-@@ -1802,6 +1800,9 @@ static int invoke_tx_handlers_late(struc
- 		goto txh_done;
- 	}
- 
-+	if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
-+		CALL_TXH(ieee80211_tx_h_rate_ctrl);
-+
- 	CALL_TXH(ieee80211_tx_h_michael_mic_add);
- 	CALL_TXH(ieee80211_tx_h_sequence);
- 	CALL_TXH(ieee80211_tx_h_fragment);
-@@ -3391,15 +3392,21 @@ out:
-  * Can be called while the sta lock is held. Anything that can cause packets to
-  * be generated will cause deadlock!
-  */
--static void ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
--				       struct sta_info *sta, u8 pn_offs,
--				       struct ieee80211_key *key,
--				       struct sk_buff *skb)
-+static ieee80211_tx_result
-+ieee80211_xmit_fast_finish(struct ieee80211_sub_if_data *sdata,
-+			   struct sta_info *sta, u8 pn_offs,
-+			   struct ieee80211_key *key,
-+			   struct ieee80211_tx_data *tx)
- {
-+	struct sk_buff *skb = tx->skb;
- 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- 	struct ieee80211_hdr *hdr = (void *)skb->data;
- 	u8 tid = IEEE80211_NUM_TIDS;
- 
-+	if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL) &&
-+	    ieee80211_tx_h_rate_ctrl(tx) != TX_CONTINUE)
-+		return TX_DROP;
-+
- 	if (key)
- 		info->control.hw_key = &key->conf;
- 
-@@ -3448,6 +3455,8 @@ static void ieee80211_xmit_fast_finish(s
- 			break;
- 		}
- 	}
-+
-+	return TX_CONTINUE;
- }
- 
- static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
-@@ -3551,24 +3560,17 @@ static bool ieee80211_xmit_fast(struct i
- 	tx.sta = sta;
- 	tx.key = fast_tx->key;
- 
--	if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
--		tx.skb = skb;
--		r = ieee80211_tx_h_rate_ctrl(&tx);
--		skb = tx.skb;
--		tx.skb = NULL;
--
--		if (r != TX_CONTINUE) {
--			if (r != TX_QUEUED)
--				kfree_skb(skb);
--			return true;
--		}
--	}
--
- 	if (ieee80211_queue_skb(local, sdata, sta, skb))
- 		return true;
- 
--	ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
--				   fast_tx->key, skb);
-+	tx.skb = skb;
-+	r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
-+				       fast_tx->key, &tx);
-+	tx.skb = NULL;
-+	if (r == TX_DROP) {
-+		kfree_skb(skb);
-+		return true;
-+	}
- 
- 	if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- 		sdata = container_of(sdata->bss,
-@@ -3685,8 +3687,12 @@ begin:
- 		    (tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
- 			pn_offs = ieee80211_hdrlen(hdr->frame_control);
- 
--		ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
--					   tx.key, skb);
-+		r = ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
-+					       tx.key, &tx);
-+		if (r != TX_CONTINUE) {
-+			ieee80211_free_txskb(&local->hw, skb);
-+			goto begin;
-+		}
- 	} else {
- 		if (invoke_tx_handlers_late(&tx))
- 			goto begin;
diff --git a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch b/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch
deleted file mode 100644
index b9f34213d5..0000000000
--- a/package/kernel/mac80211/patches/subsys/376-mac80211-add-rate-control-support-for-encap-offload.patch
+++ /dev/null
@@ -1,126 +0,0 @@
-From: Ryder Lee <ryder.lee at mediatek.com>
-Date: Fri, 28 May 2021 14:05:43 +0800
-Subject: [PATCH] mac80211: add rate control support for encap offload
-
-The software rate control cannot deal with encap offload, so fix it.
-
-Signed-off-by: Ryder Lee <ryder.lee at mediatek.com>
----
-
---- a/net/mac80211/rate.c
-+++ b/net/mac80211/rate.c
-@@ -297,15 +297,11 @@ void ieee80211_check_rate_mask(struct ie
- static bool rc_no_data_or_no_ack_use_min(struct ieee80211_tx_rate_control *txrc)
- {
- 	struct sk_buff *skb = txrc->skb;
--	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
--	__le16 fc;
--
--	fc = hdr->frame_control;
- 
- 	return (info->flags & (IEEE80211_TX_CTL_NO_ACK |
- 			       IEEE80211_TX_CTL_USE_MINRATE)) ||
--		!ieee80211_is_data(fc);
-+		!ieee80211_is_tx_data(skb);
- }
- 
- static void rc_send_low_basicrate(struct ieee80211_tx_rate *rate,
-@@ -870,7 +866,6 @@ void ieee80211_get_tx_rates(struct ieee8
- 			    int max_rates)
- {
- 	struct ieee80211_sub_if_data *sdata;
--	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
- 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- 	struct ieee80211_supported_band *sband;
- 
-@@ -882,7 +877,7 @@ void ieee80211_get_tx_rates(struct ieee8
- 	sdata = vif_to_sdata(vif);
- 	sband = sdata->local->hw.wiphy->bands[info->band];
- 
--	if (ieee80211_is_data(hdr->frame_control))
-+	if (ieee80211_is_tx_data(skb))
- 		rate_control_apply_mask(sdata, sta, sband, dest, max_rates);
- 
- 	if (dest[0].idx < 0)
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -666,6 +666,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
- 	u32 len;
- 	struct ieee80211_tx_rate_control txrc;
- 	struct ieee80211_sta_rates *ratetbl = NULL;
-+	bool encap = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
- 	bool assoc = false;
- 
- 	memset(&txrc, 0, sizeof(txrc));
-@@ -707,7 +708,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
- 	 * just wants a probe response.
- 	 */
- 	if (tx->sdata->vif.bss_conf.use_short_preamble &&
--	    (ieee80211_is_data(hdr->frame_control) ||
-+	    (ieee80211_is_tx_data(tx->skb) ||
- 	     (tx->sta && test_sta_flag(tx->sta, WLAN_STA_SHORT_PREAMBLE))))
- 		txrc.short_preamble = true;
- 
-@@ -729,7 +730,8 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
- 		 "%s: Dropped data frame as no usable bitrate found while "
- 		 "scanning and associated. Target station: "
- 		 "%pM on %d GHz band\n",
--		 tx->sdata->name, hdr->addr1,
-+		 tx->sdata->name,
-+		 encap ? ((struct ethhdr *)hdr)->h_dest : hdr->addr1,
- 		 info->band ? 5 : 2))
- 		return TX_DROP;
- 
-@@ -763,7 +765,7 @@ ieee80211_tx_h_rate_ctrl(struct ieee8021
- 
- 	if (txrc.reported_rate.idx < 0) {
- 		txrc.reported_rate = tx->rate;
--		if (tx->sta && ieee80211_is_data(hdr->frame_control))
-+		if (tx->sta && ieee80211_is_tx_data(tx->skb))
- 			tx->sta->tx_stats.last_rate = txrc.reported_rate;
- 	} else if (tx->sta)
- 		tx->sta->tx_stats.last_rate = txrc.reported_rate;
-@@ -3675,8 +3677,16 @@ begin:
- 	else
- 		info->flags &= ~IEEE80211_TX_CTL_AMPDU;
- 
--	if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
-+	if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
-+		if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
-+			r = ieee80211_tx_h_rate_ctrl(&tx);
-+			if (r != TX_CONTINUE) {
-+				ieee80211_free_txskb(&local->hw, skb);
-+				goto begin;
-+			}
-+		}
- 		goto encap_out;
-+	}
- 
- 	if (info->control.flags & IEEE80211_TX_CTRL_FAST_XMIT) {
- 		struct sta_info *sta = container_of(txq->sta, struct sta_info,
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -6765,4 +6765,22 @@ struct sk_buff *ieee80211_get_fils_disco
- struct sk_buff *
- ieee80211_get_unsol_bcast_probe_resp_tmpl(struct ieee80211_hw *hw,
- 					  struct ieee80211_vif *vif);
-+
-+/**
-+ * ieee80211_is_tx_data - check if frame is a data frame
-+ *
-+ * The function is used to check if a frame is a data frame. Frames with
-+ * hardware encapsulation enabled are data frames.
-+ *
-+ * @skb: the frame to be transmitted.
-+ */
-+static inline bool ieee80211_is_tx_data(struct sk_buff *skb)
-+{
-+	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+	struct ieee80211_hdr *hdr = (void *) skb->data;
-+
-+	return info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP ||
-+	       ieee80211_is_data(hdr->frame_control);
-+}
-+
- #endif /* MAC80211_H */
diff --git a/package/kernel/mac80211/patches/subsys/379-mac80211-fix-starting-aggregation-sessions-on-mesh-i.patch b/package/kernel/mac80211/patches/subsys/379-mac80211-fix-starting-aggregation-sessions-on-mesh-i.patch
deleted file mode 100644
index 74947348bc..0000000000
--- a/package/kernel/mac80211/patches/subsys/379-mac80211-fix-starting-aggregation-sessions-on-mesh-i.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From: Felix Fietkau <nbd at nbd.name>
-Date: Tue, 29 Jun 2021 13:25:09 +0200
-Subject: [PATCH] mac80211: fix starting aggregation sessions on mesh
- interfaces
-
-The logic for starting aggregation sessions was recently moved from minstrel_ht
-to mac80211, into the subif tx handler just after the sta lookup.
-Unfortunately this didn't work for mesh interfaces, since the sta lookup is
-deferred until a much later point in time on those.
-Fix this by also calling the aggregation check right after the deferred sta
-lookup.
-
-Fixes: 08a46c642001 ("mac80211: move A-MPDU session check from minstrel_ht to mac80211")
-Signed-off-by: Felix Fietkau <nbd at nbd.name>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1146,6 +1146,29 @@ static bool ieee80211_tx_prep_agg(struct
- 	return queued;
- }
- 
-+static void
-+ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
-+		     struct sta_info *sta,
-+		     struct sk_buff *skb)
-+{
-+	struct rate_control_ref *ref = sdata->local->rate_ctrl;
-+	u16 tid;
-+
-+	if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
-+		return;
-+
-+	if (!sta || !sta->sta.ht_cap.ht_supported ||
-+	    !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
-+	    skb->protocol == sdata->control_port_protocol)
-+		return;
-+
-+	tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
-+	if (likely(sta->ampdu_mlme.tid_tx[tid]))
-+		return;
-+
-+	ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
-+}
-+
- /*
-  * initialises @tx
-  * pass %NULL for the station if unknown, a valid pointer if known
-@@ -1159,6 +1182,7 @@ ieee80211_tx_prepare(struct ieee80211_su
- 	struct ieee80211_local *local = sdata->local;
- 	struct ieee80211_hdr *hdr;
- 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-+	bool aggr_check = false;
- 	int tid;
- 
- 	memset(tx, 0, sizeof(*tx));
-@@ -1187,8 +1211,10 @@ ieee80211_tx_prepare(struct ieee80211_su
- 		} else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
- 			tx->sta = sta_info_get_bss(sdata, hdr->addr1);
- 		}
--		if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
-+		if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) {
- 			tx->sta = sta_info_get(sdata, hdr->addr1);
-+			aggr_check = true;
-+		}
- 	}
- 
- 	if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
-@@ -1198,8 +1224,12 @@ ieee80211_tx_prepare(struct ieee80211_su
- 		struct tid_ampdu_tx *tid_tx;
- 
- 		tid = ieee80211_get_tid(hdr);
--
- 		tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
-+		if (!tid_tx && aggr_check) {
-+			ieee80211_aggr_check(sdata, tx->sta, skb);
-+			tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
-+		}
-+
- 		if (tid_tx) {
- 			bool queued;
- 
-@@ -3967,29 +3997,6 @@ void ieee80211_txq_schedule_start(struct
- }
- EXPORT_SYMBOL(ieee80211_txq_schedule_start);
- 
--static void
--ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
--		     struct sta_info *sta,
--		     struct sk_buff *skb)
--{
--	struct rate_control_ref *ref = sdata->local->rate_ctrl;
--	u16 tid;
--
--	if (!ref || !(ref->ops->capa & RATE_CTRL_CAPA_AMPDU_TRIGGER))
--		return;
--
--	if (!sta || !sta->sta.ht_cap.ht_supported ||
--	    !sta->sta.wme || skb_get_queue_mapping(skb) == IEEE80211_AC_VO ||
--	    skb->protocol == sdata->control_port_protocol)
--		return;
--
--	tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
--	if (likely(sta->ampdu_mlme.tid_tx[tid]))
--		return;
--
--	ieee80211_start_tx_ba_session(&sta->sta, tid, 0);
--}
--
- void __ieee80211_subif_start_xmit(struct sk_buff *skb,
- 				  struct net_device *dev,
- 				  u32 info_flags,
diff --git a/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch b/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch
deleted file mode 100644
index 6a561b2a08..0000000000
--- a/package/kernel/mac80211/patches/subsys/381-mac80211-rearrange-struct-txq_info-for-fewer-holes.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From: Johannes Berg <johannes.berg at intel.com>
-Date: Fri, 18 Jun 2021 13:41:44 +0300
-Subject: [PATCH] mac80211: rearrange struct txq_info for fewer holes
-
-We can slightly decrease the size of struct txq_info by
-rearranging some fields for fewer holes, so do that.
-
-Signed-off-by: Johannes Berg <johannes.berg at intel.com>
-Signed-off-by: Luca Coelho <luciano.coelho at intel.com>
-Link: https://lore.kernel.org/r/iwlwifi.20210618133832.1bf019a1fe2e.Ib54622b8d6dc1a9a7dc484e573c073119450538b@changeid
-Signed-off-by: Johannes Berg <johannes.berg at intel.com>
----
-
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -5,7 +5,7 @@
-  * Copyright 2006-2007	Jiri Benc <jbenc at suse.cz>
-  * Copyright 2007-2010	Johannes Berg <johannes at sipsolutions.net>
-  * Copyright 2013-2015  Intel Mobile Communications GmbH
-- * Copyright (C) 2018-2020 Intel Corporation
-+ * Copyright (C) 2018-2021 Intel Corporation
-  */
- 
- #ifndef IEEE80211_I_H
-@@ -843,9 +843,12 @@ struct txq_info {
- 	struct fq_tin tin;
- 	struct codel_vars def_cvars;
- 	struct codel_stats cstats;
--	struct sk_buff_head frags;
--	struct list_head schedule_order;
-+
- 	u16 schedule_round;
-+	struct list_head schedule_order;
-+
-+	struct sk_buff_head frags;
-+
- 	unsigned long flags;
- 
- 	/* keep last! */
diff --git a/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch b/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch
deleted file mode 100644
index 49f9349ec8..0000000000
--- a/package/kernel/mac80211/patches/subsys/382-mac80211-Switch-to-a-virtual-time-based-airtime-sche.patch
+++ /dev/null
@@ -1,1277 +0,0 @@
-From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke at redhat.com>
-Date: Wed, 23 Jun 2021 15:47:55 +0200
-Subject: [PATCH] mac80211: Switch to a virtual time-based airtime scheduler
-MIME-Version: 1.0
-Content-Type: text/plain; charset=UTF-8
-Content-Transfer-Encoding: 8bit
-
-This switches the airtime scheduler in mac80211 to use a virtual
-time-based scheduler instead of the round-robin scheduler used before.
-This has a couple of advantages:
-
-- No need to sync up the round-robin scheduler in firmware/hardware with
-  the round-robin airtime scheduler.
-
-- If several stations are eligible for transmission we can schedule both
-  of them; no need to hard-block the scheduling rotation until the head
-  of the queue has used up its quantum.
-
-- The check of whether a station is eligible for transmission becomes
-  simpler (in ieee80211_txq_may_transmit()).
-
-The drawback is that scheduling becomes slightly more expensive, as we
-need to maintain an rbtree of TXQs sorted by virtual time. This means
-that ieee80211_register_airtime() becomes O(logN) in the number of
-currently scheduled TXQs because it can change the order of the
-scheduled stations. We mitigate this overhead by only resorting when a
-station changes position in the tree, and hopefully N rarely grows too
-big (it's only TXQs currently backlogged, not all associated stations),
-so it shouldn't be too big of an issue.
-
-To prevent divisions in the fast path, we maintain both station sums and
-pre-computed reciprocals of the sums. This turns the fast-path operation
-into a multiplication, with divisions only happening as the number of
-active stations change (to re-compute the current sum of all active
-station weights). To prevent this re-computation of the reciprocal from
-happening too frequently, we use a time-based notion of station
-activity, instead of updating the weight every time a station gets
-scheduled or de-scheduled. As queues can oscillate between empty and
-occupied quite frequently, this can significantly cut down on the number
-of re-computations. It also has the added benefit of making the station
-airtime calculation independent on whether the queue happened to have
-drained at the time an airtime value was accounted.
-
-Co-developed-by: Yibo Zhao <yiboz at codeaurora.org>
-Signed-off-by: Yibo Zhao <yiboz at codeaurora.org>
-Signed-off-by: Toke Høiland-Jørgensen <toke at redhat.com>
-Link: https://lore.kernel.org/r/20210623134755.235545-1-toke@redhat.com
-Signed-off-by: Johannes Berg <johannes.berg at intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -6589,9 +6589,6 @@ static inline void ieee80211_txq_schedul
- {
- }
- 
--void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
--			      struct ieee80211_txq *txq, bool force);
--
- /**
-  * ieee80211_schedule_txq - schedule a TXQ for transmission
-  *
-@@ -6604,11 +6601,7 @@ void __ieee80211_schedule_txq(struct iee
-  * The driver may call this function if it has buffered packets for
-  * this TXQ internally.
-  */
--static inline void
--ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
--{
--	__ieee80211_schedule_txq(hw, txq, true);
--}
-+void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
- 
- /**
-  * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
-@@ -6620,12 +6613,8 @@ ieee80211_schedule_txq(struct ieee80211_
-  * The driver may set force=true if it has buffered packets for this TXQ
-  * internally.
-  */
--static inline void
--ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
--		     bool force)
--{
--	__ieee80211_schedule_txq(hw, txq, force);
--}
-+void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
-+			  bool force);
- 
- /**
-  * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1460,6 +1460,38 @@ static void sta_apply_mesh_params(struct
- #endif
- }
- 
-+static void sta_apply_airtime_params(struct ieee80211_local *local,
-+				     struct sta_info *sta,
-+				     struct station_parameters *params)
-+{
-+	u8 ac;
-+
-+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-+		struct airtime_sched_info *air_sched = &local->airtime[ac];
-+		struct airtime_info *air_info = &sta->airtime[ac];
-+		struct txq_info *txqi;
-+		u8 tid;
-+
-+		spin_lock_bh(&air_sched->lock);
-+		for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
-+			if (air_info->weight == params->airtime_weight ||
-+			    !sta->sta.txq[tid] ||
-+			    ac != ieee80211_ac_from_tid(tid))
-+				continue;
-+
-+			airtime_weight_set(air_info, params->airtime_weight);
-+
-+			txqi = to_txq_info(sta->sta.txq[tid]);
-+			if (RB_EMPTY_NODE(&txqi->schedule_order))
-+				continue;
-+
-+			ieee80211_update_airtime_weight(local, air_sched,
-+							0, true);
-+		}
-+		spin_unlock_bh(&air_sched->lock);
-+	}
-+}
-+
- static int sta_apply_parameters(struct ieee80211_local *local,
- 				struct sta_info *sta,
- 				struct station_parameters *params)
-@@ -1647,7 +1679,8 @@ static int sta_apply_parameters(struct i
- 		sta_apply_mesh_params(local, sta, params);
- 
- 	if (params->airtime_weight)
--		sta->airtime_weight = params->airtime_weight;
-+		sta_apply_airtime_params(local, sta, params);
-+
- 
- 	/* set the STA state after all sta info from usermode has been set */
- 	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
---- a/net/mac80211/debugfs.c
-+++ b/net/mac80211/debugfs.c
-@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct
- 			"VI	%u		%u\n"
- 			"BE	%u		%u\n"
- 			"BK	%u		%u\n",
--			local->aql_txq_limit_low[IEEE80211_AC_VO],
--			local->aql_txq_limit_high[IEEE80211_AC_VO],
--			local->aql_txq_limit_low[IEEE80211_AC_VI],
--			local->aql_txq_limit_high[IEEE80211_AC_VI],
--			local->aql_txq_limit_low[IEEE80211_AC_BE],
--			local->aql_txq_limit_high[IEEE80211_AC_BE],
--			local->aql_txq_limit_low[IEEE80211_AC_BK],
--			local->aql_txq_limit_high[IEEE80211_AC_BK]);
-+			local->airtime[IEEE80211_AC_VO].aql_txq_limit_low,
-+			local->airtime[IEEE80211_AC_VO].aql_txq_limit_high,
-+			local->airtime[IEEE80211_AC_VI].aql_txq_limit_low,
-+			local->airtime[IEEE80211_AC_VI].aql_txq_limit_high,
-+			local->airtime[IEEE80211_AC_BE].aql_txq_limit_low,
-+			local->airtime[IEEE80211_AC_BE].aql_txq_limit_high,
-+			local->airtime[IEEE80211_AC_BK].aql_txq_limit_low,
-+			local->airtime[IEEE80211_AC_BK].aql_txq_limit_high);
- 	return simple_read_from_buffer(user_buf, count, ppos,
- 				       buf, len);
- }
-@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struc
- 	if (ac >= IEEE80211_NUM_ACS)
- 		return -EINVAL;
- 
--	q_limit_low_old = local->aql_txq_limit_low[ac];
--	q_limit_high_old = local->aql_txq_limit_high[ac];
-+	q_limit_low_old = local->airtime[ac].aql_txq_limit_low;
-+	q_limit_high_old = local->airtime[ac].aql_txq_limit_high;
- 
--	local->aql_txq_limit_low[ac] = q_limit_low;
--	local->aql_txq_limit_high[ac] = q_limit_high;
-+	local->airtime[ac].aql_txq_limit_low = q_limit_low;
-+	local->airtime[ac].aql_txq_limit_high = q_limit_high;
- 
- 	mutex_lock(&local->sta_mtx);
- 	list_for_each_entry(sta, &local->sta_list, list) {
-@@ -382,6 +382,46 @@ static const struct file_operations forc
- 	.llseek = default_llseek,
- };
- 
-+static ssize_t airtime_read(struct file *file,
-+			    char __user *user_buf,
-+			    size_t count,
-+			    loff_t *ppos)
-+{
-+	struct ieee80211_local *local = file->private_data;
-+	char buf[200];
-+	u64 v_t[IEEE80211_NUM_ACS];
-+	u64 wt[IEEE80211_NUM_ACS];
-+	int len = 0, ac;
-+
-+	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
-+		spin_lock_bh(&local->airtime[ac].lock);
-+		v_t[ac] = local->airtime[ac].v_t;
-+		wt[ac] = local->airtime[ac].weight_sum;
-+		spin_unlock_bh(&local->airtime[ac].lock);
-+	}
-+	len = scnprintf(buf, sizeof(buf),
-+			"\tVO         VI         BE         BK\n"
-+			"Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
-+			"Weight\t%-10llu %-10llu %-10llu %-10llu\n",
-+			v_t[0],
-+			v_t[1],
-+			v_t[2],
-+			v_t[3],
-+			wt[0],
-+			wt[1],
-+			wt[2],
-+			wt[3]);
-+
-+	return simple_read_from_buffer(user_buf, count, ppos,
-+				       buf, len);
-+}
-+
-+static const struct file_operations airtime_ops = {
-+	.read = airtime_read,
-+	.open = simple_open,
-+	.llseek = default_llseek,
-+};
-+
- #ifdef CONFIG_PM
- static ssize_t reset_write(struct file *file, const char __user *user_buf,
- 			   size_t count, loff_t *ppos)
-@@ -632,7 +672,11 @@ void debugfs_hw_add(struct ieee80211_loc
- 	if (local->ops->wake_tx_queue)
- 		DEBUGFS_ADD_MODE(aqm, 0600);
- 
--	DEBUGFS_ADD_MODE(airtime_flags, 0600);
-+	if (wiphy_ext_feature_isset(local->hw.wiphy,
-+				    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
-+		DEBUGFS_ADD_MODE(airtime, 0600);
-+		DEBUGFS_ADD_MODE(airtime_flags, 0600);
-+	}
- 
- 	DEBUGFS_ADD(aql_txq_limit);
- 	debugfs_create_u32("aql_threshold", 0600,
---- a/net/mac80211/debugfs_netdev.c
-+++ b/net/mac80211/debugfs_netdev.c
-@@ -513,6 +513,34 @@ static ssize_t ieee80211_if_fmt_aqm(
- }
- IEEE80211_IF_FILE_R(aqm);
- 
-+static ssize_t ieee80211_if_fmt_airtime(
-+	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
-+{
-+	struct ieee80211_local *local = sdata->local;
-+	struct ieee80211_txq *txq = sdata->vif.txq;
-+	struct airtime_info *air_info;
-+	int len;
-+
-+	if (!txq)
-+		return 0;
-+
-+	spin_lock_bh(&local->airtime[txq->ac].lock);
-+	air_info = to_airtime_info(txq);
-+	len = scnprintf(buf,
-+			buflen,
-+			"RX: %llu us\nTX: %llu us\nWeight: %u\n"
-+			"Virt-T: %lld us\n",
-+			air_info->rx_airtime,
-+			air_info->tx_airtime,
-+			air_info->weight,
-+			air_info->v_t);
-+	spin_unlock_bh(&local->airtime[txq->ac].lock);
-+
-+	return len;
-+}
-+
-+IEEE80211_IF_FILE_R(airtime);
-+
- IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
- 
- /* IBSS attributes */
-@@ -658,8 +686,10 @@ static void add_common_files(struct ieee
- 
- 	if (sdata->local->ops->wake_tx_queue &&
- 	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
--	    sdata->vif.type != NL80211_IFTYPE_NAN)
-+	    sdata->vif.type != NL80211_IFTYPE_NAN) {
- 		DEBUGFS_ADD(aqm);
-+		DEBUGFS_ADD(airtime);
-+	}
- }
- 
- static void add_sta_files(struct ieee80211_sub_if_data *sdata)
---- a/net/mac80211/debugfs_sta.c
-+++ b/net/mac80211/debugfs_sta.c
-@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f
- 	size_t bufsz = 400;
- 	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
- 	u64 rx_airtime = 0, tx_airtime = 0;
--	s64 deficit[IEEE80211_NUM_ACS];
-+	u64 v_t[IEEE80211_NUM_ACS];
- 	ssize_t rv;
- 	int ac;
- 
-@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct f
- 		return -ENOMEM;
- 
- 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
--		spin_lock_bh(&local->active_txq_lock[ac]);
-+		spin_lock_bh(&local->airtime[ac].lock);
- 		rx_airtime += sta->airtime[ac].rx_airtime;
- 		tx_airtime += sta->airtime[ac].tx_airtime;
--		deficit[ac] = sta->airtime[ac].deficit;
--		spin_unlock_bh(&local->active_txq_lock[ac]);
-+		v_t[ac] = sta->airtime[ac].v_t;
-+		spin_unlock_bh(&local->airtime[ac].lock);
- 	}
- 
- 	p += scnprintf(p, bufsz + buf - p,
- 		"RX: %llu us\nTX: %llu us\nWeight: %u\n"
--		"Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
--		rx_airtime, tx_airtime, sta->airtime_weight,
--		deficit[0], deficit[1], deficit[2], deficit[3]);
-+		"Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
-+		rx_airtime, tx_airtime, sta->airtime[0].weight,
-+		v_t[0], v_t[1], v_t[2], v_t[3]);
- 
- 	rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
- 	kfree(buf);
-@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct
- 	int ac;
- 
- 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
--		spin_lock_bh(&local->active_txq_lock[ac]);
-+		spin_lock_bh(&local->airtime[ac].lock);
- 		sta->airtime[ac].rx_airtime = 0;
- 		sta->airtime[ac].tx_airtime = 0;
--		sta->airtime[ac].deficit = sta->airtime_weight;
--		spin_unlock_bh(&local->active_txq_lock[ac]);
-+		sta->airtime[ac].v_t = 0;
-+		spin_unlock_bh(&local->airtime[ac].lock);
- 	}
- 
- 	return count;
-@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file
- 		return -ENOMEM;
- 
- 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
--		spin_lock_bh(&local->active_txq_lock[ac]);
-+		spin_lock_bh(&local->airtime[ac].lock);
- 		q_limit_l[ac] = sta->airtime[ac].aql_limit_low;
- 		q_limit_h[ac] = sta->airtime[ac].aql_limit_high;
--		spin_unlock_bh(&local->active_txq_lock[ac]);
-+		spin_unlock_bh(&local->airtime[ac].lock);
- 		q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
- 	}
- 
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -835,20 +835,16 @@ 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
-  * @schedule_order: used with ieee80211_local->active_txqs
-- * @schedule_round: counter to prevent infinite loops on TXQ scheduling
-+ * @frags: used to keep fragments created after dequeue
-  */
- struct txq_info {
- 	struct fq_tin tin;
- 	struct codel_vars def_cvars;
- 	struct codel_stats cstats;
--
--	u16 schedule_round;
--	struct list_head schedule_order;
-+	struct rb_node schedule_order;
- 
- 	struct sk_buff_head frags;
--
- 	unsigned long flags;
- 
- 	/* keep last! */
-@@ -925,6 +921,8 @@ struct ieee80211_sub_if_data {
- 	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
- 	struct mac80211_qos_map __rcu *qos_map;
- 
-+	struct airtime_info airtime[IEEE80211_NUM_ACS];
-+
- 	struct work_struct csa_finalize_work;
- 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
- 	struct cfg80211_chan_def csa_chandef;
-@@ -1137,6 +1135,44 @@ enum mac80211_scan_state {
- 	SCAN_ABORT,
- };
- 
-+/**
-+ * struct airtime_sched_info - state used for airtime scheduling and AQL
-+ *
-+ * @lock: spinlock that protects all the fields in this struct
-+ * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time
-+ * @schedule_pos: the current position maintained while a driver walks the tree
-+ *                with ieee80211_next_txq()
-+ * @active_list: list of struct airtime_info structs that were active within
-+ *               the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute
-+ *               weight_sum
-+ * @last_weight_update: used for rate limiting walking active_list
-+ * @last_schedule_time: tracks the last time a transmission was scheduled; used
-+ *                      for catching up v_t if no stations are eligible for
-+ *                      transmission.
-+ * @v_t: global virtual time; queues with v_t < this are eligible for
-+ *       transmission
-+ * @weight_sum: total sum of all active stations used for dividing airtime
-+ * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast
-+ *                         path - see comment above
-+ *                         IEEE80211_RECIPROCAL_DIVISOR_64)
-+ * @aql_txq_limit_low: AQL limit when total outstanding airtime
-+ *                     is < IEEE80211_AQL_THRESHOLD
-+ * @aql_txq_limit_high: AQL limit when total outstanding airtime
-+ *                      is > IEEE80211_AQL_THRESHOLD
-+ */
-+struct airtime_sched_info {
-+	spinlock_t lock;
-+	struct rb_root_cached active_txqs;
-+	struct rb_node *schedule_pos;
-+	struct list_head active_list;
-+	u64 last_weight_update;
-+	u64 last_schedule_activity;
-+	u64 v_t;
-+	u64 weight_sum;
-+	u64 weight_sum_reciprocal;
-+	u32 aql_txq_limit_low;
-+	u32 aql_txq_limit_high;
-+};
- DECLARE_STATIC_KEY_FALSE(aql_disable);
- 
- struct ieee80211_local {
-@@ -1150,13 +1186,8 @@ struct ieee80211_local {
- 	struct codel_params cparams;
- 
- 	/* protects active_txqs and txqi->schedule_order */
--	spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
--	struct list_head active_txqs[IEEE80211_NUM_ACS];
--	u16 schedule_round[IEEE80211_NUM_ACS];
--
-+	struct airtime_sched_info airtime[IEEE80211_NUM_ACS];
- 	u16 airtime_flags;
--	u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
--	u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
- 	u32 aql_threshold;
- 	atomic_t aql_total_pending_airtime;
- 
-@@ -1574,6 +1605,125 @@ static inline bool txq_has_queue(struct
- 	return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets);
- }
- 
-+static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq)
-+{
-+	struct ieee80211_sub_if_data *sdata;
-+	struct sta_info *sta;
-+
-+	if (txq->sta) {
-+		sta = container_of(txq->sta, struct sta_info, sta);
-+		return &sta->airtime[txq->ac];
-+	}
-+
-+	sdata = vif_to_sdata(txq->vif);
-+	return &sdata->airtime[txq->ac];
-+}
-+
-+/* To avoid divisions in the fast path, we keep pre-computed reciprocals for
-+ * airtime weight calculations. There are two different weights to keep track
-+ * of: The per-station weight and the sum of weights per phy.
-+ *
-+ * For the per-station weights (kept in airtime_info below), we use 32-bit
-+ * reciprocals with a devisor of 2^19. This lets us keep the multiplications and
-+ * divisions for the station weights as 32-bit operations at the cost of a bit
-+ * of rounding error for high weights; but the choice of divisor keeps rounding
-+ * errors <10% for weights <2^15, assuming no more than 8ms of airtime is
-+ * reported at a time.
-+ *
-+ * For the per-phy sum of weights the values can get higher, so we use 64-bit
-+ * operations for those with a 32-bit divisor, which should avoid any
-+ * significant rounding errors.
-+ */
-+#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL
-+#define IEEE80211_RECIPROCAL_SHIFT_64 32
-+#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U
-+#define IEEE80211_RECIPROCAL_SHIFT_32 19
-+
-+static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight)
-+{
-+	if (air_info->weight == weight)
-+		return;
-+
-+	air_info->weight = weight;
-+	if (weight) {
-+		air_info->weight_reciprocal =
-+			IEEE80211_RECIPROCAL_DIVISOR_32 / weight;
-+	} else {
-+		air_info->weight_reciprocal = 0;
-+	}
-+}
-+
-+static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched,
-+					  int weight_sum)
-+{
-+	if (air_sched->weight_sum == weight_sum)
-+		return;
-+
-+	air_sched->weight_sum = weight_sum;
-+	if (air_sched->weight_sum) {
-+		air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64;
-+		do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum);
-+	} else {
-+		air_sched->weight_sum_reciprocal = 0;
-+	}
-+}
-+
-+/* A problem when trying to enforce airtime fairness is that we want to divide
-+ * the airtime between the currently *active* stations. However, basing this on
-+ * the instantaneous queue state of stations doesn't work, as queues tend to
-+ * oscillate very quickly between empty and occupied, leading to the scheduler
-+ * thinking only a single station is active when deciding whether to allow
-+ * transmission (and thus not throttling correctly).
-+ *
-+ * To fix this we use a timer-based notion of activity: a station is considered
-+ * active if it has been scheduled within the last 100 ms; we keep a separate
-+ * list of all the stations considered active in this manner, and lazily update
-+ * the total weight of active stations from this list (filtering the stations in
-+ * the list by their 'last active' time).
-+ *
-+ * We add one additional safeguard to guard against stations that manage to get
-+ * scheduled every 100 ms but don't transmit a lot of data, and thus don't use
-+ * up any airtime. Such stations would be able to get priority for an extended
-+ * period of time if they do start transmitting at full capacity again, and so
-+ * we add an explicit maximum for how far behind a station is allowed to fall in
-+ * the virtual airtime domain. This limit is set to a relatively high value of
-+ * 20 ms because the main mechanism for catching up idle stations is the active
-+ * state as described above; i.e., the hard limit should only be hit in
-+ * pathological cases.
-+ */
-+#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC)
-+#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */
-+
-+static inline bool airtime_is_active(struct airtime_info *air_info, u64 now)
-+{
-+	return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION;
-+}
-+
-+static inline void airtime_set_active(struct airtime_sched_info *air_sched,
-+				      struct airtime_info *air_info, u64 now)
-+{
-+	air_info->last_scheduled = now;
-+	air_sched->last_schedule_activity = now;
-+	list_move_tail(&air_info->list, &air_sched->active_list);
-+}
-+
-+static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched,
-+				       u64 v_t, u64 now)
-+{
-+	air_sched->v_t = v_t;
-+	return true;
-+}
-+
-+static inline void init_airtime_info(struct airtime_info *air_info,
-+				     struct airtime_sched_info *air_sched)
-+{
-+	atomic_set(&air_info->aql_tx_pending, 0);
-+	air_info->aql_limit_low = air_sched->aql_txq_limit_low;
-+	air_info->aql_limit_high = air_sched->aql_txq_limit_high;
-+	airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT);
-+	INIT_LIST_HEAD(&air_info->list);
-+}
-+
- static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
- {
- 	return ether_addr_equal(raddr, addr) ||
-@@ -1816,6 +1966,14 @@ int ieee80211_tx_control_port(struct wip
- 			      u64 *cookie);
- int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
- 			      const u8 *buf, size_t len);
-+void ieee80211_resort_txq(struct ieee80211_hw *hw,
-+			  struct ieee80211_txq *txq);
-+void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
-+			      struct ieee80211_txq *txq,
-+			      bool purge);
-+void ieee80211_update_airtime_weight(struct ieee80211_local *local,
-+				     struct airtime_sched_info *air_sched,
-+				     u64 now, bool force);
- 
- /* HT */
- void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -2041,6 +2041,9 @@ int ieee80211_if_add(struct ieee80211_lo
- 		}
- 	}
- 
-+	for (i = 0; i < IEEE80211_NUM_ACS; i++)
-+		init_airtime_info(&sdata->airtime[i], &local->airtime[i]);
-+
- 	ieee80211_set_default_queues(sdata);
- 
- 	sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -707,10 +707,13 @@ struct ieee80211_hw *ieee80211_alloc_hw_
- 	spin_lock_init(&local->queue_stop_reason_lock);
- 
- 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
--		INIT_LIST_HEAD(&local->active_txqs[i]);
--		spin_lock_init(&local->active_txq_lock[i]);
--		local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
--		local->aql_txq_limit_high[i] =
-+		struct airtime_sched_info *air_sched = &local->airtime[i];
-+
-+		air_sched->active_txqs = RB_ROOT_CACHED;
-+		INIT_LIST_HEAD(&air_sched->active_list);
-+		spin_lock_init(&air_sched->lock);
-+		air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
-+		air_sched->aql_txq_limit_high =
- 			IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
- 	}
- 
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -1563,12 +1563,8 @@ static void sta_ps_start(struct sta_info
- 
- 	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
- 		struct ieee80211_txq *txq = sta->sta.txq[tid];
--		struct txq_info *txqi = to_txq_info(txq);
- 
--		spin_lock(&local->active_txq_lock[txq->ac]);
--		if (!list_empty(&txqi->schedule_order))
--			list_del_init(&txqi->schedule_order);
--		spin_unlock(&local->active_txq_lock[txq->ac]);
-+		ieee80211_unschedule_txq(&local->hw, txq, false);
- 
- 		if (txq_has_queue(txq))
- 			set_bit(tid, &sta->txq_buffered_tids);
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -426,15 +426,11 @@ struct sta_info *sta_info_alloc(struct i
- 	if (sta_prepare_rate_control(local, sta, gfp))
- 		goto free_txq;
- 
--	sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT;
- 
- 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- 		skb_queue_head_init(&sta->ps_tx_buf[i]);
- 		skb_queue_head_init(&sta->tx_filtered[i]);
--		sta->airtime[i].deficit = sta->airtime_weight;
--		atomic_set(&sta->airtime[i].aql_tx_pending, 0);
--		sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i];
--		sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i];
-+		init_airtime_info(&sta->airtime[i], &local->airtime[i]);
- 	}
- 
- 	for (i = 0; i < IEEE80211_NUM_TIDS; i++)
-@@ -1893,24 +1889,59 @@ void ieee80211_sta_set_buffered(struct i
- }
- EXPORT_SYMBOL(ieee80211_sta_set_buffered);
- 
--void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
--				    u32 tx_airtime, u32 rx_airtime)
-+void ieee80211_register_airtime(struct ieee80211_txq *txq,
-+				u32 tx_airtime, u32 rx_airtime)
- {
--	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
--	struct ieee80211_local *local = sta->sdata->local;
--	u8 ac = ieee80211_ac_from_tid(tid);
-+	struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
-+	struct ieee80211_local *local = sdata->local;
-+	u64 weight_sum, weight_sum_reciprocal;
-+	struct airtime_sched_info *air_sched;
-+	struct airtime_info *air_info;
- 	u32 airtime = 0;
- 
--	if (sta->local->airtime_flags & AIRTIME_USE_TX)
-+	air_sched = &local->airtime[txq->ac];
-+	air_info = to_airtime_info(txq);
-+
-+	if (local->airtime_flags & AIRTIME_USE_TX)
- 		airtime += tx_airtime;
--	if (sta->local->airtime_flags & AIRTIME_USE_RX)
-+	if (local->airtime_flags & AIRTIME_USE_RX)
- 		airtime += rx_airtime;
- 
--	spin_lock_bh(&local->active_txq_lock[ac]);
--	sta->airtime[ac].tx_airtime += tx_airtime;
--	sta->airtime[ac].rx_airtime += rx_airtime;
--	sta->airtime[ac].deficit -= airtime;
--	spin_unlock_bh(&local->active_txq_lock[ac]);
-+	/* Weights scale so the unit weight is 256 */
-+	airtime <<= 8;
-+
-+	spin_lock_bh(&air_sched->lock);
-+
-+	air_info->tx_airtime += tx_airtime;
-+	air_info->rx_airtime += rx_airtime;
-+
-+	if (air_sched->weight_sum) {
-+		weight_sum = air_sched->weight_sum;
-+		weight_sum_reciprocal = air_sched->weight_sum_reciprocal;
-+	} else {
-+		weight_sum = air_info->weight;
-+		weight_sum_reciprocal = air_info->weight_reciprocal;
-+	}
-+
-+	/* Round the calculation of global vt */
-+	air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) *
-+				weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64;
-+	air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) *
-+			       air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32;
-+	ieee80211_resort_txq(&local->hw, txq);
-+
-+	spin_unlock_bh(&air_sched->lock);
-+}
-+
-+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
-+				    u32 tx_airtime, u32 rx_airtime)
-+{
-+	struct ieee80211_txq *txq = pubsta->txq[tid];
-+
-+	if (!txq)
-+		return;
-+
-+	ieee80211_register_airtime(txq, tx_airtime, rx_airtime);
- }
- EXPORT_SYMBOL(ieee80211_sta_register_airtime);
- 
-@@ -2354,7 +2385,7 @@ void sta_set_sinfo(struct sta_info *sta,
- 	}
- 
- 	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
--		sinfo->airtime_weight = sta->airtime_weight;
-+		sinfo->airtime_weight = sta->airtime[0].weight;
- 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
- 	}
- 
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -135,18 +135,25 @@ enum ieee80211_agg_stop_reason {
- #define AIRTIME_USE_TX		BIT(0)
- #define AIRTIME_USE_RX		BIT(1)
- 
-+
- struct airtime_info {
- 	u64 rx_airtime;
- 	u64 tx_airtime;
--	s64 deficit;
-+	u64 v_t;
-+	u64 last_scheduled;
-+	struct list_head list;
- 	atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
- 	u32 aql_limit_low;
- 	u32 aql_limit_high;
-+	u32 weight_reciprocal;
-+	u16 weight;
- };
- 
- void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
- 					  struct sta_info *sta, u8 ac,
- 					  u16 tx_airtime, bool tx_completed);
-+void ieee80211_register_airtime(struct ieee80211_txq *txq,
-+				u32 tx_airtime, u32 rx_airtime);
- 
- struct sta_info;
- 
-@@ -515,7 +522,6 @@ struct ieee80211_fragment_cache {
-  * @tid_seq: per-TID sequence numbers for sending to this STA
-  * @airtime: per-AC struct airtime_info describing airtime statistics for this
-  *	station
-- * @airtime_weight: station weight for airtime fairness calculation purposes
-  * @ampdu_mlme: A-MPDU state machine state
-  * @mesh: mesh STA information
-  * @debugfs_dir: debug filesystem directory dentry
-@@ -646,7 +652,6 @@ struct sta_info {
- 	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
- 
- 	struct airtime_info airtime[IEEE80211_NUM_ACS];
--	u16 airtime_weight;
- 
- 	/*
- 	 * Aggregation information, locked with lock.
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -970,6 +970,25 @@ static void __ieee80211_tx_status(struct
- 		if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
- 			ieee80211_frame_acked(sta, skb);
- 
-+	} else if (wiphy_ext_feature_isset(local->hw.wiphy,
-+					   NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
-+		struct ieee80211_sub_if_data *sdata;
-+		struct ieee80211_txq *txq;
-+		u32 airtime;
-+
-+		/* Account airtime to multicast queue */
-+		sdata = ieee80211_sdata_from_skb(local, skb);
-+
-+		if (sdata && (txq = sdata->vif.txq)) {
-+			airtime = info->status.tx_time ?:
-+				ieee80211_calc_expected_tx_airtime(hw,
-+								   &sdata->vif,
-+								   NULL,
-+								   skb->len,
-+								   false);
-+
-+			ieee80211_register_airtime(txq, airtime, 0);
-+		}
- 	}
- 
- 	/* SNMP counters
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -18,6 +18,7 @@
- #include <linux/bitmap.h>
- #include <linux/rcupdate.h>
- #include <linux/export.h>
-+#include <linux/timekeeping.h>
- #include <net/net_namespace.h>
- #include <net/ieee80211_radiotap.h>
- #include <net/cfg80211.h>
-@@ -1479,7 +1480,7 @@ void ieee80211_txq_init(struct ieee80211
- 	codel_vars_init(&txqi->def_cvars);
- 	codel_stats_init(&txqi->cstats);
- 	__skb_queue_head_init(&txqi->frags);
--	INIT_LIST_HEAD(&txqi->schedule_order);
-+	RB_CLEAR_NODE(&txqi->schedule_order);
- 
- 	txqi->txq.vif = &sdata->vif;
- 
-@@ -1523,9 +1524,7 @@ void ieee80211_txq_purge(struct ieee8021
- 	ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
- 	spin_unlock_bh(&fq->lock);
- 
--	spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
--	list_del_init(&txqi->schedule_order);
--	spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
-+	ieee80211_unschedule_txq(&local->hw, &txqi->txq, true);
- }
- 
- void ieee80211_txq_set_params(struct ieee80211_local *local)
-@@ -3812,102 +3811,259 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
- struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
- {
- 	struct ieee80211_local *local = hw_to_local(hw);
-+	struct airtime_sched_info *air_sched;
-+	u64 now = ktime_get_boottime_ns();
- 	struct ieee80211_txq *ret = NULL;
--	struct txq_info *txqi = NULL, *head = NULL;
--	bool found_eligible_txq = false;
-+	struct airtime_info *air_info;
-+	struct txq_info *txqi = NULL;
-+	struct rb_node *node;
-+	bool first = false;
- 
--	spin_lock_bh(&local->active_txq_lock[ac]);
-+	air_sched = &local->airtime[ac];
-+	spin_lock_bh(&air_sched->lock);
- 
-- begin:
--	txqi = list_first_entry_or_null(&local->active_txqs[ac],
--					struct txq_info,
--					schedule_order);
--	if (!txqi)
-+	node = air_sched->schedule_pos;
-+
-+begin:
-+	if (!node) {
-+		node = rb_first_cached(&air_sched->active_txqs);
-+		first = true;
-+	} else {
-+		node = rb_next(node);
-+	}
-+
-+	if (!node)
- 		goto out;
- 
--	if (txqi == head) {
--		if (!found_eligible_txq)
--			goto out;
--		else
--			found_eligible_txq = false;
-+	txqi = container_of(node, struct txq_info, schedule_order);
-+	air_info = to_airtime_info(&txqi->txq);
-+
-+	if (air_info->v_t > air_sched->v_t &&
-+	    (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now)))
-+		goto out;
-+
-+	if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) {
-+		first = false;
-+		goto begin;
- 	}
- 
--	if (!head)
--		head = txqi;
-+	air_sched->schedule_pos = node;
-+	air_sched->last_schedule_activity = now;
-+	ret = &txqi->txq;
-+out:
-+	spin_unlock_bh(&air_sched->lock);
-+	return ret;
-+}
-+EXPORT_SYMBOL(ieee80211_next_txq);
- 
--	if (txqi->txq.sta) {
--		struct sta_info *sta = container_of(txqi->txq.sta,
--						    struct sta_info, sta);
--		bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
--		s64 deficit = sta->airtime[txqi->txq.ac].deficit;
-+static void __ieee80211_insert_txq(struct rb_root_cached *root,
-+				   struct txq_info *txqi)
-+{
-+	struct rb_node **new = &root->rb_root.rb_node;
-+	struct airtime_info *old_air, *new_air;
-+	struct rb_node *parent = NULL;
-+	struct txq_info *__txqi;
-+	bool leftmost = true;
-+
-+	while (*new) {
-+		parent = *new;
-+		__txqi = rb_entry(parent, struct txq_info, schedule_order);
-+		old_air = to_airtime_info(&__txqi->txq);
-+		new_air = to_airtime_info(&txqi->txq);
- 
--		if (aql_check)
--			found_eligible_txq = true;
-+		if (new_air->v_t <= old_air->v_t) {
-+			new = &parent->rb_left;
-+		} else {
-+			new = &parent->rb_right;
-+			leftmost = false;
-+		}
-+	}
- 
--		if (deficit < 0)
--			sta->airtime[txqi->txq.ac].deficit +=
--				sta->airtime_weight;
--
--		if (deficit < 0 || !aql_check) {
--			list_move_tail(&txqi->schedule_order,
--				       &local->active_txqs[txqi->txq.ac]);
--			goto begin;
-+	rb_link_node(&txqi->schedule_order, parent, new);
-+	rb_insert_color_cached(&txqi->schedule_order, root, leftmost);
-+}
-+
-+void ieee80211_resort_txq(struct ieee80211_hw *hw,
-+			  struct ieee80211_txq *txq)
-+{
-+	struct airtime_info *air_info = to_airtime_info(txq);
-+	struct ieee80211_local *local = hw_to_local(hw);
-+	struct txq_info *txqi = to_txq_info(txq);
-+	struct airtime_sched_info *air_sched;
-+
-+	air_sched = &local->airtime[txq->ac];
-+
-+	lockdep_assert_held(&air_sched->lock);
-+
-+	if (!RB_EMPTY_NODE(&txqi->schedule_order)) {
-+		struct airtime_info *a_prev = NULL, *a_next = NULL;
-+		struct txq_info *t_prev, *t_next;
-+		struct rb_node *n_prev, *n_next;
-+
-+		/* Erasing a node can cause an expensive rebalancing operation,
-+		 * so we check the previous and next nodes first and only remove
-+		 * and re-insert if the current node is not already in the
-+		 * correct position.
-+		 */
-+		if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) {
-+			t_prev = container_of(n_prev, struct txq_info,
-+					      schedule_order);
-+			a_prev = to_airtime_info(&t_prev->txq);
-+		}
-+
-+		if ((n_next = rb_next(&txqi->schedule_order)) != NULL) {
-+			t_next = container_of(n_next, struct txq_info,
-+					      schedule_order);
-+			a_next = to_airtime_info(&t_next->txq);
- 		}
-+
-+		if ((!a_prev || a_prev->v_t <= air_info->v_t) &&
-+		    (!a_next || a_next->v_t > air_info->v_t))
-+			return;
-+
-+		if (air_sched->schedule_pos == &txqi->schedule_order)
-+			air_sched->schedule_pos = n_prev;
-+
-+		rb_erase_cached(&txqi->schedule_order,
-+				&air_sched->active_txqs);
-+		RB_CLEAR_NODE(&txqi->schedule_order);
-+		__ieee80211_insert_txq(&air_sched->active_txqs, txqi);
- 	}
-+}
-+
-+void ieee80211_update_airtime_weight(struct ieee80211_local *local,
-+				     struct airtime_sched_info *air_sched,
-+				     u64 now, bool force)
-+{
-+	struct airtime_info *air_info, *tmp;
-+	u64 weight_sum = 0;
-+
-+	if (unlikely(!now))
-+		now = ktime_get_boottime_ns();
-+
-+	lockdep_assert_held(&air_sched->lock);
-+
-+	if (!force && (air_sched->last_weight_update <
-+		       now - AIRTIME_ACTIVE_DURATION))
-+		return;
-+
-+	list_for_each_entry_safe(air_info, tmp,
-+				 &air_sched->active_list, list) {
-+		if (airtime_is_active(air_info, now))
-+			weight_sum += air_info->weight;
-+		else
-+			list_del_init(&air_info->list);
-+	}
-+	airtime_weight_sum_set(air_sched, weight_sum);
-+	air_sched->last_weight_update = now;
-+}
- 
-+void ieee80211_schedule_txq(struct ieee80211_hw *hw,
-+			    struct ieee80211_txq *txq)
-+	__acquires(txq_lock) __releases(txq_lock)
-+{
-+	struct ieee80211_local *local = hw_to_local(hw);
-+	struct txq_info *txqi = to_txq_info(txq);
-+	struct airtime_sched_info *air_sched;
-+	u64 now = ktime_get_boottime_ns();
-+	struct airtime_info *air_info;
-+	u8 ac = txq->ac;
-+	bool was_active;
- 
--	if (txqi->schedule_round == local->schedule_round[ac])
-+	air_sched = &local->airtime[ac];
-+	air_info = to_airtime_info(txq);
-+
-+	spin_lock_bh(&air_sched->lock);
-+	was_active = airtime_is_active(air_info, now);
-+	airtime_set_active(air_sched, air_info, now);
-+
-+	if (!RB_EMPTY_NODE(&txqi->schedule_order))
- 		goto out;
- 
--	list_del_init(&txqi->schedule_order);
--	txqi->schedule_round = local->schedule_round[ac];
--	ret = &txqi->txq;
-+	/* If the station has been inactive for a while, catch up its v_t so it
-+	 * doesn't get indefinite priority; see comment above the definition of
-+	 * AIRTIME_MAX_BEHIND.
-+	 */
-+	if ((!was_active && air_info->v_t < air_sched->v_t) ||
-+	    air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND)
-+		air_info->v_t = air_sched->v_t;
-+
-+	ieee80211_update_airtime_weight(local, air_sched, now, !was_active);
-+	__ieee80211_insert_txq(&air_sched->active_txqs, txqi);
- 
- out:
--	spin_unlock_bh(&local->active_txq_lock[ac]);
--	return ret;
-+	spin_unlock_bh(&air_sched->lock);
- }
--EXPORT_SYMBOL(ieee80211_next_txq);
-+EXPORT_SYMBOL(ieee80211_schedule_txq);
- 
--void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
--			      struct ieee80211_txq *txq,
--			      bool force)
-+static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw,
-+				       struct ieee80211_txq *txq,
-+				       bool purge)
- {
- 	struct ieee80211_local *local = hw_to_local(hw);
- 	struct txq_info *txqi = to_txq_info(txq);
-+	struct airtime_sched_info *air_sched;
-+	struct airtime_info *air_info;
- 
--	spin_lock_bh(&local->active_txq_lock[txq->ac]);
-+	air_sched = &local->airtime[txq->ac];
-+	air_info = to_airtime_info(&txqi->txq);
- 
--	if (list_empty(&txqi->schedule_order) &&
--	    (force || !skb_queue_empty(&txqi->frags) ||
--	     txqi->tin.backlog_packets)) {
--		/* If airtime accounting is active, always enqueue STAs at the
--		 * head of the list to ensure that they only get moved to the
--		 * back by the airtime DRR scheduler once they have a negative
--		 * deficit. A station that already has a negative deficit will
--		 * get immediately moved to the back of the list on the next
--		 * call to ieee80211_next_txq().
--		 */
--		if (txqi->txq.sta && local->airtime_flags &&
--		    wiphy_ext_feature_isset(local->hw.wiphy,
--					    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
--			list_add(&txqi->schedule_order,
--				 &local->active_txqs[txq->ac]);
--		else
--			list_add_tail(&txqi->schedule_order,
--				      &local->active_txqs[txq->ac]);
-+	lockdep_assert_held(&air_sched->lock);
-+
-+	if (purge) {
-+		list_del_init(&air_info->list);
-+		ieee80211_update_airtime_weight(local, air_sched, 0, true);
- 	}
- 
--	spin_unlock_bh(&local->active_txq_lock[txq->ac]);
-+	if (RB_EMPTY_NODE(&txqi->schedule_order))
-+		return;
-+
-+	if (air_sched->schedule_pos == &txqi->schedule_order)
-+		air_sched->schedule_pos = rb_prev(&txqi->schedule_order);
-+
-+	if (!purge)
-+		airtime_set_active(air_sched, air_info,
-+				   ktime_get_boottime_ns());
-+
-+	rb_erase_cached(&txqi->schedule_order,
-+			&air_sched->active_txqs);
-+	RB_CLEAR_NODE(&txqi->schedule_order);
-+}
-+
-+void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
-+			      struct ieee80211_txq *txq,
-+			      bool purge)
-+	__acquires(txq_lock) __releases(txq_lock)
-+{
-+	struct ieee80211_local *local = hw_to_local(hw);
-+
-+	spin_lock_bh(&local->airtime[txq->ac].lock);
-+	__ieee80211_unschedule_txq(hw, txq, purge);
-+	spin_unlock_bh(&local->airtime[txq->ac].lock);
-+}
-+
-+void ieee80211_return_txq(struct ieee80211_hw *hw,
-+			  struct ieee80211_txq *txq, bool force)
-+{
-+	struct ieee80211_local *local = hw_to_local(hw);
-+	struct txq_info *txqi = to_txq_info(txq);
-+
-+	spin_lock_bh(&local->airtime[txq->ac].lock);
-+
-+	if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force &&
-+	    !txq_has_queue(txq))
-+		__ieee80211_unschedule_txq(hw, txq, false);
-+
-+	spin_unlock_bh(&local->airtime[txq->ac].lock);
- }
--EXPORT_SYMBOL(__ieee80211_schedule_txq);
-+EXPORT_SYMBOL(ieee80211_return_txq);
- 
- DEFINE_STATIC_KEY_FALSE(aql_disable);
- 
- bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
- 				 struct ieee80211_txq *txq)
- {
--	struct sta_info *sta;
-+	struct airtime_info *air_info = to_airtime_info(txq);
- 	struct ieee80211_local *local = hw_to_local(hw);
- 
- 	if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
-@@ -3922,15 +4078,12 @@ bool ieee80211_txq_airtime_check(struct
- 	if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
- 		return true;
- 
--	sta = container_of(txq->sta, struct sta_info, sta);
--	if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
--	    sta->airtime[txq->ac].aql_limit_low)
-+	if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low)
- 		return true;
- 
- 	if (atomic_read(&local->aql_total_pending_airtime) <
- 	    local->aql_threshold &&
--	    atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
--	    sta->airtime[txq->ac].aql_limit_high)
-+	    atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high)
- 		return true;
- 
- 	return false;
-@@ -3940,60 +4093,59 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec
- bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
- 				struct ieee80211_txq *txq)
- {
-+	struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq);
- 	struct ieee80211_local *local = hw_to_local(hw);
--	struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
--	struct sta_info *sta;
--	u8 ac = txq->ac;
-+	struct airtime_sched_info *air_sched;
-+	struct airtime_info *air_info;
-+	struct rb_node *node = NULL;
-+	bool ret = false;
-+	u64 now;
- 
--	spin_lock_bh(&local->active_txq_lock[ac]);
- 
--	if (!txqi->txq.sta)
--		goto out;
-+	if (!ieee80211_txq_airtime_check(hw, txq))
-+		return false;
-+
-+	air_sched = &local->airtime[txq->ac];
-+	spin_lock_bh(&air_sched->lock);
- 
--	if (list_empty(&txqi->schedule_order))
-+	if (RB_EMPTY_NODE(&txqi->schedule_order))
- 		goto out;
- 
--	list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
--				 schedule_order) {
--		if (iter == txqi)
--			break;
-+	now = ktime_get_boottime_ns();
- 
--		if (!iter->txq.sta) {
--			list_move_tail(&iter->schedule_order,
--				       &local->active_txqs[ac]);
--			continue;
--		}
--		sta = container_of(iter->txq.sta, struct sta_info, sta);
--		if (sta->airtime[ac].deficit < 0)
--			sta->airtime[ac].deficit += sta->airtime_weight;
--		list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
-+	/* Like in ieee80211_next_txq(), make sure the first station in the
-+	 * scheduling order is eligible for transmission to avoid starvation.
-+	 */
-+	node = rb_first_cached(&air_sched->active_txqs);
-+	if (node) {
-+		first_txqi = container_of(node, struct txq_info,
-+					  schedule_order);
-+		air_info = to_airtime_info(&first_txqi->txq);
-+
-+		if (air_sched->v_t < air_info->v_t)
-+			airtime_catchup_v_t(air_sched, air_info->v_t, now);
- 	}
- 
--	sta = container_of(txqi->txq.sta, struct sta_info, sta);
--	if (sta->airtime[ac].deficit >= 0)
--		goto out;
--
--	sta->airtime[ac].deficit += sta->airtime_weight;
--	list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
--	spin_unlock_bh(&local->active_txq_lock[ac]);
-+	air_info = to_airtime_info(&txqi->txq);
-+	if (air_info->v_t <= air_sched->v_t) {
-+		air_sched->last_schedule_activity = now;
-+		ret = true;
-+	}
- 
--	return false;
- out:
--	if (!list_empty(&txqi->schedule_order))
--		list_del_init(&txqi->schedule_order);
--	spin_unlock_bh(&local->active_txq_lock[ac]);
--
--	return true;
-+	spin_unlock_bh(&air_sched->lock);
-+	return ret;
- }
- EXPORT_SYMBOL(ieee80211_txq_may_transmit);
- 
- void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
- {
- 	struct ieee80211_local *local = hw_to_local(hw);
-+	struct airtime_sched_info *air_sched = &local->airtime[ac];
- 
--	spin_lock_bh(&local->active_txq_lock[ac]);
--	local->schedule_round[ac]++;
--	spin_unlock_bh(&local->active_txq_lock[ac]);
-+	spin_lock_bh(&air_sched->lock);
-+	air_sched->schedule_pos = NULL;
-+	spin_unlock_bh(&air_sched->lock);
- }
- EXPORT_SYMBOL(ieee80211_txq_schedule_start);
- 
diff --git a/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch b/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch
deleted file mode 100644
index e195d0bcad..0000000000
--- a/package/kernel/mac80211/patches/subsys/386-mac80211-check-per-vif-offload_flags-in-Tx-path.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From: Ryder Lee <ryder.lee at mediatek.com>
-Date: Fri, 18 Jun 2021 04:38:59 +0800
-Subject: [PATCH] mac80211: check per vif offload_flags in Tx path
-
-offload_flags has been introduced to indicate encap status of each interface.
-An interface can encap offload at runtime, or if it has some extra limitations
-it can simply override the flags, so it's more flexible to check offload_flags
-in Tx path.
-
-Signed-off-by: Ryder Lee <ryder.lee at mediatek.com>
-Link: https://lore.kernel.org/r/177785418cf407808bf3a44760302d0647076990.1623961575.git.ryder.lee@mediatek.com
-Signed-off-by: Johannes Berg <johannes.berg at intel.com>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3318,6 +3318,9 @@ static bool ieee80211_amsdu_aggregate(st
- 	if (!ieee80211_hw_check(&local->hw, TX_AMSDU))
- 		return false;
- 
-+	if (sdata->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
-+		return false;
-+
- 	if (skb_is_gso(skb))
- 		return false;
- 
diff --git a/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch b/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch
index 6989375180..f2ebede15a 100644
--- a/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch
+++ b/package/kernel/mac80211/patches/subsys/387-nl80211-add-support-for-BSS-coloring.patch
@@ -23,8 +23,8 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
 
 --- a/include/net/cfg80211.h
 +++ b/include/net/cfg80211.h
-@@ -1253,6 +1253,27 @@ struct cfg80211_csa_settings {
- #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
+@@ -1258,6 +1258,27 @@ struct cfg80211_csa_settings {
+ };
  
  /**
 + * struct cfg80211_color_change_settings - color change settings
@@ -51,7 +51,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
   * struct iface_combination_params - input parameters for interface combinations
   *
   * Used to pass interface combination parameters
-@@ -3991,6 +4012,8 @@ struct mgmt_frame_regs {
+@@ -4000,6 +4021,8 @@ struct mgmt_frame_regs {
   *	given TIDs. This callback may sleep.
   *
   * @set_sar_specs: Update the SAR (TX power) settings.
@@ -60,7 +60,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
   */
  struct cfg80211_ops {
  	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
-@@ -4318,6 +4341,9 @@ struct cfg80211_ops {
+@@ -4327,6 +4350,9 @@ struct cfg80211_ops {
  				    const u8 *peer, u8 tids);
  	int	(*set_sar_specs)(struct wiphy *wiphy,
  				 struct cfg80211_sar_specs *sar);
@@ -70,7 +70,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  };
  
  /*
-@@ -8209,4 +8235,70 @@ void cfg80211_update_owe_info_event(stru
+@@ -8226,4 +8252,70 @@ void cfg80211_update_owe_info_event(stru
   */
  void cfg80211_bss_flush(struct wiphy *wiphy);
  
@@ -210,7 +210,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	/* add attributes here, update the policy in nl80211.c */
  
  	__NL80211_ATTR_AFTER_LAST,
-@@ -5950,6 +5989,9 @@ enum nl80211_feature_flags {
+@@ -5953,6 +5992,9 @@ enum nl80211_feature_flags {
   *      frame protection for all management frames exchanged during the
   *      negotiation and range measurement procedure.
   *
@@ -220,7 +220,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
   * @NUM_NL80211_EXT_FEATURES: number of extended features.
   * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
   */
-@@ -6014,6 +6056,7 @@ enum nl80211_ext_feature_index {
+@@ -6017,6 +6059,7 @@ enum nl80211_ext_feature_index {
  	NL80211_EXT_FEATURE_SECURE_LTF,
  	NL80211_EXT_FEATURE_SECURE_RTT,
  	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
@@ -241,7 +241,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  };
  
  /* policy for the key attributes */
-@@ -14815,6 +14819,106 @@ bad_tid_conf:
+@@ -14823,6 +14827,106 @@ bad_tid_conf:
  	return ret;
  }
  
@@ -348,7 +348,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  #define NL80211_FLAG_NEED_WIPHY		0x01
  #define NL80211_FLAG_NEED_NETDEV	0x02
  #define NL80211_FLAG_NEED_RTNL		0x04
-@@ -15815,6 +15919,14 @@ static const struct genl_small_ops nl802
+@@ -15823,6 +15927,14 @@ static const struct genl_small_ops nl802
  		.internal_flags = NL80211_FLAG_NEED_WIPHY |
  				  NL80211_FLAG_NEED_RTNL,
  	},
@@ -363,7 +363,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  };
  
  static struct genl_family nl80211_fam __genl_ro_after_init = {
-@@ -17446,6 +17558,51 @@ void cfg80211_ch_switch_started_notify(s
+@@ -17454,6 +17566,51 @@ void cfg80211_ch_switch_started_notify(s
  }
  EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
  
@@ -417,7 +417,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  		     const struct cfg80211_chan_def *chandef,
 --- a/net/wireless/rdev-ops.h
 +++ b/net/wireless/rdev-ops.h
-@@ -1358,4 +1358,17 @@ static inline int rdev_set_sar_specs(str
+@@ -1368,4 +1368,17 @@ static inline int rdev_set_sar_specs(str
  	return ret;
  }
  
@@ -437,7 +437,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  #endif /* __CFG80211_RDEV_OPS */
 --- a/net/wireless/trace.h
 +++ b/net/wireless/trace.h
-@@ -3565,6 +3565,52 @@ TRACE_EVENT(rdev_set_sar_specs,
+@@ -3597,6 +3597,52 @@ TRACE_EVENT(rdev_set_sar_specs,
  		  WIPHY_PR_ARG, __entry->type, __entry->num)
  );
  
diff --git a/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch b/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch
index 320570d034..196c8e10af 100644
--- a/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch
+++ b/package/kernel/mac80211/patches/subsys/388-mac80211-add-support-for-BSS-color-change.patch
@@ -19,7 +19,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
 
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -1713,6 +1713,10 @@ enum ieee80211_offload_flags {
+@@ -1715,6 +1715,10 @@ enum ieee80211_offload_flags {
   *	protected by fq->lock.
   * @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
   *	&enum ieee80211_offload_flags.
@@ -30,7 +30,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
   */
  struct ieee80211_vif {
  	enum nl80211_iftype type;
-@@ -1741,6 +1745,9 @@ struct ieee80211_vif {
+@@ -1743,6 +1747,9 @@ struct ieee80211_vif {
  
  	bool txqs_stopped[IEEE80211_NUM_ACS];
  
@@ -40,7 +40,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	/* must be last */
  	u8 drv_priv[] __aligned(sizeof(void *));
  };
-@@ -4992,6 +4999,16 @@ void ieee80211_csa_finish(struct ieee802
+@@ -5016,6 +5023,16 @@ void ieee80211_csa_finish(struct ieee802
  bool ieee80211_beacon_cntdwn_is_complete(struct ieee80211_vif *vif);
  
  /**
@@ -57,7 +57,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
   * ieee80211_proberesp_get - retrieve a Probe Response template
   * @hw: pointer obtained from ieee80211_alloc_hw().
   * @vif: &struct ieee80211_vif pointer from the add_interface callback.
-@@ -6756,6 +6773,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp
+@@ -6780,6 +6797,18 @@ ieee80211_get_unsol_bcast_probe_resp_tmp
  					  struct ieee80211_vif *vif);
  
  /**
@@ -161,7 +161,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	if (err < 0)
  		return err;
  	ieee80211_bss_info_change_notify(sdata, err);
-@@ -3163,7 +3171,7 @@ static int ieee80211_set_after_csa_beaco
+@@ -3155,7 +3163,7 @@ static int ieee80211_set_after_csa_beaco
  	switch (sdata->vif.type) {
  	case NL80211_IFTYPE_AP:
  		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
@@ -170,7 +170,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  		kfree(sdata->u.ap.next_beacon);
  		sdata->u.ap.next_beacon = NULL;
  
-@@ -3329,7 +3337,7 @@ static int ieee80211_set_csa_beacon(stru
+@@ -3321,7 +3329,7 @@ static int ieee80211_set_csa_beacon(stru
  		csa.n_counter_offsets_presp = params->n_counter_offsets_presp;
  		csa.count = params->count;
  
@@ -179,7 +179,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  		if (err < 0) {
  			kfree(sdata->u.ap.next_beacon);
  			return err;
-@@ -3418,6 +3426,15 @@ static int ieee80211_set_csa_beacon(stru
+@@ -3410,6 +3418,15 @@ static int ieee80211_set_csa_beacon(stru
  	return 0;
  }
  
@@ -195,7 +195,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  static int
  __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
  			   struct cfg80211_csa_settings *params)
-@@ -3486,6 +3503,10 @@ __ieee80211_channel_switch(struct wiphy
+@@ -3478,6 +3495,10 @@ __ieee80211_channel_switch(struct wiphy
  		goto out;
  	}
  
@@ -206,7 +206,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	err = ieee80211_set_csa_beacon(sdata, params, &changed);
  	if (err) {
  		ieee80211_vif_unreserve_chanctx(sdata);
-@@ -4137,6 +4158,196 @@ static int ieee80211_set_sar_specs(struc
+@@ -4129,6 +4150,196 @@ static int ieee80211_set_sar_specs(struc
  	return local->ops->set_sar_specs(&local->hw, sar);
  }
  
@@ -403,7 +403,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  const struct cfg80211_ops mac80211_config_ops = {
  	.add_virtual_intf = ieee80211_add_iface,
  	.del_virtual_intf = ieee80211_del_iface,
-@@ -4240,4 +4451,5 @@ const struct cfg80211_ops mac80211_confi
+@@ -4232,4 +4443,5 @@ const struct cfg80211_ops mac80211_confi
  	.set_tid_config = ieee80211_set_tid_config,
  	.reset_tid_config = ieee80211_reset_tid_config,
  	.set_sar_specs = ieee80211_set_sar_specs,
@@ -433,7 +433,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	struct list_head assigned_chanctx_list; /* protected by chanctx_mtx */
  	struct list_head reserved_chanctx_list; /* protected by chanctx_mtx */
  
-@@ -1895,6 +1903,9 @@ void ieee80211_csa_finalize_work(struct
+@@ -1891,6 +1899,9 @@ void ieee80211_csa_finalize_work(struct
  int ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
  			     struct cfg80211_csa_settings *params);
  
@@ -453,7 +453,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  
  	cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
  
-@@ -1595,6 +1596,7 @@ static void ieee80211_setup_sdata(struct
+@@ -1608,6 +1609,7 @@ static void ieee80211_setup_sdata(struct
  	INIT_WORK(&sdata->work, ieee80211_iface_work);
  	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
  	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
@@ -463,7 +463,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  
 --- a/net/mac80211/tx.c
 +++ b/net/mac80211/tx.c
-@@ -4784,11 +4784,11 @@ static int ieee80211_beacon_add_tim(stru
+@@ -4796,11 +4796,11 @@ static int ieee80211_beacon_add_tim(stru
  static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata,
  					struct beacon_data *beacon)
  {
@@ -477,7 +477,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  
  	switch (sdata->vif.type) {
  	case NL80211_IFTYPE_AP:
-@@ -4808,21 +4808,27 @@ static void ieee80211_set_beacon_cntdwn(
+@@ -4820,21 +4820,27 @@ static void ieee80211_set_beacon_cntdwn(
  	}
  
  	rcu_read_lock();
@@ -514,7 +514,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	}
  	rcu_read_unlock();
  }
-@@ -5032,6 +5038,7 @@ __ieee80211_beacon_get(struct ieee80211_
+@@ -5044,6 +5050,7 @@ __ieee80211_beacon_get(struct ieee80211_
  			if (offs) {
  				offs->tim_offset = beacon->head_len;
  				offs->tim_length = skb->len - beacon->head_len;
diff --git a/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch b/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch
index cf45c6d072..6bb7dd7df4 100644
--- a/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch
+++ b/package/kernel/mac80211/patches/subsys/389-ieee80211-add-TWT-element-definitions.patch
@@ -73,7 +73,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  			} u;
  		} __packed action;
  	} u;
-@@ -2879,6 +2925,7 @@ enum ieee80211_eid {
+@@ -2881,6 +2927,7 @@ enum ieee80211_eid {
  	WLAN_EID_AID_RESPONSE = 211,
  	WLAN_EID_S1G_BCN_COMPAT = 213,
  	WLAN_EID_S1G_SHORT_BCN_INTERVAL = 214,
@@ -81,7 +81,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	WLAN_EID_S1G_CAPABILITIES = 217,
  	WLAN_EID_VENDOR_SPECIFIC = 221,
  	WLAN_EID_QOS_PARAMETER = 222,
-@@ -2947,6 +2994,7 @@ enum ieee80211_category {
+@@ -2950,6 +2997,7 @@ enum ieee80211_category {
  	WLAN_CATEGORY_FST = 18,
  	WLAN_CATEGORY_UNPROT_DMG = 20,
  	WLAN_CATEGORY_VHT = 21,
@@ -89,7 +89,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
  	WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
  };
-@@ -3020,6 +3068,20 @@ enum ieee80211_key_len {
+@@ -3023,6 +3071,20 @@ enum ieee80211_key_len {
  	WLAN_KEY_LEN_BIP_GMAC_256 = 32,
  };
  
diff --git a/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch
index 2b7bdabfe3..f0f864c7e7 100644
--- a/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch
+++ b/package/kernel/mac80211/patches/subsys/390-mac80211-introduce-individual-TWT-support-in-AP-mode.patch
@@ -1,3 +1,4 @@
+From f5a4c24e689f54e66201f04d343bdd2e8a1d7923 Mon Sep 17 00:00:00 2001
 From: Lorenzo Bianconi <lorenzo at kernel.org>
 Date: Mon, 23 Aug 2021 20:02:39 +0200
 Subject: [PATCH] mac80211: introduce individual TWT support in AP mode
@@ -24,10 +25,33 @@ Link: https://lore.kernel.org/r/257512f2e22ba42b9f2624942a128dd8f141de4b.1629741
  fix to use ieee80211_get_he_iftype_cap() correctly]
 Signed-off-by: Johannes Berg <johannes.berg at intel.com>
 ---
+ include/net/mac80211.h     |  12 +++
+ net/mac80211/driver-ops.h  |  36 ++++++++
+ net/mac80211/ieee80211_i.h |   6 ++
+ net/mac80211/iface.c       |  41 +++++++++
+ net/mac80211/rx.c          |  73 +++++++++++++++
+ net/mac80211/s1g.c         | 180 +++++++++++++++++++++++++++++++++++++
+ net/mac80211/status.c      |  17 +++-
+ net/mac80211/trace.h       |  67 ++++++++++++++
+ 8 files changed, 430 insertions(+), 2 deletions(-)
 
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -4229,6 +4229,11 @@ struct ieee80211_ops {
+@@ -3930,6 +3930,13 @@ struct ieee80211_prep_tx_info {
+  * @set_sar_specs: Update the SAR (TX power) settings.
+  * @sta_set_decap_offload: Called to notify the driver when a station is allowed
+  *	to use rx decapsulation offload
++ * @add_twt_setup: Update hw with TWT agreement parameters received from the peer.
++ *	This callback allows the hw to check if requested parameters
++ *	are supported and if there is enough room for a new agreement.
++ *	The hw is expected to set agreement result in the req_type field of
++ *	twt structure.
++ * @twt_teardown_request: Update the hw with TWT teardown request received
++ *	from the peer.
+  */
+ struct ieee80211_ops {
+ 	void (*tx)(struct ieee80211_hw *hw,
+@@ -4253,6 +4260,11 @@ struct ieee80211_ops {
  	void (*sta_set_decap_offload)(struct ieee80211_hw *hw,
  				      struct ieee80211_vif *vif,
  				      struct ieee80211_sta *sta, bool enabled);
@@ -41,7 +65,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  /**
 --- a/net/mac80211/driver-ops.h
 +++ b/net/mac80211/driver-ops.h
-@@ -1429,4 +1429,40 @@ static inline void drv_sta_set_decap_off
+@@ -1447,4 +1447,40 @@ static inline void drv_sta_set_decap_off
  	trace_drv_return_void(local);
  }
  
@@ -92,7 +116,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  
  	u8 needed_rx_chains;
  	enum ieee80211_smps_mode smps_mode;
-@@ -2088,6 +2089,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
+@@ -2083,6 +2084,11 @@ ieee80211_he_op_ie_to_bss_conf(struct ie
  
  /* S1G */
  void ieee80211_s1g_sta_rate_init(struct sta_info *sta);
@@ -122,8 +146,25 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	INIT_WORK(&sdata->work, ieee80211_iface_work);
  
  	return 0;
-@@ -1396,6 +1398,24 @@ static void ieee80211_if_setup_no_queue(
- 	dev->priv_flags |= IFF_NO_QUEUE;
+@@ -1459,6 +1461,16 @@ static void ieee80211_iface_process_skb(
+ 			WARN_ON(1);
+ 			break;
+ 		}
++	} else if (ieee80211_is_action(mgmt->frame_control) &&
++		   mgmt->u.action.category == WLAN_CATEGORY_S1G) {
++		switch (mgmt->u.action.u.s1g.action_code) {
++		case WLAN_S1G_TWT_TEARDOWN:
++		case WLAN_S1G_TWT_SETUP:
++			ieee80211_s1g_rx_twt_action(sdata, skb);
++			break;
++		default:
++			break;
++		}
+ 	} else if (ieee80211_is_ext(mgmt->frame_control)) {
+ 		if (sdata->vif.type == NL80211_IFTYPE_STATION)
+ 			ieee80211_sta_rx_queued_ext(sdata, skb);
+@@ -1514,6 +1526,24 @@ static void ieee80211_iface_process_skb(
+ 	}
  }
  
 +static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
@@ -147,37 +188,24 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  static void ieee80211_iface_work(struct work_struct *work)
  {
  	struct ieee80211_sub_if_data *sdata =
-@@ -1474,6 +1494,16 @@ static void ieee80211_iface_work(struct
- 				WARN_ON(1);
- 				break;
- 			}
-+		} else if (ieee80211_is_action(mgmt->frame_control) &&
-+			   mgmt->u.action.category == WLAN_CATEGORY_S1G) {
-+			switch (mgmt->u.action.u.s1g.action_code) {
-+			case WLAN_S1G_TWT_TEARDOWN:
-+			case WLAN_S1G_TWT_SETUP:
-+				ieee80211_s1g_rx_twt_action(sdata, skb);
-+				break;
-+			default:
-+				break;
-+			}
- 		} else if (ieee80211_is_ext(mgmt->frame_control)) {
- 			if (sdata->vif.type == NL80211_IFTYPE_STATION)
- 				ieee80211_sta_rx_queued_ext(sdata, skb);
-@@ -1530,6 +1560,12 @@ static void ieee80211_iface_work(struct
+@@ -1543,6 +1573,16 @@ static void ieee80211_iface_work(struct
  		kcov_remote_stop();
  	}
  
 +	/* process status queue */
 +	while ((skb = skb_dequeue(&sdata->status_queue))) {
++		kcov_remote_start_common(skb_get_kcov_handle(skb));
++
 +		ieee80211_iface_process_status(sdata, skb);
 +		kfree_skb(skb);
++
++		kcov_remote_stop();
 +	}
 +
  	/* then other type-dependent work */
  	switch (sdata->vif.type) {
  	case NL80211_IFTYPE_STATION:
-@@ -1593,6 +1629,7 @@ static void ieee80211_setup_sdata(struct
+@@ -1606,6 +1646,7 @@ static void ieee80211_setup_sdata(struct
  	}
  
  	skb_queue_head_init(&sdata->skb_queue);
@@ -187,7 +215,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 --- a/net/mac80211/rx.c
 +++ b/net/mac80211/rx.c
-@@ -3198,6 +3198,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
+@@ -3211,6 +3211,68 @@ ieee80211_rx_h_mgmt_check(struct ieee802
  	return RX_CONTINUE;
  }
  
@@ -256,7 +284,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  static ieee80211_rx_result debug_noinline
  ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
  {
-@@ -3477,6 +3539,17 @@ ieee80211_rx_h_action(struct ieee80211_r
+@@ -3490,6 +3552,17 @@ ieee80211_rx_h_action(struct ieee80211_r
  		    !mesh_path_sel_is_hwmp(sdata))
  			break;
  		goto queue;
@@ -500,7 +528,7 @@ Signed-off-by: Johannes Berg <johannes.berg at intel.com>
  		rcu_read_unlock();
 --- a/net/mac80211/trace.h
 +++ b/net/mac80211/trace.h
-@@ -2804,6 +2804,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_d
+@@ -2825,6 +2825,73 @@ DEFINE_EVENT(sta_flag_evt, drv_sta_set_d
  	TP_ARGS(local, sdata, sta, enabled)
  );
  
diff --git a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch
index 870d6283b7..b9fd8e3ea2 100644
--- a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch
+++ b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch
@@ -5,7 +5,7 @@ and we should ignore this.
 
 --- a/net/wireless/core.c
 +++ b/net/wireless/core.c
-@@ -637,21 +637,6 @@ static int wiphy_verify_combinations(str
+@@ -629,21 +629,6 @@ static int wiphy_verify_combinations(str
  				    c->limits[j].max > 1))
  				return -EINVAL;
  
diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
index 6d4a9c21a5..1775dc44b1 100644
--- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
+++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
@@ -1,6 +1,6 @@
 --- a/include/net/cfg80211.h
 +++ b/include/net/cfg80211.h
-@@ -3826,6 +3826,7 @@ struct mgmt_frame_regs {
+@@ -3835,6 +3835,7 @@ struct mgmt_frame_regs {
   *	(as advertised by the nl80211 feature flag.)
   * @get_tx_power: store the current TX power into the dbm variable;
   *	return 0 if successful
@@ -8,7 +8,7 @@
   *
   * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
   *	functions to adjust rfkill hw state
-@@ -4150,6 +4151,7 @@ struct cfg80211_ops {
+@@ -4159,6 +4160,7 @@ struct cfg80211_ops {
  				enum nl80211_tx_power_setting type, int mbm);
  	int	(*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
  				int *dbm);
@@ -18,7 +18,7 @@
  
 --- a/include/net/mac80211.h
 +++ b/include/net/mac80211.h
-@@ -1564,6 +1564,7 @@ enum ieee80211_smps_mode {
+@@ -1566,6 +1566,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
-@@ -1584,6 +1585,7 @@ enum ieee80211_smps_mode {
+@@ -1586,6 +1587,7 @@ enum ieee80211_smps_mode {
  struct ieee80211_conf {
  	u32 flags;
  	int power_level, dynamic_ps_timeout;
@@ -57,7 +57,7 @@
  	__NL80211_ATTR_AFTER_LAST,
 --- a/net/mac80211/cfg.c
 +++ b/net/mac80211/cfg.c
-@@ -2768,6 +2768,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2760,6 +2760,19 @@ static int ieee80211_get_tx_power(struct
  	return 0;
  }
  
@@ -77,7 +77,7 @@
  static void ieee80211_rfkill_poll(struct wiphy *wiphy)
  {
  	struct ieee80211_local *local = wiphy_priv(wiphy);
-@@ -4403,6 +4416,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -4395,6 +4408,7 @@ const struct cfg80211_ops mac80211_confi
  	.set_wiphy_params = ieee80211_set_wiphy_params,
  	.set_tx_power = ieee80211_set_tx_power,
  	.get_tx_power = ieee80211_get_tx_power,
@@ -137,7 +137,7 @@
  };
  
  /* policy for the key attributes */
-@@ -3317,6 +3318,20 @@ static int nl80211_set_wiphy(struct sk_b
+@@ -3325,6 +3326,20 @@ static int nl80211_set_wiphy(struct sk_b
  			goto out;
  	}
  
diff --git a/package/network/utils/iw/patches/001-nl80211_h_sync.patch b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
index 2f724b61ff..f788e6915f 100644
--- a/package/network/utils/iw/patches/001-nl80211_h_sync.patch
+++ b/package/network/utils/iw/patches/001-nl80211_h_sync.patch
@@ -1,5 +1,14 @@
 --- a/nl80211.h
 +++ b/nl80211.h
+@@ -11,7 +11,7 @@
+  * Copyright 2008 Jouni Malinen <jouni.malinen at atheros.com>
+  * Copyright 2008 Colin McCabe <colin at cozybit.com>
+  * Copyright 2015-2017	Intel Deutschland GmbH
+- * Copyright (C) 2018-2020 Intel Corporation
++ * Copyright (C) 2018-2021 Intel Corporation
+  *
+  * Permission to use, copy, modify, and/or distribute this software for any
+  * purpose with or without fee is hereby granted, provided that the above
 @@ -655,6 +655,9 @@
   *	When a security association was established on an 802.1X network using
   *	fast transition, this event should be followed by an
@@ -160,7 +169,24 @@
  	/* add attributes here, update the policy in nl80211.c */
  
  	__NL80211_ATTR_AFTER_LAST,
-@@ -5896,6 +5981,22 @@ enum nl80211_feature_flags {
+@@ -3613,6 +3698,8 @@ enum nl80211_mpath_info {
+  *     defined
+  * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16),
+  *	given for all 6 GHz band channels
++ * @NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS: vendor element capabilities that are
++ *	advertised on this band/for this iftype (binary)
+  * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use
+  */
+ enum nl80211_band_iftype_attr {
+@@ -3624,6 +3711,7 @@ enum nl80211_band_iftype_attr {
+ 	NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET,
+ 	NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE,
+ 	NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA,
++	NL80211_BAND_IFTYPE_ATTR_VENDOR_ELEMS,
+ 
+ 	/* keep last */
+ 	__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST,
+@@ -5896,6 +5984,22 @@ enum nl80211_feature_flags {
   * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports
   *	unsolicited broadcast probe response transmission
   *
@@ -183,7 +209,7 @@
   * @NUM_NL80211_EXT_FEATURES: number of extended features.
   * @MAX_NL80211_EXT_FEATURES: highest extended feature index.
   */
-@@ -5956,6 +6057,11 @@ enum nl80211_ext_feature_index {
+@@ -5956,6 +6060,11 @@ enum nl80211_ext_feature_index {
  	NL80211_EXT_FEATURE_SAE_OFFLOAD_AP,
  	NL80211_EXT_FEATURE_FILS_DISCOVERY,
  	NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP,
@@ -195,7 +221,7 @@
  
  	/* add new features before the definition below */
  	NUM_NL80211_EXT_FEATURES,
-@@ -6253,11 +6359,13 @@ struct nl80211_vendor_cmd_info {
+@@ -6253,11 +6362,13 @@ struct nl80211_vendor_cmd_info {
   * @NL80211_TDLS_PEER_HT: TDLS peer is HT capable.
   * @NL80211_TDLS_PEER_VHT: TDLS peer is VHT capable.
   * @NL80211_TDLS_PEER_WMM: TDLS peer is WMM capable.
@@ -209,25 +235,29 @@
  };
  
  /**
-@@ -6849,6 +6957,9 @@ enum nl80211_peer_measurement_ftm_capa {
+@@ -6849,6 +6960,12 @@ enum nl80211_peer_measurement_ftm_capa {
   *      if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor
   *	%NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based
   *	ranging will be used.
 + * @NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK: negotiate for LMR feedback. Only
 + *	valid if either %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED or
 + *	%NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set.
++ * @NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR: optional. The BSS color of the
++ *	responder. Only valid if %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED
++ *	or %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED is set.
   *
   * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal
   * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number
-@@ -6867,6 +6978,7 @@ enum nl80211_peer_measurement_ftm_req {
+@@ -6867,6 +6984,8 @@ enum nl80211_peer_measurement_ftm_req {
  	NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC,
  	NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED,
  	NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED,
 +	NL80211_PMSR_FTM_REQ_ATTR_LMR_FEEDBACK,
++	NL80211_PMSR_FTM_REQ_ATTR_BSS_COLOR,
  
  	/* keep last */
  	NUM_NL80211_PMSR_FTM_REQ_ATTR,
-@@ -7124,4 +7236,115 @@ enum nl80211_unsol_bcast_probe_resp_attr
+@@ -7124,4 +7243,115 @@ enum nl80211_unsol_bcast_probe_resp_attr
  	NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX =
  		__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1
  };



More information about the lede-commits mailing list