Loading drivers/net/wireless/cnss2/pci.c +104 −38 Original line number Diff line number Diff line Loading @@ -95,6 +95,14 @@ static DEFINE_SPINLOCK(pci_link_down_lock); #define QCA6390_CE_REG_INTERVAL 0x2000 #define SHADOW_REG_COUNT 36 #define QCA6390_PCIE_SHADOW_REG_VALUE_0 0x1E03024 #define QCA6390_PCIE_SHADOW_REG_VALUE_35 0x1E030B0 #define SHADOW_REG_INTER_COUNT 43 #define QCA6390_PCIE_SHADOW_REG_INTER_0 0x1E05000 #define QCA6390_PCIE_SHADOW_REG_HUNG 0x1E050A8 #define QDSS_APB_DEC_CSR_BASE 0x1C01000 #define QDSS_APB_DEC_CSR_ETRIRQCTRL_OFFSET 0x6C Loading Loading @@ -157,6 +165,30 @@ static struct cnss_pci_reg qdss_csr[] = { { NULL }, }; static int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv) { u16 device_id; if (pci_priv->pci_link_state == PCI_LINK_DOWN) { cnss_pr_dbg("PCIe link is suspended\n"); return -EIO; } if (pci_priv->pci_link_down_ind) { cnss_pr_err("PCIe link is down\n"); return -EIO; } pci_read_config_word(pci_priv->pci_dev, PCI_DEVICE_ID, &device_id); if (device_id != pci_priv->device_id) { cnss_fatal_err("PCI device ID mismatch, link possibly down, current read ID: 0x%x, record ID: 0x%x\n", device_id, pci_priv->device_id); return -EIO; } return 0; } static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset) { u32 window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK; Loading @@ -171,16 +203,26 @@ static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset) } } static u32 cnss_pci_reg_read(struct cnss_pci_data *pci_priv, u32 offset) static int cnss_pci_reg_read(struct cnss_pci_data *pci_priv, u32 offset, u32 *val) { int ret; ret = cnss_pci_check_link_status(pci_priv); if (ret) return ret; if (pci_priv->pci_dev->device == QCA6174_DEVICE_ID || offset < MAX_UNWINDOWED_ADDRESS) return readl_relaxed(pci_priv->bar + offset); offset < MAX_UNWINDOWED_ADDRESS) { *val = readl_relaxed(pci_priv->bar + offset); return 0; } cnss_pci_select_window(pci_priv, offset); return readl_relaxed(pci_priv->bar + WINDOW_START + *val = readl_relaxed(pci_priv->bar + WINDOW_START + (offset & WINDOW_RANGE_MASK)); return 0; } static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save) Loading Loading @@ -353,30 +395,6 @@ int cnss_pci_link_down(struct device *dev) } EXPORT_SYMBOL(cnss_pci_link_down); static int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv) { u16 device_id; if (pci_priv->pci_link_state == PCI_LINK_DOWN) { cnss_pr_dbg("PCIe link is suspended\n"); return -EIO; } if (pci_priv->pci_link_down_ind) { cnss_pr_err("PCIe link is down\n"); return -EIO; } pci_read_config_word(pci_priv->pci_dev, PCI_DEVICE_ID, &device_id); if (device_id != pci_priv->device_id) { cnss_fatal_err("PCI device ID mismatch, link possibly down, current read ID: 0x%x, record ID: 0x%x\n", device_id, pci_priv->device_id); return -EIO; } return 0; } int cnss_pci_is_device_down(struct device *dev) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); Loading Loading @@ -521,6 +539,45 @@ int cnss_pci_update_status(struct cnss_pci_data *pci_priv, return 0; } static void cnss_pci_dump_shadow_reg(struct cnss_pci_data *pci_priv) { int i, j = 0, array_size = SHADOW_REG_COUNT + SHADOW_REG_INTER_COUNT; gfp_t gfp = GFP_KERNEL; u32 reg_offset; if (cnss_pci_check_link_status(pci_priv)) return; if (in_interrupt() || irqs_disabled()) gfp = GFP_ATOMIC; if (!pci_priv->debug_reg) { pci_priv->debug_reg = devm_kzalloc(&pci_priv->pci_dev->dev, sizeof(*pci_priv->debug_reg) * array_size, gfp); if (!pci_priv->debug_reg) return; } cnss_pr_dbg("Start to dump shadow registers\n"); for (i = 0; i < SHADOW_REG_COUNT; i++, j++) { reg_offset = QCA6390_PCIE_SHADOW_REG_VALUE_0 + i * 4; pci_priv->debug_reg[j].offset = reg_offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &pci_priv->debug_reg[j].val)) return; } for (i = 0; i < SHADOW_REG_INTER_COUNT; i++, j++) { reg_offset = QCA6390_PCIE_SHADOW_REG_INTER_0 + i * 4; pci_priv->debug_reg[j].offset = reg_offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &pci_priv->debug_reg[j].val)) return; } } #ifdef CONFIG_CNSS2_DEBUG static void cnss_pci_collect_dump(struct cnss_pci_data *pci_priv) { Loading Loading @@ -1705,6 +1762,8 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv) if (!plat_priv) return -ENODEV; cnss_pci_dump_shadow_reg(pci_priv); ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_TRIGGER_RDDM); if (ret) { cnss_fatal_err("Failed to trigger RDDM, err = %d\n", ret); Loading Loading @@ -2171,15 +2230,19 @@ static void cnss_pci_dump_qdss_reg(struct cnss_pci_data *pci_priv) if (in_interrupt() || irqs_disabled()) gfp = GFP_ATOMIC; if (!plat_priv->qdss_reg) if (!plat_priv->qdss_reg) { plat_priv->qdss_reg = devm_kzalloc(&pci_priv->pci_dev->dev, sizeof(*plat_priv->qdss_reg) * array_size, gfp); if (!plat_priv->qdss_reg) return; } for (i = 0; qdss_csr[i].name; i++) { reg_offset = QDSS_APB_DEC_CSR_BASE + qdss_csr[i].offset; plat_priv->qdss_reg[i] = cnss_pci_reg_read(pci_priv, reg_offset); if (cnss_pci_reg_read(pci_priv, reg_offset, &plat_priv->qdss_reg[i])) return; cnss_pr_dbg("%s[0x%x] = 0x%x\n", qdss_csr[i].name, reg_offset, plat_priv->qdss_reg[i]); } Loading @@ -2190,7 +2253,7 @@ static void cnss_pci_dump_ce_reg(struct cnss_pci_data *pci_priv, { int i; u32 ce_base = ce * QCA6390_CE_REG_INTERVAL; u32 reg_offset; u32 reg_offset, val; switch (ce) { case CNSS_CE_09: Loading @@ -2198,26 +2261,29 @@ static void cnss_pci_dump_ce_reg(struct cnss_pci_data *pci_priv, for (i = 0; ce_src[i].name; i++) { reg_offset = QCA6390_CE_SRC_RING_REG_BASE + ce_base + ce_src[i].offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &val)) return; cnss_pr_dbg("CE_%02d_%s[0x%x] = 0x%x\n", ce, ce_src[i].name, reg_offset, cnss_pci_reg_read(pci_priv, reg_offset)); ce, ce_src[i].name, reg_offset, val); } for (i = 0; ce_dst[i].name; i++) { reg_offset = QCA6390_CE_DST_RING_REG_BASE + ce_base + ce_dst[i].offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &val)) return; cnss_pr_dbg("CE_%02d_%s[0x%x] = 0x%x\n", ce, ce_dst[i].name, reg_offset, cnss_pci_reg_read(pci_priv, reg_offset)); ce, ce_dst[i].name, reg_offset, val); } break; case CNSS_CE_COMMON: for (i = 0; ce_cmn[i].name; i++) { reg_offset = QCA6390_CE_COMMON_REG_BASE + ce_cmn[i].offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &val)) return; cnss_pr_dbg("CE_COMMON_%s[0x%x] = 0x%x\n", ce_cmn[i].name, reg_offset, cnss_pci_reg_read(pci_priv, reg_offset)); ce_cmn[i].name, reg_offset, val); } break; default: Loading drivers/net/wireless/cnss2/pci.h +6 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,11 @@ struct cnss_pci_reg { u32 offset; }; struct cnss_pci_debug_reg { u32 offset; u32 val; }; struct cnss_pci_data { struct pci_dev *pci_dev; struct cnss_plat_data *plat_priv; Loading Loading @@ -72,6 +77,7 @@ struct cnss_pci_data { u32 remap_window; struct timer_list dev_rddm_timer; u8 disable_pc; struct cnss_pci_debug_reg *debug_reg; }; static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data) Loading Loading
drivers/net/wireless/cnss2/pci.c +104 −38 Original line number Diff line number Diff line Loading @@ -95,6 +95,14 @@ static DEFINE_SPINLOCK(pci_link_down_lock); #define QCA6390_CE_REG_INTERVAL 0x2000 #define SHADOW_REG_COUNT 36 #define QCA6390_PCIE_SHADOW_REG_VALUE_0 0x1E03024 #define QCA6390_PCIE_SHADOW_REG_VALUE_35 0x1E030B0 #define SHADOW_REG_INTER_COUNT 43 #define QCA6390_PCIE_SHADOW_REG_INTER_0 0x1E05000 #define QCA6390_PCIE_SHADOW_REG_HUNG 0x1E050A8 #define QDSS_APB_DEC_CSR_BASE 0x1C01000 #define QDSS_APB_DEC_CSR_ETRIRQCTRL_OFFSET 0x6C Loading Loading @@ -157,6 +165,30 @@ static struct cnss_pci_reg qdss_csr[] = { { NULL }, }; static int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv) { u16 device_id; if (pci_priv->pci_link_state == PCI_LINK_DOWN) { cnss_pr_dbg("PCIe link is suspended\n"); return -EIO; } if (pci_priv->pci_link_down_ind) { cnss_pr_err("PCIe link is down\n"); return -EIO; } pci_read_config_word(pci_priv->pci_dev, PCI_DEVICE_ID, &device_id); if (device_id != pci_priv->device_id) { cnss_fatal_err("PCI device ID mismatch, link possibly down, current read ID: 0x%x, record ID: 0x%x\n", device_id, pci_priv->device_id); return -EIO; } return 0; } static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset) { u32 window = (offset >> WINDOW_SHIFT) & WINDOW_VALUE_MASK; Loading @@ -171,16 +203,26 @@ static void cnss_pci_select_window(struct cnss_pci_data *pci_priv, u32 offset) } } static u32 cnss_pci_reg_read(struct cnss_pci_data *pci_priv, u32 offset) static int cnss_pci_reg_read(struct cnss_pci_data *pci_priv, u32 offset, u32 *val) { int ret; ret = cnss_pci_check_link_status(pci_priv); if (ret) return ret; if (pci_priv->pci_dev->device == QCA6174_DEVICE_ID || offset < MAX_UNWINDOWED_ADDRESS) return readl_relaxed(pci_priv->bar + offset); offset < MAX_UNWINDOWED_ADDRESS) { *val = readl_relaxed(pci_priv->bar + offset); return 0; } cnss_pci_select_window(pci_priv, offset); return readl_relaxed(pci_priv->bar + WINDOW_START + *val = readl_relaxed(pci_priv->bar + WINDOW_START + (offset & WINDOW_RANGE_MASK)); return 0; } static int cnss_set_pci_config_space(struct cnss_pci_data *pci_priv, bool save) Loading Loading @@ -353,30 +395,6 @@ int cnss_pci_link_down(struct device *dev) } EXPORT_SYMBOL(cnss_pci_link_down); static int cnss_pci_check_link_status(struct cnss_pci_data *pci_priv) { u16 device_id; if (pci_priv->pci_link_state == PCI_LINK_DOWN) { cnss_pr_dbg("PCIe link is suspended\n"); return -EIO; } if (pci_priv->pci_link_down_ind) { cnss_pr_err("PCIe link is down\n"); return -EIO; } pci_read_config_word(pci_priv->pci_dev, PCI_DEVICE_ID, &device_id); if (device_id != pci_priv->device_id) { cnss_fatal_err("PCI device ID mismatch, link possibly down, current read ID: 0x%x, record ID: 0x%x\n", device_id, pci_priv->device_id); return -EIO; } return 0; } int cnss_pci_is_device_down(struct device *dev) { struct cnss_plat_data *plat_priv = cnss_bus_dev_to_plat_priv(dev); Loading Loading @@ -521,6 +539,45 @@ int cnss_pci_update_status(struct cnss_pci_data *pci_priv, return 0; } static void cnss_pci_dump_shadow_reg(struct cnss_pci_data *pci_priv) { int i, j = 0, array_size = SHADOW_REG_COUNT + SHADOW_REG_INTER_COUNT; gfp_t gfp = GFP_KERNEL; u32 reg_offset; if (cnss_pci_check_link_status(pci_priv)) return; if (in_interrupt() || irqs_disabled()) gfp = GFP_ATOMIC; if (!pci_priv->debug_reg) { pci_priv->debug_reg = devm_kzalloc(&pci_priv->pci_dev->dev, sizeof(*pci_priv->debug_reg) * array_size, gfp); if (!pci_priv->debug_reg) return; } cnss_pr_dbg("Start to dump shadow registers\n"); for (i = 0; i < SHADOW_REG_COUNT; i++, j++) { reg_offset = QCA6390_PCIE_SHADOW_REG_VALUE_0 + i * 4; pci_priv->debug_reg[j].offset = reg_offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &pci_priv->debug_reg[j].val)) return; } for (i = 0; i < SHADOW_REG_INTER_COUNT; i++, j++) { reg_offset = QCA6390_PCIE_SHADOW_REG_INTER_0 + i * 4; pci_priv->debug_reg[j].offset = reg_offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &pci_priv->debug_reg[j].val)) return; } } #ifdef CONFIG_CNSS2_DEBUG static void cnss_pci_collect_dump(struct cnss_pci_data *pci_priv) { Loading Loading @@ -1705,6 +1762,8 @@ int cnss_pci_force_fw_assert_hdlr(struct cnss_pci_data *pci_priv) if (!plat_priv) return -ENODEV; cnss_pci_dump_shadow_reg(pci_priv); ret = cnss_pci_set_mhi_state(pci_priv, CNSS_MHI_TRIGGER_RDDM); if (ret) { cnss_fatal_err("Failed to trigger RDDM, err = %d\n", ret); Loading Loading @@ -2171,15 +2230,19 @@ static void cnss_pci_dump_qdss_reg(struct cnss_pci_data *pci_priv) if (in_interrupt() || irqs_disabled()) gfp = GFP_ATOMIC; if (!plat_priv->qdss_reg) if (!plat_priv->qdss_reg) { plat_priv->qdss_reg = devm_kzalloc(&pci_priv->pci_dev->dev, sizeof(*plat_priv->qdss_reg) * array_size, gfp); if (!plat_priv->qdss_reg) return; } for (i = 0; qdss_csr[i].name; i++) { reg_offset = QDSS_APB_DEC_CSR_BASE + qdss_csr[i].offset; plat_priv->qdss_reg[i] = cnss_pci_reg_read(pci_priv, reg_offset); if (cnss_pci_reg_read(pci_priv, reg_offset, &plat_priv->qdss_reg[i])) return; cnss_pr_dbg("%s[0x%x] = 0x%x\n", qdss_csr[i].name, reg_offset, plat_priv->qdss_reg[i]); } Loading @@ -2190,7 +2253,7 @@ static void cnss_pci_dump_ce_reg(struct cnss_pci_data *pci_priv, { int i; u32 ce_base = ce * QCA6390_CE_REG_INTERVAL; u32 reg_offset; u32 reg_offset, val; switch (ce) { case CNSS_CE_09: Loading @@ -2198,26 +2261,29 @@ static void cnss_pci_dump_ce_reg(struct cnss_pci_data *pci_priv, for (i = 0; ce_src[i].name; i++) { reg_offset = QCA6390_CE_SRC_RING_REG_BASE + ce_base + ce_src[i].offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &val)) return; cnss_pr_dbg("CE_%02d_%s[0x%x] = 0x%x\n", ce, ce_src[i].name, reg_offset, cnss_pci_reg_read(pci_priv, reg_offset)); ce, ce_src[i].name, reg_offset, val); } for (i = 0; ce_dst[i].name; i++) { reg_offset = QCA6390_CE_DST_RING_REG_BASE + ce_base + ce_dst[i].offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &val)) return; cnss_pr_dbg("CE_%02d_%s[0x%x] = 0x%x\n", ce, ce_dst[i].name, reg_offset, cnss_pci_reg_read(pci_priv, reg_offset)); ce, ce_dst[i].name, reg_offset, val); } break; case CNSS_CE_COMMON: for (i = 0; ce_cmn[i].name; i++) { reg_offset = QCA6390_CE_COMMON_REG_BASE + ce_cmn[i].offset; if (cnss_pci_reg_read(pci_priv, reg_offset, &val)) return; cnss_pr_dbg("CE_COMMON_%s[0x%x] = 0x%x\n", ce_cmn[i].name, reg_offset, cnss_pci_reg_read(pci_priv, reg_offset)); ce_cmn[i].name, reg_offset, val); } break; default: Loading
drivers/net/wireless/cnss2/pci.h +6 −0 Original line number Diff line number Diff line Loading @@ -42,6 +42,11 @@ struct cnss_pci_reg { u32 offset; }; struct cnss_pci_debug_reg { u32 offset; u32 val; }; struct cnss_pci_data { struct pci_dev *pci_dev; struct cnss_plat_data *plat_priv; Loading Loading @@ -72,6 +77,7 @@ struct cnss_pci_data { u32 remap_window; struct timer_list dev_rddm_timer; u8 disable_pc; struct cnss_pci_debug_reg *debug_reg; }; static inline void cnss_set_pci_priv(struct pci_dev *pci_dev, void *data) Loading