Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e8888c1a authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "cnss2: Dump device PCIe shadow registers for debug purpose"

parents 519c72d3 5d21973f
Loading
Loading
Loading
Loading
+104 −38
Original line number Diff line number Diff line
@@ -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
@@ -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;
@@ -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)
@@ -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);
@@ -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)
{
@@ -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);
@@ -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]);
	}
@@ -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:
@@ -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:
+6 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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)