[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
ac60b1ff [MAC80211][misc][Add Filogic 880/860/830/820/630 Release Information]
7eb946a0 [MAC80211][WiFi7][hostapd][sync hostapd patches]
91638fc9 [MAC80211][WiFi7][mac80211][sync backports code]
8e45746b [MAC80211][WiFi7][mt76][sync mt76 patches]
1c564afa [MAC80211][WiFi7][mt76][Add Eagle BE19000 ifem default bin]
[Release-log]
Change-Id: I1d4218d3b1211700acb5937fe310cbd0bf219968
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0001-mtk-Revert-wifi-mt76-mt7996-fill-txd-by-host-driver.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0001-mtk-Revert-wifi-mt76-mt7996-fill-txd-by-host-driver.patch
index 93e37fb..87c34b2 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0001-mtk-Revert-wifi-mt76-mt7996-fill-txd-by-host-driver.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0001-mtk-Revert-wifi-mt76-mt7996-fill-txd-by-host-driver.patch
@@ -1,7 +1,7 @@
-From 5278bba5f5096bf42e0d808d4c23b2af3d16dd73 Mon Sep 17 00:00:00 2001
+From 4b6925449bf9160932961c506fb8f06db29a5e77 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Tue, 19 Sep 2023 11:21:23 +0800
-Subject: [PATCH 01/17] mtk: Revert "wifi: mt76: mt7996: fill txd by host
+Subject: [PATCH 001/116] mtk: Revert "wifi: mt76: mt7996: fill txd by host
driver"
This reverts commit 325a0c4931990d553487024c4f76c776492bdcc2.
@@ -10,7 +10,7 @@
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index bc7111a7..3afdd7eb 100644
+index bc7111a71..3afdd7eb9 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -938,8 +938,11 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
@@ -41,5 +41,5 @@
if (!key)
txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0002-bp-sync-upstream-changes.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-bp-sync-upstream-changes.patch
new file mode 100644
index 0000000..0937b99
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0002-bp-sync-upstream-changes.patch
@@ -0,0 +1,79 @@
+From aff8d4c7a0312f94429e93edc21b0e6b04899e12 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 21 Mar 2024 12:14:20 +0800
+Subject: [PATCH 002/116] bp: sync upstream changes
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 6 +++---
+ mt7615/mcu.c | 2 +-
+ mt7915/mcu.c | 2 +-
+ mt7996/mcu.c | 2 +-
+ 4 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index e7b763bab..64307b967 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1613,8 +1613,8 @@ EXPORT_SYMBOL_GPL(mt76_get_sar_power);
+ static void
+ __mt76_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+- if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif))
+- ieee80211_csa_finish(vif);
++ if (vif->bss_conf.csa_active && ieee80211_beacon_cntdwn_is_complete(vif, 0))
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ void mt76_csa_finish(struct mt76_dev *dev)
+@@ -1638,7 +1638,7 @@ __mt76_csa_check(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ if (!vif->bss_conf.csa_active)
+ return;
+
+- dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif);
++ dev->csa_complete |= ieee80211_beacon_cntdwn_is_complete(vif, 0);
+ }
+
+ void mt76_csa_check(struct mt76_dev *dev)
+diff --git a/mt7615/mcu.c b/mt7615/mcu.c
+index ae34d019e..c807bd8d9 100644
+--- a/mt7615/mcu.c
++++ b/mt7615/mcu.c
+@@ -353,7 +353,7 @@ static void
+ mt7615_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+ if (vif->bss_conf.csa_active)
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ static void
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index fe54a2f40..24daa0835 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -228,7 +228,7 @@ mt7915_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ static void
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index aa4478fdf..4f8e656b2 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -341,7 +341,7 @@ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+- ieee80211_csa_finish(vif);
++ ieee80211_csa_finish(vif, 0);
+ }
+
+ static void
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0002-mtk-wifi-mt76-connac-use-peer-address-for-station-BM.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-mtk-wifi-mt76-connac-use-peer-address-for-station-BM.patch
deleted file mode 100644
index 4067faf..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0002-mtk-wifi-mt76-connac-use-peer-address-for-station-BM.patch
+++ /dev/null
@@ -1,54 +0,0 @@
-From b4eb6156a2693382e93c5a2d5d3c564c0a2bb198 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Thu, 24 Aug 2023 18:38:11 +0800
-Subject: [PATCH 02/17] mtk: wifi: mt76: connac: use peer address for station
- BMC entry
-
-Set peer address and aid for the BMC wtbl of station interface. For some
-functions such as parsing MU_EDCA parameters from beacon, firmware will
-need peer address to do the correct mapping.
-
-Reported-by: Howard Hsu <howard-yh.hsu@mediatek.com>
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
----
- mt76_connac_mcu.c | 9 ++++++++-
- mt7996/main.c | 3 +++
- 2 files changed, 11 insertions(+), 1 deletion(-)
-
-diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index 368c5f46..fec158ec 100644
---- a/mt76_connac_mcu.c
-+++ b/mt76_connac_mcu.c
-@@ -392,7 +392,14 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
-
- if (!sta) {
- basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
-- eth_broadcast_addr(basic->peer_addr);
-+
-+ if (vif->type == NL80211_IFTYPE_STATION &&
-+ !is_zero_ether_addr(vif->bss_conf.bssid)) {
-+ memcpy(basic->peer_addr, vif->bss_conf.bssid, ETH_ALEN);
-+ basic->aid = cpu_to_le16(vif->cfg.aid);
-+ } else {
-+ eth_broadcast_addr(basic->peer_addr);
-+ }
- return;
- }
-
-diff --git a/mt7996/main.c b/mt7996/main.c
-index 2bf8e8a8..37e40f1d 100644
---- a/mt7996/main.c
-+++ b/mt7996/main.c
-@@ -598,6 +598,9 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
- if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) ||
- (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||
- (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) {
-+ /* reset bmc wtbl once BSSID changed */
-+ if (changed & BSS_CHANGED_BSSID)
-+ mt7996_mcu_add_sta(dev, vif, NULL, false);
- mt7996_mcu_add_bss_info(phy, vif, true);
- mt7996_mcu_add_sta(dev, vif, NULL, true);
- }
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0003-mtk-wifi-mt76-mt7996-disable-rx-header-translation-f.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-mtk-wifi-mt76-mt7996-disable-rx-header-translation-f.patch
deleted file mode 100644
index 520f6a9..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0003-mtk-wifi-mt76-mt7996-disable-rx-header-translation-f.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From ac159c7469469353fa25787ceb7f25c8e33c59fb Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Tue, 5 Sep 2023 17:31:49 +0800
-Subject: [PATCH 03/17] mtk: wifi: mt76: mt7996: disable rx header translation
- for BMC entry
-
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
----
- mt7996/mcu.c | 9 +++++----
- 1 file changed, 5 insertions(+), 4 deletions(-)
-
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 1356ac14..7f412d6c 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -1778,10 +1778,10 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- else
- hdr_trans->from_ds = true;
-
-- wcid = (struct mt76_wcid *)sta->drv_priv;
-- if (!wcid)
-+ if (!sta)
- return;
-
-+ wcid = (struct mt76_wcid *)sta->drv_priv;
- hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);
- if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {
- hdr_trans->to_ds = true;
-@@ -2154,6 +2154,9 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
- if (!enable)
- goto out;
-
-+ /* starec hdr trans */
-+ mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
-+
- /* tag order is in accordance with firmware dependency. */
- if (sta) {
- /* starec hdrt mode */
-@@ -2178,8 +2181,6 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
- mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta);
- /* starec bfee */
- mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
-- /* starec hdr trans */
-- mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
- }
-
- ret = mt7996_mcu_add_group(dev, vif, sta);
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0003-mtk-wifi-mt76-mt7996-let-upper-layer-handle-MGMT-fra.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-mtk-wifi-mt76-mt7996-let-upper-layer-handle-MGMT-fra.patch
new file mode 100644
index 0000000..0b35ce2
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0003-mtk-wifi-mt76-mt7996-let-upper-layer-handle-MGMT-fra.patch
@@ -0,0 +1,51 @@
+From a764efbef07c65a3b712dc1c5d619c3f22bd6433 Mon Sep 17 00:00:00 2001
+From: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Date: Mon, 18 Mar 2024 17:06:58 +0800
+Subject: [PATCH 003/116] mtk: wifi: mt76: mt7996: let upper layer handle MGMT
+ frame protection
+
+The firmware support for management frame protection has limitations:
+- do not support cipher BIP-GMAC-128 and BIP-GMAC-256
+- support cipher BIP-CMAC-128 and BIP-CMAC-256, except action frame with
+ action type 'not robust'.
+
+Therefore, to simplify the logic, do not set the IGTK to firmware and
+let the encryption of management frames be handled by upper layer.
+
+CR-Id: WCNCR00289305
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/main.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 16115c279..a65a1efca 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -352,10 +352,6 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+
+ /* fall back to sw encryption for unsupported ciphers */
+ switch (key->cipher) {
+- case WLAN_CIPHER_SUITE_AES_CMAC:
+- wcid_keyidx = &wcid->hw_key_idx2;
+- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
+- break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ case WLAN_CIPHER_SUITE_CCMP:
+ case WLAN_CIPHER_SUITE_CCMP_256:
+@@ -363,6 +359,11 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ case WLAN_CIPHER_SUITE_GCMP_256:
+ case WLAN_CIPHER_SUITE_SMS4:
+ break;
++ case WLAN_CIPHER_SUITE_AES_CMAC:
++ wcid_keyidx = &wcid->hw_key_idx2;
++ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
++ fallthrough;
++ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+ if (key->keyidx == 6 || key->keyidx == 7)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-mtk-wifi-mt76-mt7996-set-RCPI-value-in-rate-control-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0004-mtk-wifi-mt76-mt7996-set-RCPI-value-in-rate-control-.patch
deleted file mode 100644
index bcbf32a..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0004-mtk-wifi-mt76-mt7996-set-RCPI-value-in-rate-control-.patch
+++ /dev/null
@@ -1,39 +0,0 @@
-From 8f88d7ea931cb3fcc12f609598f8997e66051bff Mon Sep 17 00:00:00 2001
-From: Peter Chiu <chui-hao.chiu@mediatek.com>
-Date: Mon, 13 Nov 2023 20:15:39 +0800
-Subject: [PATCH 04/17] mtk: wifi: mt76: mt7996: set RCPI value in rate control
- command
-
-Set RCPI values in mt7996_mcu_sta_rate_ctrl_tlv(), which can make the
-FW rate control be initialized with a better MCS selection table.
-
-Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
----
- mt7996/mcu.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 7f412d6c..0f1905f2 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -1968,6 +1968,7 @@ static void
- mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
- {
-+#define INIT_RCPI 180
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
- struct mt76_phy *mphy = mvif->phy->mt76;
- struct cfg80211_chan_def *chandef = &mphy->chandef;
-@@ -2065,6 +2066,8 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
- IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
- }
- ra->sta_cap = cpu_to_le32(cap);
-+
-+ memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi));
- }
-
- int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-use-hweight16-to-get-correct-tx_ant.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-use-hweight16-to-get-correct-tx_ant.patch
new file mode 100644
index 0000000..0f821aa
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-use-hweight16-to-get-correct-tx_ant.patch
@@ -0,0 +1,35 @@
+From b403f206062aee515c6d0fcabf327a87c7a04fbc Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Wed, 10 Apr 2024 14:05:12 +0800
+Subject: [PATCH 004/116] wifi: mt76: mt7996: use hweight16 to get correct
+ tx_ant
+
+The chainmask is u16 so using hweight8 cannot get correct tx_ant.
+
+Without this patch, the tx_ant of band 2 would be -1 and lead to
+the following issue:
+BUG: KASAN: stack-out-of-bounds in mt7996_mcu_add_sta+0x12e0/0x16e0 [mt7996e]
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+CR-Id: WCNCR00240772
+Change-Id: I5ccd634431c6047371e687c7c4bb4f315f2c97e5
+---
+ mt7996/mcu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 4f8e656b2..e426d0737 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1653,7 +1653,7 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_phy *phy = mvif->phy;
+- int tx_ant = hweight8(phy->mt76->chainmask) - 1;
++ int tx_ant = hweight16(phy->mt76->chainmask) - 1;
+ struct sta_rec_bf *bf;
+ struct tlv *tlv;
+ const u8 matrix[4][4] = {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0005-mtk-wifi-mt76-mt7996-enable-hw-cso-module.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0005-mtk-wifi-mt76-mt7996-enable-hw-cso-module.patch
deleted file mode 100644
index 2321fa4..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0005-mtk-wifi-mt76-mt7996-enable-hw-cso-module.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 01b4af6ea238a69c90d136cdf4684869481d03b7 Mon Sep 17 00:00:00 2001
-From: Howard Hsu <howard-yh.hsu@mediatek.com>
-Date: Wed, 3 Jan 2024 15:21:44 +0800
-Subject: [PATCH 05/17] mtk: wifi: mt76: mt7996: enable hw cso module
-
-The cso module needs to be enabled. The cso mudule can help identify if the traffic
-is TCP traffic. This can assist the firmware in adjusting algorithms to
-improve overall performance.
-
-Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
----
- mt76_connac_mcu.h | 7 +++++++
- mt7996/mcu.c | 15 +++++++++++++++
- 2 files changed, 22 insertions(+)
-
-diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 2a4aa796..f1cd2e50 100644
---- a/mt76_connac_mcu.h
-+++ b/mt76_connac_mcu.h
-@@ -610,6 +610,12 @@ struct sta_rec_ra_fixed {
- u8 mmps_mode;
- } __packed;
-
-+struct sta_rec_tx_proc {
-+ __le16 tag;
-+ __le16 len;
-+ __le32 flag;
-+} __packed;
-+
- /* wtbl_rec */
-
- struct wtbl_req_hdr {
-@@ -777,6 +783,7 @@ struct wtbl_raw {
- sizeof(struct sta_rec_ra_fixed) + \
- sizeof(struct sta_rec_he_6g_capa) + \
- sizeof(struct sta_rec_pn_info) + \
-+ sizeof(struct sta_rec_tx_proc) + \
- sizeof(struct tlv) + \
- MT76_CONNAC_WTBL_UPDATE_MAX_SIZE)
-
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 0f1905f2..aa054167 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -1748,6 +1748,19 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- bfee->fb_identity_matrix = (nrow == 1 && tx_ant == 2);
- }
-
-+static void
-+mt7996_mcu_sta_tx_proc_tlv(struct sk_buff *skb)
-+{
-+ struct sta_rec_tx_proc *tx_proc;
-+ struct tlv *tlv;
-+
-+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_TX_PROC, sizeof(*tx_proc));
-+
-+ tx_proc = (struct sta_rec_tx_proc *)tlv;
-+ /* CSO is enabled if this flag exists. */
-+ tx_proc->flag = cpu_to_le32(0);
-+}
-+
- static void
- mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb)
- {
-@@ -2159,6 +2172,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
-
- /* starec hdr trans */
- mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
-+ /* starec tx proc */
-+ mt7996_mcu_sta_tx_proc_tlv(skb);
-
- /* tag order is in accordance with firmware dependency. */
- if (sta) {
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0005-mtk-wifi-mt76-mt7996-fix-MBSS.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0005-mtk-wifi-mt76-mt7996-fix-MBSS.patch
new file mode 100644
index 0000000..331153f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0005-mtk-wifi-mt76-mt7996-fix-MBSS.patch
@@ -0,0 +1,31 @@
+From eb0640a1313c7f6a3fd579d2e0ad4209808440db Mon Sep 17 00:00:00 2001
+From: Rex Lu <rex.lu@mediatek.com>
+Date: Thu, 18 Apr 2024 14:19:21 +0800
+Subject: [PATCH 005/116] mtk: wifi: mt76: mt7996: fix MBSS
+
+Refactor 11v mbss unicmd flow
+case1(disable->enable) : when we enable 11v MBSS, we have to add 11v mbss tlv(UNI_BSS_INFO_11V_MBSSID)
+case2(enable->disable) : when we diable 11v MBSS, we should clear 11v mbss tlv (UNI_BSS_INFO_11V_MBSSID-> all value to zero) first,
+otherwise it will cause PSE opration ERR and trigger L1SER. After clear 11v mbss tlv,we have to reset UNI_BSS_INFO_BASIC(from 11v MBSS mode to legacy mode)
+
+Signed-off-by: Rex Lu <rex.lu@mediatek.com>
+---
+ mt7996/mcu.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index e426d0737..f23801901 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -822,7 +822,7 @@ mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct bss_info_uni_mbssid *mbssid;
+ struct tlv *tlv;
+
+- if (!vif->bss_conf.bssid_indicator)
++ if (!vif->bss_conf.bssid_indicator && enable)
+ return;
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_11V_MBSSID, sizeof(*mbssid));
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0006-mtk-wifi-mt76-mt7996-fix-non-main-BSS-no-beacon-issu.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0006-mtk-wifi-mt76-mt7996-fix-non-main-BSS-no-beacon-issu.patch
deleted file mode 100644
index 38cb111..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0006-mtk-wifi-mt76-mt7996-fix-non-main-BSS-no-beacon-issu.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 962986bbac91d5a97482f9ae74655ffca70763b1 Mon Sep 17 00:00:00 2001
-From: Henry Yen <henry.yen@mediatek.com>
-Date: Fri, 2 Feb 2024 16:42:24 +0800
-Subject: [PATCH 06/17] mtk: wifi: mt76: mt7996: fix non-main BSS no beacon
- issue for legacy MBSS scenario
-
-Fix non-main BSS no beacon issue for mt7992 legacy MBSS scenario.
-
-There are some design differences between mt7996 and mt7992 in terms of
-MBSS time offset. The original MBSS MCU CMD usage is not applicable to
-mt7992, so we modify the flow to avoid abnormal beaconing behavior
-in MBSS scenario.
-
-Signed-off-by: Henry.Yen <henry.yen@mediatek.com>
-
----
- mt7996/mcu.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index aa054167..6b8a5076 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -819,11 +819,14 @@ mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
- struct bss_info_uni_mbssid *mbssid;
- struct tlv *tlv;
-
-+ if (!vif->bss_conf.bssid_indicator)
-+ return;
-+
- tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_11V_MBSSID, sizeof(*mbssid));
-
- mbssid = (struct bss_info_uni_mbssid *)tlv;
-
-- if (enable && vif->bss_conf.bssid_indicator) {
-+ if (enable) {
- mbssid->max_indicator = vif->bss_conf.bssid_indicator;
- mbssid->mbss_idx = vif->bss_conf.bssid_index;
- mbssid->tx_bss_omac_idx = 0;
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-HE-and-EHT-phy-cap.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-HE-and-EHT-phy-cap.patch
new file mode 100644
index 0000000..82e083c
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-HE-and-EHT-phy-cap.patch
@@ -0,0 +1,148 @@
+From a6f5e8e1df21f5d65fcef533b96b9d26680d5bc3 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Tue, 12 Mar 2024 09:07:52 +0800
+Subject: [PATCH 006/116] wifi: mt76: mt7996: fix HE and EHT phy cap
+
+This commit fix he and eht phy capabailties ie. For HE phy cap, fix
+correct beamform capabilities for station vif. For EHT phy cap, remove
+unsupported capabilities.
+
+Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi7 (802.11be) devices")
+Fixes: 348533eb968d ("wifi: mt76: mt7996: add EHT capability init")
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+
+Change-Id: Ic853ec1b62344ac08787673ae22254f9829e0e6e
+CR-Id: WCNCR00240772
+---
+ mt7996/init.c | 65 ++++++++++++++++++++++++++++++++++-----------------
+ 1 file changed, 43 insertions(+), 22 deletions(-)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 9aa97e4a7..c264d5043 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -1010,8 +1010,6 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy,
+ return;
+
+ elem->phy_cap_info[3] |= IEEE80211_HE_PHY_CAP3_SU_BEAMFORMER;
+- if (vif == NL80211_IFTYPE_AP)
+- elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
+
+ c = FIELD_PREP(IEEE80211_HE_PHY_CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
+ sts - 1) |
+@@ -1019,6 +1017,11 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy,
+ sts - 1);
+ elem->phy_cap_info[5] |= c;
+
++ if (vif != NL80211_IFTYPE_AP)
++ return;
++
++ elem->phy_cap_info[4] |= IEEE80211_HE_PHY_CAP4_MU_BEAMFORMER;
++
+ c = IEEE80211_HE_PHY_CAP6_TRIG_SU_BEAMFORMING_FB |
+ IEEE80211_HE_PHY_CAP6_TRIG_MU_BEAMFORMING_PARTIAL_BW_FB;
+ elem->phy_cap_info[6] |= c;
+@@ -1178,7 +1181,6 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
+ IEEE80211_EHT_MAC_CAP0_OM_CONTROL;
+
+ eht_cap_elem->phy_cap_info[0] =
+- IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ |
+ IEEE80211_EHT_PHY_CAP0_NDP_4_EHT_LFT_32_GI |
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
+@@ -1192,30 +1194,36 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
+ u8_encode_bits(u8_get_bits(val, GENMASK(2, 1)),
+ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_80MHZ_MASK) |
+ u8_encode_bits(val,
+- IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK) |
+- u8_encode_bits(val,
+- IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
++ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_160MHZ_MASK);
+
+ eht_cap_elem->phy_cap_info[2] =
+ u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_80MHZ_MASK) |
+- u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK) |
+- u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK);
++ u8_encode_bits(sts - 1, IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_160MHZ_MASK);
++
++ if (band == NL80211_BAND_6GHZ) {
++ eht_cap_elem->phy_cap_info[0] |=
++ IEEE80211_EHT_PHY_CAP0_320MHZ_IN_6GHZ;
++
++ eht_cap_elem->phy_cap_info[1] |=
++ u8_encode_bits(val,
++ IEEE80211_EHT_PHY_CAP1_BEAMFORMEE_SS_320MHZ_MASK);
++
++ eht_cap_elem->phy_cap_info[2] |=
++ u8_encode_bits(sts - 1,
++ IEEE80211_EHT_PHY_CAP2_SOUNDING_DIM_320MHZ_MASK);
++ }
+
+ eht_cap_elem->phy_cap_info[3] =
+ IEEE80211_EHT_PHY_CAP3_NG_16_SU_FEEDBACK |
+ IEEE80211_EHT_PHY_CAP3_NG_16_MU_FEEDBACK |
+ IEEE80211_EHT_PHY_CAP3_CODEBOOK_4_2_SU_FDBK |
+- IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK |
+- IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
+- IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK |
+- IEEE80211_EHT_PHY_CAP3_TRIG_CQI_FDBK;
++ IEEE80211_EHT_PHY_CAP3_CODEBOOK_7_5_MU_FDBK;
+
+ eht_cap_elem->phy_cap_info[4] =
+ u8_encode_bits(min_t(int, sts - 1, 2),
+ IEEE80211_EHT_PHY_CAP4_MAX_NC_MASK);
+
+ eht_cap_elem->phy_cap_info[5] =
+- IEEE80211_EHT_PHY_CAP5_NON_TRIG_CQI_FEEDBACK |
+ u8_encode_bits(IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_16US,
+ IEEE80211_EHT_PHY_CAP5_COMMON_NOMINAL_PKT_PAD_MASK) |
+ u8_encode_bits(u8_get_bits(0x11, GENMASK(1, 0)),
+@@ -1229,14 +1237,6 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
+ IEEE80211_EHT_PHY_CAP6_MAX_NUM_SUPP_EHT_LTF_MASK) |
+ u8_encode_bits(val, IEEE80211_EHT_PHY_CAP6_MCS15_SUPP_MASK);
+
+- eht_cap_elem->phy_cap_info[7] =
+- IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
+- IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
+- IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ |
+- IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
+- IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ |
+- IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
+-
+ val = u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_RX) |
+ u8_encode_bits(nss, IEEE80211_EHT_MCS_NSS_TX);
+ #define SET_EHT_MAX_NSS(_bw, _val) do { \
+@@ -1247,8 +1247,29 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
+
+ SET_EHT_MAX_NSS(80, val);
+ SET_EHT_MAX_NSS(160, val);
+- SET_EHT_MAX_NSS(320, val);
++ if (band == NL80211_BAND_6GHZ)
++ SET_EHT_MAX_NSS(320, val);
+ #undef SET_EHT_MAX_NSS
++
++ if (iftype != NL80211_IFTYPE_AP)
++ return;
++
++ eht_cap_elem->phy_cap_info[3] |=
++ IEEE80211_EHT_PHY_CAP3_TRIG_SU_BF_FDBK |
++ IEEE80211_EHT_PHY_CAP3_TRIG_MU_BF_PART_BW_FDBK;
++
++ eht_cap_elem->phy_cap_info[7] =
++ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_80MHZ |
++ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_160MHZ |
++ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ |
++ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ;
++
++ if (band != NL80211_BAND_6GHZ)
++ return;
++
++ eht_cap_elem->phy_cap_info[7] |=
++ IEEE80211_EHT_PHY_CAP7_NON_OFDMA_UL_MU_MIMO_320MHZ |
++ IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ;
+ }
+
+ static void
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mtk-wifi-mt76-mt7996-adjust-Beamformee-SS-capability.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0007-mtk-wifi-mt76-mt7996-adjust-Beamformee-SS-capability.patch
new file mode 100644
index 0000000..d2cd068
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0007-mtk-wifi-mt76-mt7996-adjust-Beamformee-SS-capability.patch
@@ -0,0 +1,69 @@
+From 4dde35f480e8bdf961911d07a49c5443cc0c8e6a Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Tue, 27 Feb 2024 14:50:20 +0800
+Subject: [PATCH 007/116] mtk: wifi: mt76: mt7996: adjust Beamformee SS
+ capability
+
+This commit includes two changes to adjust beamformee ss capability.
+First, configure the beamformee ss capability for mt7992 chipsets.
+Second, no matter how many antenna numbers is set, always set the
+maximum capability of Beamformee SS that chipsets support.
+
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+CR-Id: WCNCR00240772
+Change-Id: I8a7efedbb02790925affdd3b4d81b623f459589c
+---
+ mt7996/init.c | 23 +++++++++++++++++------
+ 1 file changed, 17 insertions(+), 6 deletions(-)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index c264d5043..ab9445cc3 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -940,8 +940,12 @@ void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy)
+ cap = &phy->mt76->sband_5g.sband.vht_cap.cap;
+
+ *cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
+- IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
+- FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, sts - 1);
++ IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
++
++ if (is_mt7996(phy->mt76->dev))
++ *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 3);
++ else
++ *cap |= FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, 4);
+
+ *cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
+@@ -986,9 +990,15 @@ mt7996_set_stream_he_txbf_caps(struct mt7996_phy *phy,
+ IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
+ elem->phy_cap_info[2] |= c;
+
+- c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE |
+- IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 |
+- IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
++ c = IEEE80211_HE_PHY_CAP4_SU_BEAMFORMEE;
++
++ if (is_mt7996(phy->mt76->dev))
++ c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_4 |
++ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_4;
++ else
++ c |= IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_UNDER_80MHZ_5 |
++ IEEE80211_HE_PHY_CAP4_BEAMFORMEE_MAX_STS_ABOVE_80MHZ_5;
++
+ elem->phy_cap_info[4] |= c;
+
+ /* do not support NG16 due to spec D4.0 changes subcarrier idx */
+@@ -1185,7 +1195,8 @@ mt7996_init_eht_caps(struct mt7996_phy *phy, enum nl80211_band band,
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER |
+ IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE;
+
+- val = max_t(u8, sts - 1, 3);
++ /* Set the maximum capability regardless of the antenna configuration. */
++ val = is_mt7992(phy->mt76->dev) ? 4 : 3;
+ eht_cap_elem->phy_cap_info[0] |=
+ u8_encode_bits(u8_get_bits(val, BIT(0)),
+ IEEE80211_EHT_PHY_CAP0_BEAMFORMEE_SS_80MHZ_MASK);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mtk-wifi-mt76-mt7996-initialize-variable-to-avoid-un.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0007-mtk-wifi-mt76-mt7996-initialize-variable-to-avoid-un.patch
deleted file mode 100644
index 33200ad..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mtk-wifi-mt76-mt7996-initialize-variable-to-avoid-un.patch
+++ /dev/null
@@ -1,30 +0,0 @@
-From 354503529d28d44fc94ea65815da5bf0cbdb79e7 Mon Sep 17 00:00:00 2001
-From: Henry Yen <henry.yen@mediatek.com>
-Date: Fri, 19 Jan 2024 11:11:19 +0800
-Subject: [PATCH 07/17] mtk: wifi: mt76: mt7996: initialize variable to avoid
- unexpected IRQ handling
-
-Initialize the variable to avoid processing unexpected interrupts given from wrong source.
-
-Signed-off-by: Henry.Yen <henry.yen@mediatek.com>
-
----
- mt7996/mmio.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 341fa089..8fe56ed9 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -519,7 +519,7 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
- struct mt7996_dev *dev = from_tasklet(dev, t, mt76.irq_tasklet);
- struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
- struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2;
-- u32 i, intr, mask, intr1;
-+ u32 i, intr, mask, intr1 = 0;
-
- if (dev->hif2 && mtk_wed_device_active(wed_hif2)) {
- mtk_wed_device_irq_set_mask(wed_hif2, 0);
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7992-adjust-beamform-mcu-cmd-configurati.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7992-adjust-beamform-mcu-cmd-configurati.patch
new file mode 100644
index 0000000..327a8e3
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7992-adjust-beamform-mcu-cmd-configurati.patch
@@ -0,0 +1,34 @@
+From 43f21d17de82755344f60fe7a026bc3566a89dfb Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Mon, 18 Mar 2024 11:13:56 +0800
+Subject: [PATCH 008/116] wifi: mt76: mt7992: adjust beamform mcu cmd
+ configuration for mt7992
+
+Adjust the correct beamform mcu cmd configuration for mt7992 chipsets.
+
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+CR-Id: WCNCR00240772
+Change-Id: I2230c3a43d735ab7db114299a005b9cc1e89de41
+---
+ mt7996/mcu.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index f23801901..7928571e0 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3920,8 +3920,9 @@ int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action)
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, action, sizeof(*req_mod_en));
+ req_mod_en = (struct bf_mod_en_ctrl *)tlv;
+- req_mod_en->bf_num = 3;
+- req_mod_en->bf_bitmap = GENMASK(2, 0);
++ req_mod_en->bf_num = mt7996_band_valid(dev, MT_BAND2) ? 3 : 2;
++ req_mod_en->bf_bitmap = mt7996_band_valid(dev, MT_BAND2) ?
++ GENMASK(2, 0) : GENMASK(1, 0);
+ break;
+ }
+ default:
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0009-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0009-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch
new file mode 100644
index 0000000..90c2dd0
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0009-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch
@@ -0,0 +1,154 @@
+From e820e86fa2d0b0e0de3c86feb1e0cb4c2ab6e5a2 Mon Sep 17 00:00:00 2001
+From: Allen Ye <allen.ye@mediatek.com>
+Date: Thu, 18 Apr 2024 11:16:24 +0800
+Subject: [PATCH 009/116] mtk: wifi: mt76: mt7996: add preamble puncture
+ support for mt7996
+
+Add support configure preamble puncture feature through mcu commands.
+
+Co-developed-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+Signed-off-by: Allen Ye <allen.ye@mediatek.com>
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/init.c | 1 +
+ mt7996/main.c | 5 +++++
+ mt7996/mcu.c | 40 ++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h | 10 ++++++++++
+ mt7996/mt7996.h | 4 ++++
+ 6 files changed, 61 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 67be14d2a..70def0a3b 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1271,6 +1271,7 @@ enum {
+ MCU_UNI_CMD_CHANNEL_SWITCH = 0x34,
+ MCU_UNI_CMD_THERMAL = 0x35,
+ MCU_UNI_CMD_VOW = 0x37,
++ MCU_UNI_CMD_PP = 0x38,
+ MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
+ MCU_UNI_CMD_RRO = 0x57,
+ MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
+diff --git a/mt7996/init.c b/mt7996/init.c
+index ab9445cc3..afe8a0a1a 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -387,6 +387,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
++ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT);
+
+ if (!mdev->dev->of_node ||
+ !of_property_read_bool(mdev->dev->of_node,
+diff --git a/mt7996/main.c b/mt7996/main.c
+index a65a1efca..2e72fd8ed 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -411,6 +411,11 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+ int ret;
+
+ if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
++ ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE,
++ phy->mt76->chandef.punctured);
++ if (ret)
++ return ret;
++
+ ieee80211_stop_queues(hw);
+ ret = mt7996_set_channel(phy);
+ if (ret)
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 7928571e0..36f72d586 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -4550,3 +4550,43 @@ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode)
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WA_EXT_CMD(CP_SUPPORT),
+ &cp_mode, sizeof(cp_mode), true);
+ }
++
++int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap)
++{
++ struct mt7996_dev *dev = phy->dev;
++ bool pp_auto = (mode == PP_FW_MODE);
++ struct {
++ u8 _rsv1[4];
++
++ __le16 tag;
++ __le16 len;
++ u8 mgmt_mode;
++ u8 band_idx;
++ u8 force_bitmap_ctrl;
++ u8 auto_mode;
++ __le16 bitmap;
++ u8 _rsv2[2];
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_CMD_PP_EN_CTRL),
++ .len = cpu_to_le16(sizeof(req) - 4),
++
++ .mgmt_mode = !pp_auto,
++ .band_idx = phy->mt76->band_idx,
++ .force_bitmap_ctrl = (mode == PP_USR_MODE) ? 2 : 0,
++ .auto_mode = pp_auto,
++ .bitmap = cpu_to_le16(bitmap),
++ };
++
++ if (phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ ||
++ mode > PP_USR_MODE)
++ return 0;
++
++ if (bitmap && phy->punct_bitmap == bitmap)
++ return 0;
++
++ phy->punct_bitmap = bitmap;
++ phy->pp_mode = mode;
++
++ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PP),
++ &req, sizeof(req), false);
++}
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index a9ba63d14..2052555fe 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -923,6 +923,16 @@ enum {
+ MT7996_SEC_MODE_MAX,
+ };
+
++enum {
++ UNI_CMD_PP_EN_CTRL,
++};
++
++enum pp_mode {
++ PP_DISABLE = 0,
++ PP_FW_MODE,
++ PP_USR_MODE,
++};
++
+ #define MT7996_PATCH_SEC GENMASK(31, 24)
+ #define MT7996_PATCH_SCRAMBLE_KEY GENMASK(15, 8)
+ #define MT7996_PATCH_AES_KEY GENMASK(7, 0)
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 177cfff31..58fa6b458 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -237,6 +237,9 @@ struct mt7996_phy {
+ struct mt76_channel_state state_ts;
+
+ bool has_aux_rx;
++
++ u8 pp_mode;
++ u16 punct_bitmap;
+ };
+
+ struct mt7996_dev {
+@@ -614,6 +617,7 @@ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode);
++int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap);
+ #ifdef CONFIG_MAC80211_DEBUGFS
+ void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct dentry *dir);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1014-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0010-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch
similarity index 66%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1014-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0010-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch
index ad4b610..d46ffbb 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1014-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0010-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch
@@ -1,8 +1,8 @@
-From c8dbaeeaff01c35c7e27ef0958d812338e50c054 Mon Sep 17 00:00:00 2001
+From 2a8a93b5c49cb56c5eace22690c7e1544d4e80b1 Mon Sep 17 00:00:00 2001
From: mtk23510 <rudra.shahi@mediatek.com>
Date: Fri, 24 Mar 2023 19:18:53 +0800
-Subject: [PATCH 1014/1044] mtk: wifi: mt76: mt7996: add driver support for
- wpa3 ocv and bp mt76
+Subject: [PATCH 010/116] mtk: wifi: mt76: mt7996: add driver support for wpa3
+ ocv and bp mt76
Signed-off-by: mtk23510 <rudra.shahi@mediatek.com>
---
@@ -10,12 +10,12 @@
1 file changed, 2 insertions(+)
diff --git a/mt7996/init.c b/mt7996/init.c
-index fba61c01..1498787f 100644
+index afe8a0a1a..ab2e17ec4 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -391,6 +391,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
+@@ -389,6 +389,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
@@ -23,5 +23,5 @@
!of_property_read_bool(mdev->dev->of_node,
"mediatek,disable-radar-background"))
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0010-mtk-wifi-mt76-mt7996-add-eagle-default-bin-of-differ.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0010-mtk-wifi-mt76-mt7996-add-eagle-default-bin-of-differ.patch
deleted file mode 100644
index 9c922d6..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0010-mtk-wifi-mt76-mt7996-add-eagle-default-bin-of-differ.patch
+++ /dev/null
@@ -1,111 +0,0 @@
-From 22607765799dad52bcf304ffd5f393878c4317bf Mon Sep 17 00:00:00 2001
-From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Thu, 20 Jul 2023 17:27:22 +0800
-Subject: [PATCH 10/17] mtk: wifi: mt76: mt7996: add eagle default bin of
- different sku variants
-
-Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
----
- mt7996/eeprom.c | 2 ++
- mt7996/init.c | 4 ++++
- mt7996/mt7996.h | 28 ++++++++++++++++++++++++++--
- 3 files changed, 32 insertions(+), 2 deletions(-)
-
-diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 4a823711..7505a8b7 100644
---- a/mt7996/eeprom.c
-+++ b/mt7996/eeprom.c
-@@ -26,6 +26,8 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev)
- {
- switch (mt76_chip(&dev->mt76)) {
- case 0x7990:
-+ if (dev->chip_sku == MT7996_SKU_404)
-+ return MT7996_EEPROM_DEFAULT_404;
- return MT7996_EEPROM_DEFAULT;
- case 0x7992:
- return MT7992_EEPROM_DEFAULT;
-diff --git a/mt7996/init.c b/mt7996/init.c
-index 9aa97e4a..274863dc 100644
---- a/mt7996/init.c
-+++ b/mt7996/init.c
-@@ -897,6 +897,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
- INIT_LIST_HEAD(&dev->wed_rro.poll_list);
- spin_lock_init(&dev->wed_rro.lock);
-
-+ ret = mt7996_get_chip_sku(dev);
-+ if (ret)
-+ return ret;
-+
- ret = mt7996_dma_init(dev);
- if (ret)
- return ret;
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 36d1f247..b6df2167 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -40,6 +40,7 @@
- #define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin"
-
- #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
-+#define MT7996_EEPROM_DEFAULT_404 "mediatek/mt7996/mt7996_eeprom_dual_404.bin"
- #define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin"
- #define MT7996_EEPROM_SIZE 7680
- #define MT7996_EEPROM_BLOCK_SIZE 16
-@@ -88,6 +89,11 @@ struct mt7996_sta;
- struct mt7996_dfs_pulse;
- struct mt7996_dfs_pattern;
-
-+enum mt7996_sku_type {
-+ MT7996_SKU_404,
-+ MT7996_SKU_444,
-+};
-+
- enum mt7996_ram_type {
- MT7996_RAM_TYPE_WM,
- MT7996_RAM_TYPE_WA,
-@@ -257,6 +263,8 @@ struct mt7996_dev {
- struct cfg80211_chan_def rdd2_chandef;
- struct mt7996_phy *rdd2_phy;
-
-+ u8 chip_sku;
-+
- u16 chainmask;
- u8 chainshift[__MT_MAX_BAND];
- u32 hif_idx;
-@@ -398,6 +406,23 @@ mt7996_phy3(struct mt7996_dev *dev)
- return __mt7996_phy(dev, MT_BAND2);
- }
-
-+static inline int
-+mt7996_get_chip_sku(struct mt7996_dev *dev)
-+{
-+ u32 val = mt76_rr(dev, MT_PAD_GPIO);
-+
-+ /* reserve for future variants */
-+ switch (mt76_chip(&dev->mt76)) {
-+ case 0x7990:
-+ dev->chip_sku = FIELD_GET(MT_PAD_GPIO_ADIE_COMB, val) <= 1;
-+ break;
-+ default:
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
- static inline bool
- mt7996_band_valid(struct mt7996_dev *dev, u8 band)
- {
-@@ -405,8 +430,7 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
- return band <= MT_BAND1;
-
- /* tri-band support */
-- if (band <= MT_BAND2 &&
-- mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1)
-+ if (band <= MT_BAND2 && dev->chip_sku)
- return true;
-
- return band == MT_BAND0 || band == MT_BAND2;
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0008-mtk-wifi-mt76-mt7996-enable-ser-query.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0011-mtk-wifi-mt76-mt7996-enable-ser-query.patch
similarity index 68%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0008-mtk-wifi-mt76-mt7996-enable-ser-query.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0011-mtk-wifi-mt76-mt7996-enable-ser-query.patch
index e35b141..e6eb857 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0008-mtk-wifi-mt76-mt7996-enable-ser-query.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0011-mtk-wifi-mt76-mt7996-enable-ser-query.patch
@@ -1,21 +1,22 @@
-From f664f6c14d38adc2bf43f4f969ea21eb3daa48a7 Mon Sep 17 00:00:00 2001
+From 87fdddbf88629d4c0bf6dc966107fb70df157a5a Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Mon, 30 Oct 2023 20:19:41 +0800
-Subject: [PATCH 08/17] mtk: wifi: mt76: mt7996: enable ser query
+Subject: [PATCH 011/116] mtk: wifi: mt76: mt7996: enable ser query
Do not return -EINVAL when action is UNI_CMD_SER_QUERY for user
to dump SER information from FW.
+CR-Id: WCNCR00240772
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
---
mt7996/mcu.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 6b8a5076..0981f592 100644
+index 36f72d586..10637226c 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3860,6 +3860,8 @@ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
+@@ -3865,6 +3865,8 @@ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
};
switch (action) {
@@ -25,5 +26,5 @@
req.set.mask = cpu_to_le32(val);
break;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0012-mtk-wifi-mt76-mt7996-set-key-flag-IEEE80211_KEY_FLAG.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0012-mtk-wifi-mt76-mt7996-set-key-flag-IEEE80211_KEY_FLAG.patch
new file mode 100644
index 0000000..e99403e
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0012-mtk-wifi-mt76-mt7996-set-key-flag-IEEE80211_KEY_FLAG.patch
@@ -0,0 +1,43 @@
+From d33a316c3d868e7ee5b34eac5c8cd0d624b37dc3 Mon Sep 17 00:00:00 2001
+From: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Date: Thu, 18 Apr 2024 17:21:22 +0800
+Subject: [PATCH 012/116] mtk: wifi: mt76: mt7996: set key flag
+ 'IEEE80211_KEY_FLAG_GENERATE_MMIE' for other ciphers
+
+When beacon protection is enabled, FW checks MMIE tag & length in the
+beacon in every cipher mode. Therefore mt76 needs to set the flag
+'IEEE80211_KEY_GENERATE_MMIE' on so that MAC80211 generates and initializes
+MMIE for us.
+
+CR-Id: WCNCR00289305
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+---
+ mt7996/main.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 2e72fd8ed..8b8037f54 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -360,14 +360,14 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ case WLAN_CIPHER_SUITE_SMS4:
+ break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+- wcid_keyidx = &wcid->hw_key_idx2;
+- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
+- fallthrough;
+ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+- if (key->keyidx == 6 || key->keyidx == 7)
++ if (key->keyidx == 6 || key->keyidx == 7) {
++ wcid_keyidx = &wcid->hw_key_idx2;
++ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
+ break;
++ }
+ fallthrough;
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0009-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0013-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch
similarity index 71%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0009-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0013-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch
index 2cf4eec..68798c3 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0009-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0013-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch
@@ -1,21 +1,23 @@
-From 8e5ba5be6820fa12541785907085f312f13e3e04 Mon Sep 17 00:00:00 2001
+From d0bb7153ee8c546e2dc582a77b49c2d7f0f8c7c0 Mon Sep 17 00:00:00 2001
From: mtk27745 <rex.lu@mediatek.com>
Date: Fri, 17 Nov 2023 11:01:04 +0800
-Subject: [PATCH 09/17] mtk: wifi: mt76: mt7996: Fix TGax HE-4.51.1_24G fail
+Subject: [PATCH 013/116] mtk: wifi: mt76: mt7996: Fix TGax HE-4.51.1_24G fail
According to sta capability to decide to enable/disable wed pao when create ppe entry.
without this patch, TGax HE-4.51.1_24G will test fail
Signed-off-by: mtk27745 <rex.lu@mediatek.com>
+CR-Id: WCNCR00259516
+Change-Id: Ic51473fcc24757887f0f9f81a31b6f01dee2c845
---
mt7996/main.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/mt7996/main.c b/mt7996/main.c
-index 37e40f1d..625f87b4 100644
+index 8b8037f54..f553704ce 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -1447,7 +1447,12 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+@@ -1463,7 +1463,12 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
path->mtk_wdma.queue = 0;
path->mtk_wdma.wcid = msta->wcid.idx;
@@ -30,5 +32,5 @@
return 0;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0011-mtk-wifi-mt76-mt7996-add-kite-fw-default-bin-for-dif.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0014-mtk-wifi-mt76-mt7996-add-support-for-different-varia.patch
similarity index 81%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0011-mtk-wifi-mt76-mt7996-add-kite-fw-default-bin-for-dif.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0014-mtk-wifi-mt76-mt7996-add-support-for-different-varia.patch
index dd04ff3..6cbec2f 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0011-mtk-wifi-mt76-mt7996-add-kite-fw-default-bin-for-dif.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0014-mtk-wifi-mt76-mt7996-add-support-for-different-varia.patch
@@ -1,8 +1,8 @@
-From fcf4d59b7cbd6c298ca90b0eae6aec63544b14d9 Mon Sep 17 00:00:00 2001
+From a4eb2ef1c0960faae461ab4585f4572eda428ed2 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Fri, 21 Jul 2023 10:41:28 +0800
-Subject: [PATCH 11/17] mtk: wifi: mt76: mt7996: add kite fw & default bin for
- different sku variants
+Date: Thu, 20 Jul 2023 17:27:22 +0800
+Subject: [PATCH 014/116] mtk: wifi: mt76: mt7996: add support for different
+ variants
Add fem type (2i5i, 2i5e, 2e5e, ...)
Add Kite default bin for each fem type since loading wrong default bin
@@ -14,28 +14,32 @@
Chip manufactoring factories may transfer, which leads to different adie chip versions,
so we add this efuse check to avoid 7976c recognition failure.
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: I98caec6675670e3d1c0ee953bef2aeb71c3cf74e
GPIO ADie Combination of BE5040 should be considered as don't care
instead of 0
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Only check eeprom chip id when fem type (= MT7996_FEM_UNSET) is not determined yet
Without this fix, mt7996_check_eeprom will return EINVAL in mt7996_eeprom_check_fw_mode
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
- mt7996/eeprom.c | 38 +++++++++++++++++++++++++++++--
+ mt7996/eeprom.c | 40 +++++++++++++++++++++++++++++--
mt7996/eeprom.h | 1 +
- mt7996/init.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/init.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++
mt7996/mcu.c | 7 +++++-
- mt7996/mt7996.h | 49 +++++++++++++++++++++++++---------------
+ mt7996/mt7996.h | 43 ++++++++++++++++++++++++++++++---
mt7996/regs.h | 7 ++++++
- 6 files changed, 140 insertions(+), 21 deletions(-)
+ 6 files changed, 155 insertions(+), 6 deletions(-)
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 7505a8b7..3260d1fe 100644
+index 4a8237118..3260d1fef 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -9,14 +9,33 @@
@@ -73,8 +77,12 @@
default:
return -EINVAL;
}
-@@ -30,7 +49,18 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev)
- return MT7996_EEPROM_DEFAULT_404;
+@@ -26,9 +45,22 @@ static char *mt7996_eeprom_name(struct mt7996_dev *dev)
+ {
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7990:
++ if (dev->chip_sku == MT7996_SKU_404)
++ return MT7996_EEPROM_DEFAULT_404;
return MT7996_EEPROM_DEFAULT;
case 0x7992:
- return MT7992_EEPROM_DEFAULT;
@@ -93,7 +101,7 @@
default:
return MT7996_EEPROM_DEFAULT;
}
-@@ -221,6 +251,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
+@@ -219,6 +251,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
{
int ret;
@@ -105,7 +113,7 @@
if (ret < 0) {
if (ret != -EINVAL)
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 412d6e2f..72c38ad3 100644
+index 412d6e2f8..72c38ad3b 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -29,6 +29,7 @@ enum mt7996_eeprom_field {
@@ -117,10 +125,10 @@
#define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
diff --git a/mt7996/init.c b/mt7996/init.c
-index 274863dc..0e3cdc05 100644
+index ab2e17ec4..d58335a37 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -882,6 +882,65 @@ out:
+@@ -885,6 +885,65 @@ out:
#endif
}
@@ -186,8 +194,19 @@
static int mt7996_init_hardware(struct mt7996_dev *dev)
{
int ret, idx;
+@@ -900,6 +959,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
+ INIT_LIST_HEAD(&dev->wed_rro.poll_list);
+ spin_lock_init(&dev->wed_rro.lock);
+
++ ret = mt7996_get_chip_sku(dev);
++ if (ret)
++ return ret;
++
+ ret = mt7996_dma_init(dev);
+ if (ret)
+ return ret;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 0981f592..5aefecb0 100644
+index 10637226c..9e94e03d8 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -14,7 +14,12 @@
@@ -205,10 +224,10 @@
case 0x7990: \
default: \
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index b6df2167..7e5ec212 100644
+index 58fa6b458..b7197dcb7 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -39,9 +39,24 @@
+@@ -39,8 +39,24 @@
#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin"
#define MT7992_ROM_PATCH "mediatek/mt7996/mt7992_rom_patch.bin"
@@ -223,8 +242,8 @@
+#define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin"
+
#define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
- #define MT7996_EEPROM_DEFAULT_404 "mediatek/mt7996/mt7996_eeprom_dual_404.bin"
-#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom.bin"
++#define MT7996_EEPROM_DEFAULT_404 "mediatek/mt7996/mt7996_eeprom_dual_404.bin"
+#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom_2i5i.bin"
+#define MT7992_EEPROM_DEFAULT_EXT "mediatek/mt7996/mt7992_eeprom_2e5e.bin"
+#define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin"
@@ -234,7 +253,7 @@
#define MT7996_EEPROM_SIZE 7680
#define MT7996_EEPROM_BLOCK_SIZE 16
#define MT7996_TOKEN_SIZE 16384
-@@ -89,11 +104,24 @@ struct mt7996_sta;
+@@ -89,6 +105,24 @@ struct mt7996_sta;
struct mt7996_dfs_pulse;
struct mt7996_dfs_pattern;
@@ -245,11 +264,11 @@
+ MT7996_FEM_MIX,
+};
+
- enum mt7996_sku_type {
- MT7996_SKU_404,
- MT7996_SKU_444,
- };
-
++enum mt7996_sku_type {
++ MT7996_SKU_404,
++ MT7996_SKU_444,
++};
++
+enum mt7992_sku_type {
+ MT7992_SKU_23,
+ MT7992_SKU_24,
@@ -259,39 +278,27 @@
enum mt7996_ram_type {
MT7996_RAM_TYPE_WM,
MT7996_RAM_TYPE_WA,
-@@ -264,6 +292,7 @@ struct mt7996_dev {
+@@ -261,6 +295,9 @@ struct mt7996_dev {
+ struct cfg80211_chan_def rdd2_chandef;
struct mt7996_phy *rdd2_phy;
- u8 chip_sku;
++ u8 chip_sku;
+ u8 fem_type;
-
++
u16 chainmask;
u8 chainshift[__MT_MAX_BAND];
-@@ -406,23 +435,6 @@ mt7996_phy3(struct mt7996_dev *dev)
- return __mt7996_phy(dev, MT_BAND2);
- }
+ u32 hif_idx;
+@@ -409,8 +446,7 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
+ return band <= MT_BAND1;
--static inline int
--mt7996_get_chip_sku(struct mt7996_dev *dev)
--{
-- u32 val = mt76_rr(dev, MT_PAD_GPIO);
--
-- /* reserve for future variants */
-- switch (mt76_chip(&dev->mt76)) {
-- case 0x7990:
-- dev->chip_sku = FIELD_GET(MT_PAD_GPIO_ADIE_COMB, val) <= 1;
-- break;
-- default:
-- return -EINVAL;
-- }
--
-- return 0;
--}
--
- static inline bool
- mt7996_band_valid(struct mt7996_dev *dev, u8 band)
- {
-@@ -461,6 +473,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx,
+ /* tri-band support */
+- if (band <= MT_BAND2 &&
+- mt76_get_field(dev, MT_PAD_GPIO, MT_PAD_GPIO_ADIE_COMB) <= 1)
++ if (band <= MT_BAND2 && dev->chip_sku)
+ return true;
+
+ return band == MT_BAND0 || band == MT_BAND2;
+@@ -441,6 +477,7 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx,
int n_desc, int ring_base, struct mtk_wed_device *wed);
void mt7996_init_txpower(struct mt7996_phy *phy);
int mt7996_txbf_init(struct mt7996_dev *dev);
@@ -300,7 +307,7 @@
int mt7996_run(struct ieee80211_hw *hw);
int mt7996_mcu_init(struct mt7996_dev *dev);
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 47b429d8..cf12c5e0 100644
+index 47b429d8b..cf12c5e02 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -662,6 +662,13 @@ enum offs_rev {
@@ -318,5 +325,5 @@
#define MT_HW_REV 0x70010204
#define MT_HW_REV1 0x8a00
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0012-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0015-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch
similarity index 84%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0012-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0015-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch
index 0959871..778e91f 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0012-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0015-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch
@@ -1,7 +1,7 @@
-From 35f210176257373e9b71821ca3246b10f1bb1b2a Mon Sep 17 00:00:00 2001
+From 615fa2bf42b12776d01445f009f766d3c35dabf7 Mon Sep 17 00:00:00 2001
From: "fancy.liu" <fancy.liu@mediatek.com>
Date: Tue, 14 Nov 2023 10:13:24 +0800
-Subject: [PATCH 12/17] mtk: wifi: mt76: mt7996: ACS channel time too long on
+Subject: [PATCH 015/116] mtk: wifi: mt76: mt7996: ACS channel time too long on
duty channel
Step and issue:
@@ -16,6 +16,7 @@
Solution:
When scan start, need to reset chan_stat in each channel switch.
+CR-Id: WCNCR00351054
Signed-off-by: fancy.liu <fancy.liu@mediatek.com>
Issue:
@@ -37,16 +38,17 @@
Mac80211 scan state will be set in scanning, and will be reset after
scan done and before restore to duty channel.
+CR-Id: WCNCR00357653
Signed-off-by: fancy.liu <fancy.liu@mediatek.com>
---
mac80211.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mac80211.c b/mac80211.c
-index b603d40c..6e8ac6f4 100644
+index 64307b967..993e155b9 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -928,6 +928,7 @@ void mt76_set_channel(struct mt76_phy *phy)
+@@ -927,6 +927,7 @@ void mt76_set_channel(struct mt76_phy *phy)
struct cfg80211_chan_def *chandef = &hw->conf.chandef;
bool offchannel = hw->conf.flags & IEEE80211_CONF_OFFCHANNEL;
int timeout = HZ / 5;
@@ -54,7 +56,7 @@
wait_event_timeout(dev->tx_wait, !mt76_has_tx_pending(phy), timeout);
mt76_update_survey(phy);
-@@ -942,7 +943,7 @@ void mt76_set_channel(struct mt76_phy *phy)
+@@ -941,7 +942,7 @@ void mt76_set_channel(struct mt76_phy *phy)
if (!offchannel)
phy->main_chan = chandef->chan;
@@ -64,5 +66,5 @@
}
EXPORT_SYMBOL_GPL(mt76_set_channel);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0013-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0016-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch
similarity index 77%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0013-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0016-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch
index 25d942c..646da41 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0013-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0016-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch
@@ -1,14 +1,16 @@
-From cd699c6764e92f89aef0c75fa0c5a5c69402bcf6 Mon Sep 17 00:00:00 2001
+From 8cb027bb01c80130b08a9a6a5b4a0fe49a42995e Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Thu, 26 Oct 2023 10:08:10 +0800
-Subject: [PATCH 13/17] mtk: wifi: mt76: mt7996: Fixed null pointer dereference
- issue
+Subject: [PATCH 016/116] mtk: wifi: mt76: mt7996: Fixed null pointer
+ dereference issue
Without this patch, when the station is still in Authentication stage and
sends a "Notify bandwidth change action frame" to AP at the same time,
there will be a race condition that causes a crash to occur because the AP
access "msta->vif" that has not been fully initialized.
+CR-ID: WCNCR00240597
+Change-Id: Ie17fbdd8ab11651a9ae0c30faac0b5ad82176e95
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
Signed-off-by: Money Wang <money.wang@mediatek.com>
Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
@@ -17,10 +19,10 @@
1 file changed, 7 insertions(+)
diff --git a/mt7996/main.c b/mt7996/main.c
-index 625f87b4..ad2c6a9d 100644
+index f553704ce..4fc1dd9a9 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -1063,9 +1063,16 @@ static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
+@@ -1079,9 +1079,16 @@ static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_sta *sta,
u32 changed)
{
@@ -38,5 +40,5 @@
ieee80211_queue_work(hw, &dev->rc_work);
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0016-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0016-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch
deleted file mode 100644
index 2ed6aca..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0016-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch
+++ /dev/null
@@ -1,97 +0,0 @@
-From 86aed1e2968dcb516b60cad4361048c2df7a8119 Mon Sep 17 00:00:00 2001
-From: Howard Hsu <howard-yh.hsu@mediatek.com>
-Date: Fri, 22 Sep 2023 10:32:37 +0800
-Subject: [PATCH 16/17] mtk: wifi: mt76: mt7996: add preamble puncture support
- for mt7996
-
-Add support configure preamble puncture feature through mcu commands.
-
-Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
----
- mt76_connac_mcu.h | 1 +
- mt7996/mcu.c | 30 ++++++++++++++++++++++++++++++
- mt7996/mcu.h | 4 ++++
- mt7996/mt7996.h | 2 ++
- 4 files changed, 37 insertions(+)
-
-diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index f1cd2e50..482782f7 100644
---- a/mt76_connac_mcu.h
-+++ b/mt76_connac_mcu.h
-@@ -1270,6 +1270,7 @@ enum {
- MCU_UNI_CMD_CHANNEL_SWITCH = 0x34,
- MCU_UNI_CMD_THERMAL = 0x35,
- MCU_UNI_CMD_VOW = 0x37,
-+ MCU_UNI_CMD_PP = 0x38,
- MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
- MCU_UNI_CMD_RRO = 0x57,
- MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 88fb196d..b9939e0c 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -4540,3 +4540,33 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- return mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_WM_UNI_CMD(TXPOWER), true);
- }
-+
-+int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, bool auto_mode,
-+ u8 force_bitmap_ctrl, u16 bitmap)
-+{
-+ struct mt7996_dev *dev = phy->dev;
-+ struct {
-+ u8 _rsv[4];
-+
-+ __le16 tag;
-+ __le16 len;
-+ bool mgmt_mode;
-+ u8 band_idx;
-+ u8 force_bitmap_ctrl;
-+ bool auto_mode;
-+ __le16 bitmap;
-+ u8 _rsv2[2];
-+ } __packed req = {
-+ .tag = cpu_to_le16(UNI_CMD_PP_EN_CTRL),
-+ .len = cpu_to_le16(sizeof(req) - 4),
-+
-+ .mgmt_mode = !auto_mode,
-+ .band_idx = phy->mt76->band_idx,
-+ .force_bitmap_ctrl = force_bitmap_ctrl,
-+ .auto_mode = auto_mode,
-+ .bitmap = cpu_to_le16(bitmap),
-+ };
-+
-+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PP),
-+ &req, sizeof(req), false);
-+}
-diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index a9ba63d1..238c4c53 100644
---- a/mt7996/mcu.h
-+++ b/mt7996/mcu.h
-@@ -923,6 +923,10 @@ enum {
- MT7996_SEC_MODE_MAX,
- };
-
-+enum {
-+ UNI_CMD_PP_EN_CTRL,
-+};
-+
- #define MT7996_PATCH_SEC GENMASK(31, 24)
- #define MT7996_PATCH_SCRAMBLE_KEY GENMASK(15, 8)
- #define MT7996_PATCH_AES_KEY GENMASK(7, 0)
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index e1610d3b..4176e51a 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -654,6 +654,8 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif
- int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta);
-+int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, bool auto_mode, u8 force_bitmap,
-+ u16 bitmap);
- #ifdef CONFIG_MAC80211_DEBUGFS
- void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_sta *sta, struct dentry *dir);
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0014-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0017-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch
similarity index 77%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0014-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0017-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch
index 8839a71..27ef133 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0014-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0017-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch
@@ -1,19 +1,21 @@
-From 5cb8c91ff8f579d192f93e258314199fc33355c8 Mon Sep 17 00:00:00 2001
+From 49a1a916113cf23ad38ef6e3f3cfd0279f7abea4 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Mon, 30 Oct 2023 11:06:19 +0800
-Subject: [PATCH 14/17] mtk: wifi: mt76: add sanity check to prevent kernel
+Subject: [PATCH 017/116] mtk: wifi: mt76: add sanity check to prevent kernel
crash
wcid may not be initialized when mac80211 calls mt76.tx and it would lead to
kernel crash.
+CR-Id: WCNCR00240772
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Change-Id: I90004271c6e91620c6991195dd332780ce28380e
---
tx.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/tx.c b/tx.c
-index 5cf6edee..ab42f69b 100644
+index 5cf6edee4..ab42f69b8 100644
--- a/tx.c
+++ b/tx.c
@@ -345,6 +345,14 @@ mt76_tx(struct mt76_phy *phy, struct ieee80211_sta *sta,
@@ -32,5 +34,5 @@
__skb_queue_tail(&wcid->tx_pending, skb);
spin_unlock_bh(&wcid->tx_pending.lock);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0017-mtk-wifi-mt76-mt7996-add-sanity-check-for-NAPI-sched.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0017-mtk-wifi-mt76-mt7996-add-sanity-check-for-NAPI-sched.patch
deleted file mode 100644
index dbfb384..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0017-mtk-wifi-mt76-mt7996-add-sanity-check-for-NAPI-sched.patch
+++ /dev/null
@@ -1,38 +0,0 @@
-From 19ea1497e7aea34be6e8851a1aca75e3eb58b58f Mon Sep 17 00:00:00 2001
-From: "Henry.Yen" <henry.yen@mediatek.com>
-Date: Tue, 16 Jan 2024 11:30:02 +0800
-Subject: [PATCH 17/17] mtk: wifi: mt76: mt7996: add sanity check for NAPI
- schedule
-
-Add sanity check for NAPI schedule.
-
-It's observed that host driver might occasionally receive
-interrupts from unexpected Rx ring, whose Rx NAPI hasn't been
-prepared yet. Under such situation, __napi_poll crash issue
-would occur, so we add sanity check to prevent it.
-
-If without this patch, we might encounter kernel crash issue
-especially in WED-on & RRO-on software path.
-
-Signed-off-by: Henry.Yen <henry.yen@mediatek.com>
-
----
- mt7996/mmio.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 8fe56ed9..367a204d 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -560,7 +560,7 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
- napi_schedule(&dev->mt76.tx_napi);
-
- for (i = 0; i < __MT_RXQ_MAX; i++) {
-- if ((intr & MT_INT_RX(i)))
-+ if ((intr & MT_INT_RX(i)) && dev->mt76.napi[i].poll)
- napi_schedule(&dev->mt76.napi[i]);
- }
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0015-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0018-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
similarity index 96%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0015-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0018-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
index 66ee8cf..ac443b0 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0015-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0018-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch
@@ -1,9 +1,10 @@
-From 5a195822d50b588206b18344df61b36bc7e26e6e Mon Sep 17 00:00:00 2001
+From 88fd1708523b4d5a2f8c821f6aa768b2f2a6a033 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Fri, 19 May 2023 14:16:50 +0800
-Subject: [PATCH 15/17] mtk: wifi: mt76: mt7996: add firmware WA's coredump.
+Subject: [PATCH 018/116] mtk: wifi: mt76: mt7996: add firmware WA's coredump.
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Change-Id: I51f115b4ae15bc0f871f93652570d72511dbf880
---
mt7996/coredump.c | 180 ++++++++++++++++++++++++++++++----------------
mt7996/coredump.h | 35 ++++++---
@@ -14,7 +15,7 @@
6 files changed, 182 insertions(+), 83 deletions(-)
diff --git a/mt7996/coredump.c b/mt7996/coredump.c
-index ccab0d7b..60b88085 100644
+index ccab0d7b9..60b88085c 100644
--- a/mt7996/coredump.c
+++ b/mt7996/coredump.c
@@ -7,11 +7,11 @@
@@ -335,7 +336,7 @@
}
diff --git a/mt7996/coredump.h b/mt7996/coredump.h
-index af2ba219..01ed3731 100644
+index af2ba219b..01ed3731c 100644
--- a/mt7996/coredump.h
+++ b/mt7996/coredump.h
@@ -6,10 +6,13 @@
@@ -428,7 +429,7 @@
return NULL;
}
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 3afdd7eb..d88bbfb2 100644
+index 3afdd7eb9..d88bbfb24 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1998,28 +1998,25 @@ void mt7996_mac_reset_work(struct work_struct *work)
@@ -506,10 +507,10 @@
}
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 5aefecb0..88fb196d 100644
+index 9e94e03d8..0656b4a51 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -2702,6 +2702,8 @@ static int mt7996_load_patch(struct mt7996_dev *dev)
+@@ -2704,6 +2704,8 @@ static int mt7996_load_patch(struct mt7996_dev *dev)
dev_info(dev->mt76.dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
@@ -518,7 +519,7 @@
for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
struct mt7996_patch_sec *sec;
-@@ -2828,6 +2830,9 @@ static int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type,
+@@ -2830,6 +2832,9 @@ static int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type,
}
hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
@@ -529,10 +530,10 @@
fw_type, hdr->fw_ver, hdr->build_date);
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 7e5ec212..e1610d3b 100644
+index b7197dcb7..e12ad318d 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -83,6 +83,8 @@
+@@ -84,6 +84,8 @@
#define MT7996_CRIT_TEMP 110
#define MT7996_MAX_TEMP 120
@@ -541,7 +542,7 @@
#define MT7996_RRO_MAX_SESSION 1024
#define MT7996_RRO_WINDOW_MAX_LEN 1024
#define MT7996_RRO_ADDR_ELEM_LEN 128
-@@ -126,6 +128,7 @@ enum mt7996_ram_type {
+@@ -127,6 +129,7 @@ enum mt7996_ram_type {
MT7996_RAM_TYPE_WM,
MT7996_RAM_TYPE_WA,
MT7996_RAM_TYPE_DSP,
@@ -549,7 +550,7 @@
};
enum mt7996_txq_id {
-@@ -316,9 +319,11 @@ struct mt7996_dev {
+@@ -320,9 +323,11 @@ struct mt7996_dev {
struct mutex dump_mutex;
#ifdef CONFIG_DEV_COREDUMP
struct {
@@ -563,7 +564,7 @@
struct list_head sta_rc_list;
struct list_head twt_list;
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index cf12c5e0..4c20a67d 100644
+index cf12c5e02..4c20a67d7 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -597,7 +597,8 @@ enum offs_rev {
@@ -593,5 +594,5 @@
/* CONN AFE CTL CON */
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0999-mtk-wifi-mt76-mt7996-for-build-pass.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0019-mtk-wifi-mt76-mt7996-for-build-pass.patch
similarity index 75%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0999-mtk-wifi-mt76-mt7996-for-build-pass.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0019-mtk-wifi-mt76-mt7996-for-build-pass.patch
index 9c72243..dd21584 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0999-mtk-wifi-mt76-mt7996-for-build-pass.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0019-mtk-wifi-mt76-mt7996-for-build-pass.patch
@@ -1,12 +1,12 @@
-From 1df5a85005f59c81ddc50c6378562e4c9bc31056 Mon Sep 17 00:00:00 2001
+From db4bbc138ecda8790cc3e6b0d513278ff900a4cc Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Thu, 3 Nov 2022 00:27:17 +0800
-Subject: [PATCH 0999/1044] mtk: wifi: mt76: mt7996: for build pass
+Subject: [PATCH 019/116] mtk: wifi: mt76: mt7996: for build pass
+Change-Id: Ieb44c33ee6e6a2e6058c1ef528404c1a1cbcfdaf
---
debugfs.c | 3 +++
dma.c | 2 +-
- eeprom.c | 8 +++++++-
mcu.c | 1 +
mt7615/mcu.c | 1 +
mt76_connac_mcu.c | 1 +
@@ -14,10 +14,10 @@
mt7996/dma.c | 4 ++--
mt7996/eeprom.c | 1 +
mt7996/mcu.c | 1 +
- 10 files changed, 19 insertions(+), 4 deletions(-)
+ 9 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/debugfs.c b/debugfs.c
-index c4649ba0..ac5207e5 100644
+index c4649ba04..ac5207e5e 100644
--- a/debugfs.c
+++ b/debugfs.c
@@ -33,8 +33,11 @@ mt76_napi_threaded_set(void *data, u64 val)
@@ -33,7 +33,7 @@
return 0;
}
diff --git a/dma.c b/dma.c
-index f4f88c44..56044639 100644
+index f4f88c444..560446395 100644
--- a/dma.c
+++ b/dma.c
@@ -883,7 +883,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
@@ -45,29 +45,8 @@
if (!skb)
goto free_frag;
-diff --git a/eeprom.c b/eeprom.c
-index 0bc66cc1..7d5cf28f 100644
---- a/eeprom.c
-+++ b/eeprom.c
-@@ -163,9 +163,15 @@ void
- mt76_eeprom_override(struct mt76_phy *phy)
- {
- struct mt76_dev *dev = phy->dev;
-+#ifdef CONFIG_OF
- struct device_node *np = dev->dev->of_node;
-+ const u8 *mac = NULL;
-
-- of_get_mac_address(np, phy->macaddr);
-+ if (np)
-+ mac = of_get_mac_address(np);
-+ if (!IS_ERR_OR_NULL(mac))
-+ ether_addr_copy(phy->macaddr, mac);
-+#endif
-
- if (!is_valid_ether_addr(phy->macaddr)) {
- eth_random_addr(phy->macaddr);
diff --git a/mcu.c b/mcu.c
-index a8cafa39..fa4b0544 100644
+index a8cafa39a..fa4b05441 100644
--- a/mcu.c
+++ b/mcu.c
@@ -4,6 +4,7 @@
@@ -79,7 +58,7 @@
struct sk_buff *
__mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
diff --git a/mt7615/mcu.c b/mt7615/mcu.c
-index ae34d019..c9444c6d 100644
+index c807bd8d9..a9310660b 100644
--- a/mt7615/mcu.c
+++ b/mt7615/mcu.c
@@ -10,6 +10,7 @@
@@ -91,7 +70,7 @@
static bool prefer_offload_fw = true;
module_param(prefer_offload_fw, bool, 0644);
diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index fec158ec..42f12672 100644
+index b35acf86e..1e34e0ae3 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -4,6 +4,7 @@
@@ -103,7 +82,7 @@
int mt76_connac_mcu_start_firmware(struct mt76_dev *dev, u32 addr, u32 option)
{
diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index fe54a2f4..35d57989 100644
+index 24daa0835..2d017396c 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -6,6 +6,7 @@
@@ -115,7 +94,7 @@
#define fw_name(_dev, name, ...) ({ \
char *_fw; \
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index 73e633d0..759a58e8 100644
+index 73e633d0d..759a58e8e 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -641,8 +641,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
@@ -130,7 +109,7 @@
mt7996_dma_enable(dev, false);
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 3260d1fe..121a3c95 100644
+index 3260d1fef..121a3c958 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -138,6 +138,7 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
@@ -142,7 +121,7 @@
dev->has_eht = !(cap & MODE_HE_ONLY);
dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP);
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index b9939e0c..e92a3e53 100644
+index 0656b4a51..57cfa1494 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -5,6 +5,7 @@
@@ -154,5 +133,5 @@
#include "mcu.h"
#include "mac.h"
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1000-mtk-wifi-mt76-mt7996-add-debug-tool.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0020-mtk-wifi-mt76-mt7996-add-debug-tool.patch
similarity index 97%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1000-mtk-wifi-mt76-mt7996-add-debug-tool.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0020-mtk-wifi-mt76-mt7996-add-debug-tool.patch
index bfbb09d..828eee7 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1000-mtk-wifi-mt76-mt7996-add-debug-tool.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0020-mtk-wifi-mt76-mt7996-add-debug-tool.patch
@@ -1,17 +1,21 @@
-From 57b3bc3bdbb3fb05897ff92ff59e970598fbf223 Mon Sep 17 00:00:00 2001
+From 6b19a7a6cfa1095afbf622419d085c54e11d05b3 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Fri, 24 Mar 2023 14:02:32 +0800
-Subject: [PATCH 1000/1044] mtk: wifi: mt76: mt7996: add debug tool
+Subject: [PATCH 020/116] mtk: wifi: mt76: mt7996: add debug tool
+Change-Id: Ie10390b01f17db893dbfbf3221bf63a4bd1fe38f
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Add PSM bit in sta_info
+CR-Id: WCNCR00240772
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Change-Id: I591b558a9eec2fbd46d166c9bb1580a94e22072c
Remove the duplicate function in mtk_debugfs.c & mtk_debug_i.c
Only enable mt7996_mcu_fw_log_2_host function in mcu.c
+CR-ID: WCNCR00240597
Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
Support more ids category NDPA/NDP TXD/FBK and debug log recommended by
@@ -23,6 +27,8 @@
2. iwpriv ra0 set fw_dbg=2:84
3. iwpriv ra0 set fw_dbg=1:101
+CR-Id: WCNCR00261410
+Change-Id: Ifddd4db86982d39f2d39d198b8f5d3e7028983c2
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
mtk: wifi: mt76: mt7996: add wtbl_info support for mt7992
@@ -37,31 +43,58 @@
Refactor code for FW log.
+CR-Id: WCNCR00298425
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Change-Id: I00c760b31009142848e32b1249d305800585e7fd
+
+mtk: wifi: mt76: mt7996: support disable muru debug info when recording fwlog
+
+When we record fwlog, we will also enable recording muru debug info log by
+default. However, in certain test scenarios, this can result in
+recording too many logs, causing inconvenience during issue analysis.
+Therefore, this commit adds an debug option, fw_debug_muru_disable, in
+debugfs. User can modify this option to enable/disable recording muru
+debug info log.
+
+[Usage]
+Set:
+$ echo val > debugfs/fw_debug_muru_disable
+Get:
+$ cat debugfs/fw_debug_muru_disable
+
+val can be the following values:
+0 = enable recording muru debug info (Default value)
+1 = disable recording muru debug info
+
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+
+mtk: wifi: mt76: mt7996: add adie id & ver dump
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt76.h | 2 +
mt7996/Makefile | 4 +
mt7996/coredump.c | 10 +-
mt7996/coredump.h | 7 +
- mt7996/debugfs.c | 64 +-
+ mt7996/debugfs.c | 128 ++-
mt7996/mac.c | 3 +
- mt7996/mt7996.h | 11 +
+ mt7996/mt7996.h | 13 +
mt7996/mtk_debug.h | 2286 ++++++++++++++++++++++++++++++++++++++
- mt7996/mtk_debugfs.c | 2484 ++++++++++++++++++++++++++++++++++++++++++
- mt7996/mtk_mcu.c | 18 +
- mt7996/mtk_mcu.h | 16 +
+ mt7996/mtk_debugfs.c | 2507 ++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mtk_mcu.c | 39 +
+ mt7996/mtk_mcu.h | 19 +
tools/fwlog.c | 25 +-
- 12 files changed, 4905 insertions(+), 25 deletions(-)
+ 12 files changed, 5018 insertions(+), 25 deletions(-)
create mode 100644 mt7996/mtk_debug.h
create mode 100644 mt7996/mtk_debugfs.c
create mode 100644 mt7996/mtk_mcu.c
create mode 100644 mt7996/mtk_mcu.h
diff --git a/mt76.h b/mt76.h
-index 294e379a..8cf21f98 100644
+index 2cbea731e..599787db2 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -394,6 +394,8 @@ struct mt76_txwi_cache {
+@@ -399,6 +399,8 @@ struct mt76_txwi_cache {
struct sk_buff *skb;
void *ptr;
};
@@ -71,7 +104,7 @@
struct mt76_rx_tid {
diff --git a/mt7996/Makefile b/mt7996/Makefile
-index 07c8b555..a056b40e 100644
+index 07c8b555c..a056b40e0 100644
--- a/mt7996/Makefile
+++ b/mt7996/Makefile
@@ -1,4 +1,6 @@
@@ -88,7 +121,7 @@
+
+mt7996e-y += mtk_debugfs.o mtk_mcu.o
diff --git a/mt7996/coredump.c b/mt7996/coredump.c
-index 60b88085..a7f91b56 100644
+index 60b88085c..a7f91b56d 100644
--- a/mt7996/coredump.c
+++ b/mt7996/coredump.c
@@ -195,7 +195,7 @@ mt7996_coredump_fw_stack(struct mt7996_dev *dev, u8 type, struct mt7996_coredump
@@ -137,7 +170,7 @@
dev_warn(dev->mt76.dev, "no crash dump data found\n");
return -ENODATA;
diff --git a/mt7996/coredump.h b/mt7996/coredump.h
-index 01ed3731..93cd84a0 100644
+index 01ed3731c..93cd84a03 100644
--- a/mt7996/coredump.h
+++ b/mt7996/coredump.h
@@ -75,6 +75,7 @@ struct mt7996_mem_region {
@@ -162,10 +195,10 @@
mt7996_crash_data *mt7996_coredump_new(struct mt7996_dev *dev, u8 type)
{
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 9bd95358..1637b39d 100644
+index 62c03d088..344c759c0 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -290,11 +290,39 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
+@@ -295,11 +295,39 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
DEBUG_SPL,
DEBUG_RPT_RX,
DEBUG_RPT_RA = 68,
@@ -206,7 +239,7 @@
if (dev->fw_debug_bin)
val = MCU_FW_LOG_RELAY;
-@@ -309,18 +337,21 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
+@@ -314,18 +342,21 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
if (ret)
return ret;
@@ -234,9 +267,51 @@
}
return 0;
-@@ -401,11 +432,12 @@ mt7996_fw_debug_bin_set(void *data, u64 val)
+@@ -397,6 +428,39 @@ remove_buf_file_cb(struct dentry *f)
+ return 0;
+ }
+
++static int
++mt7996_fw_debug_muru_set(void *data)
++{
++ struct mt7996_dev *dev = data;
++ enum {
++ DEBUG_BSRP_STATUS = 256,
++ DEBUG_TX_DATA_BYTE_CONUT,
++ DEBUG_RX_DATA_BYTE_CONUT,
++ DEBUG_RX_TOTAL_BYTE_CONUT,
++ DEBUG_INVALID_TID_BSR,
++ DEBUG_UL_LONG_TERM_PPDU_TYPE,
++ DEBUG_DL_LONG_TERM_PPDU_TYPE,
++ DEBUG_PPDU_CLASS_TRIG_ONOFF,
++ DEBUG_AIRTIME_BUSY_STATUS,
++ DEBUG_UL_OFDMA_MIMO_STATUS,
++ DEBUG_RU_CANDIDATE,
++ DEBUG_MEC_UPDATE_AMSDU,
++ } debug;
++ int ret;
++
++ if (dev->fw_debug_muru_disable)
++ return 0;
++
++ for (debug = DEBUG_BSRP_STATUS; debug <= DEBUG_MEC_UPDATE_AMSDU; debug++) {
++ ret = mt7996_mcu_muru_dbg_info(dev, debug,
++ dev->fw_debug_bin & BIT(0));
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
+ static int
+ mt7996_fw_debug_bin_set(void *data, u64 val)
+ {
+@@ -405,17 +469,23 @@ mt7996_fw_debug_bin_set(void *data, u64 val)
+ .remove_buf_file = remove_buf_file_cb,
};
struct mt7996_dev *dev = data;
++ int ret;
- if (!dev->relay_fwlog)
+ if (!dev->relay_fwlog) {
@@ -250,7 +325,53 @@
dev->fw_debug_bin = val;
+ relay_reset(dev->relay_fwlog);
+
-@@ -819,6 +851,11 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
++ ret = mt7996_fw_debug_muru_set(dev);
++ if (ret)
++ return ret;
++
+ return mt7996_fw_debug_wm_set(dev, dev->fw_debug_wm);
+ }
+
+@@ -785,6 +855,30 @@ mt7996_rf_regval_set(void *data, u64 val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7996_rf_regval_get,
+ mt7996_rf_regval_set, "0x%08llx\n");
+
++static int
++mt7996_fw_debug_muru_disable_set(void *data, u64 val)
++{
++ struct mt7996_dev *dev = data;
++
++ dev->fw_debug_muru_disable = !!val;
++
++ return 0;
++}
++
++static int
++mt7996_fw_debug_muru_disable_get(void *data, u64 *val)
++{
++ struct mt7996_dev *dev = data;
++
++ *val = dev->fw_debug_muru_disable;
++
++ return 0;
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_muru_disable,
++ mt7996_fw_debug_muru_disable_get,
++ mt7996_fw_debug_muru_disable_set, "%lld\n");
++
+ int mt7996_init_debugfs(struct mt7996_phy *phy)
+ {
+ struct mt7996_dev *dev = phy->dev;
+@@ -820,10 +914,17 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+ debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
+ mt7996_rdd_monitor);
+ }
++ debugfs_create_file("fw_debug_muru_disable", 0600, dir, dev,
++ &fops_fw_debug_muru_disable);
+
if (phy == &dev->phy)
dev->debugfs_dir = dir;
@@ -262,7 +383,7 @@
return 0;
}
-@@ -830,7 +867,11 @@ mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen,
+@@ -835,7 +936,11 @@ mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen,
unsigned long flags;
void *dest;
@@ -274,7 +395,7 @@
dest = relay_reserve(dev->relay_fwlog, hdrlen + len + 4);
if (dest) {
*(u32 *)dest = hdrlen + len;
-@@ -863,9 +904,6 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int
+@@ -868,9 +973,6 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int
.msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),
};
@@ -285,7 +406,7 @@
hdr.timestamp = cpu_to_le32(mt76_rr(dev, MT_LPON_FRCR(0)));
hdr.len = *(__le16 *)data;
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index d88bbfb2..1f53d230 100644
+index d88bbfb24..1f53d2303 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -936,6 +936,9 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
@@ -299,10 +420,18 @@
pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
memset(txwi_ptr, 0, MT_TXD_SIZE);
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 4176e51a..34159f97 100644
+index e12ad318d..696e16fa1 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -370,6 +370,17 @@ struct mt7996_dev {
+@@ -362,6 +362,7 @@ struct mt7996_dev {
+ u8 fw_debug_wa;
+ u8 fw_debug_bin;
+ u16 fw_debug_seq;
++ bool fw_debug_muru_disable;
+
+ struct dentry *debugfs_dir;
+ struct rchan *relay_fwlog;
+@@ -374,6 +375,17 @@ struct mt7996_dev {
spinlock_t reg_lock;
u8 wtbl_size_group;
@@ -320,9 +449,17 @@
};
enum {
+@@ -670,6 +682,7 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
+
+ #ifdef CONFIG_MTK_DEBUG
+ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
++int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
+ #endif
+
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_debug.h b/mt7996/mtk_debug.h
new file mode 100644
-index 00000000..27d8f1cb
+index 000000000..27d8f1cb2
--- /dev/null
+++ b/mt7996/mtk_debug.h
@@ -0,0 +1,2286 @@
@@ -2614,10 +2751,10 @@
+#endif
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
new file mode 100644
-index 00000000..678b009e
+index 000000000..8baf27c76
--- /dev/null
+++ b/mt7996/mtk_debugfs.c
-@@ -0,0 +1,2484 @@
+@@ -0,0 +1,2507 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2023 MediaTek Inc.
@@ -2954,8 +3091,19 @@
+
+static int mt7996_dump_version(struct seq_file *s, void *data)
+{
++#define MAX_ADIE_NUM 3
+ struct mt7996_dev *dev = dev_get_drvdata(s->private);
-+ seq_printf(s, "Version: 3.3.24.2\n");
++ u32 regval;
++ u16 adie_chip_id, adie_chip_ver;
++ int adie_idx;
++ static const char * const fem_type[] = {
++ [MT7996_FEM_UNSET] = "N/A",
++ [MT7996_FEM_EXT] = "eFEM",
++ [MT7996_FEM_INT] = "iFEM",
++ [MT7996_FEM_MIX] = "mixed FEM",
++ };
++
++ seq_printf(s, "Version: 4.3.24.3\n");
+
+ if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
+ return 0;
@@ -2968,6 +3116,18 @@
+ dev->ram_build_date[MT7996_RAM_TYPE_WA]);
+ seq_printf(s, "DSP Patch Build Time: %.15s\n",
+ dev->ram_build_date[MT7996_RAM_TYPE_DSP]);
++ for (adie_idx = 0; adie_idx < MAX_ADIE_NUM; adie_idx++) {
++ mt7996_mcu_rf_regval(dev, MT_ADIE_CHIP_ID(adie_idx), ®val, false);
++ adie_chip_id = FIELD_GET(MT_ADIE_CHIP_ID_MASK, regval);
++ adie_chip_ver = FIELD_GET(MT_ADIE_VERSION_MASK, regval);
++ if (adie_chip_id)
++ seq_printf(s, "Adie %d: ID = 0x%04x, Ver = 0x%04x\n",
++ adie_idx, adie_chip_id, adie_chip_ver);
++ else
++ seq_printf(s, "Adie %d: ID = N/A, Ver = N/A\n", adie_idx);
++ }
++ seq_printf(s, "FEM type: %s\n", fem_type[dev->fem_type]);
++
+ return 0;
+}
+
@@ -5104,10 +5264,10 @@
+#endif
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
new file mode 100644
-index 00000000..e8870166
+index 000000000..c16b25ab5
--- /dev/null
+++ b/mt7996/mtk_mcu.c
-@@ -0,0 +1,18 @@
+@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: ISC
+/*
+ * Copyright (C) 2023 MediaTek Inc.
@@ -5125,13 +5285,34 @@
+
+
+
++int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val)
++{
++ struct {
++ u8 __rsv1[4];
++
++ __le16 tag;
++ __le16 len;
++
++ __le16 item;
++ u8 __rsv2[2];
++ __le32 value;
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_CMD_MURU_DBG_INFO),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .item = cpu_to_le16(item),
++ .value = cpu_to_le32(val),
++ };
++
++ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &req,
++ sizeof(req), true);
++}
+#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
new file mode 100644
-index 00000000..e741aa27
+index 000000000..7f4d4e029
--- /dev/null
+++ b/mt7996/mtk_mcu.h
-@@ -0,0 +1,16 @@
+@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: ISC */
+/*
+ * Copyright (C) 2023 MediaTek Inc.
@@ -5144,12 +5325,15 @@
+
+#ifdef CONFIG_MTK_DEBUG
+
++enum {
++ UNI_CMD_MURU_DBG_INFO = 0x18,
++};
+
+#endif
+
+#endif
diff --git a/tools/fwlog.c b/tools/fwlog.c
-index e5d4a105..3c6a61d7 100644
+index e5d4a1051..3c6a61d71 100644
--- a/tools/fwlog.c
+++ b/tools/fwlog.c
@@ -26,7 +26,7 @@ static const char *debugfs_path(const char *phyname, const char *file)
@@ -5233,5 +5417,5 @@
return ret;
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1002-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0021-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch
similarity index 76%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1002-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0021-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch
index b05982a..ccf5c1c 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1002-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0021-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch
@@ -1,24 +1,27 @@
-From 90b67bfa2b8f0bfbfd32fd93fb898d20b1e6b984 Mon Sep 17 00:00:00 2001
+From 8acf6c19fc99fc2183e62fd04b1c7b7c6ae82d3a Mon Sep 17 00:00:00 2001
From: "Allen.Ye" <allen.ye@mediatek.com>
Date: Thu, 8 Jun 2023 17:32:33 +0800
-Subject: [PATCH 1002/1044] mtk: wifi: mt76: mt7996: add check for hostapd
- config he_ldpc
+Subject: [PATCH 021/116] mtk: wifi: mt76: mt7996: add check for hostapd config
+ he_ldpc
Add check for hostapd config he_ldpc.
This capabilities is checked in mcu_beacon_check_caps in 7915.
Add check for STA LDPC cap, if STA only have BCC we should not overwrite the phy_cap with config he_ldpc.
+CR-Id: WCNCR00259302
+Change-Id: I6d6f59df8897e3c00f2e0a1e3c6e5701e31c5e4b
+Change-Id: Ibe7e40ec1dbb40bd3f3d96741e9933ec00b50df0
Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
---
mt7996/mcu.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index e92a3e53..b488a78f 100644
+index 57cfa1494..bad370839 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1185,7 +1185,8 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
+@@ -1188,7 +1188,8 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
}
static void
@@ -28,7 +31,7 @@
{
struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
struct ieee80211_he_mcs_nss_supp mcs_map;
-@@ -1205,6 +1206,11 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+@@ -1208,6 +1209,11 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
he->he_phy_cap[i] = elem->phy_cap_info[i];
}
@@ -40,7 +43,7 @@
mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
switch (sta->deflink.bandwidth) {
case IEEE80211_STA_RX_BW_160:
-@@ -2111,7 +2117,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+@@ -2113,7 +2119,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
* update sta_rec_he here.
*/
if (changed)
@@ -49,7 +52,7 @@
/* sta_rec_ra accommodates BW, NSS and only MCS range format
* i.e 0-{7,8,9} for VHT.
-@@ -2199,7 +2205,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+@@ -2201,7 +2207,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
/* starec amsdu */
mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
/* starec he */
@@ -59,5 +62,5 @@
mt7996_mcu_sta_he_6g_tlv(skb, sta);
/* starec eht */
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1004-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0022-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch
similarity index 94%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1004-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0022-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch
index 73e9626..167a546 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1004-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0022-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch
@@ -1,13 +1,14 @@
-From 4c3bdf16f108c081731b1a73a3bd7730657e81d3 Mon Sep 17 00:00:00 2001
+From 02ec22e1dac31435e5d5defea0b50778061da97e Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Wed, 1 Mar 2023 11:59:16 +0800
-Subject: [PATCH 1004/1044] mtk: wifi: mt76: testmode: add basic testmode
- support
+Date: Wed, 28 Dec 2022 22:24:25 +0800
+Subject: [PATCH 022/116] mtk: wifi: mt76: testmode: add basic testmode support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: I0e09e7f5bc0fb9aa4e4ec906a0f5f169bcc261cb
Add testmode eeprom buffer mode support
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Fix power & freq offset issue for iTest power cal & tx/rx verifcation
@@ -17,10 +18,13 @@
and 2G band. Therefore, we should avoid reseting freq offset to 0 when
6G interface is off.
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: I849b11b4ccdecd2b7b525b29801c02b5207bbf91
edcca return err in testmode; therefore, bypass it when we are in testmode idle state or testmode bf is on
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
eeprom.c | 6 +-
@@ -28,25 +32,25 @@
mt76.h | 36 +++
mt76_connac_mcu.h | 2 +
mt7996/Makefile | 1 +
- mt7996/eeprom.c | 35 ++-
+ mt7996/eeprom.c | 37 ++-
mt7996/eeprom.h | 1 +
mt7996/init.c | 8 +
mt7996/mac.c | 3 +-
- mt7996/main.c | 26 ++
+ mt7996/main.c | 27 ++
mt7996/mcu.c | 59 +++-
mt7996/mcu.h | 33 +++
mt7996/mt7996.h | 28 +-
mt7996/testmode.c | 740 ++++++++++++++++++++++++++++++++++++++++++++++
mt7996/testmode.h | 299 +++++++++++++++++++
- testmode.c | 123 ++++++--
- testmode.h | 85 +++++-
+ testmode.c | 126 ++++++--
+ testmode.h | 87 +++++-
tools/fields.c | 102 ++++++-
- 18 files changed, 1542 insertions(+), 48 deletions(-)
+ 18 files changed, 1548 insertions(+), 50 deletions(-)
create mode 100644 mt7996/testmode.c
create mode 100644 mt7996/testmode.h
diff --git a/eeprom.c b/eeprom.c
-index 7d5cf28f..85bd2a29 100644
+index 0bc66cc19..a0047d791 100644
--- a/eeprom.c
+++ b/eeprom.c
@@ -94,8 +94,10 @@ int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int l
@@ -63,10 +67,10 @@
out_put_node:
diff --git a/mac80211.c b/mac80211.c
-index 6e8ac6f4..fea19e19 100644
+index 993e155b9..b285407a8 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -846,7 +846,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
+@@ -845,7 +845,8 @@ void mt76_rx(struct mt76_dev *dev, enum mt76_rxq_id q, struct sk_buff *skb)
}
#ifdef CONFIG_NL80211_TESTMODE
@@ -77,10 +81,10 @@
if (status->flag & RX_FLAG_FAILED_FCS_CRC)
phy->test.rx_stats.fcs_error[q]++;
diff --git a/mt76.h b/mt76.h
-index 8cf21f98..f2b1e0c2 100644
+index 599787db2..58e8e726c 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -695,14 +695,21 @@ struct mt76_testmode_ops {
+@@ -700,14 +700,21 @@ struct mt76_testmode_ops {
int (*set_params)(struct mt76_phy *phy, struct nlattr **tb,
enum mt76_testmode_state new_state);
int (*dump_stats)(struct mt76_phy *phy, struct sk_buff *msg);
@@ -102,7 +106,7 @@
u32 tx_count;
u16 tx_mpdu_len;
-@@ -712,6 +719,7 @@ struct mt76_testmode_data {
+@@ -717,6 +724,7 @@ struct mt76_testmode_data {
u8 tx_rate_sgi;
u8 tx_rate_ldpc;
u8 tx_rate_stbc;
@@ -110,7 +114,7 @@
u8 tx_ltf;
u8 tx_antenna_mask;
-@@ -721,6 +729,9 @@ struct mt76_testmode_data {
+@@ -726,6 +734,9 @@ struct mt76_testmode_data {
u32 tx_time;
u32 tx_ipg;
@@ -120,7 +124,7 @@
u32 freq_offset;
u8 tx_power[4];
-@@ -735,7 +746,16 @@ struct mt76_testmode_data {
+@@ -740,7 +751,16 @@ struct mt76_testmode_data {
struct {
u64 packets[__MT_RXQ_MAX];
u64 fcs_error[__MT_RXQ_MAX];
@@ -137,7 +141,7 @@
};
struct mt76_vif {
-@@ -1439,6 +1459,22 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
+@@ -1444,6 +1464,22 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *skb,
int mt76_testmode_set_state(struct mt76_phy *phy, enum mt76_testmode_state state);
int mt76_testmode_alloc_skb(struct mt76_phy *phy, u32 len);
@@ -161,10 +165,10 @@
{
#ifdef CONFIG_NL80211_TESTMODE
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 482782f7..2e148011 100644
+index 70def0a3b..718552baf 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1266,12 +1266,14 @@ enum {
+@@ -1267,12 +1267,14 @@ enum {
MCU_UNI_CMD_EFUSE_CTRL = 0x2d,
MCU_UNI_CMD_RA = 0x2f,
MCU_UNI_CMD_MURU = 0x31,
@@ -180,7 +184,7 @@
MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
MCU_UNI_CMD_PER_STA_INFO = 0x6d,
diff --git a/mt7996/Makefile b/mt7996/Makefile
-index a056b40e..7bb17f44 100644
+index a056b40e0..7bb17f440 100644
--- a/mt7996/Makefile
+++ b/mt7996/Makefile
@@ -8,5 +8,6 @@ mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
@@ -191,7 +195,7 @@
mt7996e-y += mtk_debugfs.o mtk_mcu.o
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 121a3c95..2299793d 100644
+index 121a3c958..f9b9ca25d 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -6,6 +6,11 @@
@@ -258,17 +262,19 @@
ret = mt7996_mcu_get_eeprom_free_block(dev, &free_block_num);
if (ret < 0)
return ret;
-@@ -118,7 +141,7 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
+@@ -118,8 +141,8 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
/* read eeprom data from efuse */
block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
for (i = 0; i < block_num; i++) {
- ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size);
+- if (ret < 0)
+ ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, NULL);
- if (ret < 0)
++ if (ret && ret != -EINVAL)
return ret;
}
+ }
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 72c38ad3..de3ff4e2 100644
+index 72c38ad3b..de3ff4e27 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -14,6 +14,7 @@ enum mt7996_eeprom_field {
@@ -280,10 +286,10 @@
MT_EE_RATE_DELTA_2G = 0x1400,
MT_EE_RATE_DELTA_5G = 0x147d,
diff --git a/mt7996/init.c b/mt7996/init.c
-index 0e3cdc05..d4d1a60b 100644
+index d58335a37..440e26d58 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -966,6 +966,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
+@@ -969,6 +969,10 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
set_bit(MT76_STATE_INITIALIZED, &dev->mphy.state);
@@ -294,7 +300,7 @@
ret = mt7996_mcu_init(dev);
if (ret)
return ret;
-@@ -1384,6 +1388,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
+@@ -1419,6 +1423,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
mt7996_init_wiphy(hw, &dev->mt76.mmio.wed);
@@ -306,7 +312,7 @@
ARRAY_SIZE(mt76_rates));
if (ret)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 1f53d230..603f6c0d 100644
+index 1f53d2303..603f6c0d7 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -685,7 +685,8 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
@@ -320,7 +326,7 @@
if (!status->wcid || !ieee80211_is_data_qos(fc) || hw_aggr)
diff --git a/mt7996/main.c b/mt7996/main.c
-index ad2c6a9d..40b5cee3 100644
+index 4fc1dd9a9..48cc87e07 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -23,6 +23,18 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
@@ -342,8 +348,8 @@
int mt7996_run(struct ieee80211_hw *hw)
{
struct mt7996_dev *dev = mt7996_hw_dev(hw);
-@@ -37,6 +49,8 @@ int mt7996_run(struct ieee80211_hw *hw)
- goto out;
+@@ -45,6 +57,8 @@ int mt7996_run(struct ieee80211_hw *hw)
+ }
}
+ mt7996_testmode_disable_all(dev);
@@ -351,7 +357,7 @@
mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
-@@ -291,6 +305,11 @@ int mt7996_set_channel(struct mt7996_phy *phy)
+@@ -303,6 +317,11 @@ int mt7996_set_channel(struct mt7996_phy *phy)
mt76_set_channel(phy->mt76);
@@ -363,7 +369,7 @@
ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
if (ret)
goto out;
-@@ -398,6 +417,11 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+@@ -411,6 +430,12 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
int ret;
if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -372,10 +378,11 @@
+ if (ret)
+ return ret;
+ }
- ieee80211_stop_queues(hw);
- ret = mt7996_set_channel(phy);
++
+ ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE,
+ phy->mt76->chandef.punctured);
if (ret)
-@@ -1507,6 +1531,8 @@ const struct ieee80211_ops mt7996_ops = {
+@@ -1523,6 +1548,8 @@ const struct ieee80211_ops mt7996_ops = {
.sta_set_decap_offload = mt7996_sta_set_decap_offload,
.add_twt_setup = mt7996_mac_add_twt_setup,
.twt_teardown_request = mt7996_twt_teardown_request,
@@ -385,10 +392,10 @@
.sta_add_debugfs = mt7996_sta_add_debugfs,
#endif
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index b488a78f..d8795d30 100644
+index bad370839..f09281430 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -2863,8 +2863,12 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
+@@ -2865,8 +2865,12 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
{
int ret;
@@ -403,7 +410,7 @@
if (ret)
return ret;
-@@ -3555,17 +3559,9 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
+@@ -3557,17 +3561,9 @@ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
&req, sizeof(req), true);
}
@@ -423,7 +430,7 @@
.tag = cpu_to_le16(UNI_EFUSE_ACCESS),
.len = cpu_to_le16(sizeof(req) - 4),
.addr = cpu_to_le32(round_down(offset,
-@@ -3574,6 +3570,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
+@@ -3576,6 +3572,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
struct sk_buff *skb;
bool valid;
int ret;
@@ -431,7 +438,7 @@
ret = mt76_mcu_send_and_get_msg(&dev->mt76,
MCU_WM_UNI_CMD_QUERY(EFUSE_CTRL),
-@@ -3584,7 +3581,9 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
+@@ -3586,7 +3583,9 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset)
valid = le32_to_cpu(*(__le32 *)(skb->data + 16));
if (valid) {
u32 addr = le32_to_cpu(*(__le32 *)(skb->data + 12));
@@ -442,7 +449,7 @@
skb_pull(skb, 48);
memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE);
-@@ -4577,3 +4576,37 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, bool auto_mode,
+@@ -4609,3 +4608,37 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap)
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PP),
&req, sizeof(req), false);
}
@@ -481,7 +488,7 @@
+ &req, sizeof(req), false);
+}
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 238c4c53..325c3c97 100644
+index 2052555fe..d5ac2b38e 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -157,6 +157,16 @@ struct mt7996_mcu_eeprom {
@@ -534,7 +541,7 @@
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 29976860..5af55492 100644
+index 696e16fa1..0c6a4b96b 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -32,25 +32,30 @@
@@ -568,7 +575,7 @@
#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom_2i5i.bin"
#define MT7992_EEPROM_DEFAULT_EXT "mediatek/mt7996/mt7992_eeprom_2e5e.bin"
#define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin"
-@@ -126,6 +131,7 @@ enum mt7992_sku_type {
+@@ -127,6 +132,7 @@ enum mt7992_sku_type {
enum mt7996_ram_type {
MT7996_RAM_TYPE_WM,
@@ -576,10 +583,10 @@
MT7996_RAM_TYPE_WA,
MT7996_RAM_TYPE_DSP,
__MT7996_RAM_TYPE_MAX,
-@@ -273,6 +279,21 @@ struct mt7996_phy {
- struct mt76_channel_state state_ts;
+@@ -277,6 +283,21 @@ struct mt7996_phy {
- bool has_aux_rx;
+ u8 pp_mode;
+ u16 punct_bitmap;
+
+#ifdef CONFIG_NL80211_TESTMODE
+ struct {
@@ -598,7 +605,7 @@
};
struct mt7996_dev {
-@@ -353,6 +374,8 @@ struct mt7996_dev {
+@@ -357,6 +378,8 @@ struct mt7996_dev {
spinlock_t lock;
} wed_rro;
@@ -607,7 +614,7 @@
bool ibf;
u8 fw_debug_wm;
u8 fw_debug_wa;
-@@ -467,6 +490,7 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
+@@ -472,6 +495,7 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
extern const struct ieee80211_ops mt7996_ops;
extern struct pci_driver mt7996_pci_driver;
extern struct pci_driver mt7996_hif_driver;
@@ -615,7 +622,7 @@
struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
void __iomem *mem_base, u32 device_id);
-@@ -476,6 +500,7 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
+@@ -481,6 +505,7 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
int mt7996_register_device(struct mt7996_dev *dev);
void mt7996_unregister_device(struct mt7996_dev *dev);
int mt7996_eeprom_init(struct mt7996_dev *dev);
@@ -623,7 +630,7 @@
int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
struct ieee80211_channel *chan);
-@@ -528,7 +553,7 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+@@ -533,7 +558,7 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, void *data, u32 field);
int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
@@ -632,7 +639,7 @@
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
int mt7996_mcu_get_chip_config(struct mt7996_dev *dev, u32 *cap);
int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 set, u8 band);
-@@ -563,6 +588,7 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
+@@ -568,6 +593,7 @@ void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
@@ -642,7 +649,7 @@
{
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
new file mode 100644
-index 00000000..96079c22
+index 000000000..98eebceed
--- /dev/null
+++ b/mt7996/testmode.c
@@ -0,0 +1,740 @@
@@ -857,7 +864,7 @@
+ mt7996_tm_rf_switch_mode(dev, rf_test_mode);
+
+ mt7996_mcu_add_bss_info(phy, phy->monitor_vif, en);
-+ mt7996_mcu_add_sta(dev, phy->monitor_vif, NULL, en);
++ mt7996_mcu_add_sta(dev, phy->monitor_vif, NULL, en, false);
+
+ mt7996_tm_set(dev, SET_ID(BAND_IDX), phy->mt76->band_idx);
+
@@ -1388,7 +1395,7 @@
+};
diff --git a/mt7996/testmode.h b/mt7996/testmode.h
new file mode 100644
-index 00000000..319ef257
+index 000000000..319ef257a
--- /dev/null
+++ b/mt7996/testmode.h
@@ -0,0 +1,299 @@
@@ -1692,7 +1699,7 @@
+
+#endif
diff --git a/testmode.c b/testmode.c
-index 37783160..44f3a5bf 100644
+index ca4feccf3..44f3a5bfc 100644
--- a/testmode.c
+++ b/testmode.c
@@ -2,11 +2,13 @@
@@ -1930,7 +1937,17 @@
MT76_TM_STATS_ATTR_PAD))
return -EMSGSIZE;
+@@ -613,7 +694,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
+
-@@ -625,6 +706,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
+ if (dev->test_mtd.name &&
+ (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) ||
+- nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset)))
++ nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset) ||
++ nla_put_u8(msg, MT76_TM_ATTR_BAND_IDX, phy->band_idx)))
+ goto out;
+
+ if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
+@@ -624,6 +706,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_SGI, td->tx_rate_sgi) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_LDPC, td->tx_rate_ldpc) ||
nla_put_u8(msg, MT76_TM_ATTR_TX_RATE_STBC, td->tx_rate_stbc) ||
@@ -1939,7 +1956,7 @@
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_LTF) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
-@@ -640,7 +723,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
+@@ -639,7 +723,7 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER_CONTROL) &&
nla_put_u8(msg, MT76_TM_ATTR_TX_POWER_CONTROL, td->tx_power_control)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_FREQ_OFFSET) &&
@@ -1949,7 +1966,7 @@
if (mt76_testmode_param_present(td, MT76_TM_ATTR_TX_POWER)) {
diff --git a/testmode.h b/testmode.h
-index a40cd74b..96872e8c 100644
+index 5e2792d81..96872e8cd 100644
--- a/testmode.h
+++ b/testmode.h
@@ -5,7 +5,8 @@
@@ -1962,15 +1979,17 @@
/**
* enum mt76_testmode_attr - testmode attributes inside NL80211_ATTR_TESTDATA
-@@ -19,6 +20,7 @@
+@@ -17,7 +18,9 @@
+ *
+ * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string)
* @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
- * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
++ * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
*
+ * @MT76_TM_ATTR_SKU_EN: config txpower sku is enabled or disabled in testmode (u8)
* @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
* state to MT76_TM_STATE_TX_FRAMES (u32)
* @MT76_TM_ATTR_TX_PENDING: pending frames during MT76_TM_STATE_TX_FRAMES (u32)
-@@ -39,6 +41,11 @@
+@@ -38,6 +41,11 @@
*
* @MT76_TM_ATTR_STATS: statistics (nested, see &enum mt76_testmode_stats_attr)
*
@@ -1982,7 +2001,7 @@
* @MT76_TM_ATTR_TX_SPE_IDX: tx spatial extension index (u8)
*
* @MT76_TM_ATTR_TX_DUTY_CYCLE: packet tx duty cycle (u8)
-@@ -48,6 +55,29 @@
+@@ -47,6 +55,29 @@
* @MT76_TM_ATTR_DRV_DATA: driver specific netlink attrs (nested)
*
* @MT76_TM_ATTR_MAC_ADDRS: array of nested MAC addresses (nested)
@@ -2012,15 +2031,17 @@
*/
enum mt76_testmode_attr {
MT76_TM_ATTR_UNSPEC,
-@@ -59,6 +89,7 @@ enum mt76_testmode_attr {
+@@ -56,7 +87,9 @@ enum mt76_testmode_attr {
+
+ MT76_TM_ATTR_MTD_PART,
MT76_TM_ATTR_MTD_OFFSET,
- MT76_TM_ATTR_BAND_IDX,
++ MT76_TM_ATTR_BAND_IDX,
+ MT76_TM_ATTR_SKU_EN,
MT76_TM_ATTR_TX_COUNT,
MT76_TM_ATTR_TX_LENGTH,
MT76_TM_ATTR_TX_RATE_MODE,
-@@ -76,6 +107,8 @@ enum mt76_testmode_attr {
+@@ -74,6 +107,8 @@ enum mt76_testmode_attr {
MT76_TM_ATTR_FREQ_OFFSET,
MT76_TM_ATTR_STATS,
@@ -2029,7 +2050,7 @@
MT76_TM_ATTR_TX_SPE_IDX,
-@@ -86,6 +119,27 @@ enum mt76_testmode_attr {
+@@ -84,6 +119,27 @@ enum mt76_testmode_attr {
MT76_TM_ATTR_DRV_DATA,
MT76_TM_ATTR_MAC_ADDRS,
@@ -2057,7 +2078,7 @@
/* keep last */
NUM_MT76_TM_ATTRS,
-@@ -103,6 +157,8 @@ enum mt76_testmode_attr {
+@@ -101,6 +157,8 @@ enum mt76_testmode_attr {
* @MT76_TM_STATS_ATTR_RX_FCS_ERROR: number of rx packets with FCS error (u64)
* @MT76_TM_STATS_ATTR_LAST_RX: information about the last received packet
* see &enum mt76_testmode_rx_attr
@@ -2066,7 +2087,7 @@
*/
enum mt76_testmode_stats_attr {
MT76_TM_STATS_ATTR_UNSPEC,
-@@ -115,6 +171,7 @@ enum mt76_testmode_stats_attr {
+@@ -113,6 +171,7 @@ enum mt76_testmode_stats_attr {
MT76_TM_STATS_ATTR_RX_PACKETS,
MT76_TM_STATS_ATTR_RX_FCS_ERROR,
MT76_TM_STATS_ATTR_LAST_RX,
@@ -2074,7 +2095,7 @@
/* keep last */
NUM_MT76_TM_STATS_ATTRS,
-@@ -127,6 +184,7 @@ enum mt76_testmode_stats_attr {
+@@ -125,6 +184,7 @@ enum mt76_testmode_stats_attr {
*
* @MT76_TM_RX_ATTR_FREQ_OFFSET: frequency offset (s32)
* @MT76_TM_RX_ATTR_RCPI: received channel power indicator (array, u8)
@@ -2082,7 +2103,7 @@
* @MT76_TM_RX_ATTR_IB_RSSI: internal inband RSSI (array, s8)
* @MT76_TM_RX_ATTR_WB_RSSI: internal wideband RSSI (array, s8)
* @MT76_TM_RX_ATTR_SNR: signal-to-noise ratio (u8)
-@@ -136,6 +194,7 @@ enum mt76_testmode_rx_attr {
+@@ -134,6 +194,7 @@ enum mt76_testmode_rx_attr {
MT76_TM_RX_ATTR_FREQ_OFFSET,
MT76_TM_RX_ATTR_RCPI,
@@ -2090,7 +2111,7 @@
MT76_TM_RX_ATTR_IB_RSSI,
MT76_TM_RX_ATTR_WB_RSSI,
MT76_TM_RX_ATTR_SNR,
-@@ -179,6 +238,9 @@ enum mt76_testmode_state {
+@@ -177,6 +238,9 @@ enum mt76_testmode_state {
* @MT76_TM_TX_MODE_HE_EXT_SU: 802.11ax extended-range SU
* @MT76_TM_TX_MODE_HE_TB: 802.11ax trigger-based
* @MT76_TM_TX_MODE_HE_MU: 802.11ax multi-user MIMO
@@ -2100,7 +2121,7 @@
*/
enum mt76_testmode_tx_mode {
MT76_TM_TX_MODE_CCK,
-@@ -189,12 +251,33 @@ enum mt76_testmode_tx_mode {
+@@ -187,12 +251,33 @@ enum mt76_testmode_tx_mode {
MT76_TM_TX_MODE_HE_EXT_SU,
MT76_TM_TX_MODE_HE_TB,
MT76_TM_TX_MODE_HE_MU,
@@ -2135,7 +2156,7 @@
#endif
diff --git a/tools/fields.c b/tools/fields.c
-index e3f69089..055f90f3 100644
+index e3f690896..055f90f3c 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -10,6 +10,7 @@ static const char * const testmode_state[] = {
@@ -2350,5 +2371,5 @@
const struct tm_field msg_field = {
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1005-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0023-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch
similarity index 96%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1005-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0023-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch
index 4d70c33..dc9298f 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1005-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0023-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch
@@ -1,10 +1,11 @@
-From 10b5c0f3d23bd9f556654364584d8eb2a9424c6f Mon Sep 17 00:00:00 2001
+From d0914a4cc7a181e2a2c8c1295a99f2812525e31c Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 31 Mar 2023 11:27:24 +0800
-Subject: [PATCH 1005/1044] mtk: wifi: mt76: testmode: add testmode
+Subject: [PATCH 023/116] mtk: wifi: mt76: testmode: add testmode
pre-calibration support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: If8a6cc02fa20e35f079c826e0571e8c04c3f9c7e
---
mac80211.c | 21 ---
mt76.h | 22 +++
@@ -21,11 +22,11 @@
12 files changed, 632 insertions(+), 23 deletions(-)
diff --git a/mac80211.c b/mac80211.c
-index fea19e19..e7d02d15 100644
+index b285407a8..1127ef7b5 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -7,27 +7,6 @@
- #include <net/page_pool.h>
+@@ -6,27 +6,6 @@
+ #include <linux/of.h>
#include "mt76.h"
-#define CHAN2G(_idx, _freq) { \
@@ -53,10 +54,10 @@
CHAN2G(1, 2412),
CHAN2G(2, 2417),
diff --git a/mt76.h b/mt76.h
-index f2b1e0c2..14c5fcb1 100644
+index 58e8e726c..97a691991 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -18,6 +18,27 @@
+@@ -23,6 +23,27 @@
#include "util.h"
#include "testmode.h"
@@ -84,7 +85,7 @@
#define MT_MCU_RING_SIZE 32
#define MT_RX_BUF_SIZE 2048
#define MT_SKB_HEAD_LEN 256
-@@ -698,6 +719,7 @@ struct mt76_testmode_ops {
+@@ -703,6 +724,7 @@ struct mt76_testmode_ops {
void (*reset_rx_stats)(struct mt76_phy *phy);
void (*tx_stop)(struct mt76_phy *phy);
int (*set_eeprom)(struct mt76_phy *phy, u32 offset, u8 *val, u8 action);
@@ -93,7 +94,7 @@
#define MT_TM_FW_RX_COUNT BIT(0)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 2e148011..54310413 100644
+index 718552baf..f5ea719e4 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1042,8 +1042,10 @@ enum {
@@ -108,7 +109,7 @@
MCU_UNI_EVENT_PER_STA_INFO = 0x6d,
MCU_UNI_EVENT_ALL_STA_INFO = 0x6e,
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 2299793d..3aeffdfb 100644
+index f9b9ca25d..62c1ad489 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -12,6 +12,42 @@ static bool testmode_enable;
@@ -192,7 +193,7 @@
mt7996_eeprom_load_default(struct mt7996_dev *dev)
{
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index de3ff4e2..849b8bca 100644
+index de3ff4e27..849b8bcab 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -14,6 +14,7 @@ enum mt7996_eeprom_field {
@@ -257,10 +258,10 @@
#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index d8795d30..0e2c1f1c 100644
+index f09281430..82528f7b2 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -712,6 +712,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -715,6 +715,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_WED_RRO:
mt7996_mcu_wed_rro_event(dev, skb);
break;
@@ -273,10 +274,10 @@
break;
}
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 5af55492..e7609c63 100644
+index 0c6a4b96b..121c4a1a7 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -385,6 +385,9 @@ struct mt7996_dev {
+@@ -390,6 +390,9 @@ struct mt7996_dev {
struct dentry *debugfs_dir;
struct rchan *relay_fwlog;
@@ -286,7 +287,7 @@
struct {
u16 table_mask;
u8 n_agrt;
-@@ -505,6 +508,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
+@@ -510,6 +513,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
struct ieee80211_channel *chan);
s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band);
@@ -294,7 +295,7 @@
int mt7996_dma_init(struct mt7996_dev *dev);
void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
void mt7996_dma_prefetch(struct mt7996_dev *dev);
-@@ -589,6 +593,9 @@ void mt7996_mcu_exit(struct mt7996_dev *dev);
+@@ -594,6 +598,9 @@ void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
@@ -305,7 +306,7 @@
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
-index 96079c22..36be0ff8 100644
+index 98eebceed..a756ee10d 100644
--- a/mt7996/testmode.c
+++ b/mt7996/testmode.c
@@ -7,6 +7,8 @@
@@ -772,7 +773,7 @@
+ .dump_precal = mt7996_tm_dump_precal,
};
diff --git a/mt7996/testmode.h b/mt7996/testmode.h
-index 319ef257..9bfb86f2 100644
+index 319ef257a..9bfb86f28 100644
--- a/mt7996/testmode.h
+++ b/mt7996/testmode.h
@@ -34,6 +34,12 @@ enum bw_mapping_method {
@@ -834,7 +835,7 @@
RF_OPER_NORMAL,
RF_OPER_RF_TEST,
diff --git a/testmode.c b/testmode.c
-index 44f3a5bf..cd8cb655 100644
+index 44f3a5bfc..cd8cb6553 100644
--- a/testmode.c
+++ b/testmode.c
@@ -674,6 +674,18 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
@@ -857,7 +858,7 @@
err = -EINVAL;
diff --git a/testmode.h b/testmode.h
-index 96872e8c..d6601cdc 100644
+index 96872e8cd..d6601cdcf 100644
--- a/testmode.h
+++ b/testmode.h
@@ -220,6 +220,14 @@ enum mt76_testmode_state {
@@ -876,7 +877,7 @@
/* keep last */
diff --git a/tools/fields.c b/tools/fields.c
-index 055f90f3..b0122763 100644
+index 055f90f3c..b01227638 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -11,6 +11,14 @@ static const char * const testmode_state[] = {
@@ -895,5 +896,5 @@
static const char * const testmode_tx_mode[] = {
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1010-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0024-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch
similarity index 91%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1010-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0024-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch
index 1ca02bf..740ee4a 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1010-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0024-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch
@@ -1,7 +1,7 @@
-From e72fe68d4a6356a2fae17c21971c1fd5a5d9384d Mon Sep 17 00:00:00 2001
+From 9b77eae5dca30ef64dea0b2a48c05b22a6a8bc25 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Wed, 1 Mar 2023 12:12:51 +0800
-Subject: [PATCH 1010/1044] mtk: wifi: mt76: mt7996: add normal mode
+Subject: [PATCH 024/116] mtk: wifi: mt76: mt7996: add normal mode
pre-calibration support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -16,7 +16,7 @@
7 files changed, 188 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 4a3ea0b7..3c82c05d 100644
+index f5ea719e4..c785edb80 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1277,6 +1277,7 @@ enum {
@@ -28,10 +28,10 @@
MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
MCU_UNI_CMD_PER_STA_INFO = 0x6d,
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index c334f849..d93b1558 100644
+index 62c1ad489..4afa2a295 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
-@@ -449,6 +449,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
+@@ -356,6 +356,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
return ret;
}
@@ -43,7 +43,7 @@
if (ret < 0)
return ret;
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 8b555aeb..8f0f87b6 100644
+index 849b8bcab..58179c0c5 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -25,6 +25,8 @@ enum mt7996_eeprom_field {
@@ -56,10 +56,10 @@
#define MT_EE_WIFI_CONF0_TX_PATH GENMASK(2, 0)
diff --git a/mt7996/init.c b/mt7996/init.c
-index 5f937b26..c135da9c 100644
+index 440e26d58..201daf110 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -984,6 +984,12 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
+@@ -985,6 +985,12 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
if (ret < 0)
return ret;
@@ -73,10 +73,10 @@
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
if (idx)
diff --git a/mt7996/main.c b/mt7996/main.c
-index ecfc3dcf..07a14917 100644
+index 48cc87e07..479940095 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -321,6 +321,12 @@ int mt7996_set_channel(struct mt7996_phy *phy)
+@@ -317,6 +317,12 @@ int mt7996_set_channel(struct mt7996_phy *phy)
mt76_set_channel(phy->mt76);
@@ -90,10 +90,10 @@
mt7996_tm_update_channel(phy);
goto out;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index e103601f..0ee17ff9 100644
+index 82528f7b2..a006b0e34 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3629,6 +3629,172 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num)
+@@ -3631,6 +3631,172 @@ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num)
return 0;
}
@@ -267,10 +267,10 @@
{
#define NIC_CAP 3
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 2f067988..69db055d 100644
+index 121c4a1a7..5e2d8bef0 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -611,6 +611,9 @@ void mt7996_mcu_exit(struct mt7996_dev *dev);
+@@ -598,6 +598,9 @@ void mt7996_mcu_exit(struct mt7996_dev *dev);
int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
@@ -281,5 +281,5 @@
void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1006-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0025-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch
similarity index 86%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1006-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0025-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch
index df56fb5..8e37799 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1006-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0025-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch
@@ -1,7 +1,7 @@
-From 50d5f66613427d37f2f714ee4334e36eaa9039f7 Mon Sep 17 00:00:00 2001
+From d5f1a204501372080b078364e41762992e81eec6 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Mon, 8 May 2023 09:03:50 +0800
-Subject: [PATCH 1006/1044] mtk: wifi: mt76: mt7996: enable SCS feature for
+Subject: [PATCH 025/116] mtk: wifi: mt76: mt7996: enable SCS feature for
mt7996 driver
Enable Smart Carrier Sense algorithn by default to improve performance
@@ -20,10 +20,10 @@
8 files changed, 148 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 54310413..4a3ea0b7 100644
+index c785edb80..d8830dc25 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1261,6 +1261,7 @@ enum {
+@@ -1262,6 +1262,7 @@ enum {
MCU_UNI_CMD_GET_STAT_INFO = 0x23,
MCU_UNI_CMD_SNIFFER = 0x24,
MCU_UNI_CMD_SR = 0x25,
@@ -32,10 +32,10 @@
MCU_UNI_CMD_SET_DBDC_PARMS = 0x28,
MCU_UNI_CMD_TXPOWER = 0x2b,
diff --git a/mt7996/init.c b/mt7996/init.c
-index d4d1a60b..23a9b88b 100644
+index 201daf110..6a394c364 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -1374,6 +1374,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
+@@ -1415,6 +1415,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
dev->mt76.phy.priv = &dev->phy;
INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
@@ -44,7 +44,7 @@
INIT_LIST_HEAD(&dev->twt_list);
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 603f6c0d..c9f45abe 100644
+index 603f6c0d7..c9f45abef 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1795,6 +1795,7 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
@@ -64,10 +64,10 @@
void mt7996_mac_reset_work(struct work_struct *work)
diff --git a/mt7996/main.c b/mt7996/main.c
-index 40b5cee3..ffb1f81b 100644
+index 479940095..57865f1de 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -73,11 +73,17 @@ int mt7996_run(struct ieee80211_hw *hw)
+@@ -81,11 +81,17 @@ int mt7996_run(struct ieee80211_hw *hw)
if (ret)
goto out;
@@ -85,7 +85,7 @@
if (!running)
mt7996_mac_reset_counters(phy);
-@@ -105,6 +111,7 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+@@ -113,6 +119,7 @@ static void mt7996_stop(struct ieee80211_hw *hw)
struct mt7996_phy *phy = mt7996_hw_phy(hw);
cancel_delayed_work_sync(&phy->mt76->mac_work);
@@ -94,10 +94,10 @@
mutex_lock(&dev->mt76.mutex);
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 0e2c1f1c..62452d6e 100644
+index a006b0e34..2650dc6ff 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -4615,3 +4615,108 @@ int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 da
+@@ -4813,3 +4813,108 @@ int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 da
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(TXPOWER),
&req, sizeof(req), false);
}
@@ -207,11 +207,11 @@
+ &req, sizeof(req), false);
+}
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 325c3c97..4f4994d8 100644
+index d5ac2b38e..5953b25e8 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
-@@ -960,6 +960,12 @@ enum {
- UNI_CMD_PP_EN_CTRL,
+@@ -966,6 +966,12 @@ enum pp_mode {
+ PP_USR_MODE,
};
+enum {
@@ -224,10 +224,10 @@
#define MT7996_PATCH_SCRAMBLE_KEY GENMASK(15, 8)
#define MT7996_PATCH_AES_KEY GENMASK(7, 0)
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index e7609c63..384157c8 100644
+index 5e2d8bef0..186af3c1d 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -233,6 +233,16 @@ struct mt7996_hif {
+@@ -234,6 +234,16 @@ struct mt7996_hif {
int irq;
};
@@ -244,16 +244,16 @@
struct mt7996_wed_rro_addr {
u32 head_low;
u32 head_high : 4;
-@@ -280,6 +290,8 @@ struct mt7996_phy {
-
- bool has_aux_rx;
+@@ -284,6 +294,8 @@ struct mt7996_phy {
+ u8 pp_mode;
+ u16 punct_bitmap;
+ struct mt7996_scs_ctrl scs_ctrl;
+
#ifdef CONFIG_NL80211_TESTMODE
struct {
u32 *reg_backup;
-@@ -326,6 +338,7 @@ struct mt7996_dev {
+@@ -330,6 +342,7 @@ struct mt7996_dev {
struct work_struct rc_work;
struct work_struct dump_work;
struct work_struct reset_work;
@@ -261,7 +261,7 @@
wait_queue_head_t reset_wait;
struct {
u32 state;
-@@ -596,6 +609,8 @@ int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 da
+@@ -604,6 +617,8 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy);
#ifdef CONFIG_NL80211_TESTMODE
void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
#endif
@@ -271,10 +271,10 @@
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 678b009e..7e4ac77c 100644
+index 8baf27c76..9b4d5f68c 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -2407,6 +2407,16 @@ static int mt7996_token_read(struct seq_file *s, void *data)
+@@ -2430,6 +2430,16 @@ static int mt7996_token_read(struct seq_file *s, void *data)
return 0;
}
@@ -291,7 +291,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -2477,6 +2487,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -2500,6 +2510,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_devm_seqfile(dev->mt76.dev, "token", dir, mt7996_token_read);
debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
@@ -300,5 +300,5 @@
return 0;
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0026-mtk-wifi-mt76-mt7996-add-txpower-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0026-mtk-wifi-mt76-mt7996-add-txpower-support.patch
new file mode 100644
index 0000000..b056189
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0026-mtk-wifi-mt76-mt7996-add-txpower-support.patch
@@ -0,0 +1,1047 @@
+From c3e9680c5a1387067019b361390df5a150eb232b Mon Sep 17 00:00:00 2001
+From: Allen Ye <allen.ye@mediatek.com>
+Date: Fri, 24 Mar 2023 23:35:30 +0800
+Subject: [PATCH 026/116] mtk: wifi: mt76: mt7996: add txpower support
+
+Add single sku and default enable sku.
+
+mtk: wifi: mt76: mt7996: Porting wifi6 txpower fix to eagle
+
+Refactor txpower flow.
+1. Fix wrong bbp CR address
+2. Ignore RegDB power limit when we have single sku table. And dump more informaiton in debugfs.
+3. Refactor get_txpower ops flow, we only consider CCK and OFDM power value as maximum.
+4. Remove sku_disable due to SQC is over and default enable both sku tables.
+
+Fix wrong power value when user set limit close to path table limit.
+
+CR-Id: WCNCR00259302
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Signed-off-by: Allen Ye <allen.ye@mediatek.com>
+---
+ eeprom.c | 54 ++++++-
+ mt76.h | 9 ++
+ mt76_connac_mcu.c | 2 +-
+ mt7996/eeprom.c | 34 ++++
+ mt7996/eeprom.h | 42 +++++
+ mt7996/init.c | 16 +-
+ mt7996/main.c | 15 ++
+ mt7996/mcu.c | 69 ++++++++-
+ mt7996/mcu.h | 2 +
+ mt7996/mt7996.h | 4 +
+ mt7996/mtk_debugfs.c | 362 +++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mtk_mcu.c | 23 +++
+ mt7996/mtk_mcu.h | 92 +++++++++++
+ mt7996/regs.h | 27 ++--
+ 14 files changed, 724 insertions(+), 27 deletions(-)
+
+diff --git a/eeprom.c b/eeprom.c
+index a0047d791..11efe2937 100644
+--- a/eeprom.c
++++ b/eeprom.c
+@@ -305,9 +305,10 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data,
+ static void
+ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
+ const __be32 *data, size_t len, s8 target_power,
+- s8 nss_delta, s8 *max_power)
++ s8 nss_delta)
+ {
+ int i, cur;
++ s8 max_power = -128;
+
+ if (!data)
+ return;
+@@ -319,7 +320,7 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
+ break;
+
+ mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
+- target_power, nss_delta, max_power);
++ target_power, nss_delta, &max_power);
+ if (--cur > 0)
+ continue;
+
+@@ -335,6 +336,7 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
+ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ struct ieee80211_channel *chan,
+ struct mt76_power_limits *dest,
++ struct mt76_power_path_limits *dest_path,
+ s8 target_power)
+ {
+ struct mt76_dev *dev = phy->dev;
+@@ -342,16 +344,20 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ const __be32 *val;
+ char name[16];
+ u32 mcs_rates = dev->drv->mcs_rates;
+- u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
+ char band;
+ size_t len;
+- s8 max_power = 0;
++ s8 max_power = -127;
++ s8 max_power_backoff = -127;
+ s8 txs_delta;
++ int n_chains = hweight16(phy->chainmask);
++ s8 target_power_combine = target_power + mt76_tx_power_nss_delta(n_chains);
+
+ if (!mcs_rates)
+- mcs_rates = 10;
++ mcs_rates = 12;
+
+ memset(dest, target_power, sizeof(*dest));
++ if (dest_path != NULL)
++ memset(dest_path, 0, sizeof(*dest_path));
+
+ if (!IS_ENABLED(CONFIG_OF))
+ return target_power;
+@@ -397,12 +403,44 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1);
+ mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
+ ARRAY_SIZE(dest->mcs), val, len,
+- target_power, txs_delta, &max_power);
++ target_power, txs_delta);
+
+- val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1);
++ val = mt76_get_of_array(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1);
+ mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
+ ARRAY_SIZE(dest->ru), val, len,
+- target_power, txs_delta, &max_power);
++ target_power, txs_delta);
++
++ val = mt76_get_of_array(np, "rates-eht", &len, ARRAY_SIZE(dest->eht[0]) + 1);
++ mt76_apply_multi_array_limit(dest->eht[0], ARRAY_SIZE(dest->eht[0]),
++ ARRAY_SIZE(dest->eht), val, len,
++ target_power, txs_delta);
++
++ if (dest_path == NULL)
++ return max_power;
++
++ max_power_backoff = max_power;
++
++ val = mt76_get_of_array(np, "paths-cck", &len, ARRAY_SIZE(dest_path->cck));
++ mt76_apply_array_limit(dest_path->cck, ARRAY_SIZE(dest_path->cck), val,
++ target_power_combine, txs_delta, &max_power_backoff);
++
++ val = mt76_get_of_array(np, "paths-ofdm", &len, ARRAY_SIZE(dest_path->ofdm));
++ mt76_apply_array_limit(dest_path->ofdm, ARRAY_SIZE(dest_path->ofdm), val,
++ target_power_combine, txs_delta, &max_power_backoff);
++
++ val = mt76_get_of_array(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest_path->ofdm_bf));
++ mt76_apply_array_limit(dest_path->ofdm_bf, ARRAY_SIZE(dest_path->ofdm_bf), val,
++ target_power_combine, txs_delta, &max_power_backoff);
++
++ val = mt76_get_of_array(np, "paths-ru", &len, ARRAY_SIZE(dest_path->ru[0]) + 1);
++ mt76_apply_multi_array_limit(dest_path->ru[0], ARRAY_SIZE(dest_path->ru[0]),
++ ARRAY_SIZE(dest_path->ru), val, len,
++ target_power_combine, txs_delta);
++
++ val = mt76_get_of_array(np, "paths-ru-bf", &len, ARRAY_SIZE(dest_path->ru_bf[0]) + 1);
++ mt76_apply_multi_array_limit(dest_path->ru_bf[0], ARRAY_SIZE(dest_path->ru_bf[0]),
++ ARRAY_SIZE(dest_path->ru_bf), val, len,
++ target_power_combine, txs_delta);
+
+ return max_power;
+ }
+diff --git a/mt76.h b/mt76.h
+index 97a691991..20fdd050a 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -1059,6 +1059,14 @@ struct mt76_power_limits {
+ s8 eht[16][16];
+ };
+
++struct mt76_power_path_limits {
++ s8 cck[5];
++ s8 ofdm[5];
++ s8 ofdm_bf[4];
++ s8 ru[16][15];
++ s8 ru_bf[16][15];
++};
++
+ struct mt76_ethtool_worker_info {
+ u64 *data;
+ int idx;
+@@ -1669,6 +1677,7 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan);
+ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ struct ieee80211_channel *chan,
+ struct mt76_power_limits *dest,
++ struct mt76_power_path_limits *dest_path,
+ s8 target_power);
+
+ static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q)
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index 1e34e0ae3..0c7b69352 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -2150,7 +2150,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
+ sar_power = mt76_get_sar_power(phy, &chan, reg_power);
+
+ mt76_get_rate_power_limits(phy, &chan, limits,
+- sar_power);
++ NULL, sar_power);
+
+ tx_power_tlv.last_msg = ch_list[idx] == last_ch;
+ sku_tlbv.channel = ch_list[idx];
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 4afa2a295..6ac992a81 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -408,3 +408,37 @@ s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band)
+
+ return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta;
+ }
++
++const u8 mt7996_sku_group_len[] = {
++ [SKU_CCK] = 4,
++ [SKU_OFDM] = 8,
++ [SKU_HT20] = 8,
++ [SKU_HT40] = 9,
++ [SKU_VHT20] = 12,
++ [SKU_VHT40] = 12,
++ [SKU_VHT80] = 12,
++ [SKU_VHT160] = 12,
++ [SKU_HE26] = 12,
++ [SKU_HE52] = 12,
++ [SKU_HE106] = 12,
++ [SKU_HE242] = 12,
++ [SKU_HE484] = 12,
++ [SKU_HE996] = 12,
++ [SKU_HE2x996] = 12,
++ [SKU_EHT26] = 16,
++ [SKU_EHT52] = 16,
++ [SKU_EHT106] = 16,
++ [SKU_EHT242] = 16,
++ [SKU_EHT484] = 16,
++ [SKU_EHT996] = 16,
++ [SKU_EHT2x996] = 16,
++ [SKU_EHT4x996] = 16,
++ [SKU_EHT26_52] = 16,
++ [SKU_EHT26_106] = 16,
++ [SKU_EHT484_242] = 16,
++ [SKU_EHT996_484] = 16,
++ [SKU_EHT996_484_242] = 16,
++ [SKU_EHT2x996_484] = 16,
++ [SKU_EHT3x996] = 16,
++ [SKU_EHT3x996_484] = 16,
++};
+diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
+index 58179c0c5..b19ff068e 100644
+--- a/mt7996/eeprom.h
++++ b/mt7996/eeprom.h
+@@ -125,4 +125,46 @@ mt7996_get_channel_group_6g(int channel)
+ return DIV_ROUND_UP(channel - 29, 32);
+ }
+
++enum mt7996_sku_rate_group {
++ SKU_CCK,
++ SKU_OFDM,
++
++ SKU_HT20,
++ SKU_HT40,
++
++ SKU_VHT20,
++ SKU_VHT40,
++ SKU_VHT80,
++ SKU_VHT160,
++
++ SKU_HE26,
++ SKU_HE52,
++ SKU_HE106,
++ SKU_HE242,
++ SKU_HE484,
++ SKU_HE996,
++ SKU_HE2x996,
++
++ SKU_EHT26,
++ SKU_EHT52,
++ SKU_EHT106,
++ SKU_EHT242,
++ SKU_EHT484,
++ SKU_EHT996,
++ SKU_EHT2x996,
++ SKU_EHT4x996,
++ SKU_EHT26_52,
++ SKU_EHT26_106,
++ SKU_EHT484_242,
++ SKU_EHT996_484,
++ SKU_EHT996_484_242,
++ SKU_EHT2x996_484,
++ SKU_EHT3x996,
++ SKU_EHT3x996_484,
++
++ MAX_SKU_RATE_GROUP_NUM,
++};
++
++extern const u8 mt7996_sku_group_len[MAX_SKU_RATE_GROUP_NUM];
++
+ #endif
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 6a394c364..f1d681787 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -295,7 +295,12 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy,
+ int nss_delta = mt76_tx_power_nss_delta(nss);
+ int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band);
+ struct mt76_power_limits limits;
++ struct mt76_power_path_limits limits_path;
++ struct device_node *np;
+
++ phy->sku_limit_en = true;
++ phy->sku_path_en = true;
++ np = mt76_find_power_limits_node(&dev->mt76);
+ for (i = 0; i < sband->n_channels; i++) {
+ struct ieee80211_channel *chan = &sband->channels[i];
+ int target_power = mt7996_eeprom_get_target_power(dev, chan);
+@@ -303,11 +308,18 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy,
+ target_power += pwr_delta;
+ target_power = mt76_get_rate_power_limits(phy->mt76, chan,
+ &limits,
++ &limits_path,
+ target_power);
++ if (!limits_path.ofdm[0])
++ phy->sku_path_en = false;
++
+ target_power += nss_delta;
+ target_power = DIV_ROUND_UP(target_power, 2);
+- chan->max_power = min_t(int, chan->max_reg_power,
+- target_power);
++ if (!np)
++ chan->max_power = min_t(int, chan->max_reg_power,
++ target_power);
++ else
++ chan->max_power = target_power;
+ chan->orig_mpwr = target_power;
+ }
+ }
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 57865f1de..52870fa72 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -85,6 +85,21 @@ int mt7996_run(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++#ifdef CONFIG_MTK_DEBUG
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
++ dev->dbg.sku_disable ? 0 : phy->sku_limit_en);
++
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
++ dev->dbg.sku_disable ? 0 : phy->sku_path_en);
++#else
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
++ phy->sku_limit_en);
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
++ phy->sku_path_en);
++#endif
++ if (ret)
++ goto out;
++
+ set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 2650dc6ff..1330ff397 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -4665,9 +4665,31 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
+ sizeof(req), true);
+ }
+
++static void
++mt7996_update_max_txpower_cur(struct mt7996_phy *phy, int tx_power)
++{
++ struct mt76_phy *mphy = phy->mt76;
++ struct ieee80211_channel *chan = mphy->main_chan;
++ int e2p_power_limit = 0;
++
++ if (chan == NULL) {
++ mphy->txpower_cur = tx_power;
++ return;
++ }
++
++ e2p_power_limit = mt7996_eeprom_get_target_power(phy->dev, chan);
++ e2p_power_limit += mt7996_eeprom_get_power_delta(phy->dev, chan->band);
++
++ if (phy->sku_limit_en)
++ mphy->txpower_cur = min_t(int, e2p_power_limit, tx_power);
++ else
++ mphy->txpower_cur = e2p_power_limit;
++}
++
+ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+ {
+ #define TX_POWER_LIMIT_TABLE_RATE 0
++#define TX_POWER_LIMIT_TABLE_PATH 1
+ struct mt7996_dev *dev = phy->dev;
+ struct mt76_phy *mphy = phy->mt76;
+ struct ieee80211_hw *hw = mphy->hw;
+@@ -4687,13 +4709,22 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+ .band_idx = phy->mt76->band_idx,
+ };
+ struct mt76_power_limits la = {};
++ struct mt76_power_path_limits la_path = {};
+ struct sk_buff *skb;
+- int i, tx_power;
++ int i, ret, txpower_limit;
++
++ if (hw->conf.power_level == INT_MIN)
++ hw->conf.power_level = 127;
++ txpower_limit = mt7996_get_power_bound(phy, hw->conf.power_level);
+
+- tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
+- tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+- &la, tx_power);
+- mphy->txpower_cur = tx_power;
++ if (phy->sku_limit_en) {
++ txpower_limit = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
++ &la, &la_path, txpower_limit);
++ mt7996_update_max_txpower_cur(phy, txpower_limit);
++ } else {
++ mt7996_update_max_txpower_cur(phy, txpower_limit);
++ return 0;
++ }
+
+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
+ sizeof(req) + MT7996_SKU_PATH_NUM);
+@@ -4723,6 +4754,34 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+ /* padding */
+ skb_put_zero(skb, MT7996_SKU_PATH_NUM - MT7996_SKU_RATE_NUM);
+
++ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
++ MCU_WM_UNI_CMD(TXPOWER), true);
++ if (ret)
++ return ret;
++
++ /* only set per-path power table when it's configured */
++ if (!phy->sku_path_en)
++ return 0;
++
++ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
++ sizeof(req) + MT7996_SKU_PATH_NUM);
++ if (!skb)
++ return -ENOMEM;
++ req.power_limit_type = TX_POWER_LIMIT_TABLE_PATH;
++
++ skb_put_data(skb, &req, sizeof(req));
++ skb_put_data(skb, &la_path.cck, sizeof(la_path.cck));
++ skb_put_data(skb, &la_path.ofdm, sizeof(la_path.ofdm));
++ skb_put_data(skb, &la_path.ofdm_bf, sizeof(la_path.ofdm_bf));
++
++ for (i = 0; i < 32; i++) {
++ bool bf = i % 2;
++ u8 idx = i / 2;
++ s8 *buf = bf ? la_path.ru_bf[idx] : la_path.ru[idx];
++
++ skb_put_data(skb, buf, sizeof(la_path.ru[0]));
++ }
++
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WM_UNI_CMD(TXPOWER), true);
+ }
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index 5953b25e8..5a60ccc55 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -911,6 +911,7 @@ struct tx_power_ctrl {
+ bool ate_mode_enable;
+ bool percentage_ctrl_enable;
+ bool bf_backoff_enable;
++ u8 show_info_category;
+ u8 power_drop_level;
+ };
+ u8 band_idx;
+@@ -924,6 +925,7 @@ enum {
+ UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
+ UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
+ UNI_TXPOWER_ATE_MODE_CTRL = 6,
++ UNI_TXPOWER_SHOW_INFO = 7,
+ };
+
+ enum {
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 186af3c1d..6ab45cc7e 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -296,6 +296,9 @@ struct mt7996_phy {
+
+ struct mt7996_scs_ctrl scs_ctrl;
+
++ bool sku_limit_en;
++ bool sku_path_en;
++
+ #ifdef CONFIG_NL80211_TESTMODE
+ struct {
+ u32 *reg_backup;
+@@ -617,6 +620,7 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy);
+ #ifdef CONFIG_NL80211_TESTMODE
+ void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
+ #endif
++int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event);
+ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable);
+ void mt7996_mcu_scs_sta_poll(struct work_struct *work);
+
+diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
+index 9b4d5f68c..48209668c 100644
+--- a/mt7996/mtk_debugfs.c
++++ b/mt7996/mtk_debugfs.c
+@@ -2440,6 +2440,364 @@ mt7996_scs_enable_set(void *data, u64 val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_scs_enable, NULL,
+ mt7996_scs_enable_set, "%lld\n");
+
++static int
++mt7996_txpower_level_set(void *data, u64 val)
++{
++ struct mt7996_phy *phy = data;
++ int ret;
++
++ if (val > 100)
++ return -EINVAL;
++
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_PERCENTAGE_CTRL, !!val);
++ if (ret)
++ return ret;
++
++ return mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_PERCENTAGE_DROP_CTRL, val);
++}
++
++DEFINE_DEBUGFS_ATTRIBUTE(fops_txpower_level, NULL,
++ mt7996_txpower_level_set, "%lld\n");
++
++static ssize_t
++mt7996_get_txpower_info(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct mt7996_phy *phy = file->private_data;
++ struct mt7996_mcu_txpower_event *event;
++ struct txpower_basic_info *basic_info;
++ struct device_node *np;
++ static const size_t size = 2048;
++ int len = 0;
++ ssize_t ret;
++ char *buf;
++
++ buf = kzalloc(size, GFP_KERNEL);
++ event = kzalloc(sizeof(*event), GFP_KERNEL);
++ if (!buf || !event) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ret = mt7996_mcu_get_tx_power_info(phy, BASIC_INFO, event);
++ if (ret ||
++ le32_to_cpu(event->basic_info.category) != UNI_TXPOWER_BASIC_INFO)
++ goto out;
++
++ basic_info = &event->basic_info;
++
++ len += scnprintf(buf + len, size - len,
++ "======================== BASIC INFO ========================\n");
++ len += scnprintf(buf + len, size - len, " Band Index: %d, Channel Band: %d\n",
++ basic_info->band_idx, basic_info->band);
++ len += scnprintf(buf + len, size - len, " PA Type: %s\n",
++ basic_info->is_epa ? "ePA" : "iPA");
++ len += scnprintf(buf + len, size - len, " LNA Type: %s\n",
++ basic_info->is_elna ? "eLNA" : "iLNA");
++
++ len += scnprintf(buf + len, size - len,
++ "------------------------------------------------------------\n");
++ len += scnprintf(buf + len, size - len, " SKU: %s\n",
++ basic_info->sku_enable ? "enable" : "disable");
++ len += scnprintf(buf + len, size - len, " Percentage Control: %s\n",
++ basic_info->percentage_ctrl_enable ? "enable" : "disable");
++ len += scnprintf(buf + len, size - len, " Power Drop: %d [dBm]\n",
++ basic_info->power_drop_level >> 1);
++ len += scnprintf(buf + len, size - len, " Backoff: %s\n",
++ basic_info->bf_backoff_enable ? "enable" : "disable");
++ len += scnprintf(buf + len, size - len, " TX Front-end Loss: %d, %d, %d, %d\n",
++ basic_info->front_end_loss_tx[0], basic_info->front_end_loss_tx[1],
++ basic_info->front_end_loss_tx[2], basic_info->front_end_loss_tx[3]);
++ len += scnprintf(buf + len, size - len, " RX Front-end Loss: %d, %d, %d, %d\n",
++ basic_info->front_end_loss_rx[0], basic_info->front_end_loss_rx[1],
++ basic_info->front_end_loss_rx[2], basic_info->front_end_loss_rx[3]);
++ len += scnprintf(buf + len, size - len,
++ " MU TX Power Mode: %s\n",
++ basic_info->mu_tx_power_manual_enable ? "manual" : "auto");
++ len += scnprintf(buf + len, size - len,
++ " MU TX Power (Auto / Manual): %d / %d [0.5 dBm]\n",
++ basic_info->mu_tx_power_auto, basic_info->mu_tx_power_manual);
++ len += scnprintf(buf + len, size - len,
++ " Thermal Compensation: %s\n",
++ basic_info->thermal_compensate_enable ? "enable" : "disable");
++ len += scnprintf(buf + len, size - len,
++ " Theraml Compensation Value: %d\n",
++ basic_info->thermal_compensate_value);
++ np = mt76_find_power_limits_node(phy->mt76->dev);
++ len += scnprintf(buf + len, size - len,
++ " RegDB: %s\n",
++ !np ? "enable" : "disable");
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++out:
++ kfree(buf);
++ kfree(event);
++ return ret;
++}
++
++static const struct file_operations mt7996_txpower_info_fops = {
++ .read = mt7996_get_txpower_info,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++#define mt7996_txpower_puts(rate, _len) \
++({ \
++ len += scnprintf(buf + len, size - len, "%-*s:", _len, #rate " (TMAC)"); \
++ for (i = 0; i < mt7996_sku_group_len[SKU_##rate]; i++, offs++) \
++ len += scnprintf(buf + len, size - len, " %6d", \
++ event->phy_rate_info.frame_power[offs][band_idx]); \
++ len += scnprintf(buf + len, size - len, "\n"); \
++})
++
++static ssize_t
++mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct mt7996_phy *phy = file->private_data;
++ struct mt7996_dev *dev = phy->dev;
++ struct mt7996_mcu_txpower_event *event;
++ struct ieee80211_channel *chan = phy->mt76->chandef.chan;
++ struct ieee80211_supported_band sband;
++ u8 band_idx = phy->mt76->band_idx;
++ static const size_t size = 5120;
++ int i, offs = 0, len = 0;
++ u32 target_power = 0;
++ int n_chains = hweight16(phy->mt76->chainmask);
++ int nss_delta = mt76_tx_power_nss_delta(n_chains);
++ int pwr_delta;
++ ssize_t ret;
++ char *buf;
++ u32 reg;
++
++ buf = kzalloc(size, GFP_KERNEL);
++ event = kzalloc(sizeof(*event), GFP_KERNEL);
++ if (!buf || !event) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ret = mt7996_mcu_get_tx_power_info(phy, PHY_RATE_INFO, event);
++ if (ret ||
++ le32_to_cpu(event->phy_rate_info.category) != UNI_TXPOWER_PHY_RATE_INFO)
++ goto out;
++
++ len += scnprintf(buf + len, size - len,
++ "\nPhy %d TX Power Table (Channel %d)\n",
++ band_idx, phy->mt76->chandef.chan->hw_value);
++ len += scnprintf(buf + len, size - len, "%-21s %6s %6s %6s %6s\n",
++ " ", "1m", "2m", "5m", "11m");
++ mt7996_txpower_puts(CCK, 21);
++
++ len += scnprintf(buf + len, size - len,
++ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++ " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
++ "54m");
++ mt7996_txpower_puts(OFDM, 21);
++
++ len += scnprintf(buf + len, size - len,
++ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
++ "mcs5", "mcs6", "mcs7");
++ mt7996_txpower_puts(HT20, 21);
++
++ len += scnprintf(buf + len, size - len,
++ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
++ "mcs6", "mcs7", "mcs32");
++ mt7996_txpower_puts(HT40, 21);
++
++ len += scnprintf(buf + len, size - len,
++ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
++ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
++ "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
++ mt7996_txpower_puts(VHT20, 21);
++ mt7996_txpower_puts(VHT40, 21);
++ mt7996_txpower_puts(VHT80, 21);
++ mt7996_txpower_puts(VHT160, 21);
++ mt7996_txpower_puts(HE26, 21);
++ mt7996_txpower_puts(HE52, 21);
++ mt7996_txpower_puts(HE106, 21);
++ len += scnprintf(buf + len, size - len, "BW20/");
++ mt7996_txpower_puts(HE242, 16);
++ len += scnprintf(buf + len, size - len, "BW40/");
++ mt7996_txpower_puts(HE484, 16);
++ len += scnprintf(buf + len, size - len, "BW80/");
++ mt7996_txpower_puts(HE996, 16);
++ len += scnprintf(buf + len, size - len, "BW160/");
++ mt7996_txpower_puts(HE2x996, 15);
++
++ len += scnprintf(buf + len, size - len,
++ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s ",
++ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", "mcs6", "mcs7");
++ len += scnprintf(buf + len, size - len,
++ "%6s %6s %6s %6s %6s %6s %6s %6s\n",
++ "mcs8", "mcs9", "mcs10", "mcs11", "mcs12", "mcs13", "mcs14", "mcs15");
++ mt7996_txpower_puts(EHT26, 21);
++ mt7996_txpower_puts(EHT52, 21);
++ mt7996_txpower_puts(EHT106, 21);
++ len += scnprintf(buf + len, size - len, "BW20/");
++ mt7996_txpower_puts(EHT242, 16);
++ len += scnprintf(buf + len, size - len, "BW40/");
++ mt7996_txpower_puts(EHT484, 16);
++ len += scnprintf(buf + len, size - len, "BW80/");
++ mt7996_txpower_puts(EHT996, 16);
++ len += scnprintf(buf + len, size - len, "BW160/");
++ mt7996_txpower_puts(EHT2x996, 15);
++ len += scnprintf(buf + len, size - len, "BW320/");
++ mt7996_txpower_puts(EHT4x996, 15);
++ mt7996_txpower_puts(EHT26_52, 21);
++ mt7996_txpower_puts(EHT26_106, 21);
++ mt7996_txpower_puts(EHT484_242, 21);
++ mt7996_txpower_puts(EHT996_484, 21);
++ mt7996_txpower_puts(EHT996_484_242, 21);
++ mt7996_txpower_puts(EHT2x996_484, 21);
++ mt7996_txpower_puts(EHT3x996, 21);
++ mt7996_txpower_puts(EHT3x996_484, 21);
++
++ len += scnprintf(buf + len, size - len, "\nePA Gain: %d\n",
++ event->phy_rate_info.epa_gain);
++ len += scnprintf(buf + len, size - len, "Max Power Bound: %d\n",
++ event->phy_rate_info.max_power_bound);
++ len += scnprintf(buf + len, size - len, "Min Power Bound: %d\n",
++ event->phy_rate_info.min_power_bound);
++
++ reg = MT_WF_PHYDFE_TSSI_TXCTRL01(band_idx);
++ len += scnprintf(buf + len, size - len,
++ "\nBBP TX Power (target power from TMAC) : %6ld [0.5 dBm]\n",
++ mt76_get_field(dev, reg, MT_WF_PHYDFE_TSSI_TXCTRL_POWER_TMAC));
++ len += scnprintf(buf + len, size - len,
++ "RegDB maximum power:\t%d [dBm]\n",
++ chan->max_reg_power);
++
++ if (chan->band == NL80211_BAND_2GHZ)
++ sband = phy->mt76->sband_2g.sband;
++ else if (chan->band == NL80211_BAND_5GHZ)
++ sband = phy->mt76->sband_5g.sband;
++ else if (chan->band == NL80211_BAND_6GHZ)
++ sband = phy->mt76->sband_6g.sband;
++
++ pwr_delta = mt7996_eeprom_get_power_delta(dev, sband.band);
++
++ target_power = max_t(u32, target_power, mt7996_eeprom_get_target_power(dev, chan));
++ target_power += pwr_delta + nss_delta;
++ target_power = DIV_ROUND_UP(target_power, 2);
++ len += scnprintf(buf + len, size - len,
++ "eeprom maximum power:\t%d [dBm]\n",
++ target_power);
++
++ len += scnprintf(buf + len, size - len,
++ "nss_delta:\t%d [0.5 dBm]\n",
++ nss_delta);
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++out:
++ kfree(buf);
++ kfree(event);
++ return ret;
++}
++
++static const struct file_operations mt7996_txpower_sku_fops = {
++ .read = mt7996_get_txpower_sku,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
++#define mt7996_txpower_path_puts(rate, arr_length) \
++({ \
++ len += scnprintf(buf + len, size - len, "%23s:", #rate " (TMAC)"); \
++ for (i = 0; i < arr_length; i++, offs++) \
++ len += scnprintf(buf + len, size - len, " %4d", \
++ event->backoff_table_info.frame_power[offs]); \
++ len += scnprintf(buf + len, size - len, "\n"); \
++})
++
++static ssize_t
++mt7996_get_txpower_path(struct file *file, char __user *user_buf,
++ size_t count, loff_t *ppos)
++{
++ struct mt7996_phy *phy = file->private_data;
++ struct mt7996_mcu_txpower_event *event;
++ static const size_t size = 5120;
++ int i, offs = 0, len = 0;
++ ssize_t ret;
++ char *buf;
++
++ buf = kzalloc(size, GFP_KERNEL);
++ event = kzalloc(sizeof(*event), GFP_KERNEL);
++ if (!buf || !event) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ ret = mt7996_mcu_get_tx_power_info(phy, BACKOFF_TABLE_INFO, event);
++ if (ret ||
++ le32_to_cpu(event->phy_rate_info.category) != UNI_TXPOWER_BACKOFF_TABLE_SHOW_INFO)
++ goto out;
++
++ len += scnprintf(buf + len, size - len, "\n%*c", 25, ' ');
++ len += scnprintf(buf + len, size - len, "1T1S/2T1S/3T1S/4T1S/5T1S/2T2S/3T2S/4T2S/5T2S/"
++ "3T3S/4T3S/5T3S/4T4S/5T4S/5T5S\n");
++
++ mt7996_txpower_path_puts(CCK, 5);
++ mt7996_txpower_path_puts(OFDM, 5);
++ mt7996_txpower_path_puts(BF-OFDM, 4);
++
++ mt7996_txpower_path_puts(RU26, 15);
++ mt7996_txpower_path_puts(BF-RU26, 15);
++ mt7996_txpower_path_puts(RU52, 15);
++ mt7996_txpower_path_puts(BF-RU52, 15);
++ mt7996_txpower_path_puts(RU26_52, 15);
++ mt7996_txpower_path_puts(BF-RU26_52, 15);
++ mt7996_txpower_path_puts(RU106, 15);
++ mt7996_txpower_path_puts(BF-RU106, 15);
++ mt7996_txpower_path_puts(RU106_52, 15);
++ mt7996_txpower_path_puts(BF-RU106_52, 15);
++
++ mt7996_txpower_path_puts(BW20/RU242, 15);
++ mt7996_txpower_path_puts(BF-BW20/RU242, 15);
++ mt7996_txpower_path_puts(BW40/RU484, 15);
++ mt7996_txpower_path_puts(BF-BW40/RU484, 15);
++ mt7996_txpower_path_puts(RU242_484, 15);
++ mt7996_txpower_path_puts(BF-RU242_484, 15);
++ mt7996_txpower_path_puts(BW80/RU996, 15);
++ mt7996_txpower_path_puts(BF-BW80/RU996, 15);
++ mt7996_txpower_path_puts(RU484_996, 15);
++ mt7996_txpower_path_puts(BF-RU484_996, 15);
++ mt7996_txpower_path_puts(RU242_484_996, 15);
++ mt7996_txpower_path_puts(BF-RU242_484_996, 15);
++ mt7996_txpower_path_puts(BW160/RU996x2, 15);
++ mt7996_txpower_path_puts(BF-BW160/RU996x2, 15);
++ mt7996_txpower_path_puts(RU484_996x2, 15);
++ mt7996_txpower_path_puts(BF-RU484_996x2, 15);
++ mt7996_txpower_path_puts(RU996x3, 15);
++ mt7996_txpower_path_puts(BF-RU996x3, 15);
++ mt7996_txpower_path_puts(RU484_996x3, 15);
++ mt7996_txpower_path_puts(BF-RU484_996x3, 15);
++ mt7996_txpower_path_puts(BW320/RU996x4, 15);
++ mt7996_txpower_path_puts(BF-BW320/RU996x4, 15);
++
++ len += scnprintf(buf + len, size - len, "\nBackoff table: %s\n",
++ event->backoff_table_info.backoff_en ? "enable" : "disable");
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
++
++out:
++ kfree(buf);
++ kfree(event);
++ return ret;
++}
++
++static const struct file_operations mt7996_txpower_path_fops = {
++ .read = mt7996_get_txpower_path,
++ .open = simple_open,
++ .owner = THIS_MODULE,
++ .llseek = default_llseek,
++};
++
+ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+ {
+ struct mt7996_dev *dev = phy->dev;
+@@ -2503,6 +2861,10 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+
+ debugfs_create_devm_seqfile(dev->mt76.dev, "tr_info", dir,
+ mt7996_trinfo_read);
++ debugfs_create_file("txpower_level", 0600, dir, phy, &fops_txpower_level);
++ debugfs_create_file("txpower_info", 0600, dir, phy, &mt7996_txpower_info_fops);
++ debugfs_create_file("txpower_sku", 0600, dir, phy, &mt7996_txpower_sku_fops);
++ debugfs_create_file("txpower_path", 0600, dir, phy, &mt7996_txpower_path_fops);
+
+ debugfs_create_devm_seqfile(dev->mt76.dev, "wtbl_info", dir,
+ mt7996_wtbl_read);
+diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
+index c16b25ab5..e56ddd8ff 100644
+--- a/mt7996/mtk_mcu.c
++++ b/mt7996/mtk_mcu.c
+@@ -12,8 +12,31 @@
+
+ #ifdef CONFIG_MTK_DEBUG
+
++int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event)
++{
++ struct mt7996_dev *dev = phy->dev;
++ struct tx_power_ctrl req = {
++ .tag = cpu_to_le16(UNI_TXPOWER_SHOW_INFO),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .power_ctrl_id = UNI_TXPOWER_SHOW_INFO,
++ .show_info_category = category,
++ .band_idx = phy->mt76->band_idx,
++ };
++ struct sk_buff *skb;
++ int ret;
+
++ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
++ MCU_WM_UNI_CMD_QUERY(TXPOWER),
++ &req, sizeof(req), true, &skb);
++ if (ret)
++ return ret;
+
++ memcpy(event, skb->data, sizeof(struct mt7996_mcu_txpower_event));
++
++ dev_kfree_skb(skb);
++
++ return 0;
++}
+
+ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val)
+ {
+diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
+index 7f4d4e029..c30418cae 100644
+--- a/mt7996/mtk_mcu.h
++++ b/mt7996/mtk_mcu.h
+@@ -14,6 +14,98 @@ enum {
+ UNI_CMD_MURU_DBG_INFO = 0x18,
+ };
+
++struct txpower_basic_info {
++ u8 category;
++ u8 rsv1;
++
++ /* basic info */
++ u8 band_idx;
++ u8 band;
++
++ /* board type info */
++ bool is_epa;
++ bool is_elna;
++
++ /* power percentage info */
++ bool percentage_ctrl_enable;
++ s8 power_drop_level;
++
++ /* frond-end loss TX info */
++ s8 front_end_loss_tx[4];
++
++ /* frond-end loss RX info */
++ s8 front_end_loss_rx[4];
++
++ /* thermal info */
++ bool thermal_compensate_enable;
++ s8 thermal_compensate_value;
++ u8 rsv2;
++
++ /* TX power max/min limit info */
++ s8 max_power_bound;
++ s8 min_power_bound;
++
++ /* power limit info */
++ bool sku_enable;
++ bool bf_backoff_enable;
++
++ /* MU TX power info */
++ bool mu_tx_power_manual_enable;
++ s8 mu_tx_power_auto;
++ s8 mu_tx_power_manual;
++ u8 rsv3;
++};
++
++struct txpower_phy_rate_info {
++ u8 category;
++ u8 band_idx;
++ u8 band;
++ u8 epa_gain;
++
++ /* rate power info [dBm] */
++ s8 frame_power[MT7996_SKU_RATE_NUM][__MT_MAX_BAND];
++
++ /* TX power max/min limit info */
++ s8 max_power_bound;
++ s8 min_power_bound;
++ u8 rsv1;
++};
++
++struct txpower_backoff_table_info {
++ u8 category;
++ u8 band_idx;
++ u8 band;
++ u8 backoff_en;
++
++ s8 frame_power[MT7996_SKU_PATH_NUM];
++ u8 rsv[3];
++};
++
++struct mt7996_mcu_txpower_event {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ union {
++ struct txpower_basic_info basic_info;
++ struct txpower_phy_rate_info phy_rate_info;
++ struct txpower_backoff_table_info backoff_table_info;
++ };
++};
++
++enum txpower_category {
++ BASIC_INFO,
++ BACKOFF_TABLE_INFO,
++ PHY_RATE_INFO,
++};
++
++enum txpower_event {
++ UNI_TXPOWER_BASIC_INFO = 0,
++ UNI_TXPOWER_BACKOFF_TABLE_SHOW_INFO = 3,
++ UNI_TXPOWER_PHY_RATE_INFO = 5,
++};
++
+ #endif
+
+ #endif
+diff --git a/mt7996/regs.h b/mt7996/regs.h
+index 4c20a67d7..8ec1dc1c6 100644
+--- a/mt7996/regs.h
++++ b/mt7996/regs.h
+@@ -693,24 +693,29 @@ enum offs_rev {
+ ((_wf) << 16) + (ofs))
+ #define MT_WF_PHYRX_CSD_IRPI(_band, _wf) MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
+
+-/* PHYRX CTRL */
+-#define MT_WF_PHYRX_BAND_BASE 0x83080000
+-#define MT_WF_PHYRX_BAND(_band, ofs) (MT_WF_PHYRX_BAND_BASE + \
++/* PHYDFE CTRL */
++#define MT_WF_PHYDFE_TSSI_TXCTRL01(_band) MT_WF_PHYRX_CSD(_band, 0, 0xc718)
++#define MT_WF_PHYDFE_TSSI_TXCTRL_POWER_TMAC GENMASK(31, 24)
++
++/* PHY CTRL */
++#define MT_WF_PHY_BAND_BASE 0x83080000
++#define MT_WF_PHY_BAND(_band, ofs) (MT_WF_PHY_BAND_BASE + \
+ ((_band) << 20) + (ofs))
+
+-#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band) MT_WF_PHYRX_BAND(_band, 0x1054)
+-#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band) MT_WF_PHYRX_BAND(_band, 0x1058)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band) MT_WF_PHYRX_BAND(_band, 0x105c)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band) MT_WF_PHYRX_BAND(_band, 0x1060)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band) MT_WF_PHYRX_BAND(_band, 0x1064)
+-#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band) MT_WF_PHYRX_BAND(_band, 0x1068)
++#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band) MT_WF_PHY_BAND(_band, 0x1054)
++#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band) MT_WF_PHY_BAND(_band, 0x1058)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band) MT_WF_PHY_BAND(_band, 0x105c)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band) MT_WF_PHY_BAND(_band, 0x1060)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band) MT_WF_PHY_BAND(_band, 0x1064)
++#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band) MT_WF_PHY_BAND(_band, 0x1068)
+
+-#define MT_WF_PHYRX_BAND_RX_CTRL1(_band) MT_WF_PHYRX_BAND(_band, 0x2004)
++/* PHYRX CTRL */
++#define MT_WF_PHYRX_BAND_RX_CTRL1(_band) MT_WF_PHY_BAND(_band, 0x2004)
+ #define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN GENMASK(2, 0)
+ #define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
+
+ /* PHYRX CSD BAND */
+-#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHYRX_BAND(_band, 0x8230)
++#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHY_BAND(_band, 0x8230)
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
+ #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR BIT(29)
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1009-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0027-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch
similarity index 91%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1009-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0027-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch
index 59222a4..5ae752a 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1009-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0027-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch
@@ -1,9 +1,10 @@
-From c342da92eba77fea4b62298df80f6b3614c0635f Mon Sep 17 00:00:00 2001
+From 83c7e6d692657d514891430ad530df1337b90799 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 31 Mar 2023 11:36:34 +0800
-Subject: [PATCH 1009/1044] mtk: wifi: mt76: mt7996: add binfile mode support
+Subject: [PATCH 027/116] mtk: wifi: mt76: mt7996: add binfile mode support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: I06369a46f75c0707d9ababd8ade70d79a89b1a1c
Fix binfile cannot sync precal data to atenl
Binfile is viewed as efuse mode in atenl, so atenl does not allocate
@@ -13,7 +14,9 @@
Align upstream
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: I4c8fd2b0a9956d2ee961b70cd28973e2e9410aca
---
eeprom.c | 25 +++++++++++
mt76.h | 3 ++
@@ -25,7 +28,7 @@
7 files changed, 179 insertions(+), 6 deletions(-)
diff --git a/eeprom.c b/eeprom.c
-index c5be2843..adb87924 100644
+index 11efe2937..3da94926e 100644
--- a/eeprom.c
+++ b/eeprom.c
@@ -161,6 +161,31 @@ static int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int len)
@@ -61,10 +64,10 @@
mt76_eeprom_override(struct mt76_phy *phy)
{
diff --git a/mt76.h b/mt76.h
-index 630b3903..b2cc1085 100644
+index 20fdd050a..0b6d8b84e 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -949,6 +949,8 @@ struct mt76_dev {
+@@ -954,6 +954,8 @@ struct mt76_dev {
struct mt76_usb usb;
struct mt76_sdio sdio;
};
@@ -73,7 +76,7 @@
};
/* per-phy stats. */
-@@ -1220,6 +1222,7 @@ void mt76_eeprom_override(struct mt76_phy *phy);
+@@ -1225,6 +1227,7 @@ void mt76_eeprom_override(struct mt76_phy *phy);
int mt76_get_of_data_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len);
int mt76_get_of_data_from_nvmem(struct mt76_dev *dev, void *eep,
const char *cell_name, int len);
@@ -82,7 +85,7 @@
struct mt76_queue *
mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index acc33cfe..c334f849 100644
+index 6ac992a81..fe8b25352 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -82,10 +82,17 @@ static int mt7996_check_eeprom(struct mt7996_dev *dev)
@@ -166,7 +169,7 @@
/* testmode enable priority: eeprom field > module parameter */
dev->testmode_enable = !mt7996_check_eeprom(dev) ? eeprom[MT_EE_TESTMODE_EN] :
@@ -211,6 +248,7 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
- if (ret < 0)
+ if (ret && ret != -EINVAL)
return ret;
}
+ dev->eeprom_mode = EFUSE_MODE;
@@ -243,10 +246,10 @@
if (ret)
return ret;
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 23d4929d..8b555aeb 100644
+index b19ff068e..8f0f87b6b 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
-@@ -100,6 +100,13 @@ enum mt7996_eeprom_band {
+@@ -102,6 +102,13 @@ enum mt7996_eeprom_band {
MT_EE_BAND_SEL_6GHZ,
};
@@ -261,7 +264,7 @@
mt7996_get_channel_group_5g(int channel)
{
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 7e3d381e..2f067988 100644
+index 6ab45cc7e..9d6e85c1d 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -62,6 +62,7 @@
@@ -272,7 +275,7 @@
#define MT7996_EEPROM_SIZE 7680
#define MT7996_EEPROM_BLOCK_SIZE 16
#define MT7996_TOKEN_SIZE 16384
-@@ -389,6 +390,8 @@ struct mt7996_dev {
+@@ -395,6 +396,8 @@ struct mt7996_dev {
} wed_rro;
bool testmode_enable;
@@ -281,7 +284,7 @@
bool ibf;
u8 fw_debug_wm;
-@@ -516,6 +519,7 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance);
+@@ -523,6 +526,7 @@ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance);
u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
int mt7996_register_device(struct mt7996_dev *dev);
void mt7996_unregister_device(struct mt7996_dev *dev);
@@ -290,10 +293,10 @@
int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev);
int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index c47d65c9..09652ef5 100644
+index 48209668c..3ecce1329 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -2739,6 +2739,44 @@ static const struct file_operations mt7996_txpower_path_fops = {
+@@ -2798,6 +2798,44 @@ static const struct file_operations mt7996_txpower_path_fops = {
.llseek = default_llseek,
};
@@ -338,7 +341,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -2807,6 +2845,9 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -2866,6 +2904,9 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_file("txpower_sku", 0600, dir, phy, &mt7996_txpower_sku_fops);
debugfs_create_file("txpower_path", 0600, dir, phy, &mt7996_txpower_path_fops);
@@ -349,7 +352,7 @@
mt7996_wtbl_read);
diff --git a/testmode.h b/testmode.h
-index d6601cdc..5d677f8c 100644
+index d6601cdcf..5d677f8c1 100644
--- a/testmode.h
+++ b/testmode.h
@@ -16,7 +16,7 @@
@@ -362,5 +365,5 @@
* @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
*
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1011-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0028-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch
similarity index 97%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1011-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0028-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch
index 20f17b5..c01db67 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1011-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0028-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch
@@ -1,7 +1,7 @@
-From ca5e57a566fb60705ae7d6b0767542b32ee42afc Mon Sep 17 00:00:00 2001
+From 6e64a8af10129018ea1ff7ccd4803d5b0c7ff7ad Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Wed, 22 Mar 2023 11:19:52 +0800
-Subject: [PATCH 1011/1044] mtk: wifi: mt76: testmode: add testmode ZWDFS
+Subject: [PATCH 028/116] mtk: wifi: mt76: testmode: add testmode ZWDFS
verification support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -15,10 +15,10 @@
6 files changed, 326 insertions(+), 12 deletions(-)
diff --git a/mt76.h b/mt76.h
-index b2cc1085..a75277fe 100644
+index 0b6d8b84e..4a3e6bf40 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -778,6 +778,14 @@ struct mt76_testmode_data {
+@@ -783,6 +783,14 @@ struct mt76_testmode_data {
} cfg;
u8 aid;
@@ -34,7 +34,7 @@
struct mt76_vif {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 69db055d..2daca449 100644
+index 9d6e85c1d..7d6ec8ba4 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -289,6 +289,7 @@ struct mt7996_phy {
@@ -46,7 +46,7 @@
bool has_aux_rx;
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
-index 36be0ff8..26ae5827 100644
+index a756ee10d..836211f98 100644
--- a/mt7996/testmode.c
+++ b/mt7996/testmode.c
@@ -17,6 +17,12 @@ enum {
@@ -336,7 +336,7 @@
static int
diff --git a/mt7996/testmode.h b/mt7996/testmode.h
-index 9bfb86f2..78662b2e 100644
+index 9bfb86f28..78662b2ed 100644
--- a/mt7996/testmode.h
+++ b/mt7996/testmode.h
@@ -27,9 +27,15 @@ enum {
@@ -399,7 +399,7 @@
+
#endif
diff --git a/testmode.c b/testmode.c
-index cd8cb655..69147f86 100644
+index cd8cb6553..69147f866 100644
--- a/testmode.c
+++ b/testmode.c
@@ -27,6 +27,13 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
@@ -453,7 +453,7 @@
nla_put_u8(msg, MT76_TM_ATTR_TX_LTF, td->tx_ltf)) ||
(mt76_testmode_param_present(td, MT76_TM_ATTR_TX_ANTENNA) &&
diff --git a/tools/fields.c b/tools/fields.c
-index b0122763..77696ce7 100644
+index b01227638..77696ce7b 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -35,6 +35,15 @@ static const char * const testmode_tx_mode[] = {
@@ -486,5 +486,5 @@
FIELD_NESTED_RO(STATS, stats, "",
.print_extra = print_extra_stats),
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1022-mtk-wifi-mt76-mt7996-add-eagle-iFEM-HWITS-ZWDFS-SW-w.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0029-mtk-wifi-mt76-mt7996-support-eagle-ZWDFS-on-iFEM.patch
similarity index 85%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1022-mtk-wifi-mt76-mt7996-add-eagle-iFEM-HWITS-ZWDFS-SW-w.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0029-mtk-wifi-mt76-mt7996-support-eagle-ZWDFS-on-iFEM.patch
index ebd565c..e7908ef 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1022-mtk-wifi-mt76-mt7996-add-eagle-iFEM-HWITS-ZWDFS-SW-w.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0029-mtk-wifi-mt76-mt7996-support-eagle-ZWDFS-on-iFEM.patch
@@ -1,13 +1,13 @@
-From b0a949cc4ac49a2a276949ebbd0cbecc859c8576 Mon Sep 17 00:00:00 2001
+From 72f979ee7ce94f3f28b6fc761a1aadb37ab2d63a Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Wed, 5 Jul 2023 10:00:17 +0800
-Subject: [PATCH 1022/1044] mtk: wifi: mt76: mt7996: add eagle iFEM HWITS ZWDFS
- SW workaround
+Subject: [PATCH 029/116] mtk: wifi: mt76: mt7996: support eagle ZWDFS on iFEM
Fix the case that control channel is not first chan during first
interface setup.
Refactor ifem adie logic (if/else to switch, use sku_type & fem_type)
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt7996/main.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++---
@@ -16,10 +16,10 @@
3 files changed, 67 insertions(+), 5 deletions(-)
diff --git a/mt7996/main.c b/mt7996/main.c
-index 9ca37e1e..dbe3d33f 100644
+index 52870fa72..1a1f0242c 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -1431,6 +1431,61 @@ mt7996_twt_teardown_request(struct ieee80211_hw *hw,
+@@ -1444,6 +1444,61 @@ mt7996_twt_teardown_request(struct ieee80211_hw *hw,
mutex_unlock(&dev->mt76.mutex);
}
@@ -81,7 +81,7 @@
static int
mt7996_set_radar_background(struct ieee80211_hw *hw,
struct cfg80211_chan_def *chandef)
-@@ -1439,6 +1494,7 @@ mt7996_set_radar_background(struct ieee80211_hw *hw,
+@@ -1452,6 +1507,7 @@ mt7996_set_radar_background(struct ieee80211_hw *hw,
struct mt7996_dev *dev = phy->dev;
int ret = -EINVAL;
bool running;
@@ -89,7 +89,7 @@
mutex_lock(&dev->mt76.mutex);
-@@ -1451,13 +1507,14 @@ mt7996_set_radar_background(struct ieee80211_hw *hw,
+@@ -1464,13 +1520,14 @@ mt7996_set_radar_background(struct ieee80211_hw *hw,
goto out;
}
@@ -106,7 +106,7 @@
ret = mt7996_mcu_rdd_background_enable(phy, NULL);
if (ret)
goto out;
-@@ -1466,7 +1523,9 @@ mt7996_set_radar_background(struct ieee80211_hw *hw,
+@@ -1479,7 +1536,9 @@ mt7996_set_radar_background(struct ieee80211_hw *hw,
goto update_phy;
}
@@ -118,10 +118,10 @@
goto out;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 16341a41..bc4c3a94 100644
+index 1330ff397..f375a5aba 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -369,12 +369,14 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -372,12 +372,14 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
if (!mphy)
return;
@@ -139,10 +139,10 @@
}
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index adb0cdd1..b2fb68c3 100644
+index 7d6ec8ba4..fd93db2fc 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -441,6 +441,7 @@ struct mt7996_dev {
+@@ -399,6 +399,7 @@ struct mt7996_dev {
bool testmode_enable;
bool bin_file_mode;
u8 eeprom_mode;
@@ -151,5 +151,5 @@
bool ibf;
u8 fw_debug_wm;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0030-mtk-wifi-mt76-mt7996-refactor-eeprom-loading-flow-fo.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0030-mtk-wifi-mt76-mt7996-refactor-eeprom-loading-flow-fo.patch
new file mode 100644
index 0000000..30750f5
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0030-mtk-wifi-mt76-mt7996-refactor-eeprom-loading-flow-fo.patch
@@ -0,0 +1,485 @@
+From fcdb091e77f60c86abd005508edc7beb6dd33154 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Mon, 11 Mar 2024 10:43:03 +0800
+Subject: [PATCH 030/116] mtk: wifi: mt76: mt7996: refactor eeprom loading flow
+ for sku checking
+
+Add eeprom sku checking mechanism to avoid using the
+wrong eeprom in flash/binfile mode
+The fields listed below will be checked by comparing the loaded eeprom to the default bin
+1. FEM type
+2. MAC address (warning for using default MAC address)
+3. RF path & streams
+ (to distinguish cases such as BE7200 4i5i, BE6500 3i5i, and BE5040 2i3i)
+
+CR-Id: WCNCR00274293
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: If1905086f2a876a593d07f23a5facad35067f94a
+
+1. Reset eeprom content before loading efuse
+ eeprom array might contain incomplete data read from flash or
+ binfile, which is not overwritten since this block is invalid
+ in efuse.
+2. Remove testmode default bin since it is unnecessary
+ Not used in logan. Directly load normal mode default bin is fine.
+ Also, this way is better since we don't need to put testmode default
+ eeprom for each sku (especially kite's sku) in our SDK.
+3. Set testmode_en field for default bin mode for consistency sake
+
+CR-Id: WCNCR00274293
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+1.
+Fix efuse mode txpower = 0 issue
+This fix might be changed if fw supports efuse merge for buffer mode = EE_MODE_EFUSE
+2.
+Add Eagle BE19000 ifem default bin, add Eagle default bin bootstrip
+
+CR-Id: WCNCR00274293
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ mt7996/eeprom.c | 207 ++++++++++++++++++++++++-------------------
+ mt7996/eeprom.h | 32 +++++++
+ mt7996/mcu.c | 18 +---
+ mt7996/mt7996.h | 3 +-
+ mt7996/mtk_debugfs.c | 2 +-
+ 5 files changed, 150 insertions(+), 112 deletions(-)
+
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index fe8b25352..f97d76cc4 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -50,54 +50,84 @@ const u32 dpd_6g_bw320_ch_num = ARRAY_SIZE(dpd_6g_ch_list_bw320);
+
+ static int mt7996_check_eeprom(struct mt7996_dev *dev)
+ {
+-#define FEM_INT 0
+-#define FEM_EXT 3
+ u8 *eeprom = dev->mt76.eeprom.data;
+- u8 i, fem[__MT_MAX_BAND], fem_type;
+ u16 val = get_unaligned_le16(eeprom);
+
+- for (i = 0; i < __MT_MAX_BAND; i++)
+- fem[i] = eeprom[MT_EE_WIFI_CONF + 6 + i] & MT_EE_WIFI_PA_LNA_CONFIG;
+-
+ switch (val) {
+ case 0x7990:
+ return is_mt7996(&dev->mt76) ? 0 : -EINVAL;
+ case 0x7992:
+- if (dev->fem_type == MT7996_FEM_UNSET)
+- return is_mt7992(&dev->mt76) ? 0 : -EINVAL;
+-
+- if (fem[0] == FEM_EXT && fem[1] == FEM_EXT)
+- fem_type = MT7996_FEM_EXT;
+- else if (fem[0] == FEM_INT && fem[1] == FEM_INT)
+- fem_type = MT7996_FEM_INT;
+- else if (fem[0] == FEM_INT && fem[1] == FEM_EXT)
+- fem_type = MT7996_FEM_MIX;
+- else
+- return -EINVAL;
+-
+- return (is_mt7992(&dev->mt76) ? 0 : -EINVAL) |
+- (dev->fem_type == fem_type ? 0 : -EINVAL);
++ return is_mt7992(&dev->mt76) ? 0 : -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ }
+
+-const char *mt7996_eeprom_name(struct mt7996_dev *dev)
++static int mt7996_check_eeprom_sku(struct mt7996_dev *dev, const u8 *dflt)
+ {
+- if (dev->bin_file_mode)
+- return dev->mt76.bin_file_name;
++#define FEM_INT 0
++#define FEM_EXT 3
++ u8 *eeprom = dev->mt76.eeprom.data;
++ u8 i, fem[__MT_MAX_BAND], fem_type;
++ u16 mac_addr[__MT_MAX_BAND] = {MT_EE_MAC_ADDR, MT_EE_MAC_ADDR2, MT_EE_MAC_ADDR3};
++ int max_band = is_mt7996(&dev->mt76) ? __MT_MAX_BAND : 2;
++
++ if (dev->fem_type == MT7996_FEM_UNSET)
++ return -EINVAL;
++
++ /* FEM type */
++ for (i = 0; i < max_band; i++)
++ fem[i] = eeprom[MT_EE_WIFI_CONF + 6 + i] & MT_EE_WIFI_PA_LNA_CONFIG;
++
++ if (fem[0] == FEM_EXT && fem[1] == FEM_EXT)
++ fem_type = MT7996_FEM_EXT;
++ else if (fem[0] == FEM_INT && fem[1] == FEM_INT)
++ fem_type = MT7996_FEM_INT;
++ else if (fem[0] == FEM_INT && fem[1] == FEM_EXT)
++ fem_type = MT7996_FEM_MIX;
++ else
++ return -EINVAL;
+
+- if (dev->testmode_enable) {
+- if (is_mt7992(&dev->mt76))
+- return MT7992_EEPROM_DEFAULT_TM;
+- else
+- return MT7996_EEPROM_DEFAULT_TM;
++ if (dev->fem_type != fem_type)
++ return -EINVAL;
++
++ /* RF path & stream */
++ for (i = 0; i < max_band; i++) {
++ u8 path, rx_path, nss;
++ u8 dflt_path, dflt_rx_path, dflt_nss;
++
++ /* MAC address */
++ if (ether_addr_equal(eeprom + mac_addr[i], dflt + mac_addr[i]))
++ dev_warn(dev->mt76.dev,
++ "Currently using default MAC address for band %d\n", i);
++
++ mt7996_parse_eeprom_stream(eeprom, i, &path, &rx_path, &nss);
++ mt7996_parse_eeprom_stream(dflt, i, &dflt_path, &dflt_rx_path, &dflt_nss);
++ if (path > dflt_path || rx_path > dflt_rx_path || nss > dflt_nss) {
++ dev_err(dev->mt76.dev,
++ "Invalid path/stream configuration for band %d\n", i);
++ return -EINVAL;
++ } else if (path < dflt_path || rx_path < dflt_rx_path || nss < dflt_nss) {
++ dev_warn(dev->mt76.dev,
++ "Restricted path/stream configuration for band %d\n", i);
++ dev_warn(dev->mt76.dev,
++ "path: %u/%u, rx_path: %u/%u, nss: %u/%u\n",
++ path, dflt_path, rx_path, dflt_rx_path, nss, dflt_nss);
++ }
+ }
+
++ return 0;
++}
++
++const char *mt7996_eeprom_name(struct mt7996_dev *dev)
++{
+ switch (mt76_chip(&dev->mt76)) {
+ case 0x7990:
+ if (dev->chip_sku == MT7996_SKU_404)
+ return MT7996_EEPROM_DEFAULT_404;
++
++ if (dev->fem_type == MT7996_FEM_INT)
++ return MT7996_EEPROM_DEFAULT_INT;
+ return MT7996_EEPROM_DEFAULT;
+ case 0x7992:
+ if (dev->chip_sku == MT7992_SKU_23) {
+@@ -148,21 +178,18 @@ mt7996_get_dpd_per_band_size(struct mt7996_dev *dev, enum nl80211_band band)
+ }
+
+ static int
+-mt7996_eeprom_load_default(struct mt7996_dev *dev)
++mt7996_eeprom_load_bin(struct mt7996_dev *dev)
+ {
+ u8 *eeprom = dev->mt76.eeprom.data;
+ const struct firmware *fw = NULL;
+ int ret;
+
+- ret = request_firmware(&fw, mt7996_eeprom_name(dev), dev->mt76.dev);
++ ret = request_firmware(&fw, dev->mt76.bin_file_name, dev->mt76.dev);
+ if (ret)
+ return ret;
+
+ if (!fw || !fw->data) {
+- if (dev->bin_file_mode)
+- dev_err(dev->mt76.dev, "Invalid bin (bin file mode)\n");
+- else
+- dev_err(dev->mt76.dev, "Invalid default bin\n");
++ dev_err(dev->mt76.dev, "Invalid bin %s\n", dev->mt76.bin_file_name);
+ ret = -EINVAL;
+ goto out;
+ }
+@@ -180,7 +207,7 @@ static int mt7996_eeprom_load_flash(struct mt7996_dev *dev)
+ {
+ int ret = 1;
+
+- /* return > 0 for load success, return 0 for load failed, return < 0 for non memory */
++ /* return > 0 for load success, return 0 for load failed, return < 0 for no memory */
+ dev->bin_file_mode = mt76_check_bin_file_mode(&dev->mt76);
+ if (dev->bin_file_mode) {
+ dev->mt76.eeprom.size = MT7996_EEPROM_SIZE;
+@@ -189,15 +216,15 @@ static int mt7996_eeprom_load_flash(struct mt7996_dev *dev)
+ if (!dev->mt76.eeprom.data)
+ return -ENOMEM;
+
+- if (mt7996_eeprom_load_default(dev))
+- return 0;
+-
+- if (mt7996_check_eeprom(dev))
++ if (mt7996_eeprom_load_bin(dev))
+ return 0;
+ } else {
+ ret = mt76_eeprom_init(&dev->mt76, MT7996_EEPROM_SIZE);
+ }
+
++ if (mt7996_check_eeprom(dev))
++ return 0;
++
+ return ret;
+ }
+
+@@ -206,30 +233,30 @@ int mt7996_eeprom_check_fw_mode(struct mt7996_dev *dev)
+ u8 *eeprom;
+ int ret;
+
++ dev->testmode_enable = testmode_enable;
++
+ /* load eeprom in flash or bin file mode to determine fw mode */
+ ret = mt7996_eeprom_load_flash(dev);
++ if (ret <= 0)
++ goto out;
+
+- if (ret < 0)
+- return ret;
+-
+- if (ret) {
+- dev->flash_mode = true;
+- dev->eeprom_mode = dev->bin_file_mode ? BIN_FILE_MODE : FLASH_MODE;
+- eeprom = dev->mt76.eeprom.data;
+- /* testmode enable priority: eeprom field > module parameter */
+- dev->testmode_enable = !mt7996_check_eeprom(dev) ? eeprom[MT_EE_TESTMODE_EN] :
+- testmode_enable;
+- }
++ dev->flash_mode = true;
++ dev->eeprom_mode = dev->bin_file_mode ? BIN_FILE_MODE : FLASH_MODE;
++ eeprom = dev->mt76.eeprom.data;
++ /* testmode enable priority: eeprom field > module parameter */
++ dev->testmode_enable = eeprom[MT_EE_TESTMODE_EN];
+
++out:
+ return ret;
+ }
+
+ static int mt7996_eeprom_load(struct mt7996_dev *dev)
+ {
++ const struct firmware *fw = NULL;
+ int ret;
+- u8 free_block_num;
+ u32 block_num, i;
+ u32 eeprom_blk_size = MT7996_EEPROM_BLOCK_SIZE;
++ u8 free_block_num, *eeprom = dev->mt76.eeprom.data;
+
+ /* flash or bin file mode eeprom is loaded before mcu init */
+ if (!dev->flash_mode) {
+@@ -239,19 +266,49 @@ static int mt7996_eeprom_load(struct mt7996_dev *dev)
+
+ /* efuse info isn't enough */
+ if (free_block_num >= 59)
+- return -EINVAL;
++ goto dflt;
++
++ memset(eeprom, 0, MT7996_EEPROM_SIZE);
++ /* check if efuse contains valid eeprom data */
++ if (mt7996_mcu_get_eeprom(dev, 0, NULL) ||
++ mt7996_check_eeprom(dev))
++ goto dflt;
+
+ /* read eeprom data from efuse */
+ block_num = DIV_ROUND_UP(MT7996_EEPROM_SIZE, eeprom_blk_size);
+- for (i = 0; i < block_num; i++) {
++ for (i = 1; i < block_num; i++) {
+ ret = mt7996_mcu_get_eeprom(dev, i * eeprom_blk_size, NULL);
+ if (ret && ret != -EINVAL)
+- return ret;
++ goto dflt;
+ }
+ dev->eeprom_mode = EFUSE_MODE;
+ }
+
+- return mt7996_check_eeprom(dev);
++dflt:
++ ret = request_firmware(&fw, mt7996_eeprom_name(dev), dev->mt76.dev);
++ if (ret)
++ return ret;
++
++ if (!fw || !fw->data) {
++ dev_err(dev->mt76.dev, "Invalid default bin\n");
++ ret = -EINVAL;
++ goto out;
++ }
++
++ if (dev->eeprom_mode && !mt7996_check_eeprom_sku(dev, fw->data)) {
++ ret = 0;
++ goto out;
++ }
++
++ memcpy(eeprom, fw->data, MT7996_EEPROM_SIZE);
++ dev->bin_file_mode = false;
++ dev->flash_mode = true;
++ dev->eeprom_mode = DEFAULT_BIN_MODE;
++ eeprom[MT_EE_TESTMODE_EN] = dev->testmode_enable;
++ dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
++out:
++ release_firmware(fw);
++ return ret;
+ }
+
+ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
+@@ -323,32 +380,7 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
+ int max_path = 5, max_nss = 4;
+ int ret;
+
+- switch (band_idx) {
+- case MT_BAND1:
+- path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
+- eeprom[MT_EE_WIFI_CONF + 2]);
+- rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1,
+- eeprom[MT_EE_WIFI_CONF + 3]);
+- nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
+- eeprom[MT_EE_WIFI_CONF + 5]);
+- break;
+- case MT_BAND2:
+- path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
+- eeprom[MT_EE_WIFI_CONF + 2]);
+- rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2,
+- eeprom[MT_EE_WIFI_CONF + 4]);
+- nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
+- eeprom[MT_EE_WIFI_CONF + 5]);
+- break;
+- default:
+- path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
+- eeprom[MT_EE_WIFI_CONF + 1]);
+- rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0,
+- eeprom[MT_EE_WIFI_CONF + 3]);
+- nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
+- eeprom[MT_EE_WIFI_CONF + 4]);
+- break;
+- }
++ mt7996_parse_eeprom_stream(eeprom, band_idx, &path, &rx_path, &nss);
+
+ if (!path || path > max_path)
+ path = max_path;
+@@ -437,17 +469,8 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
+ return ret;
+
+ ret = mt7996_eeprom_load(dev);
+- if (ret < 0) {
+- if (ret != -EINVAL)
+- return ret;
+-
+- dev_warn(dev->mt76.dev, "eeprom load fail, use default bin\n");
+- dev->bin_file_mode = false;
+- dev->eeprom_mode = DEFAULT_BIN_MODE;
+- ret = mt7996_eeprom_load_default(dev);
+- if (ret)
+- return ret;
+- }
++ if (ret)
++ return ret;
+
+ ret = mt7996_eeprom_load_precal(dev);
+ if (ret)
+diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
+index 8f0f87b6b..03a4fd07d 100644
+--- a/mt7996/eeprom.h
++++ b/mt7996/eeprom.h
+@@ -132,6 +132,38 @@ mt7996_get_channel_group_6g(int channel)
+ return DIV_ROUND_UP(channel - 29, 32);
+ }
+
++static inline void
++mt7996_parse_eeprom_stream(const u8 *eep, int band_idx,
++ u8 *path, u8 *rx_path, u8 *nss)
++{
++ switch (band_idx) {
++ case MT_BAND1:
++ *path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND1,
++ eep[MT_EE_WIFI_CONF + 2]);
++ *rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND1,
++ eep[MT_EE_WIFI_CONF + 3]);
++ *nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND1,
++ eep[MT_EE_WIFI_CONF + 5]);
++ break;
++ case MT_BAND2:
++ *path = FIELD_GET(MT_EE_WIFI_CONF2_TX_PATH_BAND2,
++ eep[MT_EE_WIFI_CONF + 2]);
++ *rx_path = FIELD_GET(MT_EE_WIFI_CONF4_RX_PATH_BAND2,
++ eep[MT_EE_WIFI_CONF + 4]);
++ *nss = FIELD_GET(MT_EE_WIFI_CONF5_STREAM_NUM_BAND2,
++ eep[MT_EE_WIFI_CONF + 5]);
++ break;
++ default:
++ *path = FIELD_GET(MT_EE_WIFI_CONF1_TX_PATH_BAND0,
++ eep[MT_EE_WIFI_CONF + 1]);
++ *rx_path = FIELD_GET(MT_EE_WIFI_CONF3_RX_PATH_BAND0,
++ eep[MT_EE_WIFI_CONF + 3]);
++ *nss = FIELD_GET(MT_EE_WIFI_CONF4_STREAM_NUM_BAND0,
++ eep[MT_EE_WIFI_CONF + 4]);
++ break;
++ }
++}
++
+ enum mt7996_sku_rate_group {
+ SKU_CCK,
+ SKU_OFDM,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index f375a5aba..15751a54b 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3507,7 +3507,7 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
+ &req, sizeof(req), true);
+ }
+
+-static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
++int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
+ {
+ #define MAX_PAGE_IDX_MASK GENMASK(7, 5)
+ #define PAGE_IDX_MASK GENMASK(4, 2)
+@@ -3552,22 +3552,6 @@ static int mt7996_mcu_set_eeprom_flash(struct mt7996_dev *dev)
+ return 0;
+ }
+
+-int mt7996_mcu_set_eeprom(struct mt7996_dev *dev)
+-{
+- struct mt7996_mcu_eeprom req = {
+- .tag = cpu_to_le16(UNI_EFUSE_BUFFER_MODE),
+- .len = cpu_to_le16(sizeof(req) - 4),
+- .buffer_mode = EE_MODE_EFUSE,
+- .format = EE_FORMAT_WHOLE
+- };
+-
+- if (dev->flash_mode)
+- return mt7996_mcu_set_eeprom_flash(dev);
+-
+- return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(EFUSE_CTRL),
+- &req, sizeof(req), true);
+-}
+-
+ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf)
+ {
+ struct mt7996_mcu_eeprom_info req = {
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index fd93db2fc..b2a938162 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -54,15 +54,14 @@
+ #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin"
+
+ #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
++#define MT7996_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7996_eeprom_2i5i6i.bin"
+ #define MT7996_EEPROM_DEFAULT_404 "mediatek/mt7996/mt7996_eeprom_dual_404.bin"
+-#define MT7996_EEPROM_DEFAULT_TM "mediatek/mt7996/mt7996_eeprom_tm.bin"
+ #define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom_2i5i.bin"
+ #define MT7992_EEPROM_DEFAULT_EXT "mediatek/mt7996/mt7992_eeprom_2e5e.bin"
+ #define MT7992_EEPROM_DEFAULT_MIX "mediatek/mt7996/mt7992_eeprom_2i5e.bin"
+ #define MT7992_EEPROM_DEFAULT_24 "mediatek/mt7996/mt7992_eeprom_24_2i5i.bin"
+ #define MT7992_EEPROM_DEFAULT_23 "mediatek/mt7996/mt7992_eeprom_23_2i5i.bin"
+ #define MT7992_EEPROM_DEFAULT_23_EXT "mediatek/mt7996/mt7992_eeprom_23_2e5e.bin"
+-#define MT7992_EEPROM_DEFAULT_TM "mediatek/mt7996/mt7992_eeprom_tm.bin"
+ #define MT7996_EEPROM_SIZE 7680
+ #define MT7996_EEPROM_BLOCK_SIZE 16
+ #define MT7996_TOKEN_SIZE 16384
+diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
+index 3ecce1329..50b2df1ec 100644
+--- a/mt7996/mtk_debugfs.c
++++ b/mt7996/mtk_debugfs.c
+@@ -2827,7 +2827,7 @@ static int mt7996_show_eeprom_mode(struct seq_file *s, void *data)
+ seq_printf(s, " flash mode\n");
+ break;
+ case BIN_FILE_MODE:
+- seq_printf(s, " bin file mode\n filename = %s\n", mt7996_eeprom_name(dev));
++ seq_printf(s, " bin file mode\n filename = %s\n", dev->mt76.bin_file_name);
+ break;
+ default:
+ break;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0031-mtk-wifi-mt76-mt7996-add-vendor-commands-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0031-mtk-wifi-mt76-mt7996-add-vendor-commands-support.patch
new file mode 100644
index 0000000..ade9a1e
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0031-mtk-wifi-mt76-mt7996-add-vendor-commands-support.patch
@@ -0,0 +1,1433 @@
+From 0e813e3d82da805835d53d1af182bd2d700aaafa Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Tue, 13 Dec 2022 15:17:43 +0800
+Subject: [PATCH 031/116] mtk: wifi: mt76: mt7996: add vendor commands support
+
+mtk: wifi: mt76: fix muru_onoff as all enabled by default
+
+Fix muru_onoff default value as 0xF, which means all MU & RU are
+enabled. The purpose of this commit is to align muru_onoff value with
+hostapd and mt76 driver
+
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+
+mtk: wifi: mt76: mt7996: add vendor cmd to get available color bitmap
+
+Add a vendor cmd to notify user space available color bitmap.
+The OBSS BSS color bitmap is maintained in mac80211, so mt76 will make use of that.
+
+Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
+
+mtk: wifi: mt76: mt7996: add vendor subcmd EDCCA ctrl enable
+
+mtk: wifi: mt76: mt7996: add ibf control vendor cmd
+
+Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
+
+mtk: wifi: mt76: mt7996: add three wire pta support
+
+three wire enable bit 0 & 1 for EXT0 & EXT1, respectively
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+mtk: wifi: mt76: mt7996: Add static pp vendor support
+
+Add static pp vendor support for setting pp mode.
+User can enable/disable preamble puncture feature through hostapd
+configuration and hostapd_cli. Driver can receive the nl80211 vendor
+message and convert it to mcu commands.
+
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+Signed-off-by: Allen Ye <allen.ye@mediatek.com>
+---
+ mt76_connac_mcu.h | 2 +
+ mt7996/Makefile | 3 +-
+ mt7996/init.c | 9 +
+ mt7996/mac.c | 4 +
+ mt7996/main.c | 4 +
+ mt7996/mcu.c | 37 ++-
+ mt7996/mcu.h | 14 +
+ mt7996/mt7996.h | 53 +++
+ mt7996/mtk_mcu.c | 87 +++++
+ mt7996/mtk_mcu.h | 15 +
+ mt7996/vendor.c | 805 ++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/vendor.h | 153 +++++++++
+ 12 files changed, 1180 insertions(+), 6 deletions(-)
+ create mode 100644 mt7996/vendor.c
+ create mode 100644 mt7996/vendor.h
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index d8830dc25..2a6091939 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1252,6 +1252,7 @@ enum {
+ MCU_UNI_CMD_REG_ACCESS = 0x0d,
+ MCU_UNI_CMD_CHIP_CONFIG = 0x0e,
+ MCU_UNI_CMD_POWER_CTRL = 0x0f,
++ MCU_UNI_CMD_CFG_SMESH = 0x10,
+ MCU_UNI_CMD_RX_HDR_TRANS = 0x12,
+ MCU_UNI_CMD_SER = 0x13,
+ MCU_UNI_CMD_TWT = 0x14,
+@@ -1284,6 +1285,7 @@ enum {
+ MCU_UNI_CMD_PER_STA_INFO = 0x6d,
+ MCU_UNI_CMD_ALL_STA_INFO = 0x6e,
+ MCU_UNI_CMD_ASSERT_DUMP = 0x6f,
++ MCU_UNI_CMD_PTA_3WIRE_CTRL = 0x78,
+ };
+
+ enum {
+diff --git a/mt7996/Makefile b/mt7996/Makefile
+index 7bb17f440..6643c7a38 100644
+--- a/mt7996/Makefile
++++ b/mt7996/Makefile
+@@ -1,11 +1,12 @@
+ # SPDX-License-Identifier: ISC
+ EXTRA_CFLAGS += -DCONFIG_MT76_LEDS
+ EXTRA_CFLAGS += -DCONFIG_MTK_DEBUG
++EXTRA_CFLAGS += -DCONFIG_MTK_VENDOR
+
+ obj-$(CONFIG_MT7996E) += mt7996e.o
+
+ mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
+- debugfs.o mmio.o
++ debugfs.o mmio.o vendor.o
+
+ mt7996e-$(CONFIG_DEV_COREDUMP) += coredump.o
+ mt7996e-$(CONFIG_NL80211_TESTMODE) += testmode.o
+diff --git a/mt7996/init.c b/mt7996/init.c
+index f1d681787..5cc2e6fbf 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -378,6 +378,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+
+ phy->slottime = 9;
+ phy->beacon_rate = -1;
++ phy->muru_onoff = OFDMA_UL | OFDMA_DL | MUMIMO_DL | MUMIMO_UL;
+
+ hw->sta_data_size = sizeof(struct mt7996_sta);
+ hw->vif_data_size = sizeof(struct mt7996_vif);
+@@ -629,6 +630,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ if (ret)
+ goto error;
+
++#ifdef CONFIG_MTK_VENDOR
++ mt7996_vendor_register(phy);
++#endif
++
+ ret = mt76_register_phy(mphy, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
+ if (ret)
+@@ -1446,6 +1451,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ dev->mt76.test_ops = &mt7996_testmode_ops;
+ #endif
+
++#ifdef CONFIG_MTK_VENDOR
++ mt7996_vendor_register(&dev->phy);
++#endif
++
+ ret = mt76_register_device(&dev->mt76, true, mt76_rates,
+ ARRAY_SIZE(mt76_rates));
+ if (ret)
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index c9f45abef..d55e5a761 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -679,6 +679,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
+ *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ }
++#ifdef CONFIG_MTK_VENDOR
++ if (phy->amnt_ctrl.enable && !ieee80211_is_beacon(fc))
++ mt7996_vendor_amnt_fill_rx(phy, skb);
++#endif
+ } else {
+ status->flag |= RX_FLAG_8023;
+ mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb,
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 1a1f0242c..6d1f61cd0 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -760,6 +760,10 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ mt7996_mac_wtbl_update(dev, idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+
++#ifdef CONFIG_MTK_VENDOR
++ mt7996_vendor_amnt_sta_remove(mvif->phy, sta);
++#endif
++
+ ret = mt7996_mcu_add_sta(dev, vif, sta, true, true);
+ if (ret)
+ return ret;
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 15751a54b..91c2dab1a 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1378,6 +1378,8 @@ static void
+ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta)
+ {
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_phy *phy = mvif->phy;
+ struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
+ struct sta_rec_muru *muru;
+ struct tlv *tlv;
+@@ -1389,11 +1391,14 @@ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
+
+ muru = (struct sta_rec_muru *)tlv;
+- muru->cfg.mimo_dl_en = vif->bss_conf.eht_mu_beamformer ||
+- vif->bss_conf.he_mu_beamformer ||
+- vif->bss_conf.vht_mu_beamformer ||
+- vif->bss_conf.vht_mu_beamformee;
+- muru->cfg.ofdma_dl_en = true;
++ muru->cfg.mimo_dl_en = (vif->bss_conf.eht_mu_beamformer ||
++ vif->bss_conf.he_mu_beamformer ||
++ vif->bss_conf.vht_mu_beamformer ||
++ vif->bss_conf.vht_mu_beamformee) &&
++ !!(phy->muru_onoff & MUMIMO_DL);
++ muru->cfg.mimo_ul_en = !!(phy->muru_onoff & MUMIMO_UL);
++ muru->cfg.ofdma_dl_en = !!(phy->muru_onoff & OFDMA_DL);
++ muru->cfg.ofdma_ul_en = !!(phy->muru_onoff & OFDMA_UL);
+
+ if (sta->deflink.vht_cap.vht_supported)
+ muru->mimo_dl.vht_mu_bfee =
+@@ -4963,3 +4968,25 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(SCS),
+ &req, sizeof(req), false);
+ }
++
++#ifdef CONFIG_MTK_VENDOR
++void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
++{
++ u8 mode, val;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_phy *phy = mvif->phy;
++
++ mode = FIELD_GET(RATE_CFG_MODE, *((u32 *)data));
++ val = FIELD_GET(RATE_CFG_VAL, *((u32 *)data));
++
++ switch (mode) {
++ case RATE_PARAM_AUTO_MU:
++ if (val < 0 || val > 15) {
++ printk("Wrong value! The value is between 0-15.\n");
++ break;
++ }
++ phy->muru_onoff = val;
++ break;
++ }
++}
++#endif
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index 5a60ccc55..2e845e920 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -754,8 +754,20 @@ enum {
+ RATE_PARAM_FIXED_MCS,
+ RATE_PARAM_FIXED_GI = 11,
+ RATE_PARAM_AUTO = 20,
++#ifdef CONFIG_MTK_VENDOR
++ RATE_PARAM_AUTO_MU = 32,
++#endif
+ };
+
++#define RATE_CFG_MODE GENMASK(15, 8)
++#define RATE_CFG_VAL GENMASK(7, 0)
++
++/* MURU */
++#define OFDMA_DL BIT(0)
++#define OFDMA_UL BIT(1)
++#define MUMIMO_DL BIT(2)
++#define MUMIMO_UL BIT(3)
++
+ enum {
+ BF_SOUNDING_ON = 1,
+ BF_HW_EN_UPDATE = 17,
+@@ -833,6 +845,8 @@ mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
+
+ enum {
+ UNI_BAND_CONFIG_RADIO_ENABLE,
++ UNI_BAND_CONFIG_EDCCA_ENABLE = 0x05,
++ UNI_BAND_CONFIG_EDCCA_THRESHOLD = 0x06,
+ UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
+ };
+
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index b2a938162..402327d92 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -258,6 +258,34 @@ struct mt7996_wed_rro_session_id {
+ u16 id;
+ };
+
++#ifdef CONFIG_MTK_VENDOR
++#define MT7996_AIR_MONITOR_MAX_ENTRY 16
++#define MT7996_AIR_MONITOR_MAX_GROUP (MT7996_AIR_MONITOR_MAX_ENTRY >> 1)
++
++struct mt7996_air_monitor_group {
++ bool enable;
++ bool used[2];
++};
++
++struct mt7996_air_monitor_entry {
++ bool enable;
++
++ u8 group_idx;
++ u8 group_used_idx;
++ u8 muar_idx;
++ u8 addr[ETH_ALEN];
++ u32 last_seen;
++ s8 rssi[4];
++ struct ieee80211_sta *sta;
++};
++
++struct mt7996_air_monitor_ctrl {
++ u8 enable;
++ struct mt7996_air_monitor_group group[MT7996_AIR_MONITOR_MAX_GROUP];
++ struct mt7996_air_monitor_entry entry[MT7996_AIR_MONITOR_MAX_ENTRY];
++};
++#endif
++
+ struct mt7996_phy {
+ struct mt76_phy *mt76;
+ struct mt7996_dev *dev;
+@@ -300,6 +328,8 @@ struct mt7996_phy {
+ bool sku_limit_en;
+ bool sku_path_en;
+
++ u8 muru_onoff;
++
+ #ifdef CONFIG_NL80211_TESTMODE
+ struct {
+ u32 *reg_backup;
+@@ -314,6 +344,10 @@ struct mt7996_phy {
+ u8 spe_idx;
+ } test;
+ #endif
++#ifdef CONFIG_MTK_VENDOR
++ spinlock_t amnt_lock;
++ struct mt7996_air_monitor_ctrl amnt_ctrl;
++#endif
+ };
+
+ struct mt7996_dev {
+@@ -740,6 +774,25 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ bool hif2, int *irq);
+ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
+
++#ifdef CONFIG_MTK_VENDOR
++void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
++void mt7996_vendor_register(struct mt7996_phy *phy);
++void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb);
++int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
++ struct ieee80211_sta *sta);
++#endif
++
++int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
++int mt7996_mcu_edcca_threshold_ctrl(struct mt7996_phy *phy, u8 *value, bool set);
++
++enum edcca_bw_id {
++ EDCCA_BW_20 = 0,
++ EDCCA_BW_40,
++ EDCCA_BW_80,
++ EDCCA_BW_160,
++ EDCCA_MAX_BW_NUM,
++};
++
+ #ifdef CONFIG_MTK_DEBUG
+ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
+ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
+diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
+index e56ddd8ff..5c54d02c4 100644
+--- a/mt7996/mtk_mcu.c
++++ b/mt7996/mtk_mcu.c
+@@ -59,4 +59,91 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val)
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &req,
+ sizeof(req), true);
+ }
++
++int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable)
++{
++ struct mt7996_dev *dev = phy->dev;
++ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
++ enum nl80211_band band = chandef->chan->band;
++ struct {
++ u8 band_idx;
++ u8 _rsv[3];
++
++ __le16 tag;
++ __le16 len;
++ u8 enable;
++ u8 std;
++ u8 _rsv2[2];
++ } __packed req = {
++ .band_idx = phy->mt76->band_idx,
++ .tag = cpu_to_le16(UNI_BAND_CONFIG_EDCCA_ENABLE),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .enable = enable,
++ .std = EDCCA_DEFAULT,
++ };
++
++ switch (dev->mt76.region) {
++ case NL80211_DFS_JP:
++ req.std = EDCCA_JAPAN;
++ break;
++ case NL80211_DFS_FCC:
++ if (band == NL80211_BAND_6GHZ)
++ req.std = EDCCA_FCC;
++ break;
++ case NL80211_DFS_ETSI:
++ if (band == NL80211_BAND_6GHZ)
++ req.std = EDCCA_ETSI;
++ break;
++ default:
++ break;
++ }
++
++ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
++ &req, sizeof(req), true);
++}
++
++int mt7996_mcu_edcca_threshold_ctrl(struct mt7996_phy *phy, u8 *value, bool set)
++{
++ struct {
++ u8 band_idx;
++ u8 _rsv[3];
++
++ __le16 tag;
++ __le16 len;
++ u8 threshold[4];
++ bool init;
++ } __packed *res, req = {
++ .band_idx = phy->mt76->band_idx,
++ .tag = cpu_to_le16(UNI_BAND_CONFIG_EDCCA_THRESHOLD),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .init = false,
++ };
++ struct sk_buff *skb;
++ int ret;
++ int i;
++
++ for (i = 0; i < EDCCA_MAX_BW_NUM; i++)
++ req.threshold[i] = value[i];
++
++ if (set)
++ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
++ &req, sizeof(req), true);
++
++ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76,
++ MCU_WM_UNI_CMD_QUERY(BAND_CONFIG),
++ &req, sizeof(req), true, &skb);
++
++ if (ret)
++ return ret;
++
++ res = (void *)skb->data;
++
++ for (i = 0; i < EDCCA_MAX_BW_NUM; i++)
++ value[i] = res->threshold[i];
++
++ dev_kfree_skb(skb);
++
++ return 0;
++}
++
+ #endif
+diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
+index c30418cae..36a58ad63 100644
+--- a/mt7996/mtk_mcu.h
++++ b/mt7996/mtk_mcu.h
+@@ -106,6 +106,21 @@ enum txpower_event {
+ UNI_TXPOWER_PHY_RATE_INFO = 5,
+ };
+
++enum {
++ EDCCA_CTRL_SET_EN = 0,
++ EDCCA_CTRL_SET_THRES,
++ EDCCA_CTRL_GET_EN,
++ EDCCA_CTRL_GET_THRES,
++ EDCCA_CTRL_NUM,
++};
++
++enum {
++ EDCCA_DEFAULT = 0,
++ EDCCA_FCC = 1,
++ EDCCA_ETSI = 2,
++ EDCCA_JAPAN = 3
++};
++
+ #endif
+
+ #endif
+diff --git a/mt7996/vendor.c b/mt7996/vendor.c
+new file mode 100644
+index 000000000..0d6fa7792
+--- /dev/null
++++ b/mt7996/vendor.c
+@@ -0,0 +1,805 @@
++// SPDX-License-Identifier: ISC
++/*
++ * Copyright (C) 2020, MediaTek Inc. All rights reserved.
++ */
++
++#include <net/netlink.h>
++
++#include "mt7996.h"
++#include "mcu.h"
++#include "vendor.h"
++#include "mtk_mcu.h"
++
++static const struct nla_policy
++mu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_MU_CTRL] = {
++ [MTK_VENDOR_ATTR_MU_CTRL_ONOFF] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_MU_CTRL_DUMP] = {.type = NLA_U8 },
++};
++
++static const struct nla_policy
++amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = {
++ [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED },
++ [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED },
++};
++
++static const struct nla_policy
++amnt_set_policy[NUM_MTK_VENDOR_ATTRS_AMNT_SET] = {
++ [MTK_VENDOR_ATTR_AMNT_SET_INDEX] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_AMNT_SET_MACADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
++};
++
++static const struct nla_policy
++amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
++ [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 },
++ [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
++};
++
++static struct nla_policy
++bss_color_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL] = {
++ [MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP] = { .type = NLA_U64 },
++};
++
++static const struct nla_policy
++edcca_ctrl_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL] = {
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_MODE] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC20_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE] = { .type = NLA_S8 },
++ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL] = { .type = NLA_U8 },
++};
++
++static const struct nla_policy
++edcca_dump_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP] = {
++ [MTK_VENDOR_ATTR_EDCCA_DUMP_MODE] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL] = { .type = NLA_U8 },
++};
++
++static const struct nla_policy
++three_wire_ctrl_policy[NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL] = {
++ [MTK_VENDOR_ATTR_3WIRE_CTRL_MODE] = {.type = NLA_U8 },
++};
++
++static const struct nla_policy
++ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
++ [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
++};
++
++static struct nla_policy
++pp_ctrl_policy[NUM_MTK_VENDOR_ATTRS_PP_CTRL] = {
++ [MTK_VENDOR_ATTR_PP_MODE] = { .type = NLA_U8 },
++ [MTK_VENDOR_ATTR_PP_BAND_IDX] = { .type = NLA_U8 },
++};
++
++struct mt7996_amnt_data {
++ u8 idx;
++ u8 addr[ETH_ALEN];
++ s8 rssi[4];
++ u32 last_seen;
++};
++
++static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
++ struct wireless_dev *wdev,
++ const void *data,
++ int data_len)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_MU_CTRL];
++ int err;
++ u8 val8;
++ u32 val32 = 0;
++
++ err = nla_parse(tb, MTK_VENDOR_ATTR_MU_CTRL_MAX, data, data_len,
++ mu_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF]) {
++ val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF]);
++ val32 |= FIELD_PREP(RATE_CFG_MODE, RATE_PARAM_AUTO_MU) |
++ FIELD_PREP(RATE_CFG_VAL, val8);
++ ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
++ mt7996_set_wireless_vif, &val32);
++ }
++
++ return 0;
++}
++
++static int
++mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
++ struct sk_buff *skb, const void *data, int data_len,
++ unsigned long *storage)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ int len = 0;
++
++ if (*storage == 1)
++ return -ENOENT;
++ *storage = 1;
++
++ if (nla_put_u8(skb, MTK_VENDOR_ATTR_MU_CTRL_DUMP, phy->muru_onoff))
++ return -ENOMEM;
++ len += 1;
++
++ return len;
++}
++
++void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb)
++{
++ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
++ struct mt7996_air_monitor_ctrl *ctrl = &phy->amnt_ctrl;
++ struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
++ __le16 fc = hdr->frame_control;
++ u8 addr[ETH_ALEN];
++ int i;
++
++ if (!ieee80211_has_fromds(fc))
++ ether_addr_copy(addr, hdr->addr2);
++ else if (ieee80211_has_tods(fc))
++ ether_addr_copy(addr, hdr->addr4);
++ else
++ ether_addr_copy(addr, hdr->addr3);
++
++ spin_lock_bh(&phy->amnt_lock);
++ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++) {
++ struct mt7996_air_monitor_entry *entry;
++
++ if (ether_addr_equal(addr, ctrl->entry[i].addr)) {
++ entry = &ctrl->entry[i];
++ entry->rssi[0] = status->chain_signal[0];
++ entry->rssi[1] = status->chain_signal[1];
++ entry->rssi[2] = status->chain_signal[2];
++ entry->rssi[3] = status->chain_signal[3];
++ entry->last_seen = jiffies;
++ break;
++ }
++ }
++ spin_unlock_bh(&phy->amnt_lock);
++}
++
++static int
++mt7996_vendor_smesh_ctrl(struct mt7996_phy *phy, u8 write,
++ u8 enable, u8 *value)
++{
++#define UNI_CMD_SMESH_PARAM 0
++ struct mt7996_dev *dev = phy->dev;
++ struct smesh_param {
++ __le16 tag;
++ __le16 length;
++
++ u8 enable;
++ bool a2;
++ bool a1;
++ bool data;
++ bool mgnt;
++ bool ctrl;
++ u8 padding[2];
++ } req = {
++ .tag = cpu_to_le16(UNI_CMD_SMESH_PARAM),
++ .length = cpu_to_le16(sizeof(req) - 4),
++
++ .enable = enable,
++ .a2 = true,
++ .a1 = true,
++ .data = true,
++ .mgnt = false,
++ .ctrl = false,
++ };
++ struct smesh_param *res;
++ struct sk_buff *skb;
++ int ret = 0;
++
++ if (!value)
++ return -EINVAL;
++
++ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD(CFG_SMESH),
++ &req, sizeof(req), !write, &skb);
++
++ if (ret || write)
++ return ret;
++
++ res = (struct smesh_param *) skb->data;
++
++ *value = res->enable;
++
++ dev_kfree_skb(skb);
++
++ return 0;
++}
++
++static int
++mt7996_vendor_amnt_muar(struct mt7996_phy *phy, u8 muar_idx, u8 *addr)
++{
++#define UNI_CMD_MUAR_ENTRY 2
++ struct mt7996_dev *dev = phy->dev;
++ struct muar_entry {
++ __le16 tag;
++ __le16 length;
++
++ bool smesh;
++ u8 hw_bss_index;
++ u8 muar_idx;
++ u8 entry_add;
++ u8 mac_addr[6];
++ u8 padding[2];
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_CMD_MUAR_ENTRY),
++ .length = cpu_to_le16(sizeof(req) - 4),
++
++ .smesh = true,
++ .hw_bss_index = phy != &dev->phy,
++ .muar_idx = muar_idx,
++ .entry_add = 1,
++ };
++
++ ether_addr_copy(req.mac_addr, addr);
++ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REPT_MUAR), &req,
++ sizeof(req), true);
++}
++
++static int
++mt7996_vendor_amnt_set_en(struct mt7996_phy *phy, u8 enable)
++{
++ u8 status;
++ int ret;
++
++ ret = mt7996_vendor_smesh_ctrl(phy, 0, enable, &status);
++ if (ret)
++ return ret;
++
++ if (status == enable)
++ return 0;
++
++ ret = mt7996_vendor_smesh_ctrl(phy, 1, enable, &status);
++ if (ret)
++ return ret;
++
++ return 0;
++}
++
++static int
++mt7996_vendor_amnt_set_addr(struct mt7996_phy *phy, u8 index, u8 *addr)
++{
++ struct mt7996_air_monitor_ctrl *amnt_ctrl = &phy->amnt_ctrl;
++ struct mt7996_air_monitor_group *group;
++ struct mt7996_air_monitor_entry *entry;
++ int ret, i, j;
++
++ if (index >= MT7996_AIR_MONITOR_MAX_ENTRY)
++ return -1;
++
++ spin_lock_bh(&phy->amnt_lock);
++ entry = &amnt_ctrl->entry[index];
++ if (!is_zero_ether_addr(addr)) {
++ if (entry->enable == false) {
++ for (i = 0; i < MT7996_AIR_MONITOR_MAX_GROUP; i++) {
++ group = &(amnt_ctrl->group[i]);
++ if (group->used[0] == false)
++ j = 0;
++ else if (group->used[1] == false)
++ j = 1;
++ else
++ continue;
++
++ group->enable = true;
++ group->used[j] = true;
++ entry->enable = true;
++ entry->group_idx = i;
++ entry->group_used_idx = j;
++ entry->muar_idx = 32 + 4 * i + 2 * j;
++ break;
++ }
++ }
++ } else {
++ group = &(amnt_ctrl->group[entry->group_idx]);
++
++ group->used[entry->group_used_idx] = false;
++ if (group->used[0] == false && group->used[1] == false)
++ group->enable = false;
++
++ entry->enable = false;
++ }
++ ether_addr_copy(entry->addr, addr);
++ amnt_ctrl->enable &= ~(1 << entry->group_idx);
++ amnt_ctrl->enable |= entry->enable << entry->group_idx;
++ spin_unlock_bh(&phy->amnt_lock);
++
++ ret = mt7996_vendor_amnt_muar(phy, entry->muar_idx, addr);
++ if (ret)
++ return ret;
++
++ return mt7996_vendor_amnt_set_en(phy, amnt_ctrl->enable);
++}
++
++static int
++mt7966_vendor_amnt_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
++ const void *data, int data_len)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
++ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_SET];
++ u8 index = 0;
++ u8 mac_addr[ETH_ALEN];
++ int err;
++
++ err = nla_parse(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, data, data_len,
++ amnt_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_SET])
++ return -EINVAL;
++
++ err = nla_parse_nested(tb2, MTK_VENDOR_ATTR_AMNT_SET_MAX,
++ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_SET], amnt_set_policy, NULL);
++
++ if (!tb2[MTK_VENDOR_ATTR_AMNT_SET_INDEX] ||
++ !tb2[MTK_VENDOR_ATTR_AMNT_SET_MACADDR])
++ return -EINVAL;
++
++ index = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_SET_INDEX]);
++ memcpy(mac_addr, nla_data(tb2[MTK_VENDOR_ATTR_AMNT_SET_MACADDR]), ETH_ALEN);
++
++ return mt7996_vendor_amnt_set_addr(phy, index, mac_addr);
++}
++
++int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
++ struct ieee80211_sta *sta)
++{
++ u8 zero[ETH_ALEN] = {};
++ int i;
++
++ if (!phy->amnt_ctrl.enable)
++ return 0;
++
++ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++)
++ if (ether_addr_equal(sta->addr, phy->amnt_ctrl.entry[i].addr))
++ return mt7996_vendor_amnt_set_addr(phy, i, zero);
++ return 0;
++}
++
++static int
++mt7996_amnt_dump(struct mt7996_phy *phy, struct sk_buff *skb,
++ u8 amnt_idx, int *attrtype)
++{
++ struct mt7996_air_monitor_entry *entry;
++ struct mt7996_amnt_data data;
++ u32 last_seen = 0;
++
++ spin_lock_bh(&phy->amnt_lock);
++ entry = &phy->amnt_ctrl.entry[amnt_idx];
++ if (entry->enable == 0) {
++ spin_unlock_bh(&phy->amnt_lock);
++ return 0;
++ }
++
++ last_seen = jiffies_to_msecs(jiffies - entry->last_seen);
++ ether_addr_copy(data.addr, entry->addr);
++ data.rssi[0] = entry->rssi[0];
++ data.rssi[1] = entry->rssi[1];
++ data.rssi[2] = entry->rssi[2];
++ data.rssi[3] = entry->rssi[3];
++ spin_unlock_bh(&phy->amnt_lock);
++
++ data.idx = amnt_idx;
++ data.last_seen = last_seen;
++
++ nla_put(skb, (*attrtype)++, sizeof(struct mt7996_amnt_data), &data);
++
++ return 1;
++}
++
++static int
++mt7966_vendor_amnt_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
++ struct sk_buff *skb, const void *data, int data_len,
++ unsigned long *storage)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
++ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP];
++ void *a, *b;
++ int err = 0, attrtype = 0, i, len = 0;
++ u8 amnt_idx;
++
++ if (*storage == 1)
++ return -ENOENT;
++ *storage = 1;
++
++ err = nla_parse(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, data, data_len,
++ amnt_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP])
++ return -EINVAL;
++
++ err = nla_parse_nested(tb2, MTK_VENDOR_ATTR_AMNT_DUMP_MAX,
++ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP],
++ amnt_dump_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_INDEX])
++ return -EINVAL;
++
++ amnt_idx = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_INDEX]);
++
++ a = nla_nest_start(skb, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP);
++ b = nla_nest_start(skb, MTK_VENDOR_ATTR_AMNT_DUMP_RESULT);
++
++ if (amnt_idx != 0xff) {
++ len += mt7996_amnt_dump(phy, skb, amnt_idx, &attrtype);
++ } else {
++ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++)
++ len += mt7996_amnt_dump(phy, skb, i, &attrtype);
++ }
++
++ nla_nest_end(skb, b);
++
++ nla_put_u8(skb, MTK_VENDOR_ATTR_AMNT_DUMP_LEN, len);
++
++ nla_nest_end(skb, a);
++
++ return len + 1;
++}
++
++static int
++mt7996_vendor_bss_color_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
++ struct sk_buff *skb, const void *data, int data_len,
++ unsigned long *storage)
++{
++ struct ieee80211_vif *vif = wdev_to_ieee80211_vif(wdev);
++ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
++ int len = 0;
++
++ if (*storage == 1)
++ return -ENOENT;
++ *storage = 1;
++
++ if (nla_put_u64_64bit(skb, MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP,
++ ~bss_conf->used_color_bitmap, NL80211_ATTR_PAD))
++ return -ENOMEM;
++ len += 1;
++
++ return len;
++}
++
++static int mt7996_vendor_edcca_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
++ const void *data, int data_len)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL];
++ int err;
++ u8 edcca_mode;
++ u8 edcca_value[EDCCA_MAX_BW_NUM];
++
++ err = nla_parse(tb, MTK_VENDOR_ATTR_EDCCA_CTRL_MAX, data, data_len,
++ edcca_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE])
++ return -EINVAL;
++
++ edcca_mode = nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE]);
++ if (edcca_mode == EDCCA_CTRL_SET_EN) {
++ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL])
++ return -EINVAL;
++
++ edcca_value[0] =
++ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL]);
++
++ err = mt7996_mcu_edcca_enable(phy, !!edcca_value[0]);
++ if (err)
++ return err;
++ } else if (edcca_mode == EDCCA_CTRL_SET_THRES) {
++ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL] ||
++ !tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL] ||
++ !tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL] ||
++ !tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL]) {
++ return -EINVAL;
++ }
++ edcca_value[EDCCA_BW_20] =
++ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL]);
++ edcca_value[EDCCA_BW_40] =
++ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL]);
++ edcca_value[EDCCA_BW_80] =
++ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL]);
++ edcca_value[EDCCA_BW_160] =
++ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL]);
++
++ err = mt7996_mcu_edcca_threshold_ctrl(phy, edcca_value, true);
++
++ if (err)
++ return err;
++ } else {
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++
++static int
++mt7996_vendor_edcca_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
++ struct sk_buff *skb, const void *data, int data_len,
++ unsigned long *storage)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL];
++ int err;
++ u8 edcca_mode;
++ u8 value[EDCCA_MAX_BW_NUM];
++
++ if (*storage == 1)
++ return -ENOENT;
++ *storage = 1;
++
++ err = nla_parse(tb, MTK_VENDOR_ATTR_EDCCA_CTRL_MAX, data, data_len,
++ edcca_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE])
++ return -EINVAL;
++
++ edcca_mode = nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE]);
++
++ if (edcca_mode != EDCCA_CTRL_GET_THRES)
++ return -EINVAL;
++
++ err = mt7996_mcu_edcca_threshold_ctrl(phy, value, false);
++
++ if (err)
++ return err;
++
++ if (nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL, value[EDCCA_BW_20]) ||
++ nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL, value[EDCCA_BW_40]) ||
++ nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL, value[EDCCA_BW_80]) ||
++ nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL, value[EDCCA_BW_160]))
++ return -ENOMEM;
++
++ return EDCCA_MAX_BW_NUM;
++}
++
++static int mt7996_vendor_3wire_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
++ const void *data, int data_len)
++{
++#define UNI_3WIRE_EXT_EN 0
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL];
++ struct {
++ u8 __rsv1[4];
++
++ __le16 tag;
++ __le16 len;
++ u8 three_wire_mode;
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_3WIRE_EXT_EN),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ };
++ int err;
++
++ err = nla_parse(tb, MTK_VENDOR_ATTR_3WIRE_CTRL_MAX, data, data_len,
++ three_wire_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb[MTK_VENDOR_ATTR_3WIRE_CTRL_MODE])
++ return -EINVAL;
++
++ req.three_wire_mode = nla_get_u8(tb[MTK_VENDOR_ATTR_3WIRE_CTRL_MODE]);
++
++ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PTA_3WIRE_CTRL), &req,
++ sizeof(req), false);
++}
++
++static int mt7996_vendor_ibf_ctrl(struct wiphy *wiphy,
++ struct wireless_dev *wdev,
++ const void *data,
++ int data_len)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_dev *dev = phy->dev;
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_IBF_CTRL];
++ int err;
++ u8 val;
++
++ err = nla_parse(tb, MTK_VENDOR_ATTR_IBF_CTRL_MAX, data, data_len,
++ ibf_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (tb[MTK_VENDOR_ATTR_IBF_CTRL_ENABLE]) {
++ val = nla_get_u8(tb[MTK_VENDOR_ATTR_IBF_CTRL_ENABLE]);
++
++ dev->ibf = !!val;
++
++ err = mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
++ if (err)
++ return err;
++ }
++ return 0;
++}
++
++static int
++mt7996_vendor_ibf_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
++ struct sk_buff *skb, const void *data, int data_len,
++ unsigned long *storage)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_dev *dev = phy->dev;
++
++ if (*storage == 1)
++ return -ENOENT;
++ *storage = 1;
++
++ if (nla_put_u8(skb, MTK_VENDOR_ATTR_IBF_DUMP_ENABLE, dev->ibf))
++ return -ENOMEM;
++
++ return 1;
++}
++
++static int mt7996_vendor_pp_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
++ const void *data, int data_len)
++{
++ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_PP_CTRL];
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_phy *phy;
++ struct mt76_phy *mphy;
++ struct cfg80211_chan_def *chandef;
++ int err;
++ u8 val8, band_idx = 0;
++
++ err = nla_parse(tb, MTK_VENDOR_ATTR_PP_CTRL_MAX, data, data_len,
++ pp_ctrl_policy, NULL);
++
++ if (tb[MTK_VENDOR_ATTR_PP_BAND_IDX]) {
++ band_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_BAND_IDX]);
++ }
++
++ if (!mt7996_band_valid(dev, band_idx))
++ goto error;
++
++ mphy = dev->mt76.phys[band_idx];
++ if (!mphy)
++ goto error;
++
++ phy = (struct mt7996_phy *)mphy->priv;
++ if (!phy)
++ goto error;
++
++ chandef = &phy->chanctx->chandef;
++ if (!chandef)
++ goto error;
++
++ if (chandef->chan->band == NL80211_BAND_2GHZ)
++ return 0;
++
++ if (tb[MTK_VENDOR_ATTR_PP_MODE]) {
++ val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_MODE]);
++ switch (val8) {
++ case PP_DISABLE:
++ case PP_FW_MODE:
++ err = mt7996_mcu_set_pp_en(phy, val8, 0);
++ break;
++ case PP_USR_MODE:
++ /* handled by add_chanctx */
++ err = 0;
++ break;
++ default:
++ err = -EINVAL;
++ }
++ }
++
++ return err;
++error:
++ dev_err(dev->mt76.dev, "Invalid band idx: %d\n", band_idx);
++ return -EINVAL;
++}
++
++static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_MU_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .doit = mt7996_vendor_mu_ctrl,
++ .dumpit = mt7996_vendor_mu_ctrl_dump,
++ .policy = mu_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_MU_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .doit = mt7966_vendor_amnt_ctrl,
++ .dumpit = mt7966_vendor_amnt_ctrl_dump,
++ .policy = amnt_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .dumpit = mt7996_vendor_bss_color_ctrl_dump,
++ .policy = bss_color_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .doit = mt7996_vendor_edcca_ctrl,
++ .dumpit = mt7996_vendor_edcca_ctrl_dump,
++ .policy = edcca_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_EDCCA_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .doit = mt7996_vendor_3wire_ctrl,
++ .policy = three_wire_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_3WIRE_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .doit = mt7996_vendor_ibf_ctrl,
++ .dumpit = mt7996_vendor_ibf_ctrl_dump,
++ .policy = ibf_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_IBF_CTRL_MAX,
++ },
++ {
++ .info = {
++ .vendor_id = MTK_NL80211_VENDOR_ID,
++ .subcmd = MTK_NL80211_VENDOR_SUBCMD_PP_CTRL,
++ },
++ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
++ WIPHY_VENDOR_CMD_NEED_RUNNING,
++ .doit = mt7996_vendor_pp_ctrl,
++ .policy = pp_ctrl_policy,
++ .maxattr = MTK_VENDOR_ATTR_PP_CTRL_MAX,
++ },
++};
++
++void mt7996_vendor_register(struct mt7996_phy *phy)
++{
++ phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
++ phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
++
++ spin_lock_init(&phy->amnt_lock);
++}
+diff --git a/mt7996/vendor.h b/mt7996/vendor.h
+new file mode 100644
+index 000000000..8aaa18eec
+--- /dev/null
++++ b/mt7996/vendor.h
+@@ -0,0 +1,153 @@
++#ifndef __MT7996_VENDOR_H
++#define __MT7996_VENDOR_H
++
++#define MTK_NL80211_VENDOR_ID 0x0ce7
++
++enum mtk_nl80211_vendor_subcmds {
++ MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
++ MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
++ MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL = 0xc7,
++ MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL = 0xc8,
++ MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
++ MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
++ MTK_NL80211_VENDOR_SUBCMD_PP_CTRL = 0xcc,
++};
++
++enum mtk_vendor_attr_edcca_ctrl {
++ MTK_VENDOR_ATTR_EDCCA_THRESHOLD_INVALID = 0,
++
++ MTK_VENDOR_ATTR_EDCCA_CTRL_MODE,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC20_VAL,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL,
++ MTK_VENDOR_ATTR_EDCCA_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL - 1
++};
++
++enum mtk_vendor_attr_edcca_dump {
++ MTK_VENDOR_ATTR_EDCCA_DUMP_UNSPEC = 0,
++
++ MTK_VENDOR_ATTR_EDCCA_DUMP_MODE,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP,
++ MTK_VENDOR_ATTR_EDCCA_DUMP_MAX =
++ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP - 1
++};
++
++enum mtk_vendor_attr_3wire_ctrl {
++ MTK_VENDOR_ATTR_3WIRE_CTRL_UNSPEC,
++
++ MTK_VENDOR_ATTR_3WIRE_CTRL_MODE,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL,
++ MTK_VENDOR_ATTR_3WIRE_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL - 1
++};
++
++enum mtk_vendor_attr_mu_ctrl {
++ MTK_VENDOR_ATTR_MU_CTRL_UNSPEC,
++
++ MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
++ MTK_VENDOR_ATTR_MU_CTRL_DUMP,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_MU_CTRL,
++ MTK_VENDOR_ATTR_MU_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_MU_CTRL - 1
++};
++
++enum mtk_vendor_attr_mnt_ctrl {
++ MTK_VENDOR_ATTR_AMNT_CTRL_UNSPEC,
++
++ MTK_VENDOR_ATTR_AMNT_CTRL_SET,
++ MTK_VENDOR_ATTR_AMNT_CTRL_DUMP,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_AMNT_CTRL,
++ MTK_VENDOR_ATTR_AMNT_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_AMNT_CTRL - 1
++};
++
++enum mtk_vendor_attr_mnt_set {
++ MTK_VENDOR_ATTR_AMNT_SET_UNSPEC,
++
++ MTK_VENDOR_ATTR_AMNT_SET_INDEX,
++ MTK_VENDOR_ATTR_AMNT_SET_MACADDR,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_AMNT_SET,
++ MTK_VENDOR_ATTR_AMNT_SET_MAX =
++ NUM_MTK_VENDOR_ATTRS_AMNT_SET - 1
++};
++
++enum mtk_vendor_attr_mnt_dump {
++ MTK_VENDOR_ATTR_AMNT_DUMP_UNSPEC,
++
++ MTK_VENDOR_ATTR_AMNT_DUMP_INDEX,
++ MTK_VENDOR_ATTR_AMNT_DUMP_LEN,
++ MTK_VENDOR_ATTR_AMNT_DUMP_RESULT,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_AMNT_DUMP,
++ MTK_VENDOR_ATTR_AMNT_DUMP_MAX =
++ NUM_MTK_VENDOR_ATTRS_AMNT_DUMP - 1
++};
++
++enum mtk_vendor_attr_bss_color_ctrl {
++ MTK_VENDOR_ATTR_BSS_COLOR_CTRL_UNSPEC,
++
++ MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL,
++ MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL - 1
++};
++
++enum mtk_vendor_attr_ibf_ctrl {
++ MTK_VENDOR_ATTR_IBF_CTRL_UNSPEC,
++
++ MTK_VENDOR_ATTR_IBF_CTRL_ENABLE,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_IBF_CTRL,
++ MTK_VENDOR_ATTR_IBF_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_IBF_CTRL - 1
++};
++
++enum mtk_vendor_attr_ibf_dump {
++ MTK_VENDOR_ATTR_IBF_DUMP_UNSPEC,
++
++ MTK_VENDOR_ATTR_IBF_DUMP_ENABLE,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_IBF_DUMP,
++ MTK_VENDOR_ATTR_IBF_DUMP_MAX =
++ NUM_MTK_VENDOR_ATTRS_IBF_DUMP - 1
++};
++
++enum mtk_vendor_attr_pp_ctrl {
++ MTK_VENDOR_ATTR_PP_CTRL_UNSPEC,
++
++ MTK_VENDOR_ATTR_PP_MODE,
++ MTK_VENDOR_ATTR_PP_BAND_IDX,
++
++ /* keep last */
++ NUM_MTK_VENDOR_ATTRS_PP_CTRL,
++ MTK_VENDOR_ATTR_PP_CTRL_MAX =
++ NUM_MTK_VENDOR_ATTRS_PP_CTRL - 1
++};
++
++#endif
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1016-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0032-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch
similarity index 91%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1016-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0032-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch
index edd7ca9..87e3e08 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1016-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0032-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch
@@ -1,8 +1,7 @@
-From 69f8be02d97e911e0a844ac5a1a239a848d41930 Mon Sep 17 00:00:00 2001
+From 0b8743892c4e39e7ba7f2c248ee8929f6c599e76 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Fri, 19 May 2023 14:56:07 +0800
-Subject: [PATCH 1016/1044] mtk: wifi: mt76: mt7996: add debugfs for fw
- coredump.
+Subject: [PATCH 032/116] mtk: wifi: mt76: mt7996: add debugfs for fw coredump.
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
---
@@ -13,7 +12,7 @@
4 files changed, 56 insertions(+), 5 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index ea78166b..7a03de12 100644
+index 344c759c0..3074202bb 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
@@ -84,6 +84,8 @@ mt7996_sys_recovery_set(struct file *file, const char __user *user_buf,
@@ -65,7 +64,7 @@
desc += scnprintf(buff + desc, bufsz - desc,
"\nlet's dump firmware SER statistics...\n");
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index d55e5a76..1c1b3eb5 100644
+index d55e5a761..1c1b3eb51 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -2080,15 +2080,36 @@ void mt7996_mac_dump_work(struct work_struct *work)
@@ -117,10 +116,10 @@
}
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 68bf82fc..35f757dc 100644
+index 2e845e920..cb7260fb3 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
-@@ -956,7 +956,11 @@ enum {
+@@ -958,7 +958,11 @@ enum {
UNI_CMD_SER_SET_RECOVER_L3_BF,
UNI_CMD_SER_SET_RECOVER_L4_MDP,
UNI_CMD_SER_SET_RECOVER_FULL,
@@ -133,10 +132,10 @@
UNI_CMD_SER_ENABLE = 1,
UNI_CMD_SER_SET,
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 09ce3c35..dd9aa9e2 100644
+index 402327d92..623b782c9 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -139,6 +139,14 @@ enum mt7996_ram_type {
+@@ -138,6 +138,14 @@ enum mt7996_ram_type {
__MT7996_RAM_TYPE_MAX,
};
@@ -151,7 +150,7 @@
enum mt7996_txq_id {
MT7996_TXQ_FWDL = 16,
MT7996_TXQ_MCU_WM,
-@@ -388,6 +396,7 @@ struct mt7996_dev {
+@@ -393,6 +401,7 @@ struct mt7996_dev {
/* protects coredump data */
struct mutex dump_mutex;
@@ -159,7 +158,7 @@
#ifdef CONFIG_DEV_COREDUMP
struct {
struct mt7996_crash_data *crash_data[__MT7996_RAM_TYPE_MAX];
-@@ -573,6 +582,7 @@ void mt7996_init_txpower(struct mt7996_phy *phy);
+@@ -580,6 +589,7 @@ void mt7996_init_txpower(struct mt7996_phy *phy);
int mt7996_txbf_init(struct mt7996_dev *dev);
int mt7996_get_chip_sku(struct mt7996_dev *dev);
void mt7996_reset(struct mt7996_dev *dev);
@@ -168,5 +167,5 @@
int mt7996_mcu_init(struct mt7996_dev *dev);
int mt7996_mcu_init_firmware(struct mt7996_dev *dev);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1017-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0033-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch
similarity index 91%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1017-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0033-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch
index f9e72ad..d0aa9bb 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1017-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0033-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch
@@ -1,20 +1,21 @@
-From 1be676a268fc923a68d8b0338b104f1ac76e0838 Mon Sep 17 00:00:00 2001
+From 7582fc5bf2165b744eb41631f3892969ca6b510c Mon Sep 17 00:00:00 2001
From: Rex Lu <rex.lu@mediatek.com>
Date: Mon, 25 Dec 2023 15:17:49 +0800
-Subject: [PATCH 1017/1044] mtk: wifi: mt76: mt7996: Add mt7992 coredump
- support
+Subject: [PATCH 033/116] mtk: wifi: mt76: mt7996: Add mt7992 coredump support
1. Add mt7992 coredump support
2. fixed if new ic have not support coredump, it may cause crash when remove module
+CR-Id: WCNCR00259516
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
+Change-Id: I2ae5425aac6be8ff69a2c411e796be308b558b6b
---
mt7996/coredump.c | 80 ++++++++++++++++++++++++++++++++++++++---------
mt7996/mt7996.h | 1 +
2 files changed, 67 insertions(+), 14 deletions(-)
diff --git a/mt7996/coredump.c b/mt7996/coredump.c
-index a7f91b56..d09bcd4b 100644
+index a7f91b56d..d09bcd4bd 100644
--- a/mt7996/coredump.c
+++ b/mt7996/coredump.c
@@ -67,6 +67,44 @@ static const struct mt7996_mem_region mt7996_wa_mem_regions[] = {
@@ -147,10 +148,10 @@
}
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index dd9aa9e2..7ca9d57e 100644
+index 623b782c9..97425a025 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -230,6 +230,7 @@ struct mt7996_vif {
+@@ -229,6 +229,7 @@ struct mt7996_vif {
struct mt7996_crash_data {
guid_t guid;
struct timespec64 timestamp;
@@ -159,5 +160,5 @@
u8 *memdump_buf;
size_t memdump_buf_len;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1018-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0034-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch
similarity index 79%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1018-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0034-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch
index b7304e5..8688630 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1018-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0034-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch
@@ -1,8 +1,8 @@
-From 839e8ed5ee7eb48dd885a1f8f26a8ea9b27517ca Mon Sep 17 00:00:00 2001
+From 4982c35a7957ef3a6b9ec0985544a4245b5d5f14 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Tue, 6 Jun 2023 16:57:10 +0800
-Subject: [PATCH 1018/1044] mtk: wifi: mt76: mt7996: add support for runtime
- set in-band discovery
+Subject: [PATCH 034/116] mtk: wifi: mt76: mt7996: add support for runtime set
+ in-band discovery
with this patch, AP can runtime set inband discovery via hostapd_cli
@@ -17,10 +17,10 @@
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 8348d22a..cd7f58c3 100644
+index 91c2dab1a..94c5da5e8 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -2605,8 +2605,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+@@ -2609,8 +2609,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
if (IS_ERR(rskb))
return PTR_ERR(rskb);
@@ -30,7 +30,7 @@
interval = vif->bss_conf.fils_discovery.max_interval;
skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
-@@ -2641,7 +2640,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+@@ -2645,7 +2644,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
discov->tx_interval = interval;
discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
@@ -40,5 +40,5 @@
buf = (u8 *)tlv + sizeof(*discov);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1020-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0035-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1020-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0035-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch
index 0ae3fc9..4b4c28f 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1020-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0035-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch
@@ -1,7 +1,7 @@
-From 090298f97be235c284e47dc8302a39da2f1fa855 Mon Sep 17 00:00:00 2001
+From e4af7a0b0c39e05e0bded3de7b63831cd9b5dd97 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Mon, 10 Jul 2023 11:47:29 +0800
-Subject: [PATCH 1020/1044] mtk: wifi: mt76: mt7996: add support spatial reuse
+Subject: [PATCH 035/116] mtk: wifi: mt76: mt7996: add support spatial reuse
debug commands
This commit adds the following debug commands in debugfs:
@@ -16,6 +16,7 @@
To learn more details of these commands, please check:
https://wiki.mediatek.inc/display/APKB/mt76+Phy+feature+debug+Cheetsheet#mt76PhyfeaturedebugCheetsheet-SpatialReuse
+Change-Id: I5bf83013ea2788dfc93caaaef08486a4f97a3649
---
mt76_connac_mcu.h | 1 +
mt7996/main.c | 6 +++
@@ -27,7 +28,7 @@
7 files changed, 270 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 062268d6..9edb580c 100644
+index 2a6091939..864a802d7 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1040,6 +1040,7 @@ enum {
@@ -39,7 +40,7 @@
MCU_UNI_EVENT_TX_DONE = 0x2d,
MCU_UNI_EVENT_BF = 0x33,
diff --git a/mt7996/main.c b/mt7996/main.c
-index 478ca7ce..9ca37e1e 100644
+index 6d1f61cd0..f8ac51707 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
@@ -6,6 +6,9 @@
@@ -52,7 +53,7 @@
static bool mt7996_dev_running(struct mt7996_dev *dev)
{
-@@ -78,6 +81,9 @@ int mt7996_run(struct ieee80211_hw *hw)
+@@ -86,6 +89,9 @@ int mt7996_run(struct ieee80211_hw *hw)
goto out;
#ifdef CONFIG_MTK_DEBUG
@@ -60,13 +61,13 @@
+ phy->enhanced_sr_enable = true;
+
ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
- !dev->dbg.sku_disable);
- #else
+ dev->dbg.sku_disable ? 0 : phy->sku_limit_en);
+
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index cd7f58c3..16341a41 100644
+index 94c5da5e8..0be5a880f 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -712,6 +712,14 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -717,6 +717,14 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_WED_RRO:
mt7996_mcu_wed_rro_event(dev, skb);
break;
@@ -82,10 +83,10 @@
case MCU_UNI_EVENT_TESTMODE_CTRL:
mt7996_tm_rf_test_event(dev, skb);
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index cfa50bfe..adb0cdd1 100644
+index 97425a025..c06aae960 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -352,6 +352,10 @@ struct mt7996_phy {
+@@ -357,6 +357,10 @@ struct mt7996_phy {
spinlock_t amnt_lock;
struct mt7996_air_monitor_ctrl amnt_ctrl;
#endif
@@ -96,7 +97,7 @@
};
struct mt7996_dev {
-@@ -800,6 +804,8 @@ enum edcca_bw_id {
+@@ -807,6 +811,8 @@ enum edcca_bw_id {
#ifdef CONFIG_MTK_DEBUG
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
@@ -106,10 +107,10 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 09652ef5..ed01c089 100644
+index 50b2df1ec..9dc6ea778 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -2777,6 +2777,83 @@ static int mt7996_show_eeprom_mode(struct seq_file *s, void *data)
+@@ -2836,6 +2836,83 @@ static int mt7996_show_eeprom_mode(struct seq_file *s, void *data)
return 0;
}
@@ -193,7 +194,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -2856,6 +2933,11 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -2915,6 +2992,11 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
debugfs_create_file("scs_enable", 0200, dir, phy, &fops_scs_enable);
@@ -206,7 +207,7 @@
}
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index 5c54d02c..dbdf8d80 100644
+index 5c54d02c4..dbdf8d809 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
@@ -146,4 +146,115 @@ int mt7996_mcu_edcca_threshold_ctrl(struct mt7996_phy *phy, u8 *value, bool set)
@@ -326,7 +327,7 @@
+}
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index 36a58ad6..098e63ae 100644
+index 36a58ad63..098e63aef 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
@@ -121,6 +121,62 @@ enum {
@@ -393,5 +394,5 @@
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1021-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0036-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch
similarity index 73%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1021-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0036-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch
index bb58282..5ea0ac5 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1021-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0036-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch
@@ -1,14 +1,14 @@
-From 424dc1cf297e6bf20ed5c430d215f64517178270 Mon Sep 17 00:00:00 2001
+From 6888c8da2d1620dcd3a85834b07faef4a90c64b2 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Tue, 1 Aug 2023 16:02:28 +0800
-Subject: [PATCH 1021/1044] mtk: wifi: mt76: mt7996: Establish BA in VO queue
+Subject: [PATCH 036/116] mtk: wifi: mt76: mt7996: Establish BA in VO queue
---
mt7996/mac.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 1c1b3eb5..4e52aa1b 100644
+index 1c1b3eb51..4e52aa1bf 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1032,8 +1032,6 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
@@ -21,5 +21,5 @@
if (is_8023) {
fc = IEEE80211_FTYPE_DATA |
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1023-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0037-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch
similarity index 79%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1023-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0037-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch
index aa995e4..e762d07 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1023-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0037-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch
@@ -1,7 +1,7 @@
-From 6bca319efea2666854a49851f7e85aa01e2046ed Mon Sep 17 00:00:00 2001
+From 7bf50fae60cf0682279a316814c17c58425322c5 Mon Sep 17 00:00:00 2001
From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Date: Sat, 12 Aug 2023 04:17:22 +0800
-Subject: [PATCH 1023/1044] mtk: wifi: mt76: mt7996: report tx and rx byte to
+Subject: [PATCH 037/116] mtk: wifi: mt76: mt7996: report tx and rx byte to
tpt_led
---
@@ -9,10 +9,10 @@
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index bc4c3a94..03a2402d 100644
+index 0be5a880f..d951c733e 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -522,6 +522,8 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -525,6 +525,8 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
u8 ac;
u16 wlan_idx;
struct mt76_wcid *wcid;
@@ -21,7 +21,7 @@
switch (le16_to_cpu(res->tag)) {
case UNI_ALL_STA_TXRX_RATE:
-@@ -541,11 +543,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -544,11 +546,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
if (!wcid)
break;
@@ -43,5 +43,5 @@
break;
case UNI_ALL_STA_TXRX_MSDU_COUNT:
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1024-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0038-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch
similarity index 80%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1024-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0038-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch
index de8c46e..2d8b5d1 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1024-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0038-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch
@@ -1,9 +1,10 @@
-From ab4e26243d8bbccfe1e8ba69c1af4e3457909f32 Mon Sep 17 00:00:00 2001
+From 389b458b00f2369eeb43eb8a237836b7404b6657 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Thu, 21 Sep 2023 00:52:46 +0800
-Subject: [PATCH 1024/1044] mtk: wifi: mt76: mt7996: support dup wtbl
+Subject: [PATCH 038/116] mtk: wifi: mt76: mt7996: support dup wtbl
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I14ba41ace8341c23c1cfb6e9c4fbb2d5e93a5714
---
mt7996/init.c | 1 +
mt7996/mt7996.h | 1 +
@@ -11,10 +12,10 @@
3 files changed, 25 insertions(+)
diff --git a/mt7996/init.c b/mt7996/init.c
-index 1498787f..30879ec3 100644
+index 5cc2e6fbf..d4b0a72eb 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -675,6 +675,7 @@ static void mt7996_init_work(struct work_struct *work)
+@@ -686,6 +686,7 @@ static void mt7996_init_work(struct work_struct *work)
mt7996_mcu_set_eeprom(dev);
mt7996_mac_init(dev);
mt7996_txbf_init(dev);
@@ -23,10 +24,10 @@
void mt7996_wfsys_reset(struct mt7996_dev *dev)
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index b2fb68c3..23497b46 100644
+index c06aae960..dbc4aa634 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -807,6 +807,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
+@@ -813,6 +813,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set);
void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb);
@@ -35,7 +36,7 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index dbdf8d80..ea4e5bf2 100644
+index dbdf8d809..ea4e5bf28 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
@@ -257,4 +257,27 @@ void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb)
@@ -67,5 +68,5 @@
+}
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1026-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0039-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch
similarity index 81%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1026-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0039-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch
index 27628ed..918badb 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1026-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0039-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch
@@ -1,18 +1,20 @@
-From e41cd653fb95b60acd3f7c0ee1690ffa4ba995db Mon Sep 17 00:00:00 2001
+From 39e2b93d2071ec41a6e85523df19f5269e9550a3 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Mon, 6 Nov 2023 11:10:10 +0800
-Subject: [PATCH 1026/1044] mtk: wifi: mt76: try more times when send message
+Subject: [PATCH 039/116] mtk: wifi: mt76: try more times when send message
timeout.
+CR-Id: WCNCR00334773
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Change-Id: Ib7c01e6c9f74f68d8404a3d8bada9e5a10c4e232
---
dma.c | 7 ++++--
mcu.c | 65 ++++++++++++++++++++++++++++++++++++----------------
- mt7996/mac.c | 45 +++++++++++++++---------------------
- 3 files changed, 68 insertions(+), 49 deletions(-)
+ mt7996/mac.c | 37 ++++++++++--------------------
+ 3 files changed, 62 insertions(+), 47 deletions(-)
diff --git a/dma.c b/dma.c
-index 56044639..66c000ef 100644
+index 560446395..66c000ef0 100644
--- a/dma.c
+++ b/dma.c
@@ -504,9 +504,12 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
@@ -39,7 +41,7 @@
static int
diff --git a/mcu.c b/mcu.c
-index fa4b0544..2926f715 100644
+index fa4b05441..2926f7150 100644
--- a/mcu.c
+++ b/mcu.c
@@ -4,6 +4,7 @@
@@ -131,27 +133,10 @@
return ret;
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 4e52aa1b..c6d79989 100644
+index 4e52aa1bf..56827c9b3 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -1666,10 +1666,14 @@ mt7996_mac_restart(struct mt7996_dev *dev)
- set_bit(MT76_RESET, &dev->mphy.state);
- set_bit(MT76_MCU_RESET, &dev->mphy.state);
- wake_up(&dev->mt76.mcu.wait);
-- if (phy2)
-+ if (phy2) {
- set_bit(MT76_RESET, &phy2->mt76->state);
-- if (phy3)
-+ set_bit(MT76_MCU_RESET, &phy2->mt76->state);
-+ }
-+ if (phy3) {
- set_bit(MT76_RESET, &phy3->mt76->state);
-+ set_bit(MT76_MCU_RESET, &phy3->mt76->state);
-+ }
-
- /* lock/unlock all queues to ensure that no tx is pending */
- mt76_txq_schedule_all(&dev->mphy);
-@@ -1784,13 +1788,24 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
+@@ -1784,13 +1784,24 @@ mt7996_mac_full_reset(struct mt7996_dev *dev)
phy3 = mt7996_phy3(dev);
dev->recovery.hw_full_reset = true;
@@ -177,7 +162,7 @@
cancel_work_sync(&dev->wed_rro.work);
cancel_delayed_work_sync(&dev->mphy.mac_work);
if (phy2)
-@@ -1893,16 +1908,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -1893,16 +1904,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
set_bit(MT76_MCU_RESET, &dev->mphy.state);
wake_up(&dev->mt76.mcu.wait);
@@ -194,7 +179,7 @@
mt76_worker_disable(&dev->mt76.tx_worker);
mt76_for_each_q_rx(&dev->mt76, i) {
if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
-@@ -1913,8 +1918,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -1913,8 +1914,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
}
napi_disable(&dev->mt76.tx_napi);
@@ -203,7 +188,7 @@
mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
-@@ -1987,20 +1990,8 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -1987,20 +1986,8 @@ void mt7996_mac_reset_work(struct work_struct *work)
if (phy3)
ieee80211_wake_queues(phy3->mt76->hw);
@@ -225,5 +210,5 @@
wiphy_name(dev->mt76.hw->wiphy));
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1027-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0040-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch
similarity index 69%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1027-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0040-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch
index 54ee436..1a2df19 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1027-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0040-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch
@@ -1,18 +1,19 @@
-From a86c3c6d2be2e115540d0a6ce5166943fd6657ba Mon Sep 17 00:00:00 2001
+From 6c5c10622f2dcba5a72b60df9954060ebdde7fe4 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Tue, 21 Nov 2023 09:55:46 +0800
-Subject: [PATCH 1027/1044] mtk: wifi: mt76: mt7996: add SER overlap handle
+Subject: [PATCH 040/116] mtk: wifi: mt76: mt7996: add SER overlap handle
+CR-ID: WCNCR00355921
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
---
- mcu.c | 3 ++-
- mt7996/mac.c | 8 ++++++++
- mt7996/mcu.c | 8 ++++++++
- mt7996/mt7996.h | 2 ++
- 4 files changed, 20 insertions(+), 1 deletion(-)
+ mcu.c | 3 ++-
+ mt7996/mac.c | 11 +++++++++++
+ mt7996/mcu.c | 8 ++++++++
+ mt7996/mt7996.h | 2 ++
+ 4 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/mcu.c b/mcu.c
-index 2926f715..a7afa2d7 100644
+index 2926f7150..a7afa2d7c 100644
--- a/mcu.c
+++ b/mcu.c
@@ -94,7 +94,8 @@ int mt76_mcu_skb_send_and_get_msg(struct mt76_dev *dev, struct sk_buff *skb,
@@ -26,10 +27,10 @@
ret = dev->mcu_ops->mcu_skb_send_msg(dev, skb_tmp, cmd, &seq);
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index c6d79989..2e0fb5d9 100644
+index 56827c9b3..9b5b9951e 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -1889,6 +1889,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -1885,6 +1885,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
return;
@@ -37,7 +38,7 @@
dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
wiphy_name(dev->mt76.hw->wiphy));
-@@ -1906,6 +1907,10 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -1902,6 +1903,10 @@ void mt7996_mac_reset_work(struct work_struct *work)
set_bit(MT76_RESET, &dev->mphy.state);
set_bit(MT76_MCU_RESET, &dev->mphy.state);
@@ -48,7 +49,17 @@
wake_up(&dev->mt76.mcu.wait);
mt76_worker_disable(&dev->mt76.tx_worker);
-@@ -2120,6 +2125,9 @@ void mt7996_reset(struct mt7996_dev *dev)
+@@ -2097,6 +2102,9 @@ void mt7996_coredump(struct mt7996_dev *dev, u8 state)
+
+ void mt7996_reset(struct mt7996_dev *dev)
+ {
++ dev_info(dev->mt76.dev, "%s SER recovery state: 0x%08x\n",
++ wiphy_name(dev->mt76.hw->wiphy), READ_ONCE(dev->recovery.state));
++
+ if (!dev->recovery.hw_init_done)
+ return;
+
+@@ -2116,6 +2124,9 @@ void mt7996_reset(struct mt7996_dev *dev)
return;
}
@@ -59,7 +70,7 @@
wake_up(&dev->reset_wait);
}
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 03a2402d..c427ea20 100644
+index d951c733e..fcc2512f3 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -246,6 +246,14 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -78,10 +89,10 @@
seq = ++dev->mt76.mcu.msg_seq & 0xf;
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 23497b46..c590a8b8 100644
+index dbc4aa634..d40f8bf43 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -392,6 +392,8 @@ struct mt7996_dev {
+@@ -397,6 +397,8 @@ struct mt7996_dev {
wait_queue_head_t reset_wait;
struct {
u32 state;
@@ -91,5 +102,5 @@
u32 wm_reset_count;
bool hw_full_reset:1;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1028-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0041-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch
similarity index 87%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1028-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0041-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch
index 578e073..8e1d41b 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1028-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0041-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch
@@ -1,8 +1,7 @@
-From b1e9d2e1fd1b0b788bcb42c468b72d7e0fe1d583 Mon Sep 17 00:00:00 2001
+From f2660cb8f6840bd545b093b9dee22c8f06ccb499 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 13 Jul 2023 16:36:36 +0800
-Subject: [PATCH 1028/1044] mtk: wifi: mt76: mt7996: kite default 1-pcie
- setting
+Subject: [PATCH 041/116] mtk: wifi: mt76: mt7996: kite default 1-pcie setting
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
@@ -10,7 +9,7 @@
1 file changed, 11 insertions(+)
diff --git a/mt7996/pci.c b/mt7996/pci.c
-index 04056181..05830c01 100644
+index 040561813..05830c01c 100644
--- a/mt7996/pci.c
+++ b/mt7996/pci.c
@@ -11,6 +11,9 @@
@@ -53,5 +52,5 @@
if (ret)
return ret;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1029-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0042-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch
similarity index 90%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1029-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0042-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch
index 665f489..59b7901 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1029-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0042-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch
@@ -1,7 +1,7 @@
-From 649e775c56c37b314cf69767bbf845237a2674cc Mon Sep 17 00:00:00 2001
+From c8059abc389412d9031292c2795b2db52c78ddc5 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Fri, 28 Apr 2023 10:39:58 +0800
-Subject: [PATCH 1029/1044] mtk: wifi: mt76: mt7996: add debugfs knob for
+Subject: [PATCH 042/116] mtk: wifi: mt76: mt7996: add debugfs knob for
rx_counters
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
@@ -14,7 +14,7 @@
5 files changed, 94 insertions(+), 5 deletions(-)
diff --git a/agg-rx.c b/agg-rx.c
-index 07c386c7..37588ac2 100644
+index 07c386c7b..37588ac20 100644
--- a/agg-rx.c
+++ b/agg-rx.c
@@ -33,10 +33,13 @@ mt76_rx_aggr_release_frames(struct mt76_rx_tid *tid,
@@ -72,10 +72,10 @@
spin_lock_init(&tid->lock);
diff --git a/mac80211.c b/mac80211.c
-index e7d02d15..ae040ec4 100644
+index 1127ef7b5..0590aaf2e 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -784,6 +784,7 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
+@@ -783,6 +783,7 @@ static void mt76_rx_release_amsdu(struct mt76_phy *phy, enum mt76_rxq_id q)
}
if (ether_addr_equal(skb->data + offset, rfc1042_header)) {
@@ -83,7 +83,7 @@
dev_kfree_skb(skb);
return;
}
-@@ -1100,10 +1101,16 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
+@@ -1099,10 +1100,16 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
*sta = wcid_to_sta(mstat.wcid);
*hw = mt76_phy_hw(dev, mstat.phy_idx);
@@ -101,7 +101,7 @@
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
struct mt76_wcid *wcid = status->wcid;
-@@ -1150,7 +1157,11 @@ skip_hdr_check:
+@@ -1149,7 +1156,11 @@ skip_hdr_check:
ret = memcmp(status->iv, wcid->rx_key_pn[security_idx],
sizeof(status->iv));
if (ret <= 0) {
@@ -113,7 +113,7 @@
return;
}
-@@ -1331,7 +1342,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
+@@ -1330,7 +1341,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
while ((skb = __skb_dequeue(frames)) != NULL) {
struct sk_buff *nskb = skb_shinfo(skb)->frag_list;
@@ -122,7 +122,7 @@
skb_shinfo(skb)->frag_list = NULL;
mt76_rx_convert(dev, skb, &hw, &sta);
ieee80211_rx_list(hw, sta, skb, &list);
-@@ -1354,6 +1365,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
+@@ -1353,6 +1364,7 @@ void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
}
list_for_each_entry_safe(skb, tmp, &list, list) {
@@ -131,10 +131,10 @@
napi_gro_receive(napi, skb);
}
diff --git a/mt76.h b/mt76.h
-index a75277fe..58fd55b1 100644
+index 4a3e6bf40..631f82fd5 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -423,6 +423,7 @@ struct mt76_rx_tid {
+@@ -428,6 +428,7 @@ struct mt76_rx_tid {
struct rcu_head rcu_head;
struct mt76_dev *dev;
@@ -142,7 +142,7 @@
spinlock_t lock;
struct delayed_work reorder_work;
-@@ -854,6 +855,19 @@ struct mt76_phy {
+@@ -859,6 +860,19 @@ struct mt76_phy {
bool al;
u8 pin;
} leds;
@@ -162,7 +162,7 @@
};
struct mt76_dev {
-@@ -959,6 +973,7 @@ struct mt76_dev {
+@@ -964,6 +978,7 @@ struct mt76_dev {
};
const char *bin_file_name;
@@ -171,7 +171,7 @@
/* per-phy stats. */
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 2e0fb5d9..7885bc4c 100644
+index 9b5b9951e..18616fd29 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -469,8 +469,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
@@ -227,10 +227,10 @@
break;
}
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index ed01c089..d290ad4d 100644
+index 9dc6ea778..321e43f83 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -2854,6 +2854,46 @@ mt7996_sr_scene_cond_show(struct seq_file *file, void *data)
+@@ -2913,6 +2913,46 @@ mt7996_sr_scene_cond_show(struct seq_file *file, void *data)
}
DEFINE_SHOW_ATTRIBUTE(mt7996_sr_scene_cond);
@@ -277,7 +277,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -2917,6 +2957,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -2976,6 +3016,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_devm_seqfile(dev->mt76.dev, "tr_info", dir,
mt7996_trinfo_read);
@@ -287,5 +287,5 @@
debugfs_create_file("txpower_info", 0600, dir, phy, &mt7996_txpower_info_fops);
debugfs_create_file("txpower_sku", 0600, dir, phy, &mt7996_txpower_sku_fops);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1031-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0043-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch
similarity index 96%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1031-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0043-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch
index af11090..59dd3bf 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1031-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0043-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch
@@ -1,7 +1,7 @@
-From 3eac9c285c13a00891a81064bb346b0da307a9e8 Mon Sep 17 00:00:00 2001
+From a824fd4250a195e3010d24daa58e01cff4f45c46 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Tue, 3 Jan 2023 09:42:07 +0800
-Subject: [PATCH 1031/1044] mtk: wifi: mt76: mt7996: support BF/MIMO debug
+Subject: [PATCH 043/116] mtk: wifi: mt76: mt7996: support BF/MIMO debug
commands
This commit includes the following commands:
@@ -11,24 +11,36 @@
4. fix muru rate
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: Id6cbaf16e4e6f63238a495ac9f45744e1dd38e9b
fix the wrong wlan_idx for user3
+CR-Id: WCNCR00261410
+Change-Id: I7ece7399370f2bd22d2564029025baeda27057a5
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+
+Align the format of mcu event "mt7996_mcu_bf_starec_read" with
+firmware definition.
+
+Fw gerrit change:
+https://gerrit.mediatek.inc/c/neptune/firmware/bora/wifi/core/+/8218143
+
+CR-Id: WCNCR00240772
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
---
mt7996/mcu.c | 5 +
mt7996/mcu.h | 4 +
mt7996/mt7996.h | 5 +
mt7996/mtk_debugfs.c | 120 +++++++++
- mt7996/mtk_mcu.c | 626 +++++++++++++++++++++++++++++++++++++++++++
- mt7996/mtk_mcu.h | 342 +++++++++++++++++++++++
- 6 files changed, 1102 insertions(+)
+ mt7996/mtk_mcu.c | 624 +++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mtk_mcu.h | 342 ++++++++++++++++++++++++
+ 6 files changed, 1100 insertions(+)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index c427ea20..d4cd83c6 100644
+index fcc2512f3..4be5ca4bf 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -741,6 +741,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -744,6 +744,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_TESTMODE_CTRL:
mt7996_tm_rf_test_event(dev, skb);
break;
@@ -41,7 +53,7 @@
default:
break;
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 34fdfb26..347893c8 100644
+index cb7260fb3..29bd7a55b 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -770,8 +770,12 @@ enum {
@@ -58,10 +70,10 @@
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index c590a8b8..33936f90 100644
+index d40f8bf43..4602b4e7a 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -810,6 +810,11 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
+@@ -816,6 +816,11 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set);
void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb);
int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev);
@@ -74,10 +86,10 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index d290ad4d..2104c889 100644
+index 321e43f83..36db55479 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -2894,6 +2894,117 @@ static int mt7996_rx_counters(struct seq_file *s, void *data)
+@@ -2953,6 +2953,117 @@ static int mt7996_rx_counters(struct seq_file *s, void *data)
return 0;
}
@@ -195,7 +207,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -2980,6 +3091,15 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -3039,6 +3150,15 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_file("sr_stats", 0400, dir, phy, &mt7996_sr_stats_fops);
debugfs_create_file("sr_scene_cond", 0400, dir, phy, &mt7996_sr_scene_cond_fops);
@@ -212,10 +224,10 @@
}
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index ea4e5bf2..67419cd9 100644
+index ea4e5bf28..6b2cdad6f 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
-@@ -280,4 +280,630 @@ int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev)
+@@ -280,4 +280,628 @@ int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev)
return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(CHIP_CONFIG), &req,
sizeof(req), true);
}
@@ -511,7 +523,6 @@
+ "rStaRecBf.codebook42_su = %d\n"
+ "rStaRecBf.codebook75_mu = %d\n"
+ "rStaRecBf.he_ltf = %d\n"
-+ "rStaRecBf.pp_fd_val = %d\n"
+ "======================================\n",
+ r->smart_ant,
+ r->se_idx,
@@ -529,8 +540,7 @@
+ r->ng16_mu,
+ r->codebook42_su,
+ r->codebook75_mu,
-+ r->he_ltf,
-+ r->pp_fd_val);
++ r->he_ltf);
+ break;
+ }
+ case UNI_EVENT_BF_FBK_INFO: {
@@ -847,7 +857,7 @@
+
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index 098e63ae..71c6684a 100644
+index 098e63aef..27d6a05b8 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
@@ -119,6 +119,348 @@ enum {
@@ -972,7 +982,7 @@
+ bool codebook75_mu;
+
+ u8 he_ltf;
-+ u8 pp_fd_val;
++ u8 rsv[3];
+};
+
+#define TXBF_PFMU_ID_NUM_MAX 48
@@ -1200,5 +1210,5 @@
enum {
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1032-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0044-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch
similarity index 88%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1032-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0044-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch
index f6e1f07..a68e7f7 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1032-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0044-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch
@@ -1,13 +1,14 @@
-From e6ce0b945f7cfe7b181223b5e5db4a213c3c4433 Mon Sep 17 00:00:00 2001
+From 8531498a7a6b120e4861772b19f4f9a9a63a2484 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Tue, 13 Jun 2023 14:49:02 +0800
-Subject: [PATCH 1032/1044] mtk: wifi: mt76: mt7996: add build the following
- MURU mcu command tlvs
+Subject: [PATCH 044/116] mtk: wifi: mt76: mt7996: add build the following MURU
+ mcu command tlvs
It includes the following tlvs:
1. MURU tlv id 0x10, 0x33, 0xC8, 0xC9, 0xCA, 0xCC, 0xCD
2. BF tlv id 0x1c
+Change-Id: I0ae5cbed5b4370d39a6cfca50721873845659006
---
mt7996/mcu.h | 1 +
mt7996/mt7996.h | 3 ++
@@ -17,7 +18,7 @@
5 files changed, 108 insertions(+)
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 347893c8..527c9c79 100644
+index 29bd7a55b..848c85dae 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -776,6 +776,7 @@ enum {
@@ -29,10 +30,10 @@
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 33936f90..4a268a4e 100644
+index 4602b4e7a..205a3c7b7 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -815,6 +815,9 @@ void mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb);
+@@ -821,6 +821,9 @@ void mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb);
int mt7996_mcu_set_muru_fixed_rate_enable(struct mt7996_dev *dev, u8 action, int val);
int mt7996_mcu_set_muru_fixed_rate_parameter(struct mt7996_dev *dev, u8 action, void *para);
int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para);
@@ -43,10 +44,10 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 2104c889..9e7acd4b 100644
+index 36db55479..e337ae4f7 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -3005,6 +3005,16 @@ static const struct file_operations fops_muru_fixed_group_rate = {
+@@ -3064,6 +3064,16 @@ static const struct file_operations fops_muru_fixed_group_rate = {
.llseek = default_llseek,
};
@@ -63,7 +64,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -3100,6 +3110,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -3159,6 +3169,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_file("bf_fbk_rpt", 0600, dir, phy, &fops_bf_fbk_rpt);
debugfs_create_file("pfmu_tag_read", 0600, dir, phy, &fops_bf_pfmu_tag_read);
@@ -73,10 +74,10 @@
}
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index 67419cd9..b7d86384 100644
+index 6b2cdad6f..686506234 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
-@@ -906,4 +906,82 @@ error:
+@@ -904,4 +904,82 @@ error:
return -EINVAL;
}
@@ -160,7 +161,7 @@
+
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index 71c6684a..b061950c 100644
+index 27d6a05b8..d9686ebb5 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
@@ -119,6 +119,20 @@ enum {
@@ -185,5 +186,5 @@
struct bf_pfmu_tag {
__le16 tag;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1033-mtk-wifi-mt76-mt7996-add-cert-patch.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0045-mtk-wifi-mt76-mt7996-add-cert-patch.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1033-mtk-wifi-mt76-mt7996-add-cert-patch.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0045-mtk-wifi-mt76-mt7996-add-cert-patch.patch
index 951e868..6113da2 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1033-mtk-wifi-mt76-mt7996-add-cert-patch.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0045-mtk-wifi-mt76-mt7996-add-cert-patch.patch
@@ -1,7 +1,7 @@
-From 775ed42df549473e6e9e966ac2d9abcfed74a73b Mon Sep 17 00:00:00 2001
+From 5316ac1eaa6a54cf11d0f7b66d074b6e101b5837 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Mon, 14 Aug 2023 13:36:58 +0800
-Subject: [PATCH 1033/1044] mtk: wifi: mt76: mt7996: add cert patch
+Subject: [PATCH 045/116] mtk: wifi: mt76: mt7996: add cert patch
This patch includes TGac and TGax
@@ -9,6 +9,7 @@
Add vendor cmd set ap wireless rts_sigta support
+CR-ID: WCNCR00348946
Signed-off-by: ye he <ye.he@mediatek.com>
---
mt7996/mac.c | 9 ++
@@ -23,7 +24,7 @@
9 files changed, 778 insertions(+), 7 deletions(-)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 7885bc4c..bf42ae07 100644
+index 18616fd29..70f0c56cc 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -10,6 +10,7 @@
@@ -34,7 +35,7 @@
#define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
-@@ -2285,6 +2286,14 @@ void mt7996_mac_update_stats(struct mt7996_phy *phy)
+@@ -2284,6 +2285,14 @@ void mt7996_mac_update_stats(struct mt7996_phy *phy)
}
}
@@ -50,10 +51,10 @@
{
struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
diff --git a/mt7996/main.c b/mt7996/main.c
-index dbe3d33f..d314d9fb 100644
+index f8ac51707..2f1dd0fb7 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -588,6 +588,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -613,6 +613,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
bool beacon, bool mcast)
{
struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
@@ -61,7 +62,7 @@
struct mt76_phy *mphy = hw->priv;
u16 rate;
u8 i, idx;
-@@ -597,6 +598,9 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -622,6 +623,9 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (beacon) {
struct mt7996_phy *phy = mphy->priv;
@@ -71,7 +72,7 @@
/* odd index for driver, even index for firmware */
idx = MT7996_BEACON_RATES_TBL + 2 * phy->mt76->band_idx;
if (phy->beacon_rate != rate)
-@@ -726,6 +730,10 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+@@ -749,6 +753,10 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
u8 band_idx = mvif->phy->mt76->band_idx;
int ret, idx;
@@ -82,7 +83,7 @@
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
if (idx < 0)
return -ENOSPC;
-@@ -751,7 +759,28 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+@@ -774,7 +782,28 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
if (ret)
return ret;
@@ -113,10 +114,10 @@
void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index d4cd83c6..3a34afd9 100644
+index 4be5ca4bf..b1296ce25 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1349,6 +1349,10 @@ mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+@@ -1352,6 +1352,10 @@ mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
{
struct sta_rec_vht *vht;
struct tlv *tlv;
@@ -127,7 +128,7 @@
/* For 6G band, this tlv is necessary to let hw work normally */
if (!sta->deflink.he_6ghz_capa.capa && !sta->deflink.vht_cap.vht_supported)
-@@ -1360,6 +1364,9 @@ mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+@@ -1363,6 +1367,9 @@ mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
@@ -137,7 +138,7 @@
}
static void
-@@ -4450,6 +4457,27 @@ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val)
+@@ -4440,6 +4447,27 @@ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val)
&req, sizeof(req), true);
}
@@ -165,7 +166,7 @@
int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)
{
struct {
-@@ -4965,6 +4993,18 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+@@ -5007,6 +5035,18 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
val = FIELD_GET(RATE_CFG_VAL, *((u32 *)data));
switch (mode) {
@@ -185,7 +186,7 @@
if (val < 0 || val > 15) {
printk("Wrong value! The value is between 0-15.\n");
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 527c9c79..af078edd 100644
+index 848c85dae..806163806 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -755,6 +755,8 @@ enum {
@@ -221,10 +222,10 @@
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 4a268a4e..b9c37612 100644
+index 205a3c7b7..30ceb0018 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -349,6 +349,7 @@ struct mt7996_phy {
+@@ -354,6 +354,7 @@ struct mt7996_phy {
} test;
#endif
#ifdef CONFIG_MTK_VENDOR
@@ -232,7 +233,7 @@
spinlock_t amnt_lock;
struct mt7996_air_monitor_ctrl amnt_ctrl;
#endif
-@@ -476,6 +477,9 @@ struct mt7996_dev {
+@@ -482,6 +483,9 @@ struct mt7996_dev {
} dbg;
const struct mt7996_dbg_reg_desc *dbg_reg;
#endif
@@ -242,7 +243,7 @@
};
enum {
-@@ -673,6 +677,7 @@ void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
+@@ -679,6 +683,7 @@ void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event);
int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable);
void mt7996_mcu_scs_sta_poll(struct work_struct *work);
@@ -250,7 +251,7 @@
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
-@@ -791,6 +796,10 @@ void mt7996_vendor_register(struct mt7996_phy *phy);
+@@ -797,6 +802,10 @@ void mt7996_vendor_register(struct mt7996_phy *phy);
void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb);
int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
struct ieee80211_sta *sta);
@@ -261,7 +262,7 @@
#endif
int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
-@@ -818,6 +827,10 @@ int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para);
+@@ -824,6 +833,10 @@ int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para);
int mt7996_mcu_set_muru_cmd(struct mt7996_dev *dev, u16 action, int val);
int mt7996_mcu_muru_set_prot_frame_thr(struct mt7996_dev *dev, u32 val);
int mt7996_mcu_set_bypass_smthint(struct mt7996_phy *phy, u8 val);
@@ -273,10 +274,10 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index b7d86384..cacca449 100644
+index 686506234..b67d366d4 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
-@@ -984,4 +984,209 @@ int mt7996_mcu_set_bypass_smthint(struct mt7996_phy *phy, u8 val)
+@@ -982,4 +982,209 @@ int mt7996_mcu_set_bypass_smthint(struct mt7996_phy *phy, u8 val)
true);
}
@@ -487,7 +488,7 @@
+
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index b061950c..98c9660a 100644
+index d9686ebb5..7a4140b57 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
@@ -122,14 +122,15 @@ enum {
@@ -692,7 +693,7 @@
#endif
diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index 9ba6f00a..477c5c42 100644
+index 0d6fa7792..7ab64471f 100644
--- a/mt7996/vendor.c
+++ b/mt7996/vendor.c
@@ -10,10 +10,31 @@
@@ -727,8 +728,8 @@
};
static const struct nla_policy
-@@ -70,6 +91,17 @@ ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
- [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
+@@ -76,6 +97,17 @@ pp_ctrl_policy[NUM_MTK_VENDOR_ATTRS_PP_CTRL] = {
+ [MTK_VENDOR_ATTR_PP_BAND_IDX] = { .type = NLA_U8 },
};
+static const struct nla_policy
@@ -745,7 +746,7 @@
struct mt7996_amnt_data {
u8 idx;
u8 addr[ETH_ALEN];
-@@ -84,6 +116,8 @@ static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
+@@ -90,6 +122,8 @@ static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
{
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_MU_CTRL];
@@ -754,7 +755,7 @@
int err;
u8 val8;
u32 val32 = 0;
-@@ -99,9 +133,17 @@ static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
+@@ -105,9 +139,17 @@ static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
FIELD_PREP(RATE_CFG_VAL, val8);
ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
mt7996_set_wireless_vif, &val32);
@@ -773,7 +774,7 @@
}
static int
-@@ -124,6 +166,48 @@ mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
+@@ -130,6 +172,48 @@ mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
return len;
}
@@ -822,8 +823,8 @@
void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb)
{
struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
-@@ -647,6 +731,126 @@ mt7996_vendor_ibf_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
- return 1;
+@@ -712,6 +796,126 @@ error:
+ return -EINVAL;
}
+static int mt7996_vendor_rfeature_ctrl(struct wiphy *wiphy,
@@ -949,7 +950,7 @@
static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
{
.info = {
-@@ -660,6 +864,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
+@@ -725,6 +929,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
.policy = mu_ctrl_policy,
.maxattr = MTK_VENDOR_ATTR_MU_CTRL_MAX,
},
@@ -968,9 +969,9 @@
{
.info = {
.vendor_id = MTK_NL80211_VENDOR_ID,
-@@ -718,6 +934,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = ibf_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_IBF_CTRL_MAX,
+@@ -794,6 +1010,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
+ .policy = pp_ctrl_policy,
+ .maxattr = MTK_VENDOR_ATTR_PP_CTRL_MAX,
},
+ {
+ .info = {
@@ -986,13 +987,13 @@
};
void mt7996_vendor_register(struct mt7996_phy *phy)
-@@ -727,3 +954,4 @@ void mt7996_vendor_register(struct mt7996_phy *phy)
+@@ -803,3 +1030,4 @@ void mt7996_vendor_register(struct mt7996_phy *phy)
spin_lock_init(&phy->amnt_lock);
}
+#endif
diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 29ccc050..7011914b 100644
+index 8aaa18eec..2ee1339a5 100644
--- a/mt7996/vendor.h
+++ b/mt7996/vendor.h
@@ -3,8 +3,12 @@
@@ -1008,7 +1009,7 @@
MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL = 0xc7,
MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL = 0xc8,
-@@ -60,6 +64,7 @@ enum mtk_vendor_attr_mu_ctrl {
+@@ -61,6 +65,7 @@ enum mtk_vendor_attr_mu_ctrl {
MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
MTK_VENDOR_ATTR_MU_CTRL_DUMP,
@@ -1016,7 +1017,7 @@
/* keep last */
NUM_MTK_VENDOR_ATTRS_MU_CTRL,
-@@ -67,6 +72,66 @@ enum mtk_vendor_attr_mu_ctrl {
+@@ -68,6 +73,66 @@ enum mtk_vendor_attr_mu_ctrl {
NUM_MTK_VENDOR_ATTRS_MU_CTRL - 1
};
@@ -1083,12 +1084,12 @@
enum mtk_vendor_attr_mnt_ctrl {
MTK_VENDOR_ATTR_AMNT_CTRL_UNSPEC,
-@@ -138,3 +203,5 @@ enum mtk_vendor_attr_ibf_dump {
+@@ -151,3 +216,5 @@ enum mtk_vendor_attr_pp_ctrl {
};
#endif
+
+#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1034-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0046-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch
similarity index 77%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1034-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0046-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch
index c0cf121..120ee1e 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1034-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0046-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch
@@ -1,7 +1,7 @@
-From e5de8b93a62c62b5c44b10022e53d410f93c70d6 Mon Sep 17 00:00:00 2001
+From a0d5c65378876c6fbbc83b602e297d791640a7c3 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 6 Apr 2023 16:40:28 +0800
-Subject: [PATCH 1034/1044] mtk: wifi: mt76: testmode: add testmode bf support
+Subject: [PATCH 046/116] mtk: wifi: mt76: testmode: add testmode bf support
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -14,28 +14,40 @@
https://gerrit.mediatek.inc/c/neptune/wlan_driver/logan/+/8206056
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+mtk: wifi: mt76: testmode: add testmode ibf ver2 support
+
+Add ibf ver2 support for chips after Kite
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+mtk: wifi: mt76: testmode: add testmode ibf 5T5R support
+
+Add testmode ibf 5T5R support for Kite BE7200 2i5i
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt76.h | 5 +
mt76_connac_mcu.h | 4 +-
mt7996/mcu.c | 8 +-
- mt7996/mcu.h | 45 ++-
+ mt7996/mcu.h | 46 ++-
mt7996/mt7996.h | 12 +-
mt7996/mtk_debugfs.c | 6 +-
- mt7996/mtk_mcu.c | 79 ++++-
- mt7996/mtk_mcu.h | 338 +++++++++++++++++++-
+ mt7996/mtk_mcu.c | 143 +++++++-
+ mt7996/mtk_mcu.h | 441 +++++++++++++++++++++++-
mt7996/regs.h | 3 +
- mt7996/testmode.c | 744 +++++++++++++++++++++++++++++++++++++++++--
+ mt7996/testmode.c | 796 +++++++++++++++++++++++++++++++++++++++++--
mt7996/testmode.h | 19 ++
- testmode.c | 60 ++++
+ testmode.c | 62 ++++
testmode.h | 53 +++
- tools/fields.c | 37 +++
- 14 files changed, 1354 insertions(+), 59 deletions(-)
+ tools/fields.c | 37 ++
+ 14 files changed, 1576 insertions(+), 59 deletions(-)
diff --git a/mt76.h b/mt76.h
-index 58fd55b1..543d9de5 100644
+index 631f82fd5..11cbb2d28 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -752,6 +752,11 @@ struct mt76_testmode_data {
+@@ -757,6 +757,11 @@ struct mt76_testmode_data {
u32 tx_time;
u32 tx_ipg;
@@ -48,7 +60,7 @@
bool ebf;
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index a59e5a0b..266ee711 100644
+index 864a802d7..885e5883e 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -488,7 +488,8 @@ struct sta_rec_bf {
@@ -61,7 +73,7 @@
} __packed;
struct sta_rec_bfee {
-@@ -1278,6 +1279,7 @@ enum {
+@@ -1279,6 +1280,7 @@ enum {
MCU_UNI_CMD_VOW = 0x37,
MCU_UNI_CMD_PP = 0x38,
MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
@@ -70,10 +82,10 @@
MCU_UNI_CMD_PRECAL_RESULT = 0x47,
MCU_UNI_CMD_RRO = 0x57,
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 3a34afd9..6e3047ba 100644
+index b1296ce25..8f3e5ebfd 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1070,7 +1070,12 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+@@ -1073,7 +1073,12 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
bss->hw_bss_idx = idx;
if (vif->type == NL80211_IFTYPE_MONITOR) {
@@ -87,7 +99,7 @@
return 0;
}
-@@ -4108,7 +4113,6 @@ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
+@@ -4097,7 +4102,6 @@ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
int mt7996_mcu_set_txbf(struct mt7996_dev *dev, u8 action)
{
#define MT7996_BF_MAX_SIZE sizeof(union bf_tag_tlv)
@@ -96,7 +108,7 @@
struct sk_buff *skb;
struct tlv *tlv;
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index af078edd..054a616b 100644
+index 806163806..663128176 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -685,6 +685,22 @@ struct bf_sounding_on {
@@ -122,7 +134,7 @@
struct bf_hw_en_status_update {
__le16 tag;
__le16 len;
-@@ -710,6 +726,24 @@ union bf_tag_tlv {
+@@ -710,6 +726,25 @@ union bf_tag_tlv {
struct bf_mod_en_ctrl bf_mod_en;
};
@@ -142,12 +154,13 @@
+ BF_TXSND_INFO = 24,
+ BF_CMD_TXCMD = 27,
+ BF_CFG_PHY = 28,
++ BF_PROFILE_WRITE_20M_ALL_5X5 = 30,
+};
+
struct ra_rate {
__le16 wlan_idx;
u8 mode;
-@@ -771,17 +805,6 @@ enum {
+@@ -771,17 +806,6 @@ enum {
#define MUMIMO_UL BIT(3)
#define MUMIMO_DL_CERT BIT(4)
@@ -166,10 +179,10 @@
CMD_BAND_NONE,
CMD_BAND_24G,
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index b9c37612..2f76a0af 100644
+index 30ceb0018..84fbd0fb0 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -480,6 +480,14 @@ struct mt7996_dev {
+@@ -486,6 +486,14 @@ struct mt7996_dev {
#ifdef CONFIG_MTK_VENDOR
bool cert_mode;
#endif
@@ -184,7 +197,7 @@
};
enum {
-@@ -819,7 +827,7 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
+@@ -825,7 +833,7 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
int mt7996_mcu_set_sr_enable(struct mt7996_phy *phy, u8 action, u64 val, bool set);
void mt7996_mcu_rx_sr_event(struct mt7996_dev *dev, struct sk_buff *skb);
int mt7996_mcu_set_dup_wtbl(struct mt7996_dev *dev);
@@ -193,7 +206,7 @@
void mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb);
int mt7996_mcu_set_muru_fixed_rate_enable(struct mt7996_dev *dev, u8 action, int val);
int mt7996_mcu_set_muru_fixed_rate_parameter(struct mt7996_dev *dev, u8 action, void *para);
-@@ -831,10 +839,12 @@ int mt7996_mcu_set_rfeature_trig_type(struct mt7996_phy *phy, u8 enable, u8 trig
+@@ -837,10 +845,12 @@ int mt7996_mcu_set_rfeature_trig_type(struct mt7996_phy *phy, u8 enable, u8 trig
void mt7996_mcu_set_ppdu_tx_type(struct mt7996_phy *phy, u8 ppdu_type);
void mt7996_mcu_set_nusers_ofdma(struct mt7996_phy *phy, u8 type, u8 ofdma_user_cnt);
void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type);
@@ -207,10 +220,10 @@
+
#endif
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 9e7acd4b..c4cdbcdc 100644
+index e337ae4f7..c7713e8b2 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -2899,7 +2899,7 @@ mt7996_starec_bf_read_set(void *data, u64 wlan_idx)
+@@ -2958,7 +2958,7 @@ mt7996_starec_bf_read_set(void *data, u64 wlan_idx)
{
struct mt7996_phy *phy = data;
@@ -219,7 +232,7 @@
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_starec_bf_read, NULL,
mt7996_starec_bf_read_set, "%lld\n");
-@@ -2943,7 +2943,7 @@ mt7996_bf_fbk_rpt_set(void *data, u64 wlan_idx)
+@@ -3002,7 +3002,7 @@ mt7996_bf_fbk_rpt_set(void *data, u64 wlan_idx)
{
struct mt7996_phy *phy = data;
@@ -228,7 +241,7 @@
}
DEFINE_DEBUGFS_ATTRIBUTE(fops_bf_fbk_rpt, NULL,
mt7996_bf_fbk_rpt_set, "%lld\n");
-@@ -2953,7 +2953,7 @@ mt7996_bf_pfmu_tag_read_set(void *data, u64 wlan_idx)
+@@ -3012,7 +3012,7 @@ mt7996_bf_pfmu_tag_read_set(void *data, u64 wlan_idx)
{
struct mt7996_phy *phy = data;
@@ -238,7 +251,7 @@
DEFINE_DEBUGFS_ATTRIBUTE(fops_bf_pfmu_tag_read, NULL,
mt7996_bf_pfmu_tag_read_set, "%lld\n");
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index cacca449..f70bd0be 100644
+index b67d366d4..a9a7db15a 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
@@ -295,7 +295,7 @@ __mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len)
@@ -261,7 +274,7 @@
req->band_idx = phy->mt76->band_idx;
break;
}
-@@ -432,10 +431,36 @@ int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para)
+@@ -432,10 +431,61 @@ int mt7996_mcu_set_txbf_snd_info(struct mt7996_phy *phy, void *para)
return mt76_mcu_skb_send_msg(&phy->dev->mt76, skb, MCU_WM_UNI_CMD(BF), false);
}
@@ -272,24 +285,49 @@
+{
+ /* fw return ibf calibrated data with
+ * the mt7996_txbf_phase_info_5g struct for both 2G and 5G.
++ * (return struct mt7992_txbf_phase_info_5g for ibf 2.0)
+ * Therefore, memcpy cannot be used here.
+ */
-+ phase_assign(cal->group, m_t0_h, true);
-+ phase_assign(cal->group, m_t1_h, true);
-+ phase_assign(cal->group, m_t2_h, true);
-+ phase_assign(cal->group, m_t2_h_sx2, false);
-+ phase_assign_rx(cal->group, r0);
-+ phase_assign_rx(cal->group, r1);
-+ phase_assign_rx(cal->group, r2);
-+ phase_assign_rx(cal->group, r3);
-+ phase_assign_rx_g0(cal->group, r2_sx2);
-+ phase_assign_rx_g0(cal->group, r3_sx2);
-+ phase_assign(cal->group, r0_reserved, false);
-+ phase_assign(cal->group, r1_reserved, false);
-+ phase_assign(cal->group, r2_reserved, false);
-+ phase_assign(cal->group, r3_reserved, false);
-+ phase_assign(cal->group, r2_sx2_reserved, false);
-+ phase_assign(cal->group, r3_sx2_reserved, false);
++ if (get_ibf_version(dev) != IBF_VER_2) {
++ phase_assign(cal->group, v1, m_t0_h, true);
++ phase_assign(cal->group, v1, m_t1_h, true);
++ phase_assign(cal->group, v1, m_t2_h, true);
++ phase_assign(cal->group, v1, m_t2_h_sx2, false);
++ phase_assign_rx_v1(cal->group, v1, r0);
++ phase_assign_rx_v1(cal->group, v1, r1);
++ phase_assign_rx_v1(cal->group, v1, r2);
++ phase_assign_rx_v1(cal->group, v1, r3);
++ phase_assign_rx(cal->group, v1, r2_sx2, false);
++ phase_assign_rx(cal->group, v1, r3_sx2, false);
++ phase_assign(cal->group, v1, r0_reserved, false);
++ phase_assign(cal->group, v1, r1_reserved, false);
++ phase_assign(cal->group, v1, r2_reserved, false);
++ phase_assign(cal->group, v1, r3_reserved, false);
++ phase_assign(cal->group, v1, r2_sx2_reserved, false);
++ phase_assign(cal->group, v1, r3_sx2_reserved, false);
++ } else {
++ phase_assign(cal->group, v2, m_t0_h, true);
++ phase_assign(cal->group, v2, m_t1_h, true);
++ phase_assign(cal->group, v2, m_t2_h, true);
++ if (cal->group) {
++ phase->v2.phase_5g.m_t3_h = cal->v2.phase_5g.m_t3_h;
++ dev_info(dev->mt76.dev, "m_t3_h = %d\n", phase->v2.phase_5g.m_t3_h);
++ }
++ phase_assign_rx_ext(cal->group, v2, r0, true);
++ phase_assign_rx_ext(cal->group, v2, r1, true);
++ phase_assign_rx_ext(cal->group, v2, r2, true);
++ phase_assign_rx_ext(cal->group, v2, r3, true);
++ if (cal->group) {
++ memcpy(&phase->v2.phase_5g.r4, &cal->v2.phase_5g.r4,
++ sizeof(struct txbf_rx_phase_ext));
++ dev_info(dev->mt76.dev, "r4.rx_uh = %d\n", phase->v2.phase_5g.r4.rx_uh);
++ dev_info(dev->mt76.dev, "r4.rx_h = %d\n", phase->v2.phase_5g.r4.rx_h);
++ dev_info(dev->mt76.dev, "r4.rx_mh = %d\n", phase->v2.phase_5g.r4.rx_mh);
++ dev_info(dev->mt76.dev, "r4.rx_m = %d\n", phase->v2.phase_5g.r4.rx_m);
++ dev_info(dev->mt76.dev, "r4.rx_l = %d\n", phase->v2.phase_5g.r4.rx_l);
++ dev_info(dev->mt76.dev, "r4.rx_ul = %d\n", phase->v2.phase_5g.r4.rx_ul);
++ }
++ }
+}
+
void
@@ -299,7 +337,7 @@
struct mt7996_mcu_bf_basic_event *event;
event = (struct mt7996_mcu_bf_basic_event *)skb->data;
-@@ -470,13 +495,12 @@ mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -470,13 +520,12 @@ mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
tag->t1.nr, tag->t1.nc, tag->t1.ngroup, tag->t1.lm, tag->t1.codebook,
tag->t1.mob_cal_en);
@@ -315,18 +353,24 @@
dev_info(dev->mt76.dev, "Mem Col1 = %d, Mem Row1 = %d, Mem Col2 = %d, Mem Row2 = %d\n",
tag->t1.col_id1, tag->t1.row_id1, tag->t1.col_id2, tag->t1.row_id2);
-@@ -730,6 +754,47 @@ mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -728,6 +777,86 @@ mt7996_mcu_rx_bf_event(struct mt7996_dev *dev, struct sk_buff *skb)
break;
}
+ case UNI_EVENT_BF_CAL_PHASE: {
+ struct mt7996_ibf_cal_info *cal;
-+ struct mt7996_txbf_phase_out phase_out;
+ struct mt7996_txbf_phase *phase;
++ union {
++ struct mt7996_txbf_phase_out v1;
++ struct mt7992_txbf_phase_out v2;
++ } phase_out;
++ int phase_out_size = sizeof(struct mt7996_txbf_phase_out);
+
+ cal = (struct mt7996_ibf_cal_info *)skb->data;
+ phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
-+ memcpy(&phase_out, &cal->phase_out, sizeof(phase_out));
++ if (get_ibf_version(dev) == IBF_VER_2)
++ phase_out_size = sizeof(struct mt7992_txbf_phase_out);
++ memcpy(&phase_out, &cal->buf, phase_out_size);
+ switch (cal->cal_type) {
+ case IBF_PHASE_CAL_NORMAL:
+ case IBF_PHASE_CAL_NORMAL_INSTRUMENT:
@@ -347,16 +391,49 @@
+ break;
+ }
+
-+ dev_info(dev->mt76.dev, "c0_uh = %d, c1_uh = %d, c2_uh = %d, c3_uh = %d\n",
-+ phase_out.c0_uh, phase_out.c1_uh, phase_out.c2_uh, phase_out.c3_uh);
-+ dev_info(dev->mt76.dev, "c0_h = %d, c1_h = %d, c2_h = %d, c3_h = %d\n",
-+ phase_out.c0_h, phase_out.c1_h, phase_out.c2_h, phase_out.c3_h);
-+ dev_info(dev->mt76.dev, "c0_mh = %d, c1_mh = %d, c2_mh = %d, c3_mh = %d\n",
-+ phase_out.c0_mh, phase_out.c1_mh, phase_out.c2_mh, phase_out.c3_mh);
-+ dev_info(dev->mt76.dev, "c0_m = %d, c1_m = %d, c2_m = %d, c3_m = %d\n",
-+ phase_out.c0_m, phase_out.c1_m, phase_out.c2_m, phase_out.c3_m);
-+ dev_info(dev->mt76.dev, "c0_l = %d, c1_l = %d, c2_l = %d, c3_l = %d\n",
-+ phase_out.c0_l, phase_out.c1_l, phase_out.c2_l, phase_out.c3_l);
++ if (get_ibf_version(dev) == IBF_VER_2) {
++ dev_info(dev->mt76.dev,
++ "c0_uh = %d, c1_uh = %d, c2_uh = %d, c3_uh = %d c4_uh = %d\n",
++ phase_out.v2.c0_uh, phase_out.v2.c1_uh, phase_out.v2.c2_uh,
++ phase_out.v2.c3_uh, phase_out.v2.c4_uh);
++ dev_info(dev->mt76.dev,
++ "c0_h = %d, c1_h = %d, c2_h = %d, c3_h = %d c4_h = %d\n",
++ phase_out.v2.c0_h, phase_out.v2.c1_h, phase_out.v2.c2_h,
++ phase_out.v2.c3_h, phase_out.v2.c4_h);
++ dev_info(dev->mt76.dev,
++ "c0_mh = %d, c1_mh = %d, c2_mh = %d, c3_mh = %d c4_mh = %d\n",
++ phase_out.v2.c0_mh, phase_out.v2.c1_mh, phase_out.v2.c2_mh,
++ phase_out.v2.c3_mh, phase_out.v2.c4_mh);
++ dev_info(dev->mt76.dev,
++ "c0_m = %d, c1_m = %d, c2_m = %d, c3_m = %d c4_m = %d\n",
++ phase_out.v2.c0_m, phase_out.v2.c1_m, phase_out.v2.c2_m,
++ phase_out.v2.c3_m, phase_out.v2.c4_m);
++ dev_info(dev->mt76.dev,
++ "c0_l = %d, c1_l = %d, c2_l = %d, c3_l = %d c4_l = %d\n",
++ phase_out.v2.c0_l, phase_out.v2.c1_l, phase_out.v2.c2_l,
++ phase_out.v2.c3_l, phase_out.v2.c4_l);
++ } else {
++ dev_info(dev->mt76.dev,
++ "c0_uh = %d, c1_uh = %d, c2_uh = %d, c3_uh = %d\n",
++ phase_out.v1.c0_uh, phase_out.v1.c1_uh,
++ phase_out.v1.c2_uh, phase_out.v1.c3_uh);
++ dev_info(dev->mt76.dev,
++ "c0_h = %d, c1_h = %d, c2_h = %d, c3_h = %d\n",
++ phase_out.v1.c0_h, phase_out.v1.c1_h,
++ phase_out.v1.c2_h, phase_out.v1.c3_h);
++ dev_info(dev->mt76.dev,
++ "c0_mh = %d, c1_mh = %d, c2_mh = %d, c3_mh = %d\n",
++ phase_out.v1.c0_mh, phase_out.v1.c1_mh,
++ phase_out.v1.c2_mh, phase_out.v1.c3_mh);
++ dev_info(dev->mt76.dev,
++ "c0_m = %d, c1_m = %d, c2_m = %d, c3_m = %d\n",
++ phase_out.v1.c0_m, phase_out.v1.c1_m,
++ phase_out.v1.c2_m, phase_out.v1.c3_m);
++ dev_info(dev->mt76.dev,
++ "c0_l = %d, c1_l = %d, c2_l = %d, c3_l = %d\n",
++ phase_out.v1.c0_l, phase_out.v1.c1_l,
++ phase_out.v1.c2_l, phase_out.v1.c3_l);
++ }
+
+ break;
+ }
@@ -364,14 +441,14 @@
dev_info(dev->mt76.dev, "%s: unknown bf event tag %d\n",
__func__, event->tag);
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index 98c9660a..252ae98e 100644
+index 7a4140b57..58d61c517 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
-@@ -189,6 +189,164 @@ struct bf_txsnd_info {
+@@ -189,6 +189,165 @@ struct bf_txsnd_info {
u8 __rsv[2];
} __packed;
-+#define MAX_PHASE_GROUP_NUM 9
++#define MAX_PHASE_GROUP_NUM 13
+
+struct bf_phase_comp {
+ __le16 tag;
@@ -409,7 +486,8 @@
+ u8 cal_type;
+ u8 lna_gain_level;
+ u8 band_idx;
-+ u8 rsv[2];
++ u8 version;
++ u8 rsv[1];
+} __packed;
+
+struct bf_txcmd {
@@ -430,7 +508,7 @@
+ u8 band_idx;
+ u8 rsv[2];
+
-+ u8 buf[512];
++ u8 buf[640];
+} __packed;
+
+#define TXBF_DUT_MAC_SUBADDR 0x22
@@ -532,7 +610,7 @@
struct mt7996_mcu_bf_basic_event {
struct mt7996_mcu_rxd rxd;
-@@ -394,6 +552,181 @@ struct mt7996_pfmu_tag_event {
+@@ -394,6 +553,283 @@ struct mt7996_pfmu_tag_event {
struct mt7996_pfmu_tag2 t2;
};
@@ -572,7 +650,35 @@
+ u8 c3_uh;
+};
+
-+struct mt7996_txbf_rx_phase_2g {
++struct mt7992_txbf_phase_out {
++ u8 c0_l;
++ u8 c1_l;
++ u8 c2_l;
++ u8 c3_l;
++ u8 c4_l;
++ u8 c0_m;
++ u8 c1_m;
++ u8 c2_m;
++ u8 c3_m;
++ u8 c4_m;
++ u8 c0_mh;
++ u8 c1_mh;
++ u8 c2_mh;
++ u8 c3_mh;
++ u8 c4_mh;
++ u8 c0_h;
++ u8 c1_h;
++ u8 c2_h;
++ u8 c3_h;
++ u8 c4_h;
++ u8 c0_uh;
++ u8 c1_uh;
++ u8 c2_uh;
++ u8 c3_uh;
++ u8 c4_uh;
++};
++
++struct txbf_rx_phase {
+ u8 rx_uh;
+ u8 rx_h;
+ u8 rx_m;
@@ -580,7 +686,7 @@
+ u8 rx_ul;
+};
+
-+struct mt7996_txbf_rx_phase_5g {
++struct txbf_rx_phase_ext {
+ u8 rx_uh;
+ u8 rx_h;
+ u8 rx_mh;
@@ -590,12 +696,12 @@
+};
+
+struct mt7996_txbf_phase_info_2g {
-+ struct mt7996_txbf_rx_phase_2g r0;
-+ struct mt7996_txbf_rx_phase_2g r1;
-+ struct mt7996_txbf_rx_phase_2g r2;
-+ struct mt7996_txbf_rx_phase_2g r3;
-+ struct mt7996_txbf_rx_phase_2g r2_sx2;
-+ struct mt7996_txbf_rx_phase_2g r3_sx2;
++ struct txbf_rx_phase r0;
++ struct txbf_rx_phase r1;
++ struct txbf_rx_phase r2;
++ struct txbf_rx_phase r3;
++ struct txbf_rx_phase r2_sx2;
++ struct txbf_rx_phase r3_sx2;
+ u8 m_t0_h;
+ u8 m_t1_h;
+ u8 m_t2_h;
@@ -609,12 +715,12 @@
+};
+
+struct mt7996_txbf_phase_info_5g {
-+ struct mt7996_txbf_rx_phase_5g r0;
-+ struct mt7996_txbf_rx_phase_5g r1;
-+ struct mt7996_txbf_rx_phase_5g r2;
-+ struct mt7996_txbf_rx_phase_5g r3;
-+ struct mt7996_txbf_rx_phase_2g r2_sx2; /* no middle-high in r2_sx2 */
-+ struct mt7996_txbf_rx_phase_2g r3_sx2; /* no middle-high in r3_sx2 */
++ struct txbf_rx_phase_ext r0;
++ struct txbf_rx_phase_ext r1;
++ struct txbf_rx_phase_ext r2;
++ struct txbf_rx_phase_ext r3;
++ struct txbf_rx_phase r2_sx2; /* no middle-high in r2_sx2 */
++ struct txbf_rx_phase r3_sx2; /* no middle-high in r3_sx2 */
+ u8 m_t0_h;
+ u8 m_t1_h;
+ u8 m_t2_h;
@@ -627,49 +733,83 @@
+ u8 r3_sx2_reserved;
+};
+
++struct mt7992_txbf_phase_info_2g {
++ struct txbf_rx_phase_ext r0;
++ struct txbf_rx_phase_ext r1;
++ struct txbf_rx_phase_ext r2;
++ struct txbf_rx_phase_ext r3;
++ u8 m_t0_h;
++ u8 m_t1_h;
++ u8 m_t2_h;
++};
++
++struct mt7992_txbf_phase_info_5g {
++ struct txbf_rx_phase_ext r0;
++ struct txbf_rx_phase_ext r1;
++ struct txbf_rx_phase_ext r2;
++ struct txbf_rx_phase_ext r3;
++ struct txbf_rx_phase_ext r4;
++ u8 m_t0_h;
++ u8 m_t1_h;
++ u8 m_t2_h;
++ u8 m_t3_h;
++};
++
+struct mt7996_txbf_phase {
+ u8 status;
+ union {
-+ struct mt7996_txbf_phase_info_2g phase_2g;
-+ struct mt7996_txbf_phase_info_5g phase_5g;
++ union {
++ struct mt7996_txbf_phase_info_2g phase_2g;
++ struct mt7996_txbf_phase_info_5g phase_5g;
++ } v1;
++ union {
++ struct mt7992_txbf_phase_info_2g phase_2g;
++ struct mt7992_txbf_phase_info_5g phase_5g;
++ } v2;
++ u8 buf[44];
+ };
+};
+
-+#define phase_assign(group, field, dump, ...) ({ \
++#define phase_assign(group, v, field, dump, ...) ({ \
+ if (group) { \
-+ phase->phase_5g.field = cal->phase_5g.field; \
++ phase->v.phase_5g.field = cal->v.phase_5g.field; \
+ if (dump) \
-+ dev_info(dev->mt76.dev, "%s = %d\n", #field, phase->phase_5g.field); \
++ dev_info(dev->mt76.dev, "%s = %d\n", #field, phase->v.phase_5g.field); \
+ } else { \
-+ phase->phase_2g.field = cal->phase_5g.field; \
++ phase->v.phase_2g.field = cal->v.phase_5g.field; \
+ if (dump) \
-+ dev_info(dev->mt76.dev, "%s = %d\n", #field, phase->phase_2g.field); \
++ dev_info(dev->mt76.dev, "%s = %d\n", #field, phase->v.phase_2g.field); \
+ } \
+})
+
-+#define phase_assign_rx_g0(group, rx, ...) ({ \
-+ phase_assign(group, rx.rx_uh, false); \
-+ phase_assign(group, rx.rx_h, false); \
-+ phase_assign(group, rx.rx_m, false); \
-+ phase_assign(group, rx.rx_l, false); \
-+ phase_assign(group, rx.rx_ul, false); \
++#define phase_assign_rx(group, v, rx, dump, ...) ({ \
++ phase_assign(group, v, rx.rx_uh, dump); \
++ phase_assign(group, v, rx.rx_h, dump); \
++ phase_assign(group, v, rx.rx_m, dump); \
++ phase_assign(group, v, rx.rx_l, dump); \
++ phase_assign(group, v, rx.rx_ul, dump); \
+})
+
-+#define phase_assign_rx(group, rx, ...) ({ \
++#define phase_assign_rx_ext(group, v, rx, dump, ...) ({ \
++ phase_assign(group, v, rx.rx_uh, dump); \
++ phase_assign(group, v, rx.rx_h, dump); \
++ phase_assign(group, v, rx.rx_mh, dump); \
++ phase_assign(group, v, rx.rx_m, dump); \
++ phase_assign(group, v, rx.rx_l, dump); \
++ phase_assign(group, v, rx.rx_ul, dump); \
++})
++
++#define phase_assign_rx_v1(group, v, rx, ...) ({ \
+ if (group) { \
-+ phase_assign(group, rx.rx_uh, true); \
-+ phase_assign(group, rx.rx_h, true); \
-+ phase->phase_5g.rx.rx_mh = cal->phase_5g.rx.rx_mh; \
-+ dev_info(dev->mt76.dev, "%s.rx_mh = %d\n", #rx, phase->phase_5g.rx.rx_mh); \
-+ phase_assign(group, rx.rx_m, true); \
-+ phase_assign(group, rx.rx_l, true); \
-+ phase_assign(group, rx.rx_ul, true); \
++ phase_assign(group, v, rx.rx_uh, true); \
++ phase_assign(group, v, rx.rx_h, true); \
++ phase->v.phase_5g.rx.rx_mh = cal->v.phase_5g.rx.rx_mh; \
++ dev_info(dev->mt76.dev, "%s.rx_mh = %d\n", #rx, phase->v.phase_5g.rx.rx_mh); \
++ phase_assign(group, v, rx.rx_m, true); \
++ phase_assign(group, v, rx.rx_l, true); \
++ phase_assign(group, v, rx.rx_ul, true); \
+ } else { \
-+ phase_assign(group, rx.rx_uh, true); \
-+ phase_assign(group, rx.rx_h, true); \
-+ phase_assign(group, rx.rx_m, true); \
-+ phase_assign(group, rx.rx_l, true); \
-+ phase_assign(group, rx.rx_ul, true); \
++ phase_assign_rx(group, v, rx, true, ...); \
+ } \
+})
+
@@ -684,6 +824,14 @@
+ __le16 phi31;
+};
+
++struct mt7996_pfmu_data_5x5 {
++ __le16 subc_idx;
++ __le16 phi11;
++ __le16 phi21;
++ __le16 phi31;
++ __le16 phi41;
++};
++
+struct mt7996_ibf_cal_info {
+ struct mt7996_mcu_bf_basic_event event;
+
@@ -693,11 +841,24 @@
+ bool sx2;
+ u8 status;
+ u8 cal_type;
-+ u8 _rsv[2];
-+ struct mt7996_txbf_phase_out phase_out;
++ u8 nsts;
++ u8 version;
+ union {
-+ struct mt7996_txbf_phase_info_2g phase_2g;
-+ struct mt7996_txbf_phase_info_5g phase_5g;
++ struct {
++ struct mt7996_txbf_phase_out phase_out;
++ union {
++ struct mt7996_txbf_phase_info_2g phase_2g;
++ struct mt7996_txbf_phase_info_5g phase_5g;
++ };
++ } v1;
++ struct {
++ struct mt7992_txbf_phase_out phase_out;
++ union {
++ struct mt7992_txbf_phase_info_2g phase_2g;
++ struct mt7992_txbf_phase_info_5g phase_5g;
++ };
++ } v2;
++ u8 buf[64];
+ };
+} __packed;
+
@@ -709,12 +870,31 @@
+ IBF_PHASE_CAL_VERIFY_INSTRUMENT,
+};
+
++enum ibf_version {
++ IBF_VER_1,
++ IBF_VER_2 = 3,
++};
++
++static inline int get_ibf_version(struct mt7996_dev *dev)
++{
++ switch (mt76_chip(&dev->mt76)) {
++ case 0x7990:
++ return IBF_VER_1;
++ case 0x7992:
++ default:
++ return IBF_VER_2;
++ }
++}
++
-+#define MT7996_TXBF_SUBCAR_NUM 64
++#define MT7996_TXBF_SUBCAR_NUM 64
++#define MT7996_TXBF_PFMU_DATA_LEN (MT7996_TXBF_SUBCAR_NUM * sizeof(struct mt7996_pfmu_data))
++#define MT7996_TXBF_PFMU_DATA_LEN_5X5 (MT7996_TXBF_SUBCAR_NUM * \
++ sizeof(struct mt7996_pfmu_data_5x5))
+
enum {
UNI_EVENT_BF_PFMU_TAG = 0x5,
UNI_EVENT_BF_PFMU_DATA = 0x7,
-@@ -408,11 +741,6 @@ enum {
+@@ -408,11 +844,6 @@ enum {
UNI_EVENT_BF_MAX_NUM
};
@@ -727,7 +907,7 @@
__le16 wlan_idx0;
__le16 wlan_idx1;
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index e94f9a90..aa04d8d2 100644
+index 8ec1dc1c6..263737c52 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -326,6 +326,9 @@ enum offs_rev {
@@ -741,7 +921,7 @@
#define MT_WF_RMAC_BASE(_band) __BASE(WF_RMAC_BASE, (_band))
#define MT_WF_RMAC(_band, ofs) (MT_WF_RMAC_BASE(_band) + (ofs))
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
-index 26ae5827..2fb36a97 100644
+index 836211f98..5cec1eef6 100644
--- a/mt7996/testmode.c
+++ b/mt7996/testmode.c
@@ -23,6 +23,7 @@ enum {
@@ -893,7 +1073,7 @@
mt7996_tm_set(dev, SET_ID(TX_RATE), td->tx_rate_idx);
/* fix payload is OFDM */
mt7996_tm_set(dev, SET_ID(CONT_WAVE_MODE), CONT_WAVE_MODE_OFDM);
-@@ -1047,6 +1059,678 @@ mt7996_tm_set_ipi(struct mt7996_phy *phy)
+@@ -1047,6 +1059,730 @@ mt7996_tm_set_ipi(struct mt7996_phy *phy)
return 0;
}
@@ -957,9 +1137,9 @@
+ }
+
+ if (!dev->test.txbf_pfmu_data) {
++ /* allocate max size for 5x5 pfmu data */
+ pfmu_data = devm_kzalloc(dev->mt76.dev,
-+ sizeof(struct mt7996_pfmu_data) *
-+ MT7996_TXBF_SUBCAR_NUM,
++ MT7996_TXBF_PFMU_DATA_LEN_5X5,
+ GFP_KERNEL);
+ if (!pfmu_data)
+ return -ENOMEM;
@@ -1020,6 +1200,11 @@
+
+ td->tx_rate_mode = MT76_TM_TX_MODE_HT;
+ td->tx_rate_sgi = 0;
++ /* 5T5R ibf */
++ if (nss == 5) {
++ td->tx_rate_mode = MT76_TM_TX_MODE_VHT;
++ td->tx_rate_idx = 7;
++ }
+ } else {
+ if (td->is_txbf_dut) {
+ /* Enable ETxBF Capability */
@@ -1065,6 +1250,23 @@
+ return 0;
+}
+
++static inline void
++mt7996_tm_txbf_phase_copy(struct mt7996_dev *dev, void *des, void *src, int group)
++{
++ int phase_size;
++
++ if (group && get_ibf_version(dev) == IBF_VER_1)
++ phase_size = sizeof(struct mt7996_txbf_phase_info_5g);
++ else if (get_ibf_version(dev) == IBF_VER_1)
++ phase_size = sizeof(struct mt7996_txbf_phase_info_2g);
++ else if (group)
++ phase_size = sizeof(struct mt7992_txbf_phase_info_5g);
++ else
++ phase_size = sizeof(struct mt7992_txbf_phase_info_2g);
++
++ memcpy(des, src, phase_size);
++}
++
+static int
+mt7996_tm_txbf_phase_comp(struct mt7996_phy *phy, u16 *val)
+{
@@ -1082,12 +1284,10 @@
+ }
+ };
+ struct mt7996_txbf_phase *phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
++ int group = val[2];
+
-+ wait_event_timeout(dev->mt76.tx_wait, phase[val[2]].status != 0, HZ);
-+ if (val[2])
-+ memcpy(req.phase_comp.buf, &phase[val[2]].phase_5g, sizeof(req.phase_comp.buf));
-+ else
-+ memcpy(req.phase_comp.buf, &phase[val[2]].phase_2g, sizeof(req.phase_comp.buf));
++ wait_event_timeout(dev->mt76.tx_wait, phase[group].status != 0, HZ);
++ mt7996_tm_txbf_phase_copy(dev, req.phase_comp.buf, phase[group].buf, group);
+
+ pr_info("ibf cal process: phase comp info\n");
+ print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
@@ -1149,12 +1349,12 @@
+ };
+ u8 ndp_rate, ndpa_rate, rept_poll_rate, bf_bw;
+
-+ if (td->tx_rate_mode == MT76_TM_TX_MODE_HE_SU ||
-+ td->tx_rate_mode == MT76_TM_TX_MODE_EHT_SU) {
++ if ((td->tx_rate_mode == MT76_TM_TX_MODE_HE_SU ||
++ td->tx_rate_mode == MT76_TM_TX_MODE_EHT_SU) && !td->ibf) {
+ rept_poll_rate = 0x49;
+ ndpa_rate = 0x49;
+ ndp_rate = 0;
-+ } else if (td->tx_rate_mode == MT76_TM_TX_MODE_VHT) {
++ } else if (td->tx_rate_mode == MT76_TM_TX_MODE_VHT && !td->ibf) {
+ rept_poll_rate = 0x9;
+ ndpa_rate = 0x9;
+ ndp_rate = 0;
@@ -1165,8 +1365,16 @@
+ ndp_rate = 8;
+ else if (nr == 2)
+ ndp_rate = 16;
++ else if (nr == 4)
++ ndp_rate = 32;
+ else
+ ndp_rate = 24;
++
++ /* 5T5R ebf profile for ibf cal */
++ if (nr == 4 && td->ibf && ebf) {
++ ndp_rate = 0;
++ ndpa_rate = 11;
++ }
+ }
+
+ bf_bw = mt7996_tm_bw_mapping(phy->mt76->chandef.width, BW_MAP_NL_TO_BF);
@@ -1199,7 +1407,7 @@
+ struct mt76_testmode_data *td = &phy->mt76->test;
+ struct mt7996_dev *dev = phy->dev;
+ struct mt7996_pfmu_tag *tag = dev->test.txbf_pfmu_tag;
-+ u8 pfmu_idx = val[0], nc = val[2], nr;
++ u8 rate, pfmu_idx = val[0], nc = val[2], nr;
+ int ret;
+ bool is_atenl = val[5];
+
@@ -1207,6 +1415,8 @@
+ nr = 1;
+ else if (td->tx_antenna_mask == 7)
+ nr = 2;
++ else if (td->tx_antenna_mask == 31)
++ nr = 4;
+ else
+ nr = 3;
+
@@ -1230,7 +1440,8 @@
+ tag->t1.row_id2 = 5;
+ tag->t1.row_id3 = 6;
+ tag->t1.row_id4 = 7;
-+ tag->t1.lm = mt7996_tm_rate_mapping(MT76_TM_TX_MODE_OFDM, RATE_MODE_TO_LM);
++ rate = nr == 4 ? td->tx_rate_mode : MT76_TM_TX_MODE_OFDM;
++ tag->t1.lm = mt7996_tm_rate_mapping(rate, RATE_MODE_TO_LM);
+
+ tag->t2.ibf_timeout = 0xff;
+ tag->t2.ibf_nr = nr;
@@ -1278,6 +1489,7 @@
+ .cal_type = val[3],
+ .lna_gain_level = val[4],
+ .band_idx = phy->mt76->band_idx,
++ .version = val[5],
+ },
+ };
+ struct mt7996_txbf_phase *phase = (struct mt7996_txbf_phase *)dev->test.txbf_phase_cal;
@@ -1292,7 +1504,6 @@
+static int
+mt7996_tm_txbf_profile_update_all(struct mt7996_phy *phy, u16 *val)
+{
-+#define MT7996_TXBF_PFMU_DATA_LEN (MT7996_TXBF_SUBCAR_NUM * sizeof(struct mt7996_pfmu_data))
+ struct mt76_testmode_data *td = &phy->mt76->test;
+ u8 nss = hweight8(td->tx_antenna_mask);
+ u16 pfmu_idx = val[0];
@@ -1301,8 +1512,10 @@
+ u16 angle21 = val[3];
+ u16 angle31 = val[4];
+ u16 angle41 = val[5];
-+ s16 phi11 = 0, phi21 = 0, phi31 = 0;
-+ struct mt7996_pfmu_data *pfmu_data;
++ u16 angle51 = val[6];
++ s16 phi11 = 0, phi21 = 0, phi31 = 0, phi41 = 0;
++ s16 *pfmu_data;
++ int offs = subc_id * sizeof(struct mt7996_pfmu_data) / sizeof(*pfmu_data);
+
+ if (subc_id > MT7996_TXBF_SUBCAR_NUM - 1)
+ return -EINVAL;
@@ -1312,35 +1525,51 @@
+ } else if (nss == 3) {
+ phi11 = (s16)(angle31 - angle11);
+ phi21 = (s16)(angle31 - angle21);
++ } else if (nss == 5) {
++ phi11 = (s16)(angle51 - angle11);
++ phi21 = (s16)(angle51 - angle21);
++ phi31 = (s16)(angle51 - angle31);
++ phi41 = (s16)(angle51 - angle41);
++ offs = subc_id * sizeof(struct mt7996_pfmu_data_5x5) / sizeof(*pfmu_data);
+ } else {
+ phi11 = (s16)(angle41 - angle11);
+ phi21 = (s16)(angle41 - angle21);
+ phi31 = (s16)(angle41 - angle31);
+ }
+
-+ pfmu_data = (struct mt7996_pfmu_data *)phy->dev->test.txbf_pfmu_data;
-+ pfmu_data = &pfmu_data[subc_id];
++ pfmu_data = (s16 *)phy->dev->test.txbf_pfmu_data;
++ pfmu_data += offs;
+
+ if (subc_id < 32)
-+ pfmu_data->subc_idx = cpu_to_le16(subc_id + 224);
++ pfmu_data[0] = cpu_to_le16(subc_id + 224);
+ else
-+ pfmu_data->subc_idx = cpu_to_le16(subc_id - 32);
++ pfmu_data[0] = cpu_to_le16(subc_id - 32);
+
-+ pfmu_data->phi11 = cpu_to_le16(phi11);
-+ pfmu_data->phi21 = cpu_to_le16(phi21);
-+ pfmu_data->phi31 = cpu_to_le16(phi31);
++ pfmu_data[1] = cpu_to_le16(phi11);
++ pfmu_data[2] = cpu_to_le16(phi21);
++ pfmu_data[3] = cpu_to_le16(phi31);
++ if (nss == 5)
++ pfmu_data[4] = cpu_to_le16(phi41);
++
+ if (subc_id == MT7996_TXBF_SUBCAR_NUM - 1) {
+ struct mt7996_dev *dev = phy->dev;
+ struct mt7996_tm_bf_req req = {
+ .pfmu_data_all = {
-+ .tag = cpu_to_le16(BF_PROFILE_WRITE_20M_ALL),
++ .tag = cpu_to_le16(BF_PROFILE_WRITE_20M_ALL_5X5),
+ .len = cpu_to_le16(sizeof(req.pfmu_data_all)),
+ .pfmu_id = pfmu_idx,
+ .band_idx = phy->mt76->band_idx,
+ },
+ };
++ int size = MT7996_TXBF_PFMU_DATA_LEN_5X5;
+
-+ memcpy(req.pfmu_data_all.buf, dev->test.txbf_pfmu_data, MT7996_TXBF_PFMU_DATA_LEN);
++ if (nss != 5) {
++ size = MT7996_TXBF_PFMU_DATA_LEN;
++ req.pfmu_data_all.tag = cpu_to_le16(BF_PROFILE_WRITE_20M_ALL);
++ req.pfmu_data_all.len = cpu_to_le16(sizeof(req.pfmu_data_all) -
++ MT7996_TXBF_PFMU_DATA_LEN_5X5 + size);
++ }
++ memcpy(req.pfmu_data_all.buf, dev->test.txbf_pfmu_data, size);
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(BF),
+ &req, sizeof(req), true);
@@ -1353,7 +1582,9 @@
+mt7996_tm_txbf_e2p_update(struct mt7996_phy *phy)
+{
+#define TXBF_PHASE_EEPROM_START_OFFSET 0xc00
-+#define TXBF_PHASE_GROUP_EEPROM_OFFSET 0x2e
++#define TXBF_PHASE_GROUP_EEPROM_OFFSET_VER_1 46
++#define TXBF_PHASE_G0_EEPROM_OFFSET_VER_2 sizeof(struct mt7992_txbf_phase_info_2g)
++#define TXBF_PHASE_GX_EEPROM_OFFSET_VER_2 sizeof(struct mt7992_txbf_phase_info_5g)
+ struct mt7996_txbf_phase *phase, *p;
+ struct mt7996_dev *dev = phy->dev;
+ u8 *eeprom = dev->mt76.eeprom.data;
@@ -1369,11 +1600,12 @@
+ continue;
+
+ /* copy phase cal data to eeprom */
-+ if (i)
-+ memcpy(eeprom + offset, &p->phase_5g, sizeof(p->phase_5g));
++ mt7996_tm_txbf_phase_copy(dev, eeprom + offset, p->buf, i);
++ if (get_ibf_version(dev) == IBF_VER_1)
++ offset += TXBF_PHASE_GROUP_EEPROM_OFFSET_VER_1;
+ else
-+ memcpy(eeprom + offset, &p->phase_2g, sizeof(p->phase_2g));
-+ offset += TXBF_PHASE_GROUP_EEPROM_OFFSET;
++ offset += i ? TXBF_PHASE_GX_EEPROM_OFFSET_VER_2 :
++ TXBF_PHASE_G0_EEPROM_OFFSET_VER_2;
+ }
+
+ return 0;
@@ -1572,7 +1804,7 @@
static void
mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
{
-@@ -1086,6 +1770,8 @@ mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
+@@ -1086,6 +1822,8 @@ mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
mt7996_tm_set_ipi(phy);
if (changed & BIT(TM_CHANGED_IPI_RESET))
mt7996_tm_ipi_hist_ctrl(phy, NULL, RDD_SET_IPI_HIST_RESET);
@@ -1582,7 +1814,7 @@
static int
diff --git a/mt7996/testmode.h b/mt7996/testmode.h
-index 78662b2e..f97ccb26 100644
+index 78662b2ed..f97ccb267 100644
--- a/mt7996/testmode.h
+++ b/mt7996/testmode.h
@@ -27,6 +27,17 @@ enum {
@@ -1625,10 +1857,10 @@
__le32 func_data;
u8 band_idx;
diff --git a/testmode.c b/testmode.c
-index 69147f86..a5c07f8d 100644
+index 69147f866..b9f710970 100644
--- a/testmode.c
+++ b/testmode.c
-@@ -462,6 +462,42 @@ out:
+@@ -462,6 +462,44 @@ out:
return err;
}
@@ -1636,26 +1868,28 @@
+mt76_testmode_txbf_profile_update_all_cmd(struct mt76_phy *phy, struct nlattr **tb, u32 state)
+{
+#define PARAM_UNIT 5
++#define PARAM_UNIT_5X5 6
+ static u8 pfmu_idx;
+ struct mt76_testmode_data *td = &phy->test;
+ struct mt76_dev *dev = phy->dev;
+ struct nlattr *cur;
-+ u16 tmp_val[PARAM_UNIT], *val = td->txbf_param;
++ u16 tmp_val[PARAM_UNIT_5X5], *val = td->txbf_param;
+ int idx, rem, ret, i = 0;
++ int param_len = td->tx_antenna_mask == 31 ? PARAM_UNIT_5X5 : PARAM_UNIT;
+
+ memset(td->txbf_param, 0, sizeof(td->txbf_param));
+ nla_for_each_nested(cur, tb[MT76_TM_ATTR_TXBF_PARAM], rem) {
+ if (nla_len(cur) != 2)
+ return -EINVAL;
-+ idx = i % PARAM_UNIT;
++ idx = i % param_len;
+ tmp_val[idx] = nla_get_u16(cur);
+ if (idx == 1 && (tmp_val[idx] == 0xf0 || tmp_val[idx] == 0xff)) {
+ pfmu_idx = tmp_val[0];
+ return 0;
+ }
-+ if (idx == PARAM_UNIT - 1) {
++ if (idx == param_len - 1) {
+ val[0] = pfmu_idx;
-+ memcpy(val + 1, tmp_val, sizeof(tmp_val));
++ memcpy(val + 1, tmp_val, param_len * sizeof(u16));
+ if (dev->test_ops->set_params) {
+ ret = dev->test_ops->set_params(phy, tb, state);
+ if (ret)
@@ -1671,7 +1905,7 @@
int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
void *data, int len)
{
-@@ -607,6 +643,30 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -607,6 +645,30 @@ int mt76_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
}
}
@@ -1703,7 +1937,7 @@
err = dev->test_ops->set_params(phy, tb, state);
if (err)
diff --git a/testmode.h b/testmode.h
-index 5d677f8c..bda7624a 100644
+index 5d677f8c1..bda7624ad 100644
--- a/testmode.h
+++ b/testmode.h
@@ -286,6 +286,59 @@ enum mt76_testmode_eeprom_action {
@@ -1767,7 +2001,7 @@
#endif
diff --git a/tools/fields.c b/tools/fields.c
-index 77696ce7..f793d1a5 100644
+index 77696ce7b..f793d1a51 100644
--- a/tools/fields.c
+++ b/tools/fields.c
@@ -44,6 +44,30 @@ static const char * const testmode_offchan_bw[] = {
@@ -1829,5 +2063,5 @@
FIELD(u8, OFF_CH_SCAN_CENTER_CH, "offchan_center_ch"),
FIELD_ENUM(OFF_CH_SCAN_BW, "offchan_bw", testmode_offchan_bw),
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1035-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0047-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch
similarity index 86%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1035-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0047-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch
index 326198c..ff7ffa4 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1035-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0047-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch
@@ -1,7 +1,7 @@
-From 68abdcf3519187da5d7fe324b8aa5cbb64ea13a3 Mon Sep 17 00:00:00 2001
+From 2ad633b14de62c86fbc40d1ab2a1d3417a10d2b7 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 22 Sep 2023 12:33:06 +0800
-Subject: [PATCH 1035/1044] mtk: wifi: mt76: mt7996: add zwdfs cert mode
+Subject: [PATCH 047/116] mtk: wifi: mt76: mt7996: add zwdfs cert mode
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
@@ -13,10 +13,10 @@
5 files changed, 100 insertions(+), 12 deletions(-)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 6e3047ba..ded28e9a 100644
+index 8f3e5ebfd..8756a5df8 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -4506,18 +4506,7 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)
+@@ -4496,18 +4496,7 @@ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable)
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
u8 rx_sel, u8 val)
{
@@ -36,7 +36,7 @@
.tag = cpu_to_le16(UNI_RDD_CTRL_PARM),
.len = cpu_to_le16(sizeof(req) - 4),
.ctrl = cmd,
-@@ -4530,6 +4519,37 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+@@ -4520,6 +4509,37 @@ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
&req, sizeof(req), true);
}
@@ -75,7 +75,7 @@
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 054a616b..398bf3d2 100644
+index 663128176..f5e91a898 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -119,6 +119,20 @@ struct mt7996_mcu_rdd_report {
@@ -100,10 +100,10 @@
u8 _rsv[4];
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 2f76a0af..f937008f 100644
+index 84fbd0fb0..7f7a6223b 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -517,8 +517,11 @@ enum mt7996_rdd_cmd {
+@@ -523,8 +523,11 @@ enum mt7996_rdd_cmd {
RDD_READ_PULSE,
RDD_RESUME_BF,
RDD_IRQ_OFF,
@@ -115,7 +115,7 @@
static inline struct mt7996_phy *
mt7996_hw_phy(struct ieee80211_hw *hw)
{
-@@ -660,6 +663,8 @@ int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
+@@ -666,6 +669,8 @@ int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
u8 rx_sel, u8 val);
@@ -125,10 +125,10 @@
struct cfg80211_chan_def *chandef);
int mt7996_mcu_set_fixed_rate_table(struct mt7996_phy *phy, u8 table_idx,
diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index 477c5c42..c7fd3278 100644
+index 7ab64471f..ba00ef359 100644
--- a/mt7996/vendor.c
+++ b/mt7996/vendor.c
-@@ -102,6 +102,11 @@ rfeature_ctrl_policy[NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL] = {
+@@ -108,6 +108,11 @@ rfeature_ctrl_policy[NUM_MTK_VENDOR_ATTRS_RFEATURE_CTRL] = {
[MTK_VENDOR_ATTR_RFEATURE_CTRL_TRIG_TXBF] = { .type = NLA_U8 },
};
@@ -140,7 +140,7 @@
struct mt7996_amnt_data {
u8 idx;
u8 addr[ETH_ALEN];
-@@ -851,6 +856,27 @@ static int mt7996_vendor_wireless_ctrl(struct wiphy *wiphy,
+@@ -916,6 +921,27 @@ static int mt7996_vendor_wireless_ctrl(struct wiphy *wiphy,
return 0;
}
@@ -168,7 +168,7 @@
static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
{
.info = {
-@@ -945,6 +971,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
+@@ -1021,6 +1047,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
.policy = rfeature_ctrl_policy,
.maxattr = MTK_VENDOR_ATTR_RFEATURE_CTRL_MAX,
},
@@ -187,7 +187,7 @@
void mt7996_vendor_register(struct mt7996_phy *phy)
diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 7011914b..920b6e6a 100644
+index 2ee1339a5..7c812f914 100644
--- a/mt7996/vendor.h
+++ b/mt7996/vendor.h
@@ -14,6 +14,7 @@ enum mtk_nl80211_vendor_subcmds {
@@ -195,10 +195,10 @@
MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
+ MTK_NL80211_VENDOR_SUBCMD_BACKGROUND_RADAR_CTRL = 0xcb,
+ MTK_NL80211_VENDOR_SUBCMD_PP_CTRL = 0xcc,
};
- enum mtk_vendor_attr_edcca_ctrl {
-@@ -126,6 +127,17 @@ enum mtk_vendor_attr_wireless_dump {
+@@ -127,6 +128,17 @@ enum mtk_vendor_attr_wireless_dump {
NUM_MTK_VENDOR_ATTRS_WIRELESS_DUMP - 1
};
@@ -217,5 +217,5 @@
BW_SIGNALING_DISABLE,
BW_SIGNALING_STATIC,
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1036-mtk-wifi-mt76-testmode-add-channel-68-96.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0048-mtk-wifi-mt76-testmode-add-channel-68-96.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1036-mtk-wifi-mt76-testmode-add-channel-68-96.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0048-mtk-wifi-mt76-testmode-add-channel-68-96.patch
index e3e2aa7..3aa9441 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1036-mtk-wifi-mt76-testmode-add-channel-68-96.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0048-mtk-wifi-mt76-testmode-add-channel-68-96.patch
@@ -1,7 +1,7 @@
-From b159ab04d85f593ca0785404469f2ea23eababef Mon Sep 17 00:00:00 2001
+From 097d8d847d49f831848e990e60091d10bd9c59a5 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Mon, 11 Sep 2023 14:43:07 +0800
-Subject: [PATCH 1036/1044] mtk: wifi: mt76: testmode: add channel 68 & 96
+Subject: [PATCH 048/116] mtk: wifi: mt76: testmode: add channel 68 & 96
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
@@ -9,10 +9,12 @@
Also, "mtk: wifi: mt76: testmode: add channel 68 & 96" can be
merged into to "mtk: wifi: mt76: testmode: add basic testmode support"
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Fix 5g channel list size
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mac80211.c | 9 +++++++++
@@ -24,10 +26,10 @@
6 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/mac80211.c b/mac80211.c
-index ae040ec4..f7cd47f9 100644
+index 0590aaf2e..8091a60e0 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -35,6 +35,15 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
+@@ -34,6 +34,15 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
CHAN5G(60, 5300),
CHAN5G(64, 5320),
@@ -44,7 +46,7 @@
CHAN5G(104, 5520),
CHAN5G(108, 5540),
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index d93b1558..1eb292c0 100644
+index f97d76cc4..acf5bc179 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -18,6 +18,17 @@ const struct ieee80211_channel dpd_2g_ch_list_bw20[] = {
@@ -73,7 +75,7 @@
const u32 dpd_5g_bw160_ch_num = ARRAY_SIZE(dpd_5g_ch_list_bw160);
const u32 dpd_6g_bw160_ch_num = ARRAY_SIZE(dpd_6g_ch_list_bw160);
const u32 dpd_6g_bw320_ch_num = ARRAY_SIZE(dpd_6g_ch_list_bw320);
-@@ -138,8 +150,8 @@ mt7996_get_dpd_per_band_size(struct mt7996_dev *dev, enum nl80211_band band)
+@@ -168,8 +180,8 @@ mt7996_get_dpd_per_band_size(struct mt7996_dev *dev, enum nl80211_band band)
if (band == NL80211_BAND_2GHZ)
dpd_size = dpd_2g_bw20_ch_num * DPD_PER_CH_BW20_SIZE;
else if (band == NL80211_BAND_5GHZ)
@@ -84,7 +86,7 @@
else
dpd_size = mphy->sband_6g.sband.n_channels * DPD_PER_CH_BW20_SIZE +
(dpd_6g_bw160_ch_num + dpd_6g_bw320_ch_num) * DPD_PER_CH_GT_BW20_SIZE;
-@@ -399,6 +411,39 @@ out:
+@@ -431,6 +443,39 @@ out:
return ret;
}
@@ -125,7 +127,7 @@
{
struct mt76_dev *mdev = &dev->mt76;
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 8f0f87b6..3e9992a3 100644
+index 03a4fd07d..9a15b4462 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -67,6 +67,8 @@ enum mt7996_eeprom_field {
@@ -138,10 +140,10 @@
extern const u32 dpd_5g_bw160_ch_num;
extern const struct ieee80211_channel dpd_6g_ch_list_bw160[];
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index ded28e9a..cf46fee4 100644
+index 8756a5df8..97bf2969e 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3780,7 +3780,8 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3766,7 +3766,8 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
chan_list_size = mphy->sband_5g.sband.n_channels;
base_offset += dpd_size_2g;
if (bw == NL80211_CHAN_WIDTH_160) {
@@ -151,7 +153,7 @@
per_chan_size = DPD_PER_CH_GT_BW20_SIZE;
cal_id = RF_DPD_FLAT_5G_MEM_CAL;
chan_list = dpd_5g_ch_list_bw160;
-@@ -3789,6 +3790,9 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3775,6 +3776,9 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
/* apply (center channel - 2)'s dpd cal data for bw 40/80 channels */
channel -= 2;
}
@@ -161,7 +163,7 @@
break;
case NL80211_BAND_6GHZ:
dpd_mask = MT_EE_WIFI_CAL_DPD_6G;
-@@ -3828,6 +3832,10 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3814,6 +3818,10 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
if (idx == chan_list_size)
return -EINVAL;
@@ -173,7 +175,7 @@
for (i = 0; i < per_chan_size / MT_EE_CAL_UNIT; i++) {
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
-index 2fb36a97..0dc6629d 100644
+index 5cec1eef6..95d3bde03 100644
--- a/mt7996/testmode.c
+++ b/mt7996/testmode.c
@@ -531,6 +531,11 @@ mt7996_tm_dpd_prek_send_req(struct mt7996_phy *phy, struct mt7996_tm_req *req,
@@ -227,7 +229,7 @@
return first_control + offset;
diff --git a/mt7996/testmode.h b/mt7996/testmode.h
-index f97ccb26..ba1767ae 100644
+index f97ccb267..ba1767aed 100644
--- a/mt7996/testmode.h
+++ b/mt7996/testmode.h
@@ -38,9 +38,9 @@ enum {
@@ -244,5 +246,5 @@
enum bw_mapping_method {
BW_MAP_NL_TO_FW,
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1038-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0049-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch
similarity index 95%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1038-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0049-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch
index b005bee..7279514 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1038-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0049-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch
@@ -1,13 +1,13 @@
-From 911e50206b1155bb240eaa7670fa6715ac6cb500 Mon Sep 17 00:00:00 2001
+From 70f6d9e12225fb10db626a41cd0cd81439f2c814 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Thu, 12 Oct 2023 16:17:33 +0800
-Subject: [PATCH 1038/1044] mtk: wifi: mt76: testmode: add kite testmode
- support
+Subject: [PATCH 049/116] mtk: wifi: mt76: testmode: add kite testmode support
Add Kite testmode support
1. avoid entering connac 2 testmode flow in kite
2. refactor prek implementation for handling chip difference
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt7996/eeprom.c | 63 +++++++++++++-----------------
@@ -19,7 +19,7 @@
6 files changed, 198 insertions(+), 120 deletions(-)
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 1eb292c0..39e65010 100644
+index acf5bc179..215d81e31 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
@@ -29,12 +29,39 @@ const struct ieee80211_channel dpd_5g_skip_ch_list[] = {
@@ -74,8 +74,8 @@
-
static int mt7996_check_eeprom(struct mt7996_dev *dev)
{
- #define FEM_INT 0
-@@ -129,36 +150,6 @@ const char *mt7996_eeprom_name(struct mt7996_dev *dev)
+ u8 *eeprom = dev->mt76.eeprom.data;
+@@ -159,36 +180,6 @@ const char *mt7996_eeprom_name(struct mt7996_dev *dev)
}
}
@@ -110,10 +110,10 @@
-}
-
static int
- mt7996_eeprom_load_default(struct mt7996_dev *dev)
+ mt7996_eeprom_load_bin(struct mt7996_dev *dev)
{
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 3e9992a3..0d05e75e 100644
+index 9a15b4462..fa9c31e7a 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -45,36 +45,69 @@ enum mt7996_eeprom_field {
@@ -211,10 +211,10 @@
#define RF_DPD_FLAT_CAL BIT(28)
#define RF_PRE_CAL BIT(29)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index cf46fee4..a39b8bab 100644
+index 97bf2969e..3e92a2742 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3749,13 +3749,11 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3735,13 +3735,11 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
enum nl80211_chan_width bw = chandef->width;
const struct ieee80211_channel *chan_list;
u32 cal_id, chan_list_size, base_offset = 0, offs = MT_EE_DO_PRE_CAL;
@@ -230,7 +230,7 @@
switch (band) {
case NL80211_BAND_2GHZ:
-@@ -3771,27 +3769,35 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3757,27 +3755,35 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
return 0;
cal_id = RF_DPD_FLAT_CAL;
chan_list = dpd_2g_ch_list_bw20;
@@ -272,7 +272,7 @@
return 0;
break;
case NL80211_BAND_6GHZ:
-@@ -3799,20 +3805,27 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3785,20 +3791,27 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
cal_id = RF_DPD_FLAT_6G_CAL;
chan_list = mphy->sband_6g.sband.channels;
chan_list_size = mphy->sband_6g.sband.n_channels;
@@ -305,7 +305,7 @@
} else if (bw > NL80211_CHAN_WIDTH_20) {
/* apply (center channel - 2)'s dpd cal data for bw 40/80 channels */
channel -= 2;
-@@ -3832,9 +3845,8 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
+@@ -3818,9 +3831,8 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy)
if (idx == chan_list_size)
return -EINVAL;
@@ -318,10 +318,10 @@
cal += MT_EE_CAL_GROUP_SIZE + base_offset + idx * per_chan_size;
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index f937008f..881328be 100644
+index 7f7a6223b..0ebeb2403 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -195,6 +195,19 @@ struct mt7996_twt_flow {
+@@ -194,6 +194,19 @@ struct mt7996_twt_flow {
DECLARE_EWMA(avg_signal, 10, 8)
@@ -341,7 +341,7 @@
struct mt7996_sta {
struct mt76_wcid wcid; /* must be first */
-@@ -457,6 +470,10 @@ struct mt7996_dev {
+@@ -463,6 +476,10 @@ struct mt7996_dev {
void *cal;
u32 cur_prek_offset;
@@ -352,7 +352,7 @@
struct {
u16 table_mask;
-@@ -593,7 +610,6 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
+@@ -599,7 +616,6 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy);
int mt7996_eeprom_get_target_power(struct mt7996_dev *dev,
struct ieee80211_channel *chan);
s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band);
@@ -361,7 +361,7 @@
void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
void mt7996_dma_prefetch(struct mt7996_dev *dev);
diff --git a/mt7996/testmode.c b/mt7996/testmode.c
-index 0dc6629d..44ec84cc 100644
+index 95d3bde03..9fa4edcd6 100644
--- a/mt7996/testmode.c
+++ b/mt7996/testmode.c
@@ -434,7 +434,7 @@ mt7996_tm_set_tx_cont(struct mt7996_phy *phy, bool en)
@@ -551,7 +551,7 @@
cal_idx = le32_to_cpu(data->cal_idx);
cal_type = le32_to_cpu(data->cal_type);
diff --git a/testmode.c b/testmode.c
-index a5c07f8d..09ab68ce 100644
+index b9f710970..2dd184e48 100644
--- a/testmode.c
+++ b/testmode.c
@@ -37,6 +37,11 @@ const struct nla_policy mt76_tm_policy[NUM_MT76_TM_ATTRS] = {
@@ -594,5 +594,5 @@
return;
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1039-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0050-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch
similarity index 86%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1039-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0050-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch
index 744e679..87a2270 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1039-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0050-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch
@@ -1,16 +1,17 @@
-From 9c7e1159e0daa47df31d51c73b26a12b7c3c0a42 Mon Sep 17 00:00:00 2001
+From 77ec17101af8185206e06bc70fce00fd9b1d178f Mon Sep 17 00:00:00 2001
From: Michael-CY Lee <michael-cy.lee@mediatek.com>
Date: Tue, 14 Nov 2023 11:27:06 +0800
-Subject: [PATCH 1039/1044] mtk: wifi: mt76: mt7996: assign DEAUTH to ALTX
- queue for CERT
+Subject: [PATCH 050/116] mtk: wifi: mt76: mt7996: assign DEAUTH to ALTX queue
+ for CERT
Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+CR-Id: WCNCR00289305
---
mt7996/mac.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index bf42ae07..6fa46e46 100644
+index 70f0c56cc..727d1fb80 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -753,6 +753,8 @@ static void
@@ -38,5 +39,5 @@
mgmt->u.action.category == WLAN_CATEGORY_BACK &&
mgmt->u.action.u.addba_req.action_code == WLAN_ACTION_ADDBA_REQ)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1040-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0051-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch
similarity index 77%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1040-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0051-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch
index b1cd4c6..98055c0 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1040-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0051-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch
@@ -1,8 +1,8 @@
-From ba07e0c01317f0d39fb56aceef557c04c0f770c2 Mon Sep 17 00:00:00 2001
+From 0eb032654d67a0afcd486a730270bc7e069e1f99 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <meichia.chiu@mediatek.com>
Date: Wed, 22 Nov 2023 22:42:09 +0800
-Subject: [PATCH 1040/1044] mtk: wifi: mt76: mt7996: add no_beacon vendor
- command for cert
+Subject: [PATCH 051/116] mtk: wifi: mt76: mt7996: add no_beacon vendor command
+ for cert
Add the vendor command to disable/enable beacon
@@ -12,6 +12,8 @@
0: enable beacon
1: disable beacon
+CR-ID: WCNCR00240597
+Change-Id: Ia16707317135aeb02d6a5f6d50983e5174cc9e77
Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
---
mt7996/mcu.c | 11 +++++++++++
@@ -21,10 +23,10 @@
4 files changed, 65 insertions(+)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index a39b8bab..c97a3204 100644
+index 3e92a2742..2b12d5c12 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -5058,4 +5058,15 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+@@ -5100,4 +5100,15 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
break;
}
}
@@ -41,10 +43,10 @@
+}
#endif
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 881328be..bb2cee92 100644
+index 0ebeb2403..1bba5450f 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -829,6 +829,7 @@ void mt7996_set_wireless_amsdu(struct ieee80211_hw *hw, u8 en);
+@@ -835,6 +835,7 @@ void mt7996_set_wireless_amsdu(struct ieee80211_hw *hw, u8 en);
void mt7996_mcu_set_mimo(struct mt7996_phy *phy);
int mt7996_set_muru_cfg(struct mt7996_phy *phy, u8 action, u8 val);
int mt7996_mcu_set_muru_cfg(struct mt7996_phy *phy, void *data);
@@ -53,11 +55,11 @@
int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index 9732ed28..c87cc5c1 100644
+index ba00ef359..31688c373 100644
--- a/mt7996/vendor.c
+++ b/mt7996/vendor.c
-@@ -112,6 +112,11 @@ pp_ctrl_policy[NUM_MTK_VENDOR_ATTRS_PP_CTRL] = {
- [MTK_VENDOR_ATTR_PP_MODE] = { .type = NLA_U8 },
+@@ -113,6 +113,11 @@ background_radar_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BACKGROUND_RADAR_CTRL] = {
+ [MTK_VENDOR_ATTR_BACKGROUND_RADAR_CTRL_MODE] = {.type = NLA_U8 },
};
+static const struct nla_policy
@@ -68,8 +70,8 @@
struct mt7996_amnt_data {
u8 idx;
u8 addr[ETH_ALEN];
-@@ -904,6 +909,31 @@ static int mt7996_vendor_pp_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
- return err;
+@@ -942,6 +947,31 @@ static int mt7996_vendor_background_radar_mode_ctrl(struct wiphy *wiphy,
+ return mt7996_mcu_rdd_background_disable_timer(dev, !!background_radar_mode);
}
+static int mt7996_vendor_beacon_ctrl(struct wiphy *wiphy,
@@ -100,9 +102,9 @@
static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
{
.info = {
-@@ -1020,6 +1050,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = pp_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_PP_CTRL_MAX,
+@@ -1058,6 +1088,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
+ .policy = background_radar_ctrl_policy,
+ .maxattr = MTK_VENDOR_ATTR_BACKGROUND_RADAR_CTRL_MAX,
},
+ {
+ .info = {
@@ -119,7 +121,7 @@
void mt7996_vendor_register(struct mt7996_phy *phy)
diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 98128965..e7d88828 100644
+index 7c812f914..0d1ef3228 100644
--- a/mt7996/vendor.h
+++ b/mt7996/vendor.h
@@ -16,6 +16,7 @@ enum mtk_nl80211_vendor_subcmds {
@@ -130,7 +132,7 @@
};
enum mtk_vendor_attr_edcca_ctrl {
-@@ -226,6 +227,17 @@ enum mtk_vendor_attr_pp_ctrl {
+@@ -227,6 +228,17 @@ enum mtk_vendor_attr_pp_ctrl {
NUM_MTK_VENDOR_ATTRS_PP_CTRL - 1
};
@@ -149,5 +151,5 @@
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1041-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0052-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch
similarity index 75%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1041-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0052-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch
index e104a02..6aaed8b 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1041-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0052-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch
@@ -1,27 +1,29 @@
-From 5e847c789f6a3b7e234067e33171207fb32f46ea Mon Sep 17 00:00:00 2001
+From f33f7b6e8e9f4b8af0b9c7d4de2726556c45c566 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 24 Nov 2023 09:49:08 +0800
-Subject: [PATCH 1041/1044] mtk: wifi: mt76: mt7996: add adie efuse merge
- support
+Subject: [PATCH 052/116] mtk: wifi: mt76: mt7996: add adie efuse merge support
Merge adie-dependent parameters in efuse into eeprom after FT.
Note that Eagle BE14000 is not considered yet.
Add efuse dump command.
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: Ib088b90147c75d7437f40dd3569e3584c6ff9ab0
---
- mt7996/debugfs.c | 41 ++++++++++++++
- mt7996/eeprom.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++
- mt7996/mcu.c | 6 +-
- 3 files changed, 190 insertions(+), 2 deletions(-)
+ mt7996/debugfs.c | 41 +++++++++++++
+ mt7996/eeprom.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.c | 6 +-
+ mt7996/testmode.c | 8 ++-
+ 4 files changed, 195 insertions(+), 4 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 7a03de12..50ac6d4d 100644
+index 3074202bb..f3a520bef 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -862,6 +862,46 @@ mt7996_rf_regval_set(void *data, u64 val)
- DEFINE_DEBUGFS_ATTRIBUTE(fops_rf_regval, mt7996_rf_regval_get,
- mt7996_rf_regval_set, "0x%08llx\n");
+@@ -894,6 +894,46 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_muru_disable,
+ mt7996_fw_debug_muru_disable_get,
+ mt7996_fw_debug_muru_disable_set, "%lld\n");
+static ssize_t
+mt7996_efuse_get(struct file *file, char __user *user_buf,
@@ -47,8 +49,8 @@
+ for (i = 0; i < block_num; i++) {
+ buff = mdev->otp.data + i * MT7996_EEPROM_BLOCK_SIZE;
+ ret = mt7996_mcu_get_eeprom(dev, i * MT7996_EEPROM_BLOCK_SIZE, buff);
-+ if (ret)
-+ continue;
++ if (ret && ret != -EINVAL)
++ return ret;
+ }
+ }
+
@@ -66,7 +68,7 @@
int mt7996_init_debugfs(struct mt7996_phy *phy)
{
struct mt7996_dev *dev = phy->dev;
-@@ -888,6 +928,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+@@ -920,6 +960,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
mt7996_twt_stats);
debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
@@ -75,10 +77,10 @@
if (phy->mt76->cap.has_5ghz) {
debugfs_create_u32("dfs_hw_pattern", 0400, dir,
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 39e65010..45cbd03d 100644
+index 215d81e31..3cdd58529 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
-@@ -464,6 +464,147 @@ static int mt7996_eeprom_load_precal(struct mt7996_dev *dev)
+@@ -496,6 +496,146 @@ static int mt7996_eeprom_load_precal(struct mt7996_dev *dev)
return mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
}
@@ -101,11 +103,10 @@
+ 0x70, 0x71, 0x790, 0x791, 0x794, 0x795, 0x7a6, 0x7a8, 0x7aa, -1},
+ [ADIE_7977] = {0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x53, 0x55, 0x57, 0x59,
+ 0x69, 0x6a, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, -1},
-+ [ADIE_7978] = {0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x53, 0x55, 0x57, 0x59,
-+ 0x90, 0x91, 0x94, 0x95, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa,
-+ 0x100, 0x101, 0x102, 0x103, 0x104, 0x105, -1},
++ [ADIE_7978] = {0x91, 0x95, 0x100, 0x102, 0x104, 0x106, 0x107,
++ 0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10e, 0x110, -1},
+ [ADIE_7979] = {0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x53, 0x55, 0x57, 0x59,
-+ 0x69, 0x6a, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, -1},
++ 0x69, 0x6a, 0x7a, 0x7b, 0x7c, 0x7e, 0x80, -1},
+ };
+ static const u16 eep_offs_list[][MT_EE_CAL_FREE_MAX_SIZE] = {
+ [ADIE_7975] = {0x451, 0x453, 0x455, 0x457, 0x44c, 0x44d, 0x44e, 0x44f,
@@ -117,14 +118,11 @@
+ [ADIE_7977] = {0x124c, 0x124d, 0x124e, 0x124f, 0x1250,
+ 0x1251, 0x1253, 0x1255, 0x1257, 0x1259,
+ 0x1269, 0x126a, 0x127a, 0x127b, 0x127c, 0x127d, 0x127e, -1},
-+ [ADIE_7978] = {0x44c, 0x44d, 0x44e, 0x44f, 0x450,
-+ 0x451, 0x453, 0x455, 0x457, 0x459,
-+ 0xb90, 0xb91, 0xb94, 0xb95,
-+ 0xba6, 0xba7, 0xba8, 0xba9, 0xbaa,
-+ 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, -1},
-+ [ADIE_7979] = {0x124c, 0x124d, 0x124e, 0x124f, 0x1250,
-+ 0x1251, 0x1253, 0x1255, 0x1257, 0x1259,
-+ 0x1269, 0x126a, 0x127a, 0x127b, 0x127c, 0x127d, 0x127e, -1},
++ [ADIE_7978] = {0xb91, 0xb95, 0x480, 0x482, 0x484, 0x486, 0x487, 0x488, 0x489,
++ 0x48a, 0x48b, 0x48c, 0x48e, 0x490, -1},
++ [ADIE_7979] = {0x124c, 0x124d, 0x124e, 0x124f, 0x1250, 0x1251,
++ 0x1253, 0x1255, 0x1257, 0x1259, 0x1269, 0x126a,
++ 0x127a, 0x127b, 0x127c, 0x127e, 0x1280, -1},
+ };
+ static const u16 adie_base_7996[] = {
+ 0x400, 0x1e00, 0x1200
@@ -210,6 +208,9 @@
+ if (prev_block_num != block_num) {
+ ret = mt7996_mcu_get_eeprom(dev, adie_offset, buf);
+ if (ret) {
++ if (ret != -EINVAL)
++ return ret;
++
+ prev_block_num = -1;
+ continue;
+ }
@@ -226,7 +227,7 @@
int mt7996_eeprom_init(struct mt7996_dev *dev)
{
int ret;
-@@ -489,6 +630,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
+@@ -512,6 +652,10 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
if (ret)
return ret;
@@ -238,10 +239,10 @@
if (ret < 0)
return ret;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index c97a3204..26d0a1c1 100644
+index 2b12d5c12..6053242cd 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3620,7 +3620,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf)
+@@ -3606,7 +3606,7 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf)
};
struct sk_buff *skb;
bool valid;
@@ -250,7 +251,7 @@
u8 *buf = read_buf;
ret = mt76_mcu_send_and_get_msg(&dev->mt76,
-@@ -3638,11 +3638,13 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf)
+@@ -3624,11 +3624,13 @@ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf)
skb_pull(skb, 48);
memcpy(buf, skb->data, MT7996_EEPROM_BLOCK_SIZE);
@@ -265,6 +266,25 @@
}
int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num)
+diff --git a/mt7996/testmode.c b/mt7996/testmode.c
+index 9fa4edcd6..784a8bea4 100644
+--- a/mt7996/testmode.c
++++ b/mt7996/testmode.c
+@@ -2116,8 +2116,12 @@ mt7996_tm_write_back_to_efuse(struct mt7996_dev *dev)
+ memcpy(req.data, eeprom + i, MT76_TM_EEPROM_BLOCK_SIZE);
+
+ ret = mt7996_mcu_get_eeprom(dev, i, read_buf);
+- if (ret < 0)
+- return ret;
++ if (ret) {
++ if (ret != -EINVAL)
++ return ret;
++
++ memset(read_buf, 0, MT76_TM_EEPROM_BLOCK_SIZE);
++ }
+
+ if (!memcmp(req.data, read_buf, MT76_TM_EEPROM_BLOCK_SIZE))
+ continue;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1042-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0053-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch
similarity index 82%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1042-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0053-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch
index f515e7f..a8214cc 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1042-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0053-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch
@@ -1,16 +1,18 @@
-From cbc1ac7f49105b788c535d71885fecd5c64cffee Mon Sep 17 00:00:00 2001
+From bc31813e3f470888713d7072e2563cc1562c27a8 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Tue, 5 Dec 2023 16:48:33 +0800
-Subject: [PATCH 1042/1044] mtk: wifi: mt7996: add Eagle 2adie TBTC (BE14000)
+Subject: [PATCH 053/116] mtk: wifi: mt7996: add Eagle 2adie TBTC (BE14000)
support
Add fwdl/default eeprom load support for Eagle 2 adie TBTC
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Add Eagle 2adie TBTC efuse merge
Add Eagle 2adie TBTC group prek size
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt7996/eeprom.c | 8 ++++++--
@@ -22,19 +24,19 @@
6 files changed, 38 insertions(+), 2 deletions(-)
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 45cbd03d..3d422b0b 100644
+index 3cdd58529..5eb862914 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
-@@ -131,6 +131,8 @@ const char *mt7996_eeprom_name(struct mt7996_dev *dev)
+@@ -158,6 +158,8 @@ const char *mt7996_eeprom_name(struct mt7996_dev *dev)
case 0x7990:
if (dev->chip_sku == MT7996_SKU_404)
return MT7996_EEPROM_DEFAULT_404;
+ else if (dev->chip_sku == MT7996_SKU_233)
+ return MT7996_EEPROM_DEFAULT_233;
- return MT7996_EEPROM_DEFAULT;
- case 0x7992:
- if (dev->chip_sku == MT7992_SKU_23) {
-@@ -418,6 +420,8 @@ static void mt7996_eeprom_init_precal(struct mt7996_dev *dev)
+
+ if (dev->fem_type == MT7996_FEM_INT)
+ return MT7996_EEPROM_DEFAULT_INT;
+@@ -450,6 +452,8 @@ static void mt7996_eeprom_init_precal(struct mt7996_dev *dev)
switch (mt76_chip(&dev->mt76)) {
case 0x7990:
dev->prek.rev = mt7996_prek_rev;
@@ -43,7 +45,7 @@
/* 5g & 6g bw 80 dpd channel list is not used */
dev->prek.dpd_ch_num[DPD_CH_NUM_BW320_6G] = ARRAY_SIZE(dpd_6g_ch_list_bw320);
break;
-@@ -525,7 +529,7 @@ static int mt7996_apply_cal_free_data(struct mt7996_dev *dev)
+@@ -553,7 +557,7 @@ static int mt7996_apply_cal_free_data(struct mt7996_dev *dev)
case 0x7990:
adie_base = adie_base_7996;
/* adie 0 */
@@ -52,7 +54,7 @@
adie_id = ADIE_7975;
else
adie_id = ADIE_7976;
-@@ -533,7 +537,7 @@ static int mt7996_apply_cal_free_data(struct mt7996_dev *dev)
+@@ -561,7 +565,7 @@ static int mt7996_apply_cal_free_data(struct mt7996_dev *dev)
eep_offs[0] = eep_offs_list[adie_id];
/* adie 1 */
@@ -62,7 +64,7 @@
eep_offs[1] = eep_offs_list[ADIE_7977];
}
diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 0d05e75e..cd866123 100644
+index fa9c31e7a..43c9783c0 100644
--- a/mt7996/eeprom.h
+++ b/mt7996/eeprom.h
@@ -70,6 +70,18 @@ static const u32 mt7996_prek_rev[] = {
@@ -85,10 +87,10 @@
static const u32 mt7992_prek_rev[] = {
[GROUP_SIZE_2G] = 4 * MT_EE_CAL_UNIT,
diff --git a/mt7996/init.c b/mt7996/init.c
-index 30879ec3..ec90cdc7 100644
+index d4b0a72eb..cb0032290 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -905,6 +905,12 @@ int mt7996_get_chip_sku(struct mt7996_dev *dev)
+@@ -916,6 +916,12 @@ int mt7996_get_chip_sku(struct mt7996_dev *dev)
switch (mt76_chip(&dev->mt76)) {
case 0x7990:
@@ -102,7 +104,7 @@
if (adie_comb <= 1)
dev->chip_sku = MT7996_SKU_444;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 26d0a1c1..2cdaf845 100644
+index 6053242cd..e70932760 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -23,6 +23,11 @@
@@ -118,7 +120,7 @@
_fw = MT7996_##name; \
break; \
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index bb2cee92..bde0c086 100644
+index 1bba5450f..72865c8ef 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -35,6 +35,12 @@
@@ -134,15 +136,15 @@
#define MT7992_FIRMWARE_WA "mediatek/mt7996/mt7992_wa.bin"
#define MT7992_FIRMWARE_WM "mediatek/mt7996/mt7992_wm.bin"
#define MT7992_FIRMWARE_DSP "mediatek/mt7996/mt7992_dsp.bin"
-@@ -54,6 +60,7 @@
- #define MT7992_ROM_PATCH_23 "mediatek/mt7996/mt7992_rom_patch_23.bin"
+@@ -55,6 +61,7 @@
#define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
+ #define MT7996_EEPROM_DEFAULT_INT "mediatek/mt7996/mt7996_eeprom_2i5i6i.bin"
+#define MT7996_EEPROM_DEFAULT_233 "mediatek/mt7996/mt7996_eeprom_233.bin"
#define MT7996_EEPROM_DEFAULT_404 "mediatek/mt7996/mt7996_eeprom_dual_404.bin"
- #define MT7996_EEPROM_DEFAULT_TM "mediatek/mt7996/mt7996_eeprom_tm.bin"
#define MT7992_EEPROM_DEFAULT "mediatek/mt7996/mt7992_eeprom_2i5i.bin"
-@@ -123,6 +130,7 @@ enum mt7996_fem_type {
+ #define MT7992_EEPROM_DEFAULT_EXT "mediatek/mt7996/mt7992_eeprom_2e5e.bin"
+@@ -122,6 +129,7 @@ enum mt7996_fem_type {
enum mt7996_sku_type {
MT7996_SKU_404,
MT7996_SKU_444,
@@ -151,7 +153,7 @@
enum mt7992_sku_type {
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index aa04d8d2..8d1462a7 100644
+index 263737c52..91159c635 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -666,6 +666,7 @@ enum offs_rev {
@@ -163,5 +165,5 @@
#define MT_PAD_GPIO_ADIE_NUM_7992 BIT(15)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1043-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0054-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch
similarity index 80%
rename from recipes-wifi/linux-mt76/files/patches-3.x/1043-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0054-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch
index 5aefd99..4668cc9 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1043-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0054-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch
@@ -1,9 +1,10 @@
-From e38dd3530b0bce868b754b9fb02648974a036ab6 Mon Sep 17 00:00:00 2001
+From c7587ccb5403436628fa4568c4f1aadeb322cb81 Mon Sep 17 00:00:00 2001
From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
Date: Fri, 22 Dec 2023 17:27:10 +0800
-Subject: [PATCH 1043/1044] mtk: wifi: mt76: mt7996: add background radar hw
- cap check
+Subject: [PATCH 054/116] mtk: wifi: mt76: mt7996: add background radar hw cap
+ check
+CR-Id: WCNCR00274293
Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
---
mt7996/debugfs.c | 5 +++++
@@ -12,10 +13,10 @@
3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 50ac6d4d..2a5f82da 100644
+index f3a520bef..6c5fbc78c 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -257,6 +257,11 @@ mt7996_rdd_monitor(struct seq_file *s, void *data)
+@@ -262,6 +262,11 @@ mt7996_rdd_monitor(struct seq_file *s, void *data)
mutex_lock(&dev->mt76.mutex);
@@ -28,10 +29,10 @@
ret = -EINVAL;
goto out;
diff --git a/mt7996/init.c b/mt7996/init.c
-index ec90cdc7..20415e3c 100644
+index cb0032290..6430bfa46 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -393,9 +393,10 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+@@ -404,9 +404,10 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
@@ -46,10 +47,10 @@
NL80211_EXT_FEATURE_RADAR_BACKGROUND);
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index bde0c086..95db69ca 100644
+index 72865c8ef..c73701df1 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -599,6 +599,26 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
+@@ -605,6 +605,26 @@ mt7996_band_valid(struct mt7996_dev *dev, u8 band)
return band == MT_BAND0 || band == MT_BAND2;
}
@@ -77,5 +78,5 @@
extern struct pci_driver mt7996_pci_driver;
extern struct pci_driver mt7996_hif_driver;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0055-mtk-wifi-mt76-mt7996-add-fallback-in-case-of-missing.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0055-mtk-wifi-mt76-mt7996-add-fallback-in-case-of-missing.patch
new file mode 100644
index 0000000..e692eea
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0055-mtk-wifi-mt76-mt7996-add-fallback-in-case-of-missing.patch
@@ -0,0 +1,99 @@
+From 2f7296b87ad9175b6761aa3db3d88a8f67d45fe7 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 19 Mar 2024 17:33:49 +0800
+Subject: [PATCH 055/116] mtk: wifi: mt76: mt7996: add fallback in case of
+ missing precal data
+
+Align Wi-Fi 6 upstream changes
+https://github.com/openwrt/mt76/commit/2135e201e7a9339e018d4e2d4a33c73266e674d7
+
+CR-Id: WCNCR00274293
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ mt7996/eeprom.c | 30 +++++++++++++++++++++---------
+ mt7996/init.c | 2 +-
+ mt7996/main.c | 2 +-
+ 3 files changed, 23 insertions(+), 11 deletions(-)
+
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 5eb862914..9987bdab2 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -487,17 +487,31 @@ static int mt7996_eeprom_load_precal(struct mt7996_dev *dev)
+ size = MT_EE_CAL_GROUP_SIZE + MT_EE_CAL_DPD_SIZE;
+
+ dev->cal = devm_kzalloc(mdev->dev, size, GFP_KERNEL);
+- if (!dev->cal)
+- return -ENOMEM;
++ if (!dev->cal) {
++ ret = -ENOMEM;
++ goto fail;
++ }
+
+- if (dev->bin_file_mode)
+- return mt7996_eeprom_load_precal_binfile(dev, MT_EE_PRECAL, size);
++ if (dev->bin_file_mode) {
++ ret = mt7996_eeprom_load_precal_binfile(dev, MT_EE_PRECAL, size);
++ if (ret)
++ goto fail;
++ }
+
+ ret = mt76_get_of_data_from_mtd(mdev, dev->cal, offs, size);
+ if (!ret)
+- return ret;
++ return 0;
++
++ ret = mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
++ if (!ret)
++ return 0;
++
++fail:
++ dev_warn(dev->mt76.dev, "Failed to load precal data: %d\n", ret);
++ devm_kfree(dev->mt76.dev, dev->cal);
++ dev->cal = NULL;
+
+- return mt76_get_of_data_from_nvmem(mdev, dev->cal, "precal", size);
++ return ret;
+ }
+
+ static int mt7996_apply_cal_free_data(struct mt7996_dev *dev)
+@@ -652,9 +666,7 @@ int mt7996_eeprom_init(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
+- ret = mt7996_eeprom_load_precal(dev);
+- if (ret)
+- return ret;
++ mt7996_eeprom_load_precal(dev);
+
+ ret = mt7996_apply_cal_free_data(dev);
+ if (ret)
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 6430bfa46..c10f6675d 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -1010,7 +1010,7 @@ static int mt7996_init_hardware(struct mt7996_dev *dev)
+ if (ret < 0)
+ return ret;
+
+- if (dev->flash_mode) {
++ if (dev->cal) {
+ ret = mt7996_mcu_apply_group_cal(dev);
+ if (ret)
+ return ret;
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 2f1dd0fb7..aef08a882 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -345,7 +345,7 @@ int mt7996_set_channel(struct mt7996_phy *phy)
+
+ mt76_set_channel(phy->mt76);
+
+- if (dev->flash_mode) {
++ if (dev->cal) {
+ ret = mt7996_mcu_apply_tx_dpd(phy);
+ if (ret)
+ goto out;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0056-mtk-wifi-mt76-mt7996-add-kite-part-number-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0056-mtk-wifi-mt76-mt7996-add-kite-part-number-support.patch
new file mode 100644
index 0000000..0aa0f55
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0056-mtk-wifi-mt76-mt7996-add-kite-part-number-support.patch
@@ -0,0 +1,94 @@
+From 8353ce159acb7a91db3d9df1591b1d0882b11063 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Wed, 27 Mar 2024 17:50:16 +0800
+Subject: [PATCH 056/116] mtk: wifi: mt76: mt7996: add kite part number support
+
+CR-Id: WCNCR00274293
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: Ib06648398f18b47c324e18b476a57444d929608f
+---
+ mt7996/eeprom.c | 35 +++++++++++++++++++++++------------
+ 1 file changed, 23 insertions(+), 12 deletions(-)
+
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 9987bdab2..51455d877 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -316,26 +316,39 @@ out:
+ return ret;
+ }
+
+-static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
++static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_phy *phy,
++ u8 *path, u8 *rx_path, u8 *nss)
+ {
+ #define MODE_HE_ONLY BIT(0)
++#define STREAM_MASK GENMASK(2, 0)
++#define STREAM_OFFSET 1
++#define TX_PATH_OFFSET 10
++#define RX_PATH_OFFSET 19
+ #define WTBL_SIZE_GROUP GENMASK(31, 28)
++#define GET_STREAM_CAP(offs) ({ \
++ typeof(offs) _offs = (offs); \
++ ((cap & (STREAM_MASK << _offs)) >> _offs); \
++})
++ struct mt7996_dev *dev = phy->dev;
+ u32 cap = 0;
+ int ret;
++ u8 band_offs = phy->mt76->band_idx * hweight8(STREAM_MASK);
+
+ ret = mt7996_mcu_get_chip_config(dev, &cap);
+ if (ret)
+ return ret;
+
+- cap = 0x4b249248; /* internal hardcode */
++ dev->has_eht = true;
+ if (cap) {
+ dev->has_eht = !(cap & MODE_HE_ONLY);
+ dev->wtbl_size_group = u32_get_bits(cap, WTBL_SIZE_GROUP);
++ *nss = min_t(u8, *nss, GET_STREAM_CAP(STREAM_OFFSET + band_offs));
++ *path = min_t(u8, *path, GET_STREAM_CAP(TX_PATH_OFFSET + band_offs));
++ *rx_path = min_t(u8, *rx_path, GET_STREAM_CAP(RX_PATH_OFFSET + band_offs));
+ }
+
+- if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4 ||
+- is_mt7992(&dev->mt76))
+- dev->wtbl_size_group = 2; /* set default */
++ if (dev->wtbl_size_group < 2 || dev->wtbl_size_group > 4)
++ dev->wtbl_size_group = is_mt7996(&dev->mt76) ? 4 : 2; /* set default */
+
+ return 0;
+ }
+@@ -379,13 +392,15 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
+
+ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
+ {
++ struct mt76_phy *mphy = phy->mt76;
+ u8 path, rx_path, nss, band_idx = phy->mt76->band_idx;
+ u8 *eeprom = dev->mt76.eeprom.data;
+- struct mt76_phy *mphy = phy->mt76;
+- int max_path = 5, max_nss = 4;
+- int ret;
++ int ret, max_path = 5, max_nss = 4;
+
+ mt7996_parse_eeprom_stream(eeprom, band_idx, &path, &rx_path, &nss);
++ ret = mt7996_eeprom_parse_efuse_hw_cap(phy, &path, &rx_path, &nss);
++ if (ret)
++ return ret;
+
+ if (!path || path > max_path)
+ path = max_path;
+@@ -405,10 +420,6 @@ int mt7996_eeprom_parse_hw_cap(struct mt7996_dev *dev, struct mt7996_phy *phy)
+ dev->chainshift[band_idx + 1] = dev->chainshift[band_idx] +
+ hweight16(mphy->chainmask);
+
+- ret = mt7996_eeprom_parse_efuse_hw_cap(dev);
+- if (ret)
+- return ret;
+-
+ return mt7996_eeprom_parse_band_config(phy);
+ }
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2000-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0057-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch
similarity index 94%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2000-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0057-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch
index f17bdc5..68ec2b5 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2000-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0057-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch
@@ -1,21 +1,22 @@
-From 531fa0a7bd4865ee9e631c6cd1d5655c8e8995a6 Mon Sep 17 00:00:00 2001
+From 7883011e4646c3c69b1f181d3a7de98e811c68fb Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Mon, 6 Feb 2023 19:49:22 +0800
-Subject: [PATCH 2000/2032] mtk: wifi: mt76: revert page_poll for kernel 5.4
+Subject: [PATCH 057/116] mtk: wifi: mt76: revert page_poll for kernel 5.4
This reverts commit e8c10835cf062c577ddf426913788c39d30b4bd7.
+Change-Id: I4e5764fc545087f691fb4c2f43e7a9cefd1e1657
---
dma.c | 75 ++++++++++++++++++++++++++-------------------------
- mac80211.c | 57 ---------------------------------------
+ mac80211.c | 56 --------------------------------------
mt76.h | 22 +--------------
mt7915/main.c | 26 +++++++-----------
usb.c | 43 ++++++++++++++---------------
wed.c | 50 ++++++++++++++++++++++------------
- 6 files changed, 104 insertions(+), 169 deletions(-)
+ 6 files changed, 104 insertions(+), 168 deletions(-)
diff --git a/dma.c b/dma.c
-index 66c000ef..33a84f5f 100644
+index 66c000ef0..33a84f5fa 100644
--- a/dma.c
+++ b/dma.c
@@ -178,7 +178,7 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
@@ -204,18 +205,10 @@
if (mtk_wed_device_active(&dev->mmio.wed))
diff --git a/mac80211.c b/mac80211.c
-index f7cd47f9..380a74e4 100644
+index 8091a60e0..f7b9ba6a0 100644
--- a/mac80211.c
+++ b/mac80211.c
-@@ -4,7 +4,6 @@
- */
- #include <linux/sched.h>
- #include <linux/of.h>
--#include <net/page_pool.h>
- #include "mt76.h"
-
- static const struct ieee80211_channel mt76_channels_2ghz[] = {
-@@ -566,47 +565,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
+@@ -565,47 +565,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_unregister_phy);
@@ -263,7 +256,7 @@
struct mt76_dev *
mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
-@@ -1819,21 +1777,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
+@@ -1818,21 +1777,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
@@ -286,10 +279,10 @@
{
struct ieee80211_hw *hw = phy->hw;
diff --git a/mt76.h b/mt76.h
-index 543d9de5..540814f1 100644
+index 11cbb2d28..e21c6537f 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -246,7 +246,7 @@ struct mt76_queue {
+@@ -251,7 +251,7 @@ struct mt76_queue {
dma_addr_t desc_dma;
struct sk_buff *rx_head;
@@ -298,7 +291,7 @@
};
struct mt76_mcu_ops {
-@@ -1601,7 +1601,6 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
+@@ -1606,7 +1606,6 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
return usb_bulk_msg(udev, pipe, data, len, actual_len, timeout);
}
@@ -306,7 +299,7 @@
void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
struct mt76_sta_stats *stats, bool eht);
int mt76_skb_adjust_pad(struct sk_buff *skb, int pad);
-@@ -1747,25 +1746,6 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
+@@ -1752,25 +1751,6 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
struct mt76_txwi_cache *mt76_rx_token_release(struct mt76_dev *dev, int token);
int mt76_rx_token_consume(struct mt76_dev *dev, void *ptr,
struct mt76_txwi_cache *r, dma_addr_t phys);
@@ -333,7 +326,7 @@
static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
{
diff --git a/mt7915/main.c b/mt7915/main.c
-index 49d5b459..103a0709 100644
+index b16a63366..ad91fc3c8 100644
--- a/mt7915/main.c
+++ b/mt7915/main.c
@@ -1402,22 +1402,19 @@ void mt7915_get_et_strings(struct ieee80211_hw *hw,
@@ -391,7 +384,7 @@
static void
diff --git a/usb.c b/usb.c
-index dc690d1c..058f2d12 100644
+index dc690d1cd..058f2d124 100644
--- a/usb.c
+++ b/usb.c
@@ -319,27 +319,29 @@ mt76u_set_endpoints(struct usb_interface *intf,
@@ -525,7 +518,7 @@
static void mt76u_free_rx(struct mt76_dev *dev)
diff --git a/wed.c b/wed.c
-index f89e4537..8eca4d81 100644
+index f89e45375..8eca4d818 100644
--- a/wed.c
+++ b/wed.c
@@ -9,8 +9,12 @@
@@ -622,5 +615,5 @@
return -ENOMEM;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2001-mtk-wifi-mt76-rework-wed-rx-flow.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0058-mtk-wifi-mt76-rework-wed-rx-flow.patch
similarity index 95%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2001-mtk-wifi-mt76-rework-wed-rx-flow.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0058-mtk-wifi-mt76-rework-wed-rx-flow.patch
index 1259a33..5672878 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2001-mtk-wifi-mt76-rework-wed-rx-flow.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0058-mtk-wifi-mt76-rework-wed-rx-flow.patch
@@ -1,9 +1,10 @@
-From c6914b48e41c17245715400f8733ed9a38a4d5da Mon Sep 17 00:00:00 2001
+From ce4b2f430de33a73028d24acac09c0db3ce335e6 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Mon, 6 Feb 2023 13:37:23 +0800
-Subject: [PATCH 2001/2032] mtk: wifi: mt76: rework wed rx flow
+Subject: [PATCH 058/116] mtk: wifi: mt76: rework wed rx flow
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Change-Id: Icd787345c811cb5ad30d9c7c1c5f9e5298bd3be6
---
dma.c | 125 +++++++++++++++++++++++++++++++-----------------
mac80211.c | 2 +-
@@ -15,7 +16,7 @@
7 files changed, 144 insertions(+), 85 deletions(-)
diff --git a/dma.c b/dma.c
-index 33a84f5f..c54187bd 100644
+index 33a84f5fa..c54187bd6 100644
--- a/dma.c
+++ b/dma.c
@@ -64,17 +64,17 @@ mt76_alloc_txwi(struct mt76_dev *dev)
@@ -259,7 +260,7 @@
DMA_FROM_DEVICE);
skb_free_frag(buf);
diff --git a/mac80211.c b/mac80211.c
-index 380a74e4..91e771d3 100644
+index f7b9ba6a0..c7b222837 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -595,7 +595,6 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
@@ -279,10 +280,10 @@
for (i = 0; i < ARRAY_SIZE(dev->q_rx); i++)
skb_queue_head_init(&dev->rx_skb[i]);
diff --git a/mt76.h b/mt76.h
-index 540814f1..878553a2 100644
+index e21c6537f..aecd0a7cd 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -200,6 +200,7 @@ struct mt76_queue_entry {
+@@ -205,6 +205,7 @@ struct mt76_queue_entry {
};
union {
struct mt76_txwi_cache *txwi;
@@ -290,7 +291,7 @@
struct urb *urb;
int buf_sz;
};
-@@ -411,12 +412,16 @@ struct mt76_txwi_cache {
+@@ -416,12 +417,16 @@ struct mt76_txwi_cache {
struct list_head list;
dma_addr_t dma_addr;
@@ -312,7 +313,7 @@
};
struct mt76_rx_tid {
-@@ -504,6 +509,7 @@ struct mt76_driver_ops {
+@@ -509,6 +514,7 @@ struct mt76_driver_ops {
u16 txwi_size;
u16 token_size;
u8 mcs_rates;
@@ -320,7 +321,7 @@
void (*update_survey)(struct mt76_phy *phy);
-@@ -881,7 +887,6 @@ struct mt76_dev {
+@@ -886,7 +892,6 @@ struct mt76_dev {
struct ieee80211_hw *hw;
@@ -328,7 +329,7 @@
spinlock_t lock;
spinlock_t cc_lock;
-@@ -1563,8 +1568,8 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
+@@ -1568,8 +1573,8 @@ mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
}
void mt76_put_txwi(struct mt76_dev *dev, struct mt76_txwi_cache *t);
@@ -339,7 +340,7 @@
void mt76_free_pending_rxwi(struct mt76_dev *dev);
void mt76_rx_complete(struct mt76_dev *dev, struct sk_buff_head *frames,
struct napi_struct *napi);
-@@ -1743,9 +1748,9 @@ struct mt76_txwi_cache *
+@@ -1748,9 +1753,9 @@ struct mt76_txwi_cache *
mt76_token_release(struct mt76_dev *dev, int token, bool *wake);
int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi);
void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
@@ -352,7 +353,7 @@
static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
{
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 6004d64f..5938bd9f 100644
+index 6004d64f5..5938bd9f2 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -714,7 +714,7 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
@@ -373,7 +374,7 @@
.tx_complete_skb = mt76_connac_tx_complete_skb,
.rx_skb = mt7915_queue_rx_skb,
diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index a30d08eb..f1e2c93a 100644
+index a30d08eb0..f1e2c93a4 100644
--- a/mt7915/mt7915.h
+++ b/mt7915/mt7915.h
@@ -62,6 +62,7 @@
@@ -385,7 +386,7 @@
#define MT7915_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7915_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
diff --git a/tx.c b/tx.c
-index ab42f69b..46dae6e0 100644
+index ab42f69b8..46dae6e0a 100644
--- a/tx.c
+++ b/tx.c
@@ -851,16 +851,16 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
@@ -430,7 +431,7 @@
}
EXPORT_SYMBOL_GPL(mt76_rx_token_release);
diff --git a/wed.c b/wed.c
-index 8eca4d81..0a0b5c05 100644
+index 8eca4d818..0a0b5c05c 100644
--- a/wed.c
+++ b/wed.c
@@ -9,28 +9,45 @@
@@ -537,5 +538,5 @@
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2002-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0059-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch
similarity index 82%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2002-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0059-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch
index c1d7f8f..9634bc9 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2002-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0059-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch
@@ -1,7 +1,7 @@
-From 397754d5ae1770a66b1a1cb05ba93360f3b3b533 Mon Sep 17 00:00:00 2001
+From d4491420eea3a761e14335aa8bd57eb1b9deee51 Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Wed, 19 Apr 2023 17:13:41 +0800
-Subject: [PATCH 2002/2032] mtk: wifi: mt76: wed: change wed token init size to
+Subject: [PATCH 059/116] mtk: wifi: mt76: wed: change wed token init size to
adapt wed3.0
Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
@@ -10,7 +10,7 @@
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/tx.c b/tx.c
-index 46dae6e0..e2795067 100644
+index 46dae6e0a..e2795067c 100644
--- a/tx.c
+++ b/tx.c
@@ -827,12 +827,16 @@ EXPORT_SYMBOL_GPL(__mt76_set_tx_blocked);
@@ -34,5 +34,5 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2003-mtk-wifi-mt76-add-random-early-drop-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0060-mtk-wifi-mt76-add-random-early-drop-support.patch
similarity index 88%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2003-mtk-wifi-mt76-add-random-early-drop-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0060-mtk-wifi-mt76-add-random-early-drop-support.patch
index 547c268..ace759b 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2003-mtk-wifi-mt76-add-random-early-drop-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0060-mtk-wifi-mt76-add-random-early-drop-support.patch
@@ -1,7 +1,7 @@
-From 5a8454a960379567f438f55eda39635a54a7bfbf Mon Sep 17 00:00:00 2001
+From 6441b05d35d5b721fa16f6d529a1ca3be225ca26 Mon Sep 17 00:00:00 2001
From: Peter Chiu <chui-hao.chiu@mediatek.com>
Date: Wed, 19 Apr 2023 18:32:41 +0800
-Subject: [PATCH 2003/2032] mtk: wifi: mt76: add random early drop support
+Subject: [PATCH 060/116] mtk: wifi: mt76: add random early drop support
---
mt7996/debugfs.c | 1 +
@@ -15,10 +15,10 @@
8 files changed, 167 insertions(+), 4 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index dff9e467..01f98b2e 100644
+index 6c5fbc78c..8d639372e 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -629,6 +629,7 @@ mt7996_tx_stats_show(struct seq_file *file, void *data)
+@@ -634,6 +634,7 @@ mt7996_tx_stats_show(struct seq_file *file, void *data)
seq_printf(file, "Tx attempts: %8u (MPDUs)\n", attempts);
seq_printf(file, "Tx success: %8u (MPDUs)\n", success);
seq_printf(file, "Tx PER: %u%%\n", per);
@@ -27,7 +27,7 @@
mt7996_txbf_stat_read_phy(phy, file);
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 6fa46e46..64cec164 100644
+index 727d1fb80..78e35aa6b 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -1176,6 +1176,13 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
@@ -45,10 +45,10 @@
}
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 2cdaf845..be21dd62 100644
+index e70932760..3205f0f72 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3145,8 +3145,8 @@ int mt7996_mcu_init_firmware(struct mt7996_dev *dev)
+@@ -3147,8 +3147,8 @@ int mt7996_mcu_init_firmware(struct mt7996_dev *dev)
if (ret)
return ret;
@@ -59,7 +59,7 @@
}
int mt7996_mcu_init(struct mt7996_dev *dev)
-@@ -3178,6 +3178,83 @@ out:
+@@ -3180,6 +3180,83 @@ out:
skb_queue_purge(&dev->mt76.mcu.res_q);
}
@@ -144,7 +144,7 @@
{
struct {
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 398bf3d2..4fa399bc 100644
+index f5e91a898..ca78cd506 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -346,8 +346,9 @@ enum {
@@ -158,7 +158,7 @@
};
enum mcu_mmps_mode {
-@@ -919,6 +920,7 @@ enum {
+@@ -920,6 +921,7 @@ enum {
UNI_VOW_DRR_CTRL,
UNI_VOW_RX_AT_AIRTIME_EN = 0x0b,
UNI_VOW_RX_AT_AIRTIME_CLR_EN = 0x0e,
@@ -167,18 +167,18 @@
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 2227c08a..b0eb5d91 100644
+index c73701df1..453d22462 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -352,6 +352,7 @@ struct mt7996_phy {
- bool has_aux_rx;
+@@ -354,6 +354,7 @@ struct mt7996_phy {
+ u16 punct_bitmap;
struct mt7996_scs_ctrl scs_ctrl;
+ u32 red_drop;
- u8 muru_onoff;
-
-@@ -718,6 +719,7 @@ int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set)
+ bool sku_limit_en;
+ bool sku_path_en;
+@@ -723,6 +724,7 @@ int mt7996_mcu_rf_regval(struct mt7996_dev *dev, u32 regidx, u32 *val, bool set)
int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans);
int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val);
int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
@@ -186,7 +186,7 @@
int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
-@@ -891,11 +893,12 @@ void mt7996_mcu_set_ppdu_tx_type(struct mt7996_phy *phy, u8 ppdu_type);
+@@ -896,11 +898,12 @@ void mt7996_mcu_set_ppdu_tx_type(struct mt7996_phy *phy, u8 ppdu_type);
void mt7996_mcu_set_nusers_ofdma(struct mt7996_phy *phy, u8 type, u8 ofdma_user_cnt);
void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type);
void mt7996_tm_update_channel(struct mt7996_phy *phy);
@@ -201,10 +201,10 @@
-
#endif
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index c4cdbcdc..03f88780 100644
+index c7713e8b2..28b920e11 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -3015,6 +3015,27 @@ static int mt7996_muru_prot_thr_set(void *data, u64 val)
+@@ -3074,6 +3074,27 @@ static int mt7996_muru_prot_thr_set(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_muru_prot_thr, NULL,
mt7996_muru_prot_thr_set, "%lld\n");
@@ -232,7 +232,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -3092,6 +3113,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -3151,6 +3172,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
mt7996_wtbl_read);
debugfs_create_devm_seqfile(dev->mt76.dev, "token", dir, mt7996_token_read);
@@ -242,10 +242,10 @@
debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
debugfs_create_file("scs_enable", 0200, dir, phy, &fops_scs_enable);
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index f70bd0be..9a6636fd 100644
+index a9a7db15a..aed32e982 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
-@@ -1254,4 +1254,30 @@ void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type)
+@@ -1316,4 +1316,30 @@ void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type)
sizeof(req), false);
}
@@ -277,10 +277,10 @@
+
#endif
diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index 252ae98e..1568f10e 100644
+index 58d61c517..2cffc8937 100644
--- a/mt7996/mtk_mcu.h
+++ b/mt7996/mtk_mcu.h
-@@ -1035,6 +1035,30 @@ enum muru_vendor_ctrl {
+@@ -1138,6 +1138,30 @@ enum muru_vendor_ctrl {
MU_CTRL_DL_USER_CNT,
MU_CTRL_UL_USER_CNT,
};
@@ -312,5 +312,5 @@
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2004-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0061-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch
similarity index 81%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2004-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0061-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch
index 4f0a133..2a00de3 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2004-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0061-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch
@@ -1,29 +1,32 @@
-From 240627635f05c66751095e95a1265feb99be8224 Mon Sep 17 00:00:00 2001
+From 86ac4d3c181a20f2cf093d2502d8a6e4f1054a3d Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Thu, 18 May 2023 15:01:47 +0800
-Subject: [PATCH 2004/2032] mtk: wifi: mt76: mt7996: reset addr_elem when
- delete ba
+Subject: [PATCH 061/116] mtk: wifi: mt76: mt7996: reset addr_elem when delete
+ ba
The old addr element info may be used when the signature is not equel to
0xff, and sta will find error SDP cause the SDP/SDL=0 issue.
Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
+Change-Id: I12fb27e28b2c0310f824e66af6103b4ceba3503e
1. without this patch will delete wrong session id when delete ba.
Due to fw change the cmd format.
https://gerrit.mediatek.inc/c/neptune/firmware/bora/wifi/custom/+/7969193
Signed-off-by: mtk27745 <rex.lu@mediatek.com>
+CR-Id: WCNCR00259516
+Change-Id: I456a5d3eb2320a2c40cf57247ba63083a6d50b2e
---
mt76.h | 1 +
mt7996/mcu.h | 46 ++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/mt76.h b/mt76.h
-index 878553a2..17418e86 100644
+index aecd0a7cd..b3a5f9c12 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -439,6 +439,7 @@ struct mt76_rx_tid {
+@@ -444,6 +444,7 @@ struct mt76_rx_tid {
u16 nframes;
u8 num;
@@ -32,7 +35,7 @@
u8 started:1, stopped:1, timer_pending:1;
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 4fa399bc..a2604192 100644
+index ca78cd506..3c4ff7a5c 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -298,6 +298,52 @@ struct mt7996_mcu_thermal_notify {
@@ -89,5 +92,5 @@
UNI_MIB_OBSS_AIRTIME = 26,
UNI_MIB_NON_WIFI_TIME = 27,
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2005-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0062-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch
similarity index 84%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2005-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0062-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch
index 14c8084..9e64c36 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2005-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0062-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch
@@ -1,9 +1,10 @@
-From 57ec71ee33dacaf5050f535fc83ce0497c141b33 Mon Sep 17 00:00:00 2001
+From d5ccc55676b9a010e69111f73ecea5d2305c17f5 Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Fri, 6 Oct 2023 14:01:41 +0800
-Subject: [PATCH 2005/2032] mtk: wifi: mt76: wed: change pcie0 R5 to pcie1 to
- get 6G ICS
+Subject: [PATCH 062/116] mtk: wifi: mt76: wed: change pcie0 R5 to pcie1 to get
+ 6G ICS
+Change-Id: I23a94e3e4b797b513a303b13e4c50e0a0d72bffb
---
mt7996/dma.c | 4 ++++
mt7996/init.c | 6 ++----
@@ -11,7 +12,7 @@
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index 759a58e8..5d85e9ea 100644
+index 759a58e8e..5d85e9ea2 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -538,6 +538,10 @@ int mt7996_dma_init(struct mt7996_dev *dev)
@@ -26,10 +27,10 @@
MT_RXQ_ID(MT_RXQ_BAND2),
MT7996_RX_RING_SIZE,
diff --git a/mt7996/init.c b/mt7996/init.c
-index 20415e3c..aedf4edc 100644
+index c10f6675d..de5122f7d 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -638,10 +638,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+@@ -649,10 +649,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
goto error;
if (wed == &dev->mt76.mmio.wed_hif2 && mtk_wed_device_active(wed)) {
@@ -43,7 +44,7 @@
return 0;
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 367a204d..44e64f86 100644
+index 8fe56ed96..a082ccae8 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -527,12 +527,15 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
@@ -64,5 +65,5 @@
mt76_wr(dev, MT_INT_MASK_CSR, 0);
if (dev->hif2)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2006-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0063-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch
similarity index 76%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2006-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0063-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch
index 99ac2f6..173c70d 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2006-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0063-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch
@@ -1,15 +1,16 @@
-From 6cf957f7acc9124acdb7b231b54e98d305b968f3 Mon Sep 17 00:00:00 2001
+From 8697ea1b612b2c57459b12b2fdd812d6dd31dd18 Mon Sep 17 00:00:00 2001
From: mtk27745 <rex.lu@mediatek.com>
Date: Tue, 23 May 2023 12:06:29 +0800
-Subject: [PATCH 2006/2032] mtk: wifi: mt76: add SER support for wed3.0
+Subject: [PATCH 063/116] mtk: wifi: mt76: add SER support for wed3.0
+Change-Id: I2711b9dc336fca9a1ae32a8fbf27810a7e27b1e3
---
dma.c | 5 +++--
mt7996/mmio.c | 1 +
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dma.c b/dma.c
-index c54187bd..e5be891c 100644
+index c54187bd6..e5be891cb 100644
--- a/dma.c
+++ b/dma.c
@@ -834,8 +834,9 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
@@ -25,7 +26,7 @@
mt76_dma_rx_fill(dev, q, false);
}
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 44e64f86..92ae5138 100644
+index a082ccae8..d29579ff5 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -297,6 +297,7 @@ out:
@@ -37,5 +38,5 @@
int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2007-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0064-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch
similarity index 87%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2007-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0064-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch
index daaace2..658863f 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2007-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0064-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch
@@ -1,7 +1,7 @@
-From cbe204fc70c0aebce3a42cfc314ef0c5bd8a16cf Mon Sep 17 00:00:00 2001
+From d810c1768039fafabea801f2c4a5fc517e8cd68d Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Wed, 19 Jul 2023 10:55:09 +0800
-Subject: [PATCH 2007/2032] mtk: wifi: mt76: mt7915: wed: find rx token by
+Subject: [PATCH 064/116] mtk: wifi: mt76: mt7915: wed: find rx token by
physical address
The token id in RxDMAD may be incorrect when it is not the last frame due to
@@ -9,12 +9,13 @@
Add len == 0 check to drop garbage frames
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Change-Id: I4cd90294ad24990826075e92a710cc4e301dcbb7
---
dma.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)
diff --git a/dma.c b/dma.c
-index e5be891c..1021b3e5 100644
+index e5be891cb..1021b3e5d 100644
--- a/dma.c
+++ b/dma.c
@@ -446,9 +446,32 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
@@ -61,5 +62,5 @@
if (q->rx_head)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2008-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0065-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch
similarity index 87%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2008-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0065-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch
index 8075e12..b48ad31 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2008-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0065-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch
@@ -1,7 +1,7 @@
-From 51238985cbb77e8955cc727e6f3853b53c9c088d Mon Sep 17 00:00:00 2001
+From 4bf3625251b6086c3b57cbef75aa3ef6f3706fe3 Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Thu, 20 Jul 2023 10:25:50 +0800
-Subject: [PATCH 2008/2032] mtk: wifi: mt76: mt7996: add dma mask limitation
+Subject: [PATCH 065/116] mtk: wifi: mt76: mt7996: add dma mask limitation
Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
---
@@ -10,7 +10,7 @@
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/dma.c b/dma.c
-index 1021b3e5..da21f641 100644
+index 1021b3e5d..da21f6410 100644
--- a/dma.c
+++ b/dma.c
@@ -488,7 +488,7 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
@@ -32,7 +32,7 @@
break;
diff --git a/wed.c b/wed.c
-index 0a0b5c05..1c6d53c8 100644
+index 0a0b5c05c..1c6d53c84 100644
--- a/wed.c
+++ b/wed.c
@@ -65,14 +65,14 @@ u32 mt76_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
@@ -53,5 +53,5 @@
mt76_put_rxwi(dev, r);
goto unmap;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2009-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0066-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch
similarity index 84%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2009-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0066-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch
index d38058c..4089488 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2009-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0066-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch
@@ -1,7 +1,7 @@
-From f2dfba0451106438a4cb312552b95da9a0857c68 Mon Sep 17 00:00:00 2001
+From 313d5480374cccb0d7414913223021cb7f4171d3 Mon Sep 17 00:00:00 2001
From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Date: Fri, 18 Aug 2023 10:17:08 +0800
-Subject: [PATCH 2009/2032] mtk: wifi: mt76: mt7996: add per bss statistic info
+Subject: [PATCH 066/116] mtk: wifi: mt76: mt7996: add per bss statistic info
Whenever WED is enabled, unicast traffic might run through HW path.
As a result, we need to count them using WM event.
@@ -22,22 +22,22 @@
3 files changed, 37 insertions(+), 5 deletions(-)
diff --git a/mt7996/init.c b/mt7996/init.c
-index aedf4edc..518f70e4 100644
+index de5122f7d..8b7c27873 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -390,6 +390,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
- wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
+@@ -401,6 +401,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_PUNCT);
+ wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_STAS_COUNT);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION);
wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_PROTECTION);
diff --git a/mt7996/main.c b/mt7996/main.c
-index d314d9fb..e1c107fb 100644
+index aef08a882..f97898f5f 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -251,6 +251,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+@@ -265,6 +265,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
mvif->sta.wcid.phy_idx = band_idx;
mvif->sta.wcid.hw_key_idx = -1;
mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET;
@@ -46,10 +46,10 @@
mt7996_mac_wtbl_update(dev, idx,
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index be21dd62..479eee0e 100644
+index 3205f0f72..568e4d45a 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -521,6 +521,27 @@ mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rat
+@@ -524,6 +524,27 @@ mt7996_mcu_update_tx_gi(struct rate_info *rate, struct all_sta_trx_rate *mcu_rat
return 0;
}
@@ -77,7 +77,7 @@
static void
mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
-@@ -536,7 +557,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -539,7 +560,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
u16 wlan_idx;
struct mt76_wcid *wcid;
struct mt76_phy *mphy;
@@ -86,7 +86,7 @@
switch (le16_to_cpu(res->tag)) {
case UNI_ALL_STA_TXRX_RATE:
-@@ -564,6 +585,9 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -567,6 +588,9 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
wcid->stats.tx_bytes += tx_bytes;
wcid->stats.rx_bytes += rx_bytes;
@@ -96,7 +96,7 @@
ieee80211_tpt_led_trig_tx(mphy->hw, tx_bytes);
ieee80211_tpt_led_trig_rx(mphy->hw, rx_bytes);
}
-@@ -575,10 +599,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -578,10 +602,16 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
if (!wcid)
break;
@@ -118,5 +118,5 @@
default:
break;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2010-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0067-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch
similarity index 75%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2010-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0067-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch
index 26dc702..c8e5001 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2010-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0067-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch
@@ -1,7 +1,7 @@
-From 1b648b7fe779a9862e966a27d274ac42c24e4bcd Mon Sep 17 00:00:00 2001
+From db3c26b1e067aca67455a0246c390dc0271496f3 Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Thu, 26 Oct 2023 17:27:43 +0800
-Subject: [PATCH 2010/2032] mtk: wifi: mt76: mt7996: do not report netdev stats
+Subject: [PATCH 067/116] mtk: wifi: mt76: mt7996: do not report netdev stats
on monitor vif
This fixes the following NULL pointer crash when enabling monitor mode:
@@ -13,16 +13,18 @@
[ 205.613935] napi_threaded_poll+0x80/0xe8
[ 205.617934] kthread+0x124/0x128
+CR-Id: WCNCR00238098
+Change-Id: I66f2449401888255bf8d3edddc1d9f20bd8ba3e7
Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
---
mt7996/mcu.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 479eee0e..15644029 100644
+index 568e4d45a..337bcf559 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -537,6 +537,9 @@ static inline void __mt7996_stat_to_netdev(struct mt76_phy *mphy,
+@@ -540,6 +540,9 @@ static inline void __mt7996_stat_to_netdev(struct mt76_phy *mphy,
drv_priv);
wdev = ieee80211_vif_to_wdev(vif);
@@ -33,5 +35,5 @@
dev_sw_netstats_rx_add(wdev->netdev, rx_packets, rx_bytes);
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2011-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0068-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch
similarity index 93%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2011-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0068-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch
index 2db4015..ed8a05a 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2011-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0068-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch
@@ -1,7 +1,7 @@
-From 655711c39cac51c4b63ec8e32dd79ec362081293 Mon Sep 17 00:00:00 2001
+From 58bd9403132eee4438f9e0b67415d772af324585 Mon Sep 17 00:00:00 2001
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Date: Mon, 11 Sep 2023 16:35:15 +0800
-Subject: [PATCH 2011/2032] mtk: wifi: mt76: mt7996: add support for HW-ATF
+Subject: [PATCH 068/116] mtk: wifi: mt76: mt7996: add support for HW-ATF
---
mt7996/debugfs.c | 90 ++++++++++++++++
@@ -13,12 +13,12 @@
6 files changed, 475 insertions(+), 26 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 01f98b2e..8e4ceeeb 100644
+index 8d639372e..f8ba573f2 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -935,6 +935,91 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_muru_disable,
- mt7996_fw_debug_muru_disable_get,
- mt7996_fw_debug_muru_disable_set, "%lld\n");
+@@ -940,6 +940,91 @@ static const struct file_operations mt7996_efuse_ops = {
+ .llseek = default_llseek,
+ };
+static int
+mt7996_vow_info_read(struct seq_file *s, void *data)
@@ -108,7 +108,7 @@
int mt7996_init_debugfs(struct mt7996_phy *phy)
{
struct mt7996_dev *dev = phy->dev;
-@@ -962,6 +1047,11 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+@@ -967,6 +1052,11 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
mt7996_twt_stats);
debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
debugfs_create_file("otp", 0400, dir, dev, &mt7996_efuse_ops);
@@ -121,10 +121,10 @@
if (phy->mt76->cap.has_5ghz) {
debugfs_create_u32("dfs_hw_pattern", 0400, dir,
diff --git a/mt7996/init.c b/mt7996/init.c
-index 518f70e4..b902bcc5 100644
+index 8b7c27873..c382ded01 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -562,6 +562,37 @@ int mt7996_txbf_init(struct mt7996_dev *dev)
+@@ -573,6 +573,37 @@ int mt7996_txbf_init(struct mt7996_dev *dev)
return mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
}
@@ -162,7 +162,7 @@
static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
enum mt76_band_id band)
{
-@@ -634,6 +665,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+@@ -645,6 +676,12 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
if (ret)
goto error;
@@ -175,7 +175,7 @@
ret = mt7996_init_debugfs(phy);
if (ret)
goto error;
-@@ -1440,6 +1477,12 @@ int mt7996_register_device(struct mt7996_dev *dev)
+@@ -1483,6 +1520,12 @@ int mt7996_register_device(struct mt7996_dev *dev)
dev->recovery.hw_init_done = true;
@@ -189,7 +189,7 @@
if (ret)
goto error;
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 64cec164..8de4ab9a 100644
+index 78e35aa6b..be56abe16 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -103,6 +103,7 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
@@ -220,10 +220,10 @@
/* get signal strength of resp frames (CTS/BA/ACK) */
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 15644029..a907e667 100644
+index 337bcf559..cde4e0014 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -2223,34 +2223,37 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+@@ -2225,34 +2225,37 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
}
static int
@@ -285,7 +285,7 @@
}
int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
-@@ -2306,7 +2309,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+@@ -2308,7 +2311,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
}
@@ -294,7 +294,7 @@
if (ret) {
dev_kfree_skb(skb);
return ret;
-@@ -5143,6 +5146,218 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
+@@ -5185,6 +5188,218 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
&req, sizeof(req), false);
}
@@ -514,10 +514,10 @@
void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
{
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index a2604192..7b8540f6 100644
+index 3c4ff7a5c..700330ab5 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
-@@ -964,6 +964,7 @@ enum {
+@@ -965,6 +965,7 @@ enum {
enum {
UNI_VOW_DRR_CTRL,
@@ -526,10 +526,10 @@
UNI_VOW_RX_AT_AIRTIME_CLR_EN = 0x0e,
UNI_VOW_RED_ENABLE = 0x18,
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index b0eb5d91..b1abe42b 100644
+index 453d22462..c95c12b45 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -115,6 +115,12 @@
+@@ -114,6 +114,12 @@
#define MT7996_RX_MSDU_PAGE_SIZE (128 + \
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
@@ -542,7 +542,7 @@
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
-@@ -216,6 +222,81 @@ enum mt7996_dpd_ch_num {
+@@ -215,6 +221,81 @@ enum mt7996_dpd_ch_num {
DPD_CH_NUM_TYPE_MAX,
};
@@ -624,7 +624,7 @@
struct mt7996_sta {
struct mt76_wcid wcid; /* must be first */
-@@ -235,6 +316,8 @@ struct mt7996_sta {
+@@ -234,6 +315,8 @@ struct mt7996_sta {
u8 flowid_mask;
struct mt7996_twt_flow flow[MT7996_MAX_STA_TWT_AGRT];
} twt;
@@ -633,7 +633,7 @@
};
struct mt7996_vif {
-@@ -494,6 +577,7 @@ struct mt7996_dev {
+@@ -499,6 +582,7 @@ struct mt7996_dev {
u8 wtbl_size_group;
@@ -641,7 +641,7 @@
#ifdef CONFIG_MTK_DEBUG
u16 wlan_idx;
struct {
-@@ -734,10 +818,12 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy);
+@@ -739,10 +823,12 @@ int mt7996_mcu_apply_tx_dpd(struct mt7996_phy *phy);
#ifdef CONFIG_NL80211_TESTMODE
void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
#endif
@@ -655,7 +655,7 @@
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
-@@ -787,6 +873,14 @@ static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy)
+@@ -792,6 +878,14 @@ static inline u16 mt7996_rx_chainmask(struct mt7996_phy *phy)
return tx_chainmask | (BIT(fls(tx_chainmask)) * phy->has_aux_rx);
}
@@ -671,5 +671,5 @@
u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw);
bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2012-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0069-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2012-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0069-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch
index 7b3e94a..ed0b185 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2012-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0069-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch
@@ -1,10 +1,11 @@
-From 12a52d5e5a8643d0fe1448469d228aeeb85df362 Mon Sep 17 00:00:00 2001
+From 2285ea8b0ee712928f6980240c0103fcd2a96033 Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Thu, 12 Oct 2023 10:04:54 +0800
-Subject: [PATCH 2012/2032] mtk: wifi: mt76: mt7996: wed: add SER0.5 support w/
+Subject: [PATCH 069/116] mtk: wifi: mt76: mt7996: wed: add SER0.5 support w/
wed3.0
Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
+Change-Id: I9b26cdbea6e8ee158a153fd153c2dea77b494f2f
---
dma.c | 9 ++--
dma.h | 4 +-
@@ -18,7 +19,7 @@
9 files changed, 146 insertions(+), 64 deletions(-)
diff --git a/dma.c b/dma.c
-index da21f641..e23b744b 100644
+index da21f6410..e23b744b8 100644
--- a/dma.c
+++ b/dma.c
@@ -218,9 +218,9 @@ void __mt76_dma_queue_reset(struct mt76_dev *dev, struct mt76_queue *q,
@@ -53,7 +54,7 @@
return 0;
}
diff --git a/dma.h b/dma.h
-index 1de5a2b2..3a8c2e55 100644
+index 1de5a2b20..3a8c2e558 100644
--- a/dma.h
+++ b/dma.h
@@ -83,12 +83,12 @@ int mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
@@ -72,10 +73,10 @@
mt76_wed_dma_setup(dev, q, true);
}
diff --git a/mt76.h b/mt76.h
-index 17418e86..6ac8a279 100644
+index b3a5f9c12..e9fc37d99 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -296,7 +296,7 @@ struct mt76_queue_ops {
+@@ -301,7 +301,7 @@ struct mt76_queue_ops {
void (*kick)(struct mt76_dev *dev, struct mt76_queue *q);
@@ -84,7 +85,7 @@
};
enum mt76_phy_type {
-@@ -1731,8 +1731,13 @@ static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q)
+@@ -1736,8 +1736,13 @@ static inline bool mt76_queue_is_wed_rro_ind(struct mt76_queue *q)
static inline bool mt76_queue_is_wed_rro_data(struct mt76_queue *q)
{
return mt76_queue_is_wed_rro(q) &&
@@ -100,7 +101,7 @@
}
static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
-@@ -1741,7 +1746,8 @@ static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
+@@ -1746,7 +1751,8 @@ static inline bool mt76_queue_is_wed_rx(struct mt76_queue *q)
return false;
return FIELD_GET(MT_QFLAG_WED_TYPE, q->flags) == MT76_WED_Q_RX ||
@@ -111,7 +112,7 @@
}
diff --git a/mt792x_dma.c b/mt792x_dma.c
-index 5cc2d59b..c224bcc8 100644
+index 5cc2d59b7..c224bcc8a 100644
--- a/mt792x_dma.c
+++ b/mt792x_dma.c
@@ -181,13 +181,13 @@ mt792x_dma_reset(struct mt792x_dev *dev, bool force)
@@ -132,7 +133,7 @@
mt76_tx_status_check(&dev->mt76, true);
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index 5d85e9ea..d9e1b17f 100644
+index 5d85e9ea2..d9e1b17ff 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -711,21 +711,31 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
@@ -173,10 +174,10 @@
mt7996_dma_enable(dev, !force);
}
diff --git a/mt7996/init.c b/mt7996/init.c
-index b902bcc5..a9720120 100644
+index c382ded01..ff629e8d8 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -724,11 +724,91 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)
+@@ -735,11 +735,91 @@ void mt7996_wfsys_reset(struct mt7996_dev *dev)
msleep(20);
}
@@ -269,7 +270,7 @@
struct mt7996_wed_rro_addr *addr;
void *ptr;
int i;
-@@ -788,50 +868,9 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
+@@ -799,50 +879,9 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
addr++;
}
@@ -323,10 +324,10 @@
#else
return 0;
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 8de4ab9a..48e4ce90 100644
+index be56abe16..2ad9f4889 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -1768,6 +1768,31 @@ mt7996_mac_restart(struct mt7996_dev *dev)
+@@ -1764,6 +1764,31 @@ mt7996_mac_restart(struct mt7996_dev *dev)
if (ret)
goto out;
@@ -359,10 +360,10 @@
ret = mt7996_mcu_set_eeprom(dev);
if (ret)
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index b1abe42b..84b34ea9 100644
+index c95c12b45..4090fadfa 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -713,6 +713,7 @@ extern const struct mt76_testmode_ops mt7996_testmode_ops;
+@@ -718,6 +718,7 @@ extern const struct mt76_testmode_ops mt7996_testmode_ops;
struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
void __iomem *mem_base, u32 device_id);
void mt7996_wfsys_reset(struct mt7996_dev *dev);
@@ -371,7 +372,7 @@
u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
int mt7996_register_device(struct mt7996_dev *dev);
diff --git a/wed.c b/wed.c
-index 1c6d53c8..61a6badf 100644
+index 1c6d53c84..61a6badf2 100644
--- a/wed.c
+++ b/wed.c
@@ -155,7 +155,7 @@ int mt76_wed_dma_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
@@ -393,5 +394,5 @@
mtk_wed_device_ind_rx_ring_setup(q->wed, q->regs);
break;
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2013-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0070-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch
similarity index 88%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2013-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0070-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch
index 7bb9eea..fe42aee 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2013-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0070-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch
@@ -1,12 +1,14 @@
-From b4130d60aec743429b0bf9156a79b99776bbdc06 Mon Sep 17 00:00:00 2001
+From d31f86b70ab12fba91854fe3f4188448638f967d Mon Sep 17 00:00:00 2001
From: mtk27745 <rex.lu@mediatek.com>
Date: Fri, 6 Oct 2023 20:59:42 +0800
-Subject: [PATCH 2013/2032] mtk: wifi: mt76: mt7996: support backaward
+Subject: [PATCH 070/116] mtk: wifi: mt76: mt7996: support backaward
compatiable
revert upstream wed trigger mode to polling mode
+CR-Id: WCNCR00259341
Signed-off-by: mtk27745 <rex.lu@mediatek.com>
+Change-Id: Ifd40df7094052b13e26f42f09908f6404917ad8e
[Description]
Change the SW token size from 1024 to 15360 according to HW capability.
@@ -14,6 +16,8 @@
[Release-log]
N/A
+CR-Id: WCNCR00240772
+Change-Id: I337f41aa80758d00b4c8e7a5cc4d6faeb6f0a4a2
Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
---
@@ -27,10 +31,10 @@
7 files changed, 24 insertions(+), 17 deletions(-)
diff --git a/mt76.h b/mt76.h
-index 6ac8a279..49b66ff2 100644
+index e9fc37d99..4009e3c61 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -48,6 +48,8 @@
+@@ -53,6 +53,8 @@
#define MT76_TOKEN_FREE_THR 64
@@ -40,10 +44,10 @@
#define MT_QFLAG_WED_TYPE GENMASK(4, 2)
#define MT_QFLAG_WED BIT(5)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 48e4ce90..ed22d94e 100644
+index 2ad9f4889..8396e6def 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -1781,7 +1781,7 @@ mt7996_mac_restart(struct mt7996_dev *dev)
+@@ -1777,7 +1777,7 @@ mt7996_mac_restart(struct mt7996_dev *dev)
}
mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
@@ -52,7 +56,7 @@
mt7996_irq_enable(dev, wed_irq_mask);
mt7996_irq_disable(dev, 0);
}
-@@ -2013,6 +2013,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -2009,6 +2009,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
mtk_wed_device_start_hw_rro(&dev->mt76.mmio.wed, wed_irq_mask,
true);
@@ -61,10 +65,10 @@
mt7996_irq_disable(dev, 0);
}
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index a907e667..08979465 100644
+index cde4e0014..1a45c31b3 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -3252,7 +3252,7 @@ static int mt7996_mcu_wa_red_config(struct mt7996_dev *dev)
+@@ -3254,7 +3254,7 @@ static int mt7996_mcu_wa_red_config(struct mt7996_dev *dev)
if (!mtk_wed_device_active(&dev->mt76.mmio.wed))
req.token_per_src[RED_TOKEN_SRC_CNT - 1] =
@@ -74,7 +78,7 @@
return mt76_mcu_send_msg(&dev->mt76, MCU_WA_PARAM_CMD(SET),
&req, sizeof(req), false);
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 92ae5138..eef70faf 100644
+index d29579ff5..1c2cea2ec 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -14,7 +14,7 @@
@@ -125,10 +129,10 @@
#else
return 0;
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 84b34ea9..3ba40c3a 100644
+index 4090fadfa..7011f6659 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -74,6 +74,7 @@
+@@ -73,6 +73,7 @@
#define MT7996_EEPROM_BLOCK_SIZE 16
#define MT7996_TOKEN_SIZE 16384
#define MT7996_HW_TOKEN_SIZE 8192
@@ -137,7 +141,7 @@
#define MT7996_CFEND_RATE_DEFAULT 0x49 /* OFDM 24M */
#define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
diff --git a/mt7996/pci.c b/mt7996/pci.c
-index 05830c01..4e957771 100644
+index 05830c01c..4e957771f 100644
--- a/mt7996/pci.c
+++ b/mt7996/pci.c
@@ -171,7 +171,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
@@ -182,7 +186,7 @@
if (mtk_wed_device_active(&dev->mt76.mmio.wed_hif2))
mtk_wed_device_detach(&dev->mt76.mmio.wed_hif2);
diff --git a/wed.c b/wed.c
-index 61a6badf..634c95cf 100644
+index 61a6badf2..634c95cf9 100644
--- a/wed.c
+++ b/wed.c
@@ -120,7 +120,7 @@ int mt76_wed_offload_enable(struct mtk_wed_device *wed)
@@ -204,5 +208,5 @@
}
EXPORT_SYMBOL_GPL(mt76_wed_offload_disable);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2014-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0071-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch
similarity index 95%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2014-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0071-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch
index e7a590a..32897a4 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2014-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0071-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch
@@ -1,14 +1,16 @@
-From 2fd58d785c6aaf330211787b8fcbc3662a6f69d8 Mon Sep 17 00:00:00 2001
+From 6764f5f9c24ad031431c80834e293b0d2ec12db5 Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Fri, 8 Sep 2023 11:57:39 +0800
-Subject: [PATCH 2014/2032] mtk: wifi: mt76: mt7996: wed: add wed support for
+Subject: [PATCH 071/116] mtk: wifi: mt76: mt7996: wed: add wed support for
mt7992
Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
Fix incomplete WED initialization for Kite band-1 RX ring.
+CR-Id: WCNCR00298425
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Change-Id: I2da06c9f1412f8392d1b55feea3ad8ff48ff90ad
---
mt7996/dma.c | 91 +++++++++++++++++++++++++++++++++----------------
mt7996/init.c | 12 +++++++
@@ -20,7 +22,7 @@
7 files changed, 142 insertions(+), 48 deletions(-)
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index d9e1b17f..d62dc8ba 100644
+index d9e1b17ff..d62dc8ba9 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -77,18 +77,23 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
@@ -168,10 +170,10 @@
if (mt7996_band_valid(dev, MT_BAND2)) {
/* rx rro data queue for band2 */
diff --git a/mt7996/init.c b/mt7996/init.c
-index a9720120..7a9b9749 100644
+index ff629e8d8..e29cebeb9 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -802,6 +802,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
+@@ -813,6 +813,7 @@ void mt7996_rro_hw_init(struct mt7996_dev *dev)
/* interrupt enable */
mt76_wr(dev, MT_RRO_HOST_INT_ENA,
MT_RRO_HOST_INT_ENA_HOST_RRO_DONE_ENA);
@@ -179,7 +181,7 @@
#endif
}
-@@ -854,6 +855,17 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
+@@ -865,6 +866,17 @@ static int mt7996_wed_rro_init(struct mt7996_dev *dev)
dev->wed_rro.addr_elem[i].phy_addr;
}
@@ -198,10 +200,10 @@
MT7996_RRO_WINDOW_MAX_LEN * sizeof(*addr),
&dev->wed_rro.session.phy_addr,
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index ed22d94e..48cb2ac0 100644
+index 8396e6def..b4703804b 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -2011,6 +2011,10 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -2007,6 +2007,10 @@ void mt7996_mac_reset_work(struct work_struct *work)
mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
@@ -213,7 +215,7 @@
true);
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index eef70faf..e23c79fc 100644
+index 1c2cea2ec..3f0692c79 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -313,7 +313,8 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
@@ -305,10 +307,10 @@
dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt;
}
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 3ba40c3a..d1d35e56 100644
+index 7011f6659..929a077b9 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -122,6 +122,10 @@
+@@ -121,6 +121,10 @@
#define MT7996_DRR_STA_AC2_QNTM_MASK GENMASK(18, 16)
#define MT7996_DRR_STA_AC3_QNTM_MASK GENMASK(22, 20)
@@ -319,7 +321,7 @@
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
-@@ -181,7 +185,7 @@ enum mt7996_rxq_id {
+@@ -180,7 +184,7 @@ enum mt7996_rxq_id {
MT7996_RXQ_BAND1 = 5, /* for mt7992 */
MT7996_RXQ_BAND2 = 5,
MT7996_RXQ_RRO_BAND0 = 8,
@@ -328,7 +330,7 @@
MT7996_RXQ_RRO_BAND2 = 6,
MT7996_RXQ_MSDU_PG_BAND0 = 10,
MT7996_RXQ_MSDU_PG_BAND1 = 11,
-@@ -541,6 +545,10 @@ struct mt7996_dev {
+@@ -546,6 +550,10 @@ struct mt7996_dev {
void *ptr;
dma_addr_t phy_addr;
} session;
@@ -340,7 +342,7 @@
struct work_struct work;
struct list_head poll_list;
diff --git a/mt7996/pci.c b/mt7996/pci.c
-index 4e957771..f0d3f199 100644
+index 4e957771f..f0d3f199c 100644
--- a/mt7996/pci.c
+++ b/mt7996/pci.c
@@ -107,7 +107,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
@@ -376,7 +378,7 @@
goto free_wed_or_irq_vector;
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 8d1462a7..352d1b29 100644
+index 91159c635..e6427a351 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -77,6 +77,8 @@ enum offs_rev {
@@ -428,5 +430,5 @@
#define MT_INT_RX_DONE_RRO_IND BIT(11)
#define MT_INT_RX_DONE_MSDU_PG_BAND0 BIT(18)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2015-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0072-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch
similarity index 94%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2015-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0072-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch
index a0a1b01..3cb13db 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2015-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0072-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch
@@ -1,7 +1,7 @@
-From 5fa40f1780c96c66b3c7a01ac43c8bdebe8b746e Mon Sep 17 00:00:00 2001
+From 435235e314311be77ae5746d1fed1f5a89f0e947 Mon Sep 17 00:00:00 2001
From: "sujuan.chen" <sujuan.chen@mediatek.com>
Date: Wed, 13 Sep 2023 17:35:43 +0800
-Subject: [PATCH 2015/2032] mtk: wifi: mt76: mt7992: wed: add 2pcie one wed
+Subject: [PATCH 072/116] mtk: wifi: mt76: mt7992: wed: add 2pcie one wed
support
Signed-off-by: sujuan.chen <sujuan.chen@mediatek.com>
@@ -14,7 +14,7 @@
5 files changed, 39 insertions(+), 13 deletions(-)
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index d62dc8ba..c23b0d65 100644
+index d62dc8ba9..c23b0d651 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -355,6 +355,13 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
@@ -55,7 +55,7 @@
dev->mt76.q_rx[MT_RXQ_TXFREE_BAND0].wed = wed;
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index e23c79fc..764c1244 100644
+index 3f0692c79..91567a04b 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -375,10 +375,10 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
@@ -84,7 +84,7 @@
mt76_wr(dev, MT_INT_MASK_CSR, mdev->mmio.irqmask);
mt76_wr(dev, MT_INT1_MASK_CSR, mdev->mmio.irqmask);
diff --git a/mt7996/mtk_debug.h b/mt7996/mtk_debug.h
-index 27d8f1cb..da2a6072 100644
+index 27d8f1cb2..da2a60723 100644
--- a/mt7996/mtk_debug.h
+++ b/mt7996/mtk_debug.h
@@ -561,6 +561,11 @@ struct queue_desc {
@@ -100,10 +100,10 @@
//#define WF_WFDMA_MCU_DMA0_BASE 0x02000
#define WF_WFDMA_MCU_DMA0_BASE 0x54000000
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 03f88780..6eea2c3c 100644
+index 28b920e11..27ad9432f 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -536,14 +536,22 @@ mt7996_show_dma_info(struct seq_file *s, struct mt7996_dev *dev)
+@@ -559,14 +559,22 @@ mt7996_show_dma_info(struct seq_file *s, struct mt7996_dev *dev)
WF_WFDMA_HOST_DMA0_WPDMA_RX_RING4_CTRL0_ADDR);
dump_dma_rx_ring_info(s, dev, "R5:Data1(MAC2H)", "Both",
WF_WFDMA_HOST_DMA0_WPDMA_RX_RING5_CTRL0_ADDR);
@@ -130,7 +130,7 @@
dump_dma_rx_ring_info(s, dev, "R10:MSDU_PG0(MAC2H)", "Both",
WF_WFDMA_HOST_DMA0_WPDMA_RX_RING10_CTRL0_ADDR);
dump_dma_rx_ring_info(s, dev, "R11:MSDU_PG1(MAC2H)", "Both",
-@@ -561,15 +569,18 @@ mt7996_show_dma_info(struct seq_file *s, struct mt7996_dev *dev)
+@@ -584,15 +592,18 @@ mt7996_show_dma_info(struct seq_file *s, struct mt7996_dev *dev)
WF_WFDMA_HOST_DMA0_PCIE1_WPDMA_TX_RING21_CTRL0_ADDR);
dump_dma_tx_ring_info(s, dev, "T22:TXD?(H2WA)", "AP",
WF_WFDMA_HOST_DMA0_PCIE1_WPDMA_TX_RING22_CTRL0_ADDR);
@@ -153,7 +153,7 @@
/* MCU DMA information */
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 352d1b29..a3b62339 100644
+index e6427a351..cbd71706c 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -411,6 +411,7 @@ enum offs_rev {
@@ -173,5 +173,5 @@
#define MT_WFDMA_EXT_CSR_HIF_MISC MT_WFDMA_EXT_CSR(0x44)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2017-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0073-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch
similarity index 79%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2017-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0073-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch
index 5958fe2..82e5096 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2017-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0073-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch
@@ -1,18 +1,19 @@
-From 253dc25979390b559324187a5a2d1e35552a93c8 Mon Sep 17 00:00:00 2001
+From 4bc413bf6205f65522cc18e00c64773d70faefdf Mon Sep 17 00:00:00 2001
From: mtk27745 <rex.lu@mediatek.com>
Date: Mon, 6 Nov 2023 10:16:34 +0800
-Subject: [PATCH 2017/2032] mtk: wifi: mt76: mt7996: Remove wed rro ring add
- napi at init state
+Subject: [PATCH 073/116] mtk: wifi: mt76: mt7996: Remove wed rro ring add napi
+ at init state
without this patch. rro ring will add napi at initial state. once rro ring add napi, it will have chance to be used by host driver. if host driver accessed the ring data, it will cause some issue.
+CR-Id: WCNCR00259341
Signed-off-by: mtk27745 <rex.lu@mediatek.com>
---
dma.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/dma.c b/dma.c
-index e23b744b..38701c71 100644
+index e23b744b8..38701c71e 100644
--- a/dma.c
+++ b/dma.c
@@ -1017,6 +1017,10 @@ mt76_dma_init(struct mt76_dev *dev,
@@ -27,5 +28,5 @@
mt76_dma_rx_fill(dev, &dev->q_rx[i], false);
napi_enable(&dev->napi[i]);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2018-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0074-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch
similarity index 74%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2018-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0074-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch
index 3bfbbc4..46633a2 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2018-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0074-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch
@@ -1,21 +1,22 @@
-From 4ce1116a988fa2b0172ec96797a0a81ff4899c35 Mon Sep 17 00:00:00 2001
+From 2287fce6adb7e62918bf06792acb13f1eac3f1f9 Mon Sep 17 00:00:00 2001
From: Rex Lu <rex.lu@mediatek.com>
Date: Wed, 29 Nov 2023 13:56:52 +0800
-Subject: [PATCH 2018/2032] mtk: wifi: mt76: mt7996: Remove wed_stop during L1
+Subject: [PATCH 074/116] mtk: wifi: mt76: mt7996: Remove wed_stop during L1
SER
Align logan L1 SER flow. During L1 SER, didn't need to close wed interrupt.
+CR-Id: WCNCR00259341
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
---
mt7996/mac.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 912ae650..142e9372 100644
+index b4703804b..0805251e8 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -1954,12 +1954,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
+@@ -1950,12 +1950,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
wiphy_name(dev->mt76.hw->wiphy));
@@ -29,5 +30,5 @@
if (phy2)
ieee80211_stop_queues(phy2->mt76->hw);
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2019-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0075-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch
similarity index 84%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2019-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0075-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch
index 4b021cb..b319c54 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2019-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0075-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch
@@ -1,19 +1,21 @@
-From 302b6abf2ae7eb56c7e437d67b2aa49a7d47d4fa Mon Sep 17 00:00:00 2001
+From 5fd50b8df6409278d15377d1a6b58381e677c080 Mon Sep 17 00:00:00 2001
From: Rex Lu <rex.lu@mediatek.com>
Date: Wed, 29 Nov 2023 15:51:04 +0800
-Subject: [PATCH 2019/2032] mtk: wifi: mt76: mt7996: Refactor rro del ba
- command format
+Subject: [PATCH 075/116] mtk: wifi: mt76: mt7996: Refactor rro del ba command
+ format
1. remove unused struct
2. refactor upstream del ba command format
+CR-Id: WCNCR00259516
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
+Change-Id: Iab75446a54dd0bf3aa95dc80f32d7d80b6f7fc8b
---
mt7996/mcu.h | 50 +++-----------------------------------------------
1 file changed, 3 insertions(+), 47 deletions(-)
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 7b8540f6..a05dd6a5 100644
+index 700330ab5..a58f52d0c 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -273,7 +273,9 @@ struct mt7996_mcu_wed_rro_ba_delete_event {
@@ -81,5 +83,5 @@
UNI_MIB_OBSS_AIRTIME = 26,
UNI_MIB_NON_WIFI_TIME = 27,
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2020-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0076-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2020-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0076-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch
index 6860f6c..3591d4e 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2020-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0076-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch
@@ -1,13 +1,15 @@
-From da85f2d8c8f3147aab467ba9d65c6457cba0ad1e Mon Sep 17 00:00:00 2001
+From 226977cba476d426936788b86986dbf5b8e71920 Mon Sep 17 00:00:00 2001
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Date: Fri, 17 Nov 2023 18:08:06 +0800
-Subject: [PATCH 2020/2032] mtk: wifi: mt76: mt7996: get airtime and RSSI via
- MCU commands
+Subject: [PATCH 076/116] mtk: wifi: mt76: mt7996: get airtime and RSSI via MCU
+ commands
Direct access to WTBL for airtime and RSSI may cause synchronization issue with FW.
Moreover, frequent access to WTBL, whenever TX-Free-Done event is received, leads to heavy CPU overheads.
Therefore, indirect access to WTBL, through FW, with lower frequence is performed.
+Change-Id: I978e7432603742fae9c753f055ff3087cf6b632c
+CR-Id: WCNCR00298425
Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
---
@@ -23,10 +25,10 @@
9 files changed, 361 insertions(+), 143 deletions(-)
diff --git a/mt76.h b/mt76.h
-index 49b66ff2..c7816721 100644
+index 4009e3c61..c3c35841f 100644
--- a/mt76.h
+++ b/mt76.h
-@@ -327,11 +327,15 @@ struct mt76_sta_stats {
+@@ -332,11 +332,15 @@ struct mt76_sta_stats {
u32 tx_packets; /* unit: MSDU */
u32 tx_retries;
u32 tx_failed;
@@ -42,7 +44,7 @@
};
enum mt76_wcid_flags {
-@@ -1330,6 +1334,22 @@ static inline int mt76_decr(int val, int size)
+@@ -1335,6 +1339,22 @@ static inline int mt76_decr(int val, int size)
u8 mt76_ac_to_hwq(u8 ac);
@@ -66,10 +68,10 @@
mtxq_to_txq(struct mt76_txq *mtxq)
{
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 266ee711..4f4b7b4f 100644
+index 885e5883e..45fef88b9 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1368,11 +1368,23 @@ enum {
+@@ -1369,11 +1369,23 @@ enum {
UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT,
};
@@ -95,10 +97,10 @@
UNI_ALL_STA_GI_MODE,
UNI_ALL_STA_TXRX_MSDU_COUNT,
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 8e4ceeeb..6ccf0827 100644
+index f8ba573f2..e26de48c6 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -987,12 +987,11 @@ mt7996_airtime_read(struct seq_file *s, void *data)
+@@ -992,12 +992,11 @@ mt7996_airtime_read(struct seq_file *s, void *data)
{
struct mt7996_dev *dev = dev_get_drvdata(s->private);
struct mt76_dev *mdev = &dev->mt76;
@@ -112,7 +114,7 @@
u16 i;
seq_printf(s, "VoW Airtime Information:\n");
-@@ -1004,16 +1003,16 @@ mt7996_airtime_read(struct seq_file *s, void *data)
+@@ -1009,16 +1008,16 @@ mt7996_airtime_read(struct seq_file *s, void *data)
msta = container_of(wcid, struct mt7996_sta, wcid);
sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
@@ -137,7 +139,7 @@
rcu_read_unlock();
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 142e9372..901c2036 100644
+index 0805251e8..782594cd7 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
@@ -12,8 +12,6 @@
@@ -269,7 +271,7 @@
if (wake)
mt76_set_tx_blocked(&dev->mt76, false);
-@@ -2383,31 +2275,42 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+@@ -2379,31 +2271,42 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
void mt7996_mac_work(struct work_struct *work)
{
@@ -326,10 +328,10 @@
ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
MT7996_WATCHDOG_TIME);
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 08979465..4907f729 100644
+index 1a45c31b3..2bee4a59c 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -560,7 +560,8 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -563,7 +563,8 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
u16 wlan_idx;
struct mt76_wcid *wcid;
struct mt76_phy *mphy;
@@ -339,7 +341,7 @@
switch (le16_to_cpu(res->tag)) {
case UNI_ALL_STA_TXRX_RATE:
-@@ -581,7 +582,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -584,7 +585,7 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
break;
mphy = mt76_dev_phy(&dev->mt76, wcid->phy_idx);
@@ -348,7 +350,7 @@
tx_bytes = le32_to_cpu(res->adm_stat[i].tx_bytes[ac]);
rx_bytes = le32_to_cpu(res->adm_stat[i].rx_bytes[ac]);
-@@ -613,6 +614,24 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -616,6 +617,24 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
__mt7996_stat_to_netdev(mphy, wcid, 0, 0,
tx_packets, rx_packets);
break;
@@ -373,7 +375,7 @@
default:
break;
}
-@@ -2242,8 +2261,6 @@ mt7996_mcu_sta_init_vow(struct mt7996_phy *phy, struct mt7996_sta *msta)
+@@ -2244,8 +2263,6 @@ mt7996_mcu_sta_init_vow(struct mt7996_phy *phy, struct mt7996_sta *msta)
vow->drr_quantum[IEEE80211_AC_VI] = VOW_DRR_QUANTUM_IDX1;
vow->drr_quantum[IEEE80211_AC_BE] = VOW_DRR_QUANTUM_IDX2;
vow->drr_quantum[IEEE80211_AC_BK] = VOW_DRR_QUANTUM_IDX2;
@@ -382,7 +384,7 @@
ret = mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_BSS_GROUP);
if (ret)
-@@ -4849,9 +4866,155 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val)
+@@ -4839,9 +4856,155 @@ int mt7996_mcu_set_rro(struct mt7996_dev *dev, u16 tag, u16 val)
sizeof(req), true);
}
@@ -540,7 +542,7 @@
struct {
u8 _rsv[4];
-@@ -4862,7 +5025,7 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag)
+@@ -4852,7 +5015,7 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag)
.len = cpu_to_le16(sizeof(req) - 4),
};
@@ -550,7 +552,7 @@
}
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index a05dd6a5..cd327451 100644
+index a58f52d0c..e64812c6d 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -199,6 +199,31 @@ struct mt7996_mcu_mib {
@@ -606,10 +608,10 @@
} __packed;
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index d1d35e56..c5b83648 100644
+index 929a077b9..a0cc8f37d 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -126,6 +126,8 @@
+@@ -125,6 +125,8 @@
#define MT7996_RRO_MSDU_PG_CR_CNT 8
#define MT7996_RRO_MSDU_PG_SIZE_PER_CR 0x10000
@@ -618,7 +620,7 @@
struct mt7996_vif;
struct mt7996_sta;
struct mt7996_dfs_pulse;
-@@ -298,8 +300,6 @@ struct mt7996_vow_sta_ctrl {
+@@ -297,8 +299,6 @@ struct mt7996_vow_sta_ctrl {
bool paused;
u8 bss_grp_idx;
u8 drr_quantum[IEEE80211_NUM_ACS];
@@ -627,7 +629,7 @@
};
struct mt7996_sta {
-@@ -308,7 +308,6 @@ struct mt7996_sta {
+@@ -307,7 +307,6 @@ struct mt7996_sta {
struct mt7996_vif *vif;
struct list_head rc_list;
@@ -635,7 +637,7 @@
int ack_signal;
struct ewma_avg_signal avg_ack_signal;
-@@ -405,6 +404,21 @@ struct mt7996_air_monitor_ctrl {
+@@ -404,6 +403,21 @@ struct mt7996_air_monitor_ctrl {
};
#endif
@@ -657,7 +659,7 @@
struct mt7996_phy {
struct mt76_phy *mt76;
struct mt7996_dev *dev;
-@@ -594,6 +608,7 @@ struct mt7996_dev {
+@@ -599,6 +613,7 @@ struct mt7996_dev {
u32 fw_dbg_module;
u8 fw_dbg_lv;
u32 bcn_total_cnt[__MT_MAX_BAND];
@@ -665,7 +667,7 @@
} dbg;
const struct mt7996_dbg_reg_desc *dbg_reg;
#endif
-@@ -819,7 +834,10 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
+@@ -824,7 +839,10 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
@@ -678,10 +680,10 @@
int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 data);
int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event);
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 6eea2c3c..916c7c06 100644
+index 27ad9432f..5fb6078c1 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -3047,6 +3047,69 @@ mt7996_vow_drr_dbg(void *data, u64 val)
+@@ -3106,6 +3106,69 @@ mt7996_vow_drr_dbg(void *data, u64 val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_vow_drr_dbg, NULL,
mt7996_vow_drr_dbg, "%lld\n");
@@ -751,7 +753,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -3146,6 +3209,14 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -3205,6 +3268,14 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
debugfs_create_file("muru_prot_thr", 0200, dir, phy, &fops_muru_prot_thr);
@@ -767,7 +769,7 @@
}
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index a3b62339..476b23c3 100644
+index cbd71706c..a001d9fd6 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -122,6 +122,8 @@ enum offs_rev {
@@ -780,5 +782,5 @@
#define MT_PLE_BASE 0x820c0000
#define MT_PLE(ofs) (MT_PLE_BASE + (ofs))
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2021-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0077-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch
similarity index 88%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2021-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0077-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch
index 6366876..187b38d 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2021-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0077-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch
@@ -1,13 +1,15 @@
-From 8871427856374447f4275cde02936e73e452c080 Mon Sep 17 00:00:00 2001
+From e6455a415fefb896c325db624d03725a56eaa3f5 Mon Sep 17 00:00:00 2001
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Date: Thu, 4 Jan 2024 09:47:00 +0800
-Subject: [PATCH 2021/2032] mtk: wifi: mt76: mt7996: add support for WMM PBC
+Subject: [PATCH 077/116] mtk: wifi: mt76: mt7996: add support for WMM PBC
configuration
Query per-AC-queue packet statistics from WA, and determine if multi-AC transmission is ongoing.
If it is, enable WMM mode in WA. Otherwise, disable WMM mode.
+CR-Id: WCNCR00298425
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Change-Id: I1852a45dc0e64780af5f091fd749ceab59697dbb
---
mt76_connac_mcu.h | 2 ++
mt7996/init.c | 2 ++
@@ -18,7 +20,7 @@
6 files changed, 105 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 4f4b7b4f..b2b8f2a2 100644
+index 45fef88b9..12fdc6e12 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -1026,6 +1026,7 @@ enum {
@@ -34,14 +36,14 @@
MCU_EXT_CMD_CAL_CACHE = 0x67,
MCU_EXT_CMD_RED_ENABLE = 0x68,
+ MCU_EXT_CMD_PKT_BUDGET_CTRL = 0x6c,
+ MCU_EXT_CMD_CP_SUPPORT = 0x75,
MCU_EXT_CMD_SET_RADAR_TH = 0x7c,
MCU_EXT_CMD_SET_RDD_PATTERN = 0x7d,
- MCU_EXT_CMD_MWDS_SUPPORT = 0x80,
diff --git a/mt7996/init.c b/mt7996/init.c
-index 7a9b9749..90f3a417 100644
+index e29cebeb9..f4111460c 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -1493,6 +1493,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
+@@ -1536,6 +1536,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
INIT_WORK(&dev->dump_work, mt7996_mac_dump_work);
mutex_init(&dev->dump_mutex);
@@ -51,10 +53,10 @@
if (ret)
return ret;
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 901c2036..88e1fd14 100644
+index 782594cd7..e3758ff13 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -2302,6 +2302,10 @@ void mt7996_mac_work(struct work_struct *work)
+@@ -2298,6 +2298,10 @@ void mt7996_mac_work(struct work_struct *work)
mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_ADM_STAT);
mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_MSDU_COUNT);
}
@@ -66,10 +68,10 @@
test_bit(MT76_STATE_RUNNING, &mdev->phys[i]->state))
break;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 4907f729..6405c2fa 100644
+index 2bee4a59c..6fb9f81f0 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -666,6 +666,82 @@ mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -669,6 +669,82 @@ mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
phy->throttle_state = n->duty_percent;
}
@@ -152,7 +154,7 @@
static void
mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
{
-@@ -675,6 +751,8 @@ mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -678,6 +754,8 @@ mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_EXT_EVENT_FW_LOG_2_HOST:
mt7996_mcu_rx_log_message(dev, skb);
break;
@@ -162,7 +164,7 @@
break;
}
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index cd327451..9dc7946b 100644
+index e64812c6d..d24874a4b 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -375,10 +375,25 @@ enum {
@@ -192,10 +194,10 @@
MCU_WA_PARAM_RED_CONFIG = 0x40,
};
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index c5b83648..6ea024ef 100644
+index a0cc8f37d..19965393e 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -601,6 +601,9 @@ struct mt7996_dev {
+@@ -606,6 +606,9 @@ struct mt7996_dev {
u8 wtbl_size_group;
struct mt7996_vow_ctrl vow;
@@ -205,7 +207,7 @@
#ifdef CONFIG_MTK_DEBUG
u16 wlan_idx;
struct {
-@@ -852,6 +855,7 @@ int mt7996_mcu_set_band_confg(struct mt7996_phy *phy, u16 option, bool enable);
+@@ -857,6 +860,7 @@ int mt7996_mcu_set_band_confg(struct mt7996_phy *phy, u16 option, bool enable);
int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy, struct mt7996_sta *msta,
enum vow_drr_ctrl_id id);
int mt7996_mcu_set_vow_feature_ctrl(struct mt7996_phy *phy);
@@ -214,5 +216,5 @@
static inline u8 mt7996_max_interface_num(struct mt7996_dev *dev)
{
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2022-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0078-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch
similarity index 90%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2022-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0078-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch
index 8cf8f0f..eb0ca10 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2022-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0078-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch
@@ -1,17 +1,22 @@
-From f513775361c7aae98ca2f816edb62b1744350325 Mon Sep 17 00:00:00 2001
+From 2d0f8b5d4e08fb55a6e9ea3f05faab7afbfd65a1 Mon Sep 17 00:00:00 2001
From: Rex Lu <rex.lu@mediatek.com>
Date: Thu, 1 Feb 2024 10:32:42 +0800
-Subject: [PATCH 2022/2032] mtk: wifi: mt76: mt7996: eagle support extra
+Subject: [PATCH 078/116] mtk: wifi: mt76: mt7996: eagle support extra
option_type
1. eagle + mt7988d option_type 2 support
2. eagle single pcie support
+CR-Id: WCNCR00259516
+Change-Id: Ib8e741b3c9eba3c796704351259f926c1e4e9d69
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
1. adjust pcie outstanding value by pcie speed. not no longer by option_type.
+CR-Id: WCNCR00259516
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
+Change-Id: I1c8fa6769aa0b192b32738aec0b14c86572a493b
+(cherry picked from commit 31d64e0f571eb06ed67f4916bc12fbcfe1263c47)
---
mt7996/dma.c | 51 +++++++++++++++++++++++++++++++++----
mt7996/init.c | 67 ++++++++++++++++++++++++++++++++++++++-----------
@@ -22,7 +27,7 @@
6 files changed, 123 insertions(+), 22 deletions(-)
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index c23b0d65..3dc0e8a1 100644
+index c23b0d651..3dc0e8a1d 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -12,12 +12,20 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx, int n_desc,
@@ -110,10 +115,10 @@
mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_45_TH + hif1_ofs, 0xc000c);
mt76_wr(dev, MT_WFDMA0_PAUSE_RX_Q_67_TH + hif1_ofs, 0x10008);
diff --git a/mt7996/init.c b/mt7996/init.c
-index 90f3a417..85fedca6 100644
+index f4111460c..1e7cd5235 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -500,7 +500,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
+@@ -511,7 +511,7 @@ static void mt7996_mac_init_basic_rates(struct mt7996_dev *dev)
void mt7996_mac_init(struct mt7996_dev *dev)
{
#define HIF_TXD_V2_1 0x21
@@ -122,7 +127,7 @@
mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
-@@ -514,22 +514,45 @@ void mt7996_mac_init(struct mt7996_dev *dev)
+@@ -525,22 +525,45 @@ void mt7996_mac_init(struct mt7996_dev *dev)
}
/* rro module init */
@@ -178,7 +183,7 @@
}
mt7996_mcu_wa_cmd(dev, MCU_WA_PARAM_CMD(SET),
-@@ -607,9 +630,22 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+@@ -618,9 +641,22 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
if (phy)
return 0;
@@ -204,7 +209,7 @@
}
mphy = mt76_alloc_phy(&dev->mt76, sizeof(*phy), &mt7996_ops, band);
-@@ -1048,6 +1084,9 @@ int mt7996_get_chip_sku(struct mt7996_dev *dev)
+@@ -1059,6 +1095,9 @@ int mt7996_get_chip_sku(struct mt7996_dev *dev)
static int mt7996_init_hardware(struct mt7996_dev *dev)
{
int ret, idx;
@@ -215,10 +220,10 @@
mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
if (is_mt7992(&dev->mt76)) {
diff --git a/mt7996/main.c b/mt7996/main.c
-index e1c107fb..fd6fd78b 100644
+index f97898f5f..445f86221 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -1583,8 +1583,19 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+@@ -1606,8 +1606,19 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
struct mt7996_phy *phy = mt7996_hw_phy(hw);
struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
@@ -241,7 +246,7 @@
if (!mtk_wed_device_active(wed))
return -ENODEV;
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 6ea024ef..2ca6e55d 100644
+index 19965393e..3f1f9b362 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -8,6 +8,7 @@
@@ -252,7 +257,7 @@
#include "../mt76_connac.h"
#include "regs.h"
-@@ -350,6 +351,8 @@ struct mt7996_hif {
+@@ -349,6 +350,8 @@ struct mt7996_hif {
struct device *dev;
void __iomem *regs;
int irq;
@@ -261,7 +266,7 @@
};
struct mt7996_scs_ctrl {
-@@ -574,6 +577,8 @@ struct mt7996_dev {
+@@ -579,6 +582,8 @@ struct mt7996_dev {
u8 eeprom_mode;
u32 bg_nxt_freq;
@@ -271,7 +276,7 @@
u8 fw_debug_wm;
u8 fw_debug_wa;
diff --git a/mt7996/pci.c b/mt7996/pci.c
-index f0d3f199..24d69d4d 100644
+index f0d3f199c..24d69d4dc 100644
--- a/mt7996/pci.c
+++ b/mt7996/pci.c
@@ -5,7 +5,6 @@
@@ -291,7 +296,7 @@
list_add(&hif->list, &hif_list);
spin_unlock_bh(&hif_lock);
diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 476b23c3..050637c1 100644
+index a001d9fd6..a0e4b3e11 100644
--- a/mt7996/regs.h
+++ b/mt7996/regs.h
@@ -435,6 +435,7 @@ enum offs_rev {
@@ -321,5 +326,5 @@
#define MT_PCIE_RECOG_ID_MASK GENMASK(30, 0)
#define MT_PCIE_RECOG_ID_SEM BIT(31)
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2023-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0079-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch
similarity index 83%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2023-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0079-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch
index aa7a600..56ae4e8 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2023-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0079-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch
@@ -1,7 +1,7 @@
-From 918509adeb892bda553d29794bf475831a49f6d0 Mon Sep 17 00:00:00 2001
+From d3513854d4eaa55fabcef09ed6841ee817b00851 Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Thu, 27 Jul 2023 19:35:32 +0800
-Subject: [PATCH 2023/2032] mtk: wifi: mt76: mt7996: support enable/disable
+Subject: [PATCH 079/116] mtk: wifi: mt76: mt7996: support enable/disable
thermal protection mechanism
This commit adds a new debugfs thermal_enable to enable/disable thermal
@@ -24,22 +24,22 @@
3 files changed, 47 insertions(+)
diff --git a/mt7996/main.c b/mt7996/main.c
-index fd6fd78b..91c06cfb 100644
+index 445f86221..f7ea49f18 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -83,6 +83,7 @@ int mt7996_run(struct ieee80211_hw *hw)
+@@ -91,6 +91,7 @@ int mt7996_run(struct ieee80211_hw *hw)
#ifdef CONFIG_MTK_DEBUG
phy->sr_enable = true;
phy->enhanced_sr_enable = true;
+ phy->thermal_protection_enable = true;
ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
- !dev->dbg.sku_disable);
+ dev->dbg.sku_disable ? 0 : phy->sku_limit_en);
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 2ca6e55d..d6f7828e 100644
+index 3f1f9b362..3069e9070 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -483,6 +483,7 @@ struct mt7996_phy {
+@@ -488,6 +488,7 @@ struct mt7996_phy {
#ifdef CONFIG_MTK_DEBUG
bool sr_enable:1;
bool enhanced_sr_enable:1;
@@ -48,10 +48,10 @@
};
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 916c7c06..afef17cf 100644
+index 5fb6078c1..ee72c0e51 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -3110,6 +3110,49 @@ mt7996_show_rro_mib(struct seq_file *s, void *data)
+@@ -3169,6 +3169,49 @@ mt7996_show_rro_mib(struct seq_file *s, void *data)
return 0;
}
@@ -101,7 +101,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -3217,6 +3260,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -3276,6 +3319,8 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
mt7996_show_rro_mib);
}
@@ -111,5 +111,5 @@
}
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2024-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0080-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch
similarity index 81%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2024-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0080-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch
index 8f0e9b2..dcd5544 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2024-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0080-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch
@@ -1,8 +1,8 @@
-From 4d28b5d5f45a4494fffd03694caeff4f59765b80 Mon Sep 17 00:00:00 2001
+From 5c0d266ff3446fe53d2fa9203e930350607ab7dc Mon Sep 17 00:00:00 2001
From: Howard Hsu <howard-yh.hsu@mediatek.com>
Date: Thu, 4 Jan 2024 19:53:37 +0800
-Subject: [PATCH 2024/2032] mtk: wifi: mt76: mt7996: support thermal recal
- debug command
+Subject: [PATCH 080/116] mtk: wifi: mt76: mt7996: support thermal recal debug
+ command
Add support thermal recal debug command.
@@ -14,6 +14,8 @@
1 = enable
2 = manual trigger
+CR-Id: WCNCR00261410
+Change-Id: Ief064633dd7ab0faeb298ac3902ca1b399e70365
Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
---
mt76_connac_mcu.h | 1 +
@@ -23,10 +25,10 @@
4 files changed, 40 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index b2b8f2a2..97c2f5c0 100644
+index 12fdc6e12..151183d08 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1284,6 +1284,7 @@ enum {
+@@ -1285,6 +1285,7 @@ enum {
MCU_UNI_CMD_TESTMODE_TRX_PARAM = 0x42,
MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
MCU_UNI_CMD_PRECAL_RESULT = 0x47,
@@ -35,10 +37,10 @@
MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
MCU_UNI_CMD_PER_STA_INFO = 0x6d,
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index d6f7828e..b5673bdd 100644
+index 3069e9070..69bcf78f5 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -1027,6 +1027,7 @@ void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type);
+@@ -1032,6 +1032,7 @@ void mt7996_mcu_set_cert(struct mt7996_phy *phy, u8 type);
void mt7996_tm_update_channel(struct mt7996_phy *phy);
int mt7996_mcu_set_vow_drr_dbg(struct mt7996_dev *dev, u32 val);
@@ -47,10 +49,10 @@
#ifdef CONFIG_NET_MEDIATEK_SOC_WED
diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index afef17cf..25c21f37 100644
+index ee72c0e51..ddb4a7ca2 100644
--- a/mt7996/mtk_debugfs.c
+++ b/mt7996/mtk_debugfs.c
-@@ -3153,6 +3153,22 @@ out:
+@@ -3212,6 +3212,22 @@ out:
DEFINE_DEBUGFS_ATTRIBUTE(fops_thermal_enable, mt7996_thermal_enable_get,
mt7996_thermal_enable_set, "%lld\n");
@@ -73,7 +75,7 @@
int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
{
struct mt7996_dev *dev = phy->dev;
-@@ -3261,6 +3277,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+@@ -3320,6 +3336,7 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
}
debugfs_create_file("thermal_enable", 0600, dir, phy, &fops_thermal_enable);
@@ -82,10 +84,10 @@
return 0;
}
diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index 9a6636fd..063c2516 100644
+index aed32e982..aa44b4710 100644
--- a/mt7996/mtk_mcu.c
+++ b/mt7996/mtk_mcu.c
-@@ -1280,4 +1280,25 @@ int mt7996_mcu_set_vow_drr_dbg(struct mt7996_dev *dev, u32 val)
+@@ -1342,4 +1342,25 @@ int mt7996_mcu_set_vow_drr_dbg(struct mt7996_dev *dev, u32 val)
sizeof(req), true);
}
@@ -112,5 +114,5 @@
+}
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0081-mtk-wifi-mt76-mt7996-add-kite-two-pcie-with-two-wed-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0081-mtk-wifi-mt76-mt7996-add-kite-two-pcie-with-two-wed-.patch
new file mode 100644
index 0000000..663b42a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0081-mtk-wifi-mt76-mt7996-add-kite-two-pcie-with-two-wed-.patch
@@ -0,0 +1,327 @@
+From 3945c5fb09e36f31863f019dc12d242aa4e3644c Mon Sep 17 00:00:00 2001
+From: Rex Lu <rex.lu@mediatek.com>
+Date: Tue, 19 Mar 2024 13:16:12 +0800
+Subject: [PATCH 081/116] mtk: wifi: mt76: mt7996: add kite two pcie with two
+ wed support
+
+CR-Id: WCNCR00259516
+Signed-off-by: Rex Lu <rex.lu@mediatek.com>
+---
+ mt7996/dma.c | 68 ++++++++++++++++++++++++++++++++++++++-------------
+ mt7996/init.c | 54 +++++++++++++++++++++++-----------------
+ mt7996/main.c | 5 ++--
+ mt7996/mmio.c | 15 ++++++++++--
+ mt7996/pci.c | 5 ++--
+ mt7996/regs.h | 1 +
+ 6 files changed, 101 insertions(+), 47 deletions(-)
+
+diff --git a/mt7996/dma.c b/mt7996/dma.c
+index 3dc0e8a1d..a2490fa77 100644
+--- a/mt7996/dma.c
++++ b/mt7996/dma.c
+@@ -108,8 +108,8 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
+ }
+
+ /* data tx queue */
+- TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
+ if (is_mt7996(&dev->mt76)) {
++ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
+ if (dev->hif2) {
+ if (dev->option_type == 2) {
+ /* bn1:ring21 bn2:ring19 */
+@@ -125,7 +125,15 @@ static void mt7996_dma_config(struct mt7996_dev *dev)
+ TXQ_CONFIG(2, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
+ }
+ } else {
+- TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
++ if (dev->hif2) {
++ /* bn0:ring18 bn1:ring21 */
++ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
++ TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND2, MT7996_TXQ_BAND2);
++ } else {
++ /* single pcie bn0:ring18 bn1:ring19 */
++ TXQ_CONFIG(0, WFDMA0, MT_INT_TX_DONE_BAND0, MT7996_TXQ_BAND0);
++ TXQ_CONFIG(1, WFDMA0, MT_INT_TX_DONE_BAND1, MT7996_TXQ_BAND1);
++ }
+ }
+
+ /* mcu tx queue */
+@@ -285,8 +293,11 @@ void mt7996_dma_start(struct mt7996_dev *dev, bool reset, bool wed_reset)
+ if (mt7996_band_valid(dev, MT_BAND0))
+ irq_mask |= MT_INT_BAND0_RX_DONE;
+
+- if (mt7996_band_valid(dev, MT_BAND1))
++ if (mt7996_band_valid(dev, MT_BAND1)) {
+ irq_mask |= MT_INT_BAND1_RX_DONE;
++ if (is_mt7992(&dev->mt76) && dev->hif2)
++ irq_mask |= MT_INT_RX_TXFREE_BAND1_EXT;
++ }
+
+ if (mt7996_band_valid(dev, MT_BAND2))
+ irq_mask |= MT_INT_BAND2_RX_DONE;
+@@ -379,27 +390,46 @@ static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
+ MT_WFDMA_HOST_CONFIG_BAND1_PCIE1 |
+ MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
+
+- if (dev->option_type == 2)
+- mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+- MT_WFDMA_HOST_CONFIG_BAND0_PCIE1 |
+- MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
+- else
+- mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+- MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
+-
+- if (mtk_wed_device_active(&dev->mt76.mmio.wed) &&
+- is_mt7992(&dev->mt76)) {
++ switch (dev->option_type) {
++ case 2:
++ /* eagle + 7988d */
++ if (is_mt7996(&dev->mt76))
++ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
++ MT_WFDMA_HOST_CONFIG_BAND0_PCIE1 |
++ MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
++ else
++ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
++ MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
++ break;
++ case 3:
+ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
+- MT_WFDMA_HOST_CONFIG_PDMA_BAND |
+- MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
++ MT_WFDMA_HOST_CONFIG_BAND0_PCIE1);
++
++ break;
++ default:
++ if (is_mt7996(&dev->mt76))
++ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
++ MT_WFDMA_HOST_CONFIG_BAND2_PCIE1);
++ else
++ mt76_set(dev, MT_WFDMA_HOST_CONFIG,
++ MT_WFDMA_HOST_CONFIG_BAND1_PCIE1);
++ break;
+ }
+
+ /* AXI read outstanding number */
+ mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL,
+ MT_WFDMA_AXI_R2A_CTRL_OUTSTAND_MASK, 0x14);
+
+- if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
+- (dev->hif2->speed == PCIE_SPEED_8_0GT && dev->hif2->width < 2)) {
++ if (dev->hif2->speed < PCIE_SPEED_5_0GT ||
++ (dev->hif2->speed == PCIE_SPEED_5_0GT && dev->hif2->width < 2)) {
++ mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
++ WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
++ FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, 0x1));
++ mt76_rmw(dev, MT_WFDMA_AXI_R2A_CTRL2,
++ MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK,
++ FIELD_PREP(MT_WFDMA_AXI_R2A_CTRL2_OUTSTAND_MASK, 0x1));
++ } else if (dev->hif2->speed < PCIE_SPEED_8_0GT ||
++ (dev->hif2->speed == PCIE_SPEED_8_0GT && dev->hif2->width < 2)) {
+ mt76_rmw(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
+ WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK,
+ FIELD_PREP(WF_WFDMA0_GLO_CFG_EXT0_OUTSTAND_MASK, 0x3));
+@@ -648,6 +678,10 @@ int mt7996_dma_init(struct mt7996_dev *dev)
+
+ /* tx free notify event from WA for mt7992 band1 */
+ rx_base = MT_RXQ_RING_BASE(MT_RXQ_BAND1_WA) + hif1_ofs;
++ if (mtk_wed_device_active(wed_hif2)) {
++ dev->mt76.q_rx[MT_RXQ_BAND1_WA].flags = MT_WED_Q_TXFREE;
++ dev->mt76.q_rx[MT_RXQ_BAND1_WA].wed = wed_hif2;
++ }
+ ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_BAND1_WA],
+ MT_RXQ_ID(MT_RXQ_BAND1_WA),
+ MT7996_RX_MCU_RING_SIZE,
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 1e7cd5235..768979ef7 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -525,39 +525,46 @@ void mt7996_mac_init(struct mt7996_dev *dev)
+ }
+
+ /* rro module init */
++ rx_path_type = is_mt7996(&dev->mt76) ? 2 : 7;
++ rro_bypass = is_mt7996(&dev->mt76) ? 1 : 2;
++ txfree_path = is_mt7996(&dev->mt76) ? 0: 1;
++
+ switch (dev->option_type) {
+ case 2:
+- /* eagle + 7988d */
+- rx_path_type = 3;
+- rro_bypass = dev->has_rro ? 1 : 3;
+- txfree_path = dev->has_rro ? 0 : 1;
++ if (is_mt7996(&dev->mt76)) {
++ /* eagle + 7988d */
++ rx_path_type = 3;
++ rro_bypass = 1;
++ txfree_path = 0;
++ }
+ break;
+ case 3:
+- /* eagle + Airoha */
+- rx_path_type = 6;
+- rro_bypass = dev->has_rro ? 1 : 3;
+- txfree_path = dev->has_rro ? 0 : 1;
++ /* Airoha */
++ if (is_mt7996(&dev->mt76)) {
++ rx_path_type = 6;
++ rro_bypass = 1;
++ txfree_path = 0;
++ } else {
++ rx_path_type = 8;
++ rro_bypass = 2;
++ txfree_path = 1;
++ }
+ break;
+ case 4:
+- /* Bollinger */
+- rx_path_type = 2;
+- rro_bypass = dev->has_rro ? 1 : 3;
+- txfree_path = dev->has_rro ? 0 : 1;
++ if (is_mt7996(&dev->mt76)) {
++ /* Bollinger */
++ rx_path_type = 2;
++ rro_bypass = 1;
++ txfree_path = 0;
++ }
+ break;
+ default:
+- if (is_mt7996(&dev->mt76))
+- rx_path_type = 2;
+- else
+- rx_path_type = 7;
+-
+- rro_bypass = dev->has_rro ? 1 : 3;
+- txfree_path = dev->has_rro ? 0 : 1;
+ break;
+ }
+
+ mt7996_mcu_set_rro(dev, UNI_RRO_SET_PLATFORM_TYPE, dev->hif2 ? rx_path_type : 0);
+- mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, rro_bypass);
+- mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, txfree_path);
++ mt7996_mcu_set_rro(dev, UNI_RRO_SET_BYPASS_MODE, dev->has_rro ? rro_bypass : 3);
++ mt7996_mcu_set_rro(dev, UNI_RRO_SET_TXFREE_PATH, dev->has_rro ? txfree_path : 1);
+
+ if (dev->has_rro) {
+ u16 timeout;
+@@ -641,7 +648,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ if (phy)
+ return 0;
+
+- if (is_mt7996(&dev->mt76) && dev->hif2) {
++ if (dev->hif2) {
+ switch (dev->option_type) {
+ case 2:
+ /* eagle + 7988d */
+@@ -651,7 +658,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ }
+ break;
+ default:
+- if (band == MT_BAND2) {
++ if ((is_mt7996(&dev->mt76) && band == MT_BAND2) ||
++ (is_mt7992(&dev->mt76) && band == MT_BAND1)) {
+ hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+ wed = &dev->mt76.mmio.wed_hif2;
+ }
+diff --git a/mt7996/main.c b/mt7996/main.c
+index f7ea49f18..2fe9bf28f 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -1607,7 +1607,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+
+- if (phy != &dev->phy && dev->hif2) {
++ if (dev->hif2) {
+ switch (dev->option_type) {
+ case 2:
+ /* eagle + 7988d */
+@@ -1615,7 +1615,8 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ wed = &dev->mt76.mmio.wed_hif2;
+ break;
+ default:
+- if (phy->mt76->band_idx == MT_BAND2)
++ if ((is_mt7996(&dev->mt76) && phy->mt76->band_idx == MT_BAND2) ||
++ (is_mt7992(&dev->mt76) && phy->mt76->band_idx == MT_BAND1))
+ wed = &dev->mt76.mmio.wed_hif2;
+ break;
+ }
+diff --git a/mt7996/mmio.c b/mt7996/mmio.c
+index 91567a04b..6028182e1 100644
+--- a/mt7996/mmio.c
++++ b/mt7996/mmio.c
+@@ -336,10 +336,16 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ MT_TXQ_RING_BASE(0) +
+ MT7996_TXQ_BAND2 * MT_RING_SIZE;
+ if (dev->has_rro) {
++ u8 rxq_id = is_mt7996(&dev->mt76) ?
++ MT7996_RXQ_TXFREE2 : MT7996_RXQ_MCU_WA_EXT;
++
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(0) +
+- MT7996_RXQ_TXFREE2 * MT_RING_SIZE;
+- wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
++ rxq_id * MT_RING_SIZE;
++ if (is_mt7996(&dev->mt76))
++ wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_EXT) - 1;
++ else
++ wed->wlan.txfree_tbit = ffs(MT_INT_RX_TXFREE_BAND1_EXT) - 1;
+ } else {
+ wed->wlan.wpdma_txfree = wed->wlan.phy_base + hif1_ofs +
+ MT_RXQ_RING_BASE(0) +
+@@ -423,6 +429,8 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ MT7996_RXQ_MCU_WA_MAIN * MT_RING_SIZE;
+ }
+ dev->mt76.rx_token_size = MT7996_TOKEN_SIZE + wed->wlan.rx_npkt;
++ if(dev->hif2 && is_mt7992(&dev->mt76))
++ wed->wlan.id = 0x7992;
+ }
+
+ wed->wlan.nbuf = MT7996_TOKEN_SIZE;
+@@ -553,6 +561,9 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
+
+ if (intr1 & MT_INT_RX_DONE_BAND2_EXT)
+ napi_schedule(&dev->mt76.napi[MT_RXQ_BAND2]);
++
++ if (is_mt7992(&dev->mt76) && (intr1 & MT_INT_RX_TXFREE_BAND1_EXT))
++ napi_schedule(&dev->mt76.napi[MT_RXQ_BAND1_WA]);
+ }
+
+ if (mtk_wed_device_active(wed)) {
+diff --git a/mt7996/pci.c b/mt7996/pci.c
+index 24d69d4dc..382b6a898 100644
+--- a/mt7996/pci.c
++++ b/mt7996/pci.c
+@@ -110,7 +110,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
+ int irq, ret;
+ struct mt76_dev *mdev;
+
+- hif2_enable |= (id->device == 0x7990 || id->device == 0x7991);
++ hif2_enable |= (id->device == 0x7990 || id->device == 0x7991 || id->device == 0x799a);
+
+ ret = pcim_enable_device(pdev);
+ if (ret)
+@@ -171,8 +171,7 @@ static int mt7996_pci_probe(struct pci_dev *pdev,
+ hif2_dev = container_of(hif2->dev, struct pci_dev, dev);
+ ret = 0;
+
+- if (is_mt7996(&dev->mt76))
+- ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &irq);
++ ret = mt7996_mmio_wed_init(dev, hif2_dev, true, &irq);
+
+ if (ret < 0)
+ goto free_wed_or_irq_vector;
+diff --git a/mt7996/regs.h b/mt7996/regs.h
+index a0e4b3e11..e18935172 100644
+--- a/mt7996/regs.h
++++ b/mt7996/regs.h
+@@ -525,6 +525,7 @@ enum offs_rev {
+ #define MT_INT_RX_TXFREE_MAIN BIT(17)
+ #define MT_INT_RX_TXFREE_BAND1 BIT(15)
+ #define MT_INT_RX_TXFREE_TRI BIT(15)
++#define MT_INT_RX_TXFREE_BAND1_EXT BIT(19) /* for mt7992 two PCIE*/
+ #define MT_INT_RX_DONE_BAND2_EXT BIT(23)
+ #define MT_INT_RX_TXFREE_EXT BIT(26)
+ #define MT_INT_MCU_CMD BIT(29)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2027-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0082-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2027-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0082-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch
index 42650f3..bcb03ab 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2027-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0082-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch
@@ -1,8 +1,8 @@
-From f55be6f6596db120b2e48a7c87fcacf9d9df25ef Mon Sep 17 00:00:00 2001
+From a5d6a71a81b1bd7daadd810a601615a293beea80 Mon Sep 17 00:00:00 2001
From: Benjamin Lin <benjamin-jw.lin@mediatek.com>
Date: Thu, 11 Jan 2024 08:55:13 +0800
-Subject: [PATCH 2027/2032] mtk: wifi: mt76: mt7992: add support to enable
- index FW log for ConsysPlanet
+Subject: [PATCH 082/116] mtk: wifi: mt76: mt7992: add support to enable index
+ FW log for ConsysPlanet
Add support to enable and record index FW log, which is the input for ConsysPlanet, via mt76-test command.
@@ -25,7 +25,9 @@
- Driver Log: log message printed at driver layer
- Location: /tmp/log/clog_(timestamp)/WIFI_KERNEL_(timestamp).clog
+CR-Id: WCNCR00298425
Signed-off-by: Benjamin Lin <benjamin-jw.lin@mediatek.com>
+Change-Id: I5d72c844e920cdcbaed4c65f734de8f041e6f384
---
mt7996/debugfs.c | 90 +++++++++++++++++--
mt7996/mac.c | 10 ++-
@@ -38,10 +40,10 @@
8 files changed, 295 insertions(+), 69 deletions(-)
diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 6ccf0827..c236ec98 100644
+index e26de48c6..837758611 100644
--- a/mt7996/debugfs.c
+++ b/mt7996/debugfs.c
-@@ -425,8 +425,8 @@ create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
+@@ -430,8 +430,8 @@ create_buf_file_cb(const char *filename, struct dentry *parent, umode_t mode,
{
struct dentry *f;
@@ -52,7 +54,7 @@
if (IS_ERR(f))
return NULL;
-@@ -517,6 +517,53 @@ mt7996_fw_debug_bin_get(void *data, u64 *val)
+@@ -522,6 +522,53 @@ mt7996_fw_debug_bin_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_bin, mt7996_fw_debug_bin_get,
mt7996_fw_debug_bin_set, "%lld\n");
@@ -106,7 +108,7 @@
static int
mt7996_fw_util_wa_show(struct seq_file *file, void *data)
{
-@@ -1037,6 +1084,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+@@ -1042,6 +1089,7 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
@@ -114,7 +116,7 @@
/* TODO: wm fw cpu utilization */
debugfs_create_file("fw_util_wa", 0400, dir, dev,
&mt7996_fw_util_wa_fops);
-@@ -1103,6 +1151,32 @@ mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen,
+@@ -1108,6 +1156,32 @@ mt7996_debugfs_write_fwlog(struct mt7996_dev *dev, const void *hdr, int hdrlen,
spin_unlock_irqrestore(&lock, flags);
}
@@ -147,7 +149,7 @@
void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len)
{
struct {
-@@ -1127,11 +1201,15 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int
+@@ -1132,11 +1206,15 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int
bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len)
{
@@ -168,10 +170,10 @@
return true;
}
diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 88e1fd14..c2a8e752 100644
+index e3758ff13..8c444423b 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -2283,11 +2283,9 @@ void mt7996_mac_work(struct work_struct *work)
+@@ -2279,11 +2279,9 @@ void mt7996_mac_work(struct work_struct *work)
mutex_lock(&mdev->mutex);
mt76_update_survey(mphy);
@@ -184,7 +186,7 @@
mt7996_mac_update_stats(phy);
/* Update DEV-wise information only in
-@@ -2306,6 +2304,12 @@ void mt7996_mac_work(struct work_struct *work)
+@@ -2302,6 +2300,12 @@ void mt7996_mac_work(struct work_struct *work)
if (mt7996_mcu_wa_cmd(phy->dev, MCU_WA_PARAM_CMD(QUERY), MCU_WA_PARAM_BSS_ACQ_PKT_CNT,
BSS_ACQ_PKT_CNT_BSS_BITMAP_ALL | BSS_ACQ_PKT_CNT_READ_CLR, 0))
dev_err(mdev->dev, "Failed to query per-AC-queue packet counts.\n");
@@ -198,10 +200,10 @@
test_bit(MT76_STATE_RUNNING, &mdev->phys[i]->state))
break;
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 9e04ea2b..0cb4cfa5 100644
+index 6fb9f81f0..3a376c9ac 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -397,6 +397,7 @@ static void
+@@ -400,6 +400,7 @@ static void
mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
{
#define UNI_EVENT_FW_LOG_FORMAT 0
@@ -209,7 +211,7 @@
struct mt7996_mcu_rxd *rxd = (struct mt7996_mcu_rxd *)skb->data;
const char *data = (char *)&rxd[1] + 4, *type;
struct tlv *tlv = (struct tlv *)data;
-@@ -408,7 +409,8 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -411,7 +412,8 @@ mt7996_mcu_rx_log_message(struct mt7996_dev *dev, struct sk_buff *skb)
goto out;
}
@@ -219,7 +221,7 @@
return;
data += sizeof(*tlv) + 4;
-@@ -3444,6 +3446,36 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level)
+@@ -3184,6 +3186,36 @@ int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level)
sizeof(data), false);
}
@@ -257,7 +259,7 @@
{
struct {
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 7721a01b..826cf204 100644
+index d24874a4b..814072e3a 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
@@ -357,7 +357,8 @@ enum {
@@ -270,7 +272,7 @@
};
enum {
-@@ -949,6 +950,7 @@ enum {
+@@ -950,6 +951,7 @@ enum {
UNI_WSYS_CONFIG_FW_LOG_CTRL,
UNI_WSYS_CONFIG_FW_DBG_CTRL,
UNI_CMD_CERT_CFG = 6,
@@ -279,10 +281,10 @@
enum {
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index f172eea2..10886cb1 100644
+index 69bcf78f5..d03d3d94c 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -642,9 +642,11 @@ struct mt7996_dev {
+@@ -591,9 +591,11 @@ struct mt7996_dev {
u8 fw_debug_bin;
u16 fw_debug_seq;
bool fw_debug_muru_disable;
@@ -294,7 +296,7 @@
void *cal;
u32 cur_prek_offset;
-@@ -896,6 +898,7 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
+@@ -845,6 +847,7 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
int mt7996_mcu_red_config(struct mt7996_dev *dev, bool enable);
int mt7996_mcu_fw_log_2_host(struct mt7996_dev *dev, u8 type, u8 ctrl);
int mt7996_mcu_fw_dbg_ctrl(struct mt7996_dev *dev, u32 module, u8 level);
@@ -303,7 +305,7 @@
void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
void mt7996_mcu_exit(struct mt7996_dev *dev);
diff --git a/tools/fwlog.c b/tools/fwlog.c
-index 3c6a61d7..0e2de2dc 100644
+index 3c6a61d71..0e2de2dc2 100644
--- a/tools/fwlog.c
+++ b/tools/fwlog.c
@@ -29,10 +29,9 @@ static const char *debugfs_path(const char *phyname, const char *file)
@@ -591,7 +593,7 @@
return ret;
}
diff --git a/tools/main.c b/tools/main.c
-index 699a9eea..e9e25567 100644
+index 699a9eea6..e9e255679 100644
--- a/tools/main.c
+++ b/tools/main.c
@@ -198,6 +198,8 @@ int main(int argc, char **argv)
@@ -604,7 +606,7 @@
usage();
diff --git a/tools/mt76-test.h b/tools/mt76-test.h
-index d2fafa86..b9d508c5 100644
+index d2fafa862..b9d508c5c 100644
--- a/tools/mt76-test.h
+++ b/tools/mt76-test.h
@@ -22,6 +22,8 @@
@@ -624,5 +626,5 @@
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0083-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0083-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch
new file mode 100644
index 0000000..bb90a0e
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0083-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch
@@ -0,0 +1,452 @@
+From afcc6594ef97e51bdbb707b7e9aeb8dfb7202ef1 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 3 Nov 2023 21:44:45 +0800
+Subject: [PATCH 083/116] wifi: mt76: mt7996: implement and switch to hw scan
+ callbacks
+
+To support MLO, hw_scan callbacks are mandatory. However, the
+firmware of AP-segment doesn't support hw_scan commands, so we need
+to implement it in the driver.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+If the cfg80211_scan_request contains an unicast BSSID, the probe
+request should be unicast.
+This works for ML probe request, which should be unicast.
+
+Change-Id: Ic096b10e4a82211be4c5c435d3e34e0a76ea3b9e
+Co-developed-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Co-developed-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 3 +-
+ mt76.h | 2 +
+ mt7996/init.c | 5 ++
+ mt7996/mac.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c | 95 ++++++++++++++++++++++++++++----
+ mt7996/mcu.c | 3 +-
+ mt7996/mt7996.h | 11 +++-
+ 7 files changed, 248 insertions(+), 12 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index c7b222837..4fad03dd9 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -820,7 +820,7 @@ bool mt76_has_tx_pending(struct mt76_phy *phy)
+ }
+ EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
+
+-static struct mt76_channel_state *
++struct mt76_channel_state *
+ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ {
+ struct mt76_sband *msband;
+@@ -836,6 +836,7 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ idx = c - &msband->sband.channels[0];
+ return &msband->chan[idx];
+ }
++EXPORT_SYMBOL_GPL(mt76_channel_state);
+
+ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time)
+ {
+diff --git a/mt76.h b/mt76.h
+index c3c35841f..0abb8ebf5 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -1477,6 +1477,8 @@ void mt76_release_buffered_frames(struct ieee80211_hw *hw,
+ enum ieee80211_frame_release_type reason,
+ bool more_data);
+ bool mt76_has_tx_pending(struct mt76_phy *phy);
++struct mt76_channel_state *
++mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c);
+ void mt76_set_channel(struct mt76_phy *phy);
+ void mt76_update_survey(struct mt76_phy *phy);
+ void mt76_update_survey_active_time(struct mt76_phy *phy, ktime_t time);
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 768979ef7..952356823 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -457,6 +457,9 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+
+ wiphy->available_antennas_rx = phy->mt76->antenna_mask;
+ wiphy->available_antennas_tx = phy->mt76->antenna_mask;
++
++ wiphy->max_scan_ssids = 4;
++ wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+ }
+
+ static void
+@@ -677,6 +680,7 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ mphy->dev->phys[band] = mphy;
+
+ INIT_DELAYED_WORK(&mphy->mac_work, mt7996_mac_work);
++ INIT_DELAYED_WORK(&phy->scan_work, mt7996_scan_work);
+
+ ret = mt7996_eeprom_parse_hw_cap(dev, phy);
+ if (ret)
+@@ -1574,6 +1578,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ dev->mt76.phy.priv = &dev->phy;
+ INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
+ INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
++ INIT_DELAYED_WORK(&dev->phy.scan_work, mt7996_scan_work);
+ INIT_DELAYED_WORK(&dev->scs_work, mt7996_mcu_scs_sta_poll);
+ INIT_LIST_HEAD(&dev->sta_rc_list);
+ INIT_LIST_HEAD(&dev->twt_list);
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 8c444423b..4e9dd2c1f 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2693,3 +2693,144 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
+ dev->twt.table_mask &= ~BIT(flow->table_id);
+ dev->twt.n_agrt--;
+ }
++
++static void
++mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
++ const u8 *dst)
++{
++ struct ieee80211_hw *hw = phy->mt76->hw;
++ struct cfg80211_scan_request *req = phy->scan_req;
++ struct ieee80211_vif *vif = phy->scan_vif;
++ struct mt7996_vif *mvif;
++ struct mt76_wcid *wcid;
++ struct ieee80211_tx_info *info;
++ struct sk_buff *skb;
++
++ if (!req || !vif)
++ return;
++
++ mvif = (struct mt7996_vif *)vif->drv_priv;
++ wcid = &mvif->sta.wcid;
++
++ skb = ieee80211_probereq_get(hw, vif->addr,
++ ssid->ssid, ssid->ssid_len, req->ie_len);
++ if (!skb)
++ return;
++
++ if (is_unicast_ether_addr(dst)) {
++ struct ieee80211_hdr_3addr *hdr =
++ (struct ieee80211_hdr_3addr *)skb->data;
++ memcpy(hdr->addr1, dst, ETH_ALEN);
++ memcpy(hdr->addr3, dst, ETH_ALEN);
++ }
++
++ info = IEEE80211_SKB_CB(skb);
++ if (req->no_cck)
++ info->flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
++
++ if (req->ie_len)
++ skb_put_data(skb, req->ie, req->ie_len);
++
++ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
++
++ rcu_read_lock();
++ if (!ieee80211_tx_prepare_skb(hw, vif, skb,
++ phy->scan_chan->band,
++ NULL)) {
++ rcu_read_unlock();
++ ieee80211_free_txskb(hw, skb);
++ return;
++ }
++
++ local_bh_disable();
++ mt76_tx(phy->mt76, NULL, wcid, skb);
++ local_bh_enable();
++
++ rcu_read_unlock();
++}
++
++void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted)
++{
++ struct cfg80211_scan_info info = {
++ .aborted = aborted,
++ };
++
++ ieee80211_scan_completed(phy->mt76->hw, &info);
++ phy->scan_chan = NULL;
++ phy->scan_req = NULL;
++ phy->scan_vif = NULL;
++ clear_bit(MT76_SCANNING, &phy->mt76->state);
++}
++
++static void mt7996_scan_check_sta(void *data, struct ieee80211_sta *sta)
++{
++ bool *has_sta = data;
++
++ if (*has_sta)
++ return;
++ *has_sta = true;
++}
++
++void mt7996_scan_work(struct work_struct *work)
++{
++ struct mt7996_phy *phy = container_of(work, struct mt7996_phy, scan_work.work);
++ struct ieee80211_hw *hw = phy->mt76->hw;
++ struct cfg80211_scan_request *req = phy->scan_req;
++ struct cfg80211_chan_def chandef = {};
++ int duration;
++ bool has_sta = false, active_scan = false;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ if (phy->scan_chan_idx >= req->n_channels) {
++ mt7996_scan_complete(phy, false);
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ mt7996_set_channel(phy, &hw->conf.chandef);
++
++ return;
++ }
++
++ ieee80211_iterate_stations_atomic(hw, mt7996_scan_check_sta, &has_sta);
++
++ /* go back to operating channel */
++ if (has_sta && phy->scan_chan) {
++ phy->scan_chan = NULL;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ mt7996_set_channel(phy, &phy->mt76->chandef);
++
++ ieee80211_queue_delayed_work(hw, &phy->scan_work, HZ / 10);
++
++ return;
++ }
++
++ wiphy_info(hw->wiphy, "hw scan %d MHz\n",
++ req->channels[phy->scan_chan_idx]->center_freq);
++
++ phy->scan_chan = req->channels[phy->scan_chan_idx++];
++
++ if (!req->n_ssids ||
++ (phy->scan_chan->flags & (IEEE80211_CHAN_NO_IR |
++ IEEE80211_CHAN_RADAR))) {
++ duration = HZ / 9; /* ~110 ms */
++ } else {
++ duration = HZ / 16; /* ~60 ms */
++ active_scan = true;
++ }
++
++ cfg80211_chandef_create(&chandef, phy->scan_chan, NL80211_CHAN_HT20);
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ mt7996_set_channel(phy, &chandef);
++
++ if (active_scan) {
++ int i;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ for (i = 0; i < req->n_ssids; i++)
++ mt7996_scan_send_probe(phy, &req->ssids[i], req->bssid);
++ mutex_unlock(&phy->dev->mt76.mutex);
++ }
++
++ ieee80211_queue_delayed_work(hw, &phy->scan_work, duration);
++}
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 2fe9bf28f..c8f1b1097 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -312,6 +312,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ int idx = msta->wcid.idx;
+
++ cancel_delayed_work_sync(&phy->scan_work);
++
+ mt7996_mcu_add_sta(dev, vif, NULL, false, false);
+ mt7996_mcu_add_bss_info(phy, vif, false);
+
+@@ -323,6 +325,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+
+ mutex_lock(&dev->mt76.mutex);
++
++ if (test_bit(MT76_SCANNING, &phy->mt76->state))
++ mt7996_scan_complete(phy, true);
++
+ dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
+ phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
+ mutex_unlock(&dev->mt76.mutex);
+@@ -335,7 +341,33 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ mt76_wcid_cleanup(&dev->mt76, &msta->wcid);
+ }
+
+-int mt7996_set_channel(struct mt7996_phy *phy)
++static void ___mt7996_set_channel(struct mt7996_phy *phy,
++ struct cfg80211_chan_def *chandef)
++{
++ struct mt76_dev *mdev = phy->mt76->dev;
++ struct mt76_phy *mphy = phy->mt76;
++ bool offchannel = phy->scan_chan != NULL;
++ int timeout = HZ / 5;
++
++ wait_event_timeout(mdev->tx_wait, !mt76_has_tx_pending(mphy), timeout);
++ mt76_update_survey(mphy);
++
++ if (mphy->chandef.chan->center_freq != chandef->chan->center_freq ||
++ mphy->chandef.width != chandef->width)
++ mphy->dfs_state = MT_DFS_STATE_UNKNOWN;
++
++ mphy->chandef = *chandef;
++ mphy->chan_state = mt76_channel_state(mphy, chandef->chan);
++
++ if (!offchannel)
++ mphy->main_chan = chandef->chan;
++
++ if (chandef->chan != mphy->main_chan)
++ memset(mphy->chan_state, 0, sizeof(*mphy->chan_state));
++}
++
++static int __mt7996_set_channel(struct mt7996_phy *phy,
++ struct cfg80211_chan_def *chandef)
+ {
+ struct mt7996_dev *dev = phy->dev;
+ int ret;
+@@ -345,7 +377,7 @@ int mt7996_set_channel(struct mt7996_phy *phy)
+ mutex_lock(&dev->mt76.mutex);
+ set_bit(MT76_RESET, &phy->mt76->state);
+
+- mt76_set_channel(phy->mt76);
++ ___mt7996_set_channel(phy, chandef);
+
+ if (dev->cal) {
+ ret = mt7996_mcu_apply_tx_dpd(phy);
+@@ -381,6 +413,19 @@ out:
+ return ret;
+ }
+
++int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef)
++{
++ int ret;
++
++ ieee80211_stop_queues(phy->mt76->hw);
++ ret = __mt7996_set_channel(phy, chandef);
++ if (ret)
++ return ret;
++ ieee80211_wake_queues(phy->mt76->hw);
++
++ return 0;
++}
++
+ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+ struct ieee80211_key_conf *key)
+@@ -477,11 +522,7 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+ if (ret)
+ return ret;
+
+- ieee80211_stop_queues(hw);
+- ret = mt7996_set_channel(phy);
+- if (ret)
+- return ret;
+- ieee80211_wake_queues(hw);
++ mt7996_set_channel(phy, &hw->conf.chandef);
+ }
+
+ if (changed & (IEEE80211_CONF_CHANGE_POWER |
+@@ -1648,6 +1689,42 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+
+ #endif
+
++static int
++mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_scan_request *hw_req)
++{
++ struct cfg80211_scan_request *req = &hw_req->req;
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ if (WARN_ON(phy->scan_req || phy->scan_chan)) {
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return -EBUSY;
++ }
++
++ set_bit(MT76_SCANNING, &phy->mt76->state);
++ phy->scan_req = req;
++ phy->scan_vif = vif;
++ phy->scan_chan_idx = 0;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ ieee80211_queue_delayed_work(hw, &phy->scan_work, 0);
++
++ return 0;
++}
++
++static void
++mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
++{
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++
++ cancel_delayed_work_sync(&phy->scan_work);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ mt7996_scan_complete(phy, true);
++ mutex_unlock(&phy->dev->mt76.mutex);
++}
++
+ const struct ieee80211_ops mt7996_ops = {
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+@@ -1666,8 +1743,8 @@ const struct ieee80211_ops mt7996_ops = {
+ .ampdu_action = mt7996_ampdu_action,
+ .set_rts_threshold = mt7996_set_rts_threshold,
+ .wake_tx_queue = mt76_wake_tx_queue,
+- .sw_scan_start = mt76_sw_scan,
+- .sw_scan_complete = mt76_sw_scan_complete,
++ .hw_scan = mt7996_hw_scan,
++ .cancel_hw_scan = mt7996_cancel_hw_scan,
+ .release_buffered_frames = mt76_release_buffered_frames,
+ .get_txpower = mt76_get_txpower,
+ .channel_switch_beacon = mt7996_channel_switch_beacon,
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 3a376c9ac..99cca0dc7 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3775,7 +3775,8 @@ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag)
+ if (phy->mt76->hw->conf.flags & IEEE80211_CONF_MONITOR)
+ req.switch_reason = CH_SWITCH_NORMAL;
+ else if (phy->mt76->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL ||
+- phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE)
++ phy->mt76->hw->conf.flags & IEEE80211_CONF_IDLE ||
++ phy->scan_chan)
+ req.switch_reason = CH_SWITCH_SCAN_BYPASS_DPD;
+ else if (!cfg80211_reg_can_beacon(phy->mt76->hw->wiphy, chandef,
+ NL80211_IFTYPE_AP))
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index d03d3d94c..fbf1e835b 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -458,6 +458,13 @@ struct mt7996_phy {
+ u8 pp_mode;
+ u16 punct_bitmap;
+
++ /* for hw_scan */
++ struct delayed_work scan_work;
++ struct ieee80211_channel *scan_chan;
++ struct cfg80211_scan_request *scan_req;
++ struct ieee80211_vif *scan_vif;
++ int scan_chan_idx;
++
+ struct mt7996_scs_ctrl scs_ctrl;
+ u32 red_drop;
+
+@@ -806,7 +813,7 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_he_obss_pd *he_obss_pd);
+ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, bool changed);
+-int mt7996_set_channel(struct mt7996_phy *phy);
++int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
+ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
+ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif);
+ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+@@ -964,6 +971,8 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+ struct sk_buff *skb, u32 *info);
+ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
+ void mt7996_stats_work(struct work_struct *work);
++void mt7996_scan_work(struct work_struct *work);
++void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted);
+ int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
+ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);
+ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0084-wifi-mt76-mt7996-implement-and-switch-to-chanctx-cal.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0084-wifi-mt76-mt7996-implement-and-switch-to-chanctx-cal.patch
new file mode 100644
index 0000000..efe816c
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0084-wifi-mt76-mt7996-implement-and-switch-to-chanctx-cal.patch
@@ -0,0 +1,384 @@
+From fa5c84eb945cb472d98172876d176bff4a082d67 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 6 Nov 2023 16:17:11 +0800
+Subject: [PATCH 084/116] wifi: mt76: mt7996: implement and switch to chanctx
+ callbacks
+
+To support MLO, chanctx callbacks are mandatory, since one VIF (MLD) could
+operate on multiple channels (links).
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Change-Id: Ie4530a3bc2ac9e51045184d5aecca14118177042
+Co-developed-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/init.c | 22 ++++++
+ mt7996/mac.c | 10 ++-
+ mt7996/main.c | 178 ++++++++++++++++++++++++++++++++++++++++++++----
+ mt7996/mcu.c | 2 +-
+ mt7996/mt7996.h | 17 +++++
+ 5 files changed, 211 insertions(+), 18 deletions(-)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 952356823..6eeec3b8d 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -382,6 +382,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+
+ hw->sta_data_size = sizeof(struct mt7996_sta);
+ hw->vif_data_size = sizeof(struct mt7996_vif);
++ hw->chanctx_data_size = sizeof(struct mt7996_chanctx);
+
+ wiphy->iface_combinations = if_comb;
+ wiphy->n_iface_combinations = ARRAY_SIZE(if_comb);
+@@ -417,6 +418,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+ ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+ ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
++ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
+
+ hw->max_tx_fragments = 4;
+
+@@ -637,6 +639,22 @@ static int mt7996_vow_init(struct mt7996_phy *phy)
+ return mt7996_mcu_set_vow_feature_ctrl(phy);
+ }
+
++static void mt7996_init_chanctx(struct mt7996_phy *phy)
++{
++ struct ieee80211_supported_band *sband;
++ struct ieee80211_channel *chan;
++
++ if (phy->mt76->band_idx == MT_BAND2)
++ sband = &phy->mt76->sband_6g.sband;
++ else if (phy->mt76->band_idx == MT_BAND1)
++ sband = &phy->mt76->sband_5g.sband;
++ else
++ sband = &phy->mt76->sband_2g.sband;
++
++ chan = &sband->channels[0];
++ cfg80211_chandef_create(&phy->mt76->chandef, chan, NL80211_CHAN_HT20);
++}
++
+ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ enum mt76_band_id band)
+ {
+@@ -720,6 +738,8 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ if (ret)
+ goto error;
+
++ mt7996_init_chanctx(phy);
++
+ ret = mt7996_thermal_init(phy);
+ if (ret)
+ goto error;
+@@ -1609,6 +1629,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ mt7996_init_chanctx(&dev->phy);
++
+ ret = mt7996_thermal_init(&dev->phy);
+ if (ret)
+ return ret;
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 4e9dd2c1f..0879c7735 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2785,7 +2785,10 @@ void mt7996_scan_work(struct work_struct *work)
+ mt7996_scan_complete(phy, false);
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+- mt7996_set_channel(phy, &hw->conf.chandef);
++ if (phy->chanctx)
++ mt7996_set_channel(phy, &phy->chanctx->chandef);
++ else
++ mt7996_set_channel(phy, &phy->mt76->chandef);
+
+ return;
+ }
+@@ -2797,7 +2800,10 @@ void mt7996_scan_work(struct work_struct *work)
+ phy->scan_chan = NULL;
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+- mt7996_set_channel(phy, &phy->mt76->chandef);
++ if (phy->chanctx)
++ mt7996_set_channel(phy, &phy->chanctx->chandef);
++ else
++ mt7996_set_channel(phy, &phy->mt76->chandef);
+
+ ieee80211_queue_delayed_work(hw, &phy->scan_work, HZ / 10);
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index c8f1b1097..dd4f3a711 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -76,6 +76,11 @@ int mt7996_run(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++ /* set a parking channel */
++ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
++ if (ret)
++ goto out;
++
+ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
+ if (ret)
+ goto out;
+@@ -510,21 +515,6 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ int ret;
+
+- if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
+- if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
+- ret = mt7996_mcu_edcca_enable(phy, true);
+- if (ret)
+- return ret;
+- }
+-
+- ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE,
+- phy->mt76->chandef.punctured);
+- if (ret)
+- return ret;
+-
+- mt7996_set_channel(phy, &hw->conf.chandef);
+- }
+-
+ if (changed & (IEEE80211_CONF_CHANGE_POWER |
+ IEEE80211_CONF_CHANGE_CHANNEL)) {
+ ret = mt7996_mcu_set_txpower_sku(phy);
+@@ -1725,6 +1715,158 @@ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ mutex_unlock(&phy->dev->mt76.mutex);
+ }
+
++static int
++mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
++{
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
++ int ret;
++
++ wiphy_info(hw->wiphy, "%s: add %u\n", __func__, conf->def.chan->hw_value);
++ mutex_lock(&phy->dev->mt76.mutex);
++
++ if (ctx->assigned) {
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return -ENOSPC;
++ }
++
++ ctx->assigned = true;
++ ctx->chandef = conf->def;
++ ctx->phy = phy;
++ if (phy->chanctx) {
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return 0;
++ }
++
++ phy->chanctx = ctx;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
++ ret = mt7996_mcu_edcca_enable(phy, true);
++ if (ret)
++ return ret;
++ }
++
++ ret = mt7996_mcu_set_pp_en(phy, PP_USR_MODE, ctx->chandef.punctured);
++ if (ret)
++ return ret;
++
++ return mt7996_set_channel(phy, &ctx->chandef);
++}
++
++static void
++mt7996_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
++{
++ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
++ struct mt7996_phy *phy = ctx->phy;
++
++ wiphy_info(hw->wiphy, "%s: remove %u\n", __func__, conf->def.chan->hw_value);
++ cancel_delayed_work_sync(&phy->scan_work);
++ cancel_delayed_work_sync(&phy->mt76->mac_work);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ ctx->assigned = false;
++ if (ctx == phy->chanctx)
++ phy->chanctx = NULL;
++ mutex_unlock(&phy->dev->mt76.mutex);
++}
++
++static void
++mt7996_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf,
++ u32 changed)
++{
++ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
++ struct mt7996_phy *phy = ctx->phy;
++
++ wiphy_info(hw->wiphy, "%s: change %u, 0x%x\n", __func__, conf->def.chan->hw_value, changed);
++ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
++ ctx->chandef = conf->def;
++
++ mt7996_set_channel(phy, &ctx->chandef);
++ }
++}
++
++static int
++mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *link_conf,
++ struct ieee80211_chanctx_conf *conf)
++{
++ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
++ struct mt7996_phy *phy = ctx->phy;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++
++ wiphy_info(hw->wiphy, "Assign VIF (addr: %pM, type: %d, link_id: %d) to channel context: %d MHz\n",
++ vif->addr, vif->type, link_conf->link_id,
++ conf->def.chan->center_freq);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++
++ mvif->chanctx = ctx;
++ ctx->nbss_assigned++;
++
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ return 0;
++}
++
++static void
++mt7996_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *link_conf,
++ struct ieee80211_chanctx_conf *conf)
++{
++ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
++ struct mt7996_phy *phy = ctx->phy;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++
++ wiphy_info(hw->wiphy, "Remove VIF (addr: %pM, type: %d, link_id: %d) from channel context: %d MHz\n",
++ vif->addr, vif->type, link_conf->link_id,
++ conf->def.chan->center_freq);
++ cancel_delayed_work_sync(&phy->scan_work);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++
++ if (test_bit(MT76_SCANNING, &phy->mt76->state))
++ mt7996_scan_complete(phy, true);
++
++ mvif->chanctx = NULL;
++ ctx->nbss_assigned--;
++
++ mutex_unlock(&phy->dev->mt76.mutex);
++}
++
++static int
++mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
++ struct ieee80211_vif_chanctx_switch *vifs,
++ int n_vifs,
++ enum ieee80211_chanctx_switch_mode mode)
++{
++ struct mt7996_chanctx *old_ctx = mt7996_chanctx_get(vifs->old_ctx);
++ struct mt7996_chanctx *new_ctx = mt7996_chanctx_get(vifs->new_ctx);
++ struct mt7996_phy *phy = old_ctx->phy;
++
++ wiphy_info(hw->wiphy, "%s: old=%d, new=%d\n", __func__, vifs->old_ctx->def.chan->hw_value, vifs->new_ctx->def.chan->hw_value);
++
++ if (new_ctx->nbss_assigned && phy->chanctx == new_ctx) {
++ new_ctx->nbss_assigned += n_vifs;
++ return 0;
++ }
++
++ if (WARN_ON(old_ctx != phy->chanctx))
++ return -EINVAL;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++
++ phy->chanctx = new_ctx;
++ new_ctx->assigned = true;
++ new_ctx->chandef = vifs->new_ctx->def;
++ new_ctx->phy = phy;
++ new_ctx->nbss_assigned += n_vifs;
++
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ return mt7996_set_channel(phy, &new_ctx->chandef);
++}
++
+ const struct ieee80211_ops mt7996_ops = {
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+@@ -1775,4 +1917,10 @@ const struct ieee80211_ops mt7996_ops = {
+ .net_fill_forward_path = mt7996_net_fill_forward_path,
+ .net_setup_tc = mt76_wed_net_setup_tc,
+ #endif
++ .add_chanctx = mt7996_add_chanctx,
++ .remove_chanctx = mt7996_remove_chanctx,
++ .change_chanctx = mt7996_change_chanctx,
++ .assign_vif_chanctx = mt7996_assign_vif_chanctx,
++ .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
++ .switch_vif_chanctx = mt7996_switch_vif_chanctx,
+ };
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 99cca0dc7..85077108e 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -5309,7 +5309,7 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap)
+ .bitmap = cpu_to_le16(bitmap),
+ };
+
+- if (phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ ||
++ if (phy->chanctx->chandef.chan->band == NL80211_BAND_2GHZ ||
+ mode > PP_USR_MODE)
+ return 0;
+
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index fbf1e835b..84aafb404 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -332,6 +332,8 @@ struct mt7996_vif {
+
+ struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+ struct cfg80211_bitrate_mask bitrate_mask;
++
++ struct mt7996_chanctx *chanctx;
+ };
+
+ /* crash-dump */
+@@ -421,6 +423,14 @@ struct mt7996_rro_ba_session {
+ u32 last_in_rxtime :12;
+ };
+
++struct mt7996_chanctx {
++ struct cfg80211_chan_def chandef;
++ struct mt7996_phy *phy;
++
++ bool assigned;
++ u8 nbss_assigned;
++};
++
+ struct mt7996_phy {
+ struct mt76_phy *mt76;
+ struct mt7996_dev *dev;
+@@ -464,6 +474,7 @@ struct mt7996_phy {
+ struct cfg80211_scan_request *scan_req;
+ struct ieee80211_vif *scan_vif;
+ int scan_chan_idx;
++ struct mt7996_chanctx *chanctx;
+
+ struct mt7996_scs_ctrl scs_ctrl;
+ u32 red_drop;
+@@ -752,6 +763,12 @@ mt7996_get_background_radar_cap(struct mt7996_dev *dev)
+ return 1;
+ }
+
++static inline struct mt7996_chanctx *
++mt7996_chanctx_get(struct ieee80211_chanctx_conf *ctx)
++{
++ return (struct mt7996_chanctx *)&ctx->drv_priv;
++}
++
+ extern const struct ieee80211_ops mt7996_ops;
+ extern struct pci_driver mt7996_pci_driver;
+ extern struct pci_driver mt7996_hif_driver;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0085-wifi-mt76-mt7996-use-.sta_state-to-replace-.sta_add-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0085-wifi-mt76-mt7996-use-.sta_state-to-replace-.sta_add-.patch
new file mode 100644
index 0000000..03615f1
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0085-wifi-mt76-mt7996-use-.sta_state-to-replace-.sta_add-.patch
@@ -0,0 +1,147 @@
+From 3e111fa2be564cc27c213471242f6b6b920e253c Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 8 Nov 2023 18:52:26 +0800
+Subject: [PATCH 085/116] wifi: mt76: mt7996: use .sta_state to replace
+ .sta_add and .sta_remove
+
+MAC80211 mostly uses MLD address through TX path, and leaves the header
+translation procedure to driver. To perform address translation, driver
+needs to get the setup link address at early stage (i.e., state 1),
+however, when using .sta_add/.sta_remove callbacks, driver can only get
+the link address at state 3, so it's necessary to switch to .sta_state
+callback to meet this requirement.
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Change-Id: I8a0faef919843f2c7d5ff3256702a3bf8384ea60
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/main.c | 53 ++++++++++++++++++++-----------------------------
+ mt7996/mmio.c | 1 +
+ mt7996/mt7996.h | 2 ++
+ 3 files changed, 24 insertions(+), 32 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index dd4f3a711..c330dd479 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -784,7 +784,7 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ u8 band_idx = mvif->phy->mt76->band_idx;
+- int ret, idx;
++ int idx;
+
+ #ifdef CONFIG_MTK_VENDOR
+ struct mt7996_phy *phy = &dev->phy;
+@@ -802,23 +802,10 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ msta->wcid.phy_idx = band_idx;
+ msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+
+- ewma_avg_signal_init(&msta->avg_ack_signal);
+-
+- mt7996_mac_wtbl_update(dev, idx,
+- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+-
+ #ifdef CONFIG_MTK_VENDOR
+ mt7996_vendor_amnt_sta_remove(mvif->phy, sta);
+ #endif
+
+- ret = mt7996_mcu_add_sta(dev, vif, sta, true, true);
+- if (ret)
+- return ret;
+-
+- ret = mt7996_mcu_add_rate_ctrl(dev, vif, sta, false);
+- if (ret)
+- return ret;
+-
+ #ifdef CONFIG_MTK_VENDOR
+ switch (band_idx) {
+ case MT_BAND1:
+@@ -839,6 +826,25 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ return 0;
+ }
+
++void mt7996_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta)
++{
++ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ mt7996_mac_wtbl_update(dev, msta->wcid.idx,
++ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
++
++ mt7996_mcu_add_sta(dev, vif, sta, true, true);
++ mt7996_mcu_add_rate_ctrl(dev, vif, sta, false);
++
++ ewma_avg_signal_init(&msta->avg_ack_signal);
++
++ mutex_unlock(&dev->mt76.mutex);
++}
++
+ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+ {
+@@ -958,22 +964,6 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ return ret;
+ }
+
+-static int
+-mt7996_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta)
+-{
+- return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NOTEXIST,
+- IEEE80211_STA_NONE);
+-}
+-
+-static int
+-mt7996_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta)
+-{
+- return mt76_sta_state(hw, vif, sta, IEEE80211_STA_NONE,
+- IEEE80211_STA_NOTEXIST);
+-}
+-
+ static int
+ mt7996_get_stats(struct ieee80211_hw *hw,
+ struct ieee80211_low_level_stats *stats)
+@@ -1877,8 +1867,7 @@ const struct ieee80211_ops mt7996_ops = {
+ .conf_tx = mt7996_conf_tx,
+ .configure_filter = mt7996_configure_filter,
+ .bss_info_changed = mt7996_bss_info_changed,
+- .sta_add = mt7996_sta_add,
+- .sta_remove = mt7996_sta_remove,
++ .sta_state = mt76_sta_state,
+ .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
+ .sta_rc_update = mt7996_sta_rc_update,
+ .set_key = mt7996_set_key,
+diff --git a/mt7996/mmio.c b/mt7996/mmio.c
+index 6028182e1..6abbcb68e 100644
+--- a/mt7996/mmio.c
++++ b/mt7996/mmio.c
+@@ -655,6 +655,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
+ .rx_check = mt7996_rx_check,
+ .rx_poll_complete = mt7996_rx_poll_complete,
+ .sta_add = mt7996_mac_sta_add,
++ .sta_assoc = mt7996_mac_sta_assoc,
+ .sta_remove = mt7996_mac_sta_remove,
+ .update_survey = mt7996_update_channel,
+ };
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 84aafb404..2b266d18b 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -966,6 +966,8 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
+ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
++void mt7996_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta);
+ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
+ void mt7996_mac_work(struct work_struct *work);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0086-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0086-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch
new file mode 100644
index 0000000..e8d7384
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0086-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch
@@ -0,0 +1,2320 @@
+From 175bf6b7c7eabfb45f6618b17d19c475a1e0916e Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 24 Nov 2023 11:31:55 +0800
+Subject: [PATCH 086/116] wifi: mt76: mt7996: switch to per-link data structure
+ of vif
+
+Introduce struct mt7996_bss_conf, data structure for per-link BSS.
+Note that mt7996_vif now represents a legacy or MLD device.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/debugfs.c | 10 +-
+ mt7996/init.c | 4 +-
+ mt7996/mac.c | 25 ++-
+ mt7996/main.c | 269 ++++++++++++++++++-----------
+ mt7996/mcu.c | 429 +++++++++++++++++++++++-----------------------
+ mt7996/mt7996.h | 72 +++++---
+ mt7996/testmode.c | 17 +-
+ 7 files changed, 463 insertions(+), 363 deletions(-)
+
+diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
+index 837758611..06015d686 100644
+--- a/mt7996/debugfs.c
++++ b/mt7996/debugfs.c
+@@ -739,7 +739,7 @@ static void
+ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_dev *dev = msta->vif->phy->dev;
++ struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
+ struct seq_file *s = data;
+ u8 ac;
+
+@@ -759,7 +759,7 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
+ GENMASK(11, 0));
+ seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
+ sta->addr, msta->wcid.idx,
+- msta->vif->mt76.wmm_idx, ac, qlen);
++ msta->vif->deflink.mt76.wmm_idx, ac, qlen);
+ }
+ }
+
+@@ -1023,7 +1023,7 @@ mt7996_atf_enable_set(void *data, u64 val)
+ int ret;
+
+ vow->max_deficit = val ? 64 : 1;
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND);
+ if (ret)
+ return ret;
+
+@@ -1055,7 +1055,7 @@ mt7996_airtime_read(struct seq_file *s, void *data)
+
+ msta = container_of(wcid, struct mt7996_sta, wcid);
+ sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+- vif = &msta->vif->mt76;
++ vif = &msta->vif->deflink.mt76;
+ stats = &wcid->stats;
+
+ seq_printf(s, "%pM WCID: %hu BandIdx: %hhu OmacIdx: 0x%hhx\t"
+@@ -1230,7 +1230,7 @@ static ssize_t mt7996_sta_fixed_rate_set(struct file *file,
+ #define LONG_PREAMBLE 1
+ struct ieee80211_sta *sta = file->private_data;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_dev *dev = msta->vif->phy->dev;
++ struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
+ struct ra_rate phy = {};
+ char buf[100];
+ int ret;
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 6eeec3b8d..381e1292c 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -628,11 +628,11 @@ static int mt7996_vow_init(struct mt7996_phy *phy)
+ vow->drr_quantum[6] = VOW_DRR_QUANTUM_L6;
+ vow->drr_quantum[7] = VOW_DRR_QUANTUM_L7;
+
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, NULL, VOW_DRR_CTRL_AIRTIME_DEFICIT_BOUND);
+ if (ret)
+ return ret;
+
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, NULL, NULL, VOW_DRR_CTRL_AIRTIME_QUANTUM_ALL);
+ if (ret)
+ return ret;
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 0879c7735..63b16f92e 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -897,8 +897,9 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+
+ if (vif) {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf = &mvif->deflink;
+
+- txp->fw.bss_idx = mvif->mt76.idx;
++ txp->fw.bss_idx = mconf->mt76.idx;
+ }
+
+ txp->fw.token = cpu_to_le16(id);
+@@ -1518,12 +1519,15 @@ static void
+ mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+ struct ieee80211_hw *hw = priv;
++ struct ieee80211_bss_conf *conf = &vif->bss_conf;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf = &mvif->deflink;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+- mt7996_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
++ mt7996_mcu_add_beacon(hw, conf, mconf, conf->enable_beacon);
+ break;
+ default:
+ break;
+@@ -2237,6 +2241,8 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+ struct mt7996_dev *dev = container_of(work, struct mt7996_dev, rc_work);
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif;
++ struct ieee80211_bss_conf *conf;
++ struct mt7996_bss_conf *mconf;
+ struct mt7996_sta *msta;
+ u32 changed;
+ LIST_HEAD(list);
+@@ -2253,14 +2259,16 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+
+ sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+ vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
++ conf = &vif->bss_conf;
++ mconf = &msta->vif->deflink;
+
+ if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
+ IEEE80211_RC_NSS_CHANGED |
+ IEEE80211_RC_BW_CHANGED))
+- mt7996_mcu_add_rate_ctrl(dev, vif, sta, true);
++ mt7996_mcu_add_rate_ctrl(dev, conf, mconf, sta, true);
+
+ if (changed & IEEE80211_RC_SMPS_CHANGED)
+- mt7996_mcu_set_fixed_field(dev, vif, sta, NULL,
++ mt7996_mcu_set_fixed_field(dev, mconf, sta, NULL,
+ RATE_PARAM_MMPS_UPDATE);
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+@@ -2643,7 +2651,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+
+ flow->sched = true;
+ flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
+- curr_tsf = __mt7996_get_tsf(hw, msta->vif);
++ curr_tsf = __mt7996_get_tsf(hw, &msta->vif->deflink);
+ div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
+ flow_tsf = curr_tsf + interval - rem;
+ twt_agrt->twt = cpu_to_le64(flow_tsf);
+@@ -2652,7 +2660,8 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ }
+ flow->tsf = le64_to_cpu(twt_agrt->twt);
+
+- if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow, MCU_TWT_AGRT_ADD))
++ if (mt7996_mcu_twt_agrt_update(dev, &msta->vif->deflink, flow,
++ MCU_TWT_AGRT_ADD))
+ goto unlock;
+
+ setup_cmd = TWT_SETUP_CMD_ACCEPT;
+@@ -2674,6 +2683,7 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
+ u8 flowid)
+ {
+ struct mt7996_twt_flow *flow;
++ struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
+
+ lockdep_assert_held(&dev->mt76.mutex);
+
+@@ -2684,8 +2694,7 @@ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
+ return;
+
+ flow = &msta->twt.flow[flowid];
+- if (mt7996_mcu_twt_agrt_update(dev, msta->vif, flow,
+- MCU_TWT_AGRT_DELETE))
++ if (mt7996_mcu_twt_agrt_update(dev, mconf, flow, MCU_TWT_AGRT_DELETE))
+ return;
+
+ list_del_init(&flow->list);
+diff --git a/mt7996/main.c b/mt7996/main.c
+index c330dd479..9f61082f5 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -205,29 +205,30 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
+ return -1;
+ }
+
+-static void mt7996_init_bitrate_mask(struct ieee80211_vif *vif)
++static void mt7996_init_bitrate_mask(struct mt7996_bss_conf *mconf)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ int i;
+
+- for (i = 0; i < ARRAY_SIZE(mvif->bitrate_mask.control); i++) {
+- mvif->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI;
+- mvif->bitrate_mask.control[i].he_gi = 0xff;
+- mvif->bitrate_mask.control[i].he_ltf = 0xff;
+- mvif->bitrate_mask.control[i].legacy = GENMASK(31, 0);
+- memset(mvif->bitrate_mask.control[i].ht_mcs, 0xff,
+- sizeof(mvif->bitrate_mask.control[i].ht_mcs));
+- memset(mvif->bitrate_mask.control[i].vht_mcs, 0xff,
+- sizeof(mvif->bitrate_mask.control[i].vht_mcs));
+- memset(mvif->bitrate_mask.control[i].he_mcs, 0xff,
+- sizeof(mvif->bitrate_mask.control[i].he_mcs));
++ for (i = 0; i < ARRAY_SIZE(mconf->bitrate_mask.control); i++) {
++ mconf->bitrate_mask.control[i].gi = NL80211_TXRATE_DEFAULT_GI;
++ mconf->bitrate_mask.control[i].he_gi = 0xff;
++ mconf->bitrate_mask.control[i].he_ltf = 0xff;
++ mconf->bitrate_mask.control[i].legacy = GENMASK(31, 0);
++ memset(mconf->bitrate_mask.control[i].ht_mcs, 0xff,
++ sizeof(mconf->bitrate_mask.control[i].ht_mcs));
++ memset(mconf->bitrate_mask.control[i].vht_mcs, 0xff,
++ sizeof(mconf->bitrate_mask.control[i].vht_mcs));
++ memset(mconf->bitrate_mask.control[i].he_mcs, 0xff,
++ sizeof(mconf->bitrate_mask.control[i].he_mcs));
+ }
+ }
+
+ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+ {
++ struct ieee80211_bss_conf *conf = &vif->bss_conf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf = &mvif->deflink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt76_txq *mtxq;
+@@ -240,8 +241,8 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ is_zero_ether_addr(vif->addr))
+ phy->monitor_vif = vif;
+
+- mvif->mt76.idx = __ffs64(~dev->mt76.vif_mask);
+- if (mvif->mt76.idx >= mt7996_max_interface_num(dev)) {
++ mconf->mt76.idx = __ffs64(~dev->mt76.vif_mask);
++ if (mconf->mt76.idx >= mt7996_max_interface_num(dev)) {
+ ret = -ENOSPC;
+ goto out;
+ }
+@@ -251,19 +252,21 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ ret = -ENOSPC;
+ goto out;
+ }
+- mvif->mt76.omac_idx = idx;
+- mvif->phy = phy;
+- mvif->mt76.band_idx = band_idx;
+- mvif->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP;
+-
+- ret = mt7996_mcu_add_dev_info(phy, vif, true);
++ mconf->mt76.omac_idx = idx;
++ mconf->vif = mvif;
++ mconf->phy = phy;
++ mconf->mt76.band_idx = band_idx;
++ mconf->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP;
++ mvif->dev = dev;
++
++ ret = mt7996_mcu_add_dev_info(phy, conf, mconf, true);
+ if (ret)
+ goto out;
+
+- dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
+- phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
++ dev->mt76.vif_mask |= BIT_ULL(mconf->mt76.idx);
++ phy->omac_mask |= BIT_ULL(mconf->mt76.omac_idx);
+
+- idx = MT7996_WTBL_RESERVED - mvif->mt76.idx;
++ idx = MT7996_WTBL_RESERVED - mconf->mt76.idx;
+
+ INIT_LIST_HEAD(&mvif->sta.rc_list);
+ INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
+@@ -283,24 +286,25 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ }
+
+ if (vif->type != NL80211_IFTYPE_AP &&
+- (!mvif->mt76.omac_idx || mvif->mt76.omac_idx > 3))
++ (!mconf->mt76.omac_idx || mconf->mt76.omac_idx > 3))
+ vif->offload_flags = 0;
+ vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
+
+ if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
+- mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
++ mconf->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
+ else
+- mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
++ mconf->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
+
+- mt7996_init_bitrate_mask(vif);
++ mt7996_init_bitrate_mask(mconf);
+
+- mt7996_mcu_add_bss_info(phy, vif, true);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, true);
+ /* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA
+ * interface, since firmware only records BSSID when the entry is new
+ */
+ if (vif->type != NL80211_IFTYPE_STATION)
+- mt7996_mcu_add_sta(dev, vif, NULL, true, true);
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, true, true);
+ rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
++ rcu_assign_pointer(mvif->link[0], mconf);
+
+ out:
+ mutex_unlock(&dev->mt76.mutex);
+@@ -311,7 +315,9 @@ out:
+ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+ {
++ struct ieee80211_bss_conf *conf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+ struct mt7996_sta *msta = &mvif->sta;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+@@ -319,24 +325,22 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+
+ cancel_delayed_work_sync(&phy->scan_work);
+
+- mt7996_mcu_add_sta(dev, vif, NULL, false, false);
+- mt7996_mcu_add_bss_info(phy, vif, false);
++ mutex_lock(&dev->mt76.mutex);
++
++ conf = link_conf_dereference_protected(vif, 0);
++ mconf = mconf_dereference_protected(mvif, 0);
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, false, false);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, false);
+
+ if (vif == phy->monitor_vif)
+ phy->monitor_vif = NULL;
+
+- mt7996_mcu_add_dev_info(phy, vif, false);
++ mt7996_mcu_add_dev_info(phy, conf, mconf, false);
+
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+
+- mutex_lock(&dev->mt76.mutex);
+-
+- if (test_bit(MT76_SCANNING, &phy->mt76->state))
+- mt7996_scan_complete(phy, true);
+-
+- dev->mt76.vif_mask &= ~BIT_ULL(mvif->mt76.idx);
+- phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
+- mutex_unlock(&dev->mt76.mutex);
++ dev->mt76.vif_mask &= ~BIT_ULL(mconf->mt76.idx);
++ phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx);
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (!list_empty(&msta->wcid.poll_list))
+@@ -344,6 +348,9 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+
+ mt76_wcid_cleanup(&dev->mt76, &msta->wcid);
++ rcu_assign_pointer(mvif->link[0], NULL);
++
++ mutex_unlock(&dev->mt76.mutex);
+ }
+
+ static void ___mt7996_set_channel(struct mt7996_phy *phy,
+@@ -441,6 +448,8 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv :
+ &mvif->sta;
+ struct mt76_wcid *wcid = &msta->wcid;
++ struct mt7996_bss_conf *mconf;
++ struct ieee80211_bss_conf *conf;
+ u8 *wcid_keyidx = &wcid->hw_key_idx;
+ int idx = key->keyidx;
+ int err = 0;
+@@ -482,9 +491,11 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+
+ mutex_lock(&dev->mt76.mutex);
+
+- if (cmd == SET_KEY && !sta && !mvif->mt76.cipher) {
+- mvif->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher);
+- mt7996_mcu_add_bss_info(phy, vif, true);
++ conf = link_conf_dereference_protected(vif, 0);
++ mconf = mconf_dereference_protected(mvif, 0);
++ if (cmd == SET_KEY && !sta && !mconf->mt76.cipher) {
++ mconf->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, true);
+ }
+
+ if (cmd == SET_KEY) {
+@@ -498,9 +509,9 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ mt76_wcid_key_setup(&dev->mt76, wcid, key);
+
+ if (key->keyidx == 6 || key->keyidx == 7)
+- err = mt7996_mcu_bcn_prot_enable(dev, vif, key);
++ err = mt7996_mcu_bcn_prot_enable(dev, conf, mconf, key);
+ else
+- err = mt7996_mcu_add_key(&dev->mt76, vif, key,
++ err = mt7996_mcu_add_key(&dev->mt76, mconf, key,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
+ &msta->wcid, cmd);
+ out:
+@@ -547,7 +558,9 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id, u16 queue,
+ const struct ieee80211_tx_queue_params *params)
+ {
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+ const u8 mq_to_aci[] = {
+ [IEEE80211_AC_VO] = 3,
+ [IEEE80211_AC_VI] = 2,
+@@ -555,10 +568,15 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ [IEEE80211_AC_BK] = 1,
+ };
+
++ mutex_lock(&dev->mt76.mutex);
++ mconf = mconf_dereference_protected(mvif, 0);
++
+ /* firmware uses access class index */
+- mvif->queue_params[mq_to_aci[queue]] = *params;
++ mconf->queue_params[mq_to_aci[queue]] = *params;
+ /* no need to update right away, we'll get BSS_CHANGED_QOS */
+
++ mutex_unlock(&dev->mt76.mutex);
++
+ return 0;
+ }
+
+@@ -619,22 +637,20 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw,
+ }
+
+ static void
+-mt7996_update_bss_color(struct ieee80211_hw *hw,
+- struct ieee80211_vif *vif,
++mt7996_update_bss_color(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct mt7996_bss_conf *mconf,
+ struct cfg80211_he_bss_color *bss_color)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_AP: {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+-
+- if (mvif->mt76.omac_idx > HW_BSSID_MAX)
++ if (mconf->mt76.omac_idx > HW_BSSID_MAX)
+ return;
+ fallthrough;
+ }
+ case NL80211_IFTYPE_STATION:
+- mt7996_mcu_update_bss_color(dev, vif, bss_color);
++ mt7996_mcu_update_bss_color(dev, mconf, bss_color);
+ break;
+ default:
+ break;
+@@ -642,16 +658,15 @@ mt7996_update_bss_color(struct ieee80211_hw *hw,
+ }
+
+ static u8
+-mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- bool beacon, bool mcast)
++mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, bool beacon, bool mcast)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt76_phy *mphy = hw->priv;
++ struct mt76_phy *mphy = mconf->phy->mt76;
+ u16 rate;
+ u8 i, idx;
+
+- rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast);
++ rate = mt76_connac2_mac_tx_rate_val(mphy, conf->vif, beacon, mcast);
+
+ if (beacon) {
+ struct mt7996_phy *phy = mphy->priv;
+@@ -672,23 +687,22 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ if ((mt76_rates[i].hw_value & GENMASK(7, 0)) == idx)
+ return MT7996_BASIC_RATES_TBL + 2 * i;
+
+- return mvif->basic_rates_idx;
++ return mconf->mt76.basic_rates_idx;
+ }
+
+ static void
+-mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- struct ieee80211_bss_conf *info)
++mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- u8 band = mvif->mt76.band_idx;
++ u8 band = mconf->mt76.band_idx;
+ u32 *mu;
+
+- mu = (u32 *)info->mu_group.membership;
++ mu = (u32 *)conf->mu_group.membership;
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]);
+
+- mu = (u32 *)info->mu_group.position;
++ mu = (u32 *)conf->mu_group.position;
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]);
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]);
+@@ -700,20 +714,22 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ struct ieee80211_bss_conf *info,
+ u64 changed)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+
++ mconf = mconf_dereference_protected(mvif, 0);
+ /* station mode uses BSSID to map the wlan entry to a peer,
+ * and then peer references bss_info_rfch to set bandwidth cap.
+ */
+ if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) ||
+ (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||
+ (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) {
+- mt7996_mcu_add_bss_info(phy, vif, true);
+- mt7996_mcu_add_sta(dev, vif, NULL, true,
++ mt7996_mcu_add_bss_info(phy, info, mconf, true);
++ mt7996_mcu_add_sta(dev, info, mconf, NULL, true,
+ !!(changed & BSS_CHANGED_BSSID));
+ }
+
+@@ -725,42 +741,42 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+
+ if (slottime != phy->slottime) {
+ phy->slottime = slottime;
+- mt7996_mcu_set_timing(phy, vif);
++ mt7996_mcu_set_timing(phy, mconf);
+ }
+ }
+
+ if (changed & BSS_CHANGED_MCAST_RATE)
+- mvif->mcast_rates_idx =
+- mt7996_get_rates_table(hw, vif, false, true);
++ mconf->mt76.mcast_rates_idx =
++ mt7996_get_rates_table(hw, info, mconf, false, true);
+
+ if (changed & BSS_CHANGED_BASIC_RATES)
+- mvif->basic_rates_idx =
+- mt7996_get_rates_table(hw, vif, false, false);
++ mconf->mt76.basic_rates_idx =
++ mt7996_get_rates_table(hw, info, mconf, false, false);
+
+ /* ensure that enable txcmd_mode after bss_info */
+ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED))
+- mt7996_mcu_set_tx(dev, vif);
++ mt7996_mcu_set_tx(dev, mconf);
+
+ if (changed & BSS_CHANGED_HE_OBSS_PD)
+- mt7996_mcu_add_obss_spr(phy, vif, &info->he_obss_pd);
++ mt7996_mcu_add_obss_spr(phy, mconf, &info->he_obss_pd);
+
+ if (changed & BSS_CHANGED_HE_BSS_COLOR)
+- mt7996_update_bss_color(hw, vif, &info->he_bss_color);
++ mt7996_update_bss_color(hw, vif, mconf, &info->he_bss_color);
+
+ if (changed & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED)) {
+- mvif->beacon_rates_idx =
+- mt7996_get_rates_table(hw, vif, true, false);
++ mconf->mt76.beacon_rates_idx =
++ mt7996_get_rates_table(hw, info, mconf, true, false);
+
+- mt7996_mcu_add_beacon(hw, vif, info->enable_beacon);
++ mt7996_mcu_add_beacon(hw, info, mconf, info->enable_beacon);
+ }
+
+ if (changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+ BSS_CHANGED_FILS_DISCOVERY))
+- mt7996_mcu_beacon_inband_discov(dev, vif, changed);
++ mt7996_mcu_beacon_inband_discov(dev, info, mconf, changed);
+
+ if (changed & BSS_CHANGED_MU_GROUPS)
+- mt7996_update_mu_group(hw, vif, info);
++ mt7996_update_mu_group(hw, info, mconf);
+
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -771,9 +787,14 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct cfg80211_chan_def *chandef)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
++ struct ieee80211_bss_conf *conf;
+
+ mutex_lock(&dev->mt76.mutex);
+- mt7996_mcu_add_beacon(hw, vif, true);
++ mconf = mconf_dereference_protected(mvif, 0);
++ conf = link_conf_dereference_protected(vif, 0);
++ mt7996_mcu_add_beacon(hw, conf, mconf, true);
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -783,7 +804,8 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- u8 band_idx = mvif->phy->mt76->band_idx;
++ struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
++ u8 band_idx = mconf->phy->mt76->band_idx;
+ int idx;
+
+ #ifdef CONFIG_MTK_VENDOR
+@@ -803,7 +825,7 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+
+ #ifdef CONFIG_MTK_VENDOR
+- mt7996_vendor_amnt_sta_remove(mvif->phy, sta);
++ mt7996_vendor_amnt_sta_remove(mconf->phy, sta);
+ #endif
+
+ #ifdef CONFIG_MTK_VENDOR
+@@ -830,15 +852,20 @@ void mt7996_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+ {
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_bss_conf *mconf;
++ struct ieee80211_bss_conf *conf;
+
+ mutex_lock(&dev->mt76.mutex);
+
+ mt7996_mac_wtbl_update(dev, msta->wcid.idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+
+- mt7996_mcu_add_sta(dev, vif, sta, true, true);
+- mt7996_mcu_add_rate_ctrl(dev, vif, sta, false);
++ conf = link_conf_dereference_protected(vif, 0);
++ mconf = mconf_dereference_protected(mvif, 0);
++ mt7996_mcu_add_sta(dev, conf, mconf, sta, true, true);
++ mt7996_mcu_add_rate_ctrl(dev, conf, mconf, sta, false);
+
+ ewma_avg_signal_init(&msta->avg_ack_signal);
+
+@@ -849,10 +876,15 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+ {
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_bss_conf *mconf;
++ struct ieee80211_bss_conf *conf;
+ int i;
+
+- mt7996_mcu_add_sta(dev, vif, sta, false, false);
++ conf = link_conf_dereference_protected(vif, 0);
++ mconf = mconf_dereference_protected(mvif, 0);
++ mt7996_mcu_add_sta(dev, conf, mconf, sta, false, false);
+
+ mt7996_mac_wtbl_update(dev, msta->wcid.idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+@@ -984,7 +1016,7 @@ mt7996_get_stats(struct ieee80211_hw *hw,
+ return 0;
+ }
+
+-u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif)
++u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_bss_conf *mconf)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+@@ -996,8 +1028,8 @@ u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif)
+
+ lockdep_assert_held(&dev->mt76.mutex);
+
+- n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
+- : mvif->mt76.omac_idx;
++ n = mconf->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
++ : mconf->mt76.omac_idx;
+ /* TSF software read */
+ mt76_rmw(dev, MT_LPON_TCR(phy->mt76->band_idx, n), MT_LPON_TCR_SW_MODE,
+ MT_LPON_TCR_SW_READ);
+@@ -1012,10 +1044,12 @@ mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_bss_conf *mconf;
+ u64 ret;
+
+ mutex_lock(&dev->mt76.mutex);
+- ret = __mt7996_get_tsf(hw, mvif);
++ mconf = mconf_dereference_protected(mvif, 0);
++ ret = __mt7996_get_tsf(hw, mconf);
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+@@ -1028,6 +1062,7 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_bss_conf *mconf;
+ union {
+ u64 t64;
+ u32 t32[2];
+@@ -1036,8 +1071,9 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+
+ mutex_lock(&dev->mt76.mutex);
+
+- n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
+- : mvif->mt76.omac_idx;
++ mconf = mconf_dereference_protected(mvif, 0);
++ n = mconf->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
++ : mconf->mt76.omac_idx;
+ mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]);
+ mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]);
+ /* TSF software overwrite */
+@@ -1054,6 +1090,7 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_bss_conf *mconf;
+ union {
+ u64 t64;
+ u32 t32[2];
+@@ -1062,8 +1099,9 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+
+ mutex_lock(&dev->mt76.mutex);
+
+- n = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
+- : mvif->mt76.omac_idx;
++ mconf = mconf_dereference_protected(mvif, 0);
++ n = mconf->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
++ : mconf->mt76.omac_idx;
+ mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]);
+ mt76_wr(dev, MT_LPON_UTTR1(phy->mt76->band_idx), tsf.t32[1]);
+ /* TSF software adjust*/
+@@ -1179,7 +1217,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
+ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_dev *dev = msta->vif->phy->dev;
++ struct mt7996_dev *dev = msta->vif->dev;
+ u32 *changed = data;
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+@@ -1215,9 +1253,13 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_dev *dev = phy->dev;
++ struct mt7996_bss_conf *mconf;
+ u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+
+- mvif->bitrate_mask = *mask;
++ mutex_lock(&dev->mt76.mutex);
++ mconf = mconf_dereference_protected(mvif, 0);
++ mconf->bitrate_mask = *mask;
++ mutex_unlock(&dev->mt76.mutex);
+
+ /* if multiple rates across different preambles are given we can
+ * reconfigure this info with all peers using sta_rec command with
+@@ -1239,14 +1281,20 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,
+ bool enabled)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_bss_conf *mconf;
++
++ mutex_lock(&dev->mt76.mutex);
++ mconf = mconf_dereference_protected(mvif, 0);
+
+ if (enabled)
+ set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
+ else
+ clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
+
+- mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta);
++ mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, sta);
++ mutex_unlock(&dev->mt76.mutex);
+ }
+
+ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
+@@ -1255,14 +1303,20 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
+ bool enabled)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_bss_conf *mconf;
++
++ mutex_lock(&dev->mt76.mutex);
++ mconf = mconf_dereference_protected(mvif, 0);
+
+ if (enabled)
+ set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
+ else
+ clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
+
+- mt7996_mcu_wtbl_update_hdr_trans(dev, vif, sta);
++ mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, sta);
++ mutex_unlock(&dev->mt76.mutex);
+ }
+
+ static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = {
+@@ -1395,7 +1449,7 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
+ struct mt76_ethtool_worker_info *wi = wi_data;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+
+- if (msta->vif->mt76.idx != wi->idx)
++ if (msta->vif->deflink.mt76.idx != wi->idx)
+ return;
+
+ mt76_ethtool_worker(wi, &msta->wcid.stats, true);
+@@ -1409,15 +1463,17 @@ void mt7996_get_et_stats(struct ieee80211_hw *hw,
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+ struct mt76_mib_stats *mib = &phy->mib;
+ struct mt76_ethtool_worker_info wi = {
+ .data = data,
+- .idx = mvif->mt76.idx,
+ };
+ /* See mt7996_ampdu_stat_read_phy, etc */
+ int i, ei = 0;
+
+ mutex_lock(&dev->mt76.mutex);
++ mconf = mconf_dereference_protected(mvif, 0);
++ wi.idx = mconf->mt76.idx,
+
+ mt7996_mac_update_stats(phy);
+
+@@ -1623,6 +1679,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ struct net_device_path *path)
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf = &mvif->deflink;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+@@ -1652,7 +1709,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ path->type = DEV_PATH_MTK_WDMA;
+ path->dev = ctx->dev;
+ path->mtk_wdma.wdma_idx = wed->wdma_idx;
+- path->mtk_wdma.bss = mvif->mt76.idx;
++ path->mtk_wdma.bss = mconf->mt76.idx;
+ path->mtk_wdma.queue = 0;
+ path->mtk_wdma.wcid = msta->wcid.idx;
+
+@@ -1784,6 +1841,7 @@ mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
+ struct mt7996_phy *phy = ctx->phy;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+
+ wiphy_info(hw->wiphy, "Assign VIF (addr: %pM, type: %d, link_id: %d) to channel context: %d MHz\n",
+ vif->addr, vif->type, link_conf->link_id,
+@@ -1791,7 +1849,8 @@ mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+
+ mutex_lock(&phy->dev->mt76.mutex);
+
+- mvif->chanctx = ctx;
++ mconf = mconf_dereference_protected(mvif, 0);
++ mconf->chanctx = ctx;
+ ctx->nbss_assigned++;
+
+ mutex_unlock(&phy->dev->mt76.mutex);
+@@ -1807,6 +1866,7 @@ mt7996_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
+ struct mt7996_phy *phy = ctx->phy;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+
+ wiphy_info(hw->wiphy, "Remove VIF (addr: %pM, type: %d, link_id: %d) from channel context: %d MHz\n",
+ vif->addr, vif->type, link_conf->link_id,
+@@ -1818,7 +1878,8 @@ mt7996_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ if (test_bit(MT76_SCANNING, &phy->mt76->state))
+ mt7996_scan_complete(phy, true);
+
+- mvif->chanctx = NULL;
++ mconf = mconf_dereference_protected(mvif, 0);
++ mconf->chanctx = NULL;
+ ctx->nbss_assigned--;
+
+ mutex_unlock(&phy->dev->mt76.mutex);
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 85077108e..11700f90f 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -117,12 +117,12 @@ mt7996_mcu_get_sta_nss(u16 mcs_map)
+ }
+
+ static void
+-mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
+- u16 mcs_map)
++mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta,
++ struct mt7996_bss_conf *mconf,
++ __le16 *he_mcs, u16 mcs_map)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- enum nl80211_band band = msta->vif->phy->mt76->chandef.chan->band;
+- const u16 *mask = msta->vif->bitrate_mask.control[band].he_mcs;
++ enum nl80211_band band = mconf->phy->mt76->chandef.chan->band;
++ const u16 *mask = mconf->bitrate_mask.control[band].he_mcs;
+ int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
+
+ for (nss = 0; nss < max_nss; nss++) {
+@@ -922,8 +922,7 @@ mt7996_mcu_add_uni_tlv(struct sk_buff *skb, u16 tag, u16 len)
+ }
+
+ static void
+-mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+- struct mt7996_phy *phy)
++mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct mt7996_phy *phy)
+ {
+ static const u8 rlm_ch_band[] = {
+ [NL80211_BAND_2GHZ] = 1,
+@@ -953,8 +952,7 @@ mt7996_mcu_bss_rfch_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ }
+
+ static void
+-mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+- struct mt7996_phy *phy)
++mt7996_mcu_bss_ra_tlv(struct sk_buff *skb)
+ {
+ struct bss_ra_tlv *ra;
+ struct tlv *tlv;
+@@ -966,7 +964,7 @@ mt7996_mcu_bss_ra_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ }
+
+ static void
+-mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
++mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ struct mt7996_phy *phy)
+ {
+ #define DEFAULT_HE_PE_DURATION 4
+@@ -975,16 +973,16 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct bss_info_uni_he *he;
+ struct tlv *tlv;
+
+- cap = mt76_connac_get_he_phy_cap(phy->mt76, vif);
++ cap = mt76_connac_get_he_phy_cap(phy->mt76, conf->vif);
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_HE_BASIC, sizeof(*he));
+
+ he = (struct bss_info_uni_he *)tlv;
+- he->he_pe_duration = vif->bss_conf.htc_trig_based_pkt_ext;
++ he->he_pe_duration = conf->htc_trig_based_pkt_ext;
+ if (!he->he_pe_duration)
+ he->he_pe_duration = DEFAULT_HE_PE_DURATION;
+
+- he->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
++ he->he_rts_thres = cpu_to_le16(conf->frame_time_rts_th);
+ if (!he->he_rts_thres)
+ he->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
+
+@@ -994,13 +992,13 @@ mt7996_mcu_bss_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ }
+
+ static void
+-mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
++mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ struct mt7996_phy *phy, int enable)
+ {
+ struct bss_info_uni_mbssid *mbssid;
+ struct tlv *tlv;
+
+- if (!vif->bss_conf.bssid_indicator && enable)
++ if (!conf->bssid_indicator && enable)
+ return;
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_11V_MBSSID, sizeof(*mbssid));
+@@ -1008,23 +1006,21 @@ mt7996_mcu_bss_mbssid_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ mbssid = (struct bss_info_uni_mbssid *)tlv;
+
+ if (enable) {
+- mbssid->max_indicator = vif->bss_conf.bssid_indicator;
+- mbssid->mbss_idx = vif->bss_conf.bssid_index;
++ mbssid->max_indicator = conf->bssid_indicator;
++ mbssid->mbss_idx = conf->bssid_index;
+ mbssid->tx_bss_omac_idx = 0;
+ }
+ }
+
+ static void
+-mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
++mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct mt7996_bss_conf *mconf,
+ struct mt7996_phy *phy)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct bss_rate_tlv *bmc;
+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
+ enum nl80211_band band = chandef->chan->band;
+ struct tlv *tlv;
+- u8 idx = mvif->mcast_rates_idx ?
+- mvif->mcast_rates_idx : mvif->basic_rates_idx;
++ u8 idx = mconf->mt76.mcast_rates_idx ?: mconf->mt76.basic_rates_idx;
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_RATE, sizeof(*bmc));
+
+@@ -1048,9 +1044,9 @@ mt7996_mcu_bss_txcmd_tlv(struct sk_buff *skb, bool en)
+ }
+
+ static void
+-mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
++mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
++ struct mt7996_bss_conf *mconf)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct bss_mld_tlv *mld;
+ struct tlv *tlv;
+
+@@ -1058,33 +1054,30 @@ mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+
+ mld = (struct bss_mld_tlv *)tlv;
+ mld->group_mld_id = 0xff;
+- mld->own_mld_id = mvif->mt76.idx;
++ mld->own_mld_id = mconf->mt76.idx;
+ mld->remap_idx = 0xff;
+ }
+
+ static void
+-mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
++mt7996_mcu_bss_sec_tlv(struct sk_buff *skb, struct mt7996_bss_conf *mconf)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct bss_sec_tlv *sec;
+ struct tlv *tlv;
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_SEC, sizeof(*sec));
+
+ sec = (struct bss_sec_tlv *)tlv;
+- sec->cipher = mvif->cipher;
++ sec->cipher = mconf->mt76.cipher;
+ }
+
+ static int
+-mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+- bool bssid, bool enable)
++mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, bool bssid, bool enable)
+ {
+ #define UNI_MUAR_ENTRY 2
+ struct mt7996_dev *dev = phy->dev;
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- u32 idx = mvif->mt76.omac_idx - REPEATER_BSSID_START;
+- const u8 *addr = vif->addr;
+-
++ u32 idx = mconf->mt76.omac_idx - REPEATER_BSSID_START;
++ const u8 *addr = bssid ? conf->bssid : conf->vif->addr;
+ struct {
+ struct {
+ u8 band;
+@@ -1109,9 +1102,6 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ .entry_add = true,
+ };
+
+- if (bssid)
+- addr = vif->bss_conf.bssid;
+-
+ if (enable)
+ memcpy(req.addr, addr, ETH_ALEN);
+
+@@ -1120,10 +1110,8 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ }
+
+ static void
+-mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
++mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct mt7996_phy *phy)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_phy *phy = mvif->phy;
+ struct bss_ifs_time_tlv *ifs_time;
+ struct tlv *tlv;
+ bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
+@@ -1149,12 +1137,13 @@ mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
+
+ static int
+ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+- struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta,
+ struct mt76_phy *phy, u16 wlan_idx,
+ bool enable)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
++ struct ieee80211_vif *vif = conf->vif;
+ struct cfg80211_chan_def *chandef = &phy->chandef;
+ struct mt76_connac_bss_basic_tlv *bss;
+ u32 type = CONNECTION_INFRA_AP;
+@@ -1171,8 +1160,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ if (enable) {
+ rcu_read_lock();
+ if (!sta)
+- sta = ieee80211_find_sta(vif,
+- vif->bss_conf.bssid);
++ sta = ieee80211_find_sta(vif, conf->bssid);
+ /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
+ if (sta) {
+ struct mt76_wcid *wcid;
+@@ -1195,18 +1183,17 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_BASIC, sizeof(*bss));
+
+ bss = (struct mt76_connac_bss_basic_tlv *)tlv;
+- bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+- bss->dtim_period = vif->bss_conf.dtim_period;
+ bss->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
+ bss->sta_idx = cpu_to_le16(sta_wlan_idx);
+ bss->conn_type = cpu_to_le32(type);
+- bss->omac_idx = mvif->omac_idx;
+- bss->band_idx = mvif->band_idx;
+- bss->wmm_idx = mvif->wmm_idx;
++ bss->omac_idx = mconf->mt76.omac_idx;
++ bss->band_idx = mconf->mt76.band_idx;
++ bss->wmm_idx = mconf->mt76.wmm_idx;
+ bss->conn_state = !enable;
+ bss->active = enable;
+
+- idx = mvif->omac_idx > EXT_BSSID_START ? HW_BSSID_0 : mvif->omac_idx;
++ idx = mconf->mt76.omac_idx > EXT_BSSID_START ? HW_BSSID_0 :
++ mconf->mt76.omac_idx;
+ bss->hw_bss_idx = idx;
+
+ if (vif->type == NL80211_IFTYPE_MONITOR) {
+@@ -1219,9 +1206,9 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ return 0;
+ }
+
+- memcpy(bss->bssid, vif->bss_conf.bssid, ETH_ALEN);
+- bss->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+- bss->dtim_period = vif->bss_conf.dtim_period;
++ memcpy(bss->bssid, conf->bssid, ETH_ALEN);
++ bss->bcn_interval = cpu_to_le16(conf->beacon_int);
++ bss->dtim_period = conf->dtim_period;
+ bss->phymode = mt76_connac_get_phy_mode(phy, vif,
+ chandef->chan->band, NULL);
+ bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, vif,
+@@ -1248,63 +1235,64 @@ __mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len)
+ }
+
+ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
+- struct ieee80211_vif *vif, int enable)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, int enable)
+ {
++ struct ieee80211_vif *vif = conf->vif;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = phy->dev;
+ struct sk_buff *skb;
+
+- if (mvif->mt76.omac_idx >= REPEATER_BSSID_START) {
+- mt7996_mcu_muar_config(phy, vif, false, enable);
+- mt7996_mcu_muar_config(phy, vif, true, enable);
++ if (mconf->mt76.omac_idx >= REPEATER_BSSID_START) {
++ mt7996_mcu_muar_config(phy, conf, mconf, false, enable);
++ mt7996_mcu_muar_config(phy, conf, mconf, true, enable);
+ }
+
+- skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
++ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
+ MT7996_BSS_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ /* bss_basic must be first */
+- mt7996_mcu_bss_basic_tlv(skb, vif, NULL, phy->mt76,
++ mt7996_mcu_bss_basic_tlv(skb, conf, mconf, NULL, phy->mt76,
+ mvif->sta.wcid.idx, enable);
+- mt7996_mcu_bss_sec_tlv(skb, vif);
++ mt7996_mcu_bss_sec_tlv(skb, mconf);
+
+ if (vif->type == NL80211_IFTYPE_MONITOR)
+ goto out;
+
+ if (enable) {
+- mt7996_mcu_bss_rfch_tlv(skb, vif, phy);
+- mt7996_mcu_bss_bmc_tlv(skb, vif, phy);
+- mt7996_mcu_bss_ra_tlv(skb, vif, phy);
++ mt7996_mcu_bss_rfch_tlv(skb, phy);
++ mt7996_mcu_bss_bmc_tlv(skb, mconf, phy);
++ mt7996_mcu_bss_ra_tlv(skb);
+ mt7996_mcu_bss_txcmd_tlv(skb, true);
+- mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
++ mt7996_mcu_bss_ifs_timing_tlv(skb, phy);
+
+- if (vif->bss_conf.he_support)
+- mt7996_mcu_bss_he_tlv(skb, vif, phy);
++ if (conf->he_support)
++ mt7996_mcu_bss_he_tlv(skb, conf, phy);
+
+ /* this tag is necessary no matter if the vif is MLD */
+- mt7996_mcu_bss_mld_tlv(skb, vif);
++ mt7996_mcu_bss_mld_tlv(skb, vif, mconf);
+ }
+
+- mt7996_mcu_bss_mbssid_tlv(skb, vif, phy, enable);
++ mt7996_mcu_bss_mbssid_tlv(skb, conf, phy, enable);
+
+ out:
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+ }
+
+-int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
++int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct mt7996_bss_conf *mconf)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = phy->dev;
+ struct sk_buff *skb;
+
+- skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
++ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
+ MT7996_BSS_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+- mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
++ mt7996_mcu_bss_ifs_timing_tlv(skb, phy);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+@@ -1346,12 +1334,12 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ bool enable)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
+- struct mt7996_vif *mvif = msta->vif;
++ struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
+
+ if (enable && !params->amsdu)
+ msta->wcid.amsdu = false;
+
+- return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, true);
++ return mt7996_mcu_sta_ba(dev, &mconf->mt76, params, enable, true);
+ }
+
+ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
+@@ -1359,13 +1347,14 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
+ bool enable)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
+- struct mt7996_vif *mvif = msta->vif;
++ struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
+
+- return mt7996_mcu_sta_ba(dev, &mvif->mt76, params, enable, false);
++ return mt7996_mcu_sta_ba(dev, &mconf->mt76, params, enable, false);
+ }
+
+ static void
+-mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
++mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta)
+ {
+ struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
+@@ -1386,9 +1375,9 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ he->he_phy_cap[i] = elem->phy_cap_info[i];
+ }
+
+- if (vif->type == NL80211_IFTYPE_AP &&
++ if (conf->vif->type == NL80211_IFTYPE_AP &&
+ (elem->phy_cap_info[1] & IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
+- u8p_replace_bits(&he->he_phy_cap[1], vif->bss_conf.he_ldpc,
++ u8p_replace_bits(&he->he_phy_cap[1], conf->he_ldpc,
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD);
+
+ mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
+@@ -1396,16 +1385,16 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ case IEEE80211_STA_RX_BW_160:
+ if (elem->phy_cap_info[0] &
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+- mt7996_mcu_set_sta_he_mcs(sta,
++ mt7996_mcu_set_sta_he_mcs(sta, mconf,
+ &he->max_nss_mcs[CMD_HE_MCS_BW8080],
+ le16_to_cpu(mcs_map.rx_mcs_80p80));
+
+- mt7996_mcu_set_sta_he_mcs(sta,
++ mt7996_mcu_set_sta_he_mcs(sta, mconf,
+ &he->max_nss_mcs[CMD_HE_MCS_BW160],
+ le16_to_cpu(mcs_map.rx_mcs_160));
+ fallthrough;
+ default:
+- mt7996_mcu_set_sta_he_mcs(sta,
++ mt7996_mcu_set_sta_he_mcs(sta, mconf,
+ &he->max_nss_mcs[CMD_HE_MCS_BW80],
+ le16_to_cpu(mcs_map.rx_mcs_80));
+ break;
+@@ -1496,7 +1485,7 @@ mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+ struct tlv *tlv;
+ #ifdef CONFIG_MTK_VENDOR
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_phy *phy = (struct mt7996_phy *)msta->vif->phy;
++ struct mt7996_phy *phy = (struct mt7996_phy *)msta->vif->deflink.phy;
+ #endif
+
+ /* For 6G band, this tlv is necessary to let hw work normally */
+@@ -1553,25 +1542,26 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+
+ static void
+ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_sta *sta)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_phy *phy = mvif->phy;
++ struct mt7996_phy *phy = mconf->phy;
+ struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
+ struct sta_rec_muru *muru;
+ struct tlv *tlv;
+
+- if (vif->type != NL80211_IFTYPE_STATION &&
+- vif->type != NL80211_IFTYPE_AP)
++ if (conf->vif->type != NL80211_IFTYPE_STATION &&
++ conf->vif->type != NL80211_IFTYPE_AP)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
+
+ muru = (struct sta_rec_muru *)tlv;
+- muru->cfg.mimo_dl_en = (vif->bss_conf.eht_mu_beamformer ||
+- vif->bss_conf.he_mu_beamformer ||
+- vif->bss_conf.vht_mu_beamformer ||
+- vif->bss_conf.vht_mu_beamformee) &&
++ muru->cfg.mimo_dl_en = (conf->eht_mu_beamformer ||
++ conf->he_mu_beamformer ||
++ conf->vht_mu_beamformer ||
++ conf->vht_mu_beamformee) &&
+ !!(phy->muru_onoff & MUMIMO_DL);
+ muru->cfg.mimo_ul_en = !!(phy->muru_onoff & MUMIMO_UL);
+ muru->cfg.ofdma_dl_en = !!(phy->muru_onoff & OFDMA_DL);
+@@ -1612,13 +1602,14 @@ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ }
+
+ static inline bool
+-mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
++mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta, bool bfee)
+ {
+ int sts = hweight16(phy->mt76->chainmask);
+
+- if (vif->type != NL80211_IFTYPE_STATION &&
+- vif->type != NL80211_IFTYPE_AP)
++ if (conf->vif->type != NL80211_IFTYPE_STATION &&
++ conf->vif->type != NL80211_IFTYPE_AP)
+ return false;
+
+ if (!bfee && sts < 2)
+@@ -1629,10 +1620,10 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
+
+ if (bfee)
+- return vif->bss_conf.eht_su_beamformee &&
++ return conf->eht_su_beamformee &&
+ EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
+ else
+- return vif->bss_conf.eht_su_beamformer &&
++ return conf->eht_su_beamformer &&
+ EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
+ }
+
+@@ -1640,10 +1631,10 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
+
+ if (bfee)
+- return vif->bss_conf.he_su_beamformee &&
++ return conf->he_su_beamformee &&
+ HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
+ else
+- return vif->bss_conf.he_su_beamformer &&
++ return conf->he_su_beamformer &&
+ HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
+ }
+
+@@ -1651,10 +1642,10 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ u32 cap = sta->deflink.vht_cap.cap;
+
+ if (bfee)
+- return vif->bss_conf.vht_su_beamformee &&
++ return conf->vht_su_beamformee &&
+ (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
+ else
+- return vif->bss_conf.vht_su_beamformer &&
++ return conf->vht_su_beamformer &&
+ (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
+ }
+
+@@ -1850,10 +1841,10 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+
+ static void
+ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
++ struct ieee80211_bss_conf *conf, struct mt7996_bss_conf *mconf,
++ struct ieee80211_sta *sta)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_phy *phy = mvif->phy;
++ struct mt7996_phy *phy = mconf->phy;
+ int tx_ant = hweight16(phy->mt76->chainmask) - 1;
+ struct sta_rec_bf *bf;
+ struct tlv *tlv;
+@@ -1868,7 +1859,7 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
+ return;
+
+- ebf = mt7996_is_ebf_supported(phy, vif, sta, false);
++ ebf = mt7996_is_ebf_supported(phy, conf, mconf, sta, false);
+ if (!ebf && !dev->ibf)
+ return;
+
+@@ -1880,9 +1871,9 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ * ht: iBF only, since mac80211 lacks of eBF support
+ */
+ if (sta->deflink.eht_cap.has_eht && ebf)
+- mt7996_mcu_sta_bfer_eht(sta, vif, phy, bf);
++ mt7996_mcu_sta_bfer_eht(sta, conf->vif, phy, bf);
+ else if (sta->deflink.he_cap.has_he && ebf)
+- mt7996_mcu_sta_bfer_he(sta, vif, phy, bf);
++ mt7996_mcu_sta_bfer_he(sta, conf->vif, phy, bf);
+ else if (sta->deflink.vht_cap.vht_supported)
+ mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf);
+ else if (sta->deflink.ht_cap.ht_supported)
+@@ -1921,10 +1912,10 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+
+ static void
+ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_phy *phy = mvif->phy;
++ struct mt7996_phy *phy = mconf->phy;
+ int tx_ant = hweight8(phy->mt76->antenna_mask) - 1;
+ struct sta_rec_bfee *bfee;
+ struct tlv *tlv;
+@@ -1933,7 +1924,7 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
+ return;
+
+- if (!mt7996_is_ebf_supported(phy, vif, sta, true))
++ if (!mt7996_is_ebf_supported(phy, conf, mconf, sta, true))
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
+@@ -2055,17 +2046,17 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+ MCU_WM_UNI_CMD(RA), true);
+ }
+
+-int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta, void *data, u32 field)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct sta_phy_uni *phy = data;
+ struct sta_rec_ra_fixed_uni *ra;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+
+- skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+ &msta->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+@@ -2097,12 +2088,13 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif
+ }
+
+ static int
+-mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
+- struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
++ struct cfg80211_chan_def *chandef = &mconf->phy->mt76->chandef;
++ struct cfg80211_bitrate_mask *mask = &mconf->bitrate_mask;
+ enum nl80211_band band = chandef->chan->band;
+ struct sta_phy_uni phy = {};
+ int ret, nrates = 0;
+@@ -2144,7 +2136,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif
+
+ /* fixed single rate */
+ if (nrates == 1) {
+- ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy,
++ ret = mt7996_mcu_set_fixed_field(dev, mconf, sta, &phy,
+ RATE_PARAM_FIXED_MCS);
+ if (ret)
+ return ret;
+@@ -2166,7 +2158,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif
+ else
+ mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
+
+- ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy,
++ ret = mt7996_mcu_set_fixed_field(dev, mconf, sta, &phy,
+ RATE_PARAM_FIXED_GI);
+ if (ret)
+ return ret;
+@@ -2174,7 +2166,7 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif
+
+ /* fixed HE_LTF */
+ if (mask->control[band].he_ltf != GENMASK(7, 0)) {
+- ret = mt7996_mcu_set_fixed_field(dev, vif, sta, &phy,
++ ret = mt7996_mcu_set_fixed_field(dev, mconf, sta, &phy,
+ RATE_PARAM_FIXED_HE_LTF);
+ if (ret)
+ return ret;
+@@ -2185,13 +2177,14 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev, struct ieee80211_vif *vif
+
+ static void
+ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_sta *sta)
+ {
+ #define INIT_RCPI 180
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt76_phy *mphy = mvif->phy->mt76;
++ struct mt76_phy *mphy = mconf->phy->mt76;
+ struct cfg80211_chan_def *chandef = &mphy->chandef;
+- struct cfg80211_bitrate_mask *mask = &mvif->bitrate_mask;
++ struct cfg80211_bitrate_mask *mask = &mconf->bitrate_mask;
+ enum nl80211_band band = chandef->chan->band;
+ struct sta_rec_ra_uni *ra;
+ struct tlv *tlv;
+@@ -2203,7 +2196,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+
+ ra->valid = true;
+ ra->auto_rate = true;
+- ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
++ ra->phy_mode = mt76_connac_get_phy_mode(mphy, conf->vif, band, sta);
+ ra->channel = chandef->chan->hw_value;
+ ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ?
+ CMD_CBW_320MHZ : sta->deflink.bandwidth;
+@@ -2242,7 +2235,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ cap |= STA_CAP_TX_STBC;
+ if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+ cap |= STA_CAP_RX_STBC;
+- if (vif->bss_conf.ht_ldpc &&
++ if (conf->ht_ldpc &&
+ (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
+ cap |= STA_CAP_LDPC;
+
+@@ -2268,7 +2261,7 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ cap |= STA_CAP_VHT_TX_STBC;
+ if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
+ cap |= STA_CAP_VHT_RX_STBC;
+- if (vif->bss_conf.vht_ldpc &&
++ if (conf->vht_ldpc &&
+ (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
+ cap |= STA_CAP_VHT_LDPC;
+
+@@ -2289,15 +2282,16 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ memset(ra->rx_rcpi, INIT_RCPI, sizeof(ra->rx_rcpi));
+ }
+
+-int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta, bool changed)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct sk_buff *skb;
+ int ret;
+
+- skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+ &msta->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+@@ -2308,26 +2302,27 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ * update sta_rec_he here.
+ */
+ if (changed)
+- mt7996_mcu_sta_he_tlv(skb, vif, sta);
++ mt7996_mcu_sta_he_tlv(skb, conf, mconf, sta);
+
+ /* sta_rec_ra accommodates BW, NSS and only MCS range format
+ * i.e 0-{7,8,9} for VHT.
+ */
+- mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, vif, sta);
++ mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, conf, mconf, sta);
+
+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+ if (ret)
+ return ret;
+
+- return mt7996_mcu_add_rate_ctrl_fixed(dev, vif, sta);
++ return mt7996_mcu_add_rate_ctrl_fixed(dev, conf, mconf, sta);
+ }
+
+ static int
+-mt7996_mcu_sta_init_vow(struct mt7996_phy *phy, struct mt7996_sta *msta)
++mt7996_mcu_sta_init_vow(struct mt7996_bss_conf *mconf, struct mt7996_sta *msta)
+ {
++ struct mt7996_phy *phy = mconf->phy;
+ struct mt7996_vow_sta_ctrl *vow = &msta->vow;
+- u8 omac_idx = msta->vif->mt76.omac_idx;
++ u8 omac_idx = mconf->mt76.omac_idx;
+ int ret;
+
+ /* Assignment of STA BSS group index aligns FW.
+@@ -2344,20 +2339,22 @@ mt7996_mcu_sta_init_vow(struct mt7996_phy *phy, struct mt7996_sta *msta)
+ vow->drr_quantum[IEEE80211_AC_BE] = VOW_DRR_QUANTUM_IDX2;
+ vow->drr_quantum[IEEE80211_AC_BK] = VOW_DRR_QUANTUM_IDX2;
+
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_BSS_GROUP);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, mconf, msta, VOW_DRR_CTRL_STA_BSS_GROUP);
+ if (ret)
+ return ret;
+
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_PAUSE);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, mconf, msta, VOW_DRR_CTRL_STA_PAUSE);
+ if (ret)
+ return ret;
+
+- return mt7996_mcu_set_vow_drr_ctrl(phy, msta, VOW_DRR_CTRL_STA_ALL);
++ return mt7996_mcu_set_vow_drr_ctrl(phy, mconf, msta, VOW_DRR_CTRL_STA_ALL);
+ }
+
+-int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta, bool enable, bool newly)
++int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta,
++ bool enable, bool newly)
+ {
++ struct ieee80211_vif *vif = conf->vif;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta;
+ struct sk_buff *skb;
+@@ -2365,7 +2362,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+
+ msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
+
+- skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+ &msta->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+@@ -2387,7 +2384,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ /* starec hdrt mode */
+ mt7996_mcu_sta_hdrt_tlv(dev, skb);
+ /* starec bfer */
+- mt7996_mcu_sta_bfer_tlv(dev, skb, vif, sta);
++ mt7996_mcu_sta_bfer_tlv(dev, skb, conf, mconf, sta);
+ /* starec ht */
+ mt7996_mcu_sta_ht_tlv(skb, sta);
+ /* starec vht */
+@@ -2397,18 +2394,18 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ /* starec amsdu */
+ mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
+ /* starec he */
+- mt7996_mcu_sta_he_tlv(skb, vif, sta);
++ mt7996_mcu_sta_he_tlv(skb, conf, mconf, sta);
+ /* starec he 6g*/
+ mt7996_mcu_sta_he_6g_tlv(skb, sta);
+ /* starec eht */
+ mt7996_mcu_sta_eht_tlv(skb, sta);
+ /* starec muru */
+- mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta);
++ mt7996_mcu_sta_muru_tlv(dev, skb, conf, mconf, sta);
+ /* starec bfee */
+- mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
++ mt7996_mcu_sta_bfee_tlv(dev, skb, conf, mconf, sta);
+ }
+
+- ret = mt7996_mcu_sta_init_vow(mvif->phy, msta);
++ ret = mt7996_mcu_sta_init_vow(mconf, msta);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+@@ -2463,16 +2460,15 @@ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
+ return 0;
+ }
+
+-int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_bss_conf *mconf,
+ struct ieee80211_key_conf *key, int mcu_cmd,
+ struct mt76_wcid *wcid, enum set_key_cmd cmd)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+ struct sk_buff *skb;
+ int ret;
+
+- skb = __mt76_connac_mcu_alloc_sta_req(dev, mvif, wcid,
+- MT7996_STA_UPDATE_MAX_SIZE);
++ skb = __mt76_connac_mcu_alloc_sta_req(dev, (struct mt76_vif *)mconf,
++ wcid, MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+@@ -2483,17 +2479,18 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
+ return mt76_mcu_skb_send_msg(dev, skb, mcu_cmd, true);
+ }
+
+-static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+- u8 *pn)
++static int mt7996_mcu_get_pn(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, u8 *pn)
+ {
+ #define TSC_TYPE_BIGTK_PN 2
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv;
+ struct sta_rec_pn_info *pn_info;
+ struct sk_buff *skb, *rskb;
+ struct tlv *tlv;
+ int ret;
+
+- skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76, &mvif->sta.wcid);
++ skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, &mvif->sta.wcid);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+@@ -2517,10 +2514,11 @@ static int mt7996_mcu_get_pn(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ return 0;
+ }
+
+-int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_key_conf *key)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_mcu_bcn_prot_tlv *bcn_prot;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+@@ -2529,7 +2527,7 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif
+ sizeof(struct mt7996_mcu_bcn_prot_tlv);
+ int ret;
+
+- skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len);
++ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+@@ -2537,7 +2535,7 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif
+
+ bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv;
+
+- ret = mt7996_mcu_get_pn(dev, vif, pn);
++ ret = mt7996_mcu_get_pn(dev, conf, mconf, pn);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+@@ -2570,10 +2568,10 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif
+ MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+ }
+ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
+- struct ieee80211_vif *vif, bool enable)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, bool enable)
+ {
+ struct mt7996_dev *dev = phy->dev;
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct {
+ struct req_hdr {
+ u8 omac_idx;
+@@ -2589,8 +2587,8 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
+ } __packed tlv;
+ } data = {
+ .hdr = {
+- .omac_idx = mvif->mt76.omac_idx,
+- .band_idx = mvif->mt76.band_idx,
++ .omac_idx = mconf->mt76.omac_idx,
++ .band_idx = mconf->mt76.band_idx,
+ },
+ .tlv = {
+ .tag = cpu_to_le16(DEV_INFO_ACTIVE),
+@@ -2599,16 +2597,16 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
+ },
+ };
+
+- if (mvif->mt76.omac_idx >= REPEATER_BSSID_START)
+- return mt7996_mcu_muar_config(phy, vif, false, enable);
++ if (mconf->mt76.omac_idx >= REPEATER_BSSID_START)
++ return mt7996_mcu_muar_config(phy, conf, mconf, false, enable);
+
+- memcpy(data.tlv.omac_addr, vif->addr, ETH_ALEN);
++ memcpy(data.tlv.omac_addr, conf->addr, ETH_ALEN);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(DEV_INFO_UPDATE),
+ &data, sizeof(data), true);
+ }
+
+ static void
+-mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
++mt7996_mcu_beacon_cntdwn(struct ieee80211_bss_conf *conf, struct sk_buff *rskb,
+ struct sk_buff *skb,
+ struct ieee80211_mutable_offsets *offs)
+ {
+@@ -2619,7 +2617,7 @@ mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
+ if (!offs->cntdwn_counter_offs[0])
+ return;
+
+- tag = vif->bss_conf.csa_active ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC;
++ tag = conf->csa_active ? UNI_BSS_INFO_BCN_CSA : UNI_BSS_INFO_BCN_BCC;
+
+ tlv = mt7996_mcu_add_uni_tlv(rskb, tag, sizeof(*info));
+
+@@ -2629,14 +2627,15 @@ mt7996_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
+
+ static void
+ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
+- struct ieee80211_vif *vif, struct bss_bcn_content_tlv *bcn,
++ struct ieee80211_bss_conf *conf,
++ struct bss_bcn_content_tlv *bcn,
+ struct ieee80211_mutable_offsets *offs)
+ {
+ struct bss_bcn_mbss_tlv *mbss;
+ const struct element *elem;
+ struct tlv *tlv;
+
+- if (!vif->bss_conf.bssid_indicator)
++ if (!conf->bssid_indicator)
+ return;
+
+ tlv = mt7996_mcu_add_uni_tlv(rskb, UNI_BSS_INFO_BCN_MBSSID, sizeof(*mbss));
+@@ -2681,7 +2680,7 @@ mt7996_mcu_beacon_mbss(struct sk_buff *rskb, struct sk_buff *skb,
+ }
+
+ static void
+-mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ struct sk_buff *rskb, struct sk_buff *skb,
+ struct bss_bcn_content_tlv *bcn,
+ struct ieee80211_mutable_offsets *offs)
+@@ -2695,9 +2694,9 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ if (offs->cntdwn_counter_offs[0]) {
+ u16 offset = offs->cntdwn_counter_offs[0];
+
+- if (vif->bss_conf.csa_active)
++ if (conf->csa_active)
+ bcn->csa_ie_pos = cpu_to_le16(offset - 4);
+- if (vif->bss_conf.color_change_active)
++ if (conf->color_change_active)
+ bcn->bcc_ie_pos = cpu_to_le16(offset - 3);
+ }
+
+@@ -2709,11 +2708,11 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ }
+
+ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
+- struct ieee80211_vif *vif, int en)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, int en)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct ieee80211_mutable_offsets offs;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb, *rskb;
+@@ -2721,15 +2720,15 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
+ struct bss_bcn_content_tlv *bcn;
+ int len;
+
+- if (vif->bss_conf.nontransmitted)
++ if (conf->nontransmitted)
+ return 0;
+
+- rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
++ rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
+ MT7996_MAX_BSS_OFFLOAD_SIZE);
+ if (IS_ERR(rskb))
+ return PTR_ERR(rskb);
+
+- skb = ieee80211_beacon_get_template(hw, vif, &offs, 0);
++ skb = ieee80211_beacon_get_template(hw, conf->vif, &offs, 0);
+ if (!skb) {
+ dev_kfree_skb(rskb);
+ return -EINVAL;
+@@ -2752,9 +2751,9 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
+ if (!en)
+ goto out;
+
+- mt7996_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
+- mt7996_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
+- mt7996_mcu_beacon_cntdwn(vif, rskb, skb, &offs);
++ mt7996_mcu_beacon_cont(dev, conf, rskb, skb, bcn, &offs);
++ mt7996_mcu_beacon_mbss(rskb, skb, conf, bcn, &offs);
++ mt7996_mcu_beacon_cntdwn(conf, rskb, skb, &offs);
+ out:
+ dev_kfree_skb(skb);
+ return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
+@@ -2762,14 +2761,15 @@ out:
+ }
+
+ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+- struct ieee80211_vif *vif, u32 changed)
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, u32 changed)
+ {
+ #define OFFLOAD_TX_MODE_SU BIT(0)
+ #define OFFLOAD_TX_MODE_MU BIT(1)
+ struct ieee80211_hw *hw = mt76_hw(dev);
++ struct ieee80211_vif *vif = conf->vif;
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
++ struct cfg80211_chan_def *chandef = &mconf->phy->mt76->chandef;
+ enum nl80211_band band = chandef->chan->band;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+ struct bss_inband_discovery_tlv *discov;
+@@ -2779,20 +2779,20 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+ u8 *buf, interval;
+ int len;
+
+- if (vif->bss_conf.nontransmitted)
++ if (conf->nontransmitted)
+ return 0;
+
+- rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
++ rskb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
+ MT7996_MAX_BSS_OFFLOAD_SIZE);
+ if (IS_ERR(rskb))
+ return PTR_ERR(rskb);
+
+ if (changed & BSS_CHANGED_FILS_DISCOVERY) {
+- interval = vif->bss_conf.fils_discovery.max_interval;
++ interval = conf->fils_discovery.max_interval;
+ skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
+ } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
+- vif->bss_conf.unsol_bcast_probe_resp_interval) {
+- interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
++ conf->unsol_bcast_probe_resp_interval) {
++ interval = conf->unsol_bcast_probe_resp_interval;
+ skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
+ }
+
+@@ -3456,7 +3456,7 @@ int mt7996_mcu_set_hdr_trans(struct mt7996_dev *dev, bool hdr_trans)
+ MCU_WM_UNI_CMD(RX_HDR_TRANS), true);
+ }
+
+-int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif)
++int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf)
+ {
+ #define MCU_EDCA_AC_PARAM 0
+ #define WMM_AIFS_SET BIT(0)
+@@ -3465,12 +3465,11 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif)
+ #define WMM_TXOP_SET BIT(3)
+ #define WMM_PARAM_SET (WMM_AIFS_SET | WMM_CW_MIN_SET | \
+ WMM_CW_MAX_SET | WMM_TXOP_SET)
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct {
+ u8 bss_idx;
+ u8 __rsv[3];
+ } __packed hdr = {
+- .bss_idx = mvif->mt76.idx,
++ .bss_idx = mconf->mt76.idx,
+ };
+ struct sk_buff *skb;
+ int len = sizeof(hdr) + IEEE80211_NUM_ACS * sizeof(struct edca);
+@@ -3483,7 +3482,7 @@ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif)
+ skb_put_data(skb, &hdr, sizeof(hdr));
+
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+- struct ieee80211_tx_queue_params *q = &mvif->queue_params[ac];
++ struct ieee80211_tx_queue_params *q = &mconf->queue_params[ac];
+ struct edca *e;
+ struct tlv *tlv;
+
+@@ -4496,12 +4495,12 @@ mt7996_mcu_set_obss_spr_pd(struct mt7996_phy *phy,
+ }
+
+ static int
+-mt7996_mcu_set_obss_spr_siga(struct mt7996_phy *phy, struct ieee80211_vif *vif,
++mt7996_mcu_set_obss_spr_siga(struct mt7996_phy *phy,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_he_obss_pd *he_obss_pd)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = phy->dev;
+- u8 omac = mvif->mt76.omac_idx;
++ u8 omac = mconf->mt76.omac_idx;
+ struct {
+ u8 band_idx;
+ u8 __rsv[3];
+@@ -4573,7 +4572,8 @@ mt7996_mcu_set_obss_spr_bitmap(struct mt7996_phy *phy,
+ sizeof(req), true);
+ }
+
+-int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
++int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_he_obss_pd *he_obss_pd)
+ {
+ int ret;
+@@ -4607,7 +4607,7 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ return ret;
+
+ /* Set SR prohibit */
+- ret = mt7996_mcu_set_obss_spr_siga(phy, vif, he_obss_pd);
++ ret = mt7996_mcu_set_obss_spr_siga(phy, mconf, he_obss_pd);
+ if (ret)
+ return ret;
+
+@@ -4615,16 +4615,16 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+ return mt7996_mcu_set_obss_spr_bitmap(phy, he_obss_pd);
+ }
+
+-int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_update_bss_color(struct mt7996_dev *dev,
++ struct mt7996_bss_conf *mconf,
+ struct cfg80211_he_bss_color *he_bss_color)
+ {
+ int len = sizeof(struct bss_req_hdr) + sizeof(struct bss_color_tlv);
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct bss_color_tlv *bss_color;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+
+- skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76, len);
++ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+@@ -4643,7 +4643,7 @@ int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vi
+ #define TWT_AGRT_PROTECT BIT(2)
+
+ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
+- struct mt7996_vif *mvif,
++ struct mt7996_bss_conf *mconf,
+ struct mt7996_twt_flow *flow,
+ int cmd)
+ {
+@@ -4674,12 +4674,12 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .tbl_idx = flow->table_id,
+ .cmd = cmd,
+- .own_mac_idx = mvif->mt76.omac_idx,
++ .own_mac_idx = mconf->mt76.omac_idx,
+ .flowid = flow->id,
+ .peer_id = cpu_to_le16(flow->wcid),
+ .duration = flow->duration,
+- .bss = mvif->mt76.idx,
+- .bss_idx = mvif->mt76.idx,
++ .bss = mconf->mt76.idx,
++ .bss_idx = mconf->mt76.idx,
+ .start_tsf = cpu_to_le64(flow->tsf),
+ .mantissa = flow->mantissa,
+ .exponent = flow->exp,
+@@ -4810,15 +4810,15 @@ int mt7996_mcu_rdd_background_disable_timer(struct mt7996_dev *dev, bool disable
+
+ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
+ struct ieee80211_vif *vif,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta;
+ struct sk_buff *skb;
+
+- msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
++ msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mconf->vif->sta;
+
+- skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+ &msta->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+@@ -5462,8 +5462,9 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
+ &req, sizeof(req), false);
+ }
+
+-int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy, struct mt7996_sta *msta,
+- enum vow_drr_ctrl_id id)
++int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy,
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_sta *msta, enum vow_drr_ctrl_id id)
+ {
+ struct mt7996_vow_sta_ctrl *vow = msta ? &msta->vow : NULL;
+ u32 val = 0;
+@@ -5489,9 +5490,9 @@ int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy, struct mt7996_sta *msta,
+ .len = cpu_to_le16(sizeof(req) - 4),
+ .wlan_idx = cpu_to_le16(msta ? msta->wcid.idx : 0),
+ .band_idx = phy->mt76->band_idx,
+- .wmm_idx = msta ? msta->vif->mt76.wmm_idx : 0,
++ .wmm_idx = msta ? mconf->mt76.wmm_idx : 0,
+ .ctrl_id = cpu_to_le32(id),
+- .omac_idx = msta ? msta->vif->mt76.omac_idx : 0
++ .omac_idx = msta ? mconf->mt76.omac_idx : 0
+ };
+
+ switch (id) {
+@@ -5679,7 +5680,7 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+ {
+ u8 mode, val;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_phy *phy = mvif->phy;
++ struct mt7996_phy *phy = mvif->deflink.phy;
+
+ mode = FIELD_GET(RATE_CFG_MODE, *((u32 *)data));
+ val = FIELD_GET(RATE_CFG_VAL, *((u32 *)data));
+@@ -5710,11 +5711,11 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+ void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct ieee80211_hw *hw = mvif->phy->mt76->hw;
++ struct ieee80211_hw *hw = mvif->deflink.phy->mt76->hw;
+ u8 val = *((u8 *)data);
+
+ vif->bss_conf.enable_beacon = val;
+
+- mt7996_mcu_add_beacon(hw, vif, val);
++ mt7996_mcu_add_beacon(hw, &vif->bss_conf, &mvif->deflink, val);
+ }
+ #endif
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 2b266d18b..6b03ee17f 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -324,18 +324,25 @@ struct mt7996_sta {
+ struct mt7996_vow_sta_ctrl vow;
+ };
+
+-struct mt7996_vif {
++struct mt7996_bss_conf {
+ struct mt76_vif mt76; /* must be first */
+
+- struct mt7996_sta sta;
++ struct mt7996_vif *vif;
+ struct mt7996_phy *phy;
+-
+ struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
+ struct cfg80211_bitrate_mask bitrate_mask;
+
+ struct mt7996_chanctx *chanctx;
+ };
+
++struct mt7996_vif {
++ struct mt7996_bss_conf deflink;
++ struct mt7996_bss_conf __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
++
++ struct mt7996_sta sta;
++ struct mt7996_dev *dev;
++};
++
+ /* crash-dump */
+ struct mt7996_crash_data {
+ guid_t guid;
+@@ -769,6 +776,13 @@ mt7996_chanctx_get(struct ieee80211_chanctx_conf *ctx)
+ return (struct mt7996_chanctx *)&ctx->drv_priv;
+ }
+
++static inline struct mt7996_bss_conf *
++mconf_dereference_protected(struct mt7996_vif *mvif, u8 link_id)
++{
++ return rcu_dereference_protected(mvif->link[link_id],
++ lockdep_is_held(&mvif->dev->mt76.mutex));
++}
++
+ extern const struct ieee80211_ops mt7996_ops;
+ extern struct pci_driver mt7996_pci_driver;
+ extern struct pci_driver mt7996_hif_driver;
+@@ -779,7 +793,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
+ void mt7996_wfsys_reset(struct mt7996_dev *dev);
+ void mt7996_rro_hw_init(struct mt7996_dev *dev);
+ irqreturn_t mt7996_irq_handler(int irq, void *dev_instance);
+-u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_vif *mvif);
++u64 __mt7996_get_tsf(struct ieee80211_hw *hw, struct mt7996_bss_conf *mconf);
+ int mt7996_register_device(struct mt7996_dev *dev);
+ void mt7996_unregister_device(struct mt7996_dev *dev);
+ const char *mt7996_eeprom_name(struct mt7996_dev *dev);
+@@ -805,37 +819,47 @@ int mt7996_run(struct ieee80211_hw *hw);
+ int mt7996_mcu_init(struct mt7996_dev *dev);
+ int mt7996_mcu_init_firmware(struct mt7996_dev *dev);
+ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
+- struct mt7996_vif *mvif,
++ struct mt7996_bss_conf *mconf,
+ struct mt7996_twt_flow *flow,
+ int cmd);
+ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
+- struct ieee80211_vif *vif, bool enable);
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, bool enable);
+ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
+- struct ieee80211_vif *vif, int enable);
+-int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta, bool enable, bool newly);
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, int enable);
++int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta,
++ bool enable, bool newly);
+ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool add);
+ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool add);
+-int mt7996_mcu_update_bss_color(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_update_bss_color(struct mt7996_dev *dev,
++ struct mt7996_bss_conf *mconf,
+ struct cfg80211_he_bss_color *he_bss_color);
+-int mt7996_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+- int enable);
++int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, int en);
+ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+- struct ieee80211_vif *vif, u32 changed);
+-int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy, struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, u32 changed);
++int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_he_obss_pd *he_obss_pd);
+-int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta, bool changed);
+ int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
+ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
+-int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct ieee80211_vif *vif);
++int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf);
+ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+ void *data, u16 version);
+-int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta, void *data, u32 field);
+ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
+ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf);
+@@ -850,7 +874,7 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
+ const struct mt7996_dfs_pattern *pattern);
+ int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+-int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif);
++int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct mt7996_bss_conf *mconf);
+ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
+ int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
+ int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
+@@ -890,8 +914,9 @@ void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
+ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable);
+ void mt7996_mcu_scs_sta_poll(struct work_struct *work);
+ int mt7996_mcu_set_band_confg(struct mt7996_phy *phy, u16 option, bool enable);
+-int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy, struct mt7996_sta *msta,
+- enum vow_drr_ctrl_id id);
++int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy,
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_sta *msta, enum vow_drr_ctrl_id id);
+ int mt7996_mcu_set_vow_feature_ctrl(struct mt7996_phy *phy);
+ void mt7996_mcu_wmm_pbc_work(struct work_struct *work);
+
+@@ -1000,13 +1025,16 @@ void mt7996_update_channel(struct mt76_phy *mphy);
+ int mt7996_init_debugfs(struct mt7996_phy *phy);
+ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int len);
+ bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len);
+-int mt7996_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_bss_conf *mconf,
+ struct ieee80211_key_conf *key, int mcu_cmd,
+ struct mt76_wcid *wcid, enum set_key_cmd cmd);
+-int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_key_conf *key);
+ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
+ struct ieee80211_vif *vif,
++ struct mt7996_bss_conf *mconf,
+ struct ieee80211_sta *sta);
+ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode);
+ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap);
+diff --git a/mt7996/testmode.c b/mt7996/testmode.c
+index 784a8bea4..bf55b4309 100644
+--- a/mt7996/testmode.c
++++ b/mt7996/testmode.c
+@@ -223,6 +223,7 @@ static void
+ mt7996_tm_init(struct mt7996_phy *phy, bool en)
+ {
+ struct mt7996_dev *dev = phy->dev;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)phy->monitor_vif->drv_priv;
+ u8 rf_test_mode = en ? RF_OPER_RF_TEST : RF_OPER_NORMAL;
+
+ if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
+@@ -234,8 +235,8 @@ mt7996_tm_init(struct mt7996_phy *phy, bool en)
+
+ mt7996_tm_rf_switch_mode(dev, rf_test_mode);
+
+- mt7996_mcu_add_bss_info(phy, phy->monitor_vif, en);
+- mt7996_mcu_add_sta(dev, phy->monitor_vif, NULL, en, false);
++ mt7996_mcu_add_bss_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, en);
++ mt7996_mcu_add_sta(dev, &phy->monitor_vif->bss_conf, &mvif->deflink, NULL, en, false);
+
+ mt7996_tm_set(dev, SET_ID(BAND_IDX), phy->mt76->band_idx);
+
+@@ -1179,13 +1180,13 @@ mt7996_tm_txbf_init(struct mt7996_phy *phy, u16 *val)
+ mt7996_tm_set_mac_addr(dev, td->addr[2], SET_ID(BSSID));
+
+ /* bss idx & omac idx should be set to band idx for ibf cal */
+- mvif->mt76.idx = band_idx;
+- dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
+- mvif->mt76.omac_idx = band_idx;
+- phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
++ mvif->deflink.mt76.idx = band_idx;
++ dev->mt76.vif_mask |= BIT_ULL(mvif->deflink.mt76.idx);
++ mvif->deflink.mt76.omac_idx = band_idx;
++ phy->omac_mask |= BIT_ULL(mvif->deflink.mt76.omac_idx);
+
+- mt7996_mcu_add_dev_info(phy, phy->monitor_vif, true);
+- mt7996_mcu_add_bss_info(phy, phy->monitor_vif, true);
++ mt7996_mcu_add_dev_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, true);
++ mt7996_mcu_add_bss_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, true);
+
+ if (td->ibf) {
+ if (td->is_txbf_dut) {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0087-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0087-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch
new file mode 100644
index 0000000..fb5a898
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0087-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch
@@ -0,0 +1,2430 @@
+From c847e82ab99803a3f79be845fba1cbbf2de03bbc Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 27 Nov 2023 10:43:34 +0800
+Subject: [PATCH 087/116] wifi: mt76: mt7996: switch to per-link data structure
+ of sta
+
+Introduce struct mt7996_link_sta, data structure for per-link STA.
+Note that mt7996_sta now represents a peer legacy or MLD device.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7615/mcu.c | 4 +-
+ mt76_connac_mcu.c | 18 +-
+ mt76_connac_mcu.h | 7 +-
+ mt7915/mcu.c | 4 +-
+ mt7925/mcu.c | 4 +-
+ mt7996/debugfs.c | 20 ++-
+ mt7996/mac.c | 109 ++++++------
+ mt7996/main.c | 223 +++++++++++++++---------
+ mt7996/mcu.c | 430 ++++++++++++++++++++++++----------------------
+ mt7996/mt7996.h | 44 +++--
+ mt7996/testmode.c | 6 +-
+ 11 files changed, 482 insertions(+), 387 deletions(-)
+
+diff --git a/mt7615/mcu.c b/mt7615/mcu.c
+index a9310660b..8f4f203ef 100644
+--- a/mt7615/mcu.c
++++ b/mt7615/mcu.c
+@@ -862,8 +862,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ else
+ mvif->sta_added = true;
+ }
+- mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, sta, enable,
+- new_entry);
++ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, &sta->deflink,
++ enable, new_entry);
+ if (enable && sta)
+ mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
+ MT76_STA_INFO_STATE_ASSOC);
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index 0c7b69352..d83d31441 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -371,9 +371,10 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv);
+
+ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta,
++ struct ieee80211_link_sta *link_sta,
+ bool enable, bool newly)
+ {
++ struct ieee80211_sta *sta = link_sta ? link_sta->sta : NULL;
+ struct sta_rec_basic *basic;
+ struct tlv *tlv;
+ int conn_type;
+@@ -431,7 +432,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+ break;
+ }
+
+- memcpy(basic->peer_addr, sta->addr, ETH_ALEN);
++ memcpy(basic->peer_addr, link_sta->addr, ETH_ALEN);
+ basic->qos = sta->wme;
+ }
+ EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_basic_tlv);
+@@ -1055,7 +1056,7 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
+ return PTR_ERR(skb);
+
+ if (info->sta || !info->offload_fw)
+- mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->sta,
++ mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, &info->sta->deflink,
+ info->enable, info->newly);
+ if (info->sta && info->enable)
+ mt76_connac_mcu_sta_tlv(phy, skb, info->sta,
+@@ -1306,7 +1307,8 @@ int mt76_connac_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
+ EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba);
+
+ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
+- enum nl80211_band band, struct ieee80211_sta *sta)
++ enum nl80211_band band,
++ struct ieee80211_link_sta *link_sta)
+ {
+ struct mt76_dev *dev = phy->dev;
+ const struct ieee80211_sta_he_cap *he_cap;
+@@ -1317,10 +1319,10 @@ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ if (is_connac_v1(dev))
+ return 0x38;
+
+- if (sta) {
+- ht_cap = &sta->deflink.ht_cap;
+- vht_cap = &sta->deflink.vht_cap;
+- he_cap = &sta->deflink.he_cap;
++ if (link_sta) {
++ ht_cap = &link_sta->ht_cap;
++ vht_cap = &link_sta->vht_cap;
++ he_cap = &link_sta->he_cap;
+ } else {
+ struct ieee80211_supported_band *sband;
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 151183d08..f7da63658 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1903,8 +1903,8 @@ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy);
+ int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif);
+ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta, bool enable,
+- bool newly);
++ struct ieee80211_link_sta *link_sta,
++ bool enable, bool newly);
+ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, void *sta_wtbl,
+@@ -2012,7 +2012,8 @@ mt76_connac_get_he_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif);
+ const struct ieee80211_sta_eht_cap *
+ mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif);
+ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
+- enum nl80211_band band, struct ieee80211_sta *sta);
++ enum nl80211_band band,
++ struct ieee80211_link_sta *link_sta);
+ u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ enum nl80211_band band);
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 2d017396c..1d1b3cead 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -1504,7 +1504,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
+
+ ra->valid = true;
+ ra->auto_rate = true;
+- ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
++ ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, &sta->deflink);
+ ra->channel = chandef->chan->hw_value;
+ ra->bw = sta->deflink.bandwidth;
+ ra->phy.bw = sta->deflink.bandwidth;
+@@ -1669,7 +1669,7 @@ 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(&dev->mt76, skb, vif, sta, enable,
++ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, &sta->deflink, enable,
+ !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
+ if (!enable)
+ goto out;
+diff --git a/mt7925/mcu.c b/mt7925/mcu.c
+index bd37cb8d7..1cb556302 100644
+--- a/mt7925/mcu.c
++++ b/mt7925/mcu.c
+@@ -1626,7 +1626,7 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
+ return PTR_ERR(skb);
+
+ if (info->sta || !info->offload_fw)
+- mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, info->sta,
++ mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, &info->sta->deflink,
+ info->enable, info->newly);
+ if (info->sta && info->enable) {
+ mt7925_mcu_sta_phy_tlv(skb, info->vif, info->sta);
+@@ -2092,7 +2092,7 @@ mt7925_mcu_bss_basic_tlv(struct sk_buff *skb,
+ basic_req->nonht_basic_phy = cpu_to_le16(PHY_TYPE_OFDM_INDEX);
+
+ memcpy(basic_req->bssid, vif->bss_conf.bssid, ETH_ALEN);
+- basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, sta);
++ basic_req->phymode = mt76_connac_get_phy_mode(phy, vif, band, &sta->deflink);
+ basic_req->bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int);
+ basic_req->dtim_period = vif->bss_conf.dtim_period;
+ basic_req->bmc_tx_wlan_idx = cpu_to_le16(wlan_idx);
+diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
+index 06015d686..56e219231 100644
+--- a/mt7996/debugfs.c
++++ b/mt7996/debugfs.c
+@@ -739,14 +739,15 @@ static void
+ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink = &msta->deflink;
+ struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
+ struct seq_file *s = data;
+ u8 ac;
+
+ for (ac = 0; ac < 4; ac++) {
+ u32 qlen, ctrl, val;
+- u32 idx = msta->wcid.idx >> 5;
+- u8 offs = msta->wcid.idx & GENMASK(4, 0);
++ u32 idx = mlink->wcid.idx >> 5;
++ u8 offs = mlink->wcid.idx & GENMASK(4, 0);
+
+ ctrl = BIT(31) | BIT(11) | (ac << 24);
+ val = mt76_rr(dev, MT_PLE_AC_QEMPTY(ac, idx));
+@@ -754,11 +755,11 @@ mt7996_sta_hw_queue_read(void *data, struct ieee80211_sta *sta)
+ if (val & BIT(offs))
+ continue;
+
+- mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | msta->wcid.idx);
++ mt76_wr(dev, MT_FL_Q0_CTRL, ctrl | mlink->wcid.idx);
+ qlen = mt76_get_field(dev, MT_FL_Q3_CTRL,
+ GENMASK(11, 0));
+ seq_printf(s, "\tSTA %pM wcid %d: AC%d%d queued:%d\n",
+- sta->addr, msta->wcid.idx,
++ sta->addr, mlink->wcid.idx,
+ msta->vif->deflink.mt76.wmm_idx, ac, qlen);
+ }
+ }
+@@ -1041,7 +1042,7 @@ mt7996_airtime_read(struct seq_file *s, void *data)
+ struct mt76_dev *mdev = &dev->mt76;
+ struct mt76_sta_stats *stats;
+ struct ieee80211_sta *sta;
+- struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ struct mt76_wcid *wcid;
+ struct mt76_vif *vif;
+ u16 i;
+@@ -1053,9 +1054,9 @@ mt7996_airtime_read(struct seq_file *s, void *data)
+ if (!wcid || !wcid->sta)
+ continue;
+
+- msta = container_of(wcid, struct mt7996_sta, wcid);
+- sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+- vif = &msta->vif->deflink.mt76;
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ sta = container_of((void *)mlink->sta, struct ieee80211_sta, drv_priv);
++ vif = &mlink->sta->vif->deflink.mt76;
+ stats = &wcid->stats;
+
+ seq_printf(s, "%pM WCID: %hu BandIdx: %hhu OmacIdx: 0x%hhx\t"
+@@ -1230,6 +1231,7 @@ static ssize_t mt7996_sta_fixed_rate_set(struct file *file,
+ #define LONG_PREAMBLE 1
+ struct ieee80211_sta *sta = file->private_data;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink = &msta->deflink;
+ struct mt7996_dev *dev = msta->vif->deflink.phy->dev;
+ struct ra_rate phy = {};
+ char buf[100];
+@@ -1265,7 +1267,7 @@ static ssize_t mt7996_sta_fixed_rate_set(struct file *file,
+ goto out;
+ }
+
+- phy.wlan_idx = cpu_to_le16(msta->wcid.idx);
++ phy.wlan_idx = cpu_to_le16(mlink->wcid.idx);
+ phy.gi = cpu_to_le16(gi);
+ phy.ltf = cpu_to_le16(ltf);
+ phy.ldpc = phy.ldpc ? 7 : 0;
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 63b16f92e..3cff43d6b 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -54,7 +54,7 @@ static const struct mt7996_dfs_radar_spec jp_radar_specs = {
+ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
+ u16 idx, bool unicast)
+ {
+- struct mt7996_sta *sta;
++ struct mt7996_link_sta *mlink;
+ struct mt76_wcid *wcid;
+
+ if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+@@ -67,11 +67,11 @@ static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
+ if (!wcid->sta)
+ return NULL;
+
+- sta = container_of(wcid, struct mt7996_sta, wcid);
+- if (!sta->vif)
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ if (!mlink->sta->vif)
+ return NULL;
+
+- return &sta->vif->sta.wcid;
++ return &mlink->wcid;
+ }
+
+ bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
+@@ -92,12 +92,11 @@ u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
+ }
+
+ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
+- struct ieee80211_vif *vif, bool enable)
++ struct mt7996_link_sta *mlink, bool enable)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ u32 addr;
+
+- addr = mt7996_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
++ addr = mt7996_mac_wtbl_lmac_addr(dev, mlink->wcid.idx, 5);
+ if (enable)
+ mt76_set(dev, addr, BIT(5));
+ else
+@@ -349,7 +348,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ __le16 fc = 0;
+ int idx;
+ u8 hw_aggr = false;
+- struct mt7996_sta *msta = NULL;
++ struct mt7996_link_sta *mlink = NULL;
+
+ hw_aggr = status->aggr;
+ memset(status, 0, sizeof(*status));
+@@ -380,10 +379,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
+
+ if (status->wcid) {
+- msta = container_of(status->wcid, struct mt7996_sta, wcid);
++ mlink = container_of(status->wcid, struct mt7996_link_sta, wcid);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+- if (list_empty(&msta->wcid.poll_list))
+- list_add_tail(&msta->wcid.poll_list,
++ if (list_empty(&mlink->wcid.poll_list))
++ list_add_tail(&mlink->wcid.poll_list,
+ &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+ }
+@@ -592,7 +591,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ #endif
+ } else {
+ status->flag |= RX_FLAG_8023;
+- mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb,
++ mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], mlink ? mlink->sta : NULL, skb,
+ *info);
+ }
+
+@@ -942,6 +941,7 @@ static void
+ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
+ {
+ struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+ u16 fc, tid;
+@@ -970,7 +970,8 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
+ return;
+
+ msta = (struct mt7996_sta *)sta->drv_priv;
+- if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
++ mlink = rcu_dereference(msta->link[0]);
++ if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state))
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+ }
+
+@@ -1048,7 +1049,7 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
+ */
+ info = le32_to_cpu(*cur_info);
+ if (info & MT_TXFREE_INFO_PAIR) {
+- struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ u16 idx;
+
+ idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
+@@ -1057,10 +1058,10 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
+ if (!sta)
+ continue;
+
+- msta = container_of(wcid, struct mt7996_sta, wcid);
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
+ spin_lock_bh(&mdev->sta_poll_lock);
+- if (list_empty(&msta->wcid.poll_list))
+- list_add_tail(&msta->wcid.poll_list,
++ if (list_empty(&mlink->wcid.poll_list))
++ list_add_tail(&mlink->wcid.poll_list,
+ &mdev->sta_poll_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
+ continue;
+@@ -1265,7 +1266,7 @@ out:
+
+ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
+ {
+- struct mt7996_sta *msta = NULL;
++ struct mt7996_link_sta *mlink;
+ struct mt76_wcid *wcid;
+ __le32 *txs_data = data;
+ u16 wcidx;
+@@ -1286,16 +1287,15 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
+ if (!wcid)
+ goto out;
+
+- msta = container_of(wcid, struct mt7996_sta, wcid);
+-
+ mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
+
+ if (!wcid->sta)
+ goto out;
+
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+- if (list_empty(&msta->wcid.poll_list))
+- list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
++ if (list_empty(&mlink->wcid.poll_list))
++ list_add_tail(&mlink->wcid.poll_list, &dev->mt76.sta_poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+
+ out:
+@@ -2242,8 +2242,9 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif;
+ struct ieee80211_bss_conf *conf;
++ struct ieee80211_link_sta *link_sta;
+ struct mt7996_bss_conf *mconf;
+- struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ u32 changed;
+ LIST_HEAD(list);
+
+@@ -2251,24 +2252,25 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+ list_splice_init(&dev->sta_rc_list, &list);
+
+ while (!list_empty(&list)) {
+- msta = list_first_entry(&list, struct mt7996_sta, rc_list);
+- list_del_init(&msta->rc_list);
+- changed = msta->changed;
+- msta->changed = 0;
++ mlink = list_first_entry(&list, struct mt7996_link_sta, rc_list);
++ list_del_init(&mlink->rc_list);
++ changed = mlink->changed;
++ mlink->changed = 0;
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+
+- sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+- vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
++ sta = container_of((void *)mlink->sta, struct ieee80211_sta, drv_priv);
++ link_sta = &sta->deflink;
++ vif = container_of((void *)mlink->sta->vif, struct ieee80211_vif, drv_priv);
+ conf = &vif->bss_conf;
+- mconf = &msta->vif->deflink;
++ mconf = &mlink->sta->vif->deflink;
+
+ if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
+ IEEE80211_RC_NSS_CHANGED |
+ IEEE80211_RC_BW_CHANGED))
+- mt7996_mcu_add_rate_ctrl(dev, conf, mconf, sta, true);
++ mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, true);
+
+ if (changed & IEEE80211_RC_SMPS_CHANGED)
+- mt7996_mcu_set_fixed_field(dev, mconf, sta, NULL,
++ mt7996_mcu_set_fixed_field(dev, mconf, link_sta, mlink, NULL,
+ RATE_PARAM_MMPS_UPDATE);
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+@@ -2561,7 +2563,7 @@ static int mt7996_mac_check_twt_req(struct ieee80211_twt_setup *twt)
+ }
+
+ static bool
+-mt7996_mac_twt_param_equal(struct mt7996_sta *msta,
++mt7996_mac_twt_param_equal(struct mt7996_link_sta *mlink,
+ struct ieee80211_twt_params *twt_agrt)
+ {
+ u16 type = le16_to_cpu(twt_agrt->req_type);
+@@ -2572,10 +2574,10 @@ mt7996_mac_twt_param_equal(struct mt7996_sta *msta,
+ for (i = 0; i < MT7996_MAX_STA_TWT_AGRT; i++) {
+ struct mt7996_twt_flow *f;
+
+- if (!(msta->twt.flowid_mask & BIT(i)))
++ if (!(mlink->twt.flowid_mask & BIT(i)))
+ continue;
+
+- f = &msta->twt.flow[i];
++ f = &mlink->twt.flow[i];
+ if (f->duration == twt_agrt->min_twt_dur &&
+ f->mantissa == twt_agrt->mantissa &&
+ f->exp == exp &&
+@@ -2594,6 +2596,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ {
+ enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
+ u16 req_type = le16_to_cpu(twt_agrt->req_type);
+ enum ieee80211_twt_setup_cmd sta_setup_cmd;
+@@ -2605,11 +2608,12 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ goto out;
+
+ mutex_lock(&dev->mt76.mutex);
++ mlink = mlink_dereference_protected(msta, 0);
+
+ if (dev->twt.n_agrt == MT7996_MAX_TWT_AGRT)
+ goto unlock;
+
+- if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
++ if (hweight8(mlink->twt.flowid_mask) == ARRAY_SIZE(mlink->twt.flow))
+ goto unlock;
+
+ if (twt_agrt->min_twt_dur < MT7996_MIN_TWT_DUR) {
+@@ -2618,10 +2622,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ goto unlock;
+ }
+
+- if (mt7996_mac_twt_param_equal(msta, twt_agrt))
++ if (mt7996_mac_twt_param_equal(mlink, twt_agrt))
+ goto unlock;
+
+- flowid = ffs(~msta->twt.flowid_mask) - 1;
++ flowid = ffs(~mlink->twt.flowid_mask) - 1;
+ twt_agrt->req_type &= ~cpu_to_le16(IEEE80211_TWT_REQTYPE_FLOWID);
+ twt_agrt->req_type |= le16_encode_bits(flowid,
+ IEEE80211_TWT_REQTYPE_FLOWID);
+@@ -2630,10 +2634,10 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ exp = FIELD_GET(IEEE80211_TWT_REQTYPE_WAKE_INT_EXP, req_type);
+ sta_setup_cmd = FIELD_GET(IEEE80211_TWT_REQTYPE_SETUP_CMD, req_type);
+
+- flow = &msta->twt.flow[flowid];
++ flow = &mlink->twt.flow[flowid];
+ memset(flow, 0, sizeof(*flow));
+ INIT_LIST_HEAD(&flow->list);
+- flow->wcid = msta->wcid.idx;
++ flow->wcid = mlink->wcid.idx;
+ flow->table_id = table_id;
+ flow->id = flowid;
+ flow->duration = twt_agrt->min_twt_dur;
+@@ -2651,7 +2655,7 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+
+ flow->sched = true;
+ flow->start_tsf = mt7996_mac_twt_sched_list_add(dev, flow);
+- curr_tsf = __mt7996_get_tsf(hw, &msta->vif->deflink);
++ curr_tsf = __mt7996_get_tsf(hw, &mlink->sta->vif->deflink);
+ div_u64_rem(curr_tsf - flow->start_tsf, interval, &rem);
+ flow_tsf = curr_tsf + interval - rem;
+ twt_agrt->twt = cpu_to_le64(flow_tsf);
+@@ -2660,13 +2664,13 @@ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ }
+ flow->tsf = le64_to_cpu(twt_agrt->twt);
+
+- if (mt7996_mcu_twt_agrt_update(dev, &msta->vif->deflink, flow,
++ if (mt7996_mcu_twt_agrt_update(dev, &mlink->sta->vif->deflink, flow,
+ MCU_TWT_AGRT_ADD))
+ goto unlock;
+
+ setup_cmd = TWT_SETUP_CMD_ACCEPT;
+ dev->twt.table_mask |= BIT(table_id);
+- msta->twt.flowid_mask |= BIT(flowid);
++ mlink->twt.flowid_mask |= BIT(flowid);
+ dev->twt.n_agrt++;
+
+ unlock:
+@@ -2679,26 +2683,25 @@ out:
+ }
+
+ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
+- struct mt7996_sta *msta,
+- u8 flowid)
++ struct mt7996_link_sta *mlink, u8 flowid)
+ {
+ struct mt7996_twt_flow *flow;
+- struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
++ struct mt7996_bss_conf *mconf = mconf_dereference_protected(mlink->sta->vif, 0);
+
+ lockdep_assert_held(&dev->mt76.mutex);
+
+- if (flowid >= ARRAY_SIZE(msta->twt.flow))
++ if (flowid >= ARRAY_SIZE(mlink->twt.flow))
+ return;
+
+- if (!(msta->twt.flowid_mask & BIT(flowid)))
++ if (!(mlink->twt.flowid_mask & BIT(flowid)))
+ return;
+
+- flow = &msta->twt.flow[flowid];
++ flow = &mlink->twt.flow[flowid];
+ if (mt7996_mcu_twt_agrt_update(dev, mconf, flow, MCU_TWT_AGRT_DELETE))
+ return;
+
+ list_del_init(&flow->list);
+- msta->twt.flowid_mask &= ~BIT(flowid);
++ mlink->twt.flowid_mask &= ~BIT(flowid);
+ dev->twt.table_mask &= ~BIT(flow->table_id);
+ dev->twt.n_agrt--;
+ }
+@@ -2711,7 +2714,7 @@ mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
+ struct cfg80211_scan_request *req = phy->scan_req;
+ struct ieee80211_vif *vif = phy->scan_vif;
+ struct mt7996_vif *mvif;
+- struct mt76_wcid *wcid;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb;
+
+@@ -2719,7 +2722,6 @@ mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
+ return;
+
+ mvif = (struct mt7996_vif *)vif->drv_priv;
+- wcid = &mvif->sta.wcid;
+
+ skb = ieee80211_probereq_get(hw, vif->addr,
+ ssid->ssid, ssid->ssid_len, req->ie_len);
+@@ -2752,7 +2754,8 @@ mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
+ }
+
+ local_bh_disable();
+- mt76_tx(phy->mt76, NULL, wcid, skb);
++ mlink = rcu_dereference(mvif->sta.link[0]);
++ mt76_tx(phy->mt76, NULL, &mlink->wcid, skb);
+ local_bh_enable();
+
+ rcu_read_unlock();
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 9f61082f5..4069ffb70 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -229,6 +229,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ struct ieee80211_bss_conf *conf = &vif->bss_conf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf = &mvif->deflink;
++ struct mt7996_link_sta *mlink = &mvif->sta.deflink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt76_txq *mtxq;
+@@ -268,14 +269,15 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+
+ idx = MT7996_WTBL_RESERVED - mconf->mt76.idx;
+
+- INIT_LIST_HEAD(&mvif->sta.rc_list);
+- INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
+- mvif->sta.wcid.idx = idx;
+- mvif->sta.wcid.phy_idx = band_idx;
+- mvif->sta.wcid.hw_key_idx = -1;
+- mvif->sta.wcid.tx_info |= MT_WCID_TX_INFO_SET;
+- mvif->sta.vif = mvif;
+- mt76_wcid_init(&mvif->sta.wcid);
++ INIT_LIST_HEAD(&mlink->rc_list);
++ INIT_LIST_HEAD(&mlink->wcid.poll_list);
++ mlink->wcid.idx = idx;
++ mlink->wcid.phy_idx = band_idx;
++ mlink->wcid.hw_key_idx = -1;
++ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
++ mlink->sta = &mvif->sta;
++ mlink->sta->vif = mvif;
++ mt76_wcid_init(&mlink->wcid);
+
+ mt7996_mac_wtbl_update(dev, idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+@@ -297,14 +299,15 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+
+ mt7996_init_bitrate_mask(mconf);
+
+- mt7996_mcu_add_bss_info(phy, conf, mconf, true);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, true);
+ /* defer the first STA_REC of BMC entry to BSS_CHANGED_BSSID for STA
+ * interface, since firmware only records BSSID when the entry is new
+ */
+ if (vif->type != NL80211_IFTYPE_STATION)
+- mt7996_mcu_add_sta(dev, conf, mconf, NULL, true, true);
+- rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, true, true);
++ rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid);
+ rcu_assign_pointer(mvif->link[0], mconf);
++ rcu_assign_pointer(mvif->sta.link[0], mlink);
+
+ out:
+ mutex_unlock(&dev->mt76.mutex);
+@@ -318,10 +321,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_bss_conf *conf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf;
+- struct mt7996_sta *msta = &mvif->sta;
++ struct mt7996_link_sta *mlink = &mvif->sta.deflink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- int idx = msta->wcid.idx;
++ int idx = mlink->wcid.idx;
+
+ cancel_delayed_work_sync(&phy->scan_work);
+
+@@ -329,8 +332,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+
+ conf = link_conf_dereference_protected(vif, 0);
+ mconf = mconf_dereference_protected(mvif, 0);
+- mt7996_mcu_add_sta(dev, conf, mconf, NULL, false, false);
+- mt7996_mcu_add_bss_info(phy, conf, mconf, false);
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, false, false);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, false);
+
+ if (vif == phy->monitor_vif)
+ phy->monitor_vif = NULL;
+@@ -343,12 +346,13 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx);
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+- if (!list_empty(&msta->wcid.poll_list))
+- list_del_init(&msta->wcid.poll_list);
++ if (!list_empty(&mlink->wcid.poll_list))
++ list_del_init(&mlink->wcid.poll_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+
+- mt76_wcid_cleanup(&dev->mt76, &msta->wcid);
++ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
+ rcu_assign_pointer(mvif->link[0], NULL);
++ rcu_assign_pointer(mvif->sta.link[0], NULL);
+
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -447,10 +451,10 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv :
+ &mvif->sta;
+- struct mt76_wcid *wcid = &msta->wcid;
+ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_bss_conf *conf;
+- u8 *wcid_keyidx = &wcid->hw_key_idx;
++ u8 *wcid_keyidx;
+ int idx = key->keyidx;
+ int err = 0;
+
+@@ -464,6 +468,12 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+ return -EOPNOTSUPP;
+
++ mutex_lock(&dev->mt76.mutex);
++ conf = link_conf_dereference_protected(vif, 0);
++ mconf = mconf_dereference_protected(mvif, 0);
++ mlink = mlink_dereference_protected(msta, 0);
++ wcid_keyidx = &mlink->wcid.hw_key_idx;
++
+ /* fall back to sw encryption for unsupported ciphers */
+ switch (key->cipher) {
+ case WLAN_CIPHER_SUITE_TKIP:
+@@ -486,16 +496,13 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ default:
++ mutex_unlock(&dev->mt76.mutex);
+ return -EOPNOTSUPP;
+ }
+
+- mutex_lock(&dev->mt76.mutex);
+-
+- conf = link_conf_dereference_protected(vif, 0);
+- mconf = mconf_dereference_protected(mvif, 0);
+ if (cmd == SET_KEY && !sta && !mconf->mt76.cipher) {
+ mconf->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher);
+- mt7996_mcu_add_bss_info(phy, conf, mconf, true);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, true);
+ }
+
+ if (cmd == SET_KEY) {
+@@ -506,14 +513,14 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ goto out;
+ }
+
+- mt76_wcid_key_setup(&dev->mt76, wcid, key);
++ mt76_wcid_key_setup(&dev->mt76, &mlink->wcid, key);
+
+ if (key->keyidx == 6 || key->keyidx == 7)
+- err = mt7996_mcu_bcn_prot_enable(dev, conf, mconf, key);
++ err = mt7996_mcu_bcn_prot_enable(dev, conf, mconf, mlink, key);
+ else
+ err = mt7996_mcu_add_key(&dev->mt76, mconf, key,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
+- &msta->wcid, cmd);
++ &mlink->wcid, cmd);
+ out:
+ mutex_unlock(&dev->mt76.mutex);
+
+@@ -716,25 +723,27 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+
+ mconf = mconf_dereference_protected(mvif, 0);
++ mlink = mlink_dereference_protected(&mvif->sta, 0);
+ /* station mode uses BSSID to map the wlan entry to a peer,
+ * and then peer references bss_info_rfch to set bandwidth cap.
+ */
+ if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) ||
+ (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||
+ (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) {
+- mt7996_mcu_add_bss_info(phy, info, mconf, true);
+- mt7996_mcu_add_sta(dev, info, mconf, NULL, true,
++ mt7996_mcu_add_bss_info(phy, info, mconf, mlink, true);
++ mt7996_mcu_add_sta(dev, info, mconf, NULL, mlink, true,
+ !!(changed & BSS_CHANGED_BSSID));
+ }
+
+ if (changed & BSS_CHANGED_ERP_CTS_PROT)
+- mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot);
++ mt7996_mac_enable_rtscts(dev, mlink, info->use_cts_prot);
+
+ if (changed & BSS_CHANGED_ERP_SLOT) {
+ int slottime = info->use_short_slot ? 9 : 20;
+@@ -805,6 +814,7 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
++ struct mt7996_link_sta *mlink = &msta->deflink;
+ u8 band_idx = mconf->phy->mt76->band_idx;
+ int idx;
+
+@@ -816,13 +826,16 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ if (idx < 0)
+ return -ENOSPC;
+
+- INIT_LIST_HEAD(&msta->rc_list);
+- INIT_LIST_HEAD(&msta->wcid.poll_list);
++ INIT_LIST_HEAD(&mlink->rc_list);
++ INIT_LIST_HEAD(&mlink->wcid.poll_list);
+ msta->vif = mvif;
+- msta->wcid.sta = 1;
+- msta->wcid.idx = idx;
+- msta->wcid.phy_idx = band_idx;
+- msta->wcid.tx_info |= MT_WCID_TX_INFO_SET;
++ mlink->wcid.sta = 1;
++ mlink->wcid.idx = idx;
++ mlink->wcid.phy_idx = band_idx;
++ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
++ mlink->sta = msta;
++
++ rcu_assign_pointer(msta->link[0], mlink);
+
+ #ifdef CONFIG_MTK_VENDOR
+ mt7996_vendor_amnt_sta_remove(mconf->phy, sta);
+@@ -855,19 +868,25 @@ void mt7996_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_bss_conf *conf;
++ struct ieee80211_link_sta *link_sta;
+
+ mutex_lock(&dev->mt76.mutex);
+
+- mt7996_mac_wtbl_update(dev, msta->wcid.idx,
+- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+-
+ conf = link_conf_dereference_protected(vif, 0);
+ mconf = mconf_dereference_protected(mvif, 0);
+- mt7996_mcu_add_sta(dev, conf, mconf, sta, true, true);
+- mt7996_mcu_add_rate_ctrl(dev, conf, mconf, sta, false);
++ link_sta = link_sta_dereference_protected(sta, 0);
++ mlink = mlink_dereference_protected(msta, 0);
+
+- ewma_avg_signal_init(&msta->avg_ack_signal);
++ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
++ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
++
++ mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
++ mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
++ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
++
++ ewma_avg_signal_init(&mlink->avg_ack_signal);
+
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -879,25 +898,31 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_bss_conf *conf;
++ struct ieee80211_link_sta *link_sta;
+ int i;
+
+ conf = link_conf_dereference_protected(vif, 0);
+ mconf = mconf_dereference_protected(mvif, 0);
+- mt7996_mcu_add_sta(dev, conf, mconf, sta, false, false);
++ link_sta = link_sta_dereference_protected(sta, 0);
++ mlink = mlink_dereference_protected(msta, 0);
++ mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
+
+- mt7996_mac_wtbl_update(dev, msta->wcid.idx,
++ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
+ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+
+- for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
+- mt7996_mac_twt_teardown_flow(dev, msta, i);
++ for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
++ mt7996_mac_twt_teardown_flow(dev, mlink, i);
+
+ spin_lock_bh(&mdev->sta_poll_lock);
+- if (!list_empty(&msta->wcid.poll_list))
+- list_del_init(&msta->wcid.poll_list);
+- if (!list_empty(&msta->rc_list))
+- list_del_init(&msta->rc_list);
++ if (!list_empty(&mlink->wcid.poll_list))
++ list_del_init(&mlink->wcid.poll_list);
++ if (!list_empty(&mlink->rc_list))
++ list_del_init(&mlink->rc_list);
+ spin_unlock_bh(&mdev->sta_poll_lock);
++
++ rcu_assign_pointer(msta->link[0], NULL);
+ }
+
+ static void mt7996_tx(struct ieee80211_hw *hw,
+@@ -909,19 +934,22 @@ static void mt7996_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_vif *vif = info->control.vif;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
++ struct mt7996_link_sta *mlink;
+
+ if (control->sta) {
+- struct mt7996_sta *sta;
++ struct mt7996_sta *msta;
+
+- sta = (struct mt7996_sta *)control->sta->drv_priv;
+- wcid = &sta->wcid;
++ msta = (struct mt7996_sta *)control->sta->drv_priv;
++ mlink = rcu_dereference(msta->link[0]);
++ wcid = &mlink->wcid;
+ }
+
+ if (vif && !control->sta) {
+ struct mt7996_vif *mvif;
+
+ mvif = (struct mt7996_vif *)vif->drv_priv;
+- wcid = &mvif->sta.wcid;
++ mlink = rcu_dereference(mvif->sta.link[0]);
++ wcid = &mlink->wcid;
+ }
+
+ mt76_tx(mphy, control->sta, wcid, skb);
+@@ -948,6 +976,7 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta = params->sta;
+ struct ieee80211_txq *txq = sta->txq[params->tid];
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
+ u16 tid = params->tid;
+ u16 ssn = params->ssn;
+ struct mt76_txq *mtxq;
+@@ -959,14 +988,15 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ mtxq = (struct mt76_txq *)txq->drv_priv;
+
+ mutex_lock(&dev->mt76.mutex);
++ mlink = mlink_dereference_protected(msta, 0);
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+- mt76_rx_aggr_start(&dev->mt76, &msta->wcid, tid, ssn,
++ mt76_rx_aggr_start(&dev->mt76, &mlink->wcid, tid, ssn,
+ params->buf_size);
+ ret = mt7996_mcu_add_rx_ba(dev, params, true);
+ break;
+ case IEEE80211_AMPDU_RX_STOP:
+- mt76_rx_aggr_stop(&dev->mt76, &msta->wcid, tid);
++ mt76_rx_aggr_stop(&dev->mt76, &mlink->wcid, tid);
+ ret = mt7996_mcu_add_rx_ba(dev, params, false);
+ break;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+@@ -977,16 +1007,16 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ mtxq->aggr = false;
+- clear_bit(tid, &msta->wcid.ampdu_state);
++ clear_bit(tid, &mlink->wcid.ampdu_state);
+ ret = mt7996_mcu_add_tx_ba(dev, params, false);
+ break;
+ case IEEE80211_AMPDU_TX_START:
+- set_bit(tid, &msta->wcid.ampdu_state);
++ set_bit(tid, &mlink->wcid.ampdu_state);
+ ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
+ break;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ mtxq->aggr = false;
+- clear_bit(tid, &msta->wcid.ampdu_state);
++ clear_bit(tid, &mlink->wcid.ampdu_state);
+ ret = mt7996_mcu_add_tx_ba(dev, params, false);
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ break;
+@@ -1165,10 +1195,19 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
+ {
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct rate_info *txrate = &msta->wcid.rate;
++ struct mt7996_link_sta *mlink;
++ struct rate_info *txrate;
+
++ /* TODO: support per-link rate report */
++ mutex_lock(&dev->mt76.mutex);
++ mlink = mlink_dereference_protected(msta, 0);
++ if (!mlink)
++ goto out;
++
++ txrate = &mlink->wcid.rate;
+ if (txrate->legacy || txrate->flags) {
+ if (txrate->legacy) {
+ sinfo->txrate.legacy = txrate->legacy;
+@@ -1187,44 +1226,52 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
+ sinfo->txrate.flags = txrate->flags;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
+
+- sinfo->tx_failed = msta->wcid.stats.tx_failed;
++ sinfo->tx_failed = mlink->wcid.stats.tx_failed;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
+
+- sinfo->tx_retries = msta->wcid.stats.tx_retries;
++ sinfo->tx_retries = mlink->wcid.stats.tx_retries;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
+
+- sinfo->ack_signal = (s8)msta->ack_signal;
++ sinfo->ack_signal = (s8)mlink->ack_signal;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
+
+- sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&msta->avg_ack_signal);
++ sinfo->avg_ack_signal = -(s8)ewma_avg_signal_read(&mlink->avg_ack_signal);
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL_AVG);
+
+ if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
+- sinfo->tx_bytes = msta->wcid.stats.tx_bytes;
++ sinfo->tx_bytes = mlink->wcid.stats.tx_bytes;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
+
+- sinfo->rx_bytes = msta->wcid.stats.rx_bytes;
++ sinfo->rx_bytes = mlink->wcid.stats.rx_bytes;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BYTES64);
+
+- sinfo->tx_packets = msta->wcid.stats.tx_packets;
++ sinfo->tx_packets = mlink->wcid.stats.tx_packets;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
+
+- sinfo->rx_packets = msta->wcid.stats.rx_packets;
++ sinfo->rx_packets = mlink->wcid.stats.rx_packets;
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_PACKETS);
+ }
++out:
++ mutex_unlock(&dev->mt76.mutex);
+ }
+
+ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
+ struct mt7996_dev *dev = msta->vif->dev;
+ u32 *changed = data;
+
++ rcu_read_lock();
++ mlink = rcu_dereference(msta->link[0]);
++
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+- msta->changed |= *changed;
+- if (list_empty(&msta->rc_list))
+- list_add_tail(&msta->rc_list, &dev->sta_rc_list);
++ mlink->changed |= *changed;
++ if (list_empty(&mlink->rc_list))
++ list_add_tail(&mlink->rc_list, &dev->sta_rc_list);
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
++
++ rcu_read_unlock();
+ }
+
+ static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
+@@ -1238,7 +1285,7 @@ static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
+
+ if (!msta->vif) {
+ dev_warn(dev->mt76.dev, "Un-initialized STA %pM wcid %d in rc_work\n",
+- sta->addr, msta->wcid.idx);
++ sta->addr, msta->deflink.wcid.idx);
+ return;
+ }
+
+@@ -1284,16 +1331,18 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+
+ mutex_lock(&dev->mt76.mutex);
+ mconf = mconf_dereference_protected(mvif, 0);
++ mlink = mlink_dereference_protected(msta, 0);
+
+ if (enabled)
+- set_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
++ set_bit(MT_WCID_FLAG_4ADDR, &mlink->wcid.flags);
+ else
+- clear_bit(MT_WCID_FLAG_4ADDR, &msta->wcid.flags);
++ clear_bit(MT_WCID_FLAG_4ADDR, &mlink->wcid.flags);
+
+- mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, sta);
++ mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -1306,16 +1355,18 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+
+ mutex_lock(&dev->mt76.mutex);
+ mconf = mconf_dereference_protected(mvif, 0);
++ mlink = mlink_dereference_protected(msta, 0);
+
+ if (enabled)
+- set_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
++ set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
+ else
+- clear_bit(MT_WCID_FLAG_HDR_TRANS, &msta->wcid.flags);
++ clear_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
+
+- mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, sta);
++ mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -1448,11 +1499,12 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
+ {
+ struct mt76_ethtool_worker_info *wi = wi_data;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink = &msta->deflink;
+
+ if (msta->vif->deflink.mt76.idx != wi->idx)
+ return;
+
+- mt76_ethtool_worker(wi, &msta->wcid.stats, true);
++ mt76_ethtool_worker(wi, &mlink->wcid.stats, true);
+ }
+
+ static
+@@ -1555,10 +1607,12 @@ mt7996_twt_teardown_request(struct ieee80211_hw *hw,
+ u8 flowid)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+- mt7996_mac_twt_teardown_flow(dev, msta, flowid);
++ mlink = mlink_dereference_protected(msta, 0);
++ mt7996_mac_twt_teardown_flow(dev, mlink, flowid);
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -1681,6 +1735,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf = &mvif->deflink;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink = &msta->deflink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
+@@ -1703,7 +1758,7 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ if (!mtk_wed_device_active(wed))
+ return -ENODEV;
+
+- if (msta->wcid.idx > MT7996_WTBL_STA)
++ if (mlink->wcid.idx > MT7996_WTBL_STA)
+ return -EIO;
+
+ path->type = DEV_PATH_MTK_WDMA;
+@@ -1711,11 +1766,11 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ path->mtk_wdma.wdma_idx = wed->wdma_idx;
+ path->mtk_wdma.bss = mconf->mt76.idx;
+ path->mtk_wdma.queue = 0;
+- path->mtk_wdma.wcid = msta->wcid.idx;
++ path->mtk_wdma.wcid = mlink->wcid.idx;
+
+ if (ieee80211_hw_check(hw, SUPPORTS_AMSDU_IN_AMPDU) &&
+ mtk_wed_is_amsdu_supported(wed))
+- path->mtk_wdma.amsdu = msta->wcid.amsdu;
++ path->mtk_wdma.amsdu = mlink->wcid.amsdu;
+ else
+ path->mtk_wdma.amsdu = 0;
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 11700f90f..6d2b517e0 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -117,13 +117,13 @@ mt7996_mcu_get_sta_nss(u16 mcs_map)
+ }
+
+ static void
+-mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta,
++mt7996_mcu_set_sta_he_mcs(struct ieee80211_link_sta *link_sta,
+ struct mt7996_bss_conf *mconf,
+ __le16 *he_mcs, u16 mcs_map)
+ {
+ enum nl80211_band band = mconf->phy->mt76->chandef.chan->band;
+ const u16 *mask = mconf->bitrate_mask.control[band].he_mcs;
+- int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
++ int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss;
+
+ for (nss = 0; nss < max_nss; nss++) {
+ int mcs;
+@@ -166,11 +166,11 @@ mt7996_mcu_set_sta_he_mcs(struct ieee80211_sta *sta,
+ }
+
+ static void
+-mt7996_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
+- const u16 *mask)
++mt7996_mcu_set_sta_vht_mcs(struct ieee80211_link_sta *link_sta,
++ __le16 *vht_mcs, const u16 *mask)
+ {
+- u16 mcs, mcs_map = le16_to_cpu(sta->deflink.vht_cap.vht_mcs.rx_mcs_map);
+- int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
++ u16 mcs, mcs_map = le16_to_cpu(link_sta->vht_cap.vht_mcs.rx_mcs_map);
++ int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss;
+
+ for (nss = 0; nss < max_nss; nss++, mcs_map >>= 2) {
+ switch (mcs_map & 0x3) {
+@@ -192,13 +192,13 @@ mt7996_mcu_set_sta_vht_mcs(struct ieee80211_sta *sta, __le16 *vht_mcs,
+ }
+
+ static void
+-mt7996_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
++mt7996_mcu_set_sta_ht_mcs(struct ieee80211_link_sta *link_sta, u8 *ht_mcs,
+ const u8 *mask)
+ {
+- int nss, max_nss = sta->deflink.rx_nss > 3 ? 4 : sta->deflink.rx_nss;
++ int nss, max_nss = link_sta->rx_nss > 3 ? 4 : link_sta->rx_nss;
+
+ for (nss = 0; nss < max_nss; nss++)
+- ht_mcs[nss] = sta->deflink.ht_cap.mcs.rx_mask[nss] & mask[nss];
++ ht_mcs[nss] = link_sta->ht_cap.mcs.rx_mask[nss] & mask[nss];
+ }
+
+ static int
+@@ -531,14 +531,14 @@ static inline void __mt7996_stat_to_netdev(struct mt76_phy *mphy,
+ u32 tx_bytes, u32 rx_bytes,
+ u32 tx_packets, u32 rx_packets)
+ {
+- struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ struct ieee80211_vif *vif;
+ struct wireless_dev *wdev;
+
+ if (wiphy_ext_feature_isset(mphy->hw->wiphy,
+ NL80211_EXT_FEATURE_STAS_COUNT)) {
+- msta = container_of(wcid, struct mt7996_sta, wcid);
+- vif = container_of((void *)msta->vif, struct ieee80211_vif,
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ vif = container_of((void *)mlink->sta->vif, struct ieee80211_vif,
+ drv_priv);
+ wdev = ieee80211_vif_to_wdev(vif);
+
+@@ -1236,10 +1236,10 @@ __mt7996_mcu_alloc_bss_req(struct mt76_dev *dev, struct mt76_vif *mvif, int len)
+
+ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
+ struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf, int enable)
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink, int enable)
+ {
+ struct ieee80211_vif *vif = conf->vif;
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_dev *dev = phy->dev;
+ struct sk_buff *skb;
+
+@@ -1255,7 +1255,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
+
+ /* bss_basic must be first */
+ mt7996_mcu_bss_basic_tlv(skb, conf, mconf, NULL, phy->mt76,
+- mvif->sta.wcid.idx, enable);
++ mlink->wcid.idx, enable);
+ mt7996_mcu_bss_sec_tlv(skb, mconf);
+
+ if (vif->type == NL80211_IFTYPE_MONITOR)
+@@ -1335,9 +1335,10 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
+ struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
++ struct mt7996_link_sta *mlink = mlink_dereference_protected(msta, 0);
+
+ if (enable && !params->amsdu)
+- msta->wcid.amsdu = false;
++ mlink->wcid.amsdu = false;
+
+ return mt7996_mcu_sta_ba(dev, &mconf->mt76, params, enable, true);
+ }
+@@ -1355,15 +1356,15 @@ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
+ static void
+ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta)
++ struct ieee80211_link_sta *link_sta)
+ {
+- struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
++ struct ieee80211_he_cap_elem *elem = &link_sta->he_cap.he_cap_elem;
+ struct ieee80211_he_mcs_nss_supp mcs_map;
+ struct sta_rec_he_v2 *he;
+ struct tlv *tlv;
+ int i = 0;
+
+- if (!sta->deflink.he_cap.has_he)
++ if (!link_sta->he_cap.has_he)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_V2, sizeof(*he));
+@@ -1380,21 +1381,21 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ u8p_replace_bits(&he->he_phy_cap[1], conf->he_ldpc,
+ IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD);
+
+- mcs_map = sta->deflink.he_cap.he_mcs_nss_supp;
+- switch (sta->deflink.bandwidth) {
++ mcs_map = link_sta->he_cap.he_mcs_nss_supp;
++ switch (link_sta->bandwidth) {
+ case IEEE80211_STA_RX_BW_160:
+ if (elem->phy_cap_info[0] &
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
+- mt7996_mcu_set_sta_he_mcs(sta, mconf,
++ mt7996_mcu_set_sta_he_mcs(link_sta, mconf,
+ &he->max_nss_mcs[CMD_HE_MCS_BW8080],
+ le16_to_cpu(mcs_map.rx_mcs_80p80));
+
+- mt7996_mcu_set_sta_he_mcs(sta, mconf,
++ mt7996_mcu_set_sta_he_mcs(link_sta, mconf,
+ &he->max_nss_mcs[CMD_HE_MCS_BW160],
+ le16_to_cpu(mcs_map.rx_mcs_160));
+ fallthrough;
+ default:
+- mt7996_mcu_set_sta_he_mcs(sta, mconf,
++ mt7996_mcu_set_sta_he_mcs(link_sta, mconf,
+ &he->max_nss_mcs[CMD_HE_MCS_BW80],
+ le16_to_cpu(mcs_map.rx_mcs_80));
+ break;
+@@ -1404,24 +1405,25 @@ mt7996_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ }
+
+ static void
+-mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
++mt7996_mcu_sta_he_6g_tlv(struct sk_buff *skb,
++ struct ieee80211_link_sta *link_sta)
+ {
+ struct sta_rec_he_6g_capa *he_6g;
+ struct tlv *tlv;
+
+- if (!sta->deflink.he_6ghz_capa.capa)
++ if (!link_sta->he_6ghz_capa.capa)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE_6G, sizeof(*he_6g));
+
+ he_6g = (struct sta_rec_he_6g_capa *)tlv;
+- he_6g->capa = sta->deflink.he_6ghz_capa.capa;
++ he_6g->capa = link_sta->he_6ghz_capa.capa;
+ }
+
+ static void
+-mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
++mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv;
+ struct ieee80211_vif *vif = container_of((void *)msta->vif,
+ struct ieee80211_vif, drv_priv);
+ struct ieee80211_eht_mcs_nss_supp *mcs_map;
+@@ -1429,11 +1431,11 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+ struct sta_rec_eht *eht;
+ struct tlv *tlv;
+
+- if (!sta->deflink.eht_cap.has_eht)
++ if (!link_sta->eht_cap.has_eht)
+ return;
+
+- mcs_map = &sta->deflink.eht_cap.eht_mcs_nss_supp;
+- elem = &sta->deflink.eht_cap.eht_cap_elem;
++ mcs_map = &link_sta->eht_cap.eht_mcs_nss_supp;
++ elem = &link_sta->eht_cap.eht_cap_elem;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT, sizeof(*eht));
+
+@@ -1444,7 +1446,7 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+ eht->phy_cap_ext = cpu_to_le64(elem->phy_cap_info[8]);
+
+ if (vif->type != NL80211_IFTYPE_STATION &&
+- (sta->deflink.he_cap.he_cap_elem.phy_cap_info[0] &
++ (link_sta->he_cap.he_cap_elem.phy_cap_info[0] &
+ (IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_IN_2G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_40MHZ_80MHZ_IN_5G |
+ IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_160MHZ_IN_5G |
+@@ -1460,44 +1462,44 @@ mt7996_mcu_sta_eht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+ }
+
+ static void
+-mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
++mt7996_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)
+ {
+ struct sta_rec_ht_uni *ht;
+ struct tlv *tlv;
+
+- if (!sta->deflink.ht_cap.ht_supported)
++ if (!link_sta->ht_cap.ht_supported)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HT, sizeof(*ht));
+
+ ht = (struct sta_rec_ht_uni *)tlv;
+- ht->ht_cap = cpu_to_le16(sta->deflink.ht_cap.cap);
+- ht->ampdu_param = u8_encode_bits(sta->deflink.ht_cap.ampdu_factor,
++ ht->ht_cap = cpu_to_le16(link_sta->ht_cap.cap);
++ ht->ampdu_param = u8_encode_bits(link_sta->ht_cap.ampdu_factor,
+ IEEE80211_HT_AMPDU_PARM_FACTOR) |
+- u8_encode_bits(sta->deflink.ht_cap.ampdu_density,
++ u8_encode_bits(link_sta->ht_cap.ampdu_density,
+ IEEE80211_HT_AMPDU_PARM_DENSITY);
+ }
+
+ static void
+-mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
++mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_link_sta *link_sta)
+ {
+ struct sta_rec_vht *vht;
+ struct tlv *tlv;
+ #ifdef CONFIG_MTK_VENDOR
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv;
+ struct mt7996_phy *phy = (struct mt7996_phy *)msta->vif->deflink.phy;
+ #endif
+
+ /* For 6G band, this tlv is necessary to let hw work normally */
+- if (!sta->deflink.he_6ghz_capa.capa && !sta->deflink.vht_cap.vht_supported)
++ if (!link_sta->he_6ghz_capa.capa && !link_sta->vht_cap.vht_supported)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_VHT, sizeof(*vht));
+
+ vht = (struct sta_rec_vht *)tlv;
+- vht->vht_cap = cpu_to_le32(sta->deflink.vht_cap.cap);
+- vht->vht_rx_mcs_map = sta->deflink.vht_cap.vht_mcs.rx_mcs_map;
+- vht->vht_tx_mcs_map = sta->deflink.vht_cap.vht_mcs.tx_mcs_map;
++ vht->vht_cap = cpu_to_le32(link_sta->vht_cap.cap);
++ vht->vht_rx_mcs_map = link_sta->vht_cap.vht_mcs.rx_mcs_map;
++ vht->vht_tx_mcs_map = link_sta->vht_cap.vht_mcs.tx_mcs_map;
+ #ifdef CONFIG_MTK_VENDOR
+ vht->rts_bw_sig = phy->rts_bw_sig;
+ #endif
+@@ -1505,9 +1507,10 @@ mt7996_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+
+ static void
+ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
++ struct ieee80211_vif *vif,
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct sta_rec_amsdu *amsdu;
+ struct tlv *tlv;
+
+@@ -1516,16 +1519,16 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ vif->type != NL80211_IFTYPE_AP)
+ return;
+
+- if (!sta->deflink.agg.max_amsdu_len)
++ if (!link_sta->agg.max_amsdu_len)
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
+ amsdu = (struct sta_rec_amsdu *)tlv;
+ amsdu->max_amsdu_num = 8;
+ amsdu->amsdu_en = true;
+- msta->wcid.amsdu = true;
++ mlink->wcid.amsdu = true;
+
+- switch (sta->deflink.agg.max_amsdu_len) {
++ switch (link_sta->agg.max_amsdu_len) {
+ case IEEE80211_MAX_MPDU_LEN_VHT_11454:
+ amsdu->max_mpdu_size =
+ IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454;
+@@ -1544,10 +1547,10 @@ static void
+ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta)
++ struct ieee80211_link_sta *link_sta)
+ {
+ struct mt7996_phy *phy = mconf->phy;
+- struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
++ struct ieee80211_he_cap_elem *elem = &link_sta->he_cap.he_cap_elem;
+ struct sta_rec_muru *muru;
+ struct tlv *tlv;
+
+@@ -1567,11 +1570,11 @@ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ muru->cfg.ofdma_dl_en = !!(phy->muru_onoff & OFDMA_DL);
+ muru->cfg.ofdma_ul_en = !!(phy->muru_onoff & OFDMA_UL);
+
+- if (sta->deflink.vht_cap.vht_supported)
++ if (link_sta->vht_cap.vht_supported)
+ muru->mimo_dl.vht_mu_bfee =
+- !!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
++ !!(link_sta->vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
+
+- if (!sta->deflink.he_cap.has_he)
++ if (!link_sta->he_cap.has_he)
+ return;
+
+ muru->mimo_dl.partial_bw_dl_mimo =
+@@ -1604,7 +1607,7 @@ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ static inline bool
+ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta, bool bfee)
++ struct ieee80211_link_sta *link_sta, bool bfee)
+ {
+ int sts = hweight16(phy->mt76->chainmask);
+
+@@ -1615,8 +1618,8 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
+ if (!bfee && sts < 2)
+ return false;
+
+- if (sta->deflink.eht_cap.has_eht) {
+- struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
++ if (link_sta->eht_cap.has_eht) {
++ struct ieee80211_sta_eht_cap *pc = &link_sta->eht_cap;
+ struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
+
+ if (bfee)
+@@ -1627,8 +1630,8 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
+ EHT_PHY(CAP0_SU_BEAMFORMER, pe->phy_cap_info[0]);
+ }
+
+- if (sta->deflink.he_cap.has_he) {
+- struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
++ if (link_sta->he_cap.has_he) {
++ struct ieee80211_he_cap_elem *pe = &link_sta->he_cap.he_cap_elem;
+
+ if (bfee)
+ return conf->he_su_beamformee &&
+@@ -1638,8 +1641,8 @@ mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_bss_conf *conf,
+ HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
+ }
+
+- if (sta->deflink.vht_cap.vht_supported) {
+- u32 cap = sta->deflink.vht_cap.cap;
++ if (link_sta->vht_cap.vht_supported) {
++ u32 cap = link_sta->vht_cap.cap;
+
+ if (bfee)
+ return conf->vht_su_beamformee &&
+@@ -1662,10 +1665,10 @@ mt7996_mcu_sta_sounding_rate(struct sta_rec_bf *bf)
+ }
+
+ static void
+-mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
+- struct sta_rec_bf *bf)
++mt7996_mcu_sta_bfer_ht(struct ieee80211_link_sta *link_sta,
++ struct mt7996_phy *phy, struct sta_rec_bf *bf)
+ {
+- struct ieee80211_mcs_info *mcs = &sta->deflink.ht_cap.mcs;
++ struct ieee80211_mcs_info *mcs = &link_sta->ht_cap.mcs;
+ u8 n = 0;
+
+ bf->tx_mode = MT_PHY_TYPE_HT;
+@@ -1687,10 +1690,11 @@ mt7996_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
+ }
+
+ static void
+-mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
+- struct sta_rec_bf *bf, bool explicit)
++mt7996_mcu_sta_bfer_vht(struct ieee80211_link_sta *link_sta,
++ struct mt7996_phy *phy, struct sta_rec_bf *bf,
++ bool explicit)
+ {
+- struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
++ struct ieee80211_sta_vht_cap *pc = &link_sta->vht_cap;
+ struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
+ u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
+ u8 nss_mcs = mt7996_mcu_get_sta_nss(mcs_map);
+@@ -1711,23 +1715,24 @@ mt7996_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7996_phy *phy,
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
+ bf->ibf_ncol = bf->ncol;
+
+- if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
++ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160)
+ bf->nrow = 1;
+ } else {
+ bf->nrow = tx_ant;
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
+ bf->ibf_ncol = nss_mcs;
+
+- if (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_160)
++ if (link_sta->bandwidth == IEEE80211_STA_RX_BW_160)
+ bf->ibf_nrow = 1;
+ }
+ }
+
+ static void
+-mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+- struct mt7996_phy *phy, struct sta_rec_bf *bf)
++mt7996_mcu_sta_bfer_he(struct ieee80211_link_sta *link_sta,
++ struct ieee80211_vif *vif, struct mt7996_phy *phy,
++ struct sta_rec_bf *bf)
+ {
+- struct ieee80211_sta_he_cap *pc = &sta->deflink.he_cap;
++ struct ieee80211_sta_he_cap *pc = &link_sta->he_cap;
+ struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
+ const struct ieee80211_sta_he_cap *vc =
+ mt76_connac_get_he_phy_cap(phy->mt76, vif);
+@@ -1752,7 +1757,7 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
+ bf->ibf_ncol = bf->ncol;
+
+- if (sta->deflink.bandwidth != IEEE80211_STA_RX_BW_160)
++ if (link_sta->bandwidth != IEEE80211_STA_RX_BW_160)
+ return;
+
+ /* go over for 160MHz and 80p80 */
+@@ -1784,10 +1789,11 @@ mt7996_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+ }
+
+ static void
+-mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+- struct mt7996_phy *phy, struct sta_rec_bf *bf)
++mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta,
++ struct ieee80211_vif *vif, struct mt7996_phy *phy,
++ struct sta_rec_bf *bf)
+ {
+- struct ieee80211_sta_eht_cap *pc = &sta->deflink.eht_cap;
++ struct ieee80211_sta_eht_cap *pc = &link_sta->eht_cap;
+ struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
+ struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;
+ const struct ieee80211_sta_eht_cap *vc =
+@@ -1810,10 +1816,10 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+ bf->ncol = min_t(u8, nss_mcs, bf->nrow);
+ bf->ibf_ncol = bf->ncol;
+
+- if (sta->deflink.bandwidth < IEEE80211_STA_RX_BW_160)
++ if (link_sta->bandwidth < IEEE80211_STA_RX_BW_160)
+ return;
+
+- switch (sta->deflink.bandwidth) {
++ switch (link_sta->bandwidth) {
+ case IEEE80211_STA_RX_BW_160:
+ snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_160MHZ_MASK, ve->phy_cap_info[2]);
+ sts = EHT_PHY(CAP1_BEAMFORMEE_SS_160MHZ_MASK, pe->phy_cap_info[1]);
+@@ -1842,7 +1848,7 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+ static void
+ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct ieee80211_bss_conf *conf, struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta)
++ struct ieee80211_link_sta *link_sta)
+ {
+ struct mt7996_phy *phy = mconf->phy;
+ int tx_ant = hweight16(phy->mt76->chainmask) - 1;
+@@ -1856,10 +1862,10 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ };
+ bool ebf;
+
+- if (!(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
++ if (!(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
+ return;
+
+- ebf = mt7996_is_ebf_supported(phy, conf, mconf, sta, false);
++ ebf = mt7996_is_ebf_supported(phy, conf, mconf, link_sta, false);
+ if (!ebf && !dev->ibf)
+ return;
+
+@@ -1870,23 +1876,23 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ * vht: support eBF and iBF
+ * ht: iBF only, since mac80211 lacks of eBF support
+ */
+- if (sta->deflink.eht_cap.has_eht && ebf)
+- mt7996_mcu_sta_bfer_eht(sta, conf->vif, phy, bf);
+- else if (sta->deflink.he_cap.has_he && ebf)
+- mt7996_mcu_sta_bfer_he(sta, conf->vif, phy, bf);
+- else if (sta->deflink.vht_cap.vht_supported)
+- mt7996_mcu_sta_bfer_vht(sta, phy, bf, ebf);
+- else if (sta->deflink.ht_cap.ht_supported)
+- mt7996_mcu_sta_bfer_ht(sta, phy, bf);
++ if (link_sta->eht_cap.has_eht && ebf)
++ mt7996_mcu_sta_bfer_eht(link_sta, conf->vif, phy, bf);
++ else if (link_sta->he_cap.has_he && ebf)
++ mt7996_mcu_sta_bfer_he(link_sta, conf->vif, phy, bf);
++ else if (link_sta->vht_cap.vht_supported)
++ mt7996_mcu_sta_bfer_vht(link_sta, phy, bf, ebf);
++ else if (link_sta->ht_cap.ht_supported)
++ mt7996_mcu_sta_bfer_ht(link_sta, phy, bf);
+ else
+ return;
+
+ bf->bf_cap = ebf ? ebf : dev->ibf << 1;
+- bf->bw = sta->deflink.bandwidth;
+- bf->ibf_dbw = sta->deflink.bandwidth;
++ bf->bw = link_sta->bandwidth;
++ bf->ibf_dbw = link_sta->bandwidth;
+ bf->ibf_nrow = tx_ant;
+
+- if (!ebf && sta->deflink.bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
++ if (!ebf && link_sta->bandwidth <= IEEE80211_STA_RX_BW_40 && !bf->ncol)
+ bf->ibf_timeout = 0x48;
+ else
+ bf->ibf_timeout = 0x18;
+@@ -1896,7 +1902,7 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ else
+ bf->mem_20m = matrix[bf->nrow][bf->ncol];
+
+- switch (sta->deflink.bandwidth) {
++ switch (link_sta->bandwidth) {
+ case IEEE80211_STA_RX_BW_160:
+ case IEEE80211_STA_RX_BW_80:
+ bf->mem_total = bf->mem_20m * 2;
+@@ -1913,7 +1919,8 @@ mt7996_mcu_sta_bfer_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ static void
+ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta)
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_link_sta *link_sta)
+ {
+ struct mt7996_phy *phy = mconf->phy;
+ int tx_ant = hweight8(phy->mt76->antenna_mask) - 1;
+@@ -1921,22 +1928,22 @@ mt7996_mcu_sta_bfee_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct tlv *tlv;
+ u8 nrow = 0;
+
+- if (!(sta->deflink.vht_cap.vht_supported || sta->deflink.he_cap.has_he))
++ if (!(link_sta->vht_cap.vht_supported || link_sta->he_cap.has_he))
+ return;
+
+- if (!mt7996_is_ebf_supported(phy, conf, mconf, sta, true))
++ if (!mt7996_is_ebf_supported(phy, conf, mconf, link_sta, true))
+ return;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
+ bfee = (struct sta_rec_bfee *)tlv;
+
+- if (sta->deflink.he_cap.has_he) {
+- struct ieee80211_he_cap_elem *pe = &sta->deflink.he_cap.he_cap_elem;
++ if (link_sta->he_cap.has_he) {
++ struct ieee80211_he_cap_elem *pe = &link_sta->he_cap.he_cap_elem;
+
+ nrow = HE_PHY(CAP5_BEAMFORMEE_NUM_SND_DIM_UNDER_80MHZ_MASK,
+ pe->phy_cap_info[5]);
+- } else if (sta->deflink.vht_cap.vht_supported) {
+- struct ieee80211_sta_vht_cap *pc = &sta->deflink.vht_cap;
++ } else if (link_sta->vht_cap.vht_supported) {
++ struct ieee80211_sta_vht_cap *pc = &link_sta->vht_cap;
+
+ nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
+ pc->cap);
+@@ -1973,25 +1980,24 @@ mt7996_mcu_sta_hdrt_tlv(struct mt7996_dev *dev, struct sk_buff *skb)
+ static void
+ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ struct ieee80211_vif *vif,
+- struct ieee80211_sta *sta)
++ struct mt7996_link_sta *mlink)
+ {
+ struct sta_rec_hdr_trans *hdr_trans;
+- struct mt76_wcid *wcid;
++ struct mt76_wcid *wcid = &mlink->wcid;
+ struct tlv *tlv;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HDR_TRANS, sizeof(*hdr_trans));
+ hdr_trans = (struct sta_rec_hdr_trans *)tlv;
+ hdr_trans->dis_rx_hdr_tran = true;
+
++ if (!wcid->sta)
++ return;
++
+ if (vif->type == NL80211_IFTYPE_STATION)
+ hdr_trans->to_ds = true;
+ else
+ hdr_trans->from_ds = true;
+
+- if (!sta)
+- return;
+-
+- wcid = (struct mt76_wcid *)sta->drv_priv;
+ hdr_trans->dis_rx_hdr_tran = !test_bit(MT_WCID_FLAG_HDR_TRANS, &wcid->flags);
+ if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags)) {
+ hdr_trans->to_ds = true;
+@@ -2048,16 +2054,17 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+
+ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta, void *data, u32 field)
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink, void *data,
++ u32 field)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct sta_phy_uni *phy = data;
+ struct sta_rec_ra_fixed_uni *ra;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+- &msta->wcid,
++ &mlink->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+@@ -2076,7 +2083,7 @@ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
+ ra->phy = *phy;
+ break;
+ case RATE_PARAM_MMPS_UPDATE:
+- ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode);
++ ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);
+ break;
+ default:
+ break;
+@@ -2091,7 +2098,8 @@ static int
+ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta)
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink)
+ {
+ struct cfg80211_chan_def *chandef = &mconf->phy->mt76->chandef;
+ struct cfg80211_bitrate_mask *mask = &mconf->bitrate_mask;
+@@ -2115,11 +2123,11 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
+ } \
+ } while (0)
+
+- if (sta->deflink.he_cap.has_he) {
++ if (link_sta->he_cap.has_he) {
+ __sta_phy_bitrate_mask_check(he_mcs, he_gi, 0, 1);
+- } else if (sta->deflink.vht_cap.vht_supported) {
++ } else if (link_sta->vht_cap.vht_supported) {
+ __sta_phy_bitrate_mask_check(vht_mcs, gi, 0, 0);
+- } else if (sta->deflink.ht_cap.ht_supported) {
++ } else if (link_sta->ht_cap.ht_supported) {
+ __sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
+ } else {
+ nrates = hweight32(mask->control[band].legacy);
+@@ -2136,8 +2144,8 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
+
+ /* fixed single rate */
+ if (nrates == 1) {
+- ret = mt7996_mcu_set_fixed_field(dev, mconf, sta, &phy,
+- RATE_PARAM_FIXED_MCS);
++ ret = mt7996_mcu_set_fixed_field(dev, mconf, link_sta, mlink,
++ &phy, RATE_PARAM_FIXED_MCS);
+ if (ret)
+ return ret;
+ }
+@@ -2145,29 +2153,28 @@ mt7996_mcu_add_rate_ctrl_fixed(struct mt7996_dev *dev,
+ /* fixed GI */
+ if (mask->control[band].gi != NL80211_TXRATE_DEFAULT_GI ||
+ mask->control[band].he_gi != GENMASK(7, 0)) {
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ u32 addr;
+
+ /* firmware updates only TXCMD but doesn't take WTBL into
+ * account, so driver should update here to reflect the
+ * actual txrate hardware sends out.
+ */
+- addr = mt7996_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
+- if (sta->deflink.he_cap.has_he)
++ addr = mt7996_mac_wtbl_lmac_addr(dev, mlink->wcid.idx, 7);
++ if (link_sta->he_cap.has_he)
+ mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
+ else
+ mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
+
+- ret = mt7996_mcu_set_fixed_field(dev, mconf, sta, &phy,
+- RATE_PARAM_FIXED_GI);
++ ret = mt7996_mcu_set_fixed_field(dev, mconf, link_sta, mlink,
++ &phy, RATE_PARAM_FIXED_GI);
+ if (ret)
+ return ret;
+ }
+
+ /* fixed HE_LTF */
+ if (mask->control[band].he_ltf != GENMASK(7, 0)) {
+- ret = mt7996_mcu_set_fixed_field(dev, mconf, sta, &phy,
+- RATE_PARAM_FIXED_HE_LTF);
++ ret = mt7996_mcu_set_fixed_field(dev, mconf, link_sta, mlink,
++ &phy, RATE_PARAM_FIXED_HE_LTF);
+ if (ret)
+ return ret;
+ }
+@@ -2179,7 +2186,7 @@ static void
+ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta)
++ struct ieee80211_link_sta *link_sta)
+ {
+ #define INIT_RCPI 180
+ struct mt76_phy *mphy = mconf->phy->mt76;
+@@ -2188,20 +2195,20 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ enum nl80211_band band = chandef->chan->band;
+ struct sta_rec_ra_uni *ra;
+ struct tlv *tlv;
+- u32 supp_rate = sta->deflink.supp_rates[band];
+- u32 cap = sta->wme ? STA_CAP_WMM : 0;
++ u32 supp_rate = link_sta->supp_rates[band];
++ u32 cap = link_sta->sta->wme ? STA_CAP_WMM : 0;
+
+ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
+ ra = (struct sta_rec_ra_uni *)tlv;
+
+ ra->valid = true;
+ ra->auto_rate = true;
+- ra->phy_mode = mt76_connac_get_phy_mode(mphy, conf->vif, band, sta);
++ ra->phy_mode = mt76_connac_get_phy_mode(mphy, conf->vif, band, link_sta);
+ ra->channel = chandef->chan->hw_value;
+- ra->bw = (sta->deflink.bandwidth == IEEE80211_STA_RX_BW_320) ?
+- CMD_CBW_320MHZ : sta->deflink.bandwidth;
++ ra->bw = (link_sta->bandwidth == IEEE80211_STA_RX_BW_320) ?
++ CMD_CBW_320MHZ : link_sta->bandwidth;
+ ra->phy.bw = ra->bw;
+- ra->mmps_mode = mt7996_mcu_get_mmps_mode(sta->deflink.smps_mode);
++ ra->mmps_mode = mt7996_mcu_get_mmps_mode(link_sta->smps_mode);
+
+ if (supp_rate) {
+ supp_rate &= mask->control[band].legacy;
+@@ -2221,60 +2228,60 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ }
+ }
+
+- if (sta->deflink.ht_cap.ht_supported) {
++ if (link_sta->ht_cap.ht_supported) {
+ ra->supp_mode |= MODE_HT;
+- ra->af = sta->deflink.ht_cap.ampdu_factor;
+- ra->ht_gf = !!(sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
++ ra->af = link_sta->ht_cap.ampdu_factor;
++ ra->ht_gf = !!(link_sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD);
+
+ cap |= STA_CAP_HT;
+- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
++ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20)
+ cap |= STA_CAP_SGI_20;
+- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
++ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
+ cap |= STA_CAP_SGI_40;
+- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
++ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_TX_STBC)
+ cap |= STA_CAP_TX_STBC;
+- if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
++ if (link_sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
+ cap |= STA_CAP_RX_STBC;
+ if (conf->ht_ldpc &&
+- (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
++ (link_sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
+ cap |= STA_CAP_LDPC;
+
+- mt7996_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
++ mt7996_mcu_set_sta_ht_mcs(link_sta, ra->ht_mcs,
+ mask->control[band].ht_mcs);
+ ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
+ }
+
+- if (sta->deflink.vht_cap.vht_supported) {
++ if (link_sta->vht_cap.vht_supported) {
+ u8 af;
+
+ ra->supp_mode |= MODE_VHT;
+ af = FIELD_GET(IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK,
+- sta->deflink.vht_cap.cap);
++ link_sta->vht_cap.cap);
+ ra->af = max_t(u8, ra->af, af);
+
+ cap |= STA_CAP_VHT;
+- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
++ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_80)
+ cap |= STA_CAP_VHT_SGI_80;
+- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
++ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_SHORT_GI_160)
+ cap |= STA_CAP_VHT_SGI_160;
+- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
++ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_TXSTBC)
+ cap |= STA_CAP_VHT_TX_STBC;
+- if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
++ if (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
+ cap |= STA_CAP_VHT_RX_STBC;
+ if (conf->vht_ldpc &&
+- (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
++ (link_sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
+ cap |= STA_CAP_VHT_LDPC;
+
+- mt7996_mcu_set_sta_vht_mcs(sta, ra->supp_vht_mcs,
++ mt7996_mcu_set_sta_vht_mcs(link_sta, ra->supp_vht_mcs,
+ mask->control[band].vht_mcs);
+ }
+
+- if (sta->deflink.he_cap.has_he) {
++ if (link_sta->he_cap.has_he) {
+ ra->supp_mode |= MODE_HE;
+ cap |= STA_CAP_HE;
+
+- if (sta->deflink.he_6ghz_capa.capa)
+- ra->af = le16_get_bits(sta->deflink.he_6ghz_capa.capa,
++ if (link_sta->he_6ghz_capa.capa)
++ ra->af = le16_get_bits(link_sta->he_6ghz_capa.capa,
+ IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
+ }
+ ra->sta_cap = cpu_to_le32(cap);
+@@ -2285,14 +2292,14 @@ mt7996_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7996_dev *dev,
+ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta, bool changed)
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink, bool changed)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct sk_buff *skb;
+ int ret;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+- &msta->wcid,
++ &mlink->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+@@ -2302,26 +2309,27 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
+ * update sta_rec_he here.
+ */
+ if (changed)
+- mt7996_mcu_sta_he_tlv(skb, conf, mconf, sta);
++ mt7996_mcu_sta_he_tlv(skb, conf, mconf, link_sta);
+
+ /* sta_rec_ra accommodates BW, NSS and only MCS range format
+ * i.e 0-{7,8,9} for VHT.
+ */
+- mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, conf, mconf, sta);
++ mt7996_mcu_sta_rate_ctrl_tlv(skb, dev, conf, mconf, link_sta);
+
+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+ if (ret)
+ return ret;
+
+- return mt7996_mcu_add_rate_ctrl_fixed(dev, conf, mconf, sta);
++ return mt7996_mcu_add_rate_ctrl_fixed(dev, conf, mconf, link_sta, mlink);
+ }
+
+ static int
+-mt7996_mcu_sta_init_vow(struct mt7996_bss_conf *mconf, struct mt7996_sta *msta)
++mt7996_mcu_sta_init_vow(struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink)
+ {
+ struct mt7996_phy *phy = mconf->phy;
+- struct mt7996_vow_sta_ctrl *vow = &msta->vow;
++ struct mt7996_vow_sta_ctrl *vow = &mlink->vow;
+ u8 omac_idx = mconf->mt76.omac_idx;
+ int ret;
+
+@@ -2339,73 +2347,70 @@ mt7996_mcu_sta_init_vow(struct mt7996_bss_conf *mconf, struct mt7996_sta *msta)
+ vow->drr_quantum[IEEE80211_AC_BE] = VOW_DRR_QUANTUM_IDX2;
+ vow->drr_quantum[IEEE80211_AC_BK] = VOW_DRR_QUANTUM_IDX2;
+
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, mconf, msta, VOW_DRR_CTRL_STA_BSS_GROUP);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, mconf, mlink, VOW_DRR_CTRL_STA_BSS_GROUP);
+ if (ret)
+ return ret;
+
+- ret = mt7996_mcu_set_vow_drr_ctrl(phy, mconf, msta, VOW_DRR_CTRL_STA_PAUSE);
++ ret = mt7996_mcu_set_vow_drr_ctrl(phy, mconf, mlink, VOW_DRR_CTRL_STA_PAUSE);
+ if (ret)
+ return ret;
+
+- return mt7996_mcu_set_vow_drr_ctrl(phy, mconf, msta, VOW_DRR_CTRL_STA_ALL);
++ return mt7996_mcu_set_vow_drr_ctrl(phy, mconf, mlink, VOW_DRR_CTRL_STA_ALL);
+ }
+
+ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta,
+- bool enable, bool newly)
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink, bool enable, bool newly)
+ {
+ struct ieee80211_vif *vif = conf->vif;
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_sta *msta;
+ struct sk_buff *skb;
+ int ret;
+
+- msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
+-
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+- &msta->wcid,
++ &mlink->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ /* starec basic */
+- mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, sta, enable, newly);
++ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, link_sta, enable, newly);
+
+ if (!enable)
+ goto out;
+
+ /* starec hdr trans */
+- mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
++ mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, mlink);
+ /* starec tx proc */
+ mt7996_mcu_sta_tx_proc_tlv(skb);
+
+ /* tag order is in accordance with firmware dependency. */
+- if (sta) {
++ if (link_sta) {
+ /* starec hdrt mode */
+ mt7996_mcu_sta_hdrt_tlv(dev, skb);
+ /* starec bfer */
+- mt7996_mcu_sta_bfer_tlv(dev, skb, conf, mconf, sta);
++ mt7996_mcu_sta_bfer_tlv(dev, skb, conf, mconf, link_sta);
+ /* starec ht */
+- mt7996_mcu_sta_ht_tlv(skb, sta);
++ mt7996_mcu_sta_ht_tlv(skb, link_sta);
+ /* starec vht */
+- mt7996_mcu_sta_vht_tlv(skb, sta);
++ mt7996_mcu_sta_vht_tlv(skb, link_sta);
+ /* starec uapsd */
+- mt76_connac_mcu_sta_uapsd(skb, vif, sta);
++ mt76_connac_mcu_sta_uapsd(skb, vif, link_sta->sta);
+ /* starec amsdu */
+- mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, sta);
++ mt7996_mcu_sta_amsdu_tlv(dev, skb, vif, link_sta, mlink);
+ /* starec he */
+- mt7996_mcu_sta_he_tlv(skb, conf, mconf, sta);
++ mt7996_mcu_sta_he_tlv(skb, conf, mconf, link_sta);
+ /* starec he 6g*/
+- mt7996_mcu_sta_he_6g_tlv(skb, sta);
++ mt7996_mcu_sta_he_6g_tlv(skb, link_sta);
+ /* starec eht */
+- mt7996_mcu_sta_eht_tlv(skb, sta);
++ mt7996_mcu_sta_eht_tlv(skb, link_sta);
+ /* starec muru */
+- mt7996_mcu_sta_muru_tlv(dev, skb, conf, mconf, sta);
++ mt7996_mcu_sta_muru_tlv(dev, skb, conf, mconf, link_sta);
+ /* starec bfee */
+- mt7996_mcu_sta_bfee_tlv(dev, skb, conf, mconf, sta);
++ mt7996_mcu_sta_bfee_tlv(dev, skb, conf, mconf, link_sta);
+ }
+
+- ret = mt7996_mcu_sta_init_vow(mconf, msta);
++ ret = mt7996_mcu_sta_init_vow(mconf, mlink);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+@@ -2481,16 +2486,16 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_bss_conf *mconf,
+
+ static int mt7996_mcu_get_pn(struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf, u8 *pn)
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink, u8 *pn)
+ {
+ #define TSC_TYPE_BIGTK_PN 2
+- struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv;
+ struct sta_rec_pn_info *pn_info;
+ struct sk_buff *skb, *rskb;
+ struct tlv *tlv;
+ int ret;
+
+- skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, &mvif->sta.wcid);
++ skb = mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76, &mlink->wcid);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+@@ -2517,6 +2522,7 @@ static int mt7996_mcu_get_pn(struct mt7996_dev *dev,
+ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink,
+ struct ieee80211_key_conf *key)
+ {
+ struct mt7996_mcu_bcn_prot_tlv *bcn_prot;
+@@ -2535,7 +2541,7 @@ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,
+
+ bcn_prot = (struct mt7996_mcu_bcn_prot_tlv *)tlv;
+
+- ret = mt7996_mcu_get_pn(dev, conf, mconf, pn);
++ ret = mt7996_mcu_get_pn(dev, conf, mconf, mlink, pn);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+@@ -4811,21 +4817,18 @@ int mt7996_mcu_rdd_background_disable_timer(struct mt7996_dev *dev, bool disable
+ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
+ struct ieee80211_vif *vif,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta)
++ struct mt7996_link_sta *mlink)
+ {
+- struct mt7996_sta *msta;
+ struct sk_buff *skb;
+
+- msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mconf->vif->sta;
+-
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+- &msta->wcid,
++ &mlink->wcid,
+ MT7996_STA_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ /* starec hdr trans */
+- mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, sta);
++ mt7996_mcu_sta_hdr_trans_tlv(dev, skb, vif, mlink);
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+ }
+@@ -5014,7 +5017,7 @@ int mt7996_mcu_get_per_sta_info(struct mt76_dev *dev, u16 tag,
+ switch (tag) {
+ case UNI_PER_STA_RSSI:
+ for (i = 0; i < sta_num; ++i) {
+- struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ struct mt76_phy *phy;
+ s8 rssi[4];
+ u8 *rcpi;
+@@ -5028,10 +5031,10 @@ int mt7996_mcu_get_per_sta_info(struct mt76_dev *dev, u16 tag,
+ rssi[2] = to_rssi(MT_PRXV_RCPI0, rcpi[2]);
+ rssi[3] = to_rssi(MT_PRXV_RCPI0, rcpi[3]);
+
+- msta = container_of(wcid, struct mt7996_sta, wcid);
+- phy = msta->vif->phy->mt76;
+- msta->ack_signal = mt76_rx_signal(phy->antenna_mask, rssi);
+- ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ phy = mlink->sta->vif->deflink.phy->mt76;
++ mlink->ack_signal = mt76_rx_signal(phy->antenna_mask, rssi);
++ ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal);
+ } else {
+ ret = -EINVAL;
+ dev_err(dev->dev, "Failed to update RSSI for "
+@@ -5069,7 +5072,7 @@ int mt7996_mcu_get_rssi(struct mt76_dev *dev)
+ {
+ u16 sta_list[PER_STA_INFO_MAX_NUM];
+ LIST_HEAD(sta_poll_list);
+- struct mt7996_sta *msta;
++ struct mt7996_link_sta *mlink;
+ int i, ret;
+ bool empty = false;
+
+@@ -5089,13 +5092,13 @@ int mt7996_mcu_get_rssi(struct mt76_dev *dev)
+ empty = true;
+ break;
+ }
+- msta = list_first_entry(&sta_poll_list,
+- struct mt7996_sta,
++ mlink = list_first_entry(&sta_poll_list,
++ struct mt7996_link_sta,
+ wcid.poll_list);
+- list_del_init(&msta->wcid.poll_list);
++ list_del_init(&mlink->wcid.poll_list);
+ spin_unlock_bh(&dev->sta_poll_lock);
+
+- sta_list[i] = msta->wcid.idx;
++ sta_list[i] = mlink->wcid.idx;
+ }
+
+ ret = mt7996_mcu_get_per_sta_info(dev, UNI_PER_STA_RSSI,
+@@ -5385,10 +5388,18 @@ int mt7996_mcu_set_scs_stats(struct mt7996_phy *phy)
+ void mt7996_sta_rssi_work(void *data, struct ieee80211_sta *sta)
+ {
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
+ struct mt7996_phy *poll_phy = (struct mt7996_phy *) data;
+
+- if (poll_phy->scs_ctrl.sta_min_rssi > msta->ack_signal)
+- poll_phy->scs_ctrl.sta_min_rssi = msta->ack_signal;
++ mutex_lock(&poll_phy->dev->mt76.mutex);
++ mlink = mlink_dereference_protected(msta, 0);
++ if (!mlink)
++ goto out;
++
++ if (poll_phy->scs_ctrl.sta_min_rssi > mlink->ack_signal)
++ poll_phy->scs_ctrl.sta_min_rssi = mlink->ack_signal;
++out:
++ mutex_unlock(&poll_phy->dev->mt76.mutex);
+ }
+
+ void mt7996_mcu_scs_sta_poll(struct work_struct *work)
+@@ -5464,9 +5475,10 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
+
+ int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy,
+ struct mt7996_bss_conf *mconf,
+- struct mt7996_sta *msta, enum vow_drr_ctrl_id id)
++ struct mt7996_link_sta *mlink,
++ enum vow_drr_ctrl_id id)
+ {
+- struct mt7996_vow_sta_ctrl *vow = msta ? &msta->vow : NULL;
++ struct mt7996_vow_sta_ctrl *vow = mlink ? &mlink->vow : NULL;
+ u32 val = 0;
+ struct {
+ u8 __rsv1[4];
+@@ -5488,11 +5500,11 @@ int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy,
+ } __packed req = {
+ .tag = cpu_to_le16(UNI_VOW_DRR_CTRL),
+ .len = cpu_to_le16(sizeof(req) - 4),
+- .wlan_idx = cpu_to_le16(msta ? msta->wcid.idx : 0),
++ .wlan_idx = cpu_to_le16(mlink ? mlink->wcid.idx : 0),
+ .band_idx = phy->mt76->band_idx,
+- .wmm_idx = msta ? mconf->mt76.wmm_idx : 0,
++ .wmm_idx = mlink ? mconf->mt76.wmm_idx : 0,
+ .ctrl_id = cpu_to_le32(id),
+- .omac_idx = msta ? mconf->mt76.omac_idx : 0
++ .omac_idx = mlink ? mconf->mt76.omac_idx : 0
+ };
+
+ switch (id) {
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 6b03ee17f..370172037 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -302,10 +302,10 @@ struct mt7996_vow_sta_ctrl {
+ u8 drr_quantum[IEEE80211_NUM_ACS];
+ };
+
+-struct mt7996_sta {
++struct mt7996_link_sta {
+ struct mt76_wcid wcid; /* must be first */
+
+- struct mt7996_vif *vif;
++ struct mt7996_sta *sta;
+
+ struct list_head rc_list;
+
+@@ -324,6 +324,13 @@ struct mt7996_sta {
+ struct mt7996_vow_sta_ctrl vow;
+ };
+
++struct mt7996_sta {
++ struct mt7996_link_sta deflink;
++ struct mt7996_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
++
++ struct mt7996_vif *vif;
++};
++
+ struct mt7996_bss_conf {
+ struct mt76_vif mt76; /* must be first */
+
+@@ -783,6 +790,13 @@ mconf_dereference_protected(struct mt7996_vif *mvif, u8 link_id)
+ lockdep_is_held(&mvif->dev->mt76.mutex));
+ }
+
++static inline struct mt7996_link_sta *
++mlink_dereference_protected(struct mt7996_sta *msta, u8 link_id)
++{
++ return rcu_dereference_protected(msta->link[link_id],
++ lockdep_is_held(&msta->vif->dev->mt76.mutex));
++}
++
+ extern const struct ieee80211_ops mt7996_ops;
+ extern struct pci_driver mt7996_pci_driver;
+ extern struct pci_driver mt7996_hif_driver;
+@@ -827,10 +841,12 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
+ struct mt7996_bss_conf *mconf, bool enable);
+ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
+ struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf, int enable);
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink, int enable);
+ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta,
+- bool enable, bool newly);
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink, bool enable, bool newly);
+ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool add);
+@@ -852,7 +868,8 @@ int mt7996_mcu_add_obss_spr(struct mt7996_phy *phy,
+ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta, bool changed);
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink, bool changed);
+ int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
+ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
+ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf);
+@@ -860,7 +877,9 @@ int mt7996_mcu_set_fixed_rate_ctrl(struct mt7996_dev *dev,
+ void *data, u16 version);
+ int mt7996_mcu_set_fixed_field(struct mt7996_dev *dev,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta, void *data, u32 field);
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink, void *data,
++ u32 field);
+ int mt7996_mcu_set_eeprom(struct mt7996_dev *dev);
+ int mt7996_mcu_get_eeprom(struct mt7996_dev *dev, u32 offset, u8 *read_buf);
+ int mt7996_mcu_get_eeprom_free_block(struct mt7996_dev *dev, u8 *block_num);
+@@ -916,7 +935,8 @@ void mt7996_mcu_scs_sta_poll(struct work_struct *work);
+ int mt7996_mcu_set_band_confg(struct mt7996_phy *phy, u16 option, bool enable);
+ int mt7996_mcu_set_vow_drr_ctrl(struct mt7996_phy *phy,
+ struct mt7996_bss_conf *mconf,
+- struct mt7996_sta *msta, enum vow_drr_ctrl_id id);
++ struct mt7996_link_sta *mlink,
++ enum vow_drr_ctrl_id id);
+ int mt7996_mcu_set_vow_feature_ctrl(struct mt7996_phy *phy);
+ void mt7996_mcu_wmm_pbc_work(struct work_struct *work);
+
+@@ -983,7 +1003,7 @@ void mt7996_mac_reset_counters(struct mt7996_phy *phy);
+ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
+ void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
+ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
+- struct ieee80211_vif *vif, bool enable);
++ struct mt7996_link_sta *mlink, bool enable);
+ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ struct sk_buff *skb, struct mt76_wcid *wcid,
+ struct ieee80211_key_conf *key, int pid,
+@@ -1001,8 +1021,7 @@ void mt7996_mac_dump_work(struct work_struct *work);
+ void mt7996_mac_sta_rc_work(struct work_struct *work);
+ void mt7996_mac_update_stats(struct mt7996_phy *phy);
+ void mt7996_mac_twt_teardown_flow(struct mt7996_dev *dev,
+- struct mt7996_sta *msta,
+- u8 flowid);
++ struct mt7996_link_sta *mlink, u8 flowid);
+ void mt7996_mac_add_twt_setup(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct ieee80211_twt_setup *twt);
+@@ -1031,11 +1050,12 @@ int mt7996_mcu_add_key(struct mt76_dev *dev, struct mt7996_bss_conf *mconf,
+ int mt7996_mcu_bcn_prot_enable(struct mt7996_dev *dev,
+ struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink,
+ struct ieee80211_key_conf *key);
+ int mt7996_mcu_wtbl_update_hdr_trans(struct mt7996_dev *dev,
+ struct ieee80211_vif *vif,
+ struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta);
++ struct mt7996_link_sta *mlink);
+ int mt7996_mcu_cp_support(struct mt7996_dev *dev, u8 mode);
+ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap);
+ #ifdef CONFIG_MAC80211_DEBUGFS
+diff --git a/mt7996/testmode.c b/mt7996/testmode.c
+index bf55b4309..ba17f947b 100644
+--- a/mt7996/testmode.c
++++ b/mt7996/testmode.c
+@@ -235,8 +235,8 @@ mt7996_tm_init(struct mt7996_phy *phy, bool en)
+
+ mt7996_tm_rf_switch_mode(dev, rf_test_mode);
+
+- mt7996_mcu_add_bss_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, en);
+- mt7996_mcu_add_sta(dev, &phy->monitor_vif->bss_conf, &mvif->deflink, NULL, en, false);
++ mt7996_mcu_add_bss_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, &mvif->sta.deflink, en);
++ mt7996_mcu_add_sta(dev, &phy->monitor_vif->bss_conf, &mvif->deflink, NULL, &mvif->sta.deflink, en, false);
+
+ mt7996_tm_set(dev, SET_ID(BAND_IDX), phy->mt76->band_idx);
+
+@@ -1186,7 +1186,7 @@ mt7996_tm_txbf_init(struct mt7996_phy *phy, u16 *val)
+ phy->omac_mask |= BIT_ULL(mvif->deflink.mt76.omac_idx);
+
+ mt7996_mcu_add_dev_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, true);
+- mt7996_mcu_add_bss_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, true);
++ mt7996_mcu_add_bss_info(phy, &phy->monitor_vif->bss_conf, &mvif->deflink, &mvif->sta.deflink, true);
+
+ if (td->ibf) {
+ if (td->is_txbf_dut) {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0088-wifi-mt76-extend-wcid-and-sta-flow-for-MLO-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0088-wifi-mt76-extend-wcid-and-sta-flow-for-MLO-support.patch
new file mode 100644
index 0000000..d52447a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0088-wifi-mt76-extend-wcid-and-sta-flow-for-MLO-support.patch
@@ -0,0 +1,91 @@
+From 700547976605b447defd5492837cc123c97aba50 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 29 Nov 2023 11:04:50 +0800
+Subject: [PATCH 088/116] wifi: mt76: extend wcid and sta flow for MLO support
+
+Add link related info to wcid, and split sta connection flow of common
+parts for MLO supported chipsets.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 12 +++++++++++-
+ mt76.h | 7 ++++++-
+ 2 files changed, 17 insertions(+), 2 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 4fad03dd9..96fab2320 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1066,6 +1066,10 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
+ sizeof(mstat.chain_signal));
+ memcpy(status->chain_signal, mstat.chain_signal,
+ sizeof(mstat.chain_signal));
++ if (mstat.wcid) {
++ status->link_valid = mstat.wcid->link_valid;
++ status->link_id = mstat.wcid->link_id;
++ }
+
+ *sta = wcid_to_sta(mstat.wcid);
+ *hw = mt76_phy_hw(dev, mstat.phy_idx);
+@@ -1374,6 +1378,9 @@ mt76_sta_add(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ if (ret)
+ goto out;
+
++ if (phy->hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO)
++ goto out;
++
+ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
+ struct mt76_txq *mtxq;
+
+@@ -1403,12 +1410,15 @@ void __mt76_sta_remove(struct mt76_dev *dev, struct ieee80211_vif *vif,
+ struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
+ int i, idx = wcid->idx;
+
+- for (i = 0; i < ARRAY_SIZE(wcid->aggr); i++)
++ for (i = 0; !sta->valid_links && i < ARRAY_SIZE(wcid->aggr); i++)
+ mt76_rx_aggr_stop(dev, wcid, i);
+
+ if (dev->drv->sta_remove)
+ dev->drv->sta_remove(dev, vif, sta);
+
++ if (sta->valid_links)
++ return;
++
+ mt76_wcid_cleanup(dev, wcid);
+
+ mt76_wcid_mask_clear(dev->wcid_mask, idx);
+diff --git a/mt76.h b/mt76.h
+index 0abb8ebf5..b60b5161b 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -381,6 +381,9 @@ struct mt76_wcid {
+ u8 sta:1;
+ u8 amsdu:1;
+ u8 phy_idx:2;
++ u8 link_id:4;
++ bool link_valid;
++ struct mt76_wcid *def_wcid;
+
+ u8 rx_check_pn;
+ u8 rx_key_pn[IEEE80211_NUM_TIDS + 1][6];
+@@ -1366,11 +1369,13 @@ mtxq_to_txq(struct mt76_txq *mtxq)
+ static inline struct ieee80211_sta *
+ wcid_to_sta(struct mt76_wcid *wcid)
+ {
+- void *ptr = wcid;
++ void *ptr;
+
+ if (!wcid || !wcid->sta)
+ return NULL;
+
++ ptr = wcid->def_wcid ?: wcid;
++
+ return container_of(ptr, struct ieee80211_sta, drv_priv);
+ }
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0089-wifi-mt76-mt7996-enable-MLO-capability.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0089-wifi-mt76-mt7996-enable-MLO-capability.patch
new file mode 100644
index 0000000..479e720
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0089-wifi-mt76-mt7996-enable-MLO-capability.patch
@@ -0,0 +1,108 @@
+From c7aef97eb798ee5c8e779e5d0514cbe68b41f6a3 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 30 Nov 2023 16:31:17 +0800
+Subject: [PATCH 089/116] wifi: mt76: mt7996: enable MLO capability
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/eeprom.c | 6 ++++++
+ mt7996/init.c | 40 ++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 44 insertions(+), 2 deletions(-)
+
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 51455d877..0393e93bf 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -387,6 +387,12 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
+ break;
+ }
+
++ /* TODO: for MLO, we enable all band capabilities */
++ phy->mt76->cap.has_2ghz = true;
++ phy->mt76->cap.has_5ghz = true;
++ if (is_mt7996(&phy->dev->mt76))
++ phy->mt76->cap.has_6ghz = true;
++
+ return ret;
+ }
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 381e1292c..c6eb6a5c2 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -34,16 +34,45 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+ .max_interfaces = MT7996_MAX_INTERFACES,
+- .num_different_channels = 1,
++ .num_different_channels = 3,
+ .beacon_int_infra_match = true,
++ /*
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
++ */
+ }
+ };
+
++static const u8 mt7996_if_types_ext_capa[] = {
++ [0] = WLAN_EXT_CAPA1_EXT_CHANNEL_SWITCHING,
++ [7] = WLAN_EXT_CAPA8_OPMODE_NOTIF,
++};
++
++static const struct wiphy_iftype_ext_capab mt7996_iftypes_ext_capa[] = {
++ {
++ .iftype = NL80211_IFTYPE_STATION,
++ .extended_capabilities = mt7996_if_types_ext_capa,
++ .extended_capabilities_mask = mt7996_if_types_ext_capa,
++ .extended_capabilities_len = sizeof(mt7996_if_types_ext_capa),
++ .mld_capa_and_ops = 2,
++ },
++ {
++ .iftype = NL80211_IFTYPE_AP,
++ .extended_capabilities = mt7996_if_types_ext_capa,
++ .extended_capabilities_mask = mt7996_if_types_ext_capa,
++ .extended_capabilities_len = sizeof(mt7996_if_types_ext_capa),
++ .mld_capa_and_ops = 2,
++ /* the max number of simultaneous links is defined as the
++ * maximum number of affiliated APs minus 1.
++ * mt7996 could have 3 links in an MLD AP, so currently
++ * hardcode it to 2.
++ */
++ },
++};
++
+ static ssize_t mt7996_thermal_temp_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+@@ -417,8 +446,9 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+ ieee80211_hw_set(hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+ ieee80211_hw_set(hw, SUPPORTS_RX_DECAP_OFFLOAD);
+ ieee80211_hw_set(hw, WANT_MONITOR_VIF);
+- ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
++ // ieee80211_hw_set(hw, SUPPORTS_MULTI_BSSID);
+ ieee80211_hw_set(hw, CHANCTX_STA_CSA);
++ ieee80211_hw_set(hw, CONNECTION_MONITOR);
+
+ hw->max_tx_fragments = 4;
+
+@@ -462,6 +492,12 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
+
+ wiphy->max_scan_ssids = 4;
+ wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
++
++ /* enable MLO support */
++ wiphy->flags |= WIPHY_FLAG_SUPPORTS_MLO;
++ wiphy->iftype_ext_capab = mt7996_iftypes_ext_capa;
++ wiphy->num_iftype_ext_capab = ARRAY_SIZE(mt7996_iftypes_ext_capa);
++ wiphy->features |= NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE;
+ }
+
+ static void
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0090-wifi-mt76-mt7996-support-multi-link-vif-links-and-ML.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0090-wifi-mt76-mt7996-support-multi-link-vif-links-and-ML.patch
new file mode 100644
index 0000000..d6b68ca
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0090-wifi-mt76-mt7996-support-multi-link-vif-links-and-ML.patch
@@ -0,0 +1,590 @@
+From 4cc16942c3f1ec92f9a25802341f456d92dd5cc4 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 23 Nov 2023 18:22:11 +0800
+Subject: [PATCH 090/116] wifi: mt76: mt7996: support multi-link vif links and
+ MLO bss callbacks
+
+Rework add/remove interface functions to add/remove bss_conf functions,
+and also switch to callbacks for MLO bss.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/main.c | 298 +++++++++++++++++++++++++++++++++++++++---------
+ mt7996/mcu.c | 29 +++--
+ mt7996/mt7996.h | 9 ++
+ 3 files changed, 270 insertions(+), 66 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 4069ffb70..38aae12be 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -205,6 +205,38 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
+ return -1;
+ }
+
++static int get_own_mld_idx(u64 mask, bool group_mld)
++{
++ u8 start, end;
++ int i;
++
++ if (group_mld) {
++ start = 0;
++ end = 15;
++ } else {
++ start = 16;
++ end = 63;
++ }
++
++ i = get_free_idx(mask, start, end);
++ if (i)
++ return i - 1;
++
++ return -1;
++}
++
++static int get_mld_remap_idx(u64 mask)
++{
++ u8 start = 0, end = 15;
++ int i;
++
++ i = get_free_idx(mask, start, end);
++ if (i)
++ return i - 1;
++
++ return -1;
++}
++
+ static void mt7996_init_bitrate_mask(struct mt7996_bss_conf *mconf)
+ {
+ int i;
+@@ -223,48 +255,108 @@ static void mt7996_init_bitrate_mask(struct mt7996_bss_conf *mconf)
+ }
+ }
+
+-static int mt7996_add_interface(struct ieee80211_hw *hw,
+- struct ieee80211_vif *vif)
++static void mt7996_remove_bss_conf(struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf)
+ {
+- struct ieee80211_bss_conf *conf = &vif->bss_conf;
++ struct mt7996_phy *phy = mconf->phy;
++ struct mt7996_dev *dev = phy->dev;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf = &mvif->deflink;
+- struct mt7996_link_sta *mlink = &mvif->sta.deflink;
+- struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ u8 link_id = conf->link_id;
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(&mvif->sta, link_id);
++
++ if (!mlink)
++ return;
++
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, false, false);
++ mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, false);
++ mt7996_mcu_add_dev_info(phy, conf, mconf, false);
++
++ rcu_assign_pointer(dev->mt76.wcid[mlink->wcid.idx], NULL);
++ rcu_assign_pointer(mvif->link[link_id], NULL);
++ rcu_assign_pointer(mvif->sta.link[link_id], NULL);
++
++ dev->mt76.vif_mask &= ~BIT_ULL(mconf->mt76.idx);
++ dev->mld_id_mask &= ~BIT_ULL(mconf->own_mld_id);
++ phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx);
++
++ spin_lock_bh(&dev->mt76.sta_poll_lock);
++ if (!list_empty(&mlink->wcid.poll_list))
++ list_del_init(&mlink->wcid.poll_list);
++ spin_unlock_bh(&dev->mt76.sta_poll_lock);
++
++ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
++
++ if (mlink != &mvif->sta.deflink)
++ kfree(mlink);
++
++ if (mconf != &mvif->deflink)
++ kfree(mconf);
++}
++
++static int mt7996_add_bss_conf(struct mt7996_phy *phy,
++ struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_dev *dev = phy->dev;
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
+ struct mt76_txq *mtxq;
+ u8 band_idx = phy->mt76->band_idx;
+- int idx, ret = 0;
+-
+- mutex_lock(&dev->mt76.mutex);
++ u8 link_id = conf->link_id;
++ int idx, ret;
+
+- if (vif->type == NL80211_IFTYPE_MONITOR &&
+- is_zero_ether_addr(vif->addr))
+- phy->monitor_vif = vif;
++ if (conf != &vif->bss_conf) {
++ mconf = kzalloc(sizeof(*mconf), GFP_KERNEL);
++ if (!mconf)
++ return -ENOMEM;
++ } else {
++ mconf = &mvif->deflink;
++ }
+
+ mconf->mt76.idx = __ffs64(~dev->mt76.vif_mask);
+ if (mconf->mt76.idx >= mt7996_max_interface_num(dev)) {
+ ret = -ENOSPC;
+- goto out;
++ goto error;
+ }
+
+ idx = get_omac_idx(vif->type, phy->omac_mask);
+ if (idx < 0) {
+ ret = -ENOSPC;
+- goto out;
++ goto error;
++ }
++
++ mconf->own_mld_id = get_own_mld_idx(dev->mld_id_mask, false);
++ if (mconf->own_mld_id < 0) {
++ ret = -ENOSPC;
++ goto error;
+ }
++
+ mconf->mt76.omac_idx = idx;
+ mconf->vif = mvif;
+ mconf->phy = phy;
+ mconf->mt76.band_idx = band_idx;
+ mconf->mt76.wmm_idx = vif->type != NL80211_IFTYPE_AP;
+- mvif->dev = dev;
++ mconf->link_id = link_id;
+
+ ret = mt7996_mcu_add_dev_info(phy, conf, mconf, true);
+ if (ret)
+- goto out;
++ goto error;
++
++ if (ieee80211_vif_is_mld(vif)) {
++ mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
++ if (!mlink) {
++ ret = -ENOMEM;
++ goto error;
++ }
++ } else {
++ mlink = &mvif->sta.deflink;
++ }
+
+ dev->mt76.vif_mask |= BIT_ULL(mconf->mt76.idx);
++ dev->mld_id_mask |= BIT_ULL(mconf->own_mld_id);
+ phy->omac_mask |= BIT_ULL(mconf->mt76.omac_idx);
+
+ idx = MT7996_WTBL_RESERVED - mconf->mt76.idx;
+@@ -275,6 +367,9 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ mlink->wcid.phy_idx = band_idx;
+ mlink->wcid.hw_key_idx = -1;
+ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
++ mlink->wcid.def_wcid = &mvif->sta.deflink.wcid;
++ mlink->wcid.link_id = link_id;
++ mlink->wcid.link_valid = ieee80211_vif_is_mld(vif);
+ mlink->sta = &mvif->sta;
+ mlink->sta->vif = mvif;
+ mt76_wcid_init(&mlink->wcid);
+@@ -296,7 +391,6 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ mconf->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
+ else
+ mconf->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
+-
+ mt7996_init_bitrate_mask(mconf);
+
+ mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, true);
+@@ -306,10 +400,32 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ if (vif->type != NL80211_IFTYPE_STATION)
+ mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, true, true);
+ rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid);
+- rcu_assign_pointer(mvif->link[0], mconf);
+- rcu_assign_pointer(mvif->sta.link[0], mlink);
++ rcu_assign_pointer(mvif->link[link_id], mconf);
++ rcu_assign_pointer(mvif->sta.link[link_id], mlink);
+
+-out:
++ return 0;
++error:
++ mt7996_remove_bss_conf(vif, conf, mconf);
++ return ret;
++}
++
++static int mt7996_add_interface(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ int ret = 0;
++
++ mutex_lock(&dev->mt76.mutex);
++ if (vif->type == NL80211_IFTYPE_MONITOR &&
++ is_zero_ether_addr(vif->addr))
++ phy->monitor_vif = vif;
++
++ mvif->dev = dev;
++ mvif->sta.vif = mvif;
++
++ ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+@@ -321,38 +437,23 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct ieee80211_bss_conf *conf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf;
+- struct mt7996_link_sta *mlink = &mvif->sta.deflink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- int idx = mlink->wcid.idx;
+
+ cancel_delayed_work_sync(&phy->scan_work);
+
+ mutex_lock(&dev->mt76.mutex);
+
+- conf = link_conf_dereference_protected(vif, 0);
+- mconf = mconf_dereference_protected(mvif, 0);
+- mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, false, false);
+- mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, false);
++ if (test_bit(MT76_SCANNING, &phy->mt76->state))
++ mt7996_scan_complete(phy, true);
+
+ if (vif == phy->monitor_vif)
+ phy->monitor_vif = NULL;
+
+- mt7996_mcu_add_dev_info(phy, conf, mconf, false);
+-
+- rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+-
+- dev->mt76.vif_mask &= ~BIT_ULL(mconf->mt76.idx);
+- phy->omac_mask &= ~BIT_ULL(mconf->mt76.omac_idx);
+-
+- spin_lock_bh(&dev->mt76.sta_poll_lock);
+- if (!list_empty(&mlink->wcid.poll_list))
+- list_del_init(&mlink->wcid.poll_list);
+- spin_unlock_bh(&dev->mt76.sta_poll_lock);
++ conf = link_conf_dereference_protected(vif, 0);
++ mconf = mconf_dereference_protected(mvif, 0);
+
+- mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
+- rcu_assign_pointer(mvif->link[0], NULL);
+- rcu_assign_pointer(mvif->sta.link[0], NULL);
++ mt7996_remove_bss_conf(vif, conf, mconf);
+
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -716,10 +817,31 @@ mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_bss_conf *conf,
+ mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]);
+ }
+
+-static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+- struct ieee80211_vif *vif,
+- struct ieee80211_bss_conf *info,
+- u64 changed)
++static void mt7996_vif_cfg_changed(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif, u64 changed)
++{
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++
++ mutex_lock(&dev->mt76.mutex);
++
++ if (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) {
++ struct ieee80211_bss_conf *conf = &vif->bss_conf;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
++ struct mt7996_link_sta *mlink = mlink_dereference_protected(&mvif->sta, 0);
++
++ mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, true);
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, true, false);
++ }
++
++ mutex_unlock(&dev->mt76.mutex);
++}
++
++static void mt7996_link_info_changed(struct ieee80211_hw *hw,
++ struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *info,
++ u64 changed)
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf;
+@@ -735,7 +857,6 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ * and then peer references bss_info_rfch to set bandwidth cap.
+ */
+ if ((changed & BSS_CHANGED_BSSID && !is_zero_ether_addr(info->bssid)) ||
+- (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) ||
+ (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon)) {
+ mt7996_mcu_add_bss_info(phy, info, mconf, mlink, true);
+ mt7996_mcu_add_sta(dev, info, mconf, NULL, mlink, true,
+@@ -1078,7 +1199,7 @@ mt7996_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ u64 ret;
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, mvif->master_link_id);
+ ret = __mt7996_get_tsf(hw, mconf);
+ mutex_unlock(&dev->mt76.mutex);
+
+@@ -1101,7 +1222,7 @@ mt7996_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+
+ mutex_lock(&dev->mt76.mutex);
+
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, mvif->master_link_id);
+ n = mconf->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
+ : mconf->mt76.omac_idx;
+ mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]);
+@@ -1129,7 +1250,7 @@ mt7996_offset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+
+ mutex_lock(&dev->mt76.mutex);
+
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, mvif->master_link_id);
+ n = mconf->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0
+ : mconf->mt76.omac_idx;
+ mt76_wr(dev, MT_LPON_UTTR0(phy->mt76->band_idx), tsf.t32[0]);
+@@ -1304,7 +1425,7 @@ mt7996_set_bitrate_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u32 changed = IEEE80211_RC_SUPP_RATES_CHANGED;
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, mvif->master_link_id);
+ mconf->bitrate_mask = *mask;
+ mutex_unlock(&dev->mt76.mutex);
+
+@@ -1524,7 +1645,7 @@ void mt7996_get_et_stats(struct ieee80211_hw *hw,
+ int i, ei = 0;
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, mvif->master_link_id);
+ wi.idx = mconf->mt76.idx,
+
+ mt7996_mac_update_stats(phy);
+@@ -1897,6 +2018,8 @@ mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct mt7996_phy *phy = ctx->phy;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_bss_conf *mconf;
++ u8 link_id = link_conf->link_id;
++ int ret;
+
+ wiphy_info(hw->wiphy, "Assign VIF (addr: %pM, type: %d, link_id: %d) to channel context: %d MHz\n",
+ vif->addr, vif->type, link_conf->link_id,
+@@ -1904,10 +2027,24 @@ mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+
+ mutex_lock(&phy->dev->mt76.mutex);
+
+- mconf = mconf_dereference_protected(mvif, 0);
++ /* remove first */
++ if (rcu_access_pointer(mvif->link[link_id]))
++ mt7996_remove_bss_conf(vif, link_conf,
++ mconf_dereference_protected(mvif, link_id));
++
++ ret = mt7996_add_bss_conf(phy, vif, link_conf);
++ if (ret) {
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return ret;
++ }
++
++ mconf = mconf_dereference_protected(mvif, link_id);
+ mconf->chanctx = ctx;
+ ctx->nbss_assigned++;
+
++ if (mt7996_hw_phy(hw) == phy)
++ mvif->master_link_id = link_id;
++
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+ return 0;
+@@ -1933,7 +2070,7 @@ mt7996_unassign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ if (test_bit(MT76_SCANNING, &phy->mt76->state))
+ mt7996_scan_complete(phy, true);
+
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, link_conf->link_id);
+ mconf->chanctx = NULL;
+ ctx->nbss_assigned--;
+
+@@ -1973,6 +2110,57 @@ mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
+ return mt7996_set_channel(phy, &new_ctx->chandef);
+ }
+
++static int
++mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ u16 old_links, u16 new_links,
++ struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
++{
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ unsigned long rem = old_links & ~new_links;
++ unsigned int link_id;
++ int ret = 0;
++
++ if (old_links == new_links)
++ return 0;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ /* check if there's legacy bss needed to be removed */
++ if (rcu_access_pointer(mvif->link[0]) == &mvif->deflink)
++ rem |= BIT(0);
++ /* remove first */
++ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++
++ if (!mconf)
++ continue;
++
++ mt7996_remove_bss_conf(vif, old[link_id], mconf);
++ }
++
++ if (!old_links) {
++ mvif->group_mld_id = get_own_mld_idx(dev->mld_id_mask, true);
++ dev->mld_id_mask |= BIT_ULL(mvif->group_mld_id);
++
++ mvif->mld_remap_id = get_mld_remap_idx(dev->mld_remap_id_mask);
++ dev->mld_remap_id_mask |= BIT_ULL(mvif->mld_remap_id);
++ }
++
++ /* fallback to non-MLO interface */
++ if (!new_links) {
++ ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
++ dev->mld_id_mask &= ~BIT_ULL(mvif->group_mld_id);
++ dev->mld_remap_id_mask &= ~BIT_ULL(mvif->mld_remap_id);
++ }
++
++ mutex_unlock(&dev->mt76.mutex);
++
++ return ret;
++}
++
+ const struct ieee80211_ops mt7996_ops = {
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+@@ -1982,7 +2170,8 @@ const struct ieee80211_ops mt7996_ops = {
+ .config = mt7996_config,
+ .conf_tx = mt7996_conf_tx,
+ .configure_filter = mt7996_configure_filter,
+- .bss_info_changed = mt7996_bss_info_changed,
++ .vif_cfg_changed = mt7996_vif_cfg_changed,
++ .link_info_changed = mt7996_link_info_changed,
+ .sta_state = mt76_sta_state,
+ .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
+ .sta_rc_update = mt7996_sta_rc_update,
+@@ -2028,4 +2217,5 @@ const struct ieee80211_ops mt7996_ops = {
+ .assign_vif_chanctx = mt7996_assign_vif_chanctx,
+ .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
+ .switch_vif_chanctx = mt7996_switch_vif_chanctx,
++ .change_vif_links = mt7996_change_vif_links,
+ };
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 6d2b517e0..0eccc112d 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1047,15 +1047,23 @@ static void
+ mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ struct mt7996_bss_conf *mconf)
+ {
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct bss_mld_tlv *mld;
+ struct tlv *tlv;
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_MLD, sizeof(*mld));
+-
+ mld = (struct bss_mld_tlv *)tlv;
+- mld->group_mld_id = 0xff;
+- mld->own_mld_id = mconf->mt76.idx;
+- mld->remap_idx = 0xff;
++
++ if (ieee80211_vif_is_mld(vif)) {
++ mld->group_mld_id = mvif->group_mld_id;
++ mld->remap_idx = mvif->mld_remap_id;
++ memcpy(mld->mac_addr, vif->addr, ETH_ALEN);
++ } else {
++ mld->group_mld_id = 0xff;
++ mld->remap_idx = 0xff;
++ }
++
++ mld->own_mld_id = mconf->own_mld_id;
+ }
+
+ static void
+@@ -1136,13 +1144,11 @@ mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct mt7996_phy *phy)
+ }
+
+ static int
+-mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+- struct ieee80211_bss_conf *conf,
+- struct mt7996_bss_conf *mconf,
+- struct ieee80211_sta *sta,
+- struct mt76_phy *phy, u16 wlan_idx,
+- bool enable)
++mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf, struct ieee80211_sta *sta,
++ u16 wlan_idx, bool enable)
+ {
++ struct mt76_phy *phy = mconf->phy->mt76;
+ struct ieee80211_vif *vif = conf->vif;
+ struct cfg80211_chan_def *chandef = &phy->chandef;
+ struct mt76_connac_bss_basic_tlv *bss;
+@@ -1254,8 +1260,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
+ return PTR_ERR(skb);
+
+ /* bss_basic must be first */
+- mt7996_mcu_bss_basic_tlv(skb, conf, mconf, NULL, phy->mt76,
+- mlink->wcid.idx, enable);
++ mt7996_mcu_bss_basic_tlv(skb, conf, mconf, NULL, mlink->wcid.idx, enable);
+ mt7996_mcu_bss_sec_tlv(skb, mconf);
+
+ if (vif->type == NL80211_IFTYPE_MONITOR)
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 370172037..ed8c82e8c 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -340,6 +340,9 @@ struct mt7996_bss_conf {
+ struct cfg80211_bitrate_mask bitrate_mask;
+
+ struct mt7996_chanctx *chanctx;
++
++ u8 link_id;
++ u8 own_mld_id;
+ };
+
+ struct mt7996_vif {
+@@ -348,6 +351,10 @@ struct mt7996_vif {
+
+ struct mt7996_sta sta;
+ struct mt7996_dev *dev;
++
++ u8 master_link_id;
++ u8 group_mld_id;
++ u8 mld_remap_id;
+ };
+
+ /* crash-dump */
+@@ -549,6 +556,8 @@ struct mt7996_dev {
+ u16 chainmask;
+ u8 chainshift[__MT_MAX_BAND];
+ u32 hif_idx;
++ u64 mld_id_mask;
++ u64 mld_remap_id_mask;
+
+ struct work_struct init_work;
+ struct work_struct rc_work;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0091-wifi-mt76-mt7996-support-multi-link-sta-links-and-ML.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0091-wifi-mt76-mt7996-support-multi-link-sta-links-and-ML.patch
new file mode 100644
index 0000000..c1eda8b
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0091-wifi-mt76-mt7996-support-multi-link-sta-links-and-ML.patch
@@ -0,0 +1,604 @@
+From 9bff2b264652d23bf0dc056f1e76120951c8d833 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 29 Nov 2023 10:12:39 +0800
+Subject: [PATCH 091/116] wifi: mt76: mt7996: support multi-link sta links and
+ MLO sta callbacks
+
+Rework add_sta functions to add_link_sta functions, and support
+.change_sta_links callback.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt76_connac_mcu.h | 2 +
+ mt7996/main.c | 309 ++++++++++++++++++++++++++++++++++++----------
+ mt7996/mcu.c | 117 ++++++++++++++++++
+ mt7996/mcu.h | 29 +++++
+ mt7996/mt7996.h | 7 ++
+ 5 files changed, 398 insertions(+), 66 deletions(-)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index f7da63658..d45765beb 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -814,7 +814,9 @@ enum {
+ STA_REC_HE_6G = 0x17,
+ STA_REC_HE_V2 = 0x19,
+ STA_REC_MLD = 0x20,
++ STA_REC_EHT_MLD = 0x21,
+ STA_REC_EHT = 0x22,
++ STA_REC_MLD_TEARDOWN = 0x23,
+ STA_REC_PN_INFO = 0x26,
+ STA_REC_KEY_V3 = 0x27,
+ STA_REC_HDRT = 0x28,
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 38aae12be..b193e638e 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -928,42 +928,234 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
++static void mt7996_remove_link_sta(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_link_sta *link_sta,
++ struct mt7996_link_sta *mlink)
++{
++ struct ieee80211_sta *sta = link_sta->sta;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ int i;
++
++ if (!mlink)
++ return;
++
++ for (i = 0; i < ARRAY_SIZE(mlink->wcid.aggr); i++)
++ mt76_rx_aggr_stop(&dev->mt76, &mlink->wcid, i);
++
++ if (sta->mlo)
++ mt7996_mcu_teardown_mld_sta(dev, mconf, mlink);
++ else
++ mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
++
++ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
++ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
++
++ for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
++ mt7996_mac_twt_teardown_flow(dev, mlink, i);
++
++ rcu_assign_pointer(mlink->sta->link[mlink->wcid.link_id], NULL);
++
++ spin_lock_bh(&dev->mt76.sta_poll_lock);
++ if (!list_empty(&mlink->wcid.poll_list))
++ list_del_init(&mlink->wcid.poll_list);
++ if (!list_empty(&mlink->rc_list))
++ list_del_init(&mlink->rc_list);
++ spin_unlock_bh(&dev->mt76.sta_poll_lock);
++
++ /* TODO: update primary link */
++ if (sta->valid_links) {
++ if (mlink->wcid.link_id == msta->pri_link)
++ msta->pri_link = msta->sec_link;
++
++ if (sta->valid_links & ~(BIT(msta->pri_link)))
++ msta->sec_link = __ffs(sta->valid_links & ~(BIT(msta->pri_link)));
++ else
++ msta->sec_link = msta->pri_link;
++ }
++
++ mt76_wcid_cleanup(&dev->mt76, &mlink->wcid);
++ mt76_wcid_mask_clear(dev->mt76.wcid_mask, mlink->wcid.idx);
++ mt76_wcid_mask_clear(dev->mt76.wcid_phy_mask, mlink->wcid.idx);
++
++ if (mlink != &msta->deflink)
++ kfree(mlink);
++}
++
++static int mt7996_add_link_sta(struct mt7996_dev *dev,
++ struct ieee80211_bss_conf *conf,
++ struct mt7996_bss_conf *mconf,
++ struct ieee80211_link_sta *link_sta, bool assoc)
++{
++ struct ieee80211_sta *sta = link_sta->sta;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ u8 link_id = link_sta->link_id;
++ struct mt7996_link_sta *mlink = NULL;
++ int idx, ret;
++
++ if (!rcu_access_pointer(msta->link[link_id])) {
++ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
++ if (idx < 0)
++ return -ENOSPC;
++
++ if (sta->mlo) {
++ mlink = kzalloc(sizeof(*mlink), GFP_KERNEL);
++ if (!mlink)
++ return -ENOMEM;
++ } else {
++ mlink = &msta->deflink;
++ }
++
++ INIT_LIST_HEAD(&mlink->rc_list);
++ INIT_LIST_HEAD(&mlink->wcid.poll_list);
++ msta->vif = mvif;
++ mlink->wcid.sta = 1;
++ mlink->wcid.idx = idx;
++ mlink->wcid.phy_idx = mconf->phy->mt76->band_idx;
++ mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
++ mlink->wcid.def_wcid = &msta->deflink.wcid;
++ mlink->sta = msta;
++ if (sta->valid_links) {
++ mlink->wcid.link_valid = true;
++ mlink->wcid.link_id = link_id;
++ if (sta->valid_links & ~(BIT(msta->pri_link)))
++ msta->sec_link = __ffs(sta->valid_links &
++ ~(BIT(msta->pri_link)));
++ else
++ msta->sec_link = msta->pri_link;
++ }
++
++ rcu_assign_pointer(msta->link[link_id], mlink);
++
++ ewma_signal_init(&mlink->wcid.rssi);
++ if (mconf->phy->mt76->band_idx == MT_BAND1)
++ mt76_wcid_mask_set(dev->mt76.wcid_phy_mask, idx);
++ rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid);
++ mt76_wcid_init(&mlink->wcid);
++ }
++
++ if (!assoc)
++ return 0;
++
++ if (!mlink)
++ mlink = mlink_dereference_protected(msta, link_id);
++ mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
++ MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
++
++ ret = mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
++ if (ret)
++ goto error;
++
++ ret = mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
++ if (ret)
++ goto error;
++
++ ewma_avg_signal_init(&mlink->avg_ack_signal);
++
++ return 0;
++error:
++ mt7996_remove_link_sta(dev, conf, mconf, link_sta, mlink);
++ return ret;
++}
++
++static void
++mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta, unsigned long rem)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ unsigned int link_id;
++
++ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
++ struct ieee80211_bss_conf *conf =
++ link_conf_dereference_protected(vif, link_id);
++ struct ieee80211_link_sta *link_sta =
++ link_sta_dereference_protected(sta, link_id);
++
++ mt7996_remove_link_sta(dev, conf, mconf, link_sta, mlink);
++ }
++}
++
++static int
++mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta, unsigned long add,
++ bool assoc)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
++ unsigned int link_id;
++ int i, ret;
++
++ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct ieee80211_bss_conf *conf =
++ link_conf_dereference_protected(vif, link_id);
++ struct ieee80211_link_sta *link_sta =
++ link_sta_dereference_protected(sta, link_id);
++
++ ret = mt7996_add_link_sta(dev, conf, mconf, link_sta, assoc);
++ if (ret)
++ goto error;
++ }
++
++ if (!assoc)
++ return 0;
++
++ mlink = mlink_dereference_protected(msta, msta->pri_link);
++ for (i = 0; i < ARRAY_SIZE(sta->txq); i++) {
++ struct mt76_txq *mtxq;
++
++ if (!sta->txq[i])
++ continue;
++ mtxq = (struct mt76_txq *)sta->txq[i]->drv_priv;
++ mtxq->wcid = mlink->wcid.idx;
++ }
++
++ ret = mt7996_mcu_add_mld_sta(dev, vif, sta, add);
++ if (ret)
++ goto error;
++
++ return 0;
++error:
++ mt7996_mac_sta_remove_links(dev, vif, sta, add);
++ return ret;
++}
++
+ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+ {
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
+- struct mt7996_link_sta *mlink = &msta->deflink;
+- u8 band_idx = mconf->phy->mt76->band_idx;
+- int idx;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_bss_conf *mconf;
++ u8 link_id = sta->valid_links ? __ffs(sta->valid_links) : 0;
++ unsigned long add = BIT(link_id);
++ int ret;
+
+ #ifdef CONFIG_MTK_VENDOR
+ struct mt7996_phy *phy = &dev->phy;
+ #endif
+
+- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7996_WTBL_STA);
+- if (idx < 0)
+- return -ENOSPC;
+-
+- INIT_LIST_HEAD(&mlink->rc_list);
+- INIT_LIST_HEAD(&mlink->wcid.poll_list);
+- msta->vif = mvif;
+- mlink->wcid.sta = 1;
+- mlink->wcid.idx = idx;
+- mlink->wcid.phy_idx = band_idx;
+- mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+- mlink->sta = msta;
+-
+- rcu_assign_pointer(msta->link[0], mlink);
++ msta->pri_link = link_id;
++ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false);
++ if (ret)
++ return ret;
+
+ #ifdef CONFIG_MTK_VENDOR
++ mconf = mconf_dereference_protected(mvif, link_id);
+ mt7996_vendor_amnt_sta_remove(mconf->phy, sta);
+ #endif
+
+ #ifdef CONFIG_MTK_VENDOR
+- switch (band_idx) {
++ switch (mconf->phy->mt76->band_idx) {
+ case MT_BAND1:
+ phy = mt7996_phy2(dev);
+ break;
+@@ -986,28 +1178,11 @@ void mt7996_mac_sta_assoc(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+ {
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_bss_conf *mconf;
+- struct mt7996_link_sta *mlink;
+- struct ieee80211_bss_conf *conf;
+- struct ieee80211_link_sta *link_sta;
++ unsigned long add = sta->valid_links ?: BIT(0);
+
+ mutex_lock(&dev->mt76.mutex);
+
+- conf = link_conf_dereference_protected(vif, 0);
+- mconf = mconf_dereference_protected(mvif, 0);
+- link_sta = link_sta_dereference_protected(sta, 0);
+- mlink = mlink_dereference_protected(msta, 0);
+-
+- mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
+- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+-
+- mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, true, true);
+- mt7996_mcu_add_rate_ctrl(dev, conf, mconf, link_sta, mlink, false);
+- mlink->wcid.tx_info |= MT_WCID_TX_INFO_SET;
+-
+- ewma_avg_signal_init(&mlink->avg_ack_signal);
++ mt7996_mac_sta_add_links(dev, vif, sta, add, true);
+
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -1016,34 +1191,9 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta)
+ {
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_bss_conf *mconf;
+- struct mt7996_link_sta *mlink;
+- struct ieee80211_bss_conf *conf;
+- struct ieee80211_link_sta *link_sta;
+- int i;
+-
+- conf = link_conf_dereference_protected(vif, 0);
+- mconf = mconf_dereference_protected(mvif, 0);
+- link_sta = link_sta_dereference_protected(sta, 0);
+- mlink = mlink_dereference_protected(msta, 0);
+- mt7996_mcu_add_sta(dev, conf, mconf, link_sta, mlink, false, false);
+-
+- mt7996_mac_wtbl_update(dev, mlink->wcid.idx,
+- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
+-
+- for (i = 0; i < ARRAY_SIZE(mlink->twt.flow); i++)
+- mt7996_mac_twt_teardown_flow(dev, mlink, i);
++ unsigned long rem = sta->valid_links ?: BIT(0);
+
+- spin_lock_bh(&mdev->sta_poll_lock);
+- if (!list_empty(&mlink->wcid.poll_list))
+- list_del_init(&mlink->wcid.poll_list);
+- if (!list_empty(&mlink->rc_list))
+- list_del_init(&mlink->rc_list);
+- spin_unlock_bh(&mdev->sta_poll_lock);
+-
+- rcu_assign_pointer(msta->link[0], NULL);
++ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
+ }
+
+ static void mt7996_tx(struct ieee80211_hw *hw,
+@@ -2161,6 +2311,32 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ return ret;
+ }
+
++static int
++mt7996_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta, u16 old_links, u16 new_links)
++{
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ unsigned long add = new_links & ~old_links;
++ unsigned long rem = old_links & ~new_links;
++ int ret = 0;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ if (rem)
++ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
++
++ ret = mt7996_mac_sta_add_links(dev, vif, sta, add, false);
++ if (ret)
++ goto remove;
++
++ goto out;
++remove:
++ mt7996_mac_sta_remove_links(dev, vif, sta, add);
++out:
++ mutex_unlock(&dev->mt76.mutex);
++ return ret;
++}
++
+ const struct ieee80211_ops mt7996_ops = {
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+@@ -2218,4 +2394,5 @@ const struct ieee80211_ops mt7996_ops = {
+ .unassign_vif_chanctx = mt7996_unassign_vif_chanctx,
+ .switch_vif_chanctx = mt7996_switch_vif_chanctx,
+ .change_vif_links = mt7996_change_vif_links,
++ .change_sta_links = mt7996_change_sta_links,
+ };
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 0eccc112d..ed854b473 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2425,6 +2425,123 @@ out:
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+ }
+
++static void
++mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
++ struct ieee80211_sta *sta)
++{
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct sta_rec_mld_setup *mld_setup;
++ struct mld_setup_link *mld_setup_link;
++ struct mt7996_link_sta *mlink;
++ struct mt7996_bss_conf *mconf;
++ struct tlv *tlv;
++ unsigned long valid_links = sta->valid_links;
++ unsigned int link_id;
++
++ mlink = mlink_dereference_protected(msta, msta->pri_link);
++ if (!mlink)
++ return;
++
++ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MLD,
++ sizeof(*mld_setup) +
++ sizeof(struct mld_setup_link) *
++ hweight16(sta->valid_links));
++
++ mld_setup = (struct sta_rec_mld_setup *)tlv;
++ memcpy(mld_setup->mld_addr, sta->addr, ETH_ALEN);
++ mld_setup->setup_wcid = cpu_to_le16(mlink->wcid.idx);
++ mld_setup->primary_id = cpu_to_le16(mlink->wcid.idx);
++ if (msta->sec_link != msta->pri_link) {
++ mlink = mlink_dereference_protected(msta, msta->sec_link);
++ if (!mlink)
++ return;
++ }
++ mld_setup->seconed_id = cpu_to_le16(mlink->wcid.idx);
++ mld_setup->link_num = hweight16(sta->valid_links);
++
++ mld_setup_link = (struct mld_setup_link *)mld_setup->link_info;
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ mlink = mlink_dereference_protected(msta, link_id);
++ mconf = mconf_dereference_protected(msta->vif, link_id);
++
++ mld_setup_link->wcid = cpu_to_le16(mlink->wcid.idx);
++ mld_setup_link->bss_idx = mconf->mt76.idx;
++ mld_setup_link++;
++ }
++}
++
++static void
++mt7996_mcu_sta_eht_mld_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
++ struct ieee80211_sta *sta)
++{
++ struct sta_rec_eht_mld *eht_mld;
++ struct tlv *tlv;
++ int i;
++
++ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_EHT_MLD, sizeof(*eht_mld));
++ eht_mld = (struct sta_rec_eht_mld *)tlv;
++
++ for (i = 0; i < ARRAY_SIZE(eht_mld->str_cap); i++)
++ eht_mld->str_cap[i] = 0x7;
++ /* TODO:
++ eht_mld->nsep = ;
++ eht_mld->eml_cap = cpu_to_le16()
++ */
++}
++
++int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta, unsigned long add)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ unsigned int link_id;
++
++ if (!sta->mlo)
++ return 0;
++
++ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
++ struct sk_buff *skb;
++ int ret;
++
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
++ &mlink->wcid,
++ MT7996_STA_UPDATE_MAX_SIZE);
++ if (IS_ERR(skb))
++ return PTR_ERR(skb);
++ /* starec mld setup */
++ mt7996_mcu_sta_mld_setup_tlv(dev, skb, sta);
++ /* starec eht mld */
++ mt7996_mcu_sta_eht_mld_tlv(dev, skb, sta);
++ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
++ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
++ if (ret)
++ return ret;
++ }
++ return 0;
++}
++int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink)
++{
++ struct sk_buff *skb;
++
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76,
++ &mconf->mt76,
++ &mlink->wcid,
++ MT7996_STA_UPDATE_MAX_SIZE);
++ if (IS_ERR(skb))
++ return PTR_ERR(skb);
++
++ mt76_connac_mcu_add_tlv(skb, STA_REC_MLD_TEARDOWN, sizeof(struct tlv));
++
++ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
++ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
++}
++
+ static int
+ mt7996_mcu_sta_key_tlv(struct mt76_wcid *wcid,
+ struct sk_buff *skb,
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index 814072e3a..ee36cf5ed 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -698,6 +698,35 @@ struct sta_rec_hdr_trans {
+ u8 mesh;
+ } __packed;
+
++struct sta_rec_mld_setup {
++ __le16 tag;
++ __le16 len;
++ u8 mld_addr[ETH_ALEN];
++ __le16 primary_id;
++ __le16 seconed_id;
++ __le16 setup_wcid;
++ u8 link_num;
++ u8 info;
++ u8 __rsv[2];
++ u8 link_info[];
++} __packed;
++
++struct mld_setup_link {
++ __le16 wcid;
++ u8 bss_idx;
++ u8 __rsv[1];
++} __packed;
++
++struct sta_rec_eht_mld {
++ __le16 tag;
++ __le16 len;
++ u8 nsep;
++ u8 __rsv1[2];
++ u8 str_cap[__MT_MAX_BAND];
++ __le16 eml_cap;
++ u8 __rsv2[4];
++} __packed;
++
+ struct hdr_trans_en {
+ __le16 tag;
+ __le16 len;
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index ed8c82e8c..913aff173 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -329,6 +329,8 @@ struct mt7996_sta {
+ struct mt7996_link_sta __rcu *link[IEEE80211_MLD_MAX_NUM_LINKS];
+
+ struct mt7996_vif *vif;
++ u8 pri_link;
++ u8 sec_link;
+ };
+
+ struct mt7996_bss_conf {
+@@ -856,6 +858,9 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+ struct ieee80211_link_sta *link_sta,
+ struct mt7996_link_sta *mlink, bool enable, bool newly);
++int mt7996_mcu_teardown_mld_sta(struct mt7996_dev *dev,
++ struct mt7996_bss_conf *mconf,
++ struct mt7996_link_sta *mlink);
+ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool add);
+@@ -879,6 +884,8 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
+ struct mt7996_bss_conf *mconf,
+ struct ieee80211_link_sta *link_sta,
+ struct mt7996_link_sta *mlink, bool changed);
++int mt7996_mcu_add_mld_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta, unsigned long add);
+ int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef);
+ int mt7996_mcu_set_chan_info(struct mt7996_phy *phy, u16 tag);
+ int mt7996_mcu_set_tx(struct mt7996_dev *dev, struct mt7996_bss_conf *mconf);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0092-wifi-mt76-mt7996-introduce-mt7996_band_phy-for-ch-ba.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0092-wifi-mt76-mt7996-introduce-mt7996_band_phy-for-ch-ba.patch
new file mode 100644
index 0000000..8e8cfb9
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0092-wifi-mt76-mt7996-introduce-mt7996_band_phy-for-ch-ba.patch
@@ -0,0 +1,271 @@
+From 04384a0b4762de5741c6220aba3b0500e260d8a2 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 1 Dec 2023 16:01:53 +0800
+Subject: [PATCH 092/116] wifi: mt76: mt7996: introduce mt7996_band_phy() for
+ ch band and phy mapping
+
+For MLO devices, one ieee80211_hw can be mapped to several bands, and
+thus several mt76_phy. Add mt7996_band_phy() to temporarily do the
+mapping.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/main.c | 149 +++++++++++++++++++++++++++++-------------------
+ mt7996/mt7996.h | 22 +++++++
+ 2 files changed, 112 insertions(+), 59 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index b193e638e..435815e9a 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -41,9 +41,8 @@ static void mt7996_testmode_disable_all(struct mt7996_dev *dev)
+ int mt7996_run(struct ieee80211_hw *hw)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ bool running;
+- int ret;
++ int band, ret;
+
+ running = mt7996_dev_running(dev);
+ if (!running) {
+@@ -62,66 +61,76 @@ int mt7996_run(struct ieee80211_hw *hw)
+
+ mt7996_testmode_disable_all(dev);
+
+- mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
++ for (band = 0; band < NUM_NL80211_BANDS; band++) {
++ struct mt7996_phy *phy;
+
+- ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
+- if (ret)
+- goto out;
++ if (!hw->wiphy->bands[band])
++ continue;
+
+- ret = mt7996_mcu_set_radio_en(phy, true);
+- if (ret)
+- goto out;
++ phy = mt7996_band_phy(hw, band);
+
+- ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH);
+- if (ret)
+- goto out;
++ if (!phy || test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
++ continue;
+
+- /* set a parking channel */
+- ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
+- if (ret)
+- goto out;
++ mt7996_mac_enable_nf(dev, phy->mt76->band_idx);
+
+- ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
+- if (ret)
+- goto out;
++ ret = mt7996_mcu_set_rts_thresh(phy, 0x92b);
++ if (ret)
++ goto out;
+
+- ret = mt7996_mcu_set_thermal_protect(phy, true);
+- if (ret)
+- goto out;
++ ret = mt7996_mcu_set_radio_en(phy, true);
++ if (ret)
++ goto out;
+
+- ret = mt7996_mcu_set_scs(phy, SCS_ENABLE);
+- if (ret)
+- goto out;
++ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH);
++ if (ret)
++ goto out;
+
+-#ifdef CONFIG_MTK_DEBUG
+- phy->sr_enable = true;
+- phy->enhanced_sr_enable = true;
+- phy->thermal_protection_enable = true;
++ /* set a parking channel */
++ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_SWITCH);
++ if (ret)
++ goto out;
+
+- ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
+- dev->dbg.sku_disable ? 0 : phy->sku_limit_en);
++ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
++ if (ret)
++ goto out;
++
++ ret = mt7996_mcu_set_thermal_protect(phy, true);
++ if (ret)
++ goto out;
++
++ ret = mt7996_mcu_set_scs(phy, SCS_ENABLE);
++ if (ret)
++ goto out;
+
+- ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
+- dev->dbg.sku_disable ? 0 : phy->sku_path_en);
++#ifdef CONFIG_MTK_DEBUG
++ phy->sr_enable = true;
++ phy->enhanced_sr_enable = true;
++ phy->thermal_protection_enable = true;
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
++ dev->dbg.sku_disable ? 0 : phy->sku_limit_en);
++
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
++ dev->dbg.sku_disable ? 0 : phy->sku_path_en);
+ #else
+- ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
+- phy->sku_limit_en);
+- ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
+- phy->sku_path_en);
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
++ phy->sku_limit_en);
++ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
++ phy->sku_path_en);
+ #endif
+- if (ret)
+- goto out;
+-
+- set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
++ if (ret)
++ goto out;
+
+- ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+- MT7996_WATCHDOG_TIME);
++ set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+- ieee80211_queue_delayed_work(mt76_hw(dev), &dev->scs_work, HZ);
++ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
++ MT7996_WATCHDOG_TIME);
+
+- if (!running)
+- mt7996_mac_reset_counters(phy);
++ if (!running)
++ mt7996_mac_reset_counters(phy);
++ }
+
++ ieee80211_queue_delayed_work(mt76_hw(dev), &dev->scs_work, HZ);
+ out:
+ return ret;
+ }
+@@ -143,18 +152,29 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ static void mt7996_stop(struct ieee80211_hw *hw)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ int band;
+
+- cancel_delayed_work_sync(&phy->mt76->mac_work);
+ cancel_delayed_work_sync(&dev->scs_work);
+
+- mutex_lock(&dev->mt76.mutex);
++ for (band = 0; band < NUM_NL80211_BANDS; band++) {
++ struct mt7996_phy *phy;
+
+- mt7996_mcu_set_radio_en(phy, false);
++ if (!hw->wiphy->bands[band])
++ continue;
+
+- clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
++ phy = mt7996_band_phy(hw, band);
+
+- mutex_unlock(&dev->mt76.mutex);
++ if (!phy || !test_bit(MT76_STATE_RUNNING, &phy->mt76->state) ||
++ (phy->chanctx && phy->chanctx->nbss_assigned))
++ continue;
++
++ cancel_delayed_work_sync(&phy->mt76->mac_work);
++
++ mutex_lock(&dev->mt76.mutex);
++ mt7996_mcu_set_radio_en(phy, false);
++ clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
++ mutex_unlock(&dev->mt76.mutex);
++ }
+ }
+
+ static inline int get_free_idx(u32 mask, u8 start, u8 end)
+@@ -2057,7 +2077,7 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_scan_request *hw_req)
+ {
+ struct cfg80211_scan_request *req = &hw_req->req;
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_phy *phy = mt7996_band_phy(hw, req->channels[0]->band);
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ if (WARN_ON(phy->scan_req || phy->scan_chan)) {
+@@ -2079,19 +2099,30 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ static void
+ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ {
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ int band;
+
+- cancel_delayed_work_sync(&phy->scan_work);
++ for (band = 0; band < NUM_NL80211_BANDS; band++) {
++ struct mt7996_phy *phy;
+
+- mutex_lock(&phy->dev->mt76.mutex);
+- mt7996_scan_complete(phy, true);
+- mutex_unlock(&phy->dev->mt76.mutex);
++ if (!hw->wiphy->bands[band])
++ continue;
++
++ phy = mt7996_band_phy(hw, band);
++ if (!(test_bit(MT76_SCANNING, &phy->mt76->state)))
++ continue;
++
++ cancel_delayed_work_sync(&phy->scan_work);
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ mt7996_scan_complete(phy, true);
++ mutex_unlock(&phy->dev->mt76.mutex);
++ }
+ }
+
+ static int
+ mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
+ {
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_phy *phy = mt7996_band_phy(hw, conf->def.chan->band);
+ struct mt7996_chanctx *ctx = mt7996_chanctx_get(conf);
+ int ret;
+
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 913aff173..4c090badf 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -788,6 +788,28 @@ mt7996_get_background_radar_cap(struct mt7996_dev *dev)
+ return 1;
+ }
+
++static inline struct mt7996_phy *
++mt7996_band_phy(struct ieee80211_hw *hw, enum nl80211_band band)
++{
++ struct mt76_phy *phy = hw->priv;
++
++ if (!(hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
++ return phy->priv;
++
++ /* TODO: mlo: temporarily hardcode */
++ if (band == NL80211_BAND_6GHZ)
++ phy = phy->dev->phys[MT_BAND2];
++ else if (band == NL80211_BAND_5GHZ)
++ phy = phy->dev->phys[MT_BAND1];
++ else
++ phy = phy->dev->phys[MT_BAND0];
++
++ if (!phy)
++ phy = hw->priv;
++
++ return phy->priv;
++}
++
+ static inline struct mt7996_chanctx *
+ mt7996_chanctx_get(struct ieee80211_chanctx_conf *ctx)
+ {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0093-wifi-mt76-mt7996-rework-ieee80211_ops-callbacks-for-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0093-wifi-mt76-mt7996-rework-ieee80211_ops-callbacks-for-.patch
new file mode 100644
index 0000000..9c04e89
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0093-wifi-mt76-mt7996-rework-ieee80211_ops-callbacks-for-.patch
@@ -0,0 +1,501 @@
+From 29127cd132bbeca563f105bb43fb6e5855cc3572 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 1 Dec 2023 17:26:43 +0800
+Subject: [PATCH 093/116] wifi: mt76: mt7996: rework ieee80211_ops callbacks
+ for link consideration
+
+Extend ieee80211 callback functions to support multi-link operation.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/main.c | 313 ++++++++++++++++++++++++++++++++------------------
+ 1 file changed, 204 insertions(+), 109 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 435815e9a..3bd97d4aa 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -568,7 +568,6 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ struct ieee80211_key_conf *key)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv :
+ &mvif->sta;
+@@ -578,70 +577,77 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ u8 *wcid_keyidx;
+ int idx = key->keyidx;
+ int err = 0;
++ unsigned long add;
++ unsigned int link_id;
+
+- /* The hardware does not support per-STA RX GTK, fallback
+- * to software mode for these.
+- */
+- if ((vif->type == NL80211_IFTYPE_ADHOC ||
+- vif->type == NL80211_IFTYPE_MESH_POINT) &&
+- (key->cipher == WLAN_CIPHER_SUITE_TKIP ||
+- key->cipher == WLAN_CIPHER_SUITE_CCMP) &&
+- !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE))
+- return -EOPNOTSUPP;
++ if (key->link_id >= 0) {
++ add = BIT(key->link_id);
++ } else {
++ if (sta)
++ add = sta->valid_links ?: BIT(0);
++ else
++ add = vif->valid_links ?: BIT(0);
++ }
+
+ mutex_lock(&dev->mt76.mutex);
+- conf = link_conf_dereference_protected(vif, 0);
+- mconf = mconf_dereference_protected(mvif, 0);
+- mlink = mlink_dereference_protected(msta, 0);
+- wcid_keyidx = &mlink->wcid.hw_key_idx;
+-
+- /* fall back to sw encryption for unsupported ciphers */
+- switch (key->cipher) {
+- case WLAN_CIPHER_SUITE_TKIP:
+- case WLAN_CIPHER_SUITE_CCMP:
+- case WLAN_CIPHER_SUITE_CCMP_256:
+- case WLAN_CIPHER_SUITE_GCMP:
+- case WLAN_CIPHER_SUITE_GCMP_256:
+- case WLAN_CIPHER_SUITE_SMS4:
+- break;
+- case WLAN_CIPHER_SUITE_AES_CMAC:
+- case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+- case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+- case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+- if (key->keyidx == 6 || key->keyidx == 7) {
+- wcid_keyidx = &wcid->hw_key_idx2;
+- key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
++
++ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
++ conf = link_conf_dereference_protected(vif, link_id);
++ mconf = mconf_dereference_protected(mvif, link_id);
++ mlink = mlink_dereference_protected(msta, link_id);
++ wcid_keyidx = &mlink->wcid.hw_key_idx;
++
++ if (!conf || !mconf || !mlink)
++ continue;
++
++ /* fall back to sw encryption for unsupported ciphers */
++ switch (key->cipher) {
++ case WLAN_CIPHER_SUITE_TKIP:
++ case WLAN_CIPHER_SUITE_CCMP:
++ case WLAN_CIPHER_SUITE_CCMP_256:
++ case WLAN_CIPHER_SUITE_GCMP:
++ case WLAN_CIPHER_SUITE_GCMP_256:
++ case WLAN_CIPHER_SUITE_SMS4:
+ break;
++ case WLAN_CIPHER_SUITE_AES_CMAC:
++ case WLAN_CIPHER_SUITE_BIP_CMAC_256:
++ case WLAN_CIPHER_SUITE_BIP_GMAC_128:
++ case WLAN_CIPHER_SUITE_BIP_GMAC_256:
++ if (key->keyidx == 6 || key->keyidx == 7) {
++ wcid_keyidx = &mlink->wcid.hw_key_idx2;
++ key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIE;
++ break;
++ }
++ fallthrough;
++ case WLAN_CIPHER_SUITE_WEP40:
++ case WLAN_CIPHER_SUITE_WEP104:
++ default:
++ mutex_unlock(&dev->mt76.mutex);
++ return -EOPNOTSUPP;
+ }
+- fallthrough;
+- case WLAN_CIPHER_SUITE_WEP40:
+- case WLAN_CIPHER_SUITE_WEP104:
+- default:
+- mutex_unlock(&dev->mt76.mutex);
+- return -EOPNOTSUPP;
+- }
+
+- if (cmd == SET_KEY && !sta && !mconf->mt76.cipher) {
+- mconf->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher);
+- mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, true);
+- }
++ if (cmd == SET_KEY && !sta && !mconf->mt76.cipher) {
++ mconf->mt76.cipher = mt76_connac_mcu_get_cipher(key->cipher);
++ mt7996_mcu_add_bss_info(mconf->phy, conf, mconf, mlink, true);
++ }
+
+- if (cmd == SET_KEY) {
+- *wcid_keyidx = idx;
+- } else {
+- if (idx == *wcid_keyidx)
+- *wcid_keyidx = -1;
+- goto out;
+- }
++ if (cmd == SET_KEY) {
++ *wcid_keyidx = idx;
++ } else {
++ if (idx == *wcid_keyidx)
++ *wcid_keyidx = -1;
++ goto out;
++ }
+
+- mt76_wcid_key_setup(&dev->mt76, &mlink->wcid, key);
++ mt76_wcid_key_setup(&dev->mt76, &mlink->wcid, key);
+
+- if (key->keyidx == 6 || key->keyidx == 7)
+- err = mt7996_mcu_bcn_prot_enable(dev, conf, mconf, mlink, key);
+- else
+- err = mt7996_mcu_add_key(&dev->mt76, mconf, key,
+- MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
+- &mlink->wcid, cmd);
++ if (key->keyidx == 6 || key->keyidx == 7)
++ err = mt7996_mcu_bcn_prot_enable(dev, conf, mconf, mlink, key);
++ else
++ err = mt7996_mcu_add_key(&dev->mt76, mconf, key,
++ MCU_WMWA_UNI_CMD(STA_REC_UPDATE),
++ &mlink->wcid, cmd);
++ }
+ out:
+ mutex_unlock(&dev->mt76.mutex);
+
+@@ -697,7 +703,11 @@ mt7996_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ };
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
++ mconf = mconf_dereference_protected(mvif, link_id);
++ if (!mconf) {
++ mutex_unlock(&dev->mt76.mutex);
++ return -EINVAL;
++ }
+
+ /* firmware uses access class index */
+ mconf->queue_params[mq_to_aci[queue]] = *params;
+@@ -840,19 +850,26 @@ mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_bss_conf *conf,
+ static void mt7996_vif_cfg_changed(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif, u64 changed)
+ {
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+
+ mutex_lock(&dev->mt76.mutex);
+
+ if (changed & BSS_CHANGED_ASSOC && vif->cfg.assoc) {
+- struct ieee80211_bss_conf *conf = &vif->bss_conf;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf = mconf_dereference_protected(mvif, 0);
+- struct mt7996_link_sta *mlink = mlink_dereference_protected(&mvif->sta, 0);
+-
+- mt7996_mcu_add_bss_info(phy, conf, mconf, mlink, true);
+- mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, true, false);
++ unsigned long valid_links = vif->valid_links ?: BIT(0);
++ unsigned int link_id;
++
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct ieee80211_bss_conf *conf =
++ link_conf_dereference_protected(vif, link_id);
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(&mvif->sta, link_id);
++
++ mt7996_mcu_add_bss_info(mconf->phy, conf, mconf, mlink, true);
++ mt7996_mcu_add_sta(dev, conf, mconf, NULL, mlink, true, false);
++ }
+ }
+
+ mutex_unlock(&dev->mt76.mutex);
+@@ -871,8 +888,13 @@ static void mt7996_link_info_changed(struct ieee80211_hw *hw,
+
+ mutex_lock(&dev->mt76.mutex);
+
+- mconf = mconf_dereference_protected(mvif, 0);
+- mlink = mlink_dereference_protected(&mvif->sta, 0);
++ mconf = mconf_dereference_protected(mvif, info->link_id);
++ mlink = mlink_dereference_protected(&mvif->sta, info->link_id);
++ if (!mconf || !mlink)
++ goto out;
++
++ if (mconf->phy)
++ phy = mconf->phy;
+ /* station mode uses BSSID to map the wlan entry to a peer,
+ * and then peer references bss_info_rfch to set bandwidth cap.
+ */
+@@ -928,6 +950,7 @@ static void mt7996_link_info_changed(struct ieee80211_hw *hw,
+ if (changed & BSS_CHANGED_MU_GROUPS)
+ mt7996_update_mu_group(hw, info, mconf);
+
++out:
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -938,13 +961,22 @@ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf;
+- struct ieee80211_bss_conf *conf;
++ struct mt7996_phy *phy = mt7996_band_phy(hw, chandef->chan->band);
++ unsigned long valid_links = vif->valid_links ?: BIT(0);
++ unsigned int link_id;
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
+- conf = link_conf_dereference_protected(vif, 0);
+- mt7996_mcu_add_beacon(hw, conf, mconf, true);
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct ieee80211_bss_conf *conf =
++ link_conf_dereference_protected(vif, link_id);
++
++ if (!mconf || phy != mconf->phy)
++ continue;
++
++ mt7996_mcu_add_beacon(hw, conf, mconf, true);
++ }
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -1216,34 +1248,74 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
+ }
+
++static void
++mt7996_sta_pre_rcu_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_sta *sta)
++{
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ unsigned long rem = sta->valid_links ?: BIT(0);
++ unsigned int link_id;
++
++ mutex_lock(&dev->mt76.mutex);
++ spin_lock_bh(&dev->mt76.status_lock);
++ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
++
++ rcu_assign_pointer(dev->mt76.wcid[mlink->wcid.idx], NULL);
++ }
++ spin_unlock_bh(&dev->mt76.status_lock);
++ mutex_unlock(&dev->mt76.mutex);
++}
++
+ static void mt7996_tx(struct ieee80211_hw *hw,
+ struct ieee80211_tx_control *control,
+ struct sk_buff *skb)
+ {
+- struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt76_phy *mphy = hw->priv;
++ struct mt76_phy *mphy;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_vif *vif = info->control.vif;
+- struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+- struct mt7996_link_sta *mlink;
++ struct mt76_wcid *wcid;
++ struct mt7996_vif *mvif;
++ struct mt7996_sta *msta;
+
+ if (control->sta) {
+- struct mt7996_sta *msta;
+-
+ msta = (struct mt7996_sta *)control->sta->drv_priv;
+- mlink = rcu_dereference(msta->link[0]);
+- wcid = &mlink->wcid;
++ mvif = msta->vif;
++ } else if (vif) {
++ mvif = (struct mt7996_vif *)vif->drv_priv;
++ msta = &mvif->sta;
+ }
+
+- if (vif && !control->sta) {
+- struct mt7996_vif *mvif;
++ rcu_read_lock();
++ if (mvif && msta) {
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
++
++ u8 link_id = u32_get_bits(info->control.flags,
++ IEEE80211_TX_CTRL_MLO_LINK);
+
+- mvif = (struct mt7996_vif *)vif->drv_priv;
+- mlink = rcu_dereference(mvif->sta.link[0]);
++ if (link_id >= IEEE80211_LINK_UNSPECIFIED)
++ link_id = mvif->master_link_id;
++
++ mconf = rcu_dereference(mvif->link[link_id]);
++ mlink = rcu_dereference(msta->link[link_id]);
++
++ if (!mconf || !mlink)
++ goto unlock;
++
++ mphy = mconf->phy->mt76;
+ wcid = &mlink->wcid;
++ } else {
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++
++ mphy = hw->priv;
++ wcid = &dev->mt76.global_wcid;
+ }
+
+ mt76_tx(mphy, control->sta, wcid, skb);
++ rcu_read_unlock();
+ }
+
+ static int mt7996_set_rts_threshold(struct ieee80211_hw *hw, u32 val)
+@@ -1279,7 +1351,7 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ mtxq = (struct mt76_txq *)txq->drv_priv;
+
+ mutex_lock(&dev->mt76.mutex);
+- mlink = mlink_dereference_protected(msta, 0);
++ mlink = mlink_dereference_protected(msta, msta->pri_link);
+ switch (action) {
+ case IEEE80211_AMPDU_RX_START:
+ mt76_rx_aggr_start(&dev->mt76, &mlink->wcid, tid, ssn,
+@@ -1494,7 +1566,7 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
+
+ /* TODO: support per-link rate report */
+ mutex_lock(&dev->mt76.mutex);
+- mlink = mlink_dereference_protected(msta, 0);
++ mlink = mlink_dereference_protected(msta, msta->pri_link);
+ if (!mlink)
+ goto out;
+
+@@ -1554,7 +1626,7 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
+ u32 *changed = data;
+
+ rcu_read_lock();
+- mlink = rcu_dereference(msta->link[0]);
++ mlink = rcu_dereference(msta->link[msta->pri_link]);
+
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ mlink->changed |= *changed;
+@@ -1621,19 +1693,26 @@ static void mt7996_sta_set_4addr(struct ieee80211_hw *hw,
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_bss_conf *mconf;
+- struct mt7996_link_sta *mlink;
++ unsigned long valid_links = sta->valid_links ?: BIT(0);
++ unsigned int link_id;
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
+- mlink = mlink_dereference_protected(msta, 0);
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
+
+- if (enabled)
+- set_bit(MT_WCID_FLAG_4ADDR, &mlink->wcid.flags);
+- else
+- clear_bit(MT_WCID_FLAG_4ADDR, &mlink->wcid.flags);
++ if (!mconf || !mlink)
++ continue;
++
++ if (enabled)
++ set_bit(MT_WCID_FLAG_4ADDR, &mlink->wcid.flags);
++ else
++ clear_bit(MT_WCID_FLAG_4ADDR, &mlink->wcid.flags);
+
+- mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
++ mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
++ }
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -1645,19 +1724,26 @@ static void mt7996_sta_set_decap_offload(struct ieee80211_hw *hw,
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_bss_conf *mconf;
+- struct mt7996_link_sta *mlink;
++ unsigned long valid_links = sta->valid_links ?: BIT(0);
++ unsigned int link_id;
+
+ mutex_lock(&dev->mt76.mutex);
+- mconf = mconf_dereference_protected(mvif, 0);
+- mlink = mlink_dereference_protected(msta, 0);
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
+
+- if (enabled)
+- set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
+- else
+- clear_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
++ if (!mconf || !mlink)
++ continue;
++
++ if (enabled)
++ set_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
++ else
++ clear_bit(MT_WCID_FLAG_HDR_TRANS, &mlink->wcid.flags);
+
+- mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
++ mt7996_mcu_wtbl_update_hdr_trans(dev, vif, mconf, mlink);
++ }
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+@@ -1790,9 +1876,13 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
+ {
+ struct mt76_ethtool_worker_info *wi = wi_data;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_link_sta *mlink = &msta->deflink;
++ struct mt7996_link_sta *mlink;
++ struct mt7996_bss_conf *mconf;
++
++ mlink = mlink_dereference_protected(msta, msta->pri_link);
++ mconf = mconf_dereference_protected(msta->vif, msta->pri_link);
+
+- if (msta->vif->deflink.mt76.idx != wi->idx)
++ if (mconf->mt76.idx != wi->idx)
+ return;
+
+ mt76_ethtool_worker(wi, &mlink->wcid.stats, true);
+@@ -2024,12 +2114,13 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ struct net_device_path *path)
+ {
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf = &mvif->deflink;
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+- struct mt7996_link_sta *mlink = &msta->deflink;
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
++ u8 link_id;
+
+ if (dev->hif2) {
+ switch (dev->option_type) {
+@@ -2049,6 +2140,10 @@ mt7996_net_fill_forward_path(struct ieee80211_hw *hw,
+ if (!mtk_wed_device_active(wed))
+ return -ENODEV;
+
++ link_id = msta->pri_link;
++ mconf = rcu_dereference(mvif->link[link_id]);
++ mlink = rcu_dereference(msta->link[link_id]);
++
+ if (mlink->wcid.idx > MT7996_WTBL_STA)
+ return -EIO;
+
+@@ -2380,7 +2475,7 @@ const struct ieee80211_ops mt7996_ops = {
+ .vif_cfg_changed = mt7996_vif_cfg_changed,
+ .link_info_changed = mt7996_link_info_changed,
+ .sta_state = mt76_sta_state,
+- .sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
++ .sta_pre_rcu_remove = mt7996_sta_pre_rcu_remove,
+ .sta_rc_update = mt7996_sta_rc_update,
+ .set_key = mt7996_set_key,
+ .ampdu_action = mt7996_ampdu_action,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0094-wifi-mt76-mt7996-rework-TXD-for-multi-link-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0094-wifi-mt76-mt7996-rework-TXD-for-multi-link-support.patch
new file mode 100644
index 0000000..0519b1b
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0094-wifi-mt76-mt7996-rework-TXD-for-multi-link-support.patch
@@ -0,0 +1,203 @@
+From dba16ea5f62b21ec911c67a7ca1539004c5e5f3b Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 4 Dec 2023 11:25:54 +0800
+Subject: [PATCH 094/116] wifi: mt76: mt7996: rework TXD for multi-link support
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mac.c | 88 +++++++++++++++++++++++++++++++++++--------------
+ mt7996/mt7996.h | 9 +++++
+ 2 files changed, 73 insertions(+), 24 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 3cff43d6b..0fa3266cc 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -621,9 +621,8 @@ mt7996_mac_write_txwi_8023(struct mt7996_dev *dev, __le32 *txwi,
+ u32 val;
+
+ if (wcid->sta) {
+- struct ieee80211_sta *sta;
++ struct ieee80211_sta *sta = wcid_to_sta(wcid);
+
+- sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
+ wmm = sta->wme;
+ }
+
+@@ -724,6 +723,10 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
+ txwi[3] |= cpu_to_le32(val);
+ txwi[3] &= ~cpu_to_le32(MT_TXD3_HW_AMSDU);
+ }
++
++ if (ieee80211_vif_is_mld(info->control.vif) &&
++ (multicast || unlikely(skb->protocol == cpu_to_be16(ETH_P_PAE))))
++ txwi[5] |= cpu_to_le32(MT_TXD5_FL);
+ }
+
+ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+@@ -733,10 +736,12 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_vif *vif = info->control.vif;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
+ u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+ u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
++ u8 link_id;
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+- struct mt76_vif *mvif;
+ u16 tx_count = 15;
+ u32 val;
+ bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
+@@ -744,11 +749,16 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ bool beacon = !!(changed & (BSS_CHANGED_BEACON |
+ BSS_CHANGED_BEACON_ENABLED)) && (!inband_disc);
+
+- mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
+- if (mvif) {
+- omac_idx = mvif->omac_idx;
+- wmm_idx = mvif->wmm_idx;
+- band_idx = mvif->band_idx;
++ if (likely(wcid != &dev->mt76.global_wcid))
++ link_id = wcid->link_id;
++ else
++ link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK);
++
++ mconf = rcu_dereference(mvif->link[link_id]);
++ if (mconf) {
++ omac_idx = mconf->mt76.omac_idx;
++ wmm_idx = mconf->mt76.wmm_idx;
++ band_idx = mconf->mt76.band_idx;
+ }
+
+ if (inband_disc) {
+@@ -795,7 +805,10 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ val |= MT_TXD5_TX_STATUS_HOST;
+ txwi[5] = cpu_to_le32(val);
+
+- val = MT_TXD6_DIS_MAT | MT_TXD6_DAS;
++ val = MT_TXD6_DAS;
++ if ((q_idx >= MT_LMAC_ALTX0 && q_idx <= MT_LMAC_BCN0))
++ val |= MT_TXD6_DIS_MAT;
++
+ if (is_mt7996(&dev->mt76))
+ val |= FIELD_PREP(MT_TXD6_MSDU_CNT, 1);
+ else
+@@ -814,16 +827,18 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ is_multicast_ether_addr(hdr->addr1);
+ u8 idx = MT7996_BASIC_RATES_TBL;
+
+- if (mvif) {
+- if (mcast && mvif->mcast_rates_idx)
+- idx = mvif->mcast_rates_idx;
+- else if (beacon && mvif->beacon_rates_idx)
+- idx = mvif->beacon_rates_idx;
++ if (mconf) {
++ if (mcast && mconf->mt76.mcast_rates_idx)
++ idx = mconf->mt76.mcast_rates_idx;
++ else if (beacon && mconf->mt76.beacon_rates_idx)
++ idx = mconf->mt76.beacon_rates_idx;
+ else
+- idx = mvif->basic_rates_idx;
++ idx = mconf->mt76.basic_rates_idx;
+ }
+
+ val = FIELD_PREP(MT_TXD6_TX_RATE, idx) | MT_TXD6_FIXED_BW;
++ if (mcast)
++ val |= MT_TXD6_DIS_MAT;
+ txwi[6] |= cpu_to_le32(val);
+ txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
+ }
+@@ -839,17 +854,48 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
+ struct ieee80211_key_conf *key = info->control.hw_key;
+ struct ieee80211_vif *vif = info->control.vif;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_sta *msta;
++ struct mt7996_bss_conf *mconf;
+ struct mt76_connac_txp_common *txp;
+ struct mt76_txwi_cache *t;
+ int id, i, pid, nbuf = tx_info->nbuf - 1;
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+ u8 *txwi = (u8 *)txwi_ptr;
++ u8 link_id;
+
+ if (unlikely(tx_info->skb->len <= ETH_HLEN))
+ return -EINVAL;
+
+- if (!wcid)
+- wcid = &dev->mt76.global_wcid;
++ if (WARN_ON(!wcid))
++ return -EINVAL;
++
++ msta = sta ? (struct mt7996_sta *)sta->drv_priv : &mvif->sta;
++ if (ieee80211_is_data_qos(hdr->frame_control) && sta->mlo) {
++ if (unlikely(tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE))) {
++ link_id = msta->pri_link;
++ } else {
++ u8 tid = tx_info->skb->priority & IEEE80211_QOS_CTL_TID_MASK;
++
++ link_id = (tid % 2) ? msta->sec_link : msta->pri_link;
++ }
++ } else {
++ link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK);
++
++ if (link_id == IEEE80211_LINK_UNSPECIFIED || (sta && !sta->mlo))
++ link_id = wcid->link_id;
++ }
++
++ if (link_id != wcid->link_id) {
++ struct mt7996_link_sta *mlink = rcu_dereference(msta->link[link_id]);
++
++ if (mlink)
++ wcid = &mlink->wcid;
++ }
++
++ mconf = rcu_dereference(mvif->link[wcid->link_id]);
++ if (!mconf)
++ return -ENOLINK;
+
+ t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
+ t->skb = tx_info->skb;
+@@ -894,13 +940,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
+ txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
+
+- if (vif) {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf = &mvif->deflink;
+-
+- txp->fw.bss_idx = mconf->mt76.idx;
+- }
+-
++ txp->fw.bss_idx = mconf->mt76.idx;
+ txp->fw.token = cpu_to_le16(id);
+ txp->fw.rept_wds_wcid = cpu_to_le16(sta ? wcid->idx : 0xfff);
+
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 4c090badf..21a95c146 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -830,6 +830,15 @@ mlink_dereference_protected(struct mt7996_sta *msta, u8 link_id)
+ lockdep_is_held(&msta->vif->dev->mt76.mutex));
+ }
+
++static inline struct mt7996_link_sta *
++wcid_to_mlink(struct mt76_wcid *wcid)
++{
++ if (!wcid)
++ return NULL;
++
++ return container_of(wcid, struct mt7996_link_sta, wcid);
++}
++
+ extern const struct ieee80211_ops mt7996_ops;
+ extern struct pci_driver mt7996_pci_driver;
+ extern struct pci_driver mt7996_hif_driver;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0095-wifi-mt76-mt7996-rework-TXS-for-multi-link-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0095-wifi-mt76-mt7996-rework-TXS-for-multi-link-support.patch
new file mode 100644
index 0000000..6edeabe
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0095-wifi-mt76-mt7996-rework-TXS-for-multi-link-support.patch
@@ -0,0 +1,120 @@
+From 1f35388fa6214a36e5f7a4770c248a187a543019 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 4 Dec 2023 11:57:38 +0800
+Subject: [PATCH 095/116] wifi: mt76: mt7996: rework TXS for multi-link support
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mac.c | 9 +++++----
+ mt7996/main.c | 1 +
+ mt7996/mt7996.h | 28 ++++++++++++++++++++++++++++
+ 3 files changed, 34 insertions(+), 4 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 0fa3266cc..65431c7d7 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1192,7 +1192,7 @@ mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
+ struct ieee80211_sta *sta;
+ u8 tid;
+
+- sta = container_of((void *)wcid, struct ieee80211_sta, drv_priv);
++ sta = wcid_to_sta(wcid);
+ tid = FIELD_GET(MT_TXS0_TID, txs);
+ ieee80211_refresh_tx_agg_session_timer(sta, tid);
+ }
+@@ -1310,9 +1310,10 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
+ struct mt76_wcid *wcid;
+ __le32 *txs_data = data;
+ u16 wcidx;
+- u8 pid;
++ u8 band, pid;
+
+ wcidx = le32_get_bits(txs_data[2], MT_TXS2_WCID);
++ band = le32_get_bits(txs_data[2], MT_TXS2_BAND);
+ pid = le32_get_bits(txs_data[3], MT_TXS3_PID);
+
+ if (pid < MT_PACKET_ID_NO_SKB)
+@@ -1323,7 +1324,7 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
+
+ rcu_read_lock();
+
+- wcid = rcu_dereference(dev->mt76.wcid[wcidx]);
++ wcid = mt7996_get_link_wcid(dev, wcidx, band);
+ if (!wcid)
+ goto out;
+
+@@ -1332,7 +1333,7 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
+ if (!wcid->sta)
+ goto out;
+
+- mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ mlink = wcid_to_mlink(wcid);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&mlink->wcid.poll_list))
+ list_add_tail(&mlink->wcid.poll_list, &dev->mt76.sta_poll_list);
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 3bd97d4aa..aceb77ab2 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -2317,6 +2317,7 @@ mt7996_assign_vif_chanctx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ mconf = mconf_dereference_protected(mvif, link_id);
+ mconf->chanctx = ctx;
+ ctx->nbss_assigned++;
++ mvif->band_to_link[phy->mt76->band_idx] = link_id;
+
+ if (mt7996_hw_phy(hw) == phy)
+ mvif->master_link_id = link_id;
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 21a95c146..c6ca00f1a 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -357,6 +357,8 @@ struct mt7996_vif {
+ u8 master_link_id;
+ u8 group_mld_id;
+ u8 mld_remap_id;
++
++ u8 band_to_link[__MT_MAX_BAND];
+ };
+
+ /* crash-dump */
+@@ -839,6 +841,32 @@ wcid_to_mlink(struct mt76_wcid *wcid)
+ return container_of(wcid, struct mt7996_link_sta, wcid);
+ }
+
++static inline struct mt76_wcid *
++mt7996_get_link_wcid(struct mt7996_dev *dev, u16 idx, u8 band_idx)
++{
++ struct mt7996_link_sta *mlink;
++ struct mt76_wcid *wcid;
++ u8 link_id;
++
++ if (!idx || idx >= ARRAY_SIZE(dev->mt76.wcid))
++ return NULL;
++
++ wcid = rcu_dereference(dev->mt76.wcid[idx]);
++ if (!wcid)
++ return NULL;
++
++ if (wcid->phy_idx == band_idx)
++ return wcid;
++
++ mlink = wcid_to_mlink(wcid);
++ link_id = mlink->sta->vif->band_to_link[band_idx];
++ mlink = rcu_dereference(mlink->sta->link[link_id]);
++ if (!mlink)
++ return wcid;
++
++ return &mlink->wcid;
++}
++
+ extern const struct ieee80211_ops mt7996_ops;
+ extern struct pci_driver mt7996_pci_driver;
+ extern struct pci_driver mt7996_hif_driver;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0096-wifi-mt76-mt7996-rework-RXD-for-multi-link-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0096-wifi-mt76-mt7996-rework-RXD-for-multi-link-support.patch
new file mode 100644
index 0000000..426b18b
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0096-wifi-mt76-mt7996-rework-RXD-for-multi-link-support.patch
@@ -0,0 +1,64 @@
+From b332b97c6eadd80d210eafc4cd089163c910bf95 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 4 Dec 2023 14:50:47 +0800
+Subject: [PATCH 096/116] wifi: mt76: mt7996: rework RXD for multi-link support
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mac.c | 27 ++-------------------------
+ 1 file changed, 2 insertions(+), 25 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 65431c7d7..a32b416c4 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -51,29 +51,6 @@ static const struct mt7996_dfs_radar_spec jp_radar_specs = {
+ },
+ };
+
+-static struct mt76_wcid *mt7996_rx_get_wcid(struct mt7996_dev *dev,
+- u16 idx, bool unicast)
+-{
+- struct mt7996_link_sta *mlink;
+- struct mt76_wcid *wcid;
+-
+- if (idx >= ARRAY_SIZE(dev->mt76.wcid))
+- return NULL;
+-
+- wcid = rcu_dereference(dev->mt76.wcid[idx]);
+- if (unicast || !wcid)
+- return wcid;
+-
+- if (!wcid->sta)
+- return NULL;
+-
+- mlink = container_of(wcid, struct mt7996_link_sta, wcid);
+- if (!mlink->sta->vif)
+- return NULL;
+-
+- return &mlink->wcid;
+-}
+-
+ bool mt7996_mac_wtbl_update(struct mt7996_dev *dev, int idx, u32 mask)
+ {
+ mt76_rmw(dev, MT_WTBL_UPDATE, MT_WTBL_UPDATE_WLAN_IDX,
+@@ -376,10 +353,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+
+ unicast = FIELD_GET(MT_RXD3_NORMAL_ADDR_TYPE, rxd3) == MT_RXD3_NORMAL_U2M;
+ idx = FIELD_GET(MT_RXD1_NORMAL_WLAN_IDX, rxd1);
+- status->wcid = mt7996_rx_get_wcid(dev, idx, unicast);
++ status->wcid = mt7996_get_link_wcid(dev, idx, band_idx);
+
+ if (status->wcid) {
+- mlink = container_of(status->wcid, struct mt7996_link_sta, wcid);
++ mlink = wcid_to_mlink(status->wcid);
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ if (list_empty(&mlink->wcid.poll_list))
+ list_add_tail(&mlink->wcid.poll_list,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0097-wifi-mt76-mt7996-rework-mac-functions-for-multi-link.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0097-wifi-mt76-mt7996-rework-mac-functions-for-multi-link.patch
new file mode 100644
index 0000000..73838c5
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0097-wifi-mt76-mt7996-rework-mac-functions-for-multi-link.patch
@@ -0,0 +1,249 @@
+From 15d70608c54b7e8823589850714f396b76e39783 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 4 Dec 2023 18:31:02 +0800
+Subject: [PATCH 097/116] wifi: mt76: mt7996: rework mac functions for
+ multi-link support
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mac.c | 91 +++++++++++++++++++++++++++++++++++++---------------
+ 1 file changed, 65 insertions(+), 26 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index a32b416c4..31b916695 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -85,10 +85,11 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
+ {
+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
+ struct ethhdr *eth_hdr = (struct ethhdr *)(skb->data + hdr_gap);
+- struct mt7996_sta *msta = (struct mt7996_sta *)status->wcid;
++ struct mt7996_link_sta *mlink = (struct mt7996_link_sta *)status->wcid;
+ __le32 *rxd = (__le32 *)skb->data;
+ struct ieee80211_sta *sta;
+ struct ieee80211_vif *vif;
++ struct ieee80211_bss_conf *conf;
+ struct ieee80211_hdr hdr;
+ u16 frame_control;
+
+@@ -99,11 +100,14 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
+ if (!(le32_to_cpu(rxd[1]) & MT_RXD1_NORMAL_GROUP_4))
+ return -EINVAL;
+
+- if (!msta || !msta->vif)
++ if (!mlink->sta || !mlink->sta->vif)
+ return -EINVAL;
+
+- sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
+- vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
++ sta = wcid_to_sta(status->wcid);
++ vif = container_of((void *)mlink->sta->vif, struct ieee80211_vif, drv_priv);
++ conf = rcu_dereference(vif->link_conf[mlink->wcid.link_id]);
++ if (unlikely(!conf))
++ return -ENOLINK;
+
+ /* store the info from RXD and ethhdr to avoid being overridden */
+ frame_control = le32_get_bits(rxd[8], MT_RXD8_FRAME_CONTROL);
+@@ -116,7 +120,7 @@ static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
+ switch (frame_control & (IEEE80211_FCTL_TODS |
+ IEEE80211_FCTL_FROMDS)) {
+ case 0:
+- ether_addr_copy(hdr.addr3, vif->bss_conf.bssid);
++ ether_addr_copy(hdr.addr3, conf->bssid);
+ break;
+ case IEEE80211_FCTL_FROMDS:
+ ether_addr_copy(hdr.addr3, eth_hdr->h_source);
+@@ -955,15 +959,21 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
+ }
+
+ static void
+-mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
++mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb,
++ struct mt76_wcid *wcid)
+ {
+ struct mt7996_sta *msta;
+ struct mt7996_link_sta *mlink;
++ struct ieee80211_link_sta *link_sta;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+ u16 fc, tid;
+
+- if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
++ link_sta = rcu_dereference(sta->link[wcid->link_id]);
++ if (!link_sta)
++ return;
++
++ if (!sta->mlo && !(link_sta->ht_cap.ht_supported || link_sta->he_cap.has_he))
+ return;
+
+ tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
+@@ -987,17 +997,17 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, struct sk_buff *skb)
+ return;
+
+ msta = (struct mt7996_sta *)sta->drv_priv;
+- mlink = rcu_dereference(msta->link[0]);
++ mlink = rcu_dereference(msta->link[msta->pri_link]);
+ if (!test_and_set_bit(tid, &mlink->wcid.ampdu_state))
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+ }
+
+ static void
+ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
+- struct ieee80211_sta *sta, struct list_head *free_list)
++ struct ieee80211_sta *sta, struct mt76_wcid *wcid,
++ struct list_head *free_list)
+ {
+ struct mt76_dev *mdev = &dev->mt76;
+- struct mt76_wcid *wcid;
+ __le32 *txwi;
+ u16 wcid_idx;
+
+@@ -1007,11 +1017,10 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
+
+ txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
+ if (sta) {
+- wcid = (struct mt76_wcid *)sta->drv_priv;
+ wcid_idx = wcid->idx;
+
+ if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
+- mt7996_tx_check_aggr(sta, t->skb);
++ mt7996_tx_check_aggr(sta, t->skb, wcid);
+ } else {
+ wcid_idx = le32_get_bits(txwi[9], MT_TXD9_WLAN_IDX);
+ }
+@@ -1066,7 +1075,9 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
+ */
+ info = le32_to_cpu(*cur_info);
+ if (info & MT_TXFREE_INFO_PAIR) {
+- struct mt7996_link_sta *mlink;
++ struct mt7996_sta *msta;
++ unsigned long valid_links;
++ unsigned int link_id;
+ u16 idx;
+
+ idx = FIELD_GET(MT_TXFREE_INFO_WLAN_ID, info);
+@@ -1075,11 +1086,17 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
+ if (!sta)
+ continue;
+
+- mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ valid_links = sta->valid_links ?: BIT(0);
++ msta = (struct mt7996_sta *)sta->drv_priv;
++ /* for MLD STA, add all link's wcid to sta_poll_list */
+ spin_lock_bh(&mdev->sta_poll_lock);
+- if (list_empty(&mlink->wcid.poll_list))
+- list_add_tail(&mlink->wcid.poll_list,
+- &mdev->sta_poll_list);
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_link_sta *mlink =
++ rcu_dereference(msta->link[link_id]);
++
++ if (list_empty(&mlink->wcid.poll_list))
++ list_add_tail(&mlink->wcid.poll_list, &mdev->sta_poll_list);
++ }
+ spin_unlock_bh(&mdev->sta_poll_lock);
+ continue;
+ } else if (info & MT_TXFREE_INFO_HEADER) {
+@@ -1115,7 +1132,8 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
+ if (!txwi)
+ continue;
+
+- mt7996_txwi_free(dev, txwi, sta, &free_list);
++ mt7996_txwi_free(dev, txwi, sta, wcid, &free_list);
++ txwi->jiffies = 0;
+ }
+ }
+
+@@ -1537,19 +1555,29 @@ static void
+ mt7996_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+ struct ieee80211_hw *hw = priv;
+- struct ieee80211_bss_conf *conf = &vif->bss_conf;
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_bss_conf *mconf = &mvif->deflink;
++ unsigned long update = vif->valid_links ?: BIT(0);
++ unsigned int link_id;
+
++ mutex_lock(&dev->mt76.mutex);
+ switch (vif->type) {
+ case NL80211_IFTYPE_MESH_POINT:
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_AP:
+- mt7996_mcu_add_beacon(hw, conf, mconf, conf->enable_beacon);
++ for_each_set_bit(link_id, &update, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(mvif, link_id);
++ struct ieee80211_bss_conf *conf =
++ link_conf_dereference_protected(vif, link_id);
++
++ mt7996_mcu_add_beacon(hw, conf, mconf, conf->enable_beacon);
++ }
+ break;
+ default:
+ break;
+ }
++ mutex_unlock(&dev->mt76.mutex);
+ }
+
+ static void
+@@ -1585,7 +1613,7 @@ void mt7996_tx_token_put(struct mt7996_dev *dev)
+
+ spin_lock_bh(&dev->mt76.token_lock);
+ idr_for_each_entry(&dev->mt76.token, txwi, id) {
+- mt7996_txwi_free(dev, txwi, NULL, NULL);
++ mt7996_txwi_free(dev, txwi, NULL, NULL, NULL);
+ dev->mt76.token_count--;
+ }
+ spin_unlock_bh(&dev->mt76.token_lock);
+@@ -2266,21 +2294,31 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+ u32 changed;
+ LIST_HEAD(list);
+
++ rcu_read_lock();
+ spin_lock_bh(&dev->mt76.sta_poll_lock);
+ list_splice_init(&dev->sta_rc_list, &list);
+
+ while (!list_empty(&list)) {
++ u8 link_id;
++
+ mlink = list_first_entry(&list, struct mt7996_link_sta, rc_list);
++ link_id = mlink->wcid.link_id;
++
+ list_del_init(&mlink->rc_list);
+ changed = mlink->changed;
+ mlink->changed = 0;
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
+
+- sta = container_of((void *)mlink->sta, struct ieee80211_sta, drv_priv);
+- link_sta = &sta->deflink;
+ vif = container_of((void *)mlink->sta->vif, struct ieee80211_vif, drv_priv);
+- conf = &vif->bss_conf;
+- mconf = &mlink->sta->vif->deflink;
++ conf = rcu_dereference(vif->link_conf[link_id]);
++ mconf = rcu_dereference(mlink->sta->vif->link[link_id]);
++ sta = wcid_to_sta(&mlink->wcid);
++ link_sta = rcu_dereference(sta->link[link_id]);
++
++ if (unlikely(!conf || !mconf || !link_sta)) {
++ spin_lock_bh(&dev->mt76.sta_poll_lock);
++ continue;
++ }
+
+ if (changed & (IEEE80211_RC_SUPP_RATES_CHANGED |
+ IEEE80211_RC_NSS_CHANGED |
+@@ -2295,6 +2333,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
+ }
+
+ spin_unlock_bh(&dev->mt76.sta_poll_lock);
++ rcu_read_unlock();
+ }
+
+ void mt7996_mac_work(struct work_struct *work)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0098-wifi-mt76-connac-rework-mcu-functions-for-multi-link.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0098-wifi-mt76-connac-rework-mcu-functions-for-multi-link.patch
new file mode 100644
index 0000000..78653d9
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0098-wifi-mt76-connac-rework-mcu-functions-for-multi-link.patch
@@ -0,0 +1,259 @@
+From 8b128999c458c20f3ad09d8a0dde31e38f23e38b Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 7 Dec 2023 15:39:03 +0800
+Subject: [PATCH 098/116] wifi: mt76: connac: rework mcu functions for
+ multi-link support
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7615/mcu.c | 4 +--
+ mt76_connac_mcu.c | 11 ++++----
+ mt76_connac_mcu.h | 2 +-
+ mt7915/mcu.c | 3 +-
+ mt7925/mcu.c | 3 +-
+ mt7996/mcu.c | 70 +++++++++++++++++++++++++++++++++--------------
+ 6 files changed, 63 insertions(+), 30 deletions(-)
+
+diff --git a/mt7615/mcu.c b/mt7615/mcu.c
+index 8f4f203ef..e72dd654c 100644
+--- a/mt7615/mcu.c
++++ b/mt7615/mcu.c
+@@ -862,8 +862,8 @@ mt7615_mcu_wtbl_sta_add(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ else
+ mvif->sta_added = true;
+ }
+- mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, vif, &sta->deflink,
+- enable, new_entry);
++ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, sskb, &vif->bss_conf,
++ &sta->deflink, enable, new_entry);
+ if (enable && sta)
+ mt76_connac_mcu_sta_tlv(phy->mt76, sskb, sta, vif, 0,
+ MT76_STA_INFO_STATE_ASSOC);
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index d83d31441..9ea74719a 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -370,10 +370,11 @@ void mt76_connac_mcu_bss_omac_tlv(struct sk_buff *skb,
+ EXPORT_SYMBOL_GPL(mt76_connac_mcu_bss_omac_tlv);
+
+ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+- struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
+ struct ieee80211_link_sta *link_sta,
+ bool enable, bool newly)
+ {
++ struct ieee80211_vif *vif = conf->vif;
+ struct ieee80211_sta *sta = link_sta ? link_sta->sta : NULL;
+ struct sta_rec_basic *basic;
+ struct tlv *tlv;
+@@ -394,10 +395,9 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+
+ if (!sta) {
+ basic->conn_type = cpu_to_le32(CONNECTION_INFRA_BC);
+-
+ if (vif->type == NL80211_IFTYPE_STATION &&
+- !is_zero_ether_addr(vif->bss_conf.bssid)) {
+- memcpy(basic->peer_addr, vif->bss_conf.bssid, ETH_ALEN);
++ conf && !is_zero_ether_addr(conf->bssid)) {
++ memcpy(basic->peer_addr, conf->bssid, ETH_ALEN);
+ basic->aid = cpu_to_le16(vif->cfg.aid);
+ } else {
+ eth_broadcast_addr(basic->peer_addr);
+@@ -1056,7 +1056,8 @@ int mt76_connac_mcu_sta_cmd(struct mt76_phy *phy,
+ return PTR_ERR(skb);
+
+ if (info->sta || !info->offload_fw)
+- mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, &info->sta->deflink,
++ mt76_connac_mcu_sta_basic_tlv(dev, skb, &info->vif->bss_conf,
++ &info->sta->deflink,
+ info->enable, info->newly);
+ if (info->sta && info->enable)
+ mt76_connac_mcu_sta_tlv(phy, skb, info->sta,
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index d45765beb..7f1562b8e 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1904,7 +1904,7 @@ mt76_connac_mcu_add_tlv(struct sk_buff *skb, int tag, int len)
+ int mt76_connac_mcu_set_channel_domain(struct mt76_phy *phy);
+ int mt76_connac_mcu_set_vif_ps(struct mt76_dev *dev, struct ieee80211_vif *vif);
+ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+- struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
+ struct ieee80211_link_sta *link_sta,
+ bool enable, bool newly);
+ void mt76_connac_mcu_wtbl_generic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 1d1b3cead..366f2bba2 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -1669,7 +1669,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(&dev->mt76, skb, vif, &sta->deflink, enable,
++ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, &vif->bss_conf,
++ &sta->deflink, enable,
+ !rcu_access_pointer(dev->mt76.wcid[msta->wcid.idx]));
+ if (!enable)
+ goto out;
+diff --git a/mt7925/mcu.c b/mt7925/mcu.c
+index 1cb556302..e9cf442b8 100644
+--- a/mt7925/mcu.c
++++ b/mt7925/mcu.c
+@@ -1626,7 +1626,8 @@ mt7925_mcu_sta_cmd(struct mt76_phy *phy,
+ return PTR_ERR(skb);
+
+ if (info->sta || !info->offload_fw)
+- mt76_connac_mcu_sta_basic_tlv(dev, skb, info->vif, &info->sta->deflink,
++ mt76_connac_mcu_sta_basic_tlv(dev, skb, &info->vif->bss_conf,
++ &info->sta->deflink,
+ info->enable, info->newly);
+ if (info->sta && info->enable) {
+ mt7925_mcu_sta_phy_tlv(skb, info->vif, info->sta);
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index ed854b473..4bdb1fcbc 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1169,10 +1169,12 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ sta = ieee80211_find_sta(vif, conf->bssid);
+ /* TODO: enable BSS_INFO_UAPSD & BSS_INFO_PM */
+ if (sta) {
+- struct mt76_wcid *wcid;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ struct mt7996_link_sta *mlink;
+
+- wcid = (struct mt76_wcid *)sta->drv_priv;
+- sta_wlan_idx = wcid->idx;
++ mlink = rcu_dereference(msta->link[conf->link_id]);
++ if (mlink)
++ sta_wlan_idx = mlink->wcid.idx;
+ }
+ rcu_read_unlock();
+ }
+@@ -1306,9 +1308,8 @@ int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct mt7996_bss_conf *mconf)
+ static int
+ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif,
+ struct ieee80211_ampdu_params *params,
+- bool enable, bool tx)
++ struct mt76_wcid *wcid, bool enable, bool tx)
+ {
+- struct mt76_wcid *wcid = (struct mt76_wcid *)params->sta->drv_priv;
+ struct sta_rec_ba_uni *ba;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+@@ -1338,24 +1339,53 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
+- struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
+- struct mt7996_link_sta *mlink = mlink_dereference_protected(msta, 0);
++ struct ieee80211_sta *sta = params->sta;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ unsigned long valid_links = sta->valid_links ?: BIT(0);
++ unsigned int link_id;
++
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(msta->vif, link_id);
++ int ret;
+
+- if (enable && !params->amsdu)
+- mlink->wcid.amsdu = false;
++ if (enable && !params->amsdu)
++ mlink->wcid.amsdu = false;
+
+- return mt7996_mcu_sta_ba(dev, &mconf->mt76, params, enable, true);
++ ret = mt7996_mcu_sta_ba(dev, &mconf->mt76, params,
++ &mlink->wcid, enable, true);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
+ }
+
+ int mt7996_mcu_add_rx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+ bool enable)
+ {
+- struct mt7996_sta *msta = (struct mt7996_sta *)params->sta->drv_priv;
+- struct mt7996_bss_conf *mconf = mconf_dereference_protected(msta->vif, 0);
++ struct ieee80211_sta *sta = params->sta;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ unsigned long valid_links = sta->valid_links ?: BIT(0);
++ unsigned int link_id;
+
+- return mt7996_mcu_sta_ba(dev, &mconf->mt76, params, enable, false);
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct mt7996_link_sta *mlink =
++ mlink_dereference_protected(msta, link_id);
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(msta->vif, link_id);
++ int ret;
++
++ ret = mt7996_mcu_sta_ba(dev, &mconf->mt76, params, &mlink->wcid,
++ enable, false);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
+ }
+
+ static void
+@@ -2379,7 +2409,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ return PTR_ERR(skb);
+
+ /* starec basic */
+- mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, vif, link_sta, enable, newly);
++ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, conf, link_sta, enable, newly);
+
+ if (!enable)
+ goto out;
+@@ -2840,7 +2870,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
+ struct mt7996_bss_conf *mconf, int en)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_phy *phy = mconf->phy;
+ struct ieee80211_mutable_offsets offs;
+ struct ieee80211_tx_info *info;
+ struct sk_buff *skb, *rskb;
+@@ -2856,7 +2886,7 @@ int mt7996_mcu_add_beacon(struct ieee80211_hw *hw,
+ if (IS_ERR(rskb))
+ return PTR_ERR(rskb);
+
+- skb = ieee80211_beacon_get_template(hw, conf->vif, &offs, 0);
++ skb = ieee80211_beacon_get_template(hw, conf->vif, &offs, conf->link_id);
+ if (!skb) {
+ dev_kfree_skb(rskb);
+ return -EINVAL;
+@@ -2894,9 +2924,9 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+ {
+ #define OFFLOAD_TX_MODE_SU BIT(0)
+ #define OFFLOAD_TX_MODE_MU BIT(1)
+- struct ieee80211_hw *hw = mt76_hw(dev);
+ struct ieee80211_vif *vif = conf->vif;
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_phy *phy = mconf->phy;
+ struct cfg80211_chan_def *chandef = &mconf->phy->mt76->chandef;
+ enum nl80211_band band = chandef->chan->band;
+ struct mt76_wcid *wcid = &dev->mt76.global_wcid;
+@@ -5154,7 +5184,7 @@ int mt7996_mcu_get_per_sta_info(struct mt76_dev *dev, u16 tag,
+ rssi[3] = to_rssi(MT_PRXV_RCPI0, rcpi[3]);
+
+ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
+- phy = mlink->sta->vif->deflink.phy->mt76;
++ phy = dev->phys[wcid->phy_idx];
+ mlink->ack_signal = mt76_rx_signal(phy->antenna_mask, rssi);
+ ewma_avg_signal_add(&mlink->avg_ack_signal, -mlink->ack_signal);
+ } else {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0099-wifi-mt76-connac-rework-connac-helpers.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0099-wifi-mt76-connac-rework-connac-helpers.patch
new file mode 100644
index 0000000..78704e7
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0099-wifi-mt76-connac-rework-connac-helpers.patch
@@ -0,0 +1,174 @@
+From 458a75e252d6d8a7969108695b8b9c7cceb079e3 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 11 Dec 2023 18:45:00 +0800
+Subject: [PATCH 099/116] wifi: mt76: connac: rework connac helpers
+
+Rework connac helpers related to rate and phymode.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt76_connac.h | 2 +-
+ mt76_connac_mac.c | 17 ++++++++---------
+ mt76_connac_mcu.c | 6 +++---
+ mt76_connac_mcu.h | 2 +-
+ mt7925/main.c | 2 +-
+ mt7996/main.c | 2 +-
+ mt7996/mcu.c | 2 +-
+ 7 files changed, 16 insertions(+), 17 deletions(-)
+
+diff --git a/mt76_connac.h b/mt76_connac.h
+index 91987bdf2..0025add80 100644
+--- a/mt76_connac.h
++++ b/mt76_connac.h
+@@ -427,7 +427,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+ struct ieee80211_key_conf *key, int pid,
+ enum mt76_txq_id qid, u32 changed);
+ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
+- struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
+ bool beacon, bool mcast);
+ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
+ __le32 *txs_data);
+diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
+index b841bf628..c1e9ba0fc 100644
+--- a/mt76_connac_mac.c
++++ b/mt76_connac_mac.c
+@@ -291,12 +291,11 @@ EXPORT_SYMBOL_GPL(mt76_connac_init_tx_queues);
+ })
+
+ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
+- struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *conf,
+ bool beacon, bool mcast)
+ {
+- struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
+- struct cfg80211_chan_def *chandef = mvif->ctx ?
+- &mvif->ctx->def : &mphy->chandef;
++ struct ieee80211_vif *vif = conf->vif;
++ struct cfg80211_chan_def *chandef = &mphy->chandef;
+ u8 nss = 0, mode = 0, band = chandef->chan->band;
+ int rateidx = 0, mcast_rate;
+
+@@ -304,14 +303,14 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
+ goto legacy;
+
+ if (is_mt7921(mphy->dev)) {
+- rateidx = ffs(vif->bss_conf.basic_rates) - 1;
++ rateidx = ffs(conf->basic_rates) - 1;
+ goto legacy;
+ }
+
+ if (beacon) {
+ struct cfg80211_bitrate_mask *mask;
+
+- mask = &vif->bss_conf.beacon_tx_rate;
++ mask = &conf->beacon_tx_rate;
+
+ __bitrate_mask_check(he_mcs, HE_SU);
+ __bitrate_mask_check(vht_mcs, VHT);
+@@ -323,11 +322,11 @@ u16 mt76_connac2_mac_tx_rate_val(struct mt76_phy *mphy,
+ }
+ }
+
+- mcast_rate = vif->bss_conf.mcast_rate[band];
++ mcast_rate = conf->mcast_rate[band];
+ if (mcast && mcast_rate > 0)
+ rateidx = mcast_rate - 1;
+ else
+- rateidx = ffs(vif->bss_conf.basic_rates) - 1;
++ rateidx = ffs(conf->basic_rates) - 1;
+
+ legacy:
+ rateidx = mt76_calculate_default_rate(mphy, vif, rateidx);
+@@ -561,7 +560,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ bool multicast = ieee80211_is_data(hdr->frame_control) &&
+ is_multicast_ether_addr(hdr->addr1);
+- u16 rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon,
++ u16 rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon,
+ multicast);
+ u32 val = MT_TXD6_FIXED_BW;
+
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index 9ea74719a..71f3d301c 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -1361,7 +1361,7 @@ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ }
+ EXPORT_SYMBOL_GPL(mt76_connac_get_phy_mode);
+
+-u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
++u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf,
+ enum nl80211_band band)
+ {
+ const struct ieee80211_sta_eht_cap *eht_cap;
+@@ -1372,9 +1372,9 @@ u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ mode |= PHY_MODE_AX_6G;
+
+ sband = phy->hw->wiphy->bands[band];
+- eht_cap = ieee80211_get_eht_iftype_cap(sband, vif->type);
++ eht_cap = ieee80211_get_eht_iftype_cap(sband, conf->vif->type);
+
+- if (!eht_cap || !eht_cap->has_eht || !vif->bss_conf.eht_support)
++ if (!eht_cap || !eht_cap->has_eht || !conf->eht_support)
+ return mode;
+
+ switch (band) {
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 7f1562b8e..41e26b8a4 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -2016,7 +2016,7 @@ mt76_connac_get_eht_phy_cap(struct mt76_phy *phy, struct ieee80211_vif *vif);
+ u8 mt76_connac_get_phy_mode(struct mt76_phy *phy, struct ieee80211_vif *vif,
+ enum nl80211_band band,
+ struct ieee80211_link_sta *link_sta);
+-u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_vif *vif,
++u8 mt76_connac_get_phy_mode_ext(struct mt76_phy *phy, struct ieee80211_bss_conf *conf,
+ enum nl80211_band band);
+
+ int mt76_connac_mcu_add_key(struct mt76_dev *dev, struct ieee80211_vif *vif,
+diff --git a/mt7925/main.c b/mt7925/main.c
+index 1f07ec5a2..6d7ec7708 100644
+--- a/mt7925/main.c
++++ b/mt7925/main.c
+@@ -675,7 +675,7 @@ mt7925_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ u16 rate;
+ u8 i, idx, ht;
+
+- rate = mt76_connac2_mac_tx_rate_val(mphy, vif, beacon, mcast);
++ rate = mt76_connac2_mac_tx_rate_val(mphy, &vif->bss_conf, beacon, mcast);
+ ht = FIELD_GET(MT_TX_RATE_MODE, rate) > MT_PHY_TYPE_OFDM;
+
+ if (beacon && ht) {
+diff --git a/mt7996/main.c b/mt7996/main.c
+index aceb77ab2..bf3ae65e4 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -804,7 +804,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_bss_conf *conf,
+ u16 rate;
+ u8 i, idx;
+
+- rate = mt76_connac2_mac_tx_rate_val(mphy, conf->vif, beacon, mcast);
++ rate = mt76_connac2_mac_tx_rate_val(mphy, conf, beacon, mcast);
+
+ if (beacon) {
+ struct mt7996_phy *phy = mphy->priv;
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 4bdb1fcbc..35e0578b5 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1219,7 +1219,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ bss->dtim_period = conf->dtim_period;
+ bss->phymode = mt76_connac_get_phy_mode(phy, vif,
+ chandef->chan->band, NULL);
+- bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, vif,
++ bss->phymode_ext = mt76_connac_get_phy_mode_ext(phy, conf,
+ chandef->chan->band);
+
+ return 0;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0100-wifi-mt76-mt7996-handle-mapping-for-hw-and-phy.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0100-wifi-mt76-mt7996-handle-mapping-for-hw-and-phy.patch
new file mode 100644
index 0000000..6351831
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0100-wifi-mt76-mt7996-handle-mapping-for-hw-and-phy.patch
@@ -0,0 +1,218 @@
+From 5cbd493fec6ab4c947bde92425b7af7754112e15 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Tue, 5 Dec 2023 13:56:51 +0800
+Subject: [PATCH 100/116] wifi: mt76: mt7996: handle mapping for hw and phy
+
+We've used mt7996_band_phy() to do mapping from ieee80211_hw to mt7996_phy,
+and this patch is a temporal workaround for opposite direction.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 11 ++++++++++-
+ mt76.h | 10 ++++++++++
+ mt7996/mac.c | 7 +++++--
+ mt7996/main.c | 41 ++++++++++++++++++++++++++++++-----------
+ 4 files changed, 55 insertions(+), 14 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 96fab2320..175f19169 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -823,9 +823,13 @@ EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
+ struct mt76_channel_state *
+ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ {
++ struct mt76_phy *ori_phy = phy;
+ struct mt76_sband *msband;
+ int idx;
+
++ if (phy->main_phy)
++ phy = phy->main_phy;
++begin:
+ if (c->band == NL80211_BAND_2GHZ)
+ msband = &phy->sband_2g;
+ else if (c->band == NL80211_BAND_6GHZ)
+@@ -834,6 +838,11 @@ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ msband = &phy->sband_5g;
+
+ idx = c - &msband->sband.channels[0];
++ /* TODO: mlo: this is a temp solution, need to come up with a more clever one */
++ if (idx < 0 || idx >= msband->sband.n_channels) {
++ phy = ori_phy;
++ goto begin;
++ }
+ return &msband->chan[idx];
+ }
+ EXPORT_SYMBOL_GPL(mt76_channel_state);
+@@ -1072,7 +1081,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
+ }
+
+ *sta = wcid_to_sta(mstat.wcid);
+- *hw = mt76_phy_hw(dev, mstat.phy_idx);
++ *hw = mt76_main_hw(dev->phys[mstat.phy_idx]);
+
+ if ((mstat.flag & RX_FLAG_8023) || ieee80211_is_data_qos(hdr->frame_control)) {
+ struct mt76_phy *phy = mt76_dev_phy(dev, mstat.phy_idx);
+diff --git a/mt76.h b/mt76.h
+index b60b5161b..3f9a0b8aa 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -831,6 +831,7 @@ struct mt76_vif {
+ struct mt76_phy {
+ struct ieee80211_hw *hw;
+ struct mt76_dev *dev;
++ struct mt76_phy *main_phy;
+ void *priv;
+
+ unsigned long state;
+@@ -1322,6 +1323,15 @@ mt76_phy_hw(struct mt76_dev *dev, u8 phy_idx)
+ return mt76_dev_phy(dev, phy_idx)->hw;
+ }
+
++static inline struct ieee80211_hw *
++mt76_main_hw(struct mt76_phy *phy)
++{
++ if (phy->main_phy)
++ return mt76_dev_phy(phy->dev, phy->main_phy->band_idx)->hw;
++
++ return mt76_dev_phy(phy->dev, phy->band_idx)->hw;
++}
++
+ static inline u8 *
+ mt76_get_txwi_ptr(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+ {
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 31b916695..cd25ea616 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2383,7 +2383,10 @@ void mt7996_mac_work(struct work_struct *work)
+
+ mt76_tx_status_check(mdev, false);
+
+- ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
++ if (mphy->main_phy && !test_bit(MT76_STATE_RUNNING, &mphy->main_phy->state))
++ return;
++
++ ieee80211_queue_delayed_work(mt76_main_hw(mphy), &mphy->mac_work,
+ MT7996_WATCHDOG_TIME);
+ }
+
+@@ -2802,7 +2805,7 @@ mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+ rcu_read_lock();
+- if (!ieee80211_tx_prepare_skb(hw, vif, skb,
++ if (!ieee80211_tx_prepare_skb(mt76_main_hw(phy->mt76), vif, skb,
+ phy->scan_chan->band,
+ NULL)) {
+ rcu_read_unlock();
+diff --git a/mt7996/main.c b/mt7996/main.c
+index bf3ae65e4..8b463b17d 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -173,6 +173,7 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+ mutex_lock(&dev->mt76.mutex);
+ mt7996_mcu_set_radio_en(phy, false);
+ clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
++ phy->mt76->main_phy = NULL;
+ mutex_unlock(&dev->mt76.mutex);
+ }
+ }
+@@ -541,9 +542,10 @@ out:
+ clear_bit(MT76_RESET, &phy->mt76->state);
+ mutex_unlock(&dev->mt76.mutex);
+
+- mt76_txq_schedule_all(phy->mt76);
++ if (phy->mt76 == phy->mt76->main_phy)
++ mt76_txq_schedule_all(phy->mt76);
+
+- ieee80211_queue_delayed_work(phy->mt76->hw,
++ ieee80211_queue_delayed_work(mt76_main_hw(phy->mt76),
+ &phy->mt76->mac_work,
+ MT7996_WATCHDOG_TIME);
+
+@@ -554,11 +556,11 @@ int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef
+ {
+ int ret;
+
+- ieee80211_stop_queues(phy->mt76->hw);
++ ieee80211_stop_queues(mt76_main_hw(phy->mt76));
+ ret = __mt7996_set_channel(phy, chandef);
+ if (ret)
+ return ret;
+- ieee80211_wake_queues(phy->mt76->hw);
++ ieee80211_wake_queues(mt76_main_hw(phy->mt76));
+
+ return 0;
+ }
+@@ -731,6 +733,7 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw,
+ MT_WF_RFCR1_DROP_CFEND |
+ MT_WF_RFCR1_DROP_CFACK;
+ u32 flags = 0;
++ u8 band;
+
+ #define MT76_FILTER(_flag, _hw) do { \
+ flags |= *total_flags & FIF_##_flag; \
+@@ -764,12 +767,26 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw,
+ MT_WF_RFCR_DROP_NDPA);
+
+ *total_flags = flags;
+- mt76_wr(dev, MT_WF_RFCR(phy->mt76->band_idx), phy->rxfilter);
+
+- if (*total_flags & FIF_CONTROL)
+- mt76_clear(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags);
+- else
+- mt76_set(dev, MT_WF_RFCR1(phy->mt76->band_idx), ctl_flags);
++ /* configure rx filter to all affliated phy */
++ for (band = 0; band < __MT_MAX_BAND; band++) {
++ struct mt7996_phy *tmp;
++
++ if (!hw->wiphy->bands[band])
++ continue;
++
++ tmp = dev->mt76.phys[band]->priv;
++ if (tmp->mt76->main_phy != phy->mt76)
++ continue;
++
++ tmp->rxfilter = phy->rxfilter;
++ mt76_wr(dev, MT_WF_RFCR(tmp->mt76->band_idx), phy->rxfilter);
++
++ if (*total_flags & FIF_CONTROL)
++ mt76_clear(dev, MT_WF_RFCR1(tmp->mt76->band_idx), ctl_flags);
++ else
++ mt76_set(dev, MT_WF_RFCR1(tmp->mt76->band_idx), ctl_flags);
++ }
+
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -2186,7 +2203,7 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ phy->scan_chan_idx = 0;
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+- ieee80211_queue_delayed_work(hw, &phy->scan_work, 0);
++ ieee80211_queue_delayed_work(mt76_main_hw(phy->mt76), &phy->scan_work, 0);
+
+ return 0;
+ }
+@@ -2203,7 +2220,8 @@ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ continue;
+
+ phy = mt7996_band_phy(hw, band);
+- if (!(test_bit(MT76_SCANNING, &phy->mt76->state)))
++ if (!(test_bit(MT76_SCANNING, &phy->mt76->state) &&
++ phy->mt76->main_phy == hw->priv))
+ continue;
+
+ cancel_delayed_work_sync(&phy->scan_work);
+@@ -2224,6 +2242,7 @@ mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
+ wiphy_info(hw->wiphy, "%s: add %u\n", __func__, conf->def.chan->hw_value);
+ mutex_lock(&phy->dev->mt76.mutex);
+
++ phy->mt76->main_phy = hw->priv;
+ if (ctx->assigned) {
+ mutex_unlock(&phy->dev->mt76.mutex);
+ return -ENOSPC;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0101-wifi-mt76-mt7996-handle-mapping-for-hw-and-vif.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0101-wifi-mt76-mt7996-handle-mapping-for-hw-and-vif.patch
new file mode 100644
index 0000000..d32cbf5
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0101-wifi-mt76-mt7996-handle-mapping-for-hw-and-vif.patch
@@ -0,0 +1,222 @@
+From 239433584a6782a9b99d105698dbd4841b18cf9a Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 8 Dec 2023 18:08:13 +0800
+Subject: [PATCH 101/116] wifi: mt76: mt7996: handle mapping for hw and vif
+
+We have several temporal workarounds for ieee80211_hw and mt76_phy
+mappings. For legacy MBSS cases, we also need a method to do the
+hw and vif mappings.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ dma.c | 2 +-
+ mac80211.c | 2 +-
+ mt76.h | 14 ++++++++++++--
+ mt7996/mac.c | 24 +++++++++++++++++++++++-
+ mt7996/main.c | 1 +
+ mt7996/mcu.c | 4 ++--
+ mt7996/mmio.c | 1 +
+ mt7996/mt7996.h | 3 +++
+ tx.c | 4 ++--
+ 9 files changed, 46 insertions(+), 9 deletions(-)
+
+diff --git a/dma.c b/dma.c
+index 38701c71e..3f1fb6c2a 100644
+--- a/dma.c
++++ b/dma.c
+@@ -685,7 +685,7 @@ free:
+
+ free_skb:
+ status.skb = tx_info.skb;
+- hw = mt76_tx_status_get_hw(dev, tx_info.skb);
++ hw = mt76_tx_status_get_hw(dev, tx_info.skb, wcid);
+ spin_lock_bh(&dev->rx_lock);
+ ieee80211_tx_status_ext(hw, &status);
+ spin_unlock_bh(&dev->rx_lock);
+diff --git a/mac80211.c b/mac80211.c
+index 175f19169..dad659ecb 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1519,7 +1519,7 @@ void mt76_wcid_cleanup(struct mt76_dev *dev, struct mt76_wcid *wcid)
+ spin_unlock_bh(&phy->tx_lock);
+
+ while ((skb = __skb_dequeue(&list)) != NULL) {
+- hw = mt76_tx_status_get_hw(dev, skb);
++ hw = mt76_tx_status_get_hw(dev, skb, wcid);
+ ieee80211_free_txskb(hw, skb);
+ }
+ }
+diff --git a/mt76.h b/mt76.h
+index 3f9a0b8aa..64ea323d8 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -556,6 +556,9 @@ struct mt76_driver_ops {
+
+ void (*sta_remove)(struct mt76_dev *dev, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta);
++
++ void (*get_hw)(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 phy_idx,
++ struct ieee80211_hw **hw);
+ };
+
+ struct mt76_channel_state {
+@@ -1601,14 +1604,21 @@ static inline void mt76_testmode_reset(struct mt76_phy *phy, bool disable)
+
+ /* internal */
+ static inline struct ieee80211_hw *
+-mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb)
++mt76_tx_status_get_hw(struct mt76_dev *dev, struct sk_buff *skb,
++ struct mt76_wcid *wcid)
+ {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ u8 phy_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
+- struct ieee80211_hw *hw = mt76_phy_hw(dev, phy_idx);
++ struct ieee80211_hw *hw;
+
+ info->hw_queue &= ~MT_TX_HW_QUEUE_PHY;
+
++ if (dev->drv->get_hw) {
++ dev->drv->get_hw(dev, wcid, phy_idx, &hw);
++ } else {
++ hw = mt76_phy_hw(dev, phy_idx);
++ }
++
+ return hw;
+ }
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index cd25ea616..6ca3e06e2 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2846,13 +2846,23 @@ static void mt7996_scan_check_sta(void *data, struct ieee80211_sta *sta)
+ void mt7996_scan_work(struct work_struct *work)
+ {
+ struct mt7996_phy *phy = container_of(work, struct mt7996_phy, scan_work.work);
+- struct ieee80211_hw *hw = phy->mt76->hw;
++ struct ieee80211_vif *vif = phy->scan_vif;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct ieee80211_hw *hw = mvif->hw;
+ struct cfg80211_scan_request *req = phy->scan_req;
+ struct cfg80211_chan_def chandef = {};
+ int duration;
+ bool has_sta = false, active_scan = false;
+
+ mutex_lock(&phy->dev->mt76.mutex);
++ /* don't let non-MLD AP scan other bands */
++ if (vif->type != NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
++ phy != mt7996_hw_phy(hw)) {
++ mt7996_scan_complete(phy, false);
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return;
++ }
++
+ if (phy->scan_chan_idx >= req->n_channels) {
+ mt7996_scan_complete(phy, false);
+ mutex_unlock(&phy->dev->mt76.mutex);
+@@ -2912,3 +2922,15 @@ void mt7996_scan_work(struct work_struct *work)
+
+ ieee80211_queue_delayed_work(hw, &phy->scan_work, duration);
+ }
++
++void mt7996_get_hw(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 phy_idx,
++ struct ieee80211_hw **hw)
++{
++ struct mt7996_link_sta *mlink = wcid_to_mlink(wcid);
++
++ if (mlink) {
++ *hw = mlink->sta->vif->hw;
++ } else {
++ *hw = mt76_phy_hw(dev, phy_idx);
++ }
++}
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 8b463b17d..8bf520120 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -444,6 +444,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ phy->monitor_vif = vif;
+
+ mvif->dev = dev;
++ mvif->hw = hw;
+ mvif->sta.vif = mvif;
+
+ ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 35e0578b5..399e0ffd4 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2947,11 +2947,11 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+
+ if (changed & BSS_CHANGED_FILS_DISCOVERY) {
+ interval = conf->fils_discovery.max_interval;
+- skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
++ skb = ieee80211_get_fils_discovery_tmpl(mvif->hw, vif);
+ } else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
+ conf->unsol_bcast_probe_resp_interval) {
+ interval = conf->unsol_bcast_probe_resp_interval;
+- skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
++ skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(mvif->hw, vif);
+ }
+
+ if (!skb) {
+diff --git a/mt7996/mmio.c b/mt7996/mmio.c
+index 6abbcb68e..6bebdd81b 100644
+--- a/mt7996/mmio.c
++++ b/mt7996/mmio.c
+@@ -658,6 +658,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
+ .sta_assoc = mt7996_mac_sta_assoc,
+ .sta_remove = mt7996_mac_sta_remove,
+ .update_survey = mt7996_update_channel,
++ .get_hw = mt7996_get_hw,
+ };
+ struct mt7996_dev *dev;
+ struct mt76_dev *mdev;
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index c6ca00f1a..dc0a31d44 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -353,6 +353,7 @@ struct mt7996_vif {
+
+ struct mt7996_sta sta;
+ struct mt7996_dev *dev;
++ struct ieee80211_hw *hw;
+
+ u8 master_link_id;
+ u8 group_mld_id;
+@@ -897,6 +898,8 @@ int mt7996_init_tx_queues(struct mt7996_phy *phy, int idx,
+ void mt7996_init_txpower(struct mt7996_phy *phy);
+ int mt7996_txbf_init(struct mt7996_dev *dev);
+ int mt7996_get_chip_sku(struct mt7996_dev *dev);
++void mt7996_get_hw(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 phy_idx,
++ struct ieee80211_hw **hw);
+ void mt7996_reset(struct mt7996_dev *dev);
+ void mt7996_coredump(struct mt7996_dev *dev, u8 state);
+ int mt7996_run(struct ieee80211_hw *hw);
+diff --git a/tx.c b/tx.c
+index e2795067c..6580833e9 100644
+--- a/tx.c
++++ b/tx.c
+@@ -76,7 +76,7 @@ mt76_tx_status_unlock(struct mt76_dev *dev, struct sk_buff_head *list)
+ }
+ }
+
+- hw = mt76_tx_status_get_hw(dev, skb);
++ hw = mt76_tx_status_get_hw(dev, skb, wcid);
+ spin_lock_bh(&dev->rx_lock);
+ ieee80211_tx_status_ext(hw, &status);
+ spin_unlock_bh(&dev->rx_lock);
+@@ -272,7 +272,7 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
+ if (cb->pktid < MT_PACKET_ID_FIRST) {
+ struct ieee80211_rate_status rs = {};
+
+- hw = mt76_tx_status_get_hw(dev, skb);
++ hw = mt76_tx_status_get_hw(dev, skb, wcid);
+ status.sta = wcid_to_sta(wcid);
+ if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
+ rs.rate_idx = wcid->rate;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0102-wifi-mt76-mt7996-rework-scanning-parts-for-MLD-STA-s.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0102-wifi-mt76-mt7996-rework-scanning-parts-for-MLD-STA-s.patch
new file mode 100644
index 0000000..4aba3ff
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0102-wifi-mt76-mt7996-rework-scanning-parts-for-MLD-STA-s.patch
@@ -0,0 +1,153 @@
+From f60e775a0f4ca3389d4777b1b2200a5be06cab92 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 13 Dec 2023 16:58:31 +0800
+Subject: [PATCH 102/116] wifi: mt76: mt7996: rework scanning parts for MLD STA
+ support
+
+During the first scanning, the STA VIF is still a legacy interface,
+and at the moment it doesn't know if it's MLD or not. So do dome tricks
+here to let the legacy interface be abled to scan all bands.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mac.c | 34 +++++++++++++++++++++++++---------
+ mt7996/main.c | 17 +++++++++++++++++
+ 2 files changed, 42 insertions(+), 9 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 6ca3e06e2..d6d1c0798 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2770,23 +2770,40 @@ static void
+ mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
+ const u8 *dst)
+ {
+- struct ieee80211_hw *hw = phy->mt76->hw;
+ struct cfg80211_scan_request *req = phy->scan_req;
+ struct ieee80211_vif *vif = phy->scan_vif;
++ struct ieee80211_bss_conf *conf;
+ struct mt7996_vif *mvif;
+ struct mt7996_link_sta *mlink;
+ struct ieee80211_tx_info *info;
++ struct ieee80211_hw *hw;
+ struct sk_buff *skb;
++ unsigned long valid_links;
++ unsigned int link_id;
+
+ if (!req || !vif)
+ return;
+
++ valid_links = vif->valid_links ?: BIT(0);
+ mvif = (struct mt7996_vif *)vif->drv_priv;
++ hw = mvif->hw;
++
++ rcu_read_lock();
++
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ conf = rcu_dereference(vif->link_conf[link_id]);
++ mlink = rcu_dereference(mvif->sta.link[link_id]);
++ if (mlink->wcid.phy_idx != phy->mt76->band_idx)
++ continue;
++ }
+
+- skb = ieee80211_probereq_get(hw, vif->addr,
++ if (unlikely(!conf))
++ goto unlock;
++
++ skb = ieee80211_probereq_get(hw, conf->addr,
+ ssid->ssid, ssid->ssid_len, req->ie_len);
+ if (!skb)
+- return;
++ goto unlock;
+
+ if (is_unicast_ether_addr(dst)) {
+ struct ieee80211_hdr_3addr *hdr =
+@@ -2804,30 +2821,29 @@ mt7996_scan_send_probe(struct mt7996_phy *phy, struct cfg80211_ssid *ssid,
+
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+
+- rcu_read_lock();
+- if (!ieee80211_tx_prepare_skb(mt76_main_hw(phy->mt76), vif, skb,
+- phy->scan_chan->band,
+- NULL)) {
++ if (!ieee80211_tx_prepare_skb(hw, vif, skb,
++ phy->scan_chan->band, NULL)) {
+ rcu_read_unlock();
+ ieee80211_free_txskb(hw, skb);
+ return;
+ }
+
+ local_bh_disable();
+- mlink = rcu_dereference(mvif->sta.link[0]);
+ mt76_tx(phy->mt76, NULL, &mlink->wcid, skb);
+ local_bh_enable();
+
++unlock:
+ rcu_read_unlock();
+ }
+
+ void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted)
+ {
++ struct mt7996_vif *mvif = (struct mt7996_vif *)phy->scan_vif->drv_priv;
+ struct cfg80211_scan_info info = {
+ .aborted = aborted,
+ };
+
+- ieee80211_scan_completed(phy->mt76->hw, &info);
++ ieee80211_scan_completed(mvif->hw, &info);
+ phy->scan_chan = NULL;
+ phy->scan_req = NULL;
+ phy->scan_vif = NULL;
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 8bf520120..66972080f 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -2191,6 +2191,8 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ {
+ struct cfg80211_scan_request *req = &hw_req->req;
+ struct mt7996_phy *phy = mt7996_band_phy(hw, req->channels[0]->band);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ int ret;
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ if (WARN_ON(phy->scan_req || phy->scan_chan)) {
+@@ -2202,6 +2204,17 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ phy->scan_req = req;
+ phy->scan_vif = vif;
+ phy->scan_chan_idx = 0;
++ if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
++ (phy->mt76 != mvif->deflink.phy->mt76)) {
++ phy->mt76->main_phy = hw->priv;
++ mt7996_remove_bss_conf(vif, &vif->bss_conf, &mvif->deflink);
++
++ ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
++ if (ret) {
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return ret;
++ }
++ }
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+ ieee80211_queue_delayed_work(mt76_main_hw(phy->mt76), &phy->scan_work, 0);
+@@ -2212,6 +2225,7 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ static void
+ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ {
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ int band;
+
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
+@@ -2229,6 +2243,9 @@ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ mt7996_scan_complete(phy, true);
++ if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
++ (phy->mt76 != mvif->deflink.phy->mt76))
++ phy->mt76->main_phy = NULL;
+ mutex_unlock(&phy->dev->mt76.mutex);
+ }
+ }
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0103-wifi-mt76-mt7996-implement-mld-address-translation.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0103-wifi-mt76-mt7996-implement-mld-address-translation.patch
new file mode 100644
index 0000000..13c3519
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0103-wifi-mt76-mt7996-implement-mld-address-translation.patch
@@ -0,0 +1,125 @@
+From 3ef17fdd49c8ded3d8aad5fea83fc1ffbf8972a0 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 7 Dec 2023 16:31:56 +0800
+Subject: [PATCH 103/116] wifi: mt76: mt7996: implement mld address translation
+
+Do the MLD to link address translation for EAPOL and management frames
+in driver.
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Co-developed-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Co-developed-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mac.c | 20 ++++++++++++++++++++
+ mt7996/main.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 66 insertions(+), 3 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index d6d1c0798..3141fe4e4 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -895,6 +895,26 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
+ pid, qid, 0);
+
++ /* translate addr3 of EAPOL by driver */
++ if (unlikely(tx_info->skb->protocol == cpu_to_be16(ETH_P_PAE)) && sta->mlo) {
++ if (ether_addr_equal(vif->addr, hdr->addr3)) {
++ struct ieee80211_bss_conf *conf;
++
++ conf = rcu_dereference(vif->link_conf[wcid->link_id]);
++ if (unlikely(!conf))
++ return -ENOLINK;
++
++ memcpy(hdr->addr3, conf->addr, ETH_ALEN);
++ } else if (ether_addr_equal(sta->addr, hdr->addr3)) {
++ struct ieee80211_link_sta *link_sta;
++
++ link_sta = rcu_dereference(sta->link[wcid->link_id]);
++ memcpy(hdr->addr3, link_sta->addr, ETH_ALEN);
++ }
++
++ pr_info("EAPOL: a1=%pM, a2=%pM, a3=%pM\n", hdr->addr1, hdr->addr2, hdr->addr3);
++ }
++
+ txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
+ for (i = 0; i < nbuf; i++) {
+ u16 len;
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 66972080f..97431ae34 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -1308,14 +1308,56 @@ static void mt7996_tx(struct ieee80211_hw *hw,
+
+ rcu_read_lock();
+ if (mvif && msta) {
++ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct mt7996_bss_conf *mconf;
+ struct mt7996_link_sta *mlink;
+-
+ u8 link_id = u32_get_bits(info->control.flags,
+ IEEE80211_TX_CTRL_MLO_LINK);
++ struct ieee80211_sta *sta = ieee80211_find_sta(vif, hdr->addr1);
++
++ if (link_id >= IEEE80211_LINK_UNSPECIFIED) {
++ if (sta) {
++ struct mt7996_sta *peer;
++
++ peer = (struct mt7996_sta *)sta->drv_priv;
++ link_id = peer->pri_link;
++ } else {
++ link_id = mvif->master_link_id;
++ }
++ }
+
+- if (link_id >= IEEE80211_LINK_UNSPECIFIED)
+- link_id = mvif->master_link_id;
++ /* translate mld addr to link addr */
++ if (ieee80211_vif_is_mld(vif)) {
++ struct ieee80211_bss_conf *conf;
++ if (sta) {
++ struct ieee80211_link_sta *link_sta =
++ rcu_dereference(sta->link[link_id]);
++
++ if (!link_sta) {
++ mlo_dbg(mt7996_hw_phy(mvif->hw), "request TX on invalid link_id=%u, use primary link (id=%u) instead.\n",
++ link_id, msta->pri_link);
++ link_id = msta->pri_link;
++ link_sta = rcu_dereference(sta->link[link_id]);
++
++ if (!link_sta) {
++ mlo_dbg(mt7996_hw_phy(mvif->hw), "primary link became invalid, give up the TX\n");
++ goto unlock;
++ }
++ }
++
++ memcpy(hdr->addr1, link_sta->addr, ETH_ALEN);
++ if (ether_addr_equal(sta->addr, hdr->addr3))
++ memcpy(hdr->addr3, link_sta->addr, ETH_ALEN);
++ }
++
++ conf = rcu_dereference(vif->link_conf[link_id]);
++ if (unlikely(!conf))
++ goto unlock;
++
++ memcpy(hdr->addr2, conf->addr, ETH_ALEN);
++ if (ether_addr_equal(vif->addr, hdr->addr3))
++ memcpy(hdr->addr3, conf->addr, ETH_ALEN);
++ }
+
+ mconf = rcu_dereference(mvif->link[link_id]);
+ mlink = rcu_dereference(msta->link[link_id]);
+@@ -1333,6 +1375,7 @@ static void mt7996_tx(struct ieee80211_hw *hw,
+ }
+
+ mt76_tx(mphy, control->sta, wcid, skb);
++unlock:
+ rcu_read_unlock();
+ }
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0104-wifi-mt76-mt7996-use-BSS_CHANGED_TXPOWER-for-txpower.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0104-wifi-mt76-mt7996-use-BSS_CHANGED_TXPOWER-for-txpower.patch
new file mode 100644
index 0000000..97f1b55
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0104-wifi-mt76-mt7996-use-BSS_CHANGED_TXPOWER-for-txpower.patch
@@ -0,0 +1,106 @@
+From 463f4e447fe5f513e0b0f49b44152d359897c4c3 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Tue, 27 Feb 2024 18:07:11 +0800
+Subject: [PATCH 104/116] wifi: mt76: mt7996: use BSS_CHANGED_TXPOWER for
+ txpower setting
+
+This is a preliminary patch to add MLO support for mt7996 chipsets.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/main.c | 12 +++---------
+ mt7996/mcu.c | 5 +++--
+ mt7996/mt7996.h | 3 ++-
+ mt7996/testmode.c | 2 +-
+ 4 files changed, 9 insertions(+), 13 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 97431ae34..a38d77390 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -661,14 +661,6 @@ static int mt7996_config(struct ieee80211_hw *hw, u32 changed)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- int ret;
+-
+- if (changed & (IEEE80211_CONF_CHANGE_POWER |
+- IEEE80211_CONF_CHANGE_CHANNEL)) {
+- ret = mt7996_mcu_set_txpower_sku(phy);
+- if (ret)
+- return ret;
+- }
+
+ mutex_lock(&dev->mt76.mutex);
+
+@@ -968,6 +960,9 @@ static void mt7996_link_info_changed(struct ieee80211_hw *hw,
+ if (changed & BSS_CHANGED_MU_GROUPS)
+ mt7996_update_mu_group(hw, info, mconf);
+
++ if (changed & BSS_CHANGED_TXPOWER)
++ mt7996_mcu_set_txpower_sku(phy, info);
++
+ out:
+ mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -1607,7 +1602,6 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+ mt76_set_stream_caps(phy->mt76, true);
+ mt7996_set_stream_vht_txbf_caps(phy);
+ mt7996_set_stream_he_eht_caps(phy);
+- mt7996_mcu_set_txpower_sku(phy);
+
+ mutex_unlock(&dev->mt76.mutex);
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 399e0ffd4..39e353ab2 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -5325,7 +5325,8 @@ mt7996_update_max_txpower_cur(struct mt7996_phy *phy, int tx_power)
+ mphy->txpower_cur = e2p_power_limit;
+ }
+
+-int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
++int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy,
++ struct ieee80211_bss_conf *conf)
+ {
+ #define TX_POWER_LIMIT_TABLE_RATE 0
+ #define TX_POWER_LIMIT_TABLE_PATH 1
+@@ -5354,7 +5355,7 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
+
+ if (hw->conf.power_level == INT_MIN)
+ hw->conf.power_level = 127;
+- txpower_limit = mt7996_get_power_bound(phy, hw->conf.power_level);
++ txpower_limit = mt7996_get_power_bound(phy, conf->txpower);
+
+ if (phy->sku_limit_en) {
+ txpower_limit = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index dc0a31d44..39aa3ee5b 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -976,7 +976,8 @@ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
+ int mt7996_mcu_get_temperature(struct mt7996_phy *phy);
+ int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state);
+ int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy, bool enable);
+-int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy);
++int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy,
++ struct ieee80211_bss_conf *conf);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+ u8 rx_sel, u8 val);
+ int mt7996_mcu_rdd_background_disable_timer(struct mt7996_dev *dev,
+diff --git a/mt7996/testmode.c b/mt7996/testmode.c
+index ba17f947b..0565ebc94 100644
+--- a/mt7996/testmode.c
++++ b/mt7996/testmode.c
+@@ -1830,7 +1830,7 @@ mt7996_tm_update_params(struct mt7996_phy *phy, u32 changed)
+ mt7996_tm_update_channel(phy);
+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(SKU_POWER_LIMIT), td->sku_en);
+ mt7996_mcu_set_tx_power_ctrl(phy, POWER_CTRL(BACKOFF_POWER_LIMIT), td->sku_en);
+- mt7996_mcu_set_txpower_sku(phy);
++ mt7996_mcu_set_txpower_sku(phy, &phy->monitor_vif->bss_conf);
+ }
+ if (changed & BIT(TM_CHANGED_TX_LENGTH)) {
+ mt7996_tm_set(dev, SET_ID(TX_LEN), td->tx_mpdu_len);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0105-wifi-mt76-mt7996-temp-support-for-single-wiphy.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0105-wifi-mt76-mt7996-temp-support-for-single-wiphy.patch
new file mode 100644
index 0000000..841aaba
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0105-wifi-mt76-mt7996-temp-support-for-single-wiphy.patch
@@ -0,0 +1,436 @@
+From 155e1bd8b7933deef463abc30f7d375761b93055 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 28 Mar 2024 18:50:04 +0800
+Subject: [PATCH 105/116] wifi: mt76: mt7996: temp support for single wiphy
+
+Add temporal single wiphy for simultaneously supporting MLD and legacy
+interfaces.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 11 +------
+ mt76.h | 11 +------
+ mt7996/eeprom.c | 6 ----
+ mt7996/init.c | 23 ++++++++++---
+ mt7996/mac.c | 5 +--
+ mt7996/main.c | 88 ++++++++++++++++++++++++++++++-------------------
+ mt7996/mt7996.h | 14 ++++----
+ 7 files changed, 81 insertions(+), 77 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index dad659ecb..20ab1db4d 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -823,13 +823,9 @@ EXPORT_SYMBOL_GPL(mt76_has_tx_pending);
+ struct mt76_channel_state *
+ mt76_channel_state(struct mt76_phy *phy, struct ieee80211_channel *c)
+ {
+- struct mt76_phy *ori_phy = phy;
+ struct mt76_sband *msband;
+ int idx;
+
+- if (phy->main_phy)
+- phy = phy->main_phy;
+-begin:
+ if (c->band == NL80211_BAND_2GHZ)
+ msband = &phy->sband_2g;
+ else if (c->band == NL80211_BAND_6GHZ)
+@@ -838,11 +834,6 @@ begin:
+ msband = &phy->sband_5g;
+
+ idx = c - &msband->sband.channels[0];
+- /* TODO: mlo: this is a temp solution, need to come up with a more clever one */
+- if (idx < 0 || idx >= msband->sband.n_channels) {
+- phy = ori_phy;
+- goto begin;
+- }
+ return &msband->chan[idx];
+ }
+ EXPORT_SYMBOL_GPL(mt76_channel_state);
+@@ -1081,7 +1072,7 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
+ }
+
+ *sta = wcid_to_sta(mstat.wcid);
+- *hw = mt76_main_hw(dev->phys[mstat.phy_idx]);
++ *hw = mt76_phy_hw(dev, mstat.phy_idx);
+
+ if ((mstat.flag & RX_FLAG_8023) || ieee80211_is_data_qos(hdr->frame_control)) {
+ struct mt76_phy *phy = mt76_dev_phy(dev, mstat.phy_idx);
+diff --git a/mt76.h b/mt76.h
+index 64ea323d8..b77a2f76b 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -833,8 +833,8 @@ struct mt76_vif {
+
+ struct mt76_phy {
+ struct ieee80211_hw *hw;
++ struct ieee80211_hw *ori_hw;
+ struct mt76_dev *dev;
+- struct mt76_phy *main_phy;
+ void *priv;
+
+ unsigned long state;
+@@ -1326,15 +1326,6 @@ mt76_phy_hw(struct mt76_dev *dev, u8 phy_idx)
+ return mt76_dev_phy(dev, phy_idx)->hw;
+ }
+
+-static inline struct ieee80211_hw *
+-mt76_main_hw(struct mt76_phy *phy)
+-{
+- if (phy->main_phy)
+- return mt76_dev_phy(phy->dev, phy->main_phy->band_idx)->hw;
+-
+- return mt76_dev_phy(phy->dev, phy->band_idx)->hw;
+-}
+-
+ static inline u8 *
+ mt76_get_txwi_ptr(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+ {
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 0393e93bf..51455d877 100644
+--- a/mt7996/eeprom.c
++++ b/mt7996/eeprom.c
+@@ -387,12 +387,6 @@ static int mt7996_eeprom_parse_band_config(struct mt7996_phy *phy)
+ break;
+ }
+
+- /* TODO: for MLO, we enable all band capabilities */
+- phy->mt76->cap.has_2ghz = true;
+- phy->mt76->cap.has_5ghz = true;
+- if (is_mt7996(&phy->dev->mt76))
+- phy->mt76->cap.has_6ghz = true;
+-
+ return ret;
+ }
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index c6eb6a5c2..f374119f6 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -18,13 +18,13 @@ static const struct ieee80211_iface_limit if_limits[] = {
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_ADHOC)
+ }, {
+- .max = 16,
++ .max = 16 * 3,
+ .types = BIT(NL80211_IFTYPE_AP)
+ #ifdef CONFIG_MAC80211_MESH
+ | BIT(NL80211_IFTYPE_MESH_POINT)
+ #endif
+ }, {
+- .max = MT7996_MAX_INTERFACES,
++ .max = MT7996_MAX_INTERFACES * 3,
+ .types = BIT(NL80211_IFTYPE_STATION)
+ }
+ };
+@@ -33,7 +33,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ {
+ .limits = if_limits,
+ .n_limits = ARRAY_SIZE(if_limits),
+- .max_interfaces = MT7996_MAX_INTERFACES,
++ .max_interfaces = MT7996_MAX_INTERFACES * 3,
+ .num_different_channels = 3,
+ .beacon_int_infra_match = true,
+ /*
+@@ -795,6 +795,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ mtk_wed_device_start(&dev->mt76.mmio.wed_hif2, MT_INT_TX_RX_DONE_EXT);
+ }
+
++ /* TODO: FIXME: force to use single wiphy, need to rework init flow */
++ phy->mt76->ori_hw = mphy->hw;
++ mphy->hw = dev->phy.mt76->hw;
++
+ return 0;
+
+ error:
+@@ -811,6 +815,9 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
+ if (!phy)
+ return;
+
++ /* TODO: FIXME: temp for single wiphy support */
++ phy->mt76->hw = phy->mt76->ori_hw;
++
+ mt7996_unregister_thermal(phy);
+
+ mphy = phy->dev->mt76.phys[band];
+@@ -1679,6 +1686,12 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ hw->wiphy->bands[NL80211_BAND_2GHZ] = &dev->phy.mt76->sband_2g.sband;
++ if (mt7996_phy2(dev))
++ hw->wiphy->bands[NL80211_BAND_5GHZ] = &mt7996_phy2(dev)->mt76->sband_5g.sband;
++ if (mt7996_phy3(dev))
++ hw->wiphy->bands[NL80211_BAND_6GHZ] = &mt7996_phy3(dev)->mt76->sband_6g.sband;
++
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
+ dev->recovery.hw_init_done = true;
+@@ -1708,11 +1721,11 @@ error:
+ void mt7996_unregister_device(struct mt7996_dev *dev)
+ {
+ cancel_work_sync(&dev->wed_rro.work);
+- mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
+- mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
+ mt7996_unregister_thermal(&dev->phy);
+ mt7996_coredump_unregister(dev);
+ mt76_unregister_device(&dev->mt76);
++ mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
++ mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
+ mt7996_wed_rro_free(dev);
+ mt7996_mcu_exit(dev);
+ mt7996_tx_token_put(dev);
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 3141fe4e4..e6db1765f 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2403,10 +2403,7 @@ void mt7996_mac_work(struct work_struct *work)
+
+ mt76_tx_status_check(mdev, false);
+
+- if (mphy->main_phy && !test_bit(MT76_STATE_RUNNING, &mphy->main_phy->state))
+- return;
+-
+- ieee80211_queue_delayed_work(mt76_main_hw(mphy), &mphy->mac_work,
++ ieee80211_queue_delayed_work(mphy->hw, &mphy->mac_work,
+ MT7996_WATCHDOG_TIME);
+ }
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index a38d77390..b9cc5a2e5 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -140,6 +140,10 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ int ret;
+
++ /* only allow settings from hw0 */
++ if (hw != dev->phy.mt76->hw)
++ return -1;
++
+ flush_work(&dev->init_work);
+
+ mutex_lock(&dev->mt76.mutex);
+@@ -154,6 +158,10 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+ int band;
+
++ /* only allow settings from hw0 */
++ if (hw != dev->phy.mt76->hw)
++ return;
++
+ cancel_delayed_work_sync(&dev->scs_work);
+
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
+@@ -173,7 +181,6 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+ mutex_lock(&dev->mt76.mutex);
+ mt7996_mcu_set_radio_en(phy, false);
+ clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+- phy->mt76->main_phy = NULL;
+ mutex_unlock(&dev->mt76.mutex);
+ }
+ }
+@@ -446,8 +453,11 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ mvif->dev = dev;
+ mvif->hw = hw;
+ mvif->sta.vif = mvif;
++ /* TODO: temporaily set this to prevent some crashes */
++ mvif->deflink.phy = phy;
+
+- ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
++ if (vif->type == NL80211_IFTYPE_STATION)
++ ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+@@ -543,10 +553,9 @@ out:
+ clear_bit(MT76_RESET, &phy->mt76->state);
+ mutex_unlock(&dev->mt76.mutex);
+
+- if (phy->mt76 == phy->mt76->main_phy)
+- mt76_txq_schedule_all(phy->mt76);
++ mt76_txq_schedule_all(phy->mt76);
+
+- ieee80211_queue_delayed_work(mt76_main_hw(phy->mt76),
++ ieee80211_queue_delayed_work(phy->mt76->hw,
+ &phy->mt76->mac_work,
+ MT7996_WATCHDOG_TIME);
+
+@@ -557,11 +566,11 @@ int mt7996_set_channel(struct mt7996_phy *phy, struct cfg80211_chan_def *chandef
+ {
+ int ret;
+
+- ieee80211_stop_queues(mt76_main_hw(phy->mt76));
++ ieee80211_stop_queues(phy->mt76->hw);
+ ret = __mt7996_set_channel(phy, chandef);
+ if (ret)
+ return ret;
+- ieee80211_wake_queues(mt76_main_hw(phy->mt76));
++ ieee80211_wake_queues(phy->mt76->hw);
+
+ return 0;
+ }
+@@ -769,9 +778,6 @@ static void mt7996_configure_filter(struct ieee80211_hw *hw,
+ continue;
+
+ tmp = dev->mt76.phys[band]->priv;
+- if (tmp->mt76->main_phy != phy->mt76)
+- continue;
+-
+ tmp->rxfilter = phy->rxfilter;
+ mt76_wr(dev, MT_WF_RFCR(tmp->mt76->band_idx), phy->rxfilter);
+
+@@ -1576,9 +1582,11 @@ static int
+ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+ {
+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- int max_nss = hweight8(hw->wiphy->available_antennas_tx);
+- u8 band_idx = phy->mt76->band_idx, shift = dev->chainshift[band_idx];
++ int band, max_nss = hweight8(hw->wiphy->available_antennas_tx);
++
++ /* only allow settings from hw0 */
++ if (hw != dev->phy.mt76->hw)
++ return 0;
+
+ if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss)
+ return -EINVAL;
+@@ -1588,20 +1596,34 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+
+ mutex_lock(&dev->mt76.mutex);
+
+- phy->mt76->antenna_mask = tx_ant;
++ for (band = 0; band < NUM_NL80211_BANDS; band++) {
++ struct mt7996_phy *phy;
++ u8 band_idx, shift;
++
++ if (!hw->wiphy->bands[band])
++ continue;
+
+- /* restore to the origin chainmask which might have auxiliary path */
+- if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2)
+- phy->mt76->chainmask = ((dev->chainmask >> shift) &
+- (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift;
+- else if (hweight8(tx_ant) == max_nss)
+- phy->mt76->chainmask = (dev->chainmask >> shift) << shift;
+- else
+- phy->mt76->chainmask = tx_ant << shift;
++ phy = mt7996_band_phy(hw, band);
++ if (!phy)
++ continue;
+
+- mt76_set_stream_caps(phy->mt76, true);
+- mt7996_set_stream_vht_txbf_caps(phy);
+- mt7996_set_stream_he_eht_caps(phy);
++ phy->mt76->antenna_mask = tx_ant;
++ band_idx = phy->mt76->band_idx;
++ shift = dev->chainshift[band_idx];
++
++ /* restore to the origin chainmask which might have auxiliary path */
++ if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2)
++ phy->mt76->chainmask = ((dev->chainmask >> shift) &
++ (BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift;
++ else if (hweight8(tx_ant) == max_nss)
++ phy->mt76->chainmask = (dev->chainmask >> shift) << shift;
++ else
++ phy->mt76->chainmask = tx_ant << shift;
++
++ mt76_set_stream_caps(phy->mt76, true);
++ mt7996_set_stream_vht_txbf_caps(phy);
++ mt7996_set_stream_he_eht_caps(phy);
++ }
+
+ mutex_unlock(&dev->mt76.mutex);
+
+@@ -2243,7 +2265,7 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ phy->scan_chan_idx = 0;
+ if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
+ (phy->mt76 != mvif->deflink.phy->mt76)) {
+- phy->mt76->main_phy = hw->priv;
++ // phy->mt76->main_phy = hw->priv;
+ mt7996_remove_bss_conf(vif, &vif->bss_conf, &mvif->deflink);
+
+ ret = mt7996_add_bss_conf(phy, vif, &vif->bss_conf);
+@@ -2254,7 +2276,7 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ }
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+- ieee80211_queue_delayed_work(mt76_main_hw(phy->mt76), &phy->scan_work, 0);
++ ieee80211_queue_delayed_work(phy->mt76->hw, &phy->scan_work, 0);
+
+ return 0;
+ }
+@@ -2262,7 +2284,7 @@ mt7996_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ static void
+ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ {
+- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ // struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ int band;
+
+ for (band = 0; band < NUM_NL80211_BANDS; band++) {
+@@ -2272,17 +2294,16 @@ mt7996_cancel_hw_scan(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
+ continue;
+
+ phy = mt7996_band_phy(hw, band);
+- if (!(test_bit(MT76_SCANNING, &phy->mt76->state) &&
+- phy->mt76->main_phy == hw->priv))
++ if (!test_bit(MT76_SCANNING, &phy->mt76->state))
+ continue;
+
+ cancel_delayed_work_sync(&phy->scan_work);
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ mt7996_scan_complete(phy, true);
+- if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
+- (phy->mt76 != mvif->deflink.phy->mt76))
+- phy->mt76->main_phy = NULL;
++ // if (vif->type == NL80211_IFTYPE_STATION && !ieee80211_vif_is_mld(vif) &&
++ // (phy->mt76 != mvif->deflink.phy->mt76))
++ // phy->mt76->main_phy = NULL;
+ mutex_unlock(&phy->dev->mt76.mutex);
+ }
+ }
+@@ -2297,7 +2318,6 @@ mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
+ wiphy_info(hw->wiphy, "%s: add %u\n", __func__, conf->def.chan->hw_value);
+ mutex_lock(&phy->dev->mt76.mutex);
+
+- phy->mt76->main_phy = hw->priv;
+ if (ctx->assigned) {
+ mutex_unlock(&phy->dev->mt76.mutex);
+ return -ENOSPC;
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 39aa3ee5b..0444ae58e 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -794,21 +794,19 @@ mt7996_get_background_radar_cap(struct mt7996_dev *dev)
+ static inline struct mt7996_phy *
+ mt7996_band_phy(struct ieee80211_hw *hw, enum nl80211_band band)
+ {
+- struct mt76_phy *phy = hw->priv;
+-
+- if (!(hw->wiphy->flags & WIPHY_FLAG_SUPPORTS_MLO))
+- return phy->priv;
++ struct mt76_dev *dev = hw->priv;
++ struct mt76_phy *phy;
+
+ /* TODO: mlo: temporarily hardcode */
+ if (band == NL80211_BAND_6GHZ)
+- phy = phy->dev->phys[MT_BAND2];
++ phy = dev->phys[MT_BAND2];
+ else if (band == NL80211_BAND_5GHZ)
+- phy = phy->dev->phys[MT_BAND1];
++ phy = dev->phys[MT_BAND1];
+ else
+- phy = phy->dev->phys[MT_BAND0];
++ phy = dev->phys[MT_BAND0];
+
+ if (!phy)
+- phy = hw->priv;
++ return NULL;
+
+ return phy->priv;
+ }
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0106-wifi-mt76-mt7996-implement-ieee80211_ops-for-link-de.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0106-wifi-mt76-mt7996-implement-ieee80211_ops-for-link-de.patch
new file mode 100644
index 0000000..53a5557
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0106-wifi-mt76-mt7996-implement-ieee80211_ops-for-link-de.patch
@@ -0,0 +1,157 @@
+From d17884fc654153615c5d6f6ac4192eed3ec34525 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 29 Dec 2023 18:37:41 +0800
+Subject: [PATCH 106/116] wifi: mt76: mt7996: implement ieee80211_ops for link
+ debugfs
+
+Add .link_sta_add_debugfs and .link_add_debugfs.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/debugfs.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mac.c | 4 +--
+ mt7996/main.c | 2 ++
+ mt7996/mcu.c | 6 +++--
+ mt7996/mt7996.h | 5 ++++
+ 5 files changed, 78 insertions(+), 4 deletions(-)
+
+diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
+index 56e219231..26927eda9 100644
+--- a/mt7996/debugfs.c
++++ b/mt7996/debugfs.c
+@@ -1307,4 +1307,69 @@ void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ debugfs_create_file("hw-queues", 0400, dir, sta, &mt7996_queues_fops);
+ }
+
++static int
++mt7996_link_sta_info_show(struct seq_file *file, void *data)
++{
++ struct ieee80211_link_sta *link_sta = file->private;
++ struct mt7996_sta *msta = (struct mt7996_sta *)link_sta->sta->drv_priv;
++ struct mt7996_link_sta *mlink;
++ struct mt7996_dev *dev = msta->vif->dev;
++ struct rate_info *r;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ mlink = mlink_dereference_protected(msta, link_sta->link_id);
++ r = &mlink->wcid.rate;
++ seq_printf(file, "tx rate: flags=0x%x,legacy=%u,mcs=%u,nss=%u,bw=%u,he_gi=%u,he_dcm=%u,he_ru_alloc=%u,eht_gi=%u,eht_ru_alloc=%u\n",
++ r->flags, r->legacy, r->mcs, r->nss, r->bw, r->he_gi, r->he_dcm, r->he_ru_alloc, r->eht_gi, r->eht_ru_alloc);
++ seq_printf(file, "tx_bytes=%llu\n", mlink->wcid.stats.tx_bytes);
++ seq_printf(file, "rx_bytes=%llu\n", mlink->wcid.stats.rx_bytes);
++ seq_printf(file, "tx_airtime=%llu\n", mlink->wcid.stats.tx_airtime);
++ seq_printf(file, "rx_airtime=%llu\n", mlink->wcid.stats.rx_airtime);
++
++ mutex_unlock(&dev->mt76.mutex);
++
++ return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(mt7996_link_sta_info);
++
++void mt7996_link_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_link_sta *link_sta,
++ struct dentry *dir)
++{
++ debugfs_create_file("link_sta_info", 0600, dir, link_sta,
++ &mt7996_link_sta_info_fops);
++}
++
++static int
++mt7996_link_info_show(struct seq_file *file, void *data)
++{
++ struct ieee80211_bss_conf *conf = file->private;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)conf->vif->drv_priv;
++ struct mt7996_sta *msta = &mvif->sta;
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_link_sta *mlink;
++ struct mt7996_dev *dev = mvif->dev;
++ struct rate_info *r;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ mconf = mconf_dereference_protected(mvif, conf->link_id);
++ mlink = mlink_dereference_protected(msta, conf->link_id);
++ r = &mlink->wcid.rate;
++ seq_printf(file, "band mapping=%u\n", mconf->phy->mt76->band_idx);
++ seq_printf(file, "tx rate: flags=0x%x,legacy=%u,mcs=%u,nss=%u,bw=%u,he_gi=%u,he_dcm=%u,he_ru_alloc=%u,eht_gi=%u,eht_ru_alloc=%u\n",
++ r->flags, r->legacy, r->mcs, r->nss, r->bw, r->he_gi, r->he_dcm, r->he_ru_alloc, r->eht_gi, r->eht_ru_alloc);
++
++ mutex_unlock(&dev->mt76.mutex);
++
++ return 0;
++}
++DEFINE_SHOW_ATTRIBUTE(mt7996_link_info);
++
++void mt7996_link_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *link_conf, struct dentry *dir)
++{
++ debugfs_create_file("link_info", 0600, dir, link_conf, &mt7996_link_info_fops);
++}
+ #endif
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index e6db1765f..5967b6aeb 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -2379,10 +2379,10 @@ void mt7996_mac_work(struct work_struct *work)
+ mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_RATE);
+ mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_AIRTIME);
+ mt7996_mcu_get_rssi(mdev);
+- if (mtk_wed_device_active(&mdev->mmio.wed)) {
++ // if (mtk_wed_device_active(&mdev->mmio.wed)) {
+ mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_ADM_STAT);
+ mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_MSDU_COUNT);
+- }
++ // }
+
+ if (mt7996_mcu_wa_cmd(phy->dev, MCU_WA_PARAM_CMD(QUERY), MCU_WA_PARAM_BSS_ACQ_PKT_CNT,
+ BSS_ACQ_PKT_CNT_BSS_BITMAP_ALL | BSS_ACQ_PKT_CNT_READ_CLR, 0))
+diff --git a/mt7996/main.c b/mt7996/main.c
+index b9cc5a2e5..64797f177 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -2602,6 +2602,8 @@ const struct ieee80211_ops mt7996_ops = {
+ CFG80211_TESTMODE_DUMP(mt76_testmode_dump)
+ #ifdef CONFIG_MAC80211_DEBUGFS
+ .sta_add_debugfs = mt7996_sta_add_debugfs,
++ .link_sta_add_debugfs = mt7996_link_sta_add_debugfs,
++ // .link_add_debugfs = mt7996_link_add_debugfs,
+ #endif
+ .set_radar_background = mt7996_set_radar_background,
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 39e353ab2..24489ac27 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -616,8 +616,10 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ wcid->stats.tx_packets += tx_packets;
+ wcid->stats.rx_packets += rx_packets;
+
+- __mt7996_stat_to_netdev(mphy, wcid, 0, 0,
+- tx_packets, rx_packets);
++ if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
++ __mt7996_stat_to_netdev(mphy, wcid, 0, 0,
++ tx_packets, rx_packets);
++ }
+ break;
+ case UNI_ALL_STA_TXRX_AIRTIME:
+ wlan_idx = le16_to_cpu(res->airtime[i].wlan_idx);
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 0444ae58e..dc3cacc3a 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -1138,6 +1138,11 @@ int mt7996_mcu_set_pp_en(struct mt7996_phy *phy, u8 mode, u16 bitmap);
+ #ifdef CONFIG_MAC80211_DEBUGFS
+ void mt7996_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct dentry *dir);
++void mt7996_link_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_link_sta *link_sta,
++ struct dentry *dir);
++void mt7996_link_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ struct ieee80211_bss_conf *link_conf, struct dentry *dir);
+ #endif
+ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
+ bool hif2, int *irq);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0107-mtk-wifi-mt76-mt7996-support-multi-link-channel-swit.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0107-mtk-wifi-mt76-mt7996-support-multi-link-channel-swit.patch
new file mode 100644
index 0000000..c7e57c9
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0107-mtk-wifi-mt76-mt7996-support-multi-link-channel-swit.patch
@@ -0,0 +1,169 @@
+From 7ece9b1ea9a8960f2ff94ac84754ddddf645b3a1 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Fri, 19 Jan 2024 14:04:03 +0800
+Subject: [PATCH 107/116] mtk: wifi: mt76: mt7996: support multi-link channel
+ switch
+
+mtk: wifi: mt76: mt7996: remove the limitation of radar detect width for mlo
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+mtk: wifi: mt76: mt7996: start and finalize channel switch on link basis
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+mtk: wifi: mt76: mt7996: fix DFS RDD init issue
+
+1. Add radar enabled flag in mt76_phy since hw->conf.radar_enabled
+is only used for non-chanctx driver.
+2. Add IEEE80211_CHANCTX_CHANGE_RADAR flag in change_chanctx for RDD
+DFS state update.
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+
+mtk: wifi: mt76: mt7996: fix background radar using wrong phy for mld ap
+
+mt7996_hw_phy will be phy0 for 3 link mld ap
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ mac80211.c | 2 +-
+ mt76.h | 1 +
+ mt7996/init.c | 2 --
+ mt7996/main.c | 12 +++++++++---
+ mt7996/mcu.c | 14 +++++++++++---
+ 5 files changed, 22 insertions(+), 9 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 20ab1db4d..6512dee61 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1797,7 +1797,7 @@ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
+ test_bit(MT76_SCANNING, &phy->state))
+ return MT_DFS_STATE_DISABLED;
+
+- if (!hw->conf.radar_enabled) {
++ if (!phy->radar_enabled) {
+ if ((hw->conf.flags & IEEE80211_CONF_MONITOR) &&
+ (phy->chandef.chan->flags & IEEE80211_CHAN_RADAR))
+ return MT_DFS_STATE_ACTIVE;
+diff --git a/mt76.h b/mt76.h
+index b77a2f76b..7919d9c99 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -849,6 +849,7 @@ struct mt76_phy {
+
+ struct mt76_channel_state *chan_state;
+ enum mt76_dfs_state dfs_state;
++ bool radar_enabled;
+ ktime_t survey_time;
+
+ u32 aggr_stats[32];
+diff --git a/mt7996/init.c b/mt7996/init.c
+index f374119f6..0dee6596f 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -36,13 +36,11 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ .max_interfaces = MT7996_MAX_INTERFACES * 3,
+ .num_different_channels = 3,
+ .beacon_int_infra_match = true,
+- /*
+ .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
+ BIT(NL80211_CHAN_WIDTH_20) |
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
+- */
+ }
+ };
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 64797f177..05efec469 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -2133,7 +2133,7 @@ static int
+ mt7996_set_radar_background(struct ieee80211_hw *hw,
+ struct cfg80211_chan_def *chandef)
+ {
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
++ struct mt7996_phy *phy = mt7996_band_phy(hw, NL80211_BAND_5GHZ);
+ struct mt7996_dev *dev = phy->dev;
+ int ret = -EINVAL;
+ bool running;
+@@ -2332,6 +2332,7 @@ mt7996_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *conf)
+ }
+
+ phy->chanctx = ctx;
++ phy->mt76->radar_enabled = conf->radar_enabled;
+ mutex_unlock(&phy->dev->mt76.mutex);
+
+ if (!mt76_testmode_enabled(phy->mt76) && !phy->mt76->test.bf_en) {
+@@ -2359,8 +2360,10 @@ mt7996_remove_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *co
+
+ mutex_lock(&phy->dev->mt76.mutex);
+ ctx->assigned = false;
+- if (ctx == phy->chanctx)
++ if (ctx == phy->chanctx) {
+ phy->chanctx = NULL;
++ phy->mt76->radar_enabled = false;
++ }
+ mutex_unlock(&phy->dev->mt76.mutex);
+ }
+
+@@ -2372,8 +2375,10 @@ mt7996_change_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *co
+ struct mt7996_phy *phy = ctx->phy;
+
+ wiphy_info(hw->wiphy, "%s: change %u, 0x%x\n", __func__, conf->def.chan->hw_value, changed);
+- if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH) {
++ if (changed & IEEE80211_CHANCTX_CHANGE_WIDTH ||
++ changed & IEEE80211_CHANCTX_CHANGE_RADAR) {
+ ctx->chandef = conf->def;
++ phy->mt76->radar_enabled = conf->radar_enabled;
+
+ mt7996_set_channel(phy, &ctx->chandef);
+ }
+@@ -2471,6 +2476,7 @@ mt7996_switch_vif_chanctx(struct ieee80211_hw *hw,
+ mutex_lock(&phy->dev->mt76.mutex);
+
+ phy->chanctx = new_ctx;
++ phy->mt76->radar_enabled = vifs->new_ctx->radar_enabled;
+ new_ctx->assigned = true;
+ new_ctx->chandef = vifs->new_ctx->def;
+ new_ctx->phy = phy;
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 24489ac27..dc719ecbe 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -357,10 +357,18 @@ int mt7996_mcu_wa_cmd(struct mt7996_dev *dev, int cmd, u32 a1, u32 a2, u32 a3)
+ static void
+ mt7996_mcu_csa_finish(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ {
+- if (!vif->bss_conf.csa_active || vif->type == NL80211_IFTYPE_STATION)
++ struct mt76_phy *mphy = (struct mt76_phy *)priv;
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct ieee80211_bss_conf *link_conf;
++ int link_id, band_idx = mphy->band_idx;
++
++ link_id = mvif->band_to_link[band_idx];
++ link_conf = rcu_dereference(vif->link_conf[link_id]);
++
++ if (!link_conf || !link_conf->csa_active || vif->type == NL80211_IFTYPE_STATION)
+ return;
+
+- ieee80211_csa_finish(vif, 0);
++ ieee80211_csa_finish(vif, link_id);
+ }
+
+ static void
+@@ -475,7 +483,7 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ case UNI_EVENT_IE_COUNTDOWN_CSA:
+ ieee80211_iterate_active_interfaces_atomic(mphy->hw,
+ IEEE80211_IFACE_ITER_RESUME_ALL,
+- mt7996_mcu_csa_finish, mphy->hw);
++ mt7996_mcu_csa_finish, mphy);
+ break;
+ case UNI_EVENT_IE_COUNTDOWN_BCC:
+ ieee80211_iterate_active_interfaces_atomic(mphy->hw,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0108-mtk-mt76-mt7996-hw_scan-ACS-channel-time-too-long-on.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0108-mtk-mt76-mt7996-hw_scan-ACS-channel-time-too-long-on.patch
new file mode 100644
index 0000000..d62352f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0108-mtk-mt76-mt7996-hw_scan-ACS-channel-time-too-long-on.patch
@@ -0,0 +1,41 @@
+From 469ce653f972aa5b6cf213418cfdcecffe0af924 Mon Sep 17 00:00:00 2001
+From: Michael-CY Lee <michael-cy.lee@mediatek.com>
+Date: Thu, 22 Feb 2024 11:09:10 +0800
+Subject: [PATCH 108/116] mtk: mt76: mt7996: hw_scan: ACS channel time too long
+ on duty channel
+
+This problem happens in SW scan and was already fixed.
+(https://gerrit.mediatek.inc/c/gateway/WiFi7/mac80211/mt76/+/8312969)
+
+This commit applys same solution for HW scan.
+
+CR-Id: WCNCR00289305
+Signed-off-by: Michael-CY Lee <michael-cy.lee@mediatek.com>
+---
+ mt7996/main.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 05efec469..6943b28ba 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -497,6 +497,7 @@ static void ___mt7996_set_channel(struct mt7996_phy *phy,
+ struct mt76_phy *mphy = phy->mt76;
+ bool offchannel = phy->scan_chan != NULL;
+ int timeout = HZ / 5;
++ unsigned long was_scanning = ieee80211_get_scanning(mphy->hw);
+
+ wait_event_timeout(mdev->tx_wait, !mt76_has_tx_pending(mphy), timeout);
+ mt76_update_survey(mphy);
+@@ -511,7 +512,7 @@ static void ___mt7996_set_channel(struct mt7996_phy *phy,
+ if (!offchannel)
+ mphy->main_chan = chandef->chan;
+
+- if (chandef->chan != mphy->main_chan)
++ if (chandef->chan != mphy->main_chan || was_scanning)
+ memset(mphy->chan_state, 0, sizeof(*mphy->chan_state));
+ }
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0109-wifi-mt76-mt7996-add-beacon-monitoring-in-driver-for.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0109-wifi-mt76-mt7996-add-beacon-monitoring-in-driver-for.patch
new file mode 100644
index 0000000..b7c620f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0109-wifi-mt76-mt7996-add-beacon-monitoring-in-driver-for.patch
@@ -0,0 +1,203 @@
+From 184ecc9c9c16bbc9b93a69c994194d8bf1e41e72 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Tue, 20 Feb 2024 10:08:01 +0800
+Subject: [PATCH 109/116] wifi: mt76: mt7996: add beacon monitoring in driver
+ for mlo
+
+Add beacon monitoring in driver since mac80211 does not
+support connect monitoring if WIPHY_FLAG_SUPPORTS_MLO is set.
+(IEEE80211_HW_CONNECTION_MONITOR should be set)
+
+CR-Id: WCNCR00274293
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Change-Id: I52211987abd6309bbb23dc648af3f377adf8982a
+---
+ mt7996/mac.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c | 50 +++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mt7996.h | 7 +++++++
+ 3 files changed, 113 insertions(+)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 5967b6aeb..2a45fc03d 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -565,6 +565,21 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ */
+ if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
+ *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
++ } else if (ieee80211_is_beacon(fc)) {
++ struct ieee80211_hw *hw = phy->mt76->hw;
++ struct ieee80211_sta *sta;
++ struct mt7996_sta *msta;
++ unsigned int link_id;
++
++ sta = ieee80211_find_sta_by_link_addrs(hw, hdr->addr2, NULL, &link_id);
++ if (!sta)
++ sta = ieee80211_find_sta_by_ifaddr(hw, hdr->addr2, NULL);
++
++ if (sta) {
++ msta = (struct mt7996_sta *)sta->drv_priv;
++ if (msta && msta->vif)
++ msta->vif->beacon_received_time[band_idx] = jiffies;
++ }
+ }
+ #ifdef CONFIG_MTK_VENDOR
+ if (phy->amnt_ctrl.enable && !ieee80211_is_beacon(fc))
+@@ -2956,6 +2971,47 @@ void mt7996_scan_work(struct work_struct *work)
+ ieee80211_queue_delayed_work(hw, &phy->scan_work, duration);
+ }
+
++void mt7996_beacon_mon_work(struct work_struct *work)
++{
++ struct mt7996_vif *mvif = container_of(work, struct mt7996_vif, beacon_mon_work.work);
++ struct ieee80211_vif *vif = container_of((void *)mvif, struct ieee80211_vif, drv_priv);
++ struct ieee80211_hw *hw = mvif->hw;
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ unsigned long next_time = ULONG_MAX, valid_links = vif->valid_links ?: BIT(0);
++ unsigned int link_id;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct ieee80211_bss_conf *conf;
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_phy *phy;
++ unsigned long timeout, loss_duration;
++
++ conf = link_conf_dereference_protected(vif, link_id);
++ mconf = mconf_dereference_protected(mvif, link_id);
++ if (!conf || !mconf)
++ continue;
++
++ phy = mconf->phy;
++ loss_duration = msecs_to_jiffies(MT7996_MAX_BEACON_LOSS * conf->beacon_int);
++ timeout = mvif->beacon_received_time[phy->mt76->band_idx] + loss_duration;
++ if (time_after_eq(jiffies, timeout)) {
++ mutex_unlock(&dev->mt76.mutex);
++ wiphy_info(hw->wiphy,
++ "link %d: detected beacon loss, start disconnecting\n",
++ link_id);
++ /* TODO: disconnect single link & handle link reconfiguration for MLD */
++ ieee80211_connection_loss(vif);
++ return;
++ }
++ next_time = min(next_time, timeout - jiffies);
++ }
++ mutex_unlock(&dev->mt76.mutex);
++
++ ieee80211_queue_delayed_work(hw, &mvif->beacon_mon_work, next_time);
++}
++
+ void mt7996_get_hw(struct mt76_dev *dev, struct mt76_wcid *wcid, u8 phy_idx,
+ struct ieee80211_hw **hw)
+ {
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 6943b28ba..e37f0c013 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -450,6 +450,7 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ is_zero_ether_addr(vif->addr))
+ phy->monitor_vif = vif;
+
++ INIT_DELAYED_WORK(&mvif->beacon_mon_work, mt7996_beacon_mon_work);
+ mvif->dev = dev;
+ mvif->hw = hw;
+ mvif->sta.vif = mvif;
+@@ -2565,6 +2566,54 @@ out:
+ return ret;
+ }
+
++static void
++mt7996_event_callback(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ const struct ieee80211_event *event)
++{
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++
++ mutex_lock(&dev->mt76.mutex);
++
++ switch (event->type) {
++ case MLME_EVENT:
++ if (event->u.mlme.data == ASSOC_EVENT &&
++ event->u.mlme.status == MLME_SUCCESS) {
++ struct ieee80211_bss_conf *conf;
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_phy *phy;
++ unsigned long cur, valid_links = vif->valid_links ?: BIT(0);
++ unsigned int link_id;
++ int next_time = INT_MAX;
++
++ cur = jiffies;
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ conf = link_conf_dereference_protected(vif, link_id);
++ mconf = mconf_dereference_protected(mvif, link_id);
++ if (conf && mconf) {
++ phy = mconf->phy;
++ mvif->beacon_received_time[phy->mt76->band_idx] = cur;
++ next_time = min(next_time,
++ MT7996_MAX_BEACON_LOSS *
++ conf->beacon_int);
++ }
++ }
++
++ ieee80211_queue_delayed_work(hw, &mvif->beacon_mon_work,
++ msecs_to_jiffies(next_time));
++ break;
++ }
++
++ cancel_delayed_work_sync(&mvif->beacon_mon_work);
++ break;
++ default:
++ break;
++ }
++
++ mutex_unlock(&dev->mt76.mutex);
++ return;
++}
++
+ const struct ieee80211_ops mt7996_ops = {
+ .tx = mt7996_tx,
+ .start = mt7996_start,
+@@ -2617,6 +2666,7 @@ const struct ieee80211_ops mt7996_ops = {
+ .net_fill_forward_path = mt7996_net_fill_forward_path,
+ .net_setup_tc = mt76_wed_net_setup_tc,
+ #endif
++ .event_callback = mt7996_event_callback,
+ .add_chanctx = mt7996_add_chanctx,
+ .remove_chanctx = mt7996_remove_chanctx,
+ .change_chanctx = mt7996_change_chanctx,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index dc3cacc3a..0412d7375 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -128,6 +128,8 @@
+
+ #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
+
++#define MT7996_MAX_BEACON_LOSS 50
++
+ struct mt7996_vif;
+ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+@@ -360,6 +362,10 @@ struct mt7996_vif {
+ u8 mld_remap_id;
+
+ u8 band_to_link[__MT_MAX_BAND];
++
++ /* for beacon monitoring */
++ struct delayed_work beacon_mon_work;
++ unsigned long beacon_received_time[__MT_MAX_BAND];
+ };
+
+ /* crash-dump */
+@@ -1113,6 +1119,7 @@ bool mt7996_rx_check(struct mt76_dev *mdev, void *data, int len);
+ void mt7996_stats_work(struct work_struct *work);
+ void mt7996_scan_work(struct work_struct *work);
+ void mt7996_scan_complete(struct mt7996_phy *phy, bool aborted);
++void mt7996_beacon_mon_work(struct work_struct *work);
+ int mt76_dfs_start_rdd(struct mt7996_dev *dev, bool force);
+ int mt7996_dfs_init_radar_detector(struct mt7996_phy *phy);
+ void mt7996_set_stream_he_eht_caps(struct mt7996_phy *phy);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0110-mtk-wifi-mt76-mt7996-support-band_idx-option-for-set.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0110-mtk-wifi-mt76-mt7996-support-band_idx-option-for-set.patch
new file mode 100644
index 0000000..c07333f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0110-mtk-wifi-mt76-mt7996-support-band_idx-option-for-set.patch
@@ -0,0 +1,180 @@
+From e9b712d9fa71f982a52ee20eb86929d8938ec7ca Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Mon, 4 Mar 2024 16:21:16 +0800
+Subject: [PATCH 110/116] mtk: wifi: mt76: mt7996: support band_idx option for
+ set_mu/get_mu vendor command
+
+The vendor command set_mu and get_mu should be executed with band_idx.
+With band_idx, driver can access the corrsponding phy by band_idx.
+
+CR-Id: WCNCR00240772
+Change-Id: Id33d5efd3752e767fc11e852836d9939e4d6a088
+Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
+---
+ mt7996/mcu.c | 26 +++++++++++++++++++-------
+ mt7996/mcu.h | 1 +
+ mt7996/vendor.c | 40 +++++++++++++++++++++++++++++++++++-----
+ mt7996/vendor.h | 1 +
+ 4 files changed, 56 insertions(+), 12 deletions(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index dc719ecbe..cd49f7058 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -5853,12 +5853,23 @@ int mt7996_mcu_set_vow_feature_ctrl(struct mt7996_phy *phy)
+ #ifdef CONFIG_MTK_VENDOR
+ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+ {
+- u8 mode, val;
++ u8 mode, val, band_idx;
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+- struct mt7996_phy *phy = mvif->deflink.phy;
++ struct mt7996_phy *phy;
++ struct mt76_phy *mphy;
+
+ mode = FIELD_GET(RATE_CFG_MODE, *((u32 *)data));
+ val = FIELD_GET(RATE_CFG_VAL, *((u32 *)data));
++ band_idx = FIELD_GET(RATE_CFG_BAND_IDX, *((u32 *)data));
++
++ if (!mt7996_band_valid(mvif->dev, band_idx))
++ goto error;
++
++ mphy = mvif->dev->mt76.phys[band_idx];
++ if (!mphy)
++ goto error;
++
++ phy = (struct mt7996_phy *)mphy->priv;
+
+ switch (mode) {
+ case RATE_PARAM_FIXED_OFDMA:
+@@ -5874,13 +5885,14 @@ void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+ phy->muru_onoff = MUMIMO_UL;
+ break;
+ case RATE_PARAM_AUTO_MU:
+- if (val < 0 || val > 15) {
+- printk("Wrong value! The value is between 0-15.\n");
+- break;
+- }
+- phy->muru_onoff = val;
++ phy->muru_onoff = val & GENMASK(3, 0);
+ break;
+ }
++
++ return;
++error:
++ dev_err(mvif->dev->mt76.dev, "Invalid band_idx to config\n");
++ return;
+ }
+
+ void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index ee36cf5ed..3d5a0c3c2 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -888,6 +888,7 @@ enum {
+ #endif
+ };
+
++#define RATE_CFG_BAND_IDX GENMASK(17, 16)
+ #define RATE_CFG_MODE GENMASK(15, 8)
+ #define RATE_CFG_VAL GENMASK(7, 0)
+
+diff --git a/mt7996/vendor.c b/mt7996/vendor.c
+index 31688c373..64ef5515c 100644
+--- a/mt7996/vendor.c
++++ b/mt7996/vendor.c
+@@ -16,6 +16,7 @@ mu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_MU_CTRL] = {
+ [MTK_VENDOR_ATTR_MU_CTRL_ONOFF] = {.type = NLA_U8 },
+ [MTK_VENDOR_ATTR_MU_CTRL_DUMP] = {.type = NLA_U8 },
+ [MTK_VENDOR_ATTR_MU_CTRL_STRUCT] = {.type = NLA_BINARY },
++ [MTK_VENDOR_ATTR_MU_CTRL_BAND_IDX] = {.type = NLA_U8 },
+ };
+
+ static const struct nla_policy
+@@ -135,7 +136,7 @@ static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ struct mt7996_muru *muru;
+ int err;
+- u8 val8;
++ u8 val8, band_idx;
+ u32 val32 = 0;
+
+ err = nla_parse(tb, MTK_VENDOR_ATTR_MU_CTRL_MAX, data, data_len,
+@@ -143,10 +144,13 @@ static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
+ if (err)
+ return err;
+
+- if (tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF]) {
++ if (tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF] &&
++ tb[MTK_VENDOR_ATTR_MU_CTRL_BAND_IDX]) {
+ val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF]);
++ band_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_MU_CTRL_BAND_IDX]);
+ val32 |= FIELD_PREP(RATE_CFG_MODE, RATE_PARAM_AUTO_MU) |
+- FIELD_PREP(RATE_CFG_VAL, val8);
++ FIELD_PREP(RATE_CFG_VAL, val8) |
++ FIELD_PREP(RATE_CFG_BAND_IDX, band_idx);
+ ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+ mt7996_set_wireless_vif, &val32);
+ } else if (tb[MTK_VENDOR_ATTR_MU_CTRL_STRUCT]) {
+@@ -168,18 +172,44 @@ mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
+ unsigned long *storage)
+ {
+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
+- struct mt7996_phy *phy = mt7996_hw_phy(hw);
+- int len = 0;
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt7996_phy *phy;
++ struct mt76_phy *mphy;
++ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_MU_CTRL];
++ int len = 0, err;
++ u8 band_idx;
+
+ if (*storage == 1)
+ return -ENOENT;
+ *storage = 1;
+
++ err = nla_parse(tb, MTK_VENDOR_ATTR_MU_CTRL_MAX, data, data_len,
++ mu_ctrl_policy, NULL);
++ if (err)
++ return err;
++
++ if (!tb[MTK_VENDOR_ATTR_MU_CTRL_BAND_IDX])
++ return -EINVAL;
++
++ band_idx = nla_get_u8(tb[MTK_VENDOR_ATTR_MU_CTRL_BAND_IDX]);
++ if (!mt7996_band_valid(dev, band_idx))
++ goto error;
++
++ mphy = dev->mt76.phys[band_idx];
++ if (!mphy)
++ goto error;
++
++ phy = (struct mt7996_phy *)mphy->priv;
++
+ if (nla_put_u8(skb, MTK_VENDOR_ATTR_MU_CTRL_DUMP, phy->muru_onoff))
+ return -ENOMEM;
+ len += 1;
+
+ return len;
++
++error:
++ dev_err(dev->mt76.dev, "Invalid band idx to dump\n");
++ return -EINVAL;
+ }
+
+ void mt7996_set_wireless_rts_sigta(struct ieee80211_hw *hw, u8 value) {
+diff --git a/mt7996/vendor.h b/mt7996/vendor.h
+index 0d1ef3228..323467756 100644
+--- a/mt7996/vendor.h
++++ b/mt7996/vendor.h
+@@ -68,6 +68,7 @@ enum mtk_vendor_attr_mu_ctrl {
+ MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
+ MTK_VENDOR_ATTR_MU_CTRL_DUMP,
+ MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
++ MTK_VENDOR_ATTR_MU_CTRL_BAND_IDX,
+
+ /* keep last */
+ NUM_MTK_VENDOR_ATTRS_MU_CTRL,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0111-mtk-wifi-mt76-mt7996-tmp-disable-VOW.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0111-mtk-wifi-mt76-mt7996-tmp-disable-VOW.patch
new file mode 100644
index 0000000..e8dd3e2
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0111-mtk-wifi-mt76-mt7996-tmp-disable-VOW.patch
@@ -0,0 +1,59 @@
+From bc25ea014bff5720ae8b2276dab96b7cc317635b Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 20 Mar 2024 22:56:44 +0800
+Subject: [PATCH 111/116] mtk: wifi: mt76: mt7996: tmp disable VOW
+
+FW will return failed when legacy 5G station connects after legacy 2G
+station, need to check.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mt7996/mcu.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index cd49f7058..1fd844c27 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2369,6 +2369,7 @@ int mt7996_mcu_add_rate_ctrl(struct mt7996_dev *dev,
+ return mt7996_mcu_add_rate_ctrl_fixed(dev, conf, mconf, link_sta, mlink);
+ }
+
++#if 0
+ static int
+ mt7996_mcu_sta_init_vow(struct mt7996_bss_conf *mconf,
+ struct mt7996_link_sta *mlink)
+@@ -2402,6 +2403,7 @@ mt7996_mcu_sta_init_vow(struct mt7996_bss_conf *mconf,
+
+ return mt7996_mcu_set_vow_drr_ctrl(phy, mconf, mlink, VOW_DRR_CTRL_STA_ALL);
+ }
++#endif
+
+ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ struct mt7996_bss_conf *mconf,
+@@ -2410,7 +2412,7 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ {
+ struct ieee80211_vif *vif = conf->vif;
+ struct sk_buff *skb;
+- int ret;
++ // int ret;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
+ &mlink->wcid,
+@@ -2455,11 +2457,13 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+ mt7996_mcu_sta_bfee_tlv(dev, skb, conf, mconf, link_sta);
+ }
+
++#if 0
+ ret = mt7996_mcu_sta_init_vow(mconf, mlink);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+ }
++#endif
+ out:
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0112-mtk-wifi-mt76-mt7996-enable-ampdu-limit-to-avoid-BA-.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0112-mtk-wifi-mt76-mt7996-enable-ampdu-limit-to-avoid-BA-.patch
new file mode 100644
index 0000000..b2a0fda
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0112-mtk-wifi-mt76-mt7996-enable-ampdu-limit-to-avoid-BA-.patch
@@ -0,0 +1,188 @@
+From d707638e405334b74dd27428876edb8c7703eafd Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 1 Apr 2024 17:00:21 +0800
+Subject: [PATCH 112/116] mtk: wifi: mt76: mt7996: enable ampdu limit to avoid
+ BA bound issue
+
+[Description]
+When the station is MTK device and the peak is higher than 15G, the PPS
+would exceed HW-RRO's bandwidth and lead to Rx fifo full and PER. When
+a link occurs PER, it may occupy SSN and the other two bands are not
+able to transmit.
+
+Limit AMPDU to 512 when satisify all of the following conditions
+1. BA winsize is 1024.
+2. At least one link use BW320 and its spatial stream is larger
+than 3.
+3. At least one link use BW160 and its spatial stream is larger
+than 3.
+
+By limiting AMPDU to 512, it can solve this issue.
+1. Reduce PPS so we can avoid Rx fifo full due to HW-RRO.
+2. If a bind occupy SSN, the other two bands can use the SSN
+between 512 to 1024.
+
+[Release-log]
+N/A
+
+CR-Id: WCNCR00240772
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Change-Id: I64ea1d5df012c1eb9462391e5e9c20658ed7f4fe
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/mcu.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h | 8 +++++
+ 3 files changed, 95 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 41e26b8a4..b592890ca 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -821,6 +821,7 @@ enum {
+ STA_REC_KEY_V3 = 0x27,
+ STA_REC_HDRT = 0x28,
+ STA_REC_HDR_TRANS = 0x2B,
++ STA_REC_TX_CAP = 0x2f,
+ STA_REC_MAX_NUM
+ };
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 1fd844c27..db6aa24ed 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1344,6 +1344,85 @@ mt7996_mcu_sta_ba(struct mt7996_dev *dev, struct mt76_vif *mvif,
+ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
+ }
+
++static int
++mt7996_mcu_sta_tx_cap(struct mt7996_dev *dev, struct mt76_vif *mvif,
++ struct mt76_wcid *wcid)
++{
++ struct sta_rec_tx_cap *tx_cap;
++ struct sk_buff *skb;
++ struct tlv *tlv;
++
++ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, mvif, wcid,
++ MT7996_STA_UPDATE_MAX_SIZE);
++ if (IS_ERR(skb))
++ return PTR_ERR(skb);
++
++ tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_TX_CAP, sizeof(*tx_cap));
++
++ tx_cap = (struct sta_rec_tx_cap *)tlv;
++ tx_cap->ampdu_limit_en = true;
++
++ dev_info(dev->mt76.dev, "%s: limit wcid %d ampdu to 512\n", __func__, wcid->idx);
++
++ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
++ MCU_WMWA_UNI_CMD(STA_REC_UPDATE), true);
++}
++
++static bool mt7996_check_limit_ampdu_en(struct ieee80211_ampdu_params *params) {
++ struct ieee80211_sta *sta = params->sta;
++ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
++ unsigned long valid_links = sta->valid_links ?: BIT(0);
++ unsigned int link_id;
++ bool BW320 = false, BW160 = false;
++
++ if (params->buf_size < 1024)
++ return false;
++
++ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
++ struct ieee80211_link_sta __rcu *link =
++ link_sta_dereference_protected(sta, link_id);
++ struct mt7996_bss_conf *mconf =
++ mconf_dereference_protected(msta->vif, link_id);
++ struct mt76_phy *phy = mconf->phy->mt76;
++ struct ieee80211_eht_mcs_nss_supp_bw *ss = NULL;
++ u8 sta_bw, ap_nss, sta_nss;
++
++ switch (phy->chandef.width) {
++ case NL80211_CHAN_WIDTH_160:
++ if (link->bandwidth >= IEEE80211_STA_RX_BW_160) {
++ ss = &link->eht_cap.eht_mcs_nss_supp.bw._160;
++ sta_bw = NL80211_CHAN_WIDTH_160;
++ }
++ break;
++ case NL80211_CHAN_WIDTH_320:
++ if (link->bandwidth == IEEE80211_STA_RX_BW_320) {
++ ss = &link->eht_cap.eht_mcs_nss_supp.bw._320;
++ sta_bw = NL80211_CHAN_WIDTH_320;
++ }
++ break;
++ default:
++ break;
++ }
++
++ if (!ss)
++ continue;
++
++ ap_nss = hweight8(phy->antenna_mask);
++ sta_nss = max(u8_get_bits(ss->rx_tx_mcs11_max_nss, IEEE80211_EHT_MCS_NSS_RX),
++ u8_get_bits(ss->rx_tx_mcs13_max_nss, IEEE80211_EHT_MCS_NSS_RX));
++
++ if (min(ap_nss, sta_nss) <= 2)
++ continue;
++
++ if (sta_bw == NL80211_CHAN_WIDTH_160)
++ BW160 = true;
++ else if (sta_bw == NL80211_CHAN_WIDTH_320)
++ BW320 = true;
++ }
++
++ return BW320 && BW160;
++}
++
+ /** starec & wtbl **/
+ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ struct ieee80211_ampdu_params *params,
+@@ -1353,6 +1432,7 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ unsigned long valid_links = sta->valid_links ?: BIT(0);
+ unsigned int link_id;
++ bool limit_ampdu_en = mt7996_check_limit_ampdu_en(params);
+
+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt7996_link_sta *mlink =
+@@ -1368,6 +1448,12 @@ int mt7996_mcu_add_tx_ba(struct mt7996_dev *dev,
+ &mlink->wcid, enable, true);
+ if (ret)
+ return ret;
++
++ if (limit_ampdu_en) {
++ ret = mt7996_mcu_sta_tx_cap(dev, &mconf->mt76, &mlink->wcid);
++ if (ret)
++ return ret;
++ }
+ }
+
+ return 0;
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index 3d5a0c3c2..a1ac18f72 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -579,6 +579,13 @@ struct sta_rec_ba_uni {
+ u8 __rsv[3];
+ } __packed;
+
++struct sta_rec_tx_cap {
++ __le16 tag;
++ __le16 len;
++ u8 ampdu_limit_en;
++ u8 rsv[3];
++} __packed;
++
+ struct sta_rec_eht {
+ __le16 tag;
+ __le16 len;
+@@ -945,6 +952,7 @@ enum {
+ sizeof(struct sta_rec_eht) + \
+ sizeof(struct sta_rec_hdrt) + \
+ sizeof(struct sta_rec_hdr_trans) + \
++ sizeof(struct sta_rec_tx_cap) + \
+ sizeof(struct tlv))
+
+ #define MT7996_MAX_BEACON_SIZE 1338
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0113-wifi-mt76-mt7996-Fix-get_txpower-wrong-result-in-sin.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0113-wifi-mt76-mt7996-Fix-get_txpower-wrong-result-in-sin.patch
new file mode 100644
index 0000000..7b9c302
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0113-wifi-mt76-mt7996-Fix-get_txpower-wrong-result-in-sin.patch
@@ -0,0 +1,66 @@
+From 4449a5a89e46ab7ce56ca6313fda11c6767dde8d Mon Sep 17 00:00:00 2001
+From: Allen Ye <allen.ye@mediatek.com>
+Date: Mon, 8 Apr 2024 16:56:09 +0800
+Subject: [PATCH 113/116] wifi: mt76: mt7996: Fix get_txpower wrong result in
+ single wiphy and legacy mode
+
+Fix get_txpower wrong result in single wiphy and legacy mode.
+ieee80211_hw is get from wiphy0, so we need to get correct phy from vif.
+
+Temporarily use link 0 bss due to mac80211 didn't pass link id here.
+
+CR-Id: WCNCR00259302
+Change-Id: I306897ded276b0e5aee191339f18f0f25ca322f2
+---
+ mt7996/main.c | 28 +++++++++++++++++++++++++++-
+ 1 file changed, 27 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index e37f0c013..7abee0c57 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -975,6 +975,32 @@ out:
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
++int mt7996_get_txpower(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++ int *dbm)
++{
++ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++ struct mt7996_bss_conf *mconf;
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ struct mt76_phy *mphy;
++ int delta;
++
++ mutex_lock(&dev->mt76.mutex);
++ mconf = mconf_dereference_protected(mvif, mvif->master_link_id);
++ if (!mconf || !mconf->phy) {
++ *dbm = 0;
++ goto out;
++ }
++
++ mphy = mconf->phy->mt76;
++
++ delta = mt76_tx_power_nss_delta(hweight16(mphy->chainmask));
++
++ *dbm = DIV_ROUND_UP(mphy->txpower_cur + delta, 2);
++out:
++ mutex_unlock(&dev->mt76.mutex);
++ return 0;
++}
++
+ static void
+ mt7996_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+@@ -2635,7 +2661,7 @@ const struct ieee80211_ops mt7996_ops = {
+ .hw_scan = mt7996_hw_scan,
+ .cancel_hw_scan = mt7996_cancel_hw_scan,
+ .release_buffered_frames = mt76_release_buffered_frames,
+- .get_txpower = mt76_get_txpower,
++ .get_txpower = mt7996_get_txpower,
+ .channel_switch_beacon = mt7996_channel_switch_beacon,
+ .get_stats = mt7996_get_stats,
+ .get_et_sset_count = mt7996_get_et_sset_count,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0114-mtk-wifi-mt76-mt7996-add-beacon_int_min_gcd-to-suppo.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0114-mtk-wifi-mt76-mt7996-add-beacon_int_min_gcd-to-suppo.patch
new file mode 100644
index 0000000..c997806
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0114-mtk-wifi-mt76-mt7996-add-beacon_int_min_gcd-to-suppo.patch
@@ -0,0 +1,36 @@
+From 8da22299c32a6f07912f8d4333b2c5a904d03a0a Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Fri, 19 Apr 2024 11:01:21 +0800
+Subject: [PATCH 114/116] mtk: wifi: mt76: mt7996: add beacon_int_min_gcd to
+ support different beacon interval
+
+When beacon_int_min_gcd is zero, all beacon intervals for different
+interfaces should be same. If beacon_int_min_gcd is larger than zero,
+all beacon intervals for different interfaces should be larger or
+equal than beacon_int_min_gcd.
+
+Without this patch, set beacon fail when different interfaces use
+different beacon interval.
+
+CR-Id: WCNCR00240772
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Change-Id: Ic92582c86f6bf41b58ac1dd03175289a16be32c8
+---
+ mt7996/init.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 0dee6596f..3af9d02fe 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -41,6 +41,7 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ BIT(NL80211_CHAN_WIDTH_40) |
+ BIT(NL80211_CHAN_WIDTH_80) |
+ BIT(NL80211_CHAN_WIDTH_160),
++ .beacon_int_min_gcd = 100,
+ }
+ };
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2026-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0115-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch
similarity index 93%
rename from recipes-wifi/linux-mt76/files/patches-3.x/2026-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0115-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch
index 9cece6d..68acfd9 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2026-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0115-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch
@@ -1,29 +1,31 @@
-From 7bbed79a6d043eb149cf3b6be7982ae845ad8450 Mon Sep 17 00:00:00 2001
+From 4e663529b04108914d4d684a50ab4c3accb9f232 Mon Sep 17 00:00:00 2001
From: mtk20656 <chank.chen@mediatek.com>
Date: Sat, 20 Jan 2024 12:03:24 +0800
-Subject: [PATCH 2026/2032] mtk: wifi: mt76: mt7996: Add connac3 csi feature.
+Subject: [PATCH 115/116] mtk: wifi: mt76: mt7996: Add connac3 csi feature.
1. format align to wifi6.
2. add bw320 support.
3. add active mode.
+CR-Id: WCNCR00364748
+Change-Id: If37ac6de4781c3673671707ee3ee243dda8163f8
Signed-off-by: mtk20656 <chank.chen@mediatek.com>
---
mt76_connac_mcu.h | 2 +
mt7996/init.c | 22 +++
- mt7996/main.c | 4 +
+ mt7996/main.c | 3 +
mt7996/mcu.c | 465 ++++++++++++++++++++++++++++++++++++++++++++++
mt7996/mcu.h | 105 +++++++++++
mt7996/mt7996.h | 55 ++++++
mt7996/vendor.c | 208 +++++++++++++++++++++
mt7996/vendor.h | 50 +++++
- 8 files changed, 911 insertions(+)
+ 8 files changed, 910 insertions(+)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 97c2f5c0..8c0200a3 100644
+index b592890ca..680c08ed7 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
-@@ -1049,6 +1049,7 @@ enum {
+@@ -1052,6 +1052,7 @@ enum {
MCU_UNI_EVENT_THERMAL = 0x35,
MCU_UNI_EVENT_NIC_CAPAB = 0x43,
MCU_UNI_EVENT_TESTMODE_CTRL = 0x46,
@@ -31,7 +33,7 @@
MCU_UNI_EVENT_WED_RRO = 0x57,
MCU_UNI_EVENT_PER_STA_INFO = 0x6d,
MCU_UNI_EVENT_ALL_STA_INFO = 0x6e,
-@@ -1284,6 +1285,7 @@ enum {
+@@ -1288,6 +1289,7 @@ enum {
MCU_UNI_CMD_TESTMODE_TRX_PARAM = 0x42,
MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
MCU_UNI_CMD_PRECAL_RESULT = 0x47,
@@ -40,10 +42,10 @@
MCU_UNI_CMD_RRO = 0x57,
MCU_UNI_CMD_OFFCH_SCAN_CTRL = 0x58,
diff --git a/mt7996/init.c b/mt7996/init.c
-index bc8cfdbd..a3d7a2ed 100644
+index 3af9d02fe..ff72aabed 100644
--- a/mt7996/init.c
+++ b/mt7996/init.c
-@@ -734,6 +734,24 @@ error:
+@@ -806,6 +806,24 @@ error:
return ret;
}
@@ -68,9 +70,9 @@
static void
mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
{
-@@ -742,6 +760,10 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
- if (!phy)
- return;
+@@ -817,6 +835,10 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
+ /* TODO: FIXME: temp for single wiphy support */
+ phy->mt76->hw = phy->mt76->ori_hw;
+#ifdef CONFIG_MTK_VENDOR
+ mt7996_unregister_csi(phy);
@@ -80,25 +82,24 @@
mphy = phy->dev->mt76.phys[band];
diff --git a/mt7996/main.c b/mt7996/main.c
-index ca8e6125..97101985 100644
+index 7abee0c57..8dca88ac2 100644
--- a/mt7996/main.c
+++ b/mt7996/main.c
-@@ -797,6 +797,10 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
- int i;
+@@ -1292,6 +1292,9 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
+ unsigned long rem = sta->valid_links ?: BIT(0);
+#ifdef CONFIG_MTK_VENDOR
+ mt7996_mcu_set_csi(&dev->phy, 2, 8, 1, 0, sta->addr);
+#endif
-+
- mt7996_mcu_add_sta(dev, vif, sta, false);
+ mt7996_mac_sta_remove_links(dev, vif, sta, rem);
+ }
- mt7996_mac_wtbl_update(dev, msta->wcid.idx,
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 52651693..9e04ea2b 100644
+index db6aa24ed..d8e3181b1 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -638,6 +638,263 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -653,6 +653,263 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
}
}
@@ -362,7 +363,7 @@
static void
mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
{
-@@ -881,6 +1138,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -896,6 +1153,11 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
case MCU_UNI_EVENT_BF:
mt7996_mcu_rx_bf_event(dev, skb);
break;
@@ -374,9 +375,9 @@
#endif
default:
break;
-@@ -5671,4 +5933,207 @@ void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
+@@ -5995,4 +6257,207 @@ void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
- mt7996_mcu_add_beacon(hw, vif, val);
+ mt7996_mcu_add_beacon(hw, &vif->bss_conf, &mvif->deflink, val);
}
+
+static int mt7996_mcu_set_csi_enable(struct mt7996_phy *phy, u16 tag)
@@ -498,7 +499,7 @@
+void mt7996_csi_wcid_bitmap_update(void *data, struct ieee80211_sta *sta)
+{
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
-+ struct mt7996_phy *phy = msta->vif->phy;
++ struct mt7996_phy *phy = msta->vif->deflink.phy;
+ struct csi_bitmap_info_update *sta_info = (struct csi_bitmap_info_update *)data;
+ u16 wcid = 0;
+
@@ -506,7 +507,7 @@
+#define CSI_ACTIVE_MODE_REMOVE 0
+
+ if (!memcmp(sta_info->addr, sta->addr, ETH_ALEN)) {
-+ wcid = msta->wcid.idx;
++ wcid = msta->deflink.wcid.idx;
+
+ /* active mode: only support station with wcid less than 32 */
+ if (wcid > 32)
@@ -583,10 +584,10 @@
+}
#endif
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 9dc7946b..7721a01b 100644
+index a1ac18f72..dc93fab25 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
-@@ -1112,4 +1112,109 @@ struct fixed_rate_table_ctrl {
+@@ -1159,4 +1159,109 @@ struct fixed_rate_table_ctrl {
u8 _rsv2;
} __packed;
@@ -697,10 +698,10 @@
+
#endif
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index f1308112..f172eea2 100644
+index 0412d7375..0d537fb9b 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
-@@ -405,6 +405,47 @@ struct mt7996_air_monitor_ctrl {
+@@ -438,6 +438,47 @@ struct mt7996_air_monitor_ctrl {
struct mt7996_air_monitor_group group[MT7996_AIR_MONITOR_MAX_GROUP];
struct mt7996_air_monitor_entry entry[MT7996_AIR_MONITOR_MAX_ENTRY];
};
@@ -748,7 +749,7 @@
#endif
struct mt7996_rro_ba_session {
-@@ -482,6 +523,18 @@ struct mt7996_phy {
+@@ -534,6 +575,18 @@ struct mt7996_phy {
u8 rts_bw_sig;
spinlock_t amnt_lock;
struct mt7996_air_monitor_ctrl amnt_ctrl;
@@ -767,7 +768,7 @@
#endif
#ifdef CONFIG_MTK_DEBUG
bool sr_enable:1;
-@@ -996,6 +1049,8 @@ void mt7996_mcu_set_mimo(struct mt7996_phy *phy);
+@@ -1166,6 +1219,8 @@ void mt7996_mcu_set_mimo(struct mt7996_phy *phy);
int mt7996_set_muru_cfg(struct mt7996_phy *phy, u8 action, u8 val);
int mt7996_mcu_set_muru_cfg(struct mt7996_phy *phy, void *data);
void mt7996_set_beacon_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
@@ -777,10 +778,10 @@
int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index c87cc5c1..c37f1dba 100644
+index 64ef5515c..07c0c367f 100644
--- a/mt7996/vendor.c
+++ b/mt7996/vendor.c
-@@ -117,6 +117,18 @@ beacon_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BEACON_CTRL] = {
+@@ -119,6 +119,18 @@ beacon_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BEACON_CTRL] = {
[MTK_VENDOR_ATTR_BEACON_CTRL_MODE] = { .type = NLA_U8 },
};
@@ -799,7 +800,7 @@
struct mt7996_amnt_data {
u8 idx;
u8 addr[ETH_ALEN];
-@@ -932,7 +944,188 @@ static int mt7996_vendor_beacon_ctrl(struct wiphy *wiphy,
+@@ -1000,7 +1012,188 @@ static int mt7996_vendor_beacon_ctrl(struct wiphy *wiphy,
return 0;
}
@@ -988,7 +989,7 @@
static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
{
-@@ -1061,6 +1254,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
+@@ -1129,6 +1322,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
.policy = beacon_ctrl_policy,
.maxattr = MTK_VENDOR_ATTR_BEACON_CTRL_MAX,
},
@@ -1007,7 +1008,7 @@
};
void mt7996_vendor_register(struct mt7996_phy *phy)
-@@ -1068,6 +1273,9 @@ void mt7996_vendor_register(struct mt7996_phy *phy)
+@@ -1136,6 +1341,9 @@ void mt7996_vendor_register(struct mt7996_phy *phy)
phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
@@ -1018,7 +1019,7 @@
}
#endif
diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index e7d88828..7c9d12bb 100644
+index 323467756..abe3fdeab 100644
--- a/mt7996/vendor.h
+++ b/mt7996/vendor.h
@@ -7,6 +7,7 @@
@@ -1029,7 +1030,7 @@
MTK_NL80211_VENDOR_SUBCMD_RFEATURE_CTRL = 0xc3,
MTK_NL80211_VENDOR_SUBCMD_WIRELESS_CTRL = 0xc4,
MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
-@@ -238,6 +239,55 @@ enum mtk_vendor_attr_beacon_ctrl {
+@@ -240,6 +241,55 @@ enum mtk_vendor_attr_beacon_ctrl {
NUM_MTK_VENDOR_ATTRS_BEACON_CTRL - 1
};
@@ -1086,5 +1087,5 @@
#endif
--
-2.18.0
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0116-mtk-wifi-mt76-mt7996-add-more-debug-info-for-MLO.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0116-mtk-wifi-mt76-mt7996-add-more-debug-info-for-MLO.patch
new file mode 100644
index 0000000..5cc3522
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0116-mtk-wifi-mt76-mt7996-add-more-debug-info-for-MLO.patch
@@ -0,0 +1,2140 @@
+From 42e52bb5cc78f560047d602325a38709eed0d0ca Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Mon, 22 Apr 2024 11:06:48 +0800
+Subject: [PATCH 116/116] mtk: wifi: mt76: mt7996: add more debug info for MLO
+
+---
+ mt76_connac_mcu.c | 1 +
+ mt76_connac_mcu.h | 1 +
+ mt7996/debugfs.c | 34 +-
+ mt7996/mac.c | 15 +
+ mt7996/main.c | 14 +
+ mt7996/mcu.c | 18 +
+ mt7996/mcu.h | 8 +
+ mt7996/mt7996.h | 20 +
+ mt7996/mtk_debug.h | 660 +++++++++++++++++++++++++
+ mt7996/mtk_debugfs.c | 1085 ++++++++++++++++++++++++++++++++++++++++++
+ 10 files changed, 1847 insertions(+), 9 deletions(-)
+
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index 71f3d301c..a4924c4e4 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -433,6 +433,7 @@ void mt76_connac_mcu_sta_basic_tlv(struct mt76_dev *dev, struct sk_buff *skb,
+ }
+
+ memcpy(basic->peer_addr, link_sta->addr, ETH_ALEN);
++ pr_info("%s: link %u addr [%pM]\n", __func__, link_sta->link_id, basic->peer_addr);
+ basic->qos = sta->wme;
+ }
+ EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_basic_tlv);
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 680c08ed7..6fde64bac 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1285,6 +1285,7 @@ enum {
+ MCU_UNI_CMD_THERMAL = 0x35,
+ MCU_UNI_CMD_VOW = 0x37,
+ MCU_UNI_CMD_PP = 0x38,
++ MCU_UNI_CMD_MEC = 0x3a,
+ MCU_UNI_CMD_FIXED_RATE_TABLE = 0x40,
+ MCU_UNI_CMD_TESTMODE_TRX_PARAM = 0x42,
+ MCU_UNI_CMD_TESTMODE_CTRL = 0x46,
+diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
+index 26927eda9..77349c263 100644
+--- a/mt7996/debugfs.c
++++ b/mt7996/debugfs.c
+@@ -314,15 +314,17 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
+ DEBUG_CMD_RPT_TRIG,
+ DEBUG_SPL,
+ DEBUG_RPT_RX,
+- DEBUG_RPT_RA = 68,
+ DEBUG_IDS_SND = 84,
++ DEBUG_IDS_BSRP,
++ DEBUG_IDS_TPUT_MON,
+ DEBUG_IDS_PP = 93,
+- DEBUG_IDS_RA = 94,
+- DEBUG_IDS_BF = 95,
+- DEBUG_IDS_SR = 96,
+- DEBUG_IDS_RU = 97,
+- DEBUG_IDS_MUMIMO = 98,
+- DEBUG_IDS_ERR_LOG = 101,
++ DEBUG_IDS_RA,
++ DEBUG_IDS_BF,
++ DEBUG_IDS_SR,
++ DEBUG_IDS_RU,
++ DEBUG_IDS_MUMIMO,
++ DEBUG_IDS_MLO = 100,
++ DEBUG_IDS_ERR_LOG,
+ };
+ u8 debug_category[] = {
+ DEBUG_TXCMD,
+@@ -330,14 +332,16 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
+ DEBUG_CMD_RPT_TRIG,
+ DEBUG_SPL,
+ DEBUG_RPT_RX,
+- DEBUG_RPT_RA,
+ DEBUG_IDS_SND,
++ DEBUG_IDS_BSRP,
++ DEBUG_IDS_TPUT_MON,
+ DEBUG_IDS_PP,
+ DEBUG_IDS_RA,
+ DEBUG_IDS_BF,
+ DEBUG_IDS_SR,
+ DEBUG_IDS_RU,
+ DEBUG_IDS_MUMIMO,
++ DEBUG_IDS_MLO,
+ DEBUG_IDS_ERR_LOG,
+ };
+ bool tx, rx, en;
+@@ -372,7 +376,8 @@ mt7996_fw_debug_wm_set(void *data, u64 val)
+ if (ret)
+ return ret;
+
+- if (debug_category[i] == DEBUG_IDS_SND && en) {
++ if ((debug_category[i] == DEBUG_TXCMD ||
++ debug_category[i] == DEBUG_IDS_SND) && en) {
+ ret = mt7996_mcu_fw_dbg_ctrl(dev, debug_category[i], 2);
+ if (ret)
+ return ret;
+@@ -506,6 +511,14 @@ mt7996_fw_debug_bin_set(void *data, u64 val)
+ if (ret)
+ return ret;
+
++#ifdef CONFIG_MTK_DEBUG
++ dev->dbg.dump_mcu_pkt = val & BIT(4) ? true : false;
++ dev->dbg.dump_txd = val & BIT(5) ? true : false;
++ dev->dbg.dump_tx_pkt = val & BIT(6) ? true : false;
++ dev->dbg.dump_rx_pkt = val & BIT(7) ? true : false;
++ dev->dbg.dump_rx_raw = val & BIT(8) ? true : false;
++#endif
++
+ return mt7996_fw_debug_wm_set(dev, dev->fw_debug_wm);
+ }
+
+@@ -1208,6 +1221,9 @@ void mt7996_debugfs_rx_fw_monitor(struct mt7996_dev *dev, const void *data, int
+ bool mt7996_debugfs_rx_log(struct mt7996_dev *dev, const void *data, int len)
+ {
+ bool is_fwlog = get_unaligned_le32(data) == FW_BIN_LOG_MAGIC;
++#ifdef CONFIG_MTK_DEBUG
++ is_fwlog |= get_unaligned_le32(data) == PKT_BIN_DEBUG_MAGIC;
++#endif
+
+ if (is_fwlog) {
+ if (dev->relay_fwlog)
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 2a45fc03d..a8cf24c3c 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -331,6 +331,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ u8 hw_aggr = false;
+ struct mt7996_link_sta *mlink = NULL;
+
++#ifdef CONFIG_MTK_DEBUG
++ if (dev->dbg.dump_rx_raw)
++ mt7996_packet_log_to_host(dev, skb->data, skb->len, PKT_BIN_DEBUG_RX_RAW, 0);
++#endif
+ hw_aggr = status->aggr;
+ memset(status, 0, sizeof(*status));
+
+@@ -511,6 +515,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
+ }
+
+ hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
++#ifdef CONFIG_MTK_DEBUG
++ if (dev->dbg.dump_rx_pkt)
++ mt7996_packet_log_to_host(dev, skb->data, skb->len, PKT_BIN_DEBUG_RX, hdr_gap);
++#endif
+ if (hdr_trans && ieee80211_has_morefrags(fc)) {
+ if (mt7996_reverse_frag0_hdr_trans(skb, hdr_gap))
+ return -EINVAL;
+@@ -967,6 +975,13 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ tx_info->buf[1].skip_unmap = true;
+ tx_info->nbuf = MT_CT_DMA_BUF_NUM;
+
++#ifdef CONFIG_MTK_DEBUG
++ if (dev->dbg.dump_txd)
++ mt7996_packet_log_to_host(dev, txwi, MT_TXD_SIZE, PKT_BIN_DEBUG_TXD, 0);
++ if (dev->dbg.dump_tx_pkt)
++ mt7996_packet_log_to_host(dev, t->skb->data, t->skb->len, PKT_BIN_DEBUG_TX, 0);
++#endif
++
+ return 0;
+ }
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 8dca88ac2..74b874758 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -431,6 +431,9 @@ static int mt7996_add_bss_conf(struct mt7996_phy *phy,
+ rcu_assign_pointer(mvif->link[link_id], mconf);
+ rcu_assign_pointer(mvif->sta.link[link_id], mlink);
+
++ mlo_dbg(phy, "bss_idx=%u, link_id=%u, wcid=%u\n",
++ mconf->mt76.idx, mconf->link_id, mlink->wcid.idx);
++
+ return 0;
+ error:
+ mt7996_remove_bss_conf(vif, conf, mconf);
+@@ -603,6 +606,11 @@ static int mt7996_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+ add = vif->valid_links ?: BIT(0);
+ }
+
++ mlo_dbg(mt7996_hw_phy(hw), "cipher = 0x%x, icv_len = %u, iv_len = %u, hw_key_idx = %u, keyidx = %d, flags = 0x%x, link_id = %d, keylen = %u\n",
++ key->cipher, key->icv_len, key->iv_len, key->hw_key_idx, key->keyidx, key->flags, key->link_id, key->keylen);
++ // print_hex_dump(KERN_INFO , "", DUMP_PREFIX_OFFSET, 16, 1, key->key, key->keylen, false);
++ mlo_dbg(mt7996_hw_phy(hw), "add=%lx, valid_links=%x, active_links=%x\n", add, vif->valid_links, vif->active_links);
++
+ mutex_lock(&dev->mt76.mutex);
+
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+@@ -1133,6 +1141,8 @@ static int mt7996_add_link_sta(struct mt7996_dev *dev,
+ mt76_wcid_mask_set(dev->mt76.wcid_phy_mask, idx);
+ rcu_assign_pointer(dev->mt76.wcid[idx], &mlink->wcid);
+ mt76_wcid_init(&mlink->wcid);
++
++ mlo_dbg(mconf->phy, "wcid=%u, link_id=%u, link_addr=%pM, pri_link=%u, sec_link=%u\n", mlink->wcid.idx, link_id, link_sta->addr, msta->pri_link, msta->sec_link);
+ }
+
+ if (!assoc)
+@@ -1167,6 +1177,7 @@ mt7996_mac_sta_remove_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
+ unsigned int link_id;
+
++ mlo_dbg(mt7996_hw_phy(mvif->hw), "rem=%lu\n", rem);
+ for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt7996_bss_conf *mconf =
+ mconf_dereference_protected(mvif, link_id);
+@@ -1192,6 +1203,7 @@ mt7996_mac_sta_add_links(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ unsigned int link_id;
+ int i, ret;
+
++ mlo_dbg(mt7996_hw_phy(mvif->hw), "add=%lu, assoc=%d\n", add, assoc);
+ for_each_set_bit(link_id, &add, IEEE80211_MLD_MAX_NUM_LINKS) {
+ struct mt7996_bss_conf *mconf =
+ mconf_dereference_protected(mvif, link_id);
+@@ -2530,6 +2542,7 @@ mt7996_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned int link_id;
+ int ret = 0;
+
++ mlo_dbg(phy, "old=%u, new=%u\n", old_links, new_links);
+ if (old_links == new_links)
+ return 0;
+
+@@ -2578,6 +2591,7 @@ mt7996_change_sta_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ unsigned long rem = old_links & ~new_links;
+ int ret = 0;
+
++ mlo_dbg(mt7996_hw_phy(hw), "old=%u, new=%u\n", old_links, new_links);
+ mutex_lock(&dev->mt76.mutex);
+
+ if (rem)
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index d8e3181b1..38305d810 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -333,6 +333,10 @@ mt7996_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
+ mcu_txd->s2d_index = MCU_S2D_H2N;
+
+ exit:
++#ifdef CONFIG_MTK_DEBUG
++ if (dev->dbg.dump_mcu_pkt)
++ mt7996_packet_log_to_host(dev, skb->data, skb->len, PKT_BIN_DEBUG_MCU, 0);
++#endif
+ if (wait_seq)
+ *wait_seq = seq;
+
+@@ -1336,6 +1340,8 @@ mt7996_mcu_bss_mld_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
+ }
+
+ mld->own_mld_id = mconf->own_mld_id;
++ pr_info("%s: group_mld_id=%d own_mld_id=%d remap_idx=%d mld->addr[%pM]\n",
++ __func__, mld->group_mld_id, mld->own_mld_id, mld->remap_idx, mld->mac_addr);
+ }
+
+ static void
+@@ -1487,6 +1493,10 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb, struct ieee80211_bss_conf *conf,
+ }
+
+ memcpy(bss->bssid, conf->bssid, ETH_ALEN);
++
++ mlo_dbg(mconf->phy, "omac_idx=%d band_idx=%d wmm_idx=%d bss->bssid=%pM enable=%d\n",
++ bss->omac_idx, bss->band_idx, bss->wmm_idx, bss->bssid, enable);
++
+ bss->bcn_interval = cpu_to_le16(conf->beacon_int);
+ bss->dtim_period = conf->dtim_period;
+ bss->phymode = mt76_connac_get_phy_mode(phy, vif,
+@@ -2770,6 +2780,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_bss_conf *conf,
+
+ /* starec basic */
+ mt76_connac_mcu_sta_basic_tlv(&dev->mt76, skb, conf, link_sta, enable, newly);
++ mlo_dbg(mconf->phy, "link=%u, newly=%d, en=%d\n",
++ mlink->wcid.link_id, newly, enable);
+
+ if (!enable)
+ goto out;
+@@ -2852,12 +2864,16 @@ mt7996_mcu_sta_mld_setup_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+ mld_setup->link_num = hweight16(sta->valid_links);
+
+ mld_setup_link = (struct mld_setup_link *)mld_setup->link_info;
++ mlo_dbg(mt7996_hw_phy(mlink->sta->vif->hw), "pri_link(%u) primary_id(%d) seconed_id(%d) wcid(%d), link_num(%d), mld_addr[%pM]\n",
++ msta->pri_link, mld_setup->primary_id, mld_setup->seconed_id, mld_setup->setup_wcid, mld_setup->link_num, mld_setup->mld_addr);
+ for_each_set_bit(link_id, &valid_links, IEEE80211_MLD_MAX_NUM_LINKS) {
+ mlink = mlink_dereference_protected(msta, link_id);
+ mconf = mconf_dereference_protected(msta->vif, link_id);
+
+ mld_setup_link->wcid = cpu_to_le16(mlink->wcid.idx);
+ mld_setup_link->bss_idx = mconf->mt76.idx;
++ mlo_dbg(mt7996_hw_phy(mlink->sta->vif->hw), "link_id(%d) wcid(%d) bss_idx(%d)\n",
++ link_id, mld_setup_link->wcid, mld_setup_link->bss_idx);
+ mld_setup_link++;
+ }
+ }
+@@ -3121,6 +3137,8 @@ int mt7996_mcu_add_dev_info(struct mt7996_phy *phy,
+ return mt7996_mcu_muar_config(phy, conf, mconf, false, enable);
+
+ memcpy(data.tlv.omac_addr, conf->addr, ETH_ALEN);
++ mlo_dbg(phy, "omac=%u, band=%u, addr=%pM, en=%d\n",
++ data.hdr.omac_idx,data.hdr.band_idx, data.tlv.omac_addr, enable);
+ return mt76_mcu_send_msg(&dev->mt76, MCU_WMWA_UNI_CMD(DEV_INFO_UPDATE),
+ &data, sizeof(data), true);
+ }
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index dc93fab25..84d961d11 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -1035,6 +1035,14 @@ enum {
+ UNI_RRO_SET_FLUSH_TIMEOUT
+ };
+
++enum {
++ UNI_MEC_READ_INFO = 0,
++ UNI_MEC_AMSDU_ALGO_EN_STA,
++ UNI_MEC_AMSDU_PARA_STA,
++ UNI_MEC_AMSDU_ALGO_THRESHOLD,
++ UNI_MEC_IFAC_SPEED,
++};
++
+ enum{
+ UNI_CMD_SR_ENABLE = 0x1,
+ UNI_CMD_SR_ENABLE_SD,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 0d537fb9b..de7cf1ecc 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -730,6 +730,13 @@ struct mt7996_dev {
+ u8 fw_dbg_lv;
+ u32 bcn_total_cnt[__MT_MAX_BAND];
+ u32 sid;
++
++ bool dump_mcu_pkt:1;
++ bool dump_txd:1;
++ bool dump_tx_pkt:1;
++ bool dump_rx_pkt:1;
++ bool dump_rx_raw:1;
++ u32 token_idx;
+ } dbg;
+ const struct mt7996_dbg_reg_desc *dbg_reg;
+ #endif
+@@ -925,6 +932,8 @@ mt7996_get_link_wcid(struct mt7996_dev *dev, u16 idx, u8 band_idx)
+ return &mlink->wcid;
+ }
+
++#define mlo_dbg(phy, fmt, ...) wiphy_info(phy->mt76->hw->wiphy, "%s: " fmt, __func__, ##__VA_ARGS__)
++
+ extern const struct ieee80211_ops mt7996_ops;
+ extern struct pci_driver mt7996_pci_driver;
+ extern struct pci_driver mt7996_hif_driver;
+@@ -1256,6 +1265,17 @@ void mt7996_tm_update_channel(struct mt7996_phy *phy);
+
+ int mt7996_mcu_set_vow_drr_dbg(struct mt7996_dev *dev, u32 val);
+ int mt7996_mcu_thermal_debug(struct mt7996_dev *dev, u8 mode, u8 action);
++
++#define PKT_BIN_DEBUG_MAGIC 0xc8763123
++enum {
++ PKT_BIN_DEBUG_MCU,
++ PKT_BIN_DEBUG_TXD,
++ PKT_BIN_DEBUG_TX,
++ PKT_BIN_DEBUG_RX,
++ PKT_BIN_DEBUG_RX_RAW,
++};
++
++void mt7996_packet_log_to_host(struct mt7996_dev *dev, const void *data, int len, int type, int des_len);
+ #endif
+
+ #ifdef CONFIG_NET_MEDIATEK_SOC_WED
+diff --git a/mt7996/mtk_debug.h b/mt7996/mtk_debug.h
+index da2a60723..829902398 100644
+--- a/mt7996/mtk_debug.h
++++ b/mt7996/mtk_debug.h
+@@ -2288,4 +2288,664 @@ enum cipher_suit {
+ #define WTBL_RATE_STBC_OFFSET 14
+ #endif
+
++struct bin_debug_hdr {
++ __le32 magic_num;
++ __le16 serial_id;
++ __le16 msg_type;
++ __le16 len;
++ __le16 des_len; /* descriptor len for rxd */
++} __packed;
++
++enum umac_port {
++ ENUM_UMAC_HIF_PORT_0 = 0,
++ ENUM_UMAC_CPU_PORT_1 = 1,
++ ENUM_UMAC_LMAC_PORT_2 = 2,
++ ENUM_PLE_CTRL_PSE_PORT_3 = 3,
++ ENUM_UMAC_PSE_PLE_PORT_TOTAL_NUM = 4
++};
++
++/* N9 MCU QUEUE LIST */
++enum umac_cpu_port_queue_idx {
++ ENUM_UMAC_CTX_Q_0 = 0,
++ ENUM_UMAC_CTX_Q_1 = 1,
++ ENUM_UMAC_CTX_Q_2 = 2,
++ ENUM_UMAC_CTX_Q_3 = 3,
++ ENUM_UMAC_CRX = 0,
++ ENUM_UMAC_CIF_QUEUE_TOTAL_NUM = 4
++};
++
++/* LMAC PLE For PSE Control P3 */
++enum umac_ple_ctrl_port3_queue_idx {
++ ENUM_UMAC_PLE_CTRL_P3_Q_0X1E = 0x1e,
++ ENUM_UMAC_PLE_CTRL_P3_Q_0X1F = 0x1f,
++ ENUM_UMAC_PLE_CTRL_P3_TOTAL_NUM = 2
++};
++
++/* PSE PLE QUEUE */
++#define CR_NUM_OF_AC_MT7996 34
++#define CR_NUM_OF_AC_MT7992 17
++struct bmac_queue_info {
++ char *QueueName;
++ u32 Portid;
++ u32 Queueid;
++ u32 tgid;
++};
++
++struct bmac_queue_info_t {
++ char *QueueName;
++ u32 Portid;
++ u32 Queueid;
++};
++
++#define WF_DRR_TOP_BASE 0x820c8800
++#define WF_DRR_TOP_SBRR_ADDR (WF_DRR_TOP_BASE + 0x00E0) // 88E0
++#define WF_DRR_TOP_TWT_STA_MAP00_ADDR (WF_DRR_TOP_BASE + 0x0100) // 8900
++#define WF_DRR_TOP_TWT_STA_MAP_EXT_00_ADDR (WF_DRR_TOP_BASE + 0x0180) // 8980
++#define WF_DRR_TOP_AC0_STATION_PAUSE00_ADDR (WF_DRR_TOP_BASE + 0x0200) // 8A00
++#define WF_DRR_TOP_AC0_STATION_PAUSE_EXT_00_ADDR (WF_DRR_TOP_BASE + 0x0280) // 8A80
++#define WF_DRR_TOP_AC1_STATION_PAUSE00_ADDR (WF_DRR_TOP_BASE + 0x0300) // 8B00
++#define WF_DRR_TOP_AC1_STATION_PAUSE_EXT_00_ADDR (WF_DRR_TOP_BASE + 0x0380) // 8B80
++#define WF_DRR_TOP_AC2_STATION_PAUSE00_ADDR (WF_DRR_TOP_BASE + 0x0400) // 8C00
++#define WF_DRR_TOP_AC2_STATION_PAUSE_EXT_00_ADDR (WF_DRR_TOP_BASE + 0x0480) // 8C80
++#define WF_DRR_TOP_AC3_STATION_PAUSE00_ADDR (WF_DRR_TOP_BASE + 0x0500) // 8D00
++#define WF_DRR_TOP_AC3_STATION_PAUSE_EXT_00_ADDR (WF_DRR_TOP_BASE + 0x0580) // 8D80
++
++#define WF_DRR_TOP_SBRR_TARGET_BAND_MASK 0x00000003 // TARGET_BAND[1..0]
++/* PLE AMSDU */
++#define WF_PLE_TOP_BASE 0x820c0000
++
++#define WF_PLE_TOP_AMSDU_PACK_1_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10e0) // 10E0
++#define WF_PLE_TOP_AMSDU_PACK_2_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10e4) // 10E4
++#define WF_PLE_TOP_AMSDU_PACK_3_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10e8) // 10E8
++#define WF_PLE_TOP_AMSDU_PACK_4_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10ec) // 10EC
++#define WF_PLE_TOP_AMSDU_PACK_5_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10f0) // 10F0
++#define WF_PLE_TOP_AMSDU_PACK_6_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10f4) // 10F4
++#define WF_PLE_TOP_AMSDU_PACK_7_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10f8) // 10F8
++#define WF_PLE_TOP_AMSDU_PACK_8_MSDU_CNT_ADDR (WF_PLE_TOP_BASE + 0x10fc) // 10FC
++#define WF_PLE_TOP_AMSDU_PACK_NUM 8
++
++/* PLE */
++#define WF_PLE_TOP_PBUF_CTRL_ADDR (WF_PLE_TOP_BASE + 0x04) // 0004
++
++#define WF_PLE_TOP_PG_HIF_GROUP_ADDR (WF_PLE_TOP_BASE + 0x0c) // 000C
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_ADDR (WF_PLE_TOP_BASE + 0x10) // 0010
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_ADDR (WF_PLE_TOP_BASE + 0x14) // 0014
++#define WF_PLE_TOP_PG_CPU_GROUP_ADDR (WF_PLE_TOP_BASE + 0x18) // 0018
++#define WF_PLE_TOP_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x360) // 0360
++
++#define WF_PLE_TOP_DIS_STA_MAP0_ADDR (WF_PLE_TOP_BASE + 0x100) // 0100
++#define WF_PLE_TOP_DIS_STA_MAP1_ADDR (WF_PLE_TOP_BASE + 0x104) // 0104
++#define WF_PLE_TOP_DIS_STA_MAP2_ADDR (WF_PLE_TOP_BASE + 0x108) // 0108
++#define WF_PLE_TOP_DIS_STA_MAP3_ADDR (WF_PLE_TOP_BASE + 0x10c) // 010C
++#define WF_PLE_TOP_DIS_STA_MAP4_ADDR (WF_PLE_TOP_BASE + 0x110) // 0110
++#define WF_PLE_TOP_DIS_STA_MAP5_ADDR (WF_PLE_TOP_BASE + 0x114) // 0114
++#define WF_PLE_TOP_DIS_STA_MAP6_ADDR (WF_PLE_TOP_BASE + 0x118) // 0118
++#define WF_PLE_TOP_DIS_STA_MAP7_ADDR (WF_PLE_TOP_BASE + 0x11c) // 011C
++#define WF_PLE_TOP_DIS_STA_MAP8_ADDR (WF_PLE_TOP_BASE + 0x120) // 0120
++
++#define WF_PLE_TOP_TXCMD_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x378) // 0378
++#define WF_PLE_TOP_NATIVE_TXCMD_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x37c) // 037C
++#define WF_PLE_TOP_BN1_TXCMD_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x388) // 0388
++#define WF_PLE_TOP_BN1_NATIVE_TXCMD_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x38c) // 038C
++#define WF_PLE_TOP_BN2_TXCMD_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x398) // 0398
++#define WF_PLE_TOP_BN2_NATIVE_TXCMD_QUEUE_EMPTY_ADDR (WF_PLE_TOP_BASE + 0x39c) // 039C
++
++#define WF_PLE_TOP_FREEPG_CNT_ADDR (WF_PLE_TOP_BASE + 0x3a0) // 03A0
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_ADDR (WF_PLE_TOP_BASE + 0x3a4) // 03A4
++#define WF_PLE_TOP_HIF_PG_INFO_ADDR (WF_PLE_TOP_BASE + 0x3a8) // 03A8
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_ADDR (WF_PLE_TOP_BASE + 0x3ac) // 03AC
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_ADDR (WF_PLE_TOP_BASE + 0x3b0) // 03B0
++#define WF_PLE_TOP_CPU_PG_INFO_ADDR (WF_PLE_TOP_BASE + 0x3b4) // 03B4
++
++#define WF_PLE_TOP_FL_QUE_CTRL_0_ADDR (WF_PLE_TOP_BASE + 0x3e0) // 03E0
++#define WF_PLE_TOP_FL_QUE_CTRL_1_ADDR (WF_PLE_TOP_BASE + 0x3e4) // 03E4
++#define WF_PLE_TOP_FL_QUE_CTRL_2_ADDR (WF_PLE_TOP_BASE + 0x3e8) // 03E8
++#define WF_PLE_TOP_FL_QUE_CTRL_3_ADDR (WF_PLE_TOP_BASE + 0x3ec) // 03EC
++
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY0_ADDR (WF_PLE_TOP_BASE + 0x600) // 0600
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY1_ADDR (WF_PLE_TOP_BASE + 0x604) // 0604
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY2_ADDR (WF_PLE_TOP_BASE + 0x608) // 0608
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY3_ADDR (WF_PLE_TOP_BASE + 0x60c) // 060C
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY4_ADDR (WF_PLE_TOP_BASE + 0x610) // 0610
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY5_ADDR (WF_PLE_TOP_BASE + 0x614) // 0614
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY6_ADDR (WF_PLE_TOP_BASE + 0x618) // 0618
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY7_ADDR (WF_PLE_TOP_BASE + 0x61c) // 061C
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY8_ADDR (WF_PLE_TOP_BASE + 0x620) // 0620
++#define WF_PLE_TOP_AC0_QUEUE_EMPTY_EXT0_ADDR (WF_PLE_TOP_BASE + 0x680) // 0680
++
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY0_ADDR (WF_PLE_TOP_BASE + 0x700) // 0700
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY1_ADDR (WF_PLE_TOP_BASE + 0x704) // 0704
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY2_ADDR (WF_PLE_TOP_BASE + 0x708) // 0708
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY3_ADDR (WF_PLE_TOP_BASE + 0x70c) // 070C
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY4_ADDR (WF_PLE_TOP_BASE + 0x710) // 0710
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY5_ADDR (WF_PLE_TOP_BASE + 0x714) // 0714
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY6_ADDR (WF_PLE_TOP_BASE + 0x718) // 0718
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY7_ADDR (WF_PLE_TOP_BASE + 0x71c) // 071C
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY8_ADDR (WF_PLE_TOP_BASE + 0x720) // 0720
++#define WF_PLE_TOP_AC1_QUEUE_EMPTY_EXT0_ADDR (WF_PLE_TOP_BASE + 0x780) // 0780
++
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY0_ADDR (WF_PLE_TOP_BASE + 0x800) // 0800
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY1_ADDR (WF_PLE_TOP_BASE + 0x804) // 0804
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY2_ADDR (WF_PLE_TOP_BASE + 0x808) // 0808
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY3_ADDR (WF_PLE_TOP_BASE + 0x80c) // 080C
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY4_ADDR (WF_PLE_TOP_BASE + 0x810) // 0810
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY5_ADDR (WF_PLE_TOP_BASE + 0x814) // 0814
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY6_ADDR (WF_PLE_TOP_BASE + 0x818) // 0818
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY7_ADDR (WF_PLE_TOP_BASE + 0x81c) // 081C
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY8_ADDR (WF_PLE_TOP_BASE + 0x820) // 0820
++#define WF_PLE_TOP_AC2_QUEUE_EMPTY_EXT0_ADDR (WF_PLE_TOP_BASE + 0x880) // 0880
++
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY0_ADDR (WF_PLE_TOP_BASE + 0x900) // 0900
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY1_ADDR (WF_PLE_TOP_BASE + 0x904) // 0904
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY2_ADDR (WF_PLE_TOP_BASE + 0x908) // 0908
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY3_ADDR (WF_PLE_TOP_BASE + 0x90c) // 090C
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY4_ADDR (WF_PLE_TOP_BASE + 0x910) // 0910
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY5_ADDR (WF_PLE_TOP_BASE + 0x914) // 0914
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY6_ADDR (WF_PLE_TOP_BASE + 0x918) // 0918
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY7_ADDR (WF_PLE_TOP_BASE + 0x91c) // 091C
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY8_ADDR (WF_PLE_TOP_BASE + 0x920) // 0920
++#define WF_PLE_TOP_AC3_QUEUE_EMPTY_EXT0_ADDR (WF_PLE_TOP_BASE + 0x980) // 0980
++
++#define WF_PLE_TOP_QUEUE_EMPTY_ALL_AC_EMPTY_ADDR WF_PLE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PLE_TOP_QUEUE_EMPTY_ALL_AC_EMPTY_MASK 0x01000000 // ALL_AC_EMPTY[24]
++#define WF_PLE_TOP_QUEUE_EMPTY_ALL_AC_EMPTY_SHFT 24
++
++#define WF_PLE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_ADDR WF_PLE_TOP_PBUF_CTRL_ADDR
++#define WF_PLE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_MASK 0x80000000 // PAGE_SIZE_CFG[31]
++#define WF_PLE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_SHFT 31
++#define WF_PLE_TOP_PBUF_CTRL_PBUF_OFFSET_ADDR WF_PLE_TOP_PBUF_CTRL_ADDR
++#define WF_PLE_TOP_PBUF_CTRL_PBUF_OFFSET_MASK 0x07FE0000 // PBUF_OFFSET[26..17]
++#define WF_PLE_TOP_PBUF_CTRL_PBUF_OFFSET_SHFT 17
++#define WF_PLE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_ADDR WF_PLE_TOP_PBUF_CTRL_ADDR
++#define WF_PLE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_MASK 0x00001FFF // TOTAL_PAGE_NUM[12..0]
++#define WF_PLE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_SHFT 0
++
++#define WF_PLE_TOP_FREEPG_CNT_FFA_CNT_ADDR WF_PLE_TOP_FREEPG_CNT_ADDR
++#define WF_PLE_TOP_FREEPG_CNT_FFA_CNT_MASK 0x1FFF0000 // FFA_CNT[28..16]
++#define WF_PLE_TOP_FREEPG_CNT_FFA_CNT_SHFT 16
++#define WF_PLE_TOP_FREEPG_CNT_FREEPG_CNT_ADDR WF_PLE_TOP_FREEPG_CNT_ADDR
++#define WF_PLE_TOP_FREEPG_CNT_FREEPG_CNT_MASK 0x00001FFF // FREEPG_CNT[12..0]
++#define WF_PLE_TOP_FREEPG_CNT_FREEPG_CNT_SHFT 0
++
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_ADDR WF_PLE_TOP_FREEPG_HEAD_TAIL_ADDR
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_MASK 0x1FFF0000 // FREEPG_TAIL[28..16]
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_SHFT 16
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_ADDR WF_PLE_TOP_FREEPG_HEAD_TAIL_ADDR
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_MASK 0x00001FFF // FREEPG_HEAD[12..0]
++#define WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_SHFT 0
++
++#define WF_PLE_TOP_PG_HIF_GROUP_HIF_MAX_QUOTA_ADDR WF_PLE_TOP_PG_HIF_GROUP_ADDR
++#define WF_PLE_TOP_PG_HIF_GROUP_HIF_MAX_QUOTA_MASK 0x1FFF0000 // HIF_MAX_QUOTA[28..16]
++#define WF_PLE_TOP_PG_HIF_GROUP_HIF_MAX_QUOTA_SHFT 16
++#define WF_PLE_TOP_PG_HIF_GROUP_HIF_MIN_QUOTA_ADDR WF_PLE_TOP_PG_HIF_GROUP_ADDR
++#define WF_PLE_TOP_PG_HIF_GROUP_HIF_MIN_QUOTA_MASK 0x00001FFF // HIF_MIN_QUOTA[12..0]
++#define WF_PLE_TOP_PG_HIF_GROUP_HIF_MIN_QUOTA_SHFT 0
++
++#define WF_PLE_TOP_HIF_PG_INFO_HIF_SRC_CNT_ADDR WF_PLE_TOP_HIF_PG_INFO_ADDR
++#define WF_PLE_TOP_HIF_PG_INFO_HIF_SRC_CNT_MASK 0x1FFF0000 // HIF_SRC_CNT[28..16]
++#define WF_PLE_TOP_HIF_PG_INFO_HIF_SRC_CNT_SHFT 16
++#define WF_PLE_TOP_HIF_PG_INFO_HIF_RSV_CNT_ADDR WF_PLE_TOP_HIF_PG_INFO_ADDR
++#define WF_PLE_TOP_HIF_PG_INFO_HIF_RSV_CNT_MASK 0x00001FFF // HIF_RSV_CNT[12..0]
++#define WF_PLE_TOP_HIF_PG_INFO_HIF_RSV_CNT_SHFT 0
++
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MAX_QUOTA_ADDR WF_PLE_TOP_PG_HIF_WMTXD_GROUP_ADDR
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MAX_QUOTA_MASK 0x1FFF0000 // HIF_WMTXD_MAX_QUOTA[28..16]
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MAX_QUOTA_SHFT 16
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MIN_QUOTA_ADDR WF_PLE_TOP_PG_HIF_WMTXD_GROUP_ADDR
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MIN_QUOTA_MASK 0x00001FFF // HIF_WMTXD_MIN_QUOTA[12..0]
++#define WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MIN_QUOTA_SHFT 0
++
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_SRC_CNT_ADDR WF_PLE_TOP_HIF_WMTXD_PG_INFO_ADDR
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_SRC_CNT_MASK 0x1FFF0000 // HIF_WMTXD_SRC_CNT[28..16]
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_SRC_CNT_SHFT 16
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_RSV_CNT_ADDR WF_PLE_TOP_HIF_WMTXD_PG_INFO_ADDR
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_RSV_CNT_MASK 0x00001FFF // HIF_WMTXD_RSV_CNT[12..0]
++#define WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_RSV_CNT_SHFT 0
++
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MAX_QUOTA_ADDR WF_PLE_TOP_PG_HIF_TXCMD_GROUP_ADDR
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MAX_QUOTA_MASK 0x1FFF0000 // HIF_TXCMD_MAX_QUOTA[28..16]
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MAX_QUOTA_SHFT 16
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MIN_QUOTA_ADDR WF_PLE_TOP_PG_HIF_TXCMD_GROUP_ADDR
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MIN_QUOTA_MASK 0x00001FFF // HIF_TXCMD_MIN_QUOTA[12..0]
++#define WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MIN_QUOTA_SHFT 0
++
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_SRC_CNT_ADDR WF_PLE_TOP_HIF_TXCMD_PG_INFO_ADDR
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_SRC_CNT_MASK 0x1FFF0000 // HIF_TXCMD_SRC_CNT[28..16]
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_SRC_CNT_SHFT 16
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_RSV_CNT_ADDR WF_PLE_TOP_HIF_TXCMD_PG_INFO_ADDR
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_RSV_CNT_MASK 0x00001FFF // HIF_TXCMD_RSV_CNT[12..0]
++#define WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_RSV_CNT_SHFT 0
++
++#define WF_PLE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_ADDR WF_PLE_TOP_PG_CPU_GROUP_ADDR
++#define WF_PLE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_MASK 0x1FFF0000 // CPU_MAX_QUOTA[28..16]
++#define WF_PLE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_SHFT 16
++#define WF_PLE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_ADDR WF_PLE_TOP_PG_CPU_GROUP_ADDR
++#define WF_PLE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_MASK 0x00001FFF // CPU_MIN_QUOTA[12..0]
++#define WF_PLE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_SHFT 0
++
++#define WF_PLE_TOP_CPU_PG_INFO_CPU_SRC_CNT_ADDR WF_PLE_TOP_CPU_PG_INFO_ADDR
++#define WF_PLE_TOP_CPU_PG_INFO_CPU_SRC_CNT_MASK 0x1FFF0000 // CPU_SRC_CNT[28..16]
++#define WF_PLE_TOP_CPU_PG_INFO_CPU_SRC_CNT_SHFT 16
++#define WF_PLE_TOP_CPU_PG_INFO_CPU_RSV_CNT_ADDR WF_PLE_TOP_CPU_PG_INFO_ADDR
++#define WF_PLE_TOP_CPU_PG_INFO_CPU_RSV_CNT_MASK 0x00001FFF // CPU_RSV_CNT[12..0]
++#define WF_PLE_TOP_CPU_PG_INFO_CPU_RSV_CNT_SHFT 0
++
++#define WF_PLE_TOP_FL_QUE_CTRL_0_EXECUTE_ADDR WF_PLE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_0_EXECUTE_MASK 0x80000000 // EXECUTE[31]
++#define WF_PLE_TOP_FL_QUE_CTRL_0_EXECUTE_SHFT 31
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_ADDR WF_PLE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_MASK 0x7F000000 // Q_BUF_QID[30..24]
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_SHFT 24
++#define WF_PLE_TOP_FL_QUE_CTRL_0_FL_BUFFER_ADDR_ADDR WF_PLE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_0_FL_BUFFER_ADDR_MASK 0x00FFF000 // FL_BUFFER_ADDR[23..12]
++#define WF_PLE_TOP_FL_QUE_CTRL_0_FL_BUFFER_ADDR_SHFT 12
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_WLANID_ADDR WF_PLE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_WLANID_MASK 0x00000FFF // Q_BUF_WLANID[11..0]
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_WLANID_SHFT 0
++
++#define WF_PLE_TOP_FL_QUE_CTRL_1_Q_BUF_TGID_ADDR WF_PLE_TOP_FL_QUE_CTRL_1_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_1_Q_BUF_TGID_MASK 0xC0000000 // Q_BUF_TGID[31..30]
++#define WF_PLE_TOP_FL_QUE_CTRL_1_Q_BUF_TGID_SHFT 30
++#define WF_PLE_TOP_FL_QUE_CTRL_1_Q_BUF_PID_ADDR WF_PLE_TOP_FL_QUE_CTRL_1_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_1_Q_BUF_PID_MASK 0x30000000 // Q_BUF_PID[29..28]
++#define WF_PLE_TOP_FL_QUE_CTRL_1_Q_BUF_PID_SHFT 28
++
++#define WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_ADDR WF_PLE_TOP_FL_QUE_CTRL_2_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_MASK 0x1FFF0000 // QUEUE_TAIL_FID[28..16]
++#define WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_SHFT 16
++#define WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_ADDR WF_PLE_TOP_FL_QUE_CTRL_2_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_MASK 0x00001FFF // QUEUE_HEAD_FID[12..0]
++#define WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_SHFT 0
++
++#define WF_PLE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_ADDR WF_PLE_TOP_FL_QUE_CTRL_3_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_MASK 0x00001FFF // QUEUE_PKT_NUM[12..0]
++#define WF_PLE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_SHFT 0
++
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_TGID_ADDR WF_PLE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_TGID_MASK 0x00300000 // Q_BUF_TGID[21..20]
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_TGID_SHFT 20
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_ADDR WF_PLE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_MASK 0x00030000 // Q_BUF_PID[17..16]
++#define WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_SHFT 16
++/* PSE */
++#define WF_PSE_TOP_BASE 0x820c8000
++
++#define WF_PSE_TOP_PBUF_CTRL_ADDR (WF_PSE_TOP_BASE + 0x04) // 8004
++#define WF_PSE_TOP_QUEUE_EMPTY_ADDR (WF_PSE_TOP_BASE + 0xB0) // 80B0
++#define WF_PSE_TOP_QUEUE_EMPTY_1_ADDR (WF_PSE_TOP_BASE + 0xBC) // 80BC
++#define WF_PSE_TOP_PG_HIF0_GROUP_ADDR (WF_PSE_TOP_BASE + 0x110) // 8110
++#define WF_PSE_TOP_PG_HIF1_GROUP_ADDR (WF_PSE_TOP_BASE + 0x114) // 8114
++#define WF_PSE_TOP_PG_CPU_GROUP_ADDR (WF_PSE_TOP_BASE + 0x118) // 8118
++#define WF_PSE_TOP_PG_PLE_GROUP_ADDR (WF_PSE_TOP_BASE + 0x11C) // 811C
++#define WF_PSE_TOP_PG_PLE1_GROUP_ADDR (WF_PSE_TOP_BASE + 0x120) // 8120
++#define WF_PSE_TOP_PG_LMAC0_GROUP_ADDR (WF_PSE_TOP_BASE + 0x124) // 8124
++#define WF_PSE_TOP_PG_LMAC1_GROUP_ADDR (WF_PSE_TOP_BASE + 0x128) // 8128
++#define WF_PSE_TOP_PG_LMAC2_GROUP_ADDR (WF_PSE_TOP_BASE + 0x12C) // 812C
++#define WF_PSE_TOP_PG_LMAC3_GROUP_ADDR (WF_PSE_TOP_BASE + 0x130) // 8130
++#define WF_PSE_TOP_PG_MDP_GROUP_ADDR (WF_PSE_TOP_BASE + 0x134) // 8134
++#define WF_PSE_TOP_PG_MDP2_GROUP_ADDR (WF_PSE_TOP_BASE + 0x13C) // 813C
++#define WF_PSE_TOP_PG_HIF2_GROUP_ADDR (WF_PSE_TOP_BASE + 0x140) // 8140
++#define WF_PSE_TOP_PG_MDP3_GROUP_ADDR (WF_PSE_TOP_BASE + 0x144) // 8144
++#define WF_PSE_TOP_HIF0_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x150) // 8150
++#define WF_PSE_TOP_HIF1_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x154) // 8154
++#define WF_PSE_TOP_CPU_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x158) // 8158
++#define WF_PSE_TOP_PLE_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x15C) // 815C
++#define WF_PSE_TOP_PLE1_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x160) // 8160
++#define WF_PSE_TOP_LMAC0_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x164) // 8164
++#define WF_PSE_TOP_LMAC1_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x168) // 8168
++#define WF_PSE_TOP_LMAC2_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x16C) // 816C
++#define WF_PSE_TOP_LMAC3_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x170) // 8170
++#define WF_PSE_TOP_MDP_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x174) // 8174
++#define WF_PSE_TOP_MDP2_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x17C) // 817C
++#define WF_PSE_TOP_HIF2_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x180) // 8180
++#define WF_PSE_TOP_MDP3_PG_INFO_ADDR (WF_PSE_TOP_BASE + 0x184) // 8184
++#define WF_PSE_TOP_FL_QUE_CTRL_0_ADDR (WF_PSE_TOP_BASE + 0x1B0) // 81B0
++#define WF_PSE_TOP_FL_QUE_CTRL_1_ADDR (WF_PSE_TOP_BASE + 0x1B4) // 81B4
++#define WF_PSE_TOP_FL_QUE_CTRL_2_ADDR (WF_PSE_TOP_BASE + 0x1B8) // 81B8
++#define WF_PSE_TOP_FL_QUE_CTRL_3_ADDR (WF_PSE_TOP_BASE + 0x1BC) // 81BC
++#define WF_PSE_TOP_FREEPG_CNT_ADDR (WF_PSE_TOP_BASE + 0x3A0) // 83A0
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_ADDR (WF_PSE_TOP_BASE + 0x3A4) // 83A4
++
++#define WF_PSE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_ADDR WF_PSE_TOP_PBUF_CTRL_ADDR
++#define WF_PSE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_MASK 0x80000000 // PAGE_SIZE_CFG[31]
++#define WF_PSE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_SHFT 31
++#define WF_PSE_TOP_PBUF_CTRL_PBUF_OFFSET_ADDR WF_PSE_TOP_PBUF_CTRL_ADDR
++#define WF_PSE_TOP_PBUF_CTRL_PBUF_OFFSET_MASK 0x07FE0000 // PBUF_OFFSET[26..17]
++#define WF_PSE_TOP_PBUF_CTRL_PBUF_OFFSET_SHFT 17
++#define WF_PSE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_ADDR WF_PSE_TOP_PBUF_CTRL_ADDR
++#define WF_PSE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_MASK 0x00001FFF // TOTAL_PAGE_NUM[12..0]
++#define WF_PSE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_SHFT 0
++
++#define WF_PSE_TOP_QUEUE_EMPTY_RLS_Q_EMTPY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_RLS_Q_EMTPY_MASK 0x80000000 // RLS_Q_EMTPY[31]
++#define WF_PSE_TOP_QUEUE_EMPTY_RLS_Q_EMTPY_SHFT 31
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q4_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q4_EMPTY_MASK 0x10000000 // CPU_Q4_EMPTY[28]
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q4_EMPTY_SHFT 28
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC1_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC1_QUEUE_EMPTY_MASK 0x08000000 // MDP_RXIOC1_QUEUE_EMPTY[27]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC1_QUEUE_EMPTY_SHFT 27
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC1_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC1_QUEUE_EMPTY_MASK 0x04000000 // MDP_TXIOC1_QUEUE_EMPTY[26]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC1_QUEUE_EMPTY_SHFT 26
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_TX1_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_TX1_QUEUE_EMPTY_MASK 0x02000000 // SEC_TX1_QUEUE_EMPTY[25]
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_TX1_QUEUE_EMPTY_SHFT 25
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TX1_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TX1_QUEUE_EMPTY_MASK 0x01000000 // MDP_TX1_QUEUE_EMPTY[24]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TX1_QUEUE_EMPTY_SHFT 24
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC_QUEUE_EMPTY_MASK 0x00800000 // MDP_RXIOC_QUEUE_EMPTY[23]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC_QUEUE_EMPTY_SHFT 23
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC_QUEUE_EMPTY_MASK 0x00400000 // MDP_TXIOC_QUEUE_EMPTY[22]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC_QUEUE_EMPTY_SHFT 22
++#define WF_PSE_TOP_QUEUE_EMPTY_SFD_PARK_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_SFD_PARK_QUEUE_EMPTY_MASK 0x00200000 // SFD_PARK_QUEUE_EMPTY[21]
++#define WF_PSE_TOP_QUEUE_EMPTY_SFD_PARK_QUEUE_EMPTY_SHFT 21
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_RX_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_RX_QUEUE_EMPTY_MASK 0x00100000 // SEC_RX_QUEUE_EMPTY[20]
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_RX_QUEUE_EMPTY_SHFT 20
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_TX_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_TX_QUEUE_EMPTY_MASK 0x00080000 // SEC_TX_QUEUE_EMPTY[19]
++#define WF_PSE_TOP_QUEUE_EMPTY_SEC_TX_QUEUE_EMPTY_SHFT 19
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RX_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RX_QUEUE_EMPTY_MASK 0x00040000 // MDP_RX_QUEUE_EMPTY[18]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_RX_QUEUE_EMPTY_SHFT 18
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TX_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TX_QUEUE_EMPTY_MASK 0x00020000 // MDP_TX_QUEUE_EMPTY[17]
++#define WF_PSE_TOP_QUEUE_EMPTY_MDP_TX_QUEUE_EMPTY_SHFT 17
++#define WF_PSE_TOP_QUEUE_EMPTY_LMAC_TX_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_LMAC_TX_QUEUE_EMPTY_MASK 0x00010000 // LMAC_TX_QUEUE_EMPTY[16]
++#define WF_PSE_TOP_QUEUE_EMPTY_LMAC_TX_QUEUE_EMPTY_SHFT 16
++
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q3_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q3_EMPTY_MASK 0x00000008 // CPU_Q3_EMPTY[3]
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q3_EMPTY_SHFT 3
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q2_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q2_EMPTY_MASK 0x00000004 // CPU_Q2_EMPTY[2]
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q2_EMPTY_SHFT 2
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q1_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q1_EMPTY_MASK 0x00000002 // CPU_Q1_EMPTY[1]
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q1_EMPTY_SHFT 1
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q0_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q0_EMPTY_MASK 0x00000001 // CPU_Q0_EMPTY[0]
++#define WF_PSE_TOP_QUEUE_EMPTY_CPU_Q0_EMPTY_SHFT 0
++
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_13_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_13_EMPTY_MASK 0x20000000 // HIF_13_EMPTY[29]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_13_EMPTY_SHFT 29
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_12_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_12_EMPTY_MASK 0x10000000 // HIF_12_EMPTY[28]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_12_EMPTY_SHFT 28
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_11_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_11_EMPTY_MASK 0x08000000 // HIF_11_EMPTY[27]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_11_EMPTY_SHFT 27
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_10_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_10_EMPTY_MASK 0x04000000 // HIF_10_EMPTY[26]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_10_EMPTY_SHFT 26
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_9_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_9_EMPTY_MASK 0x02000000 // HIF_9_EMPTY[25]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_9_EMPTY_SHFT 25
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_8_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_8_EMPTY_MASK 0x01000000 // HIF_8_EMPTY[24]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_8_EMPTY_SHFT 24
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_7_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_7_EMPTY_MASK 0x00800000 // HIF_7_EMPTY[23]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_7_EMPTY_SHFT 23
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_6_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_6_EMPTY_MASK 0x00400000 // HIF_6_EMPTY[22]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_6_EMPTY_SHFT 22
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_5_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_5_EMPTY_MASK 0x00200000 // HIF_5_EMPTY[21]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_5_EMPTY_SHFT 21
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_4_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_4_EMPTY_MASK 0x00100000 // HIF_4_EMPTY[20]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_4_EMPTY_SHFT 20
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_3_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_3_EMPTY_MASK 0x00080000 // HIF_3_EMPTY[19]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_3_EMPTY_SHFT 19
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_2_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_2_EMPTY_MASK 0x00040000 // HIF_2_EMPTY[18]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_2_EMPTY_SHFT 18
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_1_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_1_EMPTY_MASK 0x00020000 // HIF_1_EMPTY[17]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_1_EMPTY_SHFT 17
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_0_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_0_EMPTY_MASK 0x00010000 // HIF_0_EMPTY[16]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_HIF_0_EMPTY_SHFT 16
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC3_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC3_QUEUE_EMPTY_MASK 0x00008000 // MDP_RXIOC3_QUEUE_EMPTY[15]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC3_QUEUE_EMPTY_SHFT 15
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC2_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC2_QUEUE_EMPTY_MASK 0x00000800 // MDP_RXIOC2_QUEUE_EMPTY[11]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC2_QUEUE_EMPTY_SHFT 11
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TXIOC2_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TXIOC2_QUEUE_EMPTY_MASK 0x00000400 // MDP_TXIOC2_QUEUE_EMPTY[10]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TXIOC2_QUEUE_EMPTY_SHFT 10
++#define WF_PSE_TOP_QUEUE_EMPTY_1_SEC_TX2_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_SEC_TX2_QUEUE_EMPTY_MASK 0x00000200 // SEC_TX2_QUEUE_EMPTY[9]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_SEC_TX2_QUEUE_EMPTY_SHFT 9
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TX2_QUEUE_EMPTY_ADDR WF_PSE_TOP_QUEUE_EMPTY_1_ADDR
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TX2_QUEUE_EMPTY_MASK 0x00000100 // MDP_TX2_QUEUE_EMPTY[8]
++#define WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TX2_QUEUE_EMPTY_SHFT 8
++
++#define WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MAX_QUOTA_ADDR WF_PSE_TOP_PG_HIF0_GROUP_ADDR
++#define WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MAX_QUOTA_MASK 0x1FFF0000 // HIF0_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MIN_QUOTA_ADDR WF_PSE_TOP_PG_HIF0_GROUP_ADDR
++#define WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MIN_QUOTA_MASK 0x00001FFF // HIF0_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MIN_QUOTA_SHFT 0
++
++
++#define WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MAX_QUOTA_ADDR WF_PSE_TOP_PG_HIF1_GROUP_ADDR
++#define WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MAX_QUOTA_MASK 0x1FFF0000 // HIF1_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MIN_QUOTA_ADDR WF_PSE_TOP_PG_HIF1_GROUP_ADDR
++#define WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MIN_QUOTA_MASK 0x00001FFF // HIF1_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_ADDR WF_PSE_TOP_PG_CPU_GROUP_ADDR
++#define WF_PSE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_MASK 0x1FFF0000 // CPU_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_ADDR WF_PSE_TOP_PG_CPU_GROUP_ADDR
++#define WF_PSE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_MASK 0x00001FFF // CPU_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_ADDR WF_PSE_TOP_PG_PLE_GROUP_ADDR
++#define WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_MASK 0x1FFF0000 // PLE_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_ADDR WF_PSE_TOP_PG_PLE_GROUP_ADDR
++#define WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_MASK 0x00001FFF // PLE_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MAX_QUOTA_ADDR WF_PSE_TOP_PG_LMAC0_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MAX_QUOTA_MASK 0x1FFF0000 // LMAC0_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MIN_QUOTA_ADDR WF_PSE_TOP_PG_LMAC0_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MIN_QUOTA_MASK 0x00001FFF // LMAC0_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MAX_QUOTA_ADDR WF_PSE_TOP_PG_LMAC1_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MAX_QUOTA_MASK 0x1FFF0000 // LMAC1_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MIN_QUOTA_ADDR WF_PSE_TOP_PG_LMAC1_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MIN_QUOTA_MASK 0x00001FFF // LMAC1_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MAX_QUOTA_ADDR WF_PSE_TOP_PG_LMAC2_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MAX_QUOTA_MASK 0x1FFF0000 // LMAC2_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MIN_QUOTA_ADDR WF_PSE_TOP_PG_LMAC2_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MIN_QUOTA_MASK 0x00001FFF // LMAC2_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MAX_QUOTA_ADDR WF_PSE_TOP_PG_LMAC3_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MAX_QUOTA_MASK 0x1FFF0000 // LMAC3_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MIN_QUOTA_ADDR WF_PSE_TOP_PG_LMAC3_GROUP_ADDR
++#define WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MIN_QUOTA_MASK 0x00001FFF // LMAC3_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_MDP_GROUP_MDP_MAX_QUOTA_ADDR WF_PSE_TOP_PG_MDP_GROUP_ADDR
++#define WF_PSE_TOP_PG_MDP_GROUP_MDP_MAX_QUOTA_MASK 0x1FFF0000 // MDP_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_MDP_GROUP_MDP_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_MDP_GROUP_MDP_MIN_QUOTA_ADDR WF_PSE_TOP_PG_MDP_GROUP_ADDR
++#define WF_PSE_TOP_PG_MDP_GROUP_MDP_MIN_QUOTA_MASK 0x00001FFF // MDP_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_MDP_GROUP_MDP_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MAX_QUOTA_ADDR WF_PSE_TOP_PG_MDP2_GROUP_ADDR
++#define WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MAX_QUOTA_MASK 0x1FFF0000 // MDP2_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MIN_QUOTA_ADDR WF_PSE_TOP_PG_MDP2_GROUP_ADDR
++#define WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MIN_QUOTA_MASK 0x00001FFF // MDP2_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MAX_QUOTA_ADDR WF_PSE_TOP_PG_HIF2_GROUP_ADDR
++#define WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MAX_QUOTA_MASK 0x1FFF0000 // HIF2_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MIN_QUOTA_ADDR WF_PSE_TOP_PG_HIF2_GROUP_ADDR
++#define WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MIN_QUOTA_MASK 0x00001FFF // HIF2_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MAX_QUOTA_ADDR WF_PSE_TOP_PG_MDP3_GROUP_ADDR
++#define WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MAX_QUOTA_MASK 0x1FFF0000 // MDP3_MAX_QUOTA[28..16]
++#define WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MAX_QUOTA_SHFT 16
++#define WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MIN_QUOTA_ADDR WF_PSE_TOP_PG_MDP3_GROUP_ADDR
++#define WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MIN_QUOTA_MASK 0x00001FFF // MDP3_MIN_QUOTA[12..0]
++#define WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MIN_QUOTA_SHFT 0
++
++#define WF_PSE_TOP_HIF0_PG_INFO_HIF0_SRC_CNT_ADDR WF_PSE_TOP_HIF0_PG_INFO_ADDR
++#define WF_PSE_TOP_HIF0_PG_INFO_HIF0_SRC_CNT_MASK 0x1FFF0000 // HIF0_SRC_CNT[28..16]
++#define WF_PSE_TOP_HIF0_PG_INFO_HIF0_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_HIF0_PG_INFO_HIF0_RSV_CNT_ADDR WF_PSE_TOP_HIF0_PG_INFO_ADDR
++#define WF_PSE_TOP_HIF0_PG_INFO_HIF0_RSV_CNT_MASK 0x00001FFF // HIF0_RSV_CNT[12..0]
++#define WF_PSE_TOP_HIF0_PG_INFO_HIF0_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_HIF1_PG_INFO_HIF1_SRC_CNT_ADDR WF_PSE_TOP_HIF1_PG_INFO_ADDR
++#define WF_PSE_TOP_HIF1_PG_INFO_HIF1_SRC_CNT_MASK 0x1FFF0000 // HIF1_SRC_CNT[28..16]
++#define WF_PSE_TOP_HIF1_PG_INFO_HIF1_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_HIF1_PG_INFO_HIF1_RSV_CNT_ADDR WF_PSE_TOP_HIF1_PG_INFO_ADDR
++#define WF_PSE_TOP_HIF1_PG_INFO_HIF1_RSV_CNT_MASK 0x00001FFF // HIF1_RSV_CNT[12..0]
++#define WF_PSE_TOP_HIF1_PG_INFO_HIF1_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_CPU_PG_INFO_CPU_SRC_CNT_ADDR WF_PSE_TOP_CPU_PG_INFO_ADDR
++#define WF_PSE_TOP_CPU_PG_INFO_CPU_SRC_CNT_MASK 0x1FFF0000 // CPU_SRC_CNT[28..16]
++#define WF_PSE_TOP_CPU_PG_INFO_CPU_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_CPU_PG_INFO_CPU_RSV_CNT_ADDR WF_PSE_TOP_CPU_PG_INFO_ADDR
++#define WF_PSE_TOP_CPU_PG_INFO_CPU_RSV_CNT_MASK 0x00001FFF // CPU_RSV_CNT[12..0]
++#define WF_PSE_TOP_CPU_PG_INFO_CPU_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_ADDR WF_PSE_TOP_PLE_PG_INFO_ADDR
++#define WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_MASK 0x1FFF0000 // PLE_SRC_CNT[28..16]
++#define WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_ADDR WF_PSE_TOP_PLE_PG_INFO_ADDR
++#define WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_MASK 0x00001FFF // PLE_RSV_CNT[12..0]
++#define WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_SRC_CNT_ADDR WF_PSE_TOP_LMAC0_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_SRC_CNT_MASK 0x1FFF0000 // LMAC0_SRC_CNT[28..16]
++#define WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_RSV_CNT_ADDR WF_PSE_TOP_LMAC0_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_RSV_CNT_MASK 0x00001FFF // LMAC0_RSV_CNT[12..0]
++#define WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_SRC_CNT_ADDR WF_PSE_TOP_LMAC1_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_SRC_CNT_MASK 0x1FFF0000 // LMAC1_SRC_CNT[28..16]
++#define WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_RSV_CNT_ADDR WF_PSE_TOP_LMAC1_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_RSV_CNT_MASK 0x00001FFF // LMAC1_RSV_CNT[12..0]
++#define WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_SRC_CNT_ADDR WF_PSE_TOP_LMAC2_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_SRC_CNT_MASK 0x1FFF0000 // LMAC2_SRC_CNT[28..16]
++#define WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_RSV_CNT_ADDR WF_PSE_TOP_LMAC2_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_RSV_CNT_MASK 0x00001FFF // LMAC2_RSV_CNT[12..0]
++#define WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_SRC_CNT_ADDR WF_PSE_TOP_LMAC3_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_SRC_CNT_MASK 0x1FFF0000 // LMAC3_SRC_CNT[28..16]
++#define WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_RSV_CNT_ADDR WF_PSE_TOP_LMAC3_PG_INFO_ADDR
++#define WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_RSV_CNT_MASK 0x00001FFF // LMAC3_RSV_CNT[12..0]
++#define WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_MDP_PG_INFO_MDP_SRC_CNT_ADDR WF_PSE_TOP_MDP_PG_INFO_ADDR
++#define WF_PSE_TOP_MDP_PG_INFO_MDP_SRC_CNT_MASK 0x1FFF0000 // MDP_SRC_CNT[28..16]
++#define WF_PSE_TOP_MDP_PG_INFO_MDP_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_MDP_PG_INFO_MDP_RSV_CNT_ADDR WF_PSE_TOP_MDP_PG_INFO_ADDR
++#define WF_PSE_TOP_MDP_PG_INFO_MDP_RSV_CNT_MASK 0x00001FFF // MDP_RSV_CNT[12..0]
++#define WF_PSE_TOP_MDP_PG_INFO_MDP_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_MDP2_PG_INFO_MDP2_SRC_CNT_ADDR WF_PSE_TOP_MDP2_PG_INFO_ADDR
++#define WF_PSE_TOP_MDP2_PG_INFO_MDP2_SRC_CNT_MASK 0x1FFF0000 // MDP2_SRC_CNT[28..16]
++#define WF_PSE_TOP_MDP2_PG_INFO_MDP2_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_MDP2_PG_INFO_MDP2_RSV_CNT_ADDR WF_PSE_TOP_MDP2_PG_INFO_ADDR
++#define WF_PSE_TOP_MDP2_PG_INFO_MDP2_RSV_CNT_MASK 0x00001FFF // MDP2_RSV_CNT[12..0]
++#define WF_PSE_TOP_MDP2_PG_INFO_MDP2_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_HIF2_PG_INFO_HIF2_SRC_CNT_ADDR WF_PSE_TOP_HIF2_PG_INFO_ADDR
++#define WF_PSE_TOP_HIF2_PG_INFO_HIF2_SRC_CNT_MASK 0x1FFF0000 // HIF2_SRC_CNT[28..16]
++#define WF_PSE_TOP_HIF2_PG_INFO_HIF2_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_HIF2_PG_INFO_HIF2_RSV_CNT_ADDR WF_PSE_TOP_HIF2_PG_INFO_ADDR
++#define WF_PSE_TOP_HIF2_PG_INFO_HIF2_RSV_CNT_MASK 0x00001FFF // HIF2_RSV_CNT[12..0]
++#define WF_PSE_TOP_HIF2_PG_INFO_HIF2_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_MDP3_PG_INFO_MDP3_SRC_CNT_ADDR WF_PSE_TOP_MDP3_PG_INFO_ADDR
++#define WF_PSE_TOP_MDP3_PG_INFO_MDP3_SRC_CNT_MASK 0x1FFF0000 // MDP3_SRC_CNT[28..16]
++#define WF_PSE_TOP_MDP3_PG_INFO_MDP3_SRC_CNT_SHFT 16
++#define WF_PSE_TOP_MDP3_PG_INFO_MDP3_RSV_CNT_ADDR WF_PSE_TOP_MDP3_PG_INFO_ADDR
++#define WF_PSE_TOP_MDP3_PG_INFO_MDP3_RSV_CNT_MASK 0x00001FFF // MDP3_RSV_CNT[12..0]
++#define WF_PSE_TOP_MDP3_PG_INFO_MDP3_RSV_CNT_SHFT 0
++
++#define WF_PSE_TOP_FL_QUE_CTRL_0_EXECUTE_ADDR WF_PSE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_0_EXECUTE_MASK 0x80000000 // EXECUTE[31]
++#define WF_PSE_TOP_FL_QUE_CTRL_0_EXECUTE_SHFT 31
++#define WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_ADDR WF_PSE_TOP_FL_QUE_CTRL_0_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_MASK 0x7F000000 // Q_BUF_QID[30..24]
++#define WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_SHFT 24
++#define WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_SHFT 16
++
++#define WF_PSE_TOP_FL_QUE_CTRL_1_Q_BUF_PID_ADDR WF_PSE_TOP_FL_QUE_CTRL_1_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_1_Q_BUF_PID_MASK 0x30000000 // Q_BUF_PID[29..28]
++#define WF_PSE_TOP_FL_QUE_CTRL_1_Q_BUF_PID_SHFT 28
++
++#define WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_ADDR WF_PSE_TOP_FL_QUE_CTRL_2_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_MASK 0x1FFF0000 // QUEUE_TAIL_FID[28..16]
++#define WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_SHFT 16
++#define WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_ADDR WF_PSE_TOP_FL_QUE_CTRL_2_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_MASK 0x00001FFF // QUEUE_HEAD_FID[12..0]
++#define WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_SHFT 0
++
++#define WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PAGE_NUM_ADDR WF_PSE_TOP_FL_QUE_CTRL_3_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PAGE_NUM_MASK 0x00FFF000 // QUEUE_PAGE_NUM[23..12]
++#define WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PAGE_NUM_SHFT 12
++#define WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_ADDR WF_PSE_TOP_FL_QUE_CTRL_3_ADDR
++#define WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_MASK 0x00001FFF // QUEUE_PKT_NUM[12..0]
++#define WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_SHFT 0
++
++#define WF_PSE_TOP_FREEPG_CNT_FFA_CNT_ADDR WF_PSE_TOP_FREEPG_CNT_ADDR
++#define WF_PSE_TOP_FREEPG_CNT_FFA_CNT_MASK 0x1FFF0000 // FFA_CNT[28..16]
++#define WF_PSE_TOP_FREEPG_CNT_FFA_CNT_SHFT 16
++#define WF_PSE_TOP_FREEPG_CNT_FREEPG_CNT_ADDR WF_PSE_TOP_FREEPG_CNT_ADDR
++#define WF_PSE_TOP_FREEPG_CNT_FREEPG_CNT_MASK 0x00001FFF // FREEPG_CNT[12..0]
++#define WF_PSE_TOP_FREEPG_CNT_FREEPG_CNT_SHFT 0
++
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_ADDR WF_PSE_TOP_FREEPG_HEAD_TAIL_ADDR
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_MASK 0x1FFF0000 // FREEPG_TAIL[28..16]
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_SHFT 16
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_ADDR WF_PSE_TOP_FREEPG_HEAD_TAIL_ADDR
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_MASK 0x00001FFF // FREEPG_HEAD[12..0]
++#define WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_SHFT 0
++
++/* RXD */
++enum {
++ BMAC_GROUP_VLD_1 = 0x01,
++ BMAC_GROUP_VLD_2 = 0x02,
++ BMAC_GROUP_VLD_3 = 0x04,
++ BMAC_GROUP_VLD_4 = 0x08,
++ BMAC_GROUP_VLD_5 = 0x10,
++};
++
+ #endif
+diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
+index ddb4a7ca2..d20c40a5f 100644
+--- a/mt7996/mtk_debugfs.c
++++ b/mt7996/mtk_debugfs.c
+@@ -3228,6 +3228,1072 @@ mt7996_thermal_recal_set(void *data, u64 val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_thermal_recal, NULL,
+ mt7996_thermal_recal_set, "%llu\n");
+
++static int
++mt7996_reset_counter(void *data, u64 val)
++{
++ struct mt7996_dev *dev = data;
++ struct mt76_dev *mdev = &dev->mt76;
++ struct mt76_wcid *wcid;
++ int ret;
++
++ /* Reset read-clear counters in FW and WTBL. */
++ ret = mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_ADM_STAT);
++ if (ret)
++ return ret;
++
++ ret = mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_MSDU_COUNT);
++ if (ret)
++ return ret;
++
++ ret = mt7996_mcu_get_all_sta_info(mdev, UNI_ALL_STA_TXRX_AIRTIME);
++ if (ret)
++ return ret;
++
++ ret = mt7996_mcu_get_per_sta_info(mdev, UNI_PER_STA_TX_CNT, 1, &dev->wlan_idx);
++ if (ret)
++ return ret;
++
++ /* Reset counters in MT76. */
++ rcu_read_lock();
++ wcid = rcu_dereference(dev->mt76.wcid[dev->wlan_idx]);
++ if (wcid)
++ memset(&wcid->stats, 0, sizeof(struct mt76_sta_stats));
++ else
++ ret = -EINVAL;
++ rcu_read_unlock();
++
++ return ret;
++}
++DEFINE_DEBUGFS_ATTRIBUTE(fops_reset_counter, NULL, mt7996_reset_counter, "%llu\n");
++
++static int
++mt7996_per_read(struct seq_file *s, void *data)
++{
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ u16 wlan_idx = dev->wlan_idx;
++ struct mt76_wcid *wcid;
++ u32 total, failed;
++ int ret;
++
++ ret = mt7996_mcu_get_per_sta_info(&dev->mt76, UNI_PER_STA_TX_CNT, 1, &wlan_idx);
++ if (ret)
++ return ret;
++
++ rcu_read_lock();
++ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
++ if (wcid) {
++ total = wcid->stats.tx_total_mpdu_cnt;
++ failed = wcid->stats.tx_failed_mpdu_cnt;
++ seq_printf(s, "WCID %hu\tTxTotalMpduCount: %u\tTxFailedMpduCount: %u\tPER: %u.%u%%\n",
++ wlan_idx, total, failed,
++ total ? failed * 1000 / total / 10 : 0,
++ total ? failed * 1000 / total % 10 : 0);
++ } else {
++ ret = -EINVAL;
++ }
++ rcu_read_unlock();
++
++ return ret;
++}
++
++void mt7996_packet_log_to_host(struct mt7996_dev *dev, const void *data, int len, int type, int des_len)
++{
++ struct bin_debug_hdr *hdr;
++ char *buf;
++
++ if (len > 1500 - sizeof(*hdr))
++ len = 1500 - sizeof(*hdr);
++
++ buf = kzalloc(sizeof(*hdr) + len, GFP_KERNEL);
++ if (!buf)
++ return;
++
++ hdr = (struct bin_debug_hdr *)buf;
++ hdr->magic_num = cpu_to_le32(PKT_BIN_DEBUG_MAGIC);
++ hdr->serial_id = cpu_to_le16(dev->fw_debug_seq++);
++ hdr->msg_type = cpu_to_le16(type);
++ hdr->len = cpu_to_le16(len);
++ hdr->des_len = cpu_to_le16(des_len);
++
++ memcpy(buf + sizeof(*hdr), data, len);
++
++ mt7996_debugfs_rx_log(dev, buf, sizeof(*hdr) + len);
++ kfree(buf);
++}
++
++static int mt7996_rx_token_read(struct seq_file *s, void *data)
++{
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ int id, count = 0;
++ struct mt76_rxwi_cache *r;
++
++ seq_printf(s, "Rx cut through token:\n");
++ spin_lock_bh(&dev->mt76.rx_token_lock);
++ idr_for_each_entry(&dev->mt76.rx_token, r, id) {
++ count++;
++ }
++ seq_printf(s, "\ttotal:%8d used:%8d\n",
++ dev->mt76.rx_token_size, count);
++ spin_unlock_bh(&dev->mt76.rx_token_lock);
++
++ return 0;
++}
++
++/* AMSDU SETTING */
++static ssize_t mt7996_amsdu_algo_write(struct file *file,
++ const char __user *user_buf,
++ size_t count,
++ loff_t *ppos)
++{
++ struct mt7996_dev *dev = file->private_data;
++ char buf[100];
++ int ret;
++ struct {
++ u8 _rsv[4];
++
++ u16 tag;
++ u16 len;
++
++ u16 wlan_idx;
++ u8 algo_en;
++ u8 rsv[1];
++ } __packed data = {
++ .tag = cpu_to_le16(UNI_MEC_AMSDU_ALGO_EN_STA),
++ .len = cpu_to_le16(sizeof(data) - 4),
++ };
++
++ if (count >= sizeof(buf))
++ return -EINVAL;
++
++ if (copy_from_user(buf, user_buf, count))
++ return -EFAULT;
++
++ if (count && buf[count - 1] == '\n')
++ buf[count - 1] = '\0';
++ else
++ buf[count] = '\0';
++
++ if (sscanf(buf, "%hu %hhu", &data.wlan_idx, &data.algo_en) != 2)
++ return -EINVAL;
++
++ if (data.wlan_idx >= mt7996_wtbl_size(dev))
++ return -EINVAL;
++
++ ret = mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MEC), &data,
++ sizeof(data), true);
++ if (ret)
++ return -EINVAL;
++
++ return count;
++}
++static const struct file_operations fops_amsdu_algo = {
++ .write = mt7996_amsdu_algo_write,
++ .read = NULL,
++ .open = simple_open,
++ .llseek = default_llseek,
++};
++
++static ssize_t mt7996_amsdu_para_write(struct file *file,
++ const char __user *user_buf,
++ size_t count,
++ loff_t *ppos)
++{
++ struct mt7996_dev *dev = file->private_data;
++ char buf[100];
++ int ret;
++ struct {
++ u8 _rsv[4];
++
++ u16 tag;
++ u16 len;
++
++ u16 wlan_idx;
++ u8 amsdu_en;
++ u8 num;
++ u16 lenth;
++ u8 rsv[2];
++ } __packed data = {
++ .tag = cpu_to_le16(UNI_MEC_AMSDU_PARA_STA),
++ .len = cpu_to_le16(sizeof(data) - 4),
++ };
++
++ if (count >= sizeof(buf))
++ return -EINVAL;
++
++ if (copy_from_user(buf, user_buf, count))
++ return -EFAULT;
++
++ if (count && buf[count - 1] == '\n')
++ buf[count - 1] = '\0';
++ else
++ buf[count] = '\0';
++
++ if (sscanf(buf, "%hu %hhu %hhu %hu", &data.wlan_idx, &data.amsdu_en, &data.num, &data.lenth) != 4)
++ return -EINVAL;
++
++ if (data.wlan_idx >= mt7996_wtbl_size(dev))
++ return -EINVAL;
++
++ ret = mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MEC), &data,
++ sizeof(data), true);
++ if (ret)
++ return -EINVAL;
++
++ return count;
++}
++static const struct file_operations fops_amsdu_para = {
++ .write = mt7996_amsdu_para_write,
++ .read = NULL,
++ .open = simple_open,
++ .llseek = default_llseek,
++};
++
++static int mt7996_amsdu_info_read(struct seq_file *s, void *data)
++{
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ u32 amsdu_cnt[WF_PLE_TOP_AMSDU_PACK_NUM] = {0}, total_cnt;
++ u8 i;
++
++ seq_printf(s, "HW A-MSDU Information:\n");
++
++ for (total_cnt = 0, i = 0; i < WF_PLE_TOP_AMSDU_PACK_NUM; ++i) {
++ amsdu_cnt[i] = mt76_rr(dev, WF_PLE_TOP_AMSDU_PACK_1_MSDU_CNT_ADDR + i * 4);
++ total_cnt += amsdu_cnt[i];
++ }
++
++ for (i = 0; i < WF_PLE_TOP_AMSDU_PACK_NUM; ++i) {
++ seq_printf(s, "# of HW A-MSDU containing %hhu MSDU: 0x%x",
++ i + 1, amsdu_cnt[i]);
++ seq_printf(s, "\t(%u.%u%%)\n",
++ total_cnt ? amsdu_cnt[i] * 1000 / total_cnt / 10 : 0,
++ total_cnt ? amsdu_cnt[i] * 1000 / total_cnt % 10 : 0);
++ }
++
++ return 0;
++}
++
++/* PSE INFO */
++static struct bmac_queue_info_t pse_queue_empty_info[] = {
++ {"CPU Q0", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_0},
++ {"CPU Q1", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_1},
++ {"CPU Q2", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_2},
++ {"CPU Q3", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_3},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, /* 4~7 not defined */
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, /* 14~15 not defined */
++ {"LMAC Q", ENUM_UMAC_LMAC_PORT_2, 0},
++ {"MDP TX Q0", ENUM_UMAC_LMAC_PORT_2, 1},
++ {"MDP RX Q", ENUM_UMAC_LMAC_PORT_2, 2},
++ {"SEC TX Q0", ENUM_UMAC_LMAC_PORT_2, 3},
++ {"SEC RX Q", ENUM_UMAC_LMAC_PORT_2, 4},
++ {"SFD_PARK Q", ENUM_UMAC_LMAC_PORT_2, 5},
++ {"MDP_TXIOC Q0", ENUM_UMAC_LMAC_PORT_2, 6},
++ {"MDP_RXIOC Q0", ENUM_UMAC_LMAC_PORT_2, 7},
++ {"MDP TX Q1", ENUM_UMAC_LMAC_PORT_2, 0x11},
++ {"SEC TX Q1", ENUM_UMAC_LMAC_PORT_2, 0x13},
++ {"MDP_TXIOC Q1", ENUM_UMAC_LMAC_PORT_2, 0x16},
++ {"MDP_RXIOC Q1", ENUM_UMAC_LMAC_PORT_2, 0x17},
++ {"CPU Q3", ENUM_UMAC_CPU_PORT_1, 4},
++ {NULL, 0, 0}, {NULL, 0, 0},
++ {"RLS Q", ENUM_PLE_CTRL_PSE_PORT_3, ENUM_UMAC_PLE_CTRL_P3_Q_0X1F}
++};
++
++static struct bmac_queue_info_t pse_queue_empty2_info[] = {
++ {"MDP_TDPIOC Q0", ENUM_UMAC_LMAC_PORT_2, 0x8},
++ {"MDP_RDPIOC Q0", ENUM_UMAC_LMAC_PORT_2, 0x9},
++ {"MDP_TDPIOC Q1", ENUM_UMAC_LMAC_PORT_2, 0x18},
++ {"MDP_RDPIOC Q1", ENUM_UMAC_LMAC_PORT_2, 0x19},
++ {"MDP_TDPIOC Q2", ENUM_UMAC_LMAC_PORT_2, 0x28},
++ {"MDP_RDPIOC Q2", ENUM_UMAC_LMAC_PORT_2, 0x29},
++ {NULL, 0, 0},
++ {"MDP_RDPIOC Q3", ENUM_UMAC_LMAC_PORT_2, 0x39},
++ {"MDP TX Q2", ENUM_UMAC_LMAC_PORT_2, 0x21},
++ {"SEC TX Q2", ENUM_UMAC_LMAC_PORT_2, 0x23},
++ {"MDP_TXIOC Q2", ENUM_UMAC_LMAC_PORT_2, 0x26},
++ {"MDP_RXIOC Q2", ENUM_UMAC_LMAC_PORT_2, 0x27},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {"MDP_RXIOC Q3", ENUM_UMAC_LMAC_PORT_2, 0x37},
++ {"HIF Q0", ENUM_UMAC_HIF_PORT_0, 0},
++ {"HIF Q1", ENUM_UMAC_HIF_PORT_0, 1},
++ {"HIF Q2", ENUM_UMAC_HIF_PORT_0, 2},
++ {"HIF Q3", ENUM_UMAC_HIF_PORT_0, 3},
++ {"HIF Q4", ENUM_UMAC_HIF_PORT_0, 4},
++ {"HIF Q5", ENUM_UMAC_HIF_PORT_0, 5},
++ {"HIF Q6", ENUM_UMAC_HIF_PORT_0, 6},
++ {"HIF Q7", ENUM_UMAC_HIF_PORT_0, 7},
++ {"HIF Q8", ENUM_UMAC_HIF_PORT_0, 8},
++ {"HIF Q9", ENUM_UMAC_HIF_PORT_0, 9},
++ {"HIF Q10", ENUM_UMAC_HIF_PORT_0, 10},
++ {"HIF Q11", ENUM_UMAC_HIF_PORT_0, 11},
++ {"HIF Q12", ENUM_UMAC_HIF_PORT_0, 12},
++ {"HIF Q13", ENUM_UMAC_HIF_PORT_0, 13},
++ {NULL, 0, 0}, {NULL, 0, 0}
++};
++
++static int
++mt7996_pseinfo_read(struct seq_file *s, void *data)
++{
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ u32 pse_buf_ctrl, pg_sz, pg_num;
++ u32 pse_stat[2], pg_flow_ctrl[28] = {0};
++ u32 fpg_cnt, ffa_cnt, fpg_head, fpg_tail;
++ u32 max_q, min_q, rsv_pg, used_pg;
++ int i;
++
++ pse_buf_ctrl = mt76_rr(dev, WF_PSE_TOP_PBUF_CTRL_ADDR);
++ pse_stat[0] = mt76_rr(dev, WF_PSE_TOP_QUEUE_EMPTY_ADDR);
++ pse_stat[1] = mt76_rr(dev, WF_PSE_TOP_QUEUE_EMPTY_1_ADDR);
++ pg_flow_ctrl[0] = mt76_rr(dev, WF_PSE_TOP_FREEPG_CNT_ADDR);
++ pg_flow_ctrl[1] = mt76_rr(dev, WF_PSE_TOP_FREEPG_HEAD_TAIL_ADDR);
++ pg_flow_ctrl[2] = mt76_rr(dev, WF_PSE_TOP_PG_HIF0_GROUP_ADDR);
++ pg_flow_ctrl[3] = mt76_rr(dev, WF_PSE_TOP_HIF0_PG_INFO_ADDR);
++ pg_flow_ctrl[4] = mt76_rr(dev, WF_PSE_TOP_PG_HIF1_GROUP_ADDR);
++ pg_flow_ctrl[5] = mt76_rr(dev, WF_PSE_TOP_HIF1_PG_INFO_ADDR);
++ pg_flow_ctrl[6] = mt76_rr(dev, WF_PSE_TOP_PG_CPU_GROUP_ADDR);
++ pg_flow_ctrl[7] = mt76_rr(dev, WF_PSE_TOP_CPU_PG_INFO_ADDR);
++ pg_flow_ctrl[8] = mt76_rr(dev, WF_PSE_TOP_PG_LMAC0_GROUP_ADDR);
++ pg_flow_ctrl[9] = mt76_rr(dev, WF_PSE_TOP_LMAC0_PG_INFO_ADDR);
++ pg_flow_ctrl[10] = mt76_rr(dev, WF_PSE_TOP_PG_LMAC1_GROUP_ADDR);
++ pg_flow_ctrl[11] = mt76_rr(dev, WF_PSE_TOP_LMAC1_PG_INFO_ADDR);
++ pg_flow_ctrl[12] = mt76_rr(dev, WF_PSE_TOP_PG_LMAC2_GROUP_ADDR);
++ pg_flow_ctrl[13] = mt76_rr(dev, WF_PSE_TOP_LMAC2_PG_INFO_ADDR);
++ pg_flow_ctrl[14] = mt76_rr(dev, WF_PSE_TOP_PG_PLE_GROUP_ADDR);
++ pg_flow_ctrl[15] = mt76_rr(dev, WF_PSE_TOP_PLE_PG_INFO_ADDR);
++ pg_flow_ctrl[16] = mt76_rr(dev, WF_PSE_TOP_PG_LMAC3_GROUP_ADDR);
++ pg_flow_ctrl[17] = mt76_rr(dev, WF_PSE_TOP_LMAC3_PG_INFO_ADDR);
++ pg_flow_ctrl[18] = mt76_rr(dev, WF_PSE_TOP_PG_MDP_GROUP_ADDR);
++ pg_flow_ctrl[19] = mt76_rr(dev, WF_PSE_TOP_MDP_PG_INFO_ADDR);
++ pg_flow_ctrl[20] = mt76_rr(dev, WF_PSE_TOP_PG_PLE1_GROUP_ADDR);
++ pg_flow_ctrl[21] = mt76_rr(dev, WF_PSE_TOP_PLE1_PG_INFO_ADDR);
++ pg_flow_ctrl[22] = mt76_rr(dev, WF_PSE_TOP_PG_MDP2_GROUP_ADDR);
++ pg_flow_ctrl[23] = mt76_rr(dev, WF_PSE_TOP_MDP2_PG_INFO_ADDR);
++ if (mt7996_band_valid(dev, MT_BAND2)) {
++ pg_flow_ctrl[24] = mt76_rr(dev, WF_PSE_TOP_PG_MDP3_GROUP_ADDR);
++ pg_flow_ctrl[25] = mt76_rr(dev, WF_PSE_TOP_MDP3_PG_INFO_ADDR);
++ }
++ pg_flow_ctrl[26] = mt76_rr(dev, WF_PSE_TOP_PG_HIF2_GROUP_ADDR);
++ pg_flow_ctrl[27] = mt76_rr(dev, WF_PSE_TOP_HIF2_PG_INFO_ADDR);
++ /* Configuration Info */
++ seq_printf(s, "PSE Configuration Info:\n");
++ seq_printf(s, "\tPacket Buffer Control: 0x%08x\n", pse_buf_ctrl);
++ pg_sz = (pse_buf_ctrl & WF_PSE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_MASK) >> WF_PSE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_SHFT;
++ seq_printf(s, "\t\tPage Size=%d(%d bytes per page)\n", pg_sz, (pg_sz == 1 ? 256 : 128));
++ seq_printf(s, "\t\tPage Offset=%d(in unit of 64KB)\n",
++ (pse_buf_ctrl & WF_PSE_TOP_PBUF_CTRL_PBUF_OFFSET_MASK) >> WF_PSE_TOP_PBUF_CTRL_PBUF_OFFSET_SHFT);
++ pg_num = (pse_buf_ctrl & WF_PSE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_MASK) >> WF_PSE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_SHFT;
++ seq_printf(s, "\t\tTotal page numbers=%d pages\n", pg_num);
++ /* Page Flow Control */
++ seq_printf(s, "PSE Page Flow Control:\n");
++ seq_printf(s, "\tFree page counter: 0x%08x\n", pg_flow_ctrl[0]);
++ fpg_cnt = (pg_flow_ctrl[0] & WF_PSE_TOP_FREEPG_CNT_FREEPG_CNT_MASK) >> WF_PSE_TOP_FREEPG_CNT_FREEPG_CNT_SHFT;
++ seq_printf(s, "\t\tThe toal page number of free=0x%03x\n", fpg_cnt);
++ ffa_cnt = (pg_flow_ctrl[0] & WF_PSE_TOP_FREEPG_CNT_FFA_CNT_MASK) >> WF_PSE_TOP_FREEPG_CNT_FFA_CNT_SHFT;
++ seq_printf(s, "\t\tThe free page numbers of free for all=0x%03x\n", ffa_cnt);
++ seq_printf(s, "\tFree page head and tail: 0x%08x\n", pg_flow_ctrl[1]);
++ fpg_head = (pg_flow_ctrl[1] & WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_MASK) >> WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_SHFT;
++ fpg_tail = (pg_flow_ctrl[1] & WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_MASK) >> WF_PSE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_SHFT;
++ seq_printf(s, "\t\tThe tail/head page of free page list=0x%03x/0x%03x\n", fpg_tail, fpg_head);
++ seq_printf(s, "\tReserved page counter of HIF0 group: 0x%08x\n", pg_flow_ctrl[2]);
++ seq_printf(s, "\tHIF0 group page status: 0x%08x\n", pg_flow_ctrl[3]);
++ min_q = (pg_flow_ctrl[2] & WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[2] & WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_HIF0_GROUP_HIF0_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of HIF0 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[3] & WF_PSE_TOP_HIF0_PG_INFO_HIF0_RSV_CNT_MASK) >> WF_PSE_TOP_HIF0_PG_INFO_HIF0_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[3] & WF_PSE_TOP_HIF0_PG_INFO_HIF0_SRC_CNT_MASK) >> WF_PSE_TOP_HIF0_PG_INFO_HIF0_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of HIF0 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of HIF1 group: 0x%08x\n", pg_flow_ctrl[4]);
++ seq_printf(s, "\tHIF1 group page status: 0x%08x\n", pg_flow_ctrl[5]);
++ min_q = (pg_flow_ctrl[4] & WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[4] & WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_HIF1_GROUP_HIF1_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of HIF1 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[5] & WF_PSE_TOP_HIF1_PG_INFO_HIF1_RSV_CNT_MASK) >> WF_PSE_TOP_HIF1_PG_INFO_HIF1_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[5] & WF_PSE_TOP_HIF1_PG_INFO_HIF1_SRC_CNT_MASK) >> WF_PSE_TOP_HIF1_PG_INFO_HIF1_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of HIF1 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of HIF2 group: 0x%08x\n", pg_flow_ctrl[26]);
++ seq_printf(s, "\tHIF2 group page status: 0x%08x\n", pg_flow_ctrl[27]);
++ min_q = (pg_flow_ctrl[26] & WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[26] & WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_HIF2_GROUP_HIF2_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of HIF2 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[27] & WF_PSE_TOP_HIF2_PG_INFO_HIF2_RSV_CNT_MASK) >> WF_PSE_TOP_HIF2_PG_INFO_HIF2_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[27] & WF_PSE_TOP_HIF2_PG_INFO_HIF2_SRC_CNT_MASK) >> WF_PSE_TOP_HIF2_PG_INFO_HIF2_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of HIF2 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of CPU group: 0x%08x\n", pg_flow_ctrl[6]);
++ seq_printf(s, "\tCPU group page status: 0x%08x\n", pg_flow_ctrl[7]);
++ min_q = (pg_flow_ctrl[6] & WF_PSE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[6] & WF_PSE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of CPU group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[7] & WF_PSE_TOP_CPU_PG_INFO_CPU_RSV_CNT_MASK) >> WF_PSE_TOP_CPU_PG_INFO_CPU_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[7] & WF_PSE_TOP_CPU_PG_INFO_CPU_SRC_CNT_MASK) >> WF_PSE_TOP_CPU_PG_INFO_CPU_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of CPU group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of LMAC0 group: 0x%08x\n", pg_flow_ctrl[8]);
++ seq_printf(s, "\tLMAC0 group page status: 0x%08x\n", pg_flow_ctrl[9]);
++ min_q = (pg_flow_ctrl[8] & WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[8] & WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC0_GROUP_LMAC0_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of LMAC0 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[9] & WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_RSV_CNT_MASK) >> WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[9] & WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_SRC_CNT_MASK) >> WF_PSE_TOP_LMAC0_PG_INFO_LMAC0_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of LMAC0 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of LMAC1 group: 0x%08x\n", pg_flow_ctrl[10]);
++ seq_printf(s, "\tLMAC1 group page status: 0x%08x\n", pg_flow_ctrl[11]);
++ min_q = (pg_flow_ctrl[10] & WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[10] & WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC1_GROUP_LMAC1_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of LMAC1 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[11] & WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_RSV_CNT_MASK) >> WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[11] & WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_SRC_CNT_MASK) >> WF_PSE_TOP_LMAC1_PG_INFO_LMAC1_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of LMAC1 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of LMAC2 group: 0x%08x\n", pg_flow_ctrl[11]);
++ seq_printf(s, "\tLMAC2 group page status: 0x%08x\n", pg_flow_ctrl[12]);
++ min_q = (pg_flow_ctrl[12] & WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[12] & WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC2_GROUP_LMAC2_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of LMAC2 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[13] & WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_RSV_CNT_MASK) >> WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[13] & WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_SRC_CNT_MASK) >> WF_PSE_TOP_LMAC2_PG_INFO_LMAC2_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of LMAC2 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++
++ seq_printf(s, "\tReserved page counter of LMAC3 group: 0x%08x\n", pg_flow_ctrl[16]);
++ seq_printf(s, "\tLMAC3 group page status: 0x%08x\n", pg_flow_ctrl[17]);
++ min_q = (pg_flow_ctrl[16] & WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[16] & WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_LMAC3_GROUP_LMAC3_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of LMAC3 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[17] & WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_RSV_CNT_MASK) >> WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[17] & WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_SRC_CNT_MASK) >> WF_PSE_TOP_LMAC3_PG_INFO_LMAC3_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of LMAC3 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++
++ seq_printf(s, "\tReserved page counter of PLE group: 0x%08x\n", pg_flow_ctrl[14]);
++ seq_printf(s, "\tPLE group page status: 0x%08x\n", pg_flow_ctrl[15]);
++ min_q = (pg_flow_ctrl[14] & WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[14] & WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of PLE group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[15] & WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_MASK) >> WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[15] & WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_MASK) >> WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of PLE group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++
++ seq_printf(s, "\tReserved page counter of PLE1 group: 0x%08x\n", pg_flow_ctrl[14]);
++ seq_printf(s, "\tPLE1 group page status: 0x%08x\n", pg_flow_ctrl[15]);
++ min_q = (pg_flow_ctrl[20] & WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_PLE_GROUP_PLE_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[20] & WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_PLE_GROUP_PLE_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of PLE1 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[21] & WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_MASK) >> WF_PSE_TOP_PLE_PG_INFO_PLE_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[21] & WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_MASK) >> WF_PSE_TOP_PLE_PG_INFO_PLE_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of PLE1 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++
++ seq_printf(s, "\tReserved page counter of MDP group: 0x%08x\n", pg_flow_ctrl[18]);
++ seq_printf(s, "\tMDP group page status: 0x%08x\n", pg_flow_ctrl[19]);
++ min_q = (pg_flow_ctrl[18] & WF_PSE_TOP_PG_MDP_GROUP_MDP_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_MDP_GROUP_MDP_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[18] & WF_PSE_TOP_PG_MDP_GROUP_MDP_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_MDP_GROUP_MDP_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of MDP group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[19] & WF_PSE_TOP_MDP_PG_INFO_MDP_RSV_CNT_MASK) >> WF_PSE_TOP_MDP_PG_INFO_MDP_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[19] & WF_PSE_TOP_MDP_PG_INFO_MDP_SRC_CNT_MASK) >> WF_PSE_TOP_MDP_PG_INFO_MDP_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of MDP group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ seq_printf(s, "\tReserved page counter of MDP2 group: 0x%08x\n", pg_flow_ctrl[22]);
++ seq_printf(s, "\tMDP2 group page status: 0x%08x\n", pg_flow_ctrl[23]);
++ min_q = (pg_flow_ctrl[22] & WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[22] & WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_MDP2_GROUP_MDP2_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of MDP2 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[23] & WF_PSE_TOP_MDP2_PG_INFO_MDP2_RSV_CNT_MASK) >> WF_PSE_TOP_MDP2_PG_INFO_MDP2_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[23] & WF_PSE_TOP_MDP2_PG_INFO_MDP2_SRC_CNT_MASK) >> WF_PSE_TOP_MDP2_PG_INFO_MDP2_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of MDP2 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ if (mt7996_band_valid(dev, MT_BAND2)) {
++ seq_printf(s, "\tReserved page counter of MDP3 group: 0x%08x\n", pg_flow_ctrl[24]);
++ seq_printf(s, "\tMDP3 group page status: 0x%08x\n", pg_flow_ctrl[25]);
++ min_q = (pg_flow_ctrl[24] & WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MIN_QUOTA_MASK) >> WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MIN_QUOTA_SHFT;
++ max_q = (pg_flow_ctrl[24] & WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MAX_QUOTA_MASK) >> WF_PSE_TOP_PG_MDP3_GROUP_MDP3_MAX_QUOTA_SHFT;
++ seq_printf(s, "\t\tThe max/min quota pages of MDP3 group=0x%03x/0x%03x\n", max_q, min_q);
++ rsv_pg = (pg_flow_ctrl[25] & WF_PSE_TOP_MDP3_PG_INFO_MDP3_RSV_CNT_MASK) >> WF_PSE_TOP_MDP3_PG_INFO_MDP3_RSV_CNT_SHFT;
++ used_pg = (pg_flow_ctrl[25] & WF_PSE_TOP_MDP3_PG_INFO_MDP3_SRC_CNT_MASK) >> WF_PSE_TOP_MDP3_PG_INFO_MDP3_SRC_CNT_SHFT;
++ seq_printf(s, "\t\tThe used/reserved pages of MDP3 group=0x%03x/0x%03x\n", used_pg, rsv_pg);
++ }
++ /* Queue Empty Status */
++ seq_printf(s, "PSE Queue Empty Status:\n");
++ seq_printf(s, "\tQUEUE_EMPTY: 0x%08x, QUEUE_EMPTY2: 0x%08x\n", pse_stat[0], pse_stat[1]);
++ seq_printf(s, "\t\tCPU Q0/1/2/3/4 empty=%d/%d/%d/%d/%d\n",
++ (pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_CPU_Q0_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_CPU_Q0_EMPTY_SHFT,
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_CPU_Q1_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_CPU_Q1_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_CPU_Q2_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_CPU_Q2_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_CPU_Q3_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_CPU_Q3_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_CPU_Q4_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_CPU_Q4_EMPTY_SHFT));
++ seq_printf(s, "\t\tHIF Q0/1/2/3/4/5/6/7/8/9/10/11/12/13 empty=%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d/%d\n",
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_0_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_0_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_1_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_1_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_2_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_2_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_3_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_3_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_4_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_4_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_5_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_5_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_6_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_6_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_7_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_7_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_8_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_8_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_9_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_9_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_10_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_10_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_11_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_11_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_12_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_12_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_HIF_13_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_HIF_13_EMPTY_SHFT));
++ seq_printf(s, "\t\tLMAC TX Q empty=%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_LMAC_TX_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_LMAC_TX_QUEUE_EMPTY_SHFT));
++ seq_printf(s, "\t\tMDP TX Q0/Q1/Q2/RX Q empty=%d/%d/%d/%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_TX_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_TX_QUEUE_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_TX1_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_TX1_QUEUE_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TX2_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TX2_QUEUE_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_RX_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_RX_QUEUE_EMPTY_SHFT));
++ seq_printf(s, "\t\tSEC TX Q0/Q1/Q2/RX Q empty=%d/%d/%d/%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_SEC_TX_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_SEC_TX_QUEUE_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_SEC_TX1_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_SEC_TX1_QUEUE_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_SEC_TX2_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_SEC_TX2_QUEUE_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_SEC_RX_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_SEC_RX_QUEUE_EMPTY_SHFT));
++ seq_printf(s, "\t\tSFD PARK Q empty=%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_SFD_PARK_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_SFD_PARK_QUEUE_EMPTY_SHFT));
++ seq_printf(s, "\t\tMDP TXIOC Q0/Q1/Q2 empty=%d/%d/%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC_QUEUE_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC1_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_TXIOC1_QUEUE_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TXIOC2_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_MDP_TXIOC2_QUEUE_EMPTY_SHFT));
++ seq_printf(s, "\t\tMDP RXIOC Q0/Q1/Q2/Q3 empty=%d/%d/%d/%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC_QUEUE_EMPTY_SHFT),
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC1_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_MDP_RXIOC1_QUEUE_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC2_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC2_QUEUE_EMPTY_SHFT),
++ ((pse_stat[1] & WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC3_QUEUE_EMPTY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_1_MDP_RXIOC3_QUEUE_EMPTY_SHFT));
++ seq_printf(s, "\t\tRLS Q empty=%d\n",
++ ((pse_stat[0] & WF_PSE_TOP_QUEUE_EMPTY_RLS_Q_EMTPY_MASK) >> WF_PSE_TOP_QUEUE_EMPTY_RLS_Q_EMTPY_SHFT));
++ seq_printf(s, "Nonempty Q info:\n");
++
++ for (i = 0; i < 31; i++) {
++ if (((pse_stat[0] & (0x1 << i)) >> i) == 0) {
++ u32 hfid, tfid, pktcnt, fl_que_ctrl[3] = {0};
++
++ if (pse_queue_empty_info[i].QueueName != NULL) {
++ seq_printf(s, "\t%s: ", pse_queue_empty_info[i].QueueName);
++ fl_que_ctrl[0] |= WF_PSE_TOP_FL_QUE_CTRL_0_EXECUTE_MASK;
++ fl_que_ctrl[0] |= (pse_queue_empty_info[i].Portid << WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_SHFT);
++ fl_que_ctrl[0] |= (pse_queue_empty_info[i].Queueid << WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_SHFT);
++ } else
++ continue;
++
++ fl_que_ctrl[0] |= (0x1 << 31);
++ mt76_wr(dev, WF_PSE_TOP_FL_QUE_CTRL_0_ADDR, fl_que_ctrl[0]);
++ fl_que_ctrl[1] = mt76_rr(dev, WF_PSE_TOP_FL_QUE_CTRL_2_ADDR);
++ fl_que_ctrl[2] = mt76_rr(dev, WF_PSE_TOP_FL_QUE_CTRL_3_ADDR);
++ hfid = (fl_que_ctrl[1] & WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_MASK) >> WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_SHFT;
++ tfid = (fl_que_ctrl[1] & WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_MASK) >> WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_SHFT;
++ pktcnt = (fl_que_ctrl[2] & WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_MASK) >> WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_SHFT;
++ seq_printf(s, "tail/head fid = 0x%03x/0x%03x, pkt cnt = 0x%03x\n",
++ tfid, hfid, pktcnt);
++ }
++ }
++
++ for (i = 0; i < 31; i++) {
++ if (((pse_stat[1] & (0x1 << i)) >> i) == 0) {
++ u32 hfid, tfid, pktcnt, fl_que_ctrl[3] = {0};
++
++ if (pse_queue_empty2_info[i].QueueName != NULL) {
++ seq_printf(s, "\t%s: ", pse_queue_empty2_info[i].QueueName);
++ fl_que_ctrl[0] |= WF_PSE_TOP_FL_QUE_CTRL_0_EXECUTE_MASK;
++ fl_que_ctrl[0] |= (pse_queue_empty2_info[i].Portid << WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_SHFT);
++ fl_que_ctrl[0] |= (pse_queue_empty2_info[i].Queueid << WF_PSE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_SHFT);
++ } else
++ continue;
++
++ fl_que_ctrl[0] |= (0x1 << 31);
++ mt76_wr(dev, WF_PSE_TOP_FL_QUE_CTRL_0_ADDR, fl_que_ctrl[0]);
++ fl_que_ctrl[1] = mt76_rr(dev, WF_PSE_TOP_FL_QUE_CTRL_2_ADDR);
++ fl_que_ctrl[2] = mt76_rr(dev, WF_PSE_TOP_FL_QUE_CTRL_3_ADDR);
++ hfid = (fl_que_ctrl[1] & WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_MASK) >> WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_SHFT;
++ tfid = (fl_que_ctrl[1] & WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_MASK) >> WF_PSE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_SHFT;
++ pktcnt = (fl_que_ctrl[2] & WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_MASK) >> WF_PSE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_SHFT;
++ seq_printf(s, "tail/head fid = 0x%03x/0x%03x, pkt cnt = 0x%03x\n",
++ tfid, hfid, pktcnt);
++ }
++ }
++
++ return 0;
++}
++
++/* PLE INFO */
++static char *sta_ctrl_reg[] = {"ENABLE", "DISABLE", "PAUSE", "TWT_PAUSE"};
++static struct bmac_queue_info ple_queue_empty_info[] = {
++ {"CPU Q0", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_0, 0},
++ {"CPU Q1", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_1, 0},
++ {"CPU Q2", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_2, 0},
++ {"CPU Q3", ENUM_UMAC_CPU_PORT_1, ENUM_UMAC_CTX_Q_3, 0},
++ {"ALTX Q0", ENUM_UMAC_LMAC_PORT_2, 0x10, 0},
++ {"BMC Q0", ENUM_UMAC_LMAC_PORT_2, 0x11, 0},
++ {"BCN Q0", ENUM_UMAC_LMAC_PORT_2, 0x12, 0},
++ {"PSMP Q0", ENUM_UMAC_LMAC_PORT_2, 0x13, 0},
++ {"ALTX Q1", ENUM_UMAC_LMAC_PORT_2, 0x10, 1},
++ {"BMC Q1", ENUM_UMAC_LMAC_PORT_2, 0x11, 1},
++ {"BCN Q1", ENUM_UMAC_LMAC_PORT_2, 0x12, 1},
++ {"PSMP Q1", ENUM_UMAC_LMAC_PORT_2, 0x13, 1},
++ {"ALTX Q2", ENUM_UMAC_LMAC_PORT_2, 0x10, 2},
++ {"BMC Q2", ENUM_UMAC_LMAC_PORT_2, 0x11, 2},
++ {"BCN Q2", ENUM_UMAC_LMAC_PORT_2, 0x12, 2},
++ {"PSMP Q2", ENUM_UMAC_LMAC_PORT_2, 0x13, 2},
++ {"NAF Q", ENUM_UMAC_LMAC_PORT_2, 0x18, 0},
++ {"NBCN Q", ENUM_UMAC_LMAC_PORT_2, 0x19, 0},
++ {NULL, 0, 0, 0}, {NULL, 0, 0, 0}, /* 18, 19 not defined */
++ {"FIXFID Q", ENUM_UMAC_LMAC_PORT_2, 0x1a, 0},
++ {NULL, 0, 0, 0}, {NULL, 0, 0, 0}, {NULL, 0, 0, 0}, {NULL, 0, 0, 0}, {NULL, 0, 0, 0},
++ {NULL, 0, 0, 0}, {NULL, 0, 0, 0},
++ {"RLS4 Q", ENUM_PLE_CTRL_PSE_PORT_3, 0x7c, 0},
++ {"RLS3 Q", ENUM_PLE_CTRL_PSE_PORT_3, 0x7d, 0},
++ {"RLS2 Q", ENUM_PLE_CTRL_PSE_PORT_3, 0x7e, 0},
++ {"RLS Q", ENUM_PLE_CTRL_PSE_PORT_3, 0x7f, 0}
++};
++
++static struct bmac_queue_info_t ple_txcmd_queue_empty_info[__MT_MAX_BAND][32] = {
++ {{"AC00Q", ENUM_UMAC_LMAC_PORT_2, 0x40},
++ {"AC01Q", ENUM_UMAC_LMAC_PORT_2, 0x41},
++ {"AC02Q", ENUM_UMAC_LMAC_PORT_2, 0x42},
++ {"AC03Q", ENUM_UMAC_LMAC_PORT_2, 0x43},
++ {"AC10Q", ENUM_UMAC_LMAC_PORT_2, 0x44},
++ {"AC11Q", ENUM_UMAC_LMAC_PORT_2, 0x45},
++ {"AC12Q", ENUM_UMAC_LMAC_PORT_2, 0x46},
++ {"AC13Q", ENUM_UMAC_LMAC_PORT_2, 0x47},
++ {"AC20Q", ENUM_UMAC_LMAC_PORT_2, 0x48},
++ {"AC21Q", ENUM_UMAC_LMAC_PORT_2, 0x49},
++ {"AC22Q", ENUM_UMAC_LMAC_PORT_2, 0x4a},
++ {"AC23Q", ENUM_UMAC_LMAC_PORT_2, 0x4b},
++ {"AC30Q", ENUM_UMAC_LMAC_PORT_2, 0x4c},
++ {"AC31Q", ENUM_UMAC_LMAC_PORT_2, 0x4d},
++ {"AC32Q", ENUM_UMAC_LMAC_PORT_2, 0x4e},
++ {"AC33Q", ENUM_UMAC_LMAC_PORT_2, 0x4f},
++ {"ALTX Q0", ENUM_UMAC_LMAC_PORT_2, 0x70},
++ {"TF Q0", ENUM_UMAC_LMAC_PORT_2, 0x71},
++ {"TWT TSF-TF Q0", ENUM_UMAC_LMAC_PORT_2, 0x72},
++ {"TWT DL Q0", ENUM_UMAC_LMAC_PORT_2, 0x73},
++ {"TWT UL Q0", ENUM_UMAC_LMAC_PORT_2, 0x74},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}},
++
++ {{"AC00Q", ENUM_UMAC_LMAC_PORT_2, 0x50},
++ {"AC01Q", ENUM_UMAC_LMAC_PORT_2, 0x51},
++ {"AC02Q", ENUM_UMAC_LMAC_PORT_2, 0x52},
++ {"AC03Q", ENUM_UMAC_LMAC_PORT_2, 0x53},
++ {"AC10Q", ENUM_UMAC_LMAC_PORT_2, 0x54},
++ {"AC11Q", ENUM_UMAC_LMAC_PORT_2, 0x55},
++ {"AC12Q", ENUM_UMAC_LMAC_PORT_2, 0x56},
++ {"AC13Q", ENUM_UMAC_LMAC_PORT_2, 0x57},
++ {"AC20Q", ENUM_UMAC_LMAC_PORT_2, 0x58},
++ {"AC21Q", ENUM_UMAC_LMAC_PORT_2, 0x59},
++ {"AC22Q", ENUM_UMAC_LMAC_PORT_2, 0x5a},
++ {"AC23Q", ENUM_UMAC_LMAC_PORT_2, 0x5b},
++ {"AC30Q", ENUM_UMAC_LMAC_PORT_2, 0x5c},
++ {"AC31Q", ENUM_UMAC_LMAC_PORT_2, 0x5d},
++ {"AC32Q", ENUM_UMAC_LMAC_PORT_2, 0x5e},
++ {"AC33Q", ENUM_UMAC_LMAC_PORT_2, 0x5f},
++ {"ALTX Q0", ENUM_UMAC_LMAC_PORT_2, 0x75},
++ {"TF Q0", ENUM_UMAC_LMAC_PORT_2, 0x76},
++ {"TWT TSF-TF Q0", ENUM_UMAC_LMAC_PORT_2, 0x77},
++ {"TWT DL Q0", ENUM_UMAC_LMAC_PORT_2, 0x78},
++ {"TWT UL Q0", ENUM_UMAC_LMAC_PORT_2, 0x79},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}},
++
++ {{"AC00Q", ENUM_UMAC_LMAC_PORT_2, 0x60},
++ {"AC01Q", ENUM_UMAC_LMAC_PORT_2, 0x61},
++ {"AC02Q", ENUM_UMAC_LMAC_PORT_2, 0x62},
++ {"AC03Q", ENUM_UMAC_LMAC_PORT_2, 0x63},
++ {"AC10Q", ENUM_UMAC_LMAC_PORT_2, 0x64},
++ {"AC11Q", ENUM_UMAC_LMAC_PORT_2, 0x65},
++ {"AC12Q", ENUM_UMAC_LMAC_PORT_2, 0x66},
++ {"AC13Q", ENUM_UMAC_LMAC_PORT_2, 0x67},
++ {"AC20Q", ENUM_UMAC_LMAC_PORT_2, 0x68},
++ {"AC21Q", ENUM_UMAC_LMAC_PORT_2, 0x69},
++ {"AC22Q", ENUM_UMAC_LMAC_PORT_2, 0x6a},
++ {"AC23Q", ENUM_UMAC_LMAC_PORT_2, 0x6b},
++ {"AC30Q", ENUM_UMAC_LMAC_PORT_2, 0x6c},
++ {"AC31Q", ENUM_UMAC_LMAC_PORT_2, 0x6d},
++ {"AC32Q", ENUM_UMAC_LMAC_PORT_2, 0x6e},
++ {"AC33Q", ENUM_UMAC_LMAC_PORT_2, 0x6f},
++ {"ALTX Q0", ENUM_UMAC_LMAC_PORT_2, 0x7a},
++ {"TF Q0", ENUM_UMAC_LMAC_PORT_2, 0x7b},
++ {"TWT TSF-TF Q0", ENUM_UMAC_LMAC_PORT_2, 0x7c},
++ {"TWT DL Q0", ENUM_UMAC_LMAC_PORT_2, 0x7d},
++ {"TWT UL Q0", ENUM_UMAC_LMAC_PORT_2, 0x7e},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0},
++ {NULL, 0, 0}, {NULL, 0, 0}, {NULL, 0, 0}}
++};
++
++static size_t
++ple_cr_num_of_ac(struct mt76_dev *dev)
++{
++ switch (mt76_chip(dev)) {
++ case 0x7990:
++ return CR_NUM_OF_AC_MT7996;
++ case 0x7992:
++ default:
++ return CR_NUM_OF_AC_MT7992;
++ }
++}
++
++static void
++mt7996_show_ple_pg_info(struct mt7996_dev *dev, struct seq_file *s)
++{
++ u32 val[2];
++
++ seq_printf(s, "PLE Configuration Info:\n");
++
++ val[0] = mt76_rr(dev, WF_PLE_TOP_PBUF_CTRL_ADDR);
++ seq_printf(s, "\tPacket Buffer Control: 0x%08x\n", val[0]);
++ seq_printf(s, "\t\tPage size: %u bytes\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PBUF_CTRL_PAGE_SIZE_CFG_MASK) ? 128 : 64);
++ seq_printf(s, "\t\tPacket buffer offset: %u (unit: 2KB)\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PBUF_CTRL_PBUF_OFFSET_MASK));
++ seq_printf(s, "\t\tTotal number of pages: %u pages\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PBUF_CTRL_TOTAL_PAGE_NUM_MASK));
++
++ seq_printf(s, "PLE Page Flow Control:\n");
++
++ val[0] = mt76_rr(dev, WF_PLE_TOP_FREEPG_CNT_ADDR);
++ val[1] = mt76_rr(dev, WF_PLE_TOP_FREEPG_HEAD_TAIL_ADDR);
++ seq_printf(s, "\tFree Page Counter: 0x%08x\n", val[0]);
++ seq_printf(s, "\tFree Page Head and Tail: 0x%08x\n", val[1]);
++ seq_printf(s, "\t\tNumber of free pages: 0x%04x\n",
++ u32_get_bits(val[0], WF_PLE_TOP_FREEPG_CNT_FREEPG_CNT_MASK));
++ seq_printf(s, "\t\tNumber of unassigned pages: 0x%04x\n",
++ u32_get_bits(val[0], WF_PLE_TOP_FREEPG_CNT_FFA_CNT_MASK));
++ seq_printf(s, "\t\tFID of tail/head free page: 0x%04x/0x%04x\n",
++ u32_get_bits(val[1], WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_TAIL_MASK),
++ u32_get_bits(val[1], WF_PLE_TOP_FREEPG_HEAD_TAIL_FREEPG_HEAD_MASK));
++
++ val[0] = mt76_rr(dev, WF_PLE_TOP_PG_HIF_GROUP_ADDR);
++ val[1] = mt76_rr(dev, WF_PLE_TOP_HIF_PG_INFO_ADDR);
++ seq_printf(s, "\tReserved Page Counter of HIF Group: 0x%08x\n", val[0]);
++ seq_printf(s, "\tHIF Group Page Status: 0x%08x\n", val[1]);
++ seq_printf(s, "\t\tMax/min page quota for HIF group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PG_HIF_GROUP_HIF_MAX_QUOTA_MASK),
++ u32_get_bits(val[0], WF_PLE_TOP_PG_HIF_GROUP_HIF_MIN_QUOTA_MASK));
++ seq_printf(s, "\t\tUsed/free page count for HIF group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[1], WF_PLE_TOP_HIF_PG_INFO_HIF_SRC_CNT_MASK),
++ u32_get_bits(val[1], WF_PLE_TOP_HIF_PG_INFO_HIF_RSV_CNT_MASK));
++
++ val[0] = mt76_rr(dev, WF_PLE_TOP_PG_HIF_WMTXD_GROUP_ADDR);
++ val[1] = mt76_rr(dev, WF_PLE_TOP_HIF_WMTXD_PG_INFO_ADDR);
++ seq_printf(s, "\tReserved Page Counter of HIF WMCPU TXD Group: 0x%08x\n", val[0]);
++ seq_printf(s, "\tHIF WMCPU TXD Group Page Status: 0x%08x\n", val[1]);
++ seq_printf(s, "\t\tMax/min page quota for HIF WMCPU TXD group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MAX_QUOTA_MASK),
++ u32_get_bits(val[0], WF_PLE_TOP_PG_HIF_WMTXD_GROUP_HIF_WMTXD_MIN_QUOTA_MASK));
++ seq_printf(s, "\t\tUsed/free page count for HIF WMCPU TXD group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[1], WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_SRC_CNT_MASK),
++ u32_get_bits(val[1], WF_PLE_TOP_HIF_WMTXD_PG_INFO_HIF_WMTXD_RSV_CNT_MASK));
++
++ val[0] = mt76_rr(dev, WF_PLE_TOP_PG_HIF_TXCMD_GROUP_ADDR);
++ val[1] = mt76_rr(dev, WF_PLE_TOP_HIF_TXCMD_PG_INFO_ADDR);
++ seq_printf(s, "\tReserved Page Counter of HIF TXCMD Group: 0x%08x\n", val[0]);
++ seq_printf(s, "\tHIF TXCMD Group Page Status: 0x%08x\n", val[1]);
++ seq_printf(s, "\t\tMax/min page quota for HIF TXCMD group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MAX_QUOTA_MASK),
++ u32_get_bits(val[0], WF_PLE_TOP_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MIN_QUOTA_MASK));
++ seq_printf(s, "\t\tUsed/free page count for HIF TXCMD group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[1], WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_SRC_CNT_MASK),
++ u32_get_bits(val[1], WF_PLE_TOP_HIF_TXCMD_PG_INFO_HIF_TXCMD_RSV_CNT_MASK));
++
++ val[0] = mt76_rr(dev, WF_PLE_TOP_PG_CPU_GROUP_ADDR);
++ val[1] = mt76_rr(dev, WF_PLE_TOP_CPU_PG_INFO_ADDR);
++ seq_printf(s, "\tReserved Page Counter of CPU Group: 0x%08x\n", val[0]);
++ seq_printf(s, "\tCPU Group Page Status: 0x%08x\n", val[1]);
++ seq_printf(s, "\t\tMax/min page quota for CPU group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[0], WF_PLE_TOP_PG_CPU_GROUP_CPU_MAX_QUOTA_MASK),
++ u32_get_bits(val[0], WF_PLE_TOP_PG_CPU_GROUP_CPU_MIN_QUOTA_MASK));
++ seq_printf(s, "\t\tUsed/free page count for CPU group: 0x%04x/0x%04x\n",
++ u32_get_bits(val[1], WF_PLE_TOP_CPU_PG_INFO_CPU_SRC_CNT_MASK),
++ u32_get_bits(val[1], WF_PLE_TOP_CPU_PG_INFO_CPU_RSV_CNT_MASK));
++}
++
++static void
++mt7996_get_ple_acq_stat(struct mt7996_dev *dev, unsigned long *ple_stat)
++{
++ u32 i, addr;
++ size_t cr_num_of_ac = ple_cr_num_of_ac(&dev->mt76);
++
++ ple_stat[0] = mt76_rr(dev, WF_PLE_TOP_QUEUE_EMPTY_ADDR);
++
++ /* Legacy */
++ addr = WF_PLE_TOP_AC0_QUEUE_EMPTY0_ADDR;
++ for (i = 1; i <= cr_num_of_ac; i++, addr += 4) {
++ if (i == cr_num_of_ac && is_mt7992(&dev->mt76))
++ ple_stat[i] = mt76_rr(dev, WF_PLE_TOP_AC0_QUEUE_EMPTY_EXT0_ADDR);
++ else
++ ple_stat[i] = mt76_rr(dev, addr);
++ }
++
++ addr = WF_PLE_TOP_AC1_QUEUE_EMPTY0_ADDR;
++ for (; i <= cr_num_of_ac * 2; i++, addr += 4) {
++ if (i == cr_num_of_ac * 2 && is_mt7992(&dev->mt76))
++ ple_stat[i] = mt76_rr(dev, WF_PLE_TOP_AC1_QUEUE_EMPTY_EXT0_ADDR);
++ else
++ ple_stat[i] = mt76_rr(dev, addr);
++ }
++
++ addr = WF_PLE_TOP_AC2_QUEUE_EMPTY0_ADDR;
++ for (; i <= cr_num_of_ac * 3; i++, addr += 4) {
++ if (i == cr_num_of_ac * 3 && is_mt7992(&dev->mt76))
++ ple_stat[i] = mt76_rr(dev, WF_PLE_TOP_AC2_QUEUE_EMPTY_EXT0_ADDR);
++ else
++ ple_stat[i] = mt76_rr(dev, addr);
++ }
++
++ addr = WF_PLE_TOP_AC3_QUEUE_EMPTY0_ADDR;
++ for (; i <= cr_num_of_ac * 4; i++, addr += 4) {
++ if (i == cr_num_of_ac * 4 && is_mt7992(&dev->mt76))
++ ple_stat[i] = mt76_rr(dev, WF_PLE_TOP_AC3_QUEUE_EMPTY_EXT0_ADDR);
++ else
++ ple_stat[i] = mt76_rr(dev, addr);
++ }
++}
++
++static void
++mt7996_get_sta_pause(struct mt7996_dev *dev, u8 band, u32 *sta_pause, u32 *twt_pause)
++{
++ u32 i, addr;
++ size_t cr_num_of_ac = ple_cr_num_of_ac(&dev->mt76);
++
++ /* switch to target band */
++ mt76_wr(dev, WF_DRR_TOP_SBRR_ADDR, u32_encode_bits(band, WF_DRR_TOP_SBRR_TARGET_BAND_MASK));
++
++ /* Legacy */
++ addr = WF_DRR_TOP_AC0_STATION_PAUSE00_ADDR;
++ for (i = 0; i < cr_num_of_ac; i++, addr += 4) {
++ if (i == cr_num_of_ac - 1 && is_mt7992(&dev->mt76))
++ sta_pause[i] = mt76_rr(dev, WF_DRR_TOP_AC0_STATION_PAUSE_EXT_00_ADDR);
++ else
++ sta_pause[i] = mt76_rr(dev, addr);
++ }
++
++ addr = WF_DRR_TOP_AC1_STATION_PAUSE00_ADDR;
++ for (; i < cr_num_of_ac * 2; i++, addr += 4) {
++ if (i == cr_num_of_ac * 2 - 1 && is_mt7992(&dev->mt76))
++ sta_pause[i] = mt76_rr(dev, WF_DRR_TOP_AC1_STATION_PAUSE_EXT_00_ADDR);
++ else
++ sta_pause[i] = mt76_rr(dev, addr);
++ }
++
++ addr = WF_DRR_TOP_AC2_STATION_PAUSE00_ADDR;
++ for (; i < cr_num_of_ac * 3; i++, addr += 4) {
++ if (i == cr_num_of_ac * 3 - 1 && is_mt7992(&dev->mt76))
++ sta_pause[i] = mt76_rr(dev, WF_DRR_TOP_AC2_STATION_PAUSE_EXT_00_ADDR);
++ else
++ sta_pause[i] = mt76_rr(dev, addr);
++ }
++
++ addr = WF_DRR_TOP_AC3_STATION_PAUSE00_ADDR;
++ for (; i < cr_num_of_ac * 4; i++, addr += 4) {
++ if (i == cr_num_of_ac * 4 - 1 && is_mt7992(&dev->mt76))
++ sta_pause[i] = mt76_rr(dev, WF_DRR_TOP_AC3_STATION_PAUSE_EXT_00_ADDR);
++ else
++ sta_pause[i] = mt76_rr(dev, addr);
++ }
++
++ /* TWT */
++ addr = WF_DRR_TOP_TWT_STA_MAP00_ADDR;
++ for (i = 0; i < cr_num_of_ac; i++, addr += 4) {
++ if (i == cr_num_of_ac - 1 && is_mt7992(&dev->mt76))
++ twt_pause[i] = mt76_rr(dev, WF_DRR_TOP_TWT_STA_MAP_EXT_00_ADDR);
++ else
++ twt_pause[i] = mt76_rr(dev, addr);
++ }
++}
++
++static void
++mt7996_get_ple_queue_info(struct mt7996_dev *dev, u32 pid, u32 qid, u32 tgid,
++ u16 wlan_idx, u16 *hfid, u16 *tfid, u16 *pktcnt)
++{
++ u32 val = WF_PLE_TOP_FL_QUE_CTRL_0_EXECUTE_MASK |
++ u32_encode_bits(pid, WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_PID_MASK) |
++ u32_encode_bits(tgid, WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_TGID_MASK) |
++ u32_encode_bits(qid, WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_QID_MASK) |
++ u32_encode_bits(wlan_idx, WF_PLE_TOP_FL_QUE_CTRL_0_Q_BUF_WLANID_MASK);
++ mt76_wr(dev, WF_PLE_TOP_FL_QUE_CTRL_0_ADDR, val);
++
++ val = mt76_rr(dev, WF_PLE_TOP_FL_QUE_CTRL_2_ADDR);
++ *hfid = u32_get_bits(val, WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_HEAD_FID_MASK);
++ *tfid = u32_get_bits(val, WF_PLE_TOP_FL_QUE_CTRL_2_QUEUE_TAIL_FID_MASK);
++
++ val = mt76_rr(dev, WF_PLE_TOP_FL_QUE_CTRL_3_ADDR);
++ *pktcnt = u32_get_bits(val, WF_PLE_TOP_FL_QUE_CTRL_3_QUEUE_PKT_NUM_MASK);
++}
++
++static void
++mt7996_show_sta_acq_info(struct seq_file *s, unsigned long *ple_stat,
++ u32 *sta_pause, u32 *twt_sta_pause)
++{
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ size_t cr_num_of_ac = ple_cr_num_of_ac(&dev->mt76);
++ size_t cr_num_of_all_ac = cr_num_of_ac * IEEE80211_NUM_ACS;
++ int i, j;
++
++ for (j = 0; j < cr_num_of_all_ac; j++) { /* show AC Q info */
++ for (i = 0; i < 32; i++) {
++ if (!test_bit(i, &ple_stat[j + 1])) {
++ u16 hfid, tfid, pktcnt, wlan_idx = i + (j % cr_num_of_ac) * 32;
++ u8 wmmidx, ctrl = 0, acq_idx = j / cr_num_of_ac;
++ struct mt7996_link_sta *mlink;
++ struct mt76_wcid *wcid;
++ size_t idx;
++
++ if (wlan_idx >= MT76_N_WCIDS) {
++ seq_printf(s, "Error: WCID %hu exceeded threshold.\n", wlan_idx);
++ continue;
++ }
++ wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
++ if (!wcid) {
++ seq_printf(s, "Error: STA %hu does not exist.\n", wlan_idx);
++ continue;
++ }
++ mlink = container_of(wcid, struct mt7996_link_sta, wcid);
++ wmmidx = mlink->sta->vif->deflink.mt76.wmm_idx;
++
++ seq_printf(s, "\tSTA%hu AC%hhu: ", wlan_idx, acq_idx);
++ mt7996_get_ple_queue_info(dev, ENUM_UMAC_LMAC_PORT_2, acq_idx,
++ 0, wlan_idx, &hfid, &tfid, &pktcnt);
++ seq_printf(s, "tail/head fid = 0x%04x/0x%04x, pkt cnt = 0x%04x",
++ tfid, hfid, pktcnt);
++
++ idx = wcid->phy_idx * cr_num_of_all_ac + j;
++ if (sta_pause[idx] & BIT(i))
++ ctrl = 2;
++
++ idx = wcid->phy_idx * cr_num_of_ac + j % cr_num_of_ac;
++ if (twt_sta_pause[idx] & BIT(i))
++ ctrl = 3;
++
++ seq_printf(s, ", ctrl = %s (wmmidx=%hhu, band=%hhu)\n",
++ sta_ctrl_reg[ctrl], wmmidx, wcid->phy_idx);
++ }
++ }
++ }
++}
++
++static void
++mt7996_show_txcmdq_info(struct seq_file *s)
++{
++ const u32 txcmd_queue_empty_addr[__MT_MAX_BAND][2] = {
++ [MT_BAND0] = {WF_PLE_TOP_TXCMD_QUEUE_EMPTY_ADDR,
++ WF_PLE_TOP_NATIVE_TXCMD_QUEUE_EMPTY_ADDR},
++ [MT_BAND1] = {WF_PLE_TOP_BN1_TXCMD_QUEUE_EMPTY_ADDR,
++ WF_PLE_TOP_BN1_NATIVE_TXCMD_QUEUE_EMPTY_ADDR},
++ [MT_BAND2] = {WF_PLE_TOP_BN2_TXCMD_QUEUE_EMPTY_ADDR,
++ WF_PLE_TOP_BN2_NATIVE_TXCMD_QUEUE_EMPTY_ADDR}
++ };
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ u8 band;
++
++ for (band = MT_BAND0; band < __MT_MAX_BAND; ++band) {
++ unsigned long txcmdq_stat, native_txcmdq_stat;
++ int i;
++
++ if (!dev->mt76.phys[band])
++ continue;
++
++ txcmdq_stat = mt76_rr(dev, txcmd_queue_empty_addr[band][0]);
++ native_txcmdq_stat = mt76_rr(dev, txcmd_queue_empty_addr[band][1]);
++
++ seq_printf(s, "Band%hhu Non-native/native TXCMD Queue Empty: 0x%08lx/0x%08lx\n",
++ band, txcmdq_stat, native_txcmdq_stat);
++
++ for (i = 0; i < 32 ; i++) {
++ if (!test_bit(i, &native_txcmdq_stat)) {
++ struct bmac_queue_info_t *queue = &ple_txcmd_queue_empty_info[band][i];
++ u16 hfid, tfid, pktcnt;
++
++ if (!queue->QueueName)
++ continue;
++
++ seq_printf(s, "\t%s: ", queue->QueueName);
++ mt7996_get_ple_queue_info(dev, queue->Portid, queue->Queueid,
++ 0, 0, &hfid, &tfid, &pktcnt);
++ seq_printf(s, "tail/head fid = 0x%04x/0x%04x, pkt cnt = 0x%04x\n",
++ tfid, hfid, pktcnt);
++ }
++ }
++ }
++}
++
++static int
++mt7996_pleinfo_read(struct seq_file *s, void *data)
++{
++ struct mt7996_dev *dev = dev_get_drvdata(s->private);
++ size_t cr_num_of_ac = ple_cr_num_of_ac(&dev->mt76);
++ size_t cr_num_of_all_ac = cr_num_of_ac * IEEE80211_NUM_ACS;
++ u32 *sta_pause, *twt_sta_pause;
++ unsigned long *ple_stat;
++ int i, j, ret = 0;
++
++ ple_stat = kzalloc((cr_num_of_all_ac + 1) * sizeof(unsigned long), GFP_KERNEL);
++ if (!ple_stat)
++ return -ENOMEM;
++
++ sta_pause = kzalloc(__MT_MAX_BAND * cr_num_of_all_ac * sizeof(u32), GFP_KERNEL);
++ if (!sta_pause) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ twt_sta_pause = kzalloc(__MT_MAX_BAND * cr_num_of_ac * sizeof(u32), GFP_KERNEL);
++ if (!twt_sta_pause) {
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ mt7996_show_ple_pg_info(dev, s);
++ mt7996_get_ple_acq_stat(dev, ple_stat);
++
++ for (i = MT_BAND0; i < __MT_MAX_BAND; i++) {
++ if (dev->mt76.phys[i])
++ mt7996_get_sta_pause(dev, i,
++ sta_pause + i * cr_num_of_all_ac,
++ twt_sta_pause + i * cr_num_of_ac);
++ }
++
++ if ((ple_stat[0] & WF_PLE_TOP_QUEUE_EMPTY_ALL_AC_EMPTY_MASK) == 0) {
++ for (j = 0; j < cr_num_of_all_ac; j++) {
++ if (j % cr_num_of_ac == 0)
++ seq_printf(s, "\n\tSTA in nonempty AC%ld TXD queue: ", j / cr_num_of_ac);
++
++ for (i = 0; i < 32; i++) {
++ if (!test_bit(i, &ple_stat[j + 1]))
++ seq_printf(s, "%lu ", i + (j % cr_num_of_ac) * 32);
++ }
++ }
++ seq_printf(s, "\n");
++ }
++
++ seq_printf(s, "Nonempty TXD Queue Info:\n");
++
++ for (i = 0; i < 32; i++) {
++ if (!test_bit(i, &ple_stat[0])) {
++ struct bmac_queue_info *queue = &ple_queue_empty_info[i];
++ u16 hfid, tfid, pktcnt;
++
++ if (!queue->QueueName)
++ continue;
++
++ seq_printf(s, "\t%s: ", queue->QueueName);
++ mt7996_get_ple_queue_info(dev, queue->Portid, queue->Queueid,
++ queue->tgid, 0, &hfid, &tfid, &pktcnt);
++ seq_printf(s, "tail/head fid = 0x%04x/0x%04x, pkt cnt = 0x%04x\n",
++ tfid, hfid, pktcnt);
++ }
++ }
++
++ mt7996_show_sta_acq_info(s, ple_stat, sta_pause, twt_sta_pause);
++ mt7996_show_txcmdq_info(s);
++
++ kfree(twt_sta_pause);
++out:
++ kfree(sta_pause);
++ kfree(ple_stat);
++ return ret;
++}
++
++/* DRR */
++static int
++mt7996_drr_info(struct seq_file *s, void *data)
++{
++ /* TODO: Wait MIB counter API implement complete */
++ return 0;
++}
++
+ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+ {
+ struct mt7996_dev *dev = phy->dev;
+@@ -3337,6 +4403,25 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
+
+ debugfs_create_file("thermal_enable", 0600, dir, phy, &fops_thermal_enable);
+ debugfs_create_file("thermal_recal", 0200, dir, dev, &fops_thermal_recal);
++ debugfs_create_file("reset_counter", 0200, dir, dev, &fops_reset_counter);
++ debugfs_create_devm_seqfile(dev->mt76.dev, "per", dir, mt7996_per_read);
++
++ debugfs_create_devm_seqfile(dev->mt76.dev, "drr_info", dir,
++ mt7996_drr_info);
++
++ debugfs_create_u32("token_idx", 0600, dir, &dev->dbg.token_idx);
++ debugfs_create_devm_seqfile(dev->mt76.dev, "rx_token", dir,
++ mt7996_rx_token_read);
++
++ debugfs_create_devm_seqfile(dev->mt76.dev, "ple_info", dir,
++ mt7996_pleinfo_read);
++ debugfs_create_devm_seqfile(dev->mt76.dev, "pse_info", dir,
++ mt7996_pseinfo_read);
++ /* amsdu */
++ debugfs_create_file("amsdu_algo", 0600, dir, dev, &fops_amsdu_algo);
++ debugfs_create_file("amsdu_para", 0600, dir, dev, &fops_amsdu_para);
++ debugfs_create_devm_seqfile(dev->mt76.dev, "amsdu_info", dir,
++ mt7996_amsdu_info_read);
+
+ return 0;
+ }
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1001-mtk-wifi-mt76-mt7996-support-record-muru-algo-log-wh.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1001-mtk-wifi-mt76-mt7996-support-record-muru-algo-log-wh.patch
deleted file mode 100644
index eab9300..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1001-mtk-wifi-mt76-mt7996-support-record-muru-algo-log-wh.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-From c772657b0835b02b512b101dc2111c99d6c3448c Mon Sep 17 00:00:00 2001
-From: Howard Hsu <howard-yh.hsu@mediatek.com>
-Date: Tue, 28 Nov 2023 16:01:33 +0800
-Subject: [PATCH 1001/1044] mtk: wifi: mt76: mt7996: support record muru algo
- log when record fw log
-
-Support record muru algorithm debug log in firmware when we use
-chihuahua tool to record fw log. This can help us to check some key
-point of muru algorithm result, like bsrp status, airtime busy status,
-ru candidate...
-Corresponding to Logan driver, it is the same as execute the iwpriv
-command: iwpriv rax0 set muruDbgInfo=[category]-1
-
-Disable muru debug log when we stop record fwlog. Without this commit,
-if we run $ echo 2 > fw_debug_wm after recording fwlog, it will print
-out too many fw debug log.
-
-Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
----
- mt7996/debugfs.c | 35 +++++++++++++++++++++++++++++++++++
- mt7996/mt7996.h | 1 +
- mt7996/mtk_mcu.c | 21 +++++++++++++++++++++
- mt7996/mtk_mcu.h | 3 +++
- 4 files changed, 60 insertions(+)
-
-diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 1637b39d..ea78166b 100644
---- a/mt7996/debugfs.c
-+++ b/mt7996/debugfs.c
-@@ -423,6 +423,36 @@ remove_buf_file_cb(struct dentry *f)
- return 0;
- }
-
-+static int
-+mt7996_fw_debug_muru_set(void *data)
-+{
-+ struct mt7996_dev *dev = data;
-+ enum {
-+ DEBUG_BSRP_STATUS = 256,
-+ DEBUG_TX_DATA_BYTE_CONUT,
-+ DEBUG_RX_DATA_BYTE_CONUT,
-+ DEBUG_RX_TOTAL_BYTE_CONUT,
-+ DEBUG_INVALID_TID_BSR,
-+ DEBUG_UL_LONG_TERM_PPDU_TYPE,
-+ DEBUG_DL_LONG_TERM_PPDU_TYPE,
-+ DEBUG_PPDU_CLASS_TRIG_ONOFF,
-+ DEBUG_AIRTIME_BUSY_STATUS,
-+ DEBUG_UL_OFDMA_MIMO_STATUS,
-+ DEBUG_RU_CANDIDATE,
-+ DEBUG_MEC_UPDATE_AMSDU,
-+ } debug;
-+ int ret;
-+
-+ for (debug = DEBUG_BSRP_STATUS; debug <= DEBUG_MEC_UPDATE_AMSDU; debug++) {
-+ ret = mt7996_mcu_muru_dbg_info(dev, debug,
-+ dev->fw_debug_bin & BIT(0));
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return 0;
-+}
-+
- static int
- mt7996_fw_debug_bin_set(void *data, u64 val)
- {
-@@ -431,6 +461,7 @@ mt7996_fw_debug_bin_set(void *data, u64 val)
- .remove_buf_file = remove_buf_file_cb,
- };
- struct mt7996_dev *dev = data;
-+ int ret;
-
- if (!dev->relay_fwlog) {
- dev->relay_fwlog = relay_open("fwlog_data", dev->debugfs_dir,
-@@ -443,6 +474,10 @@ mt7996_fw_debug_bin_set(void *data, u64 val)
-
- relay_reset(dev->relay_fwlog);
-
-+ ret = mt7996_fw_debug_muru_set(dev);
-+ if (ret)
-+ return ret;
-+
- return mt7996_fw_debug_wm_set(dev, dev->fw_debug_wm);
- }
-
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 34159f97..29976860 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -677,6 +677,7 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
-
- #ifdef CONFIG_MTK_DEBUG
- int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
-+int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
- #endif
-
- #ifdef CONFIG_NET_MEDIATEK_SOC_WED
-diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index e8870166..c16b25ab 100644
---- a/mt7996/mtk_mcu.c
-+++ b/mt7996/mtk_mcu.c
-@@ -15,4 +15,25 @@
-
-
-
-+int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val)
-+{
-+ struct {
-+ u8 __rsv1[4];
-+
-+ __le16 tag;
-+ __le16 len;
-+
-+ __le16 item;
-+ u8 __rsv2[2];
-+ __le32 value;
-+ } __packed req = {
-+ .tag = cpu_to_le16(UNI_CMD_MURU_DBG_INFO),
-+ .len = cpu_to_le16(sizeof(req) - 4),
-+ .item = cpu_to_le16(item),
-+ .value = cpu_to_le32(val),
-+ };
-+
-+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &req,
-+ sizeof(req), true);
-+}
- #endif
-diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index e741aa27..7f4d4e02 100644
---- a/mt7996/mtk_mcu.h
-+++ b/mt7996/mtk_mcu.h
-@@ -10,6 +10,9 @@
-
- #ifdef CONFIG_MTK_DEBUG
-
-+enum {
-+ UNI_CMD_MURU_DBG_INFO = 0x18,
-+};
-
- #endif
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1003-mtk-wifi-mt76-testmode-add-atenl-support-in-mt7996.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1003-mtk-wifi-mt76-testmode-add-atenl-support-in-mt7996.patch
deleted file mode 100644
index 4b48730..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1003-mtk-wifi-mt76-testmode-add-atenl-support-in-mt7996.patch
+++ /dev/null
@@ -1,49 +0,0 @@
-From a086447ff00030ee7cc2d6b813a0c099ba288990 Mon Sep 17 00:00:00 2001
-From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Wed, 28 Dec 2022 22:24:25 +0800
-Subject: [PATCH 1003/1044] mtk: wifi: mt76: testmode: add atenl support in
- mt7996
-
-Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
----
- testmode.c | 3 ++-
- testmode.h | 2 ++
- 2 files changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/testmode.c b/testmode.c
-index ca4feccf..37783160 100644
---- a/testmode.c
-+++ b/testmode.c
-@@ -613,7 +613,8 @@ int mt76_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
-
- if (dev->test_mtd.name &&
- (nla_put_string(msg, MT76_TM_ATTR_MTD_PART, dev->test_mtd.name) ||
-- nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset)))
-+ nla_put_u32(msg, MT76_TM_ATTR_MTD_OFFSET, dev->test_mtd.offset) ||
-+ nla_put_u8(msg, MT76_TM_ATTR_BAND_IDX, phy->band_idx)))
- goto out;
-
- if (nla_put_u32(msg, MT76_TM_ATTR_TX_COUNT, td->tx_count) ||
-diff --git a/testmode.h b/testmode.h
-index 5e2792d8..a40cd74b 100644
---- a/testmode.h
-+++ b/testmode.h
-@@ -17,6 +17,7 @@
- *
- * @MT76_TM_ATTR_MTD_PART: mtd partition used for eeprom data (string)
- * @MT76_TM_ATTR_MTD_OFFSET: offset of eeprom data within the partition (u32)
-+ * @MT76_TM_ATTR_BAND_IDX: band idx of the chip (u8)
- *
- * @MT76_TM_ATTR_TX_COUNT: configured number of frames to send when setting
- * state to MT76_TM_STATE_TX_FRAMES (u32)
-@@ -56,6 +57,7 @@ enum mt76_testmode_attr {
-
- MT76_TM_ATTR_MTD_PART,
- MT76_TM_ATTR_MTD_OFFSET,
-+ MT76_TM_ATTR_BAND_IDX,
-
- MT76_TM_ATTR_TX_COUNT,
- MT76_TM_ATTR_TX_LENGTH,
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1007-mtk-wifi-mt76-mt7996-add-txpower-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1007-mtk-wifi-mt76-mt7996-add-txpower-support.patch
deleted file mode 100644
index e96a9fb..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1007-mtk-wifi-mt76-mt7996-add-txpower-support.patch
+++ /dev/null
@@ -1,675 +0,0 @@
-From 668d96f2685432f602994676ff31f826fb98a99f Mon Sep 17 00:00:00 2001
-From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Fri, 24 Mar 2023 23:35:30 +0800
-Subject: [PATCH 1007/1044] mtk: wifi: mt76: mt7996: add txpower support
-
-Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
----
- mt7996/eeprom.c | 34 +++++
- mt7996/eeprom.h | 42 ++++++
- mt7996/mcu.h | 2 +
- mt7996/mt7996.h | 1 +
- mt7996/mtk_debugfs.c | 326 +++++++++++++++++++++++++++++++++++++++++++
- mt7996/mtk_mcu.c | 23 +++
- mt7996/mtk_mcu.h | 92 ++++++++++++
- mt7996/regs.h | 29 ++--
- 8 files changed, 538 insertions(+), 11 deletions(-)
-
-diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 3aeffdfb..acc33cfe 100644
---- a/mt7996/eeprom.c
-+++ b/mt7996/eeprom.c
-@@ -404,3 +404,37 @@ s8 mt7996_eeprom_get_power_delta(struct mt7996_dev *dev, int band)
-
- return val & MT_EE_RATE_DELTA_SIGN ? delta : -delta;
- }
-+
-+const u8 mt7996_sku_group_len[] = {
-+ [SKU_CCK] = 4,
-+ [SKU_OFDM] = 8,
-+ [SKU_HT20] = 8,
-+ [SKU_HT40] = 9,
-+ [SKU_VHT20] = 12,
-+ [SKU_VHT40] = 12,
-+ [SKU_VHT80] = 12,
-+ [SKU_VHT160] = 12,
-+ [SKU_HE26] = 12,
-+ [SKU_HE52] = 12,
-+ [SKU_HE106] = 12,
-+ [SKU_HE242] = 12,
-+ [SKU_HE484] = 12,
-+ [SKU_HE996] = 12,
-+ [SKU_HE2x996] = 12,
-+ [SKU_EHT26] = 16,
-+ [SKU_EHT52] = 16,
-+ [SKU_EHT106] = 16,
-+ [SKU_EHT242] = 16,
-+ [SKU_EHT484] = 16,
-+ [SKU_EHT996] = 16,
-+ [SKU_EHT2x996] = 16,
-+ [SKU_EHT4x996] = 16,
-+ [SKU_EHT26_52] = 16,
-+ [SKU_EHT26_106] = 16,
-+ [SKU_EHT484_242] = 16,
-+ [SKU_EHT996_484] = 16,
-+ [SKU_EHT996_484_242] = 16,
-+ [SKU_EHT2x996_484] = 16,
-+ [SKU_EHT3x996] = 16,
-+ [SKU_EHT3x996_484] = 16,
-+};
-diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
-index 849b8bca..23d4929d 100644
---- a/mt7996/eeprom.h
-+++ b/mt7996/eeprom.h
-@@ -123,4 +123,46 @@ mt7996_get_channel_group_6g(int channel)
- return DIV_ROUND_UP(channel - 29, 32);
- }
-
-+enum mt7996_sku_rate_group {
-+ SKU_CCK,
-+ SKU_OFDM,
-+
-+ SKU_HT20,
-+ SKU_HT40,
-+
-+ SKU_VHT20,
-+ SKU_VHT40,
-+ SKU_VHT80,
-+ SKU_VHT160,
-+
-+ SKU_HE26,
-+ SKU_HE52,
-+ SKU_HE106,
-+ SKU_HE242,
-+ SKU_HE484,
-+ SKU_HE996,
-+ SKU_HE2x996,
-+
-+ SKU_EHT26,
-+ SKU_EHT52,
-+ SKU_EHT106,
-+ SKU_EHT242,
-+ SKU_EHT484,
-+ SKU_EHT996,
-+ SKU_EHT2x996,
-+ SKU_EHT4x996,
-+ SKU_EHT26_52,
-+ SKU_EHT26_106,
-+ SKU_EHT484_242,
-+ SKU_EHT996_484,
-+ SKU_EHT996_484_242,
-+ SKU_EHT2x996_484,
-+ SKU_EHT3x996,
-+ SKU_EHT3x996_484,
-+
-+ MAX_SKU_RATE_GROUP_NUM,
-+};
-+
-+extern const u8 mt7996_sku_group_len[MAX_SKU_RATE_GROUP_NUM];
-+
- #endif
-diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 4f4994d8..887d9b49 100644
---- a/mt7996/mcu.h
-+++ b/mt7996/mcu.h
-@@ -911,6 +911,7 @@ struct tx_power_ctrl {
- bool ate_mode_enable;
- bool percentage_ctrl_enable;
- bool bf_backoff_enable;
-+ u8 show_info_category;
- u8 power_drop_level;
- };
- u8 band_idx;
-@@ -924,6 +925,7 @@ enum {
- UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL = 3,
- UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL = 4,
- UNI_TXPOWER_ATE_MODE_CTRL = 6,
-+ UNI_TXPOWER_SHOW_INFO = 7,
- };
-
- enum {
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 384157c8..18a6a46d 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -609,6 +609,7 @@ int mt7996_mcu_set_tx_power_ctrl(struct mt7996_phy *phy, u8 power_ctrl_id, u8 da
- #ifdef CONFIG_NL80211_TESTMODE
- void mt7996_tm_rf_test_event(struct mt7996_dev *dev, struct sk_buff *skb);
- #endif
-+int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event);
- int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable);
- void mt7996_mcu_scs_sta_poll(struct work_struct *work);
-
-diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 7e4ac77c..c47d65c9 100644
---- a/mt7996/mtk_debugfs.c
-+++ b/mt7996/mtk_debugfs.c
-@@ -2417,6 +2417,328 @@ mt7996_scs_enable_set(void *data, u64 val)
- DEFINE_DEBUGFS_ATTRIBUTE(fops_scs_enable, NULL,
- mt7996_scs_enable_set, "%lld\n");
-
-+static int
-+mt7996_txpower_level_set(void *data, u64 val)
-+{
-+ struct mt7996_phy *phy = data;
-+ int ret;
-+
-+ if (val > 100)
-+ return -EINVAL;
-+
-+ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_PERCENTAGE_CTRL, !!val);
-+ if (ret)
-+ return ret;
-+
-+ return mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_PERCENTAGE_DROP_CTRL, val);
-+}
-+
-+DEFINE_DEBUGFS_ATTRIBUTE(fops_txpower_level, NULL,
-+ mt7996_txpower_level_set, "%lld\n");
-+
-+static ssize_t
-+mt7996_get_txpower_info(struct file *file, char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct mt7996_phy *phy = file->private_data;
-+ struct mt7996_mcu_txpower_event *event;
-+ struct txpower_basic_info *basic_info;
-+ static const size_t size = 2048;
-+ int len = 0;
-+ ssize_t ret;
-+ char *buf;
-+
-+ buf = kzalloc(size, GFP_KERNEL);
-+ event = kzalloc(sizeof(*event), GFP_KERNEL);
-+ if (!buf || !event) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ ret = mt7996_mcu_get_tx_power_info(phy, BASIC_INFO, event);
-+ if (ret ||
-+ le32_to_cpu(event->basic_info.category) != UNI_TXPOWER_BASIC_INFO)
-+ goto out;
-+
-+ basic_info = &event->basic_info;
-+
-+ len += scnprintf(buf + len, size - len,
-+ "======================== BASIC INFO ========================\n");
-+ len += scnprintf(buf + len, size - len, " Band Index: %d, Channel Band: %d\n",
-+ basic_info->band_idx, basic_info->band);
-+ len += scnprintf(buf + len, size - len, " PA Type: %s\n",
-+ basic_info->is_epa ? "ePA" : "iPA");
-+ len += scnprintf(buf + len, size - len, " LNA Type: %s\n",
-+ basic_info->is_elna ? "eLNA" : "iLNA");
-+
-+ len += scnprintf(buf + len, size - len,
-+ "------------------------------------------------------------\n");
-+ len += scnprintf(buf + len, size - len, " SKU: %s\n",
-+ basic_info->sku_enable ? "enable" : "disable");
-+ len += scnprintf(buf + len, size - len, " Percentage Control: %s\n",
-+ basic_info->percentage_ctrl_enable ? "enable" : "disable");
-+ len += scnprintf(buf + len, size - len, " Power Drop: %d [dBm]\n",
-+ basic_info->power_drop_level >> 1);
-+ len += scnprintf(buf + len, size - len, " Backoff: %s\n",
-+ basic_info->bf_backoff_enable ? "enable" : "disable");
-+ len += scnprintf(buf + len, size - len, " TX Front-end Loss: %d, %d, %d, %d\n",
-+ basic_info->front_end_loss_tx[0], basic_info->front_end_loss_tx[1],
-+ basic_info->front_end_loss_tx[2], basic_info->front_end_loss_tx[3]);
-+ len += scnprintf(buf + len, size - len, " RX Front-end Loss: %d, %d, %d, %d\n",
-+ basic_info->front_end_loss_rx[0], basic_info->front_end_loss_rx[1],
-+ basic_info->front_end_loss_rx[2], basic_info->front_end_loss_rx[3]);
-+ len += scnprintf(buf + len, size - len,
-+ " MU TX Power Mode: %s\n",
-+ basic_info->mu_tx_power_manual_enable ? "manual" : "auto");
-+ len += scnprintf(buf + len, size - len,
-+ " MU TX Power (Auto / Manual): %d / %d [0.5 dBm]\n",
-+ basic_info->mu_tx_power_auto, basic_info->mu_tx_power_manual);
-+ len += scnprintf(buf + len, size - len,
-+ " Thermal Compensation: %s\n",
-+ basic_info->thermal_compensate_enable ? "enable" : "disable");
-+ len += scnprintf(buf + len, size - len,
-+ " Theraml Compensation Value: %d\n",
-+ basic_info->thermal_compensate_value);
-+
-+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+
-+out:
-+ kfree(buf);
-+ kfree(event);
-+ return ret;
-+}
-+
-+static const struct file_operations mt7996_txpower_info_fops = {
-+ .read = mt7996_get_txpower_info,
-+ .open = simple_open,
-+ .owner = THIS_MODULE,
-+ .llseek = default_llseek,
-+};
-+
-+#define mt7996_txpower_puts(rate) \
-+({ \
-+ len += scnprintf(buf + len, size - len, "%-21s:", #rate " (TMAC)"); \
-+ for (i = 0; i < mt7996_sku_group_len[SKU_##rate]; i++, offs++) \
-+ len += scnprintf(buf + len, size - len, " %6d", \
-+ event->phy_rate_info.frame_power[offs][band_idx]); \
-+ len += scnprintf(buf + len, size - len, "\n"); \
-+})
-+
-+static ssize_t
-+mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct mt7996_phy *phy = file->private_data;
-+ struct mt7996_dev *dev = phy->dev;
-+ struct mt7996_mcu_txpower_event *event;
-+ u8 band_idx = phy->mt76->band_idx;
-+ static const size_t size = 5120;
-+ int i, offs = 0, len = 0;
-+ ssize_t ret;
-+ char *buf;
-+ u32 reg;
-+
-+ buf = kzalloc(size, GFP_KERNEL);
-+ event = kzalloc(sizeof(*event), GFP_KERNEL);
-+ if (!buf || !event) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ ret = mt7996_mcu_get_tx_power_info(phy, PHY_RATE_INFO, event);
-+ if (ret ||
-+ le32_to_cpu(event->phy_rate_info.category) != UNI_TXPOWER_PHY_RATE_INFO)
-+ goto out;
-+
-+ len += scnprintf(buf + len, size - len,
-+ "\nPhy %d TX Power Table (Channel %d)\n",
-+ band_idx, phy->mt76->chandef.chan->hw_value);
-+ len += scnprintf(buf + len, size - len, "%-21s %6s %6s %6s %6s\n",
-+ " ", "1m", "2m", "5m", "11m");
-+ mt7996_txpower_puts(CCK);
-+
-+ len += scnprintf(buf + len, size - len,
-+ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s\n",
-+ " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
-+ "54m");
-+ mt7996_txpower_puts(OFDM);
-+
-+ len += scnprintf(buf + len, size - len,
-+ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s\n",
-+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
-+ "mcs5", "mcs6", "mcs7");
-+ mt7996_txpower_puts(HT20);
-+
-+ len += scnprintf(buf + len, size - len,
-+ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
-+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
-+ "mcs6", "mcs7", "mcs32");
-+ mt7996_txpower_puts(HT40);
-+
-+ len += scnprintf(buf + len, size - len,
-+ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
-+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
-+ "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
-+ mt7996_txpower_puts(VHT20);
-+ mt7996_txpower_puts(VHT40);
-+ mt7996_txpower_puts(VHT80);
-+ mt7996_txpower_puts(VHT160);
-+ mt7996_txpower_puts(HE26);
-+ mt7996_txpower_puts(HE52);
-+ mt7996_txpower_puts(HE106);
-+ mt7996_txpower_puts(HE242);
-+ mt7996_txpower_puts(HE484);
-+ mt7996_txpower_puts(HE996);
-+ mt7996_txpower_puts(HE2x996);
-+
-+ len += scnprintf(buf + len, size - len,
-+ "%-21s %6s %6s %6s %6s %6s %6s %6s %6s ",
-+ " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5", "mcs6", "mcs7");
-+ len += scnprintf(buf + len, size - len,
-+ "%6s %6s %6s %6s %6s %6s %6s %6s\n",
-+ "mcs8", "mcs9", "mcs10", "mcs11", "mcs12", "mcs13", "mcs14", "mcs15");
-+ mt7996_txpower_puts(EHT26);
-+ mt7996_txpower_puts(EHT52);
-+ mt7996_txpower_puts(EHT106);
-+ mt7996_txpower_puts(EHT242);
-+ mt7996_txpower_puts(EHT484);
-+ mt7996_txpower_puts(EHT996);
-+ mt7996_txpower_puts(EHT2x996);
-+ mt7996_txpower_puts(EHT4x996);
-+ mt7996_txpower_puts(EHT26_52);
-+ mt7996_txpower_puts(EHT26_106);
-+ mt7996_txpower_puts(EHT484_242);
-+ mt7996_txpower_puts(EHT996_484);
-+ mt7996_txpower_puts(EHT996_484_242);
-+ mt7996_txpower_puts(EHT2x996_484);
-+ mt7996_txpower_puts(EHT3x996);
-+ mt7996_txpower_puts(EHT3x996_484);
-+
-+ len += scnprintf(buf + len, size - len, "\nePA Gain: %d\n",
-+ event->phy_rate_info.epa_gain);
-+ len += scnprintf(buf + len, size - len, "Max Power Bound: %d\n",
-+ event->phy_rate_info.max_power_bound);
-+ len += scnprintf(buf + len, size - len, "Min Power Bound: %d\n",
-+ event->phy_rate_info.min_power_bound);
-+
-+ reg = MT_WF_PHYDFE_BAND_TPC_CTRL_STAT0(band_idx);
-+ len += scnprintf(buf + len, size - len,
-+ "BBP TX Power (target power from TMAC) : %6ld [0.5 dBm]\n",
-+ mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_TMAC));
-+ len += scnprintf(buf + len, size - len,
-+ "BBP TX Power (target power from RMAC) : %6ld [0.5 dBm]\n",
-+ mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_RMAC));
-+ len += scnprintf(buf + len, size - len,
-+ "BBP TX Power (TSSI module power input) : %6ld [0.5 dBm]\n",
-+ mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_TSSI));
-+
-+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+
-+out:
-+ kfree(buf);
-+ kfree(event);
-+ return ret;
-+}
-+
-+static const struct file_operations mt7996_txpower_sku_fops = {
-+ .read = mt7996_get_txpower_sku,
-+ .open = simple_open,
-+ .owner = THIS_MODULE,
-+ .llseek = default_llseek,
-+};
-+
-+#define mt7996_txpower_path_puts(rate, arr_length) \
-+({ \
-+ len += scnprintf(buf + len, size - len, "%-23s:", #rate " (TMAC)"); \
-+ for (i = 0; i < arr_length; i++, offs++) \
-+ len += scnprintf(buf + len, size - len, " %4d", \
-+ event->backoff_table_info.frame_power[offs]); \
-+ len += scnprintf(buf + len, size - len, "\n"); \
-+})
-+
-+static ssize_t
-+mt7996_get_txpower_path(struct file *file, char __user *user_buf,
-+ size_t count, loff_t *ppos)
-+{
-+ struct mt7996_phy *phy = file->private_data;
-+ struct mt7996_mcu_txpower_event *event;
-+ static const size_t size = 5120;
-+ int i, offs = 0, len = 0;
-+ ssize_t ret;
-+ char *buf;
-+
-+ buf = kzalloc(size, GFP_KERNEL);
-+ event = kzalloc(sizeof(*event), GFP_KERNEL);
-+ if (!buf || !event) {
-+ ret = -ENOMEM;
-+ goto out;
-+ }
-+
-+ ret = mt7996_mcu_get_tx_power_info(phy, BACKOFF_TABLE_INFO, event);
-+ if (ret ||
-+ le32_to_cpu(event->phy_rate_info.category) != UNI_TXPOWER_BACKOFF_TABLE_SHOW_INFO)
-+ goto out;
-+
-+ len += scnprintf(buf + len, size - len, "\n%*c", 25, ' ');
-+ len += scnprintf(buf + len, size - len, "1T1S/2T1S/3T1S/4T1S/5T1S/2T2S/3T2S/4T2S/5T2S/"
-+ "3T3S/4T3S/5T3S/4T4S/5T4S/5T5S\n");
-+
-+ mt7996_txpower_path_puts(CCK, 5);
-+ mt7996_txpower_path_puts(OFDM, 5);
-+ mt7996_txpower_path_puts(BF-OFDM, 4);
-+
-+ mt7996_txpower_path_puts(RU26, 15);
-+ mt7996_txpower_path_puts(BF-RU26, 15);
-+ mt7996_txpower_path_puts(RU52, 15);
-+ mt7996_txpower_path_puts(BF-RU52, 15);
-+ mt7996_txpower_path_puts(RU26_52, 15);
-+ mt7996_txpower_path_puts(BF-RU26_52, 15);
-+ mt7996_txpower_path_puts(RU106, 15);
-+ mt7996_txpower_path_puts(BF-RU106, 15);
-+ mt7996_txpower_path_puts(RU106_52, 15);
-+ mt7996_txpower_path_puts(BF-RU106_52, 15);
-+
-+ mt7996_txpower_path_puts(BW20/RU242, 15);
-+ mt7996_txpower_path_puts(BF-BW20/RU242, 15);
-+ mt7996_txpower_path_puts(BW40/RU484, 15);
-+ mt7996_txpower_path_puts(BF-BW40/RU484, 15);
-+ mt7996_txpower_path_puts(RU242_484, 15);
-+ mt7996_txpower_path_puts(BF-RU242_484, 15);
-+ mt7996_txpower_path_puts(BW80/RU996, 15);
-+ mt7996_txpower_path_puts(BF-BW80/RU996, 15);
-+ mt7996_txpower_path_puts(RU484_996, 15);
-+ mt7996_txpower_path_puts(BF-RU484_996, 15);
-+ mt7996_txpower_path_puts(RU242_484_996, 15);
-+ mt7996_txpower_path_puts(BF-RU242_484_996, 15);
-+ mt7996_txpower_path_puts(BW160/RU996x2, 15);
-+ mt7996_txpower_path_puts(BF-BW160/RU996x2, 15);
-+ mt7996_txpower_path_puts(RU484_996x2, 15);
-+ mt7996_txpower_path_puts(BF-RU484_996x2, 15);
-+ mt7996_txpower_path_puts(RU996x3, 15);
-+ mt7996_txpower_path_puts(BF-RU996x3, 15);
-+ mt7996_txpower_path_puts(RU484_996x3, 15);
-+ mt7996_txpower_path_puts(BF-RU484_996x3, 15);
-+ mt7996_txpower_path_puts(BW320/RU996x4, 15);
-+ mt7996_txpower_path_puts(BF-BW320/RU996x4, 15);
-+
-+ len += scnprintf(buf + len, size - len, "\nBackoff table: %s\n",
-+ event->backoff_table_info.backoff_en ? "enable" : "disable");
-+
-+ ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+
-+out:
-+ kfree(buf);
-+ kfree(event);
-+ return ret;
-+}
-+
-+static const struct file_operations mt7996_txpower_path_fops = {
-+ .read = mt7996_get_txpower_path,
-+ .open = simple_open,
-+ .owner = THIS_MODULE,
-+ .llseek = default_llseek,
-+};
-+
- int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
- {
- struct mt7996_dev *dev = phy->dev;
-@@ -2480,6 +2802,10 @@ int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir)
-
- debugfs_create_devm_seqfile(dev->mt76.dev, "tr_info", dir,
- mt7996_trinfo_read);
-+ debugfs_create_file("txpower_level", 0600, dir, phy, &fops_txpower_level);
-+ debugfs_create_file("txpower_info", 0600, dir, phy, &mt7996_txpower_info_fops);
-+ debugfs_create_file("txpower_sku", 0600, dir, phy, &mt7996_txpower_sku_fops);
-+ debugfs_create_file("txpower_path", 0600, dir, phy, &mt7996_txpower_path_fops);
-
- debugfs_create_devm_seqfile(dev->mt76.dev, "wtbl_info", dir,
- mt7996_wtbl_read);
-diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index c16b25ab..e56ddd8f 100644
---- a/mt7996/mtk_mcu.c
-+++ b/mt7996/mtk_mcu.c
-@@ -12,8 +12,31 @@
-
- #ifdef CONFIG_MTK_DEBUG
-
-+int mt7996_mcu_get_tx_power_info(struct mt7996_phy *phy, u8 category, void *event)
-+{
-+ struct mt7996_dev *dev = phy->dev;
-+ struct tx_power_ctrl req = {
-+ .tag = cpu_to_le16(UNI_TXPOWER_SHOW_INFO),
-+ .len = cpu_to_le16(sizeof(req) - 4),
-+ .power_ctrl_id = UNI_TXPOWER_SHOW_INFO,
-+ .show_info_category = category,
-+ .band_idx = phy->mt76->band_idx,
-+ };
-+ struct sk_buff *skb;
-+ int ret;
-
-+ ret = mt76_mcu_send_and_get_msg(&dev->mt76,
-+ MCU_WM_UNI_CMD_QUERY(TXPOWER),
-+ &req, sizeof(req), true, &skb);
-+ if (ret)
-+ return ret;
-
-+ memcpy(event, skb->data, sizeof(struct mt7996_mcu_txpower_event));
-+
-+ dev_kfree_skb(skb);
-+
-+ return 0;
-+}
-
- int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val)
- {
-diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index 7f4d4e02..c30418ca 100644
---- a/mt7996/mtk_mcu.h
-+++ b/mt7996/mtk_mcu.h
-@@ -14,6 +14,98 @@ enum {
- UNI_CMD_MURU_DBG_INFO = 0x18,
- };
-
-+struct txpower_basic_info {
-+ u8 category;
-+ u8 rsv1;
-+
-+ /* basic info */
-+ u8 band_idx;
-+ u8 band;
-+
-+ /* board type info */
-+ bool is_epa;
-+ bool is_elna;
-+
-+ /* power percentage info */
-+ bool percentage_ctrl_enable;
-+ s8 power_drop_level;
-+
-+ /* frond-end loss TX info */
-+ s8 front_end_loss_tx[4];
-+
-+ /* frond-end loss RX info */
-+ s8 front_end_loss_rx[4];
-+
-+ /* thermal info */
-+ bool thermal_compensate_enable;
-+ s8 thermal_compensate_value;
-+ u8 rsv2;
-+
-+ /* TX power max/min limit info */
-+ s8 max_power_bound;
-+ s8 min_power_bound;
-+
-+ /* power limit info */
-+ bool sku_enable;
-+ bool bf_backoff_enable;
-+
-+ /* MU TX power info */
-+ bool mu_tx_power_manual_enable;
-+ s8 mu_tx_power_auto;
-+ s8 mu_tx_power_manual;
-+ u8 rsv3;
-+};
-+
-+struct txpower_phy_rate_info {
-+ u8 category;
-+ u8 band_idx;
-+ u8 band;
-+ u8 epa_gain;
-+
-+ /* rate power info [dBm] */
-+ s8 frame_power[MT7996_SKU_RATE_NUM][__MT_MAX_BAND];
-+
-+ /* TX power max/min limit info */
-+ s8 max_power_bound;
-+ s8 min_power_bound;
-+ u8 rsv1;
-+};
-+
-+struct txpower_backoff_table_info {
-+ u8 category;
-+ u8 band_idx;
-+ u8 band;
-+ u8 backoff_en;
-+
-+ s8 frame_power[MT7996_SKU_PATH_NUM];
-+ u8 rsv[3];
-+};
-+
-+struct mt7996_mcu_txpower_event {
-+ u8 _rsv[4];
-+
-+ __le16 tag;
-+ __le16 len;
-+
-+ union {
-+ struct txpower_basic_info basic_info;
-+ struct txpower_phy_rate_info phy_rate_info;
-+ struct txpower_backoff_table_info backoff_table_info;
-+ };
-+};
-+
-+enum txpower_category {
-+ BASIC_INFO,
-+ BACKOFF_TABLE_INFO,
-+ PHY_RATE_INFO,
-+};
-+
-+enum txpower_event {
-+ UNI_TXPOWER_BASIC_INFO = 0,
-+ UNI_TXPOWER_BACKOFF_TABLE_SHOW_INFO = 3,
-+ UNI_TXPOWER_PHY_RATE_INFO = 5,
-+};
-+
- #endif
-
- #endif
-diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 4c20a67d..e94f9a90 100644
---- a/mt7996/regs.h
-+++ b/mt7996/regs.h
-@@ -693,24 +693,31 @@ enum offs_rev {
- ((_wf) << 16) + (ofs))
- #define MT_WF_PHYRX_CSD_IRPI(_band, _wf) MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
-
--/* PHYRX CTRL */
--#define MT_WF_PHYRX_BAND_BASE 0x83080000
--#define MT_WF_PHYRX_BAND(_band, ofs) (MT_WF_PHYRX_BAND_BASE + \
-+/* PHY CTRL */
-+#define MT_WF_PHY_BAND_BASE 0x83080000
-+#define MT_WF_PHY_BAND(_band, ofs) (MT_WF_PHY_BAND_BASE + \
- ((_band) << 20) + (ofs))
-
--#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band) MT_WF_PHYRX_BAND(_band, 0x1054)
--#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band) MT_WF_PHYRX_BAND(_band, 0x1058)
--#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band) MT_WF_PHYRX_BAND(_band, 0x105c)
--#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band) MT_WF_PHYRX_BAND(_band, 0x1060)
--#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band) MT_WF_PHYRX_BAND(_band, 0x1064)
--#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band) MT_WF_PHYRX_BAND(_band, 0x1068)
-+#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band) MT_WF_PHY_BAND(_band, 0x1054)
-+#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band) MT_WF_PHY_BAND(_band, 0x1058)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band) MT_WF_PHY_BAND(_band, 0x105c)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band) MT_WF_PHY_BAND(_band, 0x1060)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band) MT_WF_PHY_BAND(_band, 0x1064)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band) MT_WF_PHY_BAND(_band, 0x1068)
-
--#define MT_WF_PHYRX_BAND_RX_CTRL1(_band) MT_WF_PHYRX_BAND(_band, 0x2004)
-+/* PHYRX CTRL */
-+#define MT_WF_PHYRX_BAND_RX_CTRL1(_band) MT_WF_PHY_BAND(_band, 0x2004)
- #define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN GENMASK(2, 0)
- #define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
-
-+/* PHYDFE CTRL */
-+#define MT_WF_PHYDFE_BAND_TPC_CTRL_STAT0(_phy) MT_WF_PHY_BAND(_phy, 0xe7a0)
-+#define MT_WF_PHY_TPC_POWER_TMAC GENMASK(15, 8)
-+#define MT_WF_PHY_TPC_POWER_RMAC GENMASK(23, 16)
-+#define MT_WF_PHY_TPC_POWER_TSSI GENMASK(31, 24)
-+
- /* PHYRX CSD BAND */
--#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHYRX_BAND(_band, 0x8230)
-+#define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHY_BAND(_band, 0x8230)
- #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
- #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR BIT(29)
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1008-mtk-wifi-mt76-mt7996-add-single-sku.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1008-mtk-wifi-mt76-mt7996-add-single-sku.patch
deleted file mode 100644
index 9099d48..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1008-mtk-wifi-mt76-mt7996-add-single-sku.patch
+++ /dev/null
@@ -1,277 +0,0 @@
-From 28aa63ac8f3468494eb58e6dfb424dc3507a3396 Mon Sep 17 00:00:00 2001
-From: "Allen.Ye" <allen.ye@mediatek.com>
-Date: Mon, 10 Jul 2023 19:56:16 +0800
-Subject: [PATCH 1008/1044] mtk: wifi: mt76: mt7996: add single sku
-
-Add single sku and default enable sku.
-
-Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
----
- eeprom.c | 50 ++++++++++++++++++++++++++++++++++++++++++-----
- mt76.h | 9 +++++++++
- mt76_connac_mcu.c | 2 +-
- mt7996/init.c | 2 ++
- mt7996/main.c | 9 +++++++++
- mt7996/mcu.c | 41 ++++++++++++++++++++++++++++++++++----
- mt7996/mt7996.h | 1 +
- 7 files changed, 104 insertions(+), 10 deletions(-)
-
-diff --git a/eeprom.c b/eeprom.c
-index 85bd2a29..c5be2843 100644
---- a/eeprom.c
-+++ b/eeprom.c
-@@ -341,6 +341,7 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
- s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
- struct ieee80211_channel *chan,
- struct mt76_power_limits *dest,
-+ struct mt76_power_path_limits *dest_path,
- s8 target_power)
- {
- struct mt76_dev *dev = phy->dev;
-@@ -348,16 +349,20 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
- const __be32 *val;
- char name[16];
- u32 mcs_rates = dev->drv->mcs_rates;
-- u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
- char band;
- size_t len;
-- s8 max_power = 0;
-+ s8 max_power = -127;
-+ s8 max_power_backoff = -127;
- s8 txs_delta;
-+ int n_chains = hweight16(phy->chainmask);
-+ s8 target_power_combine = target_power + mt76_tx_power_nss_delta(n_chains);
-
- if (!mcs_rates)
-- mcs_rates = 10;
-+ mcs_rates = 12;
-
- memset(dest, target_power, sizeof(*dest));
-+ if (dest_path != NULL)
-+ memset(dest_path, 0, sizeof(*dest_path));
-
- if (!IS_ENABLED(CONFIG_OF))
- return target_power;
-@@ -405,12 +410,47 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
- ARRAY_SIZE(dest->mcs), val, len,
- target_power, txs_delta, &max_power);
-
-- val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1);
-+ val = mt76_get_of_array(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1);
- mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
- ARRAY_SIZE(dest->ru), val, len,
- target_power, txs_delta, &max_power);
-
-- return max_power;
-+ val = mt76_get_of_array(np, "rates-eht", &len, ARRAY_SIZE(dest->eht[0]) + 1);
-+ mt76_apply_multi_array_limit(dest->eht[0], ARRAY_SIZE(dest->eht[0]),
-+ ARRAY_SIZE(dest->eht), val, len,
-+ target_power, txs_delta, &max_power);
-+
-+ if (dest_path == NULL)
-+ return max_power;
-+
-+ max_power_backoff = max_power;
-+
-+ val = mt76_get_of_array(np, "paths-cck", &len, ARRAY_SIZE(dest_path->cck));
-+ mt76_apply_array_limit(dest_path->cck, ARRAY_SIZE(dest_path->cck), val,
-+ target_power_combine, txs_delta, &max_power_backoff);
-+
-+ val = mt76_get_of_array(np, "paths-ofdm", &len, ARRAY_SIZE(dest_path->ofdm));
-+ mt76_apply_array_limit(dest_path->ofdm, ARRAY_SIZE(dest_path->ofdm), val,
-+ target_power_combine, txs_delta, &max_power_backoff);
-+
-+ val = mt76_get_of_array(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest_path->ofdm_bf));
-+ mt76_apply_array_limit(dest_path->ofdm_bf, ARRAY_SIZE(dest_path->ofdm_bf), val,
-+ target_power_combine, txs_delta, &max_power_backoff);
-+
-+ val = mt76_get_of_array(np, "paths-ru", &len, ARRAY_SIZE(dest_path->ru[0]) + 1);
-+ mt76_apply_multi_array_limit(dest_path->ru[0], ARRAY_SIZE(dest_path->ru[0]),
-+ ARRAY_SIZE(dest_path->ru), val, len,
-+ target_power_combine, txs_delta, &max_power_backoff);
-+
-+ val = mt76_get_of_array(np, "paths-ru-bf", &len, ARRAY_SIZE(dest_path->ru_bf[0]) + 1);
-+ mt76_apply_multi_array_limit(dest_path->ru_bf[0], ARRAY_SIZE(dest_path->ru_bf[0]),
-+ ARRAY_SIZE(dest_path->ru_bf), val, len,
-+ target_power_combine, txs_delta, &max_power_backoff);
-+
-+ if (max_power_backoff == target_power_combine)
-+ return max_power;
-+
-+ return max_power_backoff;
- }
- EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
-
-diff --git a/mt76.h b/mt76.h
-index 14c5fcb1..630b3903 100644
---- a/mt76.h
-+++ b/mt76.h
-@@ -1054,6 +1054,14 @@ struct mt76_power_limits {
- s8 eht[16][16];
- };
-
-+struct mt76_power_path_limits {
-+ s8 cck[5];
-+ s8 ofdm[5];
-+ s8 ofdm_bf[4];
-+ s8 ru[16][15];
-+ s8 ru_bf[16][15];
-+};
-+
- struct mt76_ethtool_worker_info {
- u64 *data;
- int idx;
-@@ -1664,6 +1672,7 @@ mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan);
- s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
- struct ieee80211_channel *chan,
- struct mt76_power_limits *dest,
-+ struct mt76_power_path_limits *dest_path,
- s8 target_power);
-
- static inline bool mt76_queue_is_wed_tx_free(struct mt76_queue *q)
-diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index 42f12672..75bbb7cc 100644
---- a/mt76_connac_mcu.c
-+++ b/mt76_connac_mcu.c
-@@ -2150,7 +2150,7 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy,
- sar_power = mt76_get_sar_power(phy, &chan, reg_power);
-
- mt76_get_rate_power_limits(phy, &chan, limits,
-- sar_power);
-+ NULL, sar_power);
-
- tx_power_tlv.last_msg = ch_list[idx] == last_ch;
- sku_tlbv.channel = ch_list[idx];
-diff --git a/mt7996/init.c b/mt7996/init.c
-index 23a9b88b..5f937b26 100644
---- a/mt7996/init.c
-+++ b/mt7996/init.c
-@@ -295,6 +295,7 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy,
- int nss_delta = mt76_tx_power_nss_delta(nss);
- int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band);
- struct mt76_power_limits limits;
-+ struct mt76_power_path_limits limits_path;
-
- for (i = 0; i < sband->n_channels; i++) {
- struct ieee80211_channel *chan = &sband->channels[i];
-@@ -303,6 +304,7 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy,
- target_power += pwr_delta;
- target_power = mt76_get_rate_power_limits(phy->mt76, chan,
- &limits,
-+ &limits_path,
- target_power);
- target_power += nss_delta;
- target_power = DIV_ROUND_UP(target_power, 2);
-diff --git a/mt7996/main.c b/mt7996/main.c
-index ffb1f81b..ecfc3dcf 100644
---- a/mt7996/main.c
-+++ b/mt7996/main.c
-@@ -77,6 +77,15 @@ int mt7996_run(struct ieee80211_hw *hw)
- if (ret)
- goto out;
-
-+#ifdef CONFIG_MTK_DEBUG
-+ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
-+ !dev->dbg.sku_disable);
-+#else
-+ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL, true);
-+#endif
-+ if (ret)
-+ goto out;
-+
- set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
-
- ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 62452d6e..e103601f 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -4496,6 +4496,7 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
- int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- {
- #define TX_POWER_LIMIT_TABLE_RATE 0
-+#define TX_POWER_LIMIT_TABLE_PATH 1
- struct mt7996_dev *dev = phy->dev;
- struct mt76_phy *mphy = phy->mt76;
- struct ieee80211_hw *hw = mphy->hw;
-@@ -4509,22 +4510,23 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- u8 band_idx;
- } __packed req = {
- .tag = cpu_to_le16(UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL),
-- .len = cpu_to_le16(sizeof(req) + MT7996_SKU_RATE_NUM - 4),
-+ .len = cpu_to_le16(sizeof(req) + MT7996_SKU_PATH_NUM - 4),
- .power_ctrl_id = UNI_TXPOWER_POWER_LIMIT_TABLE_CTRL,
- .power_limit_type = TX_POWER_LIMIT_TABLE_RATE,
- .band_idx = phy->mt76->band_idx,
- };
- struct mt76_power_limits la = {};
-+ struct mt76_power_path_limits la_path = {};
- struct sk_buff *skb;
-- int i, tx_power;
-+ int i, ret, tx_power;
-
- tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
- tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
-- &la, tx_power);
-+ &la, &la_path, tx_power);
- mphy->txpower_cur = tx_power;
-
- skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
-- sizeof(req) + MT7996_SKU_RATE_NUM);
-+ sizeof(req) + MT7996_SKU_PATH_NUM);
- if (!skb)
- return -ENOMEM;
-
-@@ -4548,6 +4550,37 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- /* eht */
- skb_put_data(skb, &la.eht[0], sizeof(la.eht));
-
-+ /* padding */
-+ skb_put_zero(skb, MT7996_SKU_PATH_NUM - MT7996_SKU_RATE_NUM);
-+
-+ ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
-+ MCU_WM_UNI_CMD(TXPOWER), true);
-+ if (ret)
-+ return ret;
-+
-+ /* only set per-path power table when it's configured */
-+ if (!la_path.ofdm[0])
-+ return 0;
-+
-+ skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
-+ sizeof(req) + MT7996_SKU_PATH_NUM);
-+ if (!skb)
-+ return -ENOMEM;
-+ req.power_limit_type = TX_POWER_LIMIT_TABLE_PATH;
-+
-+ skb_put_data(skb, &req, sizeof(req));
-+ skb_put_data(skb, &la_path.cck, sizeof(la_path.cck));
-+ skb_put_data(skb, &la_path.ofdm, sizeof(la_path.ofdm));
-+ skb_put_data(skb, &la_path.ofdm_bf, sizeof(la_path.ofdm_bf));
-+
-+ for (i = 0; i < 32; i++) {
-+ bool bf = i % 2;
-+ u8 idx = i / 2;
-+ s8 *buf = bf ? la_path.ru_bf[idx] : la_path.ru[idx];
-+
-+ skb_put_data(skb, buf, sizeof(la_path.ru[0]));
-+ }
-+
- return mt76_mcu_skb_send_msg(&dev->mt76, skb,
- MCU_WM_UNI_CMD(TXPOWER), true);
- }
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 18a6a46d..7e3d381e 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -71,6 +71,7 @@
- #define MT7996_CFEND_RATE_11B 0x03 /* 11B LP, 11M */
-
- #define MT7996_SKU_RATE_NUM 417
-+#define MT7996_SKU_PATH_NUM 494
-
- #define MT7996_MAX_TWT_AGRT 16
- #define MT7996_MAX_STA_TWT_AGRT 8
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1012-mtk-wifi-mt76-mt7996-add-mu-vendor-command-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1012-mtk-wifi-mt76-mt7996-add-mu-vendor-command-support.patch
deleted file mode 100644
index 8867fe8..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1012-mtk-wifi-mt76-mt7996-add-mu-vendor-command-support.patch
+++ /dev/null
@@ -1,308 +0,0 @@
-From 940f89e5dd90f5554354036614dce057ade743e1 Mon Sep 17 00:00:00 2001
-From: MeiChia Chiu <meichia.chiu@mediatek.com>
-Date: Tue, 13 Dec 2022 15:17:43 +0800
-Subject: [PATCH 1012/1044] mtk: wifi: mt76: mt7996: add mu vendor command
- support
-
-mtk: wifi: mt76: fix muru_onoff as all enabled by default
-
-Fix muru_onoff default value as 0xF, which means all MU & RU are
-enabled. The purpose of this commit is to align muru_onoff value with
-hostapd and mt76 driver
-
-Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
----
- mt7996/Makefile | 3 +-
- mt7996/init.c | 9 ++++++
- mt7996/mcu.c | 37 ++++++++++++++++++---
- mt7996/mcu.h | 12 +++++++
- mt7996/mt7996.h | 7 ++++
- mt7996/vendor.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 22 +++++++++++++
- 7 files changed, 169 insertions(+), 6 deletions(-)
- create mode 100644 mt7996/vendor.c
- create mode 100644 mt7996/vendor.h
-
-diff --git a/mt7996/Makefile b/mt7996/Makefile
-index 7bb17f44..6643c7a3 100644
---- a/mt7996/Makefile
-+++ b/mt7996/Makefile
-@@ -1,11 +1,12 @@
- # SPDX-License-Identifier: ISC
- EXTRA_CFLAGS += -DCONFIG_MT76_LEDS
- EXTRA_CFLAGS += -DCONFIG_MTK_DEBUG
-+EXTRA_CFLAGS += -DCONFIG_MTK_VENDOR
-
- obj-$(CONFIG_MT7996E) += mt7996e.o
-
- mt7996e-y := pci.o init.o dma.o eeprom.o main.o mcu.o mac.o \
-- debugfs.o mmio.o
-+ debugfs.o mmio.o vendor.o
-
- mt7996e-$(CONFIG_DEV_COREDUMP) += coredump.o
- mt7996e-$(CONFIG_NL80211_TESTMODE) += testmode.o
-diff --git a/mt7996/init.c b/mt7996/init.c
-index c135da9c..fba61c01 100644
---- a/mt7996/init.c
-+++ b/mt7996/init.c
-@@ -368,6 +368,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw, struct mtk_wed_device *wed)
-
- phy->slottime = 9;
- phy->beacon_rate = -1;
-+ phy->muru_onoff = OFDMA_UL | OFDMA_DL | MUMIMO_DL | MUMIMO_UL;
-
- hw->sta_data_size = sizeof(struct mt7996_sta);
- hw->vif_data_size = sizeof(struct mt7996_vif);
-@@ -616,6 +617,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
- if (ret)
- goto error;
-
-+#ifdef CONFIG_MTK_VENDOR
-+ mt7996_vendor_register(phy);
-+#endif
-+
- ret = mt76_register_phy(mphy, true, mt76_rates,
- ARRAY_SIZE(mt76_rates));
- if (ret)
-@@ -1401,6 +1406,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
- dev->mt76.test_ops = &mt7996_testmode_ops;
- #endif
-
-+#ifdef CONFIG_MTK_VENDOR
-+ mt7996_vendor_register(&dev->phy);
-+#endif
-+
- ret = mt76_register_device(&dev->mt76, true, mt76_rates,
- ARRAY_SIZE(mt76_rates));
- if (ret)
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 0ee17ff9..8348d22a 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -1373,6 +1373,8 @@ static void
- mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- struct ieee80211_vif *vif, struct ieee80211_sta *sta)
- {
-+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+ struct mt7996_phy *phy = mvif->phy;
- struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
- struct sta_rec_muru *muru;
- struct tlv *tlv;
-@@ -1384,11 +1386,14 @@ mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
-
- muru = (struct sta_rec_muru *)tlv;
-- muru->cfg.mimo_dl_en = vif->bss_conf.eht_mu_beamformer ||
-- vif->bss_conf.he_mu_beamformer ||
-- vif->bss_conf.vht_mu_beamformer ||
-- vif->bss_conf.vht_mu_beamformee;
-- muru->cfg.ofdma_dl_en = true;
-+ muru->cfg.mimo_dl_en = (vif->bss_conf.eht_mu_beamformer ||
-+ vif->bss_conf.he_mu_beamformer ||
-+ vif->bss_conf.vht_mu_beamformer ||
-+ vif->bss_conf.vht_mu_beamformee) &&
-+ !!(phy->muru_onoff & MUMIMO_DL);
-+ muru->cfg.mimo_ul_en = !!(phy->muru_onoff & MUMIMO_UL);
-+ muru->cfg.ofdma_dl_en = !!(phy->muru_onoff & OFDMA_DL);
-+ muru->cfg.ofdma_ul_en = !!(phy->muru_onoff & OFDMA_UL);
-
- if (sta->deflink.vht_cap.vht_supported)
- muru->mimo_dl.vht_mu_bfee =
-@@ -4919,3 +4924,25 @@ int mt7996_mcu_set_scs(struct mt7996_phy *phy, u8 enable)
- return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(SCS),
- &req, sizeof(req), false);
- }
-+
-+#ifdef CONFIG_MTK_VENDOR
-+void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
-+{
-+ u8 mode, val;
-+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+ struct mt7996_phy *phy = mvif->phy;
-+
-+ mode = FIELD_GET(RATE_CFG_MODE, *((u32 *)data));
-+ val = FIELD_GET(RATE_CFG_VAL, *((u32 *)data));
-+
-+ switch (mode) {
-+ case RATE_PARAM_AUTO_MU:
-+ if (val < 0 || val > 15) {
-+ printk("Wrong value! The value is between 0-15.\n");
-+ break;
-+ }
-+ phy->muru_onoff = val;
-+ break;
-+ }
-+}
-+#endif
-diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 887d9b49..68bf82fc 100644
---- a/mt7996/mcu.h
-+++ b/mt7996/mcu.h
-@@ -754,8 +754,20 @@ enum {
- RATE_PARAM_FIXED_MCS,
- RATE_PARAM_FIXED_GI = 11,
- RATE_PARAM_AUTO = 20,
-+#ifdef CONFIG_MTK_VENDOR
-+ RATE_PARAM_AUTO_MU = 32,
-+#endif
- };
-
-+#define RATE_CFG_MODE GENMASK(15, 8)
-+#define RATE_CFG_VAL GENMASK(7, 0)
-+
-+/* MURU */
-+#define OFDMA_DL BIT(0)
-+#define OFDMA_UL BIT(1)
-+#define MUMIMO_DL BIT(2)
-+#define MUMIMO_UL BIT(3)
-+
- enum {
- BF_SOUNDING_ON = 1,
- BF_HW_EN_UPDATE = 17,
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 2daca449..d0b425da 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -295,6 +295,8 @@ struct mt7996_phy {
-
- struct mt7996_scs_ctrl scs_ctrl;
-
-+ u8 muru_onoff;
-+
- #ifdef CONFIG_NL80211_TESTMODE
- struct {
- u32 *reg_backup;
-@@ -733,6 +735,11 @@ int mt7996_mmio_wed_init(struct mt7996_dev *dev, void *pdev_ptr,
- bool hif2, int *irq);
- u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
-
-+#ifdef CONFIG_MTK_VENDOR
-+void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
-+void mt7996_vendor_register(struct mt7996_phy *phy);
-+#endif
-+
- #ifdef CONFIG_MTK_DEBUG
- int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
- int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-new file mode 100644
-index 00000000..b5ecbdf1
---- /dev/null
-+++ b/mt7996/vendor.c
-@@ -0,0 +1,85 @@
-+// SPDX-License-Identifier: ISC
-+/*
-+ * Copyright (C) 2020, MediaTek Inc. All rights reserved.
-+ */
-+
-+#include <net/netlink.h>
-+
-+#include "mt7996.h"
-+#include "mcu.h"
-+#include "vendor.h"
-+#include "mtk_mcu.h"
-+
-+static const struct nla_policy
-+mu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_MU_CTRL] = {
-+ [MTK_VENDOR_ATTR_MU_CTRL_ONOFF] = {.type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_MU_CTRL_DUMP] = {.type = NLA_U8 },
-+};
-+
-+static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
-+ struct wireless_dev *wdev,
-+ const void *data,
-+ int data_len)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_MU_CTRL];
-+ int err;
-+ u8 val8;
-+ u32 val32 = 0;
-+
-+ err = nla_parse(tb, MTK_VENDOR_ATTR_MU_CTRL_MAX, data, data_len,
-+ mu_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF]) {
-+ val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_MU_CTRL_ONOFF]);
-+ val32 |= FIELD_PREP(RATE_CFG_MODE, RATE_PARAM_AUTO_MU) |
-+ FIELD_PREP(RATE_CFG_VAL, val8);
-+ ieee80211_iterate_active_interfaces_atomic(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
-+ mt7996_set_wireless_vif, &val32);
-+ }
-+
-+ return 0;
-+}
-+
-+static int
-+mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ struct sk_buff *skb, const void *data, int data_len,
-+ unsigned long *storage)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ int len = 0;
-+
-+ if (*storage == 1)
-+ return -ENOENT;
-+ *storage = 1;
-+
-+ if (nla_put_u8(skb, MTK_VENDOR_ATTR_MU_CTRL_DUMP, phy->muru_onoff))
-+ return -ENOMEM;
-+ len += 1;
-+
-+ return len;
-+}
-+
-+static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_MU_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .doit = mt7996_vendor_mu_ctrl,
-+ .dumpit = mt7996_vendor_mu_ctrl_dump,
-+ .policy = mu_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_MU_CTRL_MAX,
-+ },
-+};
-+
-+void mt7996_vendor_register(struct mt7996_phy *phy)
-+{
-+ phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
-+ phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
-+}
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-new file mode 100644
-index 00000000..8ac3ba8e
---- /dev/null
-+++ b/mt7996/vendor.h
-@@ -0,0 +1,22 @@
-+#ifndef __MT7996_VENDOR_H
-+#define __MT7996_VENDOR_H
-+
-+#define MTK_NL80211_VENDOR_ID 0x0ce7
-+
-+enum mtk_nl80211_vendor_subcmds {
-+ MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
-+};
-+
-+enum mtk_vendor_attr_mu_ctrl {
-+ MTK_VENDOR_ATTR_MU_CTRL_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
-+ MTK_VENDOR_ATTR_MU_CTRL_DUMP,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_MU_CTRL,
-+ MTK_VENDOR_ATTR_MU_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_MU_CTRL - 1
-+};
-+
-+#endif
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1013-mtk-wifi-mt76-mt7996-Add-air-monitor-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1013-mtk-wifi-mt76-mt7996-Add-air-monitor-support.patch
deleted file mode 100644
index 8f43d6c..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1013-mtk-wifi-mt76-mt7996-Add-air-monitor-support.patch
+++ /dev/null
@@ -1,565 +0,0 @@
-From aaf10c9fa1670faa83c7fade6f970c92239c0853 Mon Sep 17 00:00:00 2001
-From: Evelyn Tsai <evelyn.tsai@mediatek.com>
-Date: Wed, 26 Apr 2023 04:40:05 +0800
-Subject: [PATCH 1013/1044] mtk: wifi: mt76: mt7996: Add air monitor support
-
----
- mt76_connac_mcu.h | 1 +
- mt7996/mac.c | 4 +
- mt7996/main.c | 4 +
- mt7996/mt7996.h | 35 +++++
- mt7996/vendor.c | 362 ++++++++++++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 39 +++++
- 6 files changed, 445 insertions(+)
-
-diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 3c82c05d..062268d6 100644
---- a/mt76_connac_mcu.h
-+++ b/mt76_connac_mcu.h
-@@ -1251,6 +1251,7 @@ enum {
- MCU_UNI_CMD_REG_ACCESS = 0x0d,
- MCU_UNI_CMD_CHIP_CONFIG = 0x0e,
- MCU_UNI_CMD_POWER_CTRL = 0x0f,
-+ MCU_UNI_CMD_CFG_SMESH = 0x10,
- MCU_UNI_CMD_RX_HDR_TRANS = 0x12,
- MCU_UNI_CMD_SER = 0x13,
- MCU_UNI_CMD_TWT = 0x14,
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index c9f45abe..d55e5a76 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -679,6 +679,10 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, enum mt76_rxq_id q,
- if (ieee80211_has_a4(fc) && is_mesh && status->amsdu)
- *qos &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
- }
-+#ifdef CONFIG_MTK_VENDOR
-+ if (phy->amnt_ctrl.enable && !ieee80211_is_beacon(fc))
-+ mt7996_vendor_amnt_fill_rx(phy, skb);
-+#endif
- } else {
- status->flag |= RX_FLAG_8023;
- mt7996_wed_check_ppe(dev, &dev->mt76.q_rx[q], msta, skb,
-diff --git a/mt7996/main.c b/mt7996/main.c
-index 07a14917..478ca7ce 100644
---- a/mt7996/main.c
-+++ b/mt7996/main.c
-@@ -737,6 +737,10 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- mt7996_mac_wtbl_update(dev, idx,
- MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
-
-+#ifdef CONFIG_MTK_VENDOR
-+ mt7996_vendor_amnt_sta_remove(mvif->phy, sta);
-+#endif
-+
- ret = mt7996_mcu_add_sta(dev, vif, sta, true);
- if (ret)
- return ret;
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index d0b425da..09ce3c35 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -259,6 +259,34 @@ struct mt7996_wed_rro_session_id {
- u16 id;
- };
-
-+#ifdef CONFIG_MTK_VENDOR
-+#define MT7996_AIR_MONITOR_MAX_ENTRY 16
-+#define MT7996_AIR_MONITOR_MAX_GROUP (MT7996_AIR_MONITOR_MAX_ENTRY >> 1)
-+
-+struct mt7996_air_monitor_group {
-+ bool enable;
-+ bool used[2];
-+};
-+
-+struct mt7996_air_monitor_entry {
-+ bool enable;
-+
-+ u8 group_idx;
-+ u8 group_used_idx;
-+ u8 muar_idx;
-+ u8 addr[ETH_ALEN];
-+ u32 last_seen;
-+ s8 rssi[4];
-+ struct ieee80211_sta *sta;
-+};
-+
-+struct mt7996_air_monitor_ctrl {
-+ u8 enable;
-+ struct mt7996_air_monitor_group group[MT7996_AIR_MONITOR_MAX_GROUP];
-+ struct mt7996_air_monitor_entry entry[MT7996_AIR_MONITOR_MAX_ENTRY];
-+};
-+#endif
-+
- struct mt7996_phy {
- struct mt76_phy *mt76;
- struct mt7996_dev *dev;
-@@ -311,6 +339,10 @@ struct mt7996_phy {
- u8 spe_idx;
- } test;
- #endif
-+#ifdef CONFIG_MTK_VENDOR
-+ spinlock_t amnt_lock;
-+ struct mt7996_air_monitor_ctrl amnt_ctrl;
-+#endif
- };
-
- struct mt7996_dev {
-@@ -738,6 +770,9 @@ u32 mt7996_wed_init_buf(void *ptr, dma_addr_t phys, int token_id);
- #ifdef CONFIG_MTK_VENDOR
- void mt7996_set_wireless_vif(void *data, u8 *mac, struct ieee80211_vif *vif);
- void mt7996_vendor_register(struct mt7996_phy *phy);
-+void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb);
-+int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
-+ struct ieee80211_sta *sta);
- #endif
-
- #ifdef CONFIG_MTK_DEBUG
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index b5ecbdf1..f3b089d7 100644
---- a/mt7996/vendor.c
-+++ b/mt7996/vendor.c
-@@ -16,6 +16,32 @@ mu_ctrl_policy[NUM_MTK_VENDOR_ATTRS_MU_CTRL] = {
- [MTK_VENDOR_ATTR_MU_CTRL_DUMP] = {.type = NLA_U8 },
- };
-
-+static const struct nla_policy
-+amnt_ctrl_policy[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL] = {
-+ [MTK_VENDOR_ATTR_AMNT_CTRL_SET] = {.type = NLA_NESTED },
-+ [MTK_VENDOR_ATTR_AMNT_CTRL_DUMP] = { .type = NLA_NESTED },
-+};
-+
-+static const struct nla_policy
-+amnt_set_policy[NUM_MTK_VENDOR_ATTRS_AMNT_SET] = {
-+ [MTK_VENDOR_ATTR_AMNT_SET_INDEX] = {.type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_AMNT_SET_MACADDR] = NLA_POLICY_EXACT_LEN_WARN(ETH_ALEN),
-+};
-+
-+static const struct nla_policy
-+amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
-+ [MTK_VENDOR_ATTR_AMNT_DUMP_INDEX] = {.type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_AMNT_DUMP_LEN] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
-+};
-+
-+struct mt7996_amnt_data {
-+ u8 idx;
-+ u8 addr[ETH_ALEN];
-+ s8 rssi[4];
-+ u32 last_seen;
-+};
-+
- static int mt7996_vendor_mu_ctrl(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- const void *data,
-@@ -63,6 +89,328 @@ mt7996_vendor_mu_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
- return len;
- }
-
-+void mt7996_vendor_amnt_fill_rx(struct mt7996_phy *phy, struct sk_buff *skb)
-+{
-+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
-+ struct mt7996_air_monitor_ctrl *ctrl = &phy->amnt_ctrl;
-+ struct ieee80211_hdr *hdr = mt76_skb_get_hdr(skb);
-+ __le16 fc = hdr->frame_control;
-+ u8 addr[ETH_ALEN];
-+ int i;
-+
-+ if (!ieee80211_has_fromds(fc))
-+ ether_addr_copy(addr, hdr->addr2);
-+ else if (ieee80211_has_tods(fc))
-+ ether_addr_copy(addr, hdr->addr4);
-+ else
-+ ether_addr_copy(addr, hdr->addr3);
-+
-+ spin_lock_bh(&phy->amnt_lock);
-+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++) {
-+ struct mt7996_air_monitor_entry *entry;
-+
-+ if (ether_addr_equal(addr, ctrl->entry[i].addr)) {
-+ entry = &ctrl->entry[i];
-+ entry->rssi[0] = status->chain_signal[0];
-+ entry->rssi[1] = status->chain_signal[1];
-+ entry->rssi[2] = status->chain_signal[2];
-+ entry->rssi[3] = status->chain_signal[3];
-+ entry->last_seen = jiffies;
-+ break;
-+ }
-+ }
-+ spin_unlock_bh(&phy->amnt_lock);
-+}
-+
-+static int
-+mt7996_vendor_smesh_ctrl(struct mt7996_phy *phy, u8 write,
-+ u8 enable, u8 *value)
-+{
-+#define UNI_CMD_SMESH_PARAM 0
-+ struct mt7996_dev *dev = phy->dev;
-+ struct smesh_param {
-+ __le16 tag;
-+ __le16 length;
-+
-+ u8 enable;
-+ bool a2;
-+ bool a1;
-+ bool data;
-+ bool mgnt;
-+ bool ctrl;
-+ u8 padding[2];
-+ } req = {
-+ .tag = cpu_to_le16(UNI_CMD_SMESH_PARAM),
-+ .length = cpu_to_le16(sizeof(req) - 4),
-+
-+ .enable = enable,
-+ .a2 = true,
-+ .a1 = true,
-+ .data = true,
-+ .mgnt = false,
-+ .ctrl = false,
-+ };
-+ struct smesh_param *res;
-+ struct sk_buff *skb;
-+ int ret = 0;
-+
-+ if (!value)
-+ return -EINVAL;
-+
-+ ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD(CFG_SMESH),
-+ &req, sizeof(req), !write, &skb);
-+
-+ if (ret || write)
-+ return ret;
-+
-+ res = (struct smesh_param *) skb->data;
-+
-+ *value = res->enable;
-+
-+ dev_kfree_skb(skb);
-+
-+ return 0;
-+}
-+
-+static int
-+mt7996_vendor_amnt_muar(struct mt7996_phy *phy, u8 muar_idx, u8 *addr)
-+{
-+#define UNI_CMD_MUAR_ENTRY 2
-+ struct mt7996_dev *dev = phy->dev;
-+ struct muar_entry {
-+ __le16 tag;
-+ __le16 length;
-+
-+ bool smesh;
-+ u8 hw_bss_index;
-+ u8 muar_idx;
-+ u8 entry_add;
-+ u8 mac_addr[6];
-+ u8 padding[2];
-+ } __packed req = {
-+ .tag = cpu_to_le16(UNI_CMD_MUAR_ENTRY),
-+ .length = cpu_to_le16(sizeof(req) - 4),
-+
-+ .smesh = true,
-+ .hw_bss_index = phy != &dev->phy,
-+ .muar_idx = muar_idx,
-+ .entry_add = 1,
-+ };
-+
-+ ether_addr_copy(req.mac_addr, addr);
-+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(REPT_MUAR), &req,
-+ sizeof(req), true);
-+}
-+
-+static int
-+mt7996_vendor_amnt_set_en(struct mt7996_phy *phy, u8 enable)
-+{
-+ u8 status;
-+ int ret;
-+
-+ ret = mt7996_vendor_smesh_ctrl(phy, 0, enable, &status);
-+ if (ret)
-+ return ret;
-+
-+ if (status == enable)
-+ return 0;
-+
-+ ret = mt7996_vendor_smesh_ctrl(phy, 1, enable, &status);
-+ if (ret)
-+ return ret;
-+
-+ return 0;
-+}
-+
-+static int
-+mt7996_vendor_amnt_set_addr(struct mt7996_phy *phy, u8 index, u8 *addr)
-+{
-+ struct mt7996_air_monitor_ctrl *amnt_ctrl = &phy->amnt_ctrl;
-+ struct mt7996_air_monitor_group *group;
-+ struct mt7996_air_monitor_entry *entry;
-+ int ret, i, j;
-+
-+ if (index >= MT7996_AIR_MONITOR_MAX_ENTRY)
-+ return -1;
-+
-+ spin_lock_bh(&phy->amnt_lock);
-+ entry = &amnt_ctrl->entry[index];
-+ if (!is_zero_ether_addr(addr)) {
-+ if (entry->enable == false) {
-+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_GROUP; i++) {
-+ group = &(amnt_ctrl->group[i]);
-+ if (group->used[0] == false)
-+ j = 0;
-+ else if (group->used[1] == false)
-+ j = 1;
-+ else
-+ continue;
-+
-+ group->enable = true;
-+ group->used[j] = true;
-+ entry->enable = true;
-+ entry->group_idx = i;
-+ entry->group_used_idx = j;
-+ entry->muar_idx = 32 + 4 * i + 2 * j;
-+ break;
-+ }
-+ }
-+ } else {
-+ group = &(amnt_ctrl->group[entry->group_idx]);
-+
-+ group->used[entry->group_used_idx] = false;
-+ if (group->used[0] == false && group->used[1] == false)
-+ group->enable = false;
-+
-+ entry->enable = false;
-+ }
-+ ether_addr_copy(entry->addr, addr);
-+ amnt_ctrl->enable &= ~(1 << entry->group_idx);
-+ amnt_ctrl->enable |= entry->enable << entry->group_idx;
-+ spin_unlock_bh(&phy->amnt_lock);
-+
-+ ret = mt7996_vendor_amnt_muar(phy, entry->muar_idx, addr);
-+ if (ret)
-+ return ret;
-+
-+ return mt7996_vendor_amnt_set_en(phy, amnt_ctrl->enable);
-+}
-+
-+static int
-+mt7966_vendor_amnt_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ const void *data, int data_len)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
-+ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_SET];
-+ u8 index = 0;
-+ u8 mac_addr[ETH_ALEN];
-+ int err;
-+
-+ err = nla_parse(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, data, data_len,
-+ amnt_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_SET])
-+ return -EINVAL;
-+
-+ err = nla_parse_nested(tb2, MTK_VENDOR_ATTR_AMNT_SET_MAX,
-+ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_SET], amnt_set_policy, NULL);
-+
-+ if (!tb2[MTK_VENDOR_ATTR_AMNT_SET_INDEX] ||
-+ !tb2[MTK_VENDOR_ATTR_AMNT_SET_MACADDR])
-+ return -EINVAL;
-+
-+ index = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_SET_INDEX]);
-+ memcpy(mac_addr, nla_data(tb2[MTK_VENDOR_ATTR_AMNT_SET_MACADDR]), ETH_ALEN);
-+
-+ return mt7996_vendor_amnt_set_addr(phy, index, mac_addr);
-+}
-+
-+int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
-+ struct ieee80211_sta *sta)
-+{
-+ u8 zero[ETH_ALEN] = {};
-+ int i;
-+
-+ if (!phy->amnt_ctrl.enable)
-+ return 0;
-+
-+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++)
-+ if (ether_addr_equal(sta->addr, phy->amnt_ctrl.entry[i].addr))
-+ return mt7996_vendor_amnt_set_addr(phy, i, zero);
-+ return 0;
-+}
-+
-+static int
-+mt7996_amnt_dump(struct mt7996_phy *phy, struct sk_buff *skb,
-+ u8 amnt_idx, int *attrtype)
-+{
-+ struct mt7996_air_monitor_entry *entry;
-+ struct mt7996_amnt_data data;
-+ u32 last_seen = 0;
-+
-+ spin_lock_bh(&phy->amnt_lock);
-+ entry = &phy->amnt_ctrl.entry[amnt_idx];
-+ if (entry->enable == 0) {
-+ spin_unlock_bh(&phy->amnt_lock);
-+ return 0;
-+ }
-+
-+ last_seen = jiffies_to_msecs(jiffies - entry->last_seen);
-+ ether_addr_copy(data.addr, entry->addr);
-+ data.rssi[0] = entry->rssi[0];
-+ data.rssi[1] = entry->rssi[1];
-+ data.rssi[2] = entry->rssi[2];
-+ data.rssi[3] = entry->rssi[3];
-+ spin_unlock_bh(&phy->amnt_lock);
-+
-+ data.idx = amnt_idx;
-+ data.last_seen = last_seen;
-+
-+ nla_put(skb, (*attrtype)++, sizeof(struct mt7996_amnt_data), &data);
-+
-+ return 1;
-+}
-+
-+static int
-+mt7966_vendor_amnt_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ struct sk_buff *skb, const void *data, int data_len,
-+ unsigned long *storage)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ struct nlattr *tb1[NUM_MTK_VENDOR_ATTRS_AMNT_CTRL];
-+ struct nlattr *tb2[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP];
-+ void *a, *b;
-+ int err = 0, attrtype = 0, i, len = 0;
-+ u8 amnt_idx;
-+
-+ if (*storage == 1)
-+ return -ENOENT;
-+ *storage = 1;
-+
-+ err = nla_parse(tb1, MTK_VENDOR_ATTR_AMNT_CTRL_MAX, data, data_len,
-+ amnt_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (!tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP])
-+ return -EINVAL;
-+
-+ err = nla_parse_nested(tb2, MTK_VENDOR_ATTR_AMNT_DUMP_MAX,
-+ tb1[MTK_VENDOR_ATTR_AMNT_CTRL_DUMP],
-+ amnt_dump_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (!tb2[MTK_VENDOR_ATTR_AMNT_DUMP_INDEX])
-+ return -EINVAL;
-+
-+ amnt_idx = nla_get_u8(tb2[MTK_VENDOR_ATTR_AMNT_DUMP_INDEX]);
-+
-+ a = nla_nest_start(skb, MTK_VENDOR_ATTR_AMNT_CTRL_DUMP);
-+ b = nla_nest_start(skb, MTK_VENDOR_ATTR_AMNT_DUMP_RESULT);
-+
-+ if (amnt_idx != 0xff) {
-+ len += mt7996_amnt_dump(phy, skb, amnt_idx, &attrtype);
-+ } else {
-+ for (i = 0; i < MT7996_AIR_MONITOR_MAX_ENTRY; i++)
-+ len += mt7996_amnt_dump(phy, skb, i, &attrtype);
-+ }
-+
-+ nla_nest_end(skb, b);
-+
-+ nla_put_u8(skb, MTK_VENDOR_ATTR_AMNT_DUMP_LEN, len);
-+
-+ nla_nest_end(skb, a);
-+
-+ return len + 1;
-+}
-+
-+
- static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- {
- .info = {
-@@ -76,10 +424,24 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = mu_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_MU_CTRL_MAX,
- },
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .doit = mt7966_vendor_amnt_ctrl,
-+ .dumpit = mt7966_vendor_amnt_ctrl_dump,
-+ .policy = amnt_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
-+ },
- };
-
- void mt7996_vendor_register(struct mt7996_phy *phy)
- {
- phy->mt76->hw->wiphy->vendor_commands = mt7996_vendor_commands;
- phy->mt76->hw->wiphy->n_vendor_commands = ARRAY_SIZE(mt7996_vendor_commands);
-+
-+ spin_lock_init(&phy->amnt_lock);
- }
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 8ac3ba8e..2078cafa 100644
---- a/mt7996/vendor.h
-+++ b/mt7996/vendor.h
-@@ -4,6 +4,7 @@
- #define MTK_NL80211_VENDOR_ID 0x0ce7
-
- enum mtk_nl80211_vendor_subcmds {
-+ MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
- MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
- };
-
-@@ -19,4 +20,42 @@ enum mtk_vendor_attr_mu_ctrl {
- NUM_MTK_VENDOR_ATTRS_MU_CTRL - 1
- };
-
-+enum mtk_vendor_attr_mnt_ctrl {
-+ MTK_VENDOR_ATTR_AMNT_CTRL_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_AMNT_CTRL_SET,
-+ MTK_VENDOR_ATTR_AMNT_CTRL_DUMP,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_AMNT_CTRL,
-+ MTK_VENDOR_ATTR_AMNT_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_AMNT_CTRL - 1
-+};
-+
-+enum mtk_vendor_attr_mnt_set {
-+ MTK_VENDOR_ATTR_AMNT_SET_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_AMNT_SET_INDEX,
-+ MTK_VENDOR_ATTR_AMNT_SET_MACADDR,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_AMNT_SET,
-+ MTK_VENDOR_ATTR_AMNT_SET_MAX =
-+ NUM_MTK_VENDOR_ATTRS_AMNT_SET - 1
-+};
-+
-+enum mtk_vendor_attr_mnt_dump {
-+ MTK_VENDOR_ATTR_AMNT_DUMP_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_AMNT_DUMP_INDEX,
-+ MTK_VENDOR_ATTR_AMNT_DUMP_LEN,
-+ MTK_VENDOR_ATTR_AMNT_DUMP_RESULT,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_AMNT_DUMP,
-+ MTK_VENDOR_ATTR_AMNT_DUMP_MAX =
-+ NUM_MTK_VENDOR_ATTRS_AMNT_DUMP - 1
-+};
-+
-+
- #endif
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1015-mtk-wifi-mt76-mt7996-add-vendor-cmd-to-get-available.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1015-mtk-wifi-mt76-mt7996-add-vendor-cmd-to-get-available.patch
deleted file mode 100644
index dc1df69..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1015-mtk-wifi-mt76-mt7996-add-vendor-cmd-to-get-available.patch
+++ /dev/null
@@ -1,107 +0,0 @@
-From 109e8c6a16d948bb2b0b685a8d102e91bb89e4ed Mon Sep 17 00:00:00 2001
-From: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
-Date: Wed, 3 May 2023 05:08:07 +0800
-Subject: [PATCH 1015/1044] mtk: wifi: mt76: mt7996: add vendor cmd to get
- available color bitmap
-
-Add a vendor cmd to notify user space available color bitmap.
-The OBSS BSS color bitmap is maintained in mac80211, so mt76 will make use of that.
-
-Signed-off-by: Yi-Chia Hsieh <yi-chia.hsieh@mediatek.com>
----
- mt7996/vendor.c | 36 ++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 11 +++++++++++
- 2 files changed, 47 insertions(+)
-
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index f3b089d7..39101577 100644
---- a/mt7996/vendor.c
-+++ b/mt7996/vendor.c
-@@ -35,6 +35,11 @@ amnt_dump_policy[NUM_MTK_VENDOR_ATTRS_AMNT_DUMP] = {
- [MTK_VENDOR_ATTR_AMNT_DUMP_RESULT] = { .type = NLA_NESTED },
- };
-
-+static struct nla_policy
-+bss_color_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL] = {
-+ [MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP] = { .type = NLA_U64 },
-+};
-+
- struct mt7996_amnt_data {
- u8 idx;
- u8 addr[ETH_ALEN];
-@@ -410,6 +415,26 @@ mt7966_vendor_amnt_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
- return len + 1;
- }
-
-+static int
-+mt7996_vendor_bss_color_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ struct sk_buff *skb, const void *data, int data_len,
-+ unsigned long *storage)
-+{
-+ struct ieee80211_vif *vif = wdev_to_ieee80211_vif(wdev);
-+ struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
-+ int len = 0;
-+
-+ if (*storage == 1)
-+ return -ENOENT;
-+ *storage = 1;
-+
-+ if (nla_put_u64_64bit(skb, MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP,
-+ ~bss_conf->used_color_bitmap, NL80211_ATTR_PAD))
-+ return -ENOMEM;
-+ len += 1;
-+
-+ return len;
-+}
-
- static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- {
-@@ -436,6 +461,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = amnt_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_AMNT_CTRL_MAX,
- },
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .dumpit = mt7996_vendor_bss_color_ctrl_dump,
-+ .policy = bss_color_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX,
-+ },
- };
-
- void mt7996_vendor_register(struct mt7996_phy *phy)
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 2078cafa..eec9e74a 100644
---- a/mt7996/vendor.h
-+++ b/mt7996/vendor.h
-@@ -6,6 +6,7 @@
- enum mtk_nl80211_vendor_subcmds {
- MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
- MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
-+ MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
- };
-
- enum mtk_vendor_attr_mu_ctrl {
-@@ -57,5 +58,15 @@ enum mtk_vendor_attr_mnt_dump {
- NUM_MTK_VENDOR_ATTRS_AMNT_DUMP - 1
- };
-
-+enum mtk_vendor_attr_bss_color_ctrl {
-+ MTK_VENDOR_ATTR_BSS_COLOR_CTRL_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL,
-+ MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL - 1
-+};
-
- #endif
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1019-mtk-wifi-mt76-mt7996-add-vendor-subcmd-EDCCA-ctrl-en.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1019-mtk-wifi-mt76-mt7996-add-vendor-subcmd-EDCCA-ctrl-en.patch
deleted file mode 100644
index fb38f6a..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1019-mtk-wifi-mt76-mt7996-add-vendor-subcmd-EDCCA-ctrl-en.patch
+++ /dev/null
@@ -1,379 +0,0 @@
-From 2caf106ced738d65640e21d284e3fee9cb04c611 Mon Sep 17 00:00:00 2001
-From: mtk27745 <rex.lu@mediatek.com>
-Date: Thu, 8 Jun 2023 20:21:04 +0800
-Subject: [PATCH 1019/1044] mtk: wifi: mt76: mt7996: add vendor subcmd EDCCA
- ctrl enable
-
----
- mt7996/mcu.h | 2 +
- mt7996/mt7996.h | 11 ++++
- mt7996/mtk_mcu.c | 87 +++++++++++++++++++++++++++++++
- mt7996/mtk_mcu.h | 15 ++++++
- mt7996/vendor.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 33 ++++++++++++
- 6 files changed, 280 insertions(+)
-
-diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index 35f757dc..34fdfb26 100644
---- a/mt7996/mcu.h
-+++ b/mt7996/mcu.h
-@@ -845,6 +845,8 @@ mt7996_get_power_bound(struct mt7996_phy *phy, s8 txpower)
-
- enum {
- UNI_BAND_CONFIG_RADIO_ENABLE,
-+ UNI_BAND_CONFIG_EDCCA_ENABLE = 0x05,
-+ UNI_BAND_CONFIG_EDCCA_THRESHOLD = 0x06,
- UNI_BAND_CONFIG_RTS_THRESHOLD = 0x08,
- };
-
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 7ca9d57e..cfa50bfe 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -786,6 +786,17 @@ int mt7996_vendor_amnt_sta_remove(struct mt7996_phy *phy,
- struct ieee80211_sta *sta);
- #endif
-
-+int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable);
-+int mt7996_mcu_edcca_threshold_ctrl(struct mt7996_phy *phy, u8 *value, bool set);
-+
-+enum edcca_bw_id {
-+ EDCCA_BW_20 = 0,
-+ EDCCA_BW_40,
-+ EDCCA_BW_80,
-+ EDCCA_BW_160,
-+ EDCCA_MAX_BW_NUM,
-+};
-+
- #ifdef CONFIG_MTK_DEBUG
- int mt7996_mtk_init_debugfs(struct mt7996_phy *phy, struct dentry *dir);
- int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val);
-diff --git a/mt7996/mtk_mcu.c b/mt7996/mtk_mcu.c
-index e56ddd8f..5c54d02c 100644
---- a/mt7996/mtk_mcu.c
-+++ b/mt7996/mtk_mcu.c
-@@ -59,4 +59,91 @@ int mt7996_mcu_muru_dbg_info(struct mt7996_dev *dev, u16 item, u8 val)
- return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(MURU), &req,
- sizeof(req), true);
- }
-+
-+int mt7996_mcu_edcca_enable(struct mt7996_phy *phy, bool enable)
-+{
-+ struct mt7996_dev *dev = phy->dev;
-+ struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
-+ enum nl80211_band band = chandef->chan->band;
-+ struct {
-+ u8 band_idx;
-+ u8 _rsv[3];
-+
-+ __le16 tag;
-+ __le16 len;
-+ u8 enable;
-+ u8 std;
-+ u8 _rsv2[2];
-+ } __packed req = {
-+ .band_idx = phy->mt76->band_idx,
-+ .tag = cpu_to_le16(UNI_BAND_CONFIG_EDCCA_ENABLE),
-+ .len = cpu_to_le16(sizeof(req) - 4),
-+ .enable = enable,
-+ .std = EDCCA_DEFAULT,
-+ };
-+
-+ switch (dev->mt76.region) {
-+ case NL80211_DFS_JP:
-+ req.std = EDCCA_JAPAN;
-+ break;
-+ case NL80211_DFS_FCC:
-+ if (band == NL80211_BAND_6GHZ)
-+ req.std = EDCCA_FCC;
-+ break;
-+ case NL80211_DFS_ETSI:
-+ if (band == NL80211_BAND_6GHZ)
-+ req.std = EDCCA_ETSI;
-+ break;
-+ default:
-+ break;
-+ }
-+
-+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
-+ &req, sizeof(req), true);
-+}
-+
-+int mt7996_mcu_edcca_threshold_ctrl(struct mt7996_phy *phy, u8 *value, bool set)
-+{
-+ struct {
-+ u8 band_idx;
-+ u8 _rsv[3];
-+
-+ __le16 tag;
-+ __le16 len;
-+ u8 threshold[4];
-+ bool init;
-+ } __packed *res, req = {
-+ .band_idx = phy->mt76->band_idx,
-+ .tag = cpu_to_le16(UNI_BAND_CONFIG_EDCCA_THRESHOLD),
-+ .len = cpu_to_le16(sizeof(req) - 4),
-+ .init = false,
-+ };
-+ struct sk_buff *skb;
-+ int ret;
-+ int i;
-+
-+ for (i = 0; i < EDCCA_MAX_BW_NUM; i++)
-+ req.threshold[i] = value[i];
-+
-+ if (set)
-+ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(BAND_CONFIG),
-+ &req, sizeof(req), true);
-+
-+ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76,
-+ MCU_WM_UNI_CMD_QUERY(BAND_CONFIG),
-+ &req, sizeof(req), true, &skb);
-+
-+ if (ret)
-+ return ret;
-+
-+ res = (void *)skb->data;
-+
-+ for (i = 0; i < EDCCA_MAX_BW_NUM; i++)
-+ value[i] = res->threshold[i];
-+
-+ dev_kfree_skb(skb);
-+
-+ return 0;
-+}
-+
- #endif
-diff --git a/mt7996/mtk_mcu.h b/mt7996/mtk_mcu.h
-index c30418ca..36a58ad6 100644
---- a/mt7996/mtk_mcu.h
-+++ b/mt7996/mtk_mcu.h
-@@ -106,6 +106,21 @@ enum txpower_event {
- UNI_TXPOWER_PHY_RATE_INFO = 5,
- };
-
-+enum {
-+ EDCCA_CTRL_SET_EN = 0,
-+ EDCCA_CTRL_SET_THRES,
-+ EDCCA_CTRL_GET_EN,
-+ EDCCA_CTRL_GET_THRES,
-+ EDCCA_CTRL_NUM,
-+};
-+
-+enum {
-+ EDCCA_DEFAULT = 0,
-+ EDCCA_FCC = 1,
-+ EDCCA_ETSI = 2,
-+ EDCCA_JAPAN = 3
-+};
-+
- #endif
-
- #endif
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index 39101577..9f333d0e 100644
---- a/mt7996/vendor.c
-+++ b/mt7996/vendor.c
-@@ -40,6 +40,26 @@ bss_color_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL] = {
- [MTK_VENDOR_ATTR_AVAL_BSS_COLOR_BMP] = { .type = NLA_U64 },
- };
-
-+static const struct nla_policy
-+edcca_ctrl_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL] = {
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_MODE] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC20_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE] = { .type = NLA_S8 },
-+ [MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL] = { .type = NLA_U8 },
-+};
-+
-+static const struct nla_policy
-+edcca_dump_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP] = {
-+ [MTK_VENDOR_ATTR_EDCCA_DUMP_MODE] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL] = { .type = NLA_U8 },
-+ [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL] = { .type = NLA_U8 },
-+};
-+
- struct mt7996_amnt_data {
- u8 idx;
- u8 addr[ETH_ALEN];
-@@ -436,6 +456,106 @@ mt7996_vendor_bss_color_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev
- return len;
- }
-
-+static int mt7996_vendor_edcca_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ const void *data, int data_len)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL];
-+ int err;
-+ u8 edcca_mode;
-+ u8 edcca_value[EDCCA_MAX_BW_NUM];
-+
-+ err = nla_parse(tb, MTK_VENDOR_ATTR_EDCCA_CTRL_MAX, data, data_len,
-+ edcca_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE])
-+ return -EINVAL;
-+
-+ edcca_mode = nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE]);
-+ if (edcca_mode == EDCCA_CTRL_SET_EN) {
-+ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL])
-+ return -EINVAL;
-+
-+ edcca_value[0] =
-+ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL]);
-+
-+ err = mt7996_mcu_edcca_enable(phy, !!edcca_value[0]);
-+ if (err)
-+ return err;
-+ } else if (edcca_mode == EDCCA_CTRL_SET_THRES) {
-+ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL] ||
-+ !tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL] ||
-+ !tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL] ||
-+ !tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL]) {
-+ return -EINVAL;
-+ }
-+ edcca_value[EDCCA_BW_20] =
-+ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL]);
-+ edcca_value[EDCCA_BW_40] =
-+ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL]);
-+ edcca_value[EDCCA_BW_80] =
-+ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL]);
-+ edcca_value[EDCCA_BW_160] =
-+ nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL]);
-+
-+ err = mt7996_mcu_edcca_threshold_ctrl(phy, edcca_value, true);
-+
-+ if (err)
-+ return err;
-+ } else {
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+
-+static int
-+mt7996_vendor_edcca_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ struct sk_buff *skb, const void *data, int data_len,
-+ unsigned long *storage)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL];
-+ int err;
-+ u8 edcca_mode;
-+ u8 value[EDCCA_MAX_BW_NUM];
-+
-+ if (*storage == 1)
-+ return -ENOENT;
-+ *storage = 1;
-+
-+ err = nla_parse(tb, MTK_VENDOR_ATTR_EDCCA_CTRL_MAX, data, data_len,
-+ edcca_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (!tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE])
-+ return -EINVAL;
-+
-+ edcca_mode = nla_get_u8(tb[MTK_VENDOR_ATTR_EDCCA_CTRL_MODE]);
-+
-+ if (edcca_mode != EDCCA_CTRL_GET_THRES)
-+ return -EINVAL;
-+
-+ err = mt7996_mcu_edcca_threshold_ctrl(phy, value, false);
-+
-+ if (err)
-+ return err;
-+
-+ if (nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL, value[EDCCA_BW_20]) ||
-+ nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL, value[EDCCA_BW_40]) ||
-+ nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL, value[EDCCA_BW_80]) ||
-+ nla_put_u8(skb, MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL, value[EDCCA_BW_160]))
-+ return -ENOMEM;
-+
-+ return EDCCA_MAX_BW_NUM;
-+}
-+
- static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- {
- .info = {
-@@ -472,6 +592,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = bss_color_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_BSS_COLOR_CTRL_MAX,
- },
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .doit = mt7996_vendor_edcca_ctrl,
-+ .dumpit = mt7996_vendor_edcca_ctrl_dump,
-+ .policy = edcca_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_EDCCA_CTRL_MAX,
-+ },
- };
-
- void mt7996_vendor_register(struct mt7996_phy *phy)
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index eec9e74a..4465bc9d 100644
---- a/mt7996/vendor.h
-+++ b/mt7996/vendor.h
-@@ -6,9 +6,42 @@
- enum mtk_nl80211_vendor_subcmds {
- MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
- MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
-+ MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL = 0xc7,
- MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
- };
-
-+enum mtk_vendor_attr_edcca_ctrl {
-+ MTK_VENDOR_ATTR_EDCCA_THRESHOLD_INVALID = 0,
-+
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_MODE,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_PRI20_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC20_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC40_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC80_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_COMPENSATE,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_SEC160_VAL,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL,
-+ MTK_VENDOR_ATTR_EDCCA_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_EDCCA_CTRL - 1
-+};
-+
-+enum mtk_vendor_attr_edcca_dump {
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_UNSPEC = 0,
-+
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_MODE,
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_PRI20_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC40_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC80_VAL,
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP,
-+ MTK_VENDOR_ATTR_EDCCA_DUMP_MAX =
-+ NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP - 1
-+};
-+
- enum mtk_vendor_attr_mu_ctrl {
- MTK_VENDOR_ATTR_MU_CTRL_UNSPEC,
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1025-mtk-wifi-mt76-mt7996-add-ibf-control-vendor-cmd.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1025-mtk-wifi-mt76-mt7996-add-ibf-control-vendor-cmd.patch
deleted file mode 100644
index 5fc86f1..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1025-mtk-wifi-mt76-mt7996-add-ibf-control-vendor-cmd.patch
+++ /dev/null
@@ -1,143 +0,0 @@
-From 4c1c8c14c01399c1851eefde7e56d6dcd7f9f2d3 Mon Sep 17 00:00:00 2001
-From: "Allen.Ye" <allen.ye@mediatek.com>
-Date: Fri, 22 Sep 2023 09:54:49 +0800
-Subject: [PATCH 1025/1044] mtk: wifi: mt76: mt7996: add ibf control vendor cmd
-
-Signed-off-by: Allen.Ye <allen.ye@mediatek.com>
----
- mt7996/vendor.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 23 +++++++++++++++++
- 2 files changed, 88 insertions(+)
-
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index 9f333d0e..dae3260a 100644
---- a/mt7996/vendor.c
-+++ b/mt7996/vendor.c
-@@ -60,6 +60,11 @@ edcca_dump_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP] = {
- [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL] = { .type = NLA_U8 },
- };
-
-+static const struct nla_policy
-+ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
-+ [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
-+};
-+
- struct mt7996_amnt_data {
- u8 idx;
- u8 addr[ETH_ALEN];
-@@ -556,6 +561,54 @@ mt7996_vendor_edcca_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
- return EDCCA_MAX_BW_NUM;
- }
-
-+static int mt7996_vendor_ibf_ctrl(struct wiphy *wiphy,
-+ struct wireless_dev *wdev,
-+ const void *data,
-+ int data_len)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ struct mt7996_dev *dev = phy->dev;
-+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_IBF_CTRL];
-+ int err;
-+ u8 val;
-+
-+ err = nla_parse(tb, MTK_VENDOR_ATTR_IBF_CTRL_MAX, data, data_len,
-+ ibf_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (tb[MTK_VENDOR_ATTR_IBF_CTRL_ENABLE]) {
-+ val = nla_get_u8(tb[MTK_VENDOR_ATTR_IBF_CTRL_ENABLE]);
-+
-+ dev->ibf = !!val;
-+
-+ err = mt7996_mcu_set_txbf(dev, BF_HW_EN_UPDATE);
-+ if (err)
-+ return err;
-+ }
-+ return 0;
-+}
-+
-+static int
-+mt7996_vendor_ibf_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ struct sk_buff *skb, const void *data, int data_len,
-+ unsigned long *storage)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ struct mt7996_dev *dev = phy->dev;
-+
-+ if (*storage == 1)
-+ return -ENOENT;
-+ *storage = 1;
-+
-+ if (nla_put_u8(skb, MTK_VENDOR_ATTR_IBF_DUMP_ENABLE, dev->ibf))
-+ return -ENOMEM;
-+
-+ return 1;
-+}
-+
- static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- {
- .info = {
-@@ -604,6 +657,18 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = edcca_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_EDCCA_CTRL_MAX,
- },
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .doit = mt7996_vendor_ibf_ctrl,
-+ .dumpit = mt7996_vendor_ibf_ctrl_dump,
-+ .policy = ibf_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_IBF_CTRL_MAX,
-+ },
- };
-
- void mt7996_vendor_register(struct mt7996_phy *phy)
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 4465bc9d..49f46f25 100644
---- a/mt7996/vendor.h
-+++ b/mt7996/vendor.h
-@@ -7,6 +7,7 @@ enum mtk_nl80211_vendor_subcmds {
- MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
- MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
- MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL = 0xc7,
-+ MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
- MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
- };
-
-@@ -102,4 +103,26 @@ enum mtk_vendor_attr_bss_color_ctrl {
- NUM_MTK_VENDOR_ATTRS_BSS_COLOR_CTRL - 1
- };
-
-+enum mtk_vendor_attr_ibf_ctrl {
-+ MTK_VENDOR_ATTR_IBF_CTRL_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_IBF_CTRL_ENABLE,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_IBF_CTRL,
-+ MTK_VENDOR_ATTR_IBF_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_IBF_CTRL - 1
-+};
-+
-+enum mtk_vendor_attr_ibf_dump {
-+ MTK_VENDOR_ATTR_IBF_DUMP_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_IBF_DUMP_ENABLE,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_IBF_DUMP,
-+ MTK_VENDOR_ATTR_IBF_DUMP_MAX =
-+ NUM_MTK_VENDOR_ATTRS_IBF_DUMP - 1
-+};
-+
- #endif
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1030-mtk-wifi-mt76-mt7996-add-three-wire-pta-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1030-mtk-wifi-mt76-mt7996-add-three-wire-pta-support.patch
deleted file mode 100644
index 53f6642..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1030-mtk-wifi-mt76-mt7996-add-three-wire-pta-support.patch
+++ /dev/null
@@ -1,133 +0,0 @@
-From 311174c13b07be59176f82594b6704a64acae40c Mon Sep 17 00:00:00 2001
-From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
-Date: Tue, 24 Oct 2023 15:59:18 +0800
-Subject: [PATCH 1030/1044] mtk: wifi: mt76: mt7996: add three wire pta support
-
-three wire enable bit 0 & 1 for EXT0 & EXT1, respectively
-
-Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
----
- mt76_connac_mcu.h | 1 +
- mt7996/vendor.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 12 ++++++++++++
- 3 files changed, 62 insertions(+)
-
-diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 9edb580c..a59e5a0b 100644
---- a/mt76_connac_mcu.h
-+++ b/mt76_connac_mcu.h
-@@ -1285,6 +1285,7 @@ enum {
- MCU_UNI_CMD_PER_STA_INFO = 0x6d,
- MCU_UNI_CMD_ALL_STA_INFO = 0x6e,
- MCU_UNI_CMD_ASSERT_DUMP = 0x6f,
-+ MCU_UNI_CMD_PTA_3WIRE_CTRL = 0x78,
- };
-
- enum {
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index dae3260a..9ba6f00a 100644
---- a/mt7996/vendor.c
-+++ b/mt7996/vendor.c
-@@ -60,6 +60,11 @@ edcca_dump_policy[NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP] = {
- [MTK_VENDOR_ATTR_EDCCA_DUMP_SEC160_VAL] = { .type = NLA_U8 },
- };
-
-+static const struct nla_policy
-+three_wire_ctrl_policy[NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL] = {
-+ [MTK_VENDOR_ATTR_3WIRE_CTRL_MODE] = {.type = NLA_U8 },
-+};
-+
- static const struct nla_policy
- ibf_ctrl_policy[NUM_MTK_VENDOR_ATTRS_IBF_CTRL] = {
- [MTK_VENDOR_ATTR_IBF_CTRL_ENABLE] = { .type = NLA_U8 },
-@@ -561,6 +566,39 @@ mt7996_vendor_edcca_ctrl_dump(struct wiphy *wiphy, struct wireless_dev *wdev,
- return EDCCA_MAX_BW_NUM;
- }
-
-+static int mt7996_vendor_3wire_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ const void *data, int data_len)
-+{
-+#define UNI_3WIRE_EXT_EN 0
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct mt7996_dev *dev = mt7996_hw_dev(hw);
-+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL];
-+ struct {
-+ u8 __rsv1[4];
-+
-+ __le16 tag;
-+ __le16 len;
-+ u8 three_wire_mode;
-+ } __packed req = {
-+ .tag = cpu_to_le16(UNI_3WIRE_EXT_EN),
-+ .len = cpu_to_le16(sizeof(req) - 4),
-+ };
-+ int err;
-+
-+ err = nla_parse(tb, MTK_VENDOR_ATTR_3WIRE_CTRL_MAX, data, data_len,
-+ three_wire_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (!tb[MTK_VENDOR_ATTR_3WIRE_CTRL_MODE])
-+ return -EINVAL;
-+
-+ req.three_wire_mode = nla_get_u8(tb[MTK_VENDOR_ATTR_3WIRE_CTRL_MODE]);
-+
-+ return mt76_mcu_send_msg(&dev->mt76, MCU_WM_UNI_CMD(PTA_3WIRE_CTRL), &req,
-+ sizeof(req), false);
-+}
-+
- static int mt7996_vendor_ibf_ctrl(struct wiphy *wiphy,
- struct wireless_dev *wdev,
- const void *data,
-@@ -657,6 +695,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = edcca_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_EDCCA_CTRL_MAX,
- },
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .doit = mt7996_vendor_3wire_ctrl,
-+ .policy = three_wire_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_3WIRE_CTRL_MAX,
-+ },
- {
- .info = {
- .vendor_id = MTK_NL80211_VENDOR_ID,
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 49f46f25..29ccc050 100644
---- a/mt7996/vendor.h
-+++ b/mt7996/vendor.h
-@@ -7,6 +7,7 @@ enum mtk_nl80211_vendor_subcmds {
- MTK_NL80211_VENDOR_SUBCMD_AMNT_CTRL = 0xae,
- MTK_NL80211_VENDOR_SUBCMD_MU_CTRL = 0xc5,
- MTK_NL80211_VENDOR_SUBCMD_EDCCA_CTRL = 0xc7,
-+ MTK_NL80211_VENDOR_SUBCMD_3WIRE_CTRL = 0xc8,
- MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
- MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
- };
-@@ -43,6 +44,17 @@ enum mtk_vendor_attr_edcca_dump {
- NUM_MTK_VENDOR_ATTRS_EDCCA_DUMP - 1
- };
-
-+enum mtk_vendor_attr_3wire_ctrl {
-+ MTK_VENDOR_ATTR_3WIRE_CTRL_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_3WIRE_CTRL_MODE,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL,
-+ MTK_VENDOR_ATTR_3WIRE_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_3WIRE_CTRL - 1
-+};
-+
- enum mtk_vendor_attr_mu_ctrl {
- MTK_VENDOR_ATTR_MU_CTRL_UNSPEC,
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1037-mtk-wifi-mt76-mt7996-support-enable-disable-pp-featu.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1037-mtk-wifi-mt76-mt7996-support-enable-disable-pp-featu.patch
deleted file mode 100644
index a914829..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1037-mtk-wifi-mt76-mt7996-support-enable-disable-pp-featu.patch
+++ /dev/null
@@ -1,112 +0,0 @@
-From 8548624e0e3323cf0e14ce21ab988cd5ed5167cf Mon Sep 17 00:00:00 2001
-From: Howard Hsu <howard-yh.hsu@mediatek.com>
-Date: Mon, 25 Sep 2023 19:20:49 +0800
-Subject: [PATCH 1037/1044] mtk: wifi: mt76: mt7996: support enable/disable pp
- feature by nl80211 vendor commands
-
-User can enable/disable preamble puncture feature through hostapd
-configuration and hostapd_cli. Driver can receive the nl80211 vendor
-message and convert it to mcu commands.
-
-Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
----
- mt7996/vendor.c | 38 ++++++++++++++++++++++++++++++++++++++
- mt7996/vendor.h | 12 ++++++++++++
- 2 files changed, 50 insertions(+)
-
-diff --git a/mt7996/vendor.c b/mt7996/vendor.c
-index c7fd3278..9732ed28 100644
---- a/mt7996/vendor.c
-+++ b/mt7996/vendor.c
-@@ -107,6 +107,11 @@ background_radar_ctrl_policy[NUM_MTK_VENDOR_ATTRS_BACKGROUND_RADAR_CTRL] = {
- [MTK_VENDOR_ATTR_BACKGROUND_RADAR_CTRL_MODE] = {.type = NLA_U8 },
- };
-
-+static struct nla_policy
-+pp_ctrl_policy[NUM_MTK_VENDOR_ATTRS_PP_CTRL] = {
-+ [MTK_VENDOR_ATTR_PP_MODE] = { .type = NLA_U8 },
-+};
-+
- struct mt7996_amnt_data {
- u8 idx;
- u8 addr[ETH_ALEN];
-@@ -877,6 +882,28 @@ static int mt7996_vendor_background_radar_mode_ctrl(struct wiphy *wiphy,
- return mt7996_mcu_rdd_background_disable_timer(dev, !!background_radar_mode);
- }
-
-+static int mt7996_vendor_pp_ctrl(struct wiphy *wiphy, struct wireless_dev *wdev,
-+ const void *data, int data_len)
-+{
-+ struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-+ struct nlattr *tb[NUM_MTK_VENDOR_ATTRS_PP_CTRL];
-+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
-+ int err;
-+ u8 val8;
-+
-+ err = nla_parse(tb, MTK_VENDOR_ATTR_PP_CTRL_MAX, data, data_len,
-+ pp_ctrl_policy, NULL);
-+ if (err)
-+ return err;
-+
-+ if (tb[MTK_VENDOR_ATTR_PP_MODE]) {
-+ val8 = nla_get_u8(tb[MTK_VENDOR_ATTR_PP_MODE]);
-+ err = mt7996_mcu_set_pp_en(phy, !!val8, 0, 0);
-+ }
-+
-+ return err;
-+}
-+
- static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- {
- .info = {
-@@ -982,6 +1009,17 @@ static const struct wiphy_vendor_command mt7996_vendor_commands[] = {
- .policy = background_radar_ctrl_policy,
- .maxattr = MTK_VENDOR_ATTR_BACKGROUND_RADAR_CTRL_MAX,
- },
-+ {
-+ .info = {
-+ .vendor_id = MTK_NL80211_VENDOR_ID,
-+ .subcmd = MTK_NL80211_VENDOR_SUBCMD_PP_CTRL,
-+ },
-+ .flags = WIPHY_VENDOR_CMD_NEED_NETDEV |
-+ WIPHY_VENDOR_CMD_NEED_RUNNING,
-+ .doit = mt7996_vendor_pp_ctrl,
-+ .policy = pp_ctrl_policy,
-+ .maxattr = MTK_VENDOR_ATTR_PP_CTRL_MAX,
-+ },
- };
-
- void mt7996_vendor_register(struct mt7996_phy *phy)
-diff --git a/mt7996/vendor.h b/mt7996/vendor.h
-index 920b6e6a..98128965 100644
---- a/mt7996/vendor.h
-+++ b/mt7996/vendor.h
-@@ -15,6 +15,7 @@ enum mtk_nl80211_vendor_subcmds {
- MTK_NL80211_VENDOR_SUBCMD_IBF_CTRL = 0xc9,
- MTK_NL80211_VENDOR_SUBCMD_BSS_COLOR_CTRL = 0xca,
- MTK_NL80211_VENDOR_SUBCMD_BACKGROUND_RADAR_CTRL = 0xcb,
-+ MTK_NL80211_VENDOR_SUBCMD_PP_CTRL = 0xcc,
- };
-
- enum mtk_vendor_attr_edcca_ctrl {
-@@ -214,6 +215,17 @@ enum mtk_vendor_attr_ibf_dump {
- NUM_MTK_VENDOR_ATTRS_IBF_DUMP - 1
- };
-
-+enum mtk_vendor_attr_pp_ctrl {
-+ MTK_VENDOR_ATTR_PP_CTRL_UNSPEC,
-+
-+ MTK_VENDOR_ATTR_PP_MODE,
-+
-+ /* keep last */
-+ NUM_MTK_VENDOR_ATTRS_PP_CTRL,
-+ MTK_VENDOR_ATTR_PP_CTRL_MAX =
-+ NUM_MTK_VENDOR_ATTRS_PP_CTRL - 1
-+};
-+
- #endif
-
- #endif
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/1044-mtk-wifi-mt76-mt7996-support-disable-muru-debug-info.patch b/recipes-wifi/linux-mt76/files/patches-3.x/1044-mtk-wifi-mt76-mt7996-support-disable-muru-debug-info.patch
deleted file mode 100644
index 1d601d3..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/1044-mtk-wifi-mt76-mt7996-support-disable-muru-debug-info.patch
+++ /dev/null
@@ -1,98 +0,0 @@
-From f3eec1dbbbf7cb3096017f968e616d3311172c1e Mon Sep 17 00:00:00 2001
-From: Howard Hsu <howard-yh.hsu@mediatek.com>
-Date: Fri, 22 Dec 2023 10:53:00 +0800
-Subject: [PATCH 1044/1044] mtk: wifi: mt76: mt7996: support disable muru debug
- info when recording fwlog
-
-When we record fwlog, we will also enable recording muru debug info log by
-default. However, in certain test scenarios, this can result in
-recording too many logs, causing inconvenience during issue analysis.
-Therefore, this commit adds an debug option, fw_debug_muru_disable, in
-debugfs. User can modify this option to enable/disable recording muru
-debug info log.
-
-[Usage]
-Set:
-$ echo val > debugfs/fw_debug_muru_disable
-Get:
-$ cat debugfs/fw_debug_muru_disable
-
-val can be the following values:
-0 = enable recording muru debug info (Default value)
-1 = disable recording muru debug info
-
-Signed-off-by: Howard Hsu <howard-yh.hsu@mediatek.com>
----
- mt7996/debugfs.c | 29 +++++++++++++++++++++++++++++
- mt7996/mt7996.h | 1 +
- 2 files changed, 30 insertions(+)
-
-diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 2a5f82da..dff9e467 100644
---- a/mt7996/debugfs.c
-+++ b/mt7996/debugfs.c
-@@ -463,6 +463,9 @@ mt7996_fw_debug_muru_set(void *data)
- } debug;
- int ret;
-
-+ if (dev->fw_debug_muru_disable)
-+ return 0;
-+
- for (debug = DEBUG_BSRP_STATUS; debug <= DEBUG_MEC_UPDATE_AMSDU; debug++) {
- ret = mt7996_mcu_muru_dbg_info(dev, debug,
- dev->fw_debug_bin & BIT(0));
-@@ -907,6 +910,30 @@ static const struct file_operations mt7996_efuse_ops = {
- .llseek = default_llseek,
- };
-
-+static int
-+mt7996_fw_debug_muru_disable_set(void *data, u64 val)
-+{
-+ struct mt7996_dev *dev = data;
-+
-+ dev->fw_debug_muru_disable = !!val;
-+
-+ return 0;
-+}
-+
-+static int
-+mt7996_fw_debug_muru_disable_get(void *data, u64 *val)
-+{
-+ struct mt7996_dev *dev = data;
-+
-+ *val = dev->fw_debug_muru_disable;
-+
-+ return 0;
-+}
-+
-+DEFINE_DEBUGFS_ATTRIBUTE(fops_fw_debug_muru_disable,
-+ mt7996_fw_debug_muru_disable_get,
-+ mt7996_fw_debug_muru_disable_set, "%lld\n");
-+
- int mt7996_init_debugfs(struct mt7996_phy *phy)
- {
- struct mt7996_dev *dev = phy->dev;
-@@ -943,6 +970,8 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
- debugfs_create_devm_seqfile(dev->mt76.dev, "rdd_monitor", dir,
- mt7996_rdd_monitor);
- }
-+ debugfs_create_file("fw_debug_muru_disable", 0600, dir, dev,
-+ &fops_fw_debug_muru_disable);
-
- if (phy == &dev->phy)
- dev->debugfs_dir = dir;
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 95db69ca..2227c08a 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -472,6 +472,7 @@ struct mt7996_dev {
- u8 fw_debug_wa;
- u8 fw_debug_bin;
- u16 fw_debug_seq;
-+ bool fw_debug_muru_disable;
-
- struct dentry *debugfs_dir;
- struct rchan *relay_fwlog;
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2016-mtk-wifi-mt76-mt7996-add-SER-state-log-for-debug.patch b/recipes-wifi/linux-mt76/files/patches-3.x/2016-mtk-wifi-mt76-mt7996-add-SER-state-log-for-debug.patch
deleted file mode 100644
index 62ae0f3..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2016-mtk-wifi-mt76-mt7996-add-SER-state-log-for-debug.patch
+++ /dev/null
@@ -1,28 +0,0 @@
-From 720514e0de2e86d79e4423b824734014c6040e1b Mon Sep 17 00:00:00 2001
-From: Bo Jiao <Bo.Jiao@mediatek.com>
-Date: Mon, 6 Nov 2023 16:37:23 +0800
-Subject: [PATCH 2016/2032] mtk: wifi: mt76: mt7996: add SER state log for
- debug.
-
-Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
----
- mt7996/mac.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 48cb2ac0..912ae650 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -2172,6 +2172,9 @@ void mt7996_coredump(struct mt7996_dev *dev, u8 state)
-
- void mt7996_reset(struct mt7996_dev *dev)
- {
-+ dev_info(dev->mt76.dev, "%s SER recovery state: 0x%08x\n",
-+ wiphy_name(dev->mt76.hw->wiphy), READ_ONCE(dev->recovery.state));
-+
- if (!dev->recovery.hw_init_done)
- return;
-
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/2025-mtk-wifi-mt76-mt7996-Porting-wifi6-txpower-fix-to-ea.patch b/recipes-wifi/linux-mt76/files/patches-3.x/2025-mtk-wifi-mt76-mt7996-Porting-wifi6-txpower-fix-to-ea.patch
deleted file mode 100644
index f1c1890..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/2025-mtk-wifi-mt76-mt7996-Porting-wifi6-txpower-fix-to-ea.patch
+++ /dev/null
@@ -1,470 +0,0 @@
-From 456a6bddcbec9ba8c18648735327542b837dae0d Mon Sep 17 00:00:00 2001
-From: Allen Ye <allen.ye@mediatek.com>
-Date: Thu, 25 Jan 2024 10:57:08 +0800
-Subject: [PATCH 2025/2032] mtk: wifi: mt76: mt7996: Porting wifi6 txpower fix
- to eagle
-
-Refactor txpower flow.
-1. Fix wrong bbp CR address
-2. Ignore RegDB power limit when we have single sku table. And dump more informaiton in debugfs.
-3. Refactor get_txpower ops flow, we only consider CCK and OFDM power value as maximum.
-4. Remove sku_disable due to SQC is over and default enable both sku tables.
-
-
-Fix wrong power value when user set limit close to path table limit.
-
----
- eeprom.c | 20 ++++----
- mt7996/init.c | 14 ++++-
- mt7996/main.c | 11 ++--
- mt7996/mcu.c | 41 ++++++++++++---
- mt7996/mt7996.h | 3 ++
- mt7996/mtk_debugfs.c | 120 ++++++++++++++++++++++++++++---------------
- mt7996/regs.h | 10 ++--
- 7 files changed, 149 insertions(+), 70 deletions(-)
-
-diff --git a/eeprom.c b/eeprom.c
-index adb87924..57b9b769 100644
---- a/eeprom.c
-+++ b/eeprom.c
-@@ -336,9 +336,10 @@ mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data,
- static void
- mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
- const __be32 *data, size_t len, s8 target_power,
-- s8 nss_delta, s8 *max_power)
-+ s8 nss_delta)
- {
- int i, cur;
-+ s8 max_power = -128;
-
- if (!data)
- return;
-@@ -350,7 +351,7 @@ mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
- break;
-
- mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
-- target_power, nss_delta, max_power);
-+ target_power, nss_delta, &max_power);
- if (--cur > 0)
- continue;
-
-@@ -433,17 +434,17 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
- val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1);
- mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
- ARRAY_SIZE(dest->mcs), val, len,
-- target_power, txs_delta, &max_power);
-+ target_power, txs_delta);
-
- val = mt76_get_of_array(np, "rates-ru", &len, ARRAY_SIZE(dest->ru[0]) + 1);
- mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
- ARRAY_SIZE(dest->ru), val, len,
-- target_power, txs_delta, &max_power);
-+ target_power, txs_delta);
-
- val = mt76_get_of_array(np, "rates-eht", &len, ARRAY_SIZE(dest->eht[0]) + 1);
- mt76_apply_multi_array_limit(dest->eht[0], ARRAY_SIZE(dest->eht[0]),
- ARRAY_SIZE(dest->eht), val, len,
-- target_power, txs_delta, &max_power);
-+ target_power, txs_delta);
-
- if (dest_path == NULL)
- return max_power;
-@@ -465,17 +466,14 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
- val = mt76_get_of_array(np, "paths-ru", &len, ARRAY_SIZE(dest_path->ru[0]) + 1);
- mt76_apply_multi_array_limit(dest_path->ru[0], ARRAY_SIZE(dest_path->ru[0]),
- ARRAY_SIZE(dest_path->ru), val, len,
-- target_power_combine, txs_delta, &max_power_backoff);
-+ target_power_combine, txs_delta);
-
- val = mt76_get_of_array(np, "paths-ru-bf", &len, ARRAY_SIZE(dest_path->ru_bf[0]) + 1);
- mt76_apply_multi_array_limit(dest_path->ru_bf[0], ARRAY_SIZE(dest_path->ru_bf[0]),
- ARRAY_SIZE(dest_path->ru_bf), val, len,
-- target_power_combine, txs_delta, &max_power_backoff);
-+ target_power_combine, txs_delta);
-
-- if (max_power_backoff == target_power_combine)
-- return max_power;
--
-- return max_power_backoff;
-+ return max_power;
- }
- EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
-
-diff --git a/mt7996/init.c b/mt7996/init.c
-index 85fedca6..bc8cfdbd 100644
---- a/mt7996/init.c
-+++ b/mt7996/init.c
-@@ -296,7 +296,11 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy,
- int pwr_delta = mt7996_eeprom_get_power_delta(dev, sband->band);
- struct mt76_power_limits limits;
- struct mt76_power_path_limits limits_path;
-+ struct device_node *np;
-
-+ phy->sku_limit_en = true;
-+ phy->sku_path_en = true;
-+ np = mt76_find_power_limits_node(&dev->mt76);
- for (i = 0; i < sband->n_channels; i++) {
- struct ieee80211_channel *chan = &sband->channels[i];
- int target_power = mt7996_eeprom_get_target_power(dev, chan);
-@@ -306,10 +310,16 @@ static void __mt7996_init_txpower(struct mt7996_phy *phy,
- &limits,
- &limits_path,
- target_power);
-+ if (!limits_path.ofdm[0])
-+ phy->sku_path_en = false;
-+
- target_power += nss_delta;
- target_power = DIV_ROUND_UP(target_power, 2);
-- chan->max_power = min_t(int, chan->max_reg_power,
-- target_power);
-+ if (!np)
-+ chan->max_power = min_t(int, chan->max_reg_power,
-+ target_power);
-+ else
-+ chan->max_power = target_power;
- chan->orig_mpwr = target_power;
- }
- }
-diff --git a/mt7996/main.c b/mt7996/main.c
-index 91c06cfb..ca8e6125 100644
---- a/mt7996/main.c
-+++ b/mt7996/main.c
-@@ -84,11 +84,16 @@ int mt7996_run(struct ieee80211_hw *hw)
- phy->sr_enable = true;
- phy->enhanced_sr_enable = true;
- phy->thermal_protection_enable = true;
--
- ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
-- !dev->dbg.sku_disable);
-+ dev->dbg.sku_disable ? 0 : phy->sku_limit_en);
-+
-+ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
-+ dev->dbg.sku_disable ? 0 : phy->sku_path_en);
- #else
-- ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL, true);
-+ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_SKU_POWER_LIMIT_CTRL,
-+ phy->sku_limit_en);
-+ ret = mt7996_mcu_set_tx_power_ctrl(phy, UNI_TXPOWER_BACKOFF_POWER_LIMIT_CTRL,
-+ phy->sku_path_en);
- #endif
- if (ret)
- goto out;
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 6405c2fa..52651693 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -5126,6 +5126,27 @@ int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
- sizeof(req), true);
- }
-
-+static void
-+mt7996_update_max_txpower_cur(struct mt7996_phy *phy, int tx_power)
-+{
-+ struct mt76_phy *mphy = phy->mt76;
-+ struct ieee80211_channel *chan = mphy->main_chan;
-+ int e2p_power_limit = 0;
-+
-+ if (chan == NULL) {
-+ mphy->txpower_cur = tx_power;
-+ return;
-+ }
-+
-+ e2p_power_limit = mt7996_eeprom_get_target_power(phy->dev, chan);
-+ e2p_power_limit += mt7996_eeprom_get_power_delta(phy->dev, chan->band);
-+
-+ if (phy->sku_limit_en)
-+ mphy->txpower_cur = min_t(int, e2p_power_limit, tx_power);
-+ else
-+ mphy->txpower_cur = e2p_power_limit;
-+}
-+
- int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- {
- #define TX_POWER_LIMIT_TABLE_RATE 0
-@@ -5151,12 +5172,20 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- struct mt76_power_limits la = {};
- struct mt76_power_path_limits la_path = {};
- struct sk_buff *skb;
-- int i, ret, tx_power;
-+ int i, ret, txpower_limit;
-+
-+ if (hw->conf.power_level == INT_MIN)
-+ hw->conf.power_level = 127;
-+ txpower_limit = mt7996_get_power_bound(phy, hw->conf.power_level);
-
-- tx_power = mt7996_get_power_bound(phy, hw->conf.power_level);
-- tx_power = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
-- &la, &la_path, tx_power);
-- mphy->txpower_cur = tx_power;
-+ if (phy->sku_limit_en) {
-+ txpower_limit = mt76_get_rate_power_limits(mphy, mphy->chandef.chan,
-+ &la, &la_path, txpower_limit);
-+ mt7996_update_max_txpower_cur(phy, txpower_limit);
-+ } else {
-+ mt7996_update_max_txpower_cur(phy, txpower_limit);
-+ return 0;
-+ }
-
- skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
- sizeof(req) + MT7996_SKU_PATH_NUM);
-@@ -5192,7 +5221,7 @@ int mt7996_mcu_set_txpower_sku(struct mt7996_phy *phy)
- return ret;
-
- /* only set per-path power table when it's configured */
-- if (!la_path.ofdm[0])
-+ if (!phy->sku_path_en)
- return 0;
-
- skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index b5673bdd..f1308112 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -461,6 +461,9 @@ struct mt7996_phy {
-
- u8 muru_onoff;
-
-+ bool sku_limit_en;
-+ bool sku_path_en;
-+
- #ifdef CONFIG_NL80211_TESTMODE
- struct {
- u32 *reg_backup;
-diff --git a/mt7996/mtk_debugfs.c b/mt7996/mtk_debugfs.c
-index 25c21f37..3f82b58c 100644
---- a/mt7996/mtk_debugfs.c
-+++ b/mt7996/mtk_debugfs.c
-@@ -2454,6 +2454,7 @@ mt7996_get_txpower_info(struct file *file, char __user *user_buf,
- struct mt7996_phy *phy = file->private_data;
- struct mt7996_mcu_txpower_event *event;
- struct txpower_basic_info *basic_info;
-+ struct device_node *np;
- static const size_t size = 2048;
- int len = 0;
- ssize_t ret;
-@@ -2510,7 +2511,10 @@ mt7996_get_txpower_info(struct file *file, char __user *user_buf,
- len += scnprintf(buf + len, size - len,
- " Theraml Compensation Value: %d\n",
- basic_info->thermal_compensate_value);
--
-+ np = mt76_find_power_limits_node(phy->mt76->dev);
-+ len += scnprintf(buf + len, size - len,
-+ " RegDB: %s\n",
-+ !np ? "enable" : "disable");
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-
- out:
-@@ -2526,9 +2530,9 @@ static const struct file_operations mt7996_txpower_info_fops = {
- .llseek = default_llseek,
- };
-
--#define mt7996_txpower_puts(rate) \
-+#define mt7996_txpower_puts(rate, _len) \
- ({ \
-- len += scnprintf(buf + len, size - len, "%-21s:", #rate " (TMAC)"); \
-+ len += scnprintf(buf + len, size - len, "%-*s:", _len, #rate " (TMAC)"); \
- for (i = 0; i < mt7996_sku_group_len[SKU_##rate]; i++, offs++) \
- len += scnprintf(buf + len, size - len, " %6d", \
- event->phy_rate_info.frame_power[offs][band_idx]); \
-@@ -2542,9 +2546,15 @@ mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
- struct mt7996_phy *phy = file->private_data;
- struct mt7996_dev *dev = phy->dev;
- struct mt7996_mcu_txpower_event *event;
-+ struct ieee80211_channel *chan = phy->mt76->chandef.chan;
-+ struct ieee80211_supported_band sband;
- u8 band_idx = phy->mt76->band_idx;
- static const size_t size = 5120;
- int i, offs = 0, len = 0;
-+ u32 target_power = 0;
-+ int n_chains = hweight16(phy->mt76->chainmask);
-+ int nss_delta = mt76_tx_power_nss_delta(n_chains);
-+ int pwr_delta;
- ssize_t ret;
- char *buf;
- u32 reg;
-@@ -2566,41 +2576,45 @@ mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
- band_idx, phy->mt76->chandef.chan->hw_value);
- len += scnprintf(buf + len, size - len, "%-21s %6s %6s %6s %6s\n",
- " ", "1m", "2m", "5m", "11m");
-- mt7996_txpower_puts(CCK);
-+ mt7996_txpower_puts(CCK, 21);
-
- len += scnprintf(buf + len, size - len,
- "%-21s %6s %6s %6s %6s %6s %6s %6s %6s\n",
- " ", "6m", "9m", "12m", "18m", "24m", "36m", "48m",
- "54m");
-- mt7996_txpower_puts(OFDM);
-+ mt7996_txpower_puts(OFDM, 21);
-
- len += scnprintf(buf + len, size - len,
- "%-21s %6s %6s %6s %6s %6s %6s %6s %6s\n",
- " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4",
- "mcs5", "mcs6", "mcs7");
-- mt7996_txpower_puts(HT20);
-+ mt7996_txpower_puts(HT20, 21);
-
- len += scnprintf(buf + len, size - len,
- "%-21s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
- " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
- "mcs6", "mcs7", "mcs32");
-- mt7996_txpower_puts(HT40);
-+ mt7996_txpower_puts(HT40, 21);
-
- len += scnprintf(buf + len, size - len,
- "%-21s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s %6s\n",
- " ", "mcs0", "mcs1", "mcs2", "mcs3", "mcs4", "mcs5",
- "mcs6", "mcs7", "mcs8", "mcs9", "mcs10", "mcs11");
-- mt7996_txpower_puts(VHT20);
-- mt7996_txpower_puts(VHT40);
-- mt7996_txpower_puts(VHT80);
-- mt7996_txpower_puts(VHT160);
-- mt7996_txpower_puts(HE26);
-- mt7996_txpower_puts(HE52);
-- mt7996_txpower_puts(HE106);
-- mt7996_txpower_puts(HE242);
-- mt7996_txpower_puts(HE484);
-- mt7996_txpower_puts(HE996);
-- mt7996_txpower_puts(HE2x996);
-+ mt7996_txpower_puts(VHT20, 21);
-+ mt7996_txpower_puts(VHT40, 21);
-+ mt7996_txpower_puts(VHT80, 21);
-+ mt7996_txpower_puts(VHT160, 21);
-+ mt7996_txpower_puts(HE26, 21);
-+ mt7996_txpower_puts(HE52, 21);
-+ mt7996_txpower_puts(HE106, 21);
-+ len += scnprintf(buf + len, size - len, "BW20/");
-+ mt7996_txpower_puts(HE242, 16);
-+ len += scnprintf(buf + len, size - len, "BW40/");
-+ mt7996_txpower_puts(HE484, 16);
-+ len += scnprintf(buf + len, size - len, "BW80/");
-+ mt7996_txpower_puts(HE996, 16);
-+ len += scnprintf(buf + len, size - len, "BW160/");
-+ mt7996_txpower_puts(HE2x996, 15);
-
- len += scnprintf(buf + len, size - len,
- "%-21s %6s %6s %6s %6s %6s %6s %6s %6s ",
-@@ -2608,22 +2622,27 @@ mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
- len += scnprintf(buf + len, size - len,
- "%6s %6s %6s %6s %6s %6s %6s %6s\n",
- "mcs8", "mcs9", "mcs10", "mcs11", "mcs12", "mcs13", "mcs14", "mcs15");
-- mt7996_txpower_puts(EHT26);
-- mt7996_txpower_puts(EHT52);
-- mt7996_txpower_puts(EHT106);
-- mt7996_txpower_puts(EHT242);
-- mt7996_txpower_puts(EHT484);
-- mt7996_txpower_puts(EHT996);
-- mt7996_txpower_puts(EHT2x996);
-- mt7996_txpower_puts(EHT4x996);
-- mt7996_txpower_puts(EHT26_52);
-- mt7996_txpower_puts(EHT26_106);
-- mt7996_txpower_puts(EHT484_242);
-- mt7996_txpower_puts(EHT996_484);
-- mt7996_txpower_puts(EHT996_484_242);
-- mt7996_txpower_puts(EHT2x996_484);
-- mt7996_txpower_puts(EHT3x996);
-- mt7996_txpower_puts(EHT3x996_484);
-+ mt7996_txpower_puts(EHT26, 21);
-+ mt7996_txpower_puts(EHT52, 21);
-+ mt7996_txpower_puts(EHT106, 21);
-+ len += scnprintf(buf + len, size - len, "BW20/");
-+ mt7996_txpower_puts(EHT242, 16);
-+ len += scnprintf(buf + len, size - len, "BW40/");
-+ mt7996_txpower_puts(EHT484, 16);
-+ len += scnprintf(buf + len, size - len, "BW80/");
-+ mt7996_txpower_puts(EHT996, 16);
-+ len += scnprintf(buf + len, size - len, "BW160/");
-+ mt7996_txpower_puts(EHT2x996, 15);
-+ len += scnprintf(buf + len, size - len, "BW320/");
-+ mt7996_txpower_puts(EHT4x996, 15);
-+ mt7996_txpower_puts(EHT26_52, 21);
-+ mt7996_txpower_puts(EHT26_106, 21);
-+ mt7996_txpower_puts(EHT484_242, 21);
-+ mt7996_txpower_puts(EHT996_484, 21);
-+ mt7996_txpower_puts(EHT996_484_242, 21);
-+ mt7996_txpower_puts(EHT2x996_484, 21);
-+ mt7996_txpower_puts(EHT3x996, 21);
-+ mt7996_txpower_puts(EHT3x996_484, 21);
-
- len += scnprintf(buf + len, size - len, "\nePA Gain: %d\n",
- event->phy_rate_info.epa_gain);
-@@ -2632,16 +2651,33 @@ mt7996_get_txpower_sku(struct file *file, char __user *user_buf,
- len += scnprintf(buf + len, size - len, "Min Power Bound: %d\n",
- event->phy_rate_info.min_power_bound);
-
-- reg = MT_WF_PHYDFE_BAND_TPC_CTRL_STAT0(band_idx);
-+ reg = MT_WF_PHYDFE_TSSI_TXCTRL01(band_idx);
- len += scnprintf(buf + len, size - len,
-- "BBP TX Power (target power from TMAC) : %6ld [0.5 dBm]\n",
-- mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_TMAC));
-+ "\nBBP TX Power (target power from TMAC) : %6ld [0.5 dBm]\n",
-+ mt76_get_field(dev, reg, MT_WF_PHYDFE_TSSI_TXCTRL_POWER_TMAC));
- len += scnprintf(buf + len, size - len,
-- "BBP TX Power (target power from RMAC) : %6ld [0.5 dBm]\n",
-- mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_RMAC));
-+ "RegDB maximum power:\t%d [dBm]\n",
-+ chan->max_reg_power);
-+
-+ if (chan->band == NL80211_BAND_2GHZ)
-+ sband = phy->mt76->sband_2g.sband;
-+ else if (chan->band == NL80211_BAND_5GHZ)
-+ sband = phy->mt76->sband_5g.sband;
-+ else if (chan->band == NL80211_BAND_6GHZ)
-+ sband = phy->mt76->sband_6g.sband;
-+
-+ pwr_delta = mt7996_eeprom_get_power_delta(dev, sband.band);
-+
-+ target_power = max_t(u32, target_power, mt7996_eeprom_get_target_power(dev, chan));
-+ target_power += pwr_delta + nss_delta;
-+ target_power = DIV_ROUND_UP(target_power, 2);
-+ len += scnprintf(buf + len, size - len,
-+ "eeprom maximum power:\t%d [dBm]\n",
-+ target_power);
-+
- len += scnprintf(buf + len, size - len,
-- "BBP TX Power (TSSI module power input) : %6ld [0.5 dBm]\n",
-- mt76_get_field(dev, reg, MT_WF_PHY_TPC_POWER_TSSI));
-+ "nss_delta:\t%d [0.5 dBm]\n",
-+ nss_delta);
-
- ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
-
-@@ -2660,7 +2696,7 @@ static const struct file_operations mt7996_txpower_sku_fops = {
-
- #define mt7996_txpower_path_puts(rate, arr_length) \
- ({ \
-- len += scnprintf(buf + len, size - len, "%-23s:", #rate " (TMAC)"); \
-+ len += scnprintf(buf + len, size - len, "%23s:", #rate " (TMAC)"); \
- for (i = 0; i < arr_length; i++, offs++) \
- len += scnprintf(buf + len, size - len, " %4d", \
- event->backoff_table_info.frame_power[offs]); \
-diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 050637c1..a0e4b3e1 100644
---- a/mt7996/regs.h
-+++ b/mt7996/regs.h
-@@ -718,6 +718,10 @@ enum offs_rev {
- ((_wf) << 16) + (ofs))
- #define MT_WF_PHYRX_CSD_IRPI(_band, _wf) MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
-
-+/* PHYDFE CTRL */
-+#define MT_WF_PHYDFE_TSSI_TXCTRL01(_band) MT_WF_PHYRX_CSD(_band, 0, 0xc718)
-+#define MT_WF_PHYDFE_TSSI_TXCTRL_POWER_TMAC GENMASK(31, 24)
-+
- /* PHY CTRL */
- #define MT_WF_PHY_BAND_BASE 0x83080000
- #define MT_WF_PHY_BAND(_band, ofs) (MT_WF_PHY_BAND_BASE + \
-@@ -735,12 +739,6 @@ enum offs_rev {
- #define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN GENMASK(2, 0)
- #define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN GENMASK(11, 9)
-
--/* PHYDFE CTRL */
--#define MT_WF_PHYDFE_BAND_TPC_CTRL_STAT0(_phy) MT_WF_PHY_BAND(_phy, 0xe7a0)
--#define MT_WF_PHY_TPC_POWER_TMAC GENMASK(15, 8)
--#define MT_WF_PHY_TPC_POWER_RMAC GENMASK(23, 16)
--#define MT_WF_PHY_TPC_POWER_TSSI GENMASK(31, 24)
--
- /* PHYRX CSD BAND */
- #define MT_WF_PHYRX_CSD_BAND_RXTD12(_band) MT_WF_PHY_BAND(_band, 0x8230)
- #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY BIT(18)
---
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc b/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
index 38d3c2c..4764a18 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
@@ -1,94 +1,119 @@
#patch patches (come from openwrt/lede/target/linux/mediatek)
SRC_URI_append = " \
file://0001-mtk-Revert-wifi-mt76-mt7996-fill-txd-by-host-driver.patch \
- file://0002-mtk-wifi-mt76-connac-use-peer-address-for-station-BM.patch \
- file://0003-mtk-wifi-mt76-mt7996-disable-rx-header-translation-f.patch \
- file://0004-mtk-wifi-mt76-mt7996-set-RCPI-value-in-rate-control-.patch \
- file://0005-mtk-wifi-mt76-mt7996-enable-hw-cso-module.patch \
- file://0006-mtk-wifi-mt76-mt7996-fix-non-main-BSS-no-beacon-issu.patch \
- file://0007-mtk-wifi-mt76-mt7996-initialize-variable-to-avoid-un.patch \
- file://0008-mtk-wifi-mt76-mt7996-enable-ser-query.patch \
- file://0009-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch \
- file://0010-mtk-wifi-mt76-mt7996-add-eagle-default-bin-of-differ.patch \
- file://0011-mtk-wifi-mt76-mt7996-add-kite-fw-default-bin-for-dif.patch \
- file://0012-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch \
- file://0013-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch \
- file://0014-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch \
- file://0015-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch \
- file://0016-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch \
- file://0017-mtk-wifi-mt76-mt7996-add-sanity-check-for-NAPI-sched.patch \
- file://0999-mtk-wifi-mt76-mt7996-for-build-pass.patch \
- file://1000-mtk-wifi-mt76-mt7996-add-debug-tool.patch \
- file://1001-mtk-wifi-mt76-mt7996-support-record-muru-algo-log-wh.patch \
- file://1002-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch \
- file://1003-mtk-wifi-mt76-testmode-add-atenl-support-in-mt7996.patch \
- file://1004-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch \
- file://1005-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch \
- file://1006-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch \
- file://1007-mtk-wifi-mt76-mt7996-add-txpower-support.patch \
- file://1008-mtk-wifi-mt76-mt7996-add-single-sku.patch \
- file://1009-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch \
- file://1010-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch \
- file://1011-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch \
- file://1012-mtk-wifi-mt76-mt7996-add-mu-vendor-command-support.patch \
- file://1013-mtk-wifi-mt76-mt7996-Add-air-monitor-support.patch \
- file://1014-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch \
- file://1015-mtk-wifi-mt76-mt7996-add-vendor-cmd-to-get-available.patch \
- file://1016-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch \
- file://1017-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch \
- file://1018-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch \
- file://1019-mtk-wifi-mt76-mt7996-add-vendor-subcmd-EDCCA-ctrl-en.patch \
- file://1020-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch \
- file://1021-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch \
- file://1022-mtk-wifi-mt76-mt7996-add-eagle-iFEM-HWITS-ZWDFS-SW-w.patch \
- file://1023-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch \
- file://1024-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch \
- file://1025-mtk-wifi-mt76-mt7996-add-ibf-control-vendor-cmd.patch \
- file://1026-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch \
- file://1027-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch \
- file://1028-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch \
- file://1029-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch \
- file://1030-mtk-wifi-mt76-mt7996-add-three-wire-pta-support.patch \
- file://1031-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch \
- file://1032-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch \
- file://1033-mtk-wifi-mt76-mt7996-add-cert-patch.patch \
- file://1034-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch \
- file://1035-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch \
- file://1036-mtk-wifi-mt76-testmode-add-channel-68-96.patch \
- file://1037-mtk-wifi-mt76-mt7996-support-enable-disable-pp-featu.patch \
- file://1038-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch \
- file://1039-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch \
- file://1040-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch \
- file://1041-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch \
- file://1042-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch \
- file://1043-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch \
- file://1044-mtk-wifi-mt76-mt7996-support-disable-muru-debug-info.patch \
- file://2000-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch \
- file://2001-mtk-wifi-mt76-rework-wed-rx-flow.patch \
- file://2002-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch \
- file://2003-mtk-wifi-mt76-add-random-early-drop-support.patch \
- file://2004-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch \
- file://2005-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch \
- file://2006-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch \
- file://2007-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch \
- file://2008-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch \
- file://2009-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch \
- file://2010-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch \
- file://2011-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch \
- file://2012-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch \
- file://2013-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch \
- file://2014-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch \
- file://2015-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch \
- file://2016-mtk-wifi-mt76-mt7996-add-SER-state-log-for-debug.patch \
- file://2017-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch \
- file://2018-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch \
- file://2019-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch \
- file://2020-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch \
- file://2021-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch \
- file://2022-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch \
- file://2023-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch \
- file://2024-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch \
- file://2025-mtk-wifi-mt76-mt7996-Porting-wifi6-txpower-fix-to-ea.patch \
- file://2026-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch \
- file://2027-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch \
+ file://0002-bp-sync-upstream-changes.patch \
+ file://0003-mtk-wifi-mt76-mt7996-let-upper-layer-handle-MGMT-fra.patch \
+ file://0004-wifi-mt76-mt7996-use-hweight16-to-get-correct-tx_ant.patch \
+ file://0005-mtk-wifi-mt76-mt7996-fix-MBSS.patch \
+ file://0006-wifi-mt76-mt7996-fix-HE-and-EHT-phy-cap.patch \
+ file://0007-mtk-wifi-mt76-mt7996-adjust-Beamformee-SS-capability.patch \
+ file://0008-wifi-mt76-mt7992-adjust-beamform-mcu-cmd-configurati.patch \
+ file://0009-mtk-wifi-mt76-mt7996-add-preamble-puncture-support-f.patch \
+ file://0010-mtk-wifi-mt76-mt7996-add-driver-support-for-wpa3-ocv.patch \
+ file://0011-mtk-wifi-mt76-mt7996-enable-ser-query.patch \
+ file://0012-mtk-wifi-mt76-mt7996-set-key-flag-IEEE80211_KEY_FLAG.patch \
+ file://0013-mtk-wifi-mt76-mt7996-Fix-TGax-HE-4.51.1_24G-fail.patch \
+ file://0014-mtk-wifi-mt76-mt7996-add-support-for-different-varia.patch \
+ file://0015-mtk-wifi-mt76-mt7996-ACS-channel-time-too-long-on-du.patch \
+ file://0016-mtk-wifi-mt76-mt7996-Fixed-null-pointer-dereference-.patch \
+ file://0017-mtk-wifi-mt76-add-sanity-check-to-prevent-kernel-cra.patch \
+ file://0018-mtk-wifi-mt76-mt7996-add-firmware-WA-s-coredump.patch \
+ file://0019-mtk-wifi-mt76-mt7996-for-build-pass.patch \
+ file://0020-mtk-wifi-mt76-mt7996-add-debug-tool.patch \
+ file://0021-mtk-wifi-mt76-mt7996-add-check-for-hostapd-config-he.patch \
+ file://0022-mtk-wifi-mt76-testmode-add-basic-testmode-support.patch \
+ file://0023-mtk-wifi-mt76-testmode-add-testmode-pre-calibration-.patch \
+ file://0024-mtk-wifi-mt76-mt7996-add-normal-mode-pre-calibration.patch \
+ file://0025-mtk-wifi-mt76-mt7996-enable-SCS-feature-for-mt7996-d.patch \
+ file://0026-mtk-wifi-mt76-mt7996-add-txpower-support.patch \
+ file://0027-mtk-wifi-mt76-mt7996-add-binfile-mode-support.patch \
+ file://0028-mtk-wifi-mt76-testmode-add-testmode-ZWDFS-verificati.patch \
+ file://0029-mtk-wifi-mt76-mt7996-support-eagle-ZWDFS-on-iFEM.patch \
+ file://0030-mtk-wifi-mt76-mt7996-refactor-eeprom-loading-flow-fo.patch \
+ file://0031-mtk-wifi-mt76-mt7996-add-vendor-commands-support.patch \
+ file://0032-mtk-wifi-mt76-mt7996-add-debugfs-for-fw-coredump.patch \
+ file://0033-mtk-wifi-mt76-mt7996-Add-mt7992-coredump-support.patch \
+ file://0034-mtk-wifi-mt76-mt7996-add-support-for-runtime-set-in-.patch \
+ file://0035-mtk-wifi-mt76-mt7996-add-support-spatial-reuse-debug.patch \
+ file://0036-mtk-wifi-mt76-mt7996-Establish-BA-in-VO-queue.patch \
+ file://0037-mtk-wifi-mt76-mt7996-report-tx-and-rx-byte-to-tpt_le.patch \
+ file://0038-mtk-wifi-mt76-mt7996-support-dup-wtbl.patch \
+ file://0039-mtk-wifi-mt76-try-more-times-when-send-message-timeo.patch \
+ file://0040-mtk-wifi-mt76-mt7996-add-SER-overlap-handle.patch \
+ file://0041-mtk-wifi-mt76-mt7996-kite-default-1-pcie-setting.patch \
+ file://0042-mtk-wifi-mt76-mt7996-add-debugfs-knob-for-rx_counter.patch \
+ file://0043-mtk-wifi-mt76-mt7996-support-BF-MIMO-debug-commands.patch \
+ file://0044-mtk-wifi-mt76-mt7996-add-build-the-following-MURU-mc.patch \
+ file://0045-mtk-wifi-mt76-mt7996-add-cert-patch.patch \
+ file://0046-mtk-wifi-mt76-testmode-add-testmode-bf-support.patch \
+ file://0047-mtk-wifi-mt76-mt7996-add-zwdfs-cert-mode.patch \
+ file://0048-mtk-wifi-mt76-testmode-add-channel-68-96.patch \
+ file://0049-mtk-wifi-mt76-testmode-add-kite-testmode-support.patch \
+ file://0050-mtk-wifi-mt76-mt7996-assign-DEAUTH-to-ALTX-queue-for.patch \
+ file://0051-mtk-wifi-mt76-mt7996-add-no_beacon-vendor-command-fo.patch \
+ file://0052-mtk-wifi-mt76-mt7996-add-adie-efuse-merge-support.patch \
+ file://0053-mtk-wifi-mt7996-add-Eagle-2adie-TBTC-BE14000-support.patch \
+ file://0054-mtk-wifi-mt76-mt7996-add-background-radar-hw-cap-che.patch \
+ file://0055-mtk-wifi-mt76-mt7996-add-fallback-in-case-of-missing.patch \
+ file://0056-mtk-wifi-mt76-mt7996-add-kite-part-number-support.patch \
+ file://0057-mtk-wifi-mt76-revert-page_poll-for-kernel-5.4.patch \
+ file://0058-mtk-wifi-mt76-rework-wed-rx-flow.patch \
+ file://0059-mtk-wifi-mt76-wed-change-wed-token-init-size-to-adap.patch \
+ file://0060-mtk-wifi-mt76-add-random-early-drop-support.patch \
+ file://0061-mtk-wifi-mt76-mt7996-reset-addr_elem-when-delete-ba.patch \
+ file://0062-mtk-wifi-mt76-wed-change-pcie0-R5-to-pcie1-to-get-6G.patch \
+ file://0063-mtk-wifi-mt76-add-SER-support-for-wed3.0.patch \
+ file://0064-mtk-wifi-mt76-mt7915-wed-find-rx-token-by-physical-a.patch \
+ file://0065-mtk-wifi-mt76-mt7996-add-dma-mask-limitation.patch \
+ file://0066-mtk-wifi-mt76-mt7996-add-per-bss-statistic-info.patch \
+ file://0067-mtk-wifi-mt76-mt7996-do-not-report-netdev-stats-on-m.patch \
+ file://0068-mtk-wifi-mt76-mt7996-add-support-for-HW-ATF.patch \
+ file://0069-mtk-wifi-mt76-mt7996-wed-add-SER0.5-support-w-wed3.0.patch \
+ file://0070-mtk-wifi-mt76-mt7996-support-backaward-compatiable.patch \
+ file://0071-mtk-wifi-mt76-mt7996-wed-add-wed-support-for-mt7992.patch \
+ file://0072-mtk-wifi-mt76-mt7992-wed-add-2pcie-one-wed-support.patch \
+ file://0073-mtk-wifi-mt76-mt7996-Remove-wed-rro-ring-add-napi-at.patch \
+ file://0074-mtk-wifi-mt76-mt7996-Remove-wed_stop-during-L1-SER.patch \
+ file://0075-mtk-wifi-mt76-mt7996-Refactor-rro-del-ba-command-for.patch \
+ file://0076-mtk-wifi-mt76-mt7996-get-airtime-and-RSSI-via-MCU-co.patch \
+ file://0077-mtk-wifi-mt76-mt7996-add-support-for-WMM-PBC-configu.patch \
+ file://0078-mtk-wifi-mt76-mt7996-eagle-support-extra-option_type.patch \
+ file://0079-mtk-wifi-mt76-mt7996-support-enable-disable-thermal-.patch \
+ file://0080-mtk-wifi-mt76-mt7996-support-thermal-recal-debug-com.patch \
+ file://0081-mtk-wifi-mt76-mt7996-add-kite-two-pcie-with-two-wed-.patch \
+ file://0082-mtk-wifi-mt76-mt7992-add-support-to-enable-index-FW-.patch \
+ file://0083-wifi-mt76-mt7996-implement-and-switch-to-hw-scan-cal.patch \
+ file://0084-wifi-mt76-mt7996-implement-and-switch-to-chanctx-cal.patch \
+ file://0085-wifi-mt76-mt7996-use-.sta_state-to-replace-.sta_add-.patch \
+ file://0086-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch \
+ file://0087-wifi-mt76-mt7996-switch-to-per-link-data-structure-o.patch \
+ file://0088-wifi-mt76-extend-wcid-and-sta-flow-for-MLO-support.patch \
+ file://0089-wifi-mt76-mt7996-enable-MLO-capability.patch \
+ file://0090-wifi-mt76-mt7996-support-multi-link-vif-links-and-ML.patch \
+ file://0091-wifi-mt76-mt7996-support-multi-link-sta-links-and-ML.patch \
+ file://0092-wifi-mt76-mt7996-introduce-mt7996_band_phy-for-ch-ba.patch \
+ file://0093-wifi-mt76-mt7996-rework-ieee80211_ops-callbacks-for-.patch \
+ file://0094-wifi-mt76-mt7996-rework-TXD-for-multi-link-support.patch \
+ file://0095-wifi-mt76-mt7996-rework-TXS-for-multi-link-support.patch \
+ file://0096-wifi-mt76-mt7996-rework-RXD-for-multi-link-support.patch \
+ file://0097-wifi-mt76-mt7996-rework-mac-functions-for-multi-link.patch \
+ file://0098-wifi-mt76-connac-rework-mcu-functions-for-multi-link.patch \
+ file://0099-wifi-mt76-connac-rework-connac-helpers.patch \
+ file://0100-wifi-mt76-mt7996-handle-mapping-for-hw-and-phy.patch \
+ file://0101-wifi-mt76-mt7996-handle-mapping-for-hw-and-vif.patch \
+ file://0102-wifi-mt76-mt7996-rework-scanning-parts-for-MLD-STA-s.patch \
+ file://0103-wifi-mt76-mt7996-implement-mld-address-translation.patch \
+ file://0104-wifi-mt76-mt7996-use-BSS_CHANGED_TXPOWER-for-txpower.patch \
+ file://0105-wifi-mt76-mt7996-temp-support-for-single-wiphy.patch \
+ file://0106-wifi-mt76-mt7996-implement-ieee80211_ops-for-link-de.patch \
+ file://0107-mtk-wifi-mt76-mt7996-support-multi-link-channel-swit.patch \
+ file://0108-mtk-mt76-mt7996-hw_scan-ACS-channel-time-too-long-on.patch \
+ file://0109-wifi-mt76-mt7996-add-beacon-monitoring-in-driver-for.patch \
+ file://0110-mtk-wifi-mt76-mt7996-support-band_idx-option-for-set.patch \
+ file://0111-mtk-wifi-mt76-mt7996-tmp-disable-VOW.patch \
+ file://0112-mtk-wifi-mt76-mt7996-enable-ampdu-limit-to-avoid-BA-.patch \
+ file://0113-wifi-mt76-mt7996-Fix-get_txpower-wrong-result-in-sin.patch \
+ file://0114-mtk-wifi-mt76-mt7996-add-beacon_int_min_gcd-to-suppo.patch \
+ file://0115-mtk-wifi-mt76-mt7996-Add-connac3-csi-feature.patch \
+ file://0116-mtk-wifi-mt76-mt7996-add-more-debug-info-for-MLO.patch \
"
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7915_rom_patch.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7915_rom_patch.bin
index 87ad985..10d3d8f 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7915_rom_patch.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7915_rom_patch.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wa.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wa.bin
index 16af788..83b635b 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wa.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wa.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wm.bin
index a2c95da..d09cce2 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7915_wm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7916_rom_patch.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7916_rom_patch.bin
index a145348..fee3cd8 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7916_rom_patch.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7916_rom_patch.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wa.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wa.bin
index fe19921..b6ddf15 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wa.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wa.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wm.bin
index 6c0ecdb..c7162db 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7916_wm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_rom_patch.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_rom_patch.bin
index 0f956b4..34c821e 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_rom_patch.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_rom_patch.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wa.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wa.bin
index 75dba3c..fd2fc49 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wa.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wa.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wm.bin
index a526bdd..8288120 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo.bin
index aaf9865..4f807ba 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo_0.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo_0.bin
deleted file mode 100644
index 799ad67..0000000
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7981_wo_0.bin
+++ /dev/null
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch.bin
index d0f1844..0c285b4 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin
index b40b936..8271633 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_rom_patch_mt7975.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wa.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wa.bin
index ae937a8..867a764 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wa.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wa.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm.bin
index da731ad..5561f9f 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin
index 5664006..c6efce6 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wm_mt7975.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_0.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_0.bin
index 91d591f..d2a7674 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_0.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_0.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_1.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_1.bin
index 508e6a4..f067ac3 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_1.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7986_wo_1.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp.bin
index 1f01751..3203f47 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_23.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_23.bin
index f277232..6bb8783 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_23.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_23.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_24.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_24.bin
index 1d128b7..0ee44c4 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_24.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_dsp_24.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch.bin
index 31d86e1..62b15ff 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_23.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_23.bin
index cf61154..c6127eb 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_23.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_23.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_24.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_24.bin
index 50d3a2e..556abce 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_24.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_rom_patch_24.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa.bin
index 27c7c00..0ddfc82 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_23.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_23.bin
index f62759a..54c9f8d 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_23.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_23.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_24.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_24.bin
index f37af42..cee6d27 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_24.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wa_24.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm.bin
index b3b3529..ca62f15 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_23.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_23.bin
index 6623ad1..f645c9b 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_23.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_23.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_24.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_24.bin
index 7700262..f2b68ec 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_24.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_24.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm.bin
index 74ade16..66cc70b 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_23.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_23.bin
index 04a3139..5643c9a 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_23.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_23.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_24.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_24.bin
index b1f5bad..f4a2305 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_24.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7992_wm_tm_24.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_dsp.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_dsp.bin
index d30bb8b..e9765d9 100755
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_dsp.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_dsp.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_eeprom_2i5i6i.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_eeprom_2i5i6i.bin
new file mode 100644
index 0000000..5ad238a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_eeprom_2i5i6i.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch.bin
index 6952a7f..524024f 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch_233.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch_233.bin
index cdba71d..17a1475 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch_233.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_rom_patch_233.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa.bin
index e376241..3e04fe1 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa_233.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa_233.bin
index 1e54cfc..bf1ff57 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa_233.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wa_233.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm.bin
index 84f59d7..c26be71 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_233.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_233.bin
index 232949e..c685756 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_233.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_233.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm.bin
index b9766ec..e275cbb 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm_233.bin b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm_233.bin
index 074de8c..04a5951 100644
--- a/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm_233.bin
+++ b/recipes-wifi/linux-mt76/files/src/firmware/mt7996/mt7996_wm_tm_233.bin
Binary files differ
diff --git a/recipes-wifi/linux-mt76/linux-mt76_3.x.bb b/recipes-wifi/linux-mt76/linux-mt76_3.x.bb
index 92c37fa..223e7fa 100644
--- a/recipes-wifi/linux-mt76/linux-mt76_3.x.bb
+++ b/recipes-wifi/linux-mt76/linux-mt76_3.x.bb
@@ -5,7 +5,7 @@
inherit module
-require mt76-3x.inc
+require mt76.inc
SRC_URI = " \
git://git@github.com/openwrt/mt76.git;protocol=https;branch=master \
file://COPYING;subdir=git \
diff --git a/recipes-wifi/linux-mt76/mt76-3x.inc b/recipes-wifi/linux-mt76/mt76-3x.inc
deleted file mode 100644
index 3cee0cc..0000000
--- a/recipes-wifi/linux-mt76/mt76-3x.inc
+++ /dev/null
@@ -1 +0,0 @@
-SRCREV_mt7988 = "2135e201e7a9339e018d4e2d4a33c73266e674d7"
diff --git a/recipes-wifi/linux-mt76/mt76-test.bb b/recipes-wifi/linux-mt76/mt76-test.bb
index b84adb4..853e974 100644
--- a/recipes-wifi/linux-mt76/mt76-test.bb
+++ b/recipes-wifi/linux-mt76/mt76-test.bb
@@ -10,7 +10,6 @@
PV = "1.0"
require mt76.inc
-require mt76-3x.inc
SRC_URI = " \
git://git@github.com/openwrt/mt76.git;protocol=https \