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: <1598357182-4226-4-git-send-email-yash.shah@sifive.com>
Date:   Tue, 25 Aug 2020 17:36:22 +0530
From:   Yash Shah <yash.shah@...ive.com>
To:     robh+dt@...nel.org, palmer@...belt.com, paul.walmsley@...ive.com,
        bp@...en8.de, mchehab@...nel.org, tony.luck@...el.com
Cc:     aou@...s.berkeley.edu, james.morse@....com, rrichter@...vell.com,
        devicetree@...r.kernel.org, linux-riscv@...ts.infradead.org,
        linux-kernel@...r.kernel.org, linux-edac@...r.kernel.org,
        sachin.ghadi@...ive.com, Yash Shah <yash.shah@...ive.com>
Subject: [PATCH 3/3] edac: sifive: Add EDAC support for Memory Controller in SiFive SoCs

Add Memory controller EDAC support in exisiting SiFive platform EDAC
driver. It registers for notifier events from the SiFive DDR controller
driver for DDR ECC events.

Signed-off-by: Yash Shah <yash.shah@...ive.com>
---
 drivers/edac/Kconfig       |   2 +-
 drivers/edac/sifive_edac.c | 117 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+), 1 deletion(-)

diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 7b6ec30..f8b3b53 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -462,7 +462,7 @@ config EDAC_ALTERA_SDMMC
 
 config EDAC_SIFIVE
 	bool "Sifive platform EDAC driver"
-	depends on EDAC=y && SIFIVE_L2
+	depends on EDAC=y && (SIFIVE_L2 || SIFIVE_DDR)
 	help
 	  Support for error detection and correction on the SiFive SoCs.
 
diff --git a/drivers/edac/sifive_edac.c b/drivers/edac/sifive_edac.c
index 3a3dcb1..cf032685 100644
--- a/drivers/edac/sifive_edac.c
+++ b/drivers/edac/sifive_edac.c
@@ -11,14 +11,120 @@
 #include <linux/platform_device.h>
 #include "edac_module.h"
 #include <soc/sifive/sifive_l2_cache.h>
+#include <soc/sifive/sifive_ddr.h>
 
 #define DRVNAME "sifive_edac"
+#define SIFIVE_EDAC_MOD_NAME "Sifive ECC Manager"
 
 struct sifive_edac_priv {
 	struct notifier_block notifier;
 	struct edac_device_ctl_info *dci;
 };
 
+struct sifive_edac_mc_priv {
+	struct notifier_block notifier;
+	struct mem_ctl_info *mci;
+};
+
+/**
+ * EDAC MC error callback
+ *
+ * @event: non-zero if unrecoverable.
+ */
+static
+int ecc_mc_err_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+	struct sifive_ddr_priv *priv = ptr;
+	struct sifive_edac_mc_priv *p;
+
+	p = container_of(this, struct sifive_edac_mc_priv, notifier);
+	if (event == SIFIVE_DDR_ERR_TYPE_UE) {
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, p->mci,
+				     priv->error_count, priv->page_frame_number,
+				     priv->offset_in_page, priv->syndrome,
+				     priv->top_layer, priv->mid_layer,
+				     priv->low_layer, p->mci->ctl_name, "");
+	} else if (event == SIFIVE_DDR_ERR_TYPE_CE) {
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, p->mci,
+				     priv->error_count, priv->page_frame_number,
+				     priv->offset_in_page, priv->syndrome,
+				     priv->top_layer, priv->mid_layer,
+				     priv->low_layer, p->mci->ctl_name, "");
+	}
+
+	return NOTIFY_OK;
+}
+
+static int ecc_mc_register(struct platform_device *pdev)
+{
+	struct sifive_edac_mc_priv *p;
+	struct edac_mc_layer layers[1];
+	int ret;
+
+	p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	p->notifier.notifier_call = ecc_mc_err_event;
+	platform_set_drvdata(pdev, p);
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = 1;
+	layers[0].is_virt_csrow = true;
+
+	p->mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
+	if (!p->mci) {
+		dev_err(&pdev->dev, "Failed mem allocation for mc instance\n");
+		return -ENOMEM;
+	}
+
+	p->mci->pdev = &pdev->dev;
+	/* Initialize controller capabilities */
+	p->mci->mtype_cap = MEM_FLAG_DDR4;
+	p->mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+	p->mci->edac_cap = EDAC_FLAG_SECDED;
+	p->mci->scrub_cap = SCRUB_UNKNOWN;
+	p->mci->scrub_mode = SCRUB_HW_PROG;
+	p->mci->ctl_name = dev_name(&pdev->dev);
+	p->mci->dev_name = dev_name(&pdev->dev);
+	p->mci->mod_name = SIFIVE_EDAC_MOD_NAME;
+	p->mci->ctl_page_to_phys = NULL;
+
+	/* Interrupt feature is supported by cadence mc */
+	edac_op_state = EDAC_OPSTATE_INT;
+
+	ret = edac_mc_add_mc(p->mci);
+	if (ret) {
+		edac_printk(KERN_ERR, SIFIVE_EDAC_MOD_NAME,
+			    "Failed to register with EDAC core\n");
+		goto err;
+	}
+
+#ifdef CONFIG_SIFIVE_DDR
+	register_sifive_ddr_error_notifier(&p->notifier);
+#endif
+
+	return 0;
+
+err:
+	edac_mc_free(p->mci);
+
+	return -ENXIO;
+}
+
+static int ecc_mc_unregister(struct platform_device *pdev)
+{
+	struct sifive_edac_mc_priv *p = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_SIFIVE_DDR
+	unregister_sifive_ddr_error_notifier(&p->notifier);
+#endif
+	edac_mc_del_mc(&pdev->dev);
+	edac_mc_free(p->mci);
+
+	return 0;
+}
+
 /**
  * EDAC error callback
  *
@@ -67,7 +173,9 @@ static int ecc_register(struct platform_device *pdev)
 		goto err;
 	}
 
+#ifdef CONFIG_SIFIVE_L2
 	register_sifive_l2_error_notifier(&p->notifier);
+#endif
 
 	return 0;
 
@@ -81,7 +189,9 @@ static int ecc_unregister(struct platform_device *pdev)
 {
 	struct sifive_edac_priv *p = platform_get_drvdata(pdev);
 
+#ifdef CONFIG_SIFIVE_L2
 	unregister_sifive_l2_error_notifier(&p->notifier);
+#endif
 	edac_device_del_device(&pdev->dev);
 	edac_device_free_ctl_info(p->dci);
 
@@ -102,12 +212,19 @@ static int __init sifive_edac_init(void)
 	if (ret)
 		platform_device_unregister(sifive_pdev);
 
+	ret = ecc_mc_register(sifive_pdev);
+	if (ret) {
+		ecc_unregister(sifive_pdev);
+		platform_device_unregister(sifive_pdev);
+	}
+
 	return ret;
 }
 
 static void __exit sifive_edac_exit(void)
 {
 	ecc_unregister(sifive_pdev);
+	ecc_mc_unregister(sifive_pdev);
 	platform_device_unregister(sifive_pdev);
 }
 
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