[Refactor and sync wifi from Openwrt]

[Description]
Refactor and sync wifi from Openwrt
1.mt76/mac80211/hostapd

[Release-log]
N/A

diff --git a/recipes-connectivity/hostapd/files/patches/912-master-add-destination-address-of-unsolicited-probe.patch b/recipes-connectivity/hostapd/files/patches/912-master-add-destination-address-of-unsolicited-probe.patch
deleted file mode 100644
index ae57f36..0000000
--- a/recipes-connectivity/hostapd/files/patches/912-master-add-destination-address-of-unsolicited-probe.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From b5928412d6debbaf624f9d91650b3a60443e3099 Mon Sep 17 00:00:00 2001
-From: MeiChia Chiu <meichia.chiu@mediatek.com>
-Date: Tue, 26 Apr 2022 11:21:14 +0800
-Subject: [PATCH] hostapd: add destination address of unsolicited probe
- response
-
-without this patch, hostapd generates probe responses with
-null destination address when ap enables unsolicited probe response.
-
-Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
----
- src/ap/beacon.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/ap/beacon.c b/src/ap/beacon.c
-index 8cd1c4170..3c49653cc 100644
---- a/src/ap/beacon.c
-+++ b/src/ap/beacon.c
-@@ -484,6 +484,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
- 					   WLAN_FC_STYPE_PROBE_RESP);
- 	if (req)
- 		os_memcpy(resp->da, req->sa, ETH_ALEN);
-+	else if (hapd->conf->unsol_bcast_probe_resp_interval > 0)
-+		os_memset(resp->da, 0xff, ETH_ALEN);
-+
- 	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
- 
- 	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
--- 
-2.29.2
-
diff --git a/recipes-connectivity/hostapd/files/patches/912-master-add-the-destination-address-of-unsolicited-Probe.patch b/recipes-connectivity/hostapd/files/patches/912-master-add-the-destination-address-of-unsolicited-Probe.patch
new file mode 100644
index 0000000..e9b630f
--- /dev/null
+++ b/recipes-connectivity/hostapd/files/patches/912-master-add-the-destination-address-of-unsolicited-Probe.patch
@@ -0,0 +1,71 @@
+From 96a7f383290f78e15f1e7a5bc33099c81f104c5b Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Fri, 6 May 2022 11:02:36 +0800
+Subject: hostapd: Add the destination address of unsolicited Probe Response
+ frame
+
+Without this, hostapd generates Probe Response frames with the null
+destination address when hostapd enables unsolicited Probe Response
+frame transmission. Fix this to use the broadcast address instead.
+
+Fixes: 024b4b2a298f ("AP: Unsolicited broadcast Probe Response configuration")
+Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
+---
+ src/ap/beacon.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/src/ap/beacon.c b/src/ap/beacon.c
+index eaa403326..58872bfda 100644
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -464,7 +464,8 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
+ 
+ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 				   const struct ieee80211_mgmt *req,
+-				   int is_p2p, size_t *resp_len)
++				   int is_p2p, size_t *resp_len,
++				   bool bcast_probe_resp)
+ {
+ 	struct ieee80211_mgmt *resp;
+ 	u8 *pos, *epos, *csa_pos;
+@@ -531,6 +532,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 					   WLAN_FC_STYPE_PROBE_RESP);
+ 	if (req)
+ 		os_memcpy(resp->da, req->sa, ETH_ALEN);
++	else if (bcast_probe_resp)
++		os_memset(resp->da, 0xff, ETH_ALEN);
++
+ 	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+ 
+ 	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+@@ -1141,7 +1145,7 @@ void handle_probe_req(struct hostapd_data *hapd,
+ 		     " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+ 
+ 	resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
+-				      &resp_len);
++				      &resp_len, false);
+ 	if (resp == NULL)
+ 		return;
+ 
+@@ -1210,7 +1214,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+ 			   "this");
+ 
+ 	/* Generate a Probe Response template for the non-P2P case */
+-	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
++	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false);
+ }
+ 
+ #endif /* NEED_AP_MLME */
+@@ -1228,7 +1232,8 @@ static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ 		hapd->conf->unsol_bcast_probe_resp_interval;
+ 
+ 	return hostapd_gen_probe_resp(hapd, NULL, 0,
+-				      &params->unsol_bcast_probe_resp_tmpl_len);
++				      &params->unsol_bcast_probe_resp_tmpl_len,
++				      true);
+ }
+ #endif /* CONFIG_IEEE80211AX */
+ 
+-- 
+cgit v1.2.3-18-g5258
+
diff --git a/recipes-connectivity/hostapd/files/patches/913-master-add-support-for-runtime-set-in-band-discover.patch b/recipes-connectivity/hostapd/files/patches/913-master-add-support-for-runtime-set-in-band-discover.patch
new file mode 100644
index 0000000..306b221
--- /dev/null
+++ b/recipes-connectivity/hostapd/files/patches/913-master-add-support-for-runtime-set-in-band-discover.patch
@@ -0,0 +1,204 @@
+From 8c9d9f2b8da1b0e3e0832e7d7b02d75c4c0a4f3e Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Thu, 24 May 2022 21:48:21 +0800
+Subject: [PATCH] hostapd:v2 add support for runtime set in-band discovery-v2
+
+Usage:
+hostapd_cli unsolic_probe_resp [tx_type] [interval]
+
+0: disable all in-band discovery
+1: enable unsolicited probe response
+2: enable FILS discovery
+
+Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
+---
+ hostapd/ctrl_iface.c         | 62 ++++++++++++++++++++++++++++++++++++
+ hostapd/hostapd_cli.c        | 20 ++++++++++++
+ src/ap/beacon.c              |  5 ++-
+ src/drivers/driver_nl80211.c |  8 +++--
+ src/drivers/nl80211_copy.h   |  1 +
+ 5 files changed, 92 insertions(+), 4 deletions(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 86adf18e5..41740cfd5 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -769,6 +769,65 @@ static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+ 
+ #endif /* CONFIG_INTERWORKING */
+ 
++static int hostapd_ctrl_iface_inband_discovery(struct hostapd_data *hapd,
++					       const char *cmd)
++{
++	struct hostapd_bss_config *conf = hapd->conf;
++	const char *pos = cmd;
++	int tx_type, interval, ret;
++
++	tx_type = atoi(pos);
++	if (tx_type < 0 || tx_type > 2) {
++		wpa_printf(MSG_ERROR, "Invalid tx type\n");
++		return -1;
++	}
++
++	pos = os_strchr(pos, ' ');
++	if(!pos)
++		return -1;
++	pos++;
++	interval = atoi(pos);
++	if (interval < 0 || interval > 20) {
++		wpa_printf(MSG_ERROR, "Invalid interval value\n");
++		return -1;
++	}
++
++	wpa_printf(MSG_ERROR, "Set inband discovery type:%d, interval:%d\n",
++			      tx_type, interval);
++
++#define DISABLE_INBAND_DISC 0
++#define UNSOL_PROBE_RESP 1
++#define FILS_DISCOVERY 2
++
++	conf->fils_discovery_max_int = 0;
++	conf->fils_discovery_min_int = 0;
++	conf->unsol_bcast_probe_resp_interval = 0;
++
++	switch (tx_type) {
++	case DISABLE_INBAND_DISC:
++	default:
++		/* Disable both Unsolicited probe response and FILS discovery*/
++		break;
++	case UNSOL_PROBE_RESP:
++		/* Enable Unsolicited probe response */
++		conf->unsol_bcast_probe_resp_interval = interval;
++		break;
++	case FILS_DISCOVERY:
++		/* Enable FILS discovery */
++		conf->fils_discovery_min_int = interval;
++		conf->fils_discovery_max_int = interval;
++		break;
++	}
++
++	ret = ieee802_11_update_beacons(hapd->iface);
++	if(ret) {
++		wpa_printf(MSG_DEBUG,
++			"Failed to update with inband discovery parameters\n");
++		return -1;
++	}
++
++	return 0;
++}
+ 
+ #ifdef CONFIG_WNM_AP
+ 
+@@ -3673,6 +3732,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 		if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
+ 			reply_len = -1;
+ #endif /* CONFIG_WNM_AP */
++	} else if (os_strncmp(buf, "INBAND_DISCOVERY ", 17) == 0) {
++		if (hostapd_ctrl_iface_inband_discovery(hapd, buf + 17))
++			reply_len = -1;
+ 	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
+ 		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
+ 							  reply_size);
+diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
+index 260912111..e30c4e7c1 100644
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -646,6 +646,24 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
+ }
+ #endif /* CONFIG_WPS */
+ 
++static int hostapd_cli_cmd_inband_discovery(struct wpa_ctrl *ctrl, int argc,
++					    char *argv[])
++{
++	char buf[300];
++	int res;
++
++	if (argc < 2) {
++		printf("Invalid 'inband_discovery' command - two arguments"
++		       "tx_type interval\n");
++		return -1;
++	}
++
++	res = os_snprintf(buf, sizeof(buf), "INBAND_DISCOVERY %s %s",
++			  argv[0], argv[1]);
++	if (os_snprintf_error(sizeof(buf), res))
++		return -1;
++	return wpa_ctrl_command(ctrl, buf);
++}
+ 
+ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+ 					     char *argv[])
+@@ -1744,6 +1762,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
+ 	{ "driver", hostapd_cli_cmd_driver, NULL,
+ 	  "<driver sub command> [<hex formatted data>] = send driver command data" },
+ #endif /* ANDROID */
++	{ "inband_discovery", hostapd_cli_cmd_inband_discovery, NULL,
++          "<tx type(0/1/2)> <interval> = runtime set inband discovery" },
+ 	{ NULL, NULL, NULL, NULL }
+ };
+ 
+diff --git a/src/ap/beacon.c b/src/ap/beacon.c
+index 3c49653cc..367e32611 100644
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -1406,6 +1406,8 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ 				   struct wpa_driver_ap_params *params)
+ {
+ 	params->fd_max_int = hapd->conf->fils_discovery_max_int;
++	params->unsol_bcast_probe_resp_interval =
++		hapd->conf->unsol_bcast_probe_resp_interval;
+ 	if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ 	    params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
+ 		params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
+@@ -1414,7 +1416,8 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ 	if (params->fd_min_int > params->fd_max_int)
+ 		params->fd_min_int = params->fd_max_int;
+ 
+-	if (params->fd_max_int)
++	if (params->fd_max_int ||
++	    !params->unsol_bcast_probe_resp_interval)
+ 		return hostapd_gen_fils_discovery(hapd,
+ 						  &params->fd_frame_tmpl_len);
+ 
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index aec179ac3..6113aff0b 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4491,9 +4491,10 @@ static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
+ 			params->fd_max_int) ||
+ 	    (params->fd_frame_tmpl &&
+ 	     nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
+-		     params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
++		     params->fd_frame_tmpl_len, params->fd_frame_tmpl)) ||
++	    nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE,
++			params->unsol_bcast_probe_resp_interval))
+ 		return -1;
+-
+ 	nla_nest_end(msg, attr);
+ 	return 0;
+ }
+@@ -4823,7 +4824,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
+ #endif /* CONFIG_SAE */
+ 
+ #ifdef CONFIG_FILS
+-	if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
++	if ((params->fd_max_int || !(params->unsol_bcast_probe_resp_interval)) &&
++	     nl80211_fils_discovery(bss, msg, params) < 0)
+ 		goto fail;
+ #endif /* CONFIG_FILS */
+ 
+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
+index f962c06e9..6fb7b7fcf 100644
+--- a/src/drivers/nl80211_copy.h
++++ b/src/drivers/nl80211_copy.h
+@@ -7150,6 +7150,7 @@ enum nl80211_fils_discovery_attributes {
+ 	NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ 	NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ 	NL80211_FILS_DISCOVERY_ATTR_TMPL,
++	NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE,
+ 
+ 	/* keep last */
+ 	__NL80211_FILS_DISCOVERY_ATTR_LAST,
+-- 
+2.29.2
+
diff --git a/recipes-connectivity/hostapd/files/patches/patches.inc b/recipes-connectivity/hostapd/files/patches/patches.inc
index 8db63c7..36ec650 100644
--- a/recipes-connectivity/hostapd/files/patches/patches.inc
+++ b/recipes-connectivity/hostapd/files/patches/patches.inc
@@ -61,5 +61,6 @@
     file://909-master-Add-hostapd_neighbor_set_own_report_pref.patch \
     file://910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch \
     file://911-master-print-sae-groups-by-hostapd-ctrl.patch \
-    file://912-master-add-destination-address-of-unsolicited-probe.patch \
+    file://912-master-add-the-destination-address-of-unsolicited-Probe.patch \
+    file://913-master-add-support-for-runtime-set-in-band-discover.patch \
     "
diff --git a/recipes-connectivity/hostapd/hostapd_2.10.bb b/recipes-connectivity/hostapd/hostapd_2.10.bb
index 8560d43..0a487db 100644
--- a/recipes-connectivity/hostapd/hostapd_2.10.bb
+++ b/recipes-connectivity/hostapd/hostapd_2.10.bb
@@ -59,6 +59,7 @@
     echo "CONFIG_AP=y" >> ${B}/.config
     echo "CONFIG_MESH=y" >> ${B}/.config
     echo "CONFIG_WEP=y" >> ${B}/.config
+    echo "CONFIG_FILS=y" >> ${B}/.config
 }
 
 SRC_URI_append_mt7915 += " \
diff --git a/recipes-connectivity/wpa-supplicant/files/patches/912-master-add-destination-address-of-unsolicited-probe.patch b/recipes-connectivity/wpa-supplicant/files/patches/912-master-add-destination-address-of-unsolicited-probe.patch
deleted file mode 100644
index ae57f36..0000000
--- a/recipes-connectivity/wpa-supplicant/files/patches/912-master-add-destination-address-of-unsolicited-probe.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From b5928412d6debbaf624f9d91650b3a60443e3099 Mon Sep 17 00:00:00 2001
-From: MeiChia Chiu <meichia.chiu@mediatek.com>
-Date: Tue, 26 Apr 2022 11:21:14 +0800
-Subject: [PATCH] hostapd: add destination address of unsolicited probe
- response
-
-without this patch, hostapd generates probe responses with
-null destination address when ap enables unsolicited probe response.
-
-Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
----
- src/ap/beacon.c | 3 +++
- 1 file changed, 3 insertions(+)
-
-diff --git a/src/ap/beacon.c b/src/ap/beacon.c
-index 8cd1c4170..3c49653cc 100644
---- a/src/ap/beacon.c
-+++ b/src/ap/beacon.c
-@@ -484,6 +484,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
- 					   WLAN_FC_STYPE_PROBE_RESP);
- 	if (req)
- 		os_memcpy(resp->da, req->sa, ETH_ALEN);
-+	else if (hapd->conf->unsol_bcast_probe_resp_interval > 0)
-+		os_memset(resp->da, 0xff, ETH_ALEN);
-+
- 	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
- 
- 	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
--- 
-2.29.2
-
diff --git a/recipes-connectivity/wpa-supplicant/files/patches/912-master-add-the-destination-address-of-unsolicited-Probe.patch b/recipes-connectivity/wpa-supplicant/files/patches/912-master-add-the-destination-address-of-unsolicited-Probe.patch
new file mode 100644
index 0000000..e9b630f
--- /dev/null
+++ b/recipes-connectivity/wpa-supplicant/files/patches/912-master-add-the-destination-address-of-unsolicited-Probe.patch
@@ -0,0 +1,71 @@
+From 96a7f383290f78e15f1e7a5bc33099c81f104c5b Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Fri, 6 May 2022 11:02:36 +0800
+Subject: hostapd: Add the destination address of unsolicited Probe Response
+ frame
+
+Without this, hostapd generates Probe Response frames with the null
+destination address when hostapd enables unsolicited Probe Response
+frame transmission. Fix this to use the broadcast address instead.
+
+Fixes: 024b4b2a298f ("AP: Unsolicited broadcast Probe Response configuration")
+Signed-off-by: MeiChia Chiu <meichia.chiu@mediatek.com>
+---
+ src/ap/beacon.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/src/ap/beacon.c b/src/ap/beacon.c
+index eaa403326..58872bfda 100644
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -464,7 +464,8 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
+ 
+ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 				   const struct ieee80211_mgmt *req,
+-				   int is_p2p, size_t *resp_len)
++				   int is_p2p, size_t *resp_len,
++				   bool bcast_probe_resp)
+ {
+ 	struct ieee80211_mgmt *resp;
+ 	u8 *pos, *epos, *csa_pos;
+@@ -531,6 +532,9 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+ 					   WLAN_FC_STYPE_PROBE_RESP);
+ 	if (req)
+ 		os_memcpy(resp->da, req->sa, ETH_ALEN);
++	else if (bcast_probe_resp)
++		os_memset(resp->da, 0xff, ETH_ALEN);
++
+ 	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+ 
+ 	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+@@ -1141,7 +1145,7 @@ void handle_probe_req(struct hostapd_data *hapd,
+ 		     " signal=%d", MAC2STR(mgmt->sa), ssi_signal);
+ 
+ 	resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
+-				      &resp_len);
++				      &resp_len, false);
+ 	if (resp == NULL)
+ 		return;
+ 
+@@ -1210,7 +1214,7 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+ 			   "this");
+ 
+ 	/* Generate a Probe Response template for the non-P2P case */
+-	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
++	return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, false);
+ }
+ 
+ #endif /* NEED_AP_MLME */
+@@ -1228,7 +1232,8 @@ static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd,
+ 		hapd->conf->unsol_bcast_probe_resp_interval;
+ 
+ 	return hostapd_gen_probe_resp(hapd, NULL, 0,
+-				      &params->unsol_bcast_probe_resp_tmpl_len);
++				      &params->unsol_bcast_probe_resp_tmpl_len,
++				      true);
+ }
+ #endif /* CONFIG_IEEE80211AX */
+ 
+-- 
+cgit v1.2.3-18-g5258
+
diff --git a/recipes-connectivity/wpa-supplicant/files/patches/913-master-add-support-for-runtime-set-in-band-discover.patch b/recipes-connectivity/wpa-supplicant/files/patches/913-master-add-support-for-runtime-set-in-band-discover.patch
new file mode 100644
index 0000000..306b221
--- /dev/null
+++ b/recipes-connectivity/wpa-supplicant/files/patches/913-master-add-support-for-runtime-set-in-band-discover.patch
@@ -0,0 +1,204 @@
+From 8c9d9f2b8da1b0e3e0832e7d7b02d75c4c0a4f3e Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Thu, 24 May 2022 21:48:21 +0800
+Subject: [PATCH] hostapd:v2 add support for runtime set in-band discovery-v2
+
+Usage:
+hostapd_cli unsolic_probe_resp [tx_type] [interval]
+
+0: disable all in-band discovery
+1: enable unsolicited probe response
+2: enable FILS discovery
+
+Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
+---
+ hostapd/ctrl_iface.c         | 62 ++++++++++++++++++++++++++++++++++++
+ hostapd/hostapd_cli.c        | 20 ++++++++++++
+ src/ap/beacon.c              |  5 ++-
+ src/drivers/driver_nl80211.c |  8 +++--
+ src/drivers/nl80211_copy.h   |  1 +
+ 5 files changed, 92 insertions(+), 4 deletions(-)
+
+diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
+index 86adf18e5..41740cfd5 100644
+--- a/hostapd/ctrl_iface.c
++++ b/hostapd/ctrl_iface.c
+@@ -769,6 +769,65 @@ static int hostapd_ctrl_iface_send_qos_map_conf(struct hostapd_data *hapd,
+ 
+ #endif /* CONFIG_INTERWORKING */
+ 
++static int hostapd_ctrl_iface_inband_discovery(struct hostapd_data *hapd,
++					       const char *cmd)
++{
++	struct hostapd_bss_config *conf = hapd->conf;
++	const char *pos = cmd;
++	int tx_type, interval, ret;
++
++	tx_type = atoi(pos);
++	if (tx_type < 0 || tx_type > 2) {
++		wpa_printf(MSG_ERROR, "Invalid tx type\n");
++		return -1;
++	}
++
++	pos = os_strchr(pos, ' ');
++	if(!pos)
++		return -1;
++	pos++;
++	interval = atoi(pos);
++	if (interval < 0 || interval > 20) {
++		wpa_printf(MSG_ERROR, "Invalid interval value\n");
++		return -1;
++	}
++
++	wpa_printf(MSG_ERROR, "Set inband discovery type:%d, interval:%d\n",
++			      tx_type, interval);
++
++#define DISABLE_INBAND_DISC 0
++#define UNSOL_PROBE_RESP 1
++#define FILS_DISCOVERY 2
++
++	conf->fils_discovery_max_int = 0;
++	conf->fils_discovery_min_int = 0;
++	conf->unsol_bcast_probe_resp_interval = 0;
++
++	switch (tx_type) {
++	case DISABLE_INBAND_DISC:
++	default:
++		/* Disable both Unsolicited probe response and FILS discovery*/
++		break;
++	case UNSOL_PROBE_RESP:
++		/* Enable Unsolicited probe response */
++		conf->unsol_bcast_probe_resp_interval = interval;
++		break;
++	case FILS_DISCOVERY:
++		/* Enable FILS discovery */
++		conf->fils_discovery_min_int = interval;
++		conf->fils_discovery_max_int = interval;
++		break;
++	}
++
++	ret = ieee802_11_update_beacons(hapd->iface);
++	if(ret) {
++		wpa_printf(MSG_DEBUG,
++			"Failed to update with inband discovery parameters\n");
++		return -1;
++	}
++
++	return 0;
++}
+ 
+ #ifdef CONFIG_WNM_AP
+ 
+@@ -3673,6 +3732,9 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
+ 		if (hostapd_ctrl_iface_coloc_intf_req(hapd, buf + 15))
+ 			reply_len = -1;
+ #endif /* CONFIG_WNM_AP */
++	} else if (os_strncmp(buf, "INBAND_DISCOVERY ", 17) == 0) {
++		if (hostapd_ctrl_iface_inband_discovery(hapd, buf + 17))
++			reply_len = -1;
+ 	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
+ 		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
+ 							  reply_size);
+diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
+index 260912111..e30c4e7c1 100644
+--- a/hostapd/hostapd_cli.c
++++ b/hostapd/hostapd_cli.c
+@@ -646,6 +646,24 @@ static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
+ }
+ #endif /* CONFIG_WPS */
+ 
++static int hostapd_cli_cmd_inband_discovery(struct wpa_ctrl *ctrl, int argc,
++					    char *argv[])
++{
++	char buf[300];
++	int res;
++
++	if (argc < 2) {
++		printf("Invalid 'inband_discovery' command - two arguments"
++		       "tx_type interval\n");
++		return -1;
++	}
++
++	res = os_snprintf(buf, sizeof(buf), "INBAND_DISCOVERY %s %s",
++			  argv[0], argv[1]);
++	if (os_snprintf_error(sizeof(buf), res))
++		return -1;
++	return wpa_ctrl_command(ctrl, buf);
++}
+ 
+ static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+ 					     char *argv[])
+@@ -1744,6 +1762,8 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = {
+ 	{ "driver", hostapd_cli_cmd_driver, NULL,
+ 	  "<driver sub command> [<hex formatted data>] = send driver command data" },
+ #endif /* ANDROID */
++	{ "inband_discovery", hostapd_cli_cmd_inband_discovery, NULL,
++          "<tx type(0/1/2)> <interval> = runtime set inband discovery" },
+ 	{ NULL, NULL, NULL, NULL }
+ };
+ 
+diff --git a/src/ap/beacon.c b/src/ap/beacon.c
+index 3c49653cc..367e32611 100644
+--- a/src/ap/beacon.c
++++ b/src/ap/beacon.c
+@@ -1406,6 +1406,8 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ 				   struct wpa_driver_ap_params *params)
+ {
+ 	params->fd_max_int = hapd->conf->fils_discovery_max_int;
++	params->unsol_bcast_probe_resp_interval =
++		hapd->conf->unsol_bcast_probe_resp_interval;
+ 	if (is_6ghz_op_class(hapd->iconf->op_class) &&
+ 	    params->fd_max_int > FD_MAX_INTERVAL_6GHZ)
+ 		params->fd_max_int = FD_MAX_INTERVAL_6GHZ;
+@@ -1414,7 +1416,8 @@ static u8 * hostapd_fils_discovery(struct hostapd_data *hapd,
+ 	if (params->fd_min_int > params->fd_max_int)
+ 		params->fd_min_int = params->fd_max_int;
+ 
+-	if (params->fd_max_int)
++	if (params->fd_max_int ||
++	    !params->unsol_bcast_probe_resp_interval)
+ 		return hostapd_gen_fils_discovery(hapd,
+ 						  &params->fd_frame_tmpl_len);
+ 
+diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
+index aec179ac3..6113aff0b 100644
+--- a/src/drivers/driver_nl80211.c
++++ b/src/drivers/driver_nl80211.c
+@@ -4491,9 +4491,10 @@ static int nl80211_fils_discovery(struct i802_bss *bss, struct nl_msg *msg,
+ 			params->fd_max_int) ||
+ 	    (params->fd_frame_tmpl &&
+ 	     nla_put(msg, NL80211_FILS_DISCOVERY_ATTR_TMPL,
+-		     params->fd_frame_tmpl_len, params->fd_frame_tmpl)))
++		     params->fd_frame_tmpl_len, params->fd_frame_tmpl)) ||
++	    nla_put_u32(msg, NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE,
++			params->unsol_bcast_probe_resp_interval))
+ 		return -1;
+-
+ 	nla_nest_end(msg, attr);
+ 	return 0;
+ }
+@@ -4823,7 +4824,8 @@ static int wpa_driver_nl80211_set_ap(void *priv,
+ #endif /* CONFIG_SAE */
+ 
+ #ifdef CONFIG_FILS
+-	if (params->fd_max_int && nl80211_fils_discovery(bss, msg, params) < 0)
++	if ((params->fd_max_int || !(params->unsol_bcast_probe_resp_interval)) &&
++	     nl80211_fils_discovery(bss, msg, params) < 0)
+ 		goto fail;
+ #endif /* CONFIG_FILS */
+ 
+diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
+index f962c06e9..6fb7b7fcf 100644
+--- a/src/drivers/nl80211_copy.h
++++ b/src/drivers/nl80211_copy.h
+@@ -7150,6 +7150,7 @@ enum nl80211_fils_discovery_attributes {
+ 	NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ 	NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ 	NL80211_FILS_DISCOVERY_ATTR_TMPL,
++	NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE,
+ 
+ 	/* keep last */
+ 	__NL80211_FILS_DISCOVERY_ATTR_LAST,
+-- 
+2.29.2
+
diff --git a/recipes-connectivity/wpa-supplicant/files/patches/patches.inc b/recipes-connectivity/wpa-supplicant/files/patches/patches.inc
index 8db63c7..36ec650 100644
--- a/recipes-connectivity/wpa-supplicant/files/patches/patches.inc
+++ b/recipes-connectivity/wpa-supplicant/files/patches/patches.inc
@@ -61,5 +61,6 @@
     file://909-master-Add-hostapd_neighbor_set_own_report_pref.patch \
     file://910-master-Add-hostapd_neighbor_set_pref_by_non_pref_chan.patch \
     file://911-master-print-sae-groups-by-hostapd-ctrl.patch \
-    file://912-master-add-destination-address-of-unsolicited-probe.patch \
+    file://912-master-add-the-destination-address-of-unsolicited-Probe.patch \
+    file://913-master-add-support-for-runtime-set-in-band-discover.patch \
     "
diff --git a/recipes-connectivity/wpa-supplicant/files/wpa_supplicant-full.config b/recipes-connectivity/wpa-supplicant/files/wpa_supplicant-full.config
index 800c18c..1397111 100644
--- a/recipes-connectivity/wpa-supplicant/files/wpa_supplicant-full.config
+++ b/recipes-connectivity/wpa-supplicant/files/wpa_supplicant-full.config
@@ -618,6 +618,7 @@
 # Services can connect to the bus and provide methods
 # that can be called by other services or clients.
 
+
 # OpenWrt patch 380-disable-ctrl-iface-mib.patch
 # leads to the MIB only being compiled in if
 # CONFIG_CTRL_IFACE_MIB is enabled.
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
new file mode 100644
index 0000000..5924a05
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/350-bss-color-collision.patch
@@ -0,0 +1,118 @@
+From 6d945a33f2b0aa24fc210dadaa0af3e8218e7002 Mon Sep 17 00:00:00 2001
+From: Lorenzo Bianconi <lorenzo@kernel.org>
+Date: Fri, 25 Mar 2022 11:42:41 +0100
+Subject: [PATCH] mac80211: introduce BSS color collision detection
+
+Add ieee80211_rx_check_bss_color_collision routine in order to introduce
+BSS color collision detection in mac80211 if it is not supported in HW/FW
+(e.g. for mt7915 chipset).
+Add IEEE80211_HW_DETECTS_COLOR_COLLISION flag to let the driver notify
+BSS color collision detection is supported in HW/FW. Set this for ath11k
+which apparently didn't need this code.
+
+Tested-by: Peter Chiu <Chui-Hao.Chiu@mediatek.com>
+Co-developed-by: Ryder Lee <ryder.lee@mediatek.com>
+Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
+Link: https://lore.kernel.org/r/a05eeeb1841a84560dc5aaec77894fcb69a54f27.1648204871.git.lorenzo@kernel.org
+[clarify commit message a bit, move flag to mac80211]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ drivers/net/wireless/ath/ath11k/mac.c |  5 ++-
+ include/net/mac80211.h                |  4 +++
+ net/mac80211/debugfs.c                |  1 +
+ net/mac80211/rx.c                     | 46 +++++++++++++++++++++++++++
+ 4 files changed, 55 insertions(+), 1 deletion(-)
+
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -2418,6 +2418,9 @@ struct ieee80211_txq {
+  *	usage and 802.11 frames with %RX_FLAG_ONLY_MONITOR set for monitor to
+  *	the stack.
+  *
++ * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color
++ *	collision detection and doesn't need it in software.
++ *
+  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
+  */
+ enum ieee80211_hw_flags {
+@@ -2473,6 +2476,7 @@ enum ieee80211_hw_flags {
+ 	IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
+ 	IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD,
+ 	IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP,
++	IEEE80211_HW_DETECTS_COLOR_COLLISION,
+ 
+ 	/* keep last, obviously */
+ 	NUM_IEEE80211_HW_FLAGS
+--- a/net/mac80211/debugfs.c
++++ b/net/mac80211/debugfs.c
+@@ -504,6 +504,7 @@ static const char *hw_flag_names[] = {
+ 	FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
+ 	FLAG(SUPPORTS_RX_DECAP_OFFLOAD),
+ 	FLAG(SUPPORTS_CONC_MON_RX_DECAP),
++	FLAG(DETECTS_COLOR_COLLISION),
+ #undef FLAG
+ };
+ 
+--- a/net/mac80211/rx.c
++++ b/net/mac80211/rx.c
+@@ -3177,6 +3177,49 @@ static void ieee80211_process_sa_query_r
+ 	ieee80211_tx_skb(sdata, skb);
+ }
+ 
++static void
++ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
++{
++	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
++	const struct element *ie;
++	size_t baselen;
++
++	if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
++				     NL80211_EXT_FEATURE_BSS_COLOR))
++		return;
++
++	if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION))
++		return;
++
++	if (rx->sdata->vif.csa_active)
++		return;
++
++	baselen = mgmt->u.beacon.variable - rx->skb->data;
++	if (baselen > rx->skb->len)
++		return;
++
++	ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION,
++				    mgmt->u.beacon.variable,
++				    rx->skb->len - baselen);
++	if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) &&
++	    ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) {
++		struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
++		const struct ieee80211_he_operation *he_oper;
++		u8 color;
++
++		he_oper = (void *)(ie->data + 1);
++		if (le32_get_bits(he_oper->he_oper_params,
++				  IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED))
++			return;
++
++		color = le32_get_bits(he_oper->he_oper_params,
++				      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
++		if (color == bss_conf->he_bss_color.color)
++			ieeee80211_obss_color_collision_notify(&rx->sdata->vif,
++							       BIT_ULL(color));
++	}
++}
++
+ static ieee80211_rx_result debug_noinline
+ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
+ {
+@@ -3202,6 +3245,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802
+ 	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+ 		int sig = 0;
+ 
++		/* sw bss color collision detection */
++		ieee80211_rx_check_bss_color_collision(rx);
++
+ 		if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
+ 		    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
+ 			sig = status->signal;
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/902-nl80211-internal-extend-CAC-time-for-weather-radar-c.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/902-nl80211-internal-extend-CAC-time-for-weather-radar-c.patch
index 04b3270..b6f6d69 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/902-nl80211-internal-extend-CAC-time-for-weather-radar-c.patch
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/902-nl80211-internal-extend-CAC-time-for-weather-radar-c.patch
@@ -17,9 +17,9 @@
  		cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
  
 +	if ((dfs_region == NL80211_DFS_ETSI) &&
-+	    ((chandef.width == NL80211_CHAN_WIDTH_160) &&
++	    (((chandef.width == NL80211_CHAN_WIDTH_160) &&
 +	     (chandef.center_freq2 >= 5580 && chandef.center_freq2 <= 5640)) ||
-+	    (chandef.center_freq1 >= 5580 && chandef.center_freq1 <= 5640))
++	    (chandef.center_freq1 >= 5580 && chandef.center_freq1 <= 5640)))
 +		cac_time_ms = 600000;
 +	pr_info("%s: region = %u, cetner freq1 = %u, center freq2 = %u, cac time ms = %u\n", __func__, dfs_region, chandef.center_freq1, chandef.center_freq2, cac_time_ms);
 +
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/905-mac80211-airtime_flags-depends-on-NL80211_EXT_FEATUR.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/905-mac80211-airtime_flags-depends-on-NL80211_EXT_FEATUR.patch
new file mode 100644
index 0000000..8325e96
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/905-mac80211-airtime_flags-depends-on-NL80211_EXT_FEATUR.patch
@@ -0,0 +1,19 @@
+diff --git a/net/mac80211/main.c b/net/mac80211/main.c
+index 3a442d8..f355cd3 100644
+--- a/net/mac80211/main.c
++++ b/net/mac80211/main.c
+@@ -723,8 +723,9 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
+ 		air_sched->aql_txq_limit_high =
+ 			IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
+ 	}
+-
+-	local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
++	if (wiphy_ext_feature_isset(local->hw.wiphy,
++			NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
++		local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
+ 	local->aql_threshold = IEEE80211_AQL_THRESHOLD;
+ 	atomic_set(&local->aql_total_pending_airtime, 0);
+ 
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/906-mac80211-add-support-for-runtime-set-inband-discovery.patch b/recipes-kernel/linux-mac80211/files/patches/subsys/906-mac80211-add-support-for-runtime-set-inband-discovery.patch
new file mode 100644
index 0000000..f6fc98f
--- /dev/null
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/906-mac80211-add-support-for-runtime-set-inband-discovery.patch
@@ -0,0 +1,150 @@
+diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
+--- a/include/net/cfg80211.h
++++ b/include/net/cfg80211.h
+@@ -1158,6 +1158,7 @@ struct cfg80211_fils_discovery {
+ 	u32 max_interval;
+ 	size_t tmpl_len;
+ 	const u8 *tmpl;
++	u8 disable;
+ };
+ 
+ /**
+diff --git a/include/net/mac80211.h b/include/net/mac80211.h
+--- a/include/net/mac80211.h
++++ b/include/net/mac80211.h
+@@ -505,6 +505,7 @@ struct ieee80211_ftm_responder_params {
+ struct ieee80211_fils_discovery {
+ 	u32 min_interval;
+ 	u32 max_interval;
++	u8 disable;
+ };
+ 
+ /**
+diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
+--- a/include/uapi/linux/nl80211.h
++++ b/include/uapi/linux/nl80211.h
+@@ -7236,6 +7236,7 @@ enum nl80211_fils_discovery_attributes {
+ 	NL80211_FILS_DISCOVERY_ATTR_INT_MIN,
+ 	NL80211_FILS_DISCOVERY_ATTR_INT_MAX,
+ 	NL80211_FILS_DISCOVERY_ATTR_TMPL,
++	NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE,
+ 
+ 	/* keep last */
+ 	__NL80211_FILS_DISCOVERY_ATTR_LAST,
+diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
+--- a/net/mac80211/cfg.c
++++ b/net/mac80211/cfg.c
+@@ -906,6 +906,7 @@ static int ieee80211_set_fils_discovery(
+ 	fd = &sdata->vif.bss_conf.fils_discovery;
+ 	fd->min_interval = params->min_interval;
+ 	fd->max_interval = params->max_interval;
++	fd->disable = params->disable;
+ 
+ 	old = sdata_dereference(sdata->u.ap.fils_discovery, sdata);
+ 	new = kzalloc(sizeof(*new) + params->tmpl_len, GFP_KERNEL);
+@@ -1316,6 +1317,8 @@ static int ieee80211_change_beacon(struc
+ {
+ 	struct ieee80211_sub_if_data *sdata;
+ 	struct beacon_data *old;
++	struct cfg80211_ap_settings *ap_params;
++	u32 changed;
+ 	int err;
+ 
+ 	sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+@@ -1334,7 +1337,26 @@ static int ieee80211_change_beacon(struc
+ 	err = ieee80211_assign_beacon(sdata, params, NULL, NULL);
+ 	if (err < 0)
+ 		return err;
+-	ieee80211_bss_info_change_notify(sdata, err);
++
++	changed = err;
++	ap_params = container_of(params, struct cfg80211_ap_settings, beacon);
++
++	if(ap_params->unsol_bcast_probe_resp.interval) {
++		err = ieee80211_set_unsol_bcast_probe_resp(sdata,
++							   &ap_params->unsol_bcast_probe_resp);
++		if (err < 0)
++			return err;
++		changed |= BSS_CHANGED_UNSOL_BCAST_PROBE_RESP;
++	} else {
++		err = ieee80211_set_fils_discovery(sdata,
++						   &ap_params->fils_discovery);
++		if (err < 0)
++			return err;
++		changed |= BSS_CHANGED_FILS_DISCOVERY;
++
++	}
++
++	ieee80211_bss_info_change_notify(sdata, changed);
+ 	return 0;
+ }
+ 
+diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
+--- a/net/wireless/nl80211.c
++++ b/net/wireless/nl80211.c
+@@ -421,6 +421,7 @@ nl80211_fils_discovery_policy[NL80211_FI
+ 	[NL80211_FILS_DISCOVERY_ATTR_TMPL] = { .type = NLA_BINARY,
+ 					       .len = IEEE80211_MAX_DATA_LEN },
+ #endif
++	[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE] = NLA_POLICY_MAX(NLA_U32, 20),
+ };
+ 
+ static const struct nla_policy
+@@ -5349,6 +5350,8 @@ static int nl80211_parse_fils_discovery(
+ 	fd->tmpl = nla_data(tb[NL80211_FILS_DISCOVERY_ATTR_TMPL]);
+ 	fd->min_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MIN]);
+ 	fd->max_interval = nla_get_u32(tb[NL80211_FILS_DISCOVERY_ATTR_INT_MAX]);
++	fd->disable = !(fd->max_interval ||
++			nla_get_u32(tb[NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INTE]));
+ 
+ 	return 0;
+ }
+@@ -5754,7 +5757,8 @@ static int nl80211_set_beacon(struct sk_
+ 	struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ 	struct net_device *dev = info->user_ptr[1];
+ 	struct wireless_dev *wdev = dev->ieee80211_ptr;
+-	struct cfg80211_beacon_data params;
++	struct cfg80211_ap_settings ap_params;
++	struct cfg80211_beacon_data *params;
+ 	int err;
+ 
+ 	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+@@ -5767,16 +5771,35 @@ static int nl80211_set_beacon(struct sk_
+ 	if (!wdev->beacon_interval)
+ 		return -EINVAL;
+ 
+-	err = nl80211_parse_beacon(rdev, info->attrs, &params);
++	memset(&ap_params, 0, sizeof(ap_params));
++	params = &ap_params.beacon;
++
++	err = nl80211_parse_beacon(rdev, info->attrs, params);
+ 	if (err)
+ 		goto out;
+ 
++	if (info->attrs[NL80211_ATTR_FILS_DISCOVERY]) {
++		err = nl80211_parse_fils_discovery(rdev,
++			   info->attrs[NL80211_ATTR_FILS_DISCOVERY],
++			   &ap_params);
++		if (err)
++			goto out;
++	}
++
++	if (info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP]) {
++		err = nl80211_parse_unsol_bcast_probe_resp(rdev,
++			   info->attrs[NL80211_ATTR_UNSOL_BCAST_PROBE_RESP],
++			   &ap_params);
++		if (err)
++			goto out;
++	}
++
+ 	wdev_lock(wdev);
+-	err = rdev_change_beacon(rdev, dev, &params);
++	err = rdev_change_beacon(rdev, dev, params);
+ 	wdev_unlock(wdev);
+ 
+ out:
+-	kfree(params.mbssid_ies);
++	kfree(params->mbssid_ies);
+ 	return err;
+ }
+ 
diff --git a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
index 01fd587..89f1e95 100644
--- a/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
+++ b/recipes-kernel/linux-mac80211/files/patches/subsys/subsys.inc
@@ -26,6 +26,7 @@
     file://325-mac80211-MBSSID-channel-switch.patch \
     file://326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch \
     file://329-mac80211-minstrel_ht-fix-where-rate-stats-are-stored.patch \
+    file://350-bss-color-collision.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 \
@@ -33,4 +34,6 @@
     file://902-nl80211-internal-extend-CAC-time-for-weather-radar-c.patch \
     file://903-mac80211-it-s-invalid-case-when-frag_threshold-is-gr.patch \
     file://904-mac80211-correct-legacy-rates-check-in-ieee80211_cal.patch \
+    file://905-mac80211-airtime_flags-depends-on-NL80211_EXT_FEATUR.patch \
+    file://906-mac80211-add-support-for-runtime-set-inband-discovery.patch \
     "
diff --git a/recipes-kernel/linux-mt76/files/patches/0007-mt76-mt7915-update-mt7986-CR-for-different-adie-vers.patch b/recipes-kernel/linux-mt76/files/patches/0007-mt76-mt7915-update-mt7986-CR-for-different-adie-vers.patch
index d5c72aa..1340ac9 100644
--- a/recipes-kernel/linux-mt76/files/patches/0007-mt76-mt7915-update-mt7986-CR-for-different-adie-vers.patch
+++ b/recipes-kernel/linux-mt76/files/patches/0007-mt76-mt7915-update-mt7986-CR-for-different-adie-vers.patch
@@ -1,4 +1,4 @@
-From 87efddcc9bb605802fdabe8bf3408a106bf5b997 Mon Sep 17 00:00:00 2001
+From 14baf1e2df409bdfdf3255dbe8ad5ecc1852b8b0 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Tue, 15 Mar 2022 14:21:13 +0800
 Subject: [PATCH] mt76: mt7915: update mt7986 CR for different adie version
@@ -6,14 +6,14 @@
 Signed-off-by: Peter Chiu <chui-hao.chiu@mediatek.com>
 ---
  mt7915/regs.h |  1 +
- mt7915/soc.c  | 24 +++++++++++++++++++++---
- 2 files changed, 22 insertions(+), 3 deletions(-)
+ mt7915/soc.c  | 21 ++++++++++++++++++---
+ 2 files changed, 19 insertions(+), 3 deletions(-)
 
 diff --git a/mt7915/regs.h b/mt7915/regs.h
-index e5f93c40..a69ba562 100644
+index cb7c7e14..97984aaf 100644
 --- a/mt7915/regs.h
 +++ b/mt7915/regs.h
-@@ -794,6 +794,7 @@ enum offs_rev {
+@@ -822,6 +822,7 @@ enum offs_rev {
  
  /* ADIE */
  #define MT_ADIE_CHIP_ID			0x02c
@@ -22,17 +22,17 @@
  #define MT_ADIE_IDX0			GENMASK(15, 0)
  #define MT_ADIE_IDX1			GENMASK(31, 16)
 diff --git a/mt7915/soc.c b/mt7915/soc.c
-index 04df47fd..e1892368 100644
+index d465f8d8..a977f90a 100644
 --- a/mt7915/soc.c
 +++ b/mt7915/soc.c
-@@ -468,16 +468,34 @@ static int mt7986_wmac_adie_xtal_trim_7976(struct mt7915_dev *dev, u8 adie)
+@@ -469,17 +469,32 @@ static int mt7986_wmac_adie_xtal_trim_7976(struct mt7915_dev *dev, u8 adie)
+ 
  static int mt7986_wmac_adie_patch_7976(struct mt7915_dev *dev, u8 adie)
  {
++	u32 id, version, rg_xo_01, rg_xo_03;
  	int ret;
-+	u32 id, version;
  
 -	ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_TOP_THADC, 0x4a563b00);
-+
 +	ret = mt76_wmac_spi_read(dev, adie, MT_ADIE_CHIP_ID, &id);
  	if (ret)
  		return ret;
@@ -46,20 +46,18 @@
  
 -	return mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_03, 0x34c00fe0);
 +	if (version == 0x8a00 || version == 0x8a10 || version == 0x8b00) {
-+		ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_01, 0x1d59080f);
-+		if (ret)
-+			return ret;
-+
-+		mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_03, 0x34c00fe0);
++		rg_xo_01 = 0x1d59080f;
++		rg_xo_03 = 0x34c00fe0;
 +	} else {
-+		ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_01, 0x1959c80f);
-+		if (ret)
-+			return ret;
-+
-+		mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_03, 0x34d00fe0);
++		rg_xo_01 = 0x1959f80f;
++		rg_xo_03 = 0x34d00fe0;
 +	}
 +
