[][MAC80211][mt76][enhance coredump function]

[Description]
Add pc stack dump for current coredump,
enhance coredump to adapt parse tool.

[Release-log]
N/A

Change-Id: I2f7719ca00c24e38572290fcc3eca9dc46bfe340
Reviewed-on: https://gerrit.mediatek.inc/c/openwrt/feeds/mtk_openwrt_feeds/+/7528857
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/0007-wifi-mt76-mt7915-add-pc-stack-dump-for-WM-s-coredump.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/0007-wifi-mt76-mt7915-add-pc-stack-dump-for-WM-s-coredump.patch
new file mode 100644
index 0000000..b646d67
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/0007-wifi-mt76-mt7915-add-pc-stack-dump-for-WM-s-coredump.patch
@@ -0,0 +1,640 @@
+From a15a9b160d9bb9b52cb697251777c5c39f842f24 Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 22 May 2023 13:49:37 +0800
+Subject: [PATCH] wifi: mt76: mt7915: add pc stack dump for WM's coredump.
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt76.h            |  11 +++
+ mt76_connac_mcu.c |   9 +++
+ mt7915/coredump.c | 169 +++++++++++++++++++++++++++++++---------------
+ mt7915/coredump.h |  34 +++++++---
+ mt7915/mac.c      |  33 ++++++---
+ mt7915/mt7915.h   |   2 +-
+ mt7915/regs.h     |  20 ++++++
+ 7 files changed, 207 insertions(+), 71 deletions(-)
+
+diff --git a/mt76.h b/mt76.h
+index 3f13cec6..354acc09 100644
+--- a/mt76.h
++++ b/mt76.h
+@@ -27,6 +27,8 @@
+ 
+ #define MT76_TOKEN_FREE_THR	64
+ 
++#define MT76_BUILD_TIME_LEN	24
++
+ #define MT_QFLAG_WED_RING	GENMASK(1, 0)
+ #define MT_QFLAG_WED_TYPE	GENMASK(3, 2)
+ #define MT_QFLAG_WED		BIT(4)
+@@ -54,6 +56,12 @@ enum mt76_bus_type {
+ 	MT76_BUS_SDIO,
+ };
+ 
++enum mt76_ram_type {
++	MT76_RAM_TYPE_WM,
++	MT76_RAM_TYPE_WA,
++	__MT76_RAM_TYPE_MAX,
++};
++
+ enum mt76_wed_type {
+ 	MT76_WED_Q_TX,
+ 	MT76_WED_Q_TXFREE,
+@@ -776,6 +784,9 @@ struct mt76_dev {
+ 	struct device *dma_dev;
+ 
+ 	struct mt76_mcu mcu;
++	struct mt76_connac2_patch_hdr *patch_hdr;
++	struct mt76_connac2_fw_trailer *wm_hdr;
++	struct mt76_connac2_fw_trailer *wa_hdr;
+ 
+ 	struct net_device napi_dev;
+ 	struct net_device tx_napi_dev;
+diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
+index 46f69aa8..913bad95 100644
+--- a/mt76_connac_mcu.c
++++ b/mt76_connac_mcu.c
+@@ -3017,6 +3017,9 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
+ 		goto out;
+ 	}
+ 
++	dev->wm_hdr = devm_kzalloc(dev->dev, sizeof(*hdr), GFP_KERNEL);
++	memcpy(dev->wm_hdr, hdr, sizeof(*hdr));
++
+ 	snprintf(dev->hw->wiphy->fw_version,
+ 		 sizeof(dev->hw->wiphy->fw_version),
+ 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
+@@ -3046,6 +3049,9 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
+ 		goto out;
+ 	}
+ 
++	dev->wa_hdr = devm_kzalloc(dev->dev, sizeof(*hdr), GFP_KERNEL);
++	memcpy(dev->wa_hdr, hdr, sizeof(*hdr));
++
+ 	snprintf(dev->hw->wiphy->fw_version,
+ 		 sizeof(dev->hw->wiphy->fw_version),
+ 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
+@@ -3116,6 +3122,9 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
+ 	dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
+ 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
+ 
++	dev->patch_hdr = devm_kzalloc(dev->dev, sizeof(*hdr), GFP_KERNEL);
++	memcpy(dev->patch_hdr, hdr, sizeof(*hdr));
++
+ 	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
+ 		struct mt76_connac2_patch_sec *sec;
+ 		u32 len, addr, mode;
+diff --git a/mt7915/coredump.c b/mt7915/coredump.c
+index 5daf2258..298c1cad 100644
+--- a/mt7915/coredump.c
++++ b/mt7915/coredump.c
+@@ -7,7 +7,7 @@
+ #include <linux/utsname.h>
+ #include "coredump.h"
+ 
+-static bool coredump_memdump;
++static bool coredump_memdump = true;
+ module_param(coredump_memdump, bool, 0644);
+ MODULE_PARM_DESC(coredump_memdump, "Optional ability to dump firmware memory");
+ 
+@@ -86,8 +86,11 @@ static const struct mt7915_mem_region mt798x_mem_regions[] = {
+ };
+ 
+ const struct mt7915_mem_region*
+-mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num)
++mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u8 type, u32 *num)
+ {
++	if (type == MT76_RAM_TYPE_WA)
++		return NULL;
++
+ 	switch (mt76_chip(&dev->mt76)) {
+ 	case 0x7915:
+ 		*num = ARRAY_SIZE(mt7915_mem_regions);
+@@ -104,14 +107,14 @@ mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num)
+ 	}
+ }
+ 
+-static int mt7915_coredump_get_mem_size(struct mt7915_dev *dev)
++static int mt7915_coredump_get_mem_size(struct mt7915_dev *dev, u8 type)
+ {
+ 	const struct mt7915_mem_region *mem_region;
+ 	size_t size = 0;
+ 	u32 num;
+ 	int i;
+ 
+-	mem_region = mt7915_coredump_get_mem_layout(dev, &num);
++	mem_region = mt7915_coredump_get_mem_layout(dev, type, &num);
+ 	if (!mem_region)
+ 		return 0;
+ 
+@@ -128,9 +131,9 @@ static int mt7915_coredump_get_mem_size(struct mt7915_dev *dev)
+ 	return size;
+ }
+ 
+-struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev)
++struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev, u8 type)
+ {
+-	struct mt7915_crash_data *crash_data = dev->coredump.crash_data;
++	struct mt7915_crash_data *crash_data = dev->coredump.crash_data[type];
+ 
+ 	lockdep_assert_held(&dev->dump_mutex);
+ 
+@@ -141,12 +144,15 @@ struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev)
+ }
+ 
+ static void
+-mt7915_coredump_fw_state(struct mt7915_dev *dev, struct mt7915_coredump *dump,
++mt7915_coredump_fw_state(struct mt7915_dev *dev, u8 type, struct mt7915_coredump *dump,
+ 			 bool *exception)
+ {
+-	u32 state, count, type;
++	u32 state, count, category;
++
++	if (type == MT76_RAM_TYPE_WA)
++		return;
+ 
+-	type = (u32)mt76_get_field(dev, MT_FW_EXCEPT_TYPE, GENMASK(7, 0));
++	category = (u32)mt76_get_field(dev, MT_FW_EXCEPT_TYPE, GENMASK(7, 0));
+ 	state = (u32)mt76_get_field(dev, MT_FW_ASSERT_STAT, GENMASK(7, 0));
+ 	count = is_mt7915(&dev->mt76) ?
+ 		(u32)mt76_get_field(dev, MT_FW_EXCEPT_COUNT, GENMASK(15, 8)) :
+@@ -155,7 +161,7 @@ mt7915_coredump_fw_state(struct mt7915_dev *dev, struct mt7915_coredump *dump,
+ 	/* normal mode: driver can manually trigger assert for detail info */
+ 	if (!count)
+ 		strscpy(dump->fw_state, "normal", sizeof(dump->fw_state));
+-	else if (state > 1 && (count == 1) && type == 5)
++	else if (state > 1 && (count == 1) && category == 5)
+ 		strscpy(dump->fw_state, "assert", sizeof(dump->fw_state));
+ 	else if ((state > 1 && count == 1) || count > 1)
+ 		strscpy(dump->fw_state, "exception", sizeof(dump->fw_state));
+@@ -164,11 +170,14 @@ mt7915_coredump_fw_state(struct mt7915_dev *dev, struct mt7915_coredump *dump,
+ }
+ 
+ static void
+-mt7915_coredump_fw_trace(struct mt7915_dev *dev, struct mt7915_coredump *dump,
++mt7915_coredump_fw_trace(struct mt7915_dev *dev, u8 type, struct mt7915_coredump *dump,
+ 			 bool exception)
+ {
+ 	u32 n, irq, sch, base = MT_FW_EINT_INFO;
+ 
++	if (type == MT76_RAM_TYPE_WA)
++		return;
++
+ 	/* trap or run? */
+ 	dump->last_msg_id = mt76_rr(dev, MT_FW_LAST_MSG_ID);
+ 
+@@ -221,31 +230,61 @@ mt7915_coredump_fw_trace(struct mt7915_dev *dev, struct mt7915_coredump *dump,
+ }
+ 
+ static void
+-mt7915_coredump_fw_stack(struct mt7915_dev *dev, struct mt7915_coredump *dump,
++mt7915_coredump_fw_stack(struct mt7915_dev *dev, u8 type, struct mt7915_coredump *dump,
+ 			 bool exception)
+ {
+-	u32 oldest, i, idx;
++	u32 reg, i;
++
++	if (type == MT76_RAM_TYPE_WA)
++		return;
++
++	/* read current PC */
++	mt76_rmw_field(dev, MT_CONN_DBG_CTL_LOG_SEL,
++		       MT_CONN_DBG_CTL_PC_LOG_SEL, 0x22);
++	for (i = 0; i < 10; i++) {
++		dump->pc_cur[i] = mt76_rr(dev, MT_CONN_DBG_CTL_PC_LOG);
++		usleep_range(100, 500);
++	}
+ 
+ 	/* stop call stack record */
+-	if (!exception)
+-		mt76_clear(dev, 0x89050200, BIT(0));
++	if (!exception) {
++		mt76_clear(dev, MT_MCU_WM_EXCP_PC_CTRL, BIT(0));
++		mt76_clear(dev, MT_MCU_WM_EXCP_LR_CTRL, BIT(0));
++	}
+ 
+-	oldest = (u32)mt76_get_field(dev, 0x89050200, GENMASK(20, 16)) + 2;
+-	for (i = 0; i < 16; i++) {
+-		idx = ((oldest + 2 * i + 1) % 32);
+-		dump->call_stack[i] = mt76_rr(dev, 0x89050204 + idx * 4);
++	/* read PC log */
++	dump->pc_dbg_ctrl = mt76_rr(dev, MT_MCU_WM_EXCP_PC_CTRL);
++	dump->pc_cur_idx = FIELD_GET(MT_MCU_WM_EXCP_PC_CTRL_IDX_STATUS,
++				     dump->pc_dbg_ctrl);
++	for (i = 0; i < 32; i++) {
++		reg = MT_MCU_WM_EXCP_PC_LOG + i * 4;
++		dump->pc_stack[i] = mt76_rr(dev, reg);
++	}
++
++	/* read LR log */
++	dump->lr_dbg_ctrl = mt76_rr(dev, MT_MCU_WM_EXCP_LR_CTRL);
++	dump->lr_cur_idx = FIELD_GET(MT_MCU_WM_EXCP_LR_CTRL_IDX_STATUS,
++				     dump->lr_dbg_ctrl);
++	for (i = 0; i < 32; i++) {
++		reg = MT_MCU_WM_EXCP_LR_LOG + i * 4;
++		dump->lr_stack[i] = mt76_rr(dev, reg);
+ 	}
+ 
+ 	/* start call stack record */
+-	if (!exception)
+-		mt76_set(dev, 0x89050200, BIT(0));
++	if (!exception) {
++		mt76_set(dev, MT_MCU_WM_EXCP_PC_CTRL, BIT(0));
++		mt76_set(dev, MT_MCU_WM_EXCP_LR_CTRL, BIT(0));
++	}
+ }
+ 
+ static void
+-mt7915_coredump_fw_task(struct mt7915_dev *dev, struct mt7915_coredump *dump)
++mt7915_coredump_fw_task(struct mt7915_dev *dev, u8 type, struct mt7915_coredump *dump)
+ {
+ 	u32 offs = is_mt7915(&dev->mt76) ? 0xe0 : 0x170;
+ 
++	if (type == MT76_RAM_TYPE_WA)
++		return;
++
+ 	strscpy(dump->task_qid, "(task queue id) read, write",
+ 		sizeof(dump->task_qid));
+ 
+@@ -266,10 +305,13 @@ mt7915_coredump_fw_task(struct mt7915_dev *dev, struct mt7915_coredump *dump)
+ }
+ 
+ static void
+-mt7915_coredump_fw_context(struct mt7915_dev *dev, struct mt7915_coredump *dump)
++mt7915_coredump_fw_context(struct mt7915_dev *dev, u8 type, struct mt7915_coredump *dump)
+ {
+ 	u32 count, idx, id;
+ 
++	if (type == MT76_RAM_TYPE_WA)
++		return;
++
+ 	count = mt76_rr(dev, MT_FW_CIRQ_COUNT);
+ 
+ 	/* current context */
+@@ -299,9 +341,10 @@ mt7915_coredump_fw_context(struct mt7915_dev *dev, struct mt7915_coredump *dump)
+ 	}
+ }
+ 
+-static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev)
++static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev, u8 type)
+ {
+-	struct mt7915_crash_data *crash_data = dev->coredump.crash_data;
++	struct mt76_dev *mdev = &dev->mt76;
++	struct mt7915_crash_data *crash_data = dev->coredump.crash_data[type];
+ 	struct mt7915_coredump *dump;
+ 	struct mt7915_coredump_mem *dump_mem;
+ 	size_t len, sofar = 0, hdr_len = sizeof(*dump);
+@@ -326,23 +369,34 @@ static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev)
+ 
+ 	dump = (struct mt7915_coredump *)(buf);
+ 	dump->len = len;
++	dump->hdr_len = hdr_len;
+ 
+ 	/* plain text */
+ 	strscpy(dump->magic, "mt76-crash-dump", sizeof(dump->magic));
+ 	strscpy(dump->kernel, init_utsname()->release, sizeof(dump->kernel));
+-	strscpy(dump->fw_ver, dev->mt76.hw->wiphy->fw_version,
++	strscpy(dump->fw_ver, mdev->hw->wiphy->fw_version,
+ 		sizeof(dump->fw_ver));
++	strscpy(dump->fw_type, ((type == MT76_RAM_TYPE_WA) ? "WA" : "WM"),
++		sizeof(dump->fw_type));
++	strscpy(dump->fw_patch_date, mdev->patch_hdr->build_date,
++		sizeof(dump->fw_patch_date));
++	strscpy(dump->fw_ram_date[MT76_RAM_TYPE_WM],
++		mdev->wm_hdr->build_date,
++		sizeof(mdev->wm_hdr->build_date));
++	strscpy(dump->fw_ram_date[MT76_RAM_TYPE_WA],
++		mdev->wa_hdr->build_date,
++		sizeof(mdev->wa_hdr->build_date));
+ 
+ 	guid_copy(&dump->guid, &crash_data->guid);
+ 	dump->tv_sec = crash_data->timestamp.tv_sec;
+ 	dump->tv_nsec = crash_data->timestamp.tv_nsec;
+ 	dump->device_id = mt76_chip(&dev->mt76);
+ 
+-	mt7915_coredump_fw_state(dev, dump, &exception);
+-	mt7915_coredump_fw_trace(dev, dump, exception);
+-	mt7915_coredump_fw_task(dev, dump);
+-	mt7915_coredump_fw_context(dev, dump);
+-	mt7915_coredump_fw_stack(dev, dump, exception);
++	mt7915_coredump_fw_state(dev, type, dump, &exception);
++	mt7915_coredump_fw_trace(dev, type, dump, exception);
++	mt7915_coredump_fw_task(dev, type, dump);
++	mt7915_coredump_fw_context(dev, type, dump);
++	mt7915_coredump_fw_stack(dev, type, dump, exception);
+ 
+ 	/* gather memory content */
+ 	dump_mem = (struct mt7915_coredump_mem *)(buf + sofar);
+@@ -356,17 +410,19 @@ static struct mt7915_coredump *mt7915_coredump_build(struct mt7915_dev *dev)
+ 	return dump;
+ }
+ 
+-int mt7915_coredump_submit(struct mt7915_dev *dev)
++int mt7915_coredump_submit(struct mt7915_dev *dev, u8 type)
+ {
+ 	struct mt7915_coredump *dump;
+ 
+-	dump = mt7915_coredump_build(dev);
++	dump = mt7915_coredump_build(dev, type);
+ 	if (!dump) {
+ 		dev_warn(dev->mt76.dev, "no crash dump data found\n");
+ 		return -ENODATA;
+ 	}
+ 
+ 	dev_coredumpv(dev->mt76.dev, dump, dump->len, GFP_KERNEL);
++	dev_info(dev->mt76.dev, "%s coredump completed\n",
++		 wiphy_name(dev->mt76.hw->wiphy));
+ 
+ 	return 0;
+ }
+@@ -374,23 +430,26 @@ int mt7915_coredump_submit(struct mt7915_dev *dev)
+ int mt7915_coredump_register(struct mt7915_dev *dev)
+ {
+ 	struct mt7915_crash_data *crash_data;
++	int i;
+ 
+-	crash_data = vzalloc(sizeof(*dev->coredump.crash_data));
+-	if (!crash_data)
+-		return -ENOMEM;
++	for (i = 0; i < __MT76_RAM_TYPE_MAX; i++) {
++		crash_data = vzalloc(sizeof(*dev->coredump.crash_data[i]));
++		if (!crash_data)
++			return -ENOMEM;
+ 
+-	dev->coredump.crash_data = crash_data;
++		dev->coredump.crash_data[i] = crash_data;
+ 
+-	if (coredump_memdump) {
+-		crash_data->memdump_buf_len = mt7915_coredump_get_mem_size(dev);
+-		if (!crash_data->memdump_buf_len)
+-			/* no memory content */
+-			return 0;
++		if (coredump_memdump) {
++			crash_data->memdump_buf_len = mt7915_coredump_get_mem_size(dev, i);
++			if (!crash_data->memdump_buf_len)
++				/* no memory content */
++				return 0;
+ 
+-		crash_data->memdump_buf = vzalloc(crash_data->memdump_buf_len);
+-		if (!crash_data->memdump_buf) {
+-			vfree(crash_data);
+-			return -ENOMEM;
++			crash_data->memdump_buf = vzalloc(crash_data->memdump_buf_len);
++			if (!crash_data->memdump_buf) {
++				vfree(crash_data);
++				return -ENOMEM;
++			}
+ 		}
+ 	}
+ 
+@@ -399,13 +458,17 @@ int mt7915_coredump_register(struct mt7915_dev *dev)
+ 
+ void mt7915_coredump_unregister(struct mt7915_dev *dev)
+ {
+-	if (dev->coredump.crash_data->memdump_buf) {
+-		vfree(dev->coredump.crash_data->memdump_buf);
+-		dev->coredump.crash_data->memdump_buf = NULL;
+-		dev->coredump.crash_data->memdump_buf_len = 0;
+-	}
++	int i;
+ 
+-	vfree(dev->coredump.crash_data);
+-	dev->coredump.crash_data = NULL;
++	for (i = 0; i < __MT76_RAM_TYPE_MAX; i++) {
++		if (dev->coredump.crash_data[i]->memdump_buf) {
++			vfree(dev->coredump.crash_data[i]->memdump_buf);
++			dev->coredump.crash_data[i]->memdump_buf = NULL;
++			dev->coredump.crash_data[i]->memdump_buf_len = 0;
++		}
++
++		vfree(dev->coredump.crash_data[i]);
++		dev->coredump.crash_data[i] = NULL;
++	}
+ }
+ 
+diff --git a/mt7915/coredump.h b/mt7915/coredump.h
+index 709f8e9c..809ccbdf 100644
+--- a/mt7915/coredump.h
++++ b/mt7915/coredump.h
+@@ -4,6 +4,7 @@
+ #ifndef _COREDUMP_H_
+ #define _COREDUMP_H_
+ 
++#include "../mt76_connac_mcu.h"
+ #include "mt7915.h"
+ 
+ struct trace {
+@@ -15,6 +16,7 @@ struct mt7915_coredump {
+ 	char magic[16];
+ 
+ 	u32 len;
++	u32 hdr_len;
+ 
+ 	guid_t guid;
+ 
+@@ -26,12 +28,28 @@ struct mt7915_coredump {
+ 	char kernel[64];
+ 	/* firmware version */
+ 	char fw_ver[ETHTOOL_FWVERS_LEN];
++	char fw_patch_date[MT76_BUILD_TIME_LEN];
++	char fw_ram_date[__MT76_RAM_TYPE_MAX][MT76_BUILD_TIME_LEN];
+ 
+ 	u32 device_id;
+ 
++	/* fw type */
++	char fw_type[8];
+ 	/* exception state */
+ 	char fw_state[12];
+ 
++	/* program counters */
++	u32 pc_dbg_ctrl;
++	u32 pc_cur_idx;
++	u32 pc_cur[10];
++	/* PC registers */
++	u32 pc_stack[32];
++
++	u32 lr_dbg_ctrl;
++	u32 lr_cur_idx;
++	/* LR registers */
++	u32 lr_stack[32];
++
+ 	u32 last_msg_id;
+ 	u32 eint_info_idx;
+ 	u32 irq_info_idx;
+@@ -70,9 +88,6 @@ struct mt7915_coredump {
+ 		u32 handler;
+ 	} context;
+ 
+-	/* link registers calltrace */
+-	u32 call_stack[16];
+-
+ 	/* memory content */
+ 	u8 data[];
+ } __packed;
+@@ -83,6 +98,7 @@ struct mt7915_coredump_mem {
+ } __packed;
+ 
+ struct mt7915_mem_hdr {
++	char name[64];
+ 	u32 start;
+ 	u32 len;
+ 	u8 data[];
+@@ -98,26 +114,26 @@ struct mt7915_mem_region {
+ #ifdef CONFIG_DEV_COREDUMP
+ 
+ const struct mt7915_mem_region *
+-mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num);
+-struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev);
+-int mt7915_coredump_submit(struct mt7915_dev *dev);
++mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u8 type, u32 *num);
++struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev, u8 type);
++int mt7915_coredump_submit(struct mt7915_dev *dev, u8 type);
+ int mt7915_coredump_register(struct mt7915_dev *dev);
+ void mt7915_coredump_unregister(struct mt7915_dev *dev);
+ 
+ #else /* CONFIG_DEV_COREDUMP */
+ 
+ static inline const struct mt7915_mem_region *
+-mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u32 *num)
++mt7915_coredump_get_mem_layout(struct mt7915_dev *dev, u8 type, u32 *num)
+ {
+ 	return NULL;
+ }
+ 
+-static inline int mt7915_coredump_submit(struct mt7915_dev *dev)
++static inline int mt7915_coredump_submit(struct mt7915_dev *dev, u8 type)
+ {
+ 	return 0;
+ }
+ 
+-static inline struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev)
++static inline struct mt7915_crash_data *mt7915_coredump_new(struct mt7915_dev *dev, u8 type)
+ {
+ 	return NULL;
+ }
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index a3ed4ddf..2a87b506 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -1653,28 +1653,31 @@ void mt7915_mac_reset_work(struct work_struct *work)
+ }
+ 
+ /* firmware coredump */
+-void mt7915_mac_dump_work(struct work_struct *work)
++static void mt7915_mac_fw_coredump(struct mt7915_dev *dev, u8 type)
+ {
+ 	const struct mt7915_mem_region *mem_region;
+ 	struct mt7915_crash_data *crash_data;
+-	struct mt7915_dev *dev;
+ 	struct mt7915_mem_hdr *hdr;
+ 	size_t buf_len;
+ 	int i;
+ 	u32 num;
+ 	u8 *buf;
+ 
+-	dev = container_of(work, struct mt7915_dev, dump_work);
++	if (type != MT76_RAM_TYPE_WM) {
++		dev_warn(dev->mt76.dev, "%s currently only supports WM coredump!\n",
++			 wiphy_name(dev->mt76.hw->wiphy));
++		return;
++	}
+ 
+ 	mutex_lock(&dev->dump_mutex);
+ 
+-	crash_data = mt7915_coredump_new(dev);
++	crash_data = mt7915_coredump_new(dev, type);
+ 	if (!crash_data) {
+ 		mutex_unlock(&dev->dump_mutex);
+-		goto skip_coredump;
++		return;
+ 	}
+ 
+-	mem_region = mt7915_coredump_get_mem_layout(dev, &num);
++	mem_region = mt7915_coredump_get_mem_layout(dev, type, &num);
+ 	if (!mem_region || !crash_data->memdump_buf_len) {
+ 		mutex_unlock(&dev->dump_mutex);
+ 		goto skip_memdump;
+@@ -1684,6 +1687,9 @@ void mt7915_mac_dump_work(struct work_struct *work)
+ 	buf_len = crash_data->memdump_buf_len;
+ 
+ 	/* dumping memory content... */
++	dev_info(dev->mt76.dev, "%s start coredump for %s\n",
++		 wiphy_name(dev->mt76.hw->wiphy),
++		 ((type == MT76_RAM_TYPE_WA) ? "WA" : "WM"));
+ 	memset(buf, 0, buf_len);
+ 	for (i = 0; i < num; i++) {
+ 		if (mem_region->len > buf_len) {
+@@ -1701,6 +1707,7 @@ void mt7915_mac_dump_work(struct work_struct *work)
+ 		mt7915_memcpy_fromio(dev, buf, mem_region->start,
+ 				     mem_region->len);
+ 
++		strscpy(hdr->name, mem_region->name, sizeof(mem_region->name));
+ 		hdr->start = mem_region->start;
+ 		hdr->len = mem_region->len;
+ 
+@@ -1717,8 +1724,18 @@ void mt7915_mac_dump_work(struct work_struct *work)
+ 	mutex_unlock(&dev->dump_mutex);
+ 
+ skip_memdump:
+-	mt7915_coredump_submit(dev);
+-skip_coredump:
++	mt7915_coredump_submit(dev, type);
++}
++
++void mt7915_mac_dump_work(struct work_struct *work)
++{
++	struct mt7915_dev *dev;
++
++	dev = container_of(work, struct mt7915_dev, dump_work);
++
++	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WM_WDT)
++		mt7915_mac_fw_coredump(dev, MT76_RAM_TYPE_WM);
++
+ 	queue_work(dev->mt76.wq, &dev->reset_work);
+ }
+ 
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index 54510245..4fb0a375 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -335,7 +335,7 @@ struct mt7915_dev {
+ 	struct mutex dump_mutex;
+ #ifdef CONFIG_DEV_COREDUMP
+ 	struct {
+-		struct mt7915_crash_data *crash_data;
++		struct mt7915_crash_data *crash_data[__MT76_RAM_TYPE_MAX];
+ 	} coredump;
+ #endif
+ 
+diff --git a/mt7915/regs.h b/mt7915/regs.h
+index 374677f7..636b12da 100644
+--- a/mt7915/regs.h
++++ b/mt7915/regs.h
+@@ -1215,4 +1215,24 @@ enum offs_rev {
+ #define MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR	MT_MCU_WM_CIRQ(0x108)
+ #define MT_MCU_WM_CIRQ_EINT_SOFT_ADDR		MT_MCU_WM_CIRQ(0x118)
+ 
++/* CONN DBG */
++#define MT_CONN_DBG_CTL_BASE			0x18060000
++#define MT_CONN_DBG_CTL(ofs)			(MT_CONN_DBG_CTL_BASE + (ofs))
++#define MT_CONN_DBG_CTL_LOG_SEL			MT_CONN_DBG_CTL(0x090)
++#define MT_CONN_DBG_CTL_PC_LOG_SEL		GENMASK(7, 2)
++#define MT_CONN_DBG_CTL_GPR_LOG_SEL		GENMASK(13, 8)
++#define MT_CONN_DBG_CTL_PC_LOG			MT_CONN_DBG_CTL(0x204)
++#define MT_CONN_DBG_CTL_GPR_LOG			MT_CONN_DBG_CTL(0x204)
++
++/* CONN MCU EXCP CON */
++#define MT_MCU_WM_EXCP_BASE			0x89050000
++
++#define MT_MCU_WM_EXCP(ofs)			(MT_MCU_WM_EXCP_BASE + (ofs))
++#define MT_MCU_WM_EXCP_PC_CTRL			MT_MCU_WM_EXCP(0x100)
++#define MT_MCU_WM_EXCP_PC_CTRL_IDX_STATUS	GENMASK(20, 16)
++#define MT_MCU_WM_EXCP_PC_LOG			MT_MCU_WM_EXCP(0x104)
++#define MT_MCU_WM_EXCP_LR_CTRL			MT_MCU_WM_EXCP(0x200)
++#define MT_MCU_WM_EXCP_LR_CTRL_IDX_STATUS	GENMASK(20, 16)
++#define MT_MCU_WM_EXCP_LR_LOG			MT_MCU_WM_EXCP(0x204)
++
+ #endif
+-- 
+2.18.0
+
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/1000-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/1000-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch
index 6af8966..85a5fe8 100644
--- a/autobuild_mac80211_release/package/kernel/mt76/patches/1000-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/1000-wifi-mt76-mt7915-add-mtk-internal-debug-tools-for-mt.patch
@@ -1,8 +1,7 @@
-From 7bfb1fb85edfcbd68b4b680e387efdfcf2f00f77 Mon Sep 17 00:00:00 2001
+From d7349df90b0382edfa3bbed0e48cfcc5a989e79e Mon Sep 17 00:00:00 2001
 From: Shayne Chen <shayne.chen@mediatek.com>
 Date: Wed, 22 Jun 2022 10:39:47 +0800
-Subject: [PATCH 1000/1033] wifi: mt76: mt7915: add mtk internal debug tools
- for mt76
+Subject: [PATCH] wifi: mt76: mt7915: add mtk internal debug tools for mt76
 
 ---
  mt76_connac_mcu.h     |    6 +
@@ -14,16 +13,16 @@
  mt7915/mcu.h          |    4 +
  mt7915/mt7915.h       |   43 +
  mt7915/mt7915_debug.h | 1418 ++++++++++++++++
- mt7915/mtk_debugfs.c  | 3606 +++++++++++++++++++++++++++++++++++++++++
+ mt7915/mtk_debugfs.c  | 3624 +++++++++++++++++++++++++++++++++++++++++
  mt7915/mtk_mcu.c      |   51 +
  tools/fwlog.c         |   44 +-
- 12 files changed, 5310 insertions(+), 19 deletions(-)
+ 12 files changed, 5328 insertions(+), 19 deletions(-)
  create mode 100644 mt7915/mt7915_debug.h
  create mode 100644 mt7915/mtk_debugfs.c
  create mode 100644 mt7915/mtk_mcu.c
 
 diff --git a/mt76_connac_mcu.h b/mt76_connac_mcu.h
-index ebb7f58..8d6c422 100644
+index ebb7f587..8d6c422b 100644
 --- a/mt76_connac_mcu.h
 +++ b/mt76_connac_mcu.h
 @@ -1148,6 +1148,7 @@ enum {
@@ -47,7 +46,7 @@
  	MCU_EXT_CMD_CAL_CACHE = 0x67,
  	MCU_EXT_CMD_RED_ENABLE = 0x68,
 diff --git a/mt7915/Makefile b/mt7915/Makefile
-index c4dca9c..fd71141 100644
+index c4dca9c1..fd711416 100644
 --- a/mt7915/Makefile
 +++ b/mt7915/Makefile
 @@ -4,7 +4,7 @@ EXTRA_CFLAGS += -DCONFIG_MT76_LEDS
@@ -60,7 +59,7 @@
  mt7915e-$(CONFIG_NL80211_TESTMODE) += testmode.o
  mt7915e-$(CONFIG_MT798X_WMAC) += soc.o
 diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
-index 879884e..9fca009 100644
+index 879884ea..9fca0093 100644
 --- a/mt7915/debugfs.c
 +++ b/mt7915/debugfs.c
 @@ -8,6 +8,9 @@
@@ -232,7 +231,7 @@
  
  	if (dev->relay_fwlog)
 diff --git a/mt7915/mac.c b/mt7915/mac.c
-index a3ed4dd..b5805bb 100644
+index 2a87b506..a62a9bca 100644
 --- a/mt7915/mac.c
 +++ b/mt7915/mac.c
 @@ -275,6 +275,10 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
@@ -271,7 +270,7 @@
  }
  
 diff --git a/mt7915/main.c b/mt7915/main.c
-index f78f2bf..699f767 100644
+index f78f2bf0..699f767f 100644
 --- a/mt7915/main.c
 +++ b/mt7915/main.c
 @@ -73,7 +73,11 @@ int mt7915_run(struct ieee80211_hw *hw)
@@ -287,7 +286,7 @@
  		goto out;
  
 diff --git a/mt7915/mcu.c b/mt7915/mcu.c
-index dbdc48a..5acba67 100644
+index dbdc48a0..5acba67d 100644
 --- a/mt7915/mcu.c
 +++ b/mt7915/mcu.c
 @@ -203,6 +203,11 @@ mt7915_mcu_send_message(struct mt76_dev *mdev, struct sk_buff *skb,
@@ -371,7 +370,7 @@
 +}
 +#endif
 diff --git a/mt7915/mcu.h b/mt7915/mcu.h
-index aebacc7..daea67f 100644
+index aebacc7d..daea67f0 100644
 --- a/mt7915/mcu.h
 +++ b/mt7915/mcu.h
 @@ -333,6 +333,10 @@ enum {
@@ -386,7 +385,7 @@
  };
  
 diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
-index 5451024..29394b6 100644
+index 4fb0a375..88e3bb3d 100644
 --- a/mt7915/mt7915.h
 +++ b/mt7915/mt7915.h
 @@ -9,6 +9,7 @@
@@ -453,7 +452,7 @@
  #endif
 diff --git a/mt7915/mt7915_debug.h b/mt7915/mt7915_debug.h
 new file mode 100644
-index 0000000..fa8794f
+index 00000000..fa8794fd
 --- /dev/null
 +++ b/mt7915/mt7915_debug.h
 @@ -0,0 +1,1418 @@
@@ -1877,10 +1876,10 @@
 +#endif
 diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
 new file mode 100644
-index 0000000..4bbb410
+index 00000000..b1f8631c
 --- /dev/null
 +++ b/mt7915/mtk_debugfs.c
-@@ -0,0 +1,3606 @@
+@@ -0,0 +1,3624 @@
 +#include<linux/inet.h>
 +#include "mt7915.h"
 +#include "mt7915_debug.h"
@@ -4805,6 +4804,22 @@
 +DEFINE_DEBUGFS_ATTRIBUTE(fops_wa_debug, NULL, mt7915_wa_debug,
 +			 "0x%llx\n");
 +
++static int mt7915_dump_version(struct seq_file *s, void *data)
++{
++	struct mt7915_dev *dev = dev_get_drvdata(s->private);
++	struct mt76_dev *mdev = NULL;
++	seq_printf(s, "Version: 2.2.11.0\n");
++
++	if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
++		return 0;
++
++	mdev = &dev->mt76;
++	seq_printf(s, "Rom Patch Build Time: %.16s\n", mdev->patch_hdr->build_date);
++	seq_printf(s, "WM Patch Build Time: %.16s\n", mdev->wm_hdr->build_date);
++	seq_printf(s, "WA Patch Build Time: %.16s\n", mdev->wa_hdr->build_date);
++	return 0;
++}
++
 +static inline int mt7915_snprintf_error(size_t size, int res)
 +{
 +	return res < 0 || (unsigned int) res >= size;
@@ -5468,6 +5483,8 @@
 +
 +	debugfs_create_file("fw_wa_query", 0600, dir, dev, &fops_wa_query);
 +	debugfs_create_file("fw_wa_set", 0600, dir, dev, &fops_wa_set);
++	debugfs_create_devm_seqfile(dev->mt76.dev, "fw_version", dir,
++				    mt7915_dump_version);
 +	debugfs_create_file("fw_wa_debug", 0600, dir, dev, &fops_wa_debug);
 +	debugfs_create_devm_seqfile(dev->mt76.dev, "fw_wm_info", dir,
 +				    mt7915_fw_wm_info_read);
@@ -5489,7 +5506,7 @@
 +#endif
 diff --git a/mt7915/mtk_mcu.c b/mt7915/mtk_mcu.c
 new file mode 100644
-index 0000000..143dae2
+index 00000000..143dae26
 --- /dev/null
 +++ b/mt7915/mtk_mcu.c
 @@ -0,0 +1,51 @@
@@ -5545,7 +5562,7 @@
 +				 sizeof(req), true);
 +}
 diff --git a/tools/fwlog.c b/tools/fwlog.c
-index e5d4a10..3d51d9e 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)
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/1008-wifi-mt76-mt7915-add-fw_version-dump.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/1008-wifi-mt76-mt7915-add-fw_version-dump.patch
deleted file mode 100644
index 638abb7..0000000
--- a/autobuild_mac80211_release/package/kernel/mt76/patches/1008-wifi-mt76-mt7915-add-fw_version-dump.patch
+++ /dev/null
@@ -1,100 +0,0 @@
-From 64d91a2c5c82e023639c032c8dde34da2d125628 Mon Sep 17 00:00:00 2001
-From: Evelyn Tsai <evelyn.tsai@mediatek.com>
-Date: Wed, 17 Aug 2022 13:40:24 +0800
-Subject: [PATCH 1008/1033] wifi: mt76: mt7915: add fw_version dump
-
----
- mt76.h               |  4 ++++
- mt76_connac_mcu.c    |  9 +++++++++
- mt7915/mtk_debugfs.c | 19 +++++++++++++++++++
- 3 files changed, 32 insertions(+)
-
-diff --git a/mt76.h b/mt76.h
-index a8f26a8..3425159 100644
---- a/mt76.h
-+++ b/mt76.h
-@@ -849,6 +849,10 @@ struct mt76_dev {
- 		struct mt76_usb usb;
- 		struct mt76_sdio sdio;
- 	};
-+
-+	struct mt76_connac2_patch_hdr *patch_hdr;
-+	struct mt76_connac2_fw_trailer *wm_hdr;
-+	struct mt76_connac2_fw_trailer *wa_hdr;
- };
- 
- struct mt76_power_limits {
-diff --git a/mt76_connac_mcu.c b/mt76_connac_mcu.c
-index 732a4e6..1cdef36 100644
---- a/mt76_connac_mcu.c
-+++ b/mt76_connac_mcu.c
-@@ -2976,6 +2976,9 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
- 		 sizeof(dev->hw->wiphy->fw_version),
- 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
- 
-+	dev->wm_hdr = devm_kzalloc(dev->dev, sizeof(*hdr), GFP_KERNEL);
-+	memcpy(dev->wm_hdr, hdr, sizeof(*hdr));
-+
- 	release_firmware(fw);
- 
- 	if (!fw_wa)
-@@ -3001,6 +3004,9 @@ int mt76_connac2_load_ram(struct mt76_dev *dev, const char *fw_wm,
- 		goto out;
- 	}
- 
-+	dev->wa_hdr = devm_kzalloc(dev->dev, sizeof(*hdr), GFP_KERNEL);
-+	memcpy(dev->wa_hdr, hdr, sizeof(*hdr));
-+
- 	snprintf(dev->hw->wiphy->fw_version,
- 		 sizeof(dev->hw->wiphy->fw_version),
- 		 "%.10s-%.15s", hdr->fw_ver, hdr->build_date);
-@@ -3071,6 +3077,9 @@ int mt76_connac2_load_patch(struct mt76_dev *dev, const char *fw_name)
- 	dev_info(dev->dev, "HW/SW Version: 0x%x, Build Time: %.16s\n",
- 		 be32_to_cpu(hdr->hw_sw_ver), hdr->build_date);
- 
-+	dev->patch_hdr = devm_kzalloc(dev->dev, sizeof(*hdr), GFP_KERNEL);
-+	memcpy(dev->patch_hdr, hdr, sizeof(*hdr));
-+
- 	for (i = 0; i < be32_to_cpu(hdr->desc.n_region); i++) {
- 		struct mt76_connac2_patch_sec *sec;
- 		u32 len, addr, mode;
-diff --git a/mt7915/mtk_debugfs.c b/mt7915/mtk_debugfs.c
-index fc148d4..c6cec57 100644
---- a/mt7915/mtk_debugfs.c
-+++ b/mt7915/mtk_debugfs.c
-@@ -2799,6 +2799,22 @@ static int mt7915_agginfo_read_band1(struct seq_file *s, void *data)
- 	return 0;
- }
- 
-+static int mt7915_dump_version(struct seq_file *s, void *data)
-+{
-+	struct mt7915_dev *dev = dev_get_drvdata(s->private);
-+	struct mt76_dev *mdev = NULL;
-+	seq_printf(s, "Version: 2.2.11.0\n");
-+
-+	if (!test_bit(MT76_STATE_MCU_RUNNING, &dev->mphy.state))
-+		return 0;
-+
-+	mdev = &dev->mt76;
-+	seq_printf(s, "Rom Patch Build Time: %.16s\n", mdev->patch_hdr->build_date);
-+	seq_printf(s, "WM Patch Build Time: %.16s\n", mdev->wm_hdr->build_date);
-+	seq_printf(s, "WA Patch Build Time: %.16s\n", mdev->wa_hdr->build_date);
-+	return 0;
-+}
-+
- /*usage: <en> <num> <len>
- 	en: BIT(16) 0: sw amsdu  1: hw amsdu
- 	num: GENMASK(15, 8) range 1-8
-@@ -3635,6 +3651,9 @@ int mt7915_mtk_init_debugfs(struct mt7915_phy *phy, struct dentry *dir)
- 
- 	debugfs_create_u8("sku_disable", 0600, dir, &dev->dbg.sku_disable);
- 
-+	debugfs_create_devm_seqfile(dev->mt76.dev, "fw_version", dir,
-+				    mt7915_dump_version);
-+
- 	return 0;
- }
- #endif
--- 
-2.18.0
-
diff --git a/autobuild_mac80211_release/package/kernel/mt76/patches/1034-wifi-mt76-mt7915-add-debugfs-for-fw-coredump.patch b/autobuild_mac80211_release/package/kernel/mt76/patches/1034-wifi-mt76-mt7915-add-debugfs-for-fw-coredump.patch
new file mode 100644
index 0000000..d030805
--- /dev/null
+++ b/autobuild_mac80211_release/package/kernel/mt76/patches/1034-wifi-mt76-mt7915-add-debugfs-for-fw-coredump.patch
@@ -0,0 +1,173 @@
+From 4eb61cd26244aca09e163a7a013b3190cab35ced Mon Sep 17 00:00:00 2001
+From: Bo Jiao <Bo.Jiao@mediatek.com>
+Date: Mon, 22 May 2023 15:30:21 +0800
+Subject: [PATCH] wifi: mt76: mt7915: add debugfs for fw coredump.
+
+Signed-off-by: Bo Jiao <Bo.Jiao@mediatek.com>
+---
+ mt7915/debugfs.c | 22 +++++++++++++++++-----
+ mt7915/mac.c     | 30 +++++++++++++++++++++++++++---
+ mt7915/mcu.h     |  6 +++++-
+ mt7915/mt7915.h  |  9 +++++++++
+ 4 files changed, 58 insertions(+), 9 deletions(-)
+
+diff --git a/mt7915/debugfs.c b/mt7915/debugfs.c
+index a122457e..8dd79d8f 100644
+--- a/mt7915/debugfs.c
++++ b/mt7915/debugfs.c
+@@ -82,8 +82,10 @@ mt7915_sys_recovery_set(struct file *file, const char __user *user_buf,
+ 	 * 4: trigger & enable system error L3 tx abort
+ 	 * 5: trigger & enable system error L3 tx disable.
+ 	 * 6: trigger & enable system error L3 bf recovery.
+-	 * 7: trigger & enable system error full recovery.
+-	 * 8: trigger firmware crash.
++	 * 8: trigger & enable system error full recovery.
++	 * 9: trigger firmware crash.
++	 * 10: trigger grab wa firmware coredump.
++	 * 11: trigger grab wm firmware coredump.
+ 	 */
+ 	case SER_QUERY:
+ 		ret = mt7915_mcu_set_ser(dev, 0, 0, band);
+@@ -108,7 +110,7 @@ mt7915_sys_recovery_set(struct file *file, const char __user *user_buf,
+ 		if (ret)
+ 			return ret;
+ 
+-		dev->recovery.state |= MT_MCU_CMD_WDT_MASK;
++		dev->recovery.state |= MT_MCU_CMD_WM_WDT;
+ 		mt7915_reset(dev);
+ 		break;
+ 
+@@ -117,6 +119,12 @@ mt7915_sys_recovery_set(struct file *file, const char __user *user_buf,
+ 		mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_MASK_CLR_ADDR, BIT(18));
+ 		mt76_wr(dev, MT_MCU_WM_CIRQ_EINT_SOFT_ADDR, BIT(18));
+ 		break;
++
++	case SER_SET_FW_COREDUMP_WA:
++		mt7915_coredump(dev, MT7915_COREDUMP_MANUAL_WA);
++		break;
++	case SER_SET_FW_COREDUMP_WM:
++		mt7915_coredump(dev, MT7915_COREDUMP_MANUAL_WM);
+ 	default:
+ 		break;
+ 	}
+@@ -157,9 +165,13 @@ mt7915_sys_recovery_get(struct file *file, char __user *user_buf,
+ 	desc += scnprintf(buff + desc, bufsz - desc,
+ 			  "6: trigger system error L3 bf recovery\n");
+ 	desc += scnprintf(buff + desc, bufsz - desc,
+-			  "7: trigger system error full recovery\n");
++			  "8: trigger system error full recovery\n");
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "9: trigger firmware crash\n");
++	desc += scnprintf(buff + desc, bufsz - desc,
++			  "10: trigger grab wa firmware coredump\n");
+ 	desc += scnprintf(buff + desc, bufsz - desc,
+-			  "8: trigger firmware crash\n");
++			  "11: trigger grab wm firmware coredump\n");
+ 
+ 	/* SER statistics */
+ 	desc += scnprintf(buff + desc, bufsz - desc,
+diff --git a/mt7915/mac.c b/mt7915/mac.c
+index 4e3c869c..498c3984 100644
+--- a/mt7915/mac.c
++++ b/mt7915/mac.c
+@@ -1783,10 +1783,34 @@ void mt7915_mac_dump_work(struct work_struct *work)
+ 
+ 	dev = container_of(work, struct mt7915_dev, dump_work);
+ 
+-	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WM_WDT)
++	if (dev->dump_state == MT7915_COREDUMP_MANUAL_WA ||
++	    READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WA_WDT)
++		mt7915_mac_fw_coredump(dev, MT76_RAM_TYPE_WA);
++
++	if (dev->dump_state == MT7915_COREDUMP_MANUAL_WM ||
++	    READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WM_WDT)
+ 		mt7915_mac_fw_coredump(dev, MT76_RAM_TYPE_WM);
+ 
+-	queue_work(dev->mt76.wq, &dev->reset_work);
++	if (READ_ONCE(dev->recovery.state) & MT_MCU_CMD_WDT_MASK)
++		queue_work(dev->mt76.wq, &dev->reset_work);
++
++	dev->dump_state = MT7915_COREDUMP_IDLE;
++}
++
++void mt7915_coredump(struct mt7915_dev *dev, u8 state)
++{
++	if (state == MT7915_COREDUMP_IDLE ||
++	    state > MT7915_COREDUMP_AUTO)
++		return;
++
++	if (dev->dump_state != MT7915_COREDUMP_IDLE)
++		return;
++
++	dev->dump_state = state;
++	dev_info(dev->mt76.dev, "%s attempting grab coredump\n",
++		 wiphy_name(dev->mt76.hw->wiphy));
++
++	queue_work(dev->mt76.wq, &dev->dump_work);
+ }
+ 
+ void mt7915_reset(struct mt7915_dev *dev)
+@@ -1809,7 +1833,7 @@ void mt7915_reset(struct mt7915_dev *dev)
+ 			 wiphy_name(dev->mt76.hw->wiphy));
+ 
+ 		mt7915_irq_disable(dev, MT_INT_MCU_CMD);
+-		queue_work(dev->mt76.wq, &dev->dump_work);
++		mt7915_coredump(dev, MT7915_COREDUMP_AUTO);
+ 		return;
+ 	}
+ 
+diff --git a/mt7915/mcu.h b/mt7915/mcu.h
+index 8ac70e56..7febe658 100644
+--- a/mt7915/mcu.h
++++ b/mt7915/mcu.h
+@@ -745,8 +745,12 @@ enum {
+ 	SER_SET_RECOVER_L3_TX_ABORT,
+ 	SER_SET_RECOVER_L3_TX_DISABLE,
+ 	SER_SET_RECOVER_L3_BF,
+-	SER_SET_RECOVER_FULL,
++	SER_SET_RECOVER_FULL = 8,
++	/* fw assert */
+ 	SER_SET_SYSTEM_ASSERT,
++	/* coredump */
++	SER_SET_FW_COREDUMP_WA,
++	SER_SET_FW_COREDUMP_WM,
+ 	/* action */
+ 	SER_ENABLE = 2,
+ 	SER_RECOVER
+diff --git a/mt7915/mt7915.h b/mt7915/mt7915.h
+index 677856b4..cb2afeeb 100644
+--- a/mt7915/mt7915.h
++++ b/mt7915/mt7915.h
+@@ -91,6 +91,13 @@ struct mt7915_sta;
+ struct mt7915_dfs_pulse;
+ struct mt7915_dfs_pattern;
+ 
++enum mt7915_coredump_state {
++	MT7915_COREDUMP_IDLE = 0,
++	MT7915_COREDUMP_MANUAL_WA,
++	MT7915_COREDUMP_MANUAL_WM,
++	MT7915_COREDUMP_AUTO,
++};
++
+ enum mt7915_txq_id {
+ 	MT7915_TXQ_FWDL = 16,
+ 	MT7915_TXQ_MCU_WM,
+@@ -386,6 +393,7 @@ struct mt7915_dev {
+ 
+ 	/* protects coredump data */
+ 	struct mutex dump_mutex;
++	u8 dump_state;
+ #ifdef CONFIG_DEV_COREDUMP
+ 	struct {
+ 		struct mt7915_crash_data *crash_data[__MT76_RAM_TYPE_MAX];
+@@ -573,6 +581,7 @@ int mt7915_init_vif(struct mt7915_phy *phy, struct ieee80211_vif *vif, bool bf_e
+ void mt7915_init_txpower(struct mt7915_dev *dev,
+ 			 struct ieee80211_supported_band *sband);
+ void mt7915_reset(struct mt7915_dev *dev);
++void mt7915_coredump(struct mt7915_dev *dev, u8 state);
+ int mt7915_run(struct ieee80211_hw *hw);
+ int mt7915_mcu_init(struct mt7915_dev *dev);
+ int mt7915_mcu_init_firmware(struct mt7915_dev *dev);
+-- 
+2.18.0
+