aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/realtek/rtw88/fw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/realtek/rtw88/fw.c')
-rw-r--r--drivers/net/wireless/realtek/rtw88/fw.c86
1 files changed, 70 insertions, 16 deletions
diff --git a/drivers/net/wireless/realtek/rtw88/fw.c b/drivers/net/wireless/realtek/rtw88/fw.c
index 63b00bc19000..042015bc8055 100644
--- a/drivers/net/wireless/realtek/rtw88/fw.c
+++ b/drivers/net/wireless/realtek/rtw88/fw.c
@@ -193,6 +193,15 @@ void rtw_fw_c2h_cmd_rx_irqsafe(struct rtw_dev *rtwdev, u32 pkt_offset,
}
EXPORT_SYMBOL(rtw_fw_c2h_cmd_rx_irqsafe);
+void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev)
+{
+ if (rtw_read8(rtwdev, REG_MCU_TST_CFG) == VAL_FW_TRIGGER)
+ rtw_fw_recovery(rtwdev);
+ else
+ rtw_warn(rtwdev, "unhandled firmware c2h interrupt\n");
+}
+EXPORT_SYMBOL(rtw_fw_c2h_cmd_isr);
+
static void rtw_fw_send_h2c_command(struct rtw_dev *rtwdev,
u8 *h2c)
{
@@ -1404,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));
@@ -1448,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;
}