-+	return ret;
++	ret = mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_01, rg_xo_01);
++ 	if (ret)
++	 		return ret;
++
++	return mt76_wmac_spi_write(dev, adie, MT_ADIE_RG_XO_03, rg_xo_03);
  }
  
  static int
diff --git a/recipes-kernel/linux-mt76/files/patches/0014-mt76-mt7915-limit-minimum-twt-duration-due-to-hw-lim.patch b/recipes-kernel/linux-mt76/files/patches/0014-mt76-mt7915-limit-minimum-twt-duration-due-to-hw-lim.patch
new file mode 100644
index 0000000..d5aafcb
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0014-mt76-mt7915-limit-minimum-twt-duration-due-to-hw-lim.patch
@@ -0,0 +1,37 @@
+From 58706d81a82726f488cda771097f5586708b47f2 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Tue, 12 Apr 2022 16:06:36 +0800
+Subject: [PATCH] mt76: mt7915: limit minimum twt duration due to hw limitation
+
+---
+ mt7915/mac.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index 925f5eb9..fd897fd5 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -2698,6 +2698,7 @@ void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw,
+ 			      struct ieee80211_sta *sta,
+ 			      struct ieee80211_twt_setup *twt)
+ {
++#define MT7915_MIN_TWT_DUR 64
+ 	enum ieee80211_twt_setup_cmd setup_cmd = TWT_SETUP_CMD_REJECT;
+ 	struct mt7915_sta *msta = (struct mt7915_sta *)sta->drv_priv;
+ 	struct ieee80211_twt_params *twt_agrt = (void *)twt->params;
+@@ -2719,6 +2720,12 @@ void mt7915_mac_add_twt_setup(struct ieee80211_hw *hw,
+ 	if (hweight8(msta->twt.flowid_mask) == ARRAY_SIZE(msta->twt.flow))
+ 		goto unlock;
+ 
++	if (twt_agrt->min_twt_dur < MT7915_MIN_TWT_DUR) {
++		setup_cmd = TWT_SETUP_CMD_DICTATE;
++		twt_agrt->min_twt_dur = MT7915_MIN_TWT_DUR;
++		goto unlock;
++	}
++
+ 	flowid = ffs(~msta->twt.flowid_mask) - 1;
+ 	le16p_replace_bits(&twt_agrt->req_type, flowid,
+ 			   IEEE80211_TWT_REQTYPE_FLOWID);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/0015-mt76-mt7915-drop-undefined-action-frame.patch b/recipes-kernel/linux-mt76/files/patches/0015-mt76-mt7915-drop-undefined-action-frame.patch
new file mode 100644
index 0000000..f8f766e
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0015-mt76-mt7915-drop-undefined-action-frame.patch
@@ -0,0 +1,36 @@
+From 573b80a984695b338e12c6c30bb4e9f7af7e3495 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Thu, 14 Apr 2022 15:18:02 +0800
+Subject: [PATCH] mt76: mt7915: drop undefined action frame
+
+---
+ mt7915/mac.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index 1e0ddc13..81c582f2 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -1303,6 +1303,8 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 			  struct mt76_tx_info *tx_info)
+ {
+ 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
++	struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)tx_info->skb->data;
++	__le16 fc = hdr->frame_control;
+ 	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
+ 	struct ieee80211_key_conf *key = info->control.hw_key;
+@@ -1333,6 +1335,10 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
+ 	t->skb = tx_info->skb;
+ 
++	if (ieee80211_is_action(fc) &&
++	    mgmt->u.action.category == 0xff)
++		return -1;
++
+ 	id = mt76_token_consume(mdev, &t);
+ 	if (id < 0)
+ 		return id;
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/0016-mt76-mt7915-reowrk-SER-debugfs-knob.patch b/recipes-kernel/linux-mt76/files/patches/0016-mt76-mt7915-reowrk-SER-debugfs-knob.patch
new file mode 100755
index 0000000..d4c81d9
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0016-mt76-mt7915-reowrk-SER-debugfs-knob.patch
@@ -0,0 +1,278 @@
+From f3f9ccbb417cae6e503084e13d627b68a141b0bd Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Thu, 5 May 2022 11:45:23 +0800
+Subject: [PATCH 02/10] mt76: mt7915: reowrk SER debugfs knob
+
+1. get status of system recovery from firmware.
+2. add more recovery points.
+3. make knob per phy.
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
+---
+ mt7915/debugfs.c | 106 ++++++++++++++++++++++++++++++++++++++++-------
+ mt7915/mcu.c     |   5 +--
+ mt7915/mcu.h     |  14 +++++++
+ mt7915/mmio.c    |   3 ++
+ mt7915/regs.h    |  18 +++++++-
+ 5 files changed, 126 insertions(+), 20 deletions(-)
+
+diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
+index 77bbeeed..b45181c1 100644
+--- a/mt7915/debugfs.c
++++ b/mt7915/debugfs.c
+@@ -44,35 +44,113 @@ mt7915_implicit_txbf_get(void *data, u64 *val)
+ DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
+ 			 mt7915_implicit_txbf_set, "%lld\n");
+ 
+-/* test knob of system layer 1/2 error recovery */
+-static int mt7915_ser_trigger_set(void *data, u64 val)
++/* test knob of system error recovery */
++static ssize_t
++mt7915_fw_ser_set(struct file *file, const char __user *user_buf,
++		  size_t count, loff_t *ppos)
+ {
+-	enum {
+-		SER_SET_RECOVER_L1 = 1,
+-		SER_SET_RECOVER_L2,
+-		SER_ENABLE = 2,
+-		SER_RECOVER
+-	};
+-	struct mt7915_dev *dev = data;
++	struct mt7915_phy *phy = file->private_data;
++	struct mt7915_dev *dev = phy->dev;
++	bool ext_phy = phy != &dev->phy;
++	char buf[16];
+ 	int ret = 0;
++	u16 val;
++
++	if (count >= sizeof(buf))
++		return -EINVAL;
++
++	if (copy_from_user(buf, user_buf, count))
++		return -EFAULT;
++
++	if (count && buf[count - 1] == '\n')
++		buf[count - 1] = '\0';
++	else
++		buf[count] = '\0';
++
++	if (kstrtou16(buf, 0, &val))
++		return -EINVAL;
+ 
+ 	switch (val) {
++	case SER_QUERY:
++		/* grab firmware SER stats */
++		ret = mt7915_mcu_set_ser(dev, 0, 0, ext_phy);
++		break;
+ 	case SER_SET_RECOVER_L1:
+ 	case SER_SET_RECOVER_L2:
+-		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), 0);
++	case SER_SET_RECOVER_L3_RX_ABORT:
++	case SER_SET_RECOVER_L3_TX_ABORT:
++	case SER_SET_RECOVER_L3_TX_DISABLE:
++	case SER_SET_RECOVER_L3_BF:
++		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), ext_phy);
+ 		if (ret)
+ 			return ret;
+ 
+-		return mt7915_mcu_set_ser(dev, SER_RECOVER, val, 0);
++		ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, ext_phy);
++		break;
+ 	default:
+ 		break;
+ 	}
+ 
++	return ret ? ret : count;
++}
++
++static ssize_t
++mt7915_fw_ser_get(struct file *file, char __user *user_buf,
++		  size_t count, loff_t *ppos)
++{
++	struct mt7915_phy *phy = file->private_data;
++	struct mt7915_dev *dev = phy->dev;
++	char *buff;
++	int desc = 0;
++	ssize_t ret;
++	static const size_t bufsz = 400;
++
++	buff = kmalloc(bufsz, GFP_KERNEL);
++	if (!buff)
++		return -ENOMEM;
++
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_STATUS        = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_SER_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_PLE_ERR       = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_PLE_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_PLE_ERR_1     = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_PLE1_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_PLE_ERR_AMSDU = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_PSE_ERR       = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_PSE_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_PSE_ERR_1     = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_PSE1_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_LMAC_WISR6_B0 = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_LMAC_WISR6_B1 = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_LMAC_WISR7_B0 = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATS));
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "::E  R , SER_LMAC_WISR7_B1 = 0x%08x\n",
++			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
++
++	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
++	kfree(buff);
+ 	return ret;
+ }
+ 
+-DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL,
+-			 mt7915_ser_trigger_set, "%lld\n");
++static const struct file_operations mt7915_fw_ser_ops = {
++	.write = mt7915_fw_ser_set,
++	.read = mt7915_fw_ser_get,
++	.open = simple_open,
++	.llseek = default_llseek,
++};
+ 
+ static int
+ mt7915_radar_trigger(void *data, u64 val)
+@@ -914,6 +992,7 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
+ 	debugfs_create_file("xmit-queues", 0400, dir, phy,
+ 			    &mt7915_xmit_queues_fops);
+ 	debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
++	debugfs_create_file("fw_ser", 0600, dir, phy, &mt7915_fw_ser_ops);
+ 	debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
+ 	debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
+ 	debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
+@@ -927,7 +1006,6 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
+ 			    &mt7915_rate_txpower_fops);
+ 	debugfs_create_devm_seqfile(dev->mt76.dev, "twt_stats", dir,
+ 				    mt7915_twt_stats);
+-	debugfs_create_file("ser_trigger", 0200, dir, dev, &fops_ser_trigger);
+ 	debugfs_create_file("rf_regval", 0600, dir, dev, &fops_rf_regval);
+ 
+ 	if (!dev->dbdc_support || phy->band_idx) {
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index c215bc9e..20f32f7f 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -2471,10 +2471,7 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
+ 	/* force firmware operation mode into normal state,
+ 	 * which should be set before firmware download stage.
+ 	 */
+-	if (is_mt7915(&dev->mt76))
+-		mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
+-	else
+-		mt76_wr(dev, MT_SWDEF_MODE_MT7916, MT_SWDEF_NORMAL_MODE);
++	mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
+ 
+ 	ret = mt7915_driver_own(dev, 0);
+ 	if (ret)
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index df7aefca..5cbc3ecf 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -464,6 +464,20 @@ enum {
+ 	MURU_GET_TXC_TX_STATS = 151,
+ };
+ 
++enum {
++	SER_QUERY,
++	/* recovery */
++	SER_SET_RECOVER_L1,
++	SER_SET_RECOVER_L2,
++	SER_SET_RECOVER_L3_RX_ABORT,
++	SER_SET_RECOVER_L3_TX_ABORT,
++	SER_SET_RECOVER_L3_TX_DISABLE,
++	SER_SET_RECOVER_L3_BF,
++	/* action */
++	SER_ENABLE = 2,
++	SER_RECOVER
++};
++
+ #define MT7915_BSS_UPDATE_MAX_SIZE	(sizeof(struct sta_req_hdr) +	\
+ 					 sizeof(struct bss_info_omac) +	\
+ 					 sizeof(struct bss_info_basic) +\
+diff --git a/mt7915/mmio.c b/mt7915/mmio.c
+index 0bd32daa..2d733d32 100644
+--- a/mt7915/mmio.c
++++ b/mt7915/mmio.c
+@@ -22,6 +22,7 @@ static const u32 mt7915_reg[] = {
+ 	[WFDMA_EXT_CSR_ADDR]	= 0xd7000,
+ 	[CBTOP1_PHY_END]	= 0x77ffffff,
+ 	[INFRA_MCU_ADDR_END]	= 0x7c3fffff,
++	[SWDEF_BASE_ADDR]	= 0x41f200,
+ };
+ 
+ static const u32 mt7916_reg[] = {
+@@ -36,6 +37,7 @@ static const u32 mt7916_reg[] = {
+ 	[WFDMA_EXT_CSR_ADDR]	= 0xd7000,
+ 	[CBTOP1_PHY_END]	= 0x7fffffff,
+ 	[INFRA_MCU_ADDR_END]	= 0x7c085fff,
++	[SWDEF_BASE_ADDR]	= 0x411400,
+ };
+ 
+ static const u32 mt7986_reg[] = {
+@@ -50,6 +52,7 @@ static const u32 mt7986_reg[] = {
+ 	[WFDMA_EXT_CSR_ADDR]	= 0x27000,
+ 	[CBTOP1_PHY_END]	= 0x7fffffff,
+ 	[INFRA_MCU_ADDR_END]	= 0x7c085fff,
++	[SWDEF_BASE_ADDR]	= 0x411400,
+ };
+ 
+ static const u32 mt7915_offs[] = {
+diff --git a/mt7915/regs.h b/mt7915/regs.h
+index 97984aaf..4251cf78 100644
+--- a/mt7915/regs.h
++++ b/mt7915/regs.h
+@@ -30,6 +30,7 @@ enum reg_rev {
+ 	WFDMA_EXT_CSR_ADDR,
+ 	CBTOP1_PHY_END,
+ 	INFRA_MCU_ADDR_END,
++	SWDEF_BASE_ADDR,
+ 	__MT_REG_MAX,
+ };
+ 
+@@ -942,12 +943,25 @@ enum offs_rev {
+ #define MT_ADIE_TYPE_MASK		BIT(1)
+ 
+ /* FW MODE SYNC */
+-#define MT_SWDEF_MODE			0x41f23c
+-#define MT_SWDEF_MODE_MT7916		0x41143c
++#define MT_SWDEF_BASE			__REG(SWDEF_BASE_ADDR)
++
++#define MT_SWDEF(ofs)			(MT_SWDEF_BASE + (ofs))
++#define MT_SWDEF_MODE			MT_SWDEF(0x3c)
+ #define MT_SWDEF_NORMAL_MODE		0
+ #define MT_SWDEF_ICAP_MODE		1
+ #define MT_SWDEF_SPECTRUM_MODE		2
+ 
++#define MT_SWDEF_SER_STATS		MT_SWDEF(0x040)
++#define MT_SWDEF_PLE_STATS		MT_SWDEF(0x044)
++#define MT_SWDEF_PLE1_STATS		MT_SWDEF(0x048)
++#define MT_SWDEF_PLE_AMSDU_STATS	MT_SWDEF(0x04C)
++#define MT_SWDEF_PSE_STATS		MT_SWDEF(0x050)
++#define MT_SWDEF_PSE1_STATS		MT_SWDEF(0x054)
++#define MT_SWDEF_LAMC_WISR6_BN0_STATS	MT_SWDEF(0x058)
++#define MT_SWDEF_LAMC_WISR6_BN1_STATS	MT_SWDEF(0x05C)
++#define MT_SWDEF_LAMC_WISR7_BN0_STATS	MT_SWDEF(0x060)
++#define MT_SWDEF_LAMC_WISR7_BN1_STATS	MT_SWDEF(0x064)
++
+ #define MT_DIC_CMD_REG_BASE		0x41f000
+ #define MT_DIC_CMD_REG(ofs)		(MT_DIC_CMD_REG_BASE + (ofs))
+ #define MT_DIC_CMD_REG_CMD		MT_DIC_CMD_REG(0x10)
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/0017-mt76-mt7615-mt7915-do-reset_work-with-mt76-s-work-qu.patch b/recipes-kernel/linux-mt76/files/patches/0017-mt76-mt7615-mt7915-do-reset_work-with-mt76-s-work-qu.patch
new file mode 100755
index 0000000..9e20c45
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0017-mt76-mt7615-mt7915-do-reset_work-with-mt76-s-work-qu.patch
@@ -0,0 +1,43 @@
+From a56d23330b0ac01929a54c427bd338b02a7e727e Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Fri, 6 May 2022 21:06:55 +0800
+Subject: [PATCH 03/10] mt76: mt7615/mt7915: do reset_work with mt76's work
+ queue
+
+reset_work may be blocked when mcu message timeout occurs
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt7615/mmio.c | 2 +-
+ mt7915/mmio.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/mt7615/mmio.c b/mt7615/mmio.c
+index ce45c3bf..a208035e 100644
+--- a/mt7615/mmio.c
++++ b/mt7615/mmio.c
+@@ -145,7 +145,7 @@ static void mt7615_irq_tasklet(struct tasklet_struct *t)
+ 		return;
+ 
+ 	dev->reset_state = mcu_int;
+-	ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
++	queue_work(dev->mt76.wq, &dev->reset_work);
+ 	wake_up(&dev->reset_wait);
+ }
+ 
+diff --git a/mt7915/mmio.c b/mt7915/mmio.c
+index 2d733d32..4d4537cd 100644
+--- a/mt7915/mmio.c
++++ b/mt7915/mmio.c
+@@ -612,7 +612,7 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
+ 		mt76_wr(dev, MT_MCU_CMD, val);
+ 		if (val & MT_MCU_CMD_ERROR_MASK) {
+ 			dev->reset_state = val;
+-			ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
++			queue_work(dev->mt76.wq, &dev->reset_work);
+ 			wake_up(&dev->reset_wait);
+ 		}
+ 	}
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/0018-mt76-mt7915-add-support-for-6G-in-band-discovery.patch b/recipes-kernel/linux-mt76/files/patches/0018-mt76-mt7915-add-support-for-6G-in-band-discovery.patch
new file mode 100644
index 0000000..d710df8
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0018-mt76-mt7915-add-support-for-6G-in-band-discovery.patch
@@ -0,0 +1,282 @@
+From 3b12e37a1c903b7f30c1515b6eec481c206abb4e Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
+Date: Mon, 25 Apr 2022 15:31:02 +0800
+Subject: [PATCH] mt76: mt7915: add support for 6G in-band discovery
+
+Add offloading FILS discovery and unsolicited broadcast probe response support.
+
+Reviewed-by: Ryder Lee <ryder.lee@mediatek.com>
+Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
+---
+ mt7915/init.c  |  2 +
+ mt7915/mac.c   | 17 +++--
+ mt7915/main.c  |  8 +-
+ mt7915/mcu.c   | 75 ++++++++++++++++++-
+ mt7915/mcu.h   | 15 +++-
+ mt7915/mt7915.h    |  4 +-
+ 6 files changed, 107 insertions(+), 14 deletions(-)
+
+diff --git a/mt7915/init.c b/mt7915/init.c
+index 70baad756dd0..d123ecb9fb0c 100644
+--- a/mt7915/init.c
++++ b/mt7915/init.c
+@@ -351,6 +351,8 @@ mt7915_init_wiphy(struct ieee80211_hw *hw)
+ 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HT);
+ 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_VHT);
+ 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_BEACON_RATE_HE);
++	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP);
++	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_DISCOVERY);
+ 
+ 	if (!mdev->dev->of_node ||
+ 	    !of_property_read_bool(mdev->dev->of_node,
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index e353e8c44d6c..de7bf137c234 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -1177,7 +1177,7 @@ mt7915_mac_tx_rate_val(struct mt76_phy *mphy, struct ieee80211_vif *vif,
+ 
+ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
+ 			   struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
+-			   struct ieee80211_key_conf *key, bool beacon)
++			   struct ieee80211_key_conf *key, u32 changed)
+ {
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ 	struct ieee80211_vif *vif = info->control.vif;
+@@ -1188,6 +1188,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
+ 	bool mcast = false;
+ 	u16 tx_count = 15;
+ 	u32 val;
++	bool beacon = !!(changed & (BSS_CHANGED_BEACON |
++				    BSS_CHANGED_BEACON_ENABLED));
++	bool inband_disc = !!(changed & (BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
++					 BSS_CHANGED_FILS_DISCOVERY));
+ 
+ 	if (vif) {
+ 		struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+@@ -1200,7 +1204,10 @@ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
+ 	if (ext_phy && dev->mt76.phy2)
+ 		mphy = dev->mt76.phy2;
+ 
+-	if (beacon) {
++	if (inband_disc) {
++		p_fmt = MT_TX_TYPE_FW;
++		q_idx = MT_LMAC_ALTX0;
++	} else if (beacon) {
+ 		p_fmt = MT_TX_TYPE_FW;
+ 		q_idx = MT_LMAC_BCN0;
+ 	} else if (skb_get_queue_mapping(skb) >= MT_TXQ_PSD) {
+@@ -1308,8 +1315,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 		return id;
+ 
+ 	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+-	mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key,
+-			      false);
++	mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key, 0);
+ 
+ 	txp = (struct mt7915_txp *)(txwi + MT_TXD_SIZE);
+ 	for (i = 0; i < nbuf; i++) {
+@@ -1919,7 +1925,8 @@ mt7915_update_vif_beacon(void *priv, u8 *mac, struct ieee80211_vif *vif)
+ 	case NL80211_IFTYPE_MESH_POINT:
+ 	case NL80211_IFTYPE_ADHOC:
+ 	case NL80211_IFTYPE_AP:
+-		mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon);
++		mt7915_mcu_add_beacon(hw, vif, vif->bss_conf.enable_beacon,
++				      BSS_CHANGED_BEACON_ENABLED);
+ 		break;
+ 	default:
+ 		break;
+diff --git a/mt7915/main.c b/mt7915/main.c
+index 5177b19f9154..c2c615931782 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -622,8 +622,10 @@ 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 |
+-		       BSS_CHANGED_BEACON_ENABLED))
+-		mt7915_mcu_add_beacon(hw, vif, info->enable_beacon);
++		       BSS_CHANGED_BEACON_ENABLED |
++		       BSS_CHANGED_UNSOL_BCAST_PROBE_RESP |
++		       BSS_CHANGED_FILS_DISCOVERY))
++		mt7915_mcu_add_beacon(hw, vif, info->enable_beacon, changed);
+ 
+ 	mutex_unlock(&dev->mt76.mutex);
+ }
+@@ -636,7 +638,7 @@ mt7915_channel_switch_beacon(struct ieee80211_hw *hw,
+ 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ 
+ 	mutex_lock(&dev->mt76.mutex);
+-	mt7915_mcu_add_beacon(hw, vif, true);
++	mt7915_mcu_add_beacon(hw, vif, true, BSS_CHANGED_BEACON);
+ 	mutex_unlock(&dev->mt76.mutex);
+ }
+ 
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 2a07a5d2a439..87e44c69d72b 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -1892,6 +1892,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ 	u8 *buf;
+ 	int len = sizeof(*cont) + MT_TXD_SIZE + skb->len;
+ 
++	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
+ 	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_CONTENT,
+ 					   len, &bcn->sub_ntlv, &bcn->len);
+ 
+@@ -1910,7 +1911,7 @@ mt7915_mcu_beacon_cont(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ 
+ 	buf = (u8 *)tlv + sizeof(*cont);
+ 	mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
+-			      true);
++			      BSS_CHANGED_BEACON);
+ 	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
+ }
+ 
+@@ -1992,8 +1993,71 @@ mt7915_mcu_beacon_check_caps(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ 	}
+ }
+ 
+-int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
+-			  struct ieee80211_vif *vif, int en)
++static void
++mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vif,
++				struct sk_buff *rskb, struct bss_info_bcn *bcn,
++				u32 changed)
++{
++#define OFFLOAD_TX_MODE_SU	BIT(0)
++#define OFFLOAD_TX_MODE_MU	BIT(1)
++	struct ieee80211_hw *hw = mt76_hw(dev);
++	struct mt7915_phy *phy = mt7915_hw_phy(hw);
++	struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
++	struct cfg80211_chan_def *chandef = &mvif->phy->mt76->chandef;
++	enum nl80211_band band = chandef->chan->band;
++	struct mt76_wcid *wcid = &dev->mt76.global_wcid;
++	struct bss_info_inband_discovery *discov;
++	struct ieee80211_tx_info *info;
++	struct sk_buff *skb = NULL;
++	struct tlv *tlv;
++	bool ext_phy = phy != &dev->phy;
++	u8 *buf, interval;
++	int len;
++
++	if (changed & BSS_CHANGED_FILS_DISCOVERY &&
++	    vif->bss_conf.fils_discovery.max_interval) {
++		interval = vif->bss_conf.fils_discovery.max_interval;
++		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
++	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
++		   vif->bss_conf.unsol_bcast_probe_resp_interval) {
++		interval = vif->bss_conf.unsol_bcast_probe_resp_interval;
++		skb = ieee80211_get_unsol_bcast_probe_resp_tmpl(hw, vif);
++	}
++
++	if (!skb)
++		return;
++
++	info = IEEE80211_SKB_CB(skb);
++	info->control.vif = vif;
++	info->band = band;
++
++	if (ext_phy)
++		info->hw_queue |= MT_TX_HW_QUEUE_EXT_PHY;
++
++	len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
++	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
++
++	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
++					   len, &bcn->sub_ntlv, &bcn->len);
++	discov = (struct bss_info_inband_discovery *)tlv;
++	discov->tx_mode = OFFLOAD_TX_MODE_SU;
++	/* 0: UNSOL PROBE RESP, 1: FILS DISCOV */
++	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
++	discov->tx_interval = interval;
++	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
++	discov->enable = true;
++
++	buf = (u8 *)tlv + sizeof(*discov);
++
++	mt7915_mac_write_txwi(dev, (__le32 *)buf, skb, wcid, 0, NULL,
++			      changed);
++	memcpy(buf + MT_TXD_SIZE, skb->data, skb->len);
++
++	dev_kfree_skb(skb);
++}
++
++int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
++			  int en, u32 changed)
+ {
+ #define MAX_BEACON_SIZE 512
+ 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
+@@ -2044,6 +2108,11 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw,
+ 	mt7915_mcu_beacon_cont(dev, vif, rskb, skb, bcn, &offs);
+ 	dev_kfree_skb(skb);
+ 
++	if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP ||
++	    changed & BSS_CHANGED_FILS_DISCOVERY)
++		mt7915_mcu_beacon_inband_discov(dev, vif, rskb,
++						bcn, changed);
++
+ out:
+ 	return mt76_mcu_skb_send_msg(&phy->dev->mt76, rskb,
+ 				     MCU_EXT_CMD(BSS_INFO_UPDATE), true);
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index 064d33e33738..e1d576701fdf 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -404,11 +404,23 @@ struct bss_info_bcn_cont {
+ 	__le16 pkt_len;
+ } __packed __aligned(4);
+ 
++struct bss_info_inband_discovery {
++	__le16 tag;
++	__le16 len;
++	u8 tx_type;
++	u8 tx_mode;
++	u8 tx_interval;
++	u8 enable;
++	__le16 rsv;
++	__le16 prob_rsp_len;
++} __packed __aligned(4);
++
+ enum {
+ 	BSS_INFO_BCN_CSA,
+ 	BSS_INFO_BCN_BCC,
+ 	BSS_INFO_BCN_MBSSID,
+ 	BSS_INFO_BCN_CONTENT,
++	BSS_INFO_BCN_DISCOV,
+ 	BSS_INFO_BCN_MAX
+ };
+ 
+@@ -476,6 +488,7 @@ enum {
+ #define MT7915_BEACON_UPDATE_SIZE	(sizeof(struct sta_req_hdr) +	\
+ 					 sizeof(struct bss_info_bcn_cntdwn) + \
+ 					 sizeof(struct bss_info_bcn_mbss) + \
+-					 sizeof(struct bss_info_bcn_cont))
++					 sizeof(struct bss_info_bcn_cont) + \
++					 sizeof(struct bss_info_inband_discovery))
+ 
+ #endif
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index 6c590eff14f1..03431012b2ff 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -464,7 +464,7 @@ int mt7915_mcu_add_rx_ba(struct mt7915_dev *dev,
+ int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+ 				struct cfg80211_he_bss_color *he_bss_color);
+ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+-			  int enable);
++			  int enable, u32 changed);
+ int mt7915_mcu_add_obss_spr(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+                             bool enable);
+ int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
+@@ -551,7 +551,7 @@ void mt7915_mac_cca_stats_reset(struct mt7915_phy *phy);
+ void mt7915_mac_enable_nf(struct mt7915_dev *dev, bool ext_phy);
+ void mt7915_mac_write_txwi(struct mt7915_dev *dev, __le32 *txwi,
+ 			   struct sk_buff *skb, struct mt76_wcid *wcid, int pid,
+-			   struct ieee80211_key_conf *key, bool beacon);
++			   struct ieee80211_key_conf *key, u32 changed);
+ void mt7915_mac_set_timing(struct mt7915_phy *phy);
+ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+ 		       struct ieee80211_sta *sta);
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/0019-mt76-mt7915-add-the-maximum-size-of-beacon-offload.patch b/recipes-kernel/linux-mt76/files/patches/0019-mt76-mt7915-add-the-maximum-size-of-beacon-offload.patch
new file mode 100644
index 0000000..db4638d
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/0019-mt76-mt7915-add-the-maximum-size-of-beacon-offload.patch
@@ -0,0 +1,67 @@
+From f5a80422207b76c740f284719539419b6a3dcc89 Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Mon, 23 May 2022 17:09:52 +0800
+Subject: [PATCH] mt76: mt7915: add the maximum size of beacon offload
+
+add the maximum size of beacon offload to avoid exceeding the size limit
+
+Signed-off-by: Money Wang <Money.Wang@mediatek.com>
+Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
+---
+ mt7915/mcu.c | 11 +++++++++--
+ mt7915/mcu.h |  3 +++
+ 2 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index bdef2b3..8155900 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -2037,6 +2037,13 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+ 	len = sizeof(*discov) + MT_TXD_SIZE + skb->len;
+ 	len = (len & 0x3) ? ((len | 0x3) + 1) : len;
+ 
++	if (len > (MAX_BEACON_SIZE + MAX_INBND_FRME_SIZE +
++		   MT7915_BEACON_UPDATE_SIZE) - rskb->len) {
++		dev_err(dev->mt76.dev, "inband discovery size limit exceed\n");
++		dev_kfree_skb(skb);
++		return;
++	}
++
+ 	tlv = mt7915_mcu_add_nested_subtlv(rskb, BSS_INFO_BCN_DISCOV,
+ 					   len, &bcn->sub_ntlv, &bcn->len);
+ 	discov = (struct bss_info_inband_discovery *)tlv;
+@@ -2059,7 +2066,6 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 			  int en, u32 changed)
+ {
+-#define MAX_BEACON_SIZE 512
+ 	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;
+@@ -2068,7 +2074,8 @@ int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ 	struct sk_buff *skb, *rskb;
+ 	struct tlv *tlv;
+ 	struct bss_info_bcn *bcn;
+-	int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE;
++	int len = MT7915_BEACON_UPDATE_SIZE + MAX_BEACON_SIZE +
++		  MAX_INBND_FRME_SIZE;
+ 	bool ext_phy = phy != &dev->phy;
+ 
+ 	if (vif->bss_conf.nontransmitted)
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index 21aa963..d46c8da 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -490,6 +490,9 @@ enum {
+ 	SER_RECOVER
+ };
+ 
++#define MAX_BEACON_SIZE 512
++#define MAX_INBND_FRME_SIZE 256
++
+ #define MT7915_BSS_UPDATE_MAX_SIZE	(sizeof(struct sta_req_hdr) +	\
+ 					 sizeof(struct bss_info_omac) +	\
+ 					 sizeof(struct bss_info_basic) +\
+-- 
+2.29.2
+
diff --git a/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch b/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
index c912a30..94dff56 100755
--- a/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch
@@ -1,26 +1,26 @@
-From f45027dc3cee106b6119d1343f036eca4a00d9f8 Mon Sep 17 00:00:00 2001
+From 235e69804c130fd7381fd44b1853859984e97ac5 Mon Sep 17 00:00:00 2001
 From: Bo Jiao <Bo.Jiao@mediatek.com>
 Date: Thu, 21 Apr 2022 19:42:55 +0800
 Subject: [PATCH] mt76: mt7915: add mtk internal debug tools for mt76
 
 Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
 ---
- mt76_connac_mcu.h     |    6 +
- mt7915/Makefile       |    2 +-
- mt7915/debugfs.c      |   72 +-
- mt7915/mac.c          |   14 +
- mt7915/mcu.c          |   41 +
- mt7915/mcu.h          |    4 +
- mt7915/mt7915.h       |   41 +
- mt7915/mt7915_debug.h | 1350 +++++++++++++++++++
- mt7915/mtk_debugfs.c  | 2893 +++++++++++++++++++++++++++++++++++++++++
- mt7915/mtk_mcu.c      |   51 +
- tools/fwlog.c         |   26 +-
- 11 files changed, 4489 insertions(+), 11 deletions(-)
- mode change 100644 => 100755 mt7915/mcu.c
- create mode 100644 mt7915/mt7915_debug.h
- create mode 100644 mt7915/mtk_debugfs.c
- create mode 100644 mt7915/mtk_mcu.c
+ .../wireless/mediatek/mt76/mt76_connac_mcu.h  |    6 +
+ .../wireless/mediatek/mt76/mt7915/Makefile    |    2 +-
+ .../wireless/mediatek/mt76/mt7915/debugfs.c   |   72 +-
+ .../net/wireless/mediatek/mt76/mt7915/mac.c   |   14 +
+ .../net/wireless/mediatek/mt76/mt7915/mcu.c   |   41 +
+ .../net/wireless/mediatek/mt76/mt7915/mcu.h   |    4 +
+ .../wireless/mediatek/mt76/mt7915/mt7915.h    |   41 +
+ .../mediatek/mt76/mt7915/mt7915_debug.h       | 1350 ++++++++
+ .../mediatek/mt76/mt7915/mtk_debugfs.c        | 2921 +++++++++++++++++
+ .../wireless/mediatek/mt76/mt7915/mtk_mcu.c   |   51 +
+ .../net/wireless/mediatek/mt76/tools/fwlog.c  |   44 +-
+ 11 files changed, 4533 insertions(+), 13 deletions(-)
+ mode change 100644 => 100755 drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+ create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mt7915_debug.h
+ create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mtk_debugfs.c
+ create mode 100644 drivers/net/wireless/mediatek/mt76/mt7915/mtk_mcu.c
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
 index aa14d2d4..03134066 100644
@@ -54,7 +54,7 @@
  mt7915e-$(CONFIG_MT7986_WMAC) += soc.o
 \ No newline at end of file
 diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
-index 77bbeeed..e8e26ac1 100644
+index b45181c1..27321528 100644
 --- a/mt7915/debugfs.c
 +++ b/mt7915/debugfs.c
 @@ -8,6 +8,9 @@
@@ -67,7 +67,7 @@
  
  /** global debugfs **/
  
-@@ -370,6 +373,9 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
+@@ -448,6 +451,9 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
  	int ret;
  
  	dev->fw_debug_wm = val ? MCU_FW_LOG_TO_HOST : 0;
@@ -77,7 +77,7 @@
  
  	if (dev->fw_debug_bin)
  		val = 16;
-@@ -394,6 +400,9 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
+@@ -472,6 +478,9 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
  		if (ret)
  			return ret;
  	}
