rtw88: add dump firmware fifo support
authorTzu-En Huang <tehuang@realtek.com>
Fri, 25 Sep 2020 06:12:17 +0000 (14:12 +0800)
committerKalle Valo <kvalo@codeaurora.org>
Tue, 29 Sep 2020 08:22:20 +0000 (11:22 +0300)
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
drivers/net/wireless/realtek/rtw88/debug.c
drivers/net/wireless/realtek/rtw88/fw.c
drivers/net/wireless/realtek/rtw88/fw.h
drivers/net/wireless/realtek/rtw88/main.h
drivers/net/wireless/realtek/rtw88/rtw8822b.c
drivers/net/wireless/realtek/rtw88/rtw8822c.c

index 985cf5d606159dd6a3d66289e964946fc051892a..bff6ce19345a837bb58585eb2339ad5eb1ed2345 100644 (file)
@@ -229,7 +229,8 @@ static int rtw_debugfs_get_rsvd_page(struct seq_file *m, void *v)
        if (!buf)
                return -ENOMEM;
 
-       ret = rtw_dump_drv_rsvd_page(rtwdev, offset, buf_size, (u32 *)buf);
+       ret = rtw_fw_dump_fifo(rtwdev, RTW_FW_FIFO_SEL_RSVD_PAGE, offset,
+                              buf_size, (u32 *)buf);
        if (ret) {
                rtw_err(rtwdev, "failed to dump rsvd page\n");
                vfree(buf);
index 6a50bb993cafa1059ac923d201872b4115fc7940..042015bc8055b21b0d80b7a813c808f9fd6cd237 100644 (file)
@@ -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;
 }
 
index b4e3f755e8fbc0ed9e50daf908615dcb5cc79779..9c4863c011baa119779915a029a0c1ffaaf291ae 100644 (file)
@@ -16,7 +16,6 @@
 
 #define FIFO_PAGE_SIZE_SHIFT           12
 #define FIFO_PAGE_SIZE                 4096
-#define RSVD_PAGE_START_ADDR           0x780
 #define FIFO_DUMP_ADDR                 0x8000
 
 #define DLFW_PAGE_SIZE_SHIFT_LEGACY    12
@@ -565,5 +564,7 @@ void rtw_fw_update_pkt_probe_req(struct rtw_dev *rtwdev,
 void rtw_fw_channel_switch(struct rtw_dev *rtwdev, bool enable);
 void rtw_fw_h2c_cmd_dbg(struct rtw_dev *rtwdev, u8 *h2c);
 void rtw_fw_c2h_cmd_isr(struct rtw_dev *rtwdev);
+int rtw_fw_dump_fifo(struct rtw_dev *rtwdev, u8 fifo_sel, u32 addr, u32 size,
+                    u32 *buffer);
 
 #endif
index 292336387b89c319078aad63676c286ee25f52ce..06bdc68555e7f20c48776cc390f5f6003ef665e9 100644 (file)
@@ -1083,6 +1083,17 @@ enum rtw_wlan_cpu {
        RTW_WCPU_11N,
 };
 
+enum rtw_fw_fifo_sel {
+       RTW_FW_FIFO_SEL_TX,
+       RTW_FW_FIFO_SEL_RX,
+       RTW_FW_FIFO_SEL_RSVD_PAGE,
+       RTW_FW_FIFO_SEL_REPORT,
+       RTW_FW_FIFO_SEL_LLT,
+       RTW_FW_FIFO_SEL_RXBUF_FW,
+
+       RTW_FW_FIFO_MAX,
+};
+
 /* hardware configuration for each IC */
 struct rtw_chip_info {
        struct rtw_chip_ops *ops;
@@ -1099,6 +1110,7 @@ struct rtw_chip_info {
        u32 ptct_efuse_size;
        u32 txff_size;
        u32 rxff_size;
+       u32 fw_rxff_size;
        u8 band;
        u8 page_size;
        u8 csi_buf_pg_num;
@@ -1109,6 +1121,8 @@ struct rtw_chip_info {
        bool rx_ldpc;
        u8 max_power_index;
 
+       u16 fw_fifo_addr[RTW_FW_FIFO_MAX];
+
        bool ht_supported;
        bool vht_supported;
        u8 lps_deep_mode_supported;
index b7a98dbbb09c0bc84264c6d8f72e58a05e1a956e..22d0dd640ac94fa8a06848ba23b33056748c5505 100644 (file)
@@ -2442,6 +2442,7 @@ struct rtw_chip_info rtw8822b_hw_spec = {
        .ptct_efuse_size = 96,
        .txff_size = 262144,
        .rxff_size = 24576,
+       .fw_rxff_size = 12288,
        .txgi_factor = 1,
        .is_pwr_by_rate_dec = true,
        .max_power_index = 0x3f,
@@ -2504,6 +2505,8 @@ struct rtw_chip_info rtw8822b_hw_spec = {
 
        .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8822b),
        .coex_info_hw_regs = coex_info_hw_regs_8822b,
+
+       .fw_fifo_addr = {0x780, 0x700, 0x780, 0x660, 0x650, 0x680},
 };
 EXPORT_SYMBOL(rtw8822b_hw_spec);
 
index dd216a23fc9920e7b9aa72a0c9634335a7117a51..e37300e98517b88340b5477b575b62408fce0316 100644 (file)
@@ -4294,6 +4294,7 @@ struct rtw_chip_info rtw8822c_hw_spec = {
        .ptct_efuse_size = 124,
        .txff_size = 262144,
        .rxff_size = 24576,
+       .fw_rxff_size = 12288,
        .txgi_factor = 2,
        .is_pwr_by_rate_dec = false,
        .max_power_index = 0x7f,
@@ -4364,6 +4365,8 @@ struct rtw_chip_info rtw8822c_hw_spec = {
 
        .coex_info_hw_regs_num = ARRAY_SIZE(coex_info_hw_regs_8822c),
        .coex_info_hw_regs = coex_info_hw_regs_8822c,
+
+       .fw_fifo_addr = {0x780, 0x700, 0x780, 0x660, 0x650, 0x680},
 };
 EXPORT_SYMBOL(rtw8822c_hw_spec);