[rdkb][common][bsp][Refactor and sync wifi from openwrt]
[Description]
a0c7684 [MAC80211][mt76][update mt76 patches]
a2e0f7c [MAC80211][core][Remove start disabled patch in eagle]
4562ef0 [MAC80211][hostapd][Refactor hostapd patch for git am]
22614f8 [mt76][Add vendor cmd to get available color bitmap]
b7b4fef [mac80211][Track obss color bitmap]
3f4ab41 [hostapd][Add hostapd_cli cmd to get available color bitmap]
cb120e7 [MAC80211][core][remove ba timer disabled patches]
24f983f [MAC80211][misc][sync iproute2 package]
3e866ee [MAC80211][core][Mark DFS channel available for CSA]
bdc6428 [MAC80211][hostapd][Mark DFS channel available for CSA]
9113e92 [MAC80211][app][Add eagle testmode iwpriv wrapper support]
d6bd8f4 [mac80211][mt76][Refactor mt76 patches]
7829a83 [MAC80211][mt76][Add monitor vif check in testmode]
19ead62 [mt76][eagle][hostapd mbssid and ema support]
[Release-log]
Change-Id: I75bf6ff01bc50054404bca23fd31cff9d1bc8d86
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch
deleted file mode 100644
index 44a01ec..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch
+++ /dev/null
@@ -1,249 +0,0 @@
-diff --git a/eeprom.c b/eeprom.c
-index 0a88048b..ea54b7af 100644
---- a/eeprom.c
-+++ b/eeprom.c
-@@ -138,6 +138,7 @@ mt76_find_power_limits_node(struct mt76_dev *dev)
- {
- struct device_node *np = dev->dev->of_node;
- const char *const region_names[] = {
-+ [NL80211_DFS_UNSET] = "ww",
- [NL80211_DFS_ETSI] = "etsi",
- [NL80211_DFS_FCC] = "fcc",
- [NL80211_DFS_JP] = "jp",
-diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index 614df85e..aed4ee95 100644
---- a/mt76_connac_mac.c
-+++ b/mt76_connac_mac.c
-@@ -823,7 +823,6 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
- HE_BITS(DATA2_TXOP_KNOWN),
- };
- u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
-- u32 txbf_mask = is_mt7996(dev) ? BIT(11) : BIT(10);
- struct ieee80211_radiotap_he *he;
-
- status->flag |= RX_FLAG_RADIOTAP_HE;
-@@ -837,7 +836,7 @@ void mt76_connac2_mac_decode_he_radiotap(struct mt76_dev *dev,
- he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
- le16_encode_bits(ltf_size,
- IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
-- if (le32_to_cpu(rxv[0]) & txbf_mask)
-+ if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
- he->data5 |= HE_BITS(DATA5_TXBF);
- he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
- HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
-diff --git a/mt76x0/usb_mcu.c b/mt76x0/usb_mcu.c
-index 45502fd4..6dc1f51f 100644
---- a/mt76x0/usb_mcu.c
-+++ b/mt76x0/usb_mcu.c
-@@ -148,6 +148,7 @@ static int mt76x0u_load_firmware(struct mt76x02_dev *dev)
- mt76_wr(dev, MT_USB_DMA_CFG, val);
-
- ret = mt76x0u_upload_firmware(dev, hdr);
-+ mt76x02_set_ethtool_fwver(dev, hdr);
- release_firmware(fw);
-
- mt76_wr(dev, MT_FCE_PSE_CTRL, 1);
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 674cea1a..c9a9f0e3 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -12,6 +12,10 @@
-
- #define to_rssi(field, rcpi) ((FIELD_GET(field, rcpi) - 220) / 2)
-
-+#define HE_BITS(f) cpu_to_le16(IEEE80211_RADIOTAP_HE_##f)
-+#define HE_PREP(f, m, v) le16_encode_bits(le32_get_bits(v, MT_CRXV_HE_##m),\
-+ IEEE80211_RADIOTAP_HE_##f)
-+
- static const struct mt7996_dfs_radar_spec etsi_radar_specs = {
- .pulse_th = { 110, -10, -80, 40, 5200, 128, 5200 },
- .radar_pattern = {
-@@ -251,6 +255,178 @@ void mt7996_mac_enable_rtscts(struct mt7996_dev *dev,
- mt76_clear(dev, addr, BIT(5));
- }
-
-+static void
-+mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
-+ struct ieee80211_radiotap_he *he,
-+ __le32 *rxv)
-+{
-+ u32 ru_h, ru_l;
-+ u8 ru, offs = 0;
-+
-+ ru_l = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC_L);
-+ ru_h = le32_get_bits(rxv[1], MT_PRXV_HE_RU_ALLOC_H);
-+ ru = (u8)(ru_l | ru_h << 4);
-+
-+ status->bw = RATE_INFO_BW_HE_RU;
-+
-+ switch (ru) {
-+ case 0 ... 36:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_26;
-+ offs = ru;
-+ break;
-+ case 37 ... 52:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_52;
-+ offs = ru - 37;
-+ break;
-+ case 53 ... 60:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_106;
-+ offs = ru - 53;
-+ break;
-+ case 61 ... 64:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_242;
-+ offs = ru - 61;
-+ break;
-+ case 65 ... 66:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_484;
-+ offs = ru - 65;
-+ break;
-+ case 67:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_996;
-+ break;
-+ case 68:
-+ status->he_ru = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
-+ break;
-+ }
-+
-+ he->data1 |= HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-+ he->data2 |= HE_BITS(DATA2_RU_OFFSET_KNOWN) |
-+ le16_encode_bits(offs,
-+ IEEE80211_RADIOTAP_HE_DATA2_RU_OFFSET);
-+}
-+
-+static void
-+mt7996_mac_decode_he_mu_radiotap(struct sk_buff *skb, __le32 *rxv)
-+{
-+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
-+ static const struct ieee80211_radiotap_he_mu mu_known = {
-+ .flags1 = HE_BITS(MU_FLAGS1_SIG_B_MCS_KNOWN) |
-+ HE_BITS(MU_FLAGS1_SIG_B_DCM_KNOWN) |
-+ HE_BITS(MU_FLAGS1_CH1_RU_KNOWN) |
-+ HE_BITS(MU_FLAGS1_SIG_B_SYMS_USERS_KNOWN),
-+ .flags2 = HE_BITS(MU_FLAGS2_BW_FROM_SIG_A_BW_KNOWN),
-+ };
-+ struct ieee80211_radiotap_he_mu *he_mu = NULL;
-+
-+ status->flag |= RX_FLAG_RADIOTAP_HE_MU;
-+
-+ he_mu = skb_push(skb, sizeof(mu_known));
-+ memcpy(he_mu, &mu_known, sizeof(mu_known));
-+
-+#define MU_PREP(f, v) le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
-+
-+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_MCS, status->rate_idx);
-+ if (status->he_dcm)
-+ he_mu->flags1 |= MU_PREP(FLAGS1_SIG_B_DCM, status->he_dcm);
-+
-+ he_mu->flags2 |= MU_PREP(FLAGS2_BW_FROM_SIG_A_BW, status->bw) |
-+ MU_PREP(FLAGS2_SIG_B_SYMS_USERS,
-+ le32_get_bits(rxv[2], MT_CRXV_HE_NUM_USER));
-+
-+ he_mu->ru_ch1[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU0);
-+
-+ if (status->bw >= RATE_INFO_BW_40) {
-+ he_mu->flags1 |= HE_BITS(MU_FLAGS1_CH2_RU_KNOWN);
-+ he_mu->ru_ch2[0] = le32_get_bits(rxv[3], MT_CRXV_HE_RU1);
-+ }
-+
-+ if (status->bw >= RATE_INFO_BW_80) {
-+ he_mu->ru_ch1[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU2);
-+ he_mu->ru_ch2[1] = le32_get_bits(rxv[3], MT_CRXV_HE_RU3);
-+ }
-+}
-+
-+static void
-+mt7996_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv, u8 mode)
-+{
-+ struct mt76_rx_status *status = (struct mt76_rx_status *)skb->cb;
-+ static const struct ieee80211_radiotap_he known = {
-+ .data1 = HE_BITS(DATA1_DATA_MCS_KNOWN) |
-+ HE_BITS(DATA1_DATA_DCM_KNOWN) |
-+ HE_BITS(DATA1_STBC_KNOWN) |
-+ HE_BITS(DATA1_CODING_KNOWN) |
-+ HE_BITS(DATA1_LDPC_XSYMSEG_KNOWN) |
-+ HE_BITS(DATA1_DOPPLER_KNOWN) |
-+ HE_BITS(DATA1_SPTL_REUSE_KNOWN) |
-+ HE_BITS(DATA1_BSS_COLOR_KNOWN),
-+ .data2 = HE_BITS(DATA2_GI_KNOWN) |
-+ HE_BITS(DATA2_TXBF_KNOWN) |
-+ HE_BITS(DATA2_PE_DISAMBIG_KNOWN) |
-+ HE_BITS(DATA2_TXOP_KNOWN),
-+ };
-+ struct ieee80211_radiotap_he *he = NULL;
-+ u32 ltf_size = le32_get_bits(rxv[2], MT_CRXV_HE_LTF_SIZE) + 1;
-+
-+ status->flag |= RX_FLAG_RADIOTAP_HE;
-+
-+ he = skb_push(skb, sizeof(known));
-+ memcpy(he, &known, sizeof(known));
-+
-+ he->data3 = HE_PREP(DATA3_BSS_COLOR, BSS_COLOR, rxv[14]) |
-+ HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[2]);
-+ he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[11]);
-+ he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[2]) |
-+ le16_encode_bits(ltf_size,
-+ IEEE80211_RADIOTAP_HE_DATA5_LTF_SIZE);
-+ if (le32_to_cpu(rxv[0]) & MT_PRXV_TXBF)
-+ he->data5 |= HE_BITS(DATA5_TXBF);
-+ he->data6 = HE_PREP(DATA6_TXOP, TXOP_DUR, rxv[14]) |
-+ HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[14]);
-+
-+ switch (mode) {
-+ case MT_PHY_TYPE_HE_SU:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_SU) |
-+ HE_BITS(DATA1_UL_DL_KNOWN) |
-+ HE_BITS(DATA1_BEAM_CHANGE_KNOWN) |
-+ HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-+
-+ he->data3 |= HE_PREP(DATA3_BEAM_CHANGE, BEAM_CHNG, rxv[14]) |
-+ HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
-+ break;
-+ case MT_PHY_TYPE_HE_EXT_SU:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_EXT_SU) |
-+ HE_BITS(DATA1_UL_DL_KNOWN) |
-+ HE_BITS(DATA1_BW_RU_ALLOC_KNOWN);
-+
-+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
-+ break;
-+ case MT_PHY_TYPE_HE_MU:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_MU) |
-+ HE_BITS(DATA1_UL_DL_KNOWN);
-+
-+ he->data3 |= HE_PREP(DATA3_UL_DL, UPLINK, rxv[2]);
-+ he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[7]);
-+
-+ mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
-+ mt7996_mac_decode_he_mu_radiotap(skb, rxv);
-+ break;
-+ case MT_PHY_TYPE_HE_TB:
-+ he->data1 |= HE_BITS(DATA1_FORMAT_TRIG) |
-+ HE_BITS(DATA1_SPTL_REUSE2_KNOWN) |
-+ HE_BITS(DATA1_SPTL_REUSE3_KNOWN) |
-+ HE_BITS(DATA1_SPTL_REUSE4_KNOWN);
-+
-+ he->data4 |= HE_PREP(DATA4_TB_SPTL_REUSE1, SR_MASK, rxv[11]) |
-+ HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[11]) |
-+ HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[11]) |
-+ HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[11]);
-+
-+ mt7996_mac_decode_he_radiotap_ru(status, he, rxv);
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+
- /* The HW does not translate the mac header to 802.3 for mesh point */
- static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
- {
-@@ -686,8 +862,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
- }
-
- if (rxv && mode >= MT_PHY_TYPE_HE_SU && !(status->flag & RX_FLAG_8023))
-- mt76_connac2_mac_decode_he_radiotap(&dev->mt76, skb, rxv,
-- mode);
-+ mt7996_mac_decode_he_radiotap(skb, rxv, mode);
-
- if (!status->wcid || !ieee80211_is_data_qos(fc))
- return 0;
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch
deleted file mode 100644
index 1022535..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch
+++ /dev/null
@@ -1,96 +0,0 @@
-From 6767bcfec5f48f14fdf63c9699c63e6bc741ad74 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 3 Feb 2023 11:00:59 +0800
-Subject: [PATCH 1/7] Revert "wifi: mt76: mt7996: rely on
- mt76_connac_tx_complete_skb"
-
-This reverts commit 8688756305c643b8a296c16d0626732aaae1d02a.
----
- mt7996/mac.c | 21 +++++++++++++++++++++
- mt7996/mac.h | 13 +++++++++++++
- mt7996/mmio.c | 2 +-
- mt7996/mt7996.h | 1 +
- 4 files changed, 36 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index c9a9f0e3..0d718598 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1565,6 +1565,27 @@ void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- }
- }
-
-+void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
-+{
-+ if (!e->txwi) {
-+ dev_kfree_skb_any(e->skb);
-+ return;
-+ }
-+
-+ /* error path */
-+ if (e->skb == DMA_DUMMY_DATA) {
-+ struct mt76_connac_txp_common *txp;
-+ struct mt76_txwi_cache *t;
-+
-+ txp = mt7996_txwi_to_txp(mdev, e->txwi);
-+ t = mt76_token_put(mdev, le16_to_cpu(txp->fw.token));
-+ e->skb = t ? t->skb : NULL;
-+ }
-+
-+ if (e->skb)
-+ mt76_tx_complete_skb(mdev, e->wcid, e->skb);
-+}
-+
- void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy)
- {
- struct mt7996_dev *dev = phy->dev;
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 27184cba..10e08d66 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -371,4 +371,17 @@ struct mt7996_dfs_radar_spec {
- struct mt7996_dfs_pattern radar_pattern[16];
- };
-
-+static inline struct mt76_connac_txp_common *
-+mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-+{
-+ u8 *txwi;
-+
-+ if (!t)
-+ return NULL;
-+
-+ txwi = mt76_get_txwi_ptr(dev, t);
-+
-+ return (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
-+}
-+
- #endif
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 902370a2..2237f50a 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -326,7 +326,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
- SURVEY_INFO_TIME_BSS_RX,
- .token_size = MT7996_TOKEN_SIZE,
- .tx_prepare_skb = mt7996_tx_prepare_skb,
-- .tx_complete_skb = mt76_connac_tx_complete_skb,
-+ .tx_complete_skb = mt7996_tx_complete_skb,
- .rx_skb = mt7996_queue_rx_skb,
- .rx_check = mt7996_rx_check,
- .rx_poll_complete = mt7996_rx_poll_complete,
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 018dfd2b..13f22432 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -508,6 +508,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- enum mt76_txq_id qid, struct mt76_wcid *wcid,
- struct ieee80211_sta *sta,
- struct mt76_tx_info *tx_info);
-+void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e);
- void mt7996_tx_token_put(struct mt7996_dev *dev);
- void mt7996_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- struct sk_buff *skb, u32 *info);
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch
new file mode 100644
index 0000000..66ab9ce
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch
@@ -0,0 +1,92 @@
+From 995b09b6a62700568b36cc2e4ae6b6063456942b Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Fri, 10 Feb 2023 17:39:23 +0800
+Subject: [PATCH 01/19] wifi: mt76: mt7996: add eht rx rate support
+
+Add support to report eht rx rate.
+
+Change-Id: Iee067d891bd634a918c942c2ba90ae72cd40c538
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+---
+ mac80211.c | 11 ++++++++---
+ mt76.h | 18 ++++++++++++++----
+ mt7996/mac.c | 9 +++++----
+ 3 files changed, 27 insertions(+), 11 deletions(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 87902f4b..e53166fc 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -1067,9 +1067,14 @@ mt76_rx_convert(struct mt76_dev *dev, struct sk_buff *skb,
+ status->enc_flags = mstat.enc_flags;
+ status->encoding = mstat.encoding;
+ status->bw = mstat.bw;
+- status->he_ru = mstat.he_ru;
+- status->he_gi = mstat.he_gi;
+- status->he_dcm = mstat.he_dcm;
++ if (status->encoding == RX_ENC_EHT) {
++ status->eht.ru = mstat.eht.ru;
++ status->eht.gi = mstat.eht.gi;
++ } else {
++ status->he_ru = mstat.he_ru;
++ status->he_gi = mstat.he_gi;
++ status->he_dcm = mstat.he_dcm;
++ }
+ status->rate_idx = mstat.rate_idx;
+ status->nss = mstat.nss;
+ status->band = mstat.band;
+diff --git a/mt76.h b/mt76.h
+index 183b0fc5..c3d1313e 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -621,12 +621,22 @@ struct mt76_rx_status {
+ u16 freq;
+ u32 flag;
+ u8 enc_flags;
+- u8 encoding:2, bw:3, he_ru:3;
+- u8 he_gi:2, he_dcm:1;
++ u8 encoding:3, bw:4;
++ union {
++ struct {
++ u8 he_ru:3;
++ u8 he_gi:2;
++ u8 he_dcm:1;
++ };
++ struct {
++ u8 ru:4;
++ u8 gi:2;
++ } eht;
++ };
++
+ u8 amsdu:1, first_amsdu:1, last_amsdu:1;
+ u8 rate_idx;
+- u8 nss;
+- u8 band;
++ u8 nss:5, band:3;
+ s8 signal;
+ u8 chains;
+ s8 chain_signal[IEEE80211_MAX_CHAINS];
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 3c3506c7..d811b4e0 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -572,11 +572,12 @@ mt7996_mac_fill_rx_rate(struct mt7996_dev *dev,
+ case MT_PHY_TYPE_EHT_SU:
+ case MT_PHY_TYPE_EHT_TRIG:
+ case MT_PHY_TYPE_EHT_MU:
+- /* TODO: currently report rx rate with HE rate */
+ status->nss = nss;
+- status->encoding = RX_ENC_HE;
+- bw = min_t(int, bw, IEEE80211_STA_RX_BW_160);
+- i = min_t(int, i & 0xf, 11);
++ status->encoding = RX_ENC_EHT;
++ i &= GENMASK(3, 0);
++
++ if (gi <= NL80211_RATE_INFO_EHT_GI_3_2)
++ status->eht.gi = gi;
+ break;
+ default:
+ return -EINVAL;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch
deleted file mode 100644
index fb6581a..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch
+++ /dev/null
@@ -1,46 +0,0 @@
-From 9c2313ddded0179ae1a9e6112e2762a1a3e958d7 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 3 Feb 2023 11:01:11 +0800
-Subject: [PATCH 2/7] Revert "wifi: mt76: mt7996: rely on
- mt76_connac_txp_skb_unmap"
-
-This reverts commit bdb7dc38a6d150b5aa4b09b82a8954c6bb49ba4a.
----
- mt7996/mac.c | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 0d718598..df97d7cf 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1187,6 +1187,18 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
- ieee80211_start_tx_ba_session(sta, tid, 0);
- }
-
-+static void
-+mt7996_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-+{
-+ struct mt76_connac_txp_common *txp;
-+ int i;
-+
-+ txp = mt7996_txwi_to_txp(dev, t);
-+ for (i = 0; i < txp->fw.nbuf; i++)
-+ dma_unmap_single(dev->dev, le32_to_cpu(txp->fw.buf[i]),
-+ le16_to_cpu(txp->fw.len[i]), DMA_TO_DEVICE);
-+}
-+
- static void
- mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
- struct ieee80211_sta *sta, struct list_head *free_list)
-@@ -1196,7 +1208,7 @@ mt7996_txwi_free(struct mt7996_dev *dev, struct mt76_txwi_cache *t,
- __le32 *txwi;
- u16 wcid_idx;
-
-- mt76_connac_txp_skb_unmap(mdev, t);
-+ mt7996_txp_skb_unmap(mdev, t);
- if (!t->skb)
- goto out;
-
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch
new file mode 100644
index 0000000..872ef03
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch
@@ -0,0 +1,92 @@
+From 5b858f7f944144d99fb0ca1ef26d6b8c6719890c Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 16 Feb 2023 10:52:22 +0800
+Subject: [PATCH 02/19] wifi: mt76: mt7996: let non-bufferable MMPDUs use
+ correct hw queue
+
+non-bufferable MMPDUs are expected to use ALTX hw queue, but current
+condition in mt7996_mac_write_txwi() won't let their tx descriptor
+be filled with correct q_idx. Fix this by passing qid parameter into
+the funciton.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I18bd1a5ea698912c7aa8f4d4317d4a428d4ac440
+---
+ mt7996/mac.c | 9 +++++----
+ mt7996/mcu.c | 4 ++--
+ mt7996/mt7996.h | 3 ++-
+ 3 files changed, 9 insertions(+), 7 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index d811b4e0..198eb711 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -982,7 +982,8 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
+ }
+
+ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+- struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
++ struct sk_buff *skb, struct mt76_wcid *wcid,
++ enum mt76_txq_id qid, int pid,
+ struct ieee80211_key_conf *key, u32 changed)
+ {
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+@@ -1014,7 +1015,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+ } else if (beacon) {
+ p_fmt = MT_TX_TYPE_FW;
+ q_idx = MT_LMAC_BCN0;
+- } else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
++ } else if (qid >= MT_TXQ_PSD) {
+ p_fmt = MT_TX_TYPE_CT;
+ q_idx = MT_LMAC_ALTX0;
+ } else {
+@@ -1123,8 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ memset(txwi_ptr, 0, MT_TXD_SIZE);
+ /* Transmit non qos data by 802.11 header and need to fill txd by host*/
+ if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
+- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
+- key, 0);
++ mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, qid,
++ pid, key, 0);
+
+ txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
+ for (i = 0; i < nbuf; i++) {
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 8ad51cbf..dbe10576 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -1906,7 +1906,7 @@ mt7996_mcu_beacon_cont(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+ }
+
+ buf = (u8 *)bcn + sizeof(*bcn) - MAX_BEACON_SIZE;
+- mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
++ mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, 0, NULL,
+ BSS_CHANGED_BEACON);
+ memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
+ }
+@@ -2115,7 +2115,7 @@ int mt7996_mcu_beacon_inband_discov(struct mt7996_dev *dev,
+
+ buf = (u8 *)tlv + sizeof(*discov) - MAX_INBAND_FRAME_SIZE;
+
+- mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
++ mt7996_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, 0, NULL,
+ changed);
+
+ memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 018dfd2b..d20aa5f2 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -487,7 +487,8 @@ 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);
+ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
+- struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
++ struct sk_buff *skb, struct mt76_wcid *wcid,
++ enum mt76_txq_id qid, int pid,
+ struct ieee80211_key_conf *key, u32 changed);
+ void mt7996_mac_set_timing(struct mt7996_phy *phy);
+ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch
deleted file mode 100644
index 43ea6c9..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch
+++ /dev/null
@@ -1,163 +0,0 @@
-From 8ba17e7cdbb5e921edd03102476cd8fb4f4e1b31 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 3 Feb 2023 11:12:46 +0800
-Subject: [PATCH 3/7] Revert "wifi: mt76: mt7996: rely on
- mt76_connac_txp_common structure"
-
-This reverts commit 321edbb414dcc03d349bddd08916b7cc531802e8.
----
- mt7996/mac.c | 38 +++++++++++++++++++-------------------
- mt7996/mac.h | 15 +++++++++++++--
- mt7996/mmio.c | 2 +-
- 3 files changed, 33 insertions(+), 22 deletions(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index df97d7cf..e5b5fed6 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1088,8 +1088,8 @@ 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 mt76_connac_txp_common *txp;
- struct mt76_txwi_cache *t;
-+ struct mt7996_txp *txp;
- 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;
-@@ -1123,35 +1123,35 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
- key, 0);
-
-- txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
-+ txp = (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
- for (i = 0; i < nbuf; i++) {
-- txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
-- txp->fw.len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
-+ txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
-+ txp->len[i] = cpu_to_le16(tx_info->buf[i + 1].len);
- }
-- txp->fw.nbuf = nbuf;
-+ txp->nbuf = nbuf;
-
-- txp->fw.flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
-+ txp->flags = cpu_to_le16(MT_CT_INFO_FROM_HOST);
-
- if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
-- txp->fw.flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
-+ txp->flags |= cpu_to_le16(MT_CT_INFO_APPLY_TXD);
-
- if (!key)
-- txp->fw.flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
-+ txp->flags |= cpu_to_le16(MT_CT_INFO_NONE_CIPHER_FRAME);
-
- if (!is_8023 && ieee80211_is_mgmt(hdr->frame_control))
-- txp->fw.flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
-+ txp->flags |= cpu_to_le16(MT_CT_INFO_MGMT_FRAME);
-
- if (vif) {
- struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-
-- txp->fw.bss_idx = mvif->mt76.idx;
-+ txp->bss_idx = mvif->mt76.idx;
- }
-
-- txp->fw.token = cpu_to_le16(id);
-+ txp->token = cpu_to_le16(id);
- if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
-- txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
-+ txp->rept_wds_wcid = cpu_to_le16(wcid->idx);
- else
-- txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
-+ txp->rept_wds_wcid = cpu_to_le16(0xfff);
- tx_info->skb = DMA_DUMMY_DATA;
-
- /* pass partial skb header to fw */
-@@ -1190,13 +1190,13 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
- static void
- mt7996_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
- {
-- struct mt76_connac_txp_common *txp;
-+ struct mt7996_txp *txp;
- int i;
-
- txp = mt7996_txwi_to_txp(dev, t);
-- for (i = 0; i < txp->fw.nbuf; i++)
-- dma_unmap_single(dev->dev, le32_to_cpu(txp->fw.buf[i]),
-- le16_to_cpu(txp->fw.len[i]), DMA_TO_DEVICE);
-+ for (i = 0; i < txp->nbuf; i++)
-+ dma_unmap_single(dev->dev, le32_to_cpu(txp->buf[i]),
-+ le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
- }
-
- static void
-@@ -1586,11 +1586,11 @@ void mt7996_tx_complete_skb(struct mt76_dev *mdev, struct mt76_queue_entry *e)
-
- /* error path */
- if (e->skb == DMA_DUMMY_DATA) {
-- struct mt76_connac_txp_common *txp;
- struct mt76_txwi_cache *t;
-+ struct mt7996_txp *txp;
-
- txp = mt7996_txwi_to_txp(mdev, e->txwi);
-- t = mt76_token_put(mdev, le16_to_cpu(txp->fw.token));
-+ t = mt76_token_put(mdev, le16_to_cpu(txp->token));
- e->skb = t ? t->skb : NULL;
- }
-
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 10e08d66..9f688520 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -268,6 +268,17 @@ enum tx_mgnt_type {
- /* VHT/HE only use bits 0-3 */
- #define MT_TX_RATE_IDX GENMASK(5, 0)
-
-+struct mt7996_txp {
-+ __le16 flags;
-+ __le16 token;
-+ u8 bss_idx;
-+ __le16 rept_wds_wcid;
-+ u8 nbuf;
-+#define MT_TXP_MAX_BUF_NUM 6
-+ __le32 buf[MT_TXP_MAX_BUF_NUM];
-+ __le16 len[MT_TXP_MAX_BUF_NUM];
-+} __packed __aligned(4);
-+
- #define MT_TXFREE0_PKT_TYPE GENMASK(31, 27)
- #define MT_TXFREE0_MSDU_CNT GENMASK(25, 16)
- #define MT_TXFREE0_RX_BYTE GENMASK(15, 0)
-@@ -371,7 +382,7 @@ struct mt7996_dfs_radar_spec {
- struct mt7996_dfs_pattern radar_pattern[16];
- };
-
--static inline struct mt76_connac_txp_common *
-+static inline struct mt7996_txp *
- mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
- {
- u8 *txwi;
-@@ -381,7 +392,7 @@ mt7996_txwi_to_txp(struct mt76_dev *dev, struct mt76_txwi_cache *t)
-
- txwi = mt76_get_txwi_ptr(dev, t);
-
-- return (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
-+ return (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
- }
-
- #endif
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 2237f50a..d8a2c1a7 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -318,7 +318,7 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
- {
- static const struct mt76_driver_ops drv_ops = {
- /* txwi_size = txd size + txp size */
-- .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
-+ .txwi_size = MT_TXD_SIZE + sizeof(struct mt7996_txp),
- .drv_flags = MT_DRV_TXWI_NO_FREE |
- MT_DRV_HW_MGMT_TXQ,
- .survey_flags = SURVEY_INFO_TIME_TX |
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch
new file mode 100644
index 0000000..c91eb62
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch
@@ -0,0 +1,67 @@
+From 09ef1c1248c8b38c5f2c6e624397e64e8938349f Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 16 Feb 2023 00:39:01 +0800
+Subject: [PATCH 03/19] wifi: mt76: mt7996: reduce repeated bss_info and
+ sta_rec commands
+
+Refine the flow of setting bss_info and sta_rec commands to prevent from
+sending duplicated commands, especially for station mode.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: Iffd2c81f9ec98284793e75f4b7d39e9618977024
+---
+ mt7996/main.c | 21 ++++++---------------
+ 1 file changed, 6 insertions(+), 15 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 3e4da035..e80ee19e 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -241,8 +241,8 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ struct mt7996_phy *phy = mt7996_hw_phy(hw);
+ int idx = msta->wcid.idx;
+
+- mt7996_mcu_add_bss_info(phy, vif, false);
+ mt7996_mcu_add_sta(dev, vif, NULL, false);
++ mt7996_mcu_add_bss_info(phy, vif, false);
+
+ if (vif == phy->monitor_vif)
+ phy->monitor_vif = NULL;
+@@ -510,17 +510,13 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ /* 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 &&
+- vif->type == NL80211_IFTYPE_STATION) {
+- bool join = !is_zero_ether_addr(info->bssid);
+-
+- mt7996_mcu_add_bss_info(phy, vif, join);
+- mt7996_mcu_add_sta(dev, vif, NULL, join);
++ 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);
+ }
+
+- if (changed & BSS_CHANGED_ASSOC)
+- mt7996_mcu_add_bss_info(phy, vif, vif->cfg.assoc);
+-
+ if (changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7996_mac_enable_rtscts(dev, vif, info->use_cts_prot);
+
+@@ -533,11 +529,6 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
+ }
+ }
+
+- if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
+- mt7996_mcu_add_bss_info(phy, vif, true);
+- mt7996_mcu_add_sta(dev, vif, NULL, true);
+- }
+-
+ /* ensure that enable txcmd_mode after bss_info */
+ if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED))
+ mt7996_mcu_set_tx(dev, vif);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch
new file mode 100644
index 0000000..cc366e3
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch
@@ -0,0 +1,61 @@
+From c86f2243472f00fd2011cc44b89a87f7f6e2066a Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Wed, 15 Feb 2023 18:38:04 +0800
+Subject: [PATCH 04/19] wifi: mt76: mt7996: move radio enable command to
+ mt7996_start()
+
+The radio enable and disable commands are used for per-phy radio, so
+move them into mt7996_start() and mt7996_stop(), respectively.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I610b170f5198e085eb86dbd371ee0745ac6ff50f
+---
+ mt7996/main.c | 11 ++++++-----
+ 1 file changed, 6 insertions(+), 5 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index e80ee19e..a4fd9e24 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -46,6 +46,10 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++ ret = mt7996_mcu_set_radio_en(phy, true);
++ if (ret)
++ goto out;
++
+ ret = mt7996_mcu_set_chan_info(phy, UNI_CHANNEL_RX_PATH);
+ if (ret)
+ goto out;
+@@ -77,6 +81,8 @@ 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);
+
+ ieee80211_iterate_interfaces(dev->mt76.hw,
+@@ -189,10 +195,6 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
+ if (ret)
+ goto out;
+
+- ret = mt7996_mcu_set_radio_en(phy, true);
+- if (ret)
+- goto out;
+-
+ dev->mt76.vif_mask |= BIT_ULL(mvif->mt76.idx);
+ phy->omac_mask |= BIT_ULL(mvif->mt76.omac_idx);
+
+@@ -248,7 +250,6 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
+ phy->monitor_vif = NULL;
+
+ mt7996_mcu_add_dev_info(phy, vif, false);
+- mt7996_mcu_set_radio_en(phy, false);
+
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch
new file mode 100644
index 0000000..07dffec
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch
@@ -0,0 +1,49 @@
+From 5d4c7f88b2066f4a8ec1769cf6c067d0e88abfa3 Mon Sep 17 00:00:00 2001
+From: Shayne Chen <shayne.chen@mediatek.com>
+Date: Thu, 16 Feb 2023 13:53:14 +0800
+Subject: [PATCH 05/19] wifi: mt76: connac: set correct muar_idx for connac3
+ chipset
+
+Set the muar_idx to 0xe for the hw bcast/mcast station entry of connac3
+chipset.
+
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I7054c3b3c64ec447cc280ea810f4958afdfa9e02
+---
+ mt76_connac.h | 5 +++++
+ mt76_connac_mcu.c | 3 +++
+ 2 files changed, 8 insertions(+)
+
+diff --git a/mt76_connac.h b/mt76_connac.h
+index b339c50b..c8b91e86 100644
+--- a/mt76_connac.h
++++ b/mt76_connac.h
+@@ -216,6 +216,11 @@ static inline bool is_connac_v1(struct mt76_dev *dev)
+ return is_mt7615(dev) || is_mt7663(dev) || is_mt7622(dev);
+ }
+
++static inline bool is_connac_v3(struct mt76_dev *dev)
++{
++ return is_mt7996(dev);
++}
++
+ static inline bool is_mt76_fw_txp(struct mt76_dev *dev)
+ {
+ switch (mt76_chip(dev)) {
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index efb9bfaa..4e4f6b35 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -281,6 +281,9 @@ __mt76_connac_mcu_alloc_sta_req(struct mt76_dev *dev, struct mt76_vif *mvif,
+ };
+ struct sk_buff *skb;
+
++ if (is_connac_v3(dev) && !wcid->sta)
++ hdr.muar_idx = 0xe;
++
+ mt76_connac_mcu_get_wlan_idx(dev, wcid, &hdr.wlan_idx_lo,
+ &hdr.wlan_idx_hi);
+ skb = mt76_mcu_msg_alloc(dev, NULL, len);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch
deleted file mode 100644
index 8fddb93..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch
+++ /dev/null
@@ -1,48 +0,0 @@
-From d8bef73f22f88bf857698f4018db3aed6a2fca2d Mon Sep 17 00:00:00 2001
-From: Peter Chiu <chui-hao.chiu@mediatek.com>
-Date: Tue, 29 Nov 2022 09:13:32 +0800
-Subject: [PATCH 5/7] wifi: mt76: mt7996: set txd v1
-
----
- mt7996/mac.c | 3 +++
- mt7996/mac.h | 3 ++-
- 2 files changed, 5 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index e5b5fed6..51337dde 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1092,6 +1092,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- struct mt7996_txp *txp;
- int id, i, pid, nbuf = tx_info->nbuf - 1;
- bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
-+ __le32 *txd = (__le32 *)txwi_ptr;
- u8 *txwi = (u8 *)txwi_ptr;
-
- if (unlikely(tx_info->skb->len <= ETH_HLEN))
-@@ -1123,6 +1124,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid,
- key, 0);
-
-+ txd[0] |= le32_encode_bits(1, MT_TXD0_VER);
-+
- txp = (struct mt7996_txp *)(txwi + MT_TXD_SIZE);
- for (i = 0; i < nbuf; i++) {
- txp->buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 9f688520..470b701a 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -186,7 +186,8 @@ enum tx_mgnt_type {
-
- #define MT_TXD0_Q_IDX GENMASK(31, 25)
- #define MT_TXD0_PKT_FMT GENMASK(24, 23)
--#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
-+#define MT_TXD0_VER GENMASK(22, 19)
-+#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(18, 16)
- #define MT_TXD0_TX_BYTES GENMASK(15, 0)
-
- #define MT_TXD1_FIXED_RATE BIT(31)
---
-2.25.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch
new file mode 100644
index 0000000..65596f4
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch
@@ -0,0 +1,34 @@
+From 00d76d4dc3cdb719b5fc234d9cf3bbef39f448ce Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 13 Feb 2023 14:48:10 +0800
+Subject: [PATCH 06/19] wifi: mt76: mt7996: fix pointer calculation in ie
+ countdown event
+
+Fix the tail and data pointers. The rxd->len in mt7996_mcu_rxd does not
+include the length of general rxd. It only includes the length of
+firmware event rxd. Use the skb->length to get the correct length.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I832194559e63e6b49b7ee00dc9c606b6106d8669
+---
+ mt7996/mcu.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index dbe10576..2e25572a 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -422,7 +422,8 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ if (hdr->band && dev->mt76.phys[hdr->band])
+ mphy = dev->mt76.phys[hdr->band];
+
+- tail = skb->data + le16_to_cpu(rxd->len);
++ tail = skb->data + skb->len;
++ data += sizeof(struct header);
+ while (data + sizeof(struct tlv) < tail && le16_to_cpu(tlv->len)) {
+ switch (le16_to_cpu(tlv->tag)) {
+ case UNI_EVENT_IE_COUNTDOWN_CSA:
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch
new file mode 100644
index 0000000..7988196
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch
@@ -0,0 +1,96 @@
+From c2dafe57df1726acb80e30987bc8d678b86af14a Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Tue, 14 Feb 2023 18:35:43 +0800
+Subject: [PATCH 07/19] wifi: mt76: mt7996: remove mt7996_mcu_set_pm()
+
+Currently using BSS_INFO_PS command will sometimes cause packet drop in
+hw rx queue.
+Temporarily remove this function until finding the cause.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I863fc1edb18e4d7b5dac20140dd0904875e1323c
+---
+ mt7996/main.c | 8 --------
+ mt7996/mcu.c | 26 --------------------------
+ mt7996/mt7996.h | 1 -
+ 3 files changed, 35 deletions(-)
+
+diff --git a/mt7996/main.c b/mt7996/main.c
+index a4fd9e24..44d23e1d 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -56,10 +56,6 @@ static int mt7996_start(struct ieee80211_hw *hw)
+
+ set_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+- ieee80211_iterate_interfaces(dev->mt76.hw,
+- IEEE80211_IFACE_ITER_RESUME_ALL,
+- mt7996_mcu_set_pm, dev->mt76.hw);
+-
+ ieee80211_queue_delayed_work(hw, &phy->mt76->mac_work,
+ MT7996_WATCHDOG_TIME);
+
+@@ -85,10 +81,6 @@ static void mt7996_stop(struct ieee80211_hw *hw)
+
+ clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+
+- ieee80211_iterate_interfaces(dev->mt76.hw,
+- IEEE80211_IFACE_ITER_RESUME_ALL,
+- mt7996_mcu_set_pm, dev->mt76.hw);
+-
+ mutex_unlock(&dev->mt76.mutex);
+ }
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 2e25572a..f6947438 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3577,32 +3577,6 @@ int mt7996_mcu_twt_agrt_update(struct mt7996_dev *dev,
+ &req, sizeof(req), true);
+ }
+
+-void mt7996_mcu_set_pm(void *priv, u8 *mac, struct ieee80211_vif *vif)
+-{
+-#define EXIT_PM_STATE 0
+-#define ENTER_PM_STATE 1
+- struct ieee80211_hw *hw = priv;
+- 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 bss_power_save *ps;
+- struct sk_buff *skb;
+- struct tlv *tlv;
+- bool running = test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+-
+- skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
+- MT7996_BSS_UPDATE_MAX_SIZE);
+- if (IS_ERR(skb))
+- return;
+-
+- tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_PS, sizeof(*ps));
+- ps = (struct bss_power_save *)tlv;
+- ps->profile = running ? EXIT_PM_STATE : ENTER_PM_STATE;
+-
+- mt76_mcu_skb_send_msg(&dev->mt76, skb,
+- MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
+-}
+-
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val)
+ {
+ struct {
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index d20aa5f2..f9d8fbfd 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -432,7 +432,6 @@ int mt7996_mcu_set_pulse_th(struct mt7996_dev *dev,
+ 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);
+-void mt7996_mcu_set_pm(void *priv, u8 *mac, struct ieee80211_vif *vif);
+ int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+ int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7996-add-muru-support.patch
similarity index 91%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7996-add-muru-support.patch
index dab5182..20d7f48 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0008-wifi-mt76-mt7996-add-muru-support.patch
@@ -1,7 +1,7 @@
-From 7c8b8c77489ef907f2122c5d0edb7ff5e0fed177 Mon Sep 17 00:00:00 2001
+From b587a9f1615585f8db0fa98cc46791a3253ddac7 Mon Sep 17 00:00:00 2001
From: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
Date: Mon, 28 Nov 2022 14:36:09 +0800
-Subject: [PATCH 4/7] wifi: mt76: mt7996: add muru support
+Subject: [PATCH 08/19] wifi: mt76: mt7996: add muru support
Add sta_rec_muru() and related phy cap for MU and RU support.
@@ -15,7 +15,7 @@
3 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index a5e6ee4d..39667840 100644
+index 40a99e0c..6f30a0fb 100644
--- a/mt76_connac_mcu.h
+++ b/mt76_connac_mcu.h
@@ -518,7 +518,8 @@ struct sta_rec_muru {
@@ -29,10 +29,10 @@
struct {
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index dbe30832..394dd15c 100644
+index f6947438..b6bd36c2 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1049,6 +1049,63 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+@@ -1050,6 +1050,63 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
}
}
@@ -96,7 +96,7 @@
static inline bool
mt7996_is_ebf_supported(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, bool bfee)
-@@ -1721,7 +1778,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
+@@ -1722,7 +1779,8 @@ int mt7996_mcu_add_sta(struct mt7996_dev *dev, struct ieee80211_vif *vif,
mt7996_mcu_sta_he_6g_tlv(skb, sta);
/* starec eht */
mt7996_mcu_sta_eht_tlv(skb, sta);
@@ -106,7 +106,7 @@
/* starec bfee */
mt7996_mcu_sta_bfee_tlv(dev, skb, vif, sta);
/* starec hdr trans */
-@@ -2004,6 +2062,15 @@ mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
+@@ -2005,6 +2063,15 @@ mt7996_mcu_beacon_check_caps(struct mt7996_phy *phy, struct ieee80211_vif *vif,
vc->eht_su_ebfee =
EHT_PHY(CAP0_SU_BEAMFORMEE, eht->phy_cap_info[0]) &&
EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
@@ -123,7 +123,7 @@
}
diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 13f22432..64a804a4 100644
+index f9d8fbfd..997a0bf0 100644
--- a/mt7996/mt7996.h
+++ b/mt7996/mt7996.h
@@ -125,6 +125,9 @@ struct mt7996_vif_cap {
@@ -137,5 +137,5 @@
struct mt7996_vif {
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0009-wifi-mt76-mt7996-set-txd-v1.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0009-wifi-mt76-mt7996-set-txd-v1.patch
new file mode 100644
index 0000000..cc7548a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0009-wifi-mt76-mt7996-set-txd-v1.patch
@@ -0,0 +1,48 @@
+From 9a1a54c7df9babadd8f6ae066deb2b5e49715cb0 Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 6 Feb 2023 10:40:33 +0800
+Subject: [PATCH 09/19] wifi: mt76: mt7996: set txd v1
+
+---
+ mt7996/mac.c | 3 +++
+ mt7996/mac.h | 3 ++-
+ 2 files changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 198eb711..40ef5e4b 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1096,6 +1096,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 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;
++ __le32 *txd = (__le32 *)txwi_ptr;
+ u8 *txwi = (u8 *)txwi_ptr;
+
+ if (unlikely(tx_info->skb->len <= ETH_HLEN))
+@@ -1127,6 +1128,8 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, qid,
+ pid, key, 0);
+
++ txd[0] |= le32_encode_bits(1, MT_TXD0_VER);
++
+ txp = (struct mt76_connac_txp_common *)(txwi + MT_TXD_SIZE);
+ for (i = 0; i < nbuf; i++) {
+ txp->fw.buf[i] = cpu_to_le32(tx_info->buf[i + 1].addr);
+diff --git a/mt7996/mac.h b/mt7996/mac.h
+index 2cc218f7..4914d3e5 100644
+--- a/mt7996/mac.h
++++ b/mt7996/mac.h
+@@ -183,7 +183,8 @@ enum tx_mgnt_type {
+
+ #define MT_TXD0_Q_IDX GENMASK(31, 25)
+ #define MT_TXD0_PKT_FMT GENMASK(24, 23)
+-#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(22, 16)
++#define MT_TXD0_VER GENMASK(22, 19)
++#define MT_TXD0_ETH_TYPE_OFFSET GENMASK(18, 16)
+ #define MT_TXD0_TX_BYTES GENMASK(15, 0)
+
+ #define MT_TXD1_FIXED_RATE BIT(31)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch
new file mode 100644
index 0000000..319eb1f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0010-wifi-mt76-mt7996-add-thermal-protection-support.patch
@@ -0,0 +1,437 @@
+From 1744b5397ad4240ce41bf88bfff2eef34d76d587 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Thu, 2 Feb 2023 21:20:31 +0800
+Subject: [PATCH 10/19] wifi: mt76: mt7996: add thermal protection support
+
+This commit includes the following changes:
+1. implement MTK thermal protection driver API
+2. support Linux cooling device control
+
+Change-Id: I8fecc28f5b17ee50ae4644d1dd17d188dd694731
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/init.c | 105 +++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/main.c | 8 ++++
+ mt7996/mcu.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.h | 44 +++++++++++++++++++
+ mt7996/mt7996.h | 15 +++++++
+ 6 files changed, 279 insertions(+)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index 6f30a0fb..fa10d823 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -1009,6 +1009,7 @@ enum {
+ MCU_UNI_EVENT_FW_LOG_2_HOST = 0x04,
+ MCU_UNI_EVENT_IE_COUNTDOWN = 0x09,
+ MCU_UNI_EVENT_RDD_REPORT = 0x11,
++ MCU_UNI_EVENT_THERMAL = 0x35,
+ };
+
+ #define MCU_UNI_CMD_EVENT BIT(1)
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 946da93e..5a22cd81 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -41,6 +41,98 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ }
+ };
+
++static int
++mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ *state = MT7996_CDEV_THROTTLE_MAX;
++
++ return 0;
++}
++
++static int
++mt7996_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long *state)
++{
++ struct mt7996_phy *phy = cdev->devdata;
++
++ *state = phy->cdev_state;
++
++ return 0;
++}
++
++static int
++mt7996_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
++ unsigned long state)
++{
++ struct mt7996_phy *phy = cdev->devdata;
++ u8 throttling = MT7996_THERMAL_THROTTLE_MAX - state;
++ int ret;
++
++ if (state > MT7996_CDEV_THROTTLE_MAX) {
++ dev_err(phy->dev->mt76.dev,
++ "please specify a valid throttling state\n");
++ return -EINVAL;
++ }
++
++ if (state == phy->cdev_state)
++ return 0;
++
++ /*
++ * cooling_device convention: 0 = no cooling, more = more cooling
++ * mcu convention: 1 = max cooling, more = less cooling
++ */
++ ret = mt7996_mcu_set_thermal_throttling(phy, throttling);
++ if (ret)
++ return ret;
++
++ phy->cdev_state = state;
++
++ return 0;
++}
++
++static const struct thermal_cooling_device_ops mt7996_thermal_ops = {
++ .get_max_state = mt7996_thermal_get_max_throttle_state,
++ .get_cur_state = mt7996_thermal_get_cur_throttle_state,
++ .set_cur_state = mt7996_thermal_set_cur_throttle_state,
++};
++
++static void mt7996_unregister_thermal(struct mt7996_phy *phy)
++{
++ struct wiphy *wiphy = phy->mt76->hw->wiphy;
++
++ if (!phy->cdev)
++ return;
++
++ sysfs_remove_link(&wiphy->dev.kobj, "cooling_device");
++ thermal_cooling_device_unregister(phy->cdev);
++}
++
++static int mt7996_thermal_init(struct mt7996_phy *phy)
++{
++ struct wiphy *wiphy = phy->mt76->hw->wiphy;
++ struct thermal_cooling_device *cdev;
++ const char *name;
++
++ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
++ wiphy_name(wiphy));
++
++ cdev = thermal_cooling_device_register(name, phy, &mt7996_thermal_ops);
++ if (!IS_ERR(cdev)) {
++ if (sysfs_create_link(&wiphy->dev.kobj, &cdev->device.kobj,
++ "cooling_device") < 0)
++ thermal_cooling_device_unregister(cdev);
++ else
++ phy->cdev = cdev;
++ }
++
++ /* initialize critical/maximum high temperature */
++ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
++ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
++
++ return 0;
++}
++
+ static void mt7996_led_set_config(struct led_classdev *led_cdev,
+ u8 delay_on, u8 delay_off)
+ {
+@@ -367,6 +459,10 @@ static int mt7996_register_phy(struct mt7996_dev *dev, struct mt7996_phy *phy,
+ if (ret)
+ goto error;
+
++ ret = mt7996_thermal_init(phy);
++ if (ret)
++ goto error;
++
+ ret = mt7996_init_debugfs(phy);
+ if (ret)
+ goto error;
+@@ -387,6 +483,8 @@ mt7996_unregister_phy(struct mt7996_phy *phy, enum mt76_band_id band)
+ if (!phy)
+ return;
+
++ mt7996_unregister_thermal(phy);
++
+ mphy = phy->dev->mt76.phys[band];
+ mt76_unregister_phy(mphy);
+ ieee80211_free_hw(mphy->hw);
+@@ -876,6 +974,10 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ ret = mt7996_thermal_init(&dev->phy);
++ if (ret)
++ return ret;
++
+ ieee80211_queue_work(mt76_hw(dev), &dev->init_work);
+
+ ret = mt7996_register_phy(dev, mt7996_phy2(dev), MT_BAND1);
+@@ -893,6 +995,9 @@ void mt7996_unregister_device(struct mt7996_dev *dev)
+ {
+ mt7996_unregister_phy(mt7996_phy3(dev), MT_BAND2);
+ mt7996_unregister_phy(mt7996_phy2(dev), MT_BAND1);
++
++ mt7996_unregister_thermal(&dev->phy);
++
+ mt76_unregister_device(&dev->mt76);
+ mt7996_mcu_exit(dev);
+ mt7996_tx_token_put(dev);
+diff --git a/mt7996/main.c b/mt7996/main.c
+index 44d23e1d..d8d578c0 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -54,6 +54,14 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ if (ret)
+ goto out;
+
++ ret = mt7996_mcu_set_thermal_throttling(phy, MT7996_THERMAL_THROTTLE_MAX);
++ if (ret)
++ goto out;
++
++ ret = mt7996_mcu_set_thermal_protect(phy);
++ 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 b6bd36c2..3820a63e 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -443,6 +443,34 @@ mt7996_mcu_ie_countdown(struct mt7996_dev *dev, struct sk_buff *skb)
+ }
+ }
+
++static void
++mt7996_mcu_rx_thermal_notify(struct mt7996_dev *dev, struct sk_buff *skb)
++{
++#define THERMAL_NOTIFY_TAG 0x4
++#define THERMAL_NOTIFY 0x2
++ struct mt76_phy *mphy = &dev->mt76.phy;
++ struct mt7996_mcu_thermal_notify *n;
++ struct mt7996_phy *phy;
++
++ n = (struct mt7996_mcu_thermal_notify *)skb->data;
++
++ if (n->tag != THERMAL_NOTIFY_TAG)
++ return;
++
++ if (n->event_id != THERMAL_NOTIFY)
++ return;
++
++ if (n->band_idx > MT_BAND2)
++ return;
++
++ mphy = dev->mt76.phys[n->band_idx];
++ if (!mphy)
++ return;
++
++ phy = (struct mt7996_phy *)mphy->priv;
++ phy->throttle_state = n->duty_percent;
++}
++
+ static void
+ mt7996_mcu_rx_ext_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ {
+@@ -487,6 +515,9 @@ mt7996_mcu_uni_rx_unsolicited_event(struct mt7996_dev *dev, struct sk_buff *skb)
+ case MCU_UNI_EVENT_RDD_REPORT:
+ mt7996_mcu_rx_radar_detected(dev, skb);
+ break;
++ case MCU_UNI_EVENT_THERMAL:
++ mt7996_mcu_rx_thermal_notify(dev, skb);
++ break;
+ default:
+ break;
+ }
+@@ -3277,6 +3308,81 @@ out:
+ return 0;
+ }
+
++
++int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
++{
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ struct mt7996_mcu_thermal_ctrl ctrl;
++ } __packed req = {
++ .tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .ctrl = {
++ .band_idx = phy->mt76->band_idx,
++ },
++ };
++ int level, ret;
++
++ /* set duty cycle and level */
++ for (level = 0; level < 4; level++) {
++ req.ctrl.duty.duty_level = level;
++ req.ctrl.duty.duty_cycle = state;
++ state /= 2;
++
++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), false);
++ if (ret)
++ return ret;
++ }
++
++ return 0;
++}
++
++int mt7996_mcu_set_thermal_protect(struct mt7996_phy *phy)
++{
++#define SUSTAIN_PERIOD 10
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ struct mt7996_mcu_thermal_ctrl ctrl;
++ struct mt7996_mcu_thermal_enable enable;
++ } __packed req = {
++ .len = cpu_to_le16(sizeof(req) - 4 - sizeof(req.enable)),
++ .ctrl = {
++ .band_idx = phy->mt76->band_idx,
++ .type.protect_type = 1,
++ .type.trigger_type = 1,
++ },
++ };
++ int ret;
++
++ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_DISABLE);
++
++ ret = mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req) - sizeof(req.enable), false);
++ if (ret)
++ return ret;
++
++ /* set high-temperature trigger threshold */
++ req.tag = cpu_to_le16(UNI_CMD_THERMAL_PROTECT_ENABLE);
++ /* add a safety margin ~10 */
++ req.enable.restore_temp = cpu_to_le32(phy->throttle_temp[0] - 10);
++ req.enable.trigger_temp = cpu_to_le32(phy->throttle_temp[1]);
++ req.enable.sustain_time = cpu_to_le16(SUSTAIN_PERIOD);
++
++ req.len = cpu_to_le16(sizeof(req) - 4);
++
++ return mt76_mcu_send_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), false);
++}
++
+ int mt7996_mcu_set_ser(struct mt7996_dev *dev, u8 action, u8 val, u8 band)
+ {
+ struct {
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index dd0c5ac5..7fefc28f 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -30,6 +30,28 @@ struct mt7996_mcu_uni_event {
+ __le32 status; /* 0: success, others: fail */
+ } __packed;
+
++struct mt7996_mcu_thermal_ctrl {
++ u8 ctrl_id;
++ u8 band_idx;
++ union {
++ struct {
++ u8 protect_type; /* 1: duty admit, 2: radio off */
++ u8 trigger_type; /* 0: low, 1: high */
++ } __packed type;
++ struct {
++ u8 duty_level; /* level 0~3 */
++ u8 duty_cycle;
++ } __packed duty;
++ };
++} __packed;
++
++struct mt7996_mcu_thermal_enable {
++ __le32 trigger_temp;
++ __le32 restore_temp;
++ __le16 sustain_time;
++ u8 rsv[2];
++} __packed;
++
+ struct mt7996_mcu_csa_notify {
+ struct mt7996_mcu_rxd rxd;
+
+@@ -153,6 +175,22 @@ struct mt7996_mcu_mib {
+ __le64 data;
+ } __packed;
+
++struct mt7996_mcu_thermal_notify {
++ struct mt7996_mcu_rxd rxd;
++
++ u8 __rsv1[4];
++
++ __le16 tag;
++ __le16 len;
++
++ u8 event_id;
++ u8 band_idx;
++ u8 level_idx;
++ u8 duty_percent;
++ __le32 restore_temp;
++ u8 __rsv2[4];
++} __packed;
++
+ enum mt7996_chan_mib_offs {
+ UNI_MIB_OBSS_AIRTIME = 26,
+ UNI_MIB_NON_WIFI_TIME = 27,
+@@ -642,6 +680,12 @@ enum{
+ UNI_CMD_SR_SET_SIGA = 0xd0,
+ };
+
++enum {
++ UNI_CMD_THERMAL_PROTECT_ENABLE = 0x6,
++ UNI_CMD_THERMAL_PROTECT_DISABLE,
++ UNI_CMD_THERMAL_PROTECT_DUTY_CONFIG,
++};
++
+ enum {
+ UNI_CMD_ACCESS_REG_BASIC = 0x0,
+ UNI_CMD_ACCESS_RF_REG_BASIC,
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 997a0bf0..25b20fa6 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -43,6 +43,13 @@
+ #define MT7996_MAX_STA_TWT_AGRT 8
+ #define MT7996_MAX_QUEUE (__MT_RXQ_MAX + __MT_MCUQ_MAX + 3)
+
++#define MT7996_THERMAL_THROTTLE_MAX 100
++#define MT7996_CDEV_THROTTLE_MAX 99
++#define MT7996_CRIT_TEMP_IDX 0
++#define MT7996_MAX_TEMP_IDX 1
++#define MT7996_CRIT_TEMP 110
++#define MT7996_MAX_TEMP 120
++
+ struct mt7996_vif;
+ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+@@ -211,6 +218,11 @@ struct mt7996_phy {
+
+ struct ieee80211_vif *monitor_vif;
+
++ struct thermal_cooling_device *cdev;
++ u8 cdev_state;
++ u8 throttle_state;
++ u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
++
+ u32 rxfilter;
+ u64 omac_mask;
+
+@@ -437,6 +449,9 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
+ 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_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);
+ int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
+ u8 rx_sel, u8 val);
+ int mt7996_mcu_rdd_background_enable(struct mt7996_phy *phy,
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch
new file mode 100644
index 0000000..3de5b90
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch
@@ -0,0 +1,184 @@
+From afdb511f0febad0e0cc5572461ab04794cf86852 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Thu, 2 Feb 2023 20:53:42 +0800
+Subject: [PATCH 11/19] wifi: mt76: mt7996: add thermal sensor device support
+
+---
+ mt7996/init.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ mt7996/mcu.c | 41 ++++++++++++++++++++++++
+ 2 files changed, 128 insertions(+)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 5a22cd81..631ada15 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -4,6 +4,8 @@
+ */
+
+ #include <linux/etherdevice.h>
++#include <linux/hwmon.h>
++#include <linux/hwmon-sysfs.h>
+ #include <linux/thermal.h>
+ #include "mt7996.h"
+ #include "mac.h"
+@@ -41,6 +43,81 @@ static const struct ieee80211_iface_combination if_comb[] = {
+ }
+ };
+
++static ssize_t mt7996_thermal_temp_show(struct device *dev,
++ struct device_attribute *attr,
++ char *buf)
++{
++ struct mt7996_phy *phy = dev_get_drvdata(dev);
++ int i = to_sensor_dev_attr(attr)->index;
++ int temperature;
++
++ switch (i) {
++ case 0:
++ temperature = mt7996_mcu_get_temperature(phy);
++ if (temperature < 0)
++ return temperature;
++ /* display in millidegree celcius */
++ return sprintf(buf, "%u\n", temperature * 1000);
++ case 1:
++ case 2:
++ return sprintf(buf, "%u\n",
++ phy->throttle_temp[i - 1] * 1000);
++ case 3:
++ return sprintf(buf, "%hhu\n", phy->throttle_state);
++ default:
++ return -EINVAL;
++ }
++}
++
++static ssize_t mt7996_thermal_temp_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct mt7996_phy *phy = dev_get_drvdata(dev);
++ int ret, i = to_sensor_dev_attr(attr)->index;
++ long val;
++
++ ret = kstrtol(buf, 10, &val);
++ if (ret < 0)
++ return ret;
++
++ mutex_lock(&phy->dev->mt76.mutex);
++ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), 40, 130);
++
++ if ((i - 1 == MT7996_CRIT_TEMP_IDX &&
++ val > phy->throttle_temp[MT7996_MAX_TEMP_IDX]) ||
++ (i - 1 == MT7996_MAX_TEMP_IDX &&
++ val < phy->throttle_temp[MT7996_CRIT_TEMP_IDX])) {
++ dev_err(phy->dev->mt76.dev,
++ "temp1_max shall be greater than temp1_crit.");
++ mutex_unlock(&phy->dev->mt76.mutex);
++ return -EINVAL;
++ }
++
++ phy->throttle_temp[i - 1] = val;
++ mutex_unlock(&phy->dev->mt76.mutex);
++
++ ret = mt7996_mcu_set_thermal_protect(phy);
++ if (ret)
++ return ret;
++
++ return count;
++}
++
++static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7996_thermal_temp, 0);
++static SENSOR_DEVICE_ATTR_RW(temp1_crit, mt7996_thermal_temp, 1);
++static SENSOR_DEVICE_ATTR_RW(temp1_max, mt7996_thermal_temp, 2);
++static SENSOR_DEVICE_ATTR_RO(throttle1, mt7996_thermal_temp, 3);
++
++static struct attribute *mt7996_hwmon_attrs[] = {
++ &sensor_dev_attr_temp1_input.dev_attr.attr,
++ &sensor_dev_attr_temp1_crit.dev_attr.attr,
++ &sensor_dev_attr_temp1_max.dev_attr.attr,
++ &sensor_dev_attr_throttle1.dev_attr.attr,
++ NULL,
++};
++ATTRIBUTE_GROUPS(mt7996_hwmon);
++
+ static int
+ mt7996_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+@@ -112,6 +189,7 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
+ {
+ struct wiphy *wiphy = phy->mt76->hw->wiphy;
+ struct thermal_cooling_device *cdev;
++ struct device *hwmon;
+ const char *name;
+
+ name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7996_%s",
+@@ -130,6 +208,15 @@ static int mt7996_thermal_init(struct mt7996_phy *phy)
+ phy->throttle_temp[MT7996_CRIT_TEMP_IDX] = MT7996_CRIT_TEMP;
+ phy->throttle_temp[MT7996_MAX_TEMP_IDX] = MT7996_MAX_TEMP;
+
++ if (!IS_REACHABLE(CONFIG_HWMON))
++ return 0;
++
++ hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
++ mt7996_hwmon_groups);
++
++ if (IS_ERR(hwmon))
++ return PTR_ERR(hwmon);
++
+ return 0;
+ }
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 3820a63e..b3326586 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -3308,6 +3308,47 @@ out:
+ return 0;
+ }
+
++int mt7996_mcu_get_temperature(struct mt7996_phy *phy)
++{
++#define TEMPERATURE_QUERY 0
++#define GET_TEMPERATURE 0
++ struct {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ u8 rsv1;
++ u8 action;
++ u8 band_idx;
++ u8 rsv2;
++ } req = {
++ .tag = cpu_to_le16(TEMPERATURE_QUERY),
++ .len = cpu_to_le16(sizeof(req) - 4),
++ .action = GET_TEMPERATURE,
++ .band_idx = phy->mt76->band_idx,
++ };
++ struct mt7996_mcu_thermal {
++ u8 _rsv[4];
++
++ __le16 tag;
++ __le16 len;
++
++ __le32 rsv;
++ __le32 temperature;
++ } __packed *res;
++ struct sk_buff *skb;
++ int ret;
++
++ ret = mt76_mcu_send_and_get_msg(&phy->dev->mt76, MCU_WM_UNI_CMD(THERMAL),
++ &req, sizeof(req), true, &skb);
++ if (ret)
++ return ret;
++
++ res = (void *)skb->data;
++
++ return le32_to_cpu(res->temperature);
++}
+
+ int mt7996_mcu_set_thermal_throttling(struct mt7996_phy *phy, u8 state)
+ {
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
similarity index 78%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
index 70867df..728b4e0 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
@@ -1,7 +1,7 @@
-From 6298046de15b190139552d74aeb668e8cb873b1d Mon Sep 17 00:00:00 2001
+From f78111386b1ac57a459687b9d58e1804a80d4970 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
-Date: Thu, 15 Dec 2022 18:22:37 +0800
-Subject: [PATCH 6/7] wifi: mt76: mt7996: add 802.11s mesh amsdu/de-amsdu
+Date: Mon, 6 Feb 2023 11:34:51 +0800
+Subject: [PATCH 12/19] wifi: mt76: mt7996: add 802.11s mesh amsdu/de-amsdu
support
Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
@@ -12,16 +12,12 @@
mt7996/mcu.h | 2 +-
mt7996/mmio.c | 3 ++-
5 files changed, 27 insertions(+), 4 deletions(-)
- mode change 100644 => 100755 mt7996/mac.c
- mode change 100644 => 100755 mt7996/mmio.c
diff --git a/mt7996/mac.c b/mt7996/mac.c
-old mode 100644
-new mode 100755
-index 51337dde..d17b5478
+index 40ef5e4b..8dc3a621 100644
--- a/mt7996/mac.c
+++ b/mt7996/mac.c
-@@ -630,6 +630,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -633,6 +633,7 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
u32 rxd4 = le32_to_cpu(rxd[4]);
u32 csum_mask = MT_RXD0_NORMAL_IP_SUM | MT_RXD0_NORMAL_UDP_TCP_SUM;
u32 csum_status = *(u32 *)skb->cb;
@@ -29,7 +25,7 @@
bool unicast, insert_ccmp_hdr = false;
u8 remove_pad, amsdu_info, band_idx;
u8 mode = 0, qos_ctl = 0;
-@@ -822,6 +823,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -825,6 +826,9 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
skb_pull(skb, hdr_gap);
if (!hdr_trans && status->amsdu) {
@@ -39,7 +35,7 @@
pad_start = ieee80211_get_hdrlen_from_skb(skb);
} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
/* When header translation failure is indicated,
-@@ -854,8 +858,17 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
+@@ -857,8 +861,17 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
hdr = mt76_skb_get_hdr(skb);
fc = hdr->frame_control;
if (ieee80211_is_data_qos(fc)) {
@@ -59,7 +55,7 @@
} else {
status->flag |= RX_FLAG_8023;
diff --git a/mt7996/mac.h b/mt7996/mac.h
-index 470b701a..fd0e5d1c 100644
+index 4914d3e5..e48cc68b 100644
--- a/mt7996/mac.h
+++ b/mt7996/mac.h
@@ -12,6 +12,8 @@
@@ -72,10 +68,10 @@
#define MT_RXD0_NORMAL_IP_SUM BIT(23)
#define MT_RXD0_NORMAL_UDP_TCP_SUM BIT(24)
diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 394dd15c..1e47b0ae 100644
+index b3326586..0dbe2e01 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
-@@ -1022,7 +1022,8 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+@@ -1054,7 +1054,8 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
struct tlv *tlv;
if (vif->type != NL80211_IFTYPE_STATION &&
@@ -85,7 +81,7 @@
return;
if (!sta->deflink.agg.max_amsdu_len)
-@@ -1528,6 +1529,12 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
+@@ -1560,6 +1561,12 @@ mt7996_mcu_sta_hdr_trans_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
hdr_trans->to_ds = true;
hdr_trans->from_ds = true;
}
@@ -99,10 +95,10 @@
static enum mcu_mmps_mode
diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index dd0c5ac5..009f5f06 100644
+index 7fefc28f..ad66a1f8 100644
--- a/mt7996/mcu.h
+++ b/mt7996/mcu.h
-@@ -396,7 +396,7 @@ struct sta_rec_hdr_trans {
+@@ -434,7 +434,7 @@ struct sta_rec_hdr_trans {
u8 from_ds;
u8 to_ds;
u8 dis_rx_hdr_tran;
@@ -112,14 +108,12 @@
struct hdr_trans_en {
diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-old mode 100644
-new mode 100755
-index d8a2c1a7..08164b1a
+index 902370a2..6610cc45 100644
--- a/mt7996/mmio.c
+++ b/mt7996/mmio.c
@@ -320,7 +320,8 @@ struct mt7996_dev *mt7996_mmio_probe(struct device *pdev,
/* txwi_size = txd size + txp size */
- .txwi_size = MT_TXD_SIZE + sizeof(struct mt7996_txp),
+ .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_fw_txp),
.drv_flags = MT_DRV_TXWI_NO_FREE |
- MT_DRV_HW_MGMT_TXQ,
+ MT_DRV_HW_MGMT_TXQ |
@@ -128,5 +122,5 @@
SURVEY_INFO_TIME_RX |
SURVEY_INFO_TIME_BSS_RX,
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch
new file mode 100644
index 0000000..93ec12d
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch
@@ -0,0 +1,948 @@
+From 6b8dfe2580a782be754be7bcd44da6ad79dc4231 Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 13 Feb 2023 18:00:25 +0800
+Subject: [PATCH 13/19] wifi: mt76: mt7996: add L0.5 system error recovery
+ support
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt7996/debugfs.c | 155 +++++++++++++++++++++++---
+ mt7996/dma.c | 65 +++++++++++
+ mt7996/init.c | 9 +-
+ mt7996/mac.c | 285 +++++++++++++++++++++++++++++++++++++++--------
+ mt7996/main.c | 18 ++-
+ mt7996/mcu.c | 22 ++--
+ mt7996/mcu.h | 28 +++--
+ mt7996/mmio.c | 7 +-
+ mt7996/mt7996.h | 17 ++-
+ mt7996/regs.h | 36 +++++-
+ 10 files changed, 542 insertions(+), 100 deletions(-)
+
+diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
+index 9c5e9ac1..f2c46a50 100644
+--- a/mt7996/debugfs.c
++++ b/mt7996/debugfs.c
+@@ -48,12 +48,12 @@ DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7996_implicit_txbf_get,
+
+ /* test knob of system error recovery */
+ static ssize_t
+-mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
+- size_t count, loff_t *ppos)
++mt7996_sys_recovery_set(struct file *file, const char __user *user_buf,
++ size_t count, loff_t *ppos)
+ {
+ struct mt7996_phy *phy = file->private_data;
+ struct mt7996_dev *dev = phy->dev;
+- u8 band_idx = phy->mt76->band_idx;
++ bool band = phy->mt76->band_idx;
+ char buf[16];
+ int ret = 0;
+ u16 val;
+@@ -73,17 +73,49 @@ mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
+ return -EINVAL;
+
+ switch (val) {
+- case SER_SET_RECOVER_L1:
+- case SER_SET_RECOVER_L2:
+- case SER_SET_RECOVER_L3_RX_ABORT:
+- case SER_SET_RECOVER_L3_TX_ABORT:
+- case SER_SET_RECOVER_L3_TX_DISABLE:
+- case SER_SET_RECOVER_L3_BF:
+- ret = mt7996_mcu_set_ser(dev, SER_ENABLE, BIT(val), band_idx);
++ /*
++ * 0: grab firmware current SER state.
++ * 1: trigger & enable system error L1 recovery.
++ * 2: trigger & enable system error L2 recovery.
++ * 3: trigger & enable system error L3 rx abort.
++ * 4: trigger & enable system error L3 tx abort.
++ * 5: trigger & enable system error L3 tx disable.
++ * 6: trigger & enable system error L3 bf recovery.
++ * 7: trigger & enable system error L4 MDP recovery.
++ * 8: trigger & enable system error full recovery.
++ * 9: trigger firmware crash.
++ */
++ case UNI_CMD_SER_QUERY:
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_QUERY, 0, band);
++ break;
++ case UNI_CMD_SER_SET_RECOVER_L1:
++ case UNI_CMD_SER_SET_RECOVER_L2:
++ case UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT:
++ case UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT:
++ case UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE:
++ case UNI_CMD_SER_SET_RECOVER_L3_BF:
++ case UNI_CMD_SER_SET_RECOVER_L4_MDP:
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_SET, BIT(val), band);
++ if (ret)
++ return ret;
++
++ ret = mt7996_mcu_set_ser(dev, UNI_CMD_SER_TRIGGER, val, band);
++ break;
++
++ /* enable full chip reset */
++ case UNI_CMD_SER_SET_RECOVER_FULL:
++ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
+ if (ret)
+ return ret;
+
+- ret = mt7996_mcu_set_ser(dev, SER_RECOVER, val, band_idx);
++ dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
++ mt7996_reset(dev);
++ break;
++
++ /* WARNING: trigger firmware crash */
++ case UNI_CMD_SER_SET_SYSTEM_ASSERT:
++ mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18));
++ mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18));
+ break;
+ default:
+ break;
+@@ -92,9 +124,101 @@ mt7996_fw_ser_set(struct file *file, const char __user *user_buf,
+ return ret ? ret : count;
+ }
+
+-static const struct file_operations mt7996_fw_ser_ops = {
+- .write = mt7996_fw_ser_set,
+- /* TODO: ser read */
++static ssize_t
++mt7996_sys_recovery_get(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;
++ char *buff;
++ int desc = 0;
++ ssize_t ret;
++ static const size_t bufsz = 1024;
++
++ buff = kmalloc(bufsz, GFP_KERNEL);
++ if (!buff)
++ return -ENOMEM;
++
++ /* HELP */
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "Please echo the correct value ...\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "0: grab firmware transient SER state\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "1: trigger system error L1 recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "2: trigger system error L2 recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "3: trigger system error L3 rx abort\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "4: trigger system error L3 tx abort\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "5: trigger system error L3 tx disable\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "6: trigger system error L3 bf recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "7: trigger system error L4 MDP recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "8: trigger system error full recovery\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "9: trigger firmware crash\n");
++
++ /* SER statistics */
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "\nlet's dump firmware SER statistics...\n");
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_STATUS = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_SER_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PLE_ERR = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PLE_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PLE_ERR_1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PLE1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PLE_ERR_AMSDU = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PSE_ERR = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PSE_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_PSE_ERR_1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_PSE1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR6_B0 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR6_B1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR6_B2 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN2_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR7_B0 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR7_B1 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_LMAC_WISR7_B2 = 0x%08x\n",
++ mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN2_STATS));
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "::E R , SER_WFDMA_ERR = 0x%08x\n",
++ mt76_rr(dev, WF_SWDEF_WFDMA_STATUS_ADDR));
++
++ desc += scnprintf(buff + desc, bufsz - desc,
++ "\nSYS_RESET_COUNT: WM %d, WA %d\n",
++ dev->recovery.wm_reset_count,
++ dev->recovery.wa_reset_count);
++
++ ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
++ kfree(buff);
++ return ret;
++}
++
++static const struct file_operations mt7996_sys_recovery_ops = {
++ .write = mt7996_sys_recovery_set,
++ .read = mt7996_sys_recovery_get,
+ .open = simple_open,
+ .llseek = default_llseek,
+ };
+@@ -674,6 +798,8 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+ debugfs_create_file("xmit-queues", 0400, dir, phy,
+ &mt7996_xmit_queues_fops);
+ debugfs_create_file("tx_stats", 0400, dir, phy, &mt7996_tx_stats_fops);
++ debugfs_create_file("sys_recovery", 0600, dir, phy,
++ &mt7996_sys_recovery_ops);
+ 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);
+@@ -684,7 +810,6 @@ int mt7996_init_debugfs(struct mt7996_phy *phy)
+ &fops_implicit_txbf);
+ debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
+ mt7996_twt_stats);
+- debugfs_create_file("fw_ser", 0600, dir, phy, &mt7996_fw_ser_ops);
+ debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
+
+ if (phy->mt76->cap.has_5ghz) {
+diff --git a/mt7996/dma.c b/mt7996/dma.c
+index c09fe427..18ea758c 100644
+--- a/mt7996/dma.c
++++ b/mt7996/dma.c
+@@ -352,6 +352,71 @@ int mt7996_dma_init(struct mt7996_dev *dev)
+ return 0;
+ }
+
++void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
++{
++ struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
++ struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
++ u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
++ int i;
++
++ mt76_clear(dev, MT_WFDMA0_GLO_CFG,
++ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
++ MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++
++ if (dev->hif2)
++ mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
++ MT_WFDMA0_GLO_CFG_TX_DMA_EN |
++ MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++
++ usleep_range(1000, 2000);
++
++ for (i = 0; i < __MT_TXQ_MAX; i++) {
++ mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
++ if (phy2)
++ mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
++ if (phy3)
++ mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
++ }
++
++ for (i = 0; i < __MT_MCUQ_MAX; i++)
++ mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
++
++ mt76_for_each_q_rx(&dev->mt76, i)
++ //mt76_queue_rx_reset(dev, i);
++ mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
++
++ mt76_tx_status_check(&dev->mt76, true);
++
++ /* reset wfsys */
++ if (force)
++ mt7996_wfsys_reset(dev);
++
++ mt7996_dma_disable(dev, force);
++
++ /* reset hw queues */
++ for (i = 0; i < __MT_TXQ_MAX; i++) {
++ mt76_queue_reset(dev, dev->mphy.q_tx[i]);
++ if (phy2)
++ mt76_queue_reset(dev, phy2->q_tx[i]);
++ if (phy3)
++ mt76_queue_reset(dev, phy3->q_tx[i]);
++ }
++
++ for (i = 0; i < __MT_MCUQ_MAX; i++)
++ mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
++
++ mt76_for_each_q_rx(&dev->mt76, i) {
++ mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
++ }
++
++ mt76_tx_status_check(&dev->mt76, true);
++
++ mt76_for_each_q_rx(&dev->mt76, i)
++ mt76_queue_rx_reset(dev, i);
++
++ mt7996_dma_enable(dev);
++}
++
+ void mt7996_dma_cleanup(struct mt7996_dev *dev)
+ {
+ mt7996_dma_disable(dev, true);
+diff --git a/mt7996/init.c b/mt7996/init.c
+index 631ada15..ced38ac8 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -278,8 +278,7 @@ static void mt7996_led_set_brightness(struct led_classdev *led_cdev,
+ mt7996_led_set_config(led_cdev, 0xff, 0);
+ }
+
+-static void
+-mt7996_init_txpower(struct mt7996_dev *dev,
++void mt7996_init_txpower(struct mt7996_dev *dev,
+ struct ieee80211_supported_band *sband)
+ {
+ int i, nss = hweight8(dev->mphy.antenna_mask);
+@@ -429,7 +428,7 @@ mt7996_mac_init_band(struct mt7996_dev *dev, u8 band)
+ mt76_rmw(dev, MT_WTBLOFF_RSCR(band), mask, set);
+ }
+
+-static void mt7996_mac_init(struct mt7996_dev *dev)
++void mt7996_mac_init(struct mt7996_dev *dev)
+ {
+ #define HIF_TXD_V2_1 4
+ int i;
+@@ -463,7 +462,7 @@ static void mt7996_mac_init(struct mt7996_dev *dev)
+ mt7996_mac_init_band(dev, i);
+ }
+
+-static int mt7996_txbf_init(struct mt7996_dev *dev)
++int mt7996_txbf_init(struct mt7996_dev *dev)
+ {
+ int ret;
+
+@@ -1075,6 +1074,8 @@ int mt7996_register_device(struct mt7996_dev *dev)
+ if (ret)
+ return ret;
+
++ dev->recovery.hw_init_done = true;
++
+ return mt7996_init_debugfs(&dev->phy);
+ }
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 8dc3a621..4c0c8f1e 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1724,7 +1724,7 @@ mt7996_wait_reset_state(struct mt7996_dev *dev, u32 state)
+ bool ret;
+
+ ret = wait_event_timeout(dev->reset_wait,
+- (READ_ONCE(dev->reset_state) & state),
++ (READ_ONCE(dev->recovery.state) & state),
+ MT7996_RESET_TIMEOUT);
+
+ WARN(!ret, "Timeout waiting for MCU reset state %x\n", state);
+@@ -1773,68 +1773,208 @@ mt7996_update_beacons(struct mt7996_dev *dev)
+ mt7996_update_vif_beacon, phy3->hw);
+ }
+
+-static void
+-mt7996_dma_reset(struct mt7996_dev *dev)
++void mt7996_tx_token_put(struct mt7996_dev *dev)
+ {
+- struct mt76_phy *phy2 = dev->mt76.phys[MT_BAND1];
+- struct mt76_phy *phy3 = dev->mt76.phys[MT_BAND2];
+- u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+- int i;
++ struct mt76_txwi_cache *txwi;
++ int id;
+
+- mt76_clear(dev, MT_WFDMA0_GLO_CFG,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++ spin_lock_bh(&dev->mt76.token_lock);
++ idr_for_each_entry(&dev->mt76.token, txwi, id) {
++ mt7996_txwi_free(dev, txwi, NULL, NULL);
++ dev->mt76.token_count--;
++ }
++ spin_unlock_bh(&dev->mt76.token_lock);
++ idr_destroy(&dev->mt76.token);
++}
+
+- if (dev->hif2)
+- mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+
+- usleep_range(1000, 2000);
++static int
++mt7996_mac_restart(struct mt7996_dev *dev)
++{
++ struct mt7996_phy *phy2, *phy3;
++ struct mt76_dev *mdev = &dev->mt76;
++ int i, ret;
+
+- for (i = 0; i < __MT_TXQ_MAX; i++) {
+- mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
+- if (phy2)
+- mt76_queue_tx_cleanup(dev, phy2->q_tx[i], true);
+- if (phy3)
+- mt76_queue_tx_cleanup(dev, phy3->q_tx[i], true);
++ phy2 = mt7996_phy2(dev);
++ phy3 = mt7996_phy3(dev);
++
++ if (dev->hif2) {
++ mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
++ mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
+ }
+
+- for (i = 0; i < __MT_MCUQ_MAX; i++)
+- mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
++ if (dev_is_pci(mdev->dev)) {
++ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0x0);
++ if (dev->hif2)
++ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
++ }
+
+- mt76_for_each_q_rx(&dev->mt76, i)
+- mt76_queue_rx_reset(dev, i);
++ set_bit(MT76_RESET, &dev->mphy.state);
++ set_bit(MT76_MCU_RESET, &dev->mphy.state);
++ wake_up(&dev->mt76.mcu.wait);
++ if (phy2) {
++ set_bit(MT76_RESET, &phy2->mt76->state);
++ 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);
++ }
+
+- mt76_tx_status_check(&dev->mt76, true);
++ /* lock/unlock all queues to ensure that no tx is pending */
++ mt76_txq_schedule_all(&dev->mphy);
++ if (phy2)
++ mt76_txq_schedule_all(phy2->mt76);
++ if (phy3)
++ mt76_txq_schedule_all(phy3->mt76);
++
++ /* disable all tx/rx napi */
++ mt76_worker_disable(&dev->mt76.tx_worker);
++ mt76_for_each_q_rx(mdev, i) {
++ if (mdev->q_rx[i].ndesc)
++ napi_disable(&dev->mt76.napi[i]);
++ }
++ napi_disable(&dev->mt76.tx_napi);
+
+- /* re-init prefetch settings after reset */
+- mt7996_dma_prefetch(dev);
++ /* token reinit */
++ mt7996_tx_token_put(dev);
++ idr_init(&dev->mt76.token);
+
+- mt76_set(dev, MT_WFDMA0_GLO_CFG,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++ mt7996_dma_reset(dev, true);
+
+- if (dev->hif2)
+- mt76_set(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+- MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+- MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++ local_bh_disable();
++ mt76_for_each_q_rx(mdev, i) {
++ if (mdev->q_rx[i].ndesc) {
++ napi_enable(&dev->mt76.napi[i]);
++ napi_schedule(&dev->mt76.napi[i]);
++ }
++ }
++ local_bh_enable();
++ clear_bit(MT76_MCU_RESET, &dev->mphy.state);
++ clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
++
++ mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
++ mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
++ if (dev->hif2) {
++ mt76_wr(dev, MT_INT1_MASK_CSR, dev->mt76.mmio.irqmask);
++ mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
++ }
++ if (dev_is_pci(mdev->dev)) {
++ mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
++ if (dev->hif2)
++ mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
++ }
++
++ /* load firmware */
++ ret = mt7996_mcu_init_firmware(dev);
++ if (ret)
++ goto out;
++
++ /* set the necessary init items */
++ ret = mt7996_mcu_set_eeprom(dev);
++ if (ret)
++ goto out;
++
++ mt7996_mac_init(dev);
++ mt7996_init_txpower(dev, &dev->mphy.sband_2g.sband);
++ mt7996_init_txpower(dev, &dev->mphy.sband_5g.sband);
++ mt7996_init_txpower(dev, &dev->mphy.sband_6g.sband);
++ ret = mt7996_txbf_init(dev);
++
++ if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
++ ret = mt7996_run(dev->mphy.hw);
++ if (ret)
++ goto out;
++ }
++
++ if (phy2 && test_bit(MT76_STATE_RUNNING, &phy2->mt76->state)) {
++ ret = mt7996_run(phy2->mt76->hw);
++ if (ret)
++ goto out;
++ }
++
++ if (phy3 && test_bit(MT76_STATE_RUNNING, &phy3->mt76->state)) {
++ ret = mt7996_run(phy3->mt76->hw);
++ if (ret)
++ goto out;
++ }
++
++out:
++ /* reset done */
++ clear_bit(MT76_RESET, &dev->mphy.state);
++ if (phy2)
++ clear_bit(MT76_RESET, &phy2->mt76->state);
++ if (phy3)
++ clear_bit(MT76_RESET, &phy3->mt76->state);
++
++ local_bh_disable();
++ napi_enable(&dev->mt76.tx_napi);
++ napi_schedule(&dev->mt76.tx_napi);
++ local_bh_enable();
++
++ mt76_worker_enable(&dev->mt76.tx_worker);
++ return ret;
+ }
+
+-void mt7996_tx_token_put(struct mt7996_dev *dev)
++static void
++mt7996_mac_full_reset(struct mt7996_dev *dev)
+ {
+- struct mt76_txwi_cache *txwi;
+- int id;
++ struct mt7996_phy *phy2, *phy3;
++ int i;
+
+- spin_lock_bh(&dev->mt76.token_lock);
+- idr_for_each_entry(&dev->mt76.token, txwi, id) {
+- mt7996_txwi_free(dev, txwi, NULL, NULL);
+- dev->mt76.token_count--;
++ phy2 = mt7996_phy2(dev);
++ phy3 = mt7996_phy3(dev);
++ dev->recovery.hw_full_reset = true;
++
++ wake_up(&dev->mt76.mcu.wait);
++ ieee80211_stop_queues(mt76_hw(dev));
++ if (phy2)
++ ieee80211_stop_queues(phy2->mt76->hw);
++ if (phy3)
++ ieee80211_stop_queues(phy3->mt76->hw);
++
++ cancel_delayed_work_sync(&dev->mphy.mac_work);
++ if (phy2)
++ cancel_delayed_work_sync(&phy2->mt76->mac_work);
++ if (phy3)
++ cancel_delayed_work_sync(&phy3->mt76->mac_work);
++
++ mutex_lock(&dev->mt76.mutex);
++ for (i = 0; i < 10; i++) {
++ if (!mt7996_mac_restart(dev))
++ break;
+ }
+- spin_unlock_bh(&dev->mt76.token_lock);
+- idr_destroy(&dev->mt76.token);
++ mutex_unlock(&dev->mt76.mutex);
++
++ if (i == 10)
++ dev_err(dev->mt76.dev, "chip full reset failed\n");
++
++ ieee80211_restart_hw(mt76_hw(dev));
++ if (phy2)
++ ieee80211_restart_hw(phy2->mt76->hw);
++ if (phy3)
++ ieee80211_restart_hw(phy3->mt76->hw);
++
++ ieee80211_wake_queues(mt76_hw(dev));
++ if (phy2)
++ ieee80211_wake_queues(phy2->mt76->hw);
++ if (phy3)
++ ieee80211_wake_queues(phy3->mt76->hw);
++
++ dev->recovery.hw_full_reset = false;
++ ieee80211_queue_delayed_work(mt76_hw(dev),
++ &dev->mphy.mac_work,
++ MT7996_WATCHDOG_TIME);
++ if (phy2)
++ ieee80211_queue_delayed_work(phy2->mt76->hw,
++ &phy2->mt76->mac_work,
++ MT7996_WATCHDOG_TIME);
++ if (phy3)
++ ieee80211_queue_delayed_work(phy3->mt76->hw,
++ &phy3->mt76->mac_work,
++ MT7996_WATCHDOG_TIME);
+ }
+
+-/* system error recovery */
+ void mt7996_mac_reset_work(struct work_struct *work)
+ {
+ struct mt7996_phy *phy2, *phy3;
+@@ -1845,9 +1985,36 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ phy2 = mt7996_phy2(dev);
+ phy3 = mt7996_phy3(dev);
+
+- if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
++ /* chip full reset */
++ if (dev->recovery.restart) {
++ /* disable WA/WM WDT */
++ mt76_clear(dev, MT_WFDMA0_MCU_HOST_INT_ENA,
++ MT_MCU_CMD_WDT_MASK);
++
++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
++ dev->recovery.wa_reset_count++;
++ else
++ dev->recovery.wm_reset_count++;
++
++ mt7996_mac_full_reset(dev);
++
++ /* enable mcu irq */
++ mt7996_irq_enable(dev, MT_INT_MCU_CMD);
++ mt7996_irq_disable(dev, 0);
++
++ /* enable WA/WM WDT */
++ mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, MT_MCU_CMD_WDT_MASK);
++
++ dev->recovery.state = MT_MCU_CMD_NORMAL_STATE;
++ dev->recovery.restart = false;
+ return;
++ }
+
++ if (!(READ_ONCE(dev->recovery.state) & MT_MCU_CMD_STOP_DMA))
++ return;
++
++ dev_info(dev->mt76.dev,"\n%s L1 SER recovery start.",
++ wiphy_name(dev->mt76.hw->wiphy));
+ ieee80211_stop_queues(mt76_hw(dev));
+ if (phy2)
+ ieee80211_stop_queues(phy2->mt76->hw);
+@@ -1876,7 +2043,7 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
+
+ if (mt7996_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
+- mt7996_dma_reset(dev);
++ mt7996_dma_reset(dev, false);
+
+ mt7996_tx_token_put(dev);
+ idr_init(&dev->mt76.token);
+@@ -1931,6 +2098,32 @@ void mt7996_mac_reset_work(struct work_struct *work)
+ ieee80211_queue_delayed_work(phy3->mt76->hw,
+ &phy3->mt76->mac_work,
+ MT7996_WATCHDOG_TIME);
++ dev_info(dev->mt76.dev,"\n%s L1 SER recovery completed.",
++ wiphy_name(dev->mt76.hw->wiphy));
++}
++
++void mt7996_reset(struct mt7996_dev *dev)
++{
++ if (!dev->recovery.hw_init_done)
++ return;
++
++ if (dev->recovery.hw_full_reset)
++ return;
++
++ /* wm/wa exception: do full recovery */
++ if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK) {
++ dev->recovery.restart = true;
++ dev_info(dev->mt76.dev,
++ "%s indicated firmware crash, attempting recovery\n",
++ wiphy_name(dev->mt76.hw->wiphy));
++
++ mt7996_irq_disable(dev, MT_INT_MCU_CMD);
++ queue_work(dev->mt76.wq, &dev->reset_work);
++ return;
++ }
++
++ queue_work(dev->mt76.wq, &dev->reset_work);
++ wake_up(&dev->reset_wait);
+ }
+
+ void mt7996_mac_update_stats(struct mt7996_phy *phy)
+diff --git a/mt7996/main.c b/mt7996/main.c
+index d8d578c0..cb0e0d31 100644
+--- a/mt7996/main.c
++++ b/mt7996/main.c
+@@ -22,17 +22,13 @@ static bool mt7996_dev_running(struct mt7996_dev *dev)
+ return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+ }
+
+-static int mt7996_start(struct ieee80211_hw *hw)
++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;
+
+- flush_work(&dev->init_work);
+-
+- mutex_lock(&dev->mt76.mutex);
+-
+ running = mt7996_dev_running(dev);
+ if (!running) {
+ ret = mt7996_mcu_set_hdr_trans(dev, true);
+@@ -71,6 +67,18 @@ static int mt7996_start(struct ieee80211_hw *hw)
+ mt7996_mac_reset_counters(phy);
+
+ out:
++ return ret;
++}
++
++static int mt7996_start(struct ieee80211_hw *hw)
++{
++ struct mt7996_dev *dev = mt7996_hw_dev(hw);
++ int ret;
++
++ flush_work(&dev->init_work);
++
++ mutex_lock(&dev->mt76.mutex);
++ ret = mt7996_run(hw);
+ mutex_unlock(&dev->mt76.mutex);
+
+ return ret;
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 0dbe2e01..a949ff76 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2629,17 +2629,10 @@ mt7996_mcu_init_rx_airtime(struct mt7996_dev *dev)
+ MCU_WM_UNI_CMD(VOW), true);
+ }
+
+-int mt7996_mcu_init(struct mt7996_dev *dev)
++int mt7996_mcu_init_firmware(struct mt7996_dev *dev)
+ {
+- static const struct mt76_mcu_ops mt7996_mcu_ops = {
+- .headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
+- .mcu_skb_send_msg = mt7996_mcu_send_message,
+- .mcu_parse_response = mt7996_mcu_parse_response,
+- };
+ int ret;
+
+- dev->mt76.mcu_ops = &mt7996_mcu_ops;
+-
+ /* force firmware operation mode into normal state,
+ * which should be set before firmware download stage.
+ */
+@@ -2680,6 +2673,19 @@ int mt7996_mcu_init(struct mt7996_dev *dev)
+ MCU_WA_PARAM_RED, 0, 0);
+ }
+
++int mt7996_mcu_init(struct mt7996_dev *dev)
++{
++ static const struct mt76_mcu_ops mt7996_mcu_ops = {
++ .headroom = sizeof(struct mt76_connac2_mcu_txd), /* reuse */
++ .mcu_skb_send_msg = mt7996_mcu_send_message,
++ .mcu_parse_response = mt7996_mcu_parse_response,
++ };
++
++ dev->mt76.mcu_ops = &mt7996_mcu_ops;
++
++ return mt7996_mcu_init_firmware(dev);
++}
++
+ void mt7996_mcu_exit(struct mt7996_dev *dev)
+ {
+ mt7996_mcu_restart(&dev->mt76);
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index ad66a1f8..778deedf 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -692,23 +692,21 @@ enum {
+ };
+
+ enum {
+- UNI_CMD_SER_QUERY = 0x0,
+- UNI_CMD_SER_SET = 0x2,
+- UNI_CMD_SER_TRIGGER = 0x3,
+-};
+-
+-enum {
+- SER_QUERY,
++ UNI_CMD_SER_QUERY,
+ /* recovery */
+- SER_SET_RECOVER_L1,
+- SER_SET_RECOVER_L2,
+- SER_SET_RECOVER_L3_RX_ABORT,
+- SER_SET_RECOVER_L3_TX_ABORT,
+- SER_SET_RECOVER_L3_TX_DISABLE,
+- SER_SET_RECOVER_L3_BF,
++ UNI_CMD_SER_SET_RECOVER_L1,
++ UNI_CMD_SER_SET_RECOVER_L2,
++ UNI_CMD_SER_SET_RECOVER_L3_RX_ABORT,
++ UNI_CMD_SER_SET_RECOVER_L3_TX_ABORT,
++ UNI_CMD_SER_SET_RECOVER_L3_TX_DISABLE,
++ UNI_CMD_SER_SET_RECOVER_L3_BF,
++ UNI_CMD_SER_SET_RECOVER_L4_MDP,
++ UNI_CMD_SER_SET_RECOVER_FULL,
++ UNI_CMD_SER_SET_SYSTEM_ASSERT,
+ /* action */
+- SER_ENABLE = 2,
+- SER_RECOVER
++ UNI_CMD_SER_ENABLE = 1,
++ UNI_CMD_SER_SET,
++ UNI_CMD_SER_TRIGGER
+ };
+
+ enum {
+diff --git a/mt7996/mmio.c b/mt7996/mmio.c
+index 6610cc45..0e11f398 100644
+--- a/mt7996/mmio.c
++++ b/mt7996/mmio.c
+@@ -289,10 +289,9 @@ static void mt7996_irq_tasklet(struct tasklet_struct *t)
+ u32 val = mt76_rr(dev, MT_MCU_CMD);
+
+ mt76_wr(dev, MT_MCU_CMD, val);
+- if (val & MT_MCU_CMD_ERROR_MASK) {
+- dev->reset_state = val;
+- ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
+- wake_up(&dev->reset_wait);
++ if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) {
++ dev->recovery.state = val;
++ mt7996_reset(dev);
+ }
+ }
+ }
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 25b20fa6..923e6fc9 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -268,7 +268,14 @@ struct mt7996_dev {
+ struct work_struct rc_work;
+ struct work_struct reset_work;
+ wait_queue_head_t reset_wait;
+- u32 reset_state;
++ struct {
++ u32 state;
++ u32 wa_reset_count;
++ u32 wm_reset_count;
++ bool hw_full_reset:1;
++ bool hw_init_done:1;
++ bool restart:1;
++ } recovery;
+
+ struct list_head sta_rc_list;
+ struct list_head sta_poll_list;
+@@ -401,9 +408,16 @@ 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);
+ 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);
+ void mt7996_dma_cleanup(struct mt7996_dev *dev);
++void mt7996_init_txpower(struct mt7996_dev *dev,
++ struct ieee80211_supported_band *sband);
++int mt7996_txbf_init(struct mt7996_dev *dev);
++void mt7996_reset(struct mt7996_dev *dev);
++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_twt_flow *flow,
+@@ -496,6 +510,7 @@ static inline void mt7996_irq_disable(struct mt7996_dev *dev, u32 mask)
+ mt76_set_irq_mask(&dev->mt76, MT_INT_MASK_CSR, mask, 0);
+ }
+
++void mt7996_mac_init(struct mt7996_dev *dev);
+ 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);
+ void mt7996_mac_reset_counters(struct mt7996_phy *phy);
+diff --git a/mt7996/regs.h b/mt7996/regs.h
+index 7a28cae3..0775ca58 100644
+--- a/mt7996/regs.h
++++ b/mt7996/regs.h
+@@ -317,6 +317,8 @@ enum base_rev {
+ #define MT_WFDMA0_RX_INT_PCIE_SEL MT_WFDMA0(0x154)
+ #define MT_WFDMA0_RX_INT_SEL_RING3 BIT(3)
+
++#define MT_WFDMA0_MCU_HOST_INT_ENA MT_WFDMA0(0x1f4)
++
+ #define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
+ #define MT_WFDMA0_GLO_CFG_TX_DMA_EN BIT(0)
+ #define MT_WFDMA0_GLO_CFG_RX_DMA_EN BIT(2)
+@@ -444,6 +446,10 @@ enum base_rev {
+ #define MT_MCU_CMD_NORMAL_STATE BIT(5)
+ #define MT_MCU_CMD_ERROR_MASK GENMASK(5, 1)
+
++#define MT_MCU_CMD_WA_WDT BIT(31)
++#define MT_MCU_CMD_WM_WDT BIT(30)
++#define MT_MCU_CMD_WDT_MASK GENMASK(31, 30)
++
+ /* l1/l2 remap */
+ #define MT_HIF_REMAP_L1 0x155024
+ #define MT_HIF_REMAP_L1_MASK GENMASK(31, 16)
+@@ -468,8 +474,27 @@ enum base_rev {
+ #define MT_INFRA_MCU_END 0x7c3fffff
+
+ /* FW MODE SYNC */
+-#define MT_SWDEF_MODE 0x9143c
++#define MT_SWDEF_BASE 0x00401400
++
++#define MT_SWDEF(ofs) (MT_SWDEF_BASE + (ofs))
++#define MT_SWDEF_MODE MT_SWDEF(0x3c)
+ #define MT_SWDEF_NORMAL_MODE 0
++#define MT_SWDEF_ICAP_MODE 1
++#define MT_SWDEF_SPECTRUM_MODE 2
++
++#define MT_SWDEF_SER_STATS MT_SWDEF(0x040)
++#define MT_SWDEF_PLE_STATS MT_SWDEF(0x044)
++#define MT_SWDEF_PLE1_STATS MT_SWDEF(0x048)
++#define MT_SWDEF_PLE_AMSDU_STATS MT_SWDEF(0x04C)
++#define MT_SWDEF_PSE_STATS MT_SWDEF(0x050)
++#define MT_SWDEF_PSE1_STATS MT_SWDEF(0x054)
++#define MT_SWDEF_LAMC_WISR6_BN0_STATS MT_SWDEF(0x058)
++#define MT_SWDEF_LAMC_WISR6_BN1_STATS MT_SWDEF(0x05C)
++#define MT_SWDEF_LAMC_WISR6_BN2_STATS MT_SWDEF(0x060)
++#define MT_SWDEF_LAMC_WISR7_BN0_STATS MT_SWDEF(0x064)
++#define MT_SWDEF_LAMC_WISR7_BN1_STATS MT_SWDEF(0x068)
++#define MT_SWDEF_LAMC_WISR7_BN2_STATS MT_SWDEF(0x06C)
++#define WF_SWDEF_WFDMA_STATUS_ADDR MT_SWDEF(0x090)
+
+ /* LED */
+ #define MT_LED_TOP_BASE 0x18013000
+@@ -506,7 +531,7 @@ enum base_rev {
+ #define MT_TOP_MISC_FW_STATE GENMASK(2, 0)
+
+ #define MT_HW_REV 0x70010204
+-#define MT_WF_SUBSYS_RST 0x70002600
++#define MT_WF_SUBSYS_RST 0x70028600
+
+ /* PCIE MAC */
+ #define MT_PCIE_MAC_BASE 0x74030000
+@@ -539,4 +564,11 @@ enum base_rev {
+ #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)
+
++#define MT_MCU_WM_CIRQ_BASE 0x89010000
++#define MT_MCU_WM_CIRQ(ofs) (MT_MCU_WM_CIRQ_BASE + (ofs))
++#define MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x80)
++#define MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR MT_MCU_WM_CIRQ(0xc0)
++#define MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR MT_MCU_WM_CIRQ(0x108)
++#define MT_MCU_WM_CIRQ_EINT_SOFT_ADDR MT_MCU_WM_CIRQ(0x118)
++
+ #endif
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch
new file mode 100644
index 0000000..8193a5a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch
@@ -0,0 +1,194 @@
+From 2d6ca0f6974ad4f6dcf110ccbbcbbc7185aa7655 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Fri, 17 Feb 2023 14:13:38 +0800
+Subject: [PATCH 14/19] wifi: mt76: mt7996: add dsp firmware download
+
+Add DSP firmware for phy related control. Without this patch,the
+firmware state would not be ready.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt76_connac_mcu.h | 1 +
+ mt7996/mcu.c | 94 +++++++++++++++++++++--------------------------
+ mt7996/mt7996.h | 7 ++++
+ mt7996/pci.c | 1 +
+ 4 files changed, 50 insertions(+), 53 deletions(-)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index fa10d823..79dde31a 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -22,6 +22,7 @@
+
+ #define FW_START_OVERRIDE BIT(0)
+ #define FW_START_WORKING_PDA_CR4 BIT(2)
++#define FW_START_WORKING_PDA_DSP BIT(3)
+
+ #define PATCH_SEC_NOT_SUPPORT GENMASK(31, 0)
+ #define PATCH_SEC_TYPE_MASK GENMASK(15, 0)
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index a949ff76..09800ff2 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -2353,7 +2353,7 @@ out:
+ static int
+ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
+ const struct mt7996_fw_trailer *hdr,
+- const u8 *data, bool is_wa)
++ const u8 *data, enum mt7996_ram_type type)
+ {
+ int i, offset = 0;
+ u32 override = 0, option = 0;
+@@ -2365,8 +2365,10 @@ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
+
+ region = (const struct mt7996_fw_region *)((const u8 *)hdr -
+ (hdr->n_region - i) * sizeof(*region));
++ /* DSP and WA use same mode */
+ mode = mt76_connac_mcu_gen_dl_mode(&dev->mt76,
+- region->feature_set, is_wa);
++ region->feature_set,
++ type != MT7996_RAM_TYPE_WM);
+ len = le32_to_cpu(region->len);
+ addr = le32_to_cpu(region->addr);
+
+@@ -2393,8 +2395,10 @@ mt7996_mcu_send_ram_firmware(struct mt7996_dev *dev,
+ if (override)
+ option |= FW_START_OVERRIDE;
+
+- if (is_wa)
++ if (type == MT7996_RAM_TYPE_WA)
+ option |= FW_START_WORKING_PDA_CR4;
++ else if (type == MT7996_RAM_TYPE_DSP)
++ option |= FW_START_WORKING_PDA_DSP;
+
+ return mt76_connac_mcu_start_firmware(&dev->mt76, override, option);
+ }
+@@ -2405,56 +2409,40 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
+ const struct firmware *fw;
+ int ret;
+
+- ret = request_firmware(&fw, MT7996_FIRMWARE_WM, dev->mt76.dev);
+- if (ret)
+- return ret;
+-
+- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+- dev_err(dev->mt76.dev, "Invalid firmware\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
+-
+- dev_info(dev->mt76.dev, "WM Firmware Version: %.10s, Build Time: %.15s\n",
+- hdr->fw_ver, hdr->build_date);
+-
+- ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, false);
+- if (ret) {
+- dev_err(dev->mt76.dev, "Failed to start WM firmware\n");
+- goto out;
+- }
+-
+- release_firmware(fw);
+-
+- ret = request_firmware(&fw, MT7996_FIRMWARE_WA, dev->mt76.dev);
+- if (ret)
+- return ret;
+-
+- if (!fw || !fw->data || fw->size < sizeof(*hdr)) {
+- dev_err(dev->mt76.dev, "Invalid firmware\n");
+- ret = -EINVAL;
+- goto out;
+- }
+-
+- hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
+-
+- dev_info(dev->mt76.dev, "WA Firmware Version: %.10s, Build Time: %.15s\n",
+- hdr->fw_ver, hdr->build_date);
+-
+- ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, true);
+- if (ret) {
+- dev_err(dev->mt76.dev, "Failed to start WA firmware\n");
+- goto out;
+- }
+-
+- snprintf(dev->mt76.hw->wiphy->fw_version,
+- sizeof(dev->mt76.hw->wiphy->fw_version),
+- "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
+-
+-out:
+- release_firmware(fw);
++#define LOAD_RAM(_type) \
++ do { \
++ ret = request_firmware(&fw, MT7996_FIRMWARE_##_type, dev->mt76.dev); \
++ if (ret) \
++ return ret; \
++ \
++ if (!fw || !fw->data || fw->size < sizeof(*hdr)) { \
++ dev_err(dev->mt76.dev, "Invalid firmware\n"); \
++ release_firmware(fw); \
++ return -EINVAL; \
++ } \
++ \
++ hdr = (const struct mt7996_fw_trailer *) \
++ (fw->data + fw->size - sizeof(*hdr)); \
++ \
++ dev_info(dev->mt76.dev, \
++ "%s Firmware Version: %.10s, Build Time: %.15s\n", \
++ #_type, hdr->fw_ver, hdr->build_date); \
++ \
++ ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, \
++ MT7996_RAM_TYPE_##_type); \
++ if (ret) { \
++ dev_err(dev->mt76.dev, "Failed to start %s firmware\n", #_type);\
++ release_firmware(fw); \
++ return ret; \
++ } \
++ \
++ release_firmware(fw); \
++ } while (0)
++
++ LOAD_RAM(WM);
++ LOAD_RAM(DSP);
++ LOAD_RAM(WA);
++#undef LOAD_RAM
+
+ return ret;
+ }
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 923e6fc9..c2f8900c 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -29,6 +29,7 @@
+
+ #define MT7996_FIRMWARE_WA "mediatek/mt7996/mt7996_wa.bin"
+ #define MT7996_FIRMWARE_WM "mediatek/mt7996/mt7996_wm.bin"
++#define MT7996_FIRMWARE_DSP "mediatek/mt7996/mt7996_dsp.bin"
+ #define MT7996_ROM_PATCH "mediatek/mt7996/mt7996_rom_patch.bin"
+
+ #define MT7996_EEPROM_DEFAULT "mediatek/mt7996/mt7996_eeprom.bin"
+@@ -55,6 +56,12 @@ struct mt7996_sta;
+ struct mt7996_dfs_pulse;
+ struct mt7996_dfs_pattern;
+
++enum mt7996_ram_type {
++ MT7996_RAM_TYPE_WM = 0,
++ MT7996_RAM_TYPE_WA,
++ MT7996_RAM_TYPE_DSP,
++};
++
+ enum mt7996_txq_id {
+ MT7996_TXQ_FWDL = 16,
+ MT7996_TXQ_MCU_WM,
+diff --git a/mt7996/pci.c b/mt7996/pci.c
+index 64aee3fb..c5301050 100644
+--- a/mt7996/pci.c
++++ b/mt7996/pci.c
+@@ -219,4 +219,5 @@ MODULE_DEVICE_TABLE(pci, mt7996_pci_device_table);
+ MODULE_DEVICE_TABLE(pci, mt7996_hif_device_table);
+ MODULE_FIRMWARE(MT7996_FIRMWARE_WA);
+ MODULE_FIRMWARE(MT7996_FIRMWARE_WM);
++MODULE_FIRMWARE(MT7996_FIRMWARE_DSP);
+ MODULE_FIRMWARE(MT7996_ROM_PATCH);
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch
new file mode 100644
index 0000000..236cada
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch
@@ -0,0 +1,33 @@
+From 763303e5fb846c92c22dd19ffec95d844103e425 Mon Sep 17 00:00:00 2001
+From: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+Date: Thu, 23 Feb 2023 19:18:45 +0800
+Subject: [PATCH 15/19] wifi: mt76: mt7996: fix eeprom antenna bitfield mask
+
+Signed-off-by: StanleyYP Wang <StanleyYP.Wang@mediatek.com>
+---
+ mt7996/eeprom.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/mt7996/eeprom.h b/mt7996/eeprom.h
+index 8da599e0..cfc48698 100644
+--- a/mt7996/eeprom.h
++++ b/mt7996/eeprom.h
+@@ -31,11 +31,11 @@ enum mt7996_eeprom_field {
+ #define MT_EE_WIFI_CONF2_BAND_SEL GENMASK(2, 0)
+
+ #define MT_EE_WIFI_CONF1_TX_PATH_BAND0 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF2_TX_PATH_BAND1 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF2_TX_PATH_BAND2 GENMASK(5, 3)
+ #define MT_EE_WIFI_CONF4_STREAM_NUM_BAND0 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(5, 3)
+-#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND1 GENMASK(2, 0)
++#define MT_EE_WIFI_CONF5_STREAM_NUM_BAND2 GENMASK(5, 3)
+
+ #define MT_EE_RATE_DELTA_MASK GENMASK(5, 0)
+ #define MT_EE_RATE_DELTA_SIGN BIT(6)
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0016-wifi-mt76-mt7996-init-mpdu-density.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0016-wifi-mt76-mt7996-init-mpdu-density.patch
new file mode 100644
index 0000000..74992ab
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0016-wifi-mt76-mt7996-init-mpdu-density.patch
@@ -0,0 +1,53 @@
+From 322307272a4c4ccb627d6596220b0ab5bd4aed45 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 13 Feb 2023 09:46:40 +0800
+Subject: [PATCH 16/19] wifi: mt76: mt7996: init mpdu density
+
+Init mpdu density based on the hardware capability to
+prevent hardware drop.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt7996/init.c | 9 +++++++--
+ 1 file changed, 7 insertions(+), 2 deletions(-)
+
+diff --git a/mt7996/init.c b/mt7996/init.c
+index ced38ac8..479b2cee 100644
+--- a/mt7996/init.c
++++ b/mt7996/init.c
+@@ -374,10 +374,13 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
+
+ hw->max_tx_fragments = 4;
+
+- if (phy->mt76->cap.has_2ghz)
++ if (phy->mt76->cap.has_2ghz) {
+ phy->mt76->sband_2g.sband.ht_cap.cap |=
+ IEEE80211_HT_CAP_LDPC_CODING |
+ IEEE80211_HT_CAP_MAX_AMSDU;
++ phy->mt76->sband_2g.sband.ht_cap.ampdu_density =
++ IEEE80211_HT_MPDU_DENSITY_2;
++ }
+
+ if (phy->mt76->cap.has_5ghz) {
+ phy->mt76->sband_5g.sband.ht_cap.cap |=
+@@ -389,6 +392,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
+ IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK |
+ IEEE80211_VHT_CAP_SHORT_GI_160 |
+ IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
++ phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
++ IEEE80211_HT_MPDU_DENSITY_1;
+ }
+
+ mt76_set_stream_caps(phy->mt76, true);
+@@ -873,7 +878,7 @@ mt7996_init_he_caps(struct mt7996_phy *phy, enum nl80211_band band,
+ u16 cap = IEEE80211_HE_6GHZ_CAP_TX_ANTPAT_CONS |
+ IEEE80211_HE_6GHZ_CAP_RX_ANTPAT_CONS;
+
+- cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_2,
++ cap |= u16_encode_bits(IEEE80211_HT_MPDU_DENSITY_0_5,
+ IEEE80211_HE_6GHZ_CAP_MIN_MPDU_START) |
+ u16_encode_bits(IEEE80211_VHT_MAX_AMPDU_1024K,
+ IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP) |
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch
new file mode 100644
index 0000000..0b179f4
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch
@@ -0,0 +1,71 @@
+From b4af2c843368e7a787fc02ebde5a8ff41edf0a76 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Thu, 2 Mar 2023 15:44:52 +0800
+Subject: [PATCH 17/19] wifi: mt76: mt7996: fix icv error when enable AP and
+ STA simultaneously
+
+Fix mcu command content to prevent ICV error
+1. The legacy mld index needs to start from 16.
+2. The bmc_tx_wlan_idx needs to be the vif index rather
+than peer AP's index.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt7996/mcu.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index 09800ff2..829f7be6 100644
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -664,6 +664,7 @@ 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)
+ {
++#define MT7996_LEGACY_MLD_IDX_START 16
+ struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
+ struct bss_mld_tlv *mld;
+ struct tlv *tlv;
+@@ -672,8 +673,12 @@ 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 = MT7996_LEGACY_MLD_IDX_START + mvif->mt76.idx;
+ mld->remap_idx = 0xff;
++ if (vif->type == NL80211_IFTYPE_AP) {
++ mld->group_mld_id = MT7996_LEGACY_MLD_IDX_START + mvif->mt76.idx;
++ memcpy(mld->mac_addr, vif->bss_conf.bssid, ETH_ALEN);
++ }
+ }
+
+ static void
+@@ -744,6 +749,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ struct cfg80211_chan_def *chandef = &phy->chandef;
+ struct mt76_connac_bss_basic_tlv *bss;
+ u32 type = CONNECTION_INFRA_AP;
++ u16 sta_wlan_idx = wlan_idx;
+ struct tlv *tlv;
+ int idx;
+
+@@ -763,7 +769,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ struct mt76_wcid *wcid;
+
+ wcid = (struct mt76_wcid *)sta->drv_priv;
+- wlan_idx = wcid->idx;
++ sta_wlan_idx = wcid->idx;
+ }
+ rcu_read_unlock();
+ }
+@@ -783,7 +789,7 @@ mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
+ 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(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;
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0018-wifi-mt76-mt7996-set-wcid-in-txp.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0018-wifi-mt76-mt7996-set-wcid-in-txp.patch
new file mode 100644
index 0000000..74f4e9e
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0018-wifi-mt76-mt7996-set-wcid-in-txp.patch
@@ -0,0 +1,35 @@
+From 68649746f1862d6c9b3e06492789aadde8c4d2e5 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 6 Mar 2023 15:52:26 +0800
+Subject: [PATCH 18/19] wifi: mt76: mt7996: set wcid in txp
+
+Set correct wcid in txp for SDO to get wtbl.
+
+Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
+---
+ mt7996/mac.c | 8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+diff --git a/mt7996/mac.c b/mt7996/mac.c
+index 4c0c8f1e..bb23f531 100644
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -1168,10 +1168,12 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ }
+
+ txp->fw.token = cpu_to_le16(id);
+- if (test_bit(MT_WCID_FLAG_4ADDR, &wcid->flags))
+- txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
+- else
++ if ((is_8023 && is_multicast_ether_addr(tx_info->skb->data)) ||
++ is_multicast_ether_addr(hdr->addr1))
+ txp->fw.rept_wds_wcid = cpu_to_le16(0xfff);
++ else
++ txp->fw.rept_wds_wcid = cpu_to_le16(wcid->idx);
++
+ tx_info->skb = DMA_DUMMY_DATA;
+
+ /* pass partial skb header to fw */
+--
+2.39.2
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0019-mt76-revert-page-pool-changes.patch
similarity index 92%
rename from recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch
rename to recipes-wifi/linux-mt76/files/patches-3.x/0019-mt76-revert-page-pool-changes.patch
index ab1161f..20feead 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0019-mt76-revert-page-pool-changes.patch
@@ -1,7 +1,7 @@
-From 60c4e64c0198c828fafd5e7b96027ad5fd633213 Mon Sep 17 00:00:00 2001
+From 175bf122ac5790e7e28dadecd9410370364bc16a Mon Sep 17 00:00:00 2001
From: Shayne Chen <shayne.chen@mediatek.com>
Date: Mon, 6 Feb 2023 15:34:43 +0800
-Subject: [PATCH 7/7] mt76: revert page pool changes
+Subject: [PATCH 19/19] mt76: revert page pool changes
---
dma.c | 72 ++++++++++++++++++++++++++-------------------------
@@ -10,11 +10,11 @@
mt7915/main.c | 26 +++++++------------
mt7915/mmio.c | 55 ++++++++++++++++++++++++---------------
mt7921/main.c | 31 +++-------------------
- usb.c | 42 ++++++++++++++++--------------
- 7 files changed, 108 insertions(+), 197 deletions(-)
+ usb.c | 43 +++++++++++++++---------------
+ 7 files changed, 108 insertions(+), 198 deletions(-)
diff --git a/dma.c b/dma.c
-index e3fa4f39..50a7a689 100644
+index df2ca73f..7357b398 100644
--- a/dma.c
+++ b/dma.c
@@ -173,7 +173,7 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
@@ -39,7 +39,7 @@
buf = t->ptr;
t->dma_addr = 0;
-@@ -428,9 +428,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+@@ -430,9 +430,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
} else {
buf = e->buf;
e->buf = NULL;
@@ -52,7 +52,7 @@
}
return buf;
-@@ -582,11 +582,11 @@ free_skb:
+@@ -584,11 +584,11 @@ free_skb:
}
static int
@@ -67,7 +67,7 @@
if (!q->ndesc)
return 0;
-@@ -594,25 +594,26 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -596,25 +596,26 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
spin_lock_bh(&q->lock);
while (q->queued < q->ndesc - 1) {
@@ -105,7 +105,7 @@
break;
}
frames++;
-@@ -656,7 +657,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
+@@ -658,7 +659,7 @@ int mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q, bool reset)
/* WED txfree queue needs ring to be initialized before setup */
q->flags = 0;
mt76_dma_queue_reset(dev, q);
@@ -114,7 +114,7 @@
q->flags = flags;
ret = mtk_wed_device_txfree_ring_setup(wed, q->regs);
-@@ -704,10 +705,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -706,10 +707,6 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
if (!q->entry)
return -ENOMEM;
@@ -125,7 +125,7 @@
ret = mt76_dma_wed_setup(dev, q, false);
if (ret)
return ret;
-@@ -721,6 +718,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
+@@ -723,6 +720,7 @@ mt76_dma_alloc_queue(struct mt76_dev *dev, struct mt76_queue *q,
static void
mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
{
@@ -133,7 +133,7 @@
void *buf;
bool more;
-@@ -734,7 +732,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -736,7 +734,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
if (!buf)
break;
@@ -142,7 +142,7 @@
} while (1);
if (q->rx_head) {
-@@ -743,6 +741,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -745,6 +743,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
}
spin_unlock_bh(&q->lock);
@@ -156,7 +156,7 @@
}
static void
-@@ -763,7 +768,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
+@@ -765,7 +770,7 @@ mt76_dma_rx_reset(struct mt76_dev *dev, enum mt76_rxq_id qid)
mt76_dma_wed_setup(dev, q, true);
if (q->flags != MT_WED_Q_TXFREE) {
mt76_dma_sync_idx(dev, q);
@@ -165,7 +165,7 @@
}
}
-@@ -781,7 +786,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
+@@ -783,7 +788,7 @@ mt76_add_fragment(struct mt76_dev *dev, struct mt76_queue *q, void *data,
skb_add_rx_frag(skb, nr_frags, page, offset, len, q->buf_size);
} else {
@@ -174,7 +174,7 @@
}
if (more)
-@@ -854,7 +859,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -856,7 +861,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
goto free_frag;
skb_reserve(skb, q->buf_offset);
@@ -182,7 +182,7 @@
*(u32 *)skb->cb = info;
-@@ -870,10 +874,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+@@ -872,10 +876,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
continue;
free_frag:
@@ -195,7 +195,7 @@
return done;
}
-@@ -918,7 +922,7 @@ mt76_dma_init(struct mt76_dev *dev,
+@@ -920,7 +924,7 @@ mt76_dma_init(struct mt76_dev *dev,
mt76_for_each_q_rx(dev, i) {
netif_napi_add(&dev->napi_dev, &dev->napi[i], poll);
@@ -204,7 +204,7 @@
napi_enable(&dev->napi[i]);
}
-@@ -969,8 +973,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
+@@ -971,8 +975,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
netif_napi_del(&dev->napi[i]);
mt76_dma_rx_cleanup(dev, q);
@@ -214,7 +214,7 @@
mt76_free_pending_txwi(dev);
diff --git a/mac80211.c b/mac80211.c
-index b117e446..8a5f21e8 100644
+index e53166fc..d69e7214 100644
--- a/mac80211.c
+++ b/mac80211.c
@@ -4,7 +4,6 @@
@@ -225,7 +225,7 @@
#include "mt76.h"
#define CHAN2G(_idx, _freq) { \
-@@ -557,47 +556,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
+@@ -562,47 +561,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
}
EXPORT_SYMBOL_GPL(mt76_unregister_phy);
@@ -273,7 +273,7 @@
struct mt76_dev *
mt76_alloc_device(struct device *pdev, unsigned int size,
const struct ieee80211_ops *ops,
-@@ -1732,21 +1690,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
+@@ -1746,21 +1704,6 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
}
EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
@@ -296,7 +296,7 @@
{
struct ieee80211_hw *hw = phy->hw;
diff --git a/mt76.h b/mt76.h
-index ccca0162..f6a32fe3 100644
+index c3d1313e..49da2caa 100644
--- a/mt76.h
+++ b/mt76.h
@@ -202,7 +202,7 @@ struct mt76_queue {
@@ -308,7 +308,7 @@
};
struct mt76_mcu_ops {
-@@ -1318,7 +1318,6 @@ mt76u_bulk_msg(struct mt76_dev *dev, void *data, int len, int *actual_len,
+@@ -1329,7 +1329,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);
}
@@ -316,7 +316,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);
-@@ -1430,25 +1429,6 @@ void __mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked);
+@@ -1441,25 +1440,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);
@@ -401,7 +401,7 @@
static void
diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 225a1960..cbe6e2cd 100644
+index 6f0c0e2a..5ef43c44 100644
--- a/mt7915/mmio.c
+++ b/mt7915/mmio.c
@@ -596,9 +596,13 @@ static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
@@ -505,7 +505,7 @@
return -ENOMEM;
}
diff --git a/mt7921/main.c b/mt7921/main.c
-index 75eaf86c..1434ca79 100644
+index a72964e7..4c400223 100644
--- a/mt7921/main.c
+++ b/mt7921/main.c
@@ -1090,34 +1090,17 @@ static void
@@ -571,7 +571,7 @@
static u64
diff --git a/usb.c b/usb.c
-index b88959ef..3e281715 100644
+index 5e5c7bf5..3e281715 100644
--- a/usb.c
+++ b/usb.c
@@ -319,27 +319,29 @@ mt76u_set_endpoints(struct usb_interface *intf,
@@ -688,11 +688,12 @@
int i;
for (i = 0; i < q->ndesc; i++) {
-@@ -705,7 +701,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
+@@ -705,8 +701,13 @@ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
mt76u_urb_free(q->entry[i].urb);
q->entry[i].urb = NULL;
}
- page_pool_destroy(q->page_pool);
+- q->page_pool = NULL;
+
+ if (!q->rx_page.va)
+ return;
@@ -704,5 +705,5 @@
static void mt76u_free_rx(struct mt76_dev *dev)
--
-2.25.1
+2.39.2
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
index dd28dc9..2f9a0c3 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
@@ -1,4 +1,4 @@
-From e66fbcb72e09e9e6a88fcedc84f4eda0d53ef65d Mon Sep 17 00:00:00 2001
+From a126ad08af718c71b4b05261caefb68996044330 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] mt76: mt7996: for build pass
@@ -6,16 +6,15 @@
Change-Id: Ieb44c33ee6e6a2e6058c1ef528404c1a1cbcfdaf
---
debugfs.c | 3 +++
- dma.c | 2 +-
eeprom.c | 8 +++++++-
mcu.c | 1 +
mt7615/mcu.c | 1 +
mt76_connac_mcu.c | 1 +
mt7915/mcu.c | 1 +
mt7996/dma.c | 4 ++--
- mt7996/eeprom.c | 1 +
+ mt7996/eeprom.c | 2 ++
mt7996/mcu.c | 1 +
- 10 files changed, 19 insertions(+), 4 deletions(-)
+ 9 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/debugfs.c b/debugfs.c
index 79064a4d..e10d4cbc 100644
@@ -33,19 +32,6 @@
return 0;
}
-diff --git a/dma.c b/dma.c
-index 50a7a689..beb9f4a4 100644
---- a/dma.c
-+++ b/dma.c
-@@ -854,7 +854,7 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
- !(dev->drv->rx_check(dev, data, len)))
- goto free_frag;
-
-- skb = napi_build_skb(data, q->buf_size);
-+ skb = build_skb(data, q->buf_size);
- if (!skb)
- goto free_frag;
-
diff --git a/eeprom.c b/eeprom.c
index ea54b7af..90d36c8d 100644
--- a/eeprom.c
@@ -92,7 +78,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 efb9bfaa..4a650721 100644
+index 4e4f6b35..e5815227 100644
--- a/mt76_connac_mcu.c
+++ b/mt76_connac_mcu.c
@@ -4,6 +4,7 @@
@@ -104,7 +90,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 f151ce86..20d81f05 100644
+index d08907f5..99ef8c9c 100644
--- a/mt7915/mcu.c
+++ b/mt7915/mcu.c
@@ -6,6 +6,7 @@
@@ -116,7 +102,7 @@
#define fw_name(_dev, name, ...) ({ \
char *_fw; \
diff --git a/mt7996/dma.c b/mt7996/dma.c
-index c09fe427..8c2e060d 100644
+index 18ea758c..3e2967f7 100644
--- a/mt7996/dma.c
+++ b/mt7996/dma.c
@@ -343,8 +343,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
@@ -131,19 +117,20 @@
mt7996_dma_enable(dev);
diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
-index 2e48c5a4..dd322f62 100644
+index 2e48c5a4..e747cb9f 100644
--- a/mt7996/eeprom.c
+++ b/mt7996/eeprom.c
-@@ -98,6 +98,7 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
+@@ -98,6 +98,8 @@ static int mt7996_eeprom_parse_efuse_hw_cap(struct mt7996_dev *dev)
if (ret)
return ret;
-+ cap = 0x4b249248; /* internal hardcode */
++ /* for internal testing */
++ cap = 0x4b249248;
if (cap) {
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 1e47b0ae..db715195 100644
+index 829f7be6..0d9d309f 100644
--- a/mt7996/mcu.c
+++ b/mt7996/mcu.c
@@ -5,6 +5,7 @@
@@ -155,5 +142,5 @@
#include "mcu.h"
#include "mac.h"
--
-2.25.1
+2.39.2
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 cf59945..51df096 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
@@ -1,12 +1,23 @@
#patch patches (come from openwrt/lede/target/linux/mediatek)
SRC_URI_append = " \
- file://0000-sync-to-master.patch \
- file://0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch \
- file://0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch \
- file://0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch \
- file://0004-wifi-mt76-mt7996-add-muru-support.patch \
- file://0005-wifi-mt76-mt7996-set-txd-v1.patch \
- file://0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch \
- file://0007-mt76-revert-page-pool-changes.patch \
+ file://0001-wifi-mt76-mt7996-add-eht-rx-rate-support.patch \
+ file://0002-wifi-mt76-mt7996-let-non-bufferable-MMPDUs-use-corre.patch \
+ file://0003-wifi-mt76-mt7996-reduce-repeated-bss_info-and-sta_re.patch \
+ file://0004-wifi-mt76-mt7996-move-radio-enable-command-to-mt7996.patch \
+ file://0005-wifi-mt76-connac-set-correct-muar_idx-for-connac3-ch.patch \
+ file://0006-wifi-mt76-mt7996-fix-pointer-calculation-in-ie-count.patch \
+ file://0007-wifi-mt76-mt7996-remove-mt7996_mcu_set_pm.patch \
+ file://0008-wifi-mt76-mt7996-add-muru-support.patch \
+ file://0009-wifi-mt76-mt7996-set-txd-v1.patch \
+ file://0010-wifi-mt76-mt7996-add-thermal-protection-support.patch \
+ file://0011-wifi-mt76-mt7996-add-thermal-sensor-device-support.patch \
+ file://0012-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch \
+ file://0013-wifi-mt76-mt7996-add-L0.5-system-error-recovery-supp.patch \
+ file://0014-wifi-mt76-mt7996-add-dsp-firmware-download.patch \
+ file://0015-wifi-mt76-mt7996-fix-eeprom-antenna-bitfield-mask.patch \
+ file://0016-wifi-mt76-mt7996-init-mpdu-density.patch \
+ file://0017-wifi-mt76-mt7996-fix-icv-error-when-enable-AP-and-ST.patch \
+ file://0018-wifi-mt76-mt7996-set-wcid-in-txp.patch \
+ file://0019-mt76-revert-page-pool-changes.patch \
file://0999-mt76-mt7996-for-build-pass.patch \
"