@@ -87,7 +87,7 @@
  
  	/* WM CPU info record control */
  	mt76_clear(dev, MT_CPU_UTIL_CTRL, BIT(0));
-@@ -401,6 +410,12 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
+@@ -479,6 +488,12 @@ mt7915_fw_debug_wm_set(void *data, u64 val)
  	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_MASK_CLR_ADDR, BIT(5));
  	mt76_wr(dev, MT_MCU_WM_CIRQ_IRQ_SOFT_ADDR, BIT(5));
  
@@ -100,7 +100,7 @@
  	return 0;
  }
  
-@@ -409,7 +424,11 @@ mt7915_fw_debug_wm_get(void *data, u64 *val)
+@@ -487,7 +502,11 @@ mt7915_fw_debug_wm_get(void *data, u64 *val)
  {
  	struct mt7915_dev *dev = data;
  
@@ -113,7 +113,7 @@
  
  	return 0;
  }
-@@ -489,6 +508,16 @@ mt7915_fw_debug_bin_set(void *data, u64 val)
+@@ -567,6 +586,16 @@ mt7915_fw_debug_bin_set(void *data, u64 val)
  
  	relay_reset(dev->relay_fwlog);
  
@@ -130,7 +130,7 @@
  	return mt7915_fw_debug_wm_set(dev, dev->fw_debug_wm);
  }
  
