linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line
@ 2019-02-21 12:57 Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic Miquel Raynal
                   ` (11 more replies)
  0 siblings, 12 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

The include file pretends being the header for "ECC algorithm", while
it is just the header for the Hamming implementation. Make this clear
by rewording the sentence.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 include/linux/mtd/nand-sw-hamming-engine.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
index 1bd7493c682b..4ce99fa574e3 100644
--- a/include/linux/mtd/nand-sw-hamming-engine.h
+++ b/include/linux/mtd/nand-sw-hamming-engine.h
@@ -4,7 +4,7 @@
  *			    David Woodhouse <dwmw2@infradead.org>
  *			    Thomas Gleixner <tglx@linutronix.de>
  *
- * This file is the header for the ECC algorithm.
+ * This file is the header for the NAND Hamming ECC implementation.
  */
 
 #ifndef __MTD_NAND_ECC_SW_HAMMING_H__
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-21 13:22   ` Boris Brezillon
  2019-02-21 12:57 ` [RFC PATCH 15/27] mtd: nand: Remove useless include about software Hamming ECC Miquel Raynal
                   ` (10 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Add helpers in the raw NAND core to call the generic functions that
will be re-used by the SPI-NAND layer.

While at it, do some cleanup in the file and its header.

There are two drivers (not even raw NAND controller drivers) using the
bare helpers __ecc_sw_hamming_calculate/correct(): mtd_nandecctest.c
and sm_ftl.c. It would be nice to find another way to call these
functions and finish to clean the driver.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc/sw-hamming-engine.c   | 122 +++++++++------------
 drivers/mtd/nand/raw/cs553x_nand.c         |   3 +-
 drivers/mtd/nand/raw/fsmc_nand.c           |   2 +-
 drivers/mtd/nand/raw/lpc32xx_slc.c         |   2 +-
 drivers/mtd/nand/raw/nand_base.c           |  85 +++++++++++++-
 drivers/mtd/nand/raw/ndfc.c                |   3 +-
 drivers/mtd/nand/raw/sharpsl.c             |   2 +-
 drivers/mtd/nand/raw/tmio_nand.c           |   6 +-
 drivers/mtd/nand/raw/txx9ndfmc.c           |   4 +-
 drivers/mtd/sm_ftl.c                       |  27 +++--
 drivers/mtd/tests/mtd_nandecctest.c        |  29 +++--
 include/linux/mtd/nand-sw-hamming-engine.h |  50 +++++----
 include/linux/mtd/rawnand.h                |   9 ++
 13 files changed, 208 insertions(+), 136 deletions(-)

diff --git a/drivers/mtd/nand/ecc/sw-hamming-engine.c b/drivers/mtd/nand/ecc/sw-hamming-engine.c
index 6ba0205f1b4f..3918daf5547b 100644
--- a/drivers/mtd/nand/ecc/sw-hamming-engine.c
+++ b/drivers/mtd/nand/ecc/sw-hamming-engine.c
@@ -17,8 +17,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/rawnand.h>
 #include <linux/mtd/nand-sw-hamming-engine.h>
 #include <asm/byteorder.h>
 
@@ -75,7 +73,7 @@ static const char bitsperbyte[256] = {
  * addressbits is a lookup table to filter out the bits from the xor-ed
  * ECC data that identify the faulty location.
  * this is only used for repairing parity
- * see the comments in nand_correct_data for more details
+ * see the comments in ecc_sw_hamming_correct for more details
  */
 static const char addressbits[256] = {
 	0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x01,
@@ -112,30 +110,24 @@ static const char addressbits[256] = {
 	0x0e, 0x0e, 0x0f, 0x0f, 0x0e, 0x0e, 0x0f, 0x0f
 };
 
-/**
- * __nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
- *			 block
- * @buf:	input buffer with raw data
- * @eccsize:	data bytes per ECC step (256 or 512)
- * @code:	output buffer with ECC
- * @sm_order:	Smart Media byte ordering
- */
-void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
-			  unsigned char *code, bool sm_order)
+int __ecc_sw_hamming_calculate(const unsigned char *buf,
+			       unsigned int step_size,
+			       unsigned char *code, bool sm_order)
 {
-	int i;
-	const uint32_t *bp = (uint32_t *)buf;
-	/* 256 or 512 bytes/ecc  */
-	const uint32_t eccsize_mult = eccsize >> 8;
-	uint32_t cur;		/* current value in buffer */
+	const u32 *bp = (uint32_t *)buf;
+	const u32 eccsize_mult = step_size >> 8;
+	/* current value in buffer */
+	u32 cur;
 	/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
-	uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
-	uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
-	uint32_t uninitialized_var(rp17);	/* to make compiler happy */
-	uint32_t par;		/* the cumulative parity for all data */
-	uint32_t tmppar;	/* the cumulative parity for this iteration;
-				   for rp12, rp14 and rp16 at the end of the
-				   loop */
+	u32 rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
+	u32 rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16;
+	/* Make the compiler happy */
+	u32 uninitialized_var(rp17);
+	/* Cumulative parity for all data */
+	u32 par;
+	/* Cumulative parity at the end of the loop (rp12, rp14, rp16) */
+	u32 tmppar;
+	int i;
 
 	par = 0;
 	rp4 = 0;
@@ -356,45 +348,37 @@ void __nand_calculate_ecc(const unsigned char *buf, unsigned int eccsize,
 		    (invparity[par & 0x55] << 2) |
 		    (invparity[rp17] << 1) |
 		    (invparity[rp16] << 0);
-}
-EXPORT_SYMBOL(__nand_calculate_ecc);
-
-/**
- * nand_calculate_ecc - [NAND Interface] Calculate 3-byte ECC for 256/512-byte
- *			 block
- * @chip:	NAND chip object
- * @buf:	input buffer with raw data
- * @code:	output buffer with ECC
- */
-int nand_calculate_ecc(struct nand_chip *chip, const unsigned char *buf,
-		       unsigned char *code)
-{
-	bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
-
-	__nand_calculate_ecc(buf, chip->ecc.size, code, sm_order);
 
 	return 0;
 }
-EXPORT_SYMBOL(nand_calculate_ecc);
+EXPORT_SYMBOL(__ecc_sw_hamming_calculate);
 
 /**
- * __nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @buf:	raw data read from the chip
- * @read_ecc:	ECC from the chip
- * @calc_ecc:	the ECC calculated from raw data
- * @eccsize:	data bytes per ECC step (256 or 512)
- * @sm_order:	Smart Media byte order
+ * ecc_sw_hamming_calculate - Calculate 3-byte ECC for 256/512-byte block
  *
- * Detect and correct a 1 bit error for eccsize byte block
+ * @nand: NAND device
+ * @buf: Input buffer with raw data
+ * @code: Output buffer with ECC
  */
-int __nand_correct_data(unsigned char *buf,
-			unsigned char *read_ecc, unsigned char *calc_ecc,
-			unsigned int eccsize, bool sm_order)
+int ecc_sw_hamming_calculate(struct nand_device *nand,
+			     const unsigned char *buf,
+			     unsigned char *code)
 {
+	struct ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
+	unsigned int step_size = nand->ecc.ctx.conf.step_size;
+
+	return __ecc_sw_hamming_calculate(buf, step_size, code,
+					  engine_conf->sm_order);
+}
+EXPORT_SYMBOL(ecc_sw_hamming_calculate);
+
+int __ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
+			     unsigned char *calc_ecc, unsigned int step_size,
+			     bool sm_order)
+{
+	const u32 eccsize_mult = step_size >> 8;
 	unsigned char b0, b1, b2, bit_addr;
 	unsigned int byte_addr;
-	/* 256 or 512 bytes/ecc  */
-	const uint32_t eccsize_mult = eccsize >> 8;
 
 	/*
 	 * b0 to b2 indicate which bit is faulty (if any)
@@ -458,27 +442,29 @@ int __nand_correct_data(unsigned char *buf,
 	pr_err("%s: uncorrectable ECC error\n", __func__);
 	return -EBADMSG;
 }
-EXPORT_SYMBOL(__nand_correct_data);
+EXPORT_SYMBOL(__ecc_sw_hamming_correct);
 
 /**
- * nand_correct_data - [NAND Interface] Detect and correct bit error(s)
- * @chip:	NAND chip object
- * @buf:	raw data read from the chip
- * @read_ecc:	ECC from the chip
- * @calc_ecc:	the ECC calculated from raw data
+ * ecc_sw_hamming_correct - Detect and correct bit error(s)
  *
- * Detect and correct a 1 bit error for 256/512 byte block
+ * @nand: NAND device
+ * @buf: Raw data read from the chip
+ * @read_ecc: ECC bytes read from the chip
+ * @calc_ecc: ECC calculated from the raw data
+ *
+ * Detect and correct up to 1 bit error per 256/512-byte block.
  */
-int nand_correct_data(struct nand_chip *chip, unsigned char *buf,
-		      unsigned char *read_ecc, unsigned char *calc_ecc)
+int ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
+			   unsigned char *read_ecc, unsigned char *calc_ecc)
 {
-	bool sm_order = chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER;
+	struct ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
+	unsigned int step_size = nand->ecc.ctx.conf.step_size;
 
-	return __nand_correct_data(buf, read_ecc, calc_ecc, chip->ecc.size,
-				   sm_order);
+	return __ecc_sw_hamming_correct(buf, read_ecc, calc_ecc, step_size,
+					engine_conf->sm_order);
 }
-EXPORT_SYMBOL(nand_correct_data);
+EXPORT_SYMBOL(ecc_sw_hamming_correct);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
-MODULE_DESCRIPTION("Generic NAND ECC support");
+MODULE_DESCRIPTION("NAND software Hamming ECC support");
diff --git a/drivers/mtd/nand/raw/cs553x_nand.c b/drivers/mtd/nand/raw/cs553x_nand.c
index 19596ba72ac6..3fbff2a5dab1 100644
--- a/drivers/mtd/nand/raw/cs553x_nand.c
+++ b/drivers/mtd/nand/raw/cs553x_nand.c
@@ -23,7 +23,6 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/msr.h>
@@ -219,7 +218,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
 	this->ecc.bytes = 3;
 	this->ecc.hwctl  = cs_enable_hwecc;
 	this->ecc.calculate = cs_calculate_ecc;
-	this->ecc.correct  = nand_correct_data;
+	this->ecc.correct  = rawnand_sw_hamming_correct;
 	this->ecc.strength = 1;
 
 	/* Enable the following for a flash based bad block table */
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index 9d11007b1ee5..91e813fe7dd8 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -936,7 +936,7 @@ static int fsmc_nand_attach_chip(struct nand_chip *nand)
 	case NAND_ECC_HW:
 		dev_info(host->dev, "Using 1-bit HW ECC scheme\n");
 		nand->ecc.calculate = fsmc_read_hwecc_ecc1;
-		nand->ecc.correct = nand_correct_data;
+		nand->ecc.correct = rawnand_sw_hamming_correct;
 		nand->ecc.bytes = 3;
 		nand->ecc.strength = 1;
 		nand->ecc.options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index 447c23d4f3b4..f2924ea8e126 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -901,7 +901,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 	chip->ecc.write_oob = lpc32xx_nand_write_oob_syndrome;
 	chip->ecc.read_oob = lpc32xx_nand_read_oob_syndrome;
 	chip->ecc.calculate = lpc32xx_nand_ecc_calculate;
-	chip->ecc.correct = nand_correct_data;
+	chip->ecc.correct = rawnand_sw_hamming_correct;
 	chip->ecc.strength = 1;
 	chip->ecc.hwctl = lpc32xx_nand_ecc_enable;
 
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 395a9bde5e15..751bed07fd62 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4843,6 +4843,72 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
 	kfree(chip->parameters.onfi);
 }
 
+int rawnand_sw_hamming_init(struct nand_chip *chip)
+{
+	struct mtd_info *mtd = nand_to_mtd(chip);
+	struct ecc_sw_hamming_conf *engine_conf;
+	struct nand_device *base = &chip->base;
+
+	base->ecc.user_conf.mode = NAND_ECC_SOFT;
+	base->ecc.user_conf.algo = NAND_ECC_HAMMING;
+	base->ecc.user_conf.strength = chip->ecc.strength;
+	base->ecc.user_conf.step_size = chip->ecc.size;
+
+	if (base->ecc.user_conf.strength != 1 ||
+	    (base->ecc.user_conf.step_size != 256 &&
+	     base->ecc.user_conf.step_size != 512)) {
+		pr_err("%s: unsupported strength or step size\n", __func__);
+		return -EINVAL;
+	}
+
+	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
+	if (!engine_conf)
+		return -ENOMEM;
+
+	engine_conf->code_size = 3;
+	engine_conf->nsteps = mtd->writesize / base->ecc.user_conf.step_size;
+
+	if (chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER)
+		engine_conf->sm_order = true;
+
+	base->ecc.ctx.priv = engine_conf;
+
+	chip->ecc.steps = engine_conf->nsteps;
+	chip->ecc.bytes = engine_conf->code_size;
+
+	return 0;
+}
+EXPORT_SYMBOL(rawnand_sw_hamming_init);
+
+int rawnand_sw_hamming_calculate(struct nand_chip *chip,
+				 const unsigned char *buf,
+				 unsigned char *code)
+{
+	struct nand_device *base = &chip->base;
+
+	return ecc_sw_hamming_calculate(base, buf, code);
+}
+EXPORT_SYMBOL(rawnand_sw_hamming_calculate);
+
+int rawnand_sw_hamming_correct(struct nand_chip *chip,
+			       unsigned char *buf,
+			       unsigned char *read_ecc,
+			       unsigned char *calc_ecc)
+{
+	struct nand_device *base = &chip->base;
+
+	return ecc_sw_hamming_correct(base, buf, read_ecc, calc_ecc);
+}
+EXPORT_SYMBOL(rawnand_sw_hamming_correct);
+
+void rawnand_sw_hamming_cleanup(struct nand_chip *chip)
+{
+	struct nand_device *base = &chip->base;
+
+	kfree(base->ecc.ctx.priv);
+}
+EXPORT_SYMBOL(rawnand_sw_hamming_cleanup);
+
 int rawnand_sw_bch_init(struct nand_chip *chip)
 {
 	struct nand_device *base = &chip->base;
@@ -4916,8 +4982,8 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
 
 	switch (ecc->algo) {
 	case NAND_ECC_HAMMING:
-		ecc->calculate = nand_calculate_ecc;
-		ecc->correct = nand_correct_data;
+		ecc->calculate = rawnand_sw_hamming_calculate;
+		ecc->correct = rawnand_sw_hamming_correct;
 		ecc->read_page = nand_read_page_swecc;
 		ecc->read_subpage = nand_read_subpage;
 		ecc->write_page = nand_write_page_swecc;
@@ -4933,6 +4999,12 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
 		if (IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC))
 			ecc->options |= NAND_ECC_SOFT_HAMMING_SM_ORDER;
 
+		ret = rawnand_sw_hamming_init(chip);
+		if (ret) {
+			WARN(1, "Hamming ECC initialization failed!\n");
+			return ret;
+		}
+
 		return 0;
 	case NAND_ECC_BCH:
 		if (!IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)) {
@@ -5703,9 +5775,12 @@ EXPORT_SYMBOL(nand_scan_with_ids);
  */
 void nand_cleanup(struct nand_chip *chip)
 {
-	if (chip->ecc.mode == NAND_ECC_SOFT &&
-	    chip->ecc.algo == NAND_ECC_BCH)
-		rawnand_sw_bch_cleanup(chip);
+	if (chip->ecc.mode == NAND_ECC_SOFT) {
+		if (chip->ecc.algo == NAND_ECC_HAMMING)
+			rawnand_sw_hamming_cleanup(chip);
+		else if (chip->ecc.algo == NAND_ECC_BCH)
+			rawnand_sw_bch_cleanup(chip);
+	}
 
 	/* Free bad block table memory */
 	kfree(chip->bbt);
diff --git a/drivers/mtd/nand/raw/ndfc.c b/drivers/mtd/nand/raw/ndfc.c
index d552b727b821..e92079dc1a47 100644
--- a/drivers/mtd/nand/raw/ndfc.c
+++ b/drivers/mtd/nand/raw/ndfc.c
@@ -23,7 +23,6 @@
  */
 #include <linux/module.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/ndfc.h>
 #include <linux/slab.h>
@@ -151,7 +150,7 @@ static int ndfc_chip_init(struct ndfc_controller *ndfc,
 	chip->controller = &ndfc->ndfc_control;
 	chip->legacy.read_buf = ndfc_read_buf;
 	chip->legacy.write_buf = ndfc_write_buf;
-	chip->ecc.correct = nand_correct_data;
+	chip->ecc.correct = ecc_sw_hamming_correct;
 	chip->ecc.hwctl = ndfc_enable_hwecc;
 	chip->ecc.calculate = ndfc_calculate_ecc;
 	chip->ecc.mode = NAND_ECC_HW;
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
index 32918a7ed6c4..35baff68993f 100644
--- a/drivers/mtd/nand/raw/sharpsl.c
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -168,7 +168,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 	this->badblock_pattern = data->badblock_pattern;
 	this->ecc.hwctl = sharpsl_nand_enable_hwecc;
 	this->ecc.calculate = sharpsl_nand_calculate_ecc;
-	this->ecc.correct = nand_correct_data;
+	this->ecc.correct = rawnand_sw_hamming_correct;
 
 	/* Scan to find existence of the device */
 	err = nand_scan(this, 1);
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
index 63f5100cf70b..7eeef6634c0c 100644
--- a/drivers/mtd/nand/raw/tmio_nand.c
+++ b/drivers/mtd/nand/raw/tmio_nand.c
@@ -295,11 +295,11 @@ static int tmio_nand_correct_data(struct nand_chip *chip, unsigned char *buf,
 	int r0, r1;
 
 	/* assume ecc.size = 512 and ecc.bytes = 6 */
-	r0 = __nand_correct_data(buf, read_ecc, calc_ecc, 256, false);
+	r0 = rawnand_sw_hamming_correct(chip, buf, read_ecc, calc_ecc);
 	if (r0 < 0)
 		return r0;
-	r1 = __nand_correct_data(buf + 256, read_ecc + 3, calc_ecc + 3, 256,
-				 false);
+	r1 = rawnand_sw_hamming_correct(chip, buf + 256, read_ecc + 3,
+					calc_ecc + 3);
 	if (r1 < 0)
 		return r1;
 	return r0 + r1;
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index f87f598b7688..85019684dee7 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -198,8 +198,8 @@ static int txx9ndfmc_correct_data(struct nand_chip *chip, unsigned char *buf,
 	int stat;
 
 	for (eccsize = chip->ecc.size; eccsize > 0; eccsize -= 256) {
-		stat = __nand_correct_data(buf, read_ecc, calc_ecc, 256,
-					   false);
+		stat = rawnand_sw_hamming_correct(chip, buf, read_ecc,
+						  calc_ecc);
 		if (stat < 0)
 			return stat;
 		corrected += stat;
diff --git a/drivers/mtd/sm_ftl.c b/drivers/mtd/sm_ftl.c
index 57a7d98d6a84..aaaa906423a9 100644
--- a/drivers/mtd/sm_ftl.c
+++ b/drivers/mtd/sm_ftl.c
@@ -219,20 +219,19 @@ static void sm_break_offset(struct sm_ftl *ftl, loff_t loffset,
 
 static int sm_correct_sector(uint8_t *buffer, struct sm_oob *oob)
 {
+	bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC);
 	uint8_t ecc[3];
 
-	__nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
-			     IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
-	if (__nand_correct_data(buffer, ecc, oob->ecc1, SM_SMALL_PAGE,
-				IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) < 0)
+	__ecc_sw_hamming_calculate(buffer, SM_SMALL_PAGE, ecc, sm_order);
+	if (__ecc_sw_hamming_correct(buffer, ecc, oob->ecc1, SM_SMALL_PAGE,
+				     sm_order) < 0)
 		return -EIO;
 
 	buffer += SM_SMALL_PAGE;
 
-	__nand_calculate_ecc(buffer, SM_SMALL_PAGE, ecc,
-			     IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
-	if (__nand_correct_data(buffer, ecc, oob->ecc2, SM_SMALL_PAGE,
-				IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC)) < 0)
+	__ecc_sw_hamming_calculate(buffer, SM_SMALL_PAGE, ecc, sm_order);
+	if (__ecc_sw_hamming_correct(buffer, ecc, oob->ecc2, SM_SMALL_PAGE,
+				     sm_order) < 0)
 		return -EIO;
 	return 0;
 }
@@ -371,6 +370,7 @@ static int sm_write_block(struct sm_ftl *ftl, uint8_t *buf,
 			  int zone, int block, int lba,
 			  unsigned long invalid_bitmap)
 {
+	bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC);
 	struct sm_oob oob;
 	int boffset;
 	int retry = 0;
@@ -397,13 +397,12 @@ static int sm_write_block(struct sm_ftl *ftl, uint8_t *buf,
 		}
 
 		if (ftl->smallpagenand) {
-			__nand_calculate_ecc(buf + boffset, SM_SMALL_PAGE,
-					oob.ecc1,
-					IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
+			__ecc_sw_hamming_calculate(buf + boffset, SM_SMALL_PAGE,
+						   oob.ecc1, sm_order);
 
-			__nand_calculate_ecc(buf + boffset + SM_SMALL_PAGE,
-					SM_SMALL_PAGE, oob.ecc2,
-					IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
+			__ecc_sw_hamming_calculate(buf + boffset + SM_SMALL_PAGE,
+						   SM_SMALL_PAGE, oob.ecc2,
+						   sm_order);
 		}
 		if (!sm_write_sector(ftl, zone, block, boffset,
 							buf + boffset, &oob))
diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c
index 95a94643f955..5d1a36244e59 100644
--- a/drivers/mtd/tests/mtd_nandecctest.c
+++ b/drivers/mtd/tests/mtd_nandecctest.c
@@ -118,13 +118,13 @@ static void no_bit_error(void *error_data, void *error_ecc,
 static int no_bit_error_verify(void *error_data, void *error_ecc,
 				void *correct_data, const size_t size)
 {
+	bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC);
 	unsigned char calc_ecc[3];
 	int ret;
 
-	__nand_calculate_ecc(error_data, size, calc_ecc,
-			     IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
-	ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
-				  IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
+	__ecc_sw_hamming_calculate(error_data, size, calc_ecc, sm_order);
+	ret = __ecc_sw_hamming_correct(error_data, error_ecc, calc_ecc, size,
+				       sm_order);
 	if (ret == 0 && !memcmp(correct_data, error_data, size))
 		return 0;
 
@@ -148,13 +148,13 @@ static void single_bit_error_in_ecc(void *error_data, void *error_ecc,
 static int single_bit_error_correct(void *error_data, void *error_ecc,
 				void *correct_data, const size_t size)
 {
+	bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC);
 	unsigned char calc_ecc[3];
 	int ret;
 
-	__nand_calculate_ecc(error_data, size, calc_ecc,
-			     IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
-	ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
-				  IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
+	__ecc_sw_hamming_calculate(error_data, size, calc_ecc, sm_order);
+	ret = __ecc_sw_hamming_correct(error_data, error_ecc, calc_ecc, size,
+				       sm_order);
 	if (ret == 1 && !memcmp(correct_data, error_data, size))
 		return 0;
 
@@ -185,13 +185,13 @@ static void double_bit_error_in_ecc(void *error_data, void *error_ecc,
 static int double_bit_error_detect(void *error_data, void *error_ecc,
 				void *correct_data, const size_t size)
 {
+	bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC);
 	unsigned char calc_ecc[3];
 	int ret;
 
-	__nand_calculate_ecc(error_data, size, calc_ecc,
-			     IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
-	ret = __nand_correct_data(error_data, error_ecc, calc_ecc, size,
-				  IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
+	__ecc_sw_hamming_calculate(error_data, size, calc_ecc, sm_order);
+	ret = __ecc_sw_hamming_correct(error_data, error_ecc, calc_ecc, size,
+				       sm_order);
 
 	return (ret == -EBADMSG) ? 0 : -EINVAL;
 }
@@ -247,6 +247,7 @@ static void dump_data_ecc(void *error_data, void *error_ecc, void *correct_data,
 
 static int nand_ecc_test_run(const size_t size)
 {
+	bool sm_order = IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC);
 	int i;
 	int err = 0;
 	void *error_data;
@@ -265,9 +266,7 @@ static int nand_ecc_test_run(const size_t size)
 	}
 
 	prandom_bytes(correct_data, size);
-	__nand_calculate_ecc(correct_data, size, correct_ecc,
-			     IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING_SMC));
-
+	__ecc_sw_hamming_calculate(correct_data, size, correct_ecc, sm_order);
 	for (i = 0; i < ARRAY_SIZE(nand_ecc_test); i++) {
 		nand_ecc_test[i].prepare(error_data, error_ecc,
 				correct_data, correct_ecc, size);
diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
index 4ce99fa574e3..c50da3a255b7 100644
--- a/include/linux/mtd/nand-sw-hamming-engine.h
+++ b/include/linux/mtd/nand-sw-hamming-engine.h
@@ -10,30 +10,36 @@
 #ifndef __MTD_NAND_ECC_SW_HAMMING_H__
 #define __MTD_NAND_ECC_SW_HAMMING_H__
 
-struct nand_chip;
+#include <linux/mtd/nand.h>
 
-/*
- * Calculate 3 byte ECC code for eccsize byte block
+/**
+ * struct ecc_sw_hamming_conf - private software Hamming ECC engine structure
+ * @reqooblen: Save the actual user OOB length requested before overwriting it
+ * @code_size: Number of bytes needed to store a code (one code per step)
+ * @nsteps: Number of steps
+ * @calc_buf: Buffer to use when calculating ECC bytes
+ * @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
+ * @sm_order: Smart Media special ordering
  */
-void __nand_calculate_ecc(const u_char *dat, unsigned int eccsize,
-			  u_char *ecc_code, bool sm_order);
+struct ecc_sw_hamming_conf {
+	unsigned int reqooblen;
+	unsigned int code_size;
+	unsigned int nsteps;
+	u8 *calc_buf;
+	u8 *code_buf;
+	unsigned int sm_order;
+};
 
-/*
- * Calculate 3 byte ECC code for 256/512 byte block
- */
-int nand_calculate_ecc(struct nand_chip *chip, const u_char *dat,
-		       u_char *ecc_code);
-
-/*
- * Detect and correct a 1 bit error for eccsize byte block
- */
-int __nand_correct_data(u_char *dat, u_char *read_ecc, u_char *calc_ecc,
-			unsigned int eccsize, bool sm_order);
-
-/*
- * Detect and correct a 1 bit error for 256/512 byte block
- */
-int nand_correct_data(struct nand_chip *chip, u_char *dat, u_char *read_ecc,
-		      u_char *calc_ecc);
+int __ecc_sw_hamming_calculate(const unsigned char *buf,
+			       unsigned int step_size,
+			       unsigned char *code, bool sm_order);
+int ecc_sw_hamming_calculate(struct nand_device *nand,
+			     const unsigned char *buf,
+			     unsigned char *code);
+int __ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
+			     unsigned char *calc_ecc, unsigned int step_size,
+			     bool sm_order);
+int ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
+			   unsigned char *read_ecc, unsigned char *calc_ecc);
 
 #endif /* __MTD_NAND_ECC_SW_HAMMING_H__ */
diff --git a/include/linux/mtd/rawnand.h b/include/linux/mtd/rawnand.h
index afe75e707e2c..dc6d0f899066 100644
--- a/include/linux/mtd/rawnand.h
+++ b/include/linux/mtd/rawnand.h
@@ -1230,6 +1230,15 @@ static inline int nand_opcode_8bits(unsigned int command)
 	return 0;
 }
 
+int rawnand_sw_hamming_init(struct nand_chip *chip);
+int rawnand_sw_hamming_calculate(struct nand_chip *chip,
+				 const unsigned char *buf,
+				 unsigned char *code);
+int rawnand_sw_hamming_correct(struct nand_chip *chip,
+			       unsigned char *buf,
+			       unsigned char *read_ecc,
+			       unsigned char *calc_ecc);
+void rawnand_sw_hamming_cleanup(struct nand_chip *chip);
 int rawnand_sw_bch_init(struct nand_chip *chip);
 int rawnand_sw_bch_correct(struct nand_chip *chip, unsigned char *buf,
 			   unsigned char *read_ecc, unsigned char *calc_ecc);
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 15/27] mtd: nand: Remove useless include about software Hamming ECC
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module Miquel Raynal
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Most of the includes are simply useless, drop them.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 arch/arm/mach-s3c24xx/common-smdk.c    | 1 -
 arch/arm/mach-s3c24xx/mach-anubis.c    | 1 -
 arch/arm/mach-s3c24xx/mach-at2440evb.c | 1 -
 arch/arm/mach-s3c24xx/mach-bast.c      | 1 -
 arch/arm/mach-s3c24xx/mach-gta02.c     | 1 -
 arch/arm/mach-s3c24xx/mach-jive.c      | 1 -
 arch/arm/mach-s3c24xx/mach-mini2440.c  | 1 -
 arch/arm/mach-s3c24xx/mach-osiris.c    | 1 -
 arch/arm/mach-s3c24xx/mach-qt2410.c    | 1 -
 arch/arm/mach-s3c24xx/mach-rx3715.c    | 1 -
 arch/arm/mach-s3c24xx/mach-vstms.c     | 1 -
 drivers/mtd/nand/raw/fsl_elbc_nand.c   | 1 -
 drivers/mtd/nand/raw/fsl_ifc_nand.c    | 1 -
 drivers/mtd/nand/raw/fsl_upm.c         | 1 -
 drivers/mtd/nand/raw/fsmc_nand.c       | 1 -
 drivers/mtd/nand/raw/lpc32xx_mlc.c     | 1 -
 drivers/mtd/nand/raw/lpc32xx_slc.c     | 1 -
 drivers/mtd/nand/raw/pasemi_nand.c     | 1 -
 drivers/mtd/nand/raw/s3c2410.c         | 1 -
 drivers/mtd/nand/raw/sharpsl.c         | 1 -
 drivers/mtd/nand/raw/tmio_nand.c       | 1 -
 drivers/mtd/nand/raw/txx9ndfmc.c       | 1 -
 include/linux/mtd/sharpsl.h            | 1 -
 23 files changed, 23 deletions(-)

diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c
index 8fe2e62ef730..7cab64bea951 100644
--- a/arch/arm/mach-s3c24xx/common-smdk.c
+++ b/arch/arm/mach-s3c24xx/common-smdk.c
@@ -19,7 +19,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c
index 8f1c505185b4..8e4410d1bfa1 100644
--- a/arch/arm/mach-s3c24xx/mach-anubis.c
+++ b/arch/arm/mach-s3c24xx/mach-anubis.c
@@ -36,7 +36,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <net/ax88796.h>
diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c
index 94057a8b8778..35dc86805dce 100644
--- a/arch/arm/mach-s3c24xx/mach-at2440evb.c
+++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c
@@ -37,7 +37,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <plat/devs.h>
diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c
index 08d88540becf..3f8e2e7a2dff 100644
--- a/arch/arm/mach-s3c24xx/mach-bast.c
+++ b/arch/arm/mach-s3c24xx/mach-bast.c
@@ -24,7 +24,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/platform_data/asoc-s3c24xx_simtec.h>
diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c
index 5882b370cbcf..b63f5c2aeac7 100644
--- a/arch/arm/mach-s3c24xx/mach-gta02.c
+++ b/arch/arm/mach-s3c24xx/mach-gta02.c
@@ -36,7 +36,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
 
diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c
index 658be0b24fcb..d9b920ad444e 100644
--- a/arch/arm/mach-s3c24xx/mach-jive.c
+++ b/arch/arm/mach-s3c24xx/mach-jive.c
@@ -40,7 +40,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <plat/gpio-cfg.h>
diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c
index abbdc44dfb8f..cdc305bbb74f 100644
--- a/arch/arm/mach-s3c24xx/mach-mini2440.c
+++ b/arch/arm/mach-s3c24xx/mach-mini2440.c
@@ -46,7 +46,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <plat/gpio-cfg.h>
diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c
index c00ec4d851b7..025a7678b5cc 100644
--- a/arch/arm/mach-s3c24xx/mach-osiris.c
+++ b/arch/arm/mach-s3c24xx/mach-osiris.c
@@ -33,7 +33,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <plat/cpu.h>
diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c
index 9d6e92b51e60..a1835139a6a6 100644
--- a/arch/arm/mach-s3c24xx/mach-qt2410.c
+++ b/arch/arm/mach-s3c24xx/mach-qt2410.c
@@ -21,7 +21,6 @@
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c
index f9668f4634dc..13c73f6063bb 100644
--- a/arch/arm/mach-s3c24xx/mach-rx3715.c
+++ b/arch/arm/mach-s3c24xx/mach-rx3715.c
@@ -22,7 +22,6 @@
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/mach/arch.h>
diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c
index 94f6d5ce0246..c1db572d2513 100644
--- a/arch/arm/mach-s3c24xx/mach-vstms.c
+++ b/arch/arm/mach-s3c24xx/mach-vstms.c
@@ -16,7 +16,6 @@
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/memblock.h>
 
diff --git a/drivers/mtd/nand/raw/fsl_elbc_nand.c b/drivers/mtd/nand/raw/fsl_elbc_nand.c
index 3aa88346d7cc..ed84b25e8e6e 100644
--- a/drivers/mtd/nand/raw/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_elbc_nand.c
@@ -35,7 +35,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <asm/io.h>
diff --git a/drivers/mtd/nand/raw/fsl_ifc_nand.c b/drivers/mtd/nand/raw/fsl_ifc_nand.c
index 3815487bcddd..ac85e9dd1318 100644
--- a/drivers/mtd/nand/raw/fsl_ifc_nand.c
+++ b/drivers/mtd/nand/raw/fsl_ifc_nand.c
@@ -28,7 +28,6 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
 #include <linux/mtd/partitions.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/fsl_ifc.h>
 #include <linux/iopoll.h>
 
diff --git a/drivers/mtd/nand/raw/fsl_upm.c b/drivers/mtd/nand/raw/fsl_upm.c
index c60bd00d9f2b..224ba9449fc2 100644
--- a/drivers/mtd/nand/raw/fsl_upm.c
+++ b/drivers/mtd/nand/raw/fsl_upm.c
@@ -15,7 +15,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/mtd.h>
 #include <linux/of_address.h>
diff --git a/drivers/mtd/nand/raw/fsmc_nand.c b/drivers/mtd/nand/raw/fsmc_nand.c
index 91e813fe7dd8..797028037f78 100644
--- a/drivers/mtd/nand/raw/fsmc_nand.c
+++ b/drivers/mtd/nand/raw/fsmc_nand.c
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/platform_device.h>
 #include <linux/of.h>
 #include <linux/mtd/partitions.h>
diff --git a/drivers/mtd/nand/raw/lpc32xx_mlc.c b/drivers/mtd/nand/raw/lpc32xx_mlc.c
index b821dc083542..af75eabddc6f 100644
--- a/drivers/mtd/nand/raw/lpc32xx_mlc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_mlc.c
@@ -41,7 +41,6 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 
 #define DRV_NAME "lpc32xx_mlc"
 
diff --git a/drivers/mtd/nand/raw/lpc32xx_slc.c b/drivers/mtd/nand/raw/lpc32xx_slc.c
index f2924ea8e126..5629ef7750aa 100644
--- a/drivers/mtd/nand/raw/lpc32xx_slc.c
+++ b/drivers/mtd/nand/raw/lpc32xx_slc.c
@@ -32,7 +32,6 @@
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmaengine.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/gpio.h>
 #include <linux/of.h>
 #include <linux/of_gpio.h>
diff --git a/drivers/mtd/nand/raw/pasemi_nand.c b/drivers/mtd/nand/raw/pasemi_nand.c
index 3944dc653609..3b6f51a31e7d 100644
--- a/drivers/mtd/nand/raw/pasemi_nand.c
+++ b/drivers/mtd/nand/raw/pasemi_nand.c
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
diff --git a/drivers/mtd/nand/raw/s3c2410.c b/drivers/mtd/nand/raw/s3c2410.c
index 8d79813e83d5..b8462b9b4276 100644
--- a/drivers/mtd/nand/raw/s3c2410.c
+++ b/drivers/mtd/nand/raw/s3c2410.c
@@ -43,7 +43,6 @@
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 #include <linux/platform_data/mtd-nand-s3c2410.h>
diff --git a/drivers/mtd/nand/raw/sharpsl.c b/drivers/mtd/nand/raw/sharpsl.c
index 35baff68993f..df542d77b1db 100644
--- a/drivers/mtd/nand/raw/sharpsl.c
+++ b/drivers/mtd/nand/raw/sharpsl.c
@@ -16,7 +16,6 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/sharpsl.h>
 #include <linux/interrupt.h>
diff --git a/drivers/mtd/nand/raw/tmio_nand.c b/drivers/mtd/nand/raw/tmio_nand.c
index 7eeef6634c0c..6fac98df3a92 100644
--- a/drivers/mtd/nand/raw/tmio_nand.c
+++ b/drivers/mtd/nand/raw/tmio_nand.c
@@ -35,7 +35,6 @@
 #include <linux/ioport.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/slab.h>
 
diff --git a/drivers/mtd/nand/raw/txx9ndfmc.c b/drivers/mtd/nand/raw/txx9ndfmc.c
index 85019684dee7..afdb947253bf 100644
--- a/drivers/mtd/nand/raw/txx9ndfmc.c
+++ b/drivers/mtd/nand/raw/txx9ndfmc.c
@@ -17,7 +17,6 @@
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 #include <linux/platform_data/txx9/ndfmc.h>
diff --git a/include/linux/mtd/sharpsl.h b/include/linux/mtd/sharpsl.h
index 77528c2e0a80..3375a9958cfe 100644
--- a/include/linux/mtd/sharpsl.h
+++ b/include/linux/mtd/sharpsl.h
@@ -9,7 +9,6 @@
  */
 
 #include <linux/mtd/rawnand.h>
-#include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/partitions.h>
 
 struct sharpsl_nand_platform_data {
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 15/27] mtd: nand: Remove useless include about software Hamming ECC Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-21 13:48   ` Adam Ford
  2019-02-21 12:57 ` [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected Miquel Raynal
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

There is no reason to prevent the software BCH ECC engine
implementation to be compiled as a module, so change the 'bool' into a
'tristate'.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc/Kconfig           | 2 +-
 include/linux/mtd/nand-sw-bch-engine.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
index 6ce9007e1d9b..e0106b3a7ec1 100644
--- a/drivers/mtd/nand/ecc/Kconfig
+++ b/drivers/mtd/nand/ecc/Kconfig
@@ -12,7 +12,7 @@ config MTD_NAND_ECC_SW_HAMMING_SMC
 	  The original Linux implementation had byte 0 and 1 swapped.
 
 config MTD_NAND_ECC_SW_BCH
-	bool "Software BCH ECC engine"
+	tristate "Software BCH ECC engine"
 	select BCH
 	default n
 	help
diff --git a/include/linux/mtd/nand-sw-bch-engine.h b/include/linux/mtd/nand-sw-bch-engine.h
index d8abfc9fc288..5d0b98e34a3a 100644
--- a/include/linux/mtd/nand-sw-bch-engine.h
+++ b/include/linux/mtd/nand-sw-bch-engine.h
@@ -33,7 +33,7 @@ struct ecc_sw_bch_conf {
 	unsigned char *eccmask;
 };
 
-#if defined(CONFIG_MTD_NAND_ECC_SW_BCH)
+#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)
 
 int ecc_sw_bch_calculate(struct nand_device *nand, const unsigned char *buf,
 			 unsigned char *code);
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (2 preceding siblings ...)
  2019-02-21 12:57 ` [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-21 13:20   ` Boris Brezillon
  2019-02-21 12:57 ` [RFC PATCH 18/27] mtd: nand: ecc: Create the software BCH engine instance Miquel Raynal
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

There is no reason to always embed the software Hamming ECC engine
implementation. By default it is, but we can let the user decide.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc/Kconfig               | 10 +++++-
 drivers/mtd/nand/raw/Kconfig               |  2 +-
 include/linux/mtd/nand-sw-hamming-engine.h | 38 ++++++++++++++++++++++
 3 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
index e0106b3a7ec1..ff20e621ffef 100644
--- a/drivers/mtd/nand/ecc/Kconfig
+++ b/drivers/mtd/nand/ecc/Kconfig
@@ -1,7 +1,15 @@
 menu "ECC engine support"
 
 config MTD_NAND_ECC_SW_HAMMING
-	tristate
+	tristate "Software Hamming ECC engine"
+	default y
+	help
+	  This enables support for software Hamming error
+	  correction. This correction can correct up to 1 bit error
+	  per chunk and detect up to 2 bit errors. While it used to be
+	  widely used with old parts, newer NAND chips usually require
+	  more strength correction and in this case BCH or RS will be
+	  preferred.
 
 config MTD_NAND_ECC_SW_HAMMING_SMC
 	bool "NAND ECC Smart Media byte order"
diff --git a/drivers/mtd/nand/raw/Kconfig b/drivers/mtd/nand/raw/Kconfig
index 995fa78bdedb..76a2a8493b1f 100644
--- a/drivers/mtd/nand/raw/Kconfig
+++ b/drivers/mtd/nand/raw/Kconfig
@@ -1,6 +1,5 @@
 menuconfig MTD_RAW_NAND
 	tristate "Raw/Parallel NAND Device Support"
-	select MTD_NAND_ECC_SW_HAMMING
 	help
 	  This enables support for accessing all type of raw/parallel
 	  NAND flash devices. For further information see
@@ -69,6 +68,7 @@ config MTD_NAND_AU1550
 config MTD_NAND_NDFC
 	tristate "IBM/MCC 4xx NAND controller"
 	depends on 4xx
+	depends on MTD_NAND_ECC_SW_HAMMING
 	select MTD_NAND_ECC_SW_HAMMING_SMC
 	help
 	  NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs
diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
index c50da3a255b7..378ba46f7e1d 100644
--- a/include/linux/mtd/nand-sw-hamming-engine.h
+++ b/include/linux/mtd/nand-sw-hamming-engine.h
@@ -30,6 +30,8 @@ struct ecc_sw_hamming_conf {
 	unsigned int sm_order;
 };
 
+#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
+
 int __ecc_sw_hamming_calculate(const unsigned char *buf,
 			       unsigned int step_size,
 			       unsigned char *code, bool sm_order);
@@ -42,4 +44,40 @@ int __ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
 int ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
 			   unsigned char *read_ecc, unsigned char *calc_ecc);
 
+#else /* !CONFIG_MTD_NAND_ECC_SW_HAMMING */
+
+static inline int __ecc_sw_hamming_calculate(const unsigned char *buf,
+					     unsigned int step_size,
+					     unsigned char *code,
+					     bool sm_order)
+{
+	return -ENOTSUPP;
+}
+
+static inline int ecc_sw_hamming_calculate(struct nand_device *nand,
+					   const unsigned char *buf,
+					   unsigned char *code)
+{
+	return -ENOTSUPP;
+}
+
+static inline int __ecc_sw_hamming_correct(unsigned char *buf,
+					   unsigned char *read_ecc,
+					   unsigned char *calc_ecc,
+					   unsigned int step_size,
+					   bool sm_order)
+{
+	return -ENOTSUPP;
+}
+
+static inline int ecc_sw_hamming_correct(struct nand_device *nand,
+					 unsigned char *buf,
+					 unsigned char *read_ecc,
+					 unsigned char *calc_ecc)
+{
+	return -ENOTSUPP;
+}
+
+#endif /* CONFIG_MTD_NAND_ECC_SW_HAMMING */
+
 #endif /* __MTD_NAND_ECC_SW_HAMMING_H__ */
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 18/27] mtd: nand: ecc: Create the software BCH engine instance
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (3 preceding siblings ...)
  2019-02-21 12:57 ` [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 19/27] mtd: nand: ecc: Create the software Hamming " Miquel Raynal
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Let's continue introducing the generic ECC engine abstraction in the
NAND subsystem by instantiating a first ECC engine: the software
BCH one.

While at it, make a very tidy ecc_sw_bch_init() function and move all
the sanity checks and user input management in
ecc_sw_bch_init_ctx(). This second helper will be called from the raw
NAND core.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc/sw-bch-engine.c   | 338 ++++++++++++++++++++-----
 drivers/mtd/nand/raw/nand_base.c       |  62 +----
 include/linux/mtd/nand-sw-bch-engine.h |  14 +-
 3 files changed, 300 insertions(+), 114 deletions(-)

diff --git a/drivers/mtd/nand/ecc/sw-bch-engine.c b/drivers/mtd/nand/ecc/sw-bch-engine.c
index fd982e520989..156a0d6922a1 100644
--- a/drivers/mtd/nand/ecc/sw-bch-engine.c
+++ b/drivers/mtd/nand/ecc/sw-bch-engine.c
@@ -81,7 +81,7 @@ EXPORT_SYMBOL(ecc_sw_bch_correct);
  * ecc_sw_bch_cleanup - Cleanup software BCH ECC resources
  * @nand: NAND device
  */
-void ecc_sw_bch_cleanup(struct nand_device *nand)
+static void ecc_sw_bch_cleanup(struct nand_device *nand)
 {
 	struct ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
 
@@ -89,7 +89,6 @@ void ecc_sw_bch_cleanup(struct nand_device *nand)
 	kfree(engine_conf->errloc);
 	kfree(engine_conf->eccmask);
 }
-EXPORT_SYMBOL(ecc_sw_bch_cleanup);
 
 /**
  * ecc_sw_bch_init - Initialize software BCH ECC engine
@@ -106,70 +105,36 @@ EXPORT_SYMBOL(ecc_sw_bch_cleanup);
  * step_size = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8)
  * bytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits)
  */
-int ecc_sw_bch_init(struct nand_device *nand)
+static int ecc_sw_bch_init(struct nand_device *nand)
 {
-	struct mtd_info *mtd = nanddev_to_mtd(nand);
-	unsigned int m, t, eccsteps, i;
 	struct ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
-	unsigned char *erased_page;
 	unsigned int eccsize = nand->ecc.ctx.conf.step_size;
 	unsigned int eccbytes = engine_conf->code_size;
-	unsigned int eccstrength = nand->ecc.ctx.conf.strength;
+	unsigned int m, t, i;
+	unsigned char *erased_page;
+	int ret;
 
-	if (!eccbytes && eccstrength) {
-		eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
-		engine_conf->code_size = eccbytes;
-	}
-
-	if (!eccsize || !eccbytes) {
-		pr_warn("ecc parameters not supplied\n");
-		return -EINVAL;
-	}
-
-	m = fls(1+8*eccsize);
-	t = (eccbytes*8)/m;
+	m = fls(1 + (8 * eccsize));
+	t = (eccbytes * 8) / m;
 
 	engine_conf->bch = init_bch(m, t, 0);
 	if (!engine_conf->bch)
 		return -EINVAL;
 
-	/* verify that eccbytes has the expected value */
-	if (engine_conf->bch->ecc_bytes != eccbytes) {
-		pr_warn("invalid eccbytes %u, should be %u\n",
-			eccbytes, engine_conf->bch->ecc_bytes);
-		goto fail;
-	}
-
-	eccsteps = mtd->writesize/eccsize;
-
-	/* Check that we have an oob layout description. */
-	if (!mtd->ooblayout) {
-		pr_warn("missing oob scheme");
-		goto fail;
-	}
-
-	/* sanity checks */
-	if (8*(eccsize+eccbytes) >= (1 << m)) {
-		pr_warn("eccsize %u is too large\n", eccsize);
-		goto fail;
-	}
-
-	if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
-		pr_warn("invalid ecc layout\n");
-		goto fail;
-	}
-
 	engine_conf->eccmask = kmalloc(eccbytes, GFP_KERNEL);
 	engine_conf->errloc = kmalloc_array(t, sizeof(*engine_conf->errloc),
 					    GFP_KERNEL);
-	if (!engine_conf->eccmask || !engine_conf->errloc)
-		goto fail;
-	/*
-	 * compute and store the inverted ecc of an erased ecc block
-	 */
+	if (!engine_conf->eccmask || !engine_conf->errloc) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
+
+	/* Compute and store the inverted ECC of an erased step */
 	erased_page = kmalloc(eccsize, GFP_KERNEL);
-	if (!erased_page)
-		goto fail;
+	if (!erased_page) {
+		ret = -ENOMEM;
+		goto cleanup;
+	}
 
 	memset(erased_page, 0xff, eccsize);
 	memset(engine_conf->eccmask, 0, eccbytes);
@@ -180,17 +145,276 @@ int ecc_sw_bch_init(struct nand_device *nand)
 	for (i = 0; i < eccbytes; i++)
 		engine_conf->eccmask[i] ^= 0xff;
 
-	if (!eccstrength)
-		nand->ecc.ctx.conf.strength = (eccbytes * 8) / fls(8 * eccsize);
+	/* Verify that the number of code bytes has the expected value */
+	if (engine_conf->bch->ecc_bytes != eccbytes) {
+		pr_err("Invalid number of ECC bytes: %u, expected: %u\n",
+		       eccbytes, engine_conf->bch->ecc_bytes);
+		ret = -EINVAL;
+		goto cleanup;
+	}
+
+	/* Sanity checks */
+	if (8 * (eccsize + eccbytes) >= (1 << m)) {
+		pr_err("ECC step size is too large (%u)\n", eccsize);
+		ret = -EINVAL;
+		goto cleanup;
+	}
 
 	return 0;
 
-fail:
+cleanup:
 	ecc_sw_bch_cleanup(nand);
 
-	return -EINVAL;
+	return ret;
+}
+
+int ecc_sw_bch_init_ctx(struct nand_device *nand)
+{
+	struct nand_ecc_conf *conf = &nand->ecc.ctx.conf;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct ecc_sw_bch_conf *engine_conf;
+	unsigned int code_size = 0, nsteps;
+	int ret;
+
+	/* Only large page NAND chips may use BCH */
+	if (mtd->oobsize < 64) {
+		pr_err("BCH cannot be used with small page NAND chips\n");
+		return -EINVAL;
+	}
+
+	if (!mtd->ooblayout)
+		mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
+
+	conf->step_size = nand->ecc.user_conf.step_size;
+	conf->strength = nand->ecc.user_conf.strength;
+
+	/*
+	 * Board driver should supply ECC size and ECC strength
+	 * values to select how many bits are correctable.
+	 * Otherwise, default to 512 bytes for large page devices and 256 for
+	 * small page devices.
+	 */
+	if (!conf->step_size) {
+		if (mtd->oobsize >= 64)
+			conf->step_size = 512;
+		else
+			conf->step_size = 256;
+
+		conf->strength = 4;
+	}
+
+	nsteps = mtd->writesize / conf->step_size;
+
+	/* Maximize */
+	if (nand->ecc.user_conf.maximize) {
+		conf->step_size = 1024;
+		nsteps = mtd->writesize / conf->step_size;
+		/* Reserve 2 bytes for the BBM */
+		code_size = (mtd->oobsize - 2) / nsteps;
+		conf->strength = code_size * 8 / fls(8 * conf->step_size);
+	}
+
+	if (!code_size)
+		code_size = DIV_ROUND_UP(conf->strength *
+					 fls(8 * conf->step_size), 8);
+
+	if (!conf->strength)
+		conf->strength = (code_size * 8) / fls(8 * conf->step_size);
+
+	if (!code_size && !conf->strength) {
+		pr_err("Missing ECC parameters\n");
+		return -EINVAL;
+	}
+
+	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
+	if (!engine_conf)
+		return -ENOMEM;
+
+	engine_conf->code_size = code_size;
+	engine_conf->nsteps = nsteps;
+	conf->total = nsteps * code_size;
+	engine_conf->calc_buf = kzalloc(sizeof(mtd->oobsize), GFP_KERNEL);
+	engine_conf->code_buf = kzalloc(sizeof(mtd->oobsize), GFP_KERNEL);
+	if (!engine_conf->calc_buf || !engine_conf->code_buf) {
+		kfree(engine_conf);
+		return -ENOMEM;
+	}
+
+	nand->ecc.ctx.priv = engine_conf;
+
+	ret = ecc_sw_bch_init(nand);
+	if (ret) {
+		kfree(engine_conf->calc_buf);
+		kfree(engine_conf->code_buf);
+		kfree(engine_conf);
+		return -ENOMEM;
+	}
+
+	/* Verify the layout validity */
+	if (mtd_ooblayout_count_eccbytes(mtd) !=
+	    engine_conf->nsteps * engine_conf->code_size) {
+		pr_err("Invalid ECC layout\n");
+		ecc_sw_bch_cleanup(nand);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(ecc_sw_bch_init_ctx);
+
+void ecc_sw_bch_cleanup_ctx(struct nand_device *nand)
+{
+	struct ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
+
+	if (engine_conf) {
+		ecc_sw_bch_cleanup(nand);
+		kfree(engine_conf->calc_buf);
+		kfree(engine_conf->code_buf);
+		kfree(engine_conf);
+	}
+}
+EXPORT_SYMBOL(ecc_sw_bch_cleanup_ctx);
+
+static int ecc_sw_bch_prepare_io_req(struct nand_device *nand,
+				     struct nand_page_io_req *req,
+				     void *oobbuf)
+{
+	struct ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	int eccsize = nand->ecc.ctx.conf.step_size;
+	int eccbytes = engine_conf->code_size;
+	int eccsteps = engine_conf->nsteps;
+	int total = nand->ecc.ctx.conf.total;
+	u8 *ecccalc = engine_conf->calc_buf;
+	const u8 *data = req->databuf.out;
+	int i, ret;
+
+	/* Ensure the OOB buffer is empty before using it */
+	if (req->oobbuf.in)
+		memset(req->oobbuf.in, 0xff, nanddev_per_page_oobsize(nand));
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen)
+		return 0;
+
+	/*
+	 * Ensure OOB area is fully read/written otherwise the software
+	 * correction cannot not apply.
+	 */
+	engine_conf->reqooblen = req->ooblen;
+	req->ooblen = nanddev_per_page_oobsize(nand);
+
+	/* No more preparation for page read */
+	if (req->type == NAND_PAGE_READ)
+		return 0;
+
+	/* Preparation for page write: derive the ECC bytes and place them */
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize)
+		ecc_sw_bch_calculate(nand, data, &ecccalc[i]);
+
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecccalc, oobbuf, 0, total);
+
+	/* Also place user data OOB bytes in the free area, if any */
+	if (engine_conf->reqooblen) {
+		if (req->mode == MTD_OPS_AUTO_OOB)
+			mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
+						    oobbuf,
+						    req->ooboffs,
+						    req->ooblen);
+		else
+			memcpy(oobbuf + req->ooboffs, req->oobbuf.out,
+			       req->ooblen);
+	}
+
+	return ret;
+}
+
+static int ecc_sw_bch_finish_io_req(struct nand_device *nand,
+				    struct nand_page_io_req *req,
+				    void *oobbuf)
+{
+	struct ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	int eccsize = nand->ecc.ctx.conf.step_size;
+	int total = nand->ecc.ctx.conf.total;
+	int eccbytes = engine_conf->code_size;
+	int eccsteps = engine_conf->nsteps;
+	u8 *ecccalc = engine_conf->calc_buf;
+	u8 *ecccode = engine_conf->code_buf;
+	unsigned int max_bitflips = 0;
+	u8 *data = req->databuf.in;
+	int i, ret;
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen)
+		return 0;
+
+	/* Don't mess up with the upper layer: restore the request OOB length */
+	req->ooblen = engine_conf->reqooblen;
+
+	/* Nothing more to do for page write */
+	if (req->type == NAND_PAGE_WRITE)
+		return 0;
+
+	/* Finish a page read: retrieve the (raw) ECC bytes*/
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecccode, oobbuf, 0, total);
+	if (ret)
+		return ret;
+
+	/* Calculate the ECC bytes */
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize)
+		ecc_sw_bch_calculate(nand, data, &ecccalc[i]);
+
+	/* Finish a page read: compare and correct */
+	for (eccsteps = engine_conf->nsteps, i = 0, data = req->databuf.in;
+	     eccsteps;
+	     eccsteps--, i += eccbytes, data += eccsize) {
+		int stat =  ecc_sw_bch_correct(nand, data,
+					       &ecccode[i],
+					       &ecccalc[i]);
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+
+	/* Format the OOB buffer that will be returned to the user */
+	if (req->ooblen) {
+		if (req->mode == MTD_OPS_AUTO_OOB)
+			mtd_ooblayout_get_databytes(mtd, oobbuf,
+						    req->oobbuf.in,
+						    req->ooboffs, req->ooblen);
+		else
+			memcpy(req->oobbuf.in, oobbuf + req->ooboffs,
+			       req->ooblen);
+	}
+
+	return max_bitflips;
+}
+
+static struct nand_ecc_engine_ops sw_bch_engine_ops = {
+	.init_ctx = ecc_sw_bch_init_ctx,
+	.cleanup_ctx = ecc_sw_bch_cleanup_ctx,
+	.prepare_io_req = ecc_sw_bch_prepare_io_req,
+	.finish_io_req = ecc_sw_bch_finish_io_req,
+};
+
+static struct nand_ecc_engine sw_bch_engine = {
+	.ops = &sw_bch_engine_ops,
+};
+
+struct nand_ecc_engine *ecc_sw_bch_get_engine(void)
+{
+	return &sw_bch_engine;
 }
-EXPORT_SYMBOL(ecc_sw_bch_init);
 
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>");
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index 751bed07fd62..bfefa6009b04 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4920,17 +4920,11 @@ int rawnand_sw_bch_init(struct nand_chip *chip)
 	base->ecc.user_conf.step_size = chip->ecc.size;
 	base->ecc.user_conf.strength = chip->ecc.strength;
 
-	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
-	if (!engine_conf)
-		return -ENOMEM;
-
-	engine_conf->code_size = chip->ecc.bytes;
-
-	base->ecc.ctx.priv = engine_conf;
-
-	ret = ecc_sw_bch_init(base);
+	ret = ecc_sw_bch_init_ctx(base);
 	if (ret)
-		kfree(base->ecc.ctx.priv);
+		return ret;
+
+	engine_conf = base->ecc.ctx.priv;
 
 	chip->ecc.size = base->ecc.ctx.conf.step_size;
 	chip->ecc.strength = base->ecc.ctx.conf.strength;
@@ -4938,7 +4932,7 @@ int rawnand_sw_bch_init(struct nand_chip *chip)
 	chip->ecc.steps = engine_conf->nsteps;
 	chip->ecc.bytes = engine_conf->code_size;
 
-	return ret;
+	return 0;
 }
 EXPORT_SYMBOL(rawnand_sw_bch_init);
 
@@ -4964,9 +4958,7 @@ void rawnand_sw_bch_cleanup(struct nand_chip *chip)
 {
 	struct nand_device *base = &chip->base;
 
-	ecc_sw_bch_cleanup(base);
-
-	kfree(base->ecc.ctx.priv);
+	ecc_sw_bch_cleanup_ctx(base);
 }
 EXPORT_SYMBOL(rawnand_sw_bch_cleanup);
 
@@ -5021,51 +5013,15 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
 		ecc->read_oob = nand_read_oob_std;
 		ecc->write_oob = nand_write_oob_std;
 
-		/*
-		* Board driver should supply ecc.size and ecc.strength
-		* values to select how many bits are correctable.
-		* Otherwise, default to 4 bits for large page devices.
-		*/
-		if (!ecc->size && (mtd->oobsize >= 64)) {
-			ecc->size = 512;
-			ecc->strength = 4;
-		}
-
-		/*
-		 * if no ecc placement scheme was provided pickup the default
-		 * large page one.
-		 */
-		if (!mtd->ooblayout) {
-			/* handle large page devices only */
-			if (mtd->oobsize < 64) {
-				WARN(1, "OOB layout is required when using software BCH on small pages\n");
-				return -EINVAL;
-			}
-
-			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops);
-
-		}
-
 		/*
 		 * We can only maximize ECC config when the default layout is
 		 * used, otherwise we don't know how many bytes can really be
 		 * used.
 		 */
-		if (mtd->ooblayout == &nand_ooblayout_lp_ops &&
-		    nanddev->ecc.user_conf.maximize) {
-			int steps, bytes;
+		if (nanddev->ecc.user_conf.maximize &&
+		    mtd->ooblayout != &nand_ooblayout_lp_ops)
+			nanddev->ecc.user_conf.maximize = false;
 
-			/* Always prefer 1k blocks over 512bytes ones */
-			ecc->size = 1024;
-			steps = mtd->writesize / ecc->size;
-
-			/* Reserve 2 bytes for the BBM */
-			bytes = (mtd->oobsize - 2) / steps;
-			ecc->strength = bytes * 8 / fls(8 * ecc->size);
-		}
-
-		/* See ecc_sw_bch_init() for details. */
-		ecc->bytes = 0;
 		ret = rawnand_sw_bch_init(chip);
 		if (ret) {
 			WARN(1, "BCH ECC initialization failed!\n");
diff --git a/include/linux/mtd/nand-sw-bch-engine.h b/include/linux/mtd/nand-sw-bch-engine.h
index 5d0b98e34a3a..e406aa53ec4e 100644
--- a/include/linux/mtd/nand-sw-bch-engine.h
+++ b/include/linux/mtd/nand-sw-bch-engine.h
@@ -39,8 +39,9 @@ int ecc_sw_bch_calculate(struct nand_device *nand, const unsigned char *buf,
 			 unsigned char *code);
 int ecc_sw_bch_correct(struct nand_device *nand, unsigned char *buf,
 		       unsigned char *read_ecc, unsigned char *calc_ecc);
-int ecc_sw_bch_init(struct nand_device *nand);
-void ecc_sw_bch_cleanup(struct nand_device *nand);
+int ecc_sw_bch_init_ctx(struct nand_device *nand);
+void ecc_sw_bch_cleanup_ctx(struct nand_device *nand);
+struct nand_ecc_engine *ecc_sw_bch_get_engine(void);
 
 #else /* !CONFIG_MTD_NAND_ECC_SW_BCH */
 
@@ -59,12 +60,17 @@ static inline int ecc_sw_bch_correct(struct nand_device *nand,
 	return -ENOTSUPP;
 }
 
-static inline int ecc_sw_bch_init(struct nand_device *nand)
+static inline int ecc_sw_bch_init_ctx(struct nand_device *nand)
 {
 	return -EINVAL;
 }
 
-static inline void ecc_sw_bch_cleanup(struct nand_device *nand) {}
+static inline void ecc_sw_bch_cleanup_ctx(struct nand_device *nand) {}
+
+static inline struct nand_ecc_engine *ecc_sw_bch_get_engine(void)
+{
+	return NULL;
+}
 
 #endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
 
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 19/27] mtd: nand: ecc: Create the software Hamming engine instance
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (4 preceding siblings ...)
  2019-02-21 12:57 ` [RFC PATCH 18/27] mtd: nand: ecc: Create the software BCH engine instance Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-21 12:57 ` [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core Miquel Raynal
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Let's continue introducing the generic ECC engine abstraction in the
NAND subsystem by instantiating a second ECC engine: the software
Hamming one.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc/sw-hamming-engine.c   | 201 +++++++++++++++++++++
 drivers/mtd/nand/raw/nand_base.c           |  28 ++-
 include/linux/mtd/nand-sw-hamming-engine.h |  15 ++
 3 files changed, 227 insertions(+), 17 deletions(-)

diff --git a/drivers/mtd/nand/ecc/sw-hamming-engine.c b/drivers/mtd/nand/ecc/sw-hamming-engine.c
index 3918daf5547b..58c81c812709 100644
--- a/drivers/mtd/nand/ecc/sw-hamming-engine.c
+++ b/drivers/mtd/nand/ecc/sw-hamming-engine.c
@@ -465,6 +465,207 @@ int ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
 }
 EXPORT_SYMBOL(ecc_sw_hamming_correct);
 
+int ecc_sw_hamming_init_ctx(struct nand_device *nand)
+{
+	struct nand_ecc_conf *conf = &nand->ecc.ctx.conf;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct ecc_sw_hamming_conf *engine_conf;
+
+	if (!mtd->ooblayout) {
+		switch (mtd->oobsize) {
+		case 8:
+		case 16:
+			mtd_set_ooblayout(mtd, &nand_ooblayout_sp_ops);
+			break;
+		case 64:
+		case 128:
+			mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops);
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	conf->step_size = nand->ecc.user_conf.step_size;
+	conf->strength = 1;
+
+	/* Use the strongest configuration by default */
+	if (conf->step_size != 256 && conf->step_size != 512)
+		conf->step_size = 256;
+
+	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
+	if (!engine_conf)
+		return -ENOMEM;
+
+	engine_conf->code_size = 3;
+	engine_conf->nsteps = mtd->writesize / conf->step_size;
+	engine_conf->calc_buf = kzalloc(sizeof(mtd->oobsize), GFP_KERNEL);
+	engine_conf->code_buf = kzalloc(sizeof(mtd->oobsize), GFP_KERNEL);
+	if (!engine_conf->calc_buf || !engine_conf->code_buf) {
+		kfree(engine_conf);
+		return -ENOMEM;
+	}
+
+	nand->ecc.ctx.priv = engine_conf;
+
+	return 0;
+}
+
+void ecc_sw_hamming_cleanup_ctx(struct nand_device *nand)
+{
+	struct ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
+
+	if (engine_conf) {
+		kfree(engine_conf->calc_buf);
+		kfree(engine_conf->code_buf);
+	}
+
+	kfree(engine_conf);
+}
+
+static int ecc_sw_hamming_prepare_io_req(struct nand_device *nand,
+					 struct nand_page_io_req *req,
+					 void *oobbuf)
+{
+	struct ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	int eccsize = nand->ecc.ctx.conf.step_size;
+	int eccbytes = engine_conf->code_size;
+	int eccsteps = engine_conf->nsteps;
+	int total = nand->ecc.ctx.conf.total;
+	u8 *ecccalc = engine_conf->calc_buf;
+	const u8 *data = req->databuf.out;
+	int i, ret;
+
+	/* Ensure the OOB buffer is empty before using it */
+	if (req->oobbuf.in)
+		memset(req->oobbuf.in, 0xff, nanddev_per_page_oobsize(nand));
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen)
+		return 0;
+
+	/*
+	 * Ensure OOB area is fully read/written otherwise the software
+	 * correction cannot not apply.
+	 */
+	engine_conf->reqooblen = req->ooblen;
+	req->ooblen = nanddev_per_page_oobsize(nand);
+
+	/* No preparation for page read */
+	if (req->type == NAND_PAGE_READ)
+		return 0;
+
+	/* Preparation for page write: derive the ECC bytes and place them */
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize)
+		ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
+
+	ret = mtd_ooblayout_set_eccbytes(mtd, ecccalc, oobbuf, 0, total);
+
+	/* Also place user data OOB bytes in the free area, if any */
+	if (engine_conf->reqooblen) {
+		if (req->mode == MTD_OPS_AUTO_OOB)
+			mtd_ooblayout_set_databytes(mtd, req->oobbuf.out,
+						    oobbuf,
+						    req->ooboffs,
+						    req->ooblen);
+		else
+			memcpy(oobbuf + req->ooboffs, req->oobbuf.out,
+			       req->ooblen);
+	}
+
+	return ret;
+}
+
+static int ecc_sw_hamming_finish_io_req(struct nand_device *nand,
+					struct nand_page_io_req *req,
+					void *oobbuf)
+{
+	struct ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv;
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	int eccsize = nand->ecc.ctx.conf.step_size;
+	int total = nand->ecc.ctx.conf.total;
+	int eccbytes = engine_conf->code_size;
+	int eccsteps = engine_conf->nsteps;
+	u8 *ecccalc = engine_conf->calc_buf;
+	u8 *ecccode = engine_conf->code_buf;
+	unsigned int max_bitflips = 0;
+	u8 *data = req->databuf.in;
+	int i, ret;
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	/* This engine does not provide BBM/free OOB bytes protection */
+	if (!req->datalen)
+		return 0;
+
+	/* Don't mess up with the upper layer: restore the request OOB length */
+	req->ooblen = engine_conf->reqooblen;
+
+	/* Nothing more to do for page write */
+	if (req->type == NAND_PAGE_WRITE)
+		return 0;
+
+	/* Finish a page read: retrieve the (raw) ECC bytes*/
+	ret = mtd_ooblayout_get_eccbytes(mtd, ecccode, oobbuf, 0, total);
+	if (ret)
+		return ret;
+
+	/* Calculate the ECC bytes */
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize)
+		ecc_sw_hamming_calculate(nand, data, &ecccalc[i]);
+
+	eccsteps = engine_conf->nsteps;
+
+	/* Finish a page read: compare and correct */
+	for (eccsteps = engine_conf->nsteps, i = 0, data = req->databuf.in;
+	     eccsteps;
+	     eccsteps--, i += eccbytes, data += eccsize) {
+		int stat =  ecc_sw_hamming_correct(nand, data,
+					       &ecccode[i],
+					       &ecccalc[i]);
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
+
+	/* Format the OOB buffer that will be returned to the user */
+	if (req->ooblen) {
+		if (req->mode == MTD_OPS_AUTO_OOB)
+			mtd_ooblayout_get_databytes(mtd, oobbuf,
+						    req->oobbuf.in,
+						    req->ooboffs, req->ooblen);
+		else
+			memcpy(req->oobbuf.in, oobbuf + req->ooboffs,
+			       req->ooblen);
+	}
+
+	return max_bitflips;
+}
+
+static struct nand_ecc_engine_ops sw_hamming_engine_ops = {
+	.init_ctx = ecc_sw_hamming_init_ctx,
+	.cleanup_ctx = ecc_sw_hamming_cleanup_ctx,
+	.prepare_io_req = ecc_sw_hamming_prepare_io_req,
+	.finish_io_req = ecc_sw_hamming_finish_io_req,
+};
+
+static struct nand_ecc_engine sw_hamming_engine = {
+	.ops = &sw_hamming_engine_ops,
+};
+
+struct nand_ecc_engine *ecc_sw_hamming_get_engine(void)
+{
+	return &sw_hamming_engine;
+}
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Frans Meulenbroeks <fransmeulenbroeks@gmail.com>");
 MODULE_DESCRIPTION("NAND software Hamming ECC support");
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c
index bfefa6009b04..1ed90fd512d7 100644
--- a/drivers/mtd/nand/raw/nand_base.c
+++ b/drivers/mtd/nand/raw/nand_base.c
@@ -4845,34 +4845,27 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
 
 int rawnand_sw_hamming_init(struct nand_chip *chip)
 {
-	struct mtd_info *mtd = nand_to_mtd(chip);
 	struct ecc_sw_hamming_conf *engine_conf;
 	struct nand_device *base = &chip->base;
+	int ret;
 
 	base->ecc.user_conf.mode = NAND_ECC_SOFT;
 	base->ecc.user_conf.algo = NAND_ECC_HAMMING;
 	base->ecc.user_conf.strength = chip->ecc.strength;
 	base->ecc.user_conf.step_size = chip->ecc.size;
 
-	if (base->ecc.user_conf.strength != 1 ||
-	    (base->ecc.user_conf.step_size != 256 &&
-	     base->ecc.user_conf.step_size != 512)) {
-		pr_err("%s: unsupported strength or step size\n", __func__);
-		return -EINVAL;
-	}
+	ret = ecc_sw_hamming_init_ctx(base);
+	if (ret)
+		return ret;
 
-	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
-	if (!engine_conf)
-		return -ENOMEM;
-
-	engine_conf->code_size = 3;
-	engine_conf->nsteps = mtd->writesize / base->ecc.user_conf.step_size;
+	engine_conf = base->ecc.ctx.priv;
 
 	if (chip->ecc.options & NAND_ECC_SOFT_HAMMING_SM_ORDER)
 		engine_conf->sm_order = true;
 
-	base->ecc.ctx.priv = engine_conf;
-
+	chip->ecc.size = base->ecc.ctx.conf.step_size;
+	chip->ecc.strength = base->ecc.ctx.conf.strength;
+	chip->ecc.total = base->ecc.ctx.conf.total;
 	chip->ecc.steps = engine_conf->nsteps;
 	chip->ecc.bytes = engine_conf->code_size;
 
@@ -4905,7 +4898,7 @@ void rawnand_sw_hamming_cleanup(struct nand_chip *chip)
 {
 	struct nand_device *base = &chip->base;
 
-	kfree(base->ecc.ctx.priv);
+	ecc_sw_hamming_cleanup_ctx(base);
 }
 EXPORT_SYMBOL(rawnand_sw_hamming_cleanup);
 
@@ -5369,7 +5362,8 @@ static int nand_scan_tail(struct nand_chip *chip)
 	 * If no default placement scheme is given, select an appropriate one.
 	 */
 	if (!mtd->ooblayout &&
-	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH)) {
+	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_BCH) &&
+	    !(ecc->mode == NAND_ECC_SOFT && ecc->algo == NAND_ECC_HAMMING)) {
 		switch (mtd->oobsize) {
 		case 8:
 		case 16:
diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
index 378ba46f7e1d..8df36d189482 100644
--- a/include/linux/mtd/nand-sw-hamming-engine.h
+++ b/include/linux/mtd/nand-sw-hamming-engine.h
@@ -32,6 +32,8 @@ struct ecc_sw_hamming_conf {
 
 #if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_HAMMING)
 
+int ecc_sw_hamming_init_ctx(struct nand_device *nand);
+void ecc_sw_hamming_cleanup_ctx(struct nand_device *nand);
 int __ecc_sw_hamming_calculate(const unsigned char *buf,
 			       unsigned int step_size,
 			       unsigned char *code, bool sm_order);
@@ -43,9 +45,17 @@ int __ecc_sw_hamming_correct(unsigned char *buf, unsigned char *read_ecc,
 			     bool sm_order);
 int ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf,
 			   unsigned char *read_ecc, unsigned char *calc_ecc);
+struct nand_ecc_engine *ecc_sw_hamming_get_engine(void);
 
 #else /* !CONFIG_MTD_NAND_ECC_SW_HAMMING */
 
+static inline int ecc_sw_hamming_init_ctx(struct nand_device *nand)
+{
+	return -ENOTSUPP;
+}
+
+static inline void ecc_sw_hamming_cleanup_ctx(struct nand_device *nand) {}
+
 static inline int __ecc_sw_hamming_calculate(const unsigned char *buf,
 					     unsigned int step_size,
 					     unsigned char *code,
@@ -78,6 +88,11 @@ static inline int ecc_sw_hamming_correct(struct nand_device *nand,
 	return -ENOTSUPP;
 }
 
+static inline struct nand_ecc_engine *ecc_sw_hamming_get_engine(void)
+{
+	return NULL;
+}
+
 #endif /* CONFIG_MTD_NAND_ECC_SW_HAMMING */
 
 #endif /* __MTD_NAND_ECC_SW_HAMMING_H__ */
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (5 preceding siblings ...)
  2019-02-21 12:57 ` [RFC PATCH 19/27] mtd: nand: ecc: Create the software Hamming " Miquel Raynal
@ 2019-02-21 12:57 ` Miquel Raynal
  2019-02-22 14:29   ` Boris Brezillon
  2019-02-21 12:58 ` [RFC PATCH 21/27] mtd: spinand: Fix typo in comment Miquel Raynal
                   ` (4 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:57 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Before making use of the ECC engines, we must retrieve them. Add the
boilerplate for the ones already available: software engines (Hamming
and BCH).

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/ecc/engine.c              | 14 ++++++++++++++
 include/linux/mtd/nand-sw-bch-engine.h     |  3 +++
 include/linux/mtd/nand-sw-hamming-engine.h |  3 +++
 include/linux/mtd/nand.h                   |  3 +++
 4 files changed, 23 insertions(+)

diff --git a/drivers/mtd/nand/ecc/engine.c b/drivers/mtd/nand/ecc/engine.c
index 7dd3f9772698..318dbb2d56a2 100644
--- a/drivers/mtd/nand/ecc/engine.c
+++ b/drivers/mtd/nand/ecc/engine.c
@@ -286,6 +286,20 @@ bool nand_ecc_correction_is_enough(struct nand_device *nand)
 	return corr >= ds_corr && conf->strength >= reqs->strength;
 }
 
+struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand)
+{
+	switch (nand->ecc.user_conf.algo) {
+	case NAND_ECC_HAMMING:
+		return ecc_sw_hamming_get_engine();
+	case NAND_ECC_BCH:
+		return ecc_sw_bch_get_engine();
+	default:
+		break;
+	}
+
+	return NULL;
+}
+
 MODULE_LICENSE("GPL v2");
 MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
 MODULE_DESCRIPTION("Generic ECC engine");
diff --git a/include/linux/mtd/nand-sw-bch-engine.h b/include/linux/mtd/nand-sw-bch-engine.h
index e406aa53ec4e..38cdad117fea 100644
--- a/include/linux/mtd/nand-sw-bch-engine.h
+++ b/include/linux/mtd/nand-sw-bch-engine.h
@@ -11,6 +11,9 @@
 #include <linux/mtd/nand.h>
 #include <linux/bch.h>
 
+/* Needed for cross inclusion with nand.h */
+struct nand_device;
+
 /**
  * struct ecc_sw_bch_conf - private software BCH ECC engine structure
  * @reqooblen: Save the actual user OOB length requested before overwriting it
diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
index 8df36d189482..51c5a2acee42 100644
--- a/include/linux/mtd/nand-sw-hamming-engine.h
+++ b/include/linux/mtd/nand-sw-hamming-engine.h
@@ -12,6 +12,9 @@
 
 #include <linux/mtd/nand.h>
 
+/* Needed for cross inclusion with nand.h */
+struct nand_device;
+
 /**
  * struct ecc_sw_hamming_conf - private software Hamming ECC engine structure
  * @reqooblen: Save the actual user OOB length requested before overwriting it
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 4482eb2bbfd4..3abe113e4f06 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -11,6 +11,8 @@
 #define __LINUX_MTD_NAND_H
 
 #include <linux/mtd/mtd.h>
+#include <linux/mtd/nand-sw-hamming-engine.h>
+#include <linux/mtd/nand-sw-bch-engine.h>
 
 struct nand_device;
 
@@ -253,6 +255,7 @@ struct nand_ecc_engine {
 };
 
 void nand_ecc_read_user_conf(struct nand_device *nand);
+struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand);
 int nand_ecc_init_ctx(struct nand_device *nand);
 void nand_ecc_cleanup_ctx(struct nand_device *nand);
 int nand_ecc_prepare_io_req(struct nand_device *nand,
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 21/27] mtd: spinand: Fix typo in comment
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (6 preceding siblings ...)
  2019-02-21 12:57 ` [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core Miquel Raynal
@ 2019-02-21 12:58 ` Miquel Raynal
  2019-02-22 14:31   ` Boris Brezillon
  2019-02-21 12:58 ` [RFC PATCH 22/27] mtd: spinand: Let the SPI-NAND core flag a SPI-NAND chip Miquel Raynal
                   ` (3 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:58 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

One comment in the SPI-NAND core is not very clear, fix it to ease the
understanding of what the block does.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index ab41b9434d87..9c8a5ee626cd 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1032,7 +1032,7 @@ static int spinand_init(struct spinand_device *spinand)
 
 	/*
 	 * Right now, we don't support ECC, so let the whole oob
-	 * area is available for user.
+	 * area available for the user.
 	 */
 	mtd->_read_oob = spinand_mtd_read;
 	mtd->_write_oob = spinand_mtd_write;
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 22/27] mtd: spinand: Let the SPI-NAND core flag a SPI-NAND chip
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (7 preceding siblings ...)
  2019-02-21 12:58 ` [RFC PATCH 21/27] mtd: spinand: Fix typo in comment Miquel Raynal
@ 2019-02-21 12:58 ` Miquel Raynal
  2019-02-22 14:33   ` Boris Brezillon
  2019-02-21 12:58 ` [RFC PATCH 23/27] mtd: spinand: Move the ECC helper functions into a separate file Miquel Raynal
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:58 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

As of today there is no way to make the distinction between a raw NAND
chip and a SPI-NAND chip. The ABI is stable and we cannot add a
"SPI-NAND" tag to the MTD type, but we can add a special SPINAND
capability to the flags instead. A helper is also provided to retrieve
if whether or not the chip is working over SPI or not.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/core.c    | 2 +-
 include/linux/mtd/mtd.h    | 5 +++++
 include/uapi/mtd/mtd-abi.h | 1 +
 3 files changed, 7 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index a76d206d233a..872d46b5fc0f 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -245,7 +245,7 @@ int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
 
 	mtd->type = memorg->bits_per_cell == 1 ?
 		    MTD_NANDFLASH : MTD_MLCNANDFLASH;
-	mtd->flags = MTD_CAP_NANDFLASH;
+	mtd->flags = MTD_SPINAND | MTD_CAP_NANDFLASH;
 	mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
 	mtd->writesize = memorg->pagesize;
 	mtd->writebufsize = memorg->pagesize;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 677768b21a1d..7c245d109524 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -551,6 +551,11 @@ static inline int mtd_type_is_nand(const struct mtd_info *mtd)
 	return mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
 }
 
+static inline int mtd_type_is_spinand(const struct mtd_info *mtd)
+{
+	return mtd_type_is_nand(mtd) && (mtd->flags & MTD_SPINAND);
+}
+
 static inline int mtd_can_have_bb(const struct mtd_info *mtd)
 {
 	return !!mtd->_block_isbad;
diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
index aff5b5e59845..7c7124c88fe0 100644
--- a/include/uapi/mtd/mtd-abi.h
+++ b/include/uapi/mtd/mtd-abi.h
@@ -104,6 +104,7 @@ struct mtd_write_req {
 #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
 #define MTD_NO_ERASE		0x1000	/* No erase necessary */
 #define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */
+#define MTD_SPINAND		0x4000	/* Device works over SPI */
 
 /* Some common devices / combinations of capabilities */
 #define MTD_CAP_ROM		0
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 23/27] mtd: spinand: Move the ECC helper functions into a separate file
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (8 preceding siblings ...)
  2019-02-21 12:58 ` [RFC PATCH 22/27] mtd: spinand: Let the SPI-NAND core flag a SPI-NAND chip Miquel Raynal
@ 2019-02-21 12:58 ` Miquel Raynal
  2019-02-21 12:58 ` [RFC PATCH 24/27] mtd: spinand: Instantiate a SPI-NAND on-die ECC engine Miquel Raynal
  2019-02-21 12:58 ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
  11 siblings, 0 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:58 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Prepare the creation of a SPI-NAND chips on-die ECC engine by moving
some code out of the core. The next step is to actually create that
engine by implementing the generic ECC interface.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/Makefile            |  2 +-
 drivers/mtd/nand/spi/core.c              | 36 ------------------
 drivers/mtd/nand/spi/on-die-ecc-engine.c | 47 ++++++++++++++++++++++++
 include/linux/mtd/spinand.h              |  2 +
 4 files changed, 50 insertions(+), 37 deletions(-)
 create mode 100644 drivers/mtd/nand/spi/on-die-ecc-engine.c

diff --git a/drivers/mtd/nand/spi/Makefile b/drivers/mtd/nand/spi/Makefile
index 753125082640..e8a04669bdb6 100644
--- a/drivers/mtd/nand/spi/Makefile
+++ b/drivers/mtd/nand/spi/Makefile
@@ -1,3 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
+spinand-objs := core.o on-die-ecc-engine.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
 obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
index 9c8a5ee626cd..eb0b4ffdd8ed 100644
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -200,13 +200,6 @@ static int spinand_init_quad_enable(struct spinand_device *spinand)
 			       enable ? CFG_QUAD_ENABLE : 0);
 }
 
-static int spinand_ecc_enable(struct spinand_device *spinand,
-			      bool enable)
-{
-	return spinand_upd_cfg(spinand, CFG_ECC_ENABLE,
-			       enable ? CFG_ECC_ENABLE : 0);
-}
-
 static int spinand_write_enable_op(struct spinand_device *spinand)
 {
 	struct spi_mem_op op = SPINAND_WR_EN_DIS_OP(true);
@@ -463,35 +456,6 @@ static int spinand_lock_block(struct spinand_device *spinand, u8 lock)
 	return spinand_write_reg_op(spinand, REG_BLOCK_LOCK, lock);
 }
 
-static int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
-{
-	struct nand_device *nand = spinand_to_nand(spinand);
-
-	if (spinand->eccinfo.get_status)
-		return spinand->eccinfo.get_status(spinand, status);
-
-	switch (status & STATUS_ECC_MASK) {
-	case STATUS_ECC_NO_BITFLIPS:
-		return 0;
-
-	case STATUS_ECC_HAS_BITFLIPS:
-		/*
-		 * We have no way to know exactly how many bitflips have been
-		 * fixed, so let's return the maximum possible value so that
-		 * wear-leveling layers move the data immediately.
-		 */
-		return nand->ecc.ctx.conf.strength;
-
-	case STATUS_ECC_UNCOR_ERROR:
-		return -EBADMSG;
-
-	default:
-		break;
-	}
-
-	return -EINVAL;
-}
-
 static int spinand_read_page(struct spinand_device *spinand,
 			     const struct nand_page_io_req *req,
 			     bool ecc_enabled)
diff --git a/drivers/mtd/nand/spi/on-die-ecc-engine.c b/drivers/mtd/nand/spi/on-die-ecc-engine.c
new file mode 100644
index 000000000000..3d5b83238e14
--- /dev/null
+++ b/drivers/mtd/nand/spi/on-die-ecc-engine.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * On-die Error-Correcting Code (ECC) engine for SPI-NAND devices
+ *
+ * Copyright (C) 2019 Macronix
+ * Author:
+ *     Miquèl RAYNAL <miquel.raynal@bootlin.com>
+ * Taken from the SPI-NAND core code written by:
+ *     Boris BREZILLON <bbrezillon@kernel.org>
+ */
+
+#include <linux/mtd/spinand.h>
+
+int spinand_ecc_enable(struct spinand_device *spinand, bool enable)
+{
+	return spinand_upd_cfg(spinand, CFG_ECC_ENABLE,
+			       enable ? CFG_ECC_ENABLE : 0);
+}
+
+int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
+{
+	struct nand_device *nand = spinand_to_nand(spinand);
+
+	if (spinand->eccinfo.get_status)
+		return spinand->eccinfo.get_status(spinand, status);
+
+	switch (status & STATUS_ECC_MASK) {
+	case STATUS_ECC_NO_BITFLIPS:
+		return 0;
+
+	case STATUS_ECC_HAS_BITFLIPS:
+		/*
+		 * We have no way to know exactly how many bitflips have been
+		 * fixed, so let's return the maximum possible value so that
+		 * wear-leveling layers move the data immediately.
+		 */
+		return nand->ecc.ctx.conf.strength;
+
+	case STATUS_ECC_UNCOR_ERROR:
+		return -EBADMSG;
+
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h
index 75a28dc79a9c..77d9caff4a5c 100644
--- a/include/linux/mtd/spinand.h
+++ b/include/linux/mtd/spinand.h
@@ -419,5 +419,7 @@ int spinand_match_and_init(struct spinand_device *dev,
 
 int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
 int spinand_select_target(struct spinand_device *spinand, unsigned int target);
+int spinand_ecc_enable(struct spinand_device *spinand, bool enable);
+int spinand_check_ecc_status(struct spinand_device *spinand, u8 status);
 
 #endif /* __LINUX_MTD_SPINAND_H */
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 24/27] mtd: spinand: Instantiate a SPI-NAND on-die ECC engine
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (9 preceding siblings ...)
  2019-02-21 12:58 ` [RFC PATCH 23/27] mtd: spinand: Move the ECC helper functions into a separate file Miquel Raynal
@ 2019-02-21 12:58 ` Miquel Raynal
  2019-02-22 14:38   ` Boris Brezillon
  2019-02-21 12:58 ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:58 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Make use of the existing functions taken from the SPI-NAND core to
instantiate an on-die ECC engine specific to the SPI-NAND core. The
next step will be to tweak the core to use this object instead of
calling the helpers directly.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/spi/on-die-ecc-engine.c   | 105 +++++++++++++++++++++
 include/linux/mtd/nand-spi-on-die-engine.h |  35 +++++++
 include/linux/mtd/nand.h                   |   1 +
 3 files changed, 141 insertions(+)
 create mode 100644 include/linux/mtd/nand-spi-on-die-engine.h

diff --git a/drivers/mtd/nand/spi/on-die-ecc-engine.c b/drivers/mtd/nand/spi/on-die-ecc-engine.c
index 3d5b83238e14..515b9e3efc93 100644
--- a/drivers/mtd/nand/spi/on-die-ecc-engine.c
+++ b/drivers/mtd/nand/spi/on-die-ecc-engine.c
@@ -45,3 +45,108 @@ int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
 
 	return -EINVAL;
 }
+
+static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
+				       struct mtd_oob_region *region)
+{
+	return -ERANGE;
+}
+
+static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
+					struct mtd_oob_region *region)
+{
+	if (section)
+		return -ERANGE;
+
+	/* Reserve 2 bytes for the BBM. */
+	region->offset = 2;
+	region->length = 62;
+
+	return 0;
+}
+
+static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
+	.ecc = spinand_noecc_ooblayout_ecc,
+	.free = spinand_noecc_ooblayout_free,
+};
+
+static int ecc_spinand_ondie_init_ctx(struct nand_device *nand)
+{
+	struct spinand_device *spinand = nand_to_spinand(nand);
+	struct mtd_info *mtd = nanddev_to_mtd(nand);
+	struct ecc_sw_hamming_conf *engine_conf;
+
+	nand->ecc.ctx.conf.step_size = nand->ecc.requirements.step_size;
+	nand->ecc.ctx.conf.strength = nand->ecc.requirements.strength;
+
+	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
+	if (!engine_conf)
+		return -ENOMEM;
+
+	nand->ecc.ctx.priv = engine_conf;
+
+	if (spinand->eccinfo.ooblayout)
+		mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
+	else
+		mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
+
+	return 0;
+}
+
+static void ecc_spinand_ondie_cleanup_ctx(struct nand_device *nand)
+{
+	kfree(nand->ecc.ctx.priv);
+}
+
+static int ecc_spinand_ondie_prepare_io_req(struct nand_device *nand,
+					    struct nand_page_io_req *req,
+					    void *oobbuf)
+{
+	struct spinand_device *spinand = nand_to_spinand(nand);
+	bool enable = (req->mode != MTD_OPS_RAW);
+
+	/* Only enable or disable the engine */
+	return spinand_ecc_enable(spinand, enable);
+}
+
+static int ecc_spinand_ondie_finish_io_req(struct nand_device *nand,
+					   struct nand_page_io_req *req,
+					   void *oobbuf)
+{
+	struct ecc_spinand_ondie_conf *engine_conf = nand->ecc.ctx.priv;
+	struct spinand_device *spinand = nand_to_spinand(nand);
+
+	if (req->mode == MTD_OPS_RAW)
+		return 0;
+
+	/* Nothing to do when finishing a page write */
+	if (req->type == NAND_PAGE_WRITE)
+		return 0;
+
+	/* Finish a page write: check the status, report errors/bitflips */
+	return spinand_check_ecc_status(spinand, engine_conf->status);
+}
+
+static struct nand_ecc_engine_ops spinand_ondie_engine_ops = {
+	.init_ctx = ecc_spinand_ondie_init_ctx,
+	.cleanup_ctx = ecc_spinand_ondie_cleanup_ctx,
+	.prepare_io_req = ecc_spinand_ondie_prepare_io_req,
+	.finish_io_req = ecc_spinand_ondie_finish_io_req,
+};
+
+static struct nand_ecc_engine spinand_ondie_engine = {
+	.ops = &spinand_ondie_engine_ops,
+};
+
+void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
+{
+	struct ecc_spinand_ondie_conf *engine_conf = nand->ecc.ctx.priv;
+
+	if (nand->ecc.engine == &spinand_ondie_engine && engine_conf)
+		engine_conf->status = status;
+}
+
+struct nand_ecc_engine *spinand_ondie_ecc_get_engine(void)
+{
+	return &spinand_ondie_engine;
+}
diff --git a/include/linux/mtd/nand-spi-on-die-engine.h b/include/linux/mtd/nand-spi-on-die-engine.h
new file mode 100644
index 000000000000..33e466b81583
--- /dev/null
+++ b/include/linux/mtd/nand-spi-on-die-engine.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2019 Macronix
+ * Author:
+ *     Miquèl RAYNAL <miquel.raynal@bootlin.com>
+ *
+ * This file is the header for the SPI-NAND on-die ECC implementation.
+ */
+
+#ifndef __MTD_NAND_SPI_ON_DIE_H__
+#define __MTD_NAND_SPI_ON_DIE_H__
+
+#if IS_ENABLED(CONFIG_MTD_SPI_NAND)
+
+/**
+ * struct ecc_spinand_ondie_conf - private SPI-NAND on-die ECC engine structure
+ * @status: status of the last wait operation that will be used in case
+ *          ->get_status() is not populated by the spinand device.
+ */
+struct ecc_spinand_ondie_conf {
+	u8 status;
+};
+
+struct nand_ecc_engine *spinand_ondie_ecc_get_engine(void);
+void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status);
+
+#else /* !CONFIG_MTD_SPI_NAND */
+
+static inline struct nand_ecc_engine *spinand_ondie_ecc_get_engine(void)
+{
+	return NULL;
+}
+#endif /* CONFIG_MTD_SPI_NAND */
+
+#endif /* __MTD_NAND_SPI_ON_DIE_H__ */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 3abe113e4f06..534c07fab9de 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -13,6 +13,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand-sw-hamming-engine.h>
 #include <linux/mtd/nand-sw-bch-engine.h>
+#include <linux/mtd/nand-spi-on-die-engine.h>
 
 struct nand_device;
 
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
                   ` (10 preceding siblings ...)
  2019-02-21 12:58 ` [RFC PATCH 24/27] mtd: spinand: Instantiate a SPI-NAND on-die ECC engine Miquel Raynal
@ 2019-02-21 12:58 ` Miquel Raynal
  2019-02-22 14:44   ` Boris Brezillon
  11 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 12:58 UTC (permalink / raw)
  To: Boris Brezillon, Richard Weinberger, David Woodhouse,
	Brian Norris, Marek Vasut, Tudor Ambarus
  Cc: Vignesh R, Tudor Ambarus, Julien Su, Schrempf Frieder, linux-mtd,
	Thomas Petazzoni, Miquel Raynal, Mason Yang, linux-arm-kernel

Add the logic in the NAND core to find the right ECC engine depending
on the NAND chip requirements and the user desires. Right now, the
choice may be made between (more will come):
* software Hamming
* software BCH
* on-die (SPI-NAND devices only)

Once the ECC engine has been found, the ECC engine must be
configured.

Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
---
 drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
 include/linux/mtd/nand.h |   4 ++
 2 files changed, 111 insertions(+)

diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
index 872d46b5fc0f..9feb118c9f68 100644
--- a/drivers/mtd/nand/core.c
+++ b/drivers/mtd/nand/core.c
@@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
 }
 EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
 
+/**
+ * nanddev_find_ecc_engine() - Find a suitable ECC engine
+ * @nand: NAND device
+ */
+static int nanddev_find_ecc_engine(struct nand_device *nand)
+{
+	bool is_spinand = mtd_type_is_spinand(&nand->mtd);
+
+	/* Read the user desires in terms of ECC engine/configuration */
+	nand_ecc_read_user_conf(nand);
+
+	/* No ECC engine requestedn, let's return without error */
+	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
+		return 0;
+
+	/* Raw NAND default mode is hardware */
+	if (!is_spinand && nand->ecc.user_conf.mode < 0)
+		nand->ecc.user_conf.mode = NAND_ECC_HW;
+
+	/* SPI-NAND default mode is on-die */
+	if (is_spinand && nand->ecc.user_conf.mode < 0)
+		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
+
+	switch (nand->ecc.user_conf.mode) {
+	case NAND_ECC_SOFT:
+		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
+		break;
+	case NAND_ECC_ON_DIE:
+		if (is_spinand)
+			nand->ecc.engine = spinand_ondie_ecc_get_engine();
+		else
+			pr_err("On-die ECC engines for non SPI devices not supported yet\n");
+		break;
+	case NAND_ECC_HW:
+		pr_err("Hardware ECC engines not supported yet\n");
+		break;
+	default:
+		pr_err("Missing ECC engine property\n");
+	}
+
+	if (!nand->ecc.engine)
+		return  -EINVAL;
+
+	return 0;
+}
+
+/**
+ * nanddev_find_ecc_configuration() - Find a suitable ECC configuration
+ * @nand: NAND device
+ */
+static int nanddev_find_ecc_configuration(struct nand_device *nand)
+{
+	int ret;
+
+	if (!nand->ecc.engine)
+		return -ENOTSUPP;
+
+	ret = nand_ecc_init_ctx(nand);
+	if (ret)
+		return ret;
+
+	if (!nand_ecc_correction_is_enough(nand))
+		pr_warn("WARNING: %s: the ECC used on your system is too weak compared to the one required by the NAND chip\n",
+			nand->mtd.name);
+
+	return 0;
+}
+
+/**
+ * nanddev_ecc_engine_init() - Initialize an ECC engine for the chip
+ * @nand: NAND device
+ */
+int nanddev_ecc_engine_init(struct nand_device *nand)
+{
+	int ret;
+
+	/* Look for the ECC engine to use */
+	ret = nanddev_find_ecc_engine(nand);
+	if (ret) {
+		pr_err("No ECC engine found\n");
+		return ret;
+	}
+
+	/* No ECC engine requested */
+	if (!nand->ecc.engine)
+		return 0;
+
+	/* Configure the engine: balance user input and chip requirements */
+	ret = nanddev_find_ecc_configuration(nand);
+	if (ret) {
+		pr_err("No suitable ECC configuration\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+/**
+ * nanddev_ecc_engine_cleanup() - Cleanup ECC engine initializations
+ * @nand: NAND device
+ */
+void nanddev_ecc_engine_cleanup(struct nand_device *nand)
+{
+	if (nand->ecc.engine)
+		nand_ecc_cleanup_ctx(nand);
+}
+
 /**
  * nanddev_init() - Initialize a NAND device
  * @nand: NAND device
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 534c07fab9de..bf949f55c139 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -844,6 +844,10 @@ bool nanddev_isreserved(struct nand_device *nand, const struct nand_pos *pos);
 int nanddev_erase(struct nand_device *nand, const struct nand_pos *pos);
 int nanddev_markbad(struct nand_device *nand, const struct nand_pos *pos);
 
+/* ECC related functions */
+int nanddev_ecc_engine_init(struct nand_device *nand);
+void nanddev_ecc_engine_cleanup(struct nand_device *nand);
+
 /* BBT related functions */
 enum nand_bbt_block_status {
 	NAND_BBT_BLOCK_STATUS_UNKNOWN,
-- 
2.19.1


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected
  2019-02-21 12:57 ` [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected Miquel Raynal
@ 2019-02-21 13:20   ` Boris Brezillon
  2019-02-21 13:35     ` Miquel Raynal
  0 siblings, 1 reply; 36+ messages in thread
From: Boris Brezillon @ 2019-02-21 13:20 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:57:56 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> There is no reason to always embed the software Hamming ECC engine
> implementation. By default it is, but we can let the user decide.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/ecc/Kconfig               | 10 +++++-
>  drivers/mtd/nand/raw/Kconfig               |  2 +-
>  include/linux/mtd/nand-sw-hamming-engine.h | 38 ++++++++++++++++++++++
>  3 files changed, 48 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
> index e0106b3a7ec1..ff20e621ffef 100644
> --- a/drivers/mtd/nand/ecc/Kconfig
> +++ b/drivers/mtd/nand/ecc/Kconfig
> @@ -1,7 +1,15 @@
>  menu "ECC engine support"
>  
>  config MTD_NAND_ECC_SW_HAMMING
> -	tristate
> +	tristate "Software Hamming ECC engine"
> +	default y

Same as for the NAND_CORE stuff, let users this option when they need
it instead of having a "default y". Haven't made my mind yet on whether
this option should be visible to users or not. I guess it could be with
the new infrastructure, but it's probably too early in the patch series
to change that.

> +	help
> +	  This enables support for software Hamming error
> +	  correction. This correction can correct up to 1 bit error
> +	  per chunk and detect up to 2 bit errors. While it used to be
> +	  widely used with old parts, newer NAND chips usually require
> +	  more strength correction and in this case BCH or RS will be
> +	  preferred.
>  

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic
  2019-02-21 12:57 ` [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic Miquel Raynal
@ 2019-02-21 13:22   ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-21 13:22 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:57:53 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:


> -/*
> - * Detect and correct a 1 bit error for 256/512 byte block
> - */
> -int nand_correct_data(struct nand_chip *chip, u_char *dat, u_char *read_ecc,
> -		      u_char *calc_ecc);
> +int __ecc_sw_hamming_calculate(const unsigned char *buf,

Let's stop with these __ prefixes. Just prefix functions taking a
nand_device object with nand_ and leave others with the ecc_ prefix.

> +			       unsigned int step_size,
> +			       unsigned char *code, bool sm_order);
> +int ecc_sw_hamming_calculate(struct nand_device *nand,
> +			     const unsigned char *buf,
> +			     unsigned char *code);

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected
  2019-02-21 13:20   ` Boris Brezillon
@ 2019-02-21 13:35     ` Miquel Raynal
  2019-02-21 13:41       ` Boris Brezillon
  0 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 13:35 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

Hi Boris,

Boris Brezillon <bbrezillon@kernel.org> wrote on Thu, 21 Feb 2019
14:20:02 +0100:

> On Thu, 21 Feb 2019 13:57:56 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > There is no reason to always embed the software Hamming ECC engine
> > implementation. By default it is, but we can let the user decide.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/mtd/nand/ecc/Kconfig               | 10 +++++-
> >  drivers/mtd/nand/raw/Kconfig               |  2 +-
> >  include/linux/mtd/nand-sw-hamming-engine.h | 38 ++++++++++++++++++++++
> >  3 files changed, 48 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
> > index e0106b3a7ec1..ff20e621ffef 100644
> > --- a/drivers/mtd/nand/ecc/Kconfig
> > +++ b/drivers/mtd/nand/ecc/Kconfig
> > @@ -1,7 +1,15 @@
> >  menu "ECC engine support"
> >  
> >  config MTD_NAND_ECC_SW_HAMMING
> > -	tristate
> > +	tristate "Software Hamming ECC engine"
> > +	default y  
> 
> Same as for the NAND_CORE stuff, let users this option when they need
> it instead of having a "default y". Haven't made my mind yet on whether
> this option should be visible to users or not. I guess it could be with
> the new infrastructure, but it's probably too early in the patch series
> to change that.

This one is different.

Before the series: the software Hamming ECC algorithm is part of the
'NAND package'. There is no way to ignore it, it *will* be part of your
binary (or module).

After the series: I just give the user the possibility to deselect
this option. But having 'default y' is mandatory here to avoid breaking
current defconfigs.

> 
> > +	help
> > +	  This enables support for software Hamming error
> > +	  correction. This correction can correct up to 1 bit error
> > +	  per chunk and detect up to 2 bit errors. While it used to be
> > +	  widely used with old parts, newer NAND chips usually require
> > +	  more strength correction and in this case BCH or RS will be
> > +	  preferred.
> >    


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected
  2019-02-21 13:35     ` Miquel Raynal
@ 2019-02-21 13:41       ` Boris Brezillon
  2019-02-21 13:46         ` Miquel Raynal
  0 siblings, 1 reply; 36+ messages in thread
From: Boris Brezillon @ 2019-02-21 13:41 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 14:35:39 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> Boris Brezillon <bbrezillon@kernel.org> wrote on Thu, 21 Feb 2019
> 14:20:02 +0100:
> 
> > On Thu, 21 Feb 2019 13:57:56 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > There is no reason to always embed the software Hamming ECC engine
> > > implementation. By default it is, but we can let the user decide.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/mtd/nand/ecc/Kconfig               | 10 +++++-
> > >  drivers/mtd/nand/raw/Kconfig               |  2 +-
> > >  include/linux/mtd/nand-sw-hamming-engine.h | 38 ++++++++++++++++++++++
> > >  3 files changed, 48 insertions(+), 2 deletions(-)
> > > 
> > > diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
> > > index e0106b3a7ec1..ff20e621ffef 100644
> > > --- a/drivers/mtd/nand/ecc/Kconfig
> > > +++ b/drivers/mtd/nand/ecc/Kconfig
> > > @@ -1,7 +1,15 @@
> > >  menu "ECC engine support"
> > >  
> > >  config MTD_NAND_ECC_SW_HAMMING
> > > -	tristate
> > > +	tristate "Software Hamming ECC engine"
> > > +	default y    
> > 
> > Same as for the NAND_CORE stuff, let users this option when they need
> > it instead of having a "default y". Haven't made my mind yet on whether
> > this option should be visible to users or not. I guess it could be with
> > the new infrastructure, but it's probably too early in the patch series
> > to change that.  
> 
> This one is different.
> 
> Before the series: the software Hamming ECC algorithm is part of the
> 'NAND package'. There is no way to ignore it, it *will* be part of your
> binary (or module).
> 
> After the series: I just give the user the possibility to deselect
> this option. But having 'default y' is mandatory here to avoid breaking
> current defconfigs.

Okay, then maybe

	default y if MTD_RAW_NAND

And I think you should select the option in MTD_NAND_NDFC instead of
adding a depends on. 

> 
> >   
> > > +	help
> > > +	  This enables support for software Hamming error
> > > +	  correction. This correction can correct up to 1 bit error
> > > +	  per chunk and detect up to 2 bit errors. While it used to be
> > > +	  widely used with old parts, newer NAND chips usually require
> > > +	  more strength correction and in this case BCH or RS will be
> > > +	  preferred.
> > >      
> 
> 
> Thanks,
> Miquèl


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected
  2019-02-21 13:41       ` Boris Brezillon
@ 2019-02-21 13:46         ` Miquel Raynal
  0 siblings, 0 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 13:46 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

Hi Boris,

Boris Brezillon <bbrezillon@kernel.org> wrote on Thu, 21 Feb 2019
14:41:48 +0100:

> On Thu, 21 Feb 2019 14:35:39 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Hi Boris,
> > 
> > Boris Brezillon <bbrezillon@kernel.org> wrote on Thu, 21 Feb 2019
> > 14:20:02 +0100:
> >   
> > > On Thu, 21 Feb 2019 13:57:56 +0100
> > > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > >     
> > > > There is no reason to always embed the software Hamming ECC engine
> > > > implementation. By default it is, but we can let the user decide.
> > > > 
> > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > ---
> > > >  drivers/mtd/nand/ecc/Kconfig               | 10 +++++-
> > > >  drivers/mtd/nand/raw/Kconfig               |  2 +-
> > > >  include/linux/mtd/nand-sw-hamming-engine.h | 38 ++++++++++++++++++++++
> > > >  3 files changed, 48 insertions(+), 2 deletions(-)
> > > > 
> > > > diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
> > > > index e0106b3a7ec1..ff20e621ffef 100644
> > > > --- a/drivers/mtd/nand/ecc/Kconfig
> > > > +++ b/drivers/mtd/nand/ecc/Kconfig
> > > > @@ -1,7 +1,15 @@
> > > >  menu "ECC engine support"
> > > >  
> > > >  config MTD_NAND_ECC_SW_HAMMING
> > > > -	tristate
> > > > +	tristate "Software Hamming ECC engine"
> > > > +	default y      
> > > 
> > > Same as for the NAND_CORE stuff, let users this option when they need
> > > it instead of having a "default y". Haven't made my mind yet on whether
> > > this option should be visible to users or not. I guess it could be with
> > > the new infrastructure, but it's probably too early in the patch series
> > > to change that.    
> > 
> > This one is different.
> > 
> > Before the series: the software Hamming ECC algorithm is part of the
> > 'NAND package'. There is no way to ignore it, it *will* be part of your
> > binary (or module).
> > 
> > After the series: I just give the user the possibility to deselect
> > this option. But having 'default y' is mandatory here to avoid breaking
> > current defconfigs.  
> 
> Okay, then maybe
> 
> 	default y if MTD_RAW_NAND

Right, this is more accurate.

> 
> And I think you should select the option in MTD_NAND_NDFC instead of
> adding a depends on. 

Ack.

> 
> >   
> > >     
> > > > +	help
> > > > +	  This enables support for software Hamming error
> > > > +	  correction. This correction can correct up to 1 bit error
> > > > +	  per chunk and detect up to 2 bit errors. While it used to be
> > > > +	  widely used with old parts, newer NAND chips usually require
> > > > +	  more strength correction and in this case BCH or RS will be
> > > > +	  preferred.
> > > >        
> > 
> > 
> > Thanks,
> > Miquèl  
> 




Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module
  2019-02-21 12:57 ` [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module Miquel Raynal
@ 2019-02-21 13:48   ` Adam Ford
  2019-02-21 14:02     ` Miquel Raynal
  0 siblings, 1 reply; 36+ messages in thread
From: Adam Ford @ 2019-02-21 13:48 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Boris Brezillon, Schrempf Frieder,
	Marek Vasut, linux-mtd, Thomas Petazzoni, Brian Norris,
	David Woodhouse, arm-soc

On Thu, Feb 21, 2019 at 6:58 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
>
> There is no reason to prevent the software BCH ECC engine
> implementation to be compiled as a module, so change the 'bool' into a
> 'tristate'.

If you're booting from nand and need the BCH engine, it seems to me
like you'd need it to be compiled into the kernel because you'd have
to mount the filesystem before loading the module unless you have a
initramfs.  If you need the BCH engine to mount the filesystem, it
creates a dependency issue.

Just my two cents.

adam
>
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/ecc/Kconfig           | 2 +-
>  include/linux/mtd/nand-sw-bch-engine.h | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/mtd/nand/ecc/Kconfig b/drivers/mtd/nand/ecc/Kconfig
> index 6ce9007e1d9b..e0106b3a7ec1 100644
> --- a/drivers/mtd/nand/ecc/Kconfig
> +++ b/drivers/mtd/nand/ecc/Kconfig
> @@ -12,7 +12,7 @@ config MTD_NAND_ECC_SW_HAMMING_SMC
>           The original Linux implementation had byte 0 and 1 swapped.
>
>  config MTD_NAND_ECC_SW_BCH
> -       bool "Software BCH ECC engine"
> +       tristate "Software BCH ECC engine"
>         select BCH
>         default n
>         help
> diff --git a/include/linux/mtd/nand-sw-bch-engine.h b/include/linux/mtd/nand-sw-bch-engine.h
> index d8abfc9fc288..5d0b98e34a3a 100644
> --- a/include/linux/mtd/nand-sw-bch-engine.h
> +++ b/include/linux/mtd/nand-sw-bch-engine.h
> @@ -33,7 +33,7 @@ struct ecc_sw_bch_conf {
>         unsigned char *eccmask;
>  };
>
> -#if defined(CONFIG_MTD_NAND_ECC_SW_BCH)
> +#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)
>
>  int ecc_sw_bch_calculate(struct nand_device *nand, const unsigned char *buf,
>                          unsigned char *code);
> --
> 2.19.1
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module
  2019-02-21 13:48   ` Adam Ford
@ 2019-02-21 14:02     ` Miquel Raynal
  2019-02-22 14:24       ` Boris Brezillon
  0 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-21 14:02 UTC (permalink / raw)
  To: Adam Ford
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Boris Brezillon, Schrempf Frieder,
	Marek Vasut, linux-mtd, Thomas Petazzoni, Brian Norris,
	David Woodhouse, arm-soc

Hi Adam,

Adam Ford <aford173@gmail.com> wrote on Thu, 21 Feb 2019 07:48:46 -0600:

> On Thu, Feb 21, 2019 at 6:58 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >
> > There is no reason to prevent the software BCH ECC engine
> > implementation to be compiled as a module, so change the 'bool' into a
> > 'tristate'.  
> 
> If you're booting from nand and need the BCH engine, it seems to me
> like you'd need it to be compiled into the kernel because you'd have
> to mount the filesystem before loading the module unless you have a
> initramfs.  If you need the BCH engine to mount the filesystem, it
> creates a dependency issue.

That's true, I could mention this use case in the commit log. But the
action of choosing to compile it as a module is done by the user, so I
guess preventing any user to use it as a module is nonetheless too
restrictive?


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module
  2019-02-21 14:02     ` Miquel Raynal
@ 2019-02-22 14:24       ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-22 14:24 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, Adam Ford, David Woodhouse,
	arm-soc

On Thu, 21 Feb 2019 15:02:24 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Adam,
> 
> Adam Ford <aford173@gmail.com> wrote on Thu, 21 Feb 2019 07:48:46 -0600:
> 
> > On Thu, Feb 21, 2019 at 6:58 AM Miquel Raynal <miquel.raynal@bootlin.com> wrote:  
> > >
> > > There is no reason to prevent the software BCH ECC engine
> > > implementation to be compiled as a module, so change the 'bool' into a
> > > 'tristate'.    
> > 
> > If you're booting from nand and need the BCH engine, it seems to me
> > like you'd need it to be compiled into the kernel because you'd have
> > to mount the filesystem before loading the module unless you have a
> > initramfs.  If you need the BCH engine to mount the filesystem, it
> > creates a dependency issue.  
> 
> That's true, I could mention this use case in the commit log. But the
> action of choosing to compile it as a module is done by the user, so I
> guess preventing any user to use it as a module is nonetheless too
> restrictive?

I agree.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core
  2019-02-21 12:57 ` [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core Miquel Raynal
@ 2019-02-22 14:29   ` Boris Brezillon
  2019-02-25 15:49     ` Miquel Raynal
  0 siblings, 1 reply; 36+ messages in thread
From: Boris Brezillon @ 2019-02-22 14:29 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:57:59 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Before making use of the ECC engines, we must retrieve them. Add the
> boilerplate for the ones already available: software engines (Hamming
> and BCH).
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/ecc/engine.c              | 14 ++++++++++++++
>  include/linux/mtd/nand-sw-bch-engine.h     |  3 +++
>  include/linux/mtd/nand-sw-hamming-engine.h |  3 +++
>  include/linux/mtd/nand.h                   |  3 +++
>  4 files changed, 23 insertions(+)
> 
> diff --git a/drivers/mtd/nand/ecc/engine.c b/drivers/mtd/nand/ecc/engine.c
> index 7dd3f9772698..318dbb2d56a2 100644
> --- a/drivers/mtd/nand/ecc/engine.c
> +++ b/drivers/mtd/nand/ecc/engine.c
> @@ -286,6 +286,20 @@ bool nand_ecc_correction_is_enough(struct nand_device *nand)
>  	return corr >= ds_corr && conf->strength >= reqs->strength;
>  }
>  
> +struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand)

What if you want to instantiate SW ECC with a custom layout? Can't we
instead have a function that create a new engine dynamically?

struct nand_ecc_engine *
nand_ecc_create_sw_engine(struct nand_device* nand,
			  enum nand_ecc_algo algo,
			  struct mtd_ooblayout *layout);



> +{
> +	switch (nand->ecc.user_conf.algo) {

Note that the conf is supposed to be passed afterwards, when the ctx is
created, so you should check nand->ecc.user_conf directly here.

> +	case NAND_ECC_HAMMING:
> +		return ecc_sw_hamming_get_engine();
> +	case NAND_ECC_BCH:
> +		return ecc_sw_bch_get_engine();
> +	default:
> +		break;
> +	}
> +
> +	return NULL;
> +}
> +
>  MODULE_LICENSE("GPL v2");
>  MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
>  MODULE_DESCRIPTION("Generic ECC engine");
> diff --git a/include/linux/mtd/nand-sw-bch-engine.h b/include/linux/mtd/nand-sw-bch-engine.h
> index e406aa53ec4e..38cdad117fea 100644
> --- a/include/linux/mtd/nand-sw-bch-engine.h
> +++ b/include/linux/mtd/nand-sw-bch-engine.h
> @@ -11,6 +11,9 @@
>  #include <linux/mtd/nand.h>
>  #include <linux/bch.h>
>  
> +/* Needed for cross inclusion with nand.h */
> +struct nand_device;
> +
>  /**
>   * struct ecc_sw_bch_conf - private software BCH ECC engine structure
>   * @reqooblen: Save the actual user OOB length requested before overwriting it
> diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
> index 8df36d189482..51c5a2acee42 100644
> --- a/include/linux/mtd/nand-sw-hamming-engine.h
> +++ b/include/linux/mtd/nand-sw-hamming-engine.h
> @@ -12,6 +12,9 @@
>  
>  #include <linux/mtd/nand.h>
>  
> +/* Needed for cross inclusion with nand.h */
> +struct nand_device;
> +
>  /**
>   * struct ecc_sw_hamming_conf - private software Hamming ECC engine structure
>   * @reqooblen: Save the actual user OOB length requested before overwriting it
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index 4482eb2bbfd4..3abe113e4f06 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -11,6 +11,8 @@
>  #define __LINUX_MTD_NAND_H
>  
>  #include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand-sw-hamming-engine.h>
> +#include <linux/mtd/nand-sw-bch-engine.h>
>  
>  struct nand_device;
>  
> @@ -253,6 +255,7 @@ struct nand_ecc_engine {
>  };
>  
>  void nand_ecc_read_user_conf(struct nand_device *nand);
> +struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand);
>  int nand_ecc_init_ctx(struct nand_device *nand);
>  void nand_ecc_cleanup_ctx(struct nand_device *nand);
>  int nand_ecc_prepare_io_req(struct nand_device *nand,


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 21/27] mtd: spinand: Fix typo in comment
  2019-02-21 12:58 ` [RFC PATCH 21/27] mtd: spinand: Fix typo in comment Miquel Raynal
@ 2019-02-22 14:31   ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-22 14:31 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:58:00 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> One comment in the SPI-NAND core is not very clear, fix it to ease the
> understanding of what the block does.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>

Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>

> ---
>  drivers/mtd/nand/spi/core.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c
> index ab41b9434d87..9c8a5ee626cd 100644
> --- a/drivers/mtd/nand/spi/core.c
> +++ b/drivers/mtd/nand/spi/core.c
> @@ -1032,7 +1032,7 @@ static int spinand_init(struct spinand_device *spinand)
>  
>  	/*
>  	 * Right now, we don't support ECC, so let the whole oob
> -	 * area is available for user.
> +	 * area available for the user.
>  	 */
>  	mtd->_read_oob = spinand_mtd_read;
>  	mtd->_write_oob = spinand_mtd_write;


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 22/27] mtd: spinand: Let the SPI-NAND core flag a SPI-NAND chip
  2019-02-21 12:58 ` [RFC PATCH 22/27] mtd: spinand: Let the SPI-NAND core flag a SPI-NAND chip Miquel Raynal
@ 2019-02-22 14:33   ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-22 14:33 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:58:01 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> As of today there is no way to make the distinction between a raw NAND
> chip and a SPI-NAND chip. The ABI is stable and we cannot add a
> "SPI-NAND" tag to the MTD type, but we can add a special SPINAND
> capability to the flags instead. A helper is also provided to retrieve
> if whether or not the chip is working over SPI or not.

Why would we need a new cap or a new type? The user should only care
about the class of device (NAND, NOR, SRAM, ...) and not the
bus/protocol used to communicate with this device.

> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/core.c    | 2 +-
>  include/linux/mtd/mtd.h    | 5 +++++
>  include/uapi/mtd/mtd-abi.h | 1 +
>  3 files changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> index a76d206d233a..872d46b5fc0f 100644
> --- a/drivers/mtd/nand/core.c
> +++ b/drivers/mtd/nand/core.c
> @@ -245,7 +245,7 @@ int nanddev_init(struct nand_device *nand, const struct nand_ops *ops,
>  
>  	mtd->type = memorg->bits_per_cell == 1 ?
>  		    MTD_NANDFLASH : MTD_MLCNANDFLASH;
> -	mtd->flags = MTD_CAP_NANDFLASH;
> +	mtd->flags = MTD_SPINAND | MTD_CAP_NANDFLASH;
>  	mtd->erasesize = memorg->pagesize * memorg->pages_per_eraseblock;
>  	mtd->writesize = memorg->pagesize;
>  	mtd->writebufsize = memorg->pagesize;
> diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
> index 677768b21a1d..7c245d109524 100644
> --- a/include/linux/mtd/mtd.h
> +++ b/include/linux/mtd/mtd.h
> @@ -551,6 +551,11 @@ static inline int mtd_type_is_nand(const struct mtd_info *mtd)
>  	return mtd->type == MTD_NANDFLASH || mtd->type == MTD_MLCNANDFLASH;
>  }
>  
> +static inline int mtd_type_is_spinand(const struct mtd_info *mtd)
> +{
> +	return mtd_type_is_nand(mtd) && (mtd->flags & MTD_SPINAND);
> +}
> +
>  static inline int mtd_can_have_bb(const struct mtd_info *mtd)
>  {
>  	return !!mtd->_block_isbad;
> diff --git a/include/uapi/mtd/mtd-abi.h b/include/uapi/mtd/mtd-abi.h
> index aff5b5e59845..7c7124c88fe0 100644
> --- a/include/uapi/mtd/mtd-abi.h
> +++ b/include/uapi/mtd/mtd-abi.h
> @@ -104,6 +104,7 @@ struct mtd_write_req {
>  #define MTD_BIT_WRITEABLE	0x800	/* Single bits can be flipped */
>  #define MTD_NO_ERASE		0x1000	/* No erase necessary */
>  #define MTD_POWERUP_LOCK	0x2000	/* Always locked after reset */
> +#define MTD_SPINAND		0x4000	/* Device works over SPI */
>  
>  /* Some common devices / combinations of capabilities */
>  #define MTD_CAP_ROM		0


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 24/27] mtd: spinand: Instantiate a SPI-NAND on-die ECC engine
  2019-02-21 12:58 ` [RFC PATCH 24/27] mtd: spinand: Instantiate a SPI-NAND on-die ECC engine Miquel Raynal
@ 2019-02-22 14:38   ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-22 14:38 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:58:03 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Make use of the existing functions taken from the SPI-NAND core to
> instantiate an on-die ECC engine specific to the SPI-NAND core. The
> next step will be to tweak the core to use this object instead of
> calling the helpers directly.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/spi/on-die-ecc-engine.c   | 105 +++++++++++++++++++++

Maybe on-die-ecc.c is enough. To be honest, given the amount of code,
I'd even prefer to have this code directly in core.c.


>  include/linux/mtd/nand-spi-on-die-engine.h |  35 +++++++

Hm, let's make those defs part of the spinand.h file instead of
creating a new one.


>  include/linux/mtd/nand.h                   |   1 +
>  3 files changed, 141 insertions(+)
>  create mode 100644 include/linux/mtd/nand-spi-on-die-engine.h
> 
> diff --git a/drivers/mtd/nand/spi/on-die-ecc-engine.c b/drivers/mtd/nand/spi/on-die-ecc-engine.c
> index 3d5b83238e14..515b9e3efc93 100644
> --- a/drivers/mtd/nand/spi/on-die-ecc-engine.c
> +++ b/drivers/mtd/nand/spi/on-die-ecc-engine.c
> @@ -45,3 +45,108 @@ int spinand_check_ecc_status(struct spinand_device *spinand, u8 status)
>  
>  	return -EINVAL;
>  }
> +
> +static int spinand_noecc_ooblayout_ecc(struct mtd_info *mtd, int section,
> +				       struct mtd_oob_region *region)
> +{
> +	return -ERANGE;
> +}
> +
> +static int spinand_noecc_ooblayout_free(struct mtd_info *mtd, int section,
> +					struct mtd_oob_region *region)
> +{
> +	if (section)
> +		return -ERANGE;
> +
> +	/* Reserve 2 bytes for the BBM. */
> +	region->offset = 2;
> +	region->length = 62;
> +
> +	return 0;
> +}
> +
> +static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = {
> +	.ecc = spinand_noecc_ooblayout_ecc,
> +	.free = spinand_noecc_ooblayout_free,
> +};
> +
> +static int ecc_spinand_ondie_init_ctx(struct nand_device *nand)
> +{
> +	struct spinand_device *spinand = nand_to_spinand(nand);
> +	struct mtd_info *mtd = nanddev_to_mtd(nand);
> +	struct ecc_sw_hamming_conf *engine_conf;
> +
> +	nand->ecc.ctx.conf.step_size = nand->ecc.requirements.step_size;
> +	nand->ecc.ctx.conf.strength = nand->ecc.requirements.strength;
> +
> +	engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
> +	if (!engine_conf)
> +		return -ENOMEM;
> +
> +	nand->ecc.ctx.priv = engine_conf;
> +
> +	if (spinand->eccinfo.ooblayout)
> +		mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout);
> +	else
> +		mtd_set_ooblayout(mtd, &spinand_noecc_ooblayout);
> +
> +	return 0;
> +}
> +
> +static void ecc_spinand_ondie_cleanup_ctx(struct nand_device *nand)
> +{
> +	kfree(nand->ecc.ctx.priv);
> +}
> +
> +static int ecc_spinand_ondie_prepare_io_req(struct nand_device *nand,
> +					    struct nand_page_io_req *req,
> +					    void *oobbuf)
> +{
> +	struct spinand_device *spinand = nand_to_spinand(nand);
> +	bool enable = (req->mode != MTD_OPS_RAW);
> +
> +	/* Only enable or disable the engine */
> +	return spinand_ecc_enable(spinand, enable);
> +}
> +
> +static int ecc_spinand_ondie_finish_io_req(struct nand_device *nand,
> +					   struct nand_page_io_req *req,
> +					   void *oobbuf)
> +{
> +	struct ecc_spinand_ondie_conf *engine_conf = nand->ecc.ctx.priv;
> +	struct spinand_device *spinand = nand_to_spinand(nand);
> +
> +	if (req->mode == MTD_OPS_RAW)
> +		return 0;
> +
> +	/* Nothing to do when finishing a page write */
> +	if (req->type == NAND_PAGE_WRITE)
> +		return 0;
> +
> +	/* Finish a page write: check the status, report errors/bitflips */
> +	return spinand_check_ecc_status(spinand, engine_conf->status);
> +}
> +
> +static struct nand_ecc_engine_ops spinand_ondie_engine_ops = {
> +	.init_ctx = ecc_spinand_ondie_init_ctx,
> +	.cleanup_ctx = ecc_spinand_ondie_cleanup_ctx,
> +	.prepare_io_req = ecc_spinand_ondie_prepare_io_req,
> +	.finish_io_req = ecc_spinand_ondie_finish_io_req,
> +};
> +
> +static struct nand_ecc_engine spinand_ondie_engine = {
> +	.ops = &spinand_ondie_engine_ops,
> +};
> +
> +void spinand_ondie_ecc_save_status(struct nand_device *nand, u8 status)
> +{
> +	struct ecc_spinand_ondie_conf *engine_conf = nand->ecc.ctx.priv;
> +
> +	if (nand->ecc.engine == &spinand_ondie_engine && engine_conf)
> +		engine_conf->status = status;
> +}
> +
> +struct nand_ecc_engine *spinand_ondie_ecc_get_engine(void)
> +{
> +	return &spinand_ondie_engine;

Hm, I was expecting to have one engine instance directly embedded in
spinand_device. The ECC engine is not a global thing here, it's
actually tied to the SPI NAND device itself.

> +}


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-21 12:58 ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
@ 2019-02-22 14:44   ` Boris Brezillon
  2019-02-25 16:01     ` Miquel Raynal
  2019-02-27 14:07     ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
  0 siblings, 2 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-22 14:44 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Thu, 21 Feb 2019 13:58:04 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Add the logic in the NAND core to find the right ECC engine depending
> on the NAND chip requirements and the user desires. Right now, the
> choice may be made between (more will come):
> * software Hamming
> * software BCH
> * on-die (SPI-NAND devices only)
> 
> Once the ECC engine has been found, the ECC engine must be
> configured.
> 
> Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> ---
>  drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/nand.h |   4 ++
>  2 files changed, 111 insertions(+)
> 
> diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> index 872d46b5fc0f..9feb118c9f68 100644
> --- a/drivers/mtd/nand/core.c
> +++ b/drivers/mtd/nand/core.c
> @@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
>  }
>  EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
>  
> +/**
> + * nanddev_find_ecc_engine() - Find a suitable ECC engine
> + * @nand: NAND device
> + */
> +static int nanddev_find_ecc_engine(struct nand_device *nand)

Can we pass the conf in argument instead of reading it from
nand->ecc.user_conf?

> +{
> +	bool is_spinand = mtd_type_is_spinand(&nand->mtd);

And here is the reason for the SPINAND type.

> +
> +	/* Read the user desires in terms of ECC engine/configuration */
> +	nand_ecc_read_user_conf(nand);
> +
> +	/* No ECC engine requestedn, let's return without error */
> +	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
> +		return 0;
> +
> +	/* Raw NAND default mode is hardware */
> +	if (!is_spinand && nand->ecc.user_conf.mode < 0)
> +		nand->ecc.user_conf.mode = NAND_ECC_HW;

We should let the raw NAND layer take this decision (actually, it's
even a raw NAND controller driver decision). Please complain if
user_conf.mode is invalid.
This way you won't need the SPINAND type you added in one of your
previous patch.

> +
> +	/* SPI-NAND default mode is on-die */
> +	if (is_spinand && nand->ecc.user_conf.mode < 0)
> +		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
> +
> +	switch (nand->ecc.user_conf.mode) {
> +	case NAND_ECC_SOFT:
> +		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
> +		break;
> +	case NAND_ECC_ON_DIE:
> +		if (is_spinand)
> +			nand->ecc.engine = spinand_ondie_ecc_get_engine();

So, maybe it's worth having the ondie ECC engine instance directly
embedded in nand_device instead of spinand, or maybe just a pointer, so
that you don't reserve extra space when the NAND device does not have
on-die ECC.

> +		else
> +			pr_err("On-die ECC engines for non SPI devices not supported yet\n");
> +		break;
> +	case NAND_ECC_HW:
> +		pr_err("Hardware ECC engines not supported yet\n");
> +		break;
> +	default:
> +		pr_err("Missing ECC engine property\n");
> +	}
> +
> +	if (!nand->ecc.engine)
> +		return  -EINVAL;
> +
> +	return 0;
> +}


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core
  2019-02-22 14:29   ` Boris Brezillon
@ 2019-02-25 15:49     ` Miquel Raynal
  2019-02-25 16:13       ` Boris Brezillon
  0 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-25 15:49 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

Hi Boris,

Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
15:29:57 +0100:

> On Thu, 21 Feb 2019 13:57:59 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Before making use of the ECC engines, we must retrieve them. Add the
> > boilerplate for the ones already available: software engines (Hamming
> > and BCH).
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/mtd/nand/ecc/engine.c              | 14 ++++++++++++++
> >  include/linux/mtd/nand-sw-bch-engine.h     |  3 +++
> >  include/linux/mtd/nand-sw-hamming-engine.h |  3 +++
> >  include/linux/mtd/nand.h                   |  3 +++
> >  4 files changed, 23 insertions(+)
> > 
> > diff --git a/drivers/mtd/nand/ecc/engine.c b/drivers/mtd/nand/ecc/engine.c
> > index 7dd3f9772698..318dbb2d56a2 100644
> > --- a/drivers/mtd/nand/ecc/engine.c
> > +++ b/drivers/mtd/nand/ecc/engine.c
> > @@ -286,6 +286,20 @@ bool nand_ecc_correction_is_enough(struct nand_device *nand)
> >  	return corr >= ds_corr && conf->strength >= reqs->strength;
> >  }
> >  
> > +struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand)  
> 
> What if you want to instantiate SW ECC with a custom layout? Can't we
> instead have a function that create a new engine dynamically?
> 
> struct nand_ecc_engine *
> nand_ecc_create_sw_engine(struct nand_device* nand,
> 			  enum nand_ecc_algo algo,
> 			  struct mtd_ooblayout *layout);
> 
> 

Right now, for both sw engines, a default layout is applied if there is
none at engine initialization time.

Also, do we really need a "create" helper? I don't see what's created
there. Maybe you had something else in mind, and the
ecc_sw_xxx_get_engine() approach do not match what you expected, so
please tell me more about your idea, otherwise I don't see what a
nand_ecc_create_sw_engine() would bring.

> 
> > +{
> > +	switch (nand->ecc.user_conf.algo) {  
> 
> Note that the conf is supposed to be passed afterwards, when the ctx is
> created, so you should check nand->ecc.user_conf directly here.

I think this is what I do so I suspect the above sentence is not what
you actually meant?

> 
> > +	case NAND_ECC_HAMMING:
> > +		return ecc_sw_hamming_get_engine();
> > +	case NAND_ECC_BCH:
> > +		return ecc_sw_bch_get_engine();
> > +	default:
> > +		break;
> > +	}
> > +
> > +	return NULL;
> > +}
> > +
> >  MODULE_LICENSE("GPL v2");
> >  MODULE_AUTHOR("Miquel Raynal <miquel.raynal@bootlin.com>");
> >  MODULE_DESCRIPTION("Generic ECC engine");
> > diff --git a/include/linux/mtd/nand-sw-bch-engine.h b/include/linux/mtd/nand-sw-bch-engine.h
> > index e406aa53ec4e..38cdad117fea 100644
> > --- a/include/linux/mtd/nand-sw-bch-engine.h
> > +++ b/include/linux/mtd/nand-sw-bch-engine.h
> > @@ -11,6 +11,9 @@
> >  #include <linux/mtd/nand.h>
> >  #include <linux/bch.h>
> >  
> > +/* Needed for cross inclusion with nand.h */
> > +struct nand_device;
> > +
> >  /**
> >   * struct ecc_sw_bch_conf - private software BCH ECC engine structure
> >   * @reqooblen: Save the actual user OOB length requested before overwriting it
> > diff --git a/include/linux/mtd/nand-sw-hamming-engine.h b/include/linux/mtd/nand-sw-hamming-engine.h
> > index 8df36d189482..51c5a2acee42 100644
> > --- a/include/linux/mtd/nand-sw-hamming-engine.h
> > +++ b/include/linux/mtd/nand-sw-hamming-engine.h
> > @@ -12,6 +12,9 @@
> >  
> >  #include <linux/mtd/nand.h>
> >  
> > +/* Needed for cross inclusion with nand.h */
> > +struct nand_device;
> > +
> >  /**
> >   * struct ecc_sw_hamming_conf - private software Hamming ECC engine structure
> >   * @reqooblen: Save the actual user OOB length requested before overwriting it
> > diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> > index 4482eb2bbfd4..3abe113e4f06 100644
> > --- a/include/linux/mtd/nand.h
> > +++ b/include/linux/mtd/nand.h
> > @@ -11,6 +11,8 @@
> >  #define __LINUX_MTD_NAND_H
> >  
> >  #include <linux/mtd/mtd.h>
> > +#include <linux/mtd/nand-sw-hamming-engine.h>
> > +#include <linux/mtd/nand-sw-bch-engine.h>
> >  
> >  struct nand_device;
> >  
> > @@ -253,6 +255,7 @@ struct nand_ecc_engine {
> >  };
> >  
> >  void nand_ecc_read_user_conf(struct nand_device *nand);
> > +struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand);
> >  int nand_ecc_init_ctx(struct nand_device *nand);
> >  void nand_ecc_cleanup_ctx(struct nand_device *nand);
> >  int nand_ecc_prepare_io_req(struct nand_device *nand,  
> 




Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-22 14:44   ` Boris Brezillon
@ 2019-02-25 16:01     ` Miquel Raynal
  2019-02-25 16:34       ` Boris Brezillon
  2019-02-27 14:07     ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
  1 sibling, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-25 16:01 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

Hi Boris,

Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
15:44:31 +0100:

> On Thu, 21 Feb 2019 13:58:04 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Add the logic in the NAND core to find the right ECC engine depending
> > on the NAND chip requirements and the user desires. Right now, the
> > choice may be made between (more will come):
> > * software Hamming
> > * software BCH
> > * on-die (SPI-NAND devices only)
> > 
> > Once the ECC engine has been found, the ECC engine must be
> > configured.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
> >  include/linux/mtd/nand.h |   4 ++
> >  2 files changed, 111 insertions(+)
> > 
> > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > index 872d46b5fc0f..9feb118c9f68 100644
> > --- a/drivers/mtd/nand/core.c
> > +++ b/drivers/mtd/nand/core.c
> > @@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
> >  }
> >  EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
> >  
> > +/**
> > + * nanddev_find_ecc_engine() - Find a suitable ECC engine
> > + * @nand: NAND device
> > + */
> > +static int nanddev_find_ecc_engine(struct nand_device *nand)  
> 
> Can we pass the conf in argument instead of reading it from
> nand->ecc.user_conf?
> 
> > +{
> > +	bool is_spinand = mtd_type_is_spinand(&nand->mtd);  
> 
> And here is the reason for the SPINAND type.
> 
> > +
> > +	/* Read the user desires in terms of ECC engine/configuration */
> > +	nand_ecc_read_user_conf(nand);
> > +
> > +	/* No ECC engine requestedn, let's return without error */
> > +	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
> > +		return 0;
> > +
> > +	/* Raw NAND default mode is hardware */
> > +	if (!is_spinand && nand->ecc.user_conf.mode < 0)
> > +		nand->ecc.user_conf.mode = NAND_ECC_HW;  
> 
> We should let the raw NAND layer take this decision (actually, it's
> even a raw NAND controller driver decision). Please complain if
> user_conf.mode is invalid.
> This way you won't need the SPINAND type you added in one of your
> previous patch.
> 
> > +
> > +	/* SPI-NAND default mode is on-die */
> > +	if (is_spinand && nand->ecc.user_conf.mode < 0)
> > +		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
> > +
> > +	switch (nand->ecc.user_conf.mode) {
> > +	case NAND_ECC_SOFT:
> > +		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
> > +		break;
> > +	case NAND_ECC_ON_DIE:
> > +		if (is_spinand)
> > +			nand->ecc.engine = spinand_ondie_ecc_get_engine();  
> 
> So, maybe it's worth having the ondie ECC engine instance directly
> embedded in nand_device instead of spinand, or maybe just a pointer, so
> that you don't reserve extra space when the NAND device does not have
> on-die ECC.
> 
> > +		else
> > +			pr_err("On-die ECC engines for non SPI devices not supported yet\n");
> > +		break;
> > +	case NAND_ECC_HW:
> > +		pr_err("Hardware ECC engines not supported yet\n");
> > +		break;
> > +	default:
> > +		pr_err("Missing ECC engine property\n");
> > +	}
> > +
> > +	if (!nand->ecc.engine)
> > +		return  -EINVAL;
> > +
> > +	return 0;
> > +}  
> 

