[PATCH v2 1/4] PCI: rcar-gen4: Configure AXIINTC if iMSI-RX not used

Manivannan Sadhasivam mani at kernel.org
Tue Jun 30 09:22:09 PDT 2026


On Fri, Jun 19, 2026 at 12:01:59AM +0200, Marek Vasut wrote:
> In case MSI are enabled, but DWC built-in iMSI-RX is not in use, the
> MSI are handled via GIC ITS. Configure all controller MSI registers
> fully.
> 
> Set or clear MSI capability register MSICAP0 MSI enable MSIE bit and
> PCIe Interrupt Status 0 Enable register PCIEINTSTS0EN MSI interrupt
> enable MSI_CTRL_INT bit according to MSI enable state, set both bits
> if MSI are enabled, clear both bits if MSI are disabled.
> 
> If MSI are disabled, or MSI are enabled and iMSI-RX is used, then
> deconfigure AXIINTCADDR and AXIINTCCONT to 0, which disables any
> pass through of MSI TLPs onto the AXI bus and then further into
> GIC ITS translation registers.
> 
> If MSI are enabled and iMSI-RX is not used, the configure AXIINTCADDR
> with target address of GIC ITS translation registers, and configure
> AXIINTCCONT to enable MSI TLP pass through onto AXI bus and into the
> GIC ITS. This specific configuration allows handling of MSI via the
> GIC ITS instead of integrated iMSI-RX.
> 
> Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh at renesas.com>
> Signed-off-by: Marek Vasut <marek.vasut+renesas at mailbox.org>

Same as patch 3, SoB chain is broken. Rest LGTM!

- Mani

> ---
> NOTE: This would not be possible without prior work from Shimoda-san
> ---
> Cc: "Krzysztof Wilczyński" <kwilczynski at kernel.org>
> Cc: Bjorn Helgaas <bhelgaas at google.com>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: Conor Dooley <conor+dt at kernel.org>
> Cc: Geert Uytterhoeven <geert+renesas at glider.be>
> Cc: Krzysztof Kozlowski <krzk+dt at kernel.org>
> Cc: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: Manivannan Sadhasivam <mani at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> Cc: Rob Herring <robh at kernel.org>
> Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh at renesas.com>
> Cc: devicetree at vger.kernel.org
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-doc at vger.kernel.org
> Cc: linux-kernel at vger.kernel.org
> Cc: linux-pci at vger.kernel.org
> Cc: linux-renesas-soc at vger.kernel.org
> ---
> V2: Pull GITS_TRANSLATER address from DT, which also fixes missing +0x40
>     offset of the GITS_TRANSLATER register
> ---
>  drivers/pci/controller/dwc/pcie-rcar-gen4.c | 118 +++++++++++++++++++-
>  1 file changed, 113 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> index 8b03c42f8c84c..6300ab4dc38b3 100644
> --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
> @@ -13,8 +13,11 @@
>  #include <linux/interrupt.h>
>  #include <linux/io.h>
>  #include <linux/iopoll.h>
> +#include <linux/irqchip/arm-gic-v3.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
>  #include <linux/pci.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> @@ -31,6 +34,10 @@
>  #define DEVICE_TYPE_RC		BIT(4)
>  #define BIFUR_MOD_SET_ON	BIT(0)
>  
> +/* MSI Capability */
> +#define MSICAP0			0x0050
> +#define MSICAP0_MSIE		BIT(16)
> +
>  /* PCIe Interrupt Status 0 */
>  #define PCIEINTSTS0		0x0084
>  
> @@ -55,6 +62,14 @@
>  #define APP_HOLD_PHY_RST	BIT(16)
>  #define APP_LTSSM_ENABLE	BIT(0)
>  
> +/* INTC address */
> +#define AXIINTCADDR		0x0a00
> +
> +/* INTC control & mask */
> +#define AXIINTCCONT		0x0a04
> +#define INTC_EN			BIT(31)
> +#define INTC_MASK		GENMASK(11, 2)
> +
>  /* PCIe Power Management Control */
>  #define PCIEPWRMNGCTRL		0x0070
>  #define APP_CLK_REQ_N		BIT(11)
> @@ -305,13 +320,103 @@ static struct rcar_gen4_pcie *rcar_gen4_pcie_alloc(struct platform_device *pdev)
>  	return rcar;
>  }
>  
> +static int rcar_gen4_pcie_host_msi_addr(struct dw_pcie_rp *pp, u32 *msi_addr)
> +{
> +	struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
> +	struct device_node *msi_node = NULL;
> +	struct device *dev = dw->dev;
> +	struct resource res;
> +	u64 addr;
> +	int ret;
> +
> +	/*
> +	 * Either the "msi-parent" or the "msi-map" phandle needs to exist
> +	 * to obtain the MSI node.
> +	 */
> +	of_msi_xlate(dev, &msi_node, 0);
> +	if (!msi_node)
> +		return -ENODEV;
> +
> +	/* Check if "msi-parent" or the "msi-map" points to ARM GICv3 ITS. */
> +	if (!of_device_is_compatible(msi_node, "arm,gic-v3-its"))
> +		return dev_err_probe(dev, -ENODEV, "Compatible MSI controller not found\n");
> +
> +	/* Derive GITS_TRANSLATER address from GICv3 */
> +	ret = of_address_to_resource(msi_node, 0, &res);
> +	if (ret < 0)
> +		return dev_err_probe(dev, ret, "MSI controller resources not obtained\n");
> +
> +	addr = res.start + GITS_TRANSLATER;
> +	if (addr >= SZ_4G)
> +		return dev_err_probe(dev, -EINVAL, "MSI controller address above 32bit range\n");
> +
> +	*msi_addr = addr;
> +	return 0;
> +}
> +
> +static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
> +	struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
> +	u32 val;
> +	int ret;
> +
> +	/* Make sure MSICAP0 MSIE is configured. */
> +	val = dw_pcie_readl_dbi(dw, MSICAP0);
> +	if (pci_msi_enabled())
> +		val |= MSICAP0_MSIE;
> +	else
> +		val &= ~MSICAP0_MSIE;
> +	dw_pcie_writel_dbi(dw, MSICAP0, val);
> +
> +	if (!pci_msi_enabled() || pp->use_imsi_rx) {
> +		/* Clear AXIINTC mapping. */
> +		writel(0, rcar->base + AXIINTCADDR);
> +		writel(0, rcar->base + AXIINTCCONT);
> +	} else {
> +		ret = rcar_gen4_pcie_host_msi_addr(pp, &val);
> +		if (ret)
> +			goto err;
> +
> +		/* Point AXIINTC to GIC ITS and enable. */
> +		writel(val, rcar->base + AXIINTCADDR);
> +		writel(INTC_EN | INTC_MASK, rcar->base + AXIINTCCONT);
> +	}
> +
> +	/* Configure MSI interrupt signal */
> +	val = readl(rcar->base + PCIEINTSTS0EN);
> +	if (pci_msi_enabled())
> +		val |= MSI_CTRL_INT;
> +	else
> +		val &= ~MSI_CTRL_INT;
> +	writel(val, rcar->base + PCIEINTSTS0EN);
> +
> +	return 0;
> +
> +err:
> +	/* Deconfigure MSICAP0 MSIE. */
> +	val = dw_pcie_readl_dbi(dw, MSICAP0);
> +	val &= ~MSICAP0_MSIE;
> +	dw_pcie_writel_dbi(dw, MSICAP0, val);
> +
> +	/* Clear AXIINTC mapping. */
> +	writel(0, rcar->base + AXIINTCADDR);
> +	writel(0, rcar->base + AXIINTCCONT);
> +
> +	/* Deconfigure MSI interrupt signal */
> +	val = readl(rcar->base + PCIEINTSTS0EN);
> +	val &= ~MSI_CTRL_INT;
> +	writel(val, rcar->base + PCIEINTSTS0EN);
> +
> +	return ret;
> +}
> +
>  /* Host mode */
>  static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
>  {
>  	struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
>  	struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
>  	int ret;
> -	u32 val;
>  
>  	gpiod_set_value_cansleep(dw->pe_rst, 1);
>  
> @@ -328,16 +433,19 @@ static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
>  	dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_0, 0x0);
>  	dw_pcie_writel_dbi2(dw, PCI_BASE_ADDRESS_1, 0x0);
>  
> -	/* Enable MSI interrupt signal */
> -	val = readl(rcar->base + PCIEINTSTS0EN);
> -	val |= MSI_CTRL_INT;
> -	writel(val, rcar->base + PCIEINTSTS0EN);
> +	ret = rcar_gen4_pcie_host_msi_init(pp);
> +	if (ret)
> +		goto err;
>  
>  	msleep(PCIE_T_PVPERL_MS);	/* pe_rst requires 100msec delay */
>  
>  	gpiod_set_value_cansleep(dw->pe_rst, 0);
>  
>  	return 0;
> +
> +err:
> +	rcar_gen4_pcie_common_deinit(rcar);
> +	return ret;
>  }
>  
>  static void rcar_gen4_pcie_host_deinit(struct dw_pcie_rp *pp)
> -- 
> 2.53.0
> 

-- 
மணிவண்ணன் சதாசிவம்



More information about the linux-arm-kernel mailing list