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

[Description]
99fb869a [MAC80211][mt76][Fix mt7915 sku wrong value]
88215a21 [MAC80211][hostapd][support set muru_manual_mode_config from hostapd_cli]
7994a820 [MAC80211][mt76][Support to read mwctl set_muru_manual_config]
97f14257 [MAC80211][misc][Add uci option for Autotest]
40ae7ed7 [kernel][common][eth][Add RSS ring adjustment for the ethtool]
2c91be45 [MAC80211][Rebase Patches][mt76 build fail]
31f1a8af [MAC80211][misc][mt76 Makefile]

[Release-log]

Change-Id: I23c802f2cf003f030d35f1a6feccef419ae2e638
diff --git a/recipes-wifi/atenl/files/iwpriv.sh b/recipes-wifi/atenl/files/iwpriv.sh
index 183b079..b5b6fa3 100644
--- a/recipes-wifi/atenl/files/iwpriv.sh
+++ b/recipes-wifi/atenl/files/iwpriv.sh
@@ -1163,7 +1163,7 @@
         ## In wifi 7 chipset, testmode & vendor command both use mwctl
         ## Therefore this wrapper would translate it to either mt76-test or mt76-vendor based on the attribute of the command
         ## Translate to mt76-vendor command
-        "csi"|"amnt"|"ap_rfeatures"|"ap_wireless"|"mu")
+        "csi"|"amnt"|"ap_rfeatures"|"ap_wireless"|"mu"|"set_muru_manual_config")
             if [ ${is_eagle} == "1" ]; then
                 hostapd_cmd="$(echo $* | sed 's/set/raw/')"
                 do_cmd "hostapd_cli -i $hostapd_cmd"
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch
new file mode 100644
index 0000000..fa37f91
--- /dev/null
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch
@@ -0,0 +1,638 @@
+From 011bf135a28d9e13fc27b72da4486d21c8c17e87 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Sat, 3 Jun 2023 17:12:15 +0800
+Subject: [PATCH] hostapd: mtk: add connac3 PHY MURU manual mode config support
+
+This commit supports read the following two formats to set MU/RU manual
+mode:
+1. hostapd_cli -i <intf> raw set_muru_manual_config=<field>:<value>
+2. hostapd_cli -i <intf> set_mu <field> <value>
+
+For the <field>, we support the following field:
+1. ul_comm_user_cnt/dl_comm_user_cnt: set the number of user
+2. ul_comm_bw/dl_comm_bw: set the bandwith
+3. ul_user_ru_alloc/dl_user_ru_alloc: set the RU band idx and RU
+allocate idx
+4. ul_user_mcs/dl_user_mcs: set the mcs for each user
+5. ul_user_ssAlloc_raru: set the number of ss for each user
+6. ul_comm_gi_ltf: set the combinations of gi and ltf for UL only.
+7. dl_comm_toneplan: fix ru toneplan allocation
+8. dl_comm_ack_policy: fix station ack policy
+9. update : trigger driver to send mcu command to set muru manual mode.
+
+For the value of each field, please check wiki to learn the details:
+https://wiki.mediatek.inc/display/GWKB/muru_mancfg_user_guide
+
+For the fields that mt76 support to use, we will update in this wiki:
+https://wiki.mediatek.inc/pages/viewpage.action?pageId=1271741116
+
+Please noted that this commit is only for connac 3 gen chips. If this
+feature is to be used in other generations, the following actions must
+be taken:
+1. Different data structue needs to be defined for different
+generations, e.g. connac4_muru_comm, connac4_muru_dl.
+2. hostapd_ctrl_iface_set_mu() shall be modified.
+3. A new code level configuration shall be defined to differentiate the
+code flow that different generations will go through.
+---
+ hostapd/ctrl_iface.c         | 235 +++++++++++++++++++++++++++++++----
+ src/ap/ap_config.h           |   1 +
+ src/ap/ap_drv_ops.c          |   4 +-
+ src/ap/ap_drv_ops.h          |   2 +-
+ src/ap/hostapd.c             |   2 +-
+ src/common/mtk_vendor.h      | 166 ++++++++++++++++++++++++-
+ src/drivers/driver.h         |   2 +-
+ src/drivers/driver_nl80211.c |  21 ++--
+ 8 files changed, 390 insertions(+), 43 deletions(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 274d079..663e6c8 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -3575,22 +3575,61 @@ hostapd_ctrl_iface_get_edcca(struct hostapd_data *hapd, char *cmd, char *buf,
+ 	}
+ }
+ 
++static int
++hostapd_parse_argument_helper(char *value, u16 **ptr_input)
++{
++#define MAX_MU_CTRL_NUM 17
++
++	u16 *input;
++	char *endptr;
++	int cnt = 0;
++
++	input = os_zalloc(MAX_MU_CTRL_NUM * sizeof(u16));
++	if (input == NULL) {
++		wpa_printf(MSG_ERROR, "Failed to allocate memory.\n");
++		return -1;
++	}
++	while (value) {
++		u8 val = strtol(value, &endptr, 10);
++
++		if (value != endptr) {
++			input[cnt++] = val;
++			value = os_strchr(endptr, ':');
++			if (value)
++				value++;
++		} else {
++			break;
++		}
++	}
+ 
++	*ptr_input = input;
++	return cnt;
++}
++
++#define MURU_CFG_DEPENDENCE_CHECK(_val, _mask) do {				\
++		if ((le_to_host32(_val) & (_mask)) != _mask) {			\
++			wpa_printf(MSG_ERROR, "Set %s first\n", #_mask);	\
++			goto fail;						\
++		}								\
++	} while(0)
+ static int
+ hostapd_ctrl_iface_set_mu(struct hostapd_data *hapd, char *cmd,
+-					 char *buf, size_t buflen)
++			  char *buf, size_t buflen)
+ {
+ 	char *pos, *config, *value;
+-	u8 mode;
++	u8 i;
++	int cnt = 0, ret;
++	u16 *val;
++	struct connac3_muru *muru;
++	struct connac3_muru_dl *dl;
++	struct connac3_muru_ul *ul;
++	struct connac3_muru_comm *comm;
+ 
+ 	config = cmd;
+ 	pos = os_strchr(config, ' ');
+-	if (pos == NULL)
+-		return -1;
+-	*pos++ = '\0';
++	if (pos != NULL)
++		*pos++ = '\0';
+ 
+-	if(pos == NULL)
+-		return -1;
+ 	value = pos;
+ 
+ 	if (os_strcmp(config, "onoff") == 0) {
+@@ -3600,24 +3639,167 @@ hostapd_ctrl_iface_set_mu(struct hostapd_data *hapd, char *cmd,
+ 			return -1;
+ 		}
+ 		hapd->iconf->mu_onoff = (u8) mu;
+-		mode = MU_CTRL_ONOFF;
+-	} else if (os_strcmp(config, "ul_user_cnt") == 0) {
+-		mode = MU_CTRL_UL_USER_CNT;
+-		wpa_printf(MSG_ERROR, "ul_user_cnt:%d\n", (u8)atoi(value));
+-	} else if (os_strcmp(config, "dl_user_cnt") == 0) {
+-		mode = MU_CTRL_DL_USER_CNT;
+-		wpa_printf(MSG_ERROR, "dl_user_cnt:%d\n", (u8)atoi(value));
+-	} else {
+-		wpa_printf(MSG_ERROR,
+-			"Unsupported parameter %s for SET_MU", config);
+-		return -1;
++
++		if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF) == 0)
++			return os_snprintf(buf, buflen, "OK\n");
++		else
++			goto fail;
+ 	}
+ 
+-	if(hostapd_drv_mu_ctrl(hapd, mode, (u8)atoi(value)) == 0) {
+-		return os_snprintf(buf, buflen, "OK\n");
++	if (hapd->iconf->muru_config == NULL)
++		hapd->iconf->muru_config = os_zalloc(sizeof(struct connac3_muru));
++
++	muru = hapd->iconf->muru_config;
++	dl = &muru->dl;
++	ul = &muru->ul;
++	comm = &muru->comm;
++
++	if (os_strncmp(config, "update", 6) == 0) {
++		ret = hostapd_drv_mu_ctrl(hapd, MU_CTRL_UPDATE);
++
++		os_free(hapd->iconf->muru_config);
++		hapd->iconf->muru_config = NULL;
++
++		if (ret)
++			goto fail;
++	} else if (os_strcmp(config, "ul_comm_user_cnt") == 0) {
++		ul->user_num = (u8)atoi(value);
++		comm->ppdu_format |= MURU_PPDU_HE_TRIG;
++		comm->sch_type |= MURU_OFDMA_SCH_TYPE_UL;
++		muru->cfg_comm |= host_to_le32(MURU_COMM_SET);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_TOTAL_USER_CNT);
++	} else if (os_strcmp(config, "dl_comm_user_cnt") == 0) {
++		dl->user_num = (u8)atoi(value);
++		comm->ppdu_format |= MURU_PPDU_HE_MU;
++		comm->sch_type |= MURU_OFDMA_SCH_TYPE_DL;
++		muru->cfg_comm |= host_to_le32(MURU_COMM_SET);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_TOTAL_USER_CNT);
++	} else if (os_strcmp(config, "dl_comm_bw") == 0) {
++		dl->bw = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_BW);
++	} else if (os_strcmp(config, "ul_comm_bw") == 0) {
++		ul->bw = (u8)atoi(value);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_BW);
++	} else if (os_strcmp(config, "dl_user_ru_alloc") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != (dl->user_num * 2))
++			goto para_fail;
++		for (i = 0; i < dl->user_num; i++) {
++			dl->usr[i].ru_alloc_seg = (val[2 * i] & 0x1);
++			dl->usr[i].ru_allo_ps160 = ((val[2 * i] & 0x2) >> 1);
++			dl->usr[i].ru_idx = (val[(2 * i) + 1] & 0x1);
++		}
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_RU_ALLOC);
++	} else if (os_strcmp(config, "ul_user_ru_alloc") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != (ul->user_num * 2))
++			goto para_fail;
++		for (i = 0; i < ul->user_num; i++) {
++			ul->usr[i].ru_alloc_seg = (val[2 * i] & 0x1);
++			ul->usr[i].ru_allo_ps160 = ((val[2 * i] & 0x2) >> 1);
++			ul->usr[i].ru_idx = (val[(2 * i) + 1] & 0x1);
++		}
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_RU_ALLOC);
++	} else if (os_strcmp(config, "dl_user_mcs") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != dl->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			dl->usr[i].mcs = (u8) val[i];
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_MCS);
++	} else if (os_strcmp(config, "ul_user_mcs") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != ul->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			ul->usr[i].mcs = (u8) val[i];
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_MCS);
++	} else if (os_strcmp(config, "dl_user_cod") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != dl->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			dl->usr[i].ldpc = (u8) val[i];
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_COD);
++	} else if (os_strcmp(config, "ul_user_cod") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != ul->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			ul->usr[i].ldpc = (u8) val[i];
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_COD);
++	} else if (os_strcmp(config, "ul_user_ssAlloc_raru") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != ul->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			ul->usr[i].nss = (u8) val[i];
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_NSS);
++	} else if (os_strcmp(config, "dl_comm_gi") == 0) {
++		dl->gi = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_GI);
++	} else if (os_strcmp(config, "dl_comm_ltf") == 0) {
++		dl->ltf = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_LTF);
++	} else if (os_strcmp(config, "ul_comm_gi_ltf") == 0) {
++		ul->gi_ltf = (u8)atoi(value);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_GILTF);
++	} else if (os_strcmp(config, "dl_comm_ack_policy") == 0) {
++		dl->ack_policy = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_ACK_PLY);
++	} else if (os_strcmp(config, "dl_comm_toneplan") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_BW);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		i = pow(2, dl->bw);
++		if (cnt != i)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			dl->ru[i] = host_to_le16(val[i]);
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_TONE_PLAN);
+ 	} else {
+-		return -1;
++		wpa_printf(MSG_ERROR,
++			   "Unsupported parameter %s for SET_MU", config);
++		goto fail;
+ 	}
++
++	return os_snprintf(buf, buflen, "OK\n");
++
++para_fail:
++	os_free(val);
++	wpa_printf(MSG_ERROR, "Incorrect input number\n");
++fail:
++	return os_snprintf(buf, buflen, "FAIL\n");
+ }
+ 
+ 
+@@ -4609,8 +4791,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 		reply_len = hostapd_ctrl_iface_get_edcca(hapd, buf+10, reply,
+ 							  reply_size);
+ 	} else if (os_strncmp(buf, "SET_MU ", 7) == 0) {
+-		reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 7, reply,
+-							  reply_size);
++		reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 7, reply, reply_size);
+ 	} else if (os_strncmp(buf, "GET_MU", 6) == 0) {
+ 		reply_len = hostapd_ctrl_iface_get_mu(hapd, reply, reply_size);
+ 	} else if (os_strncmp(buf, "GET_IBF", 7) == 0) {
+@@ -4636,6 +4817,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 	} else if (os_strncmp(buf, "DUMP_AMNT", 9) == 0) {
+ 		reply_len = hostapd_ctrl_iface_dump_amnt(hapd, buf+10,
+ 							reply, reply_size);
++	} else if (os_strncmp(buf, "set_muru_manual_config=", 23) == 0) {
++		// Replace first ':' with a single space ' '
++		char *pos = buf + 23;
++
++		pos = os_strchr(pos, ':');
++		if (pos)
++			*pos = ' ';
++		reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 23, reply, reply_size);
+ 	} else {
+ 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ 		reply_len = 16;
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index 9df0b2c..74dfce7 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -1190,6 +1190,7 @@ struct hostapd_config {
+ 	u8 ibf_enable;
+ 	u8 dfs_detect_mode;
+ 	u8 amsdu;
++	void *muru_config;
+ };
+ 
+ enum three_wire_mode {
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index d5c7b15..fa369c8 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -1079,11 +1079,11 @@ int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value)
+ 	return hapd->driver->get_edcca(hapd->drv_priv, mode, value);
+ }
+ 
+-int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode, u8 val)
++int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode)
+ {
+ 	if (!hapd->driver || !hapd->driver->mu_ctrl)
+ 		return 0;
+-	return hapd->driver->mu_ctrl(hapd->drv_priv, mode, val);
++	return hapd->driver->mu_ctrl(hapd->drv_priv, mode, hapd->iconf);
+ }
+ 
+ int hostapd_drv_mu_dump(struct hostapd_data *hapd, u8 *mu_onoff)
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index 82283e6..33faba5 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -148,7 +148,7 @@ int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd);
+ int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd,
+ 					  const int *threshold);
+ int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value);
+-int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode, u8 val);
++int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode);
+ int hostapd_drv_mu_dump(struct hostapd_data *hapd, u8 *mu_onoff);
+ int hostapd_drv_three_wire_ctrl(struct hostapd_data *hapd);
+ int hostapd_drv_ibf_ctrl(struct hostapd_data *hapd);
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 6fd5947..535f62b 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -2398,7 +2398,7 @@ dfs_offload:
+ 	if (hostapd_drv_configure_edcca_threshold(hapd,
+ 						  hapd->iconf->edcca_threshold) < 0)
+ 		goto fail;
+-	if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF, hapd->iconf->mu_onoff) < 0)
++	if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF) < 0)
+ 		goto fail;
+ 	if (hostapd_drv_three_wire_ctrl(hapd) < 0)
+ 		goto fail;
+diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
+index 7dd2fc4..6de8596 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -197,8 +197,11 @@ enum mtk_vendor_attr_mu_ctrl {
+ 
+ 	MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
+ 	MTK_VENDOR_ATTR_MU_CTRL_DUMP,
+-	MTK_VENDOR_ATTR_MU_CTRL_OFDMA_MODE,
+-	MTK_VENDOR_ATTR_MU_CTRL_OFDMA_VAL,
++	/**
++	 * The above attrs are also used by connac 2. It is best not to modify the
++	 * above data structure.
++	 */
++	MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
+ 
+ 	/* keep last */
+ 	NUM_MTK_VENDOR_ATTRS_MU_CTRL,
+@@ -273,8 +276,163 @@ struct amnt_resp_data {
+ };
+ 
+ enum {
++	MU_CTRL_UPDATE,
+ 	MU_CTRL_ONOFF,
+-	MU_CTRL_DL_USER_CNT,
+-	MU_CTRL_UL_USER_CNT,
+ };
++
++struct connac3_muru_comm {
++	u8 pda_pol;
++	u8 band;
++	u8 spe_idx;
++	u8 proc_type;
++
++	le16 mlo_ctrl;
++	u8 sch_type;
++	u8 ppdu_format;
++	u8 ac;
++	u8 _rsv[3];
++};
++
++struct connac3_muru_dl {
++	u8 user_num;
++	u8 tx_mode;
++	u8 bw;
++	u8 gi;
++
++	u8 ltf;
++	u8 mcs;
++	u8 dcm;
++	u8 cmprs;
++
++	le16 ru[16];
++
++	u8 c26[2];
++	u8 ack_policy;
++	u8 tx_power;
++
++	le16 mu_ppdu_duration;
++	u8 agc_disp_order;
++	u8 _rsv1;
++
++	u8 agc_disp_pol;
++	u8 agc_disp_ratio;
++	le16 agc_disp_linkMFG;
++
++	le16 prmbl_punc_bmp;
++	u8 _rsv2[2];
++
++	struct {
++		le16 wlan_idx;
++		u8 ru_alloc_seg;
++		u8 ru_idx;
++		u8 ldpc;
++		u8 nss;
++		u8 mcs;
++		u8 mu_group_idx;
++		u8 vht_groud_id;
++		u8 vht_up;
++		u8 he_start_stream;
++		u8 he_mu_spatial;
++		le16 tx_power_alpha;
++		u8 ack_policy;
++		u8 ru_allo_ps160;
++	} usr[16];
++};
++
++struct connac3_muru_ul {
++	u8 user_num;
++	u8 tx_mode;
++
++	u8 ba_type;
++	u8 _rsv;
++
++	u8 bw;
++	u8 gi_ltf;
++	le16 ul_len;
++
++	le16 trig_cnt;
++	u8 pad;
++	u8 trig_type;
++
++	le16 trig_intv;
++	u8 trig_ta[ETH_ALEN];
++	le16 ul_ru[16];
++
++	u8 c26[2];
++	le16 agc_disp_linkMFG;
++
++	u8 agc_disp_mu_len;
++	u8 agc_disp_pol;
++	u8 agc_disp_ratio;
++	u8 agc_disp_pu_idx;
++
++	struct {
++		le16 wlan_idx;
++		u8 ru_alloc_seg;
++		u8 ru_idx;
++		u8 ldpc;
++		u8 nss;
++		u8 mcs;
++		u8 target_rssi;
++		le32 trig_pkt_size;
++		u8 ru_allo_ps160;
++		u8 _rsv2[3];
++	} usr[16];
++};
++
++struct connac3_muru_dbg {
++	/* HE TB RX Debug */
++	le32 rx_hetb_nonsf_en_bitmap;
++	le32 rx_hetb_cfg[2];
++};
++
++struct connac3_muru {
++	le32 cfg_comm;
++	le32 cfg_dl;
++	le32 cfg_ul;
++	le32 cfg_dbg;
++
++	struct connac3_muru_comm comm;
++	struct connac3_muru_dl dl;
++	struct connac3_muru_ul ul;
++	struct connac3_muru_dbg dbg;
++};
++
++#define MURU_OFDMA_SCH_TYPE_DL	BIT(0)
++#define MURU_OFDMA_SCH_TYPE_UL	BIT(1)
++#define MURU_PPDU_HE_TRIG	BIT(2)
++#define MURU_PPDU_HE_MU		BIT(3)
++
++/* Common Config */
++#define MURU_COMM_PPDU_FMT	BIT(0)
++#define MURU_COMM_BAND		BIT(2)
++#define MURU_COMM_WMM		BIT(3)
++#define MURU_COMM_SPE_IDX	BIT(4)
++#define MURU_COMM_SET		(MURU_COMM_PPDU_FMT | MURU_COMM_BAND | \
++				 MURU_COMM_WMM | MURU_COMM_SPE_IDX)
++
++/* DL Common config */
++#define MURU_FIXED_DL_BW		BIT(0)
++#define MURU_FIXED_DL_GI		BIT(1)
++#define MURU_FIXED_DL_TONE_PLAN		BIT(3)
++#define MURU_FIXED_DL_TOTAL_USER_CNT	BIT(4)
++#define MURU_FIXED_DL_LTF		BIT(5)
++#define MURU_FIXED_DL_ACK_PLY		BIT(9)
++
++/* DL Per User Config */
++#define MURU_FIXED_USER_DL_COD		BIT(17)
++#define MURU_FIXED_USER_DL_MCS		BIT(18)
++#define MURU_FIXED_USER_DL_RU_ALLOC	BIT(20)
++
++/* UL Common Config */
++#define MURU_FIXED_UL_TOTAL_USER_CNT	BIT(4)
++#define MURU_FIXED_UL_BW		BIT(5)
++#define MURU_FIXED_UL_GILTF		BIT(6)
++
++/* UL Per User Config */
++#define MURU_FIXED_USER_UL_COD		BIT(18)
++#define MURU_FIXED_USER_UL_MCS		BIT(19)
++#define MURU_FIXED_USER_UL_NSS		BIT(20)
++#define MURU_FIXED_USER_UL_RU_ALLOC	BIT(21)
++
+ #endif /* MTK_VENDOR_H */
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index 6cd4dc9..bc7dcca 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -5021,7 +5021,7 @@ struct wpa_driver_ops {
+ 	 * @priv: Private driver interface data
+ 	 *
+ 	 */
+-	 int (*mu_ctrl)(void *priv, u8 mode, u8 val);
++	 int (*mu_ctrl)(void *priv, u8 mode, void *config);
+ 	 int (*mu_dump)(void *priv, u8 *mu_onoff);
+ 
+ 	/**
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index ccfc2d0..dd6580f 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -13296,12 +13296,13 @@ fail:
+ 
+ 
+ #ifdef CONFIG_IEEE80211AX
+-static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
++static int nl80211_mu_ctrl(void *priv, u8 mode, void *config)
+ {
+ 	struct i802_bss *bss = priv;
+ 	struct wpa_driver_nl80211_data *drv = bss->drv;
+ 	struct nl_msg *msg;
+ 	struct nlattr *data;
++	struct hostapd_config *cfg = config;
+ 	int ret = -ENOBUFS;
+ 
+ 	if (!drv->mtk_mu_vendor_cmd_avail) {
+@@ -13318,17 +13319,16 @@ static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
+ 
+ 	switch (mode) {
+ 	case MU_CTRL_ONOFF:
+-			if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_ONOFF, val))
+-				goto fail;
++		if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_ONOFF, cfg->mu_onoff))
++			goto fail;
+ 		break;
+-	case MU_CTRL_UL_USER_CNT:
+-	case MU_CTRL_DL_USER_CNT:
+-			if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_OFDMA_MODE, mode) ||
+-			    nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_OFDMA_VAL, val))
+-				goto fail;
++	case MU_CTRL_UPDATE:
++		if (nla_put(msg, MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
++			    sizeof(struct connac3_muru), cfg->muru_config))
++			goto fail;
+ 		break;
+ 	default:
+-		wpa_printf(MSG_ERROR, "nl80211: Wrong mu mode !");
++		wpa_printf(MSG_ERROR, "nl80211: Wrong mu mode %u!", mode);
+ 		ret = -EINVAL;
+ 		goto fail;
+ 	}
+@@ -13336,9 +13336,8 @@ static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
+ 	nla_nest_end(msg, data);
+ 
+ 	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+-	if(ret){
++	if (ret)
+ 		wpa_printf(MSG_ERROR, "Failed to set mu_ctrl. ret=%d (%s)", ret, strerror(-ret));
+-	}
+ 	return ret;
+ 
+ fail:
+-- 
+2.18.0
+
diff --git a/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc b/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
index a0c06b1..8e652e0 100644
--- a/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/hostapd/files/patches-2.10.3/patches.inc
@@ -88,6 +88,7 @@
     file://mtk-0028-hostapd-mtk-Add-muru-user-number-debug-command.patch \
     file://mtk-0029-hostapd-mtk-Fix-CCA-issue.patch \
     file://mtk-0030-hostapd-mtk-Fix-unexpected-AP-beacon-state-transitio.patch \
+    file://mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch \
     file://mtk-0032-hostapd-mtk-Add-HE-capabilities-check.patch \
     file://mtk-0100-hostapd-mtk-update-eht-operation-element.patch \
     file://mtk-0103-hostapd-mtk-Add-BW320-channel-switch-command.patch \
diff --git a/recipes-wifi/libnl-tiny/libnl-tiny_git.bb b/recipes-wifi/libnl-tiny/libnl-tiny_git.bb
index b78ff95..cdfe026 100644
--- a/recipes-wifi/libnl-tiny/libnl-tiny_git.bb
+++ b/recipes-wifi/libnl-tiny/libnl-tiny_git.bb
@@ -5,7 +5,7 @@
 SECTION = "libs"
 
 SRC_URI = "git://git.openwrt.org/project/libnl-tiny.git"
-SRCREV = "11b7c5f0745af2637b48131287f28689bb80ed3e"
+SRCREV = "d433990c00e804593f253cc709b8fe901492b530"
 PV = "git${SRCPV}"
 
 inherit cmake pkgconfig
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch
new file mode 100644
index 0000000..f7391a5
--- /dev/null
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch
@@ -0,0 +1,219 @@
+From: Felix Fietkau <nbd@nbd.name>
+Date: Fri, 30 Jun 2023 13:11:51 +0200
+Subject: [PATCH] mac80211: split mesh fast tx cache into
+ local/proxied/forwarded
+
+Depending on the origin of the packets (and their SA), 802.11 + mesh headers
+could be filled in differently. In order to properly deal with that, add a
+new field to the lookup key, indicating the type (local, proxied or
+forwarded). This can fix spurious packet drop issues that depend on the order
+in which nodes/hosts communicate with each other.
+
+Signed-off-by: Felix Fietkau <nbd@nbd.name>
+---
+
+--- a/net/mac80211/mesh.c
++++ b/net/mac80211/mesh.c
+@@ -703,6 +703,9 @@ bool ieee80211_mesh_xmit_fast(struct iee
+ 			      struct sk_buff *skb, u32 ctrl_flags)
+ {
+ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
++	struct ieee80211_mesh_fast_tx_key key = {
++		.type = MESH_FAST_TX_TYPE_LOCAL
++	};
+ 	struct ieee80211_mesh_fast_tx *entry;
+ 	struct ieee80211s_hdr *meshhdr;
+ 	u8 sa[ETH_ALEN] __aligned(2);
+@@ -738,7 +741,10 @@ bool ieee80211_mesh_xmit_fast(struct iee
+ 			return false;
+ 	}
+ 
+-	entry = mesh_fast_tx_get(sdata, skb->data);
++	ether_addr_copy(key.addr, skb->data);
++	if (!ether_addr_equal(skb->data + ETH_ALEN, sdata->vif.addr))
++		key.type = MESH_FAST_TX_TYPE_PROXIED;
++	entry = mesh_fast_tx_get(sdata, &key);
+ 	if (!entry)
+ 		return false;
+ 
+--- a/net/mac80211/mesh.h
++++ b/net/mac80211/mesh.h
+@@ -133,9 +133,33 @@ struct mesh_path {
+ #define MESH_FAST_TX_CACHE_TIMEOUT		8000 /* msecs */
+ 
+ /**
++ * enum ieee80211_mesh_fast_tx_type - cached mesh fast tx entry type
++ *
++ * @MESH_FAST_TX_TYPE_LOCAL: tx from the local vif address as SA
++ * @MESH_FAST_TX_TYPE_PROXIED: local tx with a different SA (e.g. bridged)
++ * @MESH_FAST_TX_TYPE_FORWARDED: forwarded from a different mesh point
++ */
++enum ieee80211_mesh_fast_tx_type {
++	MESH_FAST_TX_TYPE_LOCAL,
++	MESH_FAST_TX_TYPE_PROXIED,
++	MESH_FAST_TX_TYPE_FORWARDED,
++};
++
++/**
++ * struct ieee80211_mesh_fast_tx_key - cached mesh fast tx entry key
++ *
++ * @addr: The Ethernet DA for this entry
++ * @type: cache entry type
++ */
++struct ieee80211_mesh_fast_tx_key {
++	u8 addr[ETH_ALEN] __aligned(2);
++	enum ieee80211_mesh_fast_tx_type type;
++};
++
++/**
+  * struct ieee80211_mesh_fast_tx - cached mesh fast tx entry
+  * @rhash: rhashtable pointer
+- * @addr_key: The Ethernet DA which is the key for this entry
++ * @key: the lookup key for this cache entry
+  * @fast_tx: base fast_tx data
+  * @hdr: cached mesh and rfc1042 headers
+  * @hdrlen: length of mesh + rfc1042
+@@ -146,7 +170,7 @@ struct mesh_path {
+  */
+ struct ieee80211_mesh_fast_tx {
+ 	struct rhash_head rhash;
+-	u8 addr_key[ETH_ALEN] __aligned(2);
++	struct ieee80211_mesh_fast_tx_key key;
+ 
+ 	struct ieee80211_fast_tx fast_tx;
+ 	u8 hdr[sizeof(struct ieee80211s_hdr) + sizeof(rfc1042_header)];
+@@ -329,7 +353,8 @@ void mesh_path_tx_root_frame(struct ieee
+ 
+ bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
+ struct ieee80211_mesh_fast_tx *
+-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr);
++mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
++		 struct ieee80211_mesh_fast_tx_key *key);
+ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
+ 			      struct sk_buff *skb, u32 ctrl_flags);
+ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
+--- a/net/mac80211/mesh_pathtbl.c
++++ b/net/mac80211/mesh_pathtbl.c
+@@ -36,8 +36,8 @@ static const struct rhashtable_params me
+ static const struct rhashtable_params fast_tx_rht_params = {
+ 	.nelem_hint = 10,
+ 	.automatic_shrinking = true,
+-	.key_len = ETH_ALEN,
+-	.key_offset = offsetof(struct ieee80211_mesh_fast_tx, addr_key),
++	.key_len = sizeof(struct ieee80211_mesh_fast_tx_key),
++	.key_offset = offsetof(struct ieee80211_mesh_fast_tx, key),
+ 	.head_offset = offsetof(struct ieee80211_mesh_fast_tx, rhash),
+ 	.hashfn = mesh_table_hash,
+ };
+@@ -426,20 +426,21 @@ static void mesh_fast_tx_entry_free(stru
+ }
+ 
+ struct ieee80211_mesh_fast_tx *
+-mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr)
++mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
++		 struct ieee80211_mesh_fast_tx_key *key)
+ {
+ 	struct ieee80211_mesh_fast_tx *entry;
+ 	struct mesh_tx_cache *cache;
+ 
+ 	cache = &sdata->u.mesh.tx_cache;
+-	entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
++	entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
+ 	if (!entry)
+ 		return NULL;
+ 
+ 	if (!(entry->mpath->flags & MESH_PATH_ACTIVE) ||
+ 	    mpath_expired(entry->mpath)) {
+ 		spin_lock_bh(&cache->walk_lock);
+-		entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
++		entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
+ 		if (entry)
+ 		    mesh_fast_tx_entry_free(cache, entry);
+ 		spin_unlock_bh(&cache->walk_lock);
+@@ -484,18 +485,24 @@ void mesh_fast_tx_cache(struct ieee80211
+ 	if (!sta)
+ 		return;
+ 
++	build.key.type = MESH_FAST_TX_TYPE_LOCAL;
+ 	if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) {
+ 		/* This is required to keep the mppath alive */
+ 		mppath = mpp_path_lookup(sdata, meshhdr->eaddr1);
+ 		if (!mppath)
+ 			return;
+ 		build.mppath = mppath;
++		if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr))
++			build.key.type = MESH_FAST_TX_TYPE_PROXIED;
+ 	} else if (ieee80211_has_a4(hdr->frame_control)) {
+ 		mppath = mpath;
+ 	} else {
+ 		return;
+ 	}
+ 
++	if (!ether_addr_equal(hdr->addr4, sdata->vif.addr))
++		build.key.type = MESH_FAST_TX_TYPE_FORWARDED;
++
+ 	/* rate limit, in case fast xmit can't be enabled */
+ 	if (mppath->fast_tx_check == jiffies)
+ 		return;
+@@ -542,7 +549,7 @@ void mesh_fast_tx_cache(struct ieee80211
+ 		}
+ 	}
+ 
+-	memcpy(build.addr_key, mppath->dst, ETH_ALEN);
++	memcpy(build.key.addr, mppath->dst, ETH_ALEN);
+ 	build.timestamp = jiffies;
+ 	build.fast_tx.band = info->band;
+ 	build.fast_tx.da_offs = offsetof(struct ieee80211_hdr, addr3);
+@@ -644,13 +651,19 @@ void mesh_fast_tx_flush_addr(struct ieee
+ 			     const u8 *addr)
+ {
+ 	struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache;
++	struct ieee80211_mesh_fast_tx_key key = {};
+ 	struct ieee80211_mesh_fast_tx *entry;
++	int i;
+ 
++	ether_addr_copy(key.addr, addr);
+ 	cache = &sdata->u.mesh.tx_cache;
+ 	spin_lock_bh(&cache->walk_lock);
+-	entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
+-	if (entry)
+-		mesh_fast_tx_entry_free(cache, entry);
++	for (i = MESH_FAST_TX_TYPE_LOCAL; i < MESH_FAST_TX_TYPE_FORWARDED; i++) {
++		key.type = i;
++		entry = rhashtable_lookup(&cache->rht, &key, fast_tx_rht_params);
++		if (entry)
++			mesh_fast_tx_entry_free(cache, entry);
++	}
+ 	spin_unlock_bh(&cache->walk_lock);
+ }
+ 
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -2726,7 +2726,10 @@ ieee80211_rx_mesh_fast_forward(struct ie
+ 			       struct sk_buff *skb, int hdrlen)
+ {
+ 	struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+-	struct ieee80211_mesh_fast_tx *entry = NULL;
++	struct ieee80211_mesh_fast_tx_key key = {
++		.type = MESH_FAST_TX_TYPE_FORWARDED
++	};
++	struct ieee80211_mesh_fast_tx *entry;
+ 	struct ieee80211s_hdr *mesh_hdr;
+ 	struct tid_ampdu_tx *tid_tx;
+ 	struct sta_info *sta;
+@@ -2735,9 +2738,13 @@ ieee80211_rx_mesh_fast_forward(struct ie
+ 
+ 	mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
+ 	if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
+-		entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1);
++		ether_addr_copy(key.addr, mesh_hdr->eaddr1);
+ 	else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
+-		entry = mesh_fast_tx_get(sdata, skb->data);
++		ether_addr_copy(key.addr, skb->data);
++	else
++		return false;
++
++	entry = mesh_fast_tx_get(sdata, &key);
+ 	if (!entry)
+ 		return false;
+ 
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/340-mac80211-always-use-mac80211-loss-detection.patch b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/340-mac80211-always-use-mac80211-loss-detection.patch
deleted file mode 100644
index e084773..0000000
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/340-mac80211-always-use-mac80211-loss-detection.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From cdf461888f900c3a149b10a04d72b4a590ecdec3 Mon Sep 17 00:00:00 2001
-From: David Bauer <mail@david-bauer.net>
-Date: Tue, 16 May 2023 23:11:32 +0200
-Subject: [PATCH] mac80211: always use mac80211 loss detection
-
-ath10k does not report excessive loss in case of broken block-ack
-sessions. The loss is communicated to the host-os, but ath10k does not
-trigger a low-ack events by itself.
-
-The mac80211 framework for loss detection however detects this
-circumstance well in case of ath10k. So use it regardless of ath10k's
-own loss detection mechanism.
-
-Patching this in mac80211 does allow this hack to be used with any
-flavor of ath10k/ath11k.
-
-Signed-off-by: David Bauer <mail@david-bauer.net>
----
- net/mac80211/status.c | 6 ------
- 1 file changed, 6 deletions(-)
-
---- a/net/mac80211/status.c
-+++ b/net/mac80211/status.c
-@@ -794,12 +794,6 @@ static void ieee80211_lost_packet(struct
- 	unsigned long pkt_time = STA_LOST_PKT_TIME;
- 	unsigned int pkt_thr = STA_LOST_PKT_THRESHOLD;
- 
--	/* If driver relies on its own algorithm for station kickout, skip
--	 * mac80211 packet loss mechanism.
--	 */
--	if (ieee80211_hw_check(&sta->local->hw, REPORTS_LOW_ACK))
--		return;
--
- 	/* This packet was aggregated but doesn't carry status info */
- 	if ((info->flags & IEEE80211_TX_CTL_AMPDU) &&
- 	    !(info->flags & IEEE80211_TX_STAT_AMPDU))
diff --git a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
index b3f5e56..1c0c867 100644
--- a/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
+++ b/recipes-wifi/linux-mac80211/files/patches-6.x/subsys/subsys.inc
@@ -38,7 +38,7 @@
     file://335-wifi-mac80211-add-LDPC-related-flags-in-ieee80211_bs.patch \
     file://336-v6.4-wifi-mac80211-generate-EMA-beacons-in-AP-mode.patch \
     file://337-mac80211-fix-sband-iftype-data-lookup-for-AP_VLAN.patch \
-    file://340-mac80211-always-use-mac80211-loss-detection.patch \
+    file://338-mac80211-split-mesh-fast-tx-cache-into-local-proxied.patch \
     file://400-allow-ibss-mixed.patch \
     file://500-mac80211_configure_antenna_gain.patch \
     file://782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch \
diff --git a/recipes-wifi/linux-mt76/files/patches/0000-sync-to-master-codebase.patch b/recipes-wifi/linux-mt76/files/patches/0000-sync-to-master-codebase.patch
deleted file mode 100644
index 1ee1534..0000000
--- a/recipes-wifi/linux-mt76/files/patches/0000-sync-to-master-codebase.patch
+++ /dev/null
@@ -1,5882 +0,0 @@
-From d10be7604c55c961bd06a2e4aaeff1baf4fda24a Mon Sep 17 00:00:00 2001
-From: Lorenzo Bianconi <lorenzo@kernel.org>
-Date: Wed, 24 May 2023 16:39:32 +0200
-Subject: [PATCH] sync to master codebase
-
----
- Makefile                                   |   2 +-
- dma.c                                      |   6 +
- mac80211.c                                 |   6 +
- mt76.h                                     | 106 ++++++-
- mt7603/init.c                              |   2 -
- mt7603/mac.c                               |  22 +-
- mt7603/main.c                              |  20 +-
- mt7603/mt7603.h                            |   4 -
- mt7615/init.c                              |   4 +-
- mt7615/mac.c                               |  30 +-
- mt7615/main.c                              |  49 +++-
- mt7615/mt7615.h                            |   4 -
- mt7615/regs.h                              |   9 +
- mt76_connac.h                              |  10 +-
- mt76_connac2_mac.h                         |   4 +-
- mt76_connac3_mac.c                         | 182 ++++++++++++
- mt76_connac3_mac.h                         | 325 +++++++++++++++++++++
- mt76_connac_mac.c                          | 109 ++++++-
- mt76_connac_mcu.c                          |   3 +
- mt76_connac_mcu.h                          |   6 +-
- mt76x02_util.c                             |  13 -
- mt7915/debugfs.c                           | 128 ++++----
- mt7915/dma.c                               | 148 +++++-----
- mt7915/init.c                              |  12 +-
- mt7915/mac.c                               | 192 +++++-------
- mt7915/mac.h                               |   7 +-
- mt7915/main.c                              | 184 +++++++++---
- mt7915/mcu.c                               | 119 +++++++-
- mt7915/mmio.c                              |  34 +--
- mt7915/mt7915.h                            |  74 +----
- mt7915/regs.h                              |   3 +
- mt7915/soc.c                               |  53 ++--
- mt7921/debugfs.c                           |   2 +-
- mt7921/dma.c                               |  10 +-
- mt7921/init.c                              |  72 ++++-
- mt7921/mac.c                               | 118 +++-----
- mt7921/main.c                              |  42 ++-
- mt7921/mcu.c                               |  25 +-
- mt7921/mt7921.h                            |  43 +--
- mt7921/pci.c                               |  10 +-
- mt7921/pci_mac.c                           |  16 +-
- mt7921/regs.h                              |   1 -
- mt7921/usb.c                               |   3 +
- mt7996/debugfs.c                           |   4 +-
- mt7996/dma.c                               |  83 +++---
- mt7996/init.c                              |   5 +-
- mt7996/mac.c                               | 317 +++++---------------
- mt7996/mac.h                               | 315 +-------------------
- mt7996/main.c                              | 114 +++++---
- mt7996/mcu.c                               | 182 +++++++++---
- mt7996/mcu.h                               |  17 ++
- mt7996/mt7996.h                            |  80 +----
- mt7996/pci.c                               |   1 +
- mt7996/regs.h                              |  21 +-
- tx.c                                       |  16 +-
- 59 files changed, 1908 insertions(+), 1459 deletions(-)
- create mode 100644 mt76_connac3_mac.c
- create mode 100644 mt76_connac3_mac.h
-
-diff --git a/Makefile b/Makefile
-index 9c287cf4..f9b94280 100644
---- a/Makefile
-+++ b/Makefile
-@@ -28,7 +28,7 @@ mt76x02-lib-y := mt76x02_util.o mt76x02_mac.o mt76x02_mcu.o \
- 
- mt76x02-usb-y := mt76x02_usb_mcu.o mt76x02_usb_core.o
- 
--mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o
-+mt76-connac-lib-y := mt76_connac_mcu.o mt76_connac_mac.o mt76_connac3_mac.o
- 
- obj-$(CONFIG_MT76x0_COMMON) += mt76x0/
- obj-$(CONFIG_MT76x2_COMMON) += mt76x2/
-diff --git a/dma.c b/dma.c
-index 465190eb..05d9ab3c 100644
---- a/dma.c
-+++ b/dma.c
-@@ -466,6 +466,9 @@ mt76_dma_tx_queue_skb_raw(struct mt76_dev *dev, struct mt76_queue *q,
- 	struct mt76_queue_buf buf = {};
- 	dma_addr_t addr;
- 
-+	if (test_bit(MT76_MCU_RESET, &dev->phy.state))
-+		goto error;
-+
- 	if (q->queued + 1 >= q->ndesc - 1)
- 		goto error;
- 
-@@ -507,6 +510,9 @@ mt76_dma_tx_queue_skb(struct mt76_dev *dev, struct mt76_queue *q,
- 	dma_addr_t addr;
- 	u8 *txwi;
- 
-+	if (test_bit(MT76_RESET, &dev->phy.state))
-+		goto free_skb;
-+
- 	t = mt76_get_txwi(dev);
- 	if (!t)
- 		goto free_skb;
-diff --git a/mac80211.c b/mac80211.c
-index 2c4a5290..85407387 100644
---- a/mac80211.c
-+++ b/mac80211.c
-@@ -76,6 +76,7 @@ static const struct ieee80211_channel mt76_channels_5ghz[] = {
- 	CHAN5G(165, 5825),
- 	CHAN5G(169, 5845),
- 	CHAN5G(173, 5865),
-+	CHAN5G(177, 5885),
- };
- 
- static const struct ieee80211_channel mt76_channels_6ghz[] = {
-@@ -660,6 +661,8 @@ mt76_alloc_device(struct device *pdev, unsigned int size,
- 	idr_init(&dev->rx_token);
- 
- 	INIT_LIST_HEAD(&dev->wcid_list);
-+	INIT_LIST_HEAD(&dev->sta_poll_list);
-+	spin_lock_init(&dev->sta_poll_lock);
- 
- 	INIT_LIST_HEAD(&dev->txwi_cache);
- 	INIT_LIST_HEAD(&dev->rxwi_cache);
-@@ -1738,6 +1741,9 @@ void mt76_ethtool_worker(struct mt76_ethtool_worker_info *wi,
- 	for (i = 0; i < (eht ? 14 : 12); i++)
- 		data[ei++] += stats->tx_mcs[i];
- 
-+	for (i = 0; i < 4; i++)
-+		data[ei++] += stats->tx_nss[i];
-+
- 	wi->worker_stat_count = ei - wi->initial_stat_idx;
- }
- EXPORT_SYMBOL_GPL(mt76_ethtool_worker);
-diff --git a/mt76.h b/mt76.h
-index 8b4635e9..034ab90c 100644
---- a/mt76.h
-+++ b/mt76.h
-@@ -277,7 +277,7 @@ struct mt76_sta_stats {
- 	u64 tx_mcs[16];		/* mcs idx */
- 	u64 tx_bytes;
- 	/* WED TX */
--	u32 tx_packets;
-+	u32 tx_packets;		/* unit: MSDU */
- 	u32 tx_retries;
- 	u32 tx_failed;
- 	/* WED RX */
-@@ -316,6 +316,7 @@ struct mt76_wcid {
- 	int inactive_count;
- 
- 	struct rate_info rate;
-+	unsigned long ampdu_state;
- 
- 	u16 idx;
- 	u8 hw_key_idx;
-@@ -336,6 +337,8 @@ struct mt76_wcid {
- 	struct idr pktid;
- 
- 	struct mt76_sta_stats stats;
-+
-+	struct list_head poll_list;
- };
- 
- struct mt76_txq {
-@@ -692,6 +695,9 @@ struct mt76_vif {
- 	u8 wmm_idx;
- 	u8 scan_seq_num;
- 	u8 cipher;
-+	u8 basic_rates_idx;
-+	u8 mcast_rates_idx;
-+	u8 beacon_rates_idx;
- };
- 
- struct mt76_phy {
-@@ -813,6 +819,9 @@ struct mt76_dev {
- 	struct mt76_wcid __rcu *wcid[MT76_N_WCIDS];
- 	struct list_head wcid_list;
- 
-+	struct list_head sta_poll_list;
-+	spinlock_t sta_poll_lock;
-+
- 	u32 rev;
- 
- 	struct tasklet_struct pre_tbtt_tasklet;
-@@ -847,6 +856,101 @@ struct mt76_dev {
- 	};
- };
- 
-+/* per-phy stats.  */
-+struct mt76_mib_stats {
-+	u32 ack_fail_cnt;
-+	u32 fcs_err_cnt;
-+	u32 rts_cnt;
-+	u32 rts_retries_cnt;
-+	u32 ba_miss_cnt;
-+	u32 tx_bf_cnt;
-+	u32 tx_mu_bf_cnt;
-+	u32 tx_mu_mpdu_cnt;
-+	u32 tx_mu_acked_mpdu_cnt;
-+	u32 tx_su_acked_mpdu_cnt;
-+	u32 tx_bf_ibf_ppdu_cnt;
-+	u32 tx_bf_ebf_ppdu_cnt;
-+
-+	u32 tx_bf_rx_fb_all_cnt;
-+	u32 tx_bf_rx_fb_eht_cnt;
-+	u32 tx_bf_rx_fb_he_cnt;
-+	u32 tx_bf_rx_fb_vht_cnt;
-+	u32 tx_bf_rx_fb_ht_cnt;
-+
-+	u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
-+	u32 tx_bf_rx_fb_nc_cnt;
-+	u32 tx_bf_rx_fb_nr_cnt;
-+	u32 tx_bf_fb_cpl_cnt;
-+	u32 tx_bf_fb_trig_cnt;
-+
-+	u32 tx_ampdu_cnt;
-+	u32 tx_stop_q_empty_cnt;
-+	u32 tx_mpdu_attempts_cnt;
-+	u32 tx_mpdu_success_cnt;
-+	u32 tx_pkt_ebf_cnt;
-+	u32 tx_pkt_ibf_cnt;
-+
-+	u32 tx_rwp_fail_cnt;
-+	u32 tx_rwp_need_cnt;
-+
-+	/* rx stats */
-+	u32 rx_fifo_full_cnt;
-+	u32 channel_idle_cnt;
-+	u32 primary_cca_busy_time;
-+	u32 secondary_cca_busy_time;
-+	u32 primary_energy_detect_time;
-+	u32 cck_mdrdy_time;
-+	u32 ofdm_mdrdy_time;
-+	u32 green_mdrdy_time;
-+	u32 rx_vector_mismatch_cnt;
-+	u32 rx_delimiter_fail_cnt;
-+	u32 rx_mrdy_cnt;
-+	u32 rx_len_mismatch_cnt;
-+	u32 rx_mpdu_cnt;
-+	u32 rx_ampdu_cnt;
-+	u32 rx_ampdu_bytes_cnt;
-+	u32 rx_ampdu_valid_subframe_cnt;
-+	u32 rx_ampdu_valid_subframe_bytes_cnt;
-+	u32 rx_pfdrop_cnt;
-+	u32 rx_vec_queue_overflow_drop_cnt;
-+	u32 rx_ba_cnt;
-+
-+	u32 tx_amsdu[8];
-+	u32 tx_amsdu_cnt;
-+
-+	/* mcu_muru_stats */
-+	u32 dl_cck_cnt;
-+	u32 dl_ofdm_cnt;
-+	u32 dl_htmix_cnt;
-+	u32 dl_htgf_cnt;
-+	u32 dl_vht_su_cnt;
-+	u32 dl_vht_2mu_cnt;
-+	u32 dl_vht_3mu_cnt;
-+	u32 dl_vht_4mu_cnt;
-+	u32 dl_he_su_cnt;
-+	u32 dl_he_ext_su_cnt;
-+	u32 dl_he_2ru_cnt;
-+	u32 dl_he_2mu_cnt;
-+	u32 dl_he_3ru_cnt;
-+	u32 dl_he_3mu_cnt;
-+	u32 dl_he_4ru_cnt;
-+	u32 dl_he_4mu_cnt;
-+	u32 dl_he_5to8ru_cnt;
-+	u32 dl_he_9to16ru_cnt;
-+	u32 dl_he_gtr16ru_cnt;
-+
-+	u32 ul_hetrig_su_cnt;
-+	u32 ul_hetrig_2ru_cnt;
-+	u32 ul_hetrig_3ru_cnt;
-+	u32 ul_hetrig_4ru_cnt;
-+	u32 ul_hetrig_5to8ru_cnt;
-+	u32 ul_hetrig_9to16ru_cnt;
-+	u32 ul_hetrig_gtr16ru_cnt;
-+	u32 ul_hetrig_2mu_cnt;
-+	u32 ul_hetrig_3mu_cnt;
-+	u32 ul_hetrig_4mu_cnt;
-+};
-+
- struct mt76_power_limits {
- 	s8 cck[4];
- 	s8 ofdm[8];
-diff --git a/mt7603/init.c b/mt7603/init.c
-index 9a2e632d..0762de3c 100644
---- a/mt7603/init.c
-+++ b/mt7603/init.c
-@@ -500,8 +500,6 @@ int mt7603_register_device(struct mt7603_dev *dev)
- 	bus_ops->rmw = mt7603_rmw;
- 	dev->mt76.bus = bus_ops;
- 
--	INIT_LIST_HEAD(&dev->sta_poll_list);
--	spin_lock_init(&dev->sta_poll_lock);
- 	spin_lock_init(&dev->ps_lock);
- 
- 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7603_mac_work);
-diff --git a/mt7603/mac.c b/mt7603/mac.c
-index 12e0af52..de11557e 100644
---- a/mt7603/mac.c
-+++ b/mt7603/mac.c
-@@ -412,16 +412,16 @@ void mt7603_mac_sta_poll(struct mt7603_dev *dev)
- 	while (1) {
- 		bool clear = false;
- 
--		spin_lock_bh(&dev->sta_poll_lock);
--		if (list_empty(&dev->sta_poll_list)) {
--			spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		if (list_empty(&dev->mt76.sta_poll_list)) {
-+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 			break;
- 		}
- 
--		msta = list_first_entry(&dev->sta_poll_list, struct mt7603_sta,
--					poll_list);
--		list_del_init(&msta->poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		msta = list_first_entry(&dev->mt76.sta_poll_list,
-+					struct mt7603_sta, wcid.poll_list);
-+		list_del_init(&msta->wcid.poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		addr = mt7603_wtbl4_addr(msta->wcid.idx);
- 		for (i = 0; i < 4; i++) {
-@@ -1267,10 +1267,10 @@ void mt7603_mac_add_txs(struct mt7603_dev *dev, void *data)
- 	msta = container_of(wcid, struct mt7603_sta, wcid);
- 	sta = wcid_to_sta(wcid);
- 
--	if (list_empty(&msta->poll_list)) {
--		spin_lock_bh(&dev->sta_poll_lock);
--		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+	if (list_empty(&msta->wcid.poll_list)) {
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
- 	if (mt7603_mac_add_txs_skb(dev, msta, pid, txs_data))
-diff --git a/mt7603/main.c b/mt7603/main.c
-index 1b1358c6..1d489341 100644
---- a/mt7603/main.c
-+++ b/mt7603/main.c
-@@ -66,7 +66,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
- 
- 	idx = MT7603_WTBL_RESERVED - 1 - mvif->idx;
- 	dev->mt76.vif_mask |= BIT_ULL(mvif->idx);
--	INIT_LIST_HEAD(&mvif->sta.poll_list);
-+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
- 	mvif->sta.wcid.idx = idx;
- 	mvif->sta.wcid.hw_key_idx = -1;
- 	mt76_packet_id_init(&mvif->sta.wcid);
-@@ -100,10 +100,10 @@ mt7603_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
- 
- 	rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	mutex_lock(&dev->mt76.mutex);
- 	dev->mt76.vif_mask &= ~BIT_ULL(mvif->idx);
-@@ -351,7 +351,7 @@ mt7603_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	if (idx < 0)
- 		return -ENOSPC;
- 
--	INIT_LIST_HEAD(&msta->poll_list);
-+	INIT_LIST_HEAD(&msta->wcid.poll_list);
- 	__skb_queue_head_init(&msta->psq);
- 	msta->ps = ~0;
- 	msta->smps = ~0;
-@@ -388,10 +388,10 @@ mt7603_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	mt7603_filter_tx(dev, wcid->idx, true);
- 	spin_unlock_bh(&dev->ps_lock);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&mdev->sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&mdev->sta_poll_lock);
- 
- 	mt7603_wtbl_clear(dev, wcid->idx);
- }
-diff --git a/mt7603/mt7603.h b/mt7603/mt7603.h
-index 7c3be596..354b1898 100644
---- a/mt7603/mt7603.h
-+++ b/mt7603/mt7603.h
-@@ -64,7 +64,6 @@ struct mt7603_sta {
- 
- 	struct mt7603_vif *vif;
- 
--	struct list_head poll_list;
- 	u32 tx_airtime_ac[4];
- 
- 	struct sk_buff_head psq;
-@@ -110,9 +109,6 @@ struct mt7603_dev {
- 
- 	u32 rxfilter;
- 
--	struct list_head sta_poll_list;
--	spinlock_t sta_poll_lock;
--
- 	struct mt7603_sta global_sta;
- 
- 	u32 agc0, agc3;
-diff --git a/mt7615/init.c b/mt7615/init.c
-index 621e69f0..18a50ccf 100644
---- a/mt7615/init.c
-+++ b/mt7615/init.c
-@@ -397,6 +397,8 @@ mt7615_init_wiphy(struct ieee80211_hw *hw)
- 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_SET_SCAN_DWELL);
- 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_VHT_IBSS);
- 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
-+	if (!is_mt7622(&phy->dev->mt76))
-+		wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
- 
- 	ieee80211_hw_set(hw, SINGLE_SCAN_ON_ALL_BANDS);
- 	ieee80211_hw_set(hw, TX_STATUS_NO_AMPDU_LEN);
-@@ -626,8 +628,6 @@ void mt7615_init_device(struct mt7615_dev *dev)
- 	INIT_DELAYED_WORK(&dev->coredump.work, mt7615_coredump_work);
- 	skb_queue_head_init(&dev->phy.scan_event_list);
- 	skb_queue_head_init(&dev->coredump.msg_list);
--	INIT_LIST_HEAD(&dev->sta_poll_list);
--	spin_lock_init(&dev->sta_poll_lock);
- 	init_waitqueue_head(&dev->reset_wait);
- 	init_waitqueue_head(&dev->phy.roc_wait);
- 
-diff --git a/mt7615/mac.c b/mt7615/mac.c
-index da1d17b7..7ba78983 100644
---- a/mt7615/mac.c
-+++ b/mt7615/mac.c
-@@ -387,10 +387,11 @@ static int mt7615_mac_fill_rx(struct mt7615_dev *dev, struct sk_buff *skb)
- 		struct mt7615_sta *msta;
- 
- 		msta = container_of(status->wcid, struct mt7615_sta, wcid);
--		spin_lock_bh(&dev->sta_poll_lock);
--		if (list_empty(&msta->poll_list))
--			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		if (list_empty(&msta->wcid.poll_list))
-+			list_add_tail(&msta->wcid.poll_list,
-+				      &dev->mt76.sta_poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
- 	if (mt76_is_mmio(&dev->mt76) && (rxd0 & csum_mask) == csum_mask &&
-@@ -905,16 +906,19 @@ void mt7615_mac_sta_poll(struct mt7615_dev *dev)
- 	int i;
- 
- 	INIT_LIST_HEAD(&sta_poll_list);
--	spin_lock_bh(&dev->sta_poll_lock);
--	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	while (!list_empty(&sta_poll_list)) {
- 		bool clear = false;
- 
- 		msta = list_first_entry(&sta_poll_list, struct mt7615_sta,
--					poll_list);
--		list_del_init(&msta->poll_list);
-+					wcid.poll_list);
-+
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		list_del_init(&msta->wcid.poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		addr = mt7615_mac_wtbl_addr(dev, msta->wcid.idx) + 19 * 4;
- 
-@@ -1511,10 +1515,10 @@ static void mt7615_mac_add_txs(struct mt7615_dev *dev, void *data)
- 	msta = container_of(wcid, struct mt7615_sta, wcid);
- 	sta = wcid_to_sta(wcid);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (list_empty(&msta->poll_list))
--		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (list_empty(&msta->wcid.poll_list))
-+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	if (mt7615_mac_add_txs_skb(dev, msta, pid, txs_data))
- 		goto out;
-diff --git a/mt7615/main.c b/mt7615/main.c
-index dadb13f2..200b1752 100644
---- a/mt7615/main.c
-+++ b/mt7615/main.c
-@@ -222,7 +222,7 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
- 
- 	idx = MT7615_WTBL_RESERVED - mvif->mt76.idx;
- 
--	INIT_LIST_HEAD(&mvif->sta.poll_list);
-+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
- 	mvif->sta.wcid.idx = idx;
- 	mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
- 	mvif->sta.wcid.hw_key_idx = -1;
-@@ -274,10 +274,10 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,
- 
- 	mt7615_mutex_release(dev);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	mt76_packet_id_flush(&dev->mt76, &mvif->sta.wcid);
- }
-@@ -552,6 +552,32 @@ static void mt7615_configure_filter(struct ieee80211_hw *hw,
- 	mt7615_mutex_release(dev);
- }
- 
-+static void
-+mt7615_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-+		       struct ieee80211_bss_conf *info)
-+{
-+	struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
-+	struct mt7615_dev *dev = mt7615_hw_dev(hw);
-+	u8 i, band = mvif->mt76.band_idx;
-+	u32 *mu;
-+
-+	mu = (u32 *)info->mu_group.membership;
-+	for (i = 0; i < WLAN_MEMBERSHIP_LEN / sizeof(*mu); i++) {
-+		if (is_mt7663(&dev->mt76))
-+			mt76_wr(dev, MT7663_WF_PHY_GID_TAB_VLD(band, i), mu[i]);
-+		else
-+			mt76_wr(dev, MT_WF_PHY_GID_TAB_VLD(band, i), mu[i]);
-+	}
-+
-+	mu = (u32 *)info->mu_group.position;
-+	for (i = 0; i < WLAN_USER_POSITION_LEN / sizeof(*mu); i++) {
-+		if (is_mt7663(&dev->mt76))
-+			mt76_wr(dev, MT7663_WF_PHY_GID_TAB_POS(band, i), mu[i]);
-+		else
-+			mt76_wr(dev, MT_WF_PHY_GID_TAB_POS(band, i), mu[i]);
-+	}
-+}
-+
- static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
- 				    struct ieee80211_vif *vif,
- 				    struct ieee80211_bss_conf *info,
-@@ -600,6 +626,9 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
- 	if (changed & BSS_CHANGED_ASSOC)
- 		mt7615_mac_set_beacon_filter(phy, vif, vif->cfg.assoc);
- 
-+	if (changed & BSS_CHANGED_MU_GROUPS)
-+		 mt7615_update_mu_group(hw, vif, info);
-+
- 	mt7615_mutex_release(dev);
- }
- 
-@@ -628,7 +657,7 @@ int mt7615_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	if (idx < 0)
- 		return -ENOSPC;
- 
--	INIT_LIST_HEAD(&msta->poll_list);
-+	INIT_LIST_HEAD(&msta->wcid.poll_list);
- 	msta->vif = mvif;
- 	msta->wcid.sta = 1;
- 	msta->wcid.idx = idx;
-@@ -676,10 +705,10 @@ void mt7615_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	if (vif->type == NL80211_IFTYPE_STATION && !sta->tdls)
- 		mt7615_mcu_add_bss_info(phy, vif, sta, false);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&mdev->sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&mdev->sta_poll_lock);
- 
- 	mt76_connac_power_save_sched(phy->mt76, &dev->pm);
- }
-diff --git a/mt7615/mt7615.h b/mt7615/mt7615.h
-index 582d1b5b..a20322aa 100644
---- a/mt7615/mt7615.h
-+++ b/mt7615/mt7615.h
-@@ -125,7 +125,6 @@ struct mt7615_sta {
- 
- 	struct mt7615_vif *vif;
- 
--	struct list_head poll_list;
- 	u32 airtime_ac[8];
- 
- 	struct ieee80211_tx_rate rates[4];
-@@ -262,9 +261,6 @@ struct mt7615_dev {
- 	wait_queue_head_t reset_wait;
- 	u32 reset_state;
- 
--	struct list_head sta_poll_list;
--	spinlock_t sta_poll_lock;
--
- 	struct {
- 		u8 n_pulses;
- 		u32 period;
-diff --git a/mt7615/regs.h b/mt7615/regs.h
-index 7cecb22c..806b3887 100644
---- a/mt7615/regs.h
-+++ b/mt7615/regs.h
-@@ -212,6 +212,15 @@ enum mt7615_reg_base {
- 
- #define MT7663_WF_PHY_R0_PHYCTRL_STS5(_phy)	MT_WF_PHY(0x0224 + ((_phy) << 12))
- 
-+#define MT_WF_PHY_GID_TAB_VLD(_phy, i)		MT_WF_PHY(0x0254 + (i) * 4 + \
-+							  ((_phy) << 9))
-+#define MT7663_WF_PHY_GID_TAB_VLD(_phy, i)	MT_WF_PHY(0x0254 + (i) * 4 + \
-+							  ((_phy) << 12))
-+#define MT_WF_PHY_GID_TAB_POS(_phy, i)		MT_WF_PHY(0x025c + (i) * 4 + \
-+							  ((_phy) << 9))
-+#define MT7663_WF_PHY_GID_TAB_POS(_phy, i)	MT_WF_PHY(0x025c + (i) * 4 + \
-+							  ((_phy) << 12))
-+
- #define MT_WF_PHY_MIN_PRI_PWR(_phy)	MT_WF_PHY((_phy) ? 0x084 : 0x229c)
- #define MT_WF_PHY_PD_OFDM_MASK(_phy)	((_phy) ? GENMASK(24, 16) : \
- 					 GENMASK(28, 20))
-diff --git a/mt76_connac.h b/mt76_connac.h
-index 77ca8f05..22878f08 100644
---- a/mt76_connac.h
-+++ b/mt76_connac.h
-@@ -419,5 +419,13 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
- 				  struct mt76_rx_status *status,
- 				  struct ieee80211_supported_band *sband,
- 				  __le32 *rxv, u8 *mode);
--
-+void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi);
-+void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
-+			    struct ieee80211_sta *sta,
-+			    struct list_head *free_list);
-+void mt76_connac2_tx_token_put(struct mt76_dev *dev);
-+
-+/* connac3 */
-+void mt76_connac3_mac_decode_he_radiotap(struct sk_buff *skb, __le32 *rxv,
-+					 u8 mode);
- #endif /* __MT76_CONNAC_H */
-diff --git a/mt76_connac2_mac.h b/mt76_connac2_mac.h
-index a5ec0f63..bd2a9246 100644
---- a/mt76_connac2_mac.h
-+++ b/mt76_connac2_mac.h
-@@ -34,7 +34,7 @@ enum {
- 
- #define MT_TX_FREE_MSDU_CNT		GENMASK(9, 0)
- #define MT_TX_FREE_WLAN_ID		GENMASK(23, 14)
--#define MT_TX_FREE_LATENCY		GENMASK(12, 0)
-+#define MT_TX_FREE_COUNT		GENMASK(12, 0)
- /* 0: success, others: dropped */
- #define MT_TX_FREE_STATUS		GENMASK(14, 13)
- #define MT_TX_FREE_MSDU_ID		GENMASK(30, 16)
-@@ -173,7 +173,7 @@ enum {
- #define MT_TXS5_MPDU_TX_CNT		GENMASK(31, 23)
- 
- #define MT_TXS6_MPDU_FAIL_CNT		GENMASK(31, 23)
--
-+#define MT_TXS7_MPDU_RETRY_BYTE		GENMASK(22, 0)
- #define MT_TXS7_MPDU_RETRY_CNT		GENMASK(31, 23)
- 
- /* RXD DW0 */
-diff --git a/mt76_connac3_mac.c b/mt76_connac3_mac.c
-new file mode 100644
-index 00000000..73e9f283
---- /dev/null
-+++ b/mt76_connac3_mac.c
-@@ -0,0 +1,182 @@
-+// SPDX-License-Identifier: ISC
-+/* Copyright (C) 2023 MediaTek Inc. */
-+
-+#include "mt76_connac.h"
-+#include "mt76_connac3_mac.h"
-+#include "dma.h"
-+
-+#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 void
-+mt76_connac3_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
-+				       struct ieee80211_radiotap_he *he,
-+				       __le32 *rxv)
-+{
-+	u32 ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC), offs = 0;
-+
-+	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);
-+}
-+
-+#define MU_PREP(f, v)	le16_encode_bits(v, IEEE80211_RADIOTAP_HE_MU_##f)
-+static void
-+mt76_connac3_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;
-+
-+	status->flag |= RX_FLAG_RADIOTAP_HE_MU;
-+
-+	he_mu = skb_push(skb, sizeof(mu_known));
-+	memcpy(he_mu, &mu_known, sizeof(mu_known));
-+
-+	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[4], MT_CRXV_HE_NUM_USER));
-+
-+	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
-+
-+	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[16], MT_CRXV_HE_RU1) & 0xff;
-+	}
-+
-+	if (status->bw >= RATE_INFO_BW_80) {
-+		u32 ru_h, ru_l;
-+
-+		he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
-+
-+		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
-+		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
-+		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
-+	}
-+}
-+
-+void mt76_connac3_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),
-+	};
-+	u32 ltf_size = le32_get_bits(rxv[4], MT_CRXV_HE_LTF_SIZE) + 1;
-+	struct ieee80211_radiotap_he *he;
-+
-+	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[9]) |
-+		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
-+	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
-+	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
-+		    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[9]) |
-+		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
-+
-+	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[8]) |
-+			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
-+		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[5]);
-+		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[5]);
-+		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
-+
-+		mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv);
-+		mt76_connac3_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[13]) |
-+			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
-+			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
-+			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
-+
-+		mt76_connac3_mac_decode_he_radiotap_ru(status, he, rxv);
-+		break;
-+	default:
-+		break;
-+	}
-+}
-+EXPORT_SYMBOL_GPL(mt76_connac3_mac_decode_he_radiotap);
-diff --git a/mt76_connac3_mac.h b/mt76_connac3_mac.h
-new file mode 100644
-index 00000000..6663a0b4
---- /dev/null
-+++ b/mt76_connac3_mac.h
-@@ -0,0 +1,325 @@
-+/* SPDX-License-Identifier: ISC */
-+/* Copyright (C) 2023 MediaTek Inc. */
-+
-+#ifndef __MT76_CONNAC3_MAC_H
-+#define __MT76_CONNAC3_MAC_H
-+
-+#define MT_CT_PARSE_LEN			72
-+#define MT_CT_DMA_BUF_NUM		2
-+
-+#define MT_RXD0_LENGTH			GENMASK(15, 0)
-+#define MT_RXD0_PKT_FLAG                GENMASK(19, 16)
-+#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)
-+
-+#define MT_RXD0_SW_PKT_TYPE_MASK	GENMASK(31, 16)
-+#define MT_RXD0_SW_PKT_TYPE_MAP		0x380F
-+#define MT_RXD0_SW_PKT_TYPE_FRAME	0x3801
-+
-+/* RXD DW1 */
-+#define MT_RXD1_NORMAL_WLAN_IDX		GENMASK(11, 0)
-+#define MT_RXD1_NORMAL_GROUP_1		BIT(16)
-+#define MT_RXD1_NORMAL_GROUP_2		BIT(17)
-+#define MT_RXD1_NORMAL_GROUP_3		BIT(18)
-+#define MT_RXD1_NORMAL_GROUP_4		BIT(19)
-+#define MT_RXD1_NORMAL_GROUP_5		BIT(20)
-+#define MT_RXD1_NORMAL_KEY_ID		GENMASK(22, 21)
-+#define MT_RXD1_NORMAL_CM		BIT(23)
-+#define MT_RXD1_NORMAL_CLM		BIT(24)
-+#define MT_RXD1_NORMAL_ICV_ERR		BIT(25)
-+#define MT_RXD1_NORMAL_TKIP_MIC_ERR	BIT(26)
-+#define MT_RXD1_NORMAL_BAND_IDX		GENMASK(28, 27)
-+#define MT_RXD1_NORMAL_SPP_EN		BIT(29)
-+#define MT_RXD1_NORMAL_ADD_OM		BIT(30)
-+#define MT_RXD1_NORMAL_SEC_DONE		BIT(31)
-+
-+/* RXD DW2 */
-+#define MT_RXD2_NORMAL_BSSID		GENMASK(5, 0)
-+#define MT_RXD2_NORMAL_MAC_HDR_LEN	GENMASK(12, 8)
-+#define MT_RXD2_NORMAL_HDR_TRANS	BIT(7)
-+#define MT_RXD2_NORMAL_HDR_OFFSET	GENMASK(15, 13)
-+#define MT_RXD2_NORMAL_SEC_MODE		GENMASK(20, 16)
-+#define MT_RXD2_NORMAL_MU_BAR		BIT(21)
-+#define MT_RXD2_NORMAL_SW_BIT		BIT(22)
-+#define MT_RXD2_NORMAL_AMSDU_ERR	BIT(23)
-+#define MT_RXD2_NORMAL_MAX_LEN_ERROR	BIT(24)
-+#define MT_RXD2_NORMAL_HDR_TRANS_ERROR	BIT(25)
-+#define MT_RXD2_NORMAL_INT_FRAME	BIT(26)
-+#define MT_RXD2_NORMAL_FRAG		BIT(27)
-+#define MT_RXD2_NORMAL_NULL_FRAME	BIT(28)
-+#define MT_RXD2_NORMAL_NDATA		BIT(29)
-+#define MT_RXD2_NORMAL_NON_AMPDU	BIT(30)
-+#define MT_RXD2_NORMAL_BF_REPORT	BIT(31)
-+
-+/* RXD DW3 */
-+#define MT_RXD3_NORMAL_RXV_SEQ		GENMASK(7, 0)
-+#define MT_RXD3_NORMAL_CH_FREQ		GENMASK(15, 8)
-+#define MT_RXD3_NORMAL_ADDR_TYPE	GENMASK(17, 16)
-+#define MT_RXD3_NORMAL_U2M		BIT(0)
-+#define MT_RXD3_NORMAL_HTC_VLD		BIT(18)
-+#define MT_RXD3_NORMAL_BEACON_MC	BIT(20)
-+#define MT_RXD3_NORMAL_BEACON_UC	BIT(21)
-+#define MT_RXD3_NORMAL_CO_ANT		BIT(22)
-+#define MT_RXD3_NORMAL_FCS_ERR		BIT(24)
-+#define MT_RXD3_NORMAL_VLAN2ETH		BIT(31)
-+
-+/* RXD DW4 */
-+#define MT_RXD4_NORMAL_PAYLOAD_FORMAT	GENMASK(1, 0)
-+#define MT_RXD4_FIRST_AMSDU_FRAME	GENMASK(1, 0)
-+#define MT_RXD4_MID_AMSDU_FRAME		BIT(1)
-+#define MT_RXD4_LAST_AMSDU_FRAME	BIT(0)
-+
-+#define MT_RXV_HDR_BAND_IDX		BIT(24)
-+
-+/* RXD GROUP4 */
-+#define MT_RXD8_FRAME_CONTROL		GENMASK(15, 0)
-+
-+#define MT_RXD10_SEQ_CTRL		GENMASK(15, 0)
-+#define MT_RXD10_QOS_CTL		GENMASK(31, 16)
-+
-+#define MT_RXD11_HT_CONTROL		GENMASK(31, 0)
-+
-+/* P-RXV */
-+#define MT_PRXV_TX_RATE			GENMASK(6, 0)
-+#define MT_PRXV_TX_DCM			BIT(4)
-+#define MT_PRXV_TX_ER_SU_106T		BIT(5)
-+#define MT_PRXV_NSTS			GENMASK(10, 7)
-+#define MT_PRXV_TXBF			BIT(11)
-+#define MT_PRXV_HT_AD_CODE		BIT(12)
-+#define MT_PRXV_HE_RU_ALLOC		GENMASK(30, 22)
-+#define MT_PRXV_RCPI3			GENMASK(31, 24)
-+#define MT_PRXV_RCPI2			GENMASK(23, 16)
-+#define MT_PRXV_RCPI1			GENMASK(15, 8)
-+#define MT_PRXV_RCPI0			GENMASK(7, 0)
-+#define MT_PRXV_HT_SHORT_GI		GENMASK(4, 3)
-+#define MT_PRXV_HT_STBC			GENMASK(10, 9)
-+#define MT_PRXV_TX_MODE			GENMASK(14, 11)
-+#define MT_PRXV_FRAME_MODE		GENMASK(2, 0)
-+#define MT_PRXV_DCM			BIT(5)
-+
-+/* C-RXV */
-+#define MT_CRXV_HE_NUM_USER		GENMASK(26, 20)
-+#define MT_CRXV_HE_LTF_SIZE		GENMASK(28, 27)
-+#define MT_CRXV_HE_LDPC_EXT_SYM		BIT(30)
-+
-+#define MT_CRXV_HE_PE_DISAMBIG		BIT(1)
-+#define MT_CRXV_HE_UPLINK		BIT(2)
-+
-+#define MT_CRXV_HE_MU_AID		GENMASK(27, 17)
-+#define MT_CRXV_HE_BEAM_CHNG		BIT(29)
-+
-+#define MT_CRXV_HE_DOPPLER		BIT(0)
-+#define MT_CRXV_HE_BSS_COLOR		GENMASK(15, 10)
-+#define MT_CRXV_HE_TXOP_DUR		GENMASK(19, 17)
-+
-+#define MT_CRXV_HE_SR_MASK		GENMASK(11, 8)
-+#define MT_CRXV_HE_SR1_MASK		GENMASK(16, 12)
-+#define MT_CRXV_HE_SR2_MASK             GENMASK(20, 17)
-+#define MT_CRXV_HE_SR3_MASK             GENMASK(24, 21)
-+
-+#define MT_CRXV_HE_RU0			GENMASK(8, 0)
-+#define MT_CRXV_HE_RU1			GENMASK(17, 9)
-+#define MT_CRXV_HE_RU2			GENMASK(26, 18)
-+#define MT_CRXV_HE_RU3_L		GENMASK(31, 27)
-+#define MT_CRXV_HE_RU3_H		GENMASK(3, 0)
-+
-+enum tx_header_format {
-+	MT_HDR_FORMAT_802_3,
-+	MT_HDR_FORMAT_CMD,
-+	MT_HDR_FORMAT_802_11,
-+	MT_HDR_FORMAT_802_11_EXT,
-+};
-+
-+enum tx_pkt_type {
-+	MT_TX_TYPE_CT,
-+	MT_TX_TYPE_SF,
-+	MT_TX_TYPE_CMD,
-+	MT_TX_TYPE_FW,
-+};
-+
-+enum tx_port_idx {
-+	MT_TX_PORT_IDX_LMAC,
-+	MT_TX_PORT_IDX_MCU
-+};
-+
-+enum tx_mcu_port_q_idx {
-+	MT_TX_MCU_PORT_RX_Q0 = 0x20,
-+	MT_TX_MCU_PORT_RX_Q1,
-+	MT_TX_MCU_PORT_RX_Q2,
-+	MT_TX_MCU_PORT_RX_Q3,
-+	MT_TX_MCU_PORT_RX_FWDL = 0x3e
-+};
-+
-+enum tx_mgnt_type {
-+	MT_TX_NORMAL,
-+	MT_TX_TIMING,
-+	MT_TX_ADDBA,
-+};
-+
-+#define MT_CT_INFO_APPLY_TXD		BIT(0)
-+#define MT_CT_INFO_COPY_HOST_TXD_ALL	BIT(1)
-+#define MT_CT_INFO_MGMT_FRAME		BIT(2)
-+#define MT_CT_INFO_NONE_CIPHER_FRAME	BIT(3)
-+#define MT_CT_INFO_HSR2_TX		BIT(4)
-+#define MT_CT_INFO_FROM_HOST		BIT(7)
-+
-+#define MT_TXD_SIZE			(8 * 4)
-+
-+#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_TX_BYTES		GENMASK(15, 0)
-+
-+#define MT_TXD1_FIXED_RATE		BIT(31)
-+#define MT_TXD1_OWN_MAC			GENMASK(30, 25)
-+#define MT_TXD1_TID			GENMASK(24, 21)
-+#define MT_TXD1_BIP			BIT(24)
-+#define MT_TXD1_ETH_802_3		BIT(20)
-+#define MT_TXD1_HDR_INFO		GENMASK(20, 16)
-+#define MT_TXD1_HDR_FORMAT		GENMASK(15, 14)
-+#define MT_TXD1_TGID			GENMASK(13, 12)
-+#define MT_TXD1_WLAN_IDX		GENMASK(11, 0)
-+
-+#define MT_TXD2_POWER_OFFSET		GENMASK(31, 26)
-+#define MT_TXD2_MAX_TX_TIME		GENMASK(25, 16)
-+#define MT_TXD2_FRAG			GENMASK(15, 14)
-+#define MT_TXD2_HTC_VLD			BIT(13)
-+#define MT_TXD2_DURATION		BIT(12)
-+#define MT_TXD2_HDR_PAD			GENMASK(11, 10)
-+#define MT_TXD2_RTS			BIT(9)
-+#define MT_TXD2_OWN_MAC_MAP		BIT(8)
-+#define MT_TXD2_BF_TYPE			GENMASK(6, 7)
-+#define MT_TXD2_FRAME_TYPE		GENMASK(5, 4)
-+#define MT_TXD2_SUB_TYPE		GENMASK(3, 0)
-+
-+#define MT_TXD3_SN_VALID		BIT(31)
-+#define MT_TXD3_PN_VALID		BIT(30)
-+#define MT_TXD3_SW_POWER_MGMT		BIT(29)
-+#define MT_TXD3_BA_DISABLE		BIT(28)
-+#define MT_TXD3_SEQ			GENMASK(27, 16)
-+#define MT_TXD3_REM_TX_COUNT		GENMASK(15, 11)
-+#define MT_TXD3_TX_COUNT		GENMASK(10, 6)
-+#define MT_TXD3_HW_AMSDU		BIT(5)
-+#define MT_TXD3_BCM			BIT(4)
-+#define MT_TXD3_EEOSP			BIT(3)
-+#define MT_TXD3_EMRD			BIT(2)
-+#define MT_TXD3_PROTECT_FRAME		BIT(1)
-+#define MT_TXD3_NO_ACK			BIT(0)
-+
-+#define MT_TXD4_PN_LOW			GENMASK(31, 0)
-+
-+#define MT_TXD5_PN_HIGH			GENMASK(31, 16)
-+#define MT_TXD5_FL			BIT(15)
-+#define MT_TXD5_BYPASS_TBB		BIT(14)
-+#define MT_TXD5_BYPASS_RBB		BIT(13)
-+#define MT_TXD5_BSS_COLOR_ZERO		BIT(12)
-+#define MT_TXD5_TX_STATUS_HOST		BIT(10)
-+#define MT_TXD5_TX_STATUS_MCU		BIT(9)
-+#define MT_TXD5_TX_STATUS_FMT		BIT(8)
-+#define MT_TXD5_PID			GENMASK(7, 0)
-+
-+#define MT_TXD6_TX_SRC			GENMASK(31, 30)
-+#define MT_TXD6_VTA			BIT(28)
-+#define MT_TXD6_BW			GENMASK(25, 22)
-+#define MT_TXD6_TX_RATE			GENMASK(21, 16)
-+#define MT_TXD6_TIMESTAMP_OFS_EN	BIT(15)
-+#define MT_TXD6_TIMESTAMP_OFS_IDX	GENMASK(14, 10)
-+#define MT_TXD6_MSDU_CNT		GENMASK(9, 4)
-+#define MT_TXD6_DIS_MAT			BIT(3)
-+#define MT_TXD6_DAS			BIT(2)
-+#define MT_TXD6_AMSDU_CAP		BIT(1)
-+
-+#define MT_TXD7_TXD_LEN			GENMASK(31, 30)
-+#define MT_TXD7_IP_SUM			BIT(29)
-+#define MT_TXD7_DROP_BY_SDO		BIT(28)
-+#define MT_TXD7_MAC_TXD			BIT(27)
-+#define MT_TXD7_CTXD			BIT(26)
-+#define MT_TXD7_CTXD_CNT		GENMASK(25, 22)
-+#define MT_TXD7_UDP_TCP_SUM		BIT(15)
-+#define MT_TXD7_TX_TIME			GENMASK(9, 0)
-+
-+#define MT_TX_RATE_STBC			BIT(14)
-+#define MT_TX_RATE_NSS			GENMASK(13, 10)
-+#define MT_TX_RATE_MODE			GENMASK(9, 6)
-+#define MT_TX_RATE_SU_EXT_TONE		BIT(5)
-+#define MT_TX_RATE_DCM			BIT(4)
-+/* VHT/HE only use bits 0-3 */
-+#define MT_TX_RATE_IDX			GENMASK(5, 0)
-+
-+#define MT_TXFREE0_PKT_TYPE		GENMASK(31, 27)
-+#define MT_TXFREE0_MSDU_CNT		GENMASK(25, 16)
-+#define MT_TXFREE0_RX_BYTE		GENMASK(15, 0)
-+
-+#define MT_TXFREE1_VER			GENMASK(18, 16)
-+
-+#define MT_TXFREE_INFO_PAIR		BIT(31)
-+#define MT_TXFREE_INFO_HEADER		BIT(30)
-+#define MT_TXFREE_INFO_WLAN_ID		GENMASK(23, 12)
-+#define MT_TXFREE_INFO_MSDU_ID		GENMASK(14, 0)
-+#define MT_TXFREE_INFO_COUNT		GENMASK(27, 24)
-+#define MT_TXFREE_INFO_STAT		GENMASK(29, 28)
-+
-+#define MT_TXS0_BW			GENMASK(31, 29)
-+#define MT_TXS0_TID			GENMASK(28, 26)
-+#define MT_TXS0_AMPDU			BIT(25)
-+#define MT_TXS0_TXS_FORMAT		GENMASK(24, 23)
-+#define MT_TXS0_BA_ERROR		BIT(22)
-+#define MT_TXS0_PS_FLAG			BIT(21)
-+#define MT_TXS0_TXOP_TIMEOUT		BIT(20)
-+#define MT_TXS0_BIP_ERROR		BIT(19)
-+
-+#define MT_TXS0_QUEUE_TIMEOUT		BIT(18)
-+#define MT_TXS0_RTS_TIMEOUT		BIT(17)
-+#define MT_TXS0_ACK_TIMEOUT		BIT(16)
-+#define MT_TXS0_ACK_ERROR_MASK		GENMASK(18, 16)
-+
-+#define MT_TXS0_TX_STATUS_HOST		BIT(15)
-+#define MT_TXS0_TX_STATUS_MCU		BIT(14)
-+#define MT_TXS0_TX_RATE			GENMASK(13, 0)
-+
-+#define MT_TXS1_SEQNO			GENMASK(31, 20)
-+#define MT_TXS1_RESP_RATE		GENMASK(19, 16)
-+#define MT_TXS1_RXV_SEQNO		GENMASK(15, 8)
-+#define MT_TXS1_TX_POWER_DBM		GENMASK(7, 0)
-+
-+#define MT_TXS2_BF_STATUS		GENMASK(31, 30)
-+#define MT_TXS2_BAND			GENMASK(29, 28)
-+#define MT_TXS2_WCID			GENMASK(27, 16)
-+#define MT_TXS2_TX_DELAY		GENMASK(15, 0)
-+
-+#define MT_TXS3_PID			GENMASK(31, 24)
-+#define MT_TXS3_RATE_STBC		BIT(7)
-+#define MT_TXS3_FIXED_RATE		BIT(6)
-+#define MT_TXS3_SRC			GENMASK(5, 4)
-+#define MT_TXS3_SHARED_ANTENNA		BIT(3)
-+#define MT_TXS3_LAST_TX_RATE		GENMASK(2, 0)
-+
-+#define MT_TXS4_TIMESTAMP		GENMASK(31, 0)
-+
-+#define MT_TXS5_F0_FINAL_MPDU		BIT(31)
-+#define MT_TXS5_F0_QOS			BIT(30)
-+#define MT_TXS5_F0_TX_COUNT		GENMASK(29, 25)
-+#define MT_TXS5_F0_FRONT_TIME		GENMASK(24, 0)
-+#define MT_TXS5_F1_MPDU_TX_COUNT	GENMASK(31, 24)
-+#define MT_TXS5_F1_MPDU_TX_BYTES	GENMASK(23, 0)
-+
-+#define MT_TXS6_F0_NOISE_3		GENMASK(31, 24)
-+#define MT_TXS6_F0_NOISE_2		GENMASK(23, 16)
-+#define MT_TXS6_F0_NOISE_1		GENMASK(15, 8)
-+#define MT_TXS6_F0_NOISE_0		GENMASK(7, 0)
-+#define MT_TXS6_F1_MPDU_FAIL_COUNT	GENMASK(31, 24)
-+#define MT_TXS6_F1_MPDU_FAIL_BYTES	GENMASK(23, 0)
-+
-+#define MT_TXS7_F0_RCPI_3		GENMASK(31, 24)
-+#define MT_TXS7_F0_RCPI_2		GENMASK(23, 16)
-+#define MT_TXS7_F0_RCPI_1		GENMASK(15, 8)
-+#define MT_TXS7_F0_RCPI_0		GENMASK(7, 0)
-+#define MT_TXS7_F1_MPDU_RETRY_COUNT	GENMASK(31, 24)
-+#define MT_TXS7_F1_MPDU_RETRY_BYTES	GENMASK(23, 0)
-+
-+#endif /* __MT76_CONNAC3_MAC_H */
-diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index ee0fbfcd..ee5177fd 100644
---- a/mt76_connac_mac.c
-+++ b/mt76_connac_mac.c
-@@ -495,6 +495,7 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
- 				    BSS_CHANGED_BEACON_ENABLED));
- 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
- 					 BSS_CHANGED_FILS_DISCOVERY));
-+	bool amsdu_en = wcid->amsdu;
- 
- 	if (vif) {
- 		struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
-@@ -521,9 +522,9 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
- 		q_idx = wmm_idx * MT76_CONNAC_MAX_WMM_SETS +
- 			mt76_connac_lmac_mapping(skb_get_queue_mapping(skb));
- 
--		/* counting non-offloading skbs */
--		wcid->stats.tx_bytes += skb->len;
--		wcid->stats.tx_packets++;
-+		/* mt7915 WA only counts WED path */
-+		if (is_mt7915(dev) && mtk_wed_device_active(&dev->mmio.wed))
-+			wcid->stats.tx_packets++;
- 	}
- 
- 	val = FIELD_PREP(MT_TXD0_TX_BYTES, skb->len + sz_txd) |
-@@ -554,12 +555,14 @@ void mt76_connac2_mac_write_txwi(struct mt76_dev *dev, __le32 *txwi,
- 	txwi[4] = 0;
- 
- 	val = FIELD_PREP(MT_TXD5_PID, pid);
--	if (pid >= MT_PACKET_ID_FIRST)
-+	if (pid >= MT_PACKET_ID_FIRST) {
- 		val |= MT_TXD5_TX_STATUS_HOST;
-+		amsdu_en = amsdu_en && !is_mt7921(dev);
-+	}
- 
- 	txwi[5] = cpu_to_le32(val);
- 	txwi[6] = 0;
--	txwi[7] = wcid->amsdu ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
-+	txwi[7] = amsdu_en ? cpu_to_le32(MT_TXD7_HW_AMSDU) : 0;
- 
- 	if (is_8023)
- 		mt76_connac2_mac_write_txwi_8023(txwi, skb, wcid);
-@@ -606,11 +609,11 @@ bool mt76_connac2_mac_fill_txs(struct mt76_dev *dev, struct mt76_wcid *wcid,
- 	txs = le32_to_cpu(txs_data[0]);
- 
- 	/* PPDU based reporting */
--	if (FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
-+	if (mtk_wed_device_active(&dev->mmio.wed) &&
-+	    FIELD_GET(MT_TXS0_TXS_FORMAT, txs) > 1) {
- 		stats->tx_bytes +=
--			le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE);
--		stats->tx_packets +=
--			le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_CNT);
-+			le32_get_bits(txs_data[5], MT_TXS5_MPDU_TX_BYTE) -
-+			le32_get_bits(txs_data[7], MT_TXS7_MPDU_RETRY_BYTE);
- 		stats->tx_failed +=
- 			le32_get_bits(txs_data[6], MT_TXS6_MPDU_FAIL_CNT);
- 		stats->tx_retries +=
-@@ -728,17 +731,15 @@ bool mt76_connac2_mac_add_txs_skb(struct mt76_dev *dev, struct mt76_wcid *wcid,
- 	skb = mt76_tx_status_skb_get(dev, wcid, pid, &list);
- 	if (skb) {
- 		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
--		bool noacked = !(info->flags & IEEE80211_TX_STAT_ACK);
- 
- 		if (!(le32_to_cpu(txs_data[0]) & MT_TXS0_ACK_ERROR_MASK))
- 			info->flags |= IEEE80211_TX_STAT_ACK;
- 
- 		info->status.ampdu_len = 1;
--		info->status.ampdu_ack_len = !noacked;
-+		info->status.ampdu_ack_len =
-+			!!(info->flags & IEEE80211_TX_STAT_ACK);
- 		info->status.rates[0].idx = -1;
- 
--		wcid->stats.tx_failed += noacked;
--
- 		mt76_connac2_mac_fill_txs(dev, wcid, txs_data);
- 		mt76_tx_status_skb_done(dev, skb, &list);
- 	}
-@@ -1111,3 +1112,85 @@ int mt76_connac2_mac_fill_rx_rate(struct mt76_dev *dev,
- 	return 0;
- }
- EXPORT_SYMBOL_GPL(mt76_connac2_mac_fill_rx_rate);
-+
-+void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
-+{
-+	struct mt76_wcid *wcid;
-+	u16 fc, tid;
-+	u32 val;
-+
-+	if (!sta ||
-+	    !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
-+		return;
-+
-+	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
-+	if (tid >= 6) /* skip VO queue */
-+		return;
-+
-+	val = le32_to_cpu(txwi[2]);
-+	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
-+	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
-+	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
-+		return;
-+
-+	wcid = (struct mt76_wcid *)sta->drv_priv;
-+	if (!test_and_set_bit(tid, &wcid->ampdu_state))
-+		ieee80211_start_tx_ba_session(sta, tid, 0);
-+}
-+EXPORT_SYMBOL_GPL(mt76_connac2_tx_check_aggr);
-+
-+void mt76_connac2_txwi_free(struct mt76_dev *dev, struct mt76_txwi_cache *t,
-+			    struct ieee80211_sta *sta,
-+			    struct list_head *free_list)
-+{
-+	struct mt76_wcid *wcid;
-+	__le32 *txwi;
-+	u16 wcid_idx;
-+
-+	mt76_connac_txp_skb_unmap(dev, t);
-+	if (!t->skb)
-+		goto out;
-+
-+	txwi = (__le32 *)mt76_get_txwi_ptr(dev, t);
-+	if (sta) {
-+		wcid = (struct mt76_wcid *)sta->drv_priv;
-+		wcid_idx = wcid->idx;
-+	} else {
-+		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
-+		wcid = rcu_dereference(dev->wcid[wcid_idx]);
-+
-+		if (wcid && wcid->sta) {
-+			sta = container_of((void *)wcid, struct ieee80211_sta,
-+					   drv_priv);
-+			spin_lock_bh(&dev->sta_poll_lock);
-+			if (list_empty(&wcid->poll_list))
-+				list_add_tail(&wcid->poll_list,
-+					      &dev->sta_poll_list);
-+			spin_unlock_bh(&dev->sta_poll_lock);
-+		}
-+	}
-+
-+	if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
-+		mt76_connac2_tx_check_aggr(sta, txwi);
-+
-+	__mt76_tx_complete_skb(dev, wcid_idx, t->skb, free_list);
-+out:
-+	t->skb = NULL;
-+	mt76_put_txwi(dev, t);
-+}
-+EXPORT_SYMBOL_GPL(mt76_connac2_txwi_free);
-+
-+void mt76_connac2_tx_token_put(struct mt76_dev *dev)
-+{
-+	struct mt76_txwi_cache *txwi;
-+	int id;
-+
-+	spin_lock_bh(&dev->token_lock);
-+	idr_for_each_entry(&dev->token, txwi, id) {
-+		mt76_connac2_txwi_free(dev, txwi, NULL, NULL);
-+		dev->token_count--;
-+	}
-+	spin_unlock_bh(&dev->token_lock);
-+	idr_destroy(&dev->token);
-+}
-+EXPORT_SYMBOL_GPL(mt76_connac2_tx_token_put);
-diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index 46f69aa8..0f0a519f 100644
---- a/mt76_connac_mcu.c
-+++ b/mt76_connac_mcu.c
-@@ -1221,6 +1221,9 @@ EXPORT_SYMBOL_GPL(mt76_connac_mcu_sta_ba_tlv);
- 
- int mt76_connac_mcu_sta_wed_update(struct mt76_dev *dev, struct sk_buff *skb)
- {
-+	if (!mt76_is_mmio(dev))
-+		return 0;
-+
- 	if (!mtk_wed_device_active(&dev->mmio.wed))
- 		return 0;
- 
-diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index 91d98eff..fe729bbf 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)
-@@ -518,7 +519,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 {
-@@ -998,6 +1000,7 @@ enum {
- 	MCU_EXT_EVENT_ASSERT_DUMP = 0x23,
- 	MCU_EXT_EVENT_RDD_REPORT = 0x3a,
- 	MCU_EXT_EVENT_CSA_NOTIFY = 0x4f,
-+	MCU_EXT_EVENT_WA_TX_STAT = 0x74,
- 	MCU_EXT_EVENT_BCC_NOTIFY = 0x75,
- 	MCU_EXT_EVENT_MURU_CTRL = 0x9f,
- };
-@@ -1287,6 +1290,7 @@ enum {
- 	UNI_BSS_INFO_UAPSD = 19,
- 	UNI_BSS_INFO_PS = 21,
- 	UNI_BSS_INFO_BCNFT = 22,
-+	UNI_BSS_INFO_IFS_TIME = 23,
- 	UNI_BSS_INFO_OFFLOAD = 25,
- 	UNI_BSS_INFO_MLD = 26,
- };
-diff --git a/mt76x02_util.c b/mt76x02_util.c
-index dcbb5c60..a9b77083 100644
---- a/mt76x02_util.c
-+++ b/mt76x02_util.c
-@@ -413,12 +413,9 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- 	struct mt76x02_sta *msta;
- 	struct mt76_wcid *wcid;
- 	int idx = key->keyidx;
--	int ret;
- 
- 	/* fall back to sw encryption for unsupported ciphers */
- 	switch (key->cipher) {
--	case WLAN_CIPHER_SUITE_WEP40:
--	case WLAN_CIPHER_SUITE_WEP104:
- 	case WLAN_CIPHER_SUITE_TKIP:
- 	case WLAN_CIPHER_SUITE_CCMP:
- 		break;
-@@ -471,16 +468,6 @@ int mt76x02_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
- 	}
- 	mt76_wcid_key_setup(&dev->mt76, wcid, key);
- 
--	if (!msta) {
--		if (key || wcid->hw_key_idx == idx) {
--			ret = mt76x02_mac_wcid_set_key(dev, wcid->idx, key);
--			if (ret)
--				return ret;
--		}
--
--		return mt76x02_mac_shared_key_setup(dev, mvif->idx, idx, key);
--	}
--
- 	return mt76x02_mac_wcid_set_key(dev, msta->wcid.idx, key);
- }
- EXPORT_SYMBOL_GPL(mt76x02_set_key);
-diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
-index 879884ea..6c3696c8 100644
---- a/mt7915/debugfs.c
-+++ b/mt7915/debugfs.c
-@@ -251,7 +251,6 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- {
- 	struct mt7915_phy *phy = file->private;
- 	struct mt7915_dev *dev = phy->dev;
--	struct mt7915_mcu_muru_stats mu_stats = {};
- 	static const char * const dl_non_he_type[] = {
- 		"CCK", "OFDM", "HT MIX", "HT GF",
- 		"VHT SU", "VHT 2MU", "VHT 3MU", "VHT 4MU"
-@@ -275,7 +274,7 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 
- 	mutex_lock(&dev->mt76.mutex);
- 
--	ret = mt7915_mcu_muru_debug_get(phy, &mu_stats);
-+	ret = mt7915_mcu_muru_debug_get(phy);
- 	if (ret)
- 		goto exit;
- 
-@@ -285,14 +284,13 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 	for (i = 0; i < 5; i++)
- 		seq_printf(file, "%8s | ", dl_non_he_type[i]);
- 
--#define __dl_u32(s)     le32_to_cpu(mu_stats.dl.s)
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | ",
--		   __dl_u32(cck_cnt),
--		   __dl_u32(ofdm_cnt),
--		   __dl_u32(htmix_cnt),
--		   __dl_u32(htgf_cnt),
--		   __dl_u32(vht_su_cnt));
-+		   phy->mib.dl_cck_cnt,
-+		   phy->mib.dl_ofdm_cnt,
-+		   phy->mib.dl_htmix_cnt,
-+		   phy->mib.dl_htgf_cnt,
-+		   phy->mib.dl_vht_su_cnt);
- 
- 	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
- 
-@@ -301,23 +299,23 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | %8u | ",
--		   __dl_u32(vht_2mu_cnt),
--		   __dl_u32(vht_3mu_cnt),
--		   __dl_u32(vht_4mu_cnt));
-+		   phy->mib.dl_vht_2mu_cnt,
-+		   phy->mib.dl_vht_3mu_cnt,
-+		   phy->mib.dl_vht_4mu_cnt);
- 
--	sub_total_cnt = __dl_u32(vht_2mu_cnt) +
--		__dl_u32(vht_3mu_cnt) +
--		__dl_u32(vht_4mu_cnt);
-+	sub_total_cnt = phy->mib.dl_vht_2mu_cnt +
-+			phy->mib.dl_vht_3mu_cnt +
-+			phy->mib.dl_vht_4mu_cnt;
- 
- 	seq_printf(file, "\nTotal non-HE MU-MIMO DL PPDU count: %lld",
- 		   sub_total_cnt);
- 
- 	total_ppdu_cnt = sub_total_cnt +
--		__dl_u32(cck_cnt) +
--		__dl_u32(ofdm_cnt) +
--		__dl_u32(htmix_cnt) +
--		__dl_u32(htgf_cnt) +
--		__dl_u32(vht_su_cnt);
-+			 phy->mib.dl_cck_cnt +
-+			 phy->mib.dl_ofdm_cnt +
-+			 phy->mib.dl_htmix_cnt +
-+			 phy->mib.dl_htgf_cnt +
-+			 phy->mib.dl_vht_su_cnt;
- 
- 	seq_printf(file, "\nAll non-HE DL PPDU count: %lld", total_ppdu_cnt);
- 
-@@ -329,8 +327,7 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | ",
--		   __dl_u32(he_su_cnt),
--		   __dl_u32(he_ext_su_cnt));
-+		   phy->mib.dl_he_su_cnt, phy->mib.dl_he_ext_su_cnt);
- 
- 	seq_puts(file, "\nDownlink MU-MIMO\nData Type:  ");
- 
-@@ -339,9 +336,8 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | %8u | ",
--		   __dl_u32(he_2mu_cnt),
--		   __dl_u32(he_3mu_cnt),
--		   __dl_u32(he_4mu_cnt));
-+		   phy->mib.dl_he_2mu_cnt, phy->mib.dl_he_3mu_cnt,
-+		   phy->mib.dl_he_4mu_cnt);
- 
- 	seq_puts(file, "\nDownlink OFDMA\nData Type:  ");
- 
-@@ -350,37 +346,35 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | %8u | %8u | %9u | %8u | ",
--		   __dl_u32(he_2ru_cnt),
--		   __dl_u32(he_3ru_cnt),
--		   __dl_u32(he_4ru_cnt),
--		   __dl_u32(he_5to8ru_cnt),
--		   __dl_u32(he_9to16ru_cnt),
--		   __dl_u32(he_gtr16ru_cnt));
--
--	sub_total_cnt = __dl_u32(he_2mu_cnt) +
--		__dl_u32(he_3mu_cnt) +
--		__dl_u32(he_4mu_cnt);
-+		   phy->mib.dl_he_2ru_cnt,
-+		   phy->mib.dl_he_3ru_cnt,
-+		   phy->mib.dl_he_4ru_cnt,
-+		   phy->mib.dl_he_5to8ru_cnt,
-+		   phy->mib.dl_he_9to16ru_cnt,
-+		   phy->mib.dl_he_gtr16ru_cnt);
-+
-+	sub_total_cnt = phy->mib.dl_he_2mu_cnt +
-+			phy->mib.dl_he_3mu_cnt +
-+			phy->mib.dl_he_4mu_cnt;
- 	total_ppdu_cnt = sub_total_cnt;
- 
- 	seq_printf(file, "\nTotal HE MU-MIMO DL PPDU count: %lld",
- 		   sub_total_cnt);
- 
--	sub_total_cnt = __dl_u32(he_2ru_cnt) +
--		__dl_u32(he_3ru_cnt) +
--		__dl_u32(he_4ru_cnt) +
--		__dl_u32(he_5to8ru_cnt) +
--		__dl_u32(he_9to16ru_cnt) +
--		__dl_u32(he_gtr16ru_cnt);
-+	sub_total_cnt = phy->mib.dl_he_2ru_cnt +
-+			phy->mib.dl_he_3ru_cnt +
-+			phy->mib.dl_he_4ru_cnt +
-+			phy->mib.dl_he_5to8ru_cnt +
-+			phy->mib.dl_he_9to16ru_cnt +
-+			phy->mib.dl_he_gtr16ru_cnt;
- 	total_ppdu_cnt += sub_total_cnt;
- 
- 	seq_printf(file, "\nTotal HE OFDMA DL PPDU count: %lld",
- 		   sub_total_cnt);
- 
--	total_ppdu_cnt += __dl_u32(he_su_cnt) +
--		__dl_u32(he_ext_su_cnt);
-+	total_ppdu_cnt += phy->mib.dl_he_su_cnt + phy->mib.dl_he_ext_su_cnt;
- 
- 	seq_printf(file, "\nAll HE DL PPDU count: %lld", total_ppdu_cnt);
--#undef __dl_u32
- 
- 	/* HE Uplink */
- 	seq_puts(file, "\n\nUplink");
-@@ -389,12 +383,11 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 	for (i = 0; i < 3; i++)
- 		seq_printf(file, "%8s | ", ul_he_type[i]);
- 
--#define __ul_u32(s)     le32_to_cpu(mu_stats.ul.s)
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | %8u | ",
--		   __ul_u32(hetrig_2mu_cnt),
--		   __ul_u32(hetrig_3mu_cnt),
--		   __ul_u32(hetrig_4mu_cnt));
-+		   phy->mib.ul_hetrig_2mu_cnt,
-+		   phy->mib.ul_hetrig_3mu_cnt,
-+		   phy->mib.ul_hetrig_4mu_cnt);
- 
- 	seq_puts(file, "\nTrigger-based Uplink OFDMA\nData Type:  ");
- 
-@@ -403,37 +396,36 @@ static int mt7915_muru_stats_show(struct seq_file *file, void *data)
- 
- 	seq_puts(file, "\nTotal Count:");
- 	seq_printf(file, "%8u | %8u | %8u | %8u | %8u | %9u |  %7u | ",
--		   __ul_u32(hetrig_su_cnt),
--		   __ul_u32(hetrig_2ru_cnt),
--		   __ul_u32(hetrig_3ru_cnt),
--		   __ul_u32(hetrig_4ru_cnt),
--		   __ul_u32(hetrig_5to8ru_cnt),
--		   __ul_u32(hetrig_9to16ru_cnt),
--		   __ul_u32(hetrig_gtr16ru_cnt));
--
--	sub_total_cnt = __ul_u32(hetrig_2mu_cnt) +
--		__ul_u32(hetrig_3mu_cnt) +
--		__ul_u32(hetrig_4mu_cnt);
-+		   phy->mib.ul_hetrig_su_cnt,
-+		   phy->mib.ul_hetrig_2ru_cnt,
-+		   phy->mib.ul_hetrig_3ru_cnt,
-+		   phy->mib.ul_hetrig_4ru_cnt,
-+		   phy->mib.ul_hetrig_5to8ru_cnt,
-+		   phy->mib.ul_hetrig_9to16ru_cnt,
-+		   phy->mib.ul_hetrig_gtr16ru_cnt);
-+
-+	sub_total_cnt = phy->mib.ul_hetrig_2mu_cnt +
-+			phy->mib.ul_hetrig_3mu_cnt +
-+			phy->mib.ul_hetrig_4mu_cnt;
- 	total_ppdu_cnt = sub_total_cnt;
- 
- 	seq_printf(file, "\nTotal HE MU-MIMO UL TB PPDU count: %lld",
- 		   sub_total_cnt);
- 
--	sub_total_cnt = __ul_u32(hetrig_2ru_cnt) +
--		__ul_u32(hetrig_3ru_cnt) +
--		__ul_u32(hetrig_4ru_cnt) +
--		__ul_u32(hetrig_5to8ru_cnt) +
--		__ul_u32(hetrig_9to16ru_cnt) +
--		__ul_u32(hetrig_gtr16ru_cnt);
-+	sub_total_cnt = phy->mib.ul_hetrig_2ru_cnt +
-+			phy->mib.ul_hetrig_3ru_cnt +
-+			phy->mib.ul_hetrig_4ru_cnt +
-+			phy->mib.ul_hetrig_5to8ru_cnt +
-+			phy->mib.ul_hetrig_9to16ru_cnt +
-+			phy->mib.ul_hetrig_gtr16ru_cnt;
- 	total_ppdu_cnt += sub_total_cnt;
- 
- 	seq_printf(file, "\nTotal HE OFDMA UL TB PPDU count: %lld",
- 		   sub_total_cnt);
- 
--	total_ppdu_cnt += __ul_u32(hetrig_su_cnt);
-+	total_ppdu_cnt += phy->mib.ul_hetrig_su_cnt;
- 
- 	seq_printf(file, "\nAll HE UL TB PPDU count: %lld\n", total_ppdu_cnt);
--#undef __ul_u32
- 
- exit:
- 	mutex_unlock(&dev->mt76.mutex);
-@@ -719,10 +711,10 @@ mt7915_ampdu_stat_read_phy(struct mt7915_phy *phy,
- static void
- mt7915_txbf_stat_read_phy(struct mt7915_phy *phy, struct seq_file *s)
- {
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	static const char * const bw[] = {
- 		"BW20", "BW40", "BW80", "BW160"
- 	};
--	struct mib_stats *mib = &phy->mib;
- 
- 	/* Tx Beamformer monitor */
- 	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
-@@ -768,7 +760,7 @@ mt7915_tx_stats_show(struct seq_file *file, void *data)
- {
- 	struct mt7915_phy *phy = file->private;
- 	struct mt7915_dev *dev = phy->dev;
--	struct mib_stats *mib = &phy->mib;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	int i;
- 
- 	mutex_lock(&dev->mt76.mutex);
-diff --git a/mt7915/dma.c b/mt7915/dma.c
-index 86a93ded..59a44d79 100644
---- a/mt7915/dma.c
-+++ b/mt7915/dma.c
-@@ -250,12 +250,90 @@ static void mt7915_dma_disable(struct mt7915_dev *dev, bool rst)
- 	}
- }
- 
--static int mt7915_dma_enable(struct mt7915_dev *dev)
-+int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset)
- {
- 	struct mt76_dev *mdev = &dev->mt76;
- 	u32 hif1_ofs = 0;
- 	u32 irq_mask;
- 
-+	if (dev->hif2)
-+		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
-+
-+	/* enable wpdma tx/rx */
-+	if (!reset) {
-+		mt76_set(dev, MT_WFDMA0_GLO_CFG,
-+			MT_WFDMA0_GLO_CFG_TX_DMA_EN |
-+			MT_WFDMA0_GLO_CFG_RX_DMA_EN |
-+			MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
-+			MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-+
-+		if (is_mt7915(mdev))
-+			mt76_set(dev, MT_WFDMA1_GLO_CFG,
-+				MT_WFDMA1_GLO_CFG_TX_DMA_EN |
-+				MT_WFDMA1_GLO_CFG_RX_DMA_EN |
-+				MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
-+				MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
-+
-+		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 |
-+				MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
-+				MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-+
-+			if (is_mt7915(mdev))
-+				mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
-+					MT_WFDMA1_GLO_CFG_TX_DMA_EN |
-+					MT_WFDMA1_GLO_CFG_RX_DMA_EN |
-+					MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
-+					MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
-+
-+			mt76_set(dev, MT_WFDMA_HOST_CONFIG,
-+				MT_WFDMA_HOST_CONFIG_PDMA_BAND);
-+		}
-+	}
-+
-+	/* enable interrupts for TX/RX rings */
-+	irq_mask = MT_INT_RX_DONE_MCU |
-+		   MT_INT_TX_DONE_MCU |
-+		   MT_INT_MCU_CMD;
-+
-+	if (!dev->phy.mt76->band_idx)
-+		irq_mask |= MT_INT_BAND0_RX_DONE;
-+
-+	if (dev->dbdc_support || dev->phy.mt76->band_idx)
-+		irq_mask |= MT_INT_BAND1_RX_DONE;
-+
-+	if (mtk_wed_device_active(&dev->mt76.mmio.wed) && wed_reset) {
-+		u32 wed_irq_mask = irq_mask;
-+		int ret;
-+
-+		wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1;
-+		if (!is_mt798x(&dev->mt76))
-+			mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask);
-+		else
-+			mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
-+
-+		ret = mt7915_mcu_wed_enable_rx_stats(dev);
-+		if (ret)
-+			return ret;
-+
-+		mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask);
-+	}
-+
-+	irq_mask = reset ? MT_INT_MCU_CMD : irq_mask;
-+
-+	mt7915_irq_enable(dev, irq_mask);
-+	mt7915_irq_disable(dev, 0);
-+
-+	return 0;
-+}
-+
-+static int mt7915_dma_enable(struct mt7915_dev *dev, bool reset)
-+{
-+	struct mt76_dev *mdev = &dev->mt76;
-+	u32 hif1_ofs = 0;
-+
- 	if (dev->hif2)
- 		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
- 
-@@ -322,69 +400,7 @@ static int mt7915_dma_enable(struct mt7915_dev *dev)
- 	mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC,
- 		  MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000);
- 
--	/* set WFDMA Tx/Rx */
--	mt76_set(dev, MT_WFDMA0_GLO_CFG,
--		 MT_WFDMA0_GLO_CFG_TX_DMA_EN |
--		 MT_WFDMA0_GLO_CFG_RX_DMA_EN |
--		 MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
--		 MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
--
--	if (is_mt7915(mdev))
--		mt76_set(dev, MT_WFDMA1_GLO_CFG,
--			 MT_WFDMA1_GLO_CFG_TX_DMA_EN |
--			 MT_WFDMA1_GLO_CFG_RX_DMA_EN |
--			 MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
--			 MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
--
--	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 |
--			 MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
--			 MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
--
--		if (is_mt7915(mdev))
--			mt76_set(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
--				 MT_WFDMA1_GLO_CFG_TX_DMA_EN |
--				 MT_WFDMA1_GLO_CFG_RX_DMA_EN |
--				 MT_WFDMA1_GLO_CFG_OMIT_TX_INFO |
--				 MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
--
--		mt76_set(dev, MT_WFDMA_HOST_CONFIG,
--			 MT_WFDMA_HOST_CONFIG_PDMA_BAND);
--	}
--
--	/* enable interrupts for TX/RX rings */
--	irq_mask = MT_INT_RX_DONE_MCU |
--		   MT_INT_TX_DONE_MCU |
--		   MT_INT_MCU_CMD;
--
--	if (!dev->phy.mt76->band_idx)
--		irq_mask |= MT_INT_BAND0_RX_DONE;
--
--	if (dev->dbdc_support || dev->phy.mt76->band_idx)
--		irq_mask |= MT_INT_BAND1_RX_DONE;
--
--	if (mtk_wed_device_active(&dev->mt76.mmio.wed)) {
--		u32 wed_irq_mask = irq_mask;
--		int ret;
--
--		wed_irq_mask |= MT_INT_TX_DONE_BAND0 | MT_INT_TX_DONE_BAND1;
--		if (!is_mt798x(&dev->mt76))
--			mt76_wr(dev, MT_INT_WED_MASK_CSR, wed_irq_mask);
--		else
--			mt76_wr(dev, MT_INT_MASK_CSR, wed_irq_mask);
--
--		ret = mt7915_mcu_wed_enable_rx_stats(dev);
--		if (ret)
--			return ret;
--
--		mtk_wed_device_start(&dev->mt76.mmio.wed, wed_irq_mask);
--	}
--
--	mt7915_irq_enable(dev, irq_mask);
--
--	return 0;
-+	return mt7915_dma_start(dev, reset, true);
- }
- 
- int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
-@@ -560,7 +576,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
- 			  mt7915_poll_tx);
- 	napi_enable(&dev->mt76.tx_napi);
- 
--	mt7915_dma_enable(dev);
-+	mt7915_dma_enable(dev, false);
- 
- 	return 0;
- }
-@@ -642,7 +658,7 @@ int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
- 		mt76_rmw(dev, MT_WFDMA0_EXT0_CFG, MT_WFDMA0_EXT0_RXWB_KEEP,
- 			 MT_WFDMA0_EXT0_RXWB_KEEP);
- 
--	mt7915_dma_enable(dev);
-+	mt7915_dma_enable(dev, !force);
- 
- 	return 0;
- }
-diff --git a/mt7915/init.c b/mt7915/init.c
-index f85f7d39..e156a3c2 100644
---- a/mt7915/init.c
-+++ b/mt7915/init.c
-@@ -505,6 +505,12 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
- 	set = FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_MODE, 0) |
- 	      FIELD_PREP(MT_WTBLOFF_TOP_RSCR_RCPI_PARAM, 0x3);
- 	mt76_rmw(dev, MT_WTBLOFF_TOP_RSCR(band), mask, set);
-+
-+	/* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than
-+	 * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set.
-+	 */
-+	if (mtk_wed_device_active(&dev->mt76.mmio.wed))
-+		mt76_set(dev, MT_AGG_ACR4(band), MT_AGG_ACR_PPDU_TXS2H);
- }
- 
- static void
-@@ -587,6 +593,8 @@ void mt7915_mac_init(struct mt7915_dev *dev)
- 
- 	if (!is_mt7915(&dev->mt76))
- 		mt76_clear(dev, MT_MDP_DCR2, MT_MDP_DCR2_RX_TRANS_SHORT);
-+	else
-+		mt76_clear(dev, MT_PLE_HOST_RPT0, MT_PLE_HOST_RPT0_TX_LATENCY);
- 
- 	/* enable hardware de-agg */
- 	mt76_set(dev, MT_MDP_DCR0, MT_MDP_DCR0_DAMSDU_EN);
-@@ -1164,7 +1172,7 @@ static void mt7915_unregister_ext_phy(struct mt7915_dev *dev)
- static void mt7915_stop_hardware(struct mt7915_dev *dev)
- {
- 	mt7915_mcu_exit(dev);
--	mt7915_tx_token_put(dev);
-+	mt76_connac2_tx_token_put(&dev->mt76);
- 	mt7915_dma_cleanup(dev);
- 	tasklet_disable(&dev->mt76.irq_tasklet);
- 
-@@ -1183,9 +1191,7 @@ int mt7915_register_device(struct mt7915_dev *dev)
- 	INIT_WORK(&dev->rc_work, mt7915_mac_sta_rc_work);
- 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7915_mac_work);
- 	INIT_LIST_HEAD(&dev->sta_rc_list);
--	INIT_LIST_HEAD(&dev->sta_poll_list);
- 	INIT_LIST_HEAD(&dev->twt_list);
--	spin_lock_init(&dev->sta_poll_lock);
- 
- 	init_waitqueue_head(&dev->reset_wait);
- 	INIT_WORK(&dev->reset_work, mt7915_mac_reset_work);
-diff --git a/mt7915/mac.c b/mt7915/mac.c
-index fb6bab87..b8b0c0fd 100644
---- a/mt7915/mac.c
-+++ b/mt7915/mac.c
-@@ -105,9 +105,9 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
- 	LIST_HEAD(sta_poll_list);
- 	int i;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	rcu_read_lock();
- 
-@@ -118,15 +118,15 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
- 		s8 rssi[4];
- 		u8 bw;
- 
--		spin_lock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
- 		if (list_empty(&sta_poll_list)) {
--			spin_unlock_bh(&dev->sta_poll_lock);
-+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 			break;
- 		}
- 		msta = list_first_entry(&sta_poll_list,
--					struct mt7915_sta, poll_list);
--		list_del_init(&msta->poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+					struct mt7915_sta, wcid.poll_list);
-+		list_del_init(&msta->wcid.poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		idx = msta->wcid.idx;
- 
-@@ -326,10 +326,11 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
- 
- 	if (status->wcid) {
- 		msta = container_of(status->wcid, struct mt7915_sta, wcid);
--		spin_lock_bh(&dev->sta_poll_lock);
--		if (list_empty(&msta->poll_list))
--			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		if (list_empty(&msta->wcid.poll_list))
-+			list_add_tail(&msta->wcid.poll_list,
-+				      &dev->mt76.sta_poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
- 	status->freq = mphy->chandef.chan->center_freq;
-@@ -841,74 +842,6 @@ u32 mt7915_wed_init_buf(void *ptr, dma_addr_t phys, int token_id)
- 	return MT_TXD_SIZE + sizeof(*txp);
- }
- 
--static void
--mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
--{
--	struct mt7915_sta *msta;
--	u16 fc, tid;
--	u32 val;
--
--	if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
--		return;
--
--	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
--	if (tid >= 6) /* skip VO queue */
--		return;
--
--	val = le32_to_cpu(txwi[2]);
--	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
--	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
--	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
--		return;
--
--	msta = (struct mt7915_sta *)sta->drv_priv;
--	if (!test_and_set_bit(tid, &msta->ampdu_state))
--		ieee80211_start_tx_ba_session(sta, tid, 0);
--}
--
--static void
--mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
--		 struct ieee80211_sta *sta, struct list_head *free_list)
--{
--	struct mt76_dev *mdev = &dev->mt76;
--	struct mt7915_sta *msta;
--	struct mt76_wcid *wcid;
--	__le32 *txwi;
--	u16 wcid_idx;
--
--	mt76_connac_txp_skb_unmap(mdev, t);
--	if (!t->skb)
--		goto out;
--
--	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
--	if (sta) {
--		wcid = (struct mt76_wcid *)sta->drv_priv;
--		wcid_idx = wcid->idx;
--	} else {
--		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
--		wcid = rcu_dereference(dev->mt76.wcid[wcid_idx]);
--
--		if (wcid && wcid->sta) {
--			msta = container_of(wcid, struct mt7915_sta, wcid);
--			sta = container_of((void *)msta, struct ieee80211_sta,
--					  drv_priv);
--			spin_lock_bh(&dev->sta_poll_lock);
--			if (list_empty(&msta->poll_list))
--				list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--			spin_unlock_bh(&dev->sta_poll_lock);
--		}
--	}
--
--	if (sta && likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
--		mt7915_tx_check_aggr(sta, txwi);
--
--	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
--
--out:
--	t->skb = NULL;
--	mt76_put_txwi(mdev, t);
--}
--
- static void
- mt7915_mac_tx_free_prepare(struct mt7915_dev *dev)
- {
-@@ -951,6 +884,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
- 	struct mt76_dev *mdev = &dev->mt76;
- 	struct mt76_txwi_cache *txwi;
- 	struct ieee80211_sta *sta = NULL;
-+	struct mt76_wcid *wcid = NULL;
- 	LIST_HEAD(free_list);
- 	void *end = data + len;
- 	bool v3, wake = false;
-@@ -977,7 +911,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
- 		info = le32_to_cpu(*cur_info);
- 		if (info & MT_TX_FREE_PAIR) {
- 			struct mt7915_sta *msta;
--			struct mt76_wcid *wcid;
- 			u16 idx;
- 
- 			idx = FIELD_GET(MT_TX_FREE_WLAN_ID, info);
-@@ -987,14 +920,33 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
- 				continue;
- 
- 			msta = container_of(wcid, struct mt7915_sta, wcid);
--			spin_lock_bh(&dev->sta_poll_lock);
--			if (list_empty(&msta->poll_list))
--				list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--			spin_unlock_bh(&dev->sta_poll_lock);
-+			spin_lock_bh(&mdev->sta_poll_lock);
-+			if (list_empty(&msta->wcid.poll_list))
-+				list_add_tail(&msta->wcid.poll_list,
-+					      &mdev->sta_poll_list);
-+			spin_unlock_bh(&mdev->sta_poll_lock);
- 			continue;
- 		}
- 
--		if (v3 && (info & MT_TX_FREE_MPDU_HEADER))
-+		if (!mtk_wed_device_active(&mdev->mmio.wed) && wcid) {
-+			u32 tx_retries = 0, tx_failed = 0;
-+
-+			if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3)) {
-+				tx_retries =
-+					FIELD_GET(MT_TX_FREE_COUNT_V3, info) - 1;
-+				tx_failed = tx_retries +
-+					!!FIELD_GET(MT_TX_FREE_STAT_V3, info);
-+			} else if (!v3 && (info & MT_TX_FREE_MPDU_HEADER)) {
-+				tx_retries =
-+					FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
-+				tx_failed = tx_retries +
-+					!!FIELD_GET(MT_TX_FREE_STAT, info);
-+			}
-+			wcid->stats.tx_retries += tx_retries;
-+			wcid->stats.tx_failed += tx_failed;
-+		}
-+
-+		if (v3 && (info & MT_TX_FREE_MPDU_HEADER_V3))
- 			continue;
- 
- 		for (i = 0; i < 1 + v3; i++) {
-@@ -1010,7 +962,7 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
- 			if (!txwi)
- 				continue;
- 
--			mt7915_txwi_free(dev, txwi, sta, &free_list);
-+			mt76_connac2_txwi_free(mdev, txwi, sta, &free_list);
- 		}
- 	}
- 
-@@ -1042,7 +994,7 @@ mt7915_mac_tx_free_v0(struct mt7915_dev *dev, void *data, int len)
- 		if (!txwi)
- 			continue;
- 
--		mt7915_txwi_free(dev, txwi, NULL, &free_list);
-+		mt76_connac2_txwi_free(mdev, txwi, NULL, &free_list);
- 	}
- 
- 	mt7915_mac_tx_free_done(dev, &free_list, wake);
-@@ -1081,10 +1033,10 @@ static void mt7915_mac_add_txs(struct mt7915_dev *dev, void *data)
- 	if (!wcid->sta)
- 		goto out;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (list_empty(&msta->poll_list))
--		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (list_empty(&msta->wcid.poll_list))
-+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- out:
- 	rcu_read_unlock();
-@@ -1357,20 +1309,6 @@ mt7915_update_beacons(struct mt7915_dev *dev)
- 		mt7915_update_vif_beacon, mphy_ext->hw);
- }
- 
--void mt7915_tx_token_put(struct mt7915_dev *dev)
--{
--	struct mt76_txwi_cache *txwi;
--	int id;
--
--	spin_lock_bh(&dev->mt76.token_lock);
--	idr_for_each_entry(&dev->mt76.token, txwi, id) {
--		mt7915_txwi_free(dev, txwi, NULL, NULL);
--		dev->mt76.token_count--;
--	}
--	spin_unlock_bh(&dev->mt76.token_lock);
--	idr_destroy(&dev->mt76.token);
--}
--
- static int
- mt7915_mac_restart(struct mt7915_dev *dev)
- {
-@@ -1389,8 +1327,12 @@ mt7915_mac_restart(struct mt7915_dev *dev)
- 
- 	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);
-+		if (dev->hif2) {
-+			if (is_mt7915(mdev))
-+				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0x0);
-+			else
-+				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0x0);
-+		}
- 	}
- 
- 	set_bit(MT76_RESET, &dev->mphy.state);
-@@ -1415,7 +1357,7 @@ mt7915_mac_restart(struct mt7915_dev *dev)
- 	napi_disable(&dev->mt76.tx_napi);
- 
- 	/* token reinit */
--	mt7915_tx_token_put(dev);
-+	mt76_connac2_tx_token_put(&dev->mt76);
- 	idr_init(&dev->mt76.token);
- 
- 	mt7915_dma_reset(dev, true);
-@@ -1440,8 +1382,12 @@ mt7915_mac_restart(struct mt7915_dev *dev)
- 	}
- 	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);
-+		if (dev->hif2) {
-+			if (is_mt7915(mdev))
-+				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
-+			else
-+				mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE_MT7916, 0xff);
-+		}
- 	}
- 
- 	/* load firmware */
-@@ -1604,13 +1550,19 @@ void mt7915_mac_reset_work(struct work_struct *work)
- 	if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
- 		mt7915_dma_reset(dev, false);
- 
--		mt7915_tx_token_put(dev);
-+		mt76_connac2_tx_token_put(&dev->mt76);
- 		idr_init(&dev->mt76.token);
- 
- 		mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_INIT);
- 		mt7915_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
- 	}
- 
-+	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
-+	mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
-+
-+	/* enable DMA Tx/Rx and interrupt */
-+	mt7915_dma_start(dev, false, false);
-+
- 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
- 	clear_bit(MT76_RESET, &dev->mphy.state);
- 	if (phy2)
-@@ -1625,9 +1577,6 @@ void mt7915_mac_reset_work(struct work_struct *work)
- 
- 	tasklet_schedule(&dev->mt76.irq_tasklet);
- 
--	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
--	mt7915_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
--
- 	mt76_worker_enable(&dev->mt76.tx_worker);
- 
- 	local_bh_disable();
-@@ -1747,8 +1696,8 @@ void mt7915_reset(struct mt7915_dev *dev)
- 
- void mt7915_mac_update_stats(struct mt7915_phy *phy)
- {
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	struct mt7915_dev *dev = phy->dev;
--	struct mib_stats *mib = &phy->mib;
- 	int i, aggr0 = 0, aggr1, cnt;
- 	u8 band = phy->mt76->band_idx;
- 	u32 val;
-@@ -2010,7 +1959,7 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
- 	u32 changed;
- 	LIST_HEAD(list);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
- 	list_splice_init(&dev->sta_rc_list, &list);
- 
- 	while (!list_empty(&list)) {
-@@ -2018,7 +1967,7 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
- 		list_del_init(&msta->rc_list);
- 		changed = msta->changed;
- 		msta->changed = 0;
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
- 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
-@@ -2031,10 +1980,10 @@ void mt7915_mac_sta_rc_work(struct work_struct *work)
- 		if (changed & IEEE80211_RC_SMPS_CHANGED)
- 			mt7915_mcu_add_smps(dev, vif, sta);
- 
--		spin_lock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- }
- 
- void mt7915_mac_work(struct work_struct *work)
-@@ -2054,6 +2003,9 @@ void mt7915_mac_work(struct work_struct *work)
- 
- 		mt7915_mac_update_stats(phy);
- 		mt7915_mac_severe_check(phy);
-+
-+		if (phy->dev->muru_debug)
-+			mt7915_mcu_muru_debug_get(phy);
- 	}
- 
- 	mutex_unlock(&mphy->dev->mutex);
-diff --git a/mt7915/mac.h b/mt7915/mac.h
-index ce94f87e..448b1b38 100644
---- a/mt7915/mac.h
-+++ b/mt7915/mac.h
-@@ -9,7 +9,12 @@
- #define MT_TX_FREE_VER			GENMASK(18, 16)
- #define MT_TX_FREE_MSDU_CNT_V0		GENMASK(6, 0)
- /* 0: success, others: dropped */
--#define MT_TX_FREE_MPDU_HEADER		BIT(30)
-+#define MT_TX_FREE_COUNT		GENMASK(12, 0)
-+#define MT_TX_FREE_COUNT_V3		GENMASK(27, 24)
-+#define MT_TX_FREE_STAT			GENMASK(14, 13)
-+#define MT_TX_FREE_STAT_V3		GENMASK(29, 28)
-+#define MT_TX_FREE_MPDU_HEADER		BIT(15)
-+#define MT_TX_FREE_MPDU_HEADER_V3	BIT(30)
- #define MT_TX_FREE_MSDU_ID_V3		GENMASK(14, 0)
- 
- #define MT_TXS5_F0_FINAL_MPDU		BIT(31)
-diff --git a/mt7915/main.c b/mt7915/main.c
-index 8ce7b1c5..ca5631f5 100644
---- a/mt7915/main.c
-+++ b/mt7915/main.c
-@@ -248,7 +248,7 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
- 	idx = MT7915_WTBL_RESERVED - mvif->mt76.idx;
- 
- 	INIT_LIST_HEAD(&mvif->sta.rc_list);
--	INIT_LIST_HEAD(&mvif->sta.poll_list);
-+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
- 	mvif->sta.wcid.idx = idx;
- 	mvif->sta.wcid.phy_idx = ext_phy;
- 	mvif->sta.wcid.hw_key_idx = -1;
-@@ -308,10 +308,10 @@ static void mt7915_remove_interface(struct ieee80211_hw *hw,
- 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
- 	mutex_unlock(&dev->mt76.mutex);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
- }
-@@ -629,11 +629,6 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
- 		}
- 	}
- 
--	if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
--		mt7915_mcu_add_bss_info(phy, vif, true);
--		mt7915_mcu_add_sta(dev, vif, NULL, true);
--	}
--
- 	/* ensure that enable txcmd_mode after bss_info */
- 	if (changed & (BSS_CHANGED_QOS | BSS_CHANGED_BEACON_ENABLED))
- 		mt7915_mcu_set_tx(dev, vif);
-@@ -653,6 +648,37 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
- 	mutex_unlock(&dev->mt76.mutex);
- }
- 
-+static int
-+mt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-+		struct ieee80211_bss_conf *link_conf)
-+{
-+	struct mt7915_phy *phy = mt7915_hw_phy(hw);
-+	struct mt7915_dev *dev = mt7915_hw_dev(hw);
-+	int err;
-+
-+	mutex_lock(&dev->mt76.mutex);
-+
-+	err = mt7915_mcu_add_bss_info(phy, vif, true);
-+	if (err)
-+		goto out;
-+	err = mt7915_mcu_add_sta(dev, vif, NULL, true);
-+out:
-+	mutex_unlock(&dev->mt76.mutex);
-+
-+	return err;
-+}
-+
-+static void
-+mt7915_stop_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-+	       struct ieee80211_bss_conf *link_conf)
-+{
-+	struct mt7915_dev *dev = mt7915_hw_dev(hw);
-+
-+	mutex_lock(&dev->mt76.mutex);
-+	mt7915_mcu_add_sta(dev, vif, NULL, false);
-+	mutex_unlock(&dev->mt76.mutex);
-+}
-+
- static void
- mt7915_channel_switch_beacon(struct ieee80211_hw *hw,
- 			     struct ieee80211_vif *vif,
-@@ -679,7 +705,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 		return -ENOSPC;
- 
- 	INIT_LIST_HEAD(&msta->rc_list);
--	INIT_LIST_HEAD(&msta->poll_list);
-+	INIT_LIST_HEAD(&msta->wcid.poll_list);
- 	msta->vif = mvif;
- 	msta->wcid.sta = 1;
- 	msta->wcid.idx = idx;
-@@ -714,12 +740,12 @@ void mt7915_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
- 		mt7915_mac_twt_teardown_flow(dev, msta, i);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
-+	spin_lock_bh(&mdev->sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
- 	if (!list_empty(&msta->rc_list))
- 		list_del_init(&msta->rc_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_unlock_bh(&mdev->sta_poll_lock);
- }
- 
- static void mt7915_tx(struct ieee80211_hw *hw,
-@@ -801,16 +827,16 @@ mt7915_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
- 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- 		mtxq->aggr = false;
--		clear_bit(tid, &msta->ampdu_state);
-+		clear_bit(tid, &msta->wcid.ampdu_state);
- 		ret = mt7915_mcu_add_tx_ba(dev, params, false);
- 		break;
- 	case IEEE80211_AMPDU_TX_START:
--		set_bit(tid, &msta->ampdu_state);
-+		set_bit(tid, &msta->wcid.ampdu_state);
- 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
- 		break;
- 	case IEEE80211_AMPDU_TX_STOP_CONT:
- 		mtxq->aggr = false;
--		clear_bit(tid, &msta->ampdu_state);
-+		clear_bit(tid, &msta->wcid.ampdu_state);
- 		ret = mt7915_mcu_add_tx_ba(dev, params, false);
- 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- 		break;
-@@ -842,7 +868,7 @@ mt7915_get_stats(struct ieee80211_hw *hw,
- {
- 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
- 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
--	struct mib_stats *mib = &phy->mib;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 
- 	mutex_lock(&dev->mt76.mutex);
- 
-@@ -1019,21 +1045,20 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
- 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_BITRATE);
- 	}
- 
--	if (!txrate->legacy && !txrate->flags)
--		return;
--
--	if (txrate->legacy) {
--		sinfo->txrate.legacy = txrate->legacy;
--	} else {
--		sinfo->txrate.mcs = txrate->mcs;
--		sinfo->txrate.nss = txrate->nss;
--		sinfo->txrate.bw = txrate->bw;
--		sinfo->txrate.he_gi = txrate->he_gi;
--		sinfo->txrate.he_dcm = txrate->he_dcm;
--		sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
-+	if (txrate->legacy || txrate->flags) {
-+		if (txrate->legacy) {
-+			sinfo->txrate.legacy = txrate->legacy;
-+		} else {
-+			sinfo->txrate.mcs = txrate->mcs;
-+			sinfo->txrate.nss = txrate->nss;
-+			sinfo->txrate.bw = txrate->bw;
-+			sinfo->txrate.he_gi = txrate->he_gi;
-+			sinfo->txrate.he_dcm = txrate->he_dcm;
-+			sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
-+		}
-+		sinfo->txrate.flags = txrate->flags;
-+		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
- 	}
--	sinfo->txrate.flags = txrate->flags;
--	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
- 
- 	/* offloading flows bypass networking stack, so driver counts and
- 	 * reports sta statistics via NL80211_STA_INFO when WED is active.
-@@ -1042,14 +1067,10 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
- 		sinfo->tx_bytes = msta->wcid.stats.tx_bytes;
- 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BYTES64);
- 
--		sinfo->tx_packets = msta->wcid.stats.tx_packets;
--		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
--
--		sinfo->tx_failed = msta->wcid.stats.tx_failed;
--		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
--
--		sinfo->tx_retries = msta->wcid.stats.tx_retries;
--		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
-+		if (!mt7915_mcu_wed_wa_tx_stats(phy->dev, msta->wcid.idx)) {
-+			sinfo->tx_packets = msta->wcid.stats.tx_packets;
-+			sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_PACKETS);
-+		}
- 
- 		if (mtk_wed_get_rx_capa(&phy->dev->mt76.mmio.wed)) {
- 			sinfo->rx_bytes = msta->wcid.stats.rx_bytes;
-@@ -1060,6 +1081,12 @@ static void mt7915_sta_statistics(struct ieee80211_hw *hw,
- 		}
- 	}
- 
-+	sinfo->tx_failed = msta->wcid.stats.tx_failed;
-+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
-+
-+	sinfo->tx_retries = msta->wcid.stats.tx_retries;
-+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
-+
- 	sinfo->ack_signal = (s8)msta->ack_signal;
- 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_ACK_SIGNAL);
- 
-@@ -1073,11 +1100,11 @@ static void mt7915_sta_rc_work(void *data, struct ieee80211_sta *sta)
- 	struct mt7915_dev *dev = msta->vif->phy->dev;
- 	u32 *changed = data;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
- 	msta->changed |= *changed;
- 	if (list_empty(&msta->rc_list))
- 		list_add_tail(&msta->rc_list, &dev->sta_rc_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- }
- 
- static void mt7915_sta_rc_update(struct ieee80211_hw *hw,
-@@ -1253,6 +1280,38 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = {
- 	"rx_vec_queue_overflow_drop_cnt",
- 	"rx_ba_cnt",
- 
-+	/* muru mu-mimo and ofdma related stats */
-+	"dl_cck_cnt",
-+	"dl_ofdm_cnt",
-+	"dl_htmix_cnt",
-+	"dl_htgf_cnt",
-+	"dl_vht_su_cnt",
-+	"dl_vht_2mu_cnt",
-+	"dl_vht_3mu_cnt",
-+	"dl_vht_4mu_cnt",
-+	"dl_he_su_cnt",
-+	"dl_he_ext_su_cnt",
-+	"dl_he_2ru_cnt",
-+	"dl_he_2mu_cnt",
-+	"dl_he_3ru_cnt",
-+	"dl_he_3mu_cnt",
-+	"dl_he_4ru_cnt",
-+	"dl_he_4mu_cnt",
-+	"dl_he_5to8ru_cnt",
-+	"dl_he_9to16ru_cnt",
-+	"dl_he_gtr16ru_cnt",
-+
-+	"ul_hetrig_su_cnt",
-+	"ul_hetrig_2ru_cnt",
-+	"ul_hetrig_3ru_cnt",
-+	"ul_hetrig_4ru_cnt",
-+	"ul_hetrig_5to8ru_cnt",
-+	"ul_hetrig_9to16ru_cnt",
-+	"ul_hetrig_gtr16ru_cnt",
-+	"ul_hetrig_2mu_cnt",
-+	"ul_hetrig_3mu_cnt",
-+	"ul_hetrig_4mu_cnt",
-+
- 	/* per vif counters */
- 	"v_tx_mode_cck",
- 	"v_tx_mode_ofdm",
-@@ -1279,6 +1338,10 @@ static const char mt7915_gstrings_stats[][ETH_GSTRING_LEN] = {
- 	"v_tx_mcs_9",
- 	"v_tx_mcs_10",
- 	"v_tx_mcs_11",
-+	"v_tx_nss_1",
-+	"v_tx_nss_2",
-+	"v_tx_nss_3",
-+	"v_tx_nss_4",
- };
- 
- #define MT7915_SSTATS_LEN ARRAY_SIZE(mt7915_gstrings_stats)
-@@ -1326,11 +1389,11 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
- 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
- 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
- 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	struct mt76_ethtool_worker_info wi = {
- 		.data = data,
- 		.idx = mvif->mt76.idx,
- 	};
--	struct mib_stats *mib = &phy->mib;
- 	/* See mt7915_ampdu_stat_read_phy, etc */
- 	int i, ei = 0, stats_size;
- 
-@@ -1403,6 +1466,37 @@ void mt7915_get_et_stats(struct ieee80211_hw *hw,
- 	data[ei++] = mib->rx_vec_queue_overflow_drop_cnt;
- 	data[ei++] = mib->rx_ba_cnt;
- 
-+	data[ei++] = mib->dl_cck_cnt;
-+	data[ei++] = mib->dl_ofdm_cnt;
-+	data[ei++] = mib->dl_htmix_cnt;
-+	data[ei++] = mib->dl_htgf_cnt;
-+	data[ei++] = mib->dl_vht_su_cnt;
-+	data[ei++] = mib->dl_vht_2mu_cnt;
-+	data[ei++] = mib->dl_vht_3mu_cnt;
-+	data[ei++] = mib->dl_vht_4mu_cnt;
-+	data[ei++] = mib->dl_he_su_cnt;
-+	data[ei++] = mib->dl_he_ext_su_cnt;
-+	data[ei++] = mib->dl_he_2ru_cnt;
-+	data[ei++] = mib->dl_he_2mu_cnt;
-+	data[ei++] = mib->dl_he_3ru_cnt;
-+	data[ei++] = mib->dl_he_3mu_cnt;
-+	data[ei++] = mib->dl_he_4ru_cnt;
-+	data[ei++] = mib->dl_he_4mu_cnt;
-+	data[ei++] = mib->dl_he_5to8ru_cnt;
-+	data[ei++] = mib->dl_he_9to16ru_cnt;
-+	data[ei++] = mib->dl_he_gtr16ru_cnt;
-+
-+	data[ei++] = mib->ul_hetrig_su_cnt;
-+	data[ei++] = mib->ul_hetrig_2ru_cnt;
-+	data[ei++] = mib->ul_hetrig_3ru_cnt;
-+	data[ei++] = mib->ul_hetrig_4ru_cnt;
-+	data[ei++] = mib->ul_hetrig_5to8ru_cnt;
-+	data[ei++] = mib->ul_hetrig_9to16ru_cnt;
-+	data[ei++] = mib->ul_hetrig_gtr16ru_cnt;
-+	data[ei++] = mib->ul_hetrig_2mu_cnt;
-+	data[ei++] = mib->ul_hetrig_3mu_cnt;
-+	data[ei++] = mib->ul_hetrig_4mu_cnt;
-+
- 	/* Add values for all stations owned by this vif */
- 	wi.initial_stat_idx = ei;
- 	ieee80211_iterate_stations_atomic(hw, mt7915_ethtool_worker, &wi);
-@@ -1540,6 +1634,8 @@ const struct ieee80211_ops mt7915_ops = {
- 	.conf_tx = mt7915_conf_tx,
- 	.configure_filter = mt7915_configure_filter,
- 	.bss_info_changed = mt7915_bss_info_changed,
-+	.start_ap = mt7915_start_ap,
-+	.stop_ap = mt7915_stop_ap,
- 	.sta_add = mt7915_sta_add,
- 	.sta_remove = mt7915_sta_remove,
- 	.sta_pre_rcu_remove = mt76_sta_pre_rcu_remove,
-diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index aa706ff6..71eeb54a 100644
---- a/mt7915/mcu.c
-+++ b/mt7915/mcu.c
-@@ -167,7 +167,9 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
- 	}
- 
- 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
--	if (seq != rxd->seq)
-+	if (seq != rxd->seq &&
-+	    !(rxd->eid == MCU_CMD_EXT_CID &&
-+	      rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
- 		return -EAGAIN;
- 
- 	if (cmd == MCU_CMD(PATCH_SEM_CONTROL)) {
-@@ -277,7 +279,7 @@ mt7915_mcu_rx_radar_detected(struct mt7915_dev *dev, struct sk_buff *skb)
- 
- 	r = (struct mt7915_mcu_rdd_report *)skb->data;
- 
--	if (r->band_idx > MT_BAND1)
-+	if (r->band_idx > MT_RX_SEL2)
- 		return;
- 
- 	if ((r->band_idx && !dev->phy.mt76->band_idx) &&
-@@ -398,12 +400,14 @@ void mt7915_mcu_rx_event(struct mt7915_dev *dev, struct sk_buff *skb)
- 	struct mt76_connac2_mcu_rxd *rxd;
- 
- 	rxd = (struct mt76_connac2_mcu_rxd *)skb->data;
--	if (rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
--	    rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
--	    rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
--	    rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
--	    rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
--	    !rxd->seq)
-+	if ((rxd->ext_eid == MCU_EXT_EVENT_THERMAL_PROTECT ||
-+	     rxd->ext_eid == MCU_EXT_EVENT_FW_LOG_2_HOST ||
-+	     rxd->ext_eid == MCU_EXT_EVENT_ASSERT_DUMP ||
-+	     rxd->ext_eid == MCU_EXT_EVENT_PS_SYNC ||
-+	     rxd->ext_eid == MCU_EXT_EVENT_BCC_NOTIFY ||
-+	     !rxd->seq) &&
-+	     !(rxd->eid == MCU_CMD_EXT_CID &&
-+	       rxd->ext_eid == MCU_EXT_EVENT_WA_TX_STAT))
- 		mt7915_mcu_rx_unsolicited_event(dev, skb);
- 	else
- 		mt76_mcu_rx_event(&dev->mt76, skb);
-@@ -2115,12 +2119,11 @@ int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enabled)
- 				sizeof(data), false);
- }
- 
--int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms)
-+int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy)
- {
- 	struct mt7915_dev *dev = phy->dev;
- 	struct sk_buff *skb;
--	struct mt7915_mcu_muru_stats *mu_stats =
--				(struct mt7915_mcu_muru_stats *)ms;
-+	struct mt7915_mcu_muru_stats *mu_stats;
- 	int ret;
- 
- 	struct {
-@@ -2136,7 +2139,43 @@ int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms)
- 	if (ret)
- 		return ret;
- 
--	memcpy(mu_stats, skb->data, sizeof(struct mt7915_mcu_muru_stats));
-+	mu_stats = (struct mt7915_mcu_muru_stats *)(skb->data);
-+
-+	/* accumulate stats, these are clear-on-read */
-+#define __dl_u32(s)	 phy->mib.dl_##s += le32_to_cpu(mu_stats->dl.s)
-+#define __ul_u32(s)	 phy->mib.ul_##s += le32_to_cpu(mu_stats->ul.s)
-+	__dl_u32(cck_cnt);
-+	__dl_u32(ofdm_cnt);
-+	__dl_u32(htmix_cnt);
-+	__dl_u32(htgf_cnt);
-+	__dl_u32(vht_su_cnt);
-+	__dl_u32(vht_2mu_cnt);
-+	__dl_u32(vht_3mu_cnt);
-+	__dl_u32(vht_4mu_cnt);
-+	__dl_u32(he_su_cnt);
-+	__dl_u32(he_2ru_cnt);
-+	__dl_u32(he_2mu_cnt);
-+	__dl_u32(he_3ru_cnt);
-+	__dl_u32(he_3mu_cnt);
-+	__dl_u32(he_4ru_cnt);
-+	__dl_u32(he_4mu_cnt);
-+	__dl_u32(he_5to8ru_cnt);
-+	__dl_u32(he_9to16ru_cnt);
-+	__dl_u32(he_gtr16ru_cnt);
-+
-+	__ul_u32(hetrig_su_cnt);
-+	__ul_u32(hetrig_2ru_cnt);
-+	__ul_u32(hetrig_3ru_cnt);
-+	__ul_u32(hetrig_4ru_cnt);
-+	__ul_u32(hetrig_5to8ru_cnt);
-+	__ul_u32(hetrig_9to16ru_cnt);
-+	__ul_u32(hetrig_gtr16ru_cnt);
-+	__ul_u32(hetrig_2mu_cnt);
-+	__ul_u32(hetrig_3mu_cnt);
-+	__ul_u32(hetrig_4mu_cnt);
-+#undef __dl_u32
-+#undef __ul_u32
-+
- 	dev_kfree_skb(skb);
- 
- 	return 0;
-@@ -3736,6 +3775,62 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
- 				 &req, sizeof(req), true);
- }
- 
-+int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wlan_idx)
-+{
-+	struct {
-+		__le32 cmd;
-+		__le32 num;
-+		__le32 __rsv;
-+		__le16 wlan_idx;
-+	} req = {
-+		.cmd = cpu_to_le32(0x15),
-+		.num = cpu_to_le32(1),
-+		.wlan_idx = cpu_to_le16(wlan_idx),
-+	};
-+	struct mt7915_mcu_wa_tx_stat {
-+		__le16 wlan_idx;
-+		u8 __rsv[2];
-+
-+		/* tx_bytes is deprecated since WA byte counter uses u32,
-+		 * which easily leads to overflow.
-+		 */
-+		__le32 tx_bytes;
-+		__le32 tx_packets;
-+	} *res;
-+	struct mt76_wcid *wcid;
-+	struct sk_buff *skb;
-+	int ret;
-+
-+	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WA_PARAM_CMD(QUERY),
-+					&req, sizeof(req), true, &skb);
-+	if (ret)
-+		return ret;
-+
-+	if (!is_mt7915(&dev->mt76))
-+		skb_pull(skb, 4);
-+
-+	res = (struct mt7915_mcu_wa_tx_stat *)skb->data;
-+
-+	if (le16_to_cpu(res->wlan_idx) != wlan_idx) {
-+		ret = -EINVAL;
-+		goto out;
-+	}
-+
-+	rcu_read_lock();
-+
-+	wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
-+	if (wcid)
-+		wcid->stats.tx_packets += le32_to_cpu(res->tx_packets);
-+	else
-+		ret = -EINVAL;
-+
-+	rcu_read_unlock();
-+out:
-+	dev_kfree_skb(skb);
-+
-+	return ret;
-+}
-+
- int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
- {
- 	struct {
-diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 984b5f60..fc7ace63 100644
---- a/mt7915/mmio.c
-+++ b/mt7915/mmio.c
-@@ -545,8 +545,6 @@ static u32 mt7915_rmw(struct mt76_dev *mdev, u32 offset, u32 mask, u32 val)
- static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed)
- {
- 	struct mt7915_dev *dev;
--	struct mt7915_phy *phy;
--	int ret;
- 
- 	dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
- 
-@@ -554,43 +552,19 @@ static int mt7915_mmio_wed_offload_enable(struct mtk_wed_device *wed)
- 	dev->mt76.token_size = wed->wlan.token_start;
- 	spin_unlock_bh(&dev->mt76.token_lock);
- 
--	ret = wait_event_timeout(dev->mt76.tx_wait,
--				 !dev->mt76.wed_token_count, HZ);
--	if (!ret)
--		return -EAGAIN;
--
--	phy = &dev->phy;
--	mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H);
--
--	phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
--	if (phy)
--		mt76_set(dev, MT_AGG_ACR4(phy->mt76->band_idx),
--			 MT_AGG_ACR_PPDU_TXS2H);
--
--	return 0;
-+	return !wait_event_timeout(dev->mt76.tx_wait,
-+				   !dev->mt76.wed_token_count, HZ);
- }
- 
- static void mt7915_mmio_wed_offload_disable(struct mtk_wed_device *wed)
- {
- 	struct mt7915_dev *dev;
--	struct mt7915_phy *phy;
- 
- 	dev = container_of(wed, struct mt7915_dev, mt76.mmio.wed);
- 
- 	spin_lock_bh(&dev->mt76.token_lock);
- 	dev->mt76.token_size = MT7915_TOKEN_SIZE;
- 	spin_unlock_bh(&dev->mt76.token_lock);
--
--	/* MT_TXD5_TX_STATUS_HOST (MPDU format) has higher priority than
--	 * MT_AGG_ACR_PPDU_TXS2H (PPDU format) even though ACR bit is set.
--	 */
--	phy = &dev->phy;
--	mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx), MT_AGG_ACR_PPDU_TXS2H);
--
--	phy = dev->mt76.phys[MT_BAND1] ? dev->mt76.phys[MT_BAND1]->priv : NULL;
--	if (phy)
--		mt76_clear(dev, MT_AGG_ACR4(phy->mt76->band_idx),
--			   MT_AGG_ACR_PPDU_TXS2H);
- }
- 
- static void mt7915_mmio_wed_release_rx_buf(struct mtk_wed_device *wed)
-@@ -1064,7 +1038,7 @@ static int __init mt7915_init(void)
- 		goto error_pci;
- 
- 	if (IS_ENABLED(CONFIG_MT798X_WMAC)) {
--		ret = platform_driver_register(&mt7986_wmac_driver);
-+		ret = platform_driver_register(&mt798x_wmac_driver);
- 		if (ret)
- 			goto error_wmac;
- 	}
-@@ -1082,7 +1056,7 @@ error_pci:
- static void __exit mt7915_exit(void)
- {
- 	if (IS_ENABLED(CONFIG_MT798X_WMAC))
--		platform_driver_unregister(&mt7986_wmac_driver);
-+		platform_driver_unregister(&mt798x_wmac_driver);
- 
- 	pci_unregister_driver(&mt7915_pci_driver);
- 	pci_unregister_driver(&mt7915_hif_driver);
-diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 103cd0d7..0c7226b8 100644
---- a/mt7915/mt7915.h
-+++ b/mt7915/mt7915.h
-@@ -136,7 +136,6 @@ struct mt7915_sta {
- 
- 	struct mt7915_vif *vif;
- 
--	struct list_head poll_list;
- 	struct list_head rc_list;
- 	u32 airtime_ac[8];
- 
-@@ -145,7 +144,6 @@ struct mt7915_sta {
- 
- 	unsigned long changed;
- 	unsigned long jiffies;
--	unsigned long ampdu_state;
- 	struct mt76_connac_sta_key_conf bip;
- 
- 	struct {
-@@ -164,67 +162,6 @@ struct mt7915_vif {
- 	struct cfg80211_bitrate_mask bitrate_mask;
- };
- 
--/* per-phy stats.  */
--struct mib_stats {
--	u32 ack_fail_cnt;
--	u32 fcs_err_cnt;
--	u32 rts_cnt;
--	u32 rts_retries_cnt;
--	u32 ba_miss_cnt;
--	u32 tx_bf_cnt;
--	u32 tx_mu_mpdu_cnt;
--	u32 tx_mu_acked_mpdu_cnt;
--	u32 tx_su_acked_mpdu_cnt;
--	u32 tx_bf_ibf_ppdu_cnt;
--	u32 tx_bf_ebf_ppdu_cnt;
--
--	u32 tx_bf_rx_fb_all_cnt;
--	u32 tx_bf_rx_fb_he_cnt;
--	u32 tx_bf_rx_fb_vht_cnt;
--	u32 tx_bf_rx_fb_ht_cnt;
--
--	u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
--	u32 tx_bf_rx_fb_nc_cnt;
--	u32 tx_bf_rx_fb_nr_cnt;
--	u32 tx_bf_fb_cpl_cnt;
--	u32 tx_bf_fb_trig_cnt;
--
--	u32 tx_ampdu_cnt;
--	u32 tx_stop_q_empty_cnt;
--	u32 tx_mpdu_attempts_cnt;
--	u32 tx_mpdu_success_cnt;
--	u32 tx_pkt_ebf_cnt;
--	u32 tx_pkt_ibf_cnt;
--
--	u32 tx_rwp_fail_cnt;
--	u32 tx_rwp_need_cnt;
--
--	/* rx stats */
--	u32 rx_fifo_full_cnt;
--	u32 channel_idle_cnt;
--	u32 primary_cca_busy_time;
--	u32 secondary_cca_busy_time;
--	u32 primary_energy_detect_time;
--	u32 cck_mdrdy_time;
--	u32 ofdm_mdrdy_time;
--	u32 green_mdrdy_time;
--	u32 rx_vector_mismatch_cnt;
--	u32 rx_delimiter_fail_cnt;
--	u32 rx_mrdy_cnt;
--	u32 rx_len_mismatch_cnt;
--	u32 rx_mpdu_cnt;
--	u32 rx_ampdu_cnt;
--	u32 rx_ampdu_bytes_cnt;
--	u32 rx_ampdu_valid_subframe_cnt;
--	u32 rx_ampdu_valid_subframe_bytes_cnt;
--	u32 rx_pfdrop_cnt;
--	u32 rx_vec_queue_overflow_drop_cnt;
--	u32 rx_ba_cnt;
--
--	u32 tx_amsdu[8];
--	u32 tx_amsdu_cnt;
--};
--
- /* crash-dump */
- struct mt7915_crash_data {
- 	guid_t guid;
-@@ -270,7 +207,7 @@ struct mt7915_phy {
- 	u32 rx_ampdu_ts;
- 	u32 ampdu_ref;
- 
--	struct mib_stats mib;
-+	struct mt76_mib_stats mib;
- 	struct mt76_channel_state state_ts;
- 
- #ifdef CONFIG_NL80211_TESTMODE
-@@ -335,9 +272,7 @@ struct mt7915_dev {
- #endif
- 
- 	struct list_head sta_rc_list;
--	struct list_head sta_poll_list;
- 	struct list_head twt_list;
--	spinlock_t sta_poll_lock;
- 
- 	u32 hw_pattern;
- 
-@@ -437,7 +372,7 @@ extern const struct ieee80211_ops mt7915_ops;
- extern const struct mt76_testmode_ops mt7915_testmode_ops;
- extern struct pci_driver mt7915_pci_driver;
- extern struct pci_driver mt7915_hif_driver;
--extern struct platform_driver mt7986_wmac_driver;
-+extern struct platform_driver mt798x_wmac_driver;
- 
- #ifdef CONFIG_MT798X_WMAC
- int mt7986_wmac_enable(struct mt7915_dev *dev);
-@@ -472,6 +407,7 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2);
- void mt7915_dma_prefetch(struct mt7915_dev *dev);
- void mt7915_dma_cleanup(struct mt7915_dev *dev);
- int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
-+int mt7915_dma_start(struct mt7915_dev *dev, bool reset, bool wed_reset);
- int mt7915_txbf_init(struct mt7915_dev *dev);
- void mt7915_init_txpower(struct mt7915_dev *dev,
- 			 struct ieee80211_supported_band *sband);
-@@ -545,6 +481,7 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
- 			   struct ieee80211_sta *sta, struct rate_info *rate);
- int mt7915_mcu_rdd_background_enable(struct mt7915_phy *phy,
- 				     struct cfg80211_chan_def *chandef);
-+int mt7915_mcu_wed_wa_tx_stats(struct mt7915_dev *dev, u16 wcid);
- int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set);
- int mt7915_mcu_wa_cmd(struct mt7915_dev *dev, int cmd, u32 a1, u32 a2, u32 a3);
- int mt7915_mcu_fw_log_2_host(struct mt7915_dev *dev, u8 type, u8 ctrl);
-@@ -618,7 +555,6 @@ int mt7915_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 mt7915_tx_token_put(struct mt7915_dev *dev);
- void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- 			 struct sk_buff *skb, u32 *info);
- bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len);
-@@ -629,7 +565,7 @@ void mt7915_set_stream_he_caps(struct mt7915_phy *phy);
- void mt7915_set_stream_vht_txbf_caps(struct mt7915_phy *phy);
- void mt7915_update_channel(struct mt76_phy *mphy);
- int mt7915_mcu_muru_debug_set(struct mt7915_dev *dev, bool enable);
--int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms);
-+int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy);
- int mt7915_mcu_wed_enable_rx_stats(struct mt7915_dev *dev);
- int mt7915_init_debugfs(struct mt7915_phy *phy);
- void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len);
-diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 374677f7..588cd87e 100644
---- a/mt7915/regs.h
-+++ b/mt7915/regs.h
-@@ -145,6 +145,9 @@ enum offs_rev {
- #define MT_PLE_BASE			0x820c0000
- #define MT_PLE(ofs)			(MT_PLE_BASE + (ofs))
- 
-+#define MT_PLE_HOST_RPT0		MT_PLE(0x030)
-+#define MT_PLE_HOST_RPT0_TX_LATENCY	BIT(3)
-+
- #define MT_FL_Q_EMPTY			MT_PLE(__OFFS(PLE_FL_Q_EMPTY))
- #define MT_FL_Q0_CTRL			MT_PLE(__OFFS(PLE_FL_Q_CTRL))
- #define MT_FL_Q2_CTRL			MT_PLE(__OFFS(PLE_FL_Q_CTRL) + 0x8)
-diff --git a/mt7915/soc.c b/mt7915/soc.c
-index fffe3623..1f23e60f 100644
---- a/mt7915/soc.c
-+++ b/mt7915/soc.c
-@@ -174,10 +174,11 @@ static u8 mt798x_wmac_check_adie_type(struct mt7915_dev *dev)
- {
- 	u32 val;
- 
-+	/* Only DBDC A-die is used with MT7981 */
- 	if (is_mt7981(&dev->mt76))
- 		return ADIE_DBDC;
--	else
--		val = readl(dev->sku + MT_TOP_POS_SKU);
-+
-+	val = readl(dev->sku + MT_TOP_POS_SKU);
- 
- 	return FIELD_GET(MT_TOP_POS_SKU_ADIE_DBDC_MASK, val);
- }
-@@ -268,10 +269,14 @@ static int mt798x_wmac_coninfra_check(struct mt7915_dev *dev)
- 	u32 cur;
- 	u32 con_infra_version;
- 
--	if (is_mt7981(&dev->mt76))
-+	if (is_mt7981(&dev->mt76)) {
- 		con_infra_version = MT7981_CON_INFRA_VERSION;
--	if (is_mt7986(&dev->mt76))
-+	} else if (is_mt7986(&dev->mt76)) {
- 		con_infra_version = MT7986_CON_INFRA_VERSION;
-+	} else {
-+		WARN_ON(1);
-+		return -EINVAL;
-+	}
- 
- 	return read_poll_timeout(mt76_rr, cur, (cur == con_infra_version),
- 				 USEC_PER_MSEC, 50 * USEC_PER_MSEC,
-@@ -308,12 +313,9 @@ static int mt798x_wmac_coninfra_setup(struct mt7915_dev *dev)
- 		       MT_TOP_MCU_EMI_BASE_MASK, val);
- 
- 	if (is_mt7981(&dev->mt76)) {
--		/* TODO: mt7981: unsure if we need this at all
--		 * This base could be also valid for the mt7986 */
- 		mt76_rmw_field(dev, MT_TOP_WF_AP_PERI_BASE,
- 			       MT_TOP_WF_AP_PERI_BASE_MASK, 0x300d0000 >> 16);
- 
--		/* TODO: mt7986: replace by efuse reserved region? */
- 		mt76_rmw_field(dev, MT_TOP_EFUSE_BASE,
- 			       MT_TOP_EFUSE_BASE_MASK, 0x11f20000 >> 16);
- 	}
-@@ -519,10 +521,14 @@ static int mt798x_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie)
- 		rg_xo_01 = 0x1d59080f;
- 		rg_xo_03 = 0x34c00fe0;
- 	} else {
--		if (is_mt7981(&dev->mt76))
-+		if (is_mt7981(&dev->mt76)) {
- 			rg_xo_01 = 0x1959c80f;
--		else if (is_mt7986(&dev->mt76))
-+		} else if (is_mt7986(&dev->mt76)) {
- 			rg_xo_01 = 0x1959f80f;
-+		} else {
-+			WARN_ON(1);
-+			return -EINVAL;
-+		}
- 		rg_xo_03 = 0x34d00fe0;
- 	}
- 
-@@ -644,10 +650,15 @@ static int mt7986_wmac_adie_patch_7975(struct mt7915_dev *dev, u8 adie)
- 		return ret;
- 
- 	/* turn on SX0 LTBUF */
--	if (is_mt7981(&dev->mt76))
-+	if (is_mt7981(&dev->mt76)) {
- 		ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000007);
--	else if (is_mt7986(&dev->mt76))
-+	} else if (is_mt7986(&dev->mt76)) {
- 		ret = mt76_wmac_spi_write(dev, adie, 0x074, 0x00000002);
-+	} else {
-+		WARN_ON(1);
-+		return -EINVAL;
-+	}
-+
- 	if (ret)
- 		return ret;
- 
-@@ -784,7 +795,6 @@ mt7986_wmac_afe_cal(struct mt7915_dev *dev, u8 adie, bool dbdc, u32 adie_type)
- 		       MT_AFE_RG_WBG_EN_WPLL_UP_MASK, 0x1);
- 	usleep_range(60, 100);
- 
--	/* TODO: mt7981: sets also bit WF4, but mt7986 doesn't need/allow this? */
- 	txcal = (MT_AFE_RG_WBG_EN_TXCAL_BT |
- 		      MT_AFE_RG_WBG_EN_TXCAL_WF0 |
- 		      MT_AFE_RG_WBG_EN_TXCAL_WF1 |
-@@ -930,7 +940,6 @@ static int mt7986_wmac_wm_enable(struct mt7915_dev *dev, bool enable)
- {
- 	u32 cur;
- 
--	/* TODO: check if this is really needed or should be also used for mt7981 */
- 	if (is_mt7986(&dev->mt76))
- 		mt76_wr(dev, MT_CONNINFRA_SKU_DEC_ADDR, 0);
- 
-@@ -1217,7 +1226,7 @@ static int mt798x_wmac_init(struct mt7915_dev *dev)
- 	return 0;
- }
- 
--static int mt7986_wmac_probe(struct platform_device *pdev)
-+static int mt798x_wmac_probe(struct platform_device *pdev)
- {
- 	void __iomem *mem_base;
- 	struct mt7915_dev *dev;
-@@ -1277,7 +1286,7 @@ free_device:
- 	return ret;
- }
- 
--static int mt7986_wmac_remove(struct platform_device *pdev)
-+static int mt798x_wmac_remove(struct platform_device *pdev)
- {
- 	struct mt7915_dev *dev = platform_get_drvdata(pdev);
- 
-@@ -1286,21 +1295,21 @@ static int mt7986_wmac_remove(struct platform_device *pdev)
- 	return 0;
- }
- 
--static const struct of_device_id mt7986_wmac_of_match[] = {
-+static const struct of_device_id mt798x_wmac_of_match[] = {
- 	{ .compatible = "mediatek,mt7981-wmac", .data = (u32 *)0x7981 },
- 	{ .compatible = "mediatek,mt7986-wmac", .data = (u32 *)0x7986 },
- 	{},
- };
- 
--MODULE_DEVICE_TABLE(of, mt7986_wmac_of_match);
-+MODULE_DEVICE_TABLE(of, mt798x_wmac_of_match);
- 
--struct platform_driver mt7986_wmac_driver = {
-+struct platform_driver mt798x_wmac_driver = {
- 	.driver = {
--		.name = "mt7986-wmac",
--		.of_match_table = mt7986_wmac_of_match,
-+		.name = "mt798x-wmac",
-+		.of_match_table = mt798x_wmac_of_match,
- 	},
--	.probe = mt7986_wmac_probe,
--	.remove = mt7986_wmac_remove,
-+	.probe = mt798x_wmac_probe,
-+	.remove = mt798x_wmac_remove,
- };
- 
- MODULE_FIRMWARE(MT7986_FIRMWARE_WA);
-diff --git a/mt7921/debugfs.c b/mt7921/debugfs.c
-index d6b6edba..d6c66e77 100644
---- a/mt7921/debugfs.c
-+++ b/mt7921/debugfs.c
-@@ -95,7 +95,7 @@ mt7921_tx_stats_show(struct seq_file *file, void *data)
- {
- 	struct mt7921_dev *dev = file->private;
- 	struct mt7921_phy *phy = &dev->phy;
--	struct mib_stats *mib = &phy->mib;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	int i;
- 
- 	mt7921_mutex_acquire(dev);
-diff --git a/mt7921/dma.c b/mt7921/dma.c
-index 73d8dc14..4153cd6c 100644
---- a/mt7921/dma.c
-+++ b/mt7921/dma.c
-@@ -74,9 +74,9 @@ static int mt7921_dma_disable(struct mt7921_dev *dev, bool force)
- 		   MT_WFDMA0_GLO_CFG_OMIT_RX_INFO |
- 		   MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
- 
--	if (!mt76_poll(dev, MT_WFDMA0_GLO_CFG,
--		       MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
--		       MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 1000))
-+	if (!mt76_poll_msec_tick(dev, MT_WFDMA0_GLO_CFG,
-+				 MT_WFDMA0_GLO_CFG_TX_DMA_BUSY |
-+				 MT_WFDMA0_GLO_CFG_RX_DMA_BUSY, 0, 100, 1))
- 		return -ETIMEDOUT;
- 
- 	/* disable dmashdl */
-@@ -231,10 +231,6 @@ int mt7921_dma_init(struct mt7921_dev *dev)
- 	if (ret)
- 		return ret;
- 
--	ret = mt7921_wfsys_reset(dev);
--	if (ret)
--		return ret;
--
- 	/* init tx queue */
- 	ret = mt76_connac_init_tx_queues(dev->phy.mt76, MT7921_TXQ_BAND0,
- 					 MT7921_TX_RING_SIZE,
-diff --git a/mt7921/init.c b/mt7921/init.c
-index e929f6eb..94b7cdfd 100644
---- a/mt7921/init.c
-+++ b/mt7921/init.c
-@@ -2,6 +2,9 @@
- /* Copyright (C) 2020 MediaTek Inc. */
- 
- #include <linux/etherdevice.h>
-+#include <linux/hwmon.h>
-+#include <linux/hwmon-sysfs.h>
-+#include <linux/thermal.h>
- #include <linux/firmware.h>
- #include "mt7921.h"
- #include "../mt76_connac2_mac.h"
-@@ -51,6 +54,57 @@ static const struct ieee80211_iface_combination if_comb_chanctx[] = {
- 	}
- };
- 
-+static ssize_t mt7921_thermal_temp_show(struct device *dev,
-+					struct device_attribute *attr,
-+					char *buf)
-+{
-+	switch (to_sensor_dev_attr(attr)->index) {
-+	case 0: {
-+		struct mt7921_phy *phy = dev_get_drvdata(dev);
-+		struct mt7921_dev *mdev = phy->dev;
-+		int temperature;
-+
-+		mt7921_mutex_acquire(mdev);
-+		temperature = mt7921_mcu_get_temperature(phy);
-+		mt7921_mutex_release(mdev);
-+
-+		if (temperature < 0)
-+			return temperature;
-+		/* display in millidegree Celsius */
-+		return sprintf(buf, "%u\n", temperature * 1000);
-+	}
-+	default:
-+		return -EINVAL;
-+	}
-+}
-+static SENSOR_DEVICE_ATTR_RO(temp1_input, mt7921_thermal_temp, 0);
-+
-+static struct attribute *mt7921_hwmon_attrs[] = {
-+	&sensor_dev_attr_temp1_input.dev_attr.attr,
-+	NULL,
-+};
-+ATTRIBUTE_GROUPS(mt7921_hwmon);
-+
-+static int mt7921_thermal_init(struct mt7921_phy *phy)
-+{
-+	struct wiphy *wiphy = phy->mt76->hw->wiphy;
-+	struct device *hwmon;
-+	const char *name;
-+
-+	if (!IS_REACHABLE(CONFIG_HWMON))
-+		return 0;
-+
-+	name = devm_kasprintf(&wiphy->dev, GFP_KERNEL, "mt7921_%s",
-+			      wiphy_name(wiphy));
-+
-+	hwmon = devm_hwmon_device_register_with_groups(&wiphy->dev, name, phy,
-+						       mt7921_hwmon_groups);
-+	if (IS_ERR(hwmon))
-+		return PTR_ERR(hwmon);
-+
-+	return 0;
-+}
-+
- static void
- mt7921_regd_notifier(struct wiphy *wiphy,
- 		     struct regulatory_request *request)
-@@ -113,7 +167,8 @@ mt7921_init_wiphy(struct ieee80211_hw *hw)
- 	wiphy->max_sched_scan_ssids = MT76_CONNAC_MAX_SCHED_SCAN_SSID;
- 	wiphy->max_match_sets = MT76_CONNAC_MAX_SCAN_MATCH;
- 	wiphy->max_sched_scan_reqs = 1;
--	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
-+	wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH |
-+			WIPHY_FLAG_SPLIT_SCAN_6GHZ;
- 	wiphy->reg_notifier = mt7921_regd_notifier;
- 
- 	wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR |
-@@ -176,12 +231,12 @@ mt7921_mac_init_band(struct mt7921_dev *dev, u8 band)
- static u8
- mt7921_get_offload_capability(struct device *dev, const char *fw_wm)
- {
--	struct mt7921_fw_features *features = NULL;
- 	const struct mt76_connac2_fw_trailer *hdr;
- 	struct mt7921_realease_info *rel_info;
- 	const struct firmware *fw;
- 	int ret, i, offset = 0;
- 	const u8 *data, *end;
-+	u8 offload_caps = 0;
- 
- 	ret = request_firmware(&fw, fw_wm, dev);
- 	if (ret)
-@@ -213,7 +268,10 @@ mt7921_get_offload_capability(struct device *dev, const char *fw_wm)
- 		data += sizeof(*rel_info);
- 
- 		if (rel_info->tag == MT7921_FW_TAG_FEATURE) {
-+			struct mt7921_fw_features *features;
-+
- 			features = (struct mt7921_fw_features *)data;
-+			offload_caps = features->data;
- 			break;
- 		}
- 
-@@ -223,7 +281,7 @@ mt7921_get_offload_capability(struct device *dev, const char *fw_wm)
- out:
- 	release_firmware(fw);
- 
--	return features ? features->data : 0;
-+	return offload_caps;
- }
- 
- struct ieee80211_ops *
-@@ -359,6 +417,12 @@ static void mt7921_init_work(struct work_struct *work)
- 		return;
- 	}
- 
-+	ret = mt7921_thermal_init(&dev->phy);
-+	if (ret) {
-+		dev_err(dev->mt76.dev, "thermal init failed\n");
-+		return;
-+	}
-+
- 	/* we support chip reset now */
- 	dev->hw_init_done = true;
- 
-@@ -392,8 +456,6 @@ int mt7921_register_device(struct mt7921_dev *dev)
- #endif
- 	skb_queue_head_init(&dev->phy.scan_event_list);
- 	skb_queue_head_init(&dev->coredump.msg_list);
--	INIT_LIST_HEAD(&dev->sta_poll_list);
--	spin_lock_init(&dev->sta_poll_lock);
- 
- 	INIT_WORK(&dev->reset_work, mt7921_mac_reset_work);
- 	INIT_WORK(&dev->init_work, mt7921_init_work);
-diff --git a/mt7921/mac.c b/mt7921/mac.c
-index 1675bf52..368f9271 100644
---- a/mt7921/mac.c
-+++ b/mt7921/mac.c
-@@ -52,7 +52,7 @@ bool mt7921_mac_wtbl_update(struct mt7921_dev *dev, int idx, u32 mask)
- 			 0, 5000);
- }
- 
--void mt7921_mac_sta_poll(struct mt7921_dev *dev)
-+static void mt7921_mac_sta_poll(struct mt7921_dev *dev)
- {
- 	static const u8 ac_to_tid[] = {
- 		[IEEE80211_AC_BE] = 0,
-@@ -68,9 +68,9 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
- 	s8 rssi[4];
- 	int i;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	while (true) {
- 		bool clear = false;
-@@ -78,15 +78,15 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
- 		u16 idx;
- 		u8 bw;
- 
--		spin_lock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
- 		if (list_empty(&sta_poll_list)) {
--			spin_unlock_bh(&dev->sta_poll_lock);
-+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 			break;
- 		}
- 		msta = list_first_entry(&sta_poll_list,
--					struct mt7921_sta, poll_list);
--		list_del_init(&msta->poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+					struct mt7921_sta, wcid.poll_list);
-+		list_del_init(&msta->wcid.poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		idx = msta->wcid.idx;
- 		addr = mt7921_mac_wtbl_lmac_addr(idx, MT_WTBL_AC0_CTT_OFFSET);
-@@ -183,7 +183,6 @@ void mt7921_mac_sta_poll(struct mt7921_dev *dev)
- 		ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
- 	}
- }
--EXPORT_SYMBOL_GPL(mt7921_mac_sta_poll);
- 
- static void
- mt7921_get_status_freq_info(struct mt7921_dev *dev, struct mt76_phy *mphy,
-@@ -281,10 +280,11 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
- 
- 	if (status->wcid) {
- 		msta = container_of(status->wcid, struct mt7921_sta, wcid);
--		spin_lock_bh(&dev->sta_poll_lock);
--		if (list_empty(&msta->poll_list))
--			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		if (list_empty(&msta->wcid.poll_list))
-+			list_add_tail(&msta->wcid.poll_list,
-+				      &dev->mt76.sta_poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
- 	mt7921_get_status_freq_info(dev, mphy, status, chfreq);
-@@ -511,30 +511,6 @@ mt7921_mac_fill_rx(struct mt7921_dev *dev, struct sk_buff *skb)
- 	return 0;
- }
- 
--static void mt7921_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
--{
--	struct mt7921_sta *msta;
--	u16 fc, tid;
--	u32 val;
--
--	if (!sta || !(sta->deflink.ht_cap.ht_supported || sta->deflink.he_cap.has_he))
--		return;
--
--	tid = le32_get_bits(txwi[1], MT_TXD1_TID);
--	if (tid >= 6) /* skip VO queue */
--		return;
--
--	val = le32_to_cpu(txwi[2]);
--	fc = FIELD_GET(MT_TXD2_FRAME_TYPE, val) << 2 |
--	     FIELD_GET(MT_TXD2_SUB_TYPE, val) << 4;
--	if (unlikely(fc != (IEEE80211_FTYPE_DATA | IEEE80211_STYPE_QOS_DATA)))
--		return;
--
--	msta = (struct mt7921_sta *)sta->drv_priv;
--	if (!test_and_set_bit(tid, &msta->ampdu_state))
--		ieee80211_start_tx_ba_session(sta, tid, 0);
--}
--
- void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
- {
- 	struct mt7921_sta *msta = NULL;
-@@ -567,46 +543,15 @@ void mt7921_mac_add_txs(struct mt7921_dev *dev, void *data)
- 	if (!wcid->sta)
- 		goto out;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (list_empty(&msta->poll_list))
--		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (list_empty(&msta->wcid.poll_list))
-+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- out:
- 	rcu_read_unlock();
- }
- 
--void mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
--		      struct ieee80211_sta *sta, bool clear_status,
--		      struct list_head *free_list)
--{
--	struct mt76_dev *mdev = &dev->mt76;
--	__le32 *txwi;
--	u16 wcid_idx;
--
--	mt76_connac_txp_skb_unmap(mdev, t);
--	if (!t->skb)
--		goto out;
--
--	txwi = (__le32 *)mt76_get_txwi_ptr(mdev, t);
--	if (sta) {
--		struct mt76_wcid *wcid = (struct mt76_wcid *)sta->drv_priv;
--
--		if (likely(t->skb->protocol != cpu_to_be16(ETH_P_PAE)))
--			mt7921_tx_check_aggr(sta, txwi);
--
--		wcid_idx = wcid->idx;
--	} else {
--		wcid_idx = le32_get_bits(txwi[1], MT_TXD1_WLAN_IDX);
--	}
--
--	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
--out:
--	t->skb = NULL;
--	mt76_put_txwi(mdev, t);
--}
--EXPORT_SYMBOL_GPL(mt7921_txwi_free);
--
- static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
- {
- 	struct mt76_connac_tx_free *free = data;
-@@ -614,6 +559,7 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
- 	struct mt76_dev *mdev = &dev->mt76;
- 	struct mt76_txwi_cache *txwi;
- 	struct ieee80211_sta *sta = NULL;
-+	struct mt76_wcid *wcid = NULL;
- 	struct sk_buff *skb, *tmp;
- 	void *end = data + len;
- 	LIST_HEAD(free_list);
-@@ -637,7 +583,6 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
- 		 */
- 		if (info & MT_TX_FREE_PAIR) {
- 			struct mt7921_sta *msta;
--			struct mt76_wcid *wcid;
- 			u16 idx;
- 
- 			count++;
-@@ -648,21 +593,28 @@ static void mt7921_mac_tx_free(struct mt7921_dev *dev, void *data, int len)
- 				continue;
- 
- 			msta = container_of(wcid, struct mt7921_sta, wcid);
--			spin_lock_bh(&dev->sta_poll_lock);
--			if (list_empty(&msta->poll_list))
--				list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--			spin_unlock_bh(&dev->sta_poll_lock);
-+			spin_lock_bh(&mdev->sta_poll_lock);
-+			if (list_empty(&msta->wcid.poll_list))
-+				list_add_tail(&msta->wcid.poll_list,
-+					      &mdev->sta_poll_list);
-+			spin_unlock_bh(&mdev->sta_poll_lock);
- 			continue;
- 		}
- 
- 		msdu = FIELD_GET(MT_TX_FREE_MSDU_ID, info);
- 		stat = FIELD_GET(MT_TX_FREE_STATUS, info);
- 
-+		if (wcid) {
-+			wcid->stats.tx_retries +=
-+				FIELD_GET(MT_TX_FREE_COUNT, info) - 1;
-+			wcid->stats.tx_failed += !!stat;
-+		}
-+
- 		txwi = mt76_token_release(mdev, msdu, &wake);
- 		if (!txwi)
- 			continue;
- 
--		mt7921_txwi_free(dev, txwi, sta, stat, &free_list);
-+		mt76_connac2_txwi_free(mdev, txwi, sta, &free_list);
- 	}
- 
- 	if (wake)
-@@ -952,8 +904,8 @@ EXPORT_SYMBOL_GPL(mt7921_reset);
- 
- void mt7921_mac_update_mib_stats(struct mt7921_phy *phy)
- {
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	struct mt7921_dev *dev = phy->dev;
--	struct mib_stats *mib = &phy->mib;
- 	int i, aggr0 = 0, aggr1;
- 	u32 val;
- 
-@@ -1180,6 +1132,10 @@ int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- 	if (unlikely(tx_info->skb->len <= ETH_HLEN))
- 		return -EINVAL;
- 
-+	err = skb_cow_head(skb, MT_SDIO_TXD_SIZE + MT_SDIO_HDR_SIZE);
-+	if (err)
-+		return err;
-+
- 	if (!wcid)
- 		wcid = &dev->mt76.global_wcid;
- 
-@@ -1224,7 +1180,7 @@ void mt7921_usb_sdio_tx_complete_skb(struct mt76_dev *mdev,
- 	sta = wcid_to_sta(wcid);
- 
- 	if (sta && likely(e->skb->protocol != cpu_to_be16(ETH_P_PAE)))
--		mt7921_tx_check_aggr(sta, txwi);
-+		mt76_connac2_tx_check_aggr(sta, txwi);
- 
- 	skb_pull(e->skb, headroom);
- 	mt76_tx_complete_skb(mdev, e->wcid, e->skb);
-diff --git a/mt7921/main.c b/mt7921/main.c
-index 3b6adb29..87067ac3 100644
---- a/mt7921/main.c
-+++ b/mt7921/main.c
-@@ -313,7 +313,7 @@ static int mt7921_add_interface(struct ieee80211_hw *hw,
- 
- 	idx = MT7921_WTBL_RESERVED - mvif->mt76.idx;
- 
--	INIT_LIST_HEAD(&mvif->sta.poll_list);
-+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
- 	mvif->sta.wcid.idx = idx;
- 	mvif->sta.wcid.phy_idx = mvif->mt76.band_idx;
- 	mvif->sta.wcid.hw_key_idx = -1;
-@@ -357,10 +357,10 @@ static void mt7921_remove_interface(struct ieee80211_hw *hw,
- 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
- 	mt7921_mutex_release(dev);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
- }
-@@ -764,7 +764,7 @@ int mt7921_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	if (idx < 0)
- 		return -ENOSPC;
- 
--	INIT_LIST_HEAD(&msta->poll_list);
-+	INIT_LIST_HEAD(&msta->wcid.poll_list);
- 	msta->vif = mvif;
- 	msta->wcid.sta = 1;
- 	msta->wcid.idx = idx;
-@@ -842,10 +842,10 @@ void mt7921_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 						    mvif->ctx);
- 	}
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
- }
-@@ -954,16 +954,16 @@ mt7921_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
- 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- 		mtxq->aggr = false;
--		clear_bit(tid, &msta->ampdu_state);
-+		clear_bit(tid, &msta->wcid.ampdu_state);
- 		mt7921_mcu_uni_tx_ba(dev, params, false);
- 		break;
- 	case IEEE80211_AMPDU_TX_START:
--		set_bit(tid, &msta->ampdu_state);
-+		set_bit(tid, &msta->wcid.ampdu_state);
- 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
- 		break;
- 	case IEEE80211_AMPDU_TX_STOP_CONT:
- 		mtxq->aggr = false;
--		clear_bit(tid, &msta->ampdu_state);
-+		clear_bit(tid, &msta->wcid.ampdu_state);
- 		mt7921_mcu_uni_tx_ba(dev, params, false);
- 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- 		break;
-@@ -995,7 +995,7 @@ mt7921_get_stats(struct ieee80211_hw *hw,
- 		 struct ieee80211_low_level_stats *stats)
- {
- 	struct mt7921_phy *phy = mt7921_hw_phy(hw);
--	struct mib_stats *mib = &phy->mib;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 
- 	mt7921_mutex_acquire(phy->dev);
- 
-@@ -1077,6 +1077,10 @@ static const char mt7921_gstrings_stats[][ETH_GSTRING_LEN] = {
- 	"v_tx_mcs_9",
- 	"v_tx_mcs_10",
- 	"v_tx_mcs_11",
-+	"v_tx_nss_1",
-+	"v_tx_nss_2",
-+	"v_tx_nss_3",
-+	"v_tx_nss_4",
- };
- 
- static void
-@@ -1133,7 +1137,7 @@ void mt7921_get_et_stats(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 	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;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	struct mt76_ethtool_worker_info wi = {
- 		.data = data,
- 		.idx = mvif->mt76.idx,
-@@ -1363,7 +1367,7 @@ mt7921_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
- 		return -EINVAL;
- 
- 	if ((BIT(hweight8(tx_ant)) - 1) != tx_ant)
--		tx_ant = BIT(ffs(tx_ant) - 1) - 1;
-+		return -EINVAL;
- 
- 	mt7921_mutex_acquire(dev);
- 
-@@ -1399,6 +1403,12 @@ static void mt7921_sta_statistics(struct ieee80211_hw *hw,
- 		sinfo->txrate.he_dcm = txrate->he_dcm;
- 		sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
- 	}
-+	sinfo->tx_failed = msta->wcid.stats.tx_failed;
-+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
-+
-+	sinfo->tx_retries = msta->wcid.stats.tx_retries;
-+	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_RETRIES);
-+
- 	sinfo->txrate.flags = txrate->flags;
- 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
- 
-diff --git a/mt7921/mcu.c b/mt7921/mcu.c
-index c69ce6df..a0ad18c7 100644
---- a/mt7921/mcu.c
-+++ b/mt7921/mcu.c
-@@ -476,12 +476,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
- {
- 	int ret;
- 
--	ret = mt76_get_field(dev, MT_CONN_ON_MISC, MT_TOP_MISC2_FW_N9_RDY);
--	if (ret && mt76_is_mmio(&dev->mt76)) {
--		dev_dbg(dev->mt76.dev, "Firmware is already download\n");
--		goto fw_loaded;
--	}
--
- 	ret = mt76_connac2_load_patch(&dev->mt76, mt7921_patch_name(dev));
- 	if (ret)
- 		return ret;
-@@ -504,8 +498,6 @@ static int mt7921_load_firmware(struct mt7921_dev *dev)
- 		return -EIO;
- 	}
- 
--fw_loaded:
--
- #ifdef CONFIG_PM
- 	dev->mt76.hw->wiphy->wowlan = &mt76_connac_wowlan_support;
- #endif /* CONFIG_PM */
-@@ -1313,6 +1305,23 @@ int mt7921_mcu_set_clc(struct mt7921_dev *dev, u8 *alpha2,
- 	return 0;
- }
- 
-+int mt7921_mcu_get_temperature(struct mt7921_phy *phy)
-+{
-+	struct mt7921_dev *dev = phy->dev;
-+	struct {
-+		u8 ctrl_id;
-+		u8 action;
-+		u8 band_idx;
-+		u8 rsv[5];
-+	} req = {
-+		.ctrl_id = THERMAL_SENSOR_TEMP_QUERY,
-+		.band_idx = phy->mt76->band_idx,
-+	};
-+
-+	return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(THERMAL_CTRL), &req,
-+				 sizeof(req), true);
-+}
-+
- int mt7921_mcu_set_rxfilter(struct mt7921_dev *dev, u32 fif,
- 			    u8 bit_op, u32 bit_map)
- {
-diff --git a/mt7921/mt7921.h b/mt7921/mt7921.h
-index 149acb16..ec987965 100644
---- a/mt7921/mt7921.h
-+++ b/mt7921/mt7921.h
-@@ -19,7 +19,6 @@
- #define MT7921_PM_TIMEOUT		(HZ / 12)
- #define MT7921_HW_SCAN_TIMEOUT		(HZ / 10)
- #define MT7921_WATCHDOG_TIME		(HZ / 4)
--#define MT7921_RESET_TIMEOUT		(30 * HZ)
- 
- #define MT7921_TX_RING_SIZE		2048
- #define MT7921_TX_MCU_RING_SIZE		256
-@@ -151,14 +150,12 @@ struct mt7921_sta {
- 
- 	struct mt7921_vif *vif;
- 
--	struct list_head poll_list;
- 	u32 airtime_ac[8];
- 
- 	int ack_signal;
- 	struct ewma_avg_signal avg_ack_signal;
- 
- 	unsigned long last_txs;
--	unsigned long ampdu_state;
- 
- 	struct mt76_connac_sta_key_conf bip;
- };
-@@ -179,35 +176,6 @@ struct mt7921_vif {
- 	struct ieee80211_chanctx_conf *ctx;
- };
- 
--struct mib_stats {
--	u32 ack_fail_cnt;
--	u32 fcs_err_cnt;
--	u32 rts_cnt;
--	u32 rts_retries_cnt;
--	u32 ba_miss_cnt;
--
--	u32 tx_bf_ibf_ppdu_cnt;
--	u32 tx_bf_ebf_ppdu_cnt;
--	u32 tx_bf_rx_fb_all_cnt;
--	u32 tx_bf_rx_fb_he_cnt;
--	u32 tx_bf_rx_fb_vht_cnt;
--	u32 tx_bf_rx_fb_ht_cnt;
--
--	u32 tx_ampdu_cnt;
--	u32 tx_mpdu_attempts_cnt;
--	u32 tx_mpdu_success_cnt;
--	u32 tx_pkt_ebf_cnt;
--	u32 tx_pkt_ibf_cnt;
--
--	u32 rx_mpdu_cnt;
--	u32 rx_ampdu_cnt;
--	u32 rx_ampdu_bytes_cnt;
--	u32 rx_ba_cnt;
--
--	u32 tx_amsdu[8];
--	u32 tx_amsdu_cnt;
--};
--
- enum {
- 	MT7921_CLC_POWER,
- 	MT7921_CLC_CHAN,
-@@ -247,7 +215,7 @@ struct mt7921_phy {
- 	u32 rx_ampdu_ts;
- 	u32 ampdu_ref;
- 
--	struct mib_stats mib;
-+	struct mt76_mib_stats mib;
- 
- 	u8 sta_work_count;
- 
-@@ -304,9 +272,6 @@ struct mt7921_dev {
- 	bool hw_init_done:1;
- 	bool fw_assert:1;
- 
--	struct list_head sta_poll_list;
--	spinlock_t sta_poll_lock;
--
- 	struct work_struct init_work;
- 
- 	u8 fw_debug;
-@@ -477,7 +442,6 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- 			   struct mt76_tx_info *tx_info);
- 
- void mt7921_tx_worker(struct mt76_worker *w);
--void mt7921_tx_token_put(struct mt7921_dev *dev);
- bool mt7921_rx_check(struct mt76_dev *mdev, void *data, int len);
- void mt7921_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
- 			 struct sk_buff *skb, u32 *info);
-@@ -510,10 +474,6 @@ int mt7921_testmode_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 			void *data, int len);
- int mt7921_testmode_dump(struct ieee80211_hw *hw, struct sk_buff *msg,
- 			 struct netlink_callback *cb, void *data, int len);
--void mt7921_txwi_free(struct mt7921_dev *dev, struct mt76_txwi_cache *t,
--		      struct ieee80211_sta *sta, bool clear_status,
--		      struct list_head *free_list);
--void mt7921_mac_sta_poll(struct mt7921_dev *dev);
- int mt7921_mcu_parse_response(struct mt76_dev *mdev, int cmd,
- 			      struct sk_buff *skb, int seq);
- 
-@@ -540,6 +500,7 @@ int mt7921_mcu_set_sniffer(struct mt7921_dev *dev, struct ieee80211_vif *vif,
- 			   bool enable);
- int mt7921_mcu_config_sniffer(struct mt7921_vif *vif,
- 			      struct ieee80211_chanctx_conf *ctx);
-+int mt7921_mcu_get_temperature(struct mt7921_phy *phy);
- 
- int mt7921_usb_sdio_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- 				   enum mt76_txq_id qid, struct mt76_wcid *wcid,
-diff --git a/mt7921/pci.c b/mt7921/pci.c
-index 1c727870..7c8bf719 100644
---- a/mt7921/pci.c
-+++ b/mt7921/pci.c
-@@ -115,7 +115,7 @@ static void mt7921e_unregister_device(struct mt7921_dev *dev)
- 	cancel_work_sync(&pm->wake_work);
- 	cancel_work_sync(&dev->reset_work);
- 
--	mt7921_tx_token_put(dev);
-+	mt76_connac2_tx_token_put(&dev->mt76);
- 	__mt7921_mcu_drv_pmctrl(dev);
- 	mt7921_dma_cleanup(dev);
- 	mt7921_wfsys_reset(dev);
-@@ -325,6 +325,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
- 	bus_ops->rmw = mt7921_rmw;
- 	dev->mt76.bus = bus_ops;
- 
-+	ret = mt7921e_mcu_fw_pmctrl(dev);
-+	if (ret)
-+		goto err_free_dev;
-+
- 	ret = __mt7921e_mcu_drv_pmctrl(dev);
- 	if (ret)
- 		goto err_free_dev;
-@@ -333,6 +337,10 @@ static int mt7921_pci_probe(struct pci_dev *pdev,
- 		    (mt7921_l1_rr(dev, MT_HW_REV) & 0xff);
- 	dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
- 
-+	ret = mt7921_wfsys_reset(dev);
-+	if (ret)
-+		goto err_free_dev;
-+
- 	mt76_wr(dev, MT_WFDMA0_HOST_INT_ENA, 0);
- 
- 	mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
-diff --git a/mt7921/pci_mac.c b/mt7921/pci_mac.c
-index 6053a255..978c90a0 100644
---- a/mt7921/pci_mac.c
-+++ b/mt7921/pci_mac.c
-@@ -53,20 +53,6 @@ int mt7921e_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
- 	return 0;
- }
- 
--void mt7921_tx_token_put(struct mt7921_dev *dev)
--{
--	struct mt76_txwi_cache *txwi;
--	int id;
--
--	spin_lock_bh(&dev->mt76.token_lock);
--	idr_for_each_entry(&dev->mt76.token, txwi, id) {
--		mt7921_txwi_free(dev, txwi, NULL, false, NULL);
--		dev->mt76.token_count--;
--	}
--	spin_unlock_bh(&dev->mt76.token_lock);
--	idr_destroy(&dev->mt76.token);
--}
--
- int mt7921e_mac_reset(struct mt7921_dev *dev)
- {
- 	int i, err;
-@@ -91,7 +77,7 @@ int mt7921e_mac_reset(struct mt7921_dev *dev)
- 	napi_disable(&dev->mt76.napi[MT_RXQ_MCU_WA]);
- 	napi_disable(&dev->mt76.tx_napi);
- 
--	mt7921_tx_token_put(dev);
-+	mt76_connac2_tx_token_put(&dev->mt76);
- 	idr_init(&dev->mt76.token);
- 
- 	mt7921_wpdma_reset(dev, true);
-diff --git a/mt7921/regs.h b/mt7921/regs.h
-index e52977ff..b1801425 100644
---- a/mt7921/regs.h
-+++ b/mt7921/regs.h
-@@ -158,7 +158,6 @@
- 
- #define MT_MIB_MB_SDR0(_band, n)	MT_WF_MIB(_band, 0x100 + ((n) << 4))
- #define MT_MIB_RTS_RETRIES_COUNT_MASK	GENMASK(31, 16)
--#define MT_MIB_RTS_COUNT_MASK		GENMASK(15, 0)
- 
- #define MT_MIB_MB_BSDR0(_band)		MT_WF_MIB(_band, 0x688)
- #define MT_MIB_RTS_COUNT_MASK		GENMASK(15, 0)
-diff --git a/mt7996/debugfs.c b/mt7996/debugfs.c
-index 513ab4ba..4d40ec7f 100644
---- a/mt7996/debugfs.c
-+++ b/mt7996/debugfs.c
-@@ -474,10 +474,10 @@ mt7996_ampdu_stat_read_phy(struct mt7996_phy *phy, struct seq_file *file)
- static void
- mt7996_txbf_stat_read_phy(struct mt7996_phy *phy, struct seq_file *s)
- {
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	static const char * const bw[] = {
- 		"BW20", "BW40", "BW80", "BW160"
- 	};
--	struct mib_stats *mib = &phy->mib;
- 
- 	/* Tx Beamformer monitor */
- 	seq_puts(s, "\nTx Beamformer applied PPDU counts: ");
-@@ -523,7 +523,7 @@ mt7996_tx_stats_show(struct seq_file *file, void *data)
- {
- 	struct mt7996_phy *phy = file->private;
- 	struct mt7996_dev *dev = phy->dev;
--	struct mib_stats *mib = &phy->mib;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	int i;
- 	u32 attempts, success, per;
- 
-diff --git a/mt7996/dma.c b/mt7996/dma.c
-index 53414346..586e247a 100644
---- a/mt7996/dma.c
-+++ b/mt7996/dma.c
-@@ -128,11 +128,55 @@ static void mt7996_dma_disable(struct mt7996_dev *dev, bool reset)
- 	}
- }
- 
--static int mt7996_dma_enable(struct mt7996_dev *dev)
-+void mt7996_dma_start(struct mt7996_dev *dev, bool reset)
- {
- 	u32 hif1_ofs = 0;
- 	u32 irq_mask;
- 
-+	if (dev->hif2)
-+		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
-+
-+	/* enable WFDMA Tx/Rx */
-+	if (!reset) {
-+		mt76_set(dev, MT_WFDMA0_GLO_CFG,
-+			 MT_WFDMA0_GLO_CFG_TX_DMA_EN |
-+			 MT_WFDMA0_GLO_CFG_RX_DMA_EN |
-+			 MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
-+			 MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-+
-+		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 |
-+				 MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
-+				 MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
-+	}
-+
-+	/* enable interrupts for TX/RX rings */
-+	irq_mask = MT_INT_MCU_CMD;
-+	if (reset)
-+		goto done;
-+
-+	irq_mask = MT_INT_RX_DONE_MCU | MT_INT_TX_DONE_MCU;
-+
-+	if (!dev->mphy.band_idx)
-+		irq_mask |= MT_INT_BAND0_RX_DONE;
-+
-+	if (dev->dbdc_support)
-+		irq_mask |= MT_INT_BAND1_RX_DONE;
-+
-+	if (dev->tbtc_support)
-+		irq_mask |= MT_INT_BAND2_RX_DONE;
-+
-+done:
-+	mt7996_irq_enable(dev, irq_mask);
-+	mt7996_irq_disable(dev, 0);
-+}
-+
-+static void mt7996_dma_enable(struct mt7996_dev *dev, bool reset)
-+{
-+	u32 hif1_ofs = 0;
-+
- 	if (dev->hif2)
- 		hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
- 
-@@ -170,13 +214,6 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
- 	mt76_poll(dev, MT_WFDMA_EXT_CSR_HIF_MISC,
- 		  MT_WFDMA_EXT_CSR_HIF_MISC_BUSY, 0, 1000);
- 
--	/* set WFDMA Tx/Rx */
--	mt76_set(dev, MT_WFDMA0_GLO_CFG,
--		 MT_WFDMA0_GLO_CFG_TX_DMA_EN |
--		 MT_WFDMA0_GLO_CFG_RX_DMA_EN |
--		 MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
--		 MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
--
- 	/* GLO_CFG_EXT0 */
- 	mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0,
- 		 WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD |
-@@ -187,12 +224,6 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
- 		 WF_WFDMA0_GLO_CFG_EXT1_TX_FCTRL_MODE);
- 
- 	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 |
--			 MT_WFDMA0_GLO_CFG_OMIT_TX_INFO |
--			 MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
--
- 		/* GLO_CFG_EXT0 */
- 		mt76_set(dev, WF_WFDMA0_GLO_CFG_EXT0 + hif1_ofs,
- 			 WF_WFDMA0_GLO_CFG_EXT0_RX_WB_RXD |
-@@ -216,23 +247,7 @@ static int mt7996_dma_enable(struct mt7996_dev *dev)
- 		/* TODO: redirect rx ring6 interrupt to pcie0 for wed function */
- 	}
- 
--	/* enable interrupts for TX/RX rings */
--	irq_mask = MT_INT_RX_DONE_MCU |
--		   MT_INT_TX_DONE_MCU |
--		   MT_INT_MCU_CMD;
--
--	if (!dev->mphy.band_idx)
--		irq_mask |= MT_INT_BAND0_RX_DONE;
--
--	if (dev->dbdc_support)
--		irq_mask |= MT_INT_BAND1_RX_DONE;
--
--	if (dev->tbtc_support)
--		irq_mask |= MT_INT_BAND2_RX_DONE;
--
--	mt7996_irq_enable(dev, irq_mask);
--
--	return 0;
-+	mt7996_dma_start(dev, reset);
- }
- 
- int mt7996_dma_init(struct mt7996_dev *dev)
-@@ -293,7 +308,7 @@ int mt7996_dma_init(struct mt7996_dev *dev)
- 	/* event from WA */
- 	ret = mt76_queue_alloc(dev, &dev->mt76.q_rx[MT_RXQ_MCU_WA],
- 			       MT_RXQ_ID(MT_RXQ_MCU_WA),
--			       MT7996_RX_MCU_RING_SIZE,
-+			       MT7996_RX_MCU_RING_SIZE_WA,
- 			       MT_RX_BUF_SIZE,
- 			       MT_RXQ_RING_BASE(MT_RXQ_MCU_WA));
- 	if (ret)
-@@ -347,7 +362,7 @@ int mt7996_dma_init(struct mt7996_dev *dev)
- 			  mt7996_poll_tx);
- 	napi_enable(&dev->mt76.tx_napi);
- 
--	mt7996_dma_enable(dev);
-+	mt7996_dma_enable(dev, false);
- 
- 	return 0;
- }
-@@ -413,7 +428,7 @@ void mt7996_dma_reset(struct mt7996_dev *dev, bool force)
- 	mt76_for_each_q_rx(&dev->mt76, i)
- 		mt76_queue_rx_reset(dev, i);
- 
--	mt7996_dma_enable(dev);
-+	mt7996_dma_enable(dev, !force);
- }
- 
- void mt7996_dma_cleanup(struct mt7996_dev *dev)
-diff --git a/mt7996/init.c b/mt7996/init.c
-index f1b48cdd..e297e7cb 100644
---- a/mt7996/init.c
-+++ b/mt7996/init.c
-@@ -183,6 +183,7 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
- 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
- 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_ACK_SIGNAL_SUPPORT);
- 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0);
-+	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_MU_MIMO_AIR_SNIFFER);
- 
- 	if (!mdev->dev->of_node ||
- 	    !of_property_read_bool(mdev->dev->of_node,
-@@ -217,6 +218,8 @@ mt7996_init_wiphy(struct ieee80211_hw *hw)
- 			IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
- 		phy->mt76->sband_5g.sband.ht_cap.ampdu_density =
- 			IEEE80211_HT_MPDU_DENSITY_1;
-+
-+		ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
- 	}
- 
- 	mt76_set_stream_caps(phy->mt76, true);
-@@ -853,9 +856,7 @@ int mt7996_register_device(struct mt7996_dev *dev)
- 	INIT_WORK(&dev->rc_work, mt7996_mac_sta_rc_work);
- 	INIT_DELAYED_WORK(&dev->mphy.mac_work, mt7996_mac_work);
- 	INIT_LIST_HEAD(&dev->sta_rc_list);
--	INIT_LIST_HEAD(&dev->sta_poll_list);
- 	INIT_LIST_HEAD(&dev->twt_list);
--	spin_lock_init(&dev->sta_poll_lock);
- 
- 	init_waitqueue_head(&dev->reset_wait);
- 	INIT_WORK(&dev->reset_work, mt7996_mac_reset_work);
-diff --git a/mt7996/mac.c b/mt7996/mac.c
-index 0d51090d..17dd531e 100644
---- a/mt7996/mac.c
-+++ b/mt7996/mac.c
-@@ -13,10 +13,6 @@
- 
- #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 = {
-@@ -111,9 +107,9 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
- 	LIST_HEAD(sta_poll_list);
- 	int i;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	list_splice_init(&dev->sta_poll_list, &sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	rcu_read_lock();
- 
-@@ -124,15 +120,15 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
- 		s8 rssi[4];
- 		u8 bw;
- 
--		spin_lock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
- 		if (list_empty(&sta_poll_list)) {
--			spin_unlock_bh(&dev->sta_poll_lock);
-+			spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 			break;
- 		}
- 		msta = list_first_entry(&sta_poll_list,
--					struct mt7996_sta, poll_list);
--		list_del_init(&msta->poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+					struct mt7996_sta, wcid.poll_list);
-+		list_del_init(&msta->wcid.poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		idx = msta->wcid.idx;
- 
-@@ -263,180 +259,6 @@ void mt7996_mac_set_fixed_rate_table(struct mt7996_dev *dev,
- 	mt76_wr(dev, MT_WTBL_ITCR, ctrl);
- }
- 
--static void
--mt7996_mac_decode_he_radiotap_ru(struct mt76_rx_status *status,
--				 struct ieee80211_radiotap_he *he,
--				 __le32 *rxv)
--{
--	u32 ru, offs = 0;
--
--	ru = le32_get_bits(rxv[0], MT_PRXV_HE_RU_ALLOC);
--
--	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[4], MT_CRXV_HE_NUM_USER));
--
--	he_mu->ru_ch1[0] = le32_get_bits(rxv[16], MT_CRXV_HE_RU0) & 0xff;
--
--	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[16], MT_CRXV_HE_RU1) & 0xff;
--	}
--
--	if (status->bw >= RATE_INFO_BW_80) {
--		u32 ru_h, ru_l;
--
--		he_mu->ru_ch1[1] = le32_get_bits(rxv[16], MT_CRXV_HE_RU2) & 0xff;
--
--		ru_l = le32_get_bits(rxv[16], MT_CRXV_HE_RU3_L);
--		ru_h = le32_get_bits(rxv[17], MT_CRXV_HE_RU3_H) & 0x7;
--		he_mu->ru_ch2[1] = (u8)(ru_l | ru_h << 4);
--	}
--}
--
--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[4], 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[9]) |
--		    HE_PREP(DATA3_LDPC_XSYMSEG, LDPC_EXT_SYM, rxv[4]);
--	he->data4 = HE_PREP(DATA4_SU_MU_SPTL_REUSE, SR_MASK, rxv[13]);
--	he->data5 = HE_PREP(DATA5_PE_DISAMBIG, PE_DISAMBIG, rxv[5]) |
--		    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[9]) |
--		    HE_PREP(DATA6_DOPPLER, DOPPLER, rxv[9]);
--
--	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[8]) |
--			     HE_PREP(DATA3_UL_DL, UPLINK, rxv[5]);
--		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[5]);
--		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[5]);
--		he->data4 |= HE_PREP(DATA4_MU_STA_ID, MU_AID, rxv[8]);
--
--		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[13]) |
--			     HE_PREP(DATA4_TB_SPTL_REUSE2, SR1_MASK, rxv[13]) |
--			     HE_PREP(DATA4_TB_SPTL_REUSE3, SR2_MASK, rxv[13]) |
--			     HE_PREP(DATA4_TB_SPTL_REUSE4, SR3_MASK, rxv[13]);
--
--		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)
- {
-@@ -680,10 +502,11 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
- 		struct mt7996_sta *msta;
- 
- 		msta = container_of(status->wcid, struct mt7996_sta, wcid);
--		spin_lock_bh(&dev->sta_poll_lock);
--		if (list_empty(&msta->poll_list))
--			list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
-+		if (list_empty(&msta->wcid.poll_list))
-+			list_add_tail(&msta->wcid.poll_list,
-+				      &dev->mt76.sta_poll_list);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
- 	status->freq = mphy->chandef.chan->center_freq;
-@@ -835,14 +658,19 @@ mt7996_mac_fill_rx(struct mt7996_dev *dev, struct sk_buff *skb)
- 		skb_pull(skb, hdr_gap);
- 		if (!hdr_trans && status->amsdu && !(ieee80211_has_a4(fc) && is_mesh)) {
- 			pad_start = ieee80211_get_hdrlen_from_skb(skb);
--		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR) &&
--			   get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q) {
-+		} else if (hdr_trans && (rxd2 & MT_RXD2_NORMAL_HDR_TRANS_ERROR)) {
- 			/* When header translation failure is indicated,
- 			 * the hardware will insert an extra 2-byte field
- 			 * containing the data length after the protocol
--			 * type field.
-+			 * type field. This happens either when the LLC-SNAP
-+			 * pattern did not match, or if a VLAN header was
-+			 * detected.
- 			 */
--			pad_start = 16;
-+			pad_start = 12;
-+			if (get_unaligned_be16(skb->data + pad_start) == ETH_P_8021Q)
-+				pad_start += 4;
-+			else
-+				pad_start = 0;
- 		}
- 
- 		if (pad_start) {
-@@ -880,7 +708,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))
--		mt7996_mac_decode_he_radiotap(skb, rxv, mode);
-+		mt76_connac3_mac_decode_he_radiotap(skb, rxv, mode);
- 
- 	if (!status->wcid || !ieee80211_is_data_qos(fc))
- 		return 0;
-@@ -1003,7 +831,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
- {
- 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- 	struct ieee80211_vif *vif = info->control.vif;
--	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt76_vif *mvif;
- 	struct mt76_phy *mphy = &dev->mphy;
- 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
- 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
-@@ -1015,10 +843,11 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
- 	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
- 					 BSS_CHANGED_FILS_DISCOVERY));
- 
--	if (vif) {
--		omac_idx = mvif->mt76.omac_idx;
--		wmm_idx = mvif->mt76.wmm_idx;
--		band_idx = mvif->mt76.band_idx;
-+	mvif = vif ? (struct mt76_vif *)vif->drv_priv : NULL;
-+	if (mvif) {
-+		omac_idx = mvif->omac_idx;
-+		wmm_idx = mvif->wmm_idx;
-+		band_idx = mvif->band_idx;
- 	}
- 
- 	mphy = mt76_dev_phy(&dev->mt76, band_idx);
-@@ -1083,14 +912,18 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
- 		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- 		bool mcast = ieee80211_is_data(hdr->frame_control) &&
- 			     is_multicast_ether_addr(hdr->addr1);
--		u8 idx = mvif->basic_rates_idx;
-+		u8 idx = MT7996_BASIC_RATES_TBL;
- 
--		if (mcast && mvif->mcast_rates_idx)
--			idx = mvif->mcast_rates_idx;
--		else if (beacon && mvif->beacon_rates_idx)
--			idx = mvif->beacon_rates_idx;
-+		if (mvif) {
-+			if (mcast && mvif->mcast_rates_idx)
-+				idx = mvif->mcast_rates_idx;
-+			else if (beacon && mvif->beacon_rates_idx)
-+				idx = mvif->beacon_rates_idx;
-+			else
-+				idx = mvif->basic_rates_idx;
-+		}
- 
--		txwi[6] |= FIELD_PREP(MT_TXD6_TX_RATE, idx);
-+		txwi[6] |= cpu_to_le32(FIELD_PREP(MT_TXD6_TX_RATE, idx));
- 		txwi[3] |= cpu_to_le32(MT_TXD3_BA_DISABLE);
- 	}
- }
-@@ -1200,7 +1033,7 @@ mt7996_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
- 		return;
- 
- 	msta = (struct mt7996_sta *)sta->drv_priv;
--	if (!test_and_set_bit(tid, &msta->ampdu_state))
-+	if (!test_and_set_bit(tid, &msta->wcid.ampdu_state))
- 		ieee80211_start_tx_ba_session(sta, tid, 0);
- }
- 
-@@ -1288,10 +1121,11 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
- 				continue;
- 
- 			msta = container_of(wcid, struct mt7996_sta, wcid);
--			spin_lock_bh(&dev->sta_poll_lock);
--			if (list_empty(&msta->poll_list))
--				list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--			spin_unlock_bh(&dev->sta_poll_lock);
-+			spin_lock_bh(&mdev->sta_poll_lock);
-+			if (list_empty(&msta->wcid.poll_list))
-+				list_add_tail(&msta->wcid.poll_list,
-+					      &mdev->sta_poll_list);
-+			spin_unlock_bh(&mdev->sta_poll_lock);
- 			continue;
- 		}
- 
-@@ -1326,9 +1160,10 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
- }
- 
- static bool
--mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid, int pid,
--		       __le32 *txs_data, struct mt76_sta_stats *stats)
-+mt7996_mac_add_txs_skb(struct mt7996_dev *dev, struct mt76_wcid *wcid,
-+		       int pid, __le32 *txs_data)
- {
-+	struct mt76_sta_stats *stats = &wcid->stats;
- 	struct ieee80211_supported_band *sband;
- 	struct mt76_dev *mdev = &dev->mt76;
- 	struct mt76_phy *mphy;
-@@ -1490,15 +1325,15 @@ static void mt7996_mac_add_txs(struct mt7996_dev *dev, void *data)
- 
- 	msta = container_of(wcid, struct mt7996_sta, wcid);
- 
--	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data, &msta->stats);
-+	mt7996_mac_add_txs_skb(dev, wcid, pid, txs_data);
- 
- 	if (!wcid->sta)
- 		goto out;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (list_empty(&msta->poll_list))
--		list_add_tail(&msta->poll_list, &dev->sta_poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (list_empty(&msta->wcid.poll_list))
-+		list_add_tail(&msta->wcid.poll_list, &dev->mt76.sta_poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- out:
- 	rcu_read_unlock();
-@@ -1611,20 +1446,19 @@ void mt7996_mac_reset_counters(struct mt7996_phy *phy)
- 	mt7996_mcu_get_chan_mib_info(phy, true);
- }
- 
--void mt7996_mac_set_timing(struct mt7996_phy *phy)
-+void mt7996_mac_set_coverage_class(struct mt7996_phy *phy)
- {
- 	s16 coverage_class = phy->coverage_class;
- 	struct mt7996_dev *dev = phy->dev;
- 	struct mt7996_phy *phy2 = mt7996_phy2(dev);
- 	struct mt7996_phy *phy3 = mt7996_phy3(dev);
--	u32 val, reg_offset;
-+	u32 reg_offset;
- 	u32 cck = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 231) |
- 		  FIELD_PREP(MT_TIMEOUT_VAL_CCA, 48);
- 	u32 ofdm = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, 60) |
- 		   FIELD_PREP(MT_TIMEOUT_VAL_CCA, 28);
- 	u8 band_idx = phy->mt76->band_idx;
- 	int offset;
--	bool a_band = !(phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ);
- 
- 	if (!test_bit(MT76_STATE_RUNNING, &phy->mt76->state))
- 		return;
-@@ -1637,34 +1471,12 @@ void mt7996_mac_set_timing(struct mt7996_phy *phy)
- 		coverage_class = max_t(s16, coverage_class,
- 				       phy3->coverage_class);
- 
--	mt76_set(dev, MT_ARB_SCR(band_idx),
--		 MT_ARB_SCR_TX_DISABLE | MT_ARB_SCR_RX_DISABLE);
--	udelay(1);
--
- 	offset = 3 * coverage_class;
- 	reg_offset = FIELD_PREP(MT_TIMEOUT_VAL_PLCP, offset) |
- 		     FIELD_PREP(MT_TIMEOUT_VAL_CCA, offset);
- 
- 	mt76_wr(dev, MT_TMAC_CDTR(band_idx), cck + reg_offset);
- 	mt76_wr(dev, MT_TMAC_ODTR(band_idx), ofdm + reg_offset);
--	mt76_wr(dev, MT_TMAC_ICR0(band_idx),
--		FIELD_PREP(MT_IFS_EIFS_OFDM, a_band ? 84 : 78) |
--		FIELD_PREP(MT_IFS_RIFS, 2) |
--		FIELD_PREP(MT_IFS_SIFS, 10) |
--		FIELD_PREP(MT_IFS_SLOT, phy->slottime));
--
--	if (!a_band)
--		mt76_wr(dev, MT_TMAC_ICR1(band_idx),
--			FIELD_PREP(MT_IFS_EIFS_CCK, 314));
--
--	if (phy->slottime < 20 || a_band)
--		val = MT7996_CFEND_RATE_DEFAULT;
--	else
--		val = MT7996_CFEND_RATE_11B;
--
--	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);
- }
- 
- void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band)
-@@ -2048,6 +1860,12 @@ void mt7996_mac_reset_work(struct work_struct *work)
- 		mt7996_wait_reset_state(dev, MT_MCU_CMD_RECOVERY_DONE);
- 	}
- 
-+	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
-+	mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
-+
-+	/* enable DMA Tx/Tx and interrupt */
-+	mt7996_dma_start(dev, false);
-+
- 	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
- 	clear_bit(MT76_RESET, &dev->mphy.state);
- 	if (phy2)
-@@ -2064,9 +1882,6 @@ void mt7996_mac_reset_work(struct work_struct *work)
- 
- 	tasklet_schedule(&dev->mt76.irq_tasklet);
- 
--	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_RESET_DONE);
--	mt7996_wait_reset_state(dev, MT_MCU_CMD_NORMAL_STATE);
--
- 	mt76_worker_enable(&dev->mt76.tx_worker);
- 
- 	local_bh_disable();
-@@ -2193,8 +2008,8 @@ void mt7996_reset(struct mt7996_dev *dev)
- 
- void mt7996_mac_update_stats(struct mt7996_phy *phy)
- {
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	struct mt7996_dev *dev = phy->dev;
--	struct mib_stats *mib = &phy->mib;
- 	u8 band_idx = phy->mt76->band_idx;
- 	u32 cnt;
- 	int i;
-@@ -2341,7 +2156,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
- 	u32 changed;
- 	LIST_HEAD(list);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
- 	list_splice_init(&dev->sta_rc_list, &list);
- 
- 	while (!list_empty(&list)) {
-@@ -2349,7 +2164,7 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
- 		list_del_init(&msta->rc_list);
- 		changed = msta->changed;
- 		msta->changed = 0;
--		spin_unlock_bh(&dev->sta_poll_lock);
-+		spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 		sta = container_of((void *)msta, struct ieee80211_sta, drv_priv);
- 		vif = container_of((void *)msta->vif, struct ieee80211_vif, drv_priv);
-@@ -2361,10 +2176,10 @@ void mt7996_mac_sta_rc_work(struct work_struct *work)
- 
- 		/* TODO: smps change */
- 
--		spin_lock_bh(&dev->sta_poll_lock);
-+		spin_lock_bh(&dev->mt76.sta_poll_lock);
- 	}
- 
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- }
- 
- void mt7996_mac_work(struct work_struct *work)
-diff --git a/mt7996/mac.h b/mt7996/mac.h
-index bc4e6c55..e629324a 100644
---- a/mt7996/mac.h
-+++ b/mt7996/mac.h
-@@ -6,320 +6,7 @@
- #ifndef __MT7996_MAC_H
- #define __MT7996_MAC_H
- 
--#define MT_CT_PARSE_LEN			72
--#define MT_CT_DMA_BUF_NUM		2
--
--#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)
--
--#define MT_RXD0_SW_PKT_TYPE_MASK	GENMASK(31, 16)
--#define MT_RXD0_SW_PKT_TYPE_MAP		0x380F
--#define MT_RXD0_SW_PKT_TYPE_FRAME	0x3801
--
--/* RXD DW1 */
--#define MT_RXD1_NORMAL_WLAN_IDX		GENMASK(11, 0)
--#define MT_RXD1_NORMAL_GROUP_1		BIT(16)
--#define MT_RXD1_NORMAL_GROUP_2		BIT(17)
--#define MT_RXD1_NORMAL_GROUP_3		BIT(18)
--#define MT_RXD1_NORMAL_GROUP_4		BIT(19)
--#define MT_RXD1_NORMAL_GROUP_5		BIT(20)
--#define MT_RXD1_NORMAL_KEY_ID		GENMASK(22, 21)
--#define MT_RXD1_NORMAL_CM		BIT(23)
--#define MT_RXD1_NORMAL_CLM		BIT(24)
--#define MT_RXD1_NORMAL_ICV_ERR		BIT(25)
--#define MT_RXD1_NORMAL_TKIP_MIC_ERR	BIT(26)
--#define MT_RXD1_NORMAL_BAND_IDX		GENMASK(28, 27)
--#define MT_RXD1_NORMAL_SPP_EN		BIT(29)
--#define MT_RXD1_NORMAL_ADD_OM		BIT(30)
--#define MT_RXD1_NORMAL_SEC_DONE		BIT(31)
--
--/* RXD DW2 */
--#define MT_RXD2_NORMAL_BSSID		GENMASK(5, 0)
--#define MT_RXD2_NORMAL_MAC_HDR_LEN	GENMASK(12, 8)
--#define MT_RXD2_NORMAL_HDR_TRANS	BIT(7)
--#define MT_RXD2_NORMAL_HDR_OFFSET	GENMASK(15, 13)
--#define MT_RXD2_NORMAL_SEC_MODE		GENMASK(20, 16)
--#define MT_RXD2_NORMAL_MU_BAR		BIT(21)
--#define MT_RXD2_NORMAL_SW_BIT		BIT(22)
--#define MT_RXD2_NORMAL_AMSDU_ERR	BIT(23)
--#define MT_RXD2_NORMAL_MAX_LEN_ERROR	BIT(24)
--#define MT_RXD2_NORMAL_HDR_TRANS_ERROR	BIT(25)
--#define MT_RXD2_NORMAL_INT_FRAME	BIT(26)
--#define MT_RXD2_NORMAL_FRAG		BIT(27)
--#define MT_RXD2_NORMAL_NULL_FRAME	BIT(28)
--#define MT_RXD2_NORMAL_NDATA		BIT(29)
--#define MT_RXD2_NORMAL_NON_AMPDU	BIT(30)
--#define MT_RXD2_NORMAL_BF_REPORT	BIT(31)
--
--/* RXD DW3 */
--#define MT_RXD3_NORMAL_RXV_SEQ		GENMASK(7, 0)
--#define MT_RXD3_NORMAL_CH_FREQ		GENMASK(15, 8)
--#define MT_RXD3_NORMAL_ADDR_TYPE	GENMASK(17, 16)
--#define MT_RXD3_NORMAL_U2M		BIT(0)
--#define MT_RXD3_NORMAL_HTC_VLD		BIT(18)
--#define MT_RXD3_NORMAL_BEACON_MC	BIT(20)
--#define MT_RXD3_NORMAL_BEACON_UC	BIT(21)
--#define MT_RXD3_NORMAL_CO_ANT		BIT(22)
--#define MT_RXD3_NORMAL_FCS_ERR		BIT(24)
--#define MT_RXD3_NORMAL_VLAN2ETH		BIT(31)
--
--/* RXD DW4 */
--#define MT_RXD4_NORMAL_PAYLOAD_FORMAT	GENMASK(1, 0)
--#define MT_RXD4_FIRST_AMSDU_FRAME	GENMASK(1, 0)
--#define MT_RXD4_MID_AMSDU_FRAME		BIT(1)
--#define MT_RXD4_LAST_AMSDU_FRAME	BIT(0)
--
--#define MT_RXV_HDR_BAND_IDX		BIT(24)
--
--/* RXD GROUP4 */
--#define MT_RXD8_FRAME_CONTROL		GENMASK(15, 0)
--
--#define MT_RXD10_SEQ_CTRL		GENMASK(15, 0)
--#define MT_RXD10_QOS_CTL		GENMASK(31, 16)
--
--#define MT_RXD11_HT_CONTROL		GENMASK(31, 0)
--
--/* P-RXV */
--#define MT_PRXV_TX_RATE			GENMASK(6, 0)
--#define MT_PRXV_TX_DCM			BIT(4)
--#define MT_PRXV_TX_ER_SU_106T		BIT(5)
--#define MT_PRXV_NSTS			GENMASK(10, 7)
--#define MT_PRXV_TXBF			BIT(11)
--#define MT_PRXV_HT_AD_CODE		BIT(12)
--#define MT_PRXV_HE_RU_ALLOC		GENMASK(30, 22)
--#define MT_PRXV_RCPI3			GENMASK(31, 24)
--#define MT_PRXV_RCPI2			GENMASK(23, 16)
--#define MT_PRXV_RCPI1			GENMASK(15, 8)
--#define MT_PRXV_RCPI0			GENMASK(7, 0)
--#define MT_PRXV_HT_SHORT_GI		GENMASK(4, 3)
--#define MT_PRXV_HT_STBC			GENMASK(10, 9)
--#define MT_PRXV_TX_MODE			GENMASK(14, 11)
--#define MT_PRXV_FRAME_MODE		GENMASK(2, 0)
--#define MT_PRXV_DCM			BIT(5)
--
--/* C-RXV */
--#define MT_CRXV_HE_NUM_USER		GENMASK(26, 20)
--#define MT_CRXV_HE_LTF_SIZE		GENMASK(28, 27)
--#define MT_CRXV_HE_LDPC_EXT_SYM		BIT(30)
--
--#define MT_CRXV_HE_PE_DISAMBIG		BIT(1)
--#define MT_CRXV_HE_UPLINK		BIT(2)
--
--#define MT_CRXV_HE_MU_AID		GENMASK(27, 17)
--#define MT_CRXV_HE_BEAM_CHNG		BIT(29)
--
--#define MT_CRXV_HE_DOPPLER		BIT(0)
--#define MT_CRXV_HE_BSS_COLOR		GENMASK(15, 10)
--#define MT_CRXV_HE_TXOP_DUR		GENMASK(19, 17)
--
--#define MT_CRXV_HE_SR_MASK		GENMASK(11, 8)
--#define MT_CRXV_HE_SR1_MASK		GENMASK(16, 12)
--#define MT_CRXV_HE_SR2_MASK             GENMASK(20, 17)
--#define MT_CRXV_HE_SR3_MASK             GENMASK(24, 21)
--
--#define MT_CRXV_HE_RU0			GENMASK(8, 0)
--#define MT_CRXV_HE_RU1			GENMASK(17, 9)
--#define MT_CRXV_HE_RU2			GENMASK(26, 18)
--#define MT_CRXV_HE_RU3_L		GENMASK(31, 27)
--#define MT_CRXV_HE_RU3_H		GENMASK(3, 0)
--
--enum tx_header_format {
--	MT_HDR_FORMAT_802_3,
--	MT_HDR_FORMAT_CMD,
--	MT_HDR_FORMAT_802_11,
--	MT_HDR_FORMAT_802_11_EXT,
--};
--
--enum tx_pkt_type {
--	MT_TX_TYPE_CT,
--	MT_TX_TYPE_SF,
--	MT_TX_TYPE_CMD,
--	MT_TX_TYPE_FW,
--};
--
--enum tx_port_idx {
--	MT_TX_PORT_IDX_LMAC,
--	MT_TX_PORT_IDX_MCU
--};
--
--enum tx_mcu_port_q_idx {
--	MT_TX_MCU_PORT_RX_Q0 = 0x20,
--	MT_TX_MCU_PORT_RX_Q1,
--	MT_TX_MCU_PORT_RX_Q2,
--	MT_TX_MCU_PORT_RX_Q3,
--	MT_TX_MCU_PORT_RX_FWDL = 0x3e
--};
--
--enum tx_mgnt_type {
--	MT_TX_NORMAL,
--	MT_TX_TIMING,
--	MT_TX_ADDBA,
--};
--
--#define MT_CT_INFO_APPLY_TXD		BIT(0)
--#define MT_CT_INFO_COPY_HOST_TXD_ALL	BIT(1)
--#define MT_CT_INFO_MGMT_FRAME		BIT(2)
--#define MT_CT_INFO_NONE_CIPHER_FRAME	BIT(3)
--#define MT_CT_INFO_HSR2_TX		BIT(4)
--#define MT_CT_INFO_FROM_HOST		BIT(7)
--
--#define MT_TXD_SIZE			(8 * 4)
--
--#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_TX_BYTES		GENMASK(15, 0)
--
--#define MT_TXD1_FIXED_RATE		BIT(31)
--#define MT_TXD1_OWN_MAC			GENMASK(30, 25)
--#define MT_TXD1_TID			GENMASK(24, 21)
--#define MT_TXD1_BIP			BIT(24)
--#define MT_TXD1_ETH_802_3		BIT(20)
--#define MT_TXD1_HDR_INFO		GENMASK(20, 16)
--#define MT_TXD1_HDR_FORMAT		GENMASK(15, 14)
--#define MT_TXD1_TGID			GENMASK(13, 12)
--#define MT_TXD1_WLAN_IDX		GENMASK(11, 0)
--
--#define MT_TXD2_POWER_OFFSET		GENMASK(31, 26)
--#define MT_TXD2_MAX_TX_TIME		GENMASK(25, 16)
--#define MT_TXD2_FRAG			GENMASK(15, 14)
--#define MT_TXD2_HTC_VLD			BIT(13)
--#define MT_TXD2_DURATION		BIT(12)
--#define MT_TXD2_HDR_PAD			GENMASK(11, 10)
--#define MT_TXD2_RTS			BIT(9)
--#define MT_TXD2_OWN_MAC_MAP		BIT(8)
--#define MT_TXD2_BF_TYPE			GENMASK(6, 7)
--#define MT_TXD2_FRAME_TYPE		GENMASK(5, 4)
--#define MT_TXD2_SUB_TYPE		GENMASK(3, 0)
--
--#define MT_TXD3_SN_VALID		BIT(31)
--#define MT_TXD3_PN_VALID		BIT(30)
--#define MT_TXD3_SW_POWER_MGMT		BIT(29)
--#define MT_TXD3_BA_DISABLE		BIT(28)
--#define MT_TXD3_SEQ			GENMASK(27, 16)
--#define MT_TXD3_REM_TX_COUNT		GENMASK(15, 11)
--#define MT_TXD3_TX_COUNT		GENMASK(10, 6)
--#define MT_TXD3_HW_AMSDU		BIT(5)
--#define MT_TXD3_BCM			BIT(4)
--#define MT_TXD3_EEOSP			BIT(3)
--#define MT_TXD3_EMRD			BIT(2)
--#define MT_TXD3_PROTECT_FRAME		BIT(1)
--#define MT_TXD3_NO_ACK			BIT(0)
--
--#define MT_TXD4_PN_LOW			GENMASK(31, 0)
--
--#define MT_TXD5_PN_HIGH			GENMASK(31, 16)
--#define MT_TXD5_FL			BIT(15)
--#define MT_TXD5_BYPASS_TBB		BIT(14)
--#define MT_TXD5_BYPASS_RBB		BIT(13)
--#define MT_TXD5_BSS_COLOR_ZERO		BIT(12)
--#define MT_TXD5_TX_STATUS_HOST		BIT(10)
--#define MT_TXD5_TX_STATUS_MCU		BIT(9)
--#define MT_TXD5_TX_STATUS_FMT		BIT(8)
--#define MT_TXD5_PID			GENMASK(7, 0)
--
--#define MT_TXD6_TX_SRC			GENMASK(31, 30)
--#define MT_TXD6_VTA			BIT(28)
--#define MT_TXD6_BW			GENMASK(25, 22)
--#define MT_TXD6_TX_RATE			GENMASK(21, 16)
--#define MT_TXD6_TIMESTAMP_OFS_EN	BIT(15)
--#define MT_TXD6_TIMESTAMP_OFS_IDX	GENMASK(14, 10)
--#define MT_TXD6_MSDU_CNT		GENMASK(9, 4)
--#define MT_TXD6_DIS_MAT			BIT(3)
--#define MT_TXD6_DAS			BIT(2)
--#define MT_TXD6_AMSDU_CAP		BIT(1)
--
--#define MT_TXD7_TXD_LEN			GENMASK(31, 30)
--#define MT_TXD7_IP_SUM			BIT(29)
--#define MT_TXD7_DROP_BY_SDO		BIT(28)
--#define MT_TXD7_MAC_TXD			BIT(27)
--#define MT_TXD7_CTXD			BIT(26)
--#define MT_TXD7_CTXD_CNT		GENMASK(25, 22)
--#define MT_TXD7_UDP_TCP_SUM		BIT(15)
--#define MT_TXD7_TX_TIME			GENMASK(9, 0)
--
--#define MT_TX_RATE_STBC			BIT(14)
--#define MT_TX_RATE_NSS			GENMASK(13, 10)
--#define MT_TX_RATE_MODE			GENMASK(9, 6)
--#define MT_TX_RATE_SU_EXT_TONE		BIT(5)
--#define MT_TX_RATE_DCM			BIT(4)
--/* VHT/HE only use bits 0-3 */
--#define MT_TX_RATE_IDX			GENMASK(5, 0)
--
--#define MT_TXFREE0_PKT_TYPE		GENMASK(31, 27)
--#define MT_TXFREE0_MSDU_CNT		GENMASK(25, 16)
--#define MT_TXFREE0_RX_BYTE		GENMASK(15, 0)
--
--#define MT_TXFREE1_VER			GENMASK(18, 16)
--
--#define MT_TXFREE_INFO_PAIR		BIT(31)
--#define MT_TXFREE_INFO_HEADER		BIT(30)
--#define MT_TXFREE_INFO_WLAN_ID		GENMASK(23, 12)
--#define MT_TXFREE_INFO_MSDU_ID		GENMASK(14, 0)
--
--#define MT_TXS0_BW			GENMASK(31, 29)
--#define MT_TXS0_TID			GENMASK(28, 26)
--#define MT_TXS0_AMPDU			BIT(25)
--#define MT_TXS0_TXS_FORMAT		GENMASK(24, 23)
--#define MT_TXS0_BA_ERROR		BIT(22)
--#define MT_TXS0_PS_FLAG			BIT(21)
--#define MT_TXS0_TXOP_TIMEOUT		BIT(20)
--#define MT_TXS0_BIP_ERROR		BIT(19)
--
--#define MT_TXS0_QUEUE_TIMEOUT		BIT(18)
--#define MT_TXS0_RTS_TIMEOUT		BIT(17)
--#define MT_TXS0_ACK_TIMEOUT		BIT(16)
--#define MT_TXS0_ACK_ERROR_MASK		GENMASK(18, 16)
--
--#define MT_TXS0_TX_STATUS_HOST		BIT(15)
--#define MT_TXS0_TX_STATUS_MCU		BIT(14)
--#define MT_TXS0_TX_RATE			GENMASK(13, 0)
--
--#define MT_TXS1_SEQNO			GENMASK(31, 20)
--#define MT_TXS1_RESP_RATE		GENMASK(19, 16)
--#define MT_TXS1_RXV_SEQNO		GENMASK(15, 8)
--#define MT_TXS1_TX_POWER_DBM		GENMASK(7, 0)
--
--#define MT_TXS2_BF_STATUS		GENMASK(31, 30)
--#define MT_TXS2_BAND			GENMASK(29, 28)
--#define MT_TXS2_WCID			GENMASK(27, 16)
--#define MT_TXS2_TX_DELAY		GENMASK(15, 0)
--
--#define MT_TXS3_PID			GENMASK(31, 24)
--#define MT_TXS3_RATE_STBC		BIT(7)
--#define MT_TXS3_FIXED_RATE		BIT(6)
--#define MT_TXS3_SRC			GENMASK(5, 4)
--#define MT_TXS3_SHARED_ANTENNA		BIT(3)
--#define MT_TXS3_LAST_TX_RATE		GENMASK(2, 0)
--
--#define MT_TXS4_TIMESTAMP		GENMASK(31, 0)
--
--#define MT_TXS5_F0_FINAL_MPDU		BIT(31)
--#define MT_TXS5_F0_QOS			BIT(30)
--#define MT_TXS5_F0_TX_COUNT		GENMASK(29, 25)
--#define MT_TXS5_F0_FRONT_TIME		GENMASK(24, 0)
--#define MT_TXS5_F1_MPDU_TX_COUNT	GENMASK(31, 24)
--#define MT_TXS5_F1_MPDU_TX_BYTES	GENMASK(23, 0)
--
--#define MT_TXS6_F0_NOISE_3		GENMASK(31, 24)
--#define MT_TXS6_F0_NOISE_2		GENMASK(23, 16)
--#define MT_TXS6_F0_NOISE_1		GENMASK(15, 8)
--#define MT_TXS6_F0_NOISE_0		GENMASK(7, 0)
--#define MT_TXS6_F1_MPDU_FAIL_COUNT	GENMASK(31, 24)
--#define MT_TXS6_F1_MPDU_FAIL_BYTES	GENMASK(23, 0)
--
--#define MT_TXS7_F0_RCPI_3		GENMASK(31, 24)
--#define MT_TXS7_F0_RCPI_2		GENMASK(23, 16)
--#define MT_TXS7_F0_RCPI_1		GENMASK(15, 8)
--#define MT_TXS7_F0_RCPI_0		GENMASK(7, 0)
--#define MT_TXS7_F1_MPDU_RETRY_COUNT	GENMASK(31, 24)
--#define MT_TXS7_F1_MPDU_RETRY_BYTES	GENMASK(23, 0)
-+#include "../mt76_connac3_mac.h"
- 
- struct mt7996_dfs_pulse {
- 	u32 max_width;		/* us */
-diff --git a/mt7996/main.c b/mt7996/main.c
-index f306e9c5..c3a479dc 100644
---- a/mt7996/main.c
-+++ b/mt7996/main.c
-@@ -43,6 +43,10 @@ int mt7996_run(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;
-@@ -82,6 +86,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);
- 
- 	mutex_unlock(&dev->mt76.mutex);
-@@ -190,17 +196,13 @@ 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);
- 
- 	idx = MT7996_WTBL_RESERVED - mvif->mt76.idx;
- 
- 	INIT_LIST_HEAD(&mvif->sta.rc_list);
--	INIT_LIST_HEAD(&mvif->sta.poll_list);
-+	INIT_LIST_HEAD(&mvif->sta.wcid.poll_list);
- 	mvif->sta.wcid.idx = idx;
- 	mvif->sta.wcid.phy_idx = band_idx;
- 	mvif->sta.wcid.hw_key_idx = -1;
-@@ -221,9 +223,9 @@ static int mt7996_add_interface(struct ieee80211_hw *hw,
- 	vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
- 
- 	if (phy->mt76->chandef.chan->band != NL80211_BAND_2GHZ)
--		mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
-+		mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL + 4;
- 	else
--		mvif->basic_rates_idx = MT7996_BASIC_RATES_TBL;
-+		mvif->mt76.basic_rates_idx = MT7996_BASIC_RATES_TBL;
- 
- 	mt7996_init_bitrate_mask(vif);
- 
-@@ -253,7 +255,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);
- 
-@@ -262,10 +263,10 @@ static void mt7996_remove_interface(struct ieee80211_hw *hw,
- 	phy->omac_mask &= ~BIT_ULL(mvif->mt76.omac_idx);
- 	mutex_unlock(&dev->mt76.mutex);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- 
- 	mt76_packet_id_flush(&dev->mt76, &msta->wcid);
- }
-@@ -286,7 +287,6 @@ int mt7996_set_channel(struct mt7996_phy *phy)
- 	if (ret)
- 		goto out;
- 
--	mt7996_mac_set_timing(phy);
- 	ret = mt7996_dfs_init_radar_detector(phy);
- 	mt7996_mac_cca_stats_reset(phy);
- 
-@@ -505,7 +505,7 @@ static u8
- mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 		       bool beacon, bool mcast)
- {
--	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
- 	struct mt76_phy *mphy = hw->priv;
- 	u16 rate;
- 	u8 i, idx, ht;
-@@ -517,7 +517,7 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 		struct mt7996_dev *dev = mt7996_hw_dev(hw);
- 
- 		/* must odd index */
--		idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->mt76.idx % 20);
-+		idx = MT7996_BEACON_RATES_TBL + 2 * (mvif->idx % 20);
- 		mt7996_mac_set_fixed_rate_table(dev, idx, rate);
- 		return idx;
- 	}
-@@ -530,12 +530,32 @@ mt7996_get_rates_table(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 	return mvif->basic_rates_idx;
- }
- 
-+static void
-+mt7996_update_mu_group(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-+		       struct ieee80211_bss_conf *info)
-+{
-+	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt7996_dev *dev = mt7996_hw_dev(hw);
-+	u8 band = mvif->mt76.band_idx;
-+	u32 *mu;
-+
-+	mu = (u32 *)info->mu_group.membership;
-+	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD0(band), mu[0]);
-+	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_VLD1(band), mu[1]);
-+
-+	mu = (u32 *)info->mu_group.position;
-+	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS0(band), mu[0]);
-+	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS1(band), mu[1]);
-+	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS2(band), mu[2]);
-+	mt76_wr(dev, MT_WF_PHYRX_BAND_GID_TAB_POS3(band), mu[3]);
-+}
-+
- static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
- 				    struct ieee80211_vif *vif,
- 				    struct ieee80211_bss_conf *info,
- 				    u64 changed)
- {
--	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
- 	struct mt7996_phy *phy = mt7996_hw_phy(hw);
- 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
- 
-@@ -563,7 +583,7 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
- 
- 		if (slottime != phy->slottime) {
- 			phy->slottime = slottime;
--			mt7996_mac_set_timing(phy);
-+			mt7996_mcu_set_timing(phy, vif);
- 		}
- 	}
- 
-@@ -602,6 +622,9 @@ static void mt7996_bss_info_changed(struct ieee80211_hw *hw,
- 	    changed & BSS_CHANGED_FILS_DISCOVERY)
- 		mt7996_mcu_beacon_inband_discov(dev, vif, changed);
- 
-+	if (changed & BSS_CHANGED_MU_GROUPS)
-+		mt7996_update_mu_group(hw, vif, info);
-+
- 	mutex_unlock(&dev->mt76.mutex);
- }
- 
-@@ -631,7 +654,7 @@ int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 		return -ENOSPC;
- 
- 	INIT_LIST_HEAD(&msta->rc_list);
--	INIT_LIST_HEAD(&msta->poll_list);
-+	INIT_LIST_HEAD(&msta->wcid.poll_list);
- 	msta->vif = mvif;
- 	msta->wcid.sta = 1;
- 	msta->wcid.idx = idx;
-@@ -666,12 +689,12 @@ void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 	for (i = 0; i < ARRAY_SIZE(msta->twt.flow); i++)
- 		mt7996_mac_twt_teardown_flow(dev, msta, i);
- 
--	spin_lock_bh(&dev->sta_poll_lock);
--	if (!list_empty(&msta->poll_list))
--		list_del_init(&msta->poll_list);
-+	spin_lock_bh(&mdev->sta_poll_lock);
-+	if (!list_empty(&msta->wcid.poll_list))
-+		list_del_init(&msta->wcid.poll_list);
- 	if (!list_empty(&msta->rc_list))
- 		list_del_init(&msta->rc_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_unlock_bh(&mdev->sta_poll_lock);
- }
- 
- static void mt7996_tx(struct ieee80211_hw *hw,
-@@ -751,16 +774,16 @@ mt7996_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
- 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
- 		mtxq->aggr = false;
--		clear_bit(tid, &msta->ampdu_state);
-+		clear_bit(tid, &msta->wcid.ampdu_state);
- 		ret = mt7996_mcu_add_tx_ba(dev, params, false);
- 		break;
- 	case IEEE80211_AMPDU_TX_START:
--		set_bit(tid, &msta->ampdu_state);
-+		set_bit(tid, &msta->wcid.ampdu_state);
- 		ret = IEEE80211_AMPDU_TX_START_IMMEDIATE;
- 		break;
- 	case IEEE80211_AMPDU_TX_STOP_CONT:
- 		mtxq->aggr = false;
--		clear_bit(tid, &msta->ampdu_state);
-+		clear_bit(tid, &msta->wcid.ampdu_state);
- 		ret = mt7996_mcu_add_tx_ba(dev, params, false);
- 		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
- 		break;
-@@ -792,7 +815,7 @@ mt7996_get_stats(struct ieee80211_hw *hw,
- {
- 	struct mt7996_phy *phy = mt7996_hw_phy(hw);
- 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
--	struct mib_stats *mib = &phy->mib;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 
- 	mutex_lock(&dev->mt76.mutex);
- 
-@@ -903,7 +926,7 @@ mt7996_set_coverage_class(struct ieee80211_hw *hw, s16 coverage_class)
- 
- 	mutex_lock(&dev->mt76.mutex);
- 	phy->coverage_class = max_t(s16, coverage_class, 0);
--	mt7996_mac_set_timing(phy);
-+	mt7996_mac_set_coverage_class(phy);
- 	mutex_unlock(&dev->mt76.mutex);
- }
- 
-@@ -952,18 +975,19 @@ static void mt7996_sta_statistics(struct ieee80211_hw *hw,
- 	struct mt7996_sta *msta = (struct mt7996_sta *)sta->drv_priv;
- 	struct rate_info *txrate = &msta->wcid.rate;
- 
--	if (!txrate->legacy && !txrate->flags)
--		return;
--
--	if (txrate->legacy) {
--		sinfo->txrate.legacy = txrate->legacy;
--	} else {
--		sinfo->txrate.mcs = txrate->mcs;
--		sinfo->txrate.nss = txrate->nss;
--		sinfo->txrate.bw = txrate->bw;
--		sinfo->txrate.he_gi = txrate->he_gi;
--		sinfo->txrate.he_dcm = txrate->he_dcm;
--		sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
-+	if (txrate->legacy || txrate->flags) {
-+		if (txrate->legacy) {
-+			sinfo->txrate.legacy = txrate->legacy;
-+		} else {
-+			sinfo->txrate.mcs = txrate->mcs;
-+			sinfo->txrate.nss = txrate->nss;
-+			sinfo->txrate.bw = txrate->bw;
-+			sinfo->txrate.he_gi = txrate->he_gi;
-+			sinfo->txrate.he_dcm = txrate->he_dcm;
-+			sinfo->txrate.he_ru_alloc = txrate->he_ru_alloc;
-+		}
-+		sinfo->txrate.flags = txrate->flags;
-+		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
- 	}
- 	sinfo->txrate.flags = txrate->flags;
- 	sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_BITRATE);
-@@ -981,11 +1005,11 @@ static void mt7996_sta_rc_work(void *data, struct ieee80211_sta *sta)
- 	struct mt7996_dev *dev = msta->vif->phy->dev;
- 	u32 *changed = data;
- 
--	spin_lock_bh(&dev->sta_poll_lock);
-+	spin_lock_bh(&dev->mt76.sta_poll_lock);
- 	msta->changed |= *changed;
- 	if (list_empty(&msta->rc_list))
- 		list_add_tail(&msta->rc_list, &dev->sta_rc_list);
--	spin_unlock_bh(&dev->sta_poll_lock);
-+	spin_unlock_bh(&dev->mt76.sta_poll_lock);
- }
- 
- static void mt7996_sta_rc_update(struct ieee80211_hw *hw,
-@@ -1153,6 +1177,10 @@ static const char mt7996_gstrings_stats[][ETH_GSTRING_LEN] = {
- 	"v_tx_mcs_11",
- 	"v_tx_mcs_12",
- 	"v_tx_mcs_13",
-+	"v_tx_nss_1",
-+	"v_tx_nss_2",
-+	"v_tx_nss_3",
-+	"v_tx_nss_4",
- };
- 
- #define MT7996_SSTATS_LEN ARRAY_SIZE(mt7996_gstrings_stats)
-@@ -1186,7 +1214,7 @@ static void mt7996_ethtool_worker(void *wi_data, struct ieee80211_sta *sta)
- 	if (msta->vif->mt76.idx != wi->idx)
- 		return;
- 
--	mt76_ethtool_worker(wi, &msta->stats, true);
-+	mt76_ethtool_worker(wi, &msta->wcid.stats, true);
- }
- 
- static
-@@ -1197,11 +1225,11 @@ void mt7996_get_et_stats(struct ieee80211_hw *hw,
- 	struct mt7996_dev *dev = mt7996_hw_dev(hw);
- 	struct mt7996_phy *phy = mt7996_hw_phy(hw);
- 	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt76_mib_stats *mib = &phy->mib;
- 	struct mt76_ethtool_worker_info wi = {
- 		.data = data,
- 		.idx = mvif->mt76.idx,
- 	};
--	struct mib_stats *mib = &phy->mib;
- 	/* See mt7996_ampdu_stat_read_phy, etc */
- 	int i, ei = 0;
- 
-diff --git a/mt7996/mcu.c b/mt7996/mcu.c
-index 88e2f9d0..4a30db49 100644
---- a/mt7996/mcu.c
-+++ b/mt7996/mcu.c
-@@ -339,7 +339,11 @@ mt7996_mcu_rx_radar_detected(struct mt7996_dev *dev, struct sk_buff *skb)
- 	if (r->band_idx >= ARRAY_SIZE(dev->mt76.phys))
- 		return;
- 
--	mphy = dev->mt76.phys[r->band_idx];
-+	if (dev->rdd2_phy && r->band_idx == MT_RX_SEL2)
-+		mphy = dev->rdd2_phy->mt76;
-+	else
-+		mphy = dev->mt76.phys[r->band_idx];
-+
- 	if (!mphy)
- 		return;
- 
-@@ -600,7 +604,7 @@ static void
- mt7996_mcu_bss_bmc_tlv(struct sk_buff *skb, struct ieee80211_vif *vif,
- 		       struct mt7996_phy *phy)
- {
--	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt76_vif *mvif = (struct mt76_vif *)vif->drv_priv;
- 	struct bss_rate_tlv *bmc;
- 	struct cfg80211_chan_def *chandef = &phy->mt76->chandef;
- 	enum nl80211_band band = chandef->chan->band;
-@@ -701,6 +705,34 @@ mt7996_mcu_muar_config(struct mt7996_phy *phy, struct ieee80211_vif *vif,
- 				 sizeof(req), true);
- }
- 
-+static void
-+mt7996_mcu_bss_ifs_timing_tlv(struct sk_buff *skb, struct ieee80211_vif *vif)
-+{
-+	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt7996_phy *phy = mvif->phy;
-+	struct bss_ifs_time_tlv *ifs_time;
-+	struct tlv *tlv;
-+	bool is_2ghz = phy->mt76->chandef.chan->band == NL80211_BAND_2GHZ;
-+
-+	tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_IFS_TIME, sizeof(*ifs_time));
-+
-+	ifs_time = (struct bss_ifs_time_tlv *)tlv;
-+	ifs_time->slot_valid = true;
-+	ifs_time->sifs_valid = true;
-+	ifs_time->rifs_valid = true;
-+	ifs_time->eifs_valid = true;
-+
-+	ifs_time->slot_time = cpu_to_le16(phy->slottime);
-+	ifs_time->sifs_time = cpu_to_le16(10);
-+	ifs_time->rifs_time = cpu_to_le16(2);
-+	ifs_time->eifs_time = cpu_to_le16(is_2ghz ? 78 : 84);
-+
-+	if (is_2ghz) {
-+		ifs_time->eifs_cck_valid = true;
-+		ifs_time->eifs_cck_time = cpu_to_le16(314);
-+	}
-+}
-+
- static int
- mt7996_mcu_bss_basic_tlv(struct sk_buff *skb,
- 			 struct ieee80211_vif *vif,
-@@ -712,6 +744,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;
- 
-@@ -731,7 +764,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();
- 		}
-@@ -751,7 +784,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;
-@@ -825,6 +858,7 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy,
- 		mt7996_mcu_bss_bmc_tlv(skb, vif, phy);
- 		mt7996_mcu_bss_ra_tlv(skb, vif, phy);
- 		mt7996_mcu_bss_txcmd_tlv(skb, true);
-+		mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
- 
- 		if (vif->bss_conf.he_support)
- 			mt7996_mcu_bss_he_tlv(skb, vif, phy);
-@@ -837,6 +871,23 @@ out:
- 				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
- }
- 
-+int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif)
-+{
-+	struct mt7996_vif *mvif = (struct mt7996_vif *)vif->drv_priv;
-+	struct mt7996_dev *dev = phy->dev;
-+	struct sk_buff *skb;
-+
-+	skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &mvif->mt76,
-+					 MT7996_BSS_UPDATE_MAX_SIZE);
-+	if (IS_ERR(skb))
-+		return PTR_ERR(skb);
-+
-+	mt7996_mcu_bss_ifs_timing_tlv(skb, vif);
-+
-+	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
-+				     MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
-+}
-+
- static int
- mt7996_mcu_sta_ba(struct mt76_dev *dev, struct mt76_vif *mvif,
- 		  struct ieee80211_ampdu_params *params,
-@@ -1050,6 +1101,59 @@ mt7996_mcu_sta_amsdu_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
- 	}
- }
- 
-+static void
-+mt7996_mcu_sta_muru_tlv(struct mt7996_dev *dev, struct sk_buff *skb,
-+			struct ieee80211_vif *vif, struct ieee80211_sta *sta)
-+{
-+	struct ieee80211_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 = vif->bss_conf.eht_mu_beamformer ||
-+			       vif->bss_conf.he_mu_beamformer ||
-+			       vif->bss_conf.vht_mu_beamformer ||
-+			       vif->bss_conf.vht_mu_beamformee;
-+	muru->cfg.ofdma_dl_en = true;
-+
-+	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)
-@@ -1727,7 +1831,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 */
-@@ -2155,7 +2260,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;
-@@ -2167,8 +2272,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);
- 
-@@ -2195,19 +2302,22 @@ 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);
- }
- 
--static int mt7996_load_ram(struct mt7996_dev *dev)
-+static int __mt7996_load_ram(struct mt7996_dev *dev, const char *fw_type,
-+			     const char *fw_file, enum mt7996_ram_type ram_type)
- {
- 	const struct mt7996_fw_trailer *hdr;
- 	const struct firmware *fw;
- 	int ret;
- 
--	ret = request_firmware(&fw, MT7996_FIRMWARE_WM, dev->mt76.dev);
-+	ret = request_firmware(&fw, fw_file, dev->mt76.dev);
- 	if (ret)
- 		return ret;
- 
-@@ -2217,37 +2327,13 @@ static int mt7996_load_ram(struct mt7996_dev *dev)
- 		goto out;
- 	}
- 
--	hdr = (const struct mt7996_fw_trailer *)(fw->data + fw->size - sizeof(*hdr));
-+	hdr = (const void *)(fw->data + fw->size - sizeof(*hdr));
-+	dev_info(dev->mt76.dev, "%s Firmware Version: %.10s, Build Time: %.15s\n",
-+		 fw_type, hdr->fw_ver, hdr->build_date);
- 
--	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);
-+	ret = mt7996_mcu_send_ram_firmware(dev, hdr, fw->data, ram_type);
- 	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");
-+		dev_err(dev->mt76.dev, "Failed to start %s firmware\n", fw_type);
- 		goto out;
- 	}
- 
-@@ -2261,6 +2347,24 @@ out:
- 	return ret;
- }
- 
-+static int mt7996_load_ram(struct mt7996_dev *dev)
-+{
-+	int ret;
-+
-+	ret = __mt7996_load_ram(dev, "WM", MT7996_FIRMWARE_WM,
-+				MT7996_RAM_TYPE_WM);
-+	if (ret)
-+		return ret;
-+
-+	ret = __mt7996_load_ram(dev, "DSP", MT7996_FIRMWARE_DSP,
-+				MT7996_RAM_TYPE_DSP);
-+	if (ret)
-+		return ret;
-+
-+	return __mt7996_load_ram(dev, "WA", MT7996_FIRMWARE_WA,
-+				 MT7996_RAM_TYPE_WA);
-+}
-+
- static int
- mt7996_firmware_state(struct mt7996_dev *dev, bool wa)
- {
-diff --git a/mt7996/mcu.h b/mt7996/mcu.h
-index d7075a4d..078f8285 100644
---- a/mt7996/mcu.h
-+++ b/mt7996/mcu.h
-@@ -317,6 +317,22 @@ struct bss_sec_tlv {
- 	u8 __rsv2[1];
- } __packed;
- 
-+struct bss_ifs_time_tlv {
-+	__le16 tag;
-+	__le16 len;
-+	u8 slot_valid;
-+	u8 sifs_valid;
-+	u8 rifs_valid;
-+	u8 eifs_valid;
-+	__le16 slot_time;
-+	__le16 sifs_time;
-+	__le16 rifs_time;
-+	__le16 eifs_time;
-+	u8 eifs_cck_valid;
-+	u8 rsv;
-+	__le16 eifs_cck_time;
-+} __packed;
-+
- struct bss_power_save {
- 	__le16 tag;
- 	__le16 len;
-@@ -552,6 +568,7 @@ enum {
- 					 sizeof(struct bss_txcmd_tlv) +		\
- 					 sizeof(struct bss_power_save) +	\
- 					 sizeof(struct bss_sec_tlv) +		\
-+					 sizeof(struct bss_ifs_time_tlv) +	\
- 					 sizeof(struct bss_mld_tlv))
- 
- #define MT7996_STA_UPDATE_MAX_SIZE	(sizeof(struct sta_req_hdr) +		\
-diff --git a/mt7996/mt7996.h b/mt7996/mt7996.h
-index 4d7dcb95..726c222e 100644
---- a/mt7996/mt7996.h
-+++ b/mt7996/mt7996.h
-@@ -26,15 +26,17 @@
- 
- #define MT7996_RX_RING_SIZE		1536
- #define MT7996_RX_MCU_RING_SIZE		512
-+#define MT7996_RX_MCU_RING_SIZE_WA	1024
- 
- #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"
- #define MT7996_EEPROM_SIZE		7680
- #define MT7996_EEPROM_BLOCK_SIZE	16
--#define MT7996_TOKEN_SIZE		8192
-+#define MT7996_TOKEN_SIZE		16384
- 
- #define MT7996_CFEND_RATE_DEFAULT	0x49	/* OFDM 24M */
- #define MT7996_CFEND_RATE_11B		0x03	/* 11B LP, 11M */
-@@ -52,6 +54,12 @@ struct mt7996_sta;
- struct mt7996_dfs_pulse;
- struct mt7996_dfs_pattern;
- 
-+enum mt7996_ram_type {
-+	MT7996_RAM_TYPE_WM,
-+	MT7996_RAM_TYPE_WA,
-+	MT7996_RAM_TYPE_DSP,
-+};
-+
- enum mt7996_txq_id {
- 	MT7996_TXQ_FWDL = 16,
- 	MT7996_TXQ_MCU_WM,
-@@ -95,7 +103,6 @@ struct mt7996_sta {
- 
- 	struct mt7996_vif *vif;
- 
--	struct list_head poll_list;
- 	struct list_head rc_list;
- 	u32 airtime_ac[8];
- 
-@@ -104,9 +111,6 @@ struct mt7996_sta {
- 
- 	unsigned long changed;
- 	unsigned long jiffies;
--	unsigned long ampdu_state;
--
--	struct mt76_sta_stats stats;
- 
- 	struct mt76_connac_sta_key_conf bip;
- 
-@@ -124,64 +128,6 @@ struct mt7996_vif {
- 
- 	struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
- 	struct cfg80211_bitrate_mask bitrate_mask;
--
--	u8 basic_rates_idx;
--	u8 mcast_rates_idx;
--	u8 beacon_rates_idx;
--};
--
--/* per-phy stats.  */
--struct mib_stats {
--	u32 ack_fail_cnt;
--	u32 fcs_err_cnt;
--	u32 rts_cnt;
--	u32 rts_retries_cnt;
--	u32 ba_miss_cnt;
--	u32 tx_mu_bf_cnt;
--	u32 tx_mu_mpdu_cnt;
--	u32 tx_mu_acked_mpdu_cnt;
--	u32 tx_su_acked_mpdu_cnt;
--	u32 tx_bf_ibf_ppdu_cnt;
--	u32 tx_bf_ebf_ppdu_cnt;
--
--	u32 tx_bf_rx_fb_all_cnt;
--	u32 tx_bf_rx_fb_eht_cnt;
--	u32 tx_bf_rx_fb_he_cnt;
--	u32 tx_bf_rx_fb_vht_cnt;
--	u32 tx_bf_rx_fb_ht_cnt;
--
--	u32 tx_bf_rx_fb_bw; /* value of last sample, not cumulative */
--	u32 tx_bf_rx_fb_nc_cnt;
--	u32 tx_bf_rx_fb_nr_cnt;
--	u32 tx_bf_fb_cpl_cnt;
--	u32 tx_bf_fb_trig_cnt;
--
--	u32 tx_ampdu_cnt;
--	u32 tx_stop_q_empty_cnt;
--	u32 tx_mpdu_attempts_cnt;
--	u32 tx_mpdu_success_cnt;
--	/* BF counter is PPDU-based, so remove MPDU-based BF counter */
--
--	u32 tx_rwp_fail_cnt;
--	u32 tx_rwp_need_cnt;
--
--	/* rx stats */
--	u32 rx_fifo_full_cnt;
--	u32 channel_idle_cnt;
--	u32 rx_vector_mismatch_cnt;
--	u32 rx_delimiter_fail_cnt;
--	u32 rx_len_mismatch_cnt;
--	u32 rx_mpdu_cnt;
--	u32 rx_ampdu_cnt;
--	u32 rx_ampdu_bytes_cnt;
--	u32 rx_ampdu_valid_subframe_cnt;
--	u32 rx_ampdu_valid_subframe_bytes_cnt;
--	u32 rx_pfdrop_cnt;
--	u32 rx_vec_queue_overflow_drop_cnt;
--	u32 rx_ba_cnt;
--
--	u32 tx_amsdu[8];
--	u32 tx_amsdu_cnt;
- };
- 
- /* crash-dump */
-@@ -222,7 +168,7 @@ struct mt7996_phy {
- 	u32 rx_ampdu_ts;
- 	u32 ampdu_ref;
- 
--	struct mib_stats mib;
-+	struct mt76_mib_stats mib;
- 	struct mt76_channel_state state_ts;
- };
- 
-@@ -272,9 +218,7 @@ struct mt7996_dev {
- #endif
- 
- 	struct list_head sta_rc_list;
--	struct list_head sta_poll_list;
- 	struct list_head twt_list;
--	spinlock_t sta_poll_lock;
- 
- 	u32 hw_pattern;
- 
-@@ -405,6 +349,7 @@ int mt7996_dma_init(struct mt7996_dev *dev);
- void mt7996_dma_reset(struct mt7996_dev *dev, bool force);
- void mt7996_dma_prefetch(struct mt7996_dev *dev);
- void mt7996_dma_cleanup(struct mt7996_dev *dev);
-+void mt7996_dma_start(struct mt7996_dev *dev, bool reset);
- void mt7996_init_txpower(struct mt7996_dev *dev,
- 			 struct ieee80211_supported_band *sband);
- int mt7996_txbf_init(struct mt7996_dev *dev);
-@@ -456,6 +401,7 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
- 			    const struct mt7996_dfs_pattern *pattern);
- int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
- int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
-+int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif);
- int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
- int mt7996_mcu_rdd_cmd(struct mt7996_dev *dev, int cmd, u8 index,
- 		       u8 rx_sel, u8 val);
-@@ -519,7 +465,7 @@ void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
- 			   struct sk_buff *skb, struct mt76_wcid *wcid,
- 			   struct ieee80211_key_conf *key, int pid,
- 			   enum mt76_txq_id qid, u32 changed);
--void mt7996_mac_set_timing(struct mt7996_phy *phy);
-+void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
- int mt7996_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
- 		       struct ieee80211_sta *sta);
- void mt7996_mac_sta_remove(struct mt76_dev *mdev, struct ieee80211_vif *vif,
-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);
-diff --git a/mt7996/regs.h b/mt7996/regs.h
-index d1d3d154..97beab92 100644
---- a/mt7996/regs.h
-+++ b/mt7996/regs.h
-@@ -557,22 +557,29 @@ enum base_rev {
- 
- #define MT_PCIE1_MAC_INT_ENABLE			MT_PCIE1_MAC(0x188)
- 
-+/* PHYRX CSD */
-+#define MT_WF_PHYRX_CSD_BASE			0x83000000
-+#define MT_WF_PHYRX_CSD(_band, _wf, ofs)	(MT_WF_PHYRX_CSD_BASE + \
-+						 ((_band) << 20) + \
-+						 ((_wf) << 16) + (ofs))
-+#define MT_WF_PHYRX_CSD_IRPI(_band, _wf)	MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
-+
- /* PHYRX CTRL */
- #define MT_WF_PHYRX_BAND_BASE			0x83080000
- #define MT_WF_PHYRX_BAND(_band, ofs)		(MT_WF_PHYRX_BAND_BASE + \
- 						 ((_band) << 20) + (ofs))
- 
-+#define MT_WF_PHYRX_BAND_GID_TAB_VLD0(_band)	MT_WF_PHYRX_BAND(_band, 0x1054)
-+#define MT_WF_PHYRX_BAND_GID_TAB_VLD1(_band)	MT_WF_PHYRX_BAND(_band, 0x1058)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS0(_band)	MT_WF_PHYRX_BAND(_band, 0x105c)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS1(_band)	MT_WF_PHYRX_BAND(_band, 0x1060)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS2(_band)	MT_WF_PHYRX_BAND(_band, 0x1064)
-+#define MT_WF_PHYRX_BAND_GID_TAB_POS3(_band)	MT_WF_PHYRX_BAND(_band, 0x1068)
-+
- #define MT_WF_PHYRX_BAND_RX_CTRL1(_band)	MT_WF_PHYRX_BAND(_band, 0x2004)
- #define MT_WF_PHYRX_BAND_RX_CTRL1_IPI_EN	GENMASK(2, 0)
- #define MT_WF_PHYRX_BAND_RX_CTRL1_STSCNT_EN	GENMASK(11, 9)
- 
--/* PHYRX CSD */
--#define MT_WF_PHYRX_CSD_BASE			0x83000000
--#define MT_WF_PHYRX_CSD(_band, _wf, ofs)	(MT_WF_PHYRX_CSD_BASE + \
--						 ((_band) << 20) + \
--						 ((_wf) << 16) + (ofs))
--#define MT_WF_PHYRX_CSD_IRPI(_band, _wf)	MT_WF_PHYRX_CSD(_band, _wf, 0x1000)
--
- /* PHYRX CSD BAND */
- #define MT_WF_PHYRX_CSD_BAND_RXTD12(_band)		MT_WF_PHYRX_BAND(_band, 0x8230)
- #define MT_WF_PHYRX_CSD_BAND_RXTD12_IRPI_SW_CLR_ONLY	BIT(18)
-diff --git a/tx.c b/tx.c
-index 72b3ec71..6cc26cc6 100644
---- a/tx.c
-+++ b/tx.c
-@@ -121,6 +121,7 @@ int
- mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
- 		       struct sk_buff *skb)
- {
-+	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- 	struct mt76_tx_cb *cb = mt76_tx_skb_cb(skb);
- 	int pid;
-@@ -134,8 +135,14 @@ mt76_tx_status_skb_add(struct mt76_dev *dev, struct mt76_wcid *wcid,
- 		return MT_PACKET_ID_NO_ACK;
- 
- 	if (!(info->flags & (IEEE80211_TX_CTL_REQ_TX_STATUS |
--			     IEEE80211_TX_CTL_RATE_CTRL_PROBE)))
-+			     IEEE80211_TX_CTL_RATE_CTRL_PROBE))) {
-+		if (mtk_wed_device_active(&dev->mmio.wed) &&
-+		    ((info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) ||
-+		     ieee80211_is_data(hdr->frame_control)))
-+			return MT_PACKET_ID_WED;
-+
- 		return MT_PACKET_ID_NO_SKB;
-+	}
- 
- 	spin_lock_bh(&dev->status_lock);
- 
-@@ -263,8 +270,15 @@ void __mt76_tx_complete_skb(struct mt76_dev *dev, u16 wcid_idx, struct sk_buff *
- #endif
- 
- 	if (cb->pktid < MT_PACKET_ID_FIRST) {
-+		struct ieee80211_rate_status rs = {};
-+
- 		hw = mt76_tx_status_get_hw(dev, skb);
- 		status.sta = wcid_to_sta(wcid);
-+		if (status.sta && (wcid->rate.flags || wcid->rate.legacy)) {
-+			rs.rate_idx = wcid->rate;
-+			status.rates = &rs;
-+			status.n_rates = 1;
-+		}
- 		spin_lock_bh(&dev->rx_lock);
- 		ieee80211_tx_status_ext(hw, &status);
- 		spin_unlock_bh(&dev->rx_lock);
--- 
-2.18.0
-
diff --git a/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-Update-beacon-size-limitation-for-1.patch b/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-Update-beacon-size-limitation-for-1.patch
index 1cce8bc..3cae6ed 100644
--- a/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-Update-beacon-size-limitation-for-1.patch
+++ b/recipes-wifi/linux-mt76/files/patches/0001-wifi-mt76-mt7915-Update-beacon-size-limitation-for-1.patch
@@ -1,7 +1,7 @@
-From 478585697afd695e4c55bc1a805523d2f7fb572c Mon Sep 17 00:00:00 2001
+From de01138c9689f49a30908dfb2657fee979b738a2 Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Thu, 23 Mar 2023 08:49:48 +0800
-Subject: [PATCH 1/7] wifi: mt76: mt7915: Update beacon size limitation for 11v
+Subject: [PATCH] wifi: mt76: mt7915: Update beacon size limitation for 11v
 
 Separate the beacon offload command into two;
 one is for beacons and the other is for inband discovery frames.
@@ -21,10 +21,10 @@
  4 files changed, 45 insertions(+), 33 deletions(-)
 
 diff --git a/mt7915/main.c b/mt7915/main.c
-index ca5631f..0d94090 100644
+index 33bfa4a..f741517 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
-@@ -640,11 +640,13 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
+@@ -645,11 +645,13 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
  		mt7915_update_bss_color(hw, vif, &info->he_bss_color);
  
  	if (changed & (BSS_CHANGED_BEACON |
@@ -38,14 +38,14 @@
 +		       BSS_CHANGED_FILS_DISCOVERY))
 +		mt7915_mcu_add_inband_discov(dev, vif, changed);
 +
- 	mutex_unlock(&dev->mt76.mutex);
- }
- 
+ 	if (set_bss_info == 0)
+ 		mt7915_mcu_add_bss_info(phy, vif, false);
+ 	if (set_sta == 0)
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 71eeb54..5661df4 100644
+index b0328d4..79d2354 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -1879,10 +1879,9 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+@@ -1882,10 +1882,9 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
  }
  
@@ -59,7 +59,7 @@
  {
  #define OFFLOAD_TX_MODE_SU	BIT(0)
  #define OFFLOAD_TX_MODE_MU	BIT(1)
-@@ -1892,14 +1891,28 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+@@ -1895,14 +1894,28 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
  	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
  	enum nl80211_band band = chandef->chan->band;
  	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
@@ -90,7 +90,7 @@
  	if (changed & BSS_CHANGED_FILS_DISCOVERY &&
  	    vif->bss_conf.fils_discovery.max_interval) {
  		interval = vif->bss_conf.fils_discovery.max_interval;
-@@ -1911,26 +1924,25 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+@@ -1914,26 +1927,25 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
  	}
  
  	if (!skb)
@@ -123,7 +123,7 @@
  	discov->tx_mode = OFFLOAD_TX_MODE_SU;
  	/* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
  	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
-@@ -1938,13 +1950,16 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+@@ -1941,13 +1953,16 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
  	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
  	discov->enable = true;
  
@@ -141,7 +141,7 @@
  }
  
  int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-@@ -1980,7 +1995,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -1983,7 +1998,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  	if (!skb)
  		return -EINVAL;
  
@@ -150,7 +150,7 @@
  		dev_err(dev->mt76.dev, "Bcn size limit exceed\n");
  		dev_kfree_skb(skb);
  		return -EINVAL;
-@@ -1994,11 +2009,6 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -1997,11 +2012,6 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  	mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
  	dev_kfree_skb(skb);
  
@@ -199,10 +199,10 @@
  mt7915_get_power_bound(struct mt7915_phy *phy, s8 txpower)
  {
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 0c7226b..fe46a36 100644
+index 0456e56..21984e9 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
-@@ -433,6 +433,8 @@ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
+@@ -447,6 +447,8 @@ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
  			 bool add);
  int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  				struct cfg80211_he_bss_color *he_bss_color);
diff --git a/recipes-wifi/linux-mt76/files/patches/0002-wifi-mt76-mt7915-fix-the-beamformer-issue.patch b/recipes-wifi/linux-mt76/files/patches/0002-wifi-mt76-mt7915-fix-the-beamformer-issue.patch
index b5df657..cb4d246 100644
--- a/recipes-wifi/linux-mt76/files/patches/0002-wifi-mt76-mt7915-fix-the-beamformer-issue.patch
+++ b/recipes-wifi/linux-mt76/files/patches/0002-wifi-mt76-mt7915-fix-the-beamformer-issue.patch
@@ -1,7 +1,7 @@
-From ba388175c8a0ecfc3264389cb4d2c49ed2c8b557 Mon Sep 17 00:00:00 2001
+From c3596dc615aed0ff22fe5eecc2962d5003deaeaa Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Wed, 12 Apr 2023 15:53:42 +0800
-Subject: [PATCH 2/7] wifi: mt76: mt7915: fix the beamformer issue
+Subject: [PATCH] wifi: mt76: mt7915: fix the beamformer issue
 
 without this patch, when ap sets the tx stream number to 2,
 ap doesn't send any beamform packets.
@@ -12,13 +12,13 @@
  1 file changed, 2 insertions(+), 2 deletions(-)
 
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 5661df4..e820de6 100644
+index 79d2354..f2ffa6c 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -1012,13 +1012,13 @@ static inline bool
- mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+@@ -1015,13 +1015,13 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
  			struct ieee80211_sta *sta, bool bfee)
  {
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 -	int tx_ant = hweight8(phy->mt76->chainmask) - 1;
 +	int sts = hweight16(phy->mt76->chainmask);
  
diff --git a/recipes-wifi/linux-mt76/files/patches/0999-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch b/recipes-wifi/linux-mt76/files/patches/0999-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch
index aa3146d..a1c270f 100644
--- a/recipes-wifi/linux-mt76/files/patches/0999-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch
+++ b/recipes-wifi/linux-mt76/files/patches/0999-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch
@@ -1,8 +1,7 @@
-From 99a1f11d07da770d1da5278ac751ccc3f44eb72f Mon Sep 17 00:00:00 2001
+From 8f28d9cd21c2818902cd9bfe0d1cfed81401bcb9 Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Wed, 22 Jun 2022 10:39:47 +0800
-Subject: [PATCH 0999/1031] wifi: mt76: mt7915: add mtk internal debug tools
- for mt76
+Subject: [PATCH] wifi: mt76: mt7915: add mtk internal debug tools for mt76
 
 ---
  mt76_connac_mcu.h     |    6 +
@@ -271,7 +270,7 @@
  }
  
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 251df80..cc4ac94 100644
+index e403cd8..aa6a294 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -73,7 +73,11 @@ int mt7915_run(struct ieee80211_hw *hw)
@@ -287,7 +286,7 @@
  		goto out;
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 6cf2a3f..fbbd848 100644
+index 146c3d6..d30923a 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -205,6 +205,11 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -302,7 +301,7 @@
  	return mt76_tx_queue_skb_raw(dev, mdev->q_mcu[qid], skb, 0);
  }
  
-@@ -2285,7 +2290,10 @@ static int mt7915_red_set_watermark(struct mt7915_dev *dev)
+@@ -2288,7 +2293,10 @@ static int mt7915_red_set_watermark(struct mt7915_dev *dev)
  				 sizeof(req), false);
  }
  
@@ -314,7 +313,7 @@
  {
  #define RED_DISABLE		0
  #define RED_BY_WA_ENABLE	2
-@@ -3349,6 +3357,8 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
+@@ -3352,6 +3360,8 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
  		.sku_enable = enable,
  	};
  
@@ -323,7 +322,7 @@
  	return mt76_mcu_send_msg(&dev->mt76,
  				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
  				 sizeof(req), true);
-@@ -4003,6 +4013,23 @@ out:
+@@ -4006,6 +4016,23 @@ out:
  	return ret;
  }
  
@@ -347,7 +346,7 @@
  int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
  {
  	struct {
-@@ -4031,3 +4058,22 @@ int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
+@@ -4034,3 +4061,22 @@ int mt7915_mcu_rf_regval(struct mt7915_dev *dev, u32 regidx, u32 *val, bool set)
  
  	return 0;
  }
@@ -386,7 +385,7 @@
  };
  
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 4de3e05..b5e7c86 100644
+index eb66fcd..51e1301 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -9,6 +9,7 @@
@@ -397,7 +396,7 @@
  #define MT7915_MAX_INTERFACES		19
  #define MT7915_WTBL_SIZE		288
  #define MT7916_WTBL_SIZE		544
-@@ -305,6 +306,28 @@ struct mt7915_dev {
+@@ -319,6 +320,28 @@ struct mt7915_dev {
  	struct reset_control *rstc;
  	void __iomem *dcm;
  	void __iomem *sku;
@@ -426,7 +425,7 @@
  };
  
  enum {
-@@ -585,4 +608,24 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -599,4 +622,24 @@ void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
  			 bool pci, int *irq);
  
@@ -1877,7 +1876,7 @@
 +#endif
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
 new file mode 100644
-index 0000000..70e4cb2
+index 0000000..5a5f14d
 --- /dev/null
 +++ b/mt7915/mtk_debugfs.c
 @@ -0,0 +1,3624 @@
@@ -4809,7 +4808,7 @@
 +{
 +	struct mt7915_dev *dev = dev_get_drvdata(s->private);
 +	struct mt76_dev *mdev = NULL;
-+	seq_printf(s, "Version: 2.2.11.0\n");
++	seq_printf(s, "Version: 2.2.12.0\n");
 +
 +	if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
 +		return 0;
diff --git a/recipes-wifi/linux-mt76/files/patches/1002-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch b/recipes-wifi/linux-mt76/files/patches/1002-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch
index 7787604..339dd36 100644
--- a/recipes-wifi/linux-mt76/files/patches/1002-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1002-wifi-mt76-mt7915-add-support-for-muru_onoff-via.patch
@@ -1,7 +1,7 @@
-From c79fc4ca594e0c4506d8601243523476b47a13eb Mon Sep 17 00:00:00 2001
+From 790ec4b2acef90cb57142b117c12aca25fa5ea41 Mon Sep 17 00:00:00 2001
 From: Evelyn Tsai <evelyn.tsai@mediatek.com>
 Date: Tue, 4 Apr 2023 02:23:57 +0800
-Subject: [PATCH 1002/1031] wifi: mt76: mt7915: add support for muru_onoff via
+Subject: [PATCH] wifi: mt76: mt7915: add support for muru_onoff via
 
 ---
  mt7915/init.c        |  2 ++
@@ -25,26 +25,26 @@
  
  static void
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 4ef5190..a4a8194 100644
+index 1dd7863..4148bcd 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -870,6 +870,7 @@ static void
- mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
- 			struct ieee80211_sta *sta, struct ieee80211_vif *vif)
+@@ -873,6 +873,7 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  {
-+	struct mt7915_phy *phy = mvif->phy;
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
  	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
++	struct mt7915_phy *phy = mvif->phy;
  	struct sta_rec_muru *muru;
  	struct tlv *tlv;
-@@ -882,13 +883,18 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+ 
+@@ -884,13 +885,18 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  
  	muru = (struct sta_rec_muru *)tlv;
  
--	muru->cfg.mimo_dl_en = vif->bss_conf.he_mu_beamformer ||
-+	muru->cfg.mimo_dl_en = (vif->bss_conf.he_mu_beamformer ||
- 			       vif->bss_conf.vht_mu_beamformer ||
--			       vif->bss_conf.vht_mu_beamformee;
-+			       vif->bss_conf.vht_mu_beamformee) &&
+-	muru->cfg.mimo_dl_en = mvif->cap.he_mu_ebfer ||
++	muru->cfg.mimo_dl_en = (mvif->cap.he_mu_ebfer ||
+ 			       mvif->cap.vht_mu_ebfer ||
+-			       mvif->cap.vht_mu_ebfee;
++			       mvif->cap.vht_mu_ebfee) &&
 +			       !!(phy->muru_onoff & MUMIMO_DL);
  	if (!is_mt7915(&dev->mt76))
  		muru->cfg.mimo_ul_en = true;
@@ -73,10 +73,10 @@
 +
  #endif
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 7a9752f..2befa44 100644
+index 01d487c..1663814 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
-@@ -238,6 +238,8 @@ struct mt7915_phy {
+@@ -252,6 +252,8 @@ struct mt7915_phy {
  	u32 rx_ampdu_ts;
  	u32 ampdu_ref;
  
@@ -86,7 +86,7 @@
  	struct mt76_channel_state state_ts;
  
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 70e4cb2..e5fb2ce 100644
+index 5a5f14d..41148c0 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
 @@ -2558,6 +2558,38 @@ static int mt7915_token_txd_read(struct seq_file *s, void *data)
diff --git a/recipes-wifi/linux-mt76/files/patches/1024-wifi-mt76-mt7915-add-bf-backoff-limit-table-support.patch b/recipes-wifi/linux-mt76/files/patches/1024-wifi-mt76-mt7915-add-bf-backoff-limit-table-support.patch
index 17a1e96..a4d902b 100644
--- a/recipes-wifi/linux-mt76/files/patches/1024-wifi-mt76-mt7915-add-bf-backoff-limit-table-support.patch
+++ b/recipes-wifi/linux-mt76/files/patches/1024-wifi-mt76-mt7915-add-bf-backoff-limit-table-support.patch
@@ -1,4 +1,4 @@
-From 960329a1e103dd6ce72f5c866c8f925b905cca76 Mon Sep 17 00:00:00 2001
+From 9f9789d20b4956a7987409eeeb260c8977ddc0ff Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Mon, 5 Dec 2022 18:21:51 +0800
 Subject: [PATCH 1024/1031] wifi: mt76: mt7915: add bf backoff limit table
@@ -6,19 +6,30 @@
 
 Signed-off-by: Shayne Chen <shayne.chen@mediatek.com>
 ---
- eeprom.c         |  25 +++++++++-
+ eeprom.c         |  36 +++++++++++--
  mt76.h           |   8 +++
- mt7915/debugfs.c |  73 ++++++++++++++++++++++++++--
- mt7915/mcu.c     | 124 +++++++++++++++++++++++++++++++++++------------
+ mt7915/debugfs.c |  73 ++++++++++++++++++++++++--
+ mt7915/main.c    |   1 +
+ mt7915/mcu.c     | 132 ++++++++++++++++++++++++++++++++++++-----------
  mt7915/mcu.h     |   6 +++
  mt7915/mt7915.h  |   4 +-
- 6 files changed, 203 insertions(+), 37 deletions(-)
+ 7 files changed, 221 insertions(+), 39 deletions(-)
 
 diff --git a/eeprom.c b/eeprom.c
-index 412740f..b2df0f4 100644
+index 412740f..0e0c960 100644
 --- a/eeprom.c
 +++ b/eeprom.c
-@@ -317,7 +317,8 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+@@ -311,13 +311,17 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+ 	u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
+ 	char band;
+ 	size_t len;
+-	s8 max_power = 0;
++	s8 max_power = -127;
++	s8 max_power_backoff = -127;
+ 	s8 txs_delta;
++	int n_chains = hweight8(phy->antenna_mask);
++	s8 target_power_combine = target_power + mt76_tx_power_nss_delta(n_chains);
+ 
  	if (!mcs_rates)
  		mcs_rates = 10;
  
@@ -28,35 +39,41 @@
  
  	if (!IS_ENABLED(CONFIG_OF))
  		return target_power;
-@@ -370,6 +371,28 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
+@@ -370,7 +374,33 @@ s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
  				     ARRAY_SIZE(dest->ru), val, len,
  				     target_power, txs_delta, &max_power);
  
+-	return max_power;
++	max_power_backoff = max_power;
 +	val = mt76_get_of_array(np, "paths-cck", &len, ARRAY_SIZE(dest->path.cck));
 +	mt76_apply_array_limit(dest->path.cck, ARRAY_SIZE(dest->path.cck), val,
-+			       target_power, txs_delta, &max_power);
++			       target_power_combine, txs_delta, &max_power_backoff);
 +
 +	val = mt76_get_of_array(np, "paths-ofdm", &len, ARRAY_SIZE(dest->path.ofdm));
 +	mt76_apply_array_limit(dest->path.ofdm, ARRAY_SIZE(dest->path.ofdm), val,
-+			       target_power, txs_delta, &max_power);
++			       target_power_combine, txs_delta, &max_power_backoff);
 +
 +	val = mt76_get_of_array(np, "paths-ofdm-bf", &len, ARRAY_SIZE(dest->path.ofdm_bf));
 +	mt76_apply_array_limit(dest->path.ofdm_bf, ARRAY_SIZE(dest->path.ofdm_bf), val,
-+			       target_power, txs_delta, &max_power);
++			       target_power_combine, txs_delta, &max_power_backoff);
 +
 +	val = mt76_get_of_array(np, "paths-ru", &len, ARRAY_SIZE(dest->path.ru[0]) + 1);
 +	mt76_apply_multi_array_limit(dest->path.ru[0], ARRAY_SIZE(dest->path.ru[0]),
 +				     ARRAY_SIZE(dest->path.ru), val, len,
-+				     target_power, txs_delta, &max_power);
++				     target_power_combine, txs_delta, &max_power_backoff);
 +
 +	val = mt76_get_of_array(np, "paths-ru-bf", &len, ARRAY_SIZE(dest->path.ru_bf[0]) + 1);
 +	mt76_apply_multi_array_limit(dest->path.ru_bf[0], ARRAY_SIZE(dest->path.ru_bf[0]),
 +				     ARRAY_SIZE(dest->path.ru_bf), val, len,
-+				     target_power, txs_delta, &max_power);
++				     target_power_combine, txs_delta, &max_power_backoff);
 +
- 	return max_power;
++	if (max_power_backoff == target_power_combine)
++		return max_power;
++
++	return max_power_backoff;
  }
  EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
+ 
 diff --git a/mt76.h b/mt76.h
 index b4e3429..2f801de 100644
 --- a/mt76.h
@@ -188,11 +205,23 @@
  	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
  				    mt7915_twt_stats);
  	debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
+diff --git a/mt7915/main.c b/mt7915/main.c
+index fcd69ea..155197b 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -1097,6 +1097,7 @@ mt7915_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
+ 	mt76_set_stream_caps(phy->mt76, true);
+ 	mt7915_set_stream_vht_txbf_caps(phy);
+ 	mt7915_set_stream_he_caps(phy);
++	mt7915_mcu_set_txpower_sku(phy);
+ 
+ 	mutex_unlock(&dev->mt76.mutex);
+ 
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index ee951bc..9e64337 100644
+index 07c7323..d87eb5c 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -3300,7 +3300,8 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
+@@ -3303,7 +3303,8 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
  	int ret;
  	s8 txpower_sku[MT7915_SKU_RATE_NUM];
  
@@ -202,7 +231,7 @@
  	if (ret)
  		return ret;
  
-@@ -3342,51 +3343,98 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
+@@ -3345,51 +3346,106 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
  
  int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy)
  {
@@ -261,14 +290,12 @@
 +		skb_put_data(skb, &la.mcs[i], sizeof(la.mcs[i]));
 +		skb_put_zero(skb, 2);  /* padding */
 +	}
- 
--		for (j = 0; j < min_t(u8, mcs_num, len); j++)
--			req.txpower_sku[idx + j] = la[j];
++
 +	/* he */
 +	skb_put_data(skb, &la.ru[0], sizeof(la.ru));
  
--		la += mcs_num;
--		idx += len;
+-		for (j = 0; j < min_t(u8, mcs_num, len); j++)
+-			req.txpower_sku[idx + j] = la[j];
 +	ret = mt76_mcu_skb_send_msg(&dev->mt76, skb,
 +				    MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), true);
 +	if (ret)
@@ -277,7 +304,9 @@
 +	/* only set per-path power table when it's configured */
 +	if (!la.path.ofdm[0])
 +		return 0;
-+
+ 
+-		la += mcs_num;
+-		idx += len;
 +	skb = mt76_mcu_msg_alloc(&dev->mt76, NULL,
 +				 sizeof(hdr) + MT7915_SKU_PATH_NUM);
 +	if (!skb)
@@ -290,22 +319,22 @@
 +	skb_put_data(skb, &la.path.ofdm_bf[1], sizeof(la.path.ofdm_bf) - 1);
 +
 +	/* HT20 and HT40 */
-+	skb_put_data(skb, &la.path.ru[0], sizeof(la.path.ru[0]));
-+	skb_put_data(skb, &la.path.ru_bf[0][1], sizeof(la.path.ru_bf[0]) - 1);
-+	skb_put_data(skb, &la.path.ru[1], sizeof(la.path.ru[1]));
-+	skb_put_data(skb, &la.path.ru_bf[1][1], sizeof(la.path.ru_bf[1]) - 1);
++	skb_put_data(skb, &la.path.ru[3], sizeof(la.path.ru[3]));
++	skb_put_data(skb, &la.path.ru_bf[3][1], sizeof(la.path.ru_bf[3]) - 1);
++	skb_put_data(skb, &la.path.ru[4], sizeof(la.path.ru[4]));
++	skb_put_data(skb, &la.path.ru_bf[4][1], sizeof(la.path.ru_bf[4]) - 1);
 +
 +	/* start from non-bf and bf fields of
 +	 * BW20/RU242, BW40/RU484, BW80/RU996, BW160/RU2x996,
 +	 * RU26, RU52, and RU106
 +	 */
-+	for (i = 7; i < 21; i++) {
-+		bool bf = !(i % 2);
-+		u8 idx = (i - 7) / 2;
-+		s8 *buf = bf ? la.path.ru_bf[idx] : la.path.ru[idx];
 +
++	for (i = 0; i < 8; i++) {
++		bool bf = i % 2;
++		u8 idx = (i + 6) / 2;
++		s8 *buf = bf ? la.path.ru_bf[idx] : la.path.ru[idx];
 +		/* The non-bf fields of RU26 to RU106 are special cases */
-+		if (bf && i < 15)
++		if (bf)
 +			skb_put_data(skb, buf + 1, 9);
 +		else
 +			skb_put_data(skb, buf, 10);
@@ -314,6 +343,14 @@
 -	return mt76_mcu_send_msg(&dev->mt76,
 -				 MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), &req,
 -				 sizeof(req), true);
++	for (i = 0; i < 6; i++) {
++		bool bf = i % 2;
++		u8 idx = i / 2;
++		s8 *buf = bf ? la.path.ru_bf[idx] : la.path.ru[idx];
++
++		skb_put_data(skb, buf, 10);
++	}
++
 +	return mt76_mcu_skb_send_msg(&dev->mt76, skb,
 +				     MCU_EXT_CMD(TX_POWER_FEATURE_CTRL), true);
  }
@@ -326,7 +363,7 @@
  	struct mt7915_dev *dev = phy->dev;
  	struct {
  		u8 format_id;
-@@ -3395,10 +3443,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
+@@ -3398,10 +3454,9 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
  		u8 _rsv;
  	} __packed req = {
  		.format_id = TX_POWER_LIMIT_INFO,
@@ -338,7 +375,7 @@
  	struct sk_buff *skb;
  	int ret, i;
  
-@@ -3408,9 +3455,15 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
+@@ -3411,9 +3466,15 @@ int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len)
  	if (ret)
  		return ret;
  
@@ -357,7 +394,7 @@
  
  	dev_kfree_skb(skb);
  
-@@ -3452,9 +3505,18 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
+@@ -3455,9 +3516,18 @@ int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable)
  		.band_idx = phy->mt76->band_idx,
  		.sku_enable = enable,
  	};
@@ -400,7 +437,7 @@
  	SPR_ENABLE = 0x1,
  	SPR_ENABLE_SD = 0x3,
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 5e70b66..7584d1f 100644
+index bbcdd93..b80c607 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -72,6 +72,7 @@
@@ -411,7 +448,7 @@
  
  #define MT7915_MAX_TWT_AGRT		16
  #define MT7915_MAX_STA_TWT_AGRT		8
-@@ -556,7 +557,8 @@ int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
+@@ -570,7 +571,8 @@ int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
  int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
  int mt7915_mcu_set_sku_en(struct mt7915_phy *phy, bool enable);
  int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
diff --git a/recipes-wifi/linux-mt76/files/patches/2004-wifi-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch b/recipes-wifi/linux-mt76/files/patches/2004-wifi-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
index c1fd5b0..c3f1b3f 100644
--- a/recipes-wifi/linux-mt76/files/patches/2004-wifi-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
+++ b/recipes-wifi/linux-mt76/files/patches/2004-wifi-mt76-mt7915-wed-HW-ATF-support-for-mt7986.patch
@@ -1,7 +1,7 @@
-From 52823aad02634b30aa18c4e27d5e5df08b7d52e7 Mon Sep 17 00:00:00 2001
+From 42aa30b927d84f6765e06f63aec5dc93402ff9a7 Mon Sep 17 00:00:00 2001
 From: Lian Chen <lian.chen@mediatek.com>
 Date: Mon, 7 Nov 2022 14:47:44 +0800
-Subject: [PATCH 2004/2009] wifi: mt76: mt7915: wed: HW ATF support for mt7986
+Subject: [PATCH] wifi: mt76: mt7915: wed: HW ATF support for mt7986
 
 Signed-off-by: Lian Chen <lian.chen@mediatek.com>
 ---
@@ -526,7 +526,7 @@
  
  int mt7915_txbf_init(struct mt7915_dev *dev)
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 97c90ec..7b34162 100644
+index 6cf5f41..f29ac4f 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -217,6 +217,7 @@ int mt7915_init_vif(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bf_e
@@ -537,7 +537,7 @@
  	struct mt76_txq *mtxq;
  	bool ext_phy = phy != &dev->phy;
  	int idx, ret = 0;
-@@ -277,6 +278,9 @@ int mt7915_init_vif(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bf_e
+@@ -278,6 +279,9 @@ int mt7915_init_vif(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bf_e
  	mt7915_mcu_add_sta(dev, vif, NULL, true);
  	rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
  
@@ -547,7 +547,7 @@
  	return ret;
  }
  
-@@ -725,6 +729,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+@@ -755,6 +759,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
  	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
  	bool ext_phy = mvif->phy != &dev->phy;
@@ -555,7 +555,7 @@
  #ifdef CONFIG_MTK_VENDOR
  	struct mt7915_phy *phy = ext_phy ? mt7915_ext_phy(dev) : &dev->phy;
  #endif
-@@ -775,6 +780,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+@@ -805,6 +810,16 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
  	if (phy->muru_onoff & MUMIMO_DL_CERT)
  		mt7915_mcu_set_mimo(phy, 0);
  #endif
@@ -573,10 +573,10 @@
  }
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index ca472c2..7472825 100644
+index 302a022..94362c0 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -3547,6 +3547,171 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
+@@ -3550,6 +3550,171 @@ int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band)
  				 &req, sizeof(req), false);
  }
  
@@ -749,7 +749,7 @@
  {
  #define MT_BF_PROCESSING	4
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index f4e60b2..0621684 100644
+index 36f852e..4447971 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -141,6 +141,58 @@ struct mt7915_twt_flow {
@@ -818,8 +818,8 @@
 +	struct mt7915_vow_sta_cfg vow_sta_cfg;
  };
  
- struct mt7915_vif {
-@@ -402,6 +455,8 @@ struct mt7915_dev {
+ struct mt7915_vif_cap {
+@@ -416,6 +469,8 @@ struct mt7915_dev {
  	} dbg;
  	const struct mt7915_dbg_reg_desc *dbg_reg;
  #endif
@@ -828,7 +828,7 @@
  };
  
  enum {
-@@ -434,6 +489,15 @@ enum mt7915_rdd_cmd {
+@@ -448,6 +503,15 @@ enum mt7915_rdd_cmd {
  	RDD_IRQ_OFF,
  };
  
@@ -844,7 +844,7 @@
  static inline struct mt7915_phy *
  mt7915_hw_phy(struct ieee80211_hw *hw)
  {
-@@ -564,6 +628,10 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
+@@ -578,6 +642,10 @@ int mt7915_mcu_set_mac(struct mt7915_dev *dev, int band, bool enable,
  int mt7915_mcu_set_test_param(struct mt7915_dev *dev, u8 param, bool test_mode,
  			      u8 en);
  int mt7915_mcu_set_ser(struct mt7915_dev *dev, u8 action, u8 set, u8 band);
@@ -856,7 +856,7 @@
  int mt7915_mcu_set_txpower_sku(struct mt7915_phy *phy);
  int mt7915_mcu_get_txpower_sku(struct mt7915_phy *phy, s8 *txpower, int len,
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 336f38e..3eeb921 100644
+index 97eb072..a08f7ab 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
 @@ -1368,7 +1368,6 @@ static EMPTY_QUEUE_INFO_T ple_txcmd_queue_empty_info[] = {
diff --git a/recipes-wifi/linux-mt76/files/patches/9999-mt76-revert-for-backports-5.15-wireless-stack.patch b/recipes-wifi/linux-mt76/files/patches/9999-mt76-revert-for-backports-5.15-wireless-stack.patch
index 2cf9c0d..bd5447d 100644
--- a/recipes-wifi/linux-mt76/files/patches/9999-mt76-revert-for-backports-5.15-wireless-stack.patch
+++ b/recipes-wifi/linux-mt76/files/patches/9999-mt76-revert-for-backports-5.15-wireless-stack.patch
@@ -1,4 +1,4 @@
-From f433ab08414bf574d03a362ef997918cd98e696e Mon Sep 17 00:00:00 2001
+From 601321117f0811d9ce7dbefab1bf3c76e7c7a0f1 Mon Sep 17 00:00:00 2001
 From: Evelyn Tsai <evelyn.tsai@mediatek.com>
 Date: Wed, 5 Apr 2023 08:29:19 +0800
 Subject: [PATCH] mt76: revert for backports-5.15 wireless stack
@@ -11,18 +11,17 @@
  mt7615/main.c     |   6 +-
  mt7615/mcu.c      |   8 +-
  mt76_connac_mac.c |   2 +-
- mt76_connac_mcu.c | 108 +++++++++---------
+ mt76_connac_mcu.c | 108 ++++++++++----------
  mt76x02_mac.c     |   6 +-
  mt7915/debugfs.c  |   4 +-
  mt7915/dma.c      |   4 +-
  mt7915/init.c     |   3 +-
- mt7915/main.c     |  17 ++-
- mt7915/mcu.c      | 273 ++++++++++++++++++++++++++++++----------------
+ mt7915/main.c     |  36 ++-----
+ mt7915/mcu.c      | 246 ++++++++++++++++++++++++++++++----------------
  mt7915/mmio.c     |   2 +-
- mt7915/mt7915.h   |  14 +++
  mt7915/testmode.c |   8 +-
- tx.c              |  22 ++--
- 17 files changed, 286 insertions(+), 201 deletions(-)
+ tx.c              |  22 ++---
+ 16 files changed, 256 insertions(+), 209 deletions(-)
 
 diff --git a/dma.c b/dma.c
 index 4daa64d..220e684 100644
@@ -146,10 +145,10 @@
  		.bcn_interval = cpu_to_le16(vif->bss_conf.beacon_int),
  	};
 diff --git a/mt76_connac_mac.c b/mt76_connac_mac.c
-index 5edf912..44c5221 100644
+index ee5177f..383a25f 100644
 --- a/mt76_connac_mac.c
 +++ b/mt76_connac_mac.c
-@@ -1118,7 +1118,7 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
+@@ -1120,7 +1120,7 @@ void mt76_connac2_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
  	u32 val;
  
  	if (!sta ||
@@ -569,18 +568,10 @@
  
  		if (band == NL80211_BAND_6GHZ) {
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 5db7e6a..d90bdaf 100644
+index f29ac4f..b941821 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
-@@ -273,6 +273,7 @@ int mt7915_init_vif(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bf_e
- 	vif->offload_flags |= IEEE80211_OFFLOAD_ENCAP_4ADDR;
- 
- 	mt7915_init_bitrate_mask(vif);
-+	memset(&mvif->cap, -1, sizeof(mvif->cap));
- 
- 	mt7915_mcu_add_bss_info(phy, vif, true);
- 	mt7915_mcu_add_sta(dev, vif, NULL, true);
-@@ -529,7 +530,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
+@@ -530,7 +530,7 @@ static int mt7915_config(struct ieee80211_hw *hw, u32 changed)
  
  static int
  mt7915_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -589,7 +580,7 @@
  	       const struct ieee80211_tx_queue_params *params)
  {
  	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
-@@ -624,7 +625,7 @@ mt7915_update_bss_color(struct ieee80211_hw *hw,
+@@ -625,7 +625,7 @@ mt7915_update_bss_color(struct ieee80211_hw *hw,
  static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
  				    struct ieee80211_vif *vif,
  				    struct ieee80211_bss_conf *info,
@@ -598,18 +589,37 @@
  {
  	struct mt7915_phy *phy = mt7915_hw_phy(hw);
  	struct mt7915_dev *dev = mt7915_hw_dev(hw);
-@@ -644,7 +645,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
- 	}
- 
+@@ -641,7 +641,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
+ 	    vif->type == NL80211_IFTYPE_STATION)
+ 		set_bss_info = set_sta = !is_zero_ether_addr(info->bssid);
  	if (changed & BSS_CHANGED_ASSOC)
--		mt7915_mcu_add_bss_info(phy, vif, vif->cfg.assoc);
-+		mt7915_mcu_add_bss_info(phy, vif, info->assoc);
- 
- 	if (changed & BSS_CHANGED_ERP_CTS_PROT)
- 		mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot);
-@@ -680,8 +681,7 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
+-		set_bss_info = vif->cfg.assoc;
++		set_bss_info = info->assoc;
+ 	if (changed & BSS_CHANGED_BEACON_ENABLED &&
+ 	    vif->type != NL80211_IFTYPE_AP)
+ 		set_bss_info = set_sta = info->enable_beacon;
+@@ -689,27 +689,8 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
+ 	mutex_unlock(&dev->mt76.mutex);
  }
  
+-static void
+-mt7915_vif_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif)
+-{
+-	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+-	struct mt7915_vif_cap *vc = &mvif->cap;
+-
+-	vc->ht_ldpc = vif->bss_conf.ht_ldpc;
+-	vc->vht_ldpc = vif->bss_conf.vht_ldpc;
+-	vc->vht_su_ebfer = vif->bss_conf.vht_su_beamformer;
+-	vc->vht_su_ebfee = vif->bss_conf.vht_su_beamformee;
+-	vc->vht_mu_ebfer = vif->bss_conf.vht_mu_beamformer;
+-	vc->vht_mu_ebfee = vif->bss_conf.vht_mu_beamformee;
+-	vc->he_ldpc = vif->bss_conf.he_ldpc;
+-	vc->he_su_ebfer = vif->bss_conf.he_su_beamformer;
+-	vc->he_su_ebfee = vif->bss_conf.he_su_beamformee;
+-	vc->he_mu_ebfer = vif->bss_conf.he_mu_beamformer;
+-}
+-
  static int
 -mt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 -		struct ieee80211_bss_conf *link_conf)
@@ -617,7 +627,16 @@
  {
  	struct mt7915_phy *phy = mt7915_hw_phy(hw);
  	struct mt7915_dev *dev = mt7915_hw_dev(hw);
-@@ -700,8 +700,7 @@ out:
+@@ -717,8 +698,6 @@ mt7915_start_ap(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 
+ 	mutex_lock(&dev->mt76.mutex);
+ 
+-	mt7915_vif_check_caps(phy, vif);
+-
+ 	err = mt7915_mcu_add_bss_info(phy, vif, true);
+ 	if (err)
+ 		goto out;
+@@ -730,8 +709,7 @@ out:
  }
  
  static void
@@ -627,7 +646,7 @@
  {
  	struct mt7915_dev *dev = mt7915_hw_dev(hw);
  
-@@ -1265,10 +1264,10 @@ static int mt7915_sta_set_txpwr(struct ieee80211_hw *hw,
+@@ -1293,10 +1271,10 @@ static int mt7915_sta_set_txpwr(struct ieee80211_hw *hw,
  {
  	struct mt7915_phy *phy = mt7915_hw_phy(hw);
  	struct mt7915_dev *dev = mt7915_hw_dev(hw);
@@ -641,7 +660,7 @@
  
  	mutex_lock(&dev->mt76.mutex);
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 26d2964..cf80d77 100644
+index 3bbfc59..14a3c86 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -67,7 +67,7 @@ mt7915_mcu_set_sta_he_mcs(struct ieee80211_sta *sta, __le16 *he_mcs,
@@ -713,12 +732,11 @@
  		return;
  
  	ieee80211_color_change_finish(vif);
-@@ -751,13 +751,14 @@ static void
- mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+@@ -752,13 +752,13 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
  		      struct ieee80211_vif *vif)
  {
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 -	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
-+	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 +	struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem;
  	struct ieee80211_he_mcs_nss_supp mcs_map;
  	struct sta_rec_he *he;
@@ -730,16 +748,7 @@
  		return;
  
  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HE, sizeof(*he));
-@@ -784,7 +785,7 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
- 	     IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_RU_MAPPING_IN_5G))
- 		cap |= STA_REC_HE_CAP_BW20_RU242_SUPPORT;
- 
--	if (vif->bss_conf.he_ldpc &&
-+	if (mvif->cap.he_ldpc &&
- 	    (elem->phy_cap_info[1] &
- 	     IEEE80211_HE_PHY_CAP1_LDPC_CODING_IN_PAYLOAD))
- 		cap |= STA_REC_HE_CAP_LDPC;
-@@ -843,8 +844,8 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
+@@ -844,8 +844,8 @@ mt7915_mcu_sta_he_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
  
  	he->he_cap = cpu_to_le32(cap);
  
@@ -750,31 +759,16 @@
  	case IEEE80211_STA_RX_BW_160:
  		if (elem->phy_cap_info[0] &
  		    IEEE80211_HE_PHY_CAP0_CHANNEL_WIDTH_SET_80PLUS80_MHZ_IN_5G)
-@@ -893,8 +894,9 @@ static void
- mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -895,7 +895,7 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  			struct ieee80211_sta *sta, struct ieee80211_vif *vif)
  {
-+	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- 	struct mt7915_phy *phy = mvif->phy;
+ 	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
 -	struct ieee80211_he_cap_elem *elem = &sta->deflink.he_cap.he_cap_elem;
 +	struct ieee80211_he_cap_elem *elem = &sta->he_cap.he_cap_elem;
+ 	struct mt7915_phy *phy = mvif->phy;
  	struct sta_rec_muru *muru;
  	struct tlv *tlv;
- 
-@@ -906,9 +908,9 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
- 
- 	muru = (struct sta_rec_muru *)tlv;
- 
--	muru->cfg.mimo_dl_en = (vif->bss_conf.he_mu_beamformer ||
--			       vif->bss_conf.vht_mu_beamformer ||
--			       vif->bss_conf.vht_mu_beamformee) &&
-+	muru->cfg.mimo_dl_en = (mvif->cap.he_mu_ebfer ||
-+			       mvif->cap.vht_mu_ebfer ||
-+			       mvif->cap.vht_mu_ebfee) &&
- 			       !!(phy->muru_onoff & MUMIMO_DL);
- 	if (!is_mt7915(&dev->mt76))
- 		muru->cfg.mimo_ul_en = true;
-@@ -918,11 +920,11 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -920,11 +920,11 @@ mt7915_mcu_sta_muru_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	muru->cfg.ofdma_dl_en = !!(phy->muru_onoff & OFDMA_DL);
  	muru->cfg.ofdma_ul_en = !!(phy->muru_onoff & OFDMA_UL);
  
@@ -789,7 +783,7 @@
  		return;
  
  	muru->mimo_dl.partial_bw_dl_mimo =
-@@ -956,13 +958,13 @@ mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+@@ -958,13 +958,13 @@ mt7915_mcu_sta_ht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
  	struct sta_rec_ht *ht;
  	struct tlv *tlv;
  
@@ -805,7 +799,7 @@
  }
  
  static void
-@@ -971,15 +973,15 @@ mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
+@@ -973,15 +973,15 @@ mt7915_mcu_sta_vht_tlv(struct sk_buff *skb, struct ieee80211_sta *sta)
  	struct sta_rec_vht *vht;
  	struct tlv *tlv;
  
@@ -825,7 +819,7 @@
  }
  
  static void
-@@ -994,7 +996,7 @@ mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -996,7 +996,7 @@ mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	    vif->type != NL80211_IFTYPE_AP)
  		return;
  
@@ -834,7 +828,7 @@
  	    return;
  
  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_HW_AMSDU, sizeof(*amsdu));
-@@ -1003,7 +1005,7 @@ mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -1005,7 +1005,7 @@ mt7915_mcu_sta_amsdu_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	amsdu->amsdu_en = true;
  	msta->wcid.amsdu = true;
  
@@ -843,26 +837,7 @@
  	case IEEE80211_MAX_MPDU_LEN_VHT_11454:
  		if (!is_mt7915(&dev->mt76)) {
  			amsdu->max_mpdu_size =
-@@ -1046,8 +1048,8 @@ mt7915_mcu_sta_wtbl_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
- 	mt76_connac_mcu_wtbl_hdr_trans_tlv(skb, vif, wcid, tlv, wtbl_hdr);
- 	if (sta)
- 		mt76_connac_mcu_wtbl_ht_tlv(&dev->mt76, skb, sta, tlv,
--					    wtbl_hdr, vif->bss_conf.ht_ldpc,
--					    vif->bss_conf.vht_ldpc);
-+					    wtbl_hdr, mvif->cap.ht_ldpc,
-+					    mvif->cap.vht_ldpc);
- 
- 	return 0;
- }
-@@ -1056,6 +1058,7 @@ static inline bool
- mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
- 			struct ieee80211_sta *sta, bool bfee)
- {
-+	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- 	int sts = hweight16(phy->mt76->chainmask);
- 
- 	if (vif->type != NL80211_IFTYPE_STATION &&
-@@ -1065,25 +1068,25 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+@@ -1068,8 +1068,8 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
  	if (!bfee && sts < 2)
  		return false;
  
@@ -872,12 +847,8 @@
 +		struct ieee80211_he_cap_elem *pe = &sta->he_cap.he_cap_elem;
  
  		if (bfee)
--			return vif->bss_conf.he_su_beamformee &&
-+			return mvif->cap.he_su_ebfee &&
- 			       HE_PHY(CAP3_SU_BEAMFORMER, pe->phy_cap_info[3]);
- 		else
--			return vif->bss_conf.he_su_beamformer &&
-+			return mvif->cap.he_su_ebfer &&
+ 			return mvif->cap.he_su_ebfee &&
+@@ -1079,8 +1079,8 @@ mt7915_is_ebf_supported(struct mt7915_phy *phy, struct ieee80211_vif *vif,
  			       HE_PHY(CAP4_SU_BEAMFORMEE, pe->phy_cap_info[4]);
  	}
  
@@ -887,16 +858,8 @@
 +		u32 cap = sta->vht_cap.cap;
  
  		if (bfee)
--			return vif->bss_conf.vht_su_beamformee &&
-+			return mvif->cap.vht_su_ebfee &&
- 			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE);
- 		else
--			return vif->bss_conf.vht_su_beamformer &&
-+			return mvif->cap.vht_su_ebfer &&
- 			       (cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE);
- 	}
- 
-@@ -1103,7 +1106,7 @@ static void
+ 			return mvif->cap.vht_su_ebfee &&
+@@ -1106,7 +1106,7 @@ static void
  mt7915_mcu_sta_bfer_ht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
  		       struct sta_rec_bf *bf)
  {
@@ -905,7 +868,7 @@
  	u8 n = 0;
  
  	bf->tx_mode = MT_PHY_TYPE_HT;
-@@ -1128,7 +1131,7 @@ static void
+@@ -1131,7 +1131,7 @@ static void
  mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
  			struct sta_rec_bf *bf, bool explicit)
  {
@@ -914,7 +877,7 @@
  	struct ieee80211_sta_vht_cap *vc = &phy->mt76->sband_5g.sband.vht_cap;
  	u16 mcs_map = le16_to_cpu(pc->vht_mcs.rx_mcs_map);
  	u8 nss_mcs = mt7915_mcu_get_sta_nss(mcs_map);
-@@ -1149,14 +1152,14 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
+@@ -1152,14 +1152,14 @@ mt7915_mcu_sta_bfer_vht(struct ieee80211_sta *sta, struct mt7915_phy *phy,
  		bf->ncol = min_t(u8, nss_mcs, bf->nrow);
  		bf->ibf_ncol = bf->ncol;
  
@@ -931,7 +894,7 @@
  			bf->ibf_nrow = 1;
  	}
  }
-@@ -1165,7 +1168,7 @@ static void
+@@ -1168,7 +1168,7 @@ static void
  mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
  		       struct mt7915_phy *phy, struct sta_rec_bf *bf)
  {
@@ -940,7 +903,7 @@
  	struct ieee80211_he_cap_elem *pe = &pc->he_cap_elem;
  	const struct ieee80211_sta_he_cap *vc =
  		mt76_connac_get_he_phy_cap(phy->mt76, vif);
-@@ -1190,7 +1193,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
+@@ -1193,7 +1193,7 @@ mt7915_mcu_sta_bfer_he(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
  	bf->ncol = min_t(u8, nss_mcs, bf->nrow);
  	bf->ibf_ncol = bf->ncol;
  
@@ -949,7 +912,7 @@
  		return;
  
  	/* go over for 160MHz and 80p80 */
-@@ -1238,7 +1241,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -1241,7 +1241,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	};
  	bool ebf;
  
@@ -958,7 +921,7 @@
  		return;
  
  	ebf = mt7915_is_ebf_supported(phy, vif, sta, false);
-@@ -1252,21 +1255,21 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -1255,21 +1255,21 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	 * vht: support eBF and iBF
  	 * ht: iBF only, since mac80211 lacks of eBF support
  	 */
@@ -986,7 +949,7 @@
  		bf->ibf_timeout = 0x48;
  	else
  		bf->ibf_timeout = 0x18;
-@@ -1276,7 +1279,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -1279,7 +1279,7 @@ mt7915_mcu_sta_bfer_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	else
  		bf->mem_20m = matrix[bf->nrow][bf->ncol];
  
@@ -995,7 +958,7 @@
  	case IEEE80211_STA_RX_BW_160:
  	case IEEE80211_STA_RX_BW_80:
  		bf->mem_total = bf->mem_20m * 2;
-@@ -1301,7 +1304,7 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -1304,7 +1304,7 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	struct tlv *tlv;
  	u8 nrow = 0;
  
@@ -1004,7 +967,7 @@
  		return;
  
  	if (!mt7915_is_ebf_supported(phy, vif, sta, true))
-@@ -1310,13 +1313,13 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
+@@ -1313,13 +1313,13 @@ mt7915_mcu_sta_bfee_tlv(struct mt7915_dev *dev, struct sk_buff *skb,
  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_BFEE, sizeof(*bfee));
  	bfee = (struct sta_rec_bfee *)tlv;
  
@@ -1022,7 +985,7 @@
  
  		nrow = FIELD_GET(IEEE80211_VHT_CAP_SOUNDING_DIMENSIONS_MASK,
  				 pc->cap);
-@@ -1372,7 +1375,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
+@@ -1375,7 +1375,7 @@ int mt7915_mcu_set_fixed_rate_ctrl(struct mt7915_dev *dev,
  			ra->phy = *phy;
  		break;
  	case RATE_PARAM_MMPS_UPDATE:
@@ -1031,7 +994,7 @@
  		break;
  	case RATE_PARAM_SPE_UPDATE:
  		ra->spe_idx = *(u8 *)data;
-@@ -1447,7 +1450,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
+@@ -1450,7 +1450,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  	do {									\
  		u8 i, gi = mask->control[band]._gi;				\
  		gi = (_he) ? gi : gi == NL80211_TXRATE_FORCE_SGI;		\
@@ -1040,7 +1003,7 @@
  			phy.sgi |= gi << (i << (_he));				\
  			phy.he_ltf |= mask->control[band].he_ltf << (i << (_he));\
  		}								\
-@@ -1461,11 +1464,11 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
+@@ -1464,11 +1464,11 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  		}								\
  	} while (0)
  
@@ -1055,7 +1018,7 @@
  		__sta_phy_bitrate_mask_check(ht_mcs, gi, 1, 0);
  	} else {
  		nrates = hweight32(mask->control[band].legacy);
-@@ -1499,7 +1502,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
+@@ -1502,7 +1502,7 @@ mt7915_mcu_add_rate_ctrl_fixed(struct mt7915_dev *dev,
  		 * actual txrate hardware sends out.
  		 */
  		addr = mt7915_mac_wtbl_lmac_addr(dev, msta->wcid.idx, 7);
@@ -1064,7 +1027,7 @@
  			mt76_rmw_field(dev, addr, GENMASK(31, 24), phy.sgi);
  		else
  			mt76_rmw_field(dev, addr, GENMASK(15, 12), phy.sgi);
-@@ -1532,7 +1535,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
+@@ -1535,7 +1535,7 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
  	enum nl80211_band band = chandef->chan->band;
  	struct sta_rec_ra *ra;
  	struct tlv *tlv;
@@ -1073,7 +1036,7 @@
  	u32 cap = sta->wme ? STA_CAP_WMM : 0;
  
  	tlv = mt76_connac_mcu_add_tlv(skb, STA_REC_RA, sizeof(*ra));
-@@ -1542,9 +1545,9 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
+@@ -1545,9 +1545,9 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
  	ra->auto_rate = true;
  	ra->phy_mode = mt76_connac_get_phy_mode(mphy, vif, band, sta);
  	ra->channel = chandef->chan->hw_value;
@@ -1086,7 +1049,7 @@
  
  	if (supp_rate) {
  		supp_rate &= mask->control[band].legacy;
-@@ -1564,22 +1567,22 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
+@@ -1567,22 +1567,22 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
  		}
  	}
  
@@ -1111,14 +1074,13 @@
 -		if (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
 +		if (sta->ht_cap.cap & IEEE80211_HT_CAP_RX_STBC)
  			cap |= STA_CAP_RX_STBC;
--		if (vif->bss_conf.ht_ldpc &&
+ 		if (mvif->cap.ht_ldpc &&
 -		    (sta->deflink.ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
-+		if (mvif->cap.ht_ldpc &&
 +		    (sta->ht_cap.cap & IEEE80211_HT_CAP_LDPC_CODING))
  			cap |= STA_CAP_LDPC;
  
  		mt7915_mcu_set_sta_ht_mcs(sta, ra->ht_mcs,
-@@ -1587,37 +1590,37 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
+@@ -1590,37 +1590,37 @@ mt7915_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb, struct mt7915_dev *dev,
  		ra->supp_ht_mcs = *(__le32 *)ra->ht_mcs;
  	}
  
@@ -1145,9 +1107,8 @@
 -		if (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
 +		if (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXSTBC_1)
  			cap |= STA_CAP_VHT_RX_STBC;
--		if (vif->bss_conf.vht_ldpc &&
+ 		if (mvif->cap.vht_ldpc &&
 -		    (sta->deflink.vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
-+		if (mvif->cap.vht_ldpc &&
 +		    (sta->vht_cap.cap & IEEE80211_VHT_CAP_RXLDPC))
  			cap |= STA_CAP_VHT_LDPC;
  
@@ -1167,7 +1128,7 @@
  					       IEEE80211_HE_6GHZ_CAP_MAX_AMPDU_LEN_EXP);
  	}
  
-@@ -1826,7 +1829,7 @@ mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
+@@ -1829,7 +1829,7 @@ mt7915_mcu_beacon_cntdwn(struct ieee80211_vif *vif, struct sk_buff *rskb,
  	if (!offs->cntdwn_counter_offs[0])
  		return;
  
@@ -1176,7 +1137,7 @@
  	tlv = mt7915_mcu_add_nested_subtlv(rskb, sub_tag, sizeof(*info),
  					   &bcn->sub_ntlv, &bcn->len);
  	info = (struct bss_info_bcn_cntdwn *)tlv;
-@@ -1911,9 +1914,9 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+@@ -1914,9 +1914,9 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  	if (offs->cntdwn_counter_offs[0]) {
  		u16 offset = offs->cntdwn_counter_offs[0];
  
@@ -1188,7 +1149,7 @@
  			cont->bcc_ofs = cpu_to_le16(offset - 3);
  	}
  
-@@ -1923,6 +1926,85 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+@@ -1926,6 +1926,85 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
  }
  
@@ -1274,7 +1235,7 @@
  int
  mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
  			     u32 changed)
-@@ -2034,7 +2116,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -2037,7 +2116,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  	if (!en)
  		goto out;
  
@@ -1283,7 +1244,7 @@
  	if (!skb)
  		return -EINVAL;
  
-@@ -2047,6 +2129,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+@@ -2050,6 +2129,7 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
  	info = IEEE80211_SKB_CB(skb);
  	info->hw_queue = FIELD_PREP(MT_TX_HW_QUEUE_PHY, ext_phy);
  
@@ -1291,7 +1252,7 @@
  	mt7915_mcu_beacon_cntdwn(vif, rskb, skb, bcn, &offs);
  	mt7915_mcu_beacon_mbss(rskb, skb, vif, bcn, &offs);
  	mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
-@@ -3320,17 +3403,17 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
+@@ -3323,17 +3403,17 @@ int mt7915_mcu_set_txpower_frame(struct mt7915_phy *phy,
  	if (txpower) {
  		u32 offs, len, i;
  
@@ -1325,34 +1286,6 @@
  		if (unlikely(dma_mapping_error(dev->mt76.dev, phy_addr))) {
  			skb_free_frag(ptr);
  			mt76_put_rxwi(&dev->mt76, r);
-diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 85c5c95..04fc539 100644
---- a/mt7915/mt7915.h
-+++ b/mt7915/mt7915.h
-@@ -217,9 +217,23 @@ struct mt7915_sta {
- 	struct mt7915_vow_sta_cfg vow_sta_cfg;
- };
- 
-+struct mt7915_vif_cap {
-+	bool ht_ldpc:1;
-+	bool vht_ldpc:1;
-+	bool he_ldpc:1;
-+	bool vht_su_ebfer:1;
-+	bool vht_su_ebfee:1;
-+	bool vht_mu_ebfer:1;
-+	bool vht_mu_ebfee:1;
-+	bool he_su_ebfer:1;
-+	bool he_su_ebfee:1;
-+	bool he_mu_ebfer:1;
-+};
-+
- struct mt7915_vif {
- 	struct mt76_vif mt76; /* must be first */
- 
-+	struct mt7915_vif_cap cap;
- 	struct mt7915_sta sta;
- 	struct mt7915_phy *phy;
- 
 diff --git a/mt7915/testmode.c b/mt7915/testmode.c
 index fafe909..b10dec5 100644
 --- a/mt7915/testmode.c
diff --git a/recipes-wifi/linux-mt76/files/patches/patches.inc b/recipes-wifi/linux-mt76/files/patches/patches.inc
index 78fc3e8..c4eb825 100644
--- a/recipes-wifi/linux-mt76/files/patches/patches.inc
+++ b/recipes-wifi/linux-mt76/files/patches/patches.inc
@@ -1,6 +1,5 @@
 #patch patches (come from openwrt/lede/target/linux/mediatek)
 SRC_URI_append = " \
-    file://0000-sync-to-master-codebase.patch \
     file://0001-wifi-mt76-mt7915-Update-beacon-size-limitation-for-1.patch \
     file://0002-wifi-mt76-mt7915-fix-the-beamformer-issue.patch \
     file://0003-wifi-mt76-fix-incorrect-HE-TX-GI-report.patch \
diff --git a/recipes-wifi/linux-mt76/linux-mt76_3.x.bb b/recipes-wifi/linux-mt76/linux-mt76_3.x.bb
index b9a69c7..e77841d 100644
--- a/recipes-wifi/linux-mt76/linux-mt76_3.x.bb
+++ b/recipes-wifi/linux-mt76/linux-mt76_3.x.bb
@@ -5,7 +5,7 @@
 
 inherit module
 
-require mt76.inc
+require mt76-3x.inc
 SRC_URI = " \
     git://git@github.com/openwrt/mt76.git;protocol=https \
     file://COPYING;subdir=git \
diff --git a/recipes-wifi/linux-mt76/mt76-3x.inc b/recipes-wifi/linux-mt76/mt76-3x.inc
new file mode 100644
index 0000000..38febf2
--- /dev/null
+++ b/recipes-wifi/linux-mt76/mt76-3x.inc
@@ -0,0 +1 @@
+SRCREV_mt7988 = "969b7b5ebd129068ca56e4b0d831593a2f92382f"
diff --git a/recipes-wifi/linux-mt76/mt76-test.bb b/recipes-wifi/linux-mt76/mt76-test.bb
index 918123a..63e8e3e 100644
--- a/recipes-wifi/linux-mt76/mt76-test.bb
+++ b/recipes-wifi/linux-mt76/mt76-test.bb
@@ -10,6 +10,8 @@
 PV = "1.0"
 
 require mt76.inc
+require mt76-3x.inc
+
 SRC_URI = " \
     git://git@github.com/openwrt/mt76.git;protocol=https \
     file://COPYING;subdir=git \
diff --git a/recipes-wifi/linux-mt76/mt76.inc b/recipes-wifi/linux-mt76/mt76.inc
index 58276c2..9843dd0 100644
--- a/recipes-wifi/linux-mt76/mt76.inc
+++ b/recipes-wifi/linux-mt76/mt76.inc
@@ -1 +1 @@
-SRCREV ?= "969b7b5ebd129068ca56e4b0d831593a2f92382f"
+SRCREV ?= "f704e4f83c6fd21fb39046fa328efb51bee6383b"
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch
new file mode 100644
index 0000000..fa37f91
--- /dev/null
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch
@@ -0,0 +1,638 @@
+From 011bf135a28d9e13fc27b72da4486d21c8c17e87 Mon Sep 17 00:00:00 2001
+From: Howard Hsu <howard-yh.hsu@mediatek.com>
+Date: Sat, 3 Jun 2023 17:12:15 +0800
+Subject: [PATCH] hostapd: mtk: add connac3 PHY MURU manual mode config support
+
+This commit supports read the following two formats to set MU/RU manual
+mode:
+1. hostapd_cli -i <intf> raw set_muru_manual_config=<field>:<value>
+2. hostapd_cli -i <intf> set_mu <field> <value>
+
+For the <field>, we support the following field:
+1. ul_comm_user_cnt/dl_comm_user_cnt: set the number of user
+2. ul_comm_bw/dl_comm_bw: set the bandwith
+3. ul_user_ru_alloc/dl_user_ru_alloc: set the RU band idx and RU
+allocate idx
+4. ul_user_mcs/dl_user_mcs: set the mcs for each user
+5. ul_user_ssAlloc_raru: set the number of ss for each user
+6. ul_comm_gi_ltf: set the combinations of gi and ltf for UL only.
+7. dl_comm_toneplan: fix ru toneplan allocation
+8. dl_comm_ack_policy: fix station ack policy
+9. update : trigger driver to send mcu command to set muru manual mode.
+
+For the value of each field, please check wiki to learn the details:
+https://wiki.mediatek.inc/display/GWKB/muru_mancfg_user_guide
+
+For the fields that mt76 support to use, we will update in this wiki:
+https://wiki.mediatek.inc/pages/viewpage.action?pageId=1271741116
+
+Please noted that this commit is only for connac 3 gen chips. If this
+feature is to be used in other generations, the following actions must
+be taken:
+1. Different data structue needs to be defined for different
+generations, e.g. connac4_muru_comm, connac4_muru_dl.
+2. hostapd_ctrl_iface_set_mu() shall be modified.
+3. A new code level configuration shall be defined to differentiate the
+code flow that different generations will go through.
+---
+ hostapd/ctrl_iface.c         | 235 +++++++++++++++++++++++++++++++----
+ src/ap/ap_config.h           |   1 +
+ src/ap/ap_drv_ops.c          |   4 +-
+ src/ap/ap_drv_ops.h          |   2 +-
+ src/ap/hostapd.c             |   2 +-
+ src/common/mtk_vendor.h      | 166 ++++++++++++++++++++++++-
+ src/drivers/driver.h         |   2 +-
+ src/drivers/driver_nl80211.c |  21 ++--
+ 8 files changed, 390 insertions(+), 43 deletions(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 274d079..663e6c8 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -3575,22 +3575,61 @@ hostapd_ctrl_iface_get_edcca(struct hostapd_data *hapd, char *cmd, char *buf,
+ 	}
+ }
+ 
++static int
++hostapd_parse_argument_helper(char *value, u16 **ptr_input)
++{
++#define MAX_MU_CTRL_NUM 17
++
++	u16 *input;
++	char *endptr;
++	int cnt = 0;
++
++	input = os_zalloc(MAX_MU_CTRL_NUM * sizeof(u16));
++	if (input == NULL) {
++		wpa_printf(MSG_ERROR, "Failed to allocate memory.\n");
++		return -1;
++	}
++	while (value) {
++		u8 val = strtol(value, &endptr, 10);
++
++		if (value != endptr) {
++			input[cnt++] = val;
++			value = os_strchr(endptr, ':');
++			if (value)
++				value++;
++		} else {
++			break;
++		}
++	}
+ 
++	*ptr_input = input;
++	return cnt;
++}
++
++#define MURU_CFG_DEPENDENCE_CHECK(_val, _mask) do {				\
++		if ((le_to_host32(_val) & (_mask)) != _mask) {			\
++			wpa_printf(MSG_ERROR, "Set %s first\n", #_mask);	\
++			goto fail;						\
++		}								\
++	} while(0)
+ static int
+ hostapd_ctrl_iface_set_mu(struct hostapd_data *hapd, char *cmd,
+-					 char *buf, size_t buflen)
++			  char *buf, size_t buflen)
+ {
+ 	char *pos, *config, *value;
+-	u8 mode;
++	u8 i;
++	int cnt = 0, ret;
++	u16 *val;
++	struct connac3_muru *muru;
++	struct connac3_muru_dl *dl;
++	struct connac3_muru_ul *ul;
++	struct connac3_muru_comm *comm;
+ 
+ 	config = cmd;
+ 	pos = os_strchr(config, ' ');
+-	if (pos == NULL)
+-		return -1;
+-	*pos++ = '\0';
++	if (pos != NULL)
++		*pos++ = '\0';
+ 
+-	if(pos == NULL)
+-		return -1;
+ 	value = pos;
+ 
+ 	if (os_strcmp(config, "onoff") == 0) {
+@@ -3600,24 +3639,167 @@ hostapd_ctrl_iface_set_mu(struct hostapd_data *hapd, char *cmd,
+ 			return -1;
+ 		}
+ 		hapd->iconf->mu_onoff = (u8) mu;
+-		mode = MU_CTRL_ONOFF;
+-	} else if (os_strcmp(config, "ul_user_cnt") == 0) {
+-		mode = MU_CTRL_UL_USER_CNT;
+-		wpa_printf(MSG_ERROR, "ul_user_cnt:%d\n", (u8)atoi(value));
+-	} else if (os_strcmp(config, "dl_user_cnt") == 0) {
+-		mode = MU_CTRL_DL_USER_CNT;
+-		wpa_printf(MSG_ERROR, "dl_user_cnt:%d\n", (u8)atoi(value));
+-	} else {
+-		wpa_printf(MSG_ERROR,
+-			"Unsupported parameter %s for SET_MU", config);
+-		return -1;
++
++		if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF) == 0)
++			return os_snprintf(buf, buflen, "OK\n");
++		else
++			goto fail;
+ 	}
+ 
+-	if(hostapd_drv_mu_ctrl(hapd, mode, (u8)atoi(value)) == 0) {
+-		return os_snprintf(buf, buflen, "OK\n");
++	if (hapd->iconf->muru_config == NULL)
++		hapd->iconf->muru_config = os_zalloc(sizeof(struct connac3_muru));
++
++	muru = hapd->iconf->muru_config;
++	dl = &muru->dl;
++	ul = &muru->ul;
++	comm = &muru->comm;
++
++	if (os_strncmp(config, "update", 6) == 0) {
++		ret = hostapd_drv_mu_ctrl(hapd, MU_CTRL_UPDATE);
++
++		os_free(hapd->iconf->muru_config);
++		hapd->iconf->muru_config = NULL;
++
++		if (ret)
++			goto fail;
++	} else if (os_strcmp(config, "ul_comm_user_cnt") == 0) {
++		ul->user_num = (u8)atoi(value);
++		comm->ppdu_format |= MURU_PPDU_HE_TRIG;
++		comm->sch_type |= MURU_OFDMA_SCH_TYPE_UL;
++		muru->cfg_comm |= host_to_le32(MURU_COMM_SET);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_TOTAL_USER_CNT);
++	} else if (os_strcmp(config, "dl_comm_user_cnt") == 0) {
++		dl->user_num = (u8)atoi(value);
++		comm->ppdu_format |= MURU_PPDU_HE_MU;
++		comm->sch_type |= MURU_OFDMA_SCH_TYPE_DL;
++		muru->cfg_comm |= host_to_le32(MURU_COMM_SET);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_TOTAL_USER_CNT);
++	} else if (os_strcmp(config, "dl_comm_bw") == 0) {
++		dl->bw = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_BW);
++	} else if (os_strcmp(config, "ul_comm_bw") == 0) {
++		ul->bw = (u8)atoi(value);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_BW);
++	} else if (os_strcmp(config, "dl_user_ru_alloc") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != (dl->user_num * 2))
++			goto para_fail;
++		for (i = 0; i < dl->user_num; i++) {
++			dl->usr[i].ru_alloc_seg = (val[2 * i] & 0x1);
++			dl->usr[i].ru_allo_ps160 = ((val[2 * i] & 0x2) >> 1);
++			dl->usr[i].ru_idx = (val[(2 * i) + 1] & 0x1);
++		}
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_RU_ALLOC);
++	} else if (os_strcmp(config, "ul_user_ru_alloc") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != (ul->user_num * 2))
++			goto para_fail;
++		for (i = 0; i < ul->user_num; i++) {
++			ul->usr[i].ru_alloc_seg = (val[2 * i] & 0x1);
++			ul->usr[i].ru_allo_ps160 = ((val[2 * i] & 0x2) >> 1);
++			ul->usr[i].ru_idx = (val[(2 * i) + 1] & 0x1);
++		}
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_RU_ALLOC);
++	} else if (os_strcmp(config, "dl_user_mcs") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != dl->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			dl->usr[i].mcs = (u8) val[i];
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_MCS);
++	} else if (os_strcmp(config, "ul_user_mcs") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != ul->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			ul->usr[i].mcs = (u8) val[i];
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_MCS);
++	} else if (os_strcmp(config, "dl_user_cod") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != dl->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			dl->usr[i].ldpc = (u8) val[i];
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_USER_DL_COD);
++	} else if (os_strcmp(config, "ul_user_cod") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != ul->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			ul->usr[i].ldpc = (u8) val[i];
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_COD);
++	} else if (os_strcmp(config, "ul_user_ssAlloc_raru") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_ul, MURU_FIXED_UL_TOTAL_USER_CNT);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		if (cnt != ul->user_num)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			ul->usr[i].nss = (u8) val[i];
++		os_free(val);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_USER_UL_NSS);
++	} else if (os_strcmp(config, "dl_comm_gi") == 0) {
++		dl->gi = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_GI);
++	} else if (os_strcmp(config, "dl_comm_ltf") == 0) {
++		dl->ltf = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_LTF);
++	} else if (os_strcmp(config, "ul_comm_gi_ltf") == 0) {
++		ul->gi_ltf = (u8)atoi(value);
++		muru->cfg_ul |= host_to_le32(MURU_FIXED_UL_GILTF);
++	} else if (os_strcmp(config, "dl_comm_ack_policy") == 0) {
++		dl->ack_policy = (u8)atoi(value);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_ACK_PLY);
++	} else if (os_strcmp(config, "dl_comm_toneplan") == 0) {
++		MURU_CFG_DEPENDENCE_CHECK(muru->cfg_dl, MURU_FIXED_DL_BW);
++		cnt = hostapd_parse_argument_helper(value, &val);
++		if (cnt == -1)
++			goto fail;
++		i = pow(2, dl->bw);
++		if (cnt != i)
++			goto para_fail;
++		for (i = 0; i < cnt; i++)
++			dl->ru[i] = host_to_le16(val[i]);
++		os_free(val);
++		muru->cfg_dl |= host_to_le32(MURU_FIXED_DL_TONE_PLAN);
+ 	} else {
+-		return -1;
++		wpa_printf(MSG_ERROR,
++			   "Unsupported parameter %s for SET_MU", config);
++		goto fail;
+ 	}
++
++	return os_snprintf(buf, buflen, "OK\n");
++
++para_fail:
++	os_free(val);
++	wpa_printf(MSG_ERROR, "Incorrect input number\n");
++fail:
++	return os_snprintf(buf, buflen, "FAIL\n");
+ }
+ 
+ 
+@@ -4609,8 +4791,7 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 		reply_len = hostapd_ctrl_iface_get_edcca(hapd, buf+10, reply,
+ 							  reply_size);
+ 	} else if (os_strncmp(buf, "SET_MU ", 7) == 0) {
+-		reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 7, reply,
+-							  reply_size);
++		reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 7, reply, reply_size);
+ 	} else if (os_strncmp(buf, "GET_MU", 6) == 0) {
+ 		reply_len = hostapd_ctrl_iface_get_mu(hapd, reply, reply_size);
+ 	} else if (os_strncmp(buf, "GET_IBF", 7) == 0) {
+@@ -4636,6 +4817,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 	} else if (os_strncmp(buf, "DUMP_AMNT", 9) == 0) {
+ 		reply_len = hostapd_ctrl_iface_dump_amnt(hapd, buf+10,
+ 							reply, reply_size);
++	} else if (os_strncmp(buf, "set_muru_manual_config=", 23) == 0) {
++		// Replace first ':' with a single space ' '
++		char *pos = buf + 23;
++
++		pos = os_strchr(pos, ':');
++		if (pos)
++			*pos = ' ';
++		reply_len = hostapd_ctrl_iface_set_mu(hapd, buf + 23, reply, reply_size);
+ 	} else {
+ 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ 		reply_len = 16;
+diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
+index 9df0b2c..74dfce7 100644
+--- a/src/ap/ap_config.h
++++ b/src/ap/ap_config.h
+@@ -1190,6 +1190,7 @@ struct hostapd_config {
+ 	u8 ibf_enable;
+ 	u8 dfs_detect_mode;
+ 	u8 amsdu;
++	void *muru_config;
+ };
+ 
+ enum three_wire_mode {
+diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
+index d5c7b15..fa369c8 100644
+--- a/src/ap/ap_drv_ops.c
++++ b/src/ap/ap_drv_ops.c
+@@ -1079,11 +1079,11 @@ int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value)
+ 	return hapd->driver->get_edcca(hapd->drv_priv, mode, value);
+ }
+ 
+-int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode, u8 val)
++int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode)
+ {
+ 	if (!hapd->driver || !hapd->driver->mu_ctrl)
+ 		return 0;
+-	return hapd->driver->mu_ctrl(hapd->drv_priv, mode, val);
++	return hapd->driver->mu_ctrl(hapd->drv_priv, mode, hapd->iconf);
+ }
+ 
+ int hostapd_drv_mu_dump(struct hostapd_data *hapd, u8 *mu_onoff)
+diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
+index 82283e6..33faba5 100644
+--- a/src/ap/ap_drv_ops.h
++++ b/src/ap/ap_drv_ops.h
+@@ -148,7 +148,7 @@ int hostapd_drv_configure_edcca_enable(struct hostapd_data *hapd);
+ int hostapd_drv_configure_edcca_threshold(struct hostapd_data *hapd,
+ 					  const int *threshold);
+ int hostapd_drv_get_edcca(struct hostapd_data *hapd, const u8 mode, u8 *value);
+-int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode, u8 val);
++int hostapd_drv_mu_ctrl(struct hostapd_data *hapd, u8 mode);
+ int hostapd_drv_mu_dump(struct hostapd_data *hapd, u8 *mu_onoff);
+ int hostapd_drv_three_wire_ctrl(struct hostapd_data *hapd);
+ int hostapd_drv_ibf_ctrl(struct hostapd_data *hapd);
+diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
+index 6fd5947..535f62b 100644
+--- a/src/ap/hostapd.c
++++ b/src/ap/hostapd.c
+@@ -2398,7 +2398,7 @@ dfs_offload:
+ 	if (hostapd_drv_configure_edcca_threshold(hapd,
+ 						  hapd->iconf->edcca_threshold) < 0)
+ 		goto fail;
+-	if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF, hapd->iconf->mu_onoff) < 0)
++	if (hostapd_drv_mu_ctrl(hapd, MU_CTRL_ONOFF) < 0)
+ 		goto fail;
+ 	if (hostapd_drv_three_wire_ctrl(hapd) < 0)
+ 		goto fail;
+diff --git a/src/common/mtk_vendor.h b/src/common/mtk_vendor.h
+index 7dd2fc4..6de8596 100644
+--- a/src/common/mtk_vendor.h
++++ b/src/common/mtk_vendor.h
+@@ -197,8 +197,11 @@ enum mtk_vendor_attr_mu_ctrl {
+ 
+ 	MTK_VENDOR_ATTR_MU_CTRL_ONOFF,
+ 	MTK_VENDOR_ATTR_MU_CTRL_DUMP,
+-	MTK_VENDOR_ATTR_MU_CTRL_OFDMA_MODE,
+-	MTK_VENDOR_ATTR_MU_CTRL_OFDMA_VAL,
++	/**
++	 * The above attrs are also used by connac 2. It is best not to modify the
++	 * above data structure.
++	 */
++	MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
+ 
+ 	/* keep last */
+ 	NUM_MTK_VENDOR_ATTRS_MU_CTRL,
+@@ -273,8 +276,163 @@ struct amnt_resp_data {
+ };
+ 
+ enum {
++	MU_CTRL_UPDATE,
+ 	MU_CTRL_ONOFF,
+-	MU_CTRL_DL_USER_CNT,
+-	MU_CTRL_UL_USER_CNT,
+ };
++
++struct connac3_muru_comm {
++	u8 pda_pol;
++	u8 band;
++	u8 spe_idx;
++	u8 proc_type;
++
++	le16 mlo_ctrl;
++	u8 sch_type;
++	u8 ppdu_format;
++	u8 ac;
++	u8 _rsv[3];
++};
++
++struct connac3_muru_dl {
++	u8 user_num;
++	u8 tx_mode;
++	u8 bw;
++	u8 gi;
++
++	u8 ltf;
++	u8 mcs;
++	u8 dcm;
++	u8 cmprs;
++
++	le16 ru[16];
++
++	u8 c26[2];
++	u8 ack_policy;
++	u8 tx_power;
++
++	le16 mu_ppdu_duration;
++	u8 agc_disp_order;
++	u8 _rsv1;
++
++	u8 agc_disp_pol;
++	u8 agc_disp_ratio;
++	le16 agc_disp_linkMFG;
++
++	le16 prmbl_punc_bmp;
++	u8 _rsv2[2];
++
++	struct {
++		le16 wlan_idx;
++		u8 ru_alloc_seg;
++		u8 ru_idx;
++		u8 ldpc;
++		u8 nss;
++		u8 mcs;
++		u8 mu_group_idx;
++		u8 vht_groud_id;
++		u8 vht_up;
++		u8 he_start_stream;
++		u8 he_mu_spatial;
++		le16 tx_power_alpha;
++		u8 ack_policy;
++		u8 ru_allo_ps160;
++	} usr[16];
++};
++
++struct connac3_muru_ul {
++	u8 user_num;
++	u8 tx_mode;
++
++	u8 ba_type;
++	u8 _rsv;
++
++	u8 bw;
++	u8 gi_ltf;
++	le16 ul_len;
++
++	le16 trig_cnt;
++	u8 pad;
++	u8 trig_type;
++
++	le16 trig_intv;
++	u8 trig_ta[ETH_ALEN];
++	le16 ul_ru[16];
++
++	u8 c26[2];
++	le16 agc_disp_linkMFG;
++
++	u8 agc_disp_mu_len;
++	u8 agc_disp_pol;
++	u8 agc_disp_ratio;
++	u8 agc_disp_pu_idx;
++
++	struct {
++		le16 wlan_idx;
++		u8 ru_alloc_seg;
++		u8 ru_idx;
++		u8 ldpc;
++		u8 nss;
++		u8 mcs;
++		u8 target_rssi;
++		le32 trig_pkt_size;
++		u8 ru_allo_ps160;
++		u8 _rsv2[3];
++	} usr[16];
++};
++
++struct connac3_muru_dbg {
++	/* HE TB RX Debug */
++	le32 rx_hetb_nonsf_en_bitmap;
++	le32 rx_hetb_cfg[2];
++};
++
++struct connac3_muru {
++	le32 cfg_comm;
++	le32 cfg_dl;
++	le32 cfg_ul;
++	le32 cfg_dbg;
++
++	struct connac3_muru_comm comm;
++	struct connac3_muru_dl dl;
++	struct connac3_muru_ul ul;
++	struct connac3_muru_dbg dbg;
++};
++
++#define MURU_OFDMA_SCH_TYPE_DL	BIT(0)
++#define MURU_OFDMA_SCH_TYPE_UL	BIT(1)
++#define MURU_PPDU_HE_TRIG	BIT(2)
++#define MURU_PPDU_HE_MU		BIT(3)
++
++/* Common Config */
++#define MURU_COMM_PPDU_FMT	BIT(0)
++#define MURU_COMM_BAND		BIT(2)
++#define MURU_COMM_WMM		BIT(3)
++#define MURU_COMM_SPE_IDX	BIT(4)
++#define MURU_COMM_SET		(MURU_COMM_PPDU_FMT | MURU_COMM_BAND | \
++				 MURU_COMM_WMM | MURU_COMM_SPE_IDX)
++
++/* DL Common config */
++#define MURU_FIXED_DL_BW		BIT(0)
++#define MURU_FIXED_DL_GI		BIT(1)
++#define MURU_FIXED_DL_TONE_PLAN		BIT(3)
++#define MURU_FIXED_DL_TOTAL_USER_CNT	BIT(4)
++#define MURU_FIXED_DL_LTF		BIT(5)
++#define MURU_FIXED_DL_ACK_PLY		BIT(9)
++
++/* DL Per User Config */
++#define MURU_FIXED_USER_DL_COD		BIT(17)
++#define MURU_FIXED_USER_DL_MCS		BIT(18)
++#define MURU_FIXED_USER_DL_RU_ALLOC	BIT(20)
++
++/* UL Common Config */
++#define MURU_FIXED_UL_TOTAL_USER_CNT	BIT(4)
++#define MURU_FIXED_UL_BW		BIT(5)
++#define MURU_FIXED_UL_GILTF		BIT(6)
++
++/* UL Per User Config */
++#define MURU_FIXED_USER_UL_COD		BIT(18)
++#define MURU_FIXED_USER_UL_MCS		BIT(19)
++#define MURU_FIXED_USER_UL_NSS		BIT(20)
++#define MURU_FIXED_USER_UL_RU_ALLOC	BIT(21)
++
+ #endif /* MTK_VENDOR_H */
+diff --git a/src/drivers/driver.h b/src/drivers/driver.h
+index 6cd4dc9..bc7dcca 100644
+--- a/src/drivers/driver.h
++++ b/src/drivers/driver.h
+@@ -5021,7 +5021,7 @@ struct wpa_driver_ops {
+ 	 * @priv: Private driver interface data
+ 	 *
+ 	 */
+-	 int (*mu_ctrl)(void *priv, u8 mode, u8 val);
++	 int (*mu_ctrl)(void *priv, u8 mode, void *config);
+ 	 int (*mu_dump)(void *priv, u8 *mu_onoff);
+ 
+ 	/**
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index ccfc2d0..dd6580f 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -13296,12 +13296,13 @@ fail:
+ 
+ 
+ #ifdef CONFIG_IEEE80211AX
+-static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
++static int nl80211_mu_ctrl(void *priv, u8 mode, void *config)
+ {
+ 	struct i802_bss *bss = priv;
+ 	struct wpa_driver_nl80211_data *drv = bss->drv;
+ 	struct nl_msg *msg;
+ 	struct nlattr *data;
++	struct hostapd_config *cfg = config;
+ 	int ret = -ENOBUFS;
+ 
+ 	if (!drv->mtk_mu_vendor_cmd_avail) {
+@@ -13318,17 +13319,16 @@ static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
+ 
+ 	switch (mode) {
+ 	case MU_CTRL_ONOFF:
+-			if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_ONOFF, val))
+-				goto fail;
++		if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_ONOFF, cfg->mu_onoff))
++			goto fail;
+ 		break;
+-	case MU_CTRL_UL_USER_CNT:
+-	case MU_CTRL_DL_USER_CNT:
+-			if (nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_OFDMA_MODE, mode) ||
+-			    nla_put_u8(msg, MTK_VENDOR_ATTR_MU_CTRL_OFDMA_VAL, val))
+-				goto fail;
++	case MU_CTRL_UPDATE:
++		if (nla_put(msg, MTK_VENDOR_ATTR_MU_CTRL_STRUCT,
++			    sizeof(struct connac3_muru), cfg->muru_config))
++			goto fail;
+ 		break;
+ 	default:
+-		wpa_printf(MSG_ERROR, "nl80211: Wrong mu mode !");
++		wpa_printf(MSG_ERROR, "nl80211: Wrong mu mode %u!", mode);
+ 		ret = -EINVAL;
+ 		goto fail;
+ 	}
+@@ -13336,9 +13336,8 @@ static int nl80211_mu_ctrl(void *priv, u8 mode, u8 val)
+ 	nla_nest_end(msg, data);
+ 
+ 	ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+-	if(ret){
++	if (ret)
+ 		wpa_printf(MSG_ERROR, "Failed to set mu_ctrl. ret=%d (%s)", ret, strerror(-ret));
+-	}
+ 	return ret;
+ 
+ fail:
+-- 
+2.18.0
+
diff --git a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
index a0c06b1..8e652e0 100644
--- a/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
+++ b/recipes-wifi/wpa-supplicant/files/patches-2.10.3/patches.inc
@@ -88,6 +88,7 @@
     file://mtk-0028-hostapd-mtk-Add-muru-user-number-debug-command.patch \
     file://mtk-0029-hostapd-mtk-Fix-CCA-issue.patch \
     file://mtk-0030-hostapd-mtk-Fix-unexpected-AP-beacon-state-transitio.patch \
+    file://mtk-0031-hostapd-mtk-add-connac3-PHY-MURU-manual-mode-config-.patch \
     file://mtk-0032-hostapd-mtk-Add-HE-capabilities-check.patch \
     file://mtk-0100-hostapd-mtk-update-eht-operation-element.patch \
     file://mtk-0103-hostapd-mtk-Add-BW320-channel-switch-command.patch \