I think this is the root patch were our ideas diverge. For me, each
'ECC engine' has a _get() helper and the NAND core decides which one to
call to retrieve the right engine. Can you please explain what was your
idea if this one does not fit?

Also, the parsing of the DT (in nand_ecc_read_user_conf()) gives me the
user ECC mode and algo, so I cannot let the raw NAND core (or a raw
NAND controller driver) or the SPI NAND core decide which mode is the
default if not provided by the user.


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core
  2019-02-25 15:49     ` Miquel Raynal
@ 2019-02-25 16:13       ` Boris Brezillon
  2019-02-26 15:54         ` Miquel Raynal
  0 siblings, 1 reply; 36+ messages in thread
From: Boris Brezillon @ 2019-02-25 16:13 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Mon, 25 Feb 2019 16:49:33 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
> 15:29:57 +0100:
> 
> > On Thu, 21 Feb 2019 13:57:59 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > Before making use of the ECC engines, we must retrieve them. Add the
> > > boilerplate for the ones already available: software engines (Hamming
> > > and BCH).
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/mtd/nand/ecc/engine.c              | 14 ++++++++++++++
> > >  include/linux/mtd/nand-sw-bch-engine.h     |  3 +++
> > >  include/linux/mtd/nand-sw-hamming-engine.h |  3 +++
> > >  include/linux/mtd/nand.h                   |  3 +++
> > >  4 files changed, 23 insertions(+)
> > > 
> > > diff --git a/drivers/mtd/nand/ecc/engine.c b/drivers/mtd/nand/ecc/engine.c
> > > index 7dd3f9772698..318dbb2d56a2 100644
> > > --- a/drivers/mtd/nand/ecc/engine.c
> > > +++ b/drivers/mtd/nand/ecc/engine.c
> > > @@ -286,6 +286,20 @@ bool nand_ecc_correction_is_enough(struct nand_device *nand)
> > >  	return corr >= ds_corr && conf->strength >= reqs->strength;
> > >  }
> > >  
> > > +struct nand_ecc_engine *nand_ecc_sw_get_engine(struct nand_device *nand)    
> > 
> > What if you want to instantiate SW ECC with a custom layout? Can't we
> > instead have a function that create a new engine dynamically?
> > 
> > struct nand_ecc_engine *
> > nand_ecc_create_sw_engine(struct nand_device* nand,
> > 			  enum nand_ecc_algo algo,
> > 			  struct mtd_ooblayout *layout);
> > 
> >   
> 
> Right now, for both sw engines, a default layout is applied if there is
> none at engine initialization time.
> 
> Also, do we really need a "create" helper? I don't see what's created
> there. Maybe you had something else in mind, and the
> ecc_sw_xxx_get_engine() approach do not match what you expected, so
> please tell me more about your idea, otherwise I don't see what a
> nand_ecc_create_sw_engine() would bring.

The layout is part of the ECC engine properties, which I why I suggest
to create one engine instance per user and specify the layout to use
at instance creation time.

> 
> >   
> > > +{
> > > +	switch (nand->ecc.user_conf.algo) {    
> > 
> > Note that the conf is supposed to be passed afterwards, when the ctx is
> > created, so you should check nand->ecc.user_conf directly here.  
> 
> I think this is what I do so I suspect the above sentence is not what
> you actually meant?

Sorry, I meant "should not". My point is, the user_conf should only be
passed at context creation time, and should not be modified in-place by
the caller, unless proven necessary.

There's really 2 different steps that I think need to be isolated:

1/ retrieve/create an ECC engine instance (SW, HW-controller-side,
   on-die)
2/ ask this ECC engine instance to create a context out of a user conf

Your user_conf seems 2 mix the 2 concepts: the engine to use, the
strength/step-size you expect.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-25 16:01     ` Miquel Raynal
@ 2019-02-25 16:34       ` Boris Brezillon
  2019-02-25 18:48         ` Boris Brezillon
  0 siblings, 1 reply; 36+ messages in thread
