--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 22 Nov 2021 21:39:38 +0100
+Subject: [PATCH] mac80211: fix rate control for retransmitted frames
+
+Since retransmission clears info->control, rate control needs to be called
+again, otherwise the driver might crash due to invalid rates.
+
+Cc: stable@vger.kernel.org # 5.14+
+Reported-by: Aaro Koskinen <aaro.koskinen@iki.fi>
+Reported-by: Robert W <rwbugreport@lost-in-the-void.net>
+Fixes: 03c3911d2d67 ("mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -1821,15 +1821,15 @@ static int invoke_tx_handlers_late(struc
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+ ieee80211_tx_result res = TX_CONTINUE;
+
++ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
++ CALL_TXH(ieee80211_tx_h_rate_ctrl);
++
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
+ __skb_queue_tail(&tx->skbs, tx->skb);
+ tx->skb = NULL;
+ 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);
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 22 Nov 2021 21:39:38 +0100
-Subject: [PATCH] mac80211: fix rate control for retransmitted frames
-
-Since retransmission clears info->control, rate control needs to be called
-again, otherwise the driver might crash due to invalid rates.
-
-Cc: stable@vger.kernel.org # 5.14+
-Reported-by: Aaro Koskinen <aaro.koskinen@iki.fi>
-Reported-by: Robert W <rwbugreport@lost-in-the-void.net>
-Fixes: 03c3911d2d67 ("mac80211: call ieee80211_tx_h_rate_ctrl() when dequeue")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -1821,15 +1821,15 @@ static int invoke_tx_handlers_late(struc
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
- ieee80211_tx_result res = TX_CONTINUE;
-
-+ if (!ieee80211_hw_check(&tx->local->hw, HAS_RATE_CONTROL))
-+ CALL_TXH(ieee80211_tx_h_rate_ctrl);
-+
- if (unlikely(info->flags & IEEE80211_TX_INTFL_RETRANSMISSION)) {
- __skb_queue_tail(&tx->skbs, tx->skb);
- tx->skb = NULL;
- 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);
--- /dev/null
+From b478e06a16a8baa00c5ecc87c1d636981f2206d5 Mon Sep 17 00:00:00 2001
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Tue, 29 Oct 2019 10:25:25 +0100
+Subject: [PATCH] mac80211: sta: randomize BA session dialog token allocator
+
+We currently always start the dialog token generator at zero,
+so the first dialog token we use is always 1. This would be
+OK if we had a perfect guarantee that we always do a proper
+deauth/re-auth handshake, but in IBSS mode this doesn't always
+happen properly.
+
+To make problems with block ack (aggregation) sessions getting
+stuck less likely, randomize the dialog token so if we start a
+new session but the peer still has old state for us, it can
+better detect this.
+
+This is really just a workaround to make things a bit more
+robust than they are now - a better fix would be to do a full
+authentication handshake in IBSS mode upon having discovered a
+new station, and on the receiver resetting the state (removing
+and re-adding the station) on receiving the authentication
+packet.
+
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ net/mac80211/sta_info.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/mac80211/sta_info.c
++++ b/net/mac80211/sta_info.c
+@@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct i
+ INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
+ INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
+ mutex_init(&sta->ampdu_mlme.mtx);
++ sta->ampdu_mlme.dialog_token_allocator = prandom_u32_max(U8_MAX);
+ #ifdef CPTCFG_MAC80211_MESH
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+ sta->mesh = kzalloc(sizeof(*sta->mesh), gfp);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 24 Nov 2021 10:30:41 +0100
+Subject: [PATCH] mac80211: fix regression in SSN handling of addba tx
+
+Some drivers that do their own sequence number allocation (e.g. ath9k) rely
+on being able to modify params->ssn on starting tx ampdu sessions.
+This was broken by a change that modified it to use sta->tid_seq[tid] instead.
+
+Cc: stable@vger.kernel.org
+Fixes: 31d8bb4e07f8 ("mac80211: agg-tx: refactor sending addba")
+Reported-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -480,8 +480,7 @@ static void ieee80211_send_addba_with_ti
+
+ /* send AddBA request */
+ ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
+- tid_tx->dialog_token,
+- sta->tid_seq[tid] >> 4,
++ tid_tx->dialog_token, tid_tx->ssn,
+ buf_size, tid_tx->timeout);
+
+ WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
+@@ -523,6 +522,7 @@ void ieee80211_tx_ba_session_handle_star
+
+ params.ssn = sta->tid_seq[tid] >> 4;
+ ret = drv_ampdu_action(local, sdata, ¶ms);
++ tid_tx->ssn = params.ssn;
+ if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
+ return;
+ } else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
+--- a/net/mac80211/sta_info.h
++++ b/net/mac80211/sta_info.h
+@@ -199,6 +199,7 @@ struct tid_ampdu_tx {
+ u8 stop_initiator;
+ bool tx_stop;
+ u16 buf_size;
++ u16 ssn;
+
+ u16 failed_bar_ssn;
+ bool bar_pending;
--- /dev/null
+From: Xing Song <xing.song@mediatek.com>
+Date: Tue, 23 Nov 2021 11:31:23 +0800
+Subject: [PATCH] mac80211: set up the fwd_skb->dev for mesh forwarding
+
+Mesh forwarding requires that the fwd_skb->dev is set up for TX handling,
+otherwise the following warning will be generated, so set it up for the
+pending frames.
+
+[ 72.835674 ] WARNING: CPU: 0 PID: 1193 at __skb_flow_dissect+0x284/0x1298
+[ 72.842379 ] Modules linked in: ksmbd pppoe ppp_async l2tp_ppp ...
+[ 72.962020 ] CPU: 0 PID: 1193 Comm: kworker/u5:1 Tainted: P S 5.4.137 #0
+[ 72.969938 ] Hardware name: MT7622_MT7531 RFB (DT)
+[ 72.974659 ] Workqueue: napi_workq napi_workfn
+[ 72.979025 ] pstate: 60000005 (nZCv daif -PAN -UAO)
+[ 72.983822 ] pc : __skb_flow_dissect+0x284/0x1298
+[ 72.988444 ] lr : __skb_flow_dissect+0x54/0x1298
+[ 72.992977 ] sp : ffffffc010c738c0
+[ 72.996293 ] x29: ffffffc010c738c0 x28: 0000000000000000
+[ 73.001615 ] x27: 000000000000ffc2 x26: ffffff800c2eb818
+[ 73.006937 ] x25: ffffffc010a987c8 x24: 00000000000000ce
+[ 73.012259 ] x23: ffffffc010c73a28 x22: ffffffc010a99c60
+[ 73.017581 ] x21: 000000000000ffc2 x20: ffffff80094da800
+[ 73.022903 ] x19: 0000000000000000 x18: 0000000000000014
+[ 73.028226 ] x17: 00000000084d16af x16: 00000000d1fc0bab
+[ 73.033548 ] x15: 00000000715f6034 x14: 000000009dbdd301
+[ 73.038870 ] x13: 00000000ea4dcbc3 x12: 0000000000000040
+[ 73.044192 ] x11: 000000000eb00ff0 x10: 0000000000000000
+[ 73.049513 ] x9 : 000000000eb00073 x8 : 0000000000000088
+[ 73.054834 ] x7 : 0000000000000000 x6 : 0000000000000001
+[ 73.060155 ] x5 : 0000000000000000 x4 : 0000000000000000
+[ 73.065476 ] x3 : ffffffc010a98000 x2 : 0000000000000000
+[ 73.070797 ] x1 : 0000000000000000 x0 : 0000000000000000
+[ 73.076120 ] Call trace:
+[ 73.078572 ] __skb_flow_dissect+0x284/0x1298
+[ 73.082846 ] __skb_get_hash+0x7c/0x228
+[ 73.086629 ] ieee80211_txq_may_transmit+0x7fc/0x17b8 [mac80211]
+[ 73.092564 ] ieee80211_tx_prepare_skb+0x20c/0x268 [mac80211]
+[ 73.098238 ] ieee80211_tx_pending+0x144/0x330 [mac80211]
+[ 73.103560 ] tasklet_action_common.isra.16+0xb4/0x158
+[ 73.108618 ] tasklet_action+0x2c/0x38
+[ 73.112286 ] __do_softirq+0x168/0x3b0
+[ 73.115954 ] do_softirq.part.15+0x88/0x98
+[ 73.119969 ] __local_bh_enable_ip+0xb0/0xb8
+[ 73.124156 ] napi_workfn+0x58/0x90
+[ 73.127565 ] process_one_work+0x20c/0x478
+[ 73.131579 ] worker_thread+0x50/0x4f0
+[ 73.135249 ] kthread+0x124/0x128
+[ 73.138484 ] ret_from_fork+0x10/0x1c
+
+Signed-off-by: Xing Song <xing.song@mediatek.com>
+---
+
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2948,6 +2948,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
+ if (!fwd_skb)
+ goto out;
+
++ fwd_skb->dev = sdata->dev;
+ fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
+ fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
+ info = IEEE80211_SKB_CB(fwd_skb);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Thu, 2 Dec 2021 13:30:05 +0100
+Subject: [PATCH] mac80211: send ADDBA requests using the tid/queue of the
+ aggregation session
+
+Sending them out on a different queue can cause a race condition where a
+number of packets in the queue may be discarded by the receiver, because
+the ADDBA request is sent too early.
+This affects any driver with software A-MPDU setup which does not allocate
+packet seqno in hardware on tx, regardless of whether iTXQ is used or not.
+The only driver I've seen that explicitly deals with this issue internally
+is mwl8k.
+
+Cc: stable@vger.kernel.org
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -106,7 +106,7 @@ static void ieee80211_send_addba_request
+ mgmt->u.action.u.addba_req.start_seq_num =
+ cpu_to_le16(start_seq_num << 4);
+
+- ieee80211_tx_skb(sdata, skb);
++ ieee80211_tx_skb_tid(sdata, skb, tid);
+ }
+
+ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
+++ /dev/null
-From b478e06a16a8baa00c5ecc87c1d636981f2206d5 Mon Sep 17 00:00:00 2001
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Tue, 29 Oct 2019 10:25:25 +0100
-Subject: [PATCH] mac80211: sta: randomize BA session dialog token allocator
-
-We currently always start the dialog token generator at zero,
-so the first dialog token we use is always 1. This would be
-OK if we had a perfect guarantee that we always do a proper
-deauth/re-auth handshake, but in IBSS mode this doesn't always
-happen properly.
-
-To make problems with block ack (aggregation) sessions getting
-stuck less likely, randomize the dialog token so if we start a
-new session but the peer still has old state for us, it can
-better detect this.
-
-This is really just a workaround to make things a bit more
-robust than they are now - a better fix would be to do a full
-authentication handshake in IBSS mode upon having discovered a
-new station, and on the receiver resetting the state (removing
-and re-adding the station) on receiving the authentication
-packet.
-
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
- net/mac80211/sta_info.c | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/net/mac80211/sta_info.c
-+++ b/net/mac80211/sta_info.c
-@@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct i
- INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames);
- INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
- mutex_init(&sta->ampdu_mlme.mtx);
-+ sta->ampdu_mlme.dialog_token_allocator = prandom_u32_max(U8_MAX);
- #ifdef CPTCFG_MAC80211_MESH
- if (ieee80211_vif_is_mesh(&sdata->vif)) {
- sta->mesh = kzalloc(sizeof(*sta->mesh), gfp);
--- /dev/null
+From: Johannes Berg <johannes.berg@intel.com>
+Date: Mon, 29 Nov 2021 15:32:47 +0200
+Subject: [PATCH] mac80211: agg-tx: don't schedule_and_wake_txq() under
+ sta->lock
+
+When we call ieee80211_agg_start_txq(), that will in turn call
+schedule_and_wake_txq(). Called from ieee80211_stop_tx_ba_cb()
+this is done under sta->lock, which leads to certain circular
+lock dependencies, as reported by Chris Murphy:
+https://lore.kernel.org/r/CAJCQCtSXJ5qA4bqSPY=oLRMbv-irihVvP7A2uGutEbXQVkoNaw@mail.gmail.com
+
+In general, ieee80211_agg_start_txq() is usually not called
+with sta->lock held, only in this one place. But it's always
+called with sta->ampdu_mlme.mtx held, and that's therefore
+clearly sufficient.
+
+Change ieee80211_stop_tx_ba_cb() to also call it without the
+sta->lock held, by factoring it out of ieee80211_remove_tid_tx()
+(which is only called in this one place).
+
+This breaks the locking chain and makes it less likely that
+we'll have similar locking chain problems in the future.
+
+Reported-by: Chris Murphy <lists@colorremedies.com>
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
+---
+
+--- a/net/mac80211/agg-tx.c
++++ b/net/mac80211/agg-tx.c
+@@ -9,7 +9,7 @@
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2007-2010, Intel Corporation
+ * Copyright(c) 2015-2017 Intel Deutschland GmbH
+- * Copyright (C) 2018 - 2020 Intel Corporation
++ * Copyright (C) 2018 - 2021 Intel Corporation
+ */
+
+ #include <linux/ieee80211.h>
+@@ -213,6 +213,8 @@ ieee80211_agg_start_txq(struct sta_info
+ struct ieee80211_txq *txq = sta->sta.txq[tid];
+ struct txq_info *txqi;
+
++ lockdep_assert_held(&sta->ampdu_mlme.mtx);
++
+ if (!txq)
+ return;
+
+@@ -290,7 +292,6 @@ static void ieee80211_remove_tid_tx(stru
+ ieee80211_assign_tid_tx(sta, tid, NULL);
+
+ ieee80211_agg_splice_finish(sta->sdata, tid);
+- ieee80211_agg_start_txq(sta, tid, false);
+
+ kfree_rcu(tid_tx, rcu_head);
+ }
+@@ -889,6 +890,7 @@ void ieee80211_stop_tx_ba_cb(struct sta_
+ {
+ struct ieee80211_sub_if_data *sdata = sta->sdata;
+ bool send_delba = false;
++ bool start_txq = false;
+
+ ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n",
+ sta->sta.addr, tid);
+@@ -906,10 +908,14 @@ void ieee80211_stop_tx_ba_cb(struct sta_
+ send_delba = true;
+
+ ieee80211_remove_tid_tx(sta, tid);
++ start_txq = true;
+
+ unlock_sta:
+ spin_unlock_bh(&sta->lock);
+
++ if (start_txq)
++ ieee80211_agg_start_txq(sta, tid, false);
++
+ if (send_delba)
+ ieee80211_send_delba(sdata, sta->sta.addr, tid,
+ WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 24 Nov 2021 10:30:41 +0100
-Subject: [PATCH] mac80211: fix regression in SSN handling of addba tx
-
-Some drivers that do their own sequence number allocation (e.g. ath9k) rely
-on being able to modify params->ssn on starting tx ampdu sessions.
-This was broken by a change that modified it to use sta->tid_seq[tid] instead.
-
-Cc: stable@vger.kernel.org
-Fixes: 31d8bb4e07f8 ("mac80211: agg-tx: refactor sending addba")
-Reported-by: Eneas U de Queiroz <cotequeiroz@gmail.com>
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -480,8 +480,7 @@ static void ieee80211_send_addba_with_ti
-
- /* send AddBA request */
- ieee80211_send_addba_request(sdata, sta->sta.addr, tid,
-- tid_tx->dialog_token,
-- sta->tid_seq[tid] >> 4,
-+ tid_tx->dialog_token, tid_tx->ssn,
- buf_size, tid_tx->timeout);
-
- WARN_ON(test_and_set_bit(HT_AGG_STATE_SENT_ADDBA, &tid_tx->state));
-@@ -523,6 +522,7 @@ void ieee80211_tx_ba_session_handle_star
-
- params.ssn = sta->tid_seq[tid] >> 4;
- ret = drv_ampdu_action(local, sdata, ¶ms);
-+ tid_tx->ssn = params.ssn;
- if (ret == IEEE80211_AMPDU_TX_START_DELAY_ADDBA) {
- return;
- } else if (ret == IEEE80211_AMPDU_TX_START_IMMEDIATE) {
---- a/net/mac80211/sta_info.h
-+++ b/net/mac80211/sta_info.h
-@@ -199,6 +199,7 @@ struct tid_ampdu_tx {
- u8 stop_initiator;
- bool tx_stop;
- u16 buf_size;
-+ u16 ssn;
-
- u16 failed_bar_ssn;
- bool bar_pending;
+++ /dev/null
-From: Xing Song <xing.song@mediatek.com>
-Date: Tue, 23 Nov 2021 11:31:23 +0800
-Subject: [PATCH] mac80211: set up the fwd_skb->dev for mesh forwarding
-
-Mesh forwarding requires that the fwd_skb->dev is set up for TX handling,
-otherwise the following warning will be generated, so set it up for the
-pending frames.
-
-[ 72.835674 ] WARNING: CPU: 0 PID: 1193 at __skb_flow_dissect+0x284/0x1298
-[ 72.842379 ] Modules linked in: ksmbd pppoe ppp_async l2tp_ppp ...
-[ 72.962020 ] CPU: 0 PID: 1193 Comm: kworker/u5:1 Tainted: P S 5.4.137 #0
-[ 72.969938 ] Hardware name: MT7622_MT7531 RFB (DT)
-[ 72.974659 ] Workqueue: napi_workq napi_workfn
-[ 72.979025 ] pstate: 60000005 (nZCv daif -PAN -UAO)
-[ 72.983822 ] pc : __skb_flow_dissect+0x284/0x1298
-[ 72.988444 ] lr : __skb_flow_dissect+0x54/0x1298
-[ 72.992977 ] sp : ffffffc010c738c0
-[ 72.996293 ] x29: ffffffc010c738c0 x28: 0000000000000000
-[ 73.001615 ] x27: 000000000000ffc2 x26: ffffff800c2eb818
-[ 73.006937 ] x25: ffffffc010a987c8 x24: 00000000000000ce
-[ 73.012259 ] x23: ffffffc010c73a28 x22: ffffffc010a99c60
-[ 73.017581 ] x21: 000000000000ffc2 x20: ffffff80094da800
-[ 73.022903 ] x19: 0000000000000000 x18: 0000000000000014
-[ 73.028226 ] x17: 00000000084d16af x16: 00000000d1fc0bab
-[ 73.033548 ] x15: 00000000715f6034 x14: 000000009dbdd301
-[ 73.038870 ] x13: 00000000ea4dcbc3 x12: 0000000000000040
-[ 73.044192 ] x11: 000000000eb00ff0 x10: 0000000000000000
-[ 73.049513 ] x9 : 000000000eb00073 x8 : 0000000000000088
-[ 73.054834 ] x7 : 0000000000000000 x6 : 0000000000000001
-[ 73.060155 ] x5 : 0000000000000000 x4 : 0000000000000000
-[ 73.065476 ] x3 : ffffffc010a98000 x2 : 0000000000000000
-[ 73.070797 ] x1 : 0000000000000000 x0 : 0000000000000000
-[ 73.076120 ] Call trace:
-[ 73.078572 ] __skb_flow_dissect+0x284/0x1298
-[ 73.082846 ] __skb_get_hash+0x7c/0x228
-[ 73.086629 ] ieee80211_txq_may_transmit+0x7fc/0x17b8 [mac80211]
-[ 73.092564 ] ieee80211_tx_prepare_skb+0x20c/0x268 [mac80211]
-[ 73.098238 ] ieee80211_tx_pending+0x144/0x330 [mac80211]
-[ 73.103560 ] tasklet_action_common.isra.16+0xb4/0x158
-[ 73.108618 ] tasklet_action+0x2c/0x38
-[ 73.112286 ] __do_softirq+0x168/0x3b0
-[ 73.115954 ] do_softirq.part.15+0x88/0x98
-[ 73.119969 ] __local_bh_enable_ip+0xb0/0xb8
-[ 73.124156 ] napi_workfn+0x58/0x90
-[ 73.127565 ] process_one_work+0x20c/0x478
-[ 73.131579 ] worker_thread+0x50/0x4f0
-[ 73.135249 ] kthread+0x124/0x128
-[ 73.138484 ] ret_from_fork+0x10/0x1c
-
-Signed-off-by: Xing Song <xing.song@mediatek.com>
----
-
---- a/net/mac80211/rx.c
-+++ b/net/mac80211/rx.c
-@@ -2948,6 +2948,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
- if (!fwd_skb)
- goto out;
-
-+ fwd_skb->dev = sdata->dev;
- fwd_hdr = (struct ieee80211_hdr *) fwd_skb->data;
- fwd_hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_RETRY);
- info = IEEE80211_SKB_CB(fwd_skb);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Tue, 14 Dec 2021 17:53:12 +0100
+Subject: [PATCH] mac80211: use coarse boottime for airtime fairness code
+
+The time values used by the airtime fairness code only need to be accurate
+enough to cover station activity detection.
+Using ktime_get_coarse_boottime_ns instead of ktime_get_boottime_ns will
+drop the accuracy down to jiffies intervals, but at the same time saves
+a lot of CPU cycles in a hot path
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/tx.c
++++ b/net/mac80211/tx.c
+@@ -3820,7 +3820,7 @@ struct ieee80211_txq *ieee80211_next_txq
+ {
+ struct ieee80211_local *local = hw_to_local(hw);
+ struct airtime_sched_info *air_sched;
+- u64 now = ktime_get_boottime_ns();
++ u64 now = ktime_get_coarse_boottime_ns();
+ struct ieee80211_txq *ret = NULL;
+ struct airtime_info *air_info;
+ struct txq_info *txqi = NULL;
+@@ -3947,7 +3947,7 @@ void ieee80211_update_airtime_weight(str
+ u64 weight_sum = 0;
+
+ if (unlikely(!now))
+- now = ktime_get_boottime_ns();
++ now = ktime_get_coarse_boottime_ns();
+
+ lockdep_assert_held(&air_sched->lock);
+
+@@ -3973,7 +3973,7 @@ void ieee80211_schedule_txq(struct ieee8
+ 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();
++ u64 now = ktime_get_coarse_boottime_ns();
+ struct airtime_info *air_info;
+ u8 ac = txq->ac;
+ bool was_active;
+@@ -4031,7 +4031,7 @@ static void __ieee80211_unschedule_txq(s
+
+ if (!purge)
+ airtime_set_active(air_sched, air_info,
+- ktime_get_boottime_ns());
++ ktime_get_coarse_boottime_ns());
+
+ rb_erase_cached(&txqi->schedule_order,
+ &air_sched->active_txqs);
+@@ -4119,7 +4119,7 @@ bool ieee80211_txq_may_transmit(struct i
+ if (RB_EMPTY_NODE(&txqi->schedule_order))
+ goto out;
+
+- now = ktime_get_boottime_ns();
++ 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.
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Mon, 24 May 2021 11:46:09 +0200
+Subject: [PATCH] mac80211_hwsim: make 6 GHz channels usable
+
+The previous commit that claimed to add 6 GHz channels didn't actually make
+them usable, since the 6 GHz band was not registered with mac80211.
+
+Fixes: 28881922abd7 ("mac80211_hwsim: add 6GHz channels")
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/drivers/net/wireless/mac80211_hwsim.c
++++ b/drivers/net/wireless/mac80211_hwsim.c
+@@ -2992,15 +2992,19 @@ static void mac80211_hwsim_he_capab(stru
+ {
+ u16 n_iftype_data;
+
+- if (sband->band == NL80211_BAND_2GHZ) {
++ switch (sband->band) {
++ case NL80211_BAND_2GHZ:
+ n_iftype_data = ARRAY_SIZE(he_capa_2ghz);
+ sband->iftype_data =
+ (struct ieee80211_sband_iftype_data *)he_capa_2ghz;
+- } else if (sband->band == NL80211_BAND_5GHZ) {
++ break;
++ case NL80211_BAND_5GHZ:
++ case NL80211_BAND_6GHZ:
+ n_iftype_data = ARRAY_SIZE(he_capa_5ghz);
+ sband->iftype_data =
+ (struct ieee80211_sband_iftype_data *)he_capa_5ghz;
+- } else {
++ break;
++ default:
+ return;
+ }
+
+@@ -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;
++ case NL80211_BAND_6GHZ:
++ sband->channels = data->channels_6ghz;
++ sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz);
++ sband->bitrates = data->rates + 4;
++ sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
++ break;
+ case NL80211_BAND_S1GHZ:
+ memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
+ sizeof(sband->s1g_cap));
+@@ -3300,6 +3310,13 @@ static int mac80211_hwsim_new_radio(stru
+ continue;
+ }
+
++ mac80211_hwsim_he_capab(sband);
++
++ hw->wiphy->bands[band] = sband;
++
++ if (band == NL80211_BAND_6GHZ)
++ continue;
++
+ sband->ht_cap.ht_supported = true;
+ sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+ IEEE80211_HT_CAP_GRN_FLD |
+@@ -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;
+-
+- mac80211_hwsim_he_capab(sband);
+-
+- hw->wiphy->bands[band] = sband;
+ }
+
+ /* By default all radios belong to the first group */
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 12 Nov 2021 12:22:23 +0100
+Subject: [PATCH] mac80211: add support for .ndo_fill_forward_path
+
+This allows drivers to provide a destination device + info for flow offload
+Only supported in combination with 802.3 encap offload
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+Tested-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://lore.kernel.org/r/20211112112223.1209-1-nbd@nbd.name
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -3937,6 +3937,8 @@ struct ieee80211_prep_tx_info {
+ * twt structure.
+ * @twt_teardown_request: Update the hw with TWT teardown request received
+ * from the peer.
++ * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
++ * resolve a path for hardware flow offloading
+ */
+ struct ieee80211_ops {
+ void (*tx)(struct ieee80211_hw *hw,
+@@ -4265,6 +4267,11 @@ struct ieee80211_ops {
+ struct ieee80211_twt_setup *twt);
+ void (*twt_teardown_request)(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 flowid);
++ int (*net_fill_forward_path)(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta,
++ struct net_device_path_ctx *ctx,
++ struct net_device_path *path);
+ };
+
+ /**
+--- a/net/mac80211/driver-ops.h
++++ b/net/mac80211/driver-ops.h
+@@ -1483,4 +1483,26 @@ static inline void drv_twt_teardown_requ
+ trace_drv_return_void(local);
+ }
+
++static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
++ struct ieee80211_sub_if_data *sdata,
++ struct ieee80211_sta *sta,
++ struct net_device_path_ctx *ctx,
++ struct net_device_path *path)
++{
++ int ret = -EOPNOTSUPP;
++
++ sdata = get_bss_sdata(sdata);
++ if (!check_sdata_in_driver(sdata))
++ return -EIO;
++
++ trace_drv_net_fill_forward_path(local, sdata, sta);
++ if (local->ops->net_fill_forward_path)
++ ret = local->ops->net_fill_forward_path(&local->hw,
++ &sdata->vif, sta,
++ ctx, path);
++ trace_drv_return_int(local, ret);
++
++ return ret;
++}
++
+ #endif /* __MAC80211_DRIVER_OPS */
+--- a/net/mac80211/ieee80211_i.h
++++ b/net/mac80211/ieee80211_i.h
+@@ -1465,7 +1465,7 @@ struct ieee80211_local {
+ };
+
+ static inline struct ieee80211_sub_if_data *
+-IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
++IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev)
+ {
+ return netdev_priv(dev);
+ }
+--- a/net/mac80211/iface.c
++++ b/net/mac80211/iface.c
+@@ -822,6 +822,66 @@ static const struct net_device_ops ieee8
+
+ };
+
++#if LINUX_VERSION_IS_GEQ(5,10,0)
++static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx,
++ struct net_device_path *path)
++{
++ struct ieee80211_sub_if_data *sdata;
++ struct ieee80211_local *local;
++ struct sta_info *sta;
++ int ret = -ENOENT;
++
++ sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev);
++ local = sdata->local;
++
++ if (!local->ops->net_fill_forward_path)
++ return -EOPNOTSUPP;
++
++ rcu_read_lock();
++ switch (sdata->vif.type) {
++ case NL80211_IFTYPE_AP_VLAN:
++ sta = rcu_dereference(sdata->u.vlan.sta);
++ if (sta)
++ break;
++ if (sdata->wdev.use_4addr)
++ goto out;
++ if (is_multicast_ether_addr(ctx->daddr))
++ goto out;
++ sta = sta_info_get_bss(sdata, ctx->daddr);
++ break;
++ case NL80211_IFTYPE_AP:
++ if (is_multicast_ether_addr(ctx->daddr))
++ goto out;
++ sta = sta_info_get(sdata, ctx->daddr);
++ break;
++ case NL80211_IFTYPE_STATION:
++ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
++ sta = sta_info_get(sdata, ctx->daddr);
++ if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
++ if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
++ goto out;
++
++ break;
++ }
++ }
++
++ sta = sta_info_get(sdata, sdata->u.mgd.bssid);
++ break;
++ default:
++ goto out;
++ }
++
++ if (!sta)
++ goto out;
++
++ ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path);
++out:
++ rcu_read_unlock();
++
++ return ret;
++}
++#endif
++
+ static const struct net_device_ops ieee80211_dataif_8023_ops = {
+ #if LINUX_VERSION_IS_LESS(4,10,0)
+ .ndo_change_mtu = __change_mtu,
+@@ -839,7 +899,9 @@ static const struct net_device_ops ieee8
+ #else
+ .ndo_get_stats64 = bp_ieee80211_get_stats64,
+ #endif
+-
++#if LINUX_VERSION_IS_GEQ(5,10,0)
++ .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
++#endif
+ };
+
+ static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
+--- a/net/mac80211/trace.h
++++ b/net/mac80211/trace.h
+@@ -2892,6 +2892,13 @@ TRACE_EVENT(drv_twt_teardown_request,
+ )
+ );
+
++DEFINE_EVENT(sta_event, drv_net_fill_forward_path,
++ TP_PROTO(struct ieee80211_local *local,
++ struct ieee80211_sub_if_data *sdata,
++ struct ieee80211_sta *sta),
++ TP_ARGS(local, sdata, sta)
++);
++
+ #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+
+ #undef TRACE_INCLUDE_PATH
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Wed, 28 Apr 2021 21:03:13 +0200
+Subject: [PATCH] mac80211: minstrel_ht: fix MINSTREL_FRAC macro
+
+Add missing braces to avoid issues with e.g. using additions in the
+div expression
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.h
++++ b/net/mac80211/rc80211_minstrel_ht.h
+@@ -14,7 +14,7 @@
+
+ /* scaled fraction values */
+ #define MINSTREL_SCALE 12
+-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
++#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / (div))
+ #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
+
+ #define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 2 Dec 2021 13:30:05 +0100
-Subject: [PATCH] mac80211: send ADDBA requests using the tid/queue of the
- aggregation session
-
-Sending them out on a different queue can cause a race condition where a
-number of packets in the queue may be discarded by the receiver, because
-the ADDBA request is sent too early.
-This affects any driver with software A-MPDU setup which does not allocate
-packet seqno in hardware on tx, regardless of whether iTXQ is used or not.
-The only driver I've seen that explicitly deals with this issue internally
-is mwl8k.
-
-Cc: stable@vger.kernel.org
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -106,7 +106,7 @@ static void ieee80211_send_addba_request
- mgmt->u.action.u.addba_req.start_seq_num =
- cpu_to_le16(start_seq_num << 4);
-
-- ieee80211_tx_skb(sdata, skb);
-+ ieee80211_tx_skb_tid(sdata, skb, tid);
- }
-
- void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
+++ /dev/null
-From: Johannes Berg <johannes.berg@intel.com>
-Date: Mon, 29 Nov 2021 15:32:47 +0200
-Subject: [PATCH] mac80211: agg-tx: don't schedule_and_wake_txq() under
- sta->lock
-
-When we call ieee80211_agg_start_txq(), that will in turn call
-schedule_and_wake_txq(). Called from ieee80211_stop_tx_ba_cb()
-this is done under sta->lock, which leads to certain circular
-lock dependencies, as reported by Chris Murphy:
-https://lore.kernel.org/r/CAJCQCtSXJ5qA4bqSPY=oLRMbv-irihVvP7A2uGutEbXQVkoNaw@mail.gmail.com
-
-In general, ieee80211_agg_start_txq() is usually not called
-with sta->lock held, only in this one place. But it's always
-called with sta->ampdu_mlme.mtx held, and that's therefore
-clearly sufficient.
-
-Change ieee80211_stop_tx_ba_cb() to also call it without the
-sta->lock held, by factoring it out of ieee80211_remove_tid_tx()
-(which is only called in this one place).
-
-This breaks the locking chain and makes it less likely that
-we'll have similar locking chain problems in the future.
-
-Reported-by: Chris Murphy <lists@colorremedies.com>
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
----
-
---- a/net/mac80211/agg-tx.c
-+++ b/net/mac80211/agg-tx.c
-@@ -9,7 +9,7 @@
- * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
- * Copyright 2007-2010, Intel Corporation
- * Copyright(c) 2015-2017 Intel Deutschland GmbH
-- * Copyright (C) 2018 - 2020 Intel Corporation
-+ * Copyright (C) 2018 - 2021 Intel Corporation
- */
-
- #include <linux/ieee80211.h>
-@@ -213,6 +213,8 @@ ieee80211_agg_start_txq(struct sta_info
- struct ieee80211_txq *txq = sta->sta.txq[tid];
- struct txq_info *txqi;
-
-+ lockdep_assert_held(&sta->ampdu_mlme.mtx);
-+
- if (!txq)
- return;
-
-@@ -290,7 +292,6 @@ static void ieee80211_remove_tid_tx(stru
- ieee80211_assign_tid_tx(sta, tid, NULL);
-
- ieee80211_agg_splice_finish(sta->sdata, tid);
-- ieee80211_agg_start_txq(sta, tid, false);
-
- kfree_rcu(tid_tx, rcu_head);
- }
-@@ -889,6 +890,7 @@ void ieee80211_stop_tx_ba_cb(struct sta_
- {
- struct ieee80211_sub_if_data *sdata = sta->sdata;
- bool send_delba = false;
-+ bool start_txq = false;
-
- ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n",
- sta->sta.addr, tid);
-@@ -906,10 +908,14 @@ void ieee80211_stop_tx_ba_cb(struct sta_
- send_delba = true;
-
- ieee80211_remove_tid_tx(sta, tid);
-+ start_txq = true;
-
- unlock_sta:
- spin_unlock_bh(&sta->lock);
-
-+ if (start_txq)
-+ ieee80211_agg_start_txq(sta, tid, false);
-+
- if (send_delba)
- ieee80211_send_delba(sdata, sta->sta.addr, tid,
- WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 6 Feb 2021 16:08:01 +0100
+Subject: [PATCH] mac80211: minstrel_ht: reduce fluctuations in rate
+ probability stats
+
+In some scenarios when there is a lot of fluctuation in packet error rates,
+rate switching can be amplified when the statistics get skewed by time slots
+with very few tries.
+Make the input data to the moving average more smooth by adding the
+success/attempts count from the last stats window as well. This has the
+advantage of smoothing the data without introducing any extra lag to sampling
+rates.
+This significantly improves rate stability on a strong test link subjected to
+periodic noise bursts generated with a SDR
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -700,7 +700,8 @@ minstrel_ht_calc_rate_stats(struct minst
+ unsigned int cur_prob;
+
+ if (unlikely(mrs->attempts > 0)) {
+- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
++ cur_prob = MINSTREL_FRAC(mrs->success + mrs->last_success,
++ mrs->attempts + mrs->last_attempts);
+ minstrel_filter_avg_add(&mrs->prob_avg,
+ &mrs->prob_avg_1, cur_prob);
+ mrs->att_hist += mrs->attempts;
--- /dev/null
+From: Felix Fietkau <nbd@nbd.name>
+Date: Sat, 6 Feb 2021 16:33:14 +0100
+Subject: [PATCH] mac80211: minstrel_ht: rework rate downgrade code and
+ max_prob rate selection
+
+The current fallback code for fast rate switching on potentially failing rates
+is triggering too often if there is some strong noise on the channel. This can
+lead to wild fluctuations in the rate selection.
+Additionally, switching down to max_prob_rate can create a significant gap down
+in throughput, especially when using only 2 spatial streams, because max_prob_rate
+is limited to using fewer streams than the max_tp rates.
+In order to improve throughput without reducing reliability too much, use the
+rate downgrade code for the max_prob_rate only, and allow the non-downgraded
+max_prob_rate to use as many spatial streams as the max_tp rates
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/rc80211_minstrel_ht.c
++++ b/net/mac80211/rc80211_minstrel_ht.c
+@@ -511,6 +511,14 @@ minstrel_ht_set_best_prob_rate(struct mi
+ int cur_tp_avg, cur_group, cur_idx;
+ int max_gpr_group, max_gpr_idx;
+ int max_gpr_tp_avg, max_gpr_prob;
++ int min_dur;
++
++ min_dur = max(minstrel_get_duration(mi->max_tp_rate[0]),
++ minstrel_get_duration(mi->max_tp_rate[1]));
++
++ /* make the rate at least 18% slower than max tp rates */
++ if (minstrel_get_duration(index) <= min_dur * 19 / 16)
++ return;
+
+ cur_group = MI_RATE_GROUP(index);
+ cur_idx = MI_RATE_IDX(index);
+@@ -532,11 +540,6 @@ minstrel_ht_set_best_prob_rate(struct mi
+ !minstrel_ht_is_legacy_group(max_tp_group))
+ return;
+
+- /* skip rates faster than max tp rate with lower prob */
+- if (minstrel_get_duration(mi->max_tp_rate[0]) > minstrel_get_duration(index) &&
+- mrs->prob_avg < max_tp_prob)
+- return;
+-
+ max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate);
+ max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate);
+ max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
+@@ -594,40 +597,6 @@ minstrel_ht_assign_best_tp_rates(struct
+
+ }
+
+-/*
+- * Try to increase robustness of max_prob rate by decrease number of
+- * streams if possible.
+- */
+-static inline void
+-minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
+-{
+- struct minstrel_mcs_group_data *mg;
+- int tmp_max_streams, group, tmp_idx, tmp_prob;
+- int tmp_tp = 0;
+-
+- if (!mi->sta->ht_cap.ht_supported)
+- return;
+-
+- group = MI_RATE_GROUP(mi->max_tp_rate[0]);
+- tmp_max_streams = minstrel_mcs_groups[group].streams;
+- for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
+- mg = &mi->groups[group];
+- if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
+- continue;
+-
+- tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate);
+- tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
+-
+- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
+- (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
+- mi->max_prob_rate = mg->max_group_prob_rate;
+- tmp_tp = minstrel_ht_get_tp_avg(mi, group,
+- tmp_idx,
+- tmp_prob);
+- }
+- }
+-}
+-
+ static u16
+ __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
+ enum minstrel_sample_type type)
+@@ -1107,8 +1076,6 @@ minstrel_ht_update_stats(struct minstrel
+
+ mi->max_prob_rate = tmp_max_prob_rate;
+
+- /* Try to increase robustness of max_prob_rate*/
+- minstrel_ht_prob_rate_reduce_streams(mi);
+ minstrel_ht_refill_sample_rates(mi);
+
+ #ifdef CPTCFG_MAC80211_DEBUGFS
+@@ -1153,7 +1120,7 @@ minstrel_ht_txstat_valid(struct minstrel
+ }
+
+ static void
+-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
++minstrel_downgrade_prob_rate(struct minstrel_ht_sta *mi, u16 *idx)
+ {
+ int group, orig_group;
+
+@@ -1168,11 +1135,7 @@ minstrel_downgrade_rate(struct minstrel_
+ minstrel_mcs_groups[orig_group].streams)
+ continue;
+
+- if (primary)
+- *idx = mi->groups[group].max_group_tp_rate[0];
+- else
+- *idx = mi->groups[group].max_group_tp_rate[1];
+- break;
++ *idx = mi->groups[group].max_group_prob_rate;
+ }
+ }
+
+@@ -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;
+- struct minstrel_rate_stats *rate, *rate2;
++ struct minstrel_rate_stats *rate;
+ struct minstrel_priv *mp = priv;
+ u32 update_interval = mp->update_interval;
+ bool last, update = false;
+@@ -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.
++ * only do this for the max_prob_rate to prevent spurious
++ * rate fluctuations when the link changes suddenly
+ */
+- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
++ rate = minstrel_get_ratestats(mi, mi->max_prob_rate);
+ if (rate->attempts > 30 &&
+ rate->success < rate->attempts / 4) {
+- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
+- update = true;
+- }
+-
+- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
+- if (rate2->attempts > 30 &&
+- rate2->success < rate2->attempts / 4) {
+- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
++ minstrel_downgrade_prob_rate(mi, &mi->max_prob_rate);
+ update = true;
+ }
+ }
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Tue, 14 Dec 2021 17:53:12 +0100
-Subject: [PATCH] mac80211: use coarse boottime for airtime fairness code
-
-The time values used by the airtime fairness code only need to be accurate
-enough to cover station activity detection.
-Using ktime_get_coarse_boottime_ns instead of ktime_get_boottime_ns will
-drop the accuracy down to jiffies intervals, but at the same time saves
-a lot of CPU cycles in a hot path
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -3820,7 +3820,7 @@ struct ieee80211_txq *ieee80211_next_txq
- {
- struct ieee80211_local *local = hw_to_local(hw);
- struct airtime_sched_info *air_sched;
-- u64 now = ktime_get_boottime_ns();
-+ u64 now = ktime_get_coarse_boottime_ns();
- struct ieee80211_txq *ret = NULL;
- struct airtime_info *air_info;
- struct txq_info *txqi = NULL;
-@@ -3947,7 +3947,7 @@ void ieee80211_update_airtime_weight(str
- u64 weight_sum = 0;
-
- if (unlikely(!now))
-- now = ktime_get_boottime_ns();
-+ now = ktime_get_coarse_boottime_ns();
-
- lockdep_assert_held(&air_sched->lock);
-
-@@ -3973,7 +3973,7 @@ void ieee80211_schedule_txq(struct ieee8
- 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();
-+ u64 now = ktime_get_coarse_boottime_ns();
- struct airtime_info *air_info;
- u8 ac = txq->ac;
- bool was_active;
-@@ -4031,7 +4031,7 @@ static void __ieee80211_unschedule_txq(s
-
- if (!purge)
- airtime_set_active(air_sched, air_info,
-- ktime_get_boottime_ns());
-+ ktime_get_coarse_boottime_ns());
-
- rb_erase_cached(&txqi->schedule_order,
- &air_sched->active_txqs);
-@@ -4119,7 +4119,7 @@ bool ieee80211_txq_may_transmit(struct i
- if (RB_EMPTY_NODE(&txqi->schedule_order))
- goto out;
-
-- now = ktime_get_boottime_ns();
-+ 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.
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Mon, 24 May 2021 11:46:09 +0200
-Subject: [PATCH] mac80211_hwsim: make 6 GHz channels usable
-
-The previous commit that claimed to add 6 GHz channels didn't actually make
-them usable, since the 6 GHz band was not registered with mac80211.
-
-Fixes: 28881922abd7 ("mac80211_hwsim: add 6GHz channels")
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/mac80211_hwsim.c
-+++ b/drivers/net/wireless/mac80211_hwsim.c
-@@ -2992,15 +2992,19 @@ static void mac80211_hwsim_he_capab(stru
- {
- u16 n_iftype_data;
-
-- if (sband->band == NL80211_BAND_2GHZ) {
-+ switch (sband->band) {
-+ case NL80211_BAND_2GHZ:
- n_iftype_data = ARRAY_SIZE(he_capa_2ghz);
- sband->iftype_data =
- (struct ieee80211_sband_iftype_data *)he_capa_2ghz;
-- } else if (sband->band == NL80211_BAND_5GHZ) {
-+ break;
-+ case NL80211_BAND_5GHZ:
-+ case NL80211_BAND_6GHZ:
- n_iftype_data = ARRAY_SIZE(he_capa_5ghz);
- sband->iftype_data =
- (struct ieee80211_sband_iftype_data *)he_capa_5ghz;
-- } else {
-+ break;
-+ default:
- return;
- }
-
-@@ -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;
-+ case NL80211_BAND_6GHZ:
-+ sband->channels = data->channels_6ghz;
-+ sband->n_channels = ARRAY_SIZE(hwsim_channels_6ghz);
-+ sband->bitrates = data->rates + 4;
-+ sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4;
-+ break;
- case NL80211_BAND_S1GHZ:
- memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
- sizeof(sband->s1g_cap));
-@@ -3300,6 +3310,13 @@ static int mac80211_hwsim_new_radio(stru
- continue;
- }
-
-+ mac80211_hwsim_he_capab(sband);
-+
-+ hw->wiphy->bands[band] = sband;
-+
-+ if (band == NL80211_BAND_6GHZ)
-+ continue;
-+
- sband->ht_cap.ht_supported = true;
- sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
- IEEE80211_HT_CAP_GRN_FLD |
-@@ -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;
--
-- mac80211_hwsim_he_capab(sband);
--
-- hw->wiphy->bands[band] = sband;
- }
-
- /* By default all radios belong to the first group */
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Fri, 12 Nov 2021 12:22:23 +0100
-Subject: [PATCH] mac80211: add support for .ndo_fill_forward_path
-
-This allows drivers to provide a destination device + info for flow offload
-Only supported in combination with 802.3 encap offload
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
-Tested-by: Lorenzo Bianconi <lorenzo@kernel.org>
-Link: https://lore.kernel.org/r/20211112112223.1209-1-nbd@nbd.name
-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
----
-
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -3937,6 +3937,8 @@ struct ieee80211_prep_tx_info {
- * twt structure.
- * @twt_teardown_request: Update the hw with TWT teardown request received
- * from the peer.
-+ * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
-+ * resolve a path for hardware flow offloading
- */
- struct ieee80211_ops {
- void (*tx)(struct ieee80211_hw *hw,
-@@ -4265,6 +4267,11 @@ struct ieee80211_ops {
- struct ieee80211_twt_setup *twt);
- void (*twt_teardown_request)(struct ieee80211_hw *hw,
- struct ieee80211_sta *sta, u8 flowid);
-+ int (*net_fill_forward_path)(struct ieee80211_hw *hw,
-+ struct ieee80211_vif *vif,
-+ struct ieee80211_sta *sta,
-+ struct net_device_path_ctx *ctx,
-+ struct net_device_path *path);
- };
-
- /**
---- a/net/mac80211/driver-ops.h
-+++ b/net/mac80211/driver-ops.h
-@@ -1483,4 +1483,26 @@ static inline void drv_twt_teardown_requ
- trace_drv_return_void(local);
- }
-
-+static inline int drv_net_fill_forward_path(struct ieee80211_local *local,
-+ struct ieee80211_sub_if_data *sdata,
-+ struct ieee80211_sta *sta,
-+ struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ int ret = -EOPNOTSUPP;
-+
-+ sdata = get_bss_sdata(sdata);
-+ if (!check_sdata_in_driver(sdata))
-+ return -EIO;
-+
-+ trace_drv_net_fill_forward_path(local, sdata, sta);
-+ if (local->ops->net_fill_forward_path)
-+ ret = local->ops->net_fill_forward_path(&local->hw,
-+ &sdata->vif, sta,
-+ ctx, path);
-+ trace_drv_return_int(local, ret);
-+
-+ return ret;
-+}
-+
- #endif /* __MAC80211_DRIVER_OPS */
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -1465,7 +1465,7 @@ struct ieee80211_local {
- };
-
- static inline struct ieee80211_sub_if_data *
--IEEE80211_DEV_TO_SUB_IF(struct net_device *dev)
-+IEEE80211_DEV_TO_SUB_IF(const struct net_device *dev)
- {
- return netdev_priv(dev);
- }
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -822,6 +822,66 @@ static const struct net_device_ops ieee8
-
- };
-
-+#if LINUX_VERSION_IS_GEQ(5,10,0)
-+static int ieee80211_netdev_fill_forward_path(struct net_device_path_ctx *ctx,
-+ struct net_device_path *path)
-+{
-+ struct ieee80211_sub_if_data *sdata;
-+ struct ieee80211_local *local;
-+ struct sta_info *sta;
-+ int ret = -ENOENT;
-+
-+ sdata = IEEE80211_DEV_TO_SUB_IF(ctx->dev);
-+ local = sdata->local;
-+
-+ if (!local->ops->net_fill_forward_path)
-+ return -EOPNOTSUPP;
-+
-+ rcu_read_lock();
-+ switch (sdata->vif.type) {
-+ case NL80211_IFTYPE_AP_VLAN:
-+ sta = rcu_dereference(sdata->u.vlan.sta);
-+ if (sta)
-+ break;
-+ if (sdata->wdev.use_4addr)
-+ goto out;
-+ if (is_multicast_ether_addr(ctx->daddr))
-+ goto out;
-+ sta = sta_info_get_bss(sdata, ctx->daddr);
-+ break;
-+ case NL80211_IFTYPE_AP:
-+ if (is_multicast_ether_addr(ctx->daddr))
-+ goto out;
-+ sta = sta_info_get(sdata, ctx->daddr);
-+ break;
-+ case NL80211_IFTYPE_STATION:
-+ if (sdata->wdev.wiphy->flags & WIPHY_FLAG_SUPPORTS_TDLS) {
-+ sta = sta_info_get(sdata, ctx->daddr);
-+ if (sta && test_sta_flag(sta, WLAN_STA_TDLS_PEER)) {
-+ if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH))
-+ goto out;
-+
-+ break;
-+ }
-+ }
-+
-+ sta = sta_info_get(sdata, sdata->u.mgd.bssid);
-+ break;
-+ default:
-+ goto out;
-+ }
-+
-+ if (!sta)
-+ goto out;
-+
-+ ret = drv_net_fill_forward_path(local, sdata, &sta->sta, ctx, path);
-+out:
-+ rcu_read_unlock();
-+
-+ return ret;
-+}
-+#endif
-+
- static const struct net_device_ops ieee80211_dataif_8023_ops = {
- #if LINUX_VERSION_IS_LESS(4,10,0)
- .ndo_change_mtu = __change_mtu,
-@@ -839,7 +899,9 @@ static const struct net_device_ops ieee8
- #else
- .ndo_get_stats64 = bp_ieee80211_get_stats64,
- #endif
--
-+#if LINUX_VERSION_IS_GEQ(5,10,0)
-+ .ndo_fill_forward_path = ieee80211_netdev_fill_forward_path,
-+#endif
- };
-
- static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype)
---- a/net/mac80211/trace.h
-+++ b/net/mac80211/trace.h
-@@ -2892,6 +2892,13 @@ TRACE_EVENT(drv_twt_teardown_request,
- )
- );
-
-+DEFINE_EVENT(sta_event, drv_net_fill_forward_path,
-+ TP_PROTO(struct ieee80211_local *local,
-+ struct ieee80211_sub_if_data *sdata,
-+ struct ieee80211_sta *sta),
-+ TP_ARGS(local, sdata, sta)
-+);
-+
- #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
-
- #undef TRACE_INCLUDE_PATH
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Wed, 28 Apr 2021 21:03:13 +0200
-Subject: [PATCH] mac80211: minstrel_ht: fix MINSTREL_FRAC macro
-
-Add missing braces to avoid issues with e.g. using additions in the
-div expression
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.h
-+++ b/net/mac80211/rc80211_minstrel_ht.h
-@@ -14,7 +14,7 @@
-
- /* scaled fraction values */
- #define MINSTREL_SCALE 12
--#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div)
-+#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / (div))
- #define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE)
-
- #define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 6 Feb 2021 16:08:01 +0100
-Subject: [PATCH] mac80211: minstrel_ht: reduce fluctuations in rate
- probability stats
-
-In some scenarios when there is a lot of fluctuation in packet error rates,
-rate switching can be amplified when the statistics get skewed by time slots
-with very few tries.
-Make the input data to the moving average more smooth by adding the
-success/attempts count from the last stats window as well. This has the
-advantage of smoothing the data without introducing any extra lag to sampling
-rates.
-This significantly improves rate stability on a strong test link subjected to
-periodic noise bursts generated with a SDR
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -700,7 +700,8 @@ minstrel_ht_calc_rate_stats(struct minst
- unsigned int cur_prob;
-
- if (unlikely(mrs->attempts > 0)) {
-- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts);
-+ cur_prob = MINSTREL_FRAC(mrs->success + mrs->last_success,
-+ mrs->attempts + mrs->last_attempts);
- minstrel_filter_avg_add(&mrs->prob_avg,
- &mrs->prob_avg_1, cur_prob);
- mrs->att_hist += mrs->attempts;
+++ /dev/null
-From: Felix Fietkau <nbd@nbd.name>
-Date: Sat, 6 Feb 2021 16:33:14 +0100
-Subject: [PATCH] mac80211: minstrel_ht: rework rate downgrade code and
- max_prob rate selection
-
-The current fallback code for fast rate switching on potentially failing rates
-is triggering too often if there is some strong noise on the channel. This can
-lead to wild fluctuations in the rate selection.
-Additionally, switching down to max_prob_rate can create a significant gap down
-in throughput, especially when using only 2 spatial streams, because max_prob_rate
-is limited to using fewer streams than the max_tp rates.
-In order to improve throughput without reducing reliability too much, use the
-rate downgrade code for the max_prob_rate only, and allow the non-downgraded
-max_prob_rate to use as many spatial streams as the max_tp rates
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/net/mac80211/rc80211_minstrel_ht.c
-+++ b/net/mac80211/rc80211_minstrel_ht.c
-@@ -511,6 +511,14 @@ minstrel_ht_set_best_prob_rate(struct mi
- int cur_tp_avg, cur_group, cur_idx;
- int max_gpr_group, max_gpr_idx;
- int max_gpr_tp_avg, max_gpr_prob;
-+ int min_dur;
-+
-+ min_dur = max(minstrel_get_duration(mi->max_tp_rate[0]),
-+ minstrel_get_duration(mi->max_tp_rate[1]));
-+
-+ /* make the rate at least 18% slower than max tp rates */
-+ if (minstrel_get_duration(index) <= min_dur * 19 / 16)
-+ return;
-
- cur_group = MI_RATE_GROUP(index);
- cur_idx = MI_RATE_IDX(index);
-@@ -532,11 +540,6 @@ minstrel_ht_set_best_prob_rate(struct mi
- !minstrel_ht_is_legacy_group(max_tp_group))
- return;
-
-- /* skip rates faster than max tp rate with lower prob */
-- if (minstrel_get_duration(mi->max_tp_rate[0]) > minstrel_get_duration(index) &&
-- mrs->prob_avg < max_tp_prob)
-- return;
--
- max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate);
- max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate);
- max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg;
-@@ -594,40 +597,6 @@ minstrel_ht_assign_best_tp_rates(struct
-
- }
-
--/*
-- * Try to increase robustness of max_prob rate by decrease number of
-- * streams if possible.
-- */
--static inline void
--minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi)
--{
-- struct minstrel_mcs_group_data *mg;
-- int tmp_max_streams, group, tmp_idx, tmp_prob;
-- int tmp_tp = 0;
--
-- if (!mi->sta->ht_cap.ht_supported)
-- return;
--
-- group = MI_RATE_GROUP(mi->max_tp_rate[0]);
-- tmp_max_streams = minstrel_mcs_groups[group].streams;
-- for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) {
-- mg = &mi->groups[group];
-- if (!mi->supported[group] || group == MINSTREL_CCK_GROUP)
-- continue;
--
-- tmp_idx = MI_RATE_IDX(mg->max_group_prob_rate);
-- tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg;
--
-- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) &&
-- (minstrel_mcs_groups[group].streams < tmp_max_streams)) {
-- mi->max_prob_rate = mg->max_group_prob_rate;
-- tmp_tp = minstrel_ht_get_tp_avg(mi, group,
-- tmp_idx,
-- tmp_prob);
-- }
-- }
--}
--
- static u16
- __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
- enum minstrel_sample_type type)
-@@ -1107,8 +1076,6 @@ minstrel_ht_update_stats(struct minstrel
-
- mi->max_prob_rate = tmp_max_prob_rate;
-
-- /* Try to increase robustness of max_prob_rate*/
-- minstrel_ht_prob_rate_reduce_streams(mi);
- minstrel_ht_refill_sample_rates(mi);
-
- #ifdef CPTCFG_MAC80211_DEBUGFS
-@@ -1153,7 +1120,7 @@ minstrel_ht_txstat_valid(struct minstrel
- }
-
- static void
--minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary)
-+minstrel_downgrade_prob_rate(struct minstrel_ht_sta *mi, u16 *idx)
- {
- int group, orig_group;
-
-@@ -1168,11 +1135,7 @@ minstrel_downgrade_rate(struct minstrel_
- minstrel_mcs_groups[orig_group].streams)
- continue;
-
-- if (primary)
-- *idx = mi->groups[group].max_group_tp_rate[0];
-- else
-- *idx = mi->groups[group].max_group_tp_rate[1];
-- break;
-+ *idx = mi->groups[group].max_group_prob_rate;
- }
- }
-
-@@ -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;
-- struct minstrel_rate_stats *rate, *rate2;
-+ struct minstrel_rate_stats *rate;
- struct minstrel_priv *mp = priv;
- u32 update_interval = mp->update_interval;
- bool last, update = false;
-@@ -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.
-+ * only do this for the max_prob_rate to prevent spurious
-+ * rate fluctuations when the link changes suddenly
- */
-- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]);
-+ rate = minstrel_get_ratestats(mi, mi->max_prob_rate);
- if (rate->attempts > 30 &&
- rate->success < rate->attempts / 4) {
-- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true);
-- update = true;
-- }
--
-- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]);
-- if (rate2->attempts > 30 &&
-- rate2->success < rate2->attempts / 4) {
-- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false);
-+ minstrel_downgrade_prob_rate(mi, &mi->max_prob_rate);
- update = true;
- }
- }