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]
Date:   Wed,  9 Nov 2022 15:39:27 +0530
From:   Vivek Yadav <vivek.2311@...sung.com>
To:     rcsekar@...sung.com, krzysztof.kozlowski+dt@...aro.org,
        wg@...ndegger.com, mkl@...gutronix.de, davem@...emloft.net,
        edumazet@...gle.com, kuba@...nel.org, pabeni@...hat.com,
        pankaj.dubey@...sung.com, ravi.patel@...sung.com,
        alim.akhtar@...sung.com, linux-fsd@...la.com, robh+dt@...nel.org
Cc:     linux-can@...r.kernel.org, netdev@...r.kernel.org,
        linux-kernel@...r.kernel.org, linux-arm-kernel@...ts.infradead.org,
        linux-samsung-soc@...r.kernel.org, devicetree@...r.kernel.org,
        aswani.reddy@...sung.com, sriranjani.p@...sung.com,
        Vivek Yadav <vivek.2311@...sung.com>
Subject: [PATCH v2 5/6] can: m_can: Add ECC functionality for message RAM

Whenever MCAN Buffers and FIFOs are stored on message ram, there are
inherent risks of corruption known as single-bit errors.

Enable error correction code (ECC) data integrity check for Message RAM
to create valid ECC checksums.

ECC uses a respective number of bits, which are added to each word as a
parity and that will raise the error signal on the corruption in the
Interrupt Register(IR).

This indicates either bit error detected and Corrected(BEC) or No bit
error detected when reading from Message RAM.

Signed-off-by: Chandrasekar R <rcsekar@...sung.com>
Signed-off-by: Vivek Yadav <vivek.2311@...sung.com>
---
 drivers/net/can/m_can/m_can.c          | 48 +++++++++++++++-
 drivers/net/can/m_can/m_can.h          | 17 ++++++
 drivers/net/can/m_can/m_can_platform.c | 76 ++++++++++++++++++++++++--
 3 files changed, 135 insertions(+), 6 deletions(-)

diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index a776cab1a5a4..ddff615ccad4 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -307,6 +307,14 @@ enum m_can_reg {
 #define TX_EVENT_MM_MASK	GENMASK(31, 24)
 #define TX_EVENT_TXTS_MASK	GENMASK(15, 0)
 
+/* ECC Config Bits */
+#define MCAN_ECC_CFG_VALID    BIT(5)
+#define MCAN_ECC_ENABLE       BIT(3)
+#define MCAN_ECC_INIT_ENABLE  BIT(1)
+#define MCAN_ECC_INIT_DONE    BIT(0)
+#define MCAN_ECC_REG_MASK     GENMASK(5, 0)
+#define MCAN_ECC_INIT_TIMEOUT 100
+
 /* The ID and DLC registers are adjacent in M_CAN FIFO memory,
  * and we can save a (potentially slow) bus round trip by combining
  * reads and writes to them.
@@ -1516,9 +1524,9 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
 	}
 
 	if (cdev->ops->init)
-		cdev->ops->init(cdev);
+		err = cdev->ops->init(cdev);
 
-	return 0;
+	return err;
 }
 
 static void m_can_stop(struct net_device *dev)
@@ -1535,6 +1543,39 @@ static void m_can_stop(struct net_device *dev)
 	cdev->can.state = CAN_STATE_STOPPED;
 }
 
+int m_can_config_mram_ecc_check(struct m_can_classdev *cdev, bool enable)
+{
+	struct  m_can_ecc_regmap *ecc_cfg = &cdev->ecc_cfg_sys;
+	int val, ret;
+
+	val = FIELD_PREP(MCAN_ECC_REG_MASK, MCAN_ECC_ENABLE |
+			 MCAN_ECC_CFG_VALID | MCAN_ECC_INIT_ENABLE);
+	regmap_clear_bits(ecc_cfg->syscon, ecc_cfg->reg, val);
+
+	if (enable) {
+		val = FIELD_PREP(MCAN_ECC_REG_MASK, MCAN_ECC_ENABLE |
+				 MCAN_ECC_INIT_ENABLE);
+		regmap_set_bits(ecc_cfg->syscon, ecc_cfg->reg, val);
+	}
+
+	/* after enable or disable, valid flag need to be set*/
+	val = FIELD_PREP(MCAN_ECC_REG_MASK, MCAN_ECC_CFG_VALID);
+	regmap_set_bits(ecc_cfg->syscon, ecc_cfg->reg, val);
+
+	if (enable) {
+		/* Poll for completion */
+		ret = regmap_read_poll_timeout(ecc_cfg->syscon, ecc_cfg->reg,
+					       val,
+					       (val & MCAN_ECC_INIT_DONE), 5,
+					       MCAN_ECC_INIT_TIMEOUT);
+
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int m_can_close(struct net_device *dev)
 {
 	struct m_can_classdev *cdev = netdev_priv(dev);
@@ -1557,6 +1598,9 @@ static int m_can_close(struct net_device *dev)
 	if (cdev->is_peripheral)
 		can_rx_offload_disable(&cdev->offload);
 
+	if (cdev->ops->deinit)
+		cdev->ops->deinit(cdev);
+
 	close_candev(dev);
 
 	phy_power_off(cdev->transceiver);
diff --git a/drivers/net/can/m_can/m_can.h b/drivers/net/can/m_can/m_can.h
index 401410022823..9821b135a2be 100644
--- a/drivers/net/can/m_can/m_can.h
+++ b/drivers/net/can/m_can/m_can.h
@@ -19,6 +19,7 @@
 #include <linux/io.h>
 #include <linux/iopoll.h>
 #include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/of.h>
@@ -26,6 +27,7 @@
 #include <linux/phy/phy.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/pm_runtime.h>
+#include <linux/regmap.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 
@@ -52,12 +54,23 @@ enum m_can_mram_cfg {
 	MRAM_CFG_NUM,
 };
 
+enum m_can_ecc_cfg {
+	ECC_DISABLE = 0,
+	ECC_ENABLE,
+};
+
 /* address offset and element number for each FIFO/Buffer in the Message RAM */
 struct mram_cfg {
 	u16 off;
 	u8  num;
 };
 
+struct m_can_ecc_regmap {
+	struct regmap *syscon;  /* for mram ecc ctrl. reg. access */
+	unsigned int reg;       /* register index within syscon */
+	u8 ecc_cfg_flag;
+};
+
 struct m_can_classdev;
 struct m_can_ops {
 	/* Device specific call backs */
@@ -68,6 +81,7 @@ struct m_can_ops {
 	int (*write_fifo)(struct m_can_classdev *cdev, int addr_offset,
 			  const void *val, size_t val_count);
 	int (*init)(struct m_can_classdev *cdev);
+	int (*deinit)(struct m_can_classdev *cdev);
 };
 
 struct m_can_classdev {
@@ -92,7 +106,9 @@ struct m_can_classdev {
 	int pm_clock_support;
 	int is_peripheral;
 
+	struct m_can_ecc_regmap ecc_cfg_sys; /* ecc config via syscon regmap */
 	struct mram_cfg mcfg[MRAM_CFG_NUM];
+	u8 mram_cfg_flag;
 };
 
 struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv);
@@ -104,4 +120,5 @@ int m_can_init_ram(struct m_can_classdev *priv);
 
 int m_can_class_suspend(struct device *dev);
 int m_can_class_resume(struct device *dev);
+int m_can_config_mram_ecc_check(struct m_can_classdev *cdev, bool enable);
 #endif	/* _CAN_M_H_ */
diff --git a/drivers/net/can/m_can/m_can_platform.c b/drivers/net/can/m_can/m_can_platform.c
index b5a5bedb3116..1281214a3f43 100644
--- a/drivers/net/can/m_can/m_can_platform.c
+++ b/drivers/net/can/m_can/m_can_platform.c
@@ -67,11 +67,83 @@ static int iomap_write_fifo(struct m_can_classdev *cdev, int offset,
 	return 0;
 }
 
+static int m_can_plat_init(struct m_can_classdev *cdev)
+{
+	struct  m_can_ecc_regmap *ecc_cfg = &cdev->ecc_cfg_sys;
+	struct device_node *np = cdev->dev->of_node;
+	int ret = 0;
+
+	if (cdev->mram_cfg_flag != ECC_ENABLE) {
+		/* Initialize mcan message ram */
+		ret = m_can_init_ram(cdev);
+
+		if (ret)
+			return ret;
+
+		cdev->mram_cfg_flag = ECC_ENABLE;
+	}
+
+	if (ecc_cfg->ecc_cfg_flag != ECC_ENABLE) {
+		/* configure error code check for mram */
+		if (!ecc_cfg->syscon) {
+			ecc_cfg->syscon =
+			syscon_regmap_lookup_by_phandle_args(np,
+							     "tesla,mram-ecc-cfg"
+							     , 1,
+							     &ecc_cfg->reg);
+		}
+
+		if (IS_ERR(ecc_cfg->syscon)) {
+			dev_err(cdev->dev, "couldn't get the syscon reg!\n");
+			goto ecc_failed;
+		}
+
+		if (!ecc_cfg->reg) {
+			dev_err(cdev->dev,
+				"couldn't get the ecc init reg. offset!\n");
+			goto ecc_failed;
+		}
+
+		/* Enable error code check functionality for message ram */
+		if (m_can_config_mram_ecc_check(cdev, ECC_ENABLE))
+			goto ecc_failed;
+
+		ecc_cfg->ecc_cfg_flag = ECC_ENABLE;
+	}
+
+	return 0;
+
+ecc_failed:
+	dev_err(cdev->dev, "Message ram ecc enable config failed\n");
+
+	return 0;
+}
+
+static int m_can_plat_deinit(struct m_can_classdev *cdev)
+{
+	struct  m_can_ecc_regmap *ecc_cfg = &cdev->ecc_cfg_sys;
+
+	if (ecc_cfg->ecc_cfg_flag == ECC_ENABLE) {
+		/* Disable error code check functionality for message ram */
+		if (m_can_config_mram_ecc_check(cdev, ECC_DISABLE)) {
+			dev_err(cdev->dev,
+				"Message ram ecc disable config failed\n");
+			return 0;
+		}
+
+		ecc_cfg->ecc_cfg_flag = ECC_DISABLE;
+	}
+
+	return 0;
+}
+
 static struct m_can_ops m_can_plat_ops = {
 	.read_reg = iomap_read_reg,
 	.write_reg = iomap_write_reg,
 	.write_fifo = iomap_write_fifo,
 	.read_fifo = iomap_read_fifo,
+	.init = m_can_plat_init,
+	.deinit = m_can_plat_deinit,
 };
 
 static int m_can_plat_probe(struct platform_device *pdev)
@@ -140,10 +212,6 @@ static int m_can_plat_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, mcan_class);
 
-	ret = m_can_init_ram(mcan_class);
-	if (ret)
-		goto probe_fail;
-
 	pm_runtime_enable(mcan_class->dev);
 	ret = m_can_class_register(mcan_class);
 	if (ret)
-- 
2.17.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