From: Boris Brezillon @ 2019-02-25 16:34 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

On Mon, 25 Feb 2019 17:01:18 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
> 15:44:31 +0100:
> 
> > On Thu, 21 Feb 2019 13:58:04 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > Add the logic in the NAND core to find the right ECC engine depending
> > > on the NAND chip requirements and the user desires. Right now, the
> > > choice may be made between (more will come):
> > > * software Hamming
> > > * software BCH
> > > * on-die (SPI-NAND devices only)
> > > 
> > > Once the ECC engine has been found, the ECC engine must be
> > > configured.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
> > >  include/linux/mtd/nand.h |   4 ++
> > >  2 files changed, 111 insertions(+)
> > > 
> > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > index 872d46b5fc0f..9feb118c9f68 100644
> > > --- a/drivers/mtd/nand/core.c
> > > +++ b/drivers/mtd/nand/core.c
> > > @@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
> > >  }
> > >  EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
> > >  
> > > +/**
> > > + * nanddev_find_ecc_engine() - Find a suitable ECC engine
> > > + * @nand: NAND device
> > > + */
> > > +static int nanddev_find_ecc_engine(struct nand_device *nand)    
> > 
> > Can we pass the conf in argument instead of reading it from
> > nand->ecc.user_conf?
> >   
> > > +{
> > > +	bool is_spinand = mtd_type_is_spinand(&nand->mtd);    
> > 
> > And here is the reason for the SPINAND type.
> >   
> > > +
> > > +	/* Read the user desires in terms of ECC engine/configuration */
> > > +	nand_ecc_read_user_conf(nand);
> > > +
> > > +	/* No ECC engine requestedn, let's return without error */
> > > +	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
> > > +		return 0;
> > > +
> > > +	/* Raw NAND default mode is hardware */
> > > +	if (!is_spinand && nand->ecc.user_conf.mode < 0)
> > > +		nand->ecc.user_conf.mode = NAND_ECC_HW;    
> > 
> > We should let the raw NAND layer take this decision (actually, it's
> > even a raw NAND controller driver decision). Please complain if
> > user_conf.mode is invalid.
> > This way you won't need the SPINAND type you added in one of your
> > previous patch.
> >   
> > > +
> > > +	/* SPI-NAND default mode is on-die */
> > > +	if (is_spinand && nand->ecc.user_conf.mode < 0)
> > > +		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
> > > +
> > > +	switch (nand->ecc.user_conf.mode) {
> > > +	case NAND_ECC_SOFT:
> > > +		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
> > > +		break;
> > > +	case NAND_ECC_ON_DIE:
> > > +		if (is_spinand)
> > > +			nand->ecc.engine = spinand_ondie_ecc_get_engine();    
> > 
> > So, maybe it's worth having the ondie ECC engine instance directly
> > embedded in nand_device instead of spinand, or maybe just a pointer, so
> > that you don't reserve extra space when the NAND device does not have
> > on-die ECC.
> >   
> > > +		else
> > > +			pr_err("On-die ECC engines for non SPI devices not supported yet\n");
> > > +		break;
> > > +	case NAND_ECC_HW:
> > > +		pr_err("Hardware ECC engines not supported yet\n");
> > > +		break;
> > > +	default:
> > > +		pr_err("Missing ECC engine property\n");
> > > +	}
> > > +
> > > +	if (!nand->ecc.engine)
> > > +		return  -EINVAL;
> > > +
> > > +	return 0;
> > > +}    
> >   
> 
> I think this is the root patch were our ideas diverge. For me, each
> 'ECC engine' has a _get() helper and the NAND core decides which one to
> call to retrieve the right engine. Can you please explain what was your
> idea if this one does not fit?

