From: Dinh Nguyen <dinguyen@kernel.org>
To: bp@alien8.de, tony.luck@intel.com
Cc: dinguyen@kernel.org, rounakdas2025@gmail.com,
niravkumar.l.rabara@altera.com, linux-edac@vger.kernel.org,
linux-kernel@vger.kernel.org, robh@kernel.org,
krzk+dt@kernel.org, conor+dt@kernel.org,
devicetree@vger.kernel.org
Subject: [PATCH 3/4] EDAC/altera: Add support for Agilex5 ECC manager
Date: Mon, 20 Jul 2026 15:14:24 -0500 [thread overview]
Message-ID: <20260720201425.1538771-4-dinguyen@kernel.org> (raw)
In-Reply-To: <20260720201425.1538771-1-dinguyen@kernel.org>
Add a new compatible "altr,socfpga-agilex5-ecc-manager" to the Arria10
EDAC manager driver. Unlike Stratix10/Agilex7, the Agilex5 ECC manager
exposes up to 7 named interrupts on its DT node:
global_sbe - aggregate single-bit error (chained, drives IRQ domain)
global_dbe - aggregate double-bit error (chained; DBE is no longer
delivered exclusively through Asynchronous SError)
io96b0 - IO96B0 DRAM controller ECC
io96b1 - IO96B1 DRAM controller ECC
sdm_qspi_sbe - SDM QSPI single-bit error
sdm_qspi_dbe - SDM QSPI double-bit error
sdm_seu - SDM single-event-upset
On Agilex5, retrieve all seven interrupts by name via
platform_get_irq_byname_optional() and stash them in a new
agilex5_irqs[] array on struct altr_arria10_edac so subsequent
peripheral support (IO96B, SDM QSPI, CRAM SEU) can consume them without
re-parsing the DT. Only global_sbe is mandatory; the rest are optional.
global_sbe is wired up as the chained SBE handler (replacing the legacy
index-0 lookup). When present, global_dbe is hooked into the same
altr_edac_a10_irq_handler() so that the existing sb_irq/db_irq demux
routes DBE events through the manager's IRQ domain. The SError-based
panic notifier path is preserved as a fall-back.
Legacy A10/S10 probe paths are unchanged.
Assisted-by: Cursor:claude-sonnet-4.7
Signed-off-by: Dinh Nguyen <dinguyen@kernel.org>
---
drivers/edac/altera_edac.c | 85 ++++++++++++++++++++++++++++++++++++--
drivers/edac/altera_edac.h | 29 +++++++++++++
2 files changed, 110 insertions(+), 4 deletions(-)
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index 8a5b08e0d0583..44da63ef5d71e 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -1507,7 +1507,7 @@ static int altr_portb_setup(struct altr_edac_device_dev *device)
int edac_idx, rc;
struct device_node *np;
const struct edac_device_prv_data *prv = &a10_sdmmceccb_data;
- unsigned long flag = {unsigned long)device->edac->flag;
+ unsigned long flag = (unsigned long)device->edac->flag;
rc = altr_check_ecc_deps(device);
if (rc)
@@ -2111,11 +2111,63 @@ static int s10_edac_dberr_handler(struct notifier_block *this,
return NOTIFY_DONE;
}
+/*
+ * Ordered table of named interrupts published by an
+ * "altr,socfpga-agilex5-ecc-manager" device tree node. Indices match
+ * enum altr_agilex5_irq_idx. Only "global_sbe" is mandatory; the rest are
+ * optional so platforms can omit interrupts for unused subsystems.
+ */
+static const char * const altr_agilex5_irq_names[ALTR_AGILEX5_NUM_IRQS] = {
+ [ALTR_AGILEX5_IRQ_GLOBAL_SBE] = "global_sbe",
+ [ALTR_AGILEX5_IRQ_GLOBAL_DBE] = "global_dbe",
+ [ALTR_AGILEX5_IRQ_IO96B0] = "io96b0",
+ [ALTR_AGILEX5_IRQ_IO96B1] = "io96b1",
+ [ALTR_AGILEX5_IRQ_SDM_QSPI_SBE] = "sdm_qspi_sbe",
+ [ALTR_AGILEX5_IRQ_SDM_QSPI_DBE] = "sdm_qspi_dbe",
+ [ALTR_AGILEX5_IRQ_SDM_SEU] = "sdm_seu",
+};
+
+/*
+ * Populate edac->agilex5_irqs[] from the named interrupts on the manager
+ * platform device. Missing optional interrupts are stored as a negative
+ * errno (-ENXIO) so that subsequent feature code can probe whether the
+ * resource exists. global_sbe is required because it drives the manager's
+ * IRQ domain dispatch path.
+ *
+ * platform_get_irq_byname_optional() can return -EPROBE_DEFER when the
+ * parent irqchip (e.g. the GIC) is not yet probed. Propagate that error
+ * up so the kernel re-tries the probe later instead of permanently
+ * disabling the named interrupt.
+ */
+static int altr_agilex5_get_named_irqs(struct platform_device *pdev,
+ struct altr_arria10_edac *edac)
+{
+ int i, irq;
+
+ for (i = 0; i < ALTR_AGILEX5_NUM_IRQS; i++) {
+ irq = platform_get_irq_byname_optional(pdev,
+ altr_agilex5_irq_names[i]);
+ if (irq == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ edac->agilex5_irqs[i] = irq > 0 ? irq : -ENXIO;
+ }
+
+ if (edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_SBE] < 0) {
+ dev_err(&pdev->dev,
+ "Agilex5 ECC manager missing required 'global_sbe' interrupt\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
/****************** Arria 10 EDAC Probe Function *********************/
static int altr_edac_a10_probe(struct platform_device *pdev)
{
struct altr_arria10_edac *edac;
struct device_node *child;
+ int rc;
edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
if (!edac)
@@ -2151,14 +2203,31 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
return -ENOMEM;
}
- edac->sb_irq = platform_get_irq(pdev, 0);
- if (edac->sb_irq < 0)
- return edac->sb_irq;
+ if (edac->flag == SOCFPGA_AGILEX5) {
+ rc = altr_agilex5_get_named_irqs(pdev, edac);
+ if (rc)
+ return rc;
+
+ edac->sb_irq = edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_SBE];
+ } else {
+ edac->sb_irq = platform_get_irq(pdev, 0);
+ if (edac->sb_irq < 0)
+ return edac->sb_irq;
+ }
irq_set_chained_handler_and_data(edac->sb_irq,
altr_edac_a10_irq_handler,
edac);
+ /*
+ * Unlike Stratix10/Agilex7 (which deliver uncorrectable errors as
+ * Asynchronous SError), Agilex5 routes the global double-bit error
+ * through a dedicated SPI ("global_dbe"). Hook it into the same
+ * chained handler so the existing sb_irq/db_irq demux in
+ * altr_edac_a10_irq_handler() routes DBE events through the manager's
+ * IRQ domain. The panic notifier below is still registered as a
+ * fall-back for any DBEs that escape to SError.
+ */
if (edac->flag == SOCFPGA_S10) {
int dberror, err_addr;
@@ -2181,6 +2250,12 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
regmap_write(edac->ecc_mgr_map,
S10_SYSMGR_UE_ADDR_OFST, 0);
}
+ } else if (edac->flag == SOCFPGA_AGILEX5 &&
+ edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_DBE] >= 0) {
+ edac->db_irq = edac->agilex5_irqs[ALTR_AGILEX5_IRQ_GLOBAL_DBE];
+ irq_set_chained_handler_and_data(edac->db_irq,
+ altr_edac_a10_irq_handler,
+ edac);
} else {
edac->db_irq = platform_get_irq(pdev, 1);
if (edac->db_irq < 0)
@@ -2212,6 +2287,8 @@ static const struct of_device_id altr_edac_a10_of_match[] = {
{ .compatible = "altr,socfpga-a10-ecc-manager" },
{ .compatible = "altr,socfpga-s10-ecc-manager",
.data = (void *)SOCFPGA_S10 },
+ { .compatible = "altr,socfpga-agilex5-ecc-manager",
+ .data = (void *)SOCFPGA_AGILEX5 },
{},
};
MODULE_DEVICE_TABLE(of, altr_edac_a10_of_match);
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 74ab7bfc3e748..30e35da7eb6a1 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -326,6 +326,27 @@ struct altr_sdram_mc_data {
#define S10_DDR0_IRQ_MASK BIT(16)
#define S10_DBE_IRQ_MASK 0x3FFFE
+/************* Agilex5 Defines **************/
+/*
+ * The Agilex5 ECC manager exposes up to 7 named interrupts on the manager
+ * node. global_sbe and global_dbe are aggregate single/double-bit error
+ * interrupts that fan-out through the manager's IRQ domain to the child
+ * peripheral ECCs. The remaining named interrupts are routed directly from
+ * dedicated controllers (IO96B memory controllers and Secure Device Manager)
+ * to the GIC.
+ */
+#define ALTR_AGILEX5_NUM_IRQS 7
+
+enum altr_agilex5_irq_idx {
+ ALTR_AGILEX5_IRQ_GLOBAL_SBE,
+ ALTR_AGILEX5_IRQ_GLOBAL_DBE,
+ ALTR_AGILEX5_IRQ_IO96B0,
+ ALTR_AGILEX5_IRQ_IO96B1,
+ ALTR_AGILEX5_IRQ_SDM_QSPI_SBE,
+ ALTR_AGILEX5_IRQ_SDM_QSPI_DBE,
+ ALTR_AGILEX5_IRQ_SDM_SEU,
+};
+
/* Define ECC Block Offsets for peripherals */
#define ECC_BLK_ADDRESS_OFST 0x40
#define ECC_BLK_RDATA0_OFST 0x44
@@ -398,6 +419,14 @@ struct altr_arria10_edac {
struct list_head a10_ecc_devices;
struct notifier_block panic_notifier;
unsigned long flag;
+
+ /*
+ * Agilex5 ECC manager supports up to ALTR_AGILEX5_NUM_IRQS named
+ * interrupts. Entries are indexed by enum altr_agilex5_irq_idx and
+ * hold the Linux virtual IRQ number, or a negative errno when the
+ * corresponding interrupt was not provided in the device tree.
+ */
+ int agilex5_irqs[ALTR_AGILEX5_NUM_IRQS];
};
#endif /* #ifndef _ALTERA_EDAC_H */
--
2.42.0.411.g813d9a9188
next prev parent reply other threads:[~2026-07-20 20:14 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-20 20:14 [PATCH 0/4] EDAC/altera: Add support for Agilex5 platform Dinh Nguyen
2026-07-20 20:14 ` [PATCH 1/4] dt-bindings: edac: altera: agilex5: document new edac support Dinh Nguyen
2026-07-20 20:21 ` sashiko-bot
2026-07-20 20:14 ` [PATCH 2/4] EDAC/altera: use flag to differentiate 64-bit platforms Dinh Nguyen
2026-07-20 20:30 ` sashiko-bot
2026-07-20 20:14 ` Dinh Nguyen [this message]
2026-07-20 20:25 ` [PATCH 3/4] EDAC/altera: Add support for Agilex5 ECC manager sashiko-bot
2026-07-20 20:14 ` [PATCH 4/4] arm64: dts: socfpga: agilex5: add support for the " Dinh Nguyen
2026-07-20 20:35 ` sashiko-bot
2026-07-20 20:33 ` [PATCH 0/4] EDAC/altera: Add support for Agilex5 platform Borislav Petkov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260720201425.1538771-4-dinguyen@kernel.org \
--to=dinguyen@kernel.org \
--cc=bp@alien8.de \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=krzk+dt@kernel.org \
--cc=linux-edac@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=niravkumar.l.rabara@altera.com \
--cc=robh@kernel.org \
--cc=rounakdas2025@gmail.com \
--cc=tony.luck@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.