-@@ -942,6 +971,11 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
+@@ -1020,6 +1049,11 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
  	if (!ext_phy)
  		dev->debugfs_dir = dir;
  
@@ -142,7 +142,7 @@
  	return 0;
  }
  
-@@ -982,17 +1016,53 @@ void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int
+@@ -1060,17 +1094,53 @@ void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int
  		.msg_type = cpu_to_le16(PKT_TYPE_RX_FW_MONITOR),
  	};
  
@@ -197,7 +197,7 @@
  
  	if (dev->relay_fwlog)
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index c1ff04ae..e8899590 100644
+index de5f3f10..ce760cdb 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
 @@ -596,6 +596,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
@@ -211,7 +211,7 @@
  	memset(status, 0, sizeof(*status));
  
  	if ((rxd1 & MT_RXD1_NORMAL_BAND_IDX) && !phy->band_idx) {
-@@ -785,6 +789,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
+@@ -780,6 +784,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb)
  	}
  
  	hdr_gap = (u8 *)rxd - skb->data + 2 * remove_pad;
@@ -222,7 +222,7 @@
  	if (hdr_trans && ieee80211_has_morefrags(fc)) {
  		if (mt7915_reverse_frag0_hdr_trans(skb, hdr_gap))
  			return -EINVAL;
-@@ -1351,6 +1359,12 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+@@ -1352,6 +1360,12 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
  	tx_info->buf[1].skip_unmap = true;
  	tx_info->nbuf = MT_CT_DMA_BUF_NUM;
  
@@ -238,7 +238,7 @@
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
 old mode 100644
 new mode 100755
-index c215bc9e..bce14f4b
+index 20f32f7f..c325c4b6
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -298,6 +298,10 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -252,7 +252,7 @@
  	if (wait_seq)
  		*wait_seq = seq;
  
-@@ -3660,6 +3664,43 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
+@@ -3657,6 +3661,43 @@ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
  				 &req, sizeof(req), true);
  }
  