Each class of ECC engine has its own way of getting a pointer to an ECC
engine instance:

- ondie: the engine is directly attached to the device and can be
  retrieved by accessing a nand_device field (nanddev->ondie_ecc?).
- sw ECC: you can create a new instance for each device and possibly
  pass the OOB layout you want to use (assuming you don't want to use
  the default one)
- HW-controller-side engine: refers to the controller device (parent
  node) or the device pointed by the ecc-engine DT prop (we'll probably
  need a way to pass this info when for non-DT platforms). For this one
  we'll add a nanddev_get_hw_ecc_engine() which will search for all
  registered HW ECC engines and try to match with some search keys (in
  case of DT, it's the ->of_node pointer address)

Clearly, for SW-based ECC, you'll need more than just the nanddev
object, as layouts can differ depending on the controller driver. So,
what I'm suggesting is to have a

	nand_create_sw_ecc_engine(algo, layout) 

funtion that returns this ECC engine instance which the driver will
then attach to the NAND device.

> 
> Also, the parsing of the DT (in nand_ecc_read_user_conf()) gives me the
> user ECC mode and algo, so I cannot let the raw NAND core (or a raw
> NAND controller driver) or the SPI NAND core decide which mode is the
> default if not provided by the user.

Except this prop is optional in most cases, and the default value is
not always the same, which is why I think this ECC engine retrieval step
should be left to each sub-layer (and sometimes to the controller driver
behind it). Maybe you can provide helpers to help with that, but I
don't think taking this decision here, based on the bus type, is a good
idea. And I also don't like the idea of adding a new SPINAND type.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-25 16:34       ` Boris Brezillon
@ 2019-02-25 18:48         ` Boris Brezillon
  2019-02-26 15:59           ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurationsND Miquel Raynal
  0 siblings, 1 reply; 36+ messages in thread
From: Boris Brezillon @ 2019-02-25 18:48 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Brian Norris, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Mason Yang, David Woodhouse, linux-arm-kernel

On Mon, 25 Feb 2019 17:34:22 +0100
Boris Brezillon <boris.brezillon@collabora.com> wrote:

> On Mon, 25 Feb 2019 17:01:18 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Hi Boris,
> > 
> > Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
> > 15:44:31 +0100:
> >   
> > > On Thu, 21 Feb 2019 13:58:04 +0100
> > > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> > >     
> > > > Add the logic in the NAND core to find the right ECC engine depending
> > > > on the NAND chip requirements and the user desires. Right now, the
> > > > choice may be made between (more will come):
> > > > * software Hamming
> > > > * software BCH
> > > > * on-die (SPI-NAND devices only)
> > > > 
> > > > Once the ECC engine has been found, the ECC engine must be
> > > > configured.
> > > > 
> > > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > > ---
> > > >  drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
> > > >  include/linux/mtd/nand.h |   4 ++
> > > >  2 files changed, 111 insertions(+)
> > > > 
> > > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > > index 872d46b5fc0f..9feb118c9f68 100644
> > > > --- a/drivers/mtd/nand/core.c
> > > > +++ b/drivers/mtd/nand/core.c
> > > > @@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
> > > >  }
> > > >  EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
> > > >  
> > > > +/**
> > > > + * nanddev_find_ecc_engine() - Find a suitable ECC engine
> > > > + * @nand: NAND device
> > > > + */
> > > > +static int nanddev_find_ecc_engine(struct nand_device *nand)      
> > > 
> > > Can we pass the conf in argument instead of reading it from
> > > nand->ecc.user_conf?
> > >     
> > > > +{
> > > > +	bool is_spinand = mtd_type_is_spinand(&nand->mtd);      
> > > 
> > > And here is the reason for the SPINAND type.
> > >     
> > > > +
> > > > +	/* Read the user desires in terms of ECC engine/configuration */
> > > > +	nand_ecc_read_user_conf(nand);
> > > > +
> > > > +	/* No ECC engine requestedn, let's return without error */
> > > > +	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
> > > > +		return 0;
> > > > +
> > > > +	/* Raw NAND default mode is hardware */
> > > > +	if (!is_spinand && nand->ecc.user_conf.mode < 0)
> > > > +		nand->ecc.user_conf.mode = NAND_ECC_HW;      
> > > 
> > > We should let the raw NAND layer take this decision (actually, it's
> > > even a raw NAND controller driver decision). Please complain if
> > > user_conf.mode is invalid.
> > > This way you won't need the SPINAND type you added in one of your
> > > previous patch.
> > >     
> > > > +
> > > > +	/* SPI-NAND default mode is on-die */
> > > > +	if (is_spinand && nand->ecc.user_conf.mode < 0)
> > > > +		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
> > > > +
> > > > +	switch (nand->ecc.user_conf.mode) {
> > > > +	case NAND_ECC_SOFT:
> > > > +		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
> > > > +		break;
> > > > +	case NAND_ECC_ON_DIE:
> > > > +		if (is_spinand)
> > > > +			nand->ecc.engine = spinand_ondie_ecc_get_engine();      
> > > 
> > > So, maybe it's worth having the ondie ECC engine instance directly
> > > embedded in nand_device instead of spinand, or maybe just a pointer, so
> > > that you don't reserve extra space when the NAND device does not have
> > > on-die ECC.
> > >     
> > > > +		else
> > > > +			pr_err("On-die ECC engines for non SPI devices not supported yet\n");
> > > > +		break;
> > > > +	case NAND_ECC_HW:
> > > > +		pr_err("Hardware ECC engines not supported yet\n");
> > > > +		break;
> > > > +	default:
> > > > +		pr_err("Missing ECC engine property\n");
> > > > +	}
> > > > +
> > > > +	if (!nand->ecc.engine)
> > > > +		return  -EINVAL;
> > > > +
> > > > +	return 0;
> > > > +}      
> > >     
> > 
> > I think this is the root patch were our ideas diverge. For me, each
> > 'ECC engine' has a _get() helper and the NAND core decides which one to
> > call to retrieve the right engine. Can you please explain what was your
> > idea if this one does not fit?  
> 
> Each class of ECC engine has its own way of getting a pointer to an ECC
> engine instance:
> 
> - ondie: the engine is directly attached to the device and can be
>   retrieved by accessing a nand_device field (nanddev->ondie_ecc?).
> - sw ECC: you can create a new instance for each device and possibly
>   pass the OOB layout you want to use (assuming you don't want to use
>   the default one)
> - HW-controller-side engine: refers to the controller device (parent
>   node) or the device pointed by the ecc-engine DT prop (we'll probably
>   need a way to pass this info when for non-DT platforms). For this one
>   we'll add a nanddev_get_hw_ecc_engine() which will search for all
>   registered HW ECC engines and try to match with some search keys (in
>   case of DT, it's the ->of_node pointer address)
> 
> Clearly, for SW-based ECC, you'll need more than just the nanddev
> object, as layouts can differ depending on the controller driver. So,
> what I'm suggesting is to have a
> 
> 	nand_create_sw_ecc_engine(algo, layout) 
> 
> funtion that returns this ECC engine instance which the driver will
> then attach to the NAND device.

I'm reconsidering what I said here. I guess having the layout set by
the driver before nand_ecc_sw_get_engine() is called could do the
trick. We just need to make sure the layout provided has enough space
to store ECC bytes at context creation time.

> 
> > 
> > Also, the parsing of the DT (in nand_ecc_read_user_conf()) gives me the
> > user ECC mode and algo, so I cannot let the raw NAND core (or a raw
> > NAND controller driver) or the SPI NAND core decide which mode is the
> > default if not provided by the user.  
> 
> Except this prop is optional in most cases, and the default value is
> not always the same, which is why I think this ECC engine retrieval step
> should be left to each sub-layer (and sometimes to the controller driver
> behind it). Maybe you can provide helpers to help with that, but I
> don't think taking this decision here, based on the bus type, is a good
> idea. And I also don't like the idea of adding a new SPINAND type.

Hm, after thinking a bit more about it, maybe we could have something
in-between: let the controller driver or sub-layer specify what the
default values are (provider/mode and possibly algorithm if that makes
sense) so that this generic function can use these defaults when
nand->ecc.user_conf.{mode,algo} == UNKNOWN.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core
  2019-02-25 16:13       ` Boris Brezillon
@ 2019-02-26 15:54         ` Miquel Raynal
  0 siblings, 0 replies; 36+ messages in thread
From: Miquel Raynal @ 2019-02-26 15:54 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

Hi Boris,

Boris Brezillon <boris.brezillon@collabora.com> wrote on Mon, 25 Feb
2019 17:13:30 +0100:

> > > > +{
> > > > +	switch (nand->ecc.user_conf.algo) {      
> > > 
> > > Note that the conf is supposed to be passed afterwards, when the ctx is
> > > created, so you should check nand->ecc.user_conf directly here.    
> > 
> > I think this is what I do so I suspect the above sentence is not what
> > you actually meant?  
> 
> Sorry, I meant "should not". My point is, the user_conf should only be
> passed at context creation time, and should not be modified in-place by
> the caller, unless proven necessary.
> 
> There's really 2 different steps that I think need to be isolated:
> 
> 1/ retrieve/create an ECC engine instance (SW, HW-controller-side,
>    on-die)
> 2/ ask this ECC engine instance to create a context out of a user conf
> 
> Your user_conf seems 2 mix the 2 concepts: the engine to use, the
> strength/step-size you expect.

No, I am not mixing things: the user might want a specific engine and a
strength/step-size. All of this is what the user requests.

In the ECC logic, I need to make a choice: I really need to check
what the user request is in order to choose the provider. I am not
changing anything here, just reading.

Later the chosen ECC engine will be prompted to create a context with
the rest of the user configuration.

I don't think it is relevant here to split this structure.


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurationsND
  2019-02-25 18:48         ` Boris Brezillon
@ 2019-02-26 15:59           ` Miquel Raynal
  2019-02-26 16:04             ` Boris Brezillon
  0 siblings, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-26 15:59 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Brian Norris, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Mason Yang, David Woodhouse, linux-arm-kernel

Hi Boris,

Boris Brezillon <boris.brezillon@collabora.com> wrote on Mon, 25 Feb
2019 19:48:03 +0100:

> > > Also, the parsing of the DT (in nand_ecc_read_user_conf()) gives me the
> > > user ECC mode and algo, so I cannot let the raw NAND core (or a raw
> > > NAND controller driver) or the SPI NAND core decide which mode is the
> > > default if not provided by the user.    
> > 
> > Except this prop is optional in most cases, and the default value is
> > not always the same, which is why I think this ECC engine retrieval step
> > should be left to each sub-layer (and sometimes to the controller driver
> > behind it). Maybe you can provide helpers to help with that, but I
> > don't think taking this decision here, based on the bus type, is a good
> > idea. And I also don't like the idea of adding a new SPINAND type.  
> 
> Hm, after thinking a bit more about it, maybe we could have something
> in-between: let the controller driver or sub-layer specify what the
> default values are (provider/mode and possibly algorithm if that makes
> sense) so that this generic function can use these defaults when
> nand->ecc.user_conf.{mode,algo} == UNKNOWN.

Having a "default_provider" in struct nand_ecc could to the trick. It
would be filled by the controller drivers/sublayers before
nanddev_ecc_engine_init() is called.


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurationsND
  2019-02-26 15:59           ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurationsND Miquel Raynal
@ 2019-02-26 16:04             ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-26 16:04 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Brian Norris, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Mason Yang, David Woodhouse, linux-arm-kernel

On Tue, 26 Feb 2019 16:59:23 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> Boris Brezillon <boris.brezillon@collabora.com> wrote on Mon, 25 Feb
> 2019 19:48:03 +0100:
> 
> > > > Also, the parsing of the DT (in nand_ecc_read_user_conf()) gives me the
> > > > user ECC mode and algo, so I cannot let the raw NAND core (or a raw
> > > > NAND controller driver) or the SPI NAND core decide which mode is the
> > > > default if not provided by the user.      
> > > 
> > > Except this prop is optional in most cases, and the default value is
> > > not always the same, which is why I think this ECC engine retrieval step
> > > should be left to each sub-layer (and sometimes to the controller driver
> > > behind it). Maybe you can provide helpers to help with that, but I
> > > don't think taking this decision here, based on the bus type, is a good
> > > idea. And I also don't like the idea of adding a new SPINAND type.    
> > 
> > Hm, after thinking a bit more about it, maybe we could have something
> > in-between: let the controller driver or sub-layer specify what the
> > default values are (provider/mode and possibly algorithm if that makes
> > sense) so that this generic function can use these defaults when
> > nand->ecc.user_conf.{mode,algo} == UNKNOWN.  
> 
> Having a "default_provider" in struct nand_ecc could to the trick. It
> would be filled by the controller drivers/sublayers before
> nanddev_ecc_engine_init() is called.

You'll also need a default_algo, at least for SW ECC. Note that other
props, like strength, step-size or flags (like the maximize flag) can
be left undefined as well, so providing default vals for those ones (or
deriving them from ECC requirements) might make sense too.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-22 14:44   ` Boris Brezillon
  2019-02-25 16:01     ` Miquel Raynal
@ 2019-02-27 14:07     ` Miquel Raynal
  2019-02-27 14:30       ` Boris Brezillon
  1 sibling, 1 reply; 36+ messages in thread
From: Miquel Raynal @ 2019-02-27 14:07 UTC (permalink / raw)
  To: Boris Brezillon
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Schrempf Frieder, Marek Vasut, linux-mtd,
	Thomas Petazzoni, Brian Norris, David Woodhouse,
	linux-arm-kernel

Hi Boris,

Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
15:44:31 +0100:

> On Thu, 21 Feb 2019 13:58:04 +0100
> Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> 
> > Add the logic in the NAND core to find the right ECC engine depending
> > on the NAND chip requirements and the user desires. Right now, the
> > choice may be made between (more will come):
> > * software Hamming
> > * software BCH
> > * on-die (SPI-NAND devices only)
> > 
> > Once the ECC engine has been found, the ECC engine must be
> > configured.
> > 
> > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > ---
> >  drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
> >  include/linux/mtd/nand.h |   4 ++
> >  2 files changed, 111 insertions(+)
> > 
> > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > index 872d46b5fc0f..9feb118c9f68 100644
> > --- a/drivers/mtd/nand/core.c
> > +++ b/drivers/mtd/nand/core.c
> > @@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
> >  }
> >  EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
> >  
> > +/**
> > + * nanddev_find_ecc_engine() - Find a suitable ECC engine
> > + * @nand: NAND device
> > + */
> > +static int nanddev_find_ecc_engine(struct nand_device *nand)  
> 
> Can we pass the conf in argument instead of reading it from
> nand->ecc.user_conf?

I just changed the root structures, there is a

       struct nand_ecc_conf defaults;

entry now in the nand_ecc_engine structure, which every layer/driver
can overwrite to inform the NAND core of a default value.

Later in this function, I check user_conf (which I might call
"desires" now that we have a "defaults" and a "requirements" entries),
but if the value is missing I fallback to the "defaults" one if filled.
Having all these structures being passed as parameters does not make
sense to me so I would prefer sticking to the single "nand" parameter.

> 
> > +{
> > +	bool is_spinand = mtd_type_is_spinand(&nand->mtd);  
> 
> And here is the reason for the SPINAND type.

This does not exist anymore as you suggested.

> 
> > +
> > +	/* Read the user desires in terms of ECC engine/configuration */
> > +	nand_ecc_read_user_conf(nand);
> > +
> > +	/* No ECC engine requestedn, let's return without error */
> > +	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
> > +		return 0;
> > +
> > +	/* Raw NAND default mode is hardware */
> > +	if (!is_spinand && nand->ecc.user_conf.mode < 0)
> > +		nand->ecc.user_conf.mode = NAND_ECC_HW;  
> 
> We should let the raw NAND layer take this decision (actually, it's
> even a raw NAND controller driver decision). Please complain if
> user_conf.mode is invalid.
> This way you won't need the SPINAND type you added in one of your
> previous patch.

See above for the solution I choose.

> 
> > +
> > +	/* SPI-NAND default mode is on-die */
> > +	if (is_spinand && nand->ecc.user_conf.mode < 0)
> > +		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
> > +
> > +	switch (nand->ecc.user_conf.mode) {
> > +	case NAND_ECC_SOFT:
> > +		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
> > +		break;
> > +	case NAND_ECC_ON_DIE:
> > +		if (is_spinand)
> > +			nand->ecc.engine = spinand_ondie_ecc_get_engine();  
> 
> So, maybe it's worth having the ondie ECC engine instance directly
> embedded in nand_device instead of spinand, or maybe just a pointer, so
> that you don't reserve extra space when the NAND device does not have
> on-die ECC.

It is now: the nand_ecc_engine structure features a *engine and a
*ondie_engine pointer.

The nand_ecc_get_ondie_engine(nand) helper just
returns nand->ecc.ondie_engine.

> 
> > +		else
> > +			pr_err("On-die ECC engines for non SPI devices not supported yet\n");
> > +		break;
> > +	case NAND_ECC_HW:
> > +		pr_err("Hardware ECC engines not supported yet\n");
> > +		break;
> > +	default:
> > +		pr_err("Missing ECC engine property\n");
> > +	}
> > +
> > +	if (!nand->ecc.engine)
> > +		return  -EINVAL;
> > +
> > +	return 0;
> > +}  
> 


