diff options
author | Tzu-En Huang <tehuang@realtek.com> | 2020-09-25 08:12:17 +0200 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2020-09-29 10:22:20 +0200 |
commit | 0fbc2f0f34cc57e8d6076631733e0095ac031995 (patch) | |
tree | a5e7a8b2ca8edbce3a1a5ba07473784e4dab6de7 /drivers/net/wireless/realtek/rtw88/fw.c | |
parent | rtw88: handle and recover when firmware crash (diff) | |
download | linux-0fbc2f0f34cc57e8d6076631733e0095ac031995.tar.xz linux-0fbc2f0f34cc57e8d6076631733e0095ac031995.zip |
rtw88: add dump firmware fifo support
Rtw88 currently has a function to dump reserved page section of the
firmware fifo. Reserved page is just part of the firmware fifo, there
are multiple sections in the firmware fifo for different usages, such as
firmware rx fifo and tx fifo.
This commit adds a function to check not only the reserved page section
but also other parts of the firmware fifo. In addition, we need to dump
firmware fifo to dump the debug log message if firmware crashes.
Signed-off-by: Tzu-En Huang <tehuang@realtek.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Link: https://lore.kernel.org/r/20200925061219.23754-4-tehuang@realtek.com
Diffstat (limited to 'drivers/net/wireless/realtek/rtw88/fw.c')
-rw-r--r-- | drivers/net/wireless/realtek/rtw88/fw.c | 77 |
1 files changed, 61 insertions, 16 deletions
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c index 6a50bb993caf..042015bc8055 100644 --- a/drivers/net/wireless/realtek/rtw88/fw.c +++ b/drivers/net/wireless/realtek/rtw88/fw.c @@ -1413,29 +1413,16 @@ free: return ret; } -int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev, - u32 offset, u32 size, u32 *buf) +static void rtw_fw_read_fifo_page(struct rtw_dev *rtwdev, u32 offset, u32 size, + u32 *buf, u32 residue, u16 start_pg) { - struct rtw_fifo_conf *fifo = &rtwdev->fifo; - u32 residue, i; - u16 start_pg; + u32 i; u16 idx = 0; u16 ctl; u8 rcr; - if (size & 0x3) { - rtw_warn(rtwdev, "should be 4-byte aligned\n"); - return -EINVAL; - } - - offset += fifo->rsvd_boundary << TX_PAGE_SIZE_SHIFT; - residue = offset & (FIFO_PAGE_SIZE - 1); - start_pg = offset >> FIFO_PAGE_SIZE_SHIFT; - start_pg += RSVD_PAGE_START_ADDR; - rcr = rtw_read8(rtwdev, REG_RCR + 2); ctl = rtw_read16(rtwdev, REG_PKTBUF_DBG_CTRL) & 0xf000; - /* disable rx clock gate */ rtw_write8(rtwdev, REG_RCR, rcr | BIT(3)); @@ -1457,6 +1444,64 @@ int rtw_dump_drv_rsvd_page(struct rtw_dev *rtwdev, out: rtw_write16(rtwdev, REG_PKTBUF_DBG_CTRL, ctl); rtw_write8(rtwdev, REG_RCR + 2, rcr); +} + +static void rtw_fw_read_fifo(struct rtw_dev *rtwdev, enum rtw_fw_fifo_sel sel, + u32 offset, u32 size, u32 *buf) +{ + struct rtw_chip_info *chip = rtwdev->chip; + u32 start_pg, residue; + + if (sel >= RTW_FW_FIFO_MAX) { + rtw_dbg(rtwdev, RTW_DBG_FW, "wrong fw fifo sel\n"); + return; + } + if (sel == RTW_FW_FIFO_SEL_RSVD_PAGE) + offset += rtwdev->fifo.rsvd_boundary << TX_PAGE_SIZE_SHIFT; + residue = offset & (FIFO_PAGE_SIZE - 1); + start_pg = (offset >> FIFO_PAGE_SIZE_SHIFT) + chip->fw_fifo_addr[sel]; + + rtw_fw_read_fifo_page(rtwdev, offset, size, buf, residue, start_pg); +} + +static bool rtw_fw_dump_check_size(struct rtw_dev *rtwdev, + enum rtw_fw_fifo_sel sel, + u32 start_addr, u32 size) +{ + switch (sel) { + case RTW_FW_FIFO_SEL_TX: + case RTW_FW_FIFO_SEL_RX: + if ((start_addr + size) > rtwdev->chip->fw_fifo_addr[sel]) + return false; + /*fall through*/ + default: + return true; + } +} + +int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size, + u32 *buffer) +{ + if (!rtwdev->chip->fw_fifo_addr) { + rtw_dbg(rtwdev, RTW_DBG_FW, "chip not support dump fw fifo\n"); + return -ENOTSUPP; + } + + if (size == 0 || !buffer) + return -EINVAL; + + if (size & 0x3) { + rtw_dbg(rtwdev, RTW_DBG_FW, "not 4byte alignment\n"); + return -EINVAL; + } + + if (!rtw_fw_dump_check_size(rtwdev, fifo_sel, addr, size)) { + rtw_dbg(rtwdev, RTW_DBG_FW, "fw fifo dump size overflow\n"); + return -EINVAL; + } + + rtw_fw_read_fifo(rtwdev, fifo_sel, addr, size, buffer); + return 0; } |