From: Ping-Ke Shih <pkshih@realtek.com>
To: <kvalo@kernel.org>
Cc: <linux-wireless@vger.kernel.org>, <kevin_yang@realtek.com>
Subject: [PATCH 6/8] rtw89: ser: dump fw backtrace while L2 reset
Date: Mon, 14 Mar 2022 15:12:48 +0800 [thread overview]
Message-ID: <20220314071250.40292-7-pkshih@realtek.com> (raw)
In-Reply-To: <20220314071250.40292-1-pkshih@realtek.com>
From: Zong-Zhe Yang <kevin_yang@realtek.com>
Read FW backtrace entry through FW reserved payload engine, and then
add FW backtrace dump during SER (system error recover) L2 reset process.
It contains a list of RA (return address) and SP (stack pointer) which
gives us a chance to trace back the call stack of FW.
Moreover, if core dump might have wrong content due to error during
dumping, we won't invoke device core dump framework. For this case,
rtw89_ser_cd_free() is added to free buffer by ourselves.
Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
drivers/net/wireless/realtek/rtw89/fw.h | 9 +++
drivers/net/wireless/realtek/rtw89/ser.c | 97 +++++++++++++++++++++++-
2 files changed, 105 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h
index d0b93a0b406df..1aaec26722377 100644
--- a/drivers/net/wireless/realtek/rtw89/fw.h
+++ b/drivers/net/wireless/realtek/rtw89/fw.h
@@ -2196,6 +2196,15 @@ struct rtw89_fw_h2c_rf_reg_info {
#define RTW89_FW_RSVD_PLE_SIZE 0x800
+#define RTW89_WCPU_BASE_ADDR 0xA0000000
+
+#define RTW89_FW_BACKTRACE_INFO_SIZE 8
+#define RTW89_VALID_FW_BACKTRACE_SIZE(_size) \
+ ((_size) % RTW89_FW_BACKTRACE_INFO_SIZE == 0)
+
+#define RTW89_FW_BACKTRACE_MAX_SIZE 512 /* 8 * 64 (entries) */
+#define RTW89_FW_BACKTRACE_KEY 0xBACEBACE
+
int rtw89_fw_check_rdy(struct rtw89_dev *rtwdev);
int rtw89_fw_recognize(struct rtw89_dev *rtwdev);
int rtw89_fw_download(struct rtw89_dev *rtwdev, enum rtw89_fw_type type);
diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c
index bf2f97a146ece..f28cd0645ad92 100644
--- a/drivers/net/wireless/realtek/rtw89/ser.c
+++ b/drivers/net/wireless/realtek/rtw89/ser.c
@@ -87,14 +87,20 @@ static void ser_cd_ ## _name ## _init(struct ser_cd_ ## _name *p) \
enum rtw89_ser_cd_type {
RTW89_SER_CD_FW_RSVD_PLE = 0,
+ RTW89_SER_CD_FW_BACKTRACE = 1,
};
RTW89_DEF_SER_CD_TYPE(fw_rsvd_ple,
RTW89_SER_CD_FW_RSVD_PLE,
RTW89_FW_RSVD_PLE_SIZE);
+RTW89_DEF_SER_CD_TYPE(fw_backtrace,
+ RTW89_SER_CD_FW_BACKTRACE,
+ RTW89_FW_BACKTRACE_MAX_SIZE);
+
struct rtw89_ser_cd_buffer {
struct ser_cd_fw_rsvd_ple fwple;
+ struct ser_cd_fw_backtrace fwbt;
} __packed;
static struct rtw89_ser_cd_buffer *rtw89_ser_cd_prep(struct rtw89_dev *rtwdev)
@@ -106,6 +112,7 @@ static struct rtw89_ser_cd_buffer *rtw89_ser_cd_prep(struct rtw89_dev *rtwdev)
return NULL;
ser_cd_fw_rsvd_ple_init(&buf->fwple);
+ ser_cd_fw_backtrace_init(&buf->fwbt);
return buf;
}
@@ -123,6 +130,21 @@ static void rtw89_ser_cd_send(struct rtw89_dev *rtwdev,
dev_coredumpv(rtwdev->dev, buf, sizeof(*buf), GFP_KERNEL);
}
+static void rtw89_ser_cd_free(struct rtw89_dev *rtwdev,
+ struct rtw89_ser_cd_buffer *buf, bool free_self)
+{
+ if (!free_self)
+ return;
+
+ rtw89_debug(rtwdev, RTW89_DBG_SER, "SER frees core dump by self\n");
+
+ /* When some problems happen during filling data of core dump,
+ * we won't send it to device coredump framework. Instead, we
+ * free buf by ourselves.
+ */
+ vfree(buf);
+}
+
static void ser_state_run(struct rtw89_ser *ser, u8 evt)
{
struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser);
@@ -487,19 +509,92 @@ static void rtw89_ser_fw_rsvd_ple_dump(struct rtw89_dev *rtwdev, u8 *buf)
RTW89_FW_RSVD_PLE_SIZE);
}
+struct __fw_backtrace_entry {
+ u32 wcpu_addr;
+ u32 size;
+ u32 key;
+} __packed;
+
+struct __fw_backtrace_info {
+ u32 ra;
+ u32 sp;
+} __packed;
+
+static_assert(RTW89_FW_BACKTRACE_INFO_SIZE ==
+ sizeof(struct __fw_backtrace_info));
+
+static int rtw89_ser_fw_backtrace_dump(struct rtw89_dev *rtwdev, u8 *buf,
+ const struct __fw_backtrace_entry *ent)
+{
+ struct __fw_backtrace_info *ptr = (struct __fw_backtrace_info *)buf;
+ u32 fwbt_addr = ent->wcpu_addr - RTW89_WCPU_BASE_ADDR;
+ u32 fwbt_size = ent->size;
+ u32 fwbt_key = ent->key;
+ u32 i;
+
+ if (fwbt_addr == 0) {
+ rtw89_warn(rtwdev, "FW backtrace invalid address: 0x%x\n",
+ fwbt_addr);
+ return -EINVAL;
+ }
+
+ if (fwbt_key != RTW89_FW_BACKTRACE_KEY) {
+ rtw89_warn(rtwdev, "FW backtrace invalid key: 0x%x\n",
+ fwbt_key);
+ return -EINVAL;
+ }
+
+ if (fwbt_size == 0 || !RTW89_VALID_FW_BACKTRACE_SIZE(fwbt_size) ||
+ fwbt_size > RTW89_FW_BACKTRACE_MAX_SIZE) {
+ rtw89_warn(rtwdev, "FW backtrace invalid size: 0x%x\n",
+ fwbt_size);
+ return -EINVAL;
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_SER, "dump fw backtrace start\n");
+ rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, fwbt_addr);
+
+ for (i = R_AX_INDIR_ACCESS_ENTRY;
+ i < R_AX_INDIR_ACCESS_ENTRY + fwbt_size;
+ i += RTW89_FW_BACKTRACE_INFO_SIZE, ptr++) {
+ *ptr = (struct __fw_backtrace_info){
+ .ra = rtw89_read32(rtwdev, i),
+ .sp = rtw89_read32(rtwdev, i + 4),
+ };
+ rtw89_debug(rtwdev, RTW89_DBG_SER,
+ "next sp: 0x%x, next ra: 0x%x\n",
+ ptr->sp, ptr->ra);
+ }
+
+ rtw89_debug(rtwdev, RTW89_DBG_SER, "dump fw backtrace end\n");
+ return 0;
+}
+
static void ser_l2_reset_st_pre_hdl(struct rtw89_ser *ser)
{
struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser);
struct rtw89_ser_cd_buffer *buf;
+ struct __fw_backtrace_entry fwbt_ent;
+ int ret = 0;
buf = rtw89_ser_cd_prep(rtwdev);
- if (!buf)
+ if (!buf) {
+ ret = -ENOMEM;
goto bottom;
+ }
rtw89_ser_fw_rsvd_ple_dump(rtwdev, buf->fwple.data);
+
+ fwbt_ent = *(struct __fw_backtrace_entry *)buf->fwple.data;
+ ret = rtw89_ser_fw_backtrace_dump(rtwdev, buf->fwbt.data, &fwbt_ent);
+ if (ret)
+ goto bottom;
+
rtw89_ser_cd_send(rtwdev, buf);
bottom:
+ rtw89_ser_cd_free(rtwdev, buf, !!ret);
+
ser_reset_mac_binding(rtwdev);
rtw89_core_stop(rtwdev);
INIT_LIST_HEAD(&rtwdev->rtwvifs_list);
--
2.25.1
next prev parent reply other threads:[~2022-03-14 7:13 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-03-14 7:12 [PATCH 0/8] rtw89: add firmware reset and dump firmware memory and backtrace Ping-Ke Shih
2022-03-14 7:12 ` [PATCH 1/8] rtw89: ser: fix CAM leaks occurring in L2 reset Ping-Ke Shih
2022-04-06 7:46 ` Kalle Valo
2022-03-14 7:12 ` [PATCH 2/8] rtw89: mac: move table of mem base addr to common Ping-Ke Shih
2022-03-14 7:12 ` [PATCH 3/8] rtw89: mac: correct decision on error status by scenario Ping-Ke Shih
2022-03-14 7:12 ` [PATCH 4/8] rtw89: ser: control hci interrupts on/off by state Ping-Ke Shih
2022-03-14 7:12 ` [PATCH 5/8] rtw89: ser: dump memory for fw payload engine while L2 reset Ping-Ke Shih
2022-03-14 7:12 ` Ping-Ke Shih [this message]
2022-03-14 7:12 ` [PATCH 7/8] rtw89: reconstruct fw feature Ping-Ke Shih
2022-03-14 7:12 ` [PATCH 8/8] rtw89: support FW crash simulation Ping-Ke Shih
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220314071250.40292-7-pkshih@realtek.com \
--to=pkshih@realtek.com \
--cc=kevin_yang@realtek.com \
--cc=kvalo@kernel.org \
--cc=linux-wireless@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.