Thanks,
Miquèl

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations
  2019-02-27 14:07     ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
@ 2019-02-27 14:30       ` Boris Brezillon
  0 siblings, 0 replies; 36+ messages in thread
From: Boris Brezillon @ 2019-02-27 14:30 UTC (permalink / raw)
  To: Miquel Raynal
  Cc: Mason Yang, Vignesh R, Tudor Ambarus, Julien Su,
	Richard Weinberger, Boris Brezillon, Schrempf Frieder,
	Marek Vasut, linux-mtd, Thomas Petazzoni, Brian Norris,
	David Woodhouse, linux-arm-kernel

On Wed, 27 Feb 2019 15:07:13 +0100
Miquel Raynal <miquel.raynal@bootlin.com> wrote:

> Hi Boris,
> 
> Boris Brezillon <bbrezillon@kernel.org> wrote on Fri, 22 Feb 2019
> 15:44:31 +0100:
> 
> > On Thu, 21 Feb 2019 13:58:04 +0100
> > Miquel Raynal <miquel.raynal@bootlin.com> wrote:
> >   
> > > Add the logic in the NAND core to find the right ECC engine depending
> > > on the NAND chip requirements and the user desires. Right now, the
> > > choice may be made between (more will come):
> > > * software Hamming
> > > * software BCH
> > > * on-die (SPI-NAND devices only)
> > > 
> > > Once the ECC engine has been found, the ECC engine must be
> > > configured.
> > > 
> > > Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
> > > ---
> > >  drivers/mtd/nand/core.c  | 107 +++++++++++++++++++++++++++++++++++++++
> > >  include/linux/mtd/nand.h |   4 ++
> > >  2 files changed, 111 insertions(+)
> > > 
> > > diff --git a/drivers/mtd/nand/core.c b/drivers/mtd/nand/core.c
> > > index 872d46b5fc0f..9feb118c9f68 100644
> > > --- a/drivers/mtd/nand/core.c
> > > +++ b/drivers/mtd/nand/core.c
> > > @@ -207,6 +207,113 @@ int nanddev_mtd_max_bad_blocks(struct mtd_info *mtd, loff_t offs, size_t len)
> > >  }
> > >  EXPORT_SYMBOL_GPL(nanddev_mtd_max_bad_blocks);
> > >  
> > > +/**
> > > + * nanddev_find_ecc_engine() - Find a suitable ECC engine
> > > + * @nand: NAND device
> > > + */
> > > +static int nanddev_find_ecc_engine(struct nand_device *nand)    
> > 
> > Can we pass the conf in argument instead of reading it from
> > nand->ecc.user_conf?  
> 
> I just changed the root structures, there is a
> 
>        struct nand_ecc_conf defaults;
> 
> entry now in the nand_ecc_engine structure, which every layer/driver
> can overwrite to inform the NAND core of a default value.
> 
> Later in this function, I check user_conf (which I might call
> "desires" now that we have a "defaults" and a "requirements" entries),
> but if the value is missing I fallback to the "defaults" one if filled.
> Having all these structures being passed as parameters does not make
> sense to me so I would prefer sticking to the single "nand" parameter.
> 
> >   
> > > +{
> > > +	bool is_spinand = mtd_type_is_spinand(&nand->mtd);    
> > 
> > And here is the reason for the SPINAND type.  
> 
> This does not exist anymore as you suggested.
> 
> >   
> > > +
> > > +	/* Read the user desires in terms of ECC engine/configuration */
> > > +	nand_ecc_read_user_conf(nand);
> > > +
> > > +	/* No ECC engine requestedn, let's return without error */
> > > +	if (nand->ecc.user_conf.mode == NAND_ECC_NONE)
> > > +		return 0;
> > > +
> > > +	/* Raw NAND default mode is hardware */
> > > +	if (!is_spinand && nand->ecc.user_conf.mode < 0)
> > > +		nand->ecc.user_conf.mode = NAND_ECC_HW;    
> > 
> > We should let the raw NAND layer take this decision (actually, it's
> > even a raw NAND controller driver decision). Please complain if
> > user_conf.mode is invalid.
> > This way you won't need the SPINAND type you added in one of your
> > previous patch.  
> 
> See above for the solution I choose.
> 
> >   
> > > +
> > > +	/* SPI-NAND default mode is on-die */
> > > +	if (is_spinand && nand->ecc.user_conf.mode < 0)
> > > +		nand->ecc.user_conf.mode = NAND_ECC_ON_DIE;
> > > +
> > > +	switch (nand->ecc.user_conf.mode) {
> > > +	case NAND_ECC_SOFT:
> > > +		nand->ecc.engine = nand_ecc_sw_get_engine(nand);
> > > +		break;
> > > +	case NAND_ECC_ON_DIE:
> > > +		if (is_spinand)
> > > +			nand->ecc.engine = spinand_ondie_ecc_get_engine();    
> > 
> > So, maybe it's worth having the ondie ECC engine instance directly
> > embedded in nand_device instead of spinand, or maybe just a pointer, so
> > that you don't reserve extra space when the NAND device does not have
> > on-die ECC.  
> 
> It is now: the nand_ecc_engine structure features a *engine and a
> *ondie_engine pointer.
> 
> The nand_ecc_get_ondie_engine(nand) helper just
> returns nand->ecc.ondie_engine.

Ack to all of this.

______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2019-02-27 14:30 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-02-21 12:57 [RFC PATCH 13/27] mtd: nand: ecc: Clarify the software Hamming introductory line Miquel Raynal
2019-02-21 12:57 ` [RFC PATCH 14/27] mtd: nand: ecc: Turn the software Hamming implementation generic Miquel Raynal
2019-02-21 13:22   ` Boris Brezillon
2019-02-21 12:57 ` [RFC PATCH 15/27] mtd: nand: Remove useless include about software Hamming ECC Miquel Raynal
2019-02-21 12:57 ` [RFC PATCH 16/27] mtd: nand: ecc: Let the software BCH ECC engine be a module Miquel Raynal
2019-02-21 13:48   ` Adam Ford
2019-02-21 14:02     ` Miquel Raynal
2019-02-22 14:24       ` Boris Brezillon
2019-02-21 12:57 ` [RFC PATCH 17/27] mtd: nand: ecc: Let the software Hamming ECC engine be unselected Miquel Raynal
2019-02-21 13:20   ` Boris Brezillon
2019-02-21 13:35     ` Miquel Raynal
2019-02-21 13:41       ` Boris Brezillon
2019-02-21 13:46         ` Miquel Raynal
2019-02-21 12:57 ` [RFC PATCH 18/27] mtd: nand: ecc: Create the software BCH engine instance Miquel Raynal
2019-02-21 12:57 ` [RFC PATCH 19/27] mtd: nand: ecc: Create the software Hamming " Miquel Raynal
2019-02-21 12:57 ` [RFC PATCH 20/27] mtd: nand: Let software ECC engines be retrieved from the NAND core Miquel Raynal
2019-02-22 14:29   ` Boris Brezillon
2019-02-25 15:49     ` Miquel Raynal
2019-02-25 16:13       ` Boris Brezillon
2019-02-26 15:54         ` Miquel Raynal
2019-02-21 12:58 ` [RFC PATCH 21/27] mtd: spinand: Fix typo in comment Miquel Raynal
2019-02-22 14:31   ` Boris Brezillon
2019-02-21 12:58 ` [RFC PATCH 22/27] mtd: spinand: Let the SPI-NAND core flag a SPI-NAND chip Miquel Raynal
2019-02-22 14:33   ` Boris Brezillon
2019-02-21 12:58 ` [RFC PATCH 23/27] mtd: spinand: Move the ECC helper functions into a separate file Miquel Raynal
2019-02-21 12:58 ` [RFC PATCH 24/27] mtd: spinand: Instantiate a SPI-NAND on-die ECC engine Miquel Raynal
2019-02-22 14:38   ` Boris Brezillon
2019-02-21 12:58 ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
2019-02-22 14:44   ` Boris Brezillon
2019-02-25 16:01     ` Miquel Raynal
2019-02-25 16:34       ` Boris Brezillon
2019-02-25 18:48         ` Boris Brezillon
2019-02-26 15:59           ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurationsND Miquel Raynal
2019-02-26 16:04             ` Boris Brezillon
2019-02-27 14:07     ` [RFC PATCH 25/27] mtd: nand: Add helpers to manage ECC engines and configurations Miquel Raynal
2019-02-27 14:30       ` Boris Brezillon

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).