* [PATCH 1/3] dt-bindings: PCI: altera: add binding for Agilex 5
2026-04-24 9:49 [PATCH 0/3] PCI: altera: Add Agilex 5 PCIe Root Port support Mahesh Vaidya
@ 2026-04-24 9:49 ` Mahesh Vaidya
2026-04-25 10:22 ` Krzysztof Kozlowski
2026-04-24 9:49 ` [PATCH 2/3] PCI: altera: fix resource leaks on probe failure Mahesh Vaidya
2026-04-24 9:49 ` [PATCH 3/3] PCI: altera: add Agilex 5 support Mahesh Vaidya
2 siblings, 1 reply; 7+ messages in thread
From: Mahesh Vaidya @ 2026-04-24 9:49 UTC (permalink / raw)
To: joyce.ooi, lpieralisi, kwilczynski, mani, robh, bhelgaas, krzk+dt,
conor+dt
Cc: linux-pci, devicetree, linux-kernel, subhransu.sekhar.prusty,
dinguyen, Mahesh Vaidya
Add the compatible string for the Agilex 5 PCIe Hard IP root port
controller.
Co-developed-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
Co-developed-by: Peter Colberg <peter.colberg@intel.com>
Signed-off-by: Peter Colberg <peter.colberg@intel.com>
Signed-off-by: Mahesh Vaidya <mahesh.vaidya@altera.com>
---
.../bindings/pci/altr,pcie-root-port.yaml | 37 ++++++++++---------
1 file changed, 20 insertions(+), 17 deletions(-)
diff --git a/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
index f516db47ab20..f9c2089bad34 100644
--- a/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
+++ b/Documentation/devicetree/bindings/pci/altr,pcie-root-port.yaml
@@ -8,16 +8,17 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
title: Altera PCIe Root Port
maintainers:
- - Matthew Gerlach <matthew.gerlach@linux.intel.com>
+ - Mahesh Vaidya <mahesh.vaidya@altera.com>
properties:
compatible:
description: Each family of socfpga has its own implementation of the
PCI controller. The altr,pcie-root-port-1.0 is used for the Cyclone5
family of chips. The Stratix10 family of chips is supported by the
- altr,pcie-root-port-2.0. The Agilex family of chips has three,
+ altr,pcie-root-port-2.0. The Agilex7 family of chips has three,
non-register compatible, variants of PCIe Hard IP referred to as the
F-Tile, P-Tile, and R-Tile, depending on the specific chip instance.
+ The altr,pcie-root-port-4.0 is used for the Agilex5 family of chips.
enum:
- altr,pcie-root-port-1.0
@@ -25,20 +26,15 @@ properties:
- altr,pcie-root-port-3.0-f-tile
- altr,pcie-root-port-3.0-p-tile
- altr,pcie-root-port-3.0-r-tile
+ - altr,pcie-root-port-4.0
reg:
- items:
- - description: TX slave port region
- - description: Control register access region
- - description: Hard IP region
minItems: 2
+ maxItems: 3
reg-names:
- items:
- - const: Txs
- - const: Cra
- - const: Hip
minItems: 2
+ maxItems: 3
interrupts:
maxItems: 1
@@ -80,18 +76,25 @@ allOf:
then:
properties:
reg:
- maxItems: 2
-
+ items:
+ - description: TX slave port region
+ - description: Control register access region
reg-names:
- maxItems: 2
-
+ items:
+ - const: Txs
+ - const: Cra
else:
properties:
reg:
- minItems: 3
-
+ items:
+ - description: TX slave port region
+ - description: Control register access region
+ - description: Hard IP region
reg-names:
- minItems: 3
+ items:
+ - const: Txs
+ - const: Cra
+ - const: Hip
unevaluatedProperties: false
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/3] PCI: altera: fix resource leaks on probe failure
2026-04-24 9:49 [PATCH 0/3] PCI: altera: Add Agilex 5 PCIe Root Port support Mahesh Vaidya
2026-04-24 9:49 ` [PATCH 1/3] dt-bindings: PCI: altera: add binding for Agilex 5 Mahesh Vaidya
@ 2026-04-24 9:49 ` Mahesh Vaidya
2026-04-24 12:42 ` Dinh Nguyen
2026-04-24 9:49 ` [PATCH 3/3] PCI: altera: add Agilex 5 support Mahesh Vaidya
2 siblings, 1 reply; 7+ messages in thread
From: Mahesh Vaidya @ 2026-04-24 9:49 UTC (permalink / raw)
To: joyce.ooi, lpieralisi, kwilczynski, mani, robh, bhelgaas, krzk+dt,
conor+dt
Cc: linux-pci, devicetree, linux-kernel, subhransu.sekhar.prusty,
dinguyen, Mahesh Vaidya
The chained IRQ handler is installed in altera_pcie_parse_dt() but
never unregistered on probe failure. If any subsequent step in
altera_pcie_probe() fails, devm frees the pcie struct while the
handler still references it. A subsequent interrupt would trigger
a use-after-free.
The INTx IRQ domain created in altera_pcie_init_irq_domain() is
similarly leaked on probe failure, since the existing cleanup via
altera_pcie_irq_teardown() is only invoked from the remove path.
Move the handler installation from altera_pcie_parse_dt() into
altera_pcie_probe() after the IRQ domain is created, and add a
goto-based error path so altera_pcie_irq_teardown() is called on
any failure after handler installation.
Fixes: 60f2ee5f1472 ("PCI: altera: Add Agilex support")
Signed-off-by: Mahesh Vaidya <mahesh.vaidya@altera.com>
---
drivers/pci/controller/pcie-altera.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
index 3dbb7adc421c..025ba74d1ee2 100644
--- a/drivers/pci/controller/pcie-altera.c
+++ b/drivers/pci/controller/pcie-altera.c
@@ -891,7 +891,6 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
if (pcie->irq < 0)
return pcie->irq;
- irq_set_chained_handler_and_data(pcie->irq, pcie->pcie_data->ops->rp_isr, pcie);
return 0;
}
@@ -1020,6 +1019,11 @@ static int altera_pcie_probe(struct platform_device *pdev)
return ret;
}
+ /* Install chained handler after domain is ready */
+ irq_set_chained_handler_and_data(pcie->irq,
+ pcie->pcie_data->ops->rp_isr,
+ pcie);
+
if (pcie->pcie_data->version == ALTERA_PCIE_V1 ||
pcie->pcie_data->version == ALTERA_PCIE_V2) {
/* clear all interrupts */
@@ -1037,7 +1041,16 @@ static int altera_pcie_probe(struct platform_device *pdev)
bridge->busnr = pcie->root_bus_nr;
bridge->ops = &altera_pcie_ops;
- return pci_host_probe(bridge);
+ ret = pci_host_probe(bridge);
+ if (ret)
+ goto err_teardown_irq;
+
+ return 0;
+
+err_teardown_irq:
+ altera_pcie_irq_teardown(pcie);
+
+ return ret;
}
static void altera_pcie_remove(struct platform_device *pdev)
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 3/3] PCI: altera: add Agilex 5 support
2026-04-24 9:49 [PATCH 0/3] PCI: altera: Add Agilex 5 PCIe Root Port support Mahesh Vaidya
2026-04-24 9:49 ` [PATCH 1/3] dt-bindings: PCI: altera: add binding for Agilex 5 Mahesh Vaidya
2026-04-24 9:49 ` [PATCH 2/3] PCI: altera: fix resource leaks on probe failure Mahesh Vaidya
@ 2026-04-24 9:49 ` Mahesh Vaidya
2026-04-24 15:48 ` Bjorn Helgaas
2 siblings, 1 reply; 7+ messages in thread
From: Mahesh Vaidya @ 2026-04-24 9:49 UTC (permalink / raw)
To: joyce.ooi, lpieralisi, kwilczynski, mani, robh, bhelgaas, krzk+dt,
conor+dt
Cc: linux-pci, devicetree, linux-kernel, subhransu.sekhar.prusty,
dinguyen, Mahesh Vaidya
Add PCIe root port controller support for the Agilex 5 (V4) family
of SoC FPGAs.
The Agilex 5 PCIe Hard IP reuses the same config-space access path
as Agilex 7 (V3). Root port and endpoint configuration reads/writes
use direct MMIO to the HIP and CRA regions.
The difference is in the HIP port-level registers (IRQ status and IRQ
enable). On V3 these are directly mapped through the HIP MMIO window.
On V4 these registers are only reachable through an indirect access
mailbox (CFG REG IA CTRL) in the PCIe Subsystem AXI-Lite interface,
documented in the GTS AXI Streaming IP for PCIe User Guide.
This adds:
- ALTERA_PCIE_V4 version and platform data
- Indirect register read/write helpers using readl_poll_timeout_atomic
- Chained IRQ handler (aglx5_isr) for the V4 interrupt path
- OF match for "altr,pcie-root-port-4.0"
Co-developed-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
Signed-off-by: Matthew Gerlach <matthew.gerlach@linux.intel.com>
Co-developed-by: Peter Colberg <peter.colberg@intel.com>
Signed-off-by: Peter Colberg <peter.colberg@intel.com>
Signed-off-by: Mahesh Vaidya <mahesh.vaidya@altera.com>
---
drivers/pci/controller/pcie-altera.c | 156 ++++++++++++++++++++++++++-
1 file changed, 155 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/controller/pcie-altera.c b/drivers/pci/controller/pcie-altera.c
index 025ba74d1ee2..db8149d84c96 100644
--- a/drivers/pci/controller/pcie-altera.c
+++ b/drivers/pci/controller/pcie-altera.c
@@ -12,6 +12,8 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/init.h>
+#include <linux/bitfield.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_pci.h>
@@ -93,16 +95,36 @@
#define AGLX_CFG_TARGET_LOCAL_2000 2
#define AGLX_CFG_TARGET_LOCAL_3000 3
+/* PCIe subsystem indirect register access */
+#define PCIE_SS_IA_CTL 0xc8 /* control register */
+#define PCIE_SS_IA_FN_NUM 0xcc /* function number */
+#define PCIE_SS_IA_FN_WRDATA 0xd0 /* write data */
+#define PCIE_SS_IA_FN_RDDATA 0xd4 /* read data */
+
+/* PCIE_SS_IA_CTL bitfields */
+#define PCIE_SS_IA_CTL_INITIATE BIT(0)
+#define PCIE_SS_IA_CTL_WRITE BIT(1)
+#define PCIE_SS_IA_CTL_BYTE_EN GENMASK(5, 2)
+#define PCIE_SS_IA_CTL_ADDR GENMASK(31, 6)
+
+/* PCIE_SS_IA_FN_NUM function types */
+#define PCIE_SS_IA_FN_TYPE_HIP 2
+
+#define AGLX5_INDIRECT_SLEEP_US 1
+#define AGLX5_INDIRECT_TIMEOUT_US 1000
+
enum altera_pcie_version {
ALTERA_PCIE_V1 = 0,
ALTERA_PCIE_V2,
ALTERA_PCIE_V3,
+ ALTERA_PCIE_V4,
};
struct altera_pcie {
struct platform_device *pdev;
void __iomem *cra_base;
void __iomem *hip_base;
+ void __iomem *controller_base;
int irq;
u8 root_bus_nr;
struct irq_domain *irq_domain;
@@ -849,6 +871,98 @@ static void aglx_isr(struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+/*
+ * Indirect register access to HIP registers via the PCIe Subsystem
+ * AXI-Lite mailbox, documented in the GTS AXI Streaming IP for PCIe
+ * User Guide. Called from chained IRQ handler (hardirq) and probe
+ * (before handler is installed), so no locking is required.
+ */
+static int aglx5_indirect_readl(const struct altera_pcie *pcie,
+ unsigned int addr, unsigned int *val)
+{
+ unsigned int ctl;
+ int ret;
+
+ writel(PCIE_SS_IA_FN_TYPE_HIP,
+ pcie->controller_base + PCIE_SS_IA_FN_NUM);
+
+ ctl = FIELD_PREP(PCIE_SS_IA_CTL_ADDR, addr >> 2) |
+ PCIE_SS_IA_CTL_BYTE_EN | PCIE_SS_IA_CTL_INITIATE;
+ writel(ctl, (pcie->controller_base + PCIE_SS_IA_CTL));
+
+ ret = readl_poll_timeout_atomic(pcie->controller_base + PCIE_SS_IA_CTL,
+ ctl, !(ctl & PCIE_SS_IA_CTL_INITIATE),
+ AGLX5_INDIRECT_SLEEP_US,
+ AGLX5_INDIRECT_TIMEOUT_US);
+ if (ret)
+ return ret;
+
+ *val = readl(pcie->controller_base + PCIE_SS_IA_FN_RDDATA);
+
+ return 0;
+}
+
+static int aglx5_indirect_writel(const struct altera_pcie *pcie,
+ unsigned int addr, unsigned int val)
+{
+ unsigned int ctl;
+ int ret;
+
+ writel(PCIE_SS_IA_FN_TYPE_HIP,
+ pcie->controller_base + PCIE_SS_IA_FN_NUM);
+ writel(val, pcie->controller_base + PCIE_SS_IA_FN_WRDATA);
+
+ ctl = FIELD_PREP(PCIE_SS_IA_CTL_ADDR, addr >> 2) |
+ PCIE_SS_IA_CTL_BYTE_EN | PCIE_SS_IA_CTL_WRITE |
+ PCIE_SS_IA_CTL_INITIATE;
+ writel(ctl, pcie->controller_base + PCIE_SS_IA_CTL);
+
+ ret = readl_poll_timeout_atomic(pcie->controller_base + PCIE_SS_IA_CTL,
+ ctl, !(ctl & PCIE_SS_IA_CTL_INITIATE),
+ AGLX5_INDIRECT_SLEEP_US,
+ AGLX5_INDIRECT_TIMEOUT_US);
+
+ return ret;
+}
+
+static void aglx5_isr(struct irq_desc *desc)
+{
+ struct irq_chip *chip = irq_desc_get_chip(desc);
+ struct altera_pcie *pcie;
+ struct device *dev;
+ u32 status = 0;
+ int ret;
+
+ chained_irq_enter(chip, desc);
+ pcie = irq_desc_get_handler_data(desc);
+ dev = &pcie->pdev->dev;
+
+ ret = aglx5_indirect_readl(pcie, pcie->pcie_data->port_irq_status_offset, &status);
+ if (ret) {
+ dev_err(dev, "timeout reading IRQ status, masking IRQ\n");
+ disable_irq_nosync(pcie->irq);
+ goto out;
+ }
+
+ if (status & CFG_AER) {
+ ret = generic_handle_domain_irq(pcie->irq_domain, 0);
+ if (ret)
+ dev_err_ratelimited(dev, "unexpected IRQ\n");
+
+ /* W1C: clear the handled bit */
+ ret = aglx5_indirect_writel(pcie,
+ pcie->pcie_data->port_irq_status_offset,
+ CFG_AER);
+ if (ret) {
+ dev_err(dev, "timeout clearing IRQ status, masking IRQ\n");
+ disable_irq_nosync(pcie->irq);
+ }
+ }
+
+out:
+ chained_irq_exit(chip, desc);
+}
+
static int altera_pcie_init_irq_domain(struct altera_pcie *pcie)
{
struct device *dev = &pcie->pdev->dev;
@@ -880,12 +994,19 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie)
return PTR_ERR(pcie->cra_base);
if (pcie->pcie_data->version == ALTERA_PCIE_V2 ||
- pcie->pcie_data->version == ALTERA_PCIE_V3) {
+ pcie->pcie_data->version == ALTERA_PCIE_V3 ||
+ pcie->pcie_data->version == ALTERA_PCIE_V4) {
pcie->hip_base = devm_platform_ioremap_resource_byname(pdev, "Hip");
if (IS_ERR(pcie->hip_base))
return PTR_ERR(pcie->hip_base);
}
+ if (pcie->pcie_data->version == ALTERA_PCIE_V4) {
+ pcie->controller_base = devm_platform_ioremap_resource_byname(pdev, "Txs");
+ if (IS_ERR(pcie->controller_base))
+ return PTR_ERR(pcie->controller_base);
+ }
+
/* setup IRQ */
pcie->irq = platform_get_irq(pdev, 0);
if (pcie->irq < 0)
@@ -924,6 +1045,15 @@ static const struct altera_pcie_ops altera_pcie_ops_3_0 = {
.rp_isr = aglx_isr,
};
+static const struct altera_pcie_ops altera_pcie_ops_4_0 = {
+ .rp_read_cfg = aglx_rp_read_cfg,
+ .rp_write_cfg = aglx_rp_write_cfg,
+ .get_link_status = aglx_altera_pcie_link_up,
+ .ep_read_cfg = aglx_ep_read_cfg,
+ .ep_write_cfg = aglx_ep_write_cfg,
+ .rp_isr = aglx5_isr,
+};
+
static const struct altera_pcie_data altera_pcie_1_0_data = {
.ops = &altera_pcie_ops_1_0,
.cap_offset = 0x80,
@@ -971,6 +1101,20 @@ static const struct altera_pcie_data altera_pcie_3_0_r_tile_data = {
.port_irq_enable_offset = 0x4,
};
+static const struct altera_pcie_data altera_pcie_4_0_data = {
+ .ops = &altera_pcie_ops_4_0,
+ .version = ALTERA_PCIE_V4,
+ .cap_offset = 0x70,
+ .port_conf_offset = 0x14000,
+ /*
+ * Unlike V3 where IRQ offsets are relative to port_conf_offset,
+ * V4 IRQ offsets are absolute addresses in the HIP indirect access
+ * space documented in the GTS AXI Streaming IP for PCIe User Guide.
+ */
+ .port_irq_status_offset = 0x1414c,
+ .port_irq_enable_offset = 0x14150,
+};
+
static const struct of_device_id altera_pcie_of_match[] = {
{.compatible = "altr,pcie-root-port-1.0",
.data = &altera_pcie_1_0_data },
@@ -982,6 +1126,8 @@ static const struct of_device_id altera_pcie_of_match[] = {
.data = &altera_pcie_3_0_p_tile_data },
{.compatible = "altr,pcie-root-port-3.0-r-tile",
.data = &altera_pcie_3_0_r_tile_data },
+ {.compatible = "altr,pcie-root-port-4.0",
+ .data = &altera_pcie_4_0_data },
{},
};
@@ -1035,6 +1181,14 @@ static int altera_pcie_probe(struct platform_device *pdev)
writel(CFG_AER,
pcie->hip_base + pcie->pcie_data->port_conf_offset +
pcie->pcie_data->port_irq_enable_offset);
+ } else if (pcie->pcie_data->version == ALTERA_PCIE_V4) {
+ ret = aglx5_indirect_writel(pcie,
+ pcie->pcie_data->port_irq_enable_offset,
+ CFG_AER);
+ if (ret) {
+ dev_err(dev, "Failed to enable AER IRQ\n");
+ goto err_teardown_irq;
+ }
}
bridge->sysdata = pcie;
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread