diff options
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/core.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/fw.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/rtw8852a.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/realtek/rtw89/ser.c | 118 |
4 files changed, 120 insertions, 2 deletions
diff --git a/drivers/net/wireless/realtek/rtw89/core.h b/drivers/net/wireless/realtek/rtw89/core.h index 5efa5ca372c6..17ba5b85e500 100644 --- a/drivers/net/wireless/realtek/rtw89/core.h +++ b/drivers/net/wireless/realtek/rtw89/core.h @@ -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]; diff --git a/drivers/net/wireless/realtek/rtw89/fw.h b/drivers/net/wireless/realtek/rtw89/fw.h index ed8609b204e0..d0b93a0b406d 100644 --- a/drivers/net/wireless/realtek/rtw89/fw.h +++ b/drivers/net/wireless/realtek/rtw89/fw.h @@ -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); diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852a.c b/drivers/net/wireless/realtek/rtw89/rtw8852a.c index 41fc8db311ec..348ad08090b8 100644 --- a/drivers/net/wireless/realtek/rtw89/rtw8852a.c +++ b/drivers/net/wireless/realtek/rtw89/rtw8852a.c @@ -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}, diff --git a/drivers/net/wireless/realtek/rtw89/ser.c b/drivers/net/wireless/realtek/rtw89/ser.c index a20389cde7e2..bf2f97a146ec 100644 --- a/drivers/net/wireless/realtek/rtw89/ser.c +++ b/drivers/net/wireless/realtek/rtw89/ser.c @@ -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); |