diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst index 014aa1c215a1..b0c68b64f5ac 100644 --- a/Documentation/arch/arm64/silicon-errata.rst +++ b/Documentation/arch/arm64/silicon-errata.rst @@ -352,6 +352,7 @@ stable kernels. +----------------+-----------------+-----------------+-----------------------------+ | Qualcomm Tech. | Kryo4xx Gold | N/A | ARM64_ERRATUM_1286807 | +----------------+-----------------+-----------------+-----------------------------+ +| Renesas | S4/V4H/V4M | N/A | RENESAS_ERRATUM_GEN4GICITS1 | +----------------+-----------------+-----------------+-----------------------------+ | Rockchip | RK3588 | #3588001 | ROCKCHIP_ERRATUM_3588001 | +----------------+-----------------+-----------------+-----------------------------+ diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index b3afe0688919..b9e17ce475e6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1382,6 +1382,15 @@ config NVIDIA_CARMEL_CNP_ERRATUM If unsure, say Y. +config RENESAS_ERRATUM_GEN4GICITS1 + bool "Renesas R-Car Gen4: GIC600 can not access physical addresses above 4 GiB" + default y + help + The Renesas R-Car Gen4 S4/V4H/V4M GIC600 SoC integrations have AXI + addressing limited to the first 32-bit of physical address space. + + If unsure, say Y. + config ROCKCHIP_ERRATUM_3568002 bool "Rockchip 3568002: GIC600 can not access physical addresses higher than 4GB" default y diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index b57d81ad33a0..fdc693602b4e 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -4890,10 +4890,22 @@ static bool __maybe_unused its_enable_quirk_hip09_162100801(void *data) return true; } -static bool __maybe_unused its_enable_rk3568002(void *data) +static const char * const dma_32bit_impaired_platforms[] = { +#ifdef CONFIG_RENESAS_ERRATUM_GEN4GICITS1 + "renesas,r8a779f0", + "renesas,r8a779g0", + "renesas,r8a779h0", +#endif +#ifdef CONFIG_ROCKCHIP_ERRATUM_3568002 + "rockchip,rk3566", + "rockchip,rk3568", +#endif + NULL, +}; + +static bool its_enable_dma32(void *data) { - if (!of_machine_is_compatible("rockchip,rk3566") && - !of_machine_is_compatible("rockchip,rk3568")) + if (!of_machine_compatible_match(dma_32bit_impaired_platforms)) return false; gfp_flags_quirk |= GFP_DMA32; @@ -4968,14 +4980,12 @@ static const struct gic_quirk its_quirks[] = { .property = "dma-noncoherent", .init = its_set_non_coherent, }, -#ifdef CONFIG_ROCKCHIP_ERRATUM_3568002 { - .desc = "ITS: Rockchip erratum RK3568002", + .desc = "ITS: Broken GIC600 integration limited to 32bit PA", .iidr = 0x0201743b, .mask = 0xffffffff, - .init = its_enable_rk3568002, + .init = its_enable_dma32, }, -#endif { } }; diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index 16b60a791a50..dcfbe7e229fd 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -346,7 +346,7 @@ config PCIE_RCAR_GEN4 config PCIE_RCAR_GEN4_HOST tristate "Renesas R-Car Gen4 PCIe controller (host mode)" - depends on ARCH_RENESAS || COMPILE_TEST + depends on ARM64 && (ARCH_RENESAS || COMPILE_TEST) depends on PCI_MSI select PCIE_DW_HOST select PCIE_RCAR_GEN4 @@ -357,7 +357,7 @@ config PCIE_RCAR_GEN4_HOST config PCIE_RCAR_GEN4_EP tristate "Renesas R-Car Gen4 PCIe controller (endpoint mode)" - depends on ARCH_RENESAS || COMPILE_TEST + depends on ARM64 && (ARCH_RENESAS || COMPILE_TEST) depends on PCI_ENDPOINT select PCIE_DW_EP select PCIE_RCAR_GEN4 diff --git a/drivers/pci/controller/dwc/pcie-designware-host.c b/drivers/pci/controller/dwc/pcie-designware-host.c index 06722259d2e3..f5a38e6fd8d7 100644 --- a/drivers/pci/controller/dwc/pcie-designware-host.c +++ b/drivers/pci/controller/dwc/pcie-designware-host.c @@ -587,6 +587,12 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) if (ret) return ret; + if (pci_msi_enabled()) { + pp->use_imsi_rx = !(pp->ops->msi_init || + of_property_present(np, "msi-parent") || + of_property_present(np, "msi-map")); + } + if (pp->ops->init) { ret = pp->ops->init(pp); if (ret) @@ -594,10 +600,6 @@ int dw_pcie_host_init(struct dw_pcie_rp *pp) } if (pci_msi_enabled()) { - pp->use_imsi_rx = !(pp->ops->msi_init || - of_property_present(np, "msi-parent") || - of_property_present(np, "msi-map")); - /* * For the use_imsi_rx case the default assignment is handled * in the dw_pcie_msi_host_init(). diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c index 55ef0da9146c..fbe465a29068 100644 --- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c +++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c @@ -13,8 +13,11 @@ #include #include #include +#include #include #include +#include +#include #include #include #include @@ -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, 3) + /* 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)