@@ -297,7 +297,7 @@
  {
  	struct {
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index df7aefca..c36cf511 100644
+index 5cbc3ecf..3f303885 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -296,6 +296,10 @@ enum {
@@ -377,7 +377,7 @@
  #endif
 diff --git a/mt7915/mt7915_debug.h b/mt7915/mt7915_debug.h
 new file mode 100644
-index 00000000..59c057e0
+index 00000000..58ba2cdf
 --- /dev/null
 +++ b/mt7915/mt7915_debug.h
 @@ -0,0 +1,1350 @@
@@ -623,7 +623,7 @@
 +	[DBG_PLE_AC_OFFSET]		= { DBG_INVALID_BASE, 0x040},
 +	[DBG_PLE_STATION_PAUSE]		= { DBG_INVALID_BASE, 0x400},
 +	[DBG_PLE_DIS_STA_MAP]		= { DBG_INVALID_BASE, 0x440},
-+	[DBG_PSE_PBUF_CTRL]		= { DBG_INVALID_BASE, 0x004},
++	[DBG_PSE_PBUF_CTRL]		= { DBG_INVALID_BASE, 0x014},
 +	[DBG_PSE_FREEPG_CNT]		= { DBG_INVALID_BASE, 0x100},
 +	[DBG_PSE_FREEPG_HEAD_TAIL]	= { DBG_INVALID_BASE, 0x104},
 +	[DBG_PSE_HIF0_PG_INFO]		= { DBG_INVALID_BASE, 0x114},
@@ -722,7 +722,7 @@
 +	[DBG_PLE_CPU_PG_INFO]		= { DBG_INVALID_BASE, 0x394},
 +	[DBG_PLE_FL_QUE_CTRL]		= { DBG_INVALID_BASE, 0x3e0},
 +	[DBG_PLE_NATIVE_TXCMD_Q_EMPTY]	= { DBG_INVALID_BASE, 0x370},
-+	[DBG_PLE_TXCMD_Q_EMPTY]		= { DBG_INVALID_BASE, 0x374},
++	[DBG_PLE_TXCMD_Q_EMPTY]		= { DBG_INVALID_BASE, 0x36c},
 +	[DBG_PLE_AC_QEMPTY]		= { DBG_INVALID_BASE, 0x600},
 +	[DBG_PLE_AC_OFFSET]		= { DBG_INVALID_BASE, 0x080},
 +	[DBG_PLE_STATION_PAUSE]		= { DBG_INVALID_BASE, 0x100},
@@ -1098,30 +1098,30 @@
 +#define MT_DBG_PSE_BASE				0x820C8000
 +#define MT_DBG_PSE(ofs)				(MT_DBG_PSE_BASE + (ofs))
 +
-+#define MT_DBG_PSE_PBUF_CTRL			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PBUF_CTRL))
-+#define MT_DBG_PSE_QUEUE_EMPTY			MT_DBG_PLE(0x0b0)
-+#define MT_DBG_PSE_FREEPG_CNT			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_FREEPG_CNT))
-+#define MT_DBG_PSE_FREEPG_HEAD_TAIL		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_FREEPG_HEAD_TAIL))
-+#define MT_DBG_PSE_PG_HIF0_GROUP		MT_DBG_PLE(0x110)
-+#define MT_DBG_PSE_HIF0_PG_INFO			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_HIF0_PG_INFO))
-+#define MT_DBG_PSE_PG_HIF1_GROUP		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_HIF1_GROUP))
-+#define MT_DBG_PSE_HIF1_PG_INFO			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_HIF1_PG_INFO))
-+#define MT_DBG_PSE_PG_CPU_GROUP			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_CPU_GROUP))
-+#define MT_DBG_PSE_CPU_PG_INFO			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_CPU_PG_INFO))
-+#define MT_DBG_PSE_PG_LMAC0_GROUP		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC0_GROUP))
-+#define MT_DBG_PSE_LMAC0_PG_INFO		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC0_PG_INFO))
-+#define MT_DBG_PSE_PG_LMAC1_GROUP		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC1_GROUP))
-+#define MT_DBG_PSE_LMAC1_PG_INFO		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC1_PG_INFO))
-+#define MT_DBG_PSE_PG_LMAC2_GROUP		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC2_GROUP))
-+#define MT_DBG_PSE_LMAC2_PG_INFO		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC2_PG_INFO))
-+#define MT_DBG_PSE_PG_PLE_GROUP			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_PLE_GROUP))
-+#define MT_DBG_PSE_PLE_PG_INFO			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PLE_PG_INFO))
-+#define MT_DBG_PSE_PG_LMAC3_GROUP		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC3_GROUP))
-+#define MT_DBG_PSE_LMAC3_PG_INFO		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC3_PG_INFO))
-+#define MT_DBG_PSE_PG_MDP_GROUP			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_MDP_GROUP))
-+#define MT_DBG_PSE_MDP_PG_INFO			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_MDP_PG_INFO))
-+#define MT_DBG_PSE_PG_PLE1_GROUP		MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PG_PLE1_GROUP))
-+#define MT_DBG_PSE_PLE1_PG_INFO			MT_DBG_PLE(__DBG_REG_OFFS(dev, DBG_PSE_PLE1_PG_INFO))
++#define MT_DBG_PSE_PBUF_CTRL			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PBUF_CTRL))
++#define MT_DBG_PSE_QUEUE_EMPTY			MT_DBG_PSE(0x0b0)
++#define MT_DBG_PSE_FREEPG_CNT			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_FREEPG_CNT))
++#define MT_DBG_PSE_FREEPG_HEAD_TAIL		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_FREEPG_HEAD_TAIL))
++#define MT_DBG_PSE_PG_HIF0_GROUP		MT_DBG_PSE(0x110)
++#define MT_DBG_PSE_HIF0_PG_INFO			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_HIF0_PG_INFO))
++#define MT_DBG_PSE_PG_HIF1_GROUP		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_HIF1_GROUP))
++#define MT_DBG_PSE_HIF1_PG_INFO			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_HIF1_PG_INFO))
++#define MT_DBG_PSE_PG_CPU_GROUP			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_CPU_GROUP))
++#define MT_DBG_PSE_CPU_PG_INFO			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_CPU_PG_INFO))
++#define MT_DBG_PSE_PG_LMAC0_GROUP		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC0_GROUP))
++#define MT_DBG_PSE_LMAC0_PG_INFO		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC0_PG_INFO))
++#define MT_DBG_PSE_PG_LMAC1_GROUP		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC1_GROUP))
++#define MT_DBG_PSE_LMAC1_PG_INFO		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC1_PG_INFO))
++#define MT_DBG_PSE_PG_LMAC2_GROUP		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC2_GROUP))
++#define MT_DBG_PSE_LMAC2_PG_INFO		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC2_PG_INFO))
++#define MT_DBG_PSE_PG_PLE_GROUP			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_PLE_GROUP))
++#define MT_DBG_PSE_PLE_PG_INFO			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PLE_PG_INFO))
++#define MT_DBG_PSE_PG_LMAC3_GROUP		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_LMAC3_GROUP))
++#define MT_DBG_PSE_LMAC3_PG_INFO		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_LMAC3_PG_INFO))
++#define MT_DBG_PSE_PG_MDP_GROUP			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_MDP_GROUP))
++#define MT_DBG_PSE_MDP_PG_INFO			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_MDP_PG_INFO))
++#define MT_DBG_PSE_PG_PLE1_GROUP		MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PG_PLE1_GROUP))
++#define MT_DBG_PSE_PLE1_PG_INFO			MT_DBG_PSE(__DBG_REG_OFFS(dev, DBG_PSE_PLE1_PG_INFO))
 +
 +#define MT_DBG_PSE_PBUF_CTRL_PAGE_SIZE_CFG_MASK		BIT(31)
 +#define MT_DBG_PSE_PBUF_CTRL_PBUF_OFFSET_MASK		GENMASK(25, 17)
@@ -1733,10 +1733,10 @@
 +#endif
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
 new file mode 100644
-index 00000000..246eb129
+index 00000000..ccaaea78
 --- /dev/null
 +++ b/mt7915/mtk_debugfs.c
-@@ -0,0 +1,2893 @@
+@@ -0,0 +1,2921 @@
 +#include<linux/inet.h>
 +#include "mt7915.h"
 +#include "mt7915_debug.h"
@@ -1968,6 +1968,23 @@
 +#define LWTBL_LEN_IN_DW 32
 +#define UWTBL_LEN_IN_DW 8
 +#define ONE_KEY_ENTRY_LEN_IN_DW 8
++static int mt7915_sta_info(struct seq_file *s, void *data)
++{
++	struct mt7915_dev *dev = dev_get_drvdata(s->private);
++	u8 lwtbl[LWTBL_LEN_IN_DW*4] = {0};
++	u16 i = 0;
++
++	for (i=0; i < mt7915_wtbl_size(dev); i++) {
++		mt7915_wtbl_read_raw(dev, i, WTBL_TYPE_LMAC, 0,
++					LWTBL_LEN_IN_DW, lwtbl);
++		if (lwtbl[4] || lwtbl[5] || lwtbl[6] || lwtbl[7] || lwtbl[0] || lwtbl[1])
++			seq_printf(s, "wcid:%d\tAddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
++					i, lwtbl[4], lwtbl[5], lwtbl[6], lwtbl[7], lwtbl[0], lwtbl[1]);
++	}
++
++	return 0;
++}
++
 +static int mt7915_wtbl_read(struct seq_file *s, void *data)
 +{
 +	struct mt7915_dev *dev = dev_get_drvdata(s->private);
@@ -2893,7 +2910,7 @@
 +	return 0;
 +}
 +
-+#define CR_NUM_OF_AC 9
++#define CR_NUM_OF_AC 17
 +
 +typedef enum _ENUM_UMAC_PORT_T {
 +	ENUM_UMAC_HIF_PORT_0         = 0,
@@ -3023,16 +3040,15 @@
 +	u32 ac_num = 9, all_ac_num;
 +
 +	/* TDO: ac_num = 16 for mt7986 */
-+	/* if (!is_mt7915(&dev->mt76))
-+		ac_num = 16;
-+	*/
++	if (!is_mt7915(&dev->mt76))
++		ac_num = 17;
 +
 +	all_ac_num = ac_num * 4;
 +
 +	for (j = 0; j < all_ac_num; j++) { /* show AC Q info */
 +		for (i = 0; i < 32; i++) {
 +			if (((ple_stat[j + 1] & (0x1 << i)) >> i) == 0) {
-+				u32 hfid, tfid, pktcnt, ac_num = j / ac_num, ctrl = 0;
++				u32 hfid, tfid, pktcnt, ac_n = j / ac_num, ctrl = 0;
 +				u32 sta_num = i + (j % ac_num) * 32, fl_que_ctrl[3] = {0};
 +				//struct wifi_dev *wdev = wdev_search_by_wcid(pAd, sta_num);
 +				u32 wmmidx = 0;
@@ -3044,16 +3060,16 @@
 +				sta = wcid_to_sta(wcid);
 +				if (!sta) {
 +					printk("ERROR!! no found STA wcid=%d\n", sta_num);
-+					return 0;
++					continue;
 +				}
 +				msta = container_of(wcid, struct mt7915_sta, wcid);
 +				wmmidx = msta->vif->mt76.wmm_idx;
 +
-+				seq_printf(s, "\tSTA%d AC%d: ", sta_num, ac_num);
++				seq_printf(s, "\tSTA%d AC%d: ", sta_num, ac_n);
 +
 +				fl_que_ctrl[0] |= MT_DBG_PLE_FL_QUE_CTRL0_EXECUTE_MASK;
 +				fl_que_ctrl[0] |= (ENUM_UMAC_LMAC_PORT_2 << MT_PLE_FL_QUE_CTRL0_Q_BUF_PID_SHFT);
-+				fl_que_ctrl[0] |= (ac_num << MT_PLE_FL_QUE_CTRL0_Q_BUF_QID_SHFT);
++				fl_que_ctrl[0] |= (ac_n << MT_PLE_FL_QUE_CTRL0_Q_BUF_QID_SHFT);
 +				fl_que_ctrl[0] |= sta_num;
 +				mt76_wr(dev, MT_DBG_PLE_FL_QUE_CTRL0, fl_que_ctrl[0]);
 +				fl_que_ctrl[1] = mt76_rr(dev, MT_DBG_PLE_FL_QUE_CTRL2);
@@ -3090,7 +3106,7 @@
 +	int i;
 +
 +	seq_printf(s, "Nonempty TXCMD Q info:\n");
-+	for (i = 0; i < 31; i++) {
++	for (i = 0; i < 32; i++) {
 +		if (((ple_txcmd_stat & (0x1 << i)) >> i) == 0) {
 +			u32 hfid, tfid, pktcnt, fl_que_ctrl[3] = {0};
 +
@@ -3123,10 +3139,9 @@
 +	u32 ac , index;
 +
 +	/* TDO: cr_num = 16 for mt7986 */
-+	/*
 +	if(!is_mt7915(&dev->mt76))
-+		cr_num = 16;
-+	*/
++		cr_num = 17;
++
 +	all_cr_num =  cr_num * 4;
 +
 +	ple_stat[0] = mt76_rr(dev, MT_DBG_PLE_QUEUE_EMPTY);
@@ -3143,8 +3158,13 @@
 +static void chip_get_dis_sta_map(struct mt7915_dev *dev, u32 *dis_sta_map)
 +{
 +	int i;
++	u32 ac_num = 9;
++
++	/* TDO: ac_num = 16 for mt7986 */
++	if (!is_mt7915(&dev->mt76))
++		ac_num = 17;
 +
-+	for(i = 0; i < CR_NUM_OF_AC; i++) {
++	for(i = 0; i < ac_num; i++) {
 +		dis_sta_map[i] = mt76_rr(dev, MT_DBG_PLE_DIS_STA_MAP(i));
 +	}
 +}
@@ -3152,8 +3172,13 @@
 +static void chip_get_sta_pause(struct mt7915_dev *dev, u32 *sta_pause)
 +{
 +	int i;
++	u32 ac_num = 9;
 +
-+	for(i = 0; i < CR_NUM_OF_AC; i++) {
++	/* TDO: ac_num = 16 for mt7986 */
++	if (!is_mt7915(&dev->mt76))
++		ac_num = 17;
++
++	for(i = 0; i < ac_num; i++) {
 +		sta_pause[i] = mt76_rr(dev, MT_DBG_PLE_STATION_PAUSE(i));
 +	}
 +}
@@ -3162,7 +3187,7 @@
 +{
 +	struct mt7915_dev *dev = dev_get_drvdata(s->private);
 +	u32 ple_buf_ctrl, pg_sz, pg_num;
-+	u32 ple_stat[65] = {0}, pg_flow_ctrl[8] = {0};
++	u32 ple_stat[70] = {0}, pg_flow_ctrl[8] = {0};
 +	u32 ple_native_txcmd_stat;
 +	u32 ple_txcmd_stat;
 +	u32 sta_pause[CR_NUM_OF_AC] = {0}, dis_sta_map[CR_NUM_OF_AC] = {0};
@@ -3172,9 +3197,8 @@
 +	u32 ac_num = 9, all_ac_num;
 +
 +	/* TDO: ac_num = 16 for mt7986 */
-+	/* if (!is_mt7915(&dev->mt76))
-+		ac_num = 16;
-+	*/
++	if (!is_mt7915(&dev->mt76))
++		ac_num = 17;
 +
 +	all_ac_num = ac_num * 4;
 +
@@ -3240,15 +3264,17 @@
 +	seq_printf(s, "\tHIF_TXCMD group page status(0x%x): 0x%08x\n",
 +	              MT_DBG_PLE_HIF_TXCMD_PG_INFO, pg_flow_ctrl[7]);
 +	cpu_min_q = FIELD_GET(MT_DBG_PLE_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MIN_QUOTA_MASK, pg_flow_ctrl[6]);
-+	cpu_max_q = FIELD_GET(MT_DBG_PLE_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MIN_QUOTA_MASK, pg_flow_ctrl[6]);
++	cpu_max_q = FIELD_GET(MT_DBG_PLE_PG_HIF_TXCMD_GROUP_HIF_TXCMD_MAX_QUOTA_MASK, pg_flow_ctrl[6]);
 +	seq_printf(s, "\t\tThe max/min quota pages of HIF_TXCMD group=0x%03x/0x%03x\n", cpu_max_q, cpu_min_q);
 +
 +	rpg_cpu = FIELD_GET(MT_DBG_PLE_TXCMD_PG_INFO_HIF_TXCMD_RSV_CNT_MASK, pg_flow_ctrl[7]);
 +	upg_cpu = FIELD_GET(MT_DBG_PLE_TXCMD_PG_INFO_HIF_TXCMD_SRC_CNT_MASK, pg_flow_ctrl[7]);
 +	seq_printf(s, "\t\tThe used/reserved pages of HIF_TXCMD group=0x%03x/0x%03x\n", upg_cpu, rpg_cpu);
 +
-+	seq_printf(s, "\tReserved page counter of CPU group(0x820c0150): 0x%08x\n", pg_flow_ctrl[4]);
-+	seq_printf(s, "\tCPU group page status(0x820c0154): 0x%08x\n", pg_flow_ctrl[5]);
++	seq_printf(s, "\tReserved page counter of CPU group(0x%x): 0x%08x\n",
++			MT_DBG_PLE_PG_CPU_GROUP, pg_flow_ctrl[4]);
++	seq_printf(s, "\tCPU group page status(0x%x): 0x%08x\n",
++			MT_DBG_PLE_CPU_PG_INFO, pg_flow_ctrl[5]);
 +	cpu_min_q = FIELD_GET(MT_DBG_PLE_PG_CPU_GROUP_CPU_MIN_QUOTA_MASK, pg_flow_ctrl[4]);
 +	cpu_max_q = FIELD_GET(MT_DBG_PLE_PG_CPU_GROUP_CPU_MAX_QUOTA_MASK, pg_flow_ctrl[4]);
 +	seq_printf(s, "\t\tThe max/min quota pages of CPU group=0x%03x/0x%03x\n", cpu_max_q, cpu_min_q);
@@ -3263,7 +3289,7 @@
 +				seq_printf(s, "\n\tNonempty AC%d Q of STA#: ", j / ac_num);
 +			}
 +
-+			for (i = 0; i < all_ac_num; i++) {
++			for (i = 0; i < 32; i++) {
 +				if (((ple_stat[j + 1] & (0x1 << i)) >> i) == 0) {
 +					seq_printf(s, "%d ", i + (j % ac_num) * 32);
 +				}
@@ -3277,7 +3303,7 @@
 +
 +	seq_printf(s, "Nonempty Q info:\n");
 +
-+	for (i = 0; i < all_ac_num; i++) {
++	for (i = 0; i < 32; i++) {
 +		if (((ple_stat[0] & (0x1 << i)) >> i) == 0) {
 +			u32 hfid, tfid, pktcnt, fl_que_ctrl[3] = {0};
 +
@@ -4575,6 +4601,8 @@
 +	debugfs_create_file("fw_debug_level", 0600, dir, dev,
 +			    &fops_fw_debug_level);
 +
++	debugfs_create_devm_seqfile(dev->mt76.dev, "sta_info", dir,
++				    mt7915_sta_info);
 +	debugfs_create_devm_seqfile(dev->mt76.dev, "wtbl_info", dir,
 +				    mt7915_wtbl_read);
 +	debugfs_create_devm_seqfile(dev->mt76.dev, "uwtbl_info", dir,
@@ -4688,7 +4716,7 @@
 +				 sizeof(req), true);
 +}
 diff --git a/tools/fwlog.c b/tools/fwlog.c
-index e5d4a105..58a976a9 100644
+index e5d4a105..3d51d9ec 100644
 --- a/tools/fwlog.c
 +++ b/tools/fwlog.c
 @@ -26,7 +26,7 @@ static const char *debugfs_path(const char *phyname, const char *file)
@@ -4723,19 +4751,35 @@
  	struct sockaddr_in local = {
  		.sin_family = AF_INET,
  		.sin_addr.s_addr = INADDR_ANY,
-@@ -84,9 +91,9 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
+@@ -84,9 +91,10 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
  		.sin_family = AF_INET,
  		.sin_port = htons(55688),
  	};
 -	char buf[1504];
 +	char *buf = calloc(BUF_SIZE, sizeof(char));
++	FILE *logfile = NULL;
  	int ret = 0;
 -	int yes = 1;
 +	/* int yes = 1; */
  	int s, fd;
  
  	if (argc < 1) {
-@@ -105,13 +112,13 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
+@@ -99,19 +107,28 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
+ 		return 1;
+ 	}
+ 
++	if (argc == 3) {
++		fprintf(stdout, "start logging to file %s\n", argv[2]);
++		logfile = fopen(argv[2], "wb");
++		if (!logfile) {
++			perror("fopen");
++			return 1;
++		}
++	}
++
+ 	s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ 	if (s < 0) {
+ 		perror("socket");
  		return 1;
  	}
  
@@ -4751,7 +4795,7 @@
  		return 1;
  
  	fd = open(debugfs_path(phyname, "fwlog_data"), O_RDONLY);
-@@ -145,8 +152,8 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
+@@ -145,8 +162,8 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
  		if (!r)
  			continue;
  
@@ -4762,16 +4806,29 @@
  			ret = 1;
  			break;
  		}
+@@ -164,14 +181,19 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
+ 			break;
+ 		}
-@@ -171,7 +178,8 @@ int mt76_fwlog(const char *phyname, int argc, char **argv)
+ 
+-		/* send buf */
+-		sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote));
++		if (logfile)
++			fwrite(buf, 1, len, logfile);
++		else
++			/* send buf */
++			sendto(s, buf, len, 0, (struct sockaddr *)&remote, sizeof(remote));
+ 	}
+ 
  	close(fd);
  
  out:
 -	mt76_set_fwlog_en(phyname, false);
 +	mt76_set_fwlog_en(phyname, false, NULL);
 +	free(buf);
++	fclose(logfile);
  
  	return ret;
  }
 -- 
-2.18.0
+2.25.1
 
diff --git a/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch b/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
index d72aab5..31bdbf4 100644
--- a/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch
@@ -1,4 +1,4 @@
-From cdccb674bc75292020be6894dcea162e585dc5ce Mon Sep 17 00:00:00 2001
+From 6820d00b2fd86c760e281ea6e3e114cf2779cb12 Mon Sep 17 00:00:00 2001
 From: MeiChia Chiu <meichia.chiu@mediatek.com>
 Date: Mon, 28 Mar 2022 09:19:29 +0800
 Subject: [PATCH] mt76: mt7915: add support for muru_onoff via debugfs
@@ -12,7 +12,7 @@
  5 files changed, 49 insertions(+), 4 deletions(-)
 
 diff --git a/mt7915/init.c b/mt7915/init.c
-index dbcdf147..c58f045f 100644
+index ad2a9c9f..3eaf7916 100644
 --- a/mt7915/init.c
 +++ b/mt7915/init.c
 @@ -574,6 +574,7 @@ static void mt7915_init_work(struct work_struct *work)
@@ -24,7 +24,7 @@
  
  void mt7915_wfsys_reset(struct mt7915_dev *dev)
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 26831327..95825062 100644
+index c7694819..cbcd3bd4 100755
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -944,6 +944,7 @@ mt7915_mcu_sta_muru_tlv(struct sk_buff *skb, struct ieee80211_sta *sta,
@@ -55,10 +55,10 @@
  	if (sta->vht_cap.vht_supported)
  		muru->mimo_dl.vht_mu_bfee =
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index 007282d4..a5e5afae 100644
+index f166eaea..ccb1c9d0 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
-@@ -569,4 +569,10 @@ struct csi_data {
+@@ -573,4 +573,10 @@ struct csi_data {
  };
  #endif
  
@@ -70,7 +70,7 @@
 +
  #endif
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 9960785e..ec844dbe 100644
+index 1b37cef7..e6b87239 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -390,6 +390,7 @@ struct mt7915_dev {
@@ -82,10 +82,10 @@
  	const struct mt7915_dbg_reg_desc *dbg_reg;
  #endif
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index 246eb129..6c48f115 100644
+index ccaaea78..d2dbae45 100644
 --- a/mt7915/mtk_debugfs.c
 +++ b/mt7915/mtk_debugfs.c
-@@ -2454,6 +2454,38 @@ static int mt7915_token_txd_read(struct seq_file *s, void *data)
+@@ -2480,6 +2480,38 @@ static int mt7915_token_txd_read(struct seq_file *s, void *data)
  	return 0;
  }
  
@@ -124,7 +124,7 @@
  static int mt7915_amsduinfo_read(struct seq_file *s, void *data)
  {
  	struct mt7915_dev *dev = dev_get_drvdata(s->private);
-@@ -2831,6 +2863,7 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
+@@ -2857,6 +2889,7 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
  
  	mt7915_mcu_fw_log_2_host(dev, MCU_FW_LOG_WM, 0);
  
diff --git a/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-L0.5-system-error-recovery-support.patch b/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-L0.5-system-error-recovery-support.patch
new file mode 100755
index 0000000..20ccd9d
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1007-mt76-mt7915-add-L0.5-system-error-recovery-support.patch
@@ -0,0 +1,935 @@
+From ce9d865db52e49410af55a3b348f00ed1511ccbc Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Thu, 5 May 2022 16:25:44 +0800
+Subject: [PATCH 04/10] mt76: mt7915: add L0.5 system error recovery support
+
+add L0.5 system error recovery support
+auto trigger l0.5 ser when detect fw exception or mem dma hang.
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt7915/debugfs.c |  88 ++++++++++++---
+ mt7915/dma.c     |  48 ++++++++
+ mt7915/init.c    |   8 +-
+ mt7915/mac.c     | 280 +++++++++++++++++++++++++++++++++++++----------
+ mt7915/main.c    |  20 +++-
+ mt7915/mcu.c     |  96 ++++++++++++++--
+ mt7915/mcu.h     |   3 +-
+ mt7915/mmio.c    |   8 +-
+ mt7915/mt7915.h  |  23 ++++
+ mt7915/regs.h    |  16 +++
+ 10 files changed, 493 insertions(+), 97 deletions(-)
+
+diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
+index b45181c1..f07df470 100644
+--- a/mt7915/debugfs.c
++++ b/mt7915/debugfs.c
+@@ -49,12 +49,17 @@ static ssize_t
+ mt7915_fw_ser_set(struct file *file, const char __user *user_buf,
+ 		  size_t count, loff_t *ppos)
+ {
++#define SER_LEVEL	GENMASK(3, 0)
++#define SER_ACTION	GENMASK(11, 8)
++
+ 	struct mt7915_phy *phy = file->private_data;
+ 	struct mt7915_dev *dev = phy->dev;
+-	bool ext_phy = phy != &dev->phy;
++	u8 ser_action, ser_set, set_val;
++	u8 band_idx = phy->band_idx;
+ 	char buf[16];
+ 	int ret = 0;
+ 	u16 val;
++	u32 intr;
+ 
+ 	if (count >= sizeof(buf))
+ 		return -EINVAL;
+@@ -70,28 +75,71 @@ mt7915_fw_ser_set(struct file *file, const char __user *user_buf,
+ 	if (kstrtou16(buf, 0, &val))
+ 		return -EINVAL;
+ 
+-	switch (val) {
++	ser_action = FIELD_GET(SER_ACTION, val);
++	ser_set = set_val = FIELD_GET(SER_LEVEL, val);
++
++	switch (ser_action) {
+ 	case SER_QUERY:
+ 		/* grab firmware SER stats */
+-		ret = mt7915_mcu_set_ser(dev, 0, 0, ext_phy);
++		ser_set = 0;
+ 		break;
+-	case SER_SET_RECOVER_L1:
+-	case SER_SET_RECOVER_L2:
+-	case SER_SET_RECOVER_L3_RX_ABORT:
+-	case SER_SET_RECOVER_L3_TX_ABORT:
+-	case SER_SET_RECOVER_L3_TX_DISABLE:
+-	case SER_SET_RECOVER_L3_BF:
+-		ret = mt7915_mcu_set_ser(dev, SER_ENABLE, BIT(val), ext_phy);
+-		if (ret)
+-			return ret;
+-
+-		ret = mt7915_mcu_set_ser(dev, SER_RECOVER, val, ext_phy);
++	case SER_SET:
++		/*
++		 * 0x100: disable system error recovery function.
++		 * 0x101: enable system error recovery function.
++		 * 0x103: enable l0.5 recover function.
++		 */
++		ser_set = !!set_val;
++
++		dev->ser.reset_enable = ser_set;
++		intr = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
++		if (dev->ser.reset_enable)
++			intr |= MT_MCU_CMD_WDT_MASK;
++		else
++			intr &= ~MT_MCU_CMD_WDT_MASK;
++		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, intr);
+ 		break;
+-	default:
++	case SER_ENABLE:
++		/*
++		 * 0x200: enable system error tracking.
++		 * 0x201: enable system error L1 recover.
++		 * 0x202: enable system error L2 recover.
++		 * 0x203: enable system error L3 rx abort.
++		 * 0x204: enable system error L3 tx abort.
++		 * 0x205: enable system error L3 tx disable.
++		 * 0x206: enable system error L3 bf recover.
++		 * 0x207: enable system error all recover.
++		 */
++		ser_set = set_val > 7 ? 0x7f : BIT(set_val);
++		break;
++	case SER_RECOVER:
++		/*
++		 * 0x300: trigger L0.5 recover.
++		 * 0x301: trigger L1 recover.
++		 * 0x302: trigger L2 recover.
++		 * 0x303: trigger L3 rx abort.
++		 * 0x304: trigger L3 tx abort
++		 * 0x305: trigger L3 tx disable.
++		 * 0x306: trigger L3 bf recover.
++		 */
++		if (!ser_set) {
++			if (dev->ser.reset_enable) {
++				dev->reset_state |= MT_MCU_CMD_WDT_MASK;
++				mt7915_reset(dev);
++			} else {
++				dev_info(dev->mt76.dev, "SER: chip full recovery not enable\n");
++			}
++			goto out;
++		}
+ 		break;
++	default:
++		goto out;
+ 	}
+-
+-	return ret ? ret : count;
++	ret = mt7915_mcu_set_ser(dev, ser_action, ser_set, band_idx);
++	if (ret)
++		return ret;
++out:
++	return count;
+ }
+ 
+ static ssize_t
+@@ -140,6 +188,12 @@ mt7915_fw_ser_get(struct file *file, char __user *user_buf,
+ 			  "::E  R , SER_LMAC_WISR7_B1 = 0x%08x\n",
+ 			  mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATS));
+ 
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "\nWF RESET STATUS: EN %d, WM %d, WA %d\n",
++			  dev->ser.reset_enable,
++			  dev->ser.wf_reset_wm_count,
++			  dev->ser.wf_reset_wa_count);
++
+ 	ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+ 	kfree(buff);
+ 	return ret;
+diff --git a/mt7915/dma.c b/mt7915/dma.c
+index c2d655cd..9e3d14db 100644
+--- a/mt7915/dma.c
++++ b/mt7915/dma.c
+@@ -486,6 +486,54 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
+ 	return 0;
+ }
+ 
++int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
++{
++	struct mt76_phy *mphy_ext = dev->mt76.phy2;
++	int i;
++
++	/* clean up hw queues */
++	for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) {
++		mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
++		if (mphy_ext)
++			mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
++	}
++
++	for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++)
++		mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
++
++	mt76_for_each_q_rx(&dev->mt76, i)
++		mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
++
++	/* reset wfsys */
++	if (force)
++		mt7915_wfsys_reset(dev);
++
++	/* disable wfdma */
++	mt7915_dma_disable(dev, force);
++
++	/* reset hw queues */
++	for (i = 0; i < __MT_TXQ_MAX; i++) {
++		mt76_queue_reset(dev, dev->mphy.q_tx[i]);
++		if (mphy_ext)
++			mt76_queue_reset(dev, mphy_ext->q_tx[i]);
++	}
++
++	for (i = 0; i < __MT_MCUQ_MAX; i++)
++		mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
++
++	mt76_for_each_q_rx(&dev->mt76, i)
++		mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
++
++	mt76_tx_status_check(&dev->mt76, true);
++
++	mt7915_dma_enable(dev);
++
++	mt76_for_each_q_rx(&dev->mt76, i)
++		mt76_queue_rx_reset(dev, i);
++
++	return 0;
++}
++
+ void mt7915_dma_cleanup(struct mt7915_dev *dev)
+ {
+ 	mt7915_dma_disable(dev, true);
+diff --git a/mt7915/init.c b/mt7915/init.c
+index 1c956d3d..4984ec8f 100644
+--- a/mt7915/init.c
++++ b/mt7915/init.c
+@@ -262,7 +262,7 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
+ 		mt7915_led_set_config(led_cdev, 0xff, 0);
+ }
+ 
+-static void
++void
+ mt7915_init_txpower(struct mt7915_dev *dev,
+ 		    struct ieee80211_supported_band *sband)
+ {
+@@ -441,7 +441,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
+ 	mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
+ }
+ 
+-static void mt7915_mac_init(struct mt7915_dev *dev)
++void mt7915_mac_init(struct mt7915_dev *dev)
+ {
+ 	int i;
+ 	u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680;
+@@ -471,7 +471,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
+ 	}
+ }
+ 
+-static int mt7915_txbf_init(struct mt7915_dev *dev)
++int mt7915_txbf_init(struct mt7915_dev *dev)
+ {
+ 	int ret;
+ 
+@@ -1112,6 +1112,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
+ 
+ 	mt7915_init_debugfs(&dev->phy);
+ 
++	dev->ser.hw_init_done = true;
++
+ 	return 0;
+ 
+ unreg_thermal:
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index de5f3f10..1a1798d2 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -3,6 +3,7 @@
+ 
+ #include <linux/etherdevice.h>
+ #include <linux/timekeeping.h>
++#include <linux/pci.h>
+ #include "mt7915.h"
+ #include "../dma.h"
+ #include "mac.h"
+@@ -2037,85 +2038,188 @@ mt7915_update_beacons(struct mt7915_dev *dev)
+ 		mt7915_update_vif_beacon, dev->mt76.phy2->hw);
+ }
+ 
+-static void
+-mt7915_dma_reset(struct mt7915_dev *dev)
++void mt7915_tx_token_put(struct mt7915_dev *dev)
+ {
+-	struct mt76_phy *mphy_ext = dev->mt76.phy2;
+-	u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
+-	int i;
++	struct mt76_txwi_cache *txwi;
++	int id;
+ 
+-	mt76_clear(dev, MT_WFDMA0_GLO_CFG,
+-		   MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+-		   MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++	spin_lock_bh(&dev->mt76.token_lock);
++	idr_for_each_entry(&dev->mt76.token, txwi, id) {
++		mt7915_txwi_free(dev, txwi, NULL, NULL);
++		dev->mt76.token_count--;
++	}
++	spin_unlock_bh(&dev->mt76.token_lock);
++	idr_destroy(&dev->mt76.token);
++}
+ 
+-	if (is_mt7915(&dev->mt76))
+-		mt76_clear(dev, MT_WFDMA1_GLO_CFG,
+-			   MT_WFDMA1_GLO_CFG_TX_DMA_EN |
+-			   MT_WFDMA1_GLO_CFG_RX_DMA_EN);
++static int
++mt7915_mac_reset(struct mt7915_dev *dev)
++{
++	struct mt7915_phy *phy2;
++	struct mt76_phy *ext_phy;
++	struct mt76_dev *mdev = &dev->mt76;
++	int i, ret;
++	u32 irq_mask;
++
++	ext_phy = dev->mt76.phy2;
++	phy2 = ext_phy ? ext_phy->priv : NULL;
++
++	/* irq disable */
++	mt76_wr(dev, MT_INT_MASK_CSR, 0x0);
++	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
+ 	if (dev->hif2) {
+-		mt76_clear(dev, MT_WFDMA0_GLO_CFG + hif1_ofs,
+-			   MT_WFDMA0_GLO_CFG_TX_DMA_EN |
+-			   MT_WFDMA0_GLO_CFG_RX_DMA_EN);
++		mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
++		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
++	}
++	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 (is_mt7915(&dev->mt76))
+-			mt76_clear(dev, MT_WFDMA1_GLO_CFG + hif1_ofs,
+-				   MT_WFDMA1_GLO_CFG_TX_DMA_EN |
+-				   MT_WFDMA1_GLO_CFG_RX_DMA_EN);
++	set_bit(MT76_RESET, &dev->mphy.state);
++	set_bit(MT76_MCU_RESET, &dev->mphy.state);
++	wake_up(&dev->mt76.mcu.wait);
++	if (ext_phy) {
++		set_bit(MT76_RESET, &ext_phy->state);
++		set_bit(MT76_MCU_RESET, &ext_phy->state);
+ 	}
+ 
+-	usleep_range(1000, 2000);
++	/* lock/unlock all queues to ensure that no tx is pending */
++	mt76_txq_schedule_all(&dev->mphy);
++	if (ext_phy)
++		mt76_txq_schedule_all(ext_phy);
+ 
+-	for (i = 0; i < __MT_TXQ_MAX; i++) {
+-		mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
+-		if (mphy_ext)
+-			mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
++	/* disable all tx/rx napi */
++	mt76_worker_disable(&dev->mt76.tx_worker);
++	mt76_for_each_q_rx(mdev, i) {
++		if (mdev->q_rx[i].ndesc)
++			napi_disable(&dev->mt76.napi[i]);
+ 	}
++	napi_disable(&dev->mt76.tx_napi);
+ 
+-	for (i = 0; i < __MT_MCUQ_MAX; i++)
+-		mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
+-
+-	mt76_for_each_q_rx(&dev->mt76, i)
+-		mt76_queue_rx_reset(dev, i);
++	/* token reinit */
++	mt7915_tx_token_put(dev);
++	idr_init(&dev->mt76.token);
+ 
+-	mt76_tx_status_check(&dev->mt76, true);
++	mt7915_dma_reset(dev, true);
+ 
+-	/* re-init prefetch settings after reset */
+-	mt7915_dma_prefetch(dev);
++	local_bh_disable();
++	mt76_for_each_q_rx(mdev, i) {
++		if (mdev->q_rx[i].ndesc) {
++			napi_enable(&dev->mt76.napi[i]);
++			napi_schedule(&dev->mt76.napi[i]);
++		}
++	}
++	local_bh_enable();
++	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
++	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
+ 
+-	mt76_set(dev, MT_WFDMA0_GLO_CFG,
+-		 MT_WFDMA0_GLO_CFG_TX_DMA_EN | MT_WFDMA0_GLO_CFG_RX_DMA_EN);
+-	if (is_mt7915(&dev->mt76))
+-		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);
++	mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
++	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
+ 	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);
++		mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask);
++		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
++	}
++	if (dev_is_pci(mdev->dev)) {
++		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
++		if (dev->hif2)
++			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
++	}
++
++	/* load firmware */
++	ret = mt7915_run_firmware(dev);
++	if (ret)
++		goto out;
++
++	/* set the necessary init items */
++	ret = mt7915_mcu_set_eeprom(dev, dev->flash_mode);
++	if (ret)
++		goto out;
++
++	mt7915_mac_init(dev);
++	mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
++	mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
++	ret = mt7915_txbf_init(dev);
+ 
+-		if (is_mt7915(&dev->mt76))
+-			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);
++	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state)) {
++		ret = __mt7915_start(dev->mphy.hw);
++		if (ret)
++			goto out;
++	}
++
++	if (ext_phy && test_bit(MT76_STATE_RUNNING, &ext_phy->state)) {
++		ret = __mt7915_start(ext_phy->hw);
++		if (ret)
++			goto out;
+ 	}
++
++out:
++	/* reset done */
++	clear_bit(MT76_RESET, &dev->mphy.state);
++	if (phy2)
++		clear_bit(MT76_RESET, &phy2->mt76->state);
++
++	local_bh_disable();
++	napi_enable(&dev->mt76.tx_napi);
++	napi_schedule(&dev->mt76.tx_napi);
++	local_bh_enable();
++
++	mt76_worker_enable(&dev->mt76.tx_worker);
++
++	return ret;
+ }
+ 
+-void mt7915_tx_token_put(struct mt7915_dev *dev)
++static void
++mt7915_mac_full_reset(struct mt7915_dev *dev)
+ {
+-	struct mt76_txwi_cache *txwi;
+-	int id;
++	struct mt7915_phy *phy2;
++	struct mt76_phy *ext_phy;
++	int i;
+ 
+-	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--;
++	ext_phy = dev->mt76.phy2;
++	phy2 = ext_phy ? ext_phy->priv : NULL;
++
++	dev->ser.hw_full_reset = true;
++	if (READ_ONCE(dev->reset_state) & MT_MCU_CMD_WA_WDT)
++		dev->ser.wf_reset_wa_count++;
++	else
++		dev->ser.wf_reset_wm_count++;
++
++	wake_up(&dev->mt76.mcu.wait);
++	ieee80211_stop_queues(mt76_hw(dev));
++	if (ext_phy)
++		ieee80211_stop_queues(ext_phy->hw);
++
++	cancel_delayed_work_sync(&dev->mphy.mac_work);
++	if (ext_phy)
++		cancel_delayed_work_sync(&ext_phy->mac_work);
++
++	mutex_lock(&dev->mt76.mutex);
++	for (i = 0; i < 10; i++) {
++		if (!mt7915_mac_reset(dev))
++			break;
+ 	}
+-	spin_unlock_bh(&dev->mt76.token_lock);
+-	idr_destroy(&dev->mt76.token);
++	mutex_unlock(&dev->mt76.mutex);
++
++	if (i == 10)
++		dev_err(dev->mt76.dev, "chip full reset failed\n");
++
++	ieee80211_restart_hw(mt76_hw(dev));
++	if (ext_phy)
++		ieee80211_restart_hw(ext_phy->hw);
++
++	ieee80211_wake_queues(mt76_hw(dev));
++	if (ext_phy)
++		ieee80211_wake_queues(ext_phy->hw);
++
++	dev->ser.hw_full_reset = false;
++	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
++				     MT7915_WATCHDOG_TIME);
++	if (ext_phy)
++		ieee80211_queue_delayed_work(ext_phy->hw,
++					     &ext_phy->mac_work,
++					     MT7915_WATCHDOG_TIME);
+ }
+ 
+ /* system error recovery */
+@@ -2129,6 +2233,36 @@ void mt7915_mac_reset_work(struct work_struct *work)
+ 	ext_phy = dev->mt76.phy2;
+ 	phy2 = ext_phy ? ext_phy->priv : NULL;
+ 
++	/* chip full reset */
++	if (dev->ser.reset_type == SER_TYPE_FULL_RESET) {
++		u32 intr;
++
++		/* disable WA/WM WDT */
++		intr = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
++		intr &= ~MT_MCU_CMD_WDT_MASK;
++		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, intr);
++
++		mt7915_mac_full_reset(dev);
++
++		/* enable the mcu irq*/
++		mt7915_irq_enable(dev, MT_INT_MCU_CMD);
++		mt7915_irq_disable(dev, 0);
++
++		/* re-enable WA/WM WDT */
++		intr = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
++		intr |= MT_MCU_CMD_WDT_MASK;
++		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, intr);
++
++		dev->reset_state = MT_MCU_CMD_NORMAL_STATE;
++		dev->ser.reset_type = SER_TYPE_NONE;
++		dev_info(dev->mt76.dev, "SER: chip full reset completed, WM %d, WA %d\n",
++			 dev->ser.wf_reset_wm_count,
++			 dev->ser.wf_reset_wa_count);
++		return;
++	}
++
++	/* chip partial reset */
++	dev->ser.reset_type = SER_TYPE_NONE;
+ 	if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
+ 		return;
+ 
+@@ -2155,7 +2289,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
+ 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
+ 
+ 	if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
+-		mt7915_dma_reset(dev);
++		mt7915_dma_reset(dev, false);
+ 
+ 		mt7915_tx_token_put(dev);
+ 		idr_init(&dev->mt76.token);
+@@ -2206,6 +2340,34 @@ void mt7915_mac_reset_work(struct work_struct *work)
+ 					     MT7915_WATCHDOG_TIME);
+ }
+ 
++void mt7915_reset(struct mt7915_dev *dev)
++{
++	if (!dev->ser.hw_init_done)
++		return;
++
++	if (dev->ser.hw_full_reset)
++		return;
++
++	/* wm/wa exception: do full recovery */
++	if (READ_ONCE(dev->reset_state) & MT_MCU_CMD_WDT_MASK) {
++		dev_info(dev->mt76.dev, "SER: chip full recovery start, WM %d, WA %d\n",
++			 dev->ser.wf_reset_wm_count,
++			 dev->ser.wf_reset_wa_count);
++
++		dev->ser.reset_type = SER_TYPE_FULL_RESET;
++
++		mt7915_irq_disable(dev, MT_INT_MCU_CMD);
++		queue_work(dev->mt76.wq, &dev->reset_work);
++		return;
++	}
++
++	dev_info(dev->mt76.dev, "SER: chip partial recovery, reset_state(0x%08X)\n",
++		READ_ONCE(dev->reset_state));
++	dev->ser.reset_type = SER_TYPE_PARTIAL_RESET;
++	queue_work(dev->mt76.wq, &dev->reset_work);
++	wake_up(&dev->reset_wait);
++}
++
+ void mt7915_mac_update_stats(struct mt7915_phy *phy)
+ {
+ 	struct mt7915_dev *dev = phy->dev;
+diff --git a/mt7915/main.c b/mt7915/main.c
+index 78bf5ffa..eabcd785 100644
+--- a/mt7915/main.c
++++ b/mt7915/main.c
+@@ -20,17 +20,13 @@ static bool mt7915_dev_running(struct mt7915_dev *dev)
+ 	return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
+ }
+ 
+-static int mt7915_start(struct ieee80211_hw *hw)
++int __mt7915_start(struct ieee80211_hw *hw)
+ {
+ 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
+ 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ 	bool running;
+ 	int ret;
+ 
+-	flush_work(&dev->init_work);
+-
+-	mutex_lock(&dev->mt76.mutex);
+-
+ 	running = mt7915_dev_running(dev);
+ 
+ 	if (!running) {
+@@ -80,6 +76,19 @@ static int mt7915_start(struct ieee80211_hw *hw)
+ 		mt7915_mac_reset_counters(phy);
+ 
+ out:
++	return ret;
++}
++
++static int mt7915_start(struct ieee80211_hw *hw)
++{
++	struct mt7915_dev *dev = mt7915_hw_dev(hw);
++	bool running;
++	int ret;
++
++	flush_work(&dev->init_work);
++
++	mutex_lock(&dev->mt76.mutex);
++	ret = __mt7915_start(hw);
+ 	mutex_unlock(&dev->mt76.mutex);
+ 
+ 	return ret;
+@@ -91,6 +100,7 @@ static void mt7915_stop(struct ieee80211_hw *hw)
+ 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
+ 
+ 	cancel_delayed_work_sync(&phy->mt76->mac_work);
++	cancel_work_sync(&dev->reset_work);
+ 
+ 	mutex_lock(&dev->mt76.mutex);
+ 
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 20f32f7f..b29776e9 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -203,19 +203,90 @@ mt7915_mcu_set_sta_ht_mcs(struct ieee80211_sta *sta, u8 *ht_mcs,
+ 		ht_mcs[nss] = sta->ht_cap.mcs.rx_mask[nss] & mask[nss];
+ }
+ 
++static int
++mt7915_fw_exception_chk(struct mt7915_dev *dev)
++{
++	u32 reg_val;
++
++	reg_val = mt76_rr(dev, MT_EXCEPTION_ADDR);
++
++	if (is_mt7915(&dev->mt76))
++		reg_val >>= 8;
++
++	return !!(reg_val & 0xff);
++}
++
++static void
++mt7915_fw_heart_beat_chk(struct mt7915_dev *dev)
++{
++#define WM_TIMEOUT_COUNT_CHECK 5
++#define WM_HANG_COUNT_CHECK 9
++	static u32 cidx_rec[5], didx_rec[5];
++	u32 cnt, cidx, didx, queue;
++	u32 idx, i;
++
++	if (dev->ser.hw_full_reset)
++		return;
++
++	if (dev->ser.cmd_fail_cnt >= WM_TIMEOUT_COUNT_CHECK) {
++		cnt = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 4);
++		cidx = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 8);
++		didx = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 12);
++		queue = (didx > cidx) ?
++			(didx - cidx - 1) : (didx - cidx + cnt - 1);
++
++		idx = (dev->ser.cmd_fail_cnt - WM_TIMEOUT_COUNT_CHECK) % 5;
++		cidx_rec[idx] = cidx;
++		didx_rec[idx] = didx;
++
++		if ((cnt - 1) == queue &&
++		    dev->ser.cmd_fail_cnt >= WM_HANG_COUNT_CHECK) {
++
++			for (i = 0; i < 5; i++) {
++				if (cidx_rec[i] != cidx ||
++				    didx_rec[i] != didx)
++					return;
++			}
++			dev_err(dev->mt76.dev, "detect mem dma hang!\n");
++			if (dev->ser.reset_enable) {
++				dev->reset_state |= MT_MCU_CMD_WDT_MASK;
++				mt7915_reset(dev);
++			}
++			dev->ser.cmd_fail_cnt = 0;
++		}
++	}
++}
++
+ static int
+ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
+ 			  struct sk_buff *skb, int seq)
+ {
++	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
+ 	struct mt7915_mcu_rxd *rxd;
+ 	int ret = 0;
+ 
+ 	if (!skb) {
+ 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
+ 			cmd, seq);
++
++		dev->ser.cmd_fail_cnt++;
++
++		if (dev->ser.cmd_fail_cnt < 5) {
++			int exp_type = mt7915_fw_exception_chk(dev);
++
++			dev_err(mdev->dev, "Fw is status(%d)\n", exp_type);
++			if (exp_type && dev->ser.reset_enable) {
++				dev->reset_state |= MT_MCU_CMD_WDT_MASK;
++				mt7915_reset(dev);
++			}
++		}
++		mt7915_fw_heart_beat_chk(dev);
++
+ 		return -ETIMEDOUT;
+ 	}
+ 
++	dev->ser.cmd_fail_cnt = 0;
++
+ 	rxd = (struct mt7915_mcu_rxd *)skb->data;
+ 	if (seq != rxd->seq)
+ 		return -EAGAIN;
+@@ -2456,18 +2527,10 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
+ 				 sizeof(req), true);
+ }
+ 
+-int mt7915_mcu_init(struct mt7915_dev *dev)
++int mt7915_run_firmware(struct mt7915_dev *dev)
+ {
+-	static const struct mt76_mcu_ops mt7915_mcu_ops = {
+-		.headroom = sizeof(struct mt7915_mcu_txd),
+-		.mcu_skb_send_msg = mt7915_mcu_send_message,
+-		.mcu_parse_response = mt7915_mcu_parse_response,
+-		.mcu_restart = mt76_connac_mcu_restart,
+-	};
+ 	int ret;
+ 
+-	dev->mt76.mcu_ops = &mt7915_mcu_ops;
+-
+ 	/* force firmware operation mode into normal state,
+ 	 * which should be set before firmware download stage.
+ 	 */
+@@ -2516,6 +2579,21 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
+ 				 MCU_WA_PARAM_RED, 0, 0);
+ }
+ 
++int mt7915_mcu_init(struct mt7915_dev *dev)
++{
++	static const struct mt76_mcu_ops mt7915_mcu_ops = {
++		.headroom = sizeof(struct mt7915_mcu_txd),
++		.mcu_skb_send_msg = mt7915_mcu_send_message,
++		.mcu_parse_response = mt7915_mcu_parse_response,
++		.mcu_restart = mt76_connac_mcu_restart,
++	};
++	int ret;
++
++	dev->mt76.mcu_ops = &mt7915_mcu_ops;
++
++	return mt7915_run_firmware(dev);
++}
++
+ void mt7915_mcu_exit(struct mt7915_dev *dev)
+ {
+ 	__mt76_mcu_restart(&dev->mt76);
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index 5cbc3ecf..229b9d72 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -466,8 +466,9 @@ enum {
+ 
+ enum {
+ 	SER_QUERY,
++	SER_SET,
+ 	/* recovery */
+-	SER_SET_RECOVER_L1,
++	SER_SET_RECOVER_L1 = 1,
+ 	SER_SET_RECOVER_L2,
+ 	SER_SET_RECOVER_L3_RX_ABORT,
+ 	SER_SET_RECOVER_L3_TX_ABORT,
+diff --git a/mt7915/mmio.c b/mt7915/mmio.c
+index 4d4537cd..b3de3a7a 100644
+--- a/mt7915/mmio.c
++++ b/mt7915/mmio.c
+@@ -23,6 +23,7 @@ static const u32 mt7915_reg[] = {
+ 	[CBTOP1_PHY_END]	= 0x77ffffff,
+ 	[INFRA_MCU_ADDR_END]	= 0x7c3fffff,
+ 	[SWDEF_BASE_ADDR]	= 0x41f200,
++	[EXCEPTION_BASE_ADDR]	= 0x219848,
+ };
+ 
+ static const u32 mt7916_reg[] = {
+@@ -38,6 +39,7 @@ static const u32 mt7916_reg[] = {
+ 	[CBTOP1_PHY_END]	= 0x7fffffff,
+ 	[INFRA_MCU_ADDR_END]	= 0x7c085fff,
+ 	[SWDEF_BASE_ADDR]	= 0x411400,
++	[EXCEPTION_BASE_ADDR]	= 0x022050BC,
+ };
+ 
+ static const u32 mt7986_reg[] = {
+@@ -53,6 +55,7 @@ static const u32 mt7986_reg[] = {
+ 	[CBTOP1_PHY_END]	= 0x7fffffff,
+ 	[INFRA_MCU_ADDR_END]	= 0x7c085fff,
+ 	[SWDEF_BASE_ADDR]	= 0x411400,
++	[EXCEPTION_BASE_ADDR]	= 0x02204FFC,
+ };
+ 
+ static const u32 mt7915_offs[] = {
+@@ -610,10 +613,9 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
+ 		u32 val = mt76_rr(dev, MT_MCU_CMD);
+ 
+ 		mt76_wr(dev, MT_MCU_CMD, val);
+-		if (val & MT_MCU_CMD_ERROR_MASK) {
++		if (val & (MT_MCU_CMD_ERROR_MASK | MT_MCU_CMD_WDT_MASK)) {
+ 			dev->reset_state = val;
+-			queue_work(dev->mt76.wq, &dev->reset_work);
+-			wake_up(&dev->reset_wait);
++			mt7915_reset(dev);
+ 		}
+ 	}
+ }
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index e5f89161..7f7ecdfe 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -297,6 +297,15 @@ struct mt7915_dev {
+ 	struct work_struct reset_work;
+ 	wait_queue_head_t reset_wait;
+ 	u32 reset_state;
++	struct {
++		bool hw_full_reset:1;
++		bool hw_init_done:1;
++		bool reset_enable:1;
++		u32 reset_type;
++		u32 cmd_fail_cnt;
++		u32 wf_reset_wm_count;
++		u32 wf_reset_wa_count;
++	}ser;
+ 
+ 	struct list_head sta_rc_list;
+ 	struct list_head sta_poll_list;
+@@ -335,6 +344,12 @@ enum {
+ 	__MT_WFDMA_MAX,
+ };
+ 
++enum {
++	SER_TYPE_NONE,
++	SER_TYPE_PARTIAL_RESET,
++	SER_TYPE_FULL_RESET,
++};
++
+ enum {
+ 	MT_CTX0,
+ 	MT_HIF0 = 0x0,
+@@ -446,6 +461,14 @@ s8 mt7915_eeprom_get_power_delta(struct mt7915_dev *dev, int band);
+ 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);
++void mt7915_reset(struct mt7915_dev *dev);
++int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
++int __mt7915_start(struct ieee80211_hw *hw);
++void mt7915_init_txpower(struct mt7915_dev *dev,
++		    struct ieee80211_supported_band *sband);
++int mt7915_txbf_init(struct mt7915_dev *dev);
++void mt7915_mac_init(struct mt7915_dev *dev);
++int mt7915_run_firmware(struct mt7915_dev *dev);
+ int mt7915_mcu_init(struct mt7915_dev *dev);
+ int mt7915_mcu_twt_agrt_update(struct mt7915_dev *dev,
+ 			       struct mt7915_vif *mvif,
+diff --git a/mt7915/regs.h b/mt7915/regs.h
+index 4251cf78..99834310 100644
+--- a/mt7915/regs.h
++++ b/mt7915/regs.h
+@@ -31,6 +31,7 @@ enum reg_rev {
+ 	CBTOP1_PHY_END,
+ 	INFRA_MCU_ADDR_END,
+ 	SWDEF_BASE_ADDR,
++	EXCEPTION_BASE_ADDR,
+ 	__MT_REG_MAX,
+ };
+ 
+@@ -112,6 +113,11 @@ enum offs_rev {
+ #define __REG(id)			(dev->reg.reg_rev[(id)])
+ #define __OFFS(id)			(dev->reg.offs_rev[(id)])
+ 
++/* MEM WFDMA */
++#define WF_WFDMA_MEM_DMA		0x58000000
++
++#define WF_WFDMA_MEM_DMA_RX_RING_CTL	(WF_WFDMA_MEM_DMA + (0x510))
++
+ /* MCU WFDMA0 */
+ #define MT_MCU_WFDMA0_BASE		0x2000
+ #define MT_MCU_WFDMA0(ofs)		(MT_MCU_WFDMA0_BASE + (ofs))
+@@ -556,6 +562,10 @@ enum offs_rev {
+ #define MT_WFDMA0_PRI_DLY_INT_CFG1	MT_WFDMA0(0x2f4)
+ #define MT_WFDMA0_PRI_DLY_INT_CFG2	MT_WFDMA0(0x2f8)
+ 
++#define MT_WFDMA0_MCU_HOST_INT_ENA	MT_WFDMA0(0x1f4)
++#define MT_WFDMA0_MT_WA_WDT_INT		BIT(31)
++#define MT_WFDMA0_MT_WM_WDT_INT		BIT(30)
++
+ /* WFDMA1 */
+ #define MT_WFDMA1_BASE			0xd5000
+ #define MT_WFDMA1(ofs)			(MT_WFDMA1_BASE + (ofs))
+@@ -701,6 +711,10 @@ enum offs_rev {
+ #define MT_MCU_CMD_NORMAL_STATE		BIT(5)
+ #define MT_MCU_CMD_ERROR_MASK		GENMASK(5, 1)
+ 
++#define MT_MCU_CMD_WA_WDT		BIT(31)
++#define MT_MCU_CMD_WM_WDT		BIT(30)
++#define MT_MCU_CMD_WDT_MASK		GENMASK(31, 30)
++
+ /* TOP RGU */
+ #define MT_TOP_RGU_BASE			0x18000000
+ #define MT_TOP_PWR_CTRL			(MT_TOP_RGU_BASE + (0x0))
+@@ -974,6 +988,8 @@ enum offs_rev {
+ #define MT_CPU_UTIL_PEAK_IDLE_CNT	MT_CPU_UTIL(0x0c)
+ #define MT_CPU_UTIL_CTRL		MT_CPU_UTIL(0x1c)
+ 
++#define MT_EXCEPTION_ADDR		__REG(EXCEPTION_BASE_ADDR)
++
+ /* LED */
+ #define MT_LED_TOP_BASE			0x18013000
+ #define MT_LED_PHYS(_n)			(MT_LED_TOP_BASE + (_n))
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch b/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
new file mode 100644
index 0000000..ae9ca75
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1009-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch
@@ -0,0 +1,36 @@
+From 71e967c4ea7f0e119ff66197491acae7b9bd87e0 Mon Sep 17 00:00:00 2001
+From: MeiChia Chiu <meichia.chiu@mediatek.com>
+Date: Fri, 27 May 2022 15:51:48 +0800
+Subject: [PATCH] mt76: mt7915:add support for runtime set in-band discovery
+
+Signed-off-by: MeiChia Chiu <MeiChia.Chiu@mediatek.com>
+---
+ mt7915/mcu.c | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/mt7915/mcu.c b/mt7915/mcu.c
+index 203fa32..73239df 100644
+--- a/mt7915/mcu.c
++++ b/mt7915/mcu.c
+@@ -2014,8 +2014,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+ 	u8 *buf, interval;
+ 	int len;
+ 
+-	if (changed & BSS_CHANGED_FILS_DISCOVERY &&
+-	    vif->bss_conf.fils_discovery.max_interval) {
++	if (changed & BSS_CHANGED_FILS_DISCOVERY) {
+ 		interval = vif->bss_conf.fils_discovery.max_interval;
+ 		skb = ieee80211_get_fils_discovery_tmpl(hw, vif);
+ 	} else if (changed & BSS_CHANGED_UNSOL_BCAST_PROBE_RESP &&
+@@ -2051,7 +2050,7 @@ mt7915_mcu_beacon_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *vi
+ 	discov->tx_type = !!(changed & BSS_CHANGED_FILS_DISCOVERY);
+ 	discov->tx_interval = interval;
+ 	discov->prob_rsp_len = cpu_to_le16(MT_TXD_SIZE + skb->len);
+-	discov->enable = true;
++	discov->enable = !!(interval);
+ 
+ 	buf = (u8 *)tlv + sizeof(*discov);
+ 
+-- 
+2.29.2
+
diff --git a/recipes-kernel/linux-mt76/files/patches/1112-mt76-mt7915-add-L0.5-SER-for-mt7986.patch b/recipes-kernel/linux-mt76/files/patches/1112-mt76-mt7915-add-L0.5-SER-for-mt7986.patch
deleted file mode 100644
index 73b6c15..0000000
--- a/recipes-kernel/linux-mt76/files/patches/1112-mt76-mt7915-add-L0.5-SER-for-mt7986.patch
+++ /dev/null
@@ -1,930 +0,0 @@
-From 410b8c158d29137df0da4d8a1e82d494528e4fb1 Mon Sep 17 00:00:00 2001
-From: Bo Jiao <Bo.Jiao@mediatek.com>
-Date: Mon, 25 Apr 2022 10:19:29 +0800
-Subject: [PATCH] mt76: mt7915: add L0.5 SER for mt7986
-
-Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
----
- mt7915/debugfs.c | 168 +++++++++++++++++++++++++++++++++-
- mt7915/dma.c     |  49 ++++++++++
- mt7915/init.c    |   8 +-
- mt7915/mac.c     | 231 ++++++++++++++++++++++++++++++++++++++++++++++-
- mt7915/main.c    |  16 +++-
- mt7915/mcu.c     |  52 ++++++++---
- mt7915/mmio.c    |  12 ++-
- mt7915/mt7915.h  |  27 ++++++
- mt7915/regs.h    |  37 +++++++-
- 9 files changed, 572 insertions(+), 28 deletions(-)
-
-diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
-index e8e26ac1..003aacaa 100644
---- a/mt7915/debugfs.c
-+++ b/mt7915/debugfs.c
-@@ -47,7 +47,8 @@ mt7915_implicit_txbf_get(void *data, u64 *val)
- DEFINE_DEBUGFS_ATTRIBUTE(fops_implicit_txbf, mt7915_implicit_txbf_get,
- 			 mt7915_implicit_txbf_set, "%lld\n");
- 
--/* test knob of system layer 1/2 error recovery */
-+/* test knob of system layer 0.5/1/2 error recovery */
-+/*
- static int mt7915_ser_trigger_set(void *data, u64 val)
- {
- 	enum {
-@@ -74,9 +75,172 @@ static int mt7915_ser_trigger_set(void *data, u64 val)
- 	return ret;
- }
- 
-+*/
-+static int mt7915_ser_trigger_set(void *data, u64 val)
-+{
-+#define SER_SET		GENMASK(3, 0)
-+#define SER_BAND	GENMASK(7, 4)
-+#define SER_ACTION	GENMASK(11, 8)
-+	enum {
-+		SER_ACTION_SET = 1,
-+		SER_ACTION_SET_MASK = 2,
-+		SER_ACTION_TRIGGER = 3,
-+	};
-+
-+	struct mt7915_dev *dev = data;
-+	u8 ser_action, ser_band, ser_set, set_val;
-+
-+	ser_action = FIELD_GET(SER_ACTION, val);
-+	ser_set = set_val = FIELD_GET(SER_SET, val);
-+	ser_band = (ser_action == SER_ACTION_TRIGGER) ?
-+		   FIELD_GET(SER_BAND, val) : 0;
-+
-+	if (ser_band > 1)
-+		return -1;
-+
-+	switch (ser_action) {
-+	case SER_ACTION_SET:
-+		/*
-+		 * 0x100: disable system error recovery function.
-+		 * 0x101: enable system error recovery function.
-+		 */
-+		ser_set = !!set_val;
-+		break;
-+	case SER_ACTION_SET_MASK:
-+		/*
-+		 * 0x200: enable system error tracking.
-+		 * 0x201: enable system error L1 recover.
-+		 * 0x202: enable system error L2 recover.
-+		 * 0x203: enable system error L3 rx abort.
-+		 * 0x204: enable system error L3 tx abort.
-+		 * 0x205: enable system error L3 tx disable.
-+		 * 0x206: enable system error L3 bf recover.
-+		 * 0x207: enable system error all recover.
-+		 */
-+		ser_set = set_val > 7 ? 0x7f : BIT(set_val);
-+		break;
-+	case SER_ACTION_TRIGGER:
-+		/*
-+		 * 0x300: trigger L0 recover.
-+		 * 0x301/0x311: trigger L1 recover for band0/band1.
-+		 * 0x302/0x312: trigger L2 recover for band0/band1.
-+		 * 0x303/0x313: trigger L3 rx abort for band0/band1.
-+		 * 0x304/0x314: trigger L3 tx abort for band0/band1.
-+		 * 0x305/0x315: trigger L3 tx disable for band0/band1.
-+		 * 0x306/0x316: trigger L3 bf recover for band0/band1.
-+		 */
-+		if (0x300 == val || 0x310 == val) {
-+			mt7915_reset(dev, SER_TYPE_FULL_RESET);
-+			return 0;
-+		}
-+
-+		if (ser_set > 6)
-+			return -1;
-+		break;
-+	default:
-+		return -1;
-+	}
-+
-+	return mt7915_mcu_set_ser(dev, ser_action, ser_set, ser_band);
-+}
-+
- DEFINE_DEBUGFS_ATTRIBUTE(fops_ser_trigger, NULL,
- 			 mt7915_ser_trigger_set, "%lld\n");
- 
-+static int
-+mt7915_ser_stats_show(struct seq_file *s, void *data)
-+{
-+#define	SER_ACTION_QUERY	0
-+	struct mt7915_dev *dev = dev_get_drvdata(s->private);
-+	int ret = 0;
-+
-+	/* get more info from firmware */
-+	ret = mt7915_mcu_set_ser(dev, SER_ACTION_QUERY, 0, 0);
-+	msleep(100);
-+
-+	seq_printf(s, "::E  R , SER_STATUS        = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_SER_STATUS));
-+	seq_printf(s, "::E  R , SER_PLE_ERR       = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_PLE_STATUS));
-+	seq_printf(s, "::E  R , SER_PLE_ERR_1     = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_PLE1_STATUS));
-+	seq_printf(s, "::E  R , SER_PLE_ERR_AMSDU = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_PLE_AMSDU_STATUS));
-+	seq_printf(s, "::E  R , SER_PSE_ERR       = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_PSE_STATUS));
-+	seq_printf(s, "::E  R , SER_PSE_ERR_1     = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_PSE1_STATUS));
-+	seq_printf(s, "::E  R , SER_LMAC_WISR6_B0 = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN0_STATUS));
-+	seq_printf(s, "::E  R , SER_LMAC_WISR6_B1 = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_LAMC_WISR6_BN1_STATUS));
-+	seq_printf(s, "::E  R , SER_LMAC_WISR7_B0 = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN0_STATUS));
-+	seq_printf(s, "::E  R , SER_LMAC_WISR7_B1 = 0x%08X\n",
-+		   mt76_rr(dev, MT_SWDEF_LAMC_WISR7_BN1_STATUS));
-+
-+	seq_printf(s, "\nWF RESET STATUS: WM %d, WA %d, WO %d\n",
-+		   dev->ser.wf_reset_wm_count,
-+		   dev->ser.wf_reset_wa_count,
-+		   dev->ser.wf_reset_wo_count);
-+
-+	return ret;
-+}
-+
-+
-+int mt7915_fw_exception_chk(struct mt7915_dev *dev)
-+{
-+	u32 reg_val;
-+
-+	reg_val = mt76_rr(dev, MT_EXCEPTION_ADDR);
-+
-+	if (is_mt7915(&dev->mt76))
-+		reg_val >>= 8;
-+
-+	return !!(reg_val & 0xff);
-+}
-+
-+void mt7915_fw_heart_beat_chk(struct mt7915_dev *dev)
-+{
-+#define WM_TIMEOUT_COUNT_CHECK 5
-+#define WM_HANG_COUNT_CHECK 9
-+	u32 cnt, cidx, didx, queue;
-+	u32 idx, i;
-+	static struct {
-+		u32 cidx;
-+		u32 didx;
-+	} dma_rec[5];
-+
-+	if (dev->ser.hw_full_reset)
-+		return;
-+
-+	if (dev->ser.cmd_fail_cnt >= WM_TIMEOUT_COUNT_CHECK) {
-+
-+		cnt = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 4);
-+		cidx = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 8);
-+		didx = mt76_rr(dev, WF_WFDMA_MEM_DMA_RX_RING_CTL + 12);
-+		queue = (didx > cidx) ?
-+			(didx - cidx - 1) : (didx - cidx + cnt - 1);
-+
-+		idx = (dev->ser.cmd_fail_cnt - WM_TIMEOUT_COUNT_CHECK) % 5;
-+		dma_rec[idx].cidx = cidx;
-+		dma_rec[idx].cidx = didx;
-+
-+		if (((cnt - 1) == queue) &&
-+		    (dev->ser.cmd_fail_cnt >= WM_HANG_COUNT_CHECK)) {
-+
-+			for (i = 0; i < 5; i++) {
-+				if ((dma_rec[i].cidx != cidx) ||
-+				    (dma_rec[i].didx != didx))
-+					return;
-+			}
-+
-+			mt7915_reset(dev, SER_TYPE_FULL_RESET);
-+			dev->ser.cmd_fail_cnt = 0;
-+		}
-+	}
-+}
-+
- static int
- mt7915_radar_trigger(void *data, u64 val)
- {
-@@ -943,6 +1107,8 @@ int mt7915_init_debugfs(struct mt7915_phy *phy)
- 	debugfs_create_file("xmit-queues", 0400, dir, phy,
- 			    &mt7915_xmit_queues_fops);
- 	debugfs_create_file("tx_stats", 0400, dir, phy, &mt7915_tx_stats_fops);
-+	debugfs_create_devm_seqfile(dev->mt76.dev, "ser_show", dir,
-+				    mt7915_ser_stats_show);
- 	debugfs_create_file("fw_debug_wm", 0600, dir, dev, &fops_fw_debug_wm);
- 	debugfs_create_file("fw_debug_wa", 0600, dir, dev, &fops_fw_debug_wa);
- 	debugfs_create_file("fw_debug_bin", 0600, dir, dev, &fops_fw_debug_bin);
-diff --git a/mt7915/dma.c b/mt7915/dma.c
-index c2d655cd..219b440f 100644
---- a/mt7915/dma.c
-+++ b/mt7915/dma.c
-@@ -486,6 +486,55 @@ int mt7915_dma_init(struct mt7915_dev *dev, struct mt7915_phy *phy2)
- 	return 0;
- }
- 
-+
-+int mt7915_dma_reset(struct mt7915_dev *dev, bool force)
-+{
-+	struct mt76_phy *mphy_ext = dev->mt76.phy2;
-+	int i;
-+
-+	/* clean up hw queues */
-+	for (i = 0; i < ARRAY_SIZE(dev->mt76.phy.q_tx); i++) {
-+		mt76_queue_tx_cleanup(dev, dev->mphy.q_tx[i], true);
-+		if (mphy_ext)
-+			mt76_queue_tx_cleanup(dev, mphy_ext->q_tx[i], true);
-+	}
-+
-+	for (i = 0; i < ARRAY_SIZE(dev->mt76.q_mcu); i++)
-+		mt76_queue_tx_cleanup(dev, dev->mt76.q_mcu[i], true);
-+
-+	for (i = 0; i < __MT_RXQ_MAX; i++)
-+		mt76_queue_rx_cleanup(dev, &dev->mt76.q_rx[i]);
-+
-+	/* reset wfsys */
-+	if (force)
-+		mt7915_wfsys_reset(dev);
-+
-+	/* disable wfdma */
-+	mt7915_dma_disable(dev, force);
-+
-+	/* reset hw queues */
-+	for (i = 0; i < __MT_TXQ_MAX; i++) {
-+		mt76_queue_reset(dev, dev->mphy.q_tx[i]);
-+		if (mphy_ext)
-+			mt76_queue_reset(dev, mphy_ext->q_tx[i]);
-+	}
-+
-+	for (i = 0; i < __MT_MCUQ_MAX; i++)
-+		mt76_queue_reset(dev, dev->mt76.q_mcu[i]);
-+
-+	for (i = 0; i < __MT_RXQ_MAX; i++)
-+		mt76_queue_reset(dev, &dev->mt76.q_rx[i]);
-+
-+	mt76_tx_status_check(&dev->mt76, true);
-+
-+	mt7915_dma_enable(dev);
-+
-+	for (i = 0; i < __MT_RXQ_MAX; i++)
-+		mt76_queue_rx_reset(dev, i);
-+
-+	return 0;
-+}
-+
- void mt7915_dma_cleanup(struct mt7915_dev *dev)
- {
- 	mt7915_dma_disable(dev, true);
-diff --git a/mt7915/init.c b/mt7915/init.c
-index 79dae0fc..25a9b5de 100644
---- a/mt7915/init.c
-+++ b/mt7915/init.c
-@@ -262,7 +262,7 @@ static void mt7915_led_set_brightness(struct led_classdev *led_cdev,
- 		mt7915_led_set_config(led_cdev, 0xff, 0);
- }
- 
--static void
-+void
- mt7915_init_txpower(struct mt7915_dev *dev,
- 		    struct ieee80211_supported_band *sband)
- {
-@@ -446,7 +446,7 @@ mt7915_mac_init_band(struct mt7915_dev *dev, u8 band)
- 	mt76_clear(dev, MT_DMA_DCR0(band), MT_DMA_DCR0_RXD_G5_EN);
- }
- 
--static void mt7915_mac_init(struct mt7915_dev *dev)
-+void mt7915_mac_init(struct mt7915_dev *dev)
- {
- 	int i;
- 	u32 rx_len = is_mt7915(&dev->mt76) ? 0x400 : 0x680;
-@@ -476,7 +476,7 @@ static void mt7915_mac_init(struct mt7915_dev *dev)
- 	}
- }
- 
--static int mt7915_txbf_init(struct mt7915_dev *dev)
-+int mt7915_txbf_init(struct mt7915_dev *dev)
- {
- 	int ret;
- 
-@@ -1157,6 +1157,8 @@ int mt7915_register_device(struct mt7915_dev *dev)
- 
- 	mt7915_init_debugfs(&dev->phy);
- 
-+	dev->ser.hw_init_done = true;
-+
- 	return 0;
- 
- unreg_thermal:
-diff --git a/mt7915/mac.c b/mt7915/mac.c
-index b899697c..e301fe52 100644
---- a/mt7915/mac.c
-+++ b/mt7915/mac.c
-@@ -3,6 +3,7 @@
- 
- #include <linux/etherdevice.h>
- #include <linux/timekeeping.h>
-+#include <linux/pci.h>
- #include "mt7915.h"
- #include "../dma.h"
- #include "mac.h"
-@@ -2064,9 +2065,9 @@ mt7915_update_beacons(struct mt7915_dev *dev)
- 		IEEE80211_IFACE_ITER_RESUME_ALL,
- 		mt7915_update_vif_beacon, dev->mt76.phy2->hw);
- }
--
-+#if 0
- static void
--mt7915_dma_reset(struct mt7915_dev *dev)
-+mt7915_dma_reset(struct mt7915_dev *dev, bool force)
- {
- 	struct mt76_phy *mphy_ext = dev->mt76.phy2;
- 	u32 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
-@@ -2131,6 +2132,7 @@ mt7915_dma_reset(struct mt7915_dev *dev)
- 				 MT_WFDMA1_GLO_CFG_OMIT_RX_INFO);
- 	}
- }
-+#endif
- 
- void mt7915_tx_token_put(struct mt7915_dev *dev)
- {
-@@ -2146,6 +2148,172 @@ void mt7915_tx_token_put(struct mt7915_dev *dev)
- 	idr_destroy(&dev->mt76.token);
- }
- 
-+static int
-+mt7915_mac_reset(struct mt7915_dev *dev)
-+{
-+	struct mt7915_phy *phy2;
-+	struct mt76_phy *ext_phy;
-+	struct mt76_dev *mdev = &dev->mt76;
-+	int i, ret;
-+	u32 irq_mask;
-+
-+	ext_phy = dev->mt76.phy2;
-+	phy2 = ext_phy ? ext_phy->priv : NULL;
-+
-+	/* irq disable */
-+	mt76_wr(dev, MT_INT_MASK_CSR, 0x0);
-+	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
-+	if (dev->hif2) {
-+		mt76_wr(dev, MT_INT1_MASK_CSR, 0x0);
-+		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
-+	}
-+	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);
-+	}
-+
-+	set_bit(MT76_RESET, &dev->mphy.state);
-+	wake_up(&dev->mt76.mcu.wait);
-+	if (ext_phy)
-+		set_bit(MT76_RESET, &ext_phy->state);
-+
-+	/* lock/unlock all queues to ensure that no tx is pending */
-+	mt76_txq_schedule_all(&dev->mphy);
-+	if (ext_phy)
-+		mt76_txq_schedule_all(ext_phy);
-+
-+	/* disable all tx/rx napi */
-+	mt76_worker_disable(&dev->mt76.tx_worker);
-+	mt76_for_each_q_rx(mdev, i) {
-+		if (mdev->q_rx[i].ndesc)
-+			napi_disable(&dev->mt76.napi[i]);
-+	}
-+	napi_disable(&dev->mt76.tx_napi);
-+
-+	/* token reinit */
-+	mt7915_tx_token_put(dev);
-+	idr_init(&dev->mt76.token);
-+
-+	mt7915_dma_reset(dev, true);
-+	mt76_for_each_q_rx(mdev, i) {
-+		if (mdev->q_rx[i].ndesc) {
-+			napi_enable(&dev->mt76.napi[i]);
-+			napi_schedule(&dev->mt76.napi[i]);
-+		}
-+	}
-+	clear_bit(MT76_MCU_RESET, &dev->mphy.state);
-+	clear_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state);
-+
-+	mt76_wr(dev, MT_INT_MASK_CSR, dev->mt76.mmio.irqmask);
-+	mt76_wr(dev, MT_INT_SOURCE_CSR, ~0);
-+	if (dev->hif2) {
-+		mt76_wr(dev, MT_INT1_MASK_CSR, irq_mask);
-+		mt76_wr(dev, MT_INT1_SOURCE_CSR, ~0);
-+	}
-+	if (dev_is_pci(mdev->dev)) {
-+		mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
-+		if (dev->hif2)
-+			mt76_wr(dev, MT_PCIE1_MAC_INT_ENABLE, 0xff);
-+	}
-+
-+	/* load firmware */
-+	ret = mt7915_run_firmware(dev);
-+	if (ret)
-+		goto out;
-+
-+	/* set the necessary init items */
-+	ret = mt7915_mcu_set_eeprom(dev, dev->flash_mode);
-+	if (ret)
-+		goto out;
-+
-+	mt7915_mac_init(dev);
-+	mt7915_init_txpower(dev, &dev->mphy.sband_2g.sband);
-+	mt7915_init_txpower(dev, &dev->mphy.sband_5g.sband);
-+	ret = mt7915_txbf_init(dev);
-+
-+out:
-+	/* reset done */
-+	clear_bit(MT76_RESET, &dev->mphy.state);
-+	if (phy2)
-+		clear_bit(MT76_RESET, &phy2->mt76->state);
-+
-+	napi_enable(&dev->mt76.tx_napi);
-+	napi_schedule(&dev->mt76.tx_napi);
-+	mt76_worker_enable(&dev->mt76.tx_worker);
-+
-+	return ret;
-+}
-+
-+static void
-+mt7915_mac_full_reset(struct mt7915_dev *dev)
-+{
-+	struct mt7915_phy *phy2;
-+	struct mt76_phy *ext_phy;
-+	int i;
-+	struct cfg80211_scan_info info = {
-+		.aborted = true,
-+	};
-+
-+	ext_phy = dev->mt76.phy2;
-+	phy2 = ext_phy ? ext_phy->priv : NULL;
-+
-+	dev->ser.hw_full_reset = true;
-+	if (READ_ONCE(dev->reset_state) & MT_MCU_CMD_WA_WDT)
-+		dev->ser.wf_reset_wa_count++;
-+	else
-+		dev->ser.wf_reset_wm_count++;
-+
-+	wake_up(&dev->mt76.mcu.wait);
-+	ieee80211_stop_queues(mt76_hw(dev));
-+	if (ext_phy)
-+		ieee80211_stop_queues(ext_phy->hw);
-+
-+	cancel_delayed_work_sync(&dev->mphy.mac_work);
-+	if (ext_phy)
-+		cancel_delayed_work_sync(&ext_phy->mac_work);
-+
-+	mutex_lock(&dev->mt76.mutex);
-+	for (i = 0; i < 10; i++) {
-+		if (!mt7915_mac_reset(dev))
-+			break;
-+	}
-+	mutex_unlock(&dev->mt76.mutex);
-+
-+	if (i == 10)
-+		dev_err(dev->mt76.dev, "chip full reset failed\n");
-+
-+	if (test_and_clear_bit(MT76_HW_SCANNING, &dev->mphy.state))
-+		ieee80211_scan_completed(dev->mphy.hw, &info);
-+
-+	if (test_and_clear_bit(MT76_HW_SCANNING, &ext_phy->state))
-+		ieee80211_scan_completed(ext_phy->hw, &info);
-+
-+	ieee80211_wake_queues(mt76_hw(dev));
-+	if (ext_phy)
-+		ieee80211_wake_queues(ext_phy->hw);
-+
-+	if (test_bit(MT76_STATE_RUNNING, &dev->mphy.state))
-+		__mt7915_start(dev->mphy.hw);
-+
-+	if (ext_phy &&
-+	    test_bit(MT76_STATE_RUNNING, &ext_phy->state))
-+		__mt7915_start(ext_phy->hw);
-+
-+	dev->ser.hw_full_reset = false;
-+
-+	ieee80211_restart_hw(mt76_hw(dev));
-+	if (ext_phy)
-+		ieee80211_restart_hw(ext_phy->hw);
-+
-+	ieee80211_queue_delayed_work(mt76_hw(dev), &dev->mphy.mac_work,
-+				     MT7915_WATCHDOG_TIME);
-+	if (ext_phy)
-+		ieee80211_queue_delayed_work(ext_phy->hw,
-+					     &ext_phy->mac_work,
-+					     MT7915_WATCHDOG_TIME);
-+}
-+
- /* system error recovery */
- void mt7915_mac_reset_work(struct work_struct *work)
- {
-@@ -2157,6 +2325,25 @@ void mt7915_mac_reset_work(struct work_struct *work)
- 	ext_phy = dev->mt76.phy2;
- 	phy2 = ext_phy ? ext_phy->priv : NULL;
- 
-+	/* chip full reset */
-+	if (dev->ser.reset_type == SER_TYPE_FULL_RESET) {
-+		u32 val;
-+
-+		/* disable wa/wm watchdog interuppt */
-+		val = mt76_rr(dev, MT_WFDMA0_MCU_HOST_INT_ENA);
-+		val &= ~(MT_MCU_CMD_WA_WDT | MT_MCU_CMD_WM_WDT);
-+		mt76_set(dev, MT_WFDMA0_MCU_HOST_INT_ENA, val);
-+
-+		mt7915_mac_full_reset(dev);
-+
-+		/* enable the mcu irq*/
-+		mt7915_irq_enable(dev, MT_INT_MCU_CMD);
-+		mt7915_irq_disable(dev, 0);
-+		return;
-+	}
-+
-+	/* chip partial reset */
-+	dev->ser.reset_type = SER_TYPE_NONE;
- 	if (!(READ_ONCE(dev->reset_state) & MT_MCU_CMD_STOP_DMA))
- 		return;
- 
-@@ -2183,7 +2370,7 @@ void mt7915_mac_reset_work(struct work_struct *work)
- 	mt76_wr(dev, MT_MCU_INT_EVENT, MT_MCU_INT_EVENT_DMA_STOPPED);
- 
- 	if (mt7915_wait_reset_state(dev, MT_MCU_CMD_RESET_DONE)) {
--		mt7915_dma_reset(dev);
-+		mt7915_dma_reset(dev, false);
- 
- 		mt7915_tx_token_put(dev);
- 		idr_init(&dev->mt76.token);
-@@ -2234,6 +2421,44 @@ void mt7915_mac_reset_work(struct work_struct *work)
- 					     MT7915_WATCHDOG_TIME);
- }
- 
-+
-+void mt7915_reset(struct mt7915_dev *dev, u8 type)
-+{
-+	struct mt76_phy *ext_phy = dev->mt76.phy2;
-+
-+	if (!dev->ser.hw_init_done)
-+		return;
-+
-+	if (dev->ser.hw_full_reset)
-+		return;
-+
-+	dev_err(dev->mt76.dev, "SER: reset_state(0x%08X) type(0x%08X)\n",
-+		READ_ONCE(dev->reset_state), type);
-+
-+	/* WM/WA exception: do full recovery */
-+	if ((READ_ONCE(dev->reset_state) & MT_MCU_CMD_WDT_MASK) ||
-+	    type == SER_TYPE_FULL_RESET) {
-+
-+		if (!is_mt7986(&dev->mt76))
-+			return;
-+
-+		dev->ser.reset_type = SER_TYPE_FULL_RESET;
-+		set_bit(MT76_MCU_RESET, &dev->mphy.state);
-+		if (ext_phy)
-+			set_bit(MT76_MCU_RESET, &ext_phy->state);
-+
-+		ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
-+		return;
-+	}
-+
-+	/* do partial recovery */
-+	mt7915_irq_enable(dev, MT_INT_MCU_CMD);
-+	mt7915_irq_disable(dev, 0);
-+	dev->ser.reset_type = SER_TYPE_PARTIAL_RESET;
-+	ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
-+	wake_up(&dev->reset_wait);
-+}
-+
- void mt7915_mac_update_stats(struct mt7915_phy *phy)
- {
- 	struct mt7915_dev *dev = phy->dev;
-diff --git a/mt7915/main.c b/mt7915/main.c
-index 5b0a6d02..9cc60e85 100644
---- a/mt7915/main.c
-+++ b/mt7915/main.c
-@@ -20,7 +20,7 @@ static bool mt7915_dev_running(struct mt7915_dev *dev)
- 	return phy && test_bit(MT76_STATE_RUNNING, &phy->mt76->state);
- }
- 
--static int mt7915_start(struct ieee80211_hw *hw)
-+int __mt7915_start(struct ieee80211_hw *hw)
- {
- 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
- 	struct mt7915_phy *phy = mt7915_hw_phy(hw);
-@@ -29,8 +29,6 @@ static int mt7915_start(struct ieee80211_hw *hw)
- 
- 	flush_work(&dev->init_work);
- 
--	mutex_lock(&dev->mt76.mutex);
--
- 	running = mt7915_dev_running(dev);
- 
- 	if (!running) {
-@@ -85,6 +83,18 @@ out:
- 	return ret;
- }
- 
-+static int mt7915_start(struct ieee80211_hw *hw)
-+{
-+	struct mt7915_dev *dev = mt7915_hw_dev(hw);
-+	int ret;
-+
-+	mutex_lock(&dev->mt76.mutex);
-+	ret = __mt7915_start(hw);
-+	mutex_unlock(&dev->mt76.mutex);
-+
-+	return ret;
-+}
-+
- static void mt7915_stop(struct ieee80211_hw *hw)
- {
- 	struct mt7915_dev *dev = mt7915_hw_dev(hw);
-diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 681ede23..2128e4ca 100755
---- a/mt7915/mcu.c
-+++ b/mt7915/mcu.c
-@@ -212,14 +212,31 @@ mt7915_mcu_parse_response(struct mt76_dev *mdev, int cmd,
- 			  struct sk_buff *skb, int seq)
- {
- 	struct mt7915_mcu_rxd *rxd;
-+	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
- 	int ret = 0;
- 
- 	if (!skb) {
- 		dev_err(mdev->dev, "Message %08x (seq %d) timeout\n",
- 			cmd, seq);
-+
-+		dev->ser.cmd_fail_cnt++;
-+
-+		if (dev->ser.cmd_fail_cnt < 5) {
-+			int exp_type = mt7915_fw_exception_chk(dev);
-+
-+			dev_err(mdev->dev, "Fw is status(%d)\n", exp_type);
-+			if (exp_type) {
-+				dev->ser.reset_type = SER_TYPE_FULL_RESET;
-+				mt7915_reset(dev, SER_TYPE_FULL_RESET);
-+			}
-+		}
-+		mt7915_fw_heart_beat_chk(dev);
-+
- 		return -ETIMEDOUT;
- 	}
- 
-+	dev->ser.cmd_fail_cnt = 0;
-+
- 	rxd = (struct mt7915_mcu_rxd *)skb->data;
- 	if (seq != rxd->seq)
- 		return -EAGAIN;
-@@ -243,11 +260,17 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
- {
- 	struct mt7915_dev *dev = container_of(mdev, struct mt7915_dev, mt76);
- 	struct mt7915_mcu_txd *mcu_txd;
-+	//struct mt76_phy *ext_phy = mdev->phy2;
- 	enum mt76_mcuq_id qid;
- 	__le32 *txd;
- 	u32 val;
- 	u8 seq;
- 
-+	if (test_bit(MT76_MCU_RESET, &mdev->phy.state)) {
-+		dev_err(mdev->dev, "%s assert\n", __func__);
-+		return -EBUSY;
-+	}
-+
- 	/* TODO: make dynamic based on msg type */
- 	mdev->mcu.timeout = 20 * HZ;
- 
-@@ -2472,25 +2495,14 @@ mt7915_mcu_init_rx_airtime(struct mt7915_dev *dev)
- 				 sizeof(req), true);
- }
- 
--int mt7915_mcu_init(struct mt7915_dev *dev)
-+int mt7915_run_firmware(struct mt7915_dev *dev)
- {
--	static const struct mt76_mcu_ops mt7915_mcu_ops = {
--		.headroom = sizeof(struct mt7915_mcu_txd),
--		.mcu_skb_send_msg = mt7915_mcu_send_message,
--		.mcu_parse_response = mt7915_mcu_parse_response,
--		.mcu_restart = mt76_connac_mcu_restart,
--	};
- 	int ret;
- 
--	dev->mt76.mcu_ops = &mt7915_mcu_ops;
--
- 	/* force firmware operation mode into normal state,
- 	 * which should be set before firmware download stage.
- 	 */
--	if (is_mt7915(&dev->mt76))
--		mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
--	else
--		mt76_wr(dev, MT_SWDEF_MODE_MT7916, MT_SWDEF_NORMAL_MODE);
-+	mt76_wr(dev, MT_SWDEF_MODE, MT_SWDEF_NORMAL_MODE);
- 
- 	ret = mt7915_driver_own(dev, 0);
- 	if (ret)
-@@ -2535,6 +2547,20 @@ int mt7915_mcu_init(struct mt7915_dev *dev)
- 				 MCU_WA_PARAM_RED, 0, 0);
- }
- 
-+int mt7915_mcu_init(struct mt7915_dev *dev)
-+{
-+	static const struct mt76_mcu_ops mt7915_mcu_ops = {
-+		.headroom = sizeof(struct mt7915_mcu_txd),
-+		.mcu_skb_send_msg = mt7915_mcu_send_message,
-+		.mcu_parse_response = mt7915_mcu_parse_response,
-+		.mcu_restart = mt76_connac_mcu_restart,
-+	};
-+
-+	dev->mt76.mcu_ops = &mt7915_mcu_ops;
-+
-+	return mt7915_run_firmware(dev);
-+}
-+
- void mt7915_mcu_exit(struct mt7915_dev *dev)
- {
- 	__mt76_mcu_restart(&dev->mt76);
-diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index 0bd32daa..f07b0565 100644
---- a/mt7915/mmio.c
-+++ b/mt7915/mmio.c
-@@ -22,6 +22,8 @@ static const u32 mt7915_reg[] = {
- 	[WFDMA_EXT_CSR_ADDR]	= 0xd7000,
- 	[CBTOP1_PHY_END]	= 0x77ffffff,
- 	[INFRA_MCU_ADDR_END]	= 0x7c3fffff,
-+	[EXCEPTION_BASE_ADDR]	= 0x219848,
-+	[SWDEF_BASE_ADDR]	= 0x41f200,
- };
- 
- static const u32 mt7916_reg[] = {
-@@ -36,6 +38,8 @@ static const u32 mt7916_reg[] = {
- 	[WFDMA_EXT_CSR_ADDR]	= 0xd7000,
- 	[CBTOP1_PHY_END]	= 0x7fffffff,
- 	[INFRA_MCU_ADDR_END]	= 0x7c085fff,
-+	[EXCEPTION_BASE_ADDR]	= 0x022050BC,
-+	[SWDEF_BASE_ADDR]	= 0x411400,
- };
- 
- static const u32 mt7986_reg[] = {
-@@ -50,6 +54,8 @@ static const u32 mt7986_reg[] = {
- 	[WFDMA_EXT_CSR_ADDR]	= 0x27000,
- 	[CBTOP1_PHY_END]	= 0x7fffffff,
- 	[INFRA_MCU_ADDR_END]	= 0x7c085fff,
-+	[EXCEPTION_BASE_ADDR]	= 0x02204FFC,
-+	[SWDEF_BASE_ADDR]	= 0x411400,
- };
- 
- static const u32 mt7915_offs[] = {
-@@ -607,10 +613,10 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
- 		u32 val = mt76_rr(dev, MT_MCU_CMD);
- 
- 		mt76_wr(dev, MT_MCU_CMD, val);
--		if (val & MT_MCU_CMD_ERROR_MASK) {
-+		mt7915_irq_disable(dev, MT_INT_MCU_CMD);
-+		if (val & MT_MCU_CMD_ALL_ERROR_MASK) {
- 			dev->reset_state = val;
--			ieee80211_queue_work(mt76_hw(dev), &dev->reset_work);
--			wake_up(&dev->reset_wait);
-+			mt7915_reset(dev, SER_TYPE_UNKNOWN);
- 		}
- 	}
- }
-diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 24276da5..abd8d8c3 100644
---- a/mt7915/mt7915.h
-+++ b/mt7915/mt7915.h
-@@ -343,6 +343,15 @@ struct mt7915_dev {
- 	struct work_struct reset_work;
- 	wait_queue_head_t reset_wait;
- 	u32 reset_state;
-+	struct {
-+		bool hw_full_reset:1;
-+		bool hw_init_done:1;
-+		u32 reset_type;
-+		u32 cmd_fail_cnt;
-+		u32 wf_reset_wm_count;
-+		u32 wf_reset_wa_count;
-+		u32 wf_reset_wo_count;
-+	}ser;
- 
- 	struct list_head sta_rc_list;
- 	struct list_head sta_poll_list;
-@@ -439,6 +448,13 @@ enum mt7915_rdd_cmd {
- 	RDD_IRQ_OFF,
- };
- 
-+enum {
-+	SER_TYPE_NONE,
-+	SER_TYPE_PARTIAL_RESET,
-+	SER_TYPE_FULL_RESET,
-+	SER_TYPE_UNKNOWN,
-+};
-+
- static inline struct mt7915_phy *
- mt7915_hw_phy(struct ieee80211_hw *hw)
- {
-@@ -658,6 +674,17 @@ int mt7915_mcu_muru_debug_get(struct mt7915_phy *phy, void *ms);
- int mt7915_init_debugfs(struct mt7915_phy *phy);
- void mt7915_debugfs_rx_fw_monitor(struct mt7915_dev *dev, const void *data, int len);
- bool mt7915_debugfs_rx_log(struct mt7915_dev *dev, const void *data, int len);
-+int mt7915_fw_exception_chk(struct mt7915_dev *dev);
-+void mt7915_fw_heart_beat_chk(struct mt7915_dev *dev);
-+void mt7915_wfsys_reset(struct mt7915_dev *dev);
-+void mt7915_reset(struct mt7915_dev *dev, u8 type);
-+int mt7915_dma_reset(struct mt7915_dev *dev, bool force);
-+int __mt7915_start(struct ieee80211_hw *hw);
-+void mt7915_init_txpower(struct mt7915_dev *dev,
-+		    struct ieee80211_supported_band *sband);
-+int mt7915_txbf_init(struct mt7915_dev *dev);
-+void mt7915_mac_init(struct mt7915_dev *dev);
-+int mt7915_run_firmware(struct mt7915_dev *dev);
- #ifdef CONFIG_MAC80211_DEBUGFS
- void mt7915_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- 			    struct ieee80211_sta *sta, struct dentry *dir);
-diff --git a/mt7915/regs.h b/mt7915/regs.h
-index 97984aaf..a2697e92 100644
---- a/mt7915/regs.h
-+++ b/mt7915/regs.h
-@@ -30,6 +30,8 @@ enum reg_rev {
- 	WFDMA_EXT_CSR_ADDR,
- 	CBTOP1_PHY_END,
- 	INFRA_MCU_ADDR_END,
-+	EXCEPTION_BASE_ADDR,
-+	SWDEF_BASE_ADDR,
- 	__MT_REG_MAX,
- };
- 
-@@ -111,6 +113,11 @@ enum offs_rev {
- #define __REG(id)			(dev->reg.reg_rev[(id)])
- #define __OFFS(id)			(dev->reg.offs_rev[(id)])
- 
-+/* MEM WFDMA */
-+#define WF_WFDMA_MEM_DMA		0x58000000
-+
-+#define WF_WFDMA_MEM_DMA_RX_RING_CTL	(WF_WFDMA_MEM_DMA + (0x510))
-+
- /* MCU WFDMA0 */
- #define MT_MCU_WFDMA0_BASE		0x2000
- #define MT_MCU_WFDMA0(ofs)		(MT_MCU_WFDMA0_BASE + (ofs))
-@@ -555,6 +562,10 @@ enum offs_rev {
- #define MT_WFDMA0_PRI_DLY_INT_CFG1	MT_WFDMA0(0x2f4)
- #define MT_WFDMA0_PRI_DLY_INT_CFG2	MT_WFDMA0(0x2f8)
- 
-+#define MT_WFDMA0_MCU_HOST_INT_ENA	MT_WFDMA0(0x1f4)
-+#define MT_WFDMA0_MT_WA_WDT_INT		BIT(31)
-+#define MT_WFDMA0_MT_WM_WDT_INT		BIT(30)
-+
- /* WFDMA1 */
- #define MT_WFDMA1_BASE			0xd5000
- #define MT_WFDMA1(ofs)			(MT_WFDMA1_BASE + (ofs))
-@@ -700,6 +711,12 @@ enum offs_rev {
- #define MT_MCU_CMD_NORMAL_STATE		BIT(5)
- #define MT_MCU_CMD_ERROR_MASK		GENMASK(5, 1)
- 
-+#define MT_MCU_CMD_WA_WDT		BIT(31)
-+#define MT_MCU_CMD_WM_WDT		BIT(30)
-+#define MT_MCU_CMD_WDT_MASK		GENMASK(31, 30)
-+#define MT_MCU_CMD_ALL_ERROR_MASK	(MT_MCU_CMD_ERROR_MASK |	\
-+					 MT_MCU_CMD_WDT_MASK)
-+
- /* TOP RGU */
- #define MT_TOP_RGU_BASE			0x18000000
- #define MT_TOP_PWR_CTRL			(MT_TOP_RGU_BASE + (0x0))
-@@ -942,12 +959,25 @@ enum offs_rev {
- #define MT_ADIE_TYPE_MASK		BIT(1)
- 
- /* FW MODE SYNC */
--#define MT_SWDEF_MODE			0x41f23c
--#define MT_SWDEF_MODE_MT7916		0x41143c
-+#define MT_SWDEF_BASE			__REG(SWDEF_BASE_ADDR)
-+
-+#define MT_SWDEF(ofs)			(MT_SWDEF_BASE + (ofs))
-+#define MT_SWDEF_MODE			MT_SWDEF(0x3c)
- #define MT_SWDEF_NORMAL_MODE		0
- #define MT_SWDEF_ICAP_MODE		1
- #define MT_SWDEF_SPECTRUM_MODE		2
- 
-+#define MT_SWDEF_SER_STATUS		MT_SWDEF(0x040)
-+#define MT_SWDEF_PLE_STATUS		MT_SWDEF(0x044)
-+#define MT_SWDEF_PLE1_STATUS		MT_SWDEF(0x048)
-+#define MT_SWDEF_PLE_AMSDU_STATUS	MT_SWDEF(0x04C)
-+#define MT_SWDEF_PSE_STATUS		MT_SWDEF(0x050)
-+#define MT_SWDEF_PSE1_STATUS		MT_SWDEF(0x054)
-+#define MT_SWDEF_LAMC_WISR6_BN0_STATUS	MT_SWDEF(0x058)
-+#define MT_SWDEF_LAMC_WISR6_BN1_STATUS	MT_SWDEF(0x05C)
-+#define MT_SWDEF_LAMC_WISR7_BN0_STATUS	MT_SWDEF(0x060)
-+#define MT_SWDEF_LAMC_WISR7_BN1_STATUS	MT_SWDEF(0x064)
-+
- #define MT_DIC_CMD_REG_BASE		0x41f000
- #define MT_DIC_CMD_REG(ofs)		(MT_DIC_CMD_REG_BASE + (ofs))
- #define MT_DIC_CMD_REG_CMD		MT_DIC_CMD_REG(0x10)
-@@ -1029,6 +1059,9 @@ enum offs_rev {
- 
- #define MT_MCU_BUS_REMAP		MT_MCU_BUS(0x120)
- 
-+/* MISC */
-+#define MT_EXCEPTION_ADDR		__REG(EXCEPTION_BASE_ADDR)
-+
- /* TOP CFG */
- #define MT_TOP_CFG_BASE			0x184b0000
- #define MT_TOP_CFG(ofs)			(MT_TOP_CFG_BASE + (ofs))
--- 
-2.18.0
-
diff --git a/recipes-kernel/linux-mt76/files/patches/3001-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch b/recipes-kernel/linux-mt76/files/patches/1113-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
similarity index 69%
rename from recipes-kernel/linux-mt76/files/patches/3001-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
rename to recipes-kernel/linux-mt76/files/patches/1113-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
index 22ae63b..fb1188e 100644
--- a/recipes-kernel/linux-mt76/files/patches/3001-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
+++ b/recipes-kernel/linux-mt76/files/patches/1113-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch
@@ -1,17 +1,17 @@
-From 04ef8f969aa6a51dd6d9ccd2723513bed3a588a0 Mon Sep 17 00:00:00 2001
+From 9d57f49dd5ff756854029c484876325b43fc2b78 Mon Sep 17 00:00:00 2001
 From: Peter Chiu <chui-hao.chiu@mediatek.com>
 Date: Sun, 24 Apr 2022 10:07:00 +0800
-Subject: [PATCH] mt76: mt7915: init rssi in WTBL when add station
+Subject: [PATCH 1113/1116] mt76: mt7915: init rssi in WTBL when add station
 
 ---
  mt7915/main.c | 4 ++++
  1 file changed, 4 insertions(+)
 
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 09659dc7..3c6c66b8 100644
+index 5b0a6d02..f50dbbb5 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
-@@ -671,6 +671,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+@@ -651,6 +651,7 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
  	struct mt7915_phy *phy;
  #endif
  	int ret, idx;
@@ -19,7 +19,7 @@
  
  	idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT7915_WTBL_STA);
  	if (idx < 0)
-@@ -692,6 +693,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
+@@ -672,6 +673,9 @@ int mt7915_mac_sta_add(struct mt76_dev *mdev, struct ieee80211_vif *vif,
  	if (ret)
  		return ret;
  
diff --git a/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-drop-packets-when-TWT-stations-use-more-.patch b/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-drop-packets-when-TWT-stations-use-more-.patch
new file mode 100644
index 0000000..743f41b
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1114-mt76-mt7915-drop-packets-when-TWT-stations-use-more-.patch
@@ -0,0 +1,98 @@
+From c83d3e3692a758084e4d78fad127043d8789d263 Mon Sep 17 00:00:00 2001
+From: Peter Chiu <chui-hao.chiu@mediatek.com>
+Date: Mon, 9 May 2022 16:36:38 +0800
+Subject: [PATCH] mt76: mt7915: drop packets when TWT stations use more tokens
+ than 128
+
+---
+ mt7915/mac.c    | 21 ++++++++++++++++++---
+ mt7915/mt7915.h |  2 ++
+ 2 files changed, 20 insertions(+), 3 deletions(-)
+
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index c73e767b..588c0d58 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -1292,6 +1292,7 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
+ 	struct ieee80211_key_conf *key = info->control.hw_key;
+ 	struct ieee80211_vif *vif = info->control.vif;
++	struct mt7915_sta *msta = NULL;
+ 	struct mt76_txwi_cache *t;
+ 	struct mt7915_txp *txp;
+ 	int id, i, nbuf = tx_info->nbuf - 1;
+@@ -1305,8 +1306,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 		wcid = &dev->mt76.global_wcid;
+ 
+ 	if (sta) {
+-		struct mt7915_sta *msta;
+-
+ 		msta = (struct mt7915_sta *)sta->drv_priv;
+ 
+ 		if (time_after(jiffies, msta->jiffies + HZ / 4)) {
+@@ -1318,10 +1317,22 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+ 	t = (struct mt76_txwi_cache *)(txwi + mdev->drv->txwi_size);
+ 	t->skb = tx_info->skb;
+ 
++	spin_lock_bh(&mdev->token_lock);
++	if (msta && msta->twt.flowid_mask && msta->token_count > 128) {
++		spin_unlock_bh(&mdev->token_lock);
++		return -1;
++	}
++	spin_unlock_bh(&mdev->token_lock);
++
+ 	id = mt76_token_consume(mdev, &t);
+ 	if (id < 0)
+ 		return id;
+ 
++	spin_lock_bh(&mdev->token_lock);
++	if (msta)
++		msta->token_count++;
++	spin_unlock_bh(&mdev->token_lock);
++
+ 	pid = mt76_tx_status_skb_add(mdev, wcid, tx_info->skb);
+ 	mt7915_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, pid, key,
+ 			      false);
+@@ -1513,6 +1524,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 mt7915_sta *msta = NULL;
+ 	LIST_HEAD(free_list);
+ 	void *end = data + len;
+ 	bool v3, wake = false;
+@@ -1536,7 +1548,6 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
+ 		 * 1'b0: msdu_id with the same 'wcid pair' as above.
+ 		 */
+ 		if (info & MT_TX_FREE_PAIR) {
+-			struct mt7915_sta *msta;
+ 			struct mt76_wcid *wcid;
+ 			u16 idx;
+ 
+@@ -1569,6 +1580,10 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
+ 			txwi = mt76_token_release(mdev, msdu, &wake);
+ 			if (!txwi)
+ 				continue;
++			spin_lock(&mdev->token_lock);
++			if (msta)
++				msta->token_count--;
++			spin_unlock(&mdev->token_lock);
+ 
+ 			mt7915_txwi_free(dev, txwi, sta, &free_list);
+ 		}
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index cd54f087..b78b1a9a 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -136,6 +136,8 @@ struct mt7915_sta {
+ 		u8 flowid_mask;
+ 		struct mt7915_twt_flow flow[MT7915_MAX_STA_TWT_AGRT];
+ 	} twt;
++
++	int token_count;
+ };
+ 
+ struct mt7915_vif_cap {
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/1115-mt76-airtime-fairness-feature-off-in-mac80211.patch b/recipes-kernel/linux-mt76/files/patches/1115-mt76-airtime-fairness-feature-off-in-mac80211.patch
new file mode 100644
index 0000000..a11702f
--- /dev/null
+++ b/recipes-kernel/linux-mt76/files/patches/1115-mt76-airtime-fairness-feature-off-in-mac80211.patch
@@ -0,0 +1,24 @@
+From fcf24bbef66458b2c44feadcd6f75f9ee20360cf Mon Sep 17 00:00:00 2001
+From: Evelyn Tsai <evelyn.tsai@mediatek.com>
+Date: Fri, 6 May 2022 15:58:42 +0800
+Subject: [PATCH 1115/1116] mt76: airtime fairness feature off in mac80211
+
+---
+ mac80211.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/mac80211.c b/mac80211.c
+index 49b99f36..e17b04b1 100644
+--- a/mac80211.c
++++ b/mac80211.c
+@@ -419,7 +419,6 @@ mt76_phy_init(struct mt76_phy *phy, struct ieee80211_hw *hw)
+ 			WIPHY_FLAG_AP_UAPSD;
+ 
+ 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST);
+-	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS);
+ 	wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_AQL);
+ 
+ 	wiphy->available_antennas_tx = phy->antenna_mask;
+-- 
+2.18.0
+
diff --git a/recipes-kernel/linux-mt76/files/patches/3000-mt76-remove-WED-support-patch-for-build-err.patch b/recipes-kernel/linux-mt76/files/patches/3000-mt76-remove-WED-support-patch-for-build-err.patch
index dd1e092..26fd886 100644
--- a/recipes-kernel/linux-mt76/files/patches/3000-mt76-remove-WED-support-patch-for-build-err.patch
+++ b/recipes-kernel/linux-mt76/files/patches/3000-mt76-remove-WED-support-patch-for-build-err.patch
@@ -1,4 +1,4 @@
-From f00aa90bc4a1b77e1b0c884b24a71c1b49a94ee6 Mon Sep 17 00:00:00 2001
+From 1100bd66f9de10e2091d6640d8d9952d12891a42 Mon Sep 17 00:00:00 2001
 From: Sujuan Chen <sujuan.chen@mediatek.com>
 Date: Tue, 12 Apr 2022 15:58:28 +0800
 Subject: [PATCH] mt76:remove WED support patch for build err
@@ -232,10 +232,10 @@
  }
  EXPORT_SYMBOL_GPL(mt76_dma_cleanup);
 diff --git a/mac80211.c b/mac80211.c
-index 21eaf994..ceab8412 100644
+index e17b04b1..1b9a400b 100644
 --- a/mac80211.c
 +++ b/mac80211.c
-@@ -1596,7 +1596,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna);
+@@ -1594,7 +1594,7 @@ EXPORT_SYMBOL_GPL(mt76_get_antenna);
  
  struct mt76_queue *
  mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
@@ -244,7 +244,7 @@
  {
  	struct mt76_queue *hwq;
  	int err;
-@@ -1605,8 +1605,6 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
+@@ -1603,8 +1603,6 @@ mt76_init_queue(struct mt76_dev *dev, int qid, int idx, int n_desc,
  	if (!hwq)
  		return ERR_PTR(-ENOMEM);
  
@@ -442,7 +442,7 @@
  		return ret;
  
 diff --git a/mt7915/dma.c b/mt7915/dma.c
-index 219b440f..60b4368a 100644
+index 9e3d14db..4358e9bf 100644
 --- a/mt7915/dma.c
 +++ b/mt7915/dma.c
 @@ -8,16 +8,9 @@
@@ -527,10 +527,10 @@
  		return ret;
  
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index 8df38a23..8b0b90da 100644
+index 588c0d58..f3049639 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
-@@ -1379,29 +1379,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
+@@ -1380,29 +1380,6 @@ int mt7915_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
  	return 0;
  }
  
@@ -560,7 +560,7 @@
  static void
  mt7915_tx_check_aggr(struct ieee80211_sta *sta, __le32 *txwi)
  {
-@@ -1435,7 +1412,7 @@ mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
+@@ -1436,7 +1413,7 @@ mt7915_txp_skb_unmap(struct mt76_dev *dev, struct mt76_txwi_cache *t)
  
  	txp = mt7915_txwi_to_txp(dev, t);
  	for (i = 0; i < txp->nbuf; i++)
@@ -569,7 +569,7 @@
  				 le16_to_cpu(txp->len[i]), DMA_TO_DEVICE);
  }
  
-@@ -1444,7 +1421,6 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
+@@ -1445,7 +1422,6 @@ 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;
@@ -577,7 +577,7 @@
  	struct mt76_wcid *wcid;
  	__le32 *txwi;
  	u16 wcid_idx;
-@@ -1457,24 +1433,13 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
+@@ -1458,24 +1434,13 @@ mt7915_txwi_free(struct mt7915_dev *dev, struct mt76_txwi_cache *t,
  	if (sta) {
  		wcid = (struct mt76_wcid *)sta->drv_priv;
  		wcid_idx = wcid->idx;
@@ -605,7 +605,7 @@
  	__mt76_tx_complete_skb(mdev, wcid_idx, t->skb, free_list);
  
  out:
-@@ -1482,55 +1447,29 @@ out:
+@@ -1483,56 +1448,30 @@ out:
  	mt76_put_txwi(mdev, t);
  }
  
@@ -651,6 +651,7 @@
 +	struct mt76_phy *mphy_ext = mdev->phy2;
  	struct mt76_txwi_cache *txwi;
  	struct ieee80211_sta *sta = NULL;
+ 	struct mt7915_sta *msta = NULL;
  	LIST_HEAD(free_list);
 +	struct sk_buff *skb, *tmp;
  	void *end = data + len;
@@ -670,7 +671,7 @@
  
  	total = le16_get_bits(free->ctrl, MT_TX_FREE_MSDU_CNT);
  	v3 = (FIELD_GET(MT_TX_FREE_VER, txd) == 0x4);
-@@ -1587,38 +1526,17 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
+@@ -1589,38 +1528,17 @@ mt7915_mac_tx_free(struct mt7915_dev *dev, void *data, int len)
  		}
  	}
  
@@ -716,7 +717,7 @@
  }
  
  static bool
-@@ -1798,9 +1716,6 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
+@@ -1800,9 +1718,6 @@ bool mt7915_rx_check(struct mt76_dev *mdev, void *data, int len)
  	case PKT_TYPE_TXRX_NOTIFY:
  		mt7915_mac_tx_free(dev, data, len);
  		return false;
@@ -726,7 +727,7 @@
  	case PKT_TYPE_TXS:
  		for (rxd += 2; rxd + 8 <= end; rxd += 8)
  		    mt7915_mac_add_txs(dev, rxd);
-@@ -1828,10 +1743,6 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
+@@ -1830,10 +1745,6 @@ void mt7915_queue_rx_skb(struct mt76_dev *mdev, enum mt76_rxq_id q,
  		mt7915_mac_tx_free(dev, skb->data, skb->len);
  		napi_consume_skb(skb, 1);
  		break;
@@ -758,10 +759,10 @@
  #define MT_TX_FREE_LATENCY		GENMASK(12, 0)
  /* 0: success, others: dropped */
 diff --git a/mt7915/main.c b/mt7915/main.c
-index 23f89379..09659dc7 100644
+index 87f4c5ab..ffc2ed0d 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
-@@ -1414,39 +1414,6 @@ out:
+@@ -1405,39 +1405,6 @@ out:
  	return ret;
  }
  
@@ -801,7 +802,7 @@
  const struct ieee80211_ops mt7915_ops = {
  	.tx = mt7915_tx,
  	.start = mt7915_start,
-@@ -1494,7 +1461,4 @@ const struct ieee80211_ops mt7915_ops = {
+@@ -1485,7 +1452,4 @@ const struct ieee80211_ops mt7915_ops = {
  	.sta_add_debugfs = mt7915_sta_add_debugfs,
  #endif
  	.set_radar_background = mt7915_set_radar_background,
@@ -810,10 +811,10 @@
 -#endif
  };
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index 8d7e7422..afdbb5aa 100644
+index d547cf6f..562f3346 100755
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
-@@ -2527,9 +2527,6 @@ int mt7915_run_firmware(struct mt7915_dev *dev)
+@@ -2575,9 +2575,6 @@ int mt7915_run_firmware(struct mt7915_dev *dev)
  	if (ret)
  		return ret;
  
@@ -824,7 +825,7 @@
  	if (ret)
  		return ret;
 diff --git a/mt7915/mmio.c b/mt7915/mmio.c
-index f07b0565..561ac650 100644
+index b3de3a7a..3768c1a6 100644
 --- a/mt7915/mmio.c
 +++ b/mt7915/mmio.c
 @@ -555,21 +555,15 @@ static void mt7915_rx_poll_complete(struct mt76_dev *mdev,
@@ -855,7 +856,7 @@
  
  	if (dev->hif2) {
  		intr1 = mt76_rr(dev, MT_INT1_SOURCE_CSR);
-@@ -624,15 +618,10 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
+@@ -623,15 +617,10 @@ static void mt7915_irq_tasklet(struct tasklet_struct *t)
  irqreturn_t mt7915_irq_handler(int irq, void *dev_instance)
  {
  	struct mt7915_dev *dev = dev_instance;
@@ -875,7 +876,7 @@
  	if (!test_bit(MT76_STATE_INITIALIZED, &dev->mphy.state))
  		return IRQ_NONE;
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index b7838385..454232ba 100644
+index b78b1a9a..fca0bfcb 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -517,8 +517,6 @@ struct mt7915_dev *mt7915_mmio_probe(struct device *pdev,
@@ -1026,7 +1027,7 @@
  	mt76_free_device(&dev->mt76);
  
 diff --git a/mt7915/regs.h b/mt7915/regs.h
-index a3b9bf4c..27f682fe 100644
+index 99834310..02d097fa 100644
 --- a/mt7915/regs.h
 +++ b/mt7915/regs.h
 @@ -591,31 +591,18 @@ enum offs_rev {
@@ -1077,7 +1078,7 @@
  		return err;
  
 diff --git a/tx.c b/tx.c
-index 892f3618..2c26b955 100644
+index 0457c3eb..656b7090 100644
 --- a/tx.c
 +++ b/tx.c
 @@ -725,12 +725,6 @@ int mt76_token_consume(struct mt76_dev *dev, struct mt76_txwi_cache **ptxwi)
diff --git a/recipes-kernel/linux-mt76/files/patches/patches.inc b/recipes-kernel/linux-mt76/files/patches/patches.inc
index b331b64..da8acdd 100644
--- a/recipes-kernel/linux-mt76/files/patches/patches.inc
+++ b/recipes-kernel/linux-mt76/files/patches/patches.inc
@@ -7,12 +7,20 @@
     file://0007-mt76-mt7915-update-mt7986-CR-for-different-adie-vers.patch \
     file://0009-mt76-mt7915-fix-table_mask-to-u16.patch \
     file://0012-mt76-mt7915-reject-duplicated-twt-flow.patch \
+    file://0014-mt76-mt7915-limit-minimum-twt-duration-due-to-hw-lim.patch \
+    file://0015-mt76-mt7915-drop-undefined-action-frame.patch \
+    file://0016-mt76-mt7915-reowrk-SER-debugfs-knob.patch \
+    file://0017-mt76-mt7615-mt7915-do-reset_work-with-mt76-s-work-qu.patch \
+    file://0018-mt76-mt7915-add-support-for-6G-in-band-discovery.patch \
+    file://0019-mt76-mt7915-add-the-maximum-size-of-beacon-offload.patch \
     file://100-Revert-of-net-pass-the-dst-buffer-to-of_get_mac_addr.patch \
     file://1001-mt76-mt7915-add-mtk-internal-debug-tools-for-mt76.patch \
     file://1002-mt76-mt7915-csi-implement-csi-support.patch \
     file://1003-mt76-mt7915-air-monitor-support.patch \
     file://1004-mt76-mt7915-add-support-for-muru_onoff-via-debugfs.patch \
     file://1005-mt76-certification-patches.patch \
+    file://1007-mt76-mt7915-add-L0.5-system-error-recovery-support.patch \
+    file://1009-mt76-mt7915-add-support-for-runtime-set-in-band-disc.patch \
     file://1100-mt76-testmode-support-eeprom-handle.patch \
     file://1101-mt76-enable-more-5g-channels.patch \
     file://1102-mt76-testmode-add-attributes-for-setting-rf-config.patch \
@@ -25,7 +33,8 @@
     file://1109-mt76-testmode-add-support-to-queue-skb-of-multiple-s.patch \
     file://1110-mt76-mt7915-implement-aid-support-in-testmode.patch \
     file://1111-mt76-tool-add-more-commands.patch \
-    file://1112-mt76-mt7915-add-L0.5-SER-for-mt7986.patch \
+    file://1113-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch \
+    file://1114-mt76-mt7915-drop-packets-when-TWT-stations-use-more-.patch \
+    file://1115-mt76-airtime-fairness-feature-off-in-mac80211.patch \
     file://3000-mt76-remove-WED-support-patch-for-build-err.patch \
-    file://3001-mt76-mt7915-init-rssi-in-WTBL-when-add-station.patch \
     "