linux-edac.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Serge Semin <Sergey.Semin@baikalelectronics.ru>
To: Rob Herring <robh+dt@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
	Michal Simek <michal.simek@xilinx.com>,
	Borislav Petkov <bp@alien8.de>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Tony Luck <tony.luck@intel.com>,
	James Morse <james.morse@arm.com>,
	Robert Richter <rric@kernel.org>
Cc: Serge Semin <Sergey.Semin@baikalelectronics.ru>,
	Serge Semin <fancer.lancer@gmail.com>,
	Alexey Malahov <Alexey.Malahov@baikalelectronics.ru>,
	Michail Ivanov <Michail.Ivanov@baikalelectronics.ru>,
	Pavel Parkhomenko <Pavel.Parkhomenko@baikalelectronics.ru>,
	Punnaiah Choudary Kalluri  <punnaiah.choudary.kalluri@xilinx.com>,
	Manish Narani <manish.narani@xilinx.com>,
	Dinh Nguyen <dinguyen@kernel.org>, Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>,
	<devicetree@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>,
	<linux-edac@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: [PATCH v3 09/13] EDAC/synopsys: Add DFI alert_n IRQ support
Date: Fri, 30 Sep 2022 02:41:17 +0300	[thread overview]
Message-ID: <20220929234121.13955-10-Sergey.Semin@baikalelectronics.ru> (raw)
In-Reply-To: <20220929234121.13955-1-Sergey.Semin@baikalelectronics.ru>

In accordance with [1] DW uMCTL2 DDR controller can generate an IRQ in
case if an attached SDRAM detects a CRC/Parity error. That capability is
mainly applicable for the DDR4 memory which has an additional signals
PARITY/ALERT_n indicating the even SDRAM address/command parity signal and
alert if the parity turns to be not even. But in accordance with [1] at
least the SDRAM address/command parity is calculated irrespective of the
memory protocol and then sent out by means of the dfi_parity_n signal
further to the DDR PHY. So depending on the DDR protocol and the DDR PHY
implementation the CRC/Parity error can be checked at some point
independently from the DDR devices type and then signaled via the
dfi_alert_n line. In anycase it would be very much useful to catch the
event and at least warn the user about problems with the DFI/SDRAM signals
integrity.

So here we suggest to add the DFI CRC/Parity IRQs handling support. First
the IRQ line is requested by the name "dfi_e" (defined in the DT-bindings)
and register its handler in case of the platform with the individual DW
uMCTL2 DDRC IRQs. If individual IRQs are unavailable the common IRQ
handler will call the DFI CRC/Parity event handler. Note the handler
doesn't do much. It just checks the IRQ status, reads the number of
errors, reports the fatal error to the MCI core and clears the IRQ status.
Alas neither the erroneous SDRAM address nor the executed command are
available in this case. Secondly the DFI CRC/Parity IRQ is
enabled/disabled together with the ECC CE/UE interrupts in the controller
probe procedure.  Finally the CRC/Parity capability is advertised by the
EDAC controller capabilities flags.

[1] DesignWare® Cores Enhanced Universal DDR Memory Controller (uMCTL2)
    Databook, Version 3.91a, October 2020, p.131-132

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
---
 drivers/edac/synopsys_edac.c | 78 ++++++++++++++++++++++++++++++++++--
 1 file changed, 75 insertions(+), 3 deletions(-)

diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
index 6a47e53deab5..8d8952826bce 100644
--- a/drivers/edac/synopsys_edac.c
+++ b/drivers/edac/synopsys_edac.c
@@ -80,6 +80,12 @@
 #define ECC_POISON0_OFST		0xB8
 #define ECC_POISON1_OFST		0xBC
 
+/* DDR CRC/Parity register */
+#define DDR_CRCPARCTL0_OFST		0xC0
+#define DDR_CRCPARCTL1_OFST		0xC4
+#define DDR_CRCPARCTL2_OFST		0xC8
+#define DDR_CRCPARSTAT_OFST		0xCC
+
 /* DDR Address map0 Registers */
 #define DDR_ADDRMAP0_OFST		0x200
 
@@ -153,6 +159,13 @@
 #define ECC_CEADDR1_BANK_MASK		GENMASK(23, 16)
 #define ECC_CEADDR1_COL_MASK		GENMASK(11, 0)
 
