[Refactor and sync wifi from Openwrt]
[Description]
Refactor and sync wifi from Openwrt
1.mt76/mac80211/hostapd/iw/wireless-regdb
[Release-log]
N/A
diff --git a/recipes-connectivity/hostapd/files/patches/991-fix-compile.patch b/recipes-connectivity/hostapd/files/patches/991-fix-compile.patch
new file mode 100644
index 0000000..d08efa0
--- /dev/null
+++ b/recipes-connectivity/hostapd/files/patches/991-fix-compile.patch
@@ -0,0 +1,19 @@
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -8104,6 +8104,7 @@ int wpas_network_disabled(struct wpa_sup
+ !ssid->mem_only_psk)
+ return 1;
+
++#ifdef CONFIG_IEEE8021X_EAPOL
+ #ifdef CRYPTO_RSA_OAEP_SHA256
+ if (ssid->eap.imsi_privacy_cert) {
+ struct crypto_rsa_key *key;
+@@ -8121,7 +8122,7 @@ int wpas_network_disabled(struct wpa_sup
+ }
+ }
+ #endif /* CRYPTO_RSA_OAEP_SHA256 */
+-
++#endif /* CONFIG_IEEE8021X_EAPOL */
+ return 0;
+ }
+
diff --git a/recipes-connectivity/hostapd/files/patches/patches.inc b/recipes-connectivity/hostapd/files/patches/patches.inc
index af2e054..1eb26eb 100644
--- a/recipes-connectivity/hostapd/files/patches/patches.inc
+++ b/recipes-connectivity/hostapd/files/patches/patches.inc
@@ -63,4 +63,5 @@
file://911-master-print-sae-groups-by-hostapd-ctrl.patch \
file://913-master-add-support-for-runtime-set-in-band-discover.patch \
file://990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch \
+ file://991-fix-compile.patch \
"
diff --git a/recipes-connectivity/hostapd/hostapd_2.10.bb b/recipes-connectivity/hostapd/hostapd_2.10.bb
index c36cbe3..e6fac22 100644
--- a/recipes-connectivity/hostapd/hostapd_2.10.bb
+++ b/recipes-connectivity/hostapd/hostapd_2.10.bb
@@ -12,7 +12,7 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
FILESEXTRAPATHS_prepend := "${THISDIR}/files/patches:"
-SRCREV ?= "b859b9bceadccd882252ff0aa2fdba0d3b91764e"
+SRCREV ?= "4383528e01955d995d3b3db201e4c0f9840e8236"
SRC_URI = " \
git://w1.fi/hostap.git;protocol=https;branch=main \
file://hostapd-full.config \
diff --git a/recipes-connectivity/wpa-supplicant/files/patches/991-fix-compile.patch b/recipes-connectivity/wpa-supplicant/files/patches/991-fix-compile.patch
new file mode 100644
index 0000000..d08efa0
--- /dev/null
+++ b/recipes-connectivity/wpa-supplicant/files/patches/991-fix-compile.patch
@@ -0,0 +1,19 @@
+--- a/wpa_supplicant/wpa_supplicant.c
++++ b/wpa_supplicant/wpa_supplicant.c
+@@ -8104,6 +8104,7 @@ int wpas_network_disabled(struct wpa_sup
+ !ssid->mem_only_psk)
+ return 1;
+
++#ifdef CONFIG_IEEE8021X_EAPOL
+ #ifdef CRYPTO_RSA_OAEP_SHA256
+ if (ssid->eap.imsi_privacy_cert) {
+ struct crypto_rsa_key *key;
+@@ -8121,7 +8122,7 @@ int wpas_network_disabled(struct wpa_sup
+ }
+ }
+ #endif /* CRYPTO_RSA_OAEP_SHA256 */
+-
++#endif /* CONFIG_IEEE8021X_EAPOL */
+ return 0;
+ }
+
diff --git a/recipes-connectivity/wpa-supplicant/files/patches/patches.inc b/recipes-connectivity/wpa-supplicant/files/patches/patches.inc
index af2e054..1eb26eb 100644
--- a/recipes-connectivity/wpa-supplicant/files/patches/patches.inc
+++ b/recipes-connectivity/wpa-supplicant/files/patches/patches.inc
@@ -63,4 +63,5 @@
file://911-master-print-sae-groups-by-hostapd-ctrl.patch \
file://913-master-add-support-for-runtime-set-in-band-discover.patch \
file://990-ctrl-make-WNM_AP-functions-dependant-on-CONFIG_AP.patch \
+ file://991-fix-compile.patch \
"
diff --git a/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.10.bb b/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.10.bb
index fad0f81..8e9f458 100644
--- a/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.10.bb
+++ b/recipes-connectivity/wpa-supplicant/wpa-supplicant_2.10.bb
@@ -10,7 +10,7 @@
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
FILESEXTRAPATHS_prepend := "${THISDIR}/files/patches:"
-SRCREV ?= "b859b9bceadccd882252ff0aa2fdba0d3b91764e"
+SRCREV ?= "4383528e01955d995d3b3db201e4c0f9840e8236"
SRC_URI = "git://w1.fi/hostap.git;protocol=https;branch=main \
file://wpa-supplicant.sh \
file://wpa_supplicant.conf \
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/330-mac80211-fix-overflow-issues-in-airtime-fairness-cod.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/330-mac80211-fix-overflow-issues-in-airtime-fairness-cod.patch
deleted file mode 100644
index b7c1507..0000000
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/330-mac80211-fix-overflow-issues-in-airtime-fairness-cod.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 28 May 2022 16:44:53 +0200
-Subject: [PATCH] mac80211: fix overflow issues in airtime fairness code
-
-The airtime weight calculation overflows with a default weight value of 256
-whenever more than 8ms worth of airtime is reported.
-Bigger weight values impose even smaller limits on maximum airtime values.
-This can mess up airtime based calculations for drivers that don't report
-per-PPDU airtime values, but batch up values instead.
-
-Fix this by reordering multiplications/shifts and by reducing unnecessary
-intermediate precision (which was lost in a later stage anyway).
-
-The new shift value limits the maximum weight to 4096, which should be more
-than enough. Any values bigger than that will be rejected.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1602,6 +1602,9 @@ static int sta_apply_parameters(struct i
- mask = params->sta_flags_mask;
- set = params->sta_flags_set;
-
-+ if (params->airtime_weight > BIT(IEEE80211_RECIPROCAL_SHIFT_STA))
-+ return -EINVAL;
-+
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- /*
- * In mesh mode, ASSOCIATED isn't part of the nl80211
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1666,50 +1666,33 @@ static inline struct airtime_info *to_ai
- /* 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.
-+ * The per-sta shift value supports weight values of 1-4096
- */
--#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL
--#define IEEE80211_RECIPROCAL_SHIFT_64 32
--#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U
--#define IEEE80211_RECIPROCAL_SHIFT_32 19
-+#define IEEE80211_RECIPROCAL_SHIFT_SUM 24
-+#define IEEE80211_RECIPROCAL_SHIFT_STA 12
-+#define IEEE80211_WEIGHT_SHIFT 8
-
--static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight)
-+static inline void airtime_weight_set(struct airtime_info *air_info, u32 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;
-- }
-+ if (weight)
-+ weight = BIT(IEEE80211_RECIPROCAL_SHIFT_STA) / weight;
-+ air_info->weight_reciprocal = weight;
- }
-
- static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched,
-- int weight_sum)
-+ u32 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;
-- }
-+ if (weight_sum)
-+ weight_sum = BIT(IEEE80211_RECIPROCAL_SHIFT_SUM) / weight_sum;
-+ air_sched->weight_sum_reciprocal = weight_sum;
- }
-
- /* A problem when trying to enforce airtime fairness is that we want to divide
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -1894,9 +1894,9 @@ void ieee80211_register_airtime(struct i
- {
- 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;
-+ u64 weight_sum_reciprocal;
- u32 airtime = 0;
-
- air_sched = &local->airtime[txq->ac];
-@@ -1907,27 +1907,21 @@ void ieee80211_register_airtime(struct i
- if (local->airtime_flags & AIRTIME_USE_RX)
- airtime += rx_airtime;
-
-- /* 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;
-+ if (air_sched->weight_sum)
- weight_sum_reciprocal = air_sched->weight_sum_reciprocal;
-- } else {
-- weight_sum = air_info->weight;
-+ else
- 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;
-+ air_sched->v_t += ((u64)airtime * weight_sum_reciprocal) >>
-+ (IEEE80211_RECIPROCAL_SHIFT_SUM - IEEE80211_WEIGHT_SHIFT);
-+ air_info->v_t += (airtime * air_info->weight_reciprocal) >>
-+ (IEEE80211_RECIPROCAL_SHIFT_STA - IEEE80211_WEIGHT_SHIFT);
- ieee80211_resort_txq(&local->hw, txq);
-
- spin_unlock_bh(&air_sched->lock);
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/331-mac80211-improve-AQL-tx-time-estimation.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/331-mac80211-improve-AQL-tx-time-estimation.patch
deleted file mode 100644
index 529ad13..0000000
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/331-mac80211-improve-AQL-tx-time-estimation.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 11 Jun 2022 16:34:32 +0200
-Subject: [PATCH] mac80211: improve AQL tx time estimation
-
-If airtime cannot be calculated because of missing or unsupported rate info,
-use the smallest possible non-zero value for estimated tx time.
-This improves handling of these cases by preventing queueing of as many packets
-as the driver/hardware queue can hold for these stations.
-Also slightly improve limiting queueing by explicitly rounding up small values.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1107,20 +1107,24 @@ struct ieee80211_tx_info {
- };
- };
-
-+#define IEEE80211_TX_TIME_EST_UNIT 4
-+
-+static inline u16
-+ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
-+{
-+ return info->tx_time_est * IEEE80211_TX_TIME_EST_UNIT;
-+}
-+
- static inline u16
- ieee80211_info_set_tx_time_est(struct ieee80211_tx_info *info, u16 tx_time_est)
- {
- /* We only have 10 bits in tx_time_est, so store airtime
- * in increments of 4us and clamp the maximum to 2**12-1
- */
-- info->tx_time_est = min_t(u16, tx_time_est, 4095) >> 2;
-- return info->tx_time_est << 2;
--}
-+ tx_time_est = DIV_ROUND_UP(tx_time_est, IEEE80211_TX_TIME_EST_UNIT);
-+ info->tx_time_est = min_t(u16, tx_time_est, BIT(10) - 1);
-
--static inline u16
--ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info)
--{
-- return info->tx_time_est << 2;
-+ return ieee80211_info_get_tx_time_est(info);
- }
-
- /**
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -999,6 +999,8 @@ static void __ieee80211_tx_status(struct
- NULL,
- skb->len,
- false);
-+ if (!airtime)
-+ airtime = IEEE80211_TX_TIME_EST_UNIT;
-
- ieee80211_register_airtime(txq, airtime, 0);
- }
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3798,13 +3798,12 @@ encap_out:
-
- airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
- skb->len, ampdu);
-- if (airtime) {
-- airtime = ieee80211_info_set_tx_time_est(info, airtime);
-- ieee80211_sta_update_pending_airtime(local, tx.sta,
-- txq->ac,
-- airtime,
-- false);
-- }
-+ if (!airtime)
-+ airtime = IEEE80211_TX_TIME_EST_UNIT;
-+
-+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
-+ ieee80211_sta_update_pending_airtime(local, tx.sta, txq->ac,
-+ airtime, false);
- }
-
- return skb;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/332-mac80211-fix-ieee80211_txq_may_transmit-regression.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/332-mac80211-fix-ieee80211_txq_may_transmit-regression.patch
deleted file mode 100644
index e3c08d3..0000000
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/332-mac80211-fix-ieee80211_txq_may_transmit-regression.patch
+++ /dev/null
@@ -1,91 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 11 Jun 2022 17:28:02 +0200
-Subject: [PATCH] mac80211: fix ieee80211_txq_may_transmit regression
-
-After switching to the virtual time based airtime scheduler, there were reports
-that ath10k with tx queueing in push-pull mode was experiencing significant
-latency for some stations.
-The reason for it is the fact that queues from which the ath10k firmware wants
-to pull are getting starved by airtime fairness constraints.
-Theoretically the same issue should have been there before the switch to virtual
-time, however it seems that in the old round-robin implementation it was simply
-looping until the requested txq was considered eligible, which led to it pretty
-much ignoring fairness constraints anyway.
-
-In order to fix the immediate regression, let's make bypassing airtime fairness
-explicit for now.
-Also update the documentation for ieee80211_txq_may_transmit, which was still
-referring to implementation details of the old round-robin scheduler
-
-Fixes: 2433647bc8d9 ("mac80211: Switch to a virtual time-based airtime scheduler")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -6700,22 +6700,11 @@ void ieee80211_return_txq(struct ieee802
- /**
- * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
- *
-- * This function is used to check whether given txq is allowed to transmit by
-- * the airtime scheduler, and can be used by drivers to access the airtime
-- * fairness accounting without going using the scheduling order enfored by
-- * next_txq().
-+ * Returns %true if there is remaining AQL budget for the tx queue and %false
-+ * if it should be throttled. It will also mark the queue as active for the
-+ * airtime scheduler.
- *
-- * Returns %true if the airtime scheduler thinks the TXQ should be allowed to
-- * transmit, and %false if it should be throttled. This function can also have
-- * the side effect of rotating the TXQ in the scheduler rotation, which will
-- * eventually bring the deficit to positive and allow the station to transmit
-- * again.
-- *
-- * The API ieee80211_txq_may_transmit() also ensures that TXQ list will be
-- * aligned against driver's own round-robin scheduler list. i.e it rotates
-- * the TXQ list till it makes the requested node becomes the first entry
-- * in TXQ list. Thus both the TXQ list and driver's list are in sync. If this
-- * function returns %true, the driver is expected to schedule packets
-+ * If this function returns %true, the driver is expected to schedule packets
- * for transmission, and then return the TXQ through ieee80211_return_txq().
- *
- * @hw: pointer as obtained from ieee80211_alloc_hw()
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -4100,15 +4100,13 @@ 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 *txqi = to_txq_info(txq);
- struct airtime_sched_info *air_sched;
- struct airtime_info *air_info;
-- struct rb_node *node = NULL;
- bool ret = false;
- u64 now;
-
--
- if (!ieee80211_txq_airtime_check(hw, txq))
- return false;
-
-@@ -4120,19 +4118,6 @@ bool ieee80211_txq_may_transmit(struct i
-
- now = ktime_get_coarse_boottime_ns();
-
-- /* 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);
-- }
--
- air_info = to_airtime_info(&txqi->txq);
- if (air_info->v_t <= air_sched->v_t) {
- air_sched->last_schedule_activity = now;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/333-mac80211-rework-the-airtime-fairness-implementation.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/333-mac80211-rework-the-airtime-fairness-implementation.patch
deleted file mode 100644
index c900b25..0000000
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/333-mac80211-rework-the-airtime-fairness-implementation.patch
+++ /dev/null
@@ -1,819 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 28 May 2022 16:51:51 +0200
-Subject: [PATCH] mac80211: rework the airtime fairness implementation
-
-The current ATF implementation has a number of issues which have shown up
-during testing. Since it does not take into account the AQL budget of
-pending packets, the implementation might queue up large amounts of packets
-for a single txq until airtime gets reported after tx completion.
-The same then happens to the next txq afterwards. While the end result could
-still be considered fair, the bursty behavior introduces a large amount of
-latency.
-The current code also tries to avoid frequent re-sorting of txq entries in
-order to avoid having to re-balance the rbtree often.
-
-In order to fix these issues, introduce skip lists as a data structure, which
-offer similar lookup/insert/delete times as rbtree, but avoids the need for
-rebalacing by being probabilistic.
-Use this to keep tx entries sorted by virtual time + pending AQL budget and
-re-sort after each ieee80211_return_txq call.
-
-Since multiple txqs share a single air_time struct with a virtual time value,
-switch the active_txqs list to queue up air_time structs instead of queues.
-This helps avoid imbalance between shared txqs by servicing them round robin.
-
-ieee80211_next_txq now only dequeues the first element of active_txqs. To
-make that work for non-AQL or non-ATF drivers as well, add estimated tx
-airtime directly to air_info virtual time if either AQL or ATF is not
-supported.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
- create mode 100644 include/linux/skiplist.h
-
---- /dev/null
-+++ b/include/linux/skiplist.h
-@@ -0,0 +1,250 @@
-+/* SPDX-License-Identifier: GPL-2.0-or-later */
-+/*
-+ * A skip list is a probabilistic alternative to balanced trees. Unlike the
-+ * red-black tree, it does not require rebalancing.
-+ *
-+ * This implementation uses only unidirectional next pointers and is optimized
-+ * for use in a priority queue where elements are mostly deleted from the front
-+ * of the queue.
-+ *
-+ * When storing up to 2^n elements in a n-level skiplist. lookup and deletion
-+ * for the first element happens in O(1) time, other than that, insertion and
-+ * deletion takes O(log n) time, assuming that the number of elements for an
-+ * n-level list does not exceed 2^n.
-+ *
-+ * Usage:
-+ * DECLARE_SKIPLIST_TYPE(foo, 5) will define the data types for a 5-level list:
-+ * struct foo_list: the list data type
-+ * struct foo_node: the node data for an element in the list
-+ *
-+ * DECLARE_SKIPLIST_IMPL(foo, foo_cmp_fn)
-+ *
-+ * Adds the skip list implementation. It depends on a provided function:
-+ * int foo_cmp_fn(struct foo_list *list, struct foo_node *n1, struct foo_node *n2)
-+ * This compares two elements given by their node pointers, returning values <0
-+ * if n1 is less than n2, =0 and >0 for equal or bigger than respectively.
-+ *
-+ * This macro implements the following functions:
-+ *
-+ * void foo_list_init(struct foo_list *list)
-+ * initializes the skip list
-+ *
-+ * void foo_node_init(struct foo_node *node)
-+ * initializes a node. must be called before adding the node to the list
-+ *
-+ * struct foo_node *foo_node_next(struct foo_node *node)
-+ * gets the node directly after the provided node, or NULL if it was the last
-+ * element in the list.
-+ *
-+ * bool foo_is_queued(struct foo_node *node)
-+ * returns true if the node is on a list
-+ *
-+ * struct foo_node *foo_dequeue(struct foo_list *list)
-+ * deletes and returns the first element of the list (or returns NULL if empty)
-+ *
-+ * struct foo_node *foo_peek(struct foo_list *list)
-+ * returns the first element of the list
-+ *
-+ * void foo_insert(struct foo_list *list, struct foo_node *node)
-+ * inserts the node into the list. the node must be initialized and not on a
-+ * list already.
-+ *
-+ * void foo_delete(struct foo_list *list, struct foo_node *node)
-+ * deletes the node from the list, or does nothing if it's not on the list
-+ */
-+#ifndef __SKIPLIST_H
-+#define __SKIPLIST_H
-+
-+#include <linux/bits.h>
-+#include <linux/minmax.h>
-+#include <linux/bug.h>
-+#include <linux/prandom.h>
-+
-+#define SKIPLIST_POISON ((void *)1)
-+
-+#define DECLARE_SKIPLIST_TYPE(name, levels) \
-+struct name##_node { \
-+ struct name##_node *next[levels]; \
-+}; \
-+struct name##_list { \
-+ struct name##_node head; \
-+ unsigned int max_level; \
-+ unsigned int count; \
-+};
-+
-+#define DECLARE_SKIPLIST_IMPL(name, cmp_fn) \
-+static inline void \
-+name##_list_init(struct name##_list *list) \
-+{ \
-+ memset(list, 0, sizeof(*list)); \
-+} \
-+static inline void \
-+name##_node_init(struct name##_node *node) \
-+{ \
-+ node->next[0] = SKIPLIST_POISON; \
-+} \
-+static inline struct name##_node * \
-+name##_node_next(struct name##_node *node) \
-+{ \
-+ return node->next[0]; \
-+} \
-+static inline bool \
-+name##_is_queued(struct name##_node *node) \
-+{ \
-+ return node->next[0] != SKIPLIST_POISON; \
-+} \
-+static inline int \
-+__skiplist_##name##_cmp_impl(void *head, void *n1, void *n2) \
-+{ \
-+ return cmp_fn(head, n1, n2); \
-+} \
-+static inline void \
-+__##name##_delete(struct name##_list *list) \
-+{ \
-+ list->count--; \
-+ while (list->max_level && \
-+ !list->head.next[list->max_level]) \
-+ list->max_level--; \
-+} \
-+static inline struct name##_node * \
-+name##_dequeue(struct name##_list *list) \
-+{ \
-+ struct name##_node *ret; \
-+ unsigned int max_level = ARRAY_SIZE(list->head.next) - 1; \
-+ ret = (void *)__skiplist_dequeue((void **)&list->head, \
-+ max_level); \
-+ if (!ret) \
-+ return NULL; \
-+ __##name##_delete(list); \
-+ return ret; \
-+} \
-+static inline struct name##_node * \
-+name##_peek(struct name##_list *list) \
-+{ \
-+ return list->head.next[0]; \
-+} \
-+static inline void \
-+name##_insert(struct name##_list *list, struct name##_node *node) \
-+{ \
-+ int level = __skiplist_level(ARRAY_SIZE(list->head.next) - 1, \
-+ list->count, prandom_u32()); \
-+ level = min_t(int, level, list->max_level + 1); \
-+ __skiplist_insert((void *)&list->head, (void *)node, level, \
-+ __skiplist_##name##_cmp_impl); \
-+ if (level > list->max_level) \
-+ list->max_level = level; \
-+ list->count++; \
-+} \
-+static inline void \
-+name##_delete(struct name##_list *list, struct name##_node *node) \
-+{ \
-+ if (node->next[0] == SKIPLIST_POISON) \
-+ return; \
-+ __skiplist_delete((void *)&list->head, (void *)node, \
-+ ARRAY_SIZE(list->head.next) - 1, \
-+ __skiplist_##name##_cmp_impl); \
-+ __##name##_delete(list); \
-+}
-+
-+
-+typedef int (*__skiplist_cmp_t)(void *head, void *n1, void *n2);
-+
-+#define __skiplist_cmp(cmp, head, cur, node) \
-+ ({ \
-+ int cmp_val = cmp(head, cur, node); \
-+ if (!cmp_val) \
-+ cmp_val = (unsigned long)(cur) - \
-+ (unsigned long)(node); \
-+ cmp_val; \
-+ })
-+
-+static inline void *
-+__skiplist_dequeue(void **list, int max_level)
-+{
-+ void **node = list[0];
-+ unsigned int i;
-+
-+ if (!node)
-+ return NULL;
-+
-+ list[0] = node[0];
-+ for (i = 1; i <= max_level; i++) {
-+ if (list[i] != node)
-+ break;
-+
-+ list[i] = node[i];
-+ }
-+ node[0] = SKIPLIST_POISON;
-+
-+ return node;
-+}
-+
-+static inline void
-+__skiplist_insert(void **list, void **node, int level, __skiplist_cmp_t cmp)
-+{
-+ void **head = list;
-+
-+ if (WARN(node[0] != SKIPLIST_POISON, "Insert on already inserted or uninitialized node"))
-+ return;
-+ for (; level >= 0; level--) {
-+ while (list[level] &&
-+ __skiplist_cmp(cmp, head, list[level], node) < 0)
-+ list = list[level];
-+
-+ node[level] = list[level];
-+ list[level] = node;
-+ }
-+}
-+
-+
-+static inline void
-+__skiplist_delete(void **list, void **node, int max_level, __skiplist_cmp_t cmp)
-+{
-+ void *head = list;
-+ int i;
-+
-+ for (i = max_level; i >= 0; i--) {
-+ while (list[i] && list[i] != node &&
-+ __skiplist_cmp(cmp, head, list[i], node) <= 0)
-+ list = list[i];
-+
-+ if (list[i] != node)
-+ continue;
-+
-+ list[i] = node[i];
-+ }
-+ node[0] = SKIPLIST_POISON;
-+}
-+
-+static inline unsigned int
-+__skiplist_level(unsigned int max_level, unsigned int count, unsigned int seed)
-+{
-+ unsigned int level = 0;
-+
-+ if (max_level >= 16 && !(seed & GENMASK(15, 0))) {
-+ level += 16;
-+ seed >>= 16;
-+ }
-+
-+ if (max_level >= 8 && !(seed & GENMASK(7, 0))) {
-+ level += 8;
-+ seed >>= 8;
-+ }
-+
-+ if (max_level >= 4 && !(seed & GENMASK(3, 0))) {
-+ level += 4;
-+ seed >>= 4;
-+ }
-+
-+ if (!(seed & GENMASK(1, 0))) {
-+ level += 2;
-+ seed >>= 2;
-+ }
-+
-+ if (!(seed & BIT(0)))
-+ level++;
-+
-+ return min(level, max_level);
-+}
-+
-+#endif
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -1563,7 +1563,6 @@ static void sta_apply_airtime_params(str
- 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);
-@@ -1575,10 +1574,6 @@ static void sta_apply_airtime_params(str
-
- 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);
- }
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -25,7 +25,8 @@
- #include <linux/leds.h>
- #include <linux/idr.h>
- #include <linux/rhashtable.h>
--#include <linux/rbtree.h>
-+#include <linux/prandom.h>
-+#include <linux/skiplist.h>
- #include <net/ieee80211_radiotap.h>
- #include <net/cfg80211.h>
- #include <net/mac80211.h>
-@@ -854,6 +855,7 @@ enum txq_info_flags {
- IEEE80211_TXQ_AMPDU,
- IEEE80211_TXQ_NO_AMSDU,
- IEEE80211_TXQ_STOP_NETIF_TX,
-+ IEEE80211_TXQ_FORCE_ACTIVE,
- };
-
- /**
-@@ -870,7 +872,6 @@ struct txq_info {
- struct fq_tin tin;
- struct codel_vars def_cvars;
- struct codel_stats cstats;
-- struct rb_node schedule_order;
-
- struct sk_buff_head frags;
- unsigned long flags;
-@@ -1185,8 +1186,7 @@ enum mac80211_scan_state {
- *
- * @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()
-+ * @schedule_pos: last used airtime_info node while a driver walks the tree
- * @active_list: list of struct airtime_info structs that were active within
- * the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute
- * weight_sum
-@@ -1207,8 +1207,8 @@ enum mac80211_scan_state {
- */
- struct airtime_sched_info {
- spinlock_t lock;
-- struct rb_root_cached active_txqs;
-- struct rb_node *schedule_pos;
-+ struct airtime_sched_list active_txqs;
-+ struct airtime_sched_node *schedule_pos;
- struct list_head active_list;
- u64 last_weight_update;
- u64 last_schedule_activity;
-@@ -1663,6 +1663,20 @@ static inline struct airtime_info *to_ai
- return &sdata->airtime[txq->ac];
- }
-
-+static inline int
-+airtime_sched_cmp(struct airtime_sched_list *list,
-+ struct airtime_sched_node *n1, struct airtime_sched_node *n2)
-+{
-+ struct airtime_info *a1, *a2;
-+
-+ a1 = container_of(n1, struct airtime_info, schedule_order);
-+ a2 = container_of(n2, struct airtime_info, schedule_order);
-+
-+ return a1->v_t_cur - a2->v_t_cur;
-+}
-+
-+DECLARE_SKIPLIST_IMPL(airtime_sched, airtime_sched_cmp);
-+
- /* 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.
-@@ -1749,6 +1763,7 @@ static inline void init_airtime_info(str
- 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);
-+ airtime_sched_node_init(&air_info->schedule_order);
- }
-
- static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
---- a/net/mac80211/main.c
-+++ b/net/mac80211/main.c
-@@ -709,7 +709,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
- for (i = 0; i < IEEE80211_NUM_ACS; i++) {
- struct airtime_sched_info *air_sched = &local->airtime[i];
-
-- air_sched->active_txqs = RB_ROOT_CACHED;
-+ airtime_sched_list_init(&air_sched->active_txqs);
- 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;
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -1902,8 +1902,7 @@ void ieee80211_register_airtime(struct i
- air_sched = &local->airtime[txq->ac];
- air_info = to_airtime_info(txq);
-
-- if (local->airtime_flags & AIRTIME_USE_TX)
-- airtime += tx_airtime;
-+ airtime += tx_airtime;
- if (local->airtime_flags & AIRTIME_USE_RX)
- airtime += rx_airtime;
-
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -135,11 +135,14 @@ enum ieee80211_agg_stop_reason {
- #define AIRTIME_USE_TX BIT(0)
- #define AIRTIME_USE_RX BIT(1)
-
-+DECLARE_SKIPLIST_TYPE(airtime_sched, 5);
-
- struct airtime_info {
-+ struct airtime_sched_node schedule_order;
-+ struct ieee80211_txq *txq[3];
- u64 rx_airtime;
- u64 tx_airtime;
-- u64 v_t;
-+ u64 v_t, v_t_cur;
- u64 last_scheduled;
- struct list_head list;
- atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
-@@ -147,6 +150,7 @@ struct airtime_info {
- u32 aql_limit_high;
- u32 weight_reciprocal;
- u16 weight;
-+ u8 txq_idx;
- };
-
- void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -19,6 +19,7 @@
- #include <linux/rcupdate.h>
- #include <linux/export.h>
- #include <linux/timekeeping.h>
-+#include <linux/prandom.h>
- #include <net/net_namespace.h>
- #include <net/ieee80211_radiotap.h>
- #include <net/cfg80211.h>
-@@ -1476,11 +1477,12 @@ void ieee80211_txq_init(struct ieee80211
- struct sta_info *sta,
- struct txq_info *txqi, int tid)
- {
-+ struct airtime_info *air_info;
-+
- fq_tin_init(&txqi->tin);
- codel_vars_init(&txqi->def_cvars);
- codel_stats_init(&txqi->cstats);
- __skb_queue_head_init(&txqi->frags);
-- RB_CLEAR_NODE(&txqi->schedule_order);
-
- txqi->txq.vif = &sdata->vif;
-
-@@ -1489,7 +1491,7 @@ void ieee80211_txq_init(struct ieee80211
- txqi->txq.tid = 0;
- txqi->txq.ac = IEEE80211_AC_BE;
-
-- return;
-+ goto out;
- }
-
- if (tid == IEEE80211_NUM_TIDS) {
-@@ -1511,6 +1513,12 @@ void ieee80211_txq_init(struct ieee80211
- txqi->txq.sta = &sta->sta;
- txqi->txq.tid = tid;
- sta->sta.txq[tid] = &txqi->txq;
-+
-+out:
-+ air_info = to_airtime_info(&txqi->txq);
-+ air_info->txq[air_info->txq_idx++] = &txqi->txq;
-+ if (air_info->txq_idx == ARRAY_SIZE(air_info->txq))
-+ air_info->txq_idx--;
- }
-
- void ieee80211_txq_purge(struct ieee80211_local *local,
-@@ -3633,6 +3641,8 @@ struct sk_buff *ieee80211_tx_dequeue(str
- struct ieee80211_tx_data tx;
- ieee80211_tx_result r;
- struct ieee80211_vif *vif = txq->vif;
-+ u32 airtime;
-+ bool ampdu;
-
- WARN_ON_ONCE(softirq_count() == 0);
-
-@@ -3791,20 +3801,35 @@ begin:
- encap_out:
- IEEE80211_SKB_CB(skb)->control.vif = vif;
-
-- if (vif &&
-- wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
-- bool ampdu = txq->ac != IEEE80211_AC_VO;
-- u32 airtime;
--
-- airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
-- skb->len, ampdu);
-- if (!airtime)
-- airtime = IEEE80211_TX_TIME_EST_UNIT;
--
-- airtime = ieee80211_info_set_tx_time_est(info, airtime);
-- ieee80211_sta_update_pending_airtime(local, tx.sta, txq->ac,
-- airtime, false);
-- }
-+ if (!vif)
-+ return skb;
-+
-+ ampdu = txq->ac != IEEE80211_AC_VO;
-+ airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta,
-+ skb->len, ampdu);
-+ if (!airtime)
-+ airtime = IEEE80211_TX_TIME_EST_UNIT;
-+
-+ /*
-+ * Tx queue scheduling always happens in airtime order and queues are
-+ * sorted by virtual time + pending AQL budget.
-+ * If AQL is not supported, pending AQL budget is always zero.
-+ * If airtime fairness is not supported, virtual time won't be directly
-+ * increased by driver tx completion.
-+ * Because of that, we register estimated tx time as airtime if either
-+ * AQL or ATF support is missing.
-+ */
-+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL) ||
-+ !wiphy_ext_feature_isset(local->hw.wiphy,
-+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
-+ ieee80211_register_airtime(txq, airtime, 0);
-+
-+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
-+ return skb;
-+
-+ airtime = ieee80211_info_set_tx_time_est(info, airtime);
-+ ieee80211_sta_update_pending_airtime(local, tx.sta, txq->ac,
-+ airtime, false);
-
- return skb;
-
-@@ -3815,85 +3840,92 @@ out:
- }
- EXPORT_SYMBOL(ieee80211_tx_dequeue);
-
-+static struct ieee80211_txq *
-+airtime_info_next_txq_idx(struct airtime_info *air_info)
-+{
-+ air_info->txq_idx++;
-+ if (air_info->txq_idx >= ARRAY_SIZE(air_info->txq) ||
-+ !air_info->txq[air_info->txq_idx])
-+ air_info->txq_idx = 0;
-+ return air_info->txq[air_info->txq_idx];
-+}
-+
- 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_coarse_boottime_ns();
-- struct ieee80211_txq *ret = NULL;
-+ struct airtime_sched_node *node = NULL;
-+ struct ieee80211_txq *txq;
- struct airtime_info *air_info;
- struct txq_info *txqi = NULL;
-- struct rb_node *node;
-- bool first = false;
-+ u8 txq_idx;
-
- air_sched = &local->airtime[ac];
- spin_lock_bh(&air_sched->lock);
-
-- node = air_sched->schedule_pos;
--
- begin:
-- if (!node) {
-- node = rb_first_cached(&air_sched->active_txqs);
-- first = true;
-- } else {
-- node = rb_next(node);
-- }
-+ txq = NULL;
-+ if (airtime_sched_peek(&air_sched->active_txqs) ==
-+ air_sched->schedule_pos)
-+ goto out;
-
-+ node = airtime_sched_dequeue(&air_sched->active_txqs);
- if (!node)
- goto out;
-
-- txqi = container_of(node, struct txq_info, schedule_order);
-- air_info = to_airtime_info(&txqi->txq);
-+ air_info = container_of(node, struct airtime_info, schedule_order);
-
-- 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;
-+ txq = airtime_info_next_txq_idx(air_info);
-+ txq_idx = air_info->txq_idx;
-+ if (!ieee80211_txq_airtime_check(hw, txq))
- goto begin;
-+
-+ while (1) {
-+ txqi = to_txq_info(txq);
-+ if (test_and_clear_bit(IEEE80211_TXQ_FORCE_ACTIVE, &txqi->flags))
-+ break;
-+
-+ if (txq_has_queue(txq))
-+ break;
-+
-+ txq = airtime_info_next_txq_idx(air_info);
-+ if (txq_idx == air_info->txq_idx)
-+ goto begin;
- }
-
-+ if (air_info->v_t_cur > air_sched->v_t)
-+ airtime_catchup_v_t(air_sched, air_info->v_t_cur, now);
-+
- air_sched->schedule_pos = node;
- air_sched->last_schedule_activity = now;
-- ret = &txqi->txq;
- out:
- spin_unlock_bh(&air_sched->lock);
-- return ret;
-+ return txq;
- }
- EXPORT_SYMBOL(ieee80211_next_txq);
-
--static void __ieee80211_insert_txq(struct rb_root_cached *root,
-+static void __ieee80211_insert_txq(struct ieee80211_local *local,
-+ struct airtime_sched_info *air_sched,
- 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);
-+ struct airtime_info *air_info = to_airtime_info(&txqi->txq);
-+ u32 aql_time = 0;
-
-- if (new_air->v_t <= old_air->v_t) {
-- new = &parent->rb_left;
-- } else {
-- new = &parent->rb_right;
-- leftmost = false;
-- }
-+ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
-+ aql_time = atomic_read(&air_info->aql_tx_pending);
-+ aql_time *= air_info->weight_reciprocal;
-+ aql_time >>= IEEE80211_RECIPROCAL_SHIFT_STA - IEEE80211_WEIGHT_SHIFT;
- }
-
-- rb_link_node(&txqi->schedule_order, parent, new);
-- rb_insert_color_cached(&txqi->schedule_order, root, leftmost);
-+ airtime_sched_delete(&air_sched->active_txqs, &air_info->schedule_order);
-+ air_info->v_t_cur = air_info->v_t + aql_time;
-+ airtime_sched_insert(&air_sched->active_txqs, &air_info->schedule_order);
- }
-
- 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;
-@@ -3901,41 +3933,7 @@ void ieee80211_resort_txq(struct ieee802
- 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);
-- }
-+ __ieee80211_insert_txq(local, air_sched, txqi);
- }
-
- void ieee80211_update_airtime_weight(struct ieee80211_local *local,
-@@ -3984,7 +3982,7 @@ void ieee80211_schedule_txq(struct ieee8
- was_active = airtime_is_active(air_info, now);
- airtime_set_active(air_sched, air_info, now);
-
-- if (!RB_EMPTY_NODE(&txqi->schedule_order))
-+ if (airtime_sched_is_queued(&air_info->schedule_order))
- goto out;
-
- /* If the station has been inactive for a while, catch up its v_t so it
-@@ -3996,7 +3994,7 @@ void ieee80211_schedule_txq(struct ieee8
- 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);
-+ __ieee80211_insert_txq(local, air_sched, txqi);
-
- out:
- spin_unlock_bh(&air_sched->lock);
-@@ -4017,24 +4015,14 @@ static void __ieee80211_unschedule_txq(s
-
- lockdep_assert_held(&air_sched->lock);
-
-+ airtime_sched_delete(&air_sched->active_txqs, &air_info->schedule_order);
- if (purge) {
- list_del_init(&air_info->list);
- ieee80211_update_airtime_weight(local, air_sched, 0, true);
-- }
--
-- 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)
-+ } else {
- airtime_set_active(air_sched, air_info,
- ktime_get_coarse_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,
-@@ -4054,14 +4042,22 @@ void ieee80211_return_txq(struct ieee802
- {
- 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->airtime[txq->ac].lock);
-+ air_sched = &local->airtime[txq->ac];
-+ air_info = to_airtime_info(&txqi->txq);
-
-- if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force &&
-- !txq_has_queue(txq))
-- __ieee80211_unschedule_txq(hw, txq, false);
-+ if (force)
-+ set_bit(IEEE80211_TXQ_FORCE_ACTIVE, &txqi->flags);
-
-- spin_unlock_bh(&local->airtime[txq->ac].lock);
-+ spin_lock_bh(&air_sched->lock);
-+ if (force || (txq_has_queue(txq) &&
-+ ieee80211_txq_airtime_check(hw, &txqi->txq)))
-+ __ieee80211_insert_txq(local, air_sched, txqi);
-+ else
-+ __ieee80211_unschedule_txq(hw, txq, false);
-+ spin_unlock_bh(&air_sched->lock);
- }
- EXPORT_SYMBOL(ieee80211_return_txq);
-
-@@ -4113,9 +4109,6 @@ bool ieee80211_txq_may_transmit(struct i
- air_sched = &local->airtime[txq->ac];
- spin_lock_bh(&air_sched->lock);
-
-- if (RB_EMPTY_NODE(&txqi->schedule_order))
-- goto out;
--
- now = ktime_get_coarse_boottime_ns();
-
- air_info = to_airtime_info(&txqi->txq);
-@@ -4124,7 +4117,6 @@ bool ieee80211_txq_may_transmit(struct i
- ret = true;
- }
-
--out:
- spin_unlock_bh(&air_sched->lock);
- return ret;
- }
-@@ -4135,9 +4127,7 @@ void ieee80211_txq_schedule_start(struct
- struct ieee80211_local *local = hw_to_local(hw);
- struct airtime_sched_info *air_sched = &local->airtime[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/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
index 6339f85..5924a05 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
@@ -26,7 +26,7 @@
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -2422,6 +2422,9 @@ struct ieee80211_txq {
+@@ -2418,6 +2418,9 @@ struct ieee80211_txq {
* usage and 802.11 frames with %RX_FLAG_ONLY_MONITOR set for monitor to
* the stack.
*
@@ -36,7 +36,7 @@
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/
enum ieee80211_hw_flags {
-@@ -2477,6 +2480,7 @@ enum ieee80211_hw_flags {
+@@ -2473,6 +2476,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD,
IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP,
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/500-mac80211_configure_antenna_gain.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/500-mac80211_configure_antenna_gain.patch
index 15632e4..612b9d6 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/500-mac80211_configure_antenna_gain.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/500-mac80211_configure_antenna_gain.patch
@@ -18,7 +18,7 @@
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
-@@ -1570,6 +1570,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
-@@ -1590,6 +1591,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
-@@ -2843,6 +2843,19 @@ static int ieee80211_get_tx_power(struct
+@@ -2845,6 +2845,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);
-@@ -4547,6 +4560,7 @@ const struct cfg80211_ops mac80211_confi
+@@ -4549,6 +4562,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,
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/907-mac80211-fix-331-include-minmax-fail.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/907-mac80211-fix-331-include-minmax-fail.patch
deleted file mode 100644
index aa96a7e..0000000
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/907-mac80211-fix-331-include-minmax-fail.patch
+++ /dev/null
@@ -1,16 +0,0 @@
-diff --git a/include/linux/skiplist.h b/include/linux/skiplist.h
-index 2312ed8..0677cb7 100644
---- a/include/linux/skiplist.h
-+++ b/include/linux/skiplist.h
-@@ -56,7 +56,7 @@
- #define __SKIPLIST_H
-
- #include <linux/bits.h>
--#include <linux/minmax.h>
-+#include <linux/kernel.h>
- #include <linux/bug.h>
- #include <linux/prandom.h>
-
---
-2.29.2
-
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
index 7f39831..4a27cd0 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
@@ -27,10 +27,6 @@
file://326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch \
file://328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch \
file://329-mac80211-minstrel_ht-fix-where-rate-stats-are-stored.patch \
- file://330-mac80211-fix-overflow-issues-in-airtime-fairness-cod.patch \
- file://331-mac80211-improve-AQL-tx-time-estimation.patch \
- file://332-mac80211-fix-ieee80211_txq_may_transmit-regression.patch \
- file://333-mac80211-rework-the-airtime-fairness-implementation.patch \
file://350-bss-color-collision.patch \
file://400-allow-ibss-mixed.patch \
file://500-mac80211_configure_antenna_gain.patch \
@@ -42,6 +38,5 @@
file://904-mac80211-correct-legacy-rates-check-in-ieee80211_cal.patch \
file://905-mac80211-airtime_flags-depends-on-NL80211_EXT_FEATUR.patch \
file://906-mac80211-add-support-for-runtime-set-inband-discovery.patch \
- file://907-mac80211-fix-331-include-minmax-fail.patch \
file://908-mac80211-add-s1g-category-to-_ieee80211_is_robust_mg.patch \
"
diff --git a/recipes-kernel/linux-mt76/files/patches/0009-check-starec-newly.patch b/recipes-kernel/linux-mt76/files/patches/0009-check-starec-newly.patch
new file mode 100644
index 0000000..ed3059e
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0009-check-starec-newly.patch
@@ -0,0 +1,55 @@
+From 03a261c28f08e5c8aae5e4dde8f5f45e841fb0de Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 15 Jun 2022 23:15:13 +0800
+Subject: [PATCH] check starec newly
+
+---
+ mt7915/main.c | 2 +-
+ mt7915/mcu.c | 4 +++-
+ 2 files changed, 4 insertions(+), 2 deletions(-)
+
+diff --git a/mt7915/main.c b/mt7915/main.c
+index 7da3eada..9feba0d6 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -247,7 +247,6 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
+ mt7915_mac_wtbl_update(dev, idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+
+- rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
+ if (vif->txq) {
+ mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ mtxq->wcid = idx;
+@@ -263,6 +262,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
+
+ mt7915_mcu_add_bss_info(phy, vif, true);
+ mt7915_mcu_add_sta(dev, vif, NULL, true);
++ rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
+
+ out:
+ mutex_unlock(&dev->mt76.mutex);
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 36151959..ff5a73e3 100755
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -1803,6 +1803,7 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct mt7915_sta *msta;
+ struct sk_buff *skb;
++ bool newly;
+ int ret;
+
+ msta = sta ? (struct mt7915_sta *)sta->drv_priv : &mvif->sta;
+@@ -1813,7 +1814,8 @@ int mt7915_mcu_add_sta(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ return PTR_ERR(skb);
+
+ /* starec basic */
+- mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable, true);
++ newly = !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]);
++ mt76_connac_mcu_sta_basic_tlv(skb, vif, sta, enable, newly);
+ if (!enable)
+ goto out;
+
+--
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/0009-mt76-mt7915-4addr-null-frame-using-fixed-rate-to-success-WDS.patch b/recipes-kernel/linux-mt76/files/patches/0009-mt76-mt7915-4addr-null-frame-using-fixed-rate-to-success-WDS.patch
new file mode 100755
index 0000000..5b61802
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0009-mt76-mt7915-4addr-null-frame-using-fixed-rate-to-success-WDS.patch
@@ -0,0 +1,25 @@
+From 84ecaf8d9a4c7d0a1eae5b3b0ed20e171a58b3c7 Mon Sep 17 00:00:00 2001
+From: "lian.chen" <lian.chen@mediatek.com>
+Date: Thu, 16 Jun 2022 17:41:28 +0800
+Subject: [PATCH] mt76: mt7915: 4addr null frame using fixed rate to success WDS
+
+---
+ mt7915/mac.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index 094d10a5..b0933625 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -1133,7 +1133,7 @@ mt7915_mac_write_txwi_80211(struct mt7915_dev *dev, __le32 *txwi,
+ txwi[3] &= ~cpu_to_le32(MT_TXD3_PROTECT_FRAME);
+ }
+
+- if (!ieee80211_is_data(fc) || *mcast ||
++ if (!ieee80211_is_data(fc) || *mcast || ((ieee80211_is_nullfunc(fc) && ieee80211_has_a4(fc))) ||
+ info->flags & IEEE80211_TX_CTL_USE_MINRATE)
+ val |= MT_TXD2_FIX_RATE;
+
+--
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/patches.inc b/recipes-kernel/linux-mt76/files/patches/patches.inc
index 5407a8a..4446a12 100644
--- a/recipes-kernel/linux-mt76/files/patches/patches.inc
+++ b/recipes-kernel/linux-mt76/files/patches/patches.inc
@@ -8,6 +8,8 @@
file://0006-mt76-mt7915-add-the-maximum-size-of-beacon-offload.patch \
file://0007-mt76-mt7915-update-mpdu-density-in-6g-capability.patch \
file://0008-mt76-common-RF-CR-idx-require-8-bits.patch \
+ file://0009-check-starec-newly.patch \
+ file://0009-mt76-mt7915-4addr-null-frame-using-fixed-rate-to-success-WDS.patch \
file://100-Revert-of-net-pass-the-dst-buffer-to-of_get_mac_addr.patch \
file://1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch \
file://1002-mt76-mt7915-csi-implement-csi-support.patch \