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

Commit b9ea04a9 authored by Tony Truong's avatar Tony Truong Committed by Yan He
Browse files

msm: pcie: add PCIe AER support



Add PCIe Advance Error Reporting support in PCIe bus driver to log
the error reports from root complex and endpoint devices, which
helps investigate the stability of PCIe system.

Change-Id: I543f6fc5c2f9f3953e505454efe79a1dbbae75ac
Signed-off-by: default avatarTony Truong <truong@codeaurora.org>
parent 63bb07f2
Loading
Loading
Loading
Loading
+171 −0
Original line number Diff line number Diff line
@@ -176,6 +176,7 @@
#define PCIE20_ELBI_SYS_STTS		 0x08

#define PCIE20_CAP			   0x70
#define PCIE20_CAP_DEVCTRLSTATUS	(PCIE20_CAP + 0x08)
#define PCIE20_CAP_LINKCTRLSTATUS	(PCIE20_CAP + 0x10)

#define PCIE20_COMMAND_STATUS	    0x04
@@ -201,9 +202,17 @@
#define PCIE20_CTRL1_TYPE_CFG0		0x04
#define PCIE20_CTRL1_TYPE_CFG1		0x05

#define PCIE20_CAP_ID			0x10
#define L1SUB_CAP_ID			0x1E

#define PCIE_CAP_PTR_OFFSET		0x34
#define PCIE_EXT_CAP_OFFSET		0x100

#define PCIE20_AER_UNCORR_ERR_STATUS_REG	0x104
#define PCIE20_AER_CORR_ERR_STATUS_REG		0x110
#define PCIE20_AER_ROOT_ERR_STATUS_REG		0x130
#define PCIE20_AER_ERR_SRC_ID_REG		0x134

#define PCIE_VENDOR_ID_RCP		 0x17cb
#define PCIE_DEVICE_ID_RCP		 0x0300

@@ -2436,6 +2445,13 @@ static void msm_pcie_config_controller(struct msm_pcie_dev_t *dev)

	PCIE_DBG2(dev, "Updated PCIE20_ACK_F_ASPM_CTRL_REG:0x%x\n",
		readl_relaxed(dev->dm_core + PCIE20_ACK_F_ASPM_CTRL_REG));

	/* Enable AER on RC */
	msm_pcie_write_mask(dev->dm_core +  PCIE20_CAP_DEVCTRLSTATUS, 0,
					BIT(3)|BIT(2)|BIT(1)|BIT(0));

	PCIE_DBG(dev, "RC's PCIE20_CAP_DEVCTRLSTATUS:0x%x\n",
		readl_relaxed(dev->dm_core + PCIE20_CAP_DEVCTRLSTATUS));
}

static void msm_pcie_config_link_state(struct msm_pcie_dev_t *dev)
@@ -3123,6 +3139,42 @@ static struct hw_pci msm_pci[MAX_RC_NUM] = {
	},
};

static void msm_pcie_config_ep_aer(struct msm_pcie_dev_t *dev,
					void __iomem *ep_base)
{
	u32 val;
	u32 ep_device_control_status_offset = 0;
	u32 current_offset = readl_relaxed(ep_base + PCIE_CAP_PTR_OFFSET) &
						0xff;

	while (current_offset) {
		val = readl_relaxed(ep_base + current_offset);
		if ((val & 0xff) == PCIE20_CAP_ID) {
			ep_device_control_status_offset =
				current_offset + 0x8;
			break;
		}
		current_offset = (val >> 8) & 0xff;
	}

	if (!ep_device_control_status_offset) {
		PCIE_DBG(dev,
			"RC%d endpoint does not support PCIe cap registers\n",
			dev->rc_idx);
		return;
	}

	PCIE_DBG2(dev, "RC%d: ep_device_control_status_offset: 0x%x\n",
		dev->rc_idx, ep_device_control_status_offset);

	/* Enable AER on EP */
	msm_pcie_write_mask(ep_base + ep_device_control_status_offset, 0,
				BIT(3)|BIT(2)|BIT(1)|BIT(0));

	PCIE_DBG(dev, "EP's PCIE20_CAP_DEVCTRLSTATUS:0x%x\n",
		readl_relaxed(ep_base + ep_device_control_status_offset));
}

static int msm_pcie_config_device_table(struct device *dev, void *pdev)
{
	struct pci_dev *pcidev = to_pci_dev(dev);
@@ -3194,6 +3246,10 @@ static int msm_pcie_config_device_table(struct device *dev, void *pdev)
							PCIE20_COMMAND_STATUS,
							bme | 0x06);
					}

					msm_pcie_config_ep_aer(pcie_dev,
						dev_table_t[index].conf_base);

					break;
				}
			}
@@ -3387,6 +3443,91 @@ out:
	mutex_unlock(&dev->recovery_lock);
}

static irqreturn_t handle_aer_irq(int irq, void *data)
{
	struct msm_pcie_dev_t *dev = data;

	int corr_val, uncorr_val, rc_err_status, ep_corr_val, ep_uncorr_val;
	int i, j, ep_src_bdf;
	void __iomem *ep_base;

	PCIE_DBG(dev, "AER Interrupt handler fired for RC%d irq %d\n",
		dev->rc_idx, irq);

	uncorr_val = readl_relaxed(dev->dm_core +
				PCIE20_AER_UNCORR_ERR_STATUS_REG);
	corr_val = readl_relaxed(dev->dm_core +
				PCIE20_AER_CORR_ERR_STATUS_REG);
	rc_err_status = readl_relaxed(dev->dm_core +
				PCIE20_AER_ROOT_ERR_STATUS_REG);

	PCIE_DBG(dev, "RC's PCIE20_AER_UNCORR_ERR_STATUS_REG:0x%x\n",
			uncorr_val);
	PCIE_DBG(dev, "RC's PCIE20_AER_CORR_ERR_STATUS_REG:0x%x\n",
			corr_val);
	PCIE_DBG(dev, "RC's PCIE20_AER_ROOT_ERR_STATUS_REG:0x%x\n",
			rc_err_status);

	if (dev->link_status == MSM_PCIE_LINK_DISABLED) {
		PCIE_DBG(dev, "RC%d link is down\n", dev->rc_idx);
		goto out;
	}

	for (i = 0; i < 2; i++) {
		if (i)
			ep_src_bdf = readl_relaxed(dev->dm_core +
				PCIE20_AER_ERR_SRC_ID_REG) & ~0xffff;
		else
			ep_src_bdf = (readl_relaxed(dev->dm_core +
				PCIE20_AER_ERR_SRC_ID_REG) & 0xffff) << 16;

		if (!ep_src_bdf)
			continue;

		for (j = 0; j < MAX_DEVICE_NUM; j++) {
			if (ep_src_bdf == dev->pcidev_table[j].bdf) {
				PCIE_DBG(dev,
					"PCIe: %s Error from Endpoint: %02x:%02x.%01x\n",
					i ? "Uncorrectable" : "Correctable",
					dev->pcidev_table[j].bdf >> 24,
					dev->pcidev_table[j].bdf >> 19 & 0x1f,
					dev->pcidev_table[j].bdf >> 16 & 0x07);
				ep_base = dev->pcidev_table[j].conf_base;
				break;
			}
		}

		ep_uncorr_val = readl_relaxed(ep_base +
					PCIE20_AER_UNCORR_ERR_STATUS_REG);
		ep_corr_val = readl_relaxed(ep_base +
					PCIE20_AER_CORR_ERR_STATUS_REG);

		PCIE_DBG(dev, "EP's PCIE20_AER_UNCORR_ERR_STATUS_REG:0x%x\n",
				ep_uncorr_val);
		PCIE_DBG(dev, "EP's PCIE20_AER_CORR_ERR_STATUS_REG:0x%x\n",
				ep_corr_val);

		msm_pcie_write_reg_field(ep_base,
				PCIE20_AER_UNCORR_ERR_STATUS_REG,
				0x3fff031, 0x3fff031);
		msm_pcie_write_reg_field(ep_base,
				PCIE20_AER_CORR_ERR_STATUS_REG,
				0xf1c1, 0xf1c1);
	}
out:
	msm_pcie_write_reg_field(dev->dm_core,
			PCIE20_AER_UNCORR_ERR_STATUS_REG,
			0x3fff031, 0x3fff031);
	msm_pcie_write_reg_field(dev->dm_core,
			PCIE20_AER_CORR_ERR_STATUS_REG,
			0xf1c1, 0xf1c1);
	msm_pcie_write_reg_field(dev->dm_core,
			PCIE20_AER_ROOT_ERR_STATUS_REG,
			0x7f, 0x7f);

	return IRQ_HANDLED;
}

static irqreturn_t handle_wake_irq(int irq, void *data)
{
	struct msm_pcie_dev_t *dev = data;
@@ -3792,6 +3933,36 @@ int32_t msm_pcie_irq_init(struct msm_pcie_dev_t *dev)
		return rc;
	}

	/* register handler for AER interrupt */
	rc = devm_request_irq(pdev,
			dev->irq[MSM_PCIE_INT_PLS_ERR].num,
			handle_aer_irq,
			IRQF_TRIGGER_RISING,
			dev->irq[MSM_PCIE_INT_PLS_ERR].name,
			dev);
	if (rc) {
		PCIE_ERR(dev,
			"PCIe: RC%d: Unable to request aer pls_err interrupt: %d\n",
			dev->rc_idx,
			dev->irq[MSM_PCIE_INT_PLS_ERR].num);
		return rc;
	}

	/* register handler for AER legacy interrupt */
	rc = devm_request_irq(pdev,
			dev->irq[MSM_PCIE_INT_AER_LEGACY].num,
			handle_aer_irq,
			IRQF_TRIGGER_RISING,
			dev->irq[MSM_PCIE_INT_AER_LEGACY].name,
			dev);
	if (rc) {
		PCIE_ERR(dev,
			"PCIe: RC%d: Unable to request aer aer_legacy interrupt: %d\n",
			dev->rc_idx,
			dev->irq[MSM_PCIE_INT_AER_LEGACY].num);
		return rc;
	}

	/* register handler for PCIE_WAKE_N interrupt line */
	rc = devm_request_irq(pdev,
			dev->wake_n, handle_wake_irq, IRQF_TRIGGER_FALLING,