Commit 9f8004bf authored by Zong-Zhe Yang's avatar Zong-Zhe Yang Committed by Kalle Valo

rtw89: ser: dump memory for fw payload engine while L2 reset

When FW encounters exception or assertion, SER L2 reset process will start.
It will dump some error information and re-download FW eventually. Since
such errors are usually critical, we would like to keep more information
about error to increase possibility of analysis and debugging FW. We first
add FW payload engine (fw reserved playoad engine, fw_rsvd_ple) memory
dump. FW will record things like CPU registers, backtrace entry, etc. in it
for debugging.

Moreover, device core dump framework is used and wrapped to collect kinds
of dumps during SER L2 reset process.
Signed-off-by: default avatarZong-Zhe Yang <kevin_yang@realtek.com>
Signed-off-by: default avatarPing-Ke Shih <pkshih@realtek.com>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220314071250.40292-6-pkshih@realtek.com
parent 14f9f479
......@@ -2275,6 +2275,7 @@ struct rtw89_chip_info {
u32 fifo_size;
u16 max_amsdu_limit;
bool dis_2g_40m_ul_ofdma;
u32 rsvd_ple_ofst;
const struct rtw89_hfc_param_ini *hfc_param_ini;
const struct rtw89_dle_mem *dle_mem;
u32 rf_base_addr[2];
......
......@@ -2194,6 +2194,8 @@ struct rtw89_fw_h2c_rf_reg_info {
#define H2C_CL_OUTSRC_RF_REG_A 0x8
#define H2C_CL_OUTSRC_RF_REG_B 0x9
#define RTW89_FW_RSVD_PLE_SIZE 0x800
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);
......
......@@ -2041,6 +2041,7 @@ const struct rtw89_chip_info rtw8852a_chip_info = {
.fifo_size = 458752,
.max_amsdu_limit = 3500,
.dis_2g_40m_ul_ofdma = true,
.rsvd_ple_ofst = 0x6f800,
.hfc_param_ini = rtw8852a_hfc_param_ini_pcie,
.dle_mem = rtw8852a_dle_mem_pcie,
.rf_base_addr = {0xc000, 0xd000},
......
......@@ -2,10 +2,14 @@
/* Copyright(c) 2019-2020 Realtek Corporation
*/
#include <linux/devcoredump.h>
#include "cam.h"
#include "debug.h"
#include "fw.h"
#include "mac.h"
#include "ps.h"
#include "reg.h"
#include "ser.h"
#include "util.h"
......@@ -67,6 +71,58 @@ static char *ser_st_name(struct rtw89_ser *ser)
return "err_st_name";
}
#define RTW89_DEF_SER_CD_TYPE(_name, _type, _size) \
struct ser_cd_ ## _name { \
u32 type; \
u32 type_size; \
u64 padding; \
u8 data[_size]; \
} __packed; \
static void ser_cd_ ## _name ## _init(struct ser_cd_ ## _name *p) \
{ \
p->type = _type; \
p->type_size = sizeof(p->data); \
p->padding = 0x0123456789abcdef; \
}
enum rtw89_ser_cd_type {
RTW89_SER_CD_FW_RSVD_PLE = 0,
};
RTW89_DEF_SER_CD_TYPE(fw_rsvd_ple,
RTW89_SER_CD_FW_RSVD_PLE,
RTW89_FW_RSVD_PLE_SIZE);
struct rtw89_ser_cd_buffer {
struct ser_cd_fw_rsvd_ple fwple;
} __packed;
static struct rtw89_ser_cd_buffer *rtw89_ser_cd_prep(struct rtw89_dev *rtwdev)
{
struct rtw89_ser_cd_buffer *buf;
buf = vzalloc(sizeof(*buf));
if (!buf)
return NULL;
ser_cd_fw_rsvd_ple_init(&buf->fwple);
return buf;
}
static void rtw89_ser_cd_send(struct rtw89_dev *rtwdev,
struct rtw89_ser_cd_buffer *buf)
{
rtw89_debug(rtwdev, RTW89_DBG_SER, "SER sends core dump\n");
/* After calling dev_coredump, buf's lifetime is supposed to be
* handled by the device coredump framework. Note that a new dump
* will be discarded if a previous one hasn't been released by
* framework yet.
*/
dev_coredumpv(rtwdev->dev, buf, sizeof(*buf), GFP_KERNEL);
}
static void ser_state_run(struct rtw89_ser *ser, u8 evt)
{
struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser);
......@@ -390,6 +446,65 @@ static void ser_do_hci_st_hdl(struct rtw89_ser *ser, u8 evt)
}
}
static void ser_mac_mem_dump(struct rtw89_dev *rtwdev, u8 *buf,
u8 sel, u32 start_addr, u32 len)
{
u32 *ptr = (u32 *)buf;
u32 base_addr, start_page, residue;
u32 cnt = 0;
u32 i;
start_page = start_addr / MAC_MEM_DUMP_PAGE_SIZE;
residue = start_addr % MAC_MEM_DUMP_PAGE_SIZE;
base_addr = rtw89_mac_mem_base_addrs[sel];
base_addr += start_page * MAC_MEM_DUMP_PAGE_SIZE;
while (cnt < len) {
rtw89_write32(rtwdev, R_AX_FILTER_MODEL_ADDR, base_addr);
for (i = R_AX_INDIR_ACCESS_ENTRY + residue;
i < R_AX_INDIR_ACCESS_ENTRY + MAC_MEM_DUMP_PAGE_SIZE;
i += 4, ptr++) {
*ptr = rtw89_read32(rtwdev, i);
cnt += 4;
if (cnt >= len)
break;
}
residue = 0;
base_addr += MAC_MEM_DUMP_PAGE_SIZE;
}
}
static void rtw89_ser_fw_rsvd_ple_dump(struct rtw89_dev *rtwdev, u8 *buf)
{
u32 start_addr = rtwdev->chip->rsvd_ple_ofst;
rtw89_debug(rtwdev, RTW89_DBG_SER,
"dump mem for fw rsvd payload engine (start addr: 0x%x)\n",
start_addr);
ser_mac_mem_dump(rtwdev, buf, RTW89_MAC_MEM_SHARED_BUF, start_addr,
RTW89_FW_RSVD_PLE_SIZE);
}
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;
buf = rtw89_ser_cd_prep(rtwdev);
if (!buf)
goto bottom;
rtw89_ser_fw_rsvd_ple_dump(rtwdev, buf->fwple.data);
rtw89_ser_cd_send(rtwdev, buf);
bottom:
ser_reset_mac_binding(rtwdev);
rtw89_core_stop(rtwdev);
INIT_LIST_HEAD(&rtwdev->rtwvifs_list);
}
static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt)
{
struct rtw89_dev *rtwdev = container_of(ser, struct rtw89_dev, ser);
......@@ -397,8 +512,7 @@ static void ser_l2_reset_st_hdl(struct rtw89_ser *ser, u8 evt)
switch (evt) {
case SER_EV_STATE_IN:
mutex_lock(&rtwdev->mutex);
ser_reset_mac_binding(rtwdev);
rtw89_core_stop(rtwdev);
ser_l2_reset_st_pre_hdl(ser);
mutex_unlock(&rtwdev->mutex);
ieee80211_restart_hw(rtwdev->hw);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment