Linux EDAC development
 help / color / mirror / Atom feed
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


  parent reply	other threads:[~2026-07-20 20:14 UTC|newest]

Thread overview: 6+ 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:14 ` [PATCH 2/4] EDAC/altera: use flag to differentiate 64-bit platforms Dinh Nguyen
2026-07-20 20:14 ` Dinh Nguyen [this message]
2026-07-20 20:14 ` [PATCH 4/4] arm64: dts: socfpga: agilex5: add support for the ECC manager Dinh Nguyen
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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox