Commit 3baec684 authored by Jim Quinlan's avatar Jim Quinlan Committed by Lorenzo Pieralisi
Browse files

PCI: brcmstb: Accommodate MSI for older chips

Older BrcmSTB chips do not have a separate register for MSI interrupts; the
MSIs are in a register that also contains unrelated interrupts.  In
addition, the interrupts lie in bits [31..24] for these legacy chips.  This
commit provides common code for both legacy and non-legacy MSI interrupt
registers.

Link: https://lore.kernel.org/r/20200911175232.19016-9-james.quinlan@broadcom.com


Signed-off-by: default avatarJim Quinlan <jquinlan@broadcom.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Reviewed-by: default avatarRob Herring <robh@kernel.org>
Acked-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
parent 52ded9e4
Loading
Loading
Loading
Loading
+49 −21
Original line number Diff line number Diff line
@@ -83,7 +83,8 @@
#define PCIE_MISC_MSI_BAR_CONFIG_HI			0x4048

#define PCIE_MISC_MSI_DATA_CONFIG			0x404c
#define  PCIE_MISC_MSI_DATA_CONFIG_VAL			0xffe06540
#define  PCIE_MISC_MSI_DATA_CONFIG_VAL_32		0xffe06540
#define  PCIE_MISC_MSI_DATA_CONFIG_VAL_8		0xfff86540

#define PCIE_MISC_PCIE_CTRL				0x4064
#define  PCIE_MISC_PCIE_CTRL_PCIE_L23_REQUEST_MASK	0x1
@@ -95,6 +96,9 @@
#define  PCIE_MISC_PCIE_STATUS_PCIE_PHYLINKUP_MASK	0x10
#define  PCIE_MISC_PCIE_STATUS_PCIE_LINK_IN_L23_MASK	0x40

#define PCIE_MISC_REVISION				0x406c
#define  BRCM_PCIE_HW_REV_33				0x0303

#define PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT		0x4070
#define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_LIMIT_MASK	0xfff00000
#define  PCIE_MISC_CPU_2_PCIE_MEM_WIN0_BASE_LIMIT_BASE_MASK	0xfff0
@@ -115,10 +119,14 @@
#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_CLKREQ_DEBUG_ENABLE_MASK	0x2
#define  PCIE_MISC_HARD_PCIE_HARD_DEBUG_SERDES_IDDQ_MASK		0x08000000

#define PCIE_MSI_INTR2_STATUS				0x4500
#define PCIE_MSI_INTR2_CLR				0x4508
#define PCIE_MSI_INTR2_MASK_SET				0x4510
#define PCIE_MSI_INTR2_MASK_CLR				0x4514

#define PCIE_INTR2_CPU_BASE		0x4300
#define PCIE_MSI_INTR2_BASE		0x4500
/* Offsets from PCIE_INTR2_CPU_BASE and PCIE_MSI_INTR2_BASE */
#define  MSI_INT_STATUS			0x0
#define  MSI_INT_CLR			0x8
#define  MSI_INT_MASK_SET		0x10
#define  MSI_INT_MASK_CLR		0x14

#define PCIE_EXT_CFG_DATA				0x8000

@@ -138,6 +146,8 @@
/* PCIe parameters */
#define BRCM_NUM_PCIE_OUT_WINS		0x4
#define BRCM_INT_PCI_MSI_NR		32
#define BRCM_INT_PCI_MSI_LEGACY_NR	8
#define BRCM_INT_PCI_MSI_SHIFT		0

/* MSI target adresses */
#define BRCM_MSI_TARGET_ADDR_LT_4GB	0x0fffffffcULL
@@ -253,6 +263,12 @@ struct brcm_msi {
	int			irq;
	/* used indicates which MSI interrupts have been alloc'd */
	unsigned long		used;
	bool			legacy;
	/* Some chips have MSIs in bits [31..24] of a shared register. */
	int			legacy_shift;
	int			nr; /* No. of MSI available, depends on chip */
	/* This is the base pointer for interrupt status/set/clr regs */
	void __iomem		*intr_base;
};

/* Internal PCIe Host Controller Information.*/
@@ -463,8 +479,10 @@ static void brcm_pcie_msi_isr(struct irq_desc *desc)
	msi = irq_desc_get_handler_data(desc);
	dev = msi->dev;

	status = readl(msi->base + PCIE_MSI_INTR2_STATUS);
	for_each_set_bit(bit, &status, BRCM_INT_PCI_MSI_NR) {
	status = readl(msi->intr_base + MSI_INT_STATUS);
	status >>= msi->legacy_shift;

	for_each_set_bit(bit, &status, msi->nr) {
		virq = irq_find_mapping(msi->inner_domain, bit);
		if (virq)
			generic_handle_irq(virq);
@@ -481,7 +499,7 @@ static void brcm_msi_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)

	msg->address_lo = lower_32_bits(msi->target_addr);
	msg->address_hi = upper_32_bits(msi->target_addr);
	msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL) | data->hwirq;
	msg->data = (0xffff & PCIE_MISC_MSI_DATA_CONFIG_VAL_32) | data->hwirq;
}

static int brcm_msi_set_affinity(struct irq_data *irq_data,
@@ -493,8 +511,9 @@ static int brcm_msi_set_affinity(struct irq_data *irq_data,
static void brcm_msi_ack_irq(struct irq_data *data)
{
	struct brcm_msi *msi = irq_data_get_irq_chip_data(data);
	const int shift_amt = data->hwirq + msi->legacy_shift;

	writel(1 << data->hwirq, msi->base + PCIE_MSI_INTR2_CLR);
	writel(1 << shift_amt, msi->intr_base + MSI_INT_CLR);
}


@@ -510,7 +529,7 @@ static int brcm_msi_alloc(struct brcm_msi *msi)
	int hwirq;

	mutex_lock(&msi->lock);
	hwirq = bitmap_find_free_region(&msi->used, BRCM_INT_PCI_MSI_NR, 0);
	hwirq = bitmap_find_free_region(&msi->used, msi->nr, 0);
	mutex_unlock(&msi->lock);

	return hwirq;
@@ -559,8 +578,7 @@ static int brcm_allocate_domains(struct brcm_msi *msi)
	struct fwnode_handle *fwnode = of_node_to_fwnode(msi->np);
	struct device *dev = msi->dev;

	msi->inner_domain = irq_domain_add_linear(NULL, BRCM_INT_PCI_MSI_NR,
						  &msi_domain_ops, msi);
	msi->inner_domain = irq_domain_add_linear(NULL, msi->nr, &msi_domain_ops, msi);
	if (!msi->inner_domain) {
		dev_err(dev, "failed to create IRQ domain\n");
		return -ENOMEM;
@@ -597,7 +615,10 @@ static void brcm_msi_remove(struct brcm_pcie *pcie)

static void brcm_msi_set_regs(struct brcm_msi *msi)
{
	writel(0xffffffff, msi->base + PCIE_MSI_INTR2_MASK_CLR);
	u32 val = __GENMASK(31, msi->legacy_shift);

	writel(val, msi->intr_base + MSI_INT_MASK_CLR);
	writel(val, msi->intr_base + MSI_INT_CLR);

	/*
	 * The 0 bit of PCIE_MISC_MSI_BAR_CONFIG_LO is repurposed to MSI
@@ -608,8 +629,8 @@ static void brcm_msi_set_regs(struct brcm_msi *msi)
	writel(upper_32_bits(msi->target_addr),
	       msi->base + PCIE_MISC_MSI_BAR_CONFIG_HI);

	writel(PCIE_MISC_MSI_DATA_CONFIG_VAL,
	       msi->base + PCIE_MISC_MSI_DATA_CONFIG);
	val = msi->legacy ? PCIE_MISC_MSI_DATA_CONFIG_VAL_8 : PCIE_MISC_MSI_DATA_CONFIG_VAL_32;
	writel(val, msi->base + PCIE_MISC_MSI_DATA_CONFIG);
}

static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
@@ -634,6 +655,17 @@ static int brcm_pcie_enable_msi(struct brcm_pcie *pcie)
	msi->np = pcie->np;
	msi->target_addr = pcie->msi_target_addr;
	msi->irq = irq;
	msi->legacy = pcie->hw_rev < BRCM_PCIE_HW_REV_33;

	if (msi->legacy) {
		msi->intr_base = msi->base + PCIE_INTR2_CPU_BASE;
		msi->nr = BRCM_INT_PCI_MSI_LEGACY_NR;
		msi->legacy_shift = 24;
	} else {
		msi->intr_base = msi->base + PCIE_MSI_INTR2_BASE;
		msi->nr = BRCM_INT_PCI_MSI_NR;
		msi->legacy_shift = 0;
	}

	ret = brcm_allocate_domains(msi);
	if (ret)
@@ -904,12 +936,6 @@ static int brcm_pcie_setup(struct brcm_pcie *pcie)
	tmp &= ~PCIE_MISC_RC_BAR3_CONFIG_LO_SIZE_MASK;
	writel(tmp, base + PCIE_MISC_RC_BAR3_CONFIG_LO);

	/* Mask all interrupts since we are not handling any yet */
	writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_MASK_SET);

	/* clear any interrupts we find on boot */
	writel(0xffffffff, pcie->base + PCIE_MSI_INTR2_CLR);

	if (pcie->gen)
		brcm_pcie_set_gen(pcie, pcie->gen);

@@ -1253,6 +1279,8 @@ static int brcm_pcie_probe(struct platform_device *pdev)
	if (ret)
		goto fail;

	pcie->hw_rev = readl(pcie->base + PCIE_MISC_REVISION);

	msi_np = of_parse_phandle(pcie->np, "msi-parent", 0);
	if (pci_msi_enabled() && msi_np == pcie->np) {
		ret = brcm_pcie_enable_msi(pcie);