[rdkb][common][bsp][Refactor and sync wifi from openwrt]

[Description]
feda97c [MAC80211][mt76][Enable sigma daemon in mt7988]
90bafdf [MAC80211][mt76][rework patches for mt7996]
1b21440 [MAC80211][mt76][Add mac80211 5.15 source]
c75c5a6 [MAC80211][mt76][Refactor mt76 internal patches]

[Release-log]

Change-Id: I5b2706e2673bc43437f51713260237f67e8fbea9
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
new file mode 100644
index 0000000..44a01ec
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0000-sync-to-master.patch
@@ -0,0 +1,249 @@
+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
new file mode 100644
index 0000000..1022535
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0001-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_tx_compl.patch
@@ -0,0 +1,96 @@
+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-fix-chainmask-calculation-in-mt7996.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-fix-chainmask-calculation-in-mt7996.patch
deleted file mode 100644
index dfc04e5..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0001-wifi-mt76-mt7996-fix-chainmask-calculation-in-mt7996.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-From 36dcb418d47fb74f7a5a6fb276ff2fee63f4533a Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Wed, 30 Nov 2022 23:18:03 +0800
-Subject: [PATCH 1/7] wifi: mt76: mt7996: fix chainmask calculation in
- mt7996_set_antenna()
-
-Fix per-band chainmask when restoring from the dev chainmask.
-
-Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
-Change-Id: Idf607cfdfb342fd283d2911231262f0f74994360
----
- mt7996/main.c | 5 ++++-
- 1 file changed, 4 insertions(+), 1 deletion(-)
-
-diff --git a/mt7996/main.c b/mt7996/main.c
-index 4421cd5..c423b05 100644
---- a/mt7996/main.c
-+++ b/mt7996/main.c
-@@ -880,7 +880,10 @@ mt7996_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
- 	phy->mt76->antenna_mask = tx_ant;
- 
- 	/* restore to the origin chainmask which might have auxiliary path */
--	if (hweight8(tx_ant) == max_nss)
-+	if (hweight8(tx_ant) == max_nss && band_idx < MT_BAND2)
-+		phy->mt76->chainmask = ((dev->chainmask >> shift) &
-+					(BIT(dev->chainshift[band_idx + 1] - shift) - 1)) << shift;
-+	else if (hweight8(tx_ant) == max_nss)
- 		phy->mt76->chainmask = (dev->chainmask >> shift) << shift;
- 	else
- 		phy->mt76->chainmask = tx_ant << shift;
--- 
-2.36.1
-
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
new file mode 100644
index 0000000..fb6581a
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0002-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_skb_.patch
@@ -0,0 +1,46 @@
+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-update-register-for-CFEND_RATE.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-update-register-for-CFEND_RATE.patch
deleted file mode 100644
index 927bbe6..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0002-wifi-mt76-mt7996-update-register-for-CFEND_RATE.patch
+++ /dev/null
@@ -1,85 +0,0 @@
-From 6098317d391c07b301bede6002c03ea0eed72103 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Thu, 1 Dec 2022 14:23:35 +0800
-Subject: [PATCH 2/7] wifi: mt76: mt7996: update register for CFEND_RATE
-
-In newer chipsets, CFEND_RATE setting has been moved to different hw
-module.
-
-Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
-Change-Id: I41dd443010ede910d934f38f4d86aaa3e7f31032
----
- mt7996/mac.c  |  2 +-
- mt7996/mmio.c |  1 +
- mt7996/regs.h | 15 ++++++++-------
- 3 files changed, 10 insertions(+), 8 deletions(-)
-
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 0b3e287..ce4242f 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -1690,7 +1690,7 @@ void mt7996_mac_set_timing(struct mt7996_phy *phy)
- 	else
- 		val = MT7996_CFEND_RATE_11B;
- 
--	mt76_rmw_field(dev, MT_AGG_ACR0(band_idx), MT_AGG_ACR_CFEND_RATE, val);
-+	mt76_rmw_field(dev, MT_RATE_HRCR0(band_idx), MT_RATE_HRCR0_CFEND_RATE, val);
- 	mt76_clear(dev, MT_ARB_SCR(band_idx),
- 		   MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
- }
-diff --git a/mt7996/mmio.c b/mt7996/mmio.c
-index 60781d0..d8a2c1a 100644
---- a/mt7996/mmio.c
-+++ b/mt7996/mmio.c
-@@ -21,6 +21,7 @@ static const struct __base mt7996_reg_base[] = {
- 	[WF_ETBF_BASE]		= { { 0x820ea000, 0x820fa000, 0x830ea000 } },
- 	[WF_LPON_BASE]		= { { 0x820eb000, 0x820fb000, 0x830eb000 } },
- 	[WF_MIB_BASE]		= { { 0x820ed000, 0x820fd000, 0x830ed000 } },
-+	[WF_RATE_BASE]		= { { 0x820ee000, 0x820fe000, 0x830ee000 } },
- };
- 
- static const struct __map mt7996_reg_map[] = {
-diff --git a/mt7996/regs.h b/mt7996/regs.h
-index 42980b9..7a28cae 100644
---- a/mt7996/regs.h
-+++ b/mt7996/regs.h
-@@ -33,6 +33,7 @@ enum base_rev {
- 	WF_ETBF_BASE,
- 	WF_LPON_BASE,
- 	WF_MIB_BASE,
-+	WF_RATE_BASE,
- 	__MT_REG_BASE_MAX,
- };
- 
-@@ -235,13 +236,6 @@ enum base_rev {
- 						 FIELD_PREP(MT_WTBL_LMAC_ID, _id) | \
- 						 FIELD_PREP(MT_WTBL_LMAC_DW, _dw))
- 
--/* AGG: band 0(0x820e2000), band 1(0x820f2000), band 2(0x830e2000) */
--#define MT_WF_AGG_BASE(_band)			__BASE(WF_AGG_BASE, (_band))
--#define MT_WF_AGG(_band, ofs)			(MT_WF_AGG_BASE(_band) + (ofs))
--
--#define MT_AGG_ACR0(_band)			MT_WF_AGG(_band, 0x054)
--#define MT_AGG_ACR_CFEND_RATE			GENMASK(13, 0)
--
- /* ARB: band 0(0x820e3000), band 1(0x820f3000), band 2(0x830e3000) */
- #define MT_WF_ARB_BASE(_band)			__BASE(WF_ARB_BASE, (_band))
- #define MT_WF_ARB(_band, ofs)			(MT_WF_ARB_BASE(_band) + (ofs))
-@@ -300,6 +294,13 @@ enum base_rev {
- #define MT_WF_RMAC_RSVD0(_band)			MT_WF_RMAC(_band, 0x03e0)
- #define MT_WF_RMAC_RSVD0_EIFS_CLR		BIT(21)
- 
-+/* RATE: band 0(0x820ee000), band 1(0x820fe000), band 2(0x830ee000) */
-+#define MT_WF_RATE_BASE(_band)			__BASE(WF_RATE_BASE, (_band))
-+#define MT_WF_RATE(_band, ofs)			(MT_WF_RATE_BASE(_band) + (ofs))
-+
-+#define MT_RATE_HRCR0(_band)			MT_WF_RATE(_band, 0x050)
-+#define MT_RATE_HRCR0_CFEND_RATE		GENMASK(14, 0)
-+
- /* WFDMA0 */
- #define MT_WFDMA0_BASE				0xd4000
- #define MT_WFDMA0(ofs)				(MT_WFDMA0_BASE + (ofs))
--- 
-2.36.1
-
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
new file mode 100644
index 0000000..43ea6c9
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0003-Revert-wifi-mt76-mt7996-rely-on-mt76_connac_txp_comm.patch
@@ -0,0 +1,163 @@
+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-do-not-hardcode-vht-beamform-cap.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-do-not-hardcode-vht-beamform-cap.patch
deleted file mode 100644
index 4d9142b..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0003-wifi-mt76-mt7996-do-not-hardcode-vht-beamform-cap.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From bc54af3f8657ee2633a1c976247fb8d2f07ad568 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 9 Dec 2022 16:38:03 +0800
-Subject: [PATCH 3/7] wifi: mt76: mt7996: do not hardcode vht beamform cap
-
-Use the sts variable when setting vht beamform sts cap.
-
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
-Change-Id: Idbc52c144220ee855251d4a316e475510cfdadad
----
- mt7996/init.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/mt7996/init.c b/mt7996/init.c
-index 64e8dfd..7a9692a 100644
---- a/mt7996/init.c
-+++ b/mt7996/init.c
-@@ -465,7 +465,7 @@ void mt7996_set_stream_vht_txbf_caps(struct mt7996_phy *phy)
- 
- 	*cap |= IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE |
- 		IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE |
--		(3 << IEEE80211_VHT_CAP_BEAMFORMEE_STS_SHIFT);
-+		FIELD_PREP(IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK, sts - 1);
- 
- 	*cap &= ~(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK |
- 		  IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE |
--- 
-2.36.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-connac-fix-POWER_CTRL-command-name-typo.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-connac-fix-POWER_CTRL-command-name-typo.patch
deleted file mode 100644
index 55c75e5..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-connac-fix-POWER_CTRL-command-name-typo.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From 5842d6dc7b6644545dac3444a522910a87df7e2b Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Fri, 9 Dec 2022 16:22:16 +0800
-Subject: [PATCH 4/7] wifi: mt76: connac: fix POWER_CTRL command name typo
-
-Fix typo MCU_UNI_CMD_POWER_CREL to MCU_UNI_CMD_POWER_CTRL.
-
-Fixes: 779d34de055e ("wifi: mt76: connac: add more unified command IDs")
-Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
-Change-Id: I89f9e930be97acb91b456c6361b8fb818fe6cbda
----
- mt76_connac_mcu.h | 2 +-
- mt7996/mcu.c      | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index f1e942b..82fdf6d 100644
---- a/mt76_connac_mcu.h
-+++ b/mt76_connac_mcu.h
-@@ -1198,7 +1198,7 @@ enum {
- 	MCU_UNI_CMD_REPT_MUAR = 0x09,
- 	MCU_UNI_CMD_WSYS_CONFIG = 0x0b,
- 	MCU_UNI_CMD_REG_ACCESS = 0x0d,
--	MCU_UNI_CMD_POWER_CREL = 0x0f,
-+	MCU_UNI_CMD_POWER_CTRL = 0x0f,
- 	MCU_UNI_CMD_RX_HDR_TRANS = 0x12,
- 	MCU_UNI_CMD_SER = 0x13,
- 	MCU_UNI_CMD_TWT = 0x14,
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index a88fc76..d781c6e 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -2399,7 +2399,7 @@ mt7996_mcu_restart(struct mt76_dev *dev)
- 		.power_mode = 1,
- 	};
- 
--	return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(POWER_CREL), &req,
-+	return mt76_mcu_send_msg(dev, MCU_WM_UNI_CMD(POWER_CTRL), &req,
- 				 sizeof(req), false);
- }
- 
--- 
-2.36.1
-
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/0004-wifi-mt76-mt7996-add-muru-support.patch
new file mode 100644
index 0000000..dab5182
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0004-wifi-mt76-mt7996-add-muru-support.patch
@@ -0,0 +1,141 @@
+From 7c8b8c77489ef907f2122c5d0edb7ff5e0fed177 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
+
+Add sta_rec_muru() and related phy cap for MU and RU support.
+
+Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
+Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
+Change-Id: I2206a9bb6fd6e50f4bf1380a8bea19920f1b7bfd
+---
+ mt76_connac_mcu.h |  3 ++-
+ mt7996/mcu.c      | 69 ++++++++++++++++++++++++++++++++++++++++++++++-
+ mt7996/mt7996.h   |  3 +++
+ 3 files changed, 73 insertions(+), 2 deletions(-)
+
+diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
+index a5e6ee4d..39667840 100644
+--- a/mt76_connac_mcu.h
++++ b/mt76_connac_mcu.h
+@@ -518,7 +518,8 @@ struct sta_rec_muru {
+ 		u8 uo_ra;
+ 		u8 he_2x996_tone;
+ 		u8 rx_t_frame_11ac;
+-		u8 rsv[3];
++		u8 rx_ctrl_frame_to_mbss;
++		u8 rsv[2];
+ 	} ofdma_ul;
+ 
+ 	struct {
+diff --git a/mt7996/mcu.c b/mt7996/mcu.c
+index dbe30832..394dd15c 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,
+ 	}
+ }
+ 
++static void
++mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
++			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
++{
++	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
++	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
++	struct sta_rec_muru *muru;
++	struct tlv *tlv;
++
++	if (vif->type != NL80211_IFTYPE_STATION &&
++	    vif->type != NL80211_IFTYPE_AP)
++		return;
++
++	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_MURU, sizeof(*muru));
++
++	muru = (struct sta_rec_muru *)tlv;
++
++	muru->cfg.mimo_dl_en = mvif->cap.eht_mu_ebfer_bw80 ||
++			       mvif->cap.eht_mu_ebfer_bw160 ||
++			       mvif->cap.eht_mu_ebfer_bw320 ||
++			       mvif->cap.he_mu_ebfer ||
++			       mvif->cap.vht_mu_ebfer ||
++			       mvif->cap.vht_mu_ebfee;
++	muru->cfg.ofdma_dl_en = true;
++
++	if (sta->deflink.vht_cap.vht_supported)
++		muru->mimo_dl.vht_mu_bfee =
++			!!(sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE);
++
++	if (!sta->deflink.he_cap.has_he)
++		return;
++
++	muru->mimo_dl.partial_bw_dl_mimo =
++		HE_PHY(CAP6_PARTIAL_BANDWIDTH_DL_MUMIMO, elem->phy_cap_info[6]);
++
++	muru->mimo_ul.full_ul_mimo =
++		HE_PHY(CAP2_UL_MU_FULL_MU_MIMO, elem->phy_cap_info[2]);
++	muru->mimo_ul.partial_ul_mimo =
++		HE_PHY(CAP2_UL_MU_PARTIAL_MU_MIMO, elem->phy_cap_info[2]);
++
++	muru->ofdma_dl.punc_pream_rx =
++		HE_PHY(CAP1_PREAMBLE_PUNC_RX_MASK, elem->phy_cap_info[1]);
++	muru->ofdma_dl.he_20m_in_40m_2g =
++		HE_PHY(CAP8_20MHZ_IN_40MHZ_HE_PPDU_IN_2G, elem->phy_cap_info[8]);
++	muru->ofdma_dl.he_20m_in_160m =
++		HE_PHY(CAP8_20MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
++	muru->ofdma_dl.he_80m_in_160m =
++		HE_PHY(CAP8_80MHZ_IN_160MHZ_HE_PPDU, elem->phy_cap_info[8]);
++
++	muru->ofdma_ul.t_frame_dur =
++		HE_MAC(CAP1_TF_MAC_PAD_DUR_MASK, elem->mac_cap_info[1]);
++	muru->ofdma_ul.mu_cascading =
++		HE_MAC(CAP2_MU_CASCADING, elem->mac_cap_info[2]);
++	muru->ofdma_ul.uo_ra =
++		HE_MAC(CAP3_OFDMA_RA, elem->mac_cap_info[3]);
++}
++
+ 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,
+ 		mt7996_mcu_sta_he_6g_tlv(skb, sta);
+ 		/* starec eht */
+ 		mt7996_mcu_sta_eht_tlv(skb, sta);
+-		/* TODO: starec muru */
++		/* starec muru */
++		mt7996_mcu_sta_muru_tlv(dev, skb, vif, sta);
+ 		/* 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,
+ 		vc->eht_su_ebfee =
+ 			EHT_PHY(CAP0_SU_BEAMFORMEE, eht->phy_cap_info[0]) &&
+ 			EHT_PHY(CAP0_SU_BEAMFORMEE, pe->phy_cap_info[0]);
++		vc->eht_mu_ebfer_bw80 =
++			EHT_PHY(CAP7_MU_BEAMFORMER_80MHZ, eht->phy_cap_info[7]) &&
++			EHT_PHY(CAP7_MU_BEAMFORMER_80MHZ, pe->phy_cap_info[7]);
++		vc->eht_mu_ebfer_bw160 =
++			EHT_PHY(CAP7_MU_BEAMFORMER_160MHZ, eht->phy_cap_info[7]) &&
++			EHT_PHY(CAP7_MU_BEAMFORMER_160MHZ, pe->phy_cap_info[7]);
++		vc->eht_mu_ebfer_bw320 =
++			EHT_PHY(CAP7_MU_BEAMFORMER_320MHZ, eht->phy_cap_info[7]) &&
++			EHT_PHY(CAP7_MU_BEAMFORMER_320MHZ, pe->phy_cap_info[7]);
+ 	}
+ }
+ 
+diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
+index 13f22432..64a804a4 100644
+--- a/mt7996/mt7996.h
++++ b/mt7996/mt7996.h
+@@ -125,6 +125,9 @@ struct mt7996_vif_cap {
+ 	bool he_mu_ebfer:1;
+ 	bool eht_su_ebfer:1;
+ 	bool eht_su_ebfee:1;
++	bool eht_mu_ebfer_bw80:1;
++	bool eht_mu_ebfer_bw160:1;
++	bool eht_mu_ebfer_bw320:1;
+ };
+ 
+ struct mt7996_vif {
+-- 
+2.25.1
+
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
new file mode 100644
index 0000000..8fddb93
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0005-wifi-mt76-mt7996-set-txd-v1.patch
@@ -0,0 +1,48 @@
+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-add-802.11s-mesh-amsdu-de-amsdu-sup.patch b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
new file mode 100644
index 0000000..70867df
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0006-wifi-mt76-mt7996-add-802.11s-mesh-amsdu-de-amsdu-sup.patch
@@ -0,0 +1,132 @@
+From 6298046de15b190139552d74aeb668e8cb873b1d 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
+ support
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt7996/mac.c  | 15 ++++++++++++++-
+ mt7996/mac.h  |  2 ++
+ mt7996/mcu.c  |  9 ++++++++-
+ 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
+--- a/mt7996/mac.c
++++ b/mt7996/mac.c
+@@ -630,6 +630,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;
++	u32 mesh_mask = MT_RXD0_MESH | MT_RXD0_MHCP;
+ 	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)
+ 
+ 		skb_pull(skb, hdr_gap);
+ 		if (!hdr_trans && status->amsdu) {
++		    if(ieee80211_has_a4(fc) && ((rxd0 & mesh_mask) == mesh_mask))
++			pad_start = 0;
++		    else
+ 			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)
+ 		hdr = mt76_skb_get_hdr(skb);
+ 		fc = hdr->frame_control;
+ 		if (ieee80211_is_data_qos(fc)) {
++			u8 *p = ieee80211_get_qos_ctl(hdr);
++
+ 			seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
+-			qos_ctl = *ieee80211_get_qos_ctl(hdr);
++			qos_ctl = *p;
++
++			/* the hardware support mesh de-amsdu by default,
++			 * so, clear amsdu present bit in the Qos Control field.
++			 */
++			if (ieee80211_has_a4(fc) && status->amsdu &&
++			    ((rxd0 & mesh_mask) == mesh_mask))
++				*p &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
+ 		}
+ 	} else {
+ 		status->flag |= RX_FLAG_8023;
+diff --git a/mt7996/mac.h b/mt7996/mac.h
+index 470b701a..fd0e5d1c 100644
+--- a/mt7996/mac.h
++++ b/mt7996/mac.h
+@@ -12,6 +12,8 @@
+ #define MT_RXD0_LENGTH			GENMASK(15, 0)
+ #define MT_RXD0_PKT_TYPE		GENMASK(31, 27)
+ 
++#define MT_RXD0_MESH			BIT(18)
++#define MT_RXD0_MHCP			BIT(19)
+ #define MT_RXD0_NORMAL_ETH_TYPE_OFS	GENMASK(22, 16)
+ #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
+--- 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,
+ 	struct tlv *tlv;
+ 
+ 	if (vif->type != NL80211_IFTYPE_STATION &&
+-	    vif->type != NL80211_IFTYPE_AP)
++	    vif->type != NL80211_IFTYPE_AP &&
++	    vif->type != NL80211_IFTYPE_MESH_POINT)
+ 		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,
+ 		hdr_trans->to_ds = true;
+ 		hdr_trans->from_ds = true;
+ 	}
++
++	if (vif->type == NL80211_IFTYPE_MESH_POINT) {
++		hdr_trans->to_ds = true;
++		hdr_trans->from_ds = true;
++		hdr_trans->mesh = true;
++	}
+ }
+ 
+ static enum mcu_mmps_mode
+diff --git a/mt7996/mcu.h b/mt7996/mcu.h
+index dd0c5ac5..009f5f06 100644
+--- a/mt7996/mcu.h
++++ b/mt7996/mcu.h
+@@ -396,7 +396,7 @@ struct sta_rec_hdr_trans {
+ 	u8 from_ds;
+ 	u8 to_ds;
+ 	u8 dis_rx_hdr_tran;
+-	u8 rsv;
++	u8 mesh;
+ } __packed;
+ 
+ struct hdr_trans_en {
+diff --git a/mt7996/mmio.c b/mt7996/mmio.c
+old mode 100644
+new mode 100755
+index d8a2c1a7..08164b1a
+--- 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),
+ 		.drv_flags = MT_DRV_TXWI_NO_FREE |
+-			     MT_DRV_HW_MGMT_TXQ,
++			     MT_DRV_HW_MGMT_TXQ |
++			     MT_DRV_AMSDU_OFFLOAD,
+ 		.survey_flags = SURVEY_INFO_TIME_TX |
+ 				SURVEY_INFO_TIME_RX |
+ 				SURVEY_INFO_TIME_BSS_RX,
+-- 
+2.25.1
+
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/0007-mt76-revert-page-pool-changes.patch
new file mode 100644
index 0000000..ab1161f
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0007-mt76-revert-page-pool-changes.patch
@@ -0,0 +1,708 @@
+From 60c4e64c0198c828fafd5e7b96027ad5fd633213 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
+
+---
+ dma.c         | 72 ++++++++++++++++++++++++++-------------------------
+ mac80211.c    | 57 ----------------------------------------
+ mt76.h        | 22 +---------------
+ mt7915/main.c | 26 +++++++------------
+ mt7915/mmio.c | 55 ++++++++++++++++++++++++---------------
+ mt7921/main.c | 31 +++-------------------
+ usb.c         | 42 ++++++++++++++++--------------
+ 7 files changed, 108 insertions(+), 197 deletions(-)
+
+diff --git a/dma.c b/dma.c
+index e3fa4f39..50a7a689 100644
+--- a/dma.c
++++ b/dma.c
+@@ -173,7 +173,7 @@ mt76_free_pending_rxwi(struct mt76_dev *dev)
+ 	local_bh_disable();
+ 	while ((t = __mt76_get_rxwi(dev)) != NULL) {
+ 		if (t->ptr)
+-			mt76_put_page_pool_buf(t->ptr, false);
++			skb_free_frag(t->ptr);
+ 		kfree(t);
+ 	}
+ 	local_bh_enable();
+@@ -409,9 +409,9 @@ mt76_dma_get_buf(struct mt76_dev *dev, struct mt76_queue *q, int idx,
+ 		if (!t)
+ 			return NULL;
+ 
+-		dma_sync_single_for_cpu(dev->dma_dev, t->dma_addr,
+-				SKB_WITH_OVERHEAD(q->buf_size),
+-				page_pool_get_dma_dir(q->page_pool));
++		dma_unmap_single(dev->dma_dev, t->dma_addr,
++				 SKB_WITH_OVERHEAD(q->buf_size),
++				 DMA_FROM_DEVICE);
+ 
+ 		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,
+ 	} else {
+ 		buf = e->buf;
+ 		e->buf = NULL;
+-		dma_sync_single_for_cpu(dev->dma_dev, e->dma_addr[0],
+-				SKB_WITH_OVERHEAD(q->buf_size),
+-				page_pool_get_dma_dir(q->page_pool));
++		dma_unmap_single(dev->dma_dev, e->dma_addr[0],
++				 SKB_WITH_OVERHEAD(q->buf_size),
++				 DMA_FROM_DEVICE);
+ 	}
+ 
+ 	return buf;
+@@ -582,11 +582,11 @@ free_skb:
+ }
+ 
+ static int
+-mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
+-		 bool allow_direct)
++mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q)
+ {
+ 	int len = SKB_WITH_OVERHEAD(q->buf_size);
+-	int frames = 0;
++	int frames = 0, offset = q->buf_offset;
++	dma_addr_t addr;
+ 
+ 	if (!q->ndesc)
+ 		return 0;
+@@ -594,25 +594,26 @@ mt76_dma_rx_fill(struct mt76_dev *dev, struct mt76_queue *q,
+ 	spin_lock_bh(&q->lock);
+ 
+ 	while (q->queued < q->ndesc - 1) {
+-		enum dma_data_direction dir;
+ 		struct mt76_queue_buf qbuf;
+-		dma_addr_t addr;
+-		int offset;
+-		void *buf;
++		void *buf = NULL;
+ 
+-		buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
++		buf = page_frag_alloc(&q->rx_page, q->buf_size, GFP_ATOMIC);
+ 		if (!buf)
+ 			break;
+ 
+-		addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
+-		dir = page_pool_get_dma_dir(q->page_pool);
+-		dma_sync_single_for_device(dev->dma_dev, addr, len, dir);
++		addr = dma_map_single(dev->dma_dev, buf, len, DMA_FROM_DEVICE);
++		if (unlikely(dma_mapping_error(dev->dma_dev, addr))) {
++			skb_free_frag(buf);
++			break;
++		}
+ 
+-		qbuf.addr = addr + q->buf_offset;
+-		qbuf.len = len - q->buf_offset;
++		qbuf.addr = addr + offset;
++		qbuf.len = len - offset;
+ 		qbuf.skip_unmap = false;
+ 		if (mt76_dma_add_rx_buf(dev, q, &qbuf, buf) < 0) {
+-			mt76_put_page_pool_buf(buf, allow_direct);
++			dma_unmap_single(dev->dma_dev, addr, len,
++					 DMA_FROM_DEVICE);
++			skb_free_frag(buf);
+ 			break;
+ 		}
+ 		frames++;
+@@ -656,7 +657,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);
+-		mt76_dma_rx_fill(dev, q, false);
++		mt76_dma_rx_fill(dev, q);
+ 		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,
+ 	if (!q->entry)
+ 		return -ENOMEM;
+ 
+-	ret = mt76_create_page_pool(dev, q);
+-	if (ret)
+-		return ret;
+-
+ 	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,
+ static void
+ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+ {
++	struct page *page;
+ 	void *buf;
+ 	bool more;
+ 
+@@ -734,7 +732,7 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+ 		if (!buf)
+ 			break;
+ 
+-		mt76_put_page_pool_buf(buf, false);
++		skb_free_frag(buf);
+ 	} while (1);
+ 
+ 	if (q->rx_head) {
+@@ -743,6 +741,13 @@ mt76_dma_rx_cleanup(struct mt76_dev *dev, struct mt76_queue *q)
+ 	}
+ 
+ 	spin_unlock_bh(&q->lock);
++
++	if (!q->rx_page.va)
++		return;
++
++	page = virt_to_page(q->rx_page.va);
++	__page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
++	memset(&q->rx_page, 0, sizeof(q->rx_page));
+ }
+ 
+ static void
+@@ -763,7 +768,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);
+-		mt76_dma_rx_fill(dev, q, false);
++		mt76_dma_rx_fill(dev, q);
+ 	}
+ }
+ 
+@@ -781,7 +786,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 {
+-		mt76_put_page_pool_buf(data, true);
++		skb_free_frag(data);
+ 	}
+ 
+ 	if (more)
+@@ -854,7 +859,6 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+ 			goto free_frag;
+ 
+ 		skb_reserve(skb, q->buf_offset);
+-		skb_mark_for_recycle(skb);
+ 
+ 		*(u32 *)skb->cb = info;
+ 
+@@ -870,10 +874,10 @@ mt76_dma_rx_process(struct mt76_dev *dev, struct mt76_queue *q, int budget)
+ 		continue;
+ 
+ free_frag:
+-		mt76_put_page_pool_buf(data, true);
++		skb_free_frag(data);
+ 	}
+ 
+-	mt76_dma_rx_fill(dev, q, true);
++	mt76_dma_rx_fill(dev, q);
+ 	return done;
+ }
+ 
+@@ -918,7 +922,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);
+-		mt76_dma_rx_fill(dev, &dev->q_rx[i], false);
++		mt76_dma_rx_fill(dev, &dev->q_rx[i]);
+ 		napi_enable(&dev->napi[i]);
+ 	}
+ 
+@@ -969,8 +973,6 @@ void mt76_dma_cleanup(struct mt76_dev *dev)
+ 
+ 		netif_napi_del(&dev->napi[i]);
+ 		mt76_dma_rx_cleanup(dev, q);
+-
+-		page_pool_destroy(q->page_pool);
+ 	}
+ 
+ 	mt76_free_pending_txwi(dev);
+diff --git a/mac80211.c b/mac80211.c
+index b117e446..8a5f21e8 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -4,7 +4,6 @@
+  */
+ #include <linux/sched.h>
+ #include <linux/of.h>
+-#include <net/page_pool.h>
+ #include "mt76.h"
+ 
+ #define CHAN2G(_idx, _freq) {			\
+@@ -557,47 +556,6 @@ void mt76_unregister_phy(struct mt76_phy *phy)
+ }
+ EXPORT_SYMBOL_GPL(mt76_unregister_phy);
+ 
+-int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q)
+-{
+-	struct page_pool_params pp_params = {
+-		.order = 0,
+-		.flags = PP_FLAG_PAGE_FRAG,
+-		.nid = NUMA_NO_NODE,
+-		.dev = dev->dma_dev,
+-	};
+-	int idx = q - dev->q_rx;
+-
+-	switch (idx) {
+-	case MT_RXQ_MAIN:
+-	case MT_RXQ_BAND1:
+-	case MT_RXQ_BAND2:
+-		pp_params.pool_size = 256;
+-		break;
+-	default:
+-		pp_params.pool_size = 16;
+-		break;
+-	}
+-
+-	if (mt76_is_mmio(dev)) {
+-		/* rely on page_pool for DMA mapping */
+-		pp_params.flags |= PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV;
+-		pp_params.dma_dir = DMA_FROM_DEVICE;
+-		pp_params.max_len = PAGE_SIZE;
+-		pp_params.offset = 0;
+-	}
+-
+-	q->page_pool = page_pool_create(&pp_params);
+-	if (IS_ERR(q->page_pool)) {
+-		int err = PTR_ERR(q->page_pool);
+-
+-		q->page_pool = NULL;
+-		return err;
+-	}
+-
+-	return 0;
+-}
+-EXPORT_SYMBOL_GPL(mt76_create_page_pool);
+-
+ 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,
+ }
+ EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
+ 
+-void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index)
+-{
+-#ifdef CONFIG_PAGE_POOL_STATS
+-	struct page_pool_stats stats = {};
+-	int i;
+-
+-	mt76_for_each_q_rx(dev, i)
+-		page_pool_get_stats(dev->q_rx[i].page_pool, &stats);
+-
+-	page_pool_ethtool_stats_get(data, &stats);
+-	*index += page_pool_ethtool_stats_get_count();
+-#endif
+-}
+-EXPORT_SYMBOL_GPL(mt76_ethtool_page_pool_stats);
+-
+ enum mt76_dfs_state mt76_phy_dfs_state(struct mt76_phy *phy)
+ {
+ 	struct ieee80211_hw *hw = phy->hw;
+diff --git a/mt76.h b/mt76.h
+index ccca0162..f6a32fe3 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -202,7 +202,7 @@ struct mt76_queue {
+ 
+ 	dma_addr_t desc_dma;
+ 	struct sk_buff *rx_head;
+-	struct page_pool *page_pool;
++	struct page_frag_cache rx_page;
+ };
+ 
+ struct mt76_mcu_ops {
+@@ -1318,7 +1318,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);
+ }
+ 
+-void mt76_ethtool_page_pool_stats(struct mt76_dev *dev, u64 *data, int *index);
+ 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);
+ 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);
+-int mt76_create_page_pool(struct mt76_dev *dev, struct mt76_queue *q);
+-static inline void mt76_put_page_pool_buf(void *buf, bool allow_direct)
+-{
+-	struct page *page = virt_to_head_page(buf);
+-
+-	page_pool_put_full_page(page->pp, page, allow_direct);
+-}
+-
+-static inline void *
+-mt76_get_page_pool_buf(struct mt76_queue *q, u32 *offset, u32 size)
+-{
+-	struct page *page;
+-
+-	page = page_pool_dev_alloc_frag(q->page_pool, offset, size);
+-	if (!page)
+-		return NULL;
+-
+-	return page_address(page) + *offset;
+-}
+ 
+ static inline void mt76_set_tx_blocked(struct mt76_dev *dev, bool blocked)
+ {
+diff --git a/mt7915/main.c b/mt7915/main.c
+index 3bbccbdf..161a2d1e 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -1291,22 +1291,19 @@ void mt7915_get_et_strings(struct ieee80211_hw *hw,
+ 			   struct ieee80211_vif *vif,
+ 			   u32 sset, u8 *data)
+ {
+-	if (sset != ETH_SS_STATS)
+-		return;
+-
+-	memcpy(data, *mt7915_gstrings_stats, sizeof(mt7915_gstrings_stats));
+-	data += sizeof(mt7915_gstrings_stats);
+-	page_pool_ethtool_stats_get_strings(data);
++	if (sset == ETH_SS_STATS)
++		memcpy(data, *mt7915_gstrings_stats,
++		       sizeof(mt7915_gstrings_stats));
+ }
+ 
+ static
+ int mt7915_get_et_sset_count(struct ieee80211_hw *hw,
+ 			     struct ieee80211_vif *vif, int sset)
+ {
+-	if (sset != ETH_SS_STATS)
+-		return 0;
++	if (sset == ETH_SS_STATS)
++		return MT7915_SSTATS_LEN;
+ 
+-	return MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count();
++	return 0;
+ }
+ 
+ static void mt7915_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
+@@ -1334,7 +1331,7 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
+ 	};
+ 	struct mib_stats *mib = &phy->mib;
+ 	/* See mt7915_ampdu_stat_read_phy, etc */
+-	int i, ei = 0, stats_size;
++	int i, ei = 0;
+ 
+ 	mutex_lock(&dev->mt76.mutex);
+ 
+@@ -1415,12 +1412,9 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
+ 		return;
+ 
+ 	ei += wi.worker_stat_count;
+-
+-	mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei);
+-
+-	stats_size = MT7915_SSTATS_LEN + page_pool_ethtool_stats_get_count();
+-	if (ei != stats_size)
+-		dev_err(dev->mt76.dev, "ei: %d size: %d", ei, stats_size);
++	if (ei != MT7915_SSTATS_LEN)
++		dev_err(dev->mt76.dev, "ei: %d  MT7915_SSTATS_LEN: %d",
++			ei, (int)MT7915_SSTATS_LEN);
+ }
+ 
+ static void
+diff --git a/mt7915/mmio.c b/mt7915/mmio.c
+index 225a1960..cbe6e2cd 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)
+ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
+ {
+ 	struct mt7915_dev *dev;
++	u32 length;
+ 	int i;
+ 
+ 	dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
++	length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size +
++				sizeof(struct skb_shared_info));
++
+ 	for (i = 0; i < dev->mt76.rx_token_size; i++) {
+ 		struct mt76_txwi_cache *t;
+ 
+@@ -606,7 +610,9 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
+ 		if (!t || !t->ptr)
+ 			continue;
+ 
+-		mt76_put_page_pool_buf(t->ptr, false);
++		dma_unmap_single(dev->mt76.dma_dev, t->dma_addr,
++				 wed->wlan.rx_size, DMA_FROM_DEVICE);
++		__free_pages(virt_to_page(t->ptr), get_order(length));
+ 		t->ptr = NULL;
+ 
+ 		mt76_put_rxwi(&dev->mt76, t);
+@@ -618,38 +624,47 @@ static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
+ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
+ {
+ 	struct mtk_rxbm_desc *desc = wed->rx_buf_ring.desc;
+-	struct mt76_txwi_cache *t = NULL;
+ 	struct mt7915_dev *dev;
+-	struct mt76_queue *q;
+-	int i, len;
++	u32 length;
++	int i;
+ 
+ 	dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
+-	q = &dev->mt76.q_rx[MT_RXQ_MAIN];
+-	len = SKB_WITH_OVERHEAD(q->buf_size);
++	length = SKB_DATA_ALIGN(NET_SKB_PAD + wed->wlan.rx_size +
++				sizeof(struct skb_shared_info));
+ 
+ 	for (i = 0; i < size; i++) {
+-		enum dma_data_direction dir;
+-		dma_addr_t addr;
+-		u32 offset;
++		struct mt76_txwi_cache *t = mt76_get_rxwi(&dev->mt76);
++		dma_addr_t phy_addr;
++		struct page *page;
+ 		int token;
+-		void *buf;
++		void *ptr;
+ 
+-		t = mt76_get_rxwi(&dev->mt76);
+ 		if (!t)
+ 			goto unmap;
+ 
+-		buf = mt76_get_page_pool_buf(q, &offset, q->buf_size);
+-		if (!buf)
++		page = __dev_alloc_pages(GFP_KERNEL, get_order(length));
++		if (!page) {
++			mt76_put_rxwi(&dev->mt76, t);
+ 			goto unmap;
++		}
+ 
+-		addr = page_pool_get_dma_addr(virt_to_head_page(buf)) + offset;
+-		dir = page_pool_get_dma_dir(q->page_pool);
+-		dma_sync_single_for_device(dev->mt76.dma_dev, addr, len, dir);
++		ptr = page_address(page);
++		phy_addr = dma_map_single(dev->mt76.dma_dev, ptr,
++					  wed->wlan.rx_size,
++					  DMA_TO_DEVICE);
++		if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) {
++			__free_pages(page, get_order(length));
++			mt76_put_rxwi(&dev->mt76, t);
++			goto unmap;
++		}
+ 
+-		desc->buf0 = cpu_to_le32(addr);
+-		token = mt76_rx_token_consume(&dev->mt76, buf, t, addr);
++		desc->buf0 = cpu_to_le32(phy_addr);
++		token = mt76_rx_token_consume(&dev->mt76, ptr, t, phy_addr);
+ 		if (token < 0) {
+-			mt76_put_page_pool_buf(buf, false);
++			dma_unmap_single(dev->mt76.dma_dev, phy_addr,
++					 wed->wlan.rx_size, DMA_TO_DEVICE);
++			__free_pages(page, get_order(length));
++			mt76_put_rxwi(&dev->mt76, t);
+ 			goto unmap;
+ 		}
+ 
+@@ -661,8 +676,6 @@ static u32 mt7915_mmio_wed_init_rx_buf(struct mtk_wed_device *wed, int size)
+ 	return 0;
+ 
+ unmap:
+-	if (t)
+-		mt76_put_rxwi(&dev->mt76, t);
+ 	mt7915_mmio_wed_release_rx_buf(wed);
+ 	return -ENOMEM;
+ }
+diff --git a/mt7921/main.c b/mt7921/main.c
+index 75eaf86c..1434ca79 100644
+--- a/mt7921/main.c
++++ b/mt7921/main.c
+@@ -1090,34 +1090,17 @@ static void
+ mt7921_get_et_strings(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 		      u32 sset, u8 *data)
+ {
+-	struct mt7921_dev *dev = mt7921_hw_dev(hw);
+-
+ 	if (sset != ETH_SS_STATS)
+ 		return;
+ 
+ 	memcpy(data, *mt7921_gstrings_stats, sizeof(mt7921_gstrings_stats));
+-
+-	if (mt76_is_sdio(&dev->mt76))
+-		return;
+-
+-	data += sizeof(mt7921_gstrings_stats);
+-	page_pool_ethtool_stats_get_strings(data);
+ }
+ 
+ static int
+ mt7921_get_et_sset_count(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 			 int sset)
+ {
+-	struct mt7921_dev *dev = mt7921_hw_dev(hw);
+-
+-	if (sset != ETH_SS_STATS)
+-		return 0;
+-
+-	if (mt76_is_sdio(&dev->mt76))
+-		return ARRAY_SIZE(mt7921_gstrings_stats);
+-
+-	return ARRAY_SIZE(mt7921_gstrings_stats) +
+-	       page_pool_ethtool_stats_get_count();
++	return sset == ETH_SS_STATS ? ARRAY_SIZE(mt7921_gstrings_stats) : 0;
+ }
+ 
+ static void
+@@ -1137,7 +1120,6 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 			 struct ethtool_stats *stats, u64 *data)
+ {
+ 	struct mt7921_vif *mvif = (struct mt7921_vif *)vif->drv_priv;
+-	int stats_size = ARRAY_SIZE(mt7921_gstrings_stats);
+ 	struct mt7921_phy *phy = mt7921_hw_phy(hw);
+ 	struct mt7921_dev *dev = phy->dev;
+ 	struct mib_stats *mib = &phy->mib;
+@@ -1193,14 +1175,9 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 		return;
+ 
+ 	ei += wi.worker_stat_count;
+-
+-	if (!mt76_is_sdio(&dev->mt76)) {
+-		mt76_ethtool_page_pool_stats(&dev->mt76, &data[ei], &ei);
+-		stats_size += page_pool_ethtool_stats_get_count();
+-	}
+-
+-	if (ei != stats_size)
+-		dev_err(dev->mt76.dev, "ei: %d  SSTATS_LEN: %d", ei, stats_size);
++	if (ei != ARRAY_SIZE(mt7921_gstrings_stats))
++		dev_err(dev->mt76.dev, "ei: %d  SSTATS_LEN: %zu",
++			ei, ARRAY_SIZE(mt7921_gstrings_stats));
+ }
+ 
+ static u64
+diff --git a/usb.c b/usb.c
+index b88959ef..3e281715 100644
+--- a/usb.c
++++ b/usb.c
+@@ -319,27 +319,29 @@ mt76u_set_endpoints(struct usb_interface *intf,
+ 
+ static int
+ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
+-		 int nsgs)
++		 int nsgs, gfp_t gfp)
+ {
+ 	int i;
+ 
+ 	for (i = 0; i < nsgs; i++) {
++		struct page *page;
+ 		void *data;
+ 		int offset;
+ 
+-		data = mt76_get_page_pool_buf(q, &offset, q->buf_size);
++		data = page_frag_alloc(&q->rx_page, q->buf_size, gfp);
+ 		if (!data)
+ 			break;
+ 
+-		sg_set_page(&urb->sg[i], virt_to_head_page(data), q->buf_size,
+-			    offset);
++		page = virt_to_head_page(data);
++		offset = data - page_address(page);
++		sg_set_page(&urb->sg[i], page, q->buf_size, offset);
+ 	}
+ 
+ 	if (i < nsgs) {
+ 		int j;
+ 
+ 		for (j = nsgs; j < urb->num_sgs; j++)
+-			mt76_put_page_pool_buf(sg_virt(&urb->sg[j]), false);
++			skb_free_frag(sg_virt(&urb->sg[j]));
+ 		urb->num_sgs = i;
+ 	}
+ 
+@@ -352,16 +354,15 @@ mt76u_fill_rx_sg(struct mt76_dev *dev, struct mt76_queue *q, struct urb *urb,
+ 
+ static int
+ mt76u_refill_rx(struct mt76_dev *dev, struct mt76_queue *q,
+-		struct urb *urb, int nsgs)
++		struct urb *urb, int nsgs, gfp_t gfp)
+ {
+ 	enum mt76_rxq_id qid = q - &dev->q_rx[MT_RXQ_MAIN];
+-	int offset;
+ 
+ 	if (qid == MT_RXQ_MAIN && dev->usb.sg_en)
+-		return mt76u_fill_rx_sg(dev, q, urb, nsgs);
++		return mt76u_fill_rx_sg(dev, q, urb, nsgs, gfp);
+ 
+ 	urb->transfer_buffer_length = q->buf_size;
+-	urb->transfer_buffer = mt76_get_page_pool_buf(q, &offset, q->buf_size);
++	urb->transfer_buffer = page_frag_alloc(&q->rx_page, q->buf_size, gfp);
+ 
+ 	return urb->transfer_buffer ? 0 : -ENOMEM;
+ }
+@@ -399,7 +400,7 @@ mt76u_rx_urb_alloc(struct mt76_dev *dev, struct mt76_queue *q,
+ 	if (err)
+ 		return err;
+ 
+-	return mt76u_refill_rx(dev, q, e->urb, sg_size);
++	return mt76u_refill_rx(dev, q, e->urb, sg_size, GFP_KERNEL);
+ }
+ 
+ static void mt76u_urb_free(struct urb *urb)
+@@ -407,10 +408,10 @@ static void mt76u_urb_free(struct urb *urb)
+ 	int i;
+ 
+ 	for (i = 0; i < urb->num_sgs; i++)
+-		mt76_put_page_pool_buf(sg_virt(&urb->sg[i]), false);
++		skb_free_frag(sg_virt(&urb->sg[i]));
+ 
+ 	if (urb->transfer_buffer)
+-		mt76_put_page_pool_buf(urb->transfer_buffer, false);
++		skb_free_frag(urb->transfer_buffer);
+ 
+ 	usb_free_urb(urb);
+ }
+@@ -546,8 +547,6 @@ mt76u_process_rx_entry(struct mt76_dev *dev, struct urb *urb,
+ 		len -= data_len;
+ 		nsgs++;
+ 	}
+-
+-	skb_mark_for_recycle(skb);
+ 	dev->drv->rx_skb(dev, MT_RXQ_MAIN, skb, NULL);
+ 
+ 	return nsgs;
+@@ -613,7 +612,7 @@ mt76u_process_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
+ 
+ 		count = mt76u_process_rx_entry(dev, urb, q->buf_size);
+ 		if (count > 0) {
+-			err = mt76u_refill_rx(dev, q, urb, count);
++			err = mt76u_refill_rx(dev, q, urb, count, GFP_ATOMIC);
+ 			if (err < 0)
+ 				break;
+ 		}
+@@ -664,10 +663,6 @@ mt76u_alloc_rx_queue(struct mt76_dev *dev, enum mt76_rxq_id qid)
+ 	struct mt76_queue *q = &dev->q_rx[qid];
+ 	int i, err;
+ 
+-	err = mt76_create_page_pool(dev, q);
+-	if (err)
+-		return err;
+-
+ 	spin_lock_init(&q->lock);
+ 	q->entry = devm_kcalloc(dev->dev,
+ 				MT_NUM_RX_ENTRIES, sizeof(*q->entry),
+@@ -696,6 +691,7 @@ EXPORT_SYMBOL_GPL(mt76u_alloc_mcu_queue);
+ static void
+ mt76u_free_rx_queue(struct mt76_dev *dev, struct mt76_queue *q)
+ {
++	struct page *page;
+ 	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)
+ 		mt76u_urb_free(q->entry[i].urb);
+ 		q->entry[i].urb = NULL;
+ 	}
+-	page_pool_destroy(q->page_pool);
++
++	if (!q->rx_page.va)
++		return;
++
++	page = virt_to_page(q->rx_page.va);
++	__page_frag_cache_drain(page, q->rx_page.pagecnt_bias);
++	memset(&q->rx_page, 0, sizeof(q->rx_page));
+ }
+ 
+ static void mt76u_free_rx(struct mt76_dev *dev)
+-- 
+2.25.1
+
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
new file mode 100644
index 0000000..dd28dc9
--- /dev/null
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/0999-mt76-mt7996-for-build-pass.patch
@@ -0,0 +1,159 @@
+From e66fbcb72e09e9e6a88fcedc84f4eda0d53ef65d 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
+
+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/mcu.c      | 1 +
+ 10 files changed, 19 insertions(+), 4 deletions(-)
+
+diff --git a/debugfs.c b/debugfs.c
+index 79064a4d..e10d4cbc 100644
+--- a/debugfs.c
++++ b/debugfs.c
+@@ -33,8 +33,11 @@ mt76_napi_threaded_set(void *data, u64 val)
+ 	if (!mt76_is_mmio(dev))
+ 		return -EOPNOTSUPP;
+ 
++#if 0
++	/* need to backport patch from networking stack */
+ 	if (dev->napi_dev.threaded != val)
+ 		return dev_set_threaded(&dev->napi_dev, val);
++#endif
+ 
+ 	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
++++ b/eeprom.c
+@@ -106,9 +106,15 @@ void
+ mt76_eeprom_override(struct mt76_phy *phy)
+ {
+ 	struct mt76_dev *dev = phy->dev;
++#ifdef CONFIG_OF
+ 	struct device_node *np = dev->dev->of_node;
++	const u8 *mac = NULL;
+ 
+-	of_get_mac_address(np, phy->macaddr);
++	if (np)
++		mac = of_get_mac_address(np);
++	if (!IS_ERR_OR_NULL(mac))
++		ether_addr_copy(phy->macaddr, mac);
++#endif
+ 
+ 	if (!is_valid_ether_addr(phy->macaddr)) {
+ 		eth_random_addr(phy->macaddr);
+diff --git a/mcu.c b/mcu.c
+index a8cafa39..fa4b0544 100644
+--- a/mcu.c
++++ b/mcu.c
+@@ -4,6 +4,7 @@
+  */
+ 
+ #include "mt76.h"
++#include <linux/moduleparam.h>
+ 
+ struct sk_buff *
+ __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
+diff --git a/mt7615/mcu.c b/mt7615/mcu.c
+index eea398c7..4593b2e1 100644
+--- a/mt7615/mcu.c
++++ b/mt7615/mcu.c
+@@ -10,6 +10,7 @@
+ #include "mcu.h"
+ #include "mac.h"
+ #include "eeprom.h"
++#include <linux/moduleparam.h>
+ 
+ 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
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -4,6 +4,7 @@
+ #include <linux/firmware.h>
+ #include "mt76_connac2_mac.h"
+ #include "mt76_connac_mcu.h"
++#include <linux/module.h>
+ 
+ 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
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -6,6 +6,7 @@
+ #include "mcu.h"
+ #include "mac.h"
+ #include "eeprom.h"
++#include <linux/moduleparam.h>
+ 
+ #define fw_name(_dev, name, ...)	({			\
+ 	char *_fw;						\
+diff --git a/mt7996/dma.c b/mt7996/dma.c
+index c09fe427..8c2e060d 100644
+--- a/mt7996/dma.c
++++ b/mt7996/dma.c
+@@ -343,8 +343,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
+ 	if (ret < 0)
+ 		return ret;
+ 
+-	netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
+-			  mt7996_poll_tx);
++	netif_tx_napi_add(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
++			  mt7996_poll_tx, NAPI_POLL_WEIGHT);
+ 	napi_enable(&dev->mt76.tx_napi);
+ 
+ 	mt7996_dma_enable(dev);
+diff --git a/mt7996/eeprom.c b/mt7996/eeprom.c
+index 2e48c5a4..dd322f62 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)
+ 	if (ret)
+ 		return ret;
+ 
++	cap = 0x4b249248;	/* internal hardcode */
+ 	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
+--- a/mt7996/mcu.c
++++ b/mt7996/mcu.c
+@@ -5,6 +5,7 @@
+ 
+ #include <linux/firmware.h>
+ #include <linux/fs.h>
++#include <linux/moduleparam.h>
+ #include "mt7996.h"
+ #include "mcu.h"
+ #include "mac.h"
+-- 
+2.25.1
+
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/4001-mt76-mt7996-for-build-pass.patch b/recipes-wifi/linux-mt76/files/patches-3.x/4001-mt76-mt7996-for-build-pass.patch
deleted file mode 100644
index 3f327fc..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/4001-mt76-mt7996-for-build-pass.patch
+++ /dev/null
@@ -1,67 +0,0 @@
-From c7c415e89ab0e47caa0d0a8d6b62bc179a16c35a Mon Sep 17 00:00:00 2001
-From: Evelyn Tsai <evelyn.tsai@mediatek.com>
-Date: Fri, 23 Dec 2022 17:28:03 +0800
-Subject: [PATCH 4001/4003] mt76: mt7996: for build pass
-
----
- debugfs.c    | 3 +++
- dma.c        | 4 ++--
- mt7996/dma.c | 4 ++--
- 3 files changed, 7 insertions(+), 4 deletions(-)
-
-diff --git a/debugfs.c b/debugfs.c
-index 79064a4..e10d4cb 100644
---- a/debugfs.c
-+++ b/debugfs.c
-@@ -33,8 +33,11 @@ mt76_napi_threaded_set(void *data, u64 val)
- 	if (!mt76_is_mmio(dev))
- 		return -EOPNOTSUPP;
- 
-+#if 0
-+	/* need to backport patch from networking stack */
- 	if (dev->napi_dev.threaded != val)
- 		return dev_set_threaded(&dev->napi_dev, val);
-+#endif
- 
- 	return 0;
- }
-diff --git a/dma.c b/dma.c
-index fc24b35..beb03cd 100644
---- a/dma.c
-+++ b/dma.c
-@@ -627,7 +627,7 @@ mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
- 
- 	switch (type) {
- 	case MT76_WED_Q_TX:
--		ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs);
-+		ret = mtk_wed_device_tx_ring_setup(wed, ring, q->regs, 0);
- 		if (!ret)
- 			q->wed_regs = wed->tx_ring[ring].reg_base;
- 		break;
-@@ -643,7 +643,7 @@ mt76_dma_wed_setup(struct mt76_dev *dev, struct mt76_queue *q)
- 			q->wed_regs = wed->txfree_ring.reg_base;
- 		break;
- 	case MT76_WED_Q_RX:
--		ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs);
-+		ret = mtk_wed_device_rx_ring_setup(wed, ring, q->regs, 0);
- 		if (!ret)
- 			q->wed_regs = wed->rx_ring[ring].reg_base;
- 		break;
-diff --git a/mt7996/dma.c b/mt7996/dma.c
-index c09fe42..8c2e060 100644
---- a/mt7996/dma.c
-+++ b/mt7996/dma.c
-@@ -343,8 +343,8 @@ int mt7996_dma_init(struct mt7996_dev *dev)
- 	if (ret < 0)
- 		return ret;
- 
--	netif_napi_add_tx(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
--			  mt7996_poll_tx);
-+	netif_tx_napi_add(&dev->mt76.tx_napi_dev, &dev->mt76.tx_napi,
-+			  mt7996_poll_tx, NAPI_POLL_WEIGHT);
- 	napi_enable(&dev->mt76.tx_napi);
- 
- 	mt7996_dma_enable(dev);
--- 
-2.36.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/4002-mt76-revert-get_of_mac_addr.patch b/recipes-wifi/linux-mt76/files/patches-3.x/4002-mt76-revert-get_of_mac_addr.patch
deleted file mode 100644
index ad2ac2e..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/4002-mt76-revert-get_of_mac_addr.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From 4b50024ac0c221561d57a947fa6e76faf613c1a6 Mon Sep 17 00:00:00 2001
-From: Shayne Chen <shayne.chen@mediatek.com>
-Date: Tue, 13 Dec 2022 10:51:46 +0800
-Subject: [PATCH 4002/4003] mt76: revert get_of_mac_addr
-
----
- eeprom.c | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
-diff --git a/eeprom.c b/eeprom.c
-index 0a88048..680f76f 100644
---- a/eeprom.c
-+++ b/eeprom.c
-@@ -106,9 +106,15 @@ void
- mt76_eeprom_override(struct mt76_phy *phy)
- {
- 	struct mt76_dev *dev = phy->dev;
-+#ifdef CONFIG_OF
- 	struct device_node *np = dev->dev->of_node;
-+	const u8 *mac = NULL;
- 
--	of_get_mac_address(np, phy->macaddr);
-+	if (np)
-+		mac = of_get_mac_address(np);
-+	if (!IS_ERR_OR_NULL(mac))
-+		ether_addr_copy(phy->macaddr, mac);
-+#endif
- 
- 	if (!is_valid_ether_addr(phy->macaddr)) {
- 		eth_random_addr(phy->macaddr);
--- 
-2.36.1
-
diff --git a/recipes-wifi/linux-mt76/files/patches-3.x/4003-mt76-include-header-files-for-module-param.patch b/recipes-wifi/linux-mt76/files/patches-3.x/4003-mt76-include-header-files-for-module-param.patch
deleted file mode 100644
index 6fc5e0b..0000000
--- a/recipes-wifi/linux-mt76/files/patches-3.x/4003-mt76-include-header-files-for-module-param.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-From 6ca19bb406e52edaed41d8ea84f67e872df113a4 Mon Sep 17 00:00:00 2001
-From: Evelyn Tsai <evelyn.tsai@mediatek.com>
-Date: Fri, 23 Dec 2022 17:06:03 +0800
-Subject: [PATCH 4003/4003] mt76: include header files for module param
-
----
- mcu.c             | 1 +
- mt7615/mcu.c      | 1 +
- mt76_connac_mcu.c | 1 +
- mt7915/mcu.c      | 1 +
- mt7996/mcu.c      | 1 +
- 5 files changed, 5 insertions(+)
-
-diff --git a/mcu.c b/mcu.c
-index a8cafa3..fa4b054 100644
---- a/mcu.c
-+++ b/mcu.c
-@@ -4,6 +4,7 @@
-  */
- 
- #include "mt76.h"
-+#include <linux/moduleparam.h>
- 
- struct sk_buff *
- __mt76_mcu_msg_alloc(struct mt76_dev *dev, const void *data,
-diff --git a/mt7615/mcu.c b/mt7615/mcu.c
-index 83f3030..e917d02 100644
---- a/mt7615/mcu.c
-+++ b/mt7615/mcu.c
-@@ -10,6 +10,7 @@
- #include "mcu.h"
- #include "mac.h"
- #include "eeprom.h"
-+#include <linux/moduleparam.h>
- 
- 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 5a047e6..b0dcc5a 100644
---- a/mt76_connac_mcu.c
-+++ b/mt76_connac_mcu.c
-@@ -4,6 +4,7 @@
- #include <linux/firmware.h>
- #include "mt76_connac2_mac.h"
- #include "mt76_connac_mcu.h"
-+#include <linux/module.h>
- 
- 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 35441dc..56b5a24 100644
---- a/mt7915/mcu.c
-+++ b/mt7915/mcu.c
-@@ -6,6 +6,7 @@
- #include "mcu.h"
- #include "mac.h"
- #include "eeprom.h"
-+#include <linux/moduleparam.h>
- 
- #define fw_name(_dev, name, ...)	({			\
- 	char *_fw;						\
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index d781c6e..37cf269 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -8,6 +8,7 @@
- #include "mt7996.h"
- #include "mcu.h"
- #include "mac.h"
-+#include <linux/moduleparam.h>
- #include "eeprom.h"
- 
- struct mt7996_patch_hdr {
--- 
-2.36.1
-
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 cc889fc..cf59945 100644
--- a/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches-3.x/patches.inc
@@ -1,10 +1,12 @@
 #patch patches (come from openwrt/lede/target/linux/mediatek)
 SRC_URI_append = " \
-    file://0001-wifi-mt76-mt7996-fix-chainmask-calculation-in-mt7996.patch \
-    file://0002-wifi-mt76-mt7996-update-register-for-CFEND_RATE.patch \
-    file://0003-wifi-mt76-mt7996-do-not-hardcode-vht-beamform-cap.patch \
-    file://0004-wifi-mt76-connac-fix-POWER_CTRL-command-name-typo.patch \
-    file://4001-mt76-mt7996-for-build-pass.patch \
-    file://4002-mt76-revert-get_of_mac_addr.patch \
-    file://4003-mt76-include-header-files-for-module-param.patch \
+    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://0999-mt76-mt7996-for-build-pass.patch \
     "