@@ -81,6 +81,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
.fix_l1ss = true,
+ .sram_dump = NULL,
},
{
.hw_rev = ATH11K_HW_IPQ6018_HW10,
@@ -129,6 +130,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_suspend = false,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
.fix_l1ss = true,
+ .sram_dump = NULL,
},
{
.name = "qca6390 hw2.0",
@@ -176,6 +178,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.supports_suspend = true,
.hal_desc_sz = sizeof(struct hal_rx_desc_ipq8074),
.fix_l1ss = true,
+ .sram_dump = &sram_dump_qca6390,
},
{
.name = "qcn9074 hw1.0",
@@ -223,6 +226,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_mem_mode = 2,
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9074),
.fix_l1ss = true,
+ .sram_dump = NULL,
},
{
.name = "wcn6855 hw2.0",
@@ -269,6 +273,7 @@ static const struct ath11k_hw_params ath11k_hw_params[] = {
.fw_mem_mode = 0,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn6855),
.fix_l1ss = false,
+ .sram_dump = &sram_dump_wcn6855,
},
};
@@ -707,6 +712,9 @@ static int ath11k_core_soc_create(struct ath11k_base *ab)
goto err_debugfs_reg;
}
+ if (ab->hw_params.sram_dump)
+ ath11k_debugfs_sram_dump_create(ab);
+
ret = ath11k_hif_power_up(ab);
if (ret) {
ath11k_err(ab, "failed to power up :%d\n", ret);
@@ -12,6 +12,7 @@
#include "dp_tx.h"
#include "debugfs_htt_stats.h"
#include "peer.h"
+#include "hif.h"
static const char *htt_bp_umac_ring[HTT_SW_UMAC_RING_IDX_MAX] = {
"REO2SW1_RING",
@@ -1122,3 +1123,66 @@ int ath11k_debugfs_register(struct ath11k *ar)
void ath11k_debugfs_unregister(struct ath11k *ar)
{
}
+
+static int ath11k_open_sram_dump(struct inode *inode, struct file *file)
+{
+ struct ath11k_base *ab = inode->i_private;
+ u8 *buf;
+ u32 start, end;
+ int ret;
+
+ start = ab->hw_params.sram_dump->start;
+ end = ab->hw_params.sram_dump->end;
+
+ buf = vmalloc(end - start + 1);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = ath11k_hif_dump_sram(ab, buf, start, end);
+ if (ret) {
+ ath11k_err(ab, "failed to dump sram: %d\n", ret);
+ vfree(buf);
+ return ret;
+ }
+
+ file->private_data = buf;
+ return 0;
+}
+
+static ssize_t ath11k_read_sram_dump(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath11k_base *ab = file->f_inode->i_private;
+ const char *buf = file->private_data;
+ int len;
+ u32 start, end;
+
+ start = ab->hw_params.sram_dump->start;
+ end = ab->hw_params.sram_dump->end;
+ len = end - start + 1;
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static int ath11k_release_sram_dump(struct inode *inode, struct file *file)
+{
+ vfree(file->private_data);
+ file->private_data = NULL;
+
+ return 0;
+}
+
+static const struct file_operations fops_sram_dump = {
+ .open = ath11k_open_sram_dump,
+ .read = ath11k_read_sram_dump,
+ .release = ath11k_release_sram_dump,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void ath11k_debugfs_sram_dump_create(struct ath11k_base *ab)
+{
+ debugfs_create_file("sram", 0400, ab->debugfs_soc, ab,
+ &fops_sram_dump);
+}
@@ -147,6 +147,7 @@ static inline int ath11k_debugfs_rx_filter(struct ath11k *ar)
void ath11k_debugfs_crash_trigger_create(struct ath11k_base *ab);
void ath11k_debugfs_dp_stats_create(struct ath11k_base *ab);
+void ath11k_debugfs_sram_dump_create(struct ath11k_base *ab);
#else
static inline int ath11k_debugfs_soc_create(struct ath11k_base *ab)
{
@@ -221,6 +222,10 @@ static inline void ath11k_debugfs_crash_trigger_create(struct ath11k_base *ab)
static inline void ath11k_debugfs_dp_stats_create(struct ath11k_base *ab)
{
}
+
+static inline void ath11k_debugfs_sram_dump_create(struct ath11k_base *ab)
+{
+}
#endif /* CONFIG_MAC80211_DEBUGFS*/
#endif /* _ATH11K_DEBUGFS_H_ */
@@ -29,6 +29,7 @@ struct ath11k_hif_ops {
void (*ce_irq_enable)(struct ath11k_base *ab);
void (*ce_irq_disable)(struct ath11k_base *ab);
void (*get_ce_msi_idx)(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx);
+ int (*dump_sram)(struct ath11k_base *ab, u8 *buf, u32 start, u32 end);
};
static inline void ath11k_hif_ce_irq_enable(struct ath11k_base *ab)
@@ -134,4 +135,13 @@ static inline void ath11k_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id,
else
*msi_data_idx = ce_id;
}
+
+static inline int ath11k_hif_dump_sram(struct ath11k_base *ab, u8 *buf,
+ u32 start, u32 end)
+{
+ if (!ab->hif.ops->dump_sram)
+ return -EOPNOTSUPP;
+
+ return ab->hif.ops->dump_sram(ab, buf, start, end);
+}
#endif /* _HIF_H_ */
@@ -2124,3 +2124,13 @@ const struct ath11k_hw_regs wcn6855_regs = {
.pcie_qserdes_sysclk_en_sel = 0x01e0c0ac,
.pcie_pcs_osc_dtct_config_base = 0x01e0c628,
};
+
+const struct ath11k_hw_sram_dump sram_dump_qca6390 = {
+ .start = 0x01400000,
+ .end = 0x0171ffff,
+};
+
+const struct ath11k_hw_sram_dump sram_dump_wcn6855 = {
+ .start = 0x01400000,
+ .end = 0x0177ffff,
+};
@@ -120,6 +120,11 @@ struct ath11k_hw_ring_mask {
u8 host2rxdma[ATH11K_EXT_IRQ_GRP_NUM_MAX];
};
+struct ath11k_hw_sram_dump {
+ u32 start;
+ u32 end;
+};
+
struct ath11k_hw_params {
const char *name;
u16 hw_rev;
@@ -173,6 +178,7 @@ struct ath11k_hw_params {
bool supports_suspend;
u32 hal_desc_sz;
bool fix_l1ss;
+ const struct ath11k_hw_sram_dump *sram_dump;
};
struct ath11k_hw_ops {
@@ -336,4 +342,6 @@ extern const struct ath11k_hw_regs qca6390_regs;
extern const struct ath11k_hw_regs qcn9074_regs;
extern const struct ath11k_hw_regs wcn6855_regs;
+extern const struct ath11k_hw_sram_dump sram_dump_qca6390;
+extern const struct ath11k_hw_sram_dump sram_dump_wcn6855;
#endif
@@ -273,6 +273,35 @@ u32 ath11k_pci_read32(struct ath11k_base *ab, u32 offset)
return val;
}
+static int ath11k_pci_dump_sram(struct ath11k_base *ab, u8 *buf,
+ u32 start, u32 end)
+{
+ struct ath11k_pci *ab_pci = ath11k_pci_priv(ab);
+ u32 i;
+ int ret;
+ bool wakeup_required;
+ u32 *data = (u32 *)buf;
+
+ /* for offset beyond BAR + 4K - 32, may
+ * need to wakeup MHI to access.
+ */
+ wakeup_required = test_bit(ATH11K_PCI_FLAG_INIT_DONE, &ab_pci->flags) &&
+ end >= ACCESS_ALWAYS_OFF;
+ if (wakeup_required) {
+ ret = mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
+ if (ret)
+ ath11k_warn(ab, "%s: failed to wakeup MHI: %d\n", __func__, ret);
+ }
+
+ for (i = start; i < end + 1; i += 4)
+ *data++ = ath11k_pci_do_read32(ab, i);
+
+ if (wakeup_required && !ret)
+ mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
+
+ return 0;
+}
+
static void ath11k_pci_soc_global_reset(struct ath11k_base *ab)
{
u32 val, delay;
@@ -1213,6 +1242,7 @@ static const struct ath11k_hif_ops ath11k_pci_hif_ops = {
.ce_irq_enable = ath11k_pci_hif_ce_irq_enable,
.ce_irq_disable = ath11k_pci_hif_ce_irq_disable,
.get_ce_msi_idx = ath11k_pci_get_ce_msi_idx,
+ .dump_sram = ath11k_pci_dump_sram,
};
static void ath11k_pci_read_hw_version(struct ath11k_base *ab, u32 *major, u32 *minor)