+/* DDR CRC/Parity register definitions */
+#define DDR_CRCPARCTL0_CLR_ALRT_ERRCNT	BIT(2)
+#define DDR_CRCPARCTL0_CLR_ALRT_ERR	BIT(1)
+#define DDR_CRCPARCTL0_EN_ALRT_IRQ	BIT(0)
+#define DDR_CRCPARSTAT_ALRT_ERR		BIT(16)
+#define DDR_CRCPARSTAT_ALRT_CNT_MASK	GENMASK(15, 0)
+
 /* ECC Poison register shifts */
 #define ECC_POISON0_RANK_MASK		GENMASK(27, 24)
 #define ECC_POISON0_COL_MASK		GENMASK(11, 0)
@@ -829,6 +842,48 @@ static irqreturn_t snps_ue_irq_handler(int irq, void *dev_id)
 	return IRQ_HANDLED;
 }
 
+/**
+ * snps_dfi_irq_handler - DFI CRC/Parity error interrupt handler.
+ * @irq:        IRQ number.
+ * @dev_id:     Device ID.
+ *
+ * Return: IRQ_NONE, if interrupt not set or IRQ_HANDLED otherwise.
+ */
+static irqreturn_t snps_dfi_irq_handler(int irq, void *dev_id)
+{
+	struct mem_ctl_info *mci = dev_id;
+	struct snps_edac_priv *priv = mci->pvt_info;
+	unsigned long flags;
+	u32 regval;
+	u16 ecnt;
+
+	/* Make sure IRQ is caused by an DFI alert error */
+	regval = readl(priv->baseaddr + DDR_CRCPARSTAT_OFST);
+	if (!(regval & DDR_CRCPARSTAT_ALRT_ERR))
+		return IRQ_NONE;
+
+	/* Just a number of CRC/Parity errors is available */
+	ecnt = FIELD_GET(DDR_CRCPARSTAT_ALRT_CNT_MASK, regval);
+
+	/* Report the detected errors with just the custom message */
+	snprintf(priv->message, SNPS_EDAC_MSG_SIZE,
+		 "DFI CRC/Parity error detected on dfi_alert_n");
+
+	edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, ecnt,
+			     0, 0, 0, 0, 0, -1, priv->message, "");
+
+	/* Make sure the DFI alert IRQ status is cleared */
+	spin_lock_irqsave(&priv->lock, flags);
+
+	regval = readl(priv->baseaddr + DDR_CRCPARCTL0_OFST) |
+		 DDR_CRCPARCTL0_CLR_ALRT_ERR | DDR_CRCPARCTL0_CLR_ALRT_ERRCNT;
+	writel(regval, priv->baseaddr + DDR_CRCPARCTL0_OFST);
+
+	spin_unlock_irqrestore(&priv->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
 /**
  * snps_com_irq_handler - Interrupt IRQ signal handler.
  * @irq:        IRQ number.
@@ -844,6 +899,8 @@ static irqreturn_t snps_com_irq_handler(int irq, void *dev_id)
 
 	rc |= snps_ue_irq_handler(irq, dev_id);
 
+	rc |= snps_dfi_irq_handler(irq, dev_id);
+
 	return rc;
 }
 
@@ -859,11 +916,16 @@ static void snps_enable_irq(struct snps_edac_priv *priv)
 		return;
 	}
 
-	/* IRQs Enable/Disable feature has been available since v3.10a */
+	/*
+	 * ECC IRQs Enable/Disable feature has been available since v3.10a,
+	 * while CRC/Parity interrupts control - since v2.10a.
+	 */
 	spin_lock_irqsave(&priv->lock, flags);
 
 	writel(ECC_CTRL_EN_CE_IRQ | ECC_CTRL_EN_UE_IRQ,
 	       priv->baseaddr + ECC_CLR_OFST);
+	writel(DDR_CRCPARCTL0_EN_ALRT_IRQ,
+	       priv->baseaddr + DDR_CRCPARCTL0_OFST);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -883,6 +945,7 @@ static void snps_disable_irq(struct snps_edac_priv *priv)
 	spin_lock_irqsave(&priv->lock, flags);
 
 	writel(0, priv->baseaddr + ECC_CLR_OFST);
+	writel(0, priv->baseaddr + DDR_CRCPARCTL0_OFST);
 
 	spin_unlock_irqrestore(&priv->lock, flags);
 }
@@ -1483,7 +1546,8 @@ static struct mem_ctl_info *snps_mc_create(struct snps_edac_priv *priv)
 	mci->mtype_cap = MEM_FLAG_LPDDR | MEM_FLAG_DDR2 | MEM_FLAG_LPDDR2 |
 			 MEM_FLAG_DDR3 | MEM_FLAG_LPDDR3 |
 			 MEM_FLAG_DDR4 | MEM_FLAG_LPDDR4;
-	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_PARITY;
+	mci->edac_cap = mci->edac_ctl_cap;
 
 	if (priv->info.caps & SNPS_CAP_ECC_SCRUB) {
 		mci->scrub_mode = SCRUB_HW_SRC;
@@ -1493,7 +1557,6 @@ static struct mem_ctl_info *snps_mc_create(struct snps_edac_priv *priv)
 		mci->scrub_cap = SCRUB_FLAG_SW_SRC;
 	}
 
-	mci->edac_cap = EDAC_FLAG_SECDED;
 	mci->ctl_name = "snps_umctl2_ddrc";
 	mci->dev_name = SNPS_EDAC_MOD_STRING;
 	mci->mod_name = SNPS_EDAC_MOD_VER;
@@ -1559,6 +1622,15 @@ static int snps_request_ind_irq(struct mem_ctl_info *mci)
 		return rc;
 	}
 
+	irq = platform_get_irq_byname_optional(priv->pdev, "dfi_e");
+	if (irq > 0) {
+		rc = devm_request_irq(dev, irq, snps_dfi_irq_handler, 0, "dfi_e", mci);
+		if (rc) {
+			edac_printk(KERN_ERR, EDAC_MC, "Failed to request DFI IRQ\n");
+			return rc;
+		}
+	}
+
 	return 0;
 }
 
-- 
2.37.3



  parent reply	other threads:[~2022-10-01  0:21 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-29 23:41 [PATCH v3 00/13] EDAC/synopsys: Add generic resources and Baikal-T1 support Serge Semin
2022-09-29 23:41 ` [PATCH v3 01/13] dt-bindings: memory: snps: Convert the schema to being generic Serge Semin
2022-10-05 13:12   ` Rob Herring
2022-09-29 23:41 ` [PATCH v3 02/13] dt-bindings: memory: Add Baikal-T1 DDRC DT-schema Serge Semin
2022-10-03 13:24   ` Rob Herring
2022-10-05 14:59     ` Krzysztof Kozlowski
2022-10-06 12:26       ` Serge Semin
2022-09-29 23:41 ` [PATCH v3 03/13] EDAC/synopsys: Add multi-ranked memory support Serge Semin
2022-09-29 23:41 ` [PATCH v3 04/13] EDAC/synopsys: Add optional ECC Scrub support Serge Semin
2022-09-29 23:41 ` [PATCH v3 05/13] EDAC/synopsys: Drop ECC poison address from private data Serge Semin
2022-09-29 23:41 ` [PATCH v3 06/13] EDAC/synopsys: Add data poisoning disable support Serge Semin
2022-09-29 23:41 ` [PATCH v3 07/13] EDAC/synopsys: Split up ECC UE/CE IRQs handler Serge Semin
2022-09-29 23:41 ` [PATCH v3 08/13] EDAC/synopsys: Add individual named ECC IRQs support Serge Semin
2022-09-29 23:41 ` Serge Semin [this message]
2022-09-29 23:41 ` [PATCH v3 10/13] EDAC/synopsys: Add reference clocks support Serge Semin
2022-09-29 23:41 ` [PATCH v3 11/13] EDAC/synopsys: Add ECC Scrubber support Serge Semin
2022-09-29 23:41 ` [PATCH v3 12/13] EDAC/synopsys: Drop vendor-specific arch dependency Serge Semin
2022-09-29 23:41 ` [PATCH v3 13/13] EDAC/synopsys: Add Baikal-T1 DDRC support Serge Semin

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=20220929234121.13955-10-Sergey.Semin@baikalelectronics.ru \
    --to=sergey.semin@baikalelectronics.ru \
    --cc=Alexey.Malahov@baikalelectronics.ru \
    --cc=Michail.Ivanov@baikalelectronics.ru \
    --cc=Pavel.Parkhomenko@baikalelectronics.ru \
    --cc=bp@alien8.de \
    --cc=devicetree@vger.kernel.org \
    --cc=dinguyen@kernel.org \
    --cc=fancer.lancer@gmail.com \
    --cc=james.morse@arm.com \
    --cc=krzysztof.kozlowski+dt@linaro.org \
    --cc=krzysztof.kozlowski@linaro.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-edac@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=manish.narani@xilinx.com \
    --cc=mchehab@kernel.org \
    --cc=michal.simek@xilinx.com \
    --cc=punnaiah.choudary.kalluri@xilinx.com \
    --cc=robh+dt@kernel.org \
    --cc=robh@kernel.org \
    --cc=rric@kernel.org \
    --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;
as well as URLs for NNTP newsgroup(s).