Re: [PATCH v2 1/4] PCI: rcar-gen4: Configure AXIINTC if iMSI-RX not used
From: Manivannan Sadhasivam
Date: Tue Jun 30 2026 - 12:22:36 EST
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@xxxxxxxxxxx>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@xxxxxxxxxxx>
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@xxxxxxxxxx>
> Cc: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
> Cc: Catalin Marinas <catalin.marinas@xxxxxxx>
> Cc: Conor Dooley <conor+dt@xxxxxxxxxx>
> Cc: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
> Cc: Krzysztof Kozlowski <krzk+dt@xxxxxxxxxx>
> Cc: Lorenzo Pieralisi <lpieralisi@xxxxxxxxxx>
> Cc: Manivannan Sadhasivam <mani@xxxxxxxxxx>
> Cc: Marc Zyngier <maz@xxxxxxxxxx>
> Cc: Rob Herring <robh@xxxxxxxxxx>
> Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
> Cc: devicetree@xxxxxxxxxxxxxxx
> Cc: linux-arm-kernel@xxxxxxxxxxxxxxxxxxx
> Cc: linux-doc@xxxxxxxxxxxxxxx
> Cc: linux-kernel@xxxxxxxxxxxxxxx
> Cc: linux-pci@xxxxxxxxxxxxxxx
> Cc: linux-renesas-soc@xxxxxxxxxxxxxxx
> ---
> 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
>
--
மணிவண்ணன் சதாசிவம்