lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251028092232.773991-5-niravkumarlaxmidas.rabara@altera.com>
Date: Tue, 28 Oct 2025 17:22:30 +0800
From: niravkumarlaxmidas.rabara@...era.com
To: dinguyen@...nel.org,
	matthew.gerlach@...era.com,
	robh@...nel.org,
	krzk+dt@...nel.org,
	conor+dt@...nel.org,
	bp@...en8.de,
	tony.luck@...el.com
Cc: linux-edac@...r.kernel.org,
	devicetree@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Niravkumar L Rabara <niravkumarlaxmidas.rabara@...era.com>
Subject: [PATCH 4/6] EDAC/altera: Add IO96B ECC support for Agilex5 SoCFPGA

From: Niravkumar L Rabara <niravkumarlaxmidas.rabara@...era.com>

Add EDAC driver support for the two IO96B memory controllers present in
Agilex5 SoCFPGA.

The IO96B controller provides dedicated mailbox registers for status
and control. ECC error injection is handled via Secure Monitor Calls (SMC).

Signed-off-by: Niravkumar L Rabara <niravkumarlaxmidas.rabara@...era.com>
---
 drivers/edac/Kconfig                         |  10 +
 drivers/edac/altera_edac.c                   | 305 ++++++++++++++++---
 drivers/edac/altera_edac.h                   |  42 +++
 include/linux/firmware/intel/stratix10-smc.h |  18 ++
 4 files changed, 326 insertions(+), 49 deletions(-)

diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 39352b9b7a7e..33a9fccde2fe 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -410,6 +410,16 @@ config EDAC_ALTERA_SDRAM
 	  preloader must initialize the SDRAM before loading
 	  the kernel.
 
+config EDAC_ALTERA_IO96B
+	bool "Altera I096B ECC"
+	depends on EDAC_ALTERA=y && ARM64
+	help
+	  Support for SERR and DERR detection and correction on the
+	  IO96B memory controller interface for Altera SoCFPGA.
+
+	  I096B memory controller provides dedicated mailbox registers
+	  for error injection and error information.
+
 config EDAC_ALTERA_L2C
 	bool "Altera L2 Cache ECC"
 	depends on EDAC_ALTERA=y && CACHE_L2X0
diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c
index ee3270bf75e6..a82c3b01be1a 100644
--- a/drivers/edac/altera_edac.c
+++ b/drivers/edac/altera_edac.c
@@ -656,6 +656,19 @@ static const struct file_operations altr_edac_a10_device_inject_fops __maybe_unu
 	.llseek = generic_file_llseek,
 };
 
+#ifdef CONFIG_EDAC_ALTERA_IO96B
+static ssize_t __maybe_unused
+altr_edac_io96b_device_trig(struct file *file, const char __user *user_buf,
+			    size_t count, loff_t *ppos);
+
+static const struct file_operations
+altr_edac_io96b_inject_fops __maybe_unused = {
+	.open = simple_open,
+	.write = altr_edac_io96b_device_trig,
+	.llseek = generic_file_llseek,
+};
+#endif
+
 static ssize_t __maybe_unused
 altr_edac_a10_device_trig2(struct file *file, const char __user *user_buf,
 			   size_t count, loff_t *ppos);
@@ -1121,6 +1134,33 @@ static const struct edac_device_prv_data s10_sdramecc_data = {
 };
 #endif /* CONFIG_EDAC_ALTERA_SDRAM */
 
+/************************IO96B EDAC *************************************/
+
+#ifdef CONFIG_EDAC_ALTERA_IO96B
+static DEFINE_MUTEX(io96b_mb_mutex);
+
+static int altr_agilex5_io96b_ecc_init(struct altr_edac_device_dev *device)
+{
+	u32 ecc_status;
+
+	ecc_status = readl(device->base + IO96B_ECC_ENABLE_INFO_OFST);
+	ecc_status &= GENMASK(1, 0);
+
+	if (!ecc_status) {
+		edac_printk(KERN_ERR, EDAC_DEVICE,
+			    "%s: No ECC present or ECC disabled.\n",
+			    device->edac_dev_name);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static const struct edac_device_prv_data agilex5_io96b_data = {
+	.setup = altr_agilex5_io96b_ecc_init,
+	.inject_fops = &altr_edac_io96b_inject_fops,
+};
+#endif /* CONFIG_EDAC_ALTERA_IO96B */
+
 /*********************** OCRAM EDAC Device Functions *********************/
 
 #ifdef CONFIG_EDAC_ALTERA_OCRAM
@@ -1717,11 +1757,62 @@ static const struct of_device_id altr_edac_a10_device_of_match[] = {
 #endif
 #ifdef CONFIG_EDAC_ALTERA_SDRAM
 	{ .compatible = "altr,sdram-edac-s10", .data = &s10_sdramecc_data },
+#endif
+#ifdef CONFIG_EDAC_ALTERA_IO96B
+	{ .compatible = "altr,socfpga-io96b0-ecc", .data = &agilex5_io96b_data },
+	{ .compatible = "altr,socfpga-io96b1-ecc", .data = &agilex5_io96b_data },
 #endif
 	{},
 };
 MODULE_DEVICE_TABLE(of, altr_edac_a10_device_of_match);
 
+/*
+ * The IO96B EDAC Device Functions differ from the rest of the
+ * ECC peripherals.
+ */
+
+#ifdef CONFIG_EDAC_ALTERA_IO96B
+static ssize_t __maybe_unused
+altr_edac_io96b_device_trig(struct file *file, const char __user *user_buf,
+			    size_t count, loff_t *ppos)
+{
+	struct edac_device_ctl_info *edac_dci = file->private_data;
+	struct altr_edac_device_dev *drvdata = edac_dci->pvt_info;
+	u8 trig_type;
+	u32 val;
+	struct arm_smccc_res result;
+
+	if (!user_buf || get_user(trig_type, user_buf))
+		return -EFAULT;
+
+	mutex_lock(&io96b_mb_mutex);
+	if (readl(drvdata->base + IO96B_CMD_RESP_STATUS_OFST))
+		writel(0, drvdata->base + IO96B_CMD_RESP_STATUS_OFST);
+
+	arm_smccc_smc(INTEL_SIP_SMC_IO96B_INJECT_ECC_ERR,
+		      (trig_type == ALTR_UE_TRIGGER_CHAR) ?
+		      IO96B_DBE_SYNDROME : IO96B_SBE_SYNDROME,
+		      IO96B_CMD_TRIG_ECC_ENJECT_OP, 0, 0, 0, 0, 0, &result);
+
+	writel(IO06B_ECC_SCRUB_INTERVAL, drvdata->base + IO96B_CMD_PARAM_0_OFST);
+	writel(IO06B_ECC_SCRUB_LEN, drvdata->base + IO96B_CMD_PARAM_1_OFST);
+	writel(IO06B_ECC_SCRUB_FULL_MEM, drvdata->base + IO96B_CMD_PARAM_2_OFST);
+	writel(IO96B_CMD_ECC_SCRUB_MODE_0, drvdata->base + IO96B_CMD_REQ_OFST);
+
+	if (readl_relaxed_poll_timeout(drvdata->base + IO96B_ECC_SCRUB_STAT0_OFST,
+				       val, !(val & IO96B_ECC_SCRUB_COMPLETE),
+				       IO96B_ECC_SCRUB_POLL_US,
+				       IO96B_ECC_SCRUB_TIMEOUT))
+		edac_printk(KERN_ALERT, EDAC_DEVICE,
+			    "IO96B ECC Scrubing timeout - Try again.\n");
+
+	writel(0, drvdata->base + IO96B_CMD_RESP_STATUS_OFST);
+	mutex_unlock(&io96b_mb_mutex);
+
+	return count;
+}
+#endif
+
 /*
  * The Arria10 EDAC Device Functions differ from the Cyclone5/Arria5
  * because 2 IRQs are shared among the all ECC peripherals. The ECC
@@ -1819,6 +1910,70 @@ altr_edac_a10_device_trig2(struct file *file, const char __user *user_buf,
 	return count;
 }
 
+static irqreturn_t io96b_irq_handler(int irq, void *dev_id)
+{
+	struct altr_edac_device_dev *dci = dev_id;
+	u32 err_word0;
+	u32 err_word1;
+	u32 cnt = 0;
+	u32 ecc_error_status;
+	u16 err_queue_overflow;
+	u16 err_count = 0;
+	bool dbe = false;
+	enum io96b_error_type error_type;
+	u32 err_queue = IO96B_ECC_ERR_ENTRIES_OFST;
+
+	ecc_error_status = readl(dci->base + IO96B_ECC_ERR_REG_OFST);
+	err_queue_overflow = ecc_error_status & GENMASK(31, 16);
+	err_count = ecc_error_status & GENMASK(15, 0);
+
+	if (!err_queue_overflow) {
+		while (cnt < err_count) {
+			err_word0 = readl(dci->base + err_queue);
+			err_word1 = readl(dci->base + (err_queue + 4));
+
+			error_type = (err_word0 & GENMASK(9, 6)) >> 6;
+			if (error_type == ECC_SINGLE_DBE || error_type == ECC_MULTI_DBE ||
+			    error_type == ECC_WRITE_LINK_DBE ||
+			    error_type == ECC_READ_LINK_DBE ||
+			    error_type == ECC_READ_LINK_RMW_DBE) {
+				edac_printk(KERN_ERR, EDAC_DEVICE,
+					    "%s: DBE: word0:0x%08X, word1:0x%08X\n",
+					    dci->edac_dev_name, err_word0, err_word1);
+				dbe = true;
+			} else {
+				edac_printk(KERN_ERR, EDAC_DEVICE,
+					    "%s: SBE: word0:0x%08X, word1:0x%08X\n",
+					    dci->edac_dev_name, err_word0, err_word1);
+				edac_device_handle_ce(dci->edac_dev, 0, 0,
+						      dci->edac_dev_name);
+			}
+			cnt++;
+			err_queue += 8;
+		}
+		if (dbe)
+			panic("\nEDAC:IO96B[Uncorrectable errors]\n");
+	} else {
+		err_queue_overflow = (err_word0 & GENMASK(9, 6)) >> 6;
+		if (error_type == ECC_SINGLE_DBE || error_type == ECC_MULTI_DBE ||
+		    error_type == ECC_WRITE_LINK_DBE ||
+		    error_type == ECC_READ_LINK_DBE ||
+		    error_type == ECC_READ_LINK_RMW_DBE) {
+			panic("\nEDAC: UE: %s: word0:0x%08X, word1:0x%08X\n",
+			      dci->edac_dev_name, err_word0, err_word1);
+		} else {
+			edac_printk(KERN_ERR, EDAC_DEVICE,
+				    "%s: Buffer Overflow SBE:0x%08X\n",
+				    dci->edac_dev_name, err_queue_overflow);
+			edac_device_handle_ce(dci->edac_dev, 0, 0, dci->edac_dev_name);
+		}
+	}
+
+	//Clear Queue
+	writel(IO96B_ECC_ERROR_QUEUE_CLEAR, dci->base + IO96B_CMD_REQ_OFST);
+	return IRQ_HANDLED;
+}
+
 static void altr_edac_a10_irq_handler(struct irq_desc *desc)
 {
 	int dberr, bit, sm_offset, irq_status;
@@ -1885,6 +2040,8 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
 	struct resource res;
 	int edac_idx;
 	int rc = 0;
+	bool io96b0_ecc = false;
+	bool io96b1_ecc = false;
 	const struct edac_device_prv_data *prv;
 	/* Get matching node and check for valid result */
 	const struct of_device_id *pdev_id =
@@ -1902,11 +2059,15 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
 
 	if (!devres_open_group(edac->dev, altr_edac_a10_device_add, GFP_KERNEL))
 		return -ENOMEM;
-
-	if (of_device_is_compatible(np, "altr,sdram-edac-s10"))
+	if (of_device_is_compatible(np, "altr,socfpga-io96b0-ecc")) {
+		io96b0_ecc = true;
+	} else if (of_device_is_compatible(np, "altr,socfpga-io96b1-ecc")) {
+		io96b1_ecc = true;
+	} else if (of_device_is_compatible(np, "altr,sdram-edac-s10")) {
 		rc = get_s10_sdram_edac_resource(np, &res);
-	else
+	} else {
 		rc = of_address_to_resource(np, 0, &res);
+	}
 
 	if (rc < 0) {
 		edac_printk(KERN_ERR, EDAC_DEVICE,
@@ -1938,10 +2099,22 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
 	dci->mod_name = ecc_name;
 	dci->dev_name = ecc_name;
 
-	altdev->base = devm_ioremap_resource(edac->dev, &res);
-	if (IS_ERR(altdev->base)) {
-		rc = PTR_ERR(altdev->base);
-		goto err_release_group1;
+	if (io96b0_ecc || io96b1_ecc) {
+		rc = of_address_to_resource(np, 0, &res);
+		if (rc)
+			goto err_release_group1;
+
+		altdev->base = ioremap(res.start, resource_size(&res));
+		if (IS_ERR(altdev->base)) {
+			rc = PTR_ERR(altdev->base);
+			goto err_release_group1;
+		}
+	} else {
+		altdev->base = devm_ioremap_resource(edac->dev, &res);
+		if (IS_ERR(altdev->base)) {
+			rc = PTR_ERR(altdev->base);
+			goto err_release_group1;
+		}
 	}
 
 	/* Check specific dependencies for the module */
@@ -1951,26 +2124,70 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
 			goto err_release_group1;
 	}
 
-	altdev->sb_irq = irq_of_parse_and_map(np, 0);
-	if (!altdev->sb_irq) {
-		edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating SBIRQ\n");
-		rc = -ENODEV;
-		goto err_release_group1;
-	}
-	rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler,
-			      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
-			      ecc_name, altdev);
-	if (rc) {
-		edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n");
-		goto err_release_group1;
-	}
+	if (io96b0_ecc) {
+		altdev->io96b0_irq = altdev->edac->io96b0_irq;
+		rc = devm_request_threaded_irq(edac->dev, altdev->io96b0_irq, NULL,
+					       io96b_irq_handler, IRQF_ONESHOT,
+					       ecc_name, altdev);
+		if (rc) {
+			edac_printk(KERN_ERR, EDAC_DEVICE, "No IO96B0 IRQ resource\n");
+			goto err_release_group1;
+		}
+	} else if (io96b1_ecc) {
+		altdev->io96b1_irq = altdev->edac->io96b1_irq;
+		rc = devm_request_threaded_irq(edac->dev, altdev->io96b1_irq, NULL,
+					       io96b_irq_handler, IRQF_ONESHOT,
+					       ecc_name, altdev);
+		if (rc) {
+			edac_printk(KERN_ERR, EDAC_DEVICE, "No IO96B1 IRQ resource\n");
+			goto err_release_group1;
+		}
+	} else {
+		altdev->sb_irq = irq_of_parse_and_map(np, 0);
+		if (!altdev->sb_irq) {
+			edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating SBIRQ\n");
+			rc = -ENODEV;
+			goto err_release_group1;
+		}
+		rc = devm_request_irq(edac->dev, altdev->sb_irq, prv->ecc_irq_handler,
+				      IRQF_ONESHOT | IRQF_TRIGGER_HIGH, ecc_name, altdev);
+		if (rc) {
+			edac_printk(KERN_ERR, EDAC_DEVICE, "No SBERR IRQ resource\n");
+			goto err_release_group1;
+		}
 
 #ifdef CONFIG_64BIT
-	if (of_machine_is_compatible("intel,socfpga-agilex5")) {
+		if (of_machine_is_compatible("intel,socfpga-agilex5")) {
+			altdev->db_irq = irq_of_parse_and_map(np, 1);
+			if (!altdev->db_irq) {
+				edac_printk(KERN_ERR, EDAC_DEVICE,
+					    "Error allocating DBIRQ\n");
+				rc = -ENODEV;
+				goto err_release_group1;
+			}
+			rc = devm_request_irq(edac->dev, altdev->db_irq,
+					      prv->ecc_irq_handler,
+					      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
+					      ecc_name, altdev);
+			if (rc) {
+				edac_printk(KERN_ERR, EDAC_DEVICE,
+					    "No DBERR IRQ resource\n");
+				goto err_release_group1;
+			}
+		} else {
+			/* Use IRQ to determine SError origin instead of assigning IRQ */
+			rc = of_property_read_u32_index(np, "interrupts", 0,
+							&altdev->db_irq);
+			if (rc) {
+				edac_printk(KERN_ERR, EDAC_DEVICE,
+					    "Unable to parse DB IRQ index\n");
+				goto err_release_group1;
+			}
+		}
+#else
 		altdev->db_irq = irq_of_parse_and_map(np, 1);
 		if (!altdev->db_irq) {
-			edac_printk(KERN_ERR, EDAC_DEVICE,
-				    "Error allocating DBIRQ\n");
+			edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating DBIRQ\n");
 			rc = -ENODEV;
 			goto err_release_group1;
 		}
@@ -1979,35 +2196,11 @@ static int altr_edac_a10_device_add(struct altr_arria10_edac *edac,
 				      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
 				      ecc_name, altdev);
 		if (rc) {
-			edac_printk(KERN_ERR, EDAC_DEVICE,
-				    "No DBERR IRQ resource\n");
+			edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
 			goto err_release_group1;
 		}
-	} else {
-		/* Use IRQ to determine SError origin instead of assigning IRQ */
-		rc = of_property_read_u32_index(np, "interrupts", 0,
-						&altdev->db_irq);
-		if (rc) {
-			edac_printk(KERN_ERR, EDAC_DEVICE,
-				    "Unable to parse DB IRQ index\n");
-			goto err_release_group1;
-		}
-	}
-#else
-	altdev->db_irq = irq_of_parse_and_map(np, 1);
-	if (!altdev->db_irq) {
-		edac_printk(KERN_ERR, EDAC_DEVICE, "Error allocating DBIRQ\n");
-		rc = -ENODEV;
-		goto err_release_group1;
-	}
-	rc = devm_request_irq(edac->dev, altdev->db_irq, prv->ecc_irq_handler,
-			      IRQF_ONESHOT | IRQF_TRIGGER_HIGH,
-			      ecc_name, altdev);
-	if (rc) {
-		edac_printk(KERN_ERR, EDAC_DEVICE, "No DBERR IRQ resource\n");
-		goto err_release_group1;
-	}
 #endif
+	}
 
 	rc = edac_device_add_device(dci);
 	if (rc) {
@@ -2198,7 +2391,21 @@ static int altr_edac_a10_probe(struct platform_device *pdev)
 			regmap_write(edac->ecc_mgr_map,
 				     S10_SYSMGR_UE_ADDR_OFST, 0);
 		}
+
+#ifdef CONFIG_EDAC_ALTERA_IO96B
+		edac->io96b0_irq = platform_get_irq_byname(pdev, "io96b0");
+		if (edac->io96b0_irq < 0) {
+			dev_err(&pdev->dev, "No io96b0 IRQ resource\n");
+			return edac->io96b0_irq;
+		}
+		edac->io96b1_irq = platform_get_irq_byname(pdev, "io96b1");
+		if (edac->io96b1_irq < 0) {
+			dev_err(&pdev->dev, "No io96b1 IRQ resource\n");
+			return edac->io96b1_irq;
+		}
+#endif
 	}
+
 #else
 	edac->db_irq = platform_get_irq(pdev, 1);
 	if (edac->db_irq < 0)
diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h
index 7248d24c4908..a2c8b80eefa8 100644
--- a/drivers/edac/altera_edac.h
+++ b/drivers/edac/altera_edac.h
@@ -352,6 +352,44 @@ struct altr_sdram_mc_data {
 #define ECC_READ_EOVR                     0x2
 #define ECC_READ_EDOVR                    0x3
 
+/************ IO96B ECC defines *******/
+#define IO96B_ECC_ENABLE_INFO_OFST		0x240
+#define IO96B_ECC_SCRUB_STAT0_OFST		0x244
+#define IO96B_ECC_ERR_REG_OFST			0x300
+#define IO96B_ECC_ERR_ENTRIES_OFST		0x310
+
+#define IO96B_CMD_RESP_STATUS_OFST		0x45C
+#define IO96B_CMD_RESP_DATA_0_OFST		0x458
+#define IO96B_CMD_RESP_DATA_1_OFST		0x454
+#define IO96B_CMD_RESP_DATA_2_OFST		0x450
+#define IO96B_CMD_REQ_OFST			0x43C
+#define IO96B_CMD_PARAM_0_OFST			0x438
+#define IO96B_CMD_PARAM_1_OFST			0x434
+#define IO96B_CMD_PARAM_2_OFST			0x430
+
+#define IO96B_CMD_TRIG_ECC_ENJECT_OP		0x20040109
+#define IO96B_CMD_ECC_SCRUB_MODE_0		0x20040202
+#define IO96B_ECC_ERROR_QUEUE_CLEAR		0x20040110
+
+#define IO06B_ECC_SCRUB_INTERVAL		0x14
+#define IO06B_ECC_SCRUB_LEN			0x100
+#define IO06B_ECC_SCRUB_FULL_MEM		0x1
+
+#define IO96B_SBE_SYNDROME			0xF4
+#define IO96B_DBE_SYNDROME			0xFF
+
+#define IO96B_ECC_SCRUB_TIMEOUT		400000
+#define IO96B_ECC_SCRUB_POLL_US		500
+#define IO96B_ECC_SCRUB_COMPLETE		BIT(1)
+
+enum io96b_error_type {
+	ECC_SINGLE_DBE = 2,
+	ECC_MULTI_DBE = 3,
+	ECC_WRITE_LINK_DBE = 0xa,
+	ECC_READ_LINK_DBE = 0xc,
+	ECC_READ_LINK_RMW_DBE
+};
+
 struct altr_edac_device_dev;
 
 struct edac_device_prv_data {
@@ -384,6 +422,8 @@ struct altr_edac_device_dev {
 	struct edac_device_ctl_info *edac_dev;
 	struct device ddev;
 	int edac_idx;
+	int io96b0_irq;
+	int io96b1_irq;
 };
 
 struct altr_arria10_edac {
@@ -395,6 +435,8 @@ struct altr_arria10_edac {
 	struct irq_chip		irq_chip;
 	struct list_head	a10_ecc_devices;
 	struct notifier_block	panic_notifier;
+	int io96b0_irq;
+	int io96b1_irq;
 };
 
 #endif	/* #ifndef _ALTERA_EDAC_H */
diff --git a/include/linux/firmware/intel/stratix10-smc.h b/include/linux/firmware/intel/stratix10-smc.h
index ee80ca4bb0d0..283597022e61 100644
--- a/include/linux/firmware/intel/stratix10-smc.h
+++ b/include/linux/firmware/intel/stratix10-smc.h
@@ -620,4 +620,22 @@ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
 #define INTEL_SIP_SMC_FCS_GET_PROVISION_DATA \
 	INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FCS_GET_PROVISION_DATA)
 
+/**
+ * Request INTEL_SIP_SMC_IO96B_INJECT_ECC_ERR
+ * Sync call to inject IO96B ECC Error.
+ *
+ * Call register usage:
+ * a0 INTEL_SIP_SMC_FUNCID_IO96B_INJECT_ECC_ERR
+ * a1 IO96B error syndrome
+ * a2 I096B mailbox command
+ *
+ * Return status:
+ * a0 INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_STATUS_NOT_SUPPORTED or
+ *    INTEL_SIP_SMC_STATUS_ERROR
+ * a1-a3 Not used
+ */
+#define INTEL_SIP_SMC_FUNCID_IO96B_INJECT_ECC_ERR 156
+#define INTEL_SIP_SMC_IO96B_INJECT_ECC_ERR \
+		INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_IO96B_INJECT_ECC_ERR)
+
 #endif
-- 
2.25.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