mirror of
https://github.com/LibreELEC/LibreELEC.tv
synced 2025-09-24 19:46:01 +07:00
https://patchwork.kernel.org/project/linux-wireless/cover/d2870a44-9b91-4090-9a25-873eb62997f5@gmail.com/
235 lines
7.7 KiB
Diff
235 lines
7.7 KiB
Diff
From 20907fc069976fcf972239b7b253cf7c59c08a14 Mon Sep 17 00:00:00 2001
|
|
From: Chin-Yen Lee <timlee@realtek.com>
|
|
Date: Mon, 16 Oct 2023 13:35:54 +0800
|
|
Subject: [PATCH] wifi: rtw88: dump firmware debug information in abnormal
|
|
state
|
|
|
|
Sometimes firmware may enter strange state or infinite
|
|
loop due to unknown bug, and then it will lead critical
|
|
function fail, such as sending H2C command or changing
|
|
power mode. In these abnormal states, we add more debug
|
|
information, including hardware register status, to help
|
|
further investigation.
|
|
|
|
Signed-off-by: Chin-Yen Lee <timlee@realtek.com>
|
|
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
|
|
Signed-off-by: Kalle Valo <kvalo@kernel.org>
|
|
Link: https://lore.kernel.org/r/20231016053554.744180-3-pkshih@realtek.com
|
|
---
|
|
drivers/net/wireless/realtek/rtw88/fw.c | 74 +++++++++++++++++++++++
|
|
drivers/net/wireless/realtek/rtw88/fw.h | 3 +
|
|
drivers/net/wireless/realtek/rtw88/main.h | 6 ++
|
|
drivers/net/wireless/realtek/rtw88/ps.c | 2 +
|
|
drivers/net/wireless/realtek/rtw88/reg.h | 23 +++++++
|
|
5 files changed, 108 insertions(+)
|
|
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
|
|
index a1b674e3caaa3c..acd78311c8c4a1 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/fw.c
|
|
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
|
|
@@ -17,6 +17,79 @@
|
|
#include "phy.h"
|
|
#include "mac.h"
|
|
|
|
+static const struct rtw_hw_reg_desc fw_h2c_regs[] = {
|
|
+ {REG_FWIMR, MASKDWORD, "FWIMR"},
|
|
+ {REG_FWIMR, BIT_FS_H2CCMD_INT_EN, "FWIMR enable"},
|
|
+ {REG_FWISR, MASKDWORD, "FWISR"},
|
|
+ {REG_FWISR, BIT_FS_H2CCMD_INT, "FWISR enable"},
|
|
+ {REG_HMETFR, BIT_INT_BOX_ALL, "BoxBitMap"},
|
|
+ {REG_HMEBOX0, MASKDWORD, "MSG 0"},
|
|
+ {REG_HMEBOX0_EX, MASKDWORD, "MSG_EX 0"},
|
|
+ {REG_HMEBOX1, MASKDWORD, "MSG 1"},
|
|
+ {REG_HMEBOX1_EX, MASKDWORD, "MSG_EX 1"},
|
|
+ {REG_HMEBOX2, MASKDWORD, "MSG 2"},
|
|
+ {REG_HMEBOX2_EX, MASKDWORD, "MSG_EX 2"},
|
|
+ {REG_HMEBOX3, MASKDWORD, "MSG 3"},
|
|
+ {REG_HMEBOX3_EX, MASKDWORD, "MSG_EX 3"},
|
|
+ {REG_FT1IMR, MASKDWORD, "FT1IMR"},
|
|
+ {REG_FT1IMR, BIT_FS_H2C_CMD_OK_INT_EN, "FT1IMR enable"},
|
|
+ {REG_FT1ISR, MASKDWORD, "FT1ISR"},
|
|
+ {REG_FT1ISR, BIT_FS_H2C_CMD_OK_INT, "FT1ISR enable "},
|
|
+};
|
|
+
|
|
+static const struct rtw_hw_reg_desc fw_c2h_regs[] = {
|
|
+ {REG_FWIMR, MASKDWORD, "FWIMR"},
|
|
+ {REG_FWIMR, BIT_FS_H2CCMD_INT_EN, "CPWM"},
|
|
+ {REG_FWIMR, BIT_FS_HRCV_INT_EN, "HRECV"},
|
|
+ {REG_FWISR, MASKDWORD, "FWISR"},
|
|
+ {REG_FWISR, BIT_FS_H2CCMD_INT, "CPWM"},
|
|
+ {REG_FWISR, BIT_FS_HRCV_INT, "HRECV"},
|
|
+ {REG_CPWM, MASKDWORD, "REG_CPWM"},
|
|
+};
|
|
+
|
|
+static const struct rtw_hw_reg_desc fw_core_regs[] = {
|
|
+ {REG_ARFR2_V1, MASKDWORD, "EPC"},
|
|
+ {REG_ARFRH2_V1, MASKDWORD, "BADADDR"},
|
|
+ {REG_ARFR3_V1, MASKDWORD, "CAUSE"},
|
|
+ {REG_ARFR3_V1, BIT_EXC_CODE, "ExcCode"},
|
|
+ {REG_ARFRH3_V1, MASKDWORD, "Status"},
|
|
+ {REG_ARFR4, MASKDWORD, "SP"},
|
|
+ {REG_ARFRH4, MASKDWORD, "RA"},
|
|
+ {REG_FW_DBG6, MASKDWORD, "DBG 6"},
|
|
+ {REG_FW_DBG7, MASKDWORD, "DBG 7"},
|
|
+};
|
|
+
|
|
+static void _rtw_fw_dump_dbg_info(struct rtw_dev *rtwdev,
|
|
+ const struct rtw_hw_reg_desc regs[], u32 size)
|
|
+{
|
|
+ const struct rtw_hw_reg_desc *reg;
|
|
+ u32 val;
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < size; i++) {
|
|
+ reg = ®s[i];
|
|
+ val = rtw_read32_mask(rtwdev, reg->addr, reg->mask);
|
|
+
|
|
+ rtw_dbg(rtwdev, RTW_DBG_FW, "[%s]addr:0x%x mask:0x%x value:0x%x\n",
|
|
+ reg->desc, reg->addr, reg->mask, val);
|
|
+ }
|
|
+}
|
|
+
|
|
+void rtw_fw_dump_dbg_info(struct rtw_dev *rtwdev)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (!rtw_dbg_is_enabled(rtwdev, RTW_DBG_FW))
|
|
+ return;
|
|
+
|
|
+ _rtw_fw_dump_dbg_info(rtwdev, fw_h2c_regs, ARRAY_SIZE(fw_h2c_regs));
|
|
+ _rtw_fw_dump_dbg_info(rtwdev, fw_c2h_regs, ARRAY_SIZE(fw_c2h_regs));
|
|
+ for (i = 0 ; i < RTW_DEBUG_DUMP_TIMES; i++) {
|
|
+ rtw_dbg(rtwdev, RTW_DBG_FW, "Firmware Coredump %dth\n", i + 1);
|
|
+ _rtw_fw_dump_dbg_info(rtwdev, fw_core_regs, ARRAY_SIZE(fw_core_regs));
|
|
+ }
|
|
+}
|
|
+
|
|
static void rtw_fw_c2h_cmd_handle_ext(struct rtw_dev *rtwdev,
|
|
struct sk_buff *skb)
|
|
{
|
|
@@ -349,6 +422,7 @@ static void rtw_fw_send_h2c_command_register(struct rtw_dev *rtwdev,
|
|
|
|
if (ret) {
|
|
rtw_err(rtwdev, "failed to send h2c command\n");
|
|
+ rtw_fw_dump_dbg_info(rtwdev);
|
|
return;
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/fw.h b/drivers/net/wireless/realtek/rtw88/fw.h
|
|
index 43ccdf9965ac46..84e47c71ea1255 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/fw.h
|
|
+++ b/drivers/net/wireless/realtek/rtw88/fw.h
|
|
@@ -44,6 +44,8 @@
|
|
#define RTW_OLD_PROBE_PG_CNT 2
|
|
#define RTW_PROBE_PG_CNT 4
|
|
|
|
+#define RTW_DEBUG_DUMP_TIMES 10
|
|
+
|
|
enum rtw_c2h_cmd_id {
|
|
C2H_CCX_TX_RPT = 0x03,
|
|
C2H_BT_INFO = 0x09,
|
|
@@ -808,6 +810,7 @@ static inline bool rtw_fw_feature_ext_check(struct rtw_fw_state *fw,
|
|
return !!(fw->feature_ext & feature);
|
|
}
|
|
|
|
+void rtw_fw_dump_dbg_info(struct rtw_dev *rtwdev);
|
|
void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
|
|
struct sk_buff *skb);
|
|
void rtw_fw_c2h_cmd_handle(struct rtw_dev *rtwdev, struct sk_buff *skb);
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/main.h b/drivers/net/wireless/realtek/rtw88/main.h
|
|
index 86dc1516effade..b6bfd4c02e2db3 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/main.h
|
|
+++ b/drivers/net/wireless/realtek/rtw88/main.h
|
|
@@ -524,6 +524,12 @@ struct rtw_hw_reg {
|
|
u32 mask;
|
|
};
|
|
|
|
+struct rtw_hw_reg_desc {
|
|
+ u32 addr;
|
|
+ u32 mask;
|
|
+ const char *desc;
|
|
+};
|
|
+
|
|
struct rtw_ltecoex_addr {
|
|
u32 ctrl;
|
|
u32 wdata;
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/ps.c b/drivers/net/wireless/realtek/rtw88/ps.c
|
|
index 07e8cbd436cd81..add5a20b84320f 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/ps.c
|
|
+++ b/drivers/net/wireless/realtek/rtw88/ps.c
|
|
@@ -104,6 +104,7 @@ void rtw_power_mode_change(struct rtw_dev *rtwdev, bool enter)
|
|
*/
|
|
WARN(1, "firmware failed to ack driver for %s Deep Power mode\n",
|
|
enter ? "entering" : "leaving");
|
|
+ rtw_fw_dump_dbg_info(rtwdev);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(rtw_power_mode_change);
|
|
@@ -164,6 +165,7 @@ static void rtw_fw_leave_lps_check(struct rtw_dev *rtwdev)
|
|
if (ret) {
|
|
rtw_write32_clr(rtwdev, REG_TCR, BIT_PWRMGT_HWDATA_EN);
|
|
rtw_warn(rtwdev, "firmware failed to leave lps state\n");
|
|
+ rtw_fw_dump_dbg_info(rtwdev);
|
|
}
|
|
}
|
|
|
|
diff --git a/drivers/net/wireless/realtek/rtw88/reg.h b/drivers/net/wireless/realtek/rtw88/reg.h
|
|
index 7c6c11d50ff30f..1634f03784f171 100644
|
|
--- a/drivers/net/wireless/realtek/rtw88/reg.h
|
|
+++ b/drivers/net/wireless/realtek/rtw88/reg.h
|
|
@@ -224,12 +224,25 @@
|
|
#define REG_RXFF_BNDY 0x011C
|
|
#define REG_FE1IMR 0x0120
|
|
#define BIT_FS_RXDONE BIT(16)
|
|
+#define REG_CPWM 0x012C
|
|
+#define REG_FWIMR 0x0130
|
|
+#define BIT_FS_H2CCMD_INT_EN BIT(4)
|
|
+#define BIT_FS_HRCV_INT_EN BIT(5)
|
|
+#define REG_FWISR 0x0134
|
|
+#define BIT_FS_H2CCMD_INT BIT(4)
|
|
+#define BIT_FS_HRCV_INT BIT(5)
|
|
#define REG_PKTBUF_DBG_CTRL 0x0140
|
|
#define REG_C2HEVT 0x01A0
|
|
#define REG_MCUTST_1 0x01C0
|
|
#define REG_MCUTST_II 0x01C4
|
|
#define REG_WOWLAN_WAKE_REASON 0x01C7
|
|
#define REG_HMETFR 0x01CC
|
|
+#define BIT_INT_BOX0 BIT(0)
|
|
+#define BIT_INT_BOX1 BIT(1)
|
|
+#define BIT_INT_BOX2 BIT(2)
|
|
+#define BIT_INT_BOX3 BIT(3)
|
|
+#define BIT_INT_BOX_ALL (BIT_INT_BOX0 | BIT_INT_BOX1 | BIT_INT_BOX2 | \
|
|
+ BIT_INT_BOX3)
|
|
#define REG_HMEBOX0 0x01D0
|
|
#define REG_HMEBOX1 0x01D4
|
|
#define REG_HMEBOX2 0x01D8
|
|
@@ -338,6 +351,11 @@
|
|
#define BIT_EN_GNT_BT_AWAKE BIT(3)
|
|
#define BIT_EN_EOF_V1 BIT(2)
|
|
#define REG_DATA_SC 0x0483
|
|
+#define REG_ARFR2_V1 0x048C
|
|
+#define REG_ARFRH2_V1 0x0490
|
|
+#define REG_ARFR3_V1 0x0494
|
|
+#define BIT_EXC_CODE GENMASK(6, 2)
|
|
+#define REG_ARFRH3_V1 0x0498
|
|
#define REG_ARFR4 0x049C
|
|
#define BIT_WL_RFK BIT(0)
|
|
#define REG_ARFRH4 0x04A0
|
|
@@ -548,11 +566,16 @@
|
|
|
|
#define REG_H2C_PKT_READADDR 0x10D0
|
|
#define REG_H2C_PKT_WRITEADDR 0x10D4
|
|
+#define REG_FW_DBG6 0x10F8
|
|
#define REG_FW_DBG7 0x10FC
|
|
#define FW_KEY_MASK 0xffffff00
|
|
|
|
#define REG_CR_EXT 0x1100
|
|
|
|
+#define REG_FT1IMR 0x1138
|
|
+#define BIT_FS_H2C_CMD_OK_INT_EN BIT(25)
|
|
+#define REG_FT1ISR 0x113c
|
|
+#define BIT_FS_H2C_CMD_OK_INT BIT(25)
|
|
#define REG_DDMA_CH0SA 0x1200
|
|
#define REG_DDMA_CH0DA 0x1204
|
|
#define REG_DDMA_CH0CTRL 0x1208
|