[PATCH 2/3] mtd: nand: Add support for raw access when using on-die ECC

Richard Weinberger richard at nod.at
Wed Mar 25 07:02:30 PDT 2015


Implementing raw access for on-die ECC mode is a bit beautiless
because we have to disable on-die ECC before sending the NAND read
command and re-enable it again at all locations where raw access
can happen.
If the kernel was built without on-die ECC support or the current
ECC mode is not on-die these operations are no-ops.

Signed-off-by: Richard Weinberger <richard at nod.at>
---
 drivers/mtd/nand/nand_base.c | 38 +++++++++++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 92e7ed7..b42f556 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1589,16 +1589,21 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 						 __func__, buf);
 
 read_retry:
+			if (unlikely(ops->mode == MTD_OPS_RAW))
+				nand_setup_on_die_ecc_micron(mtd, 0);
+
 			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
 			/*
 			 * Now read the page into the buffer.  Absent an error,
 			 * the read methods return max bitflips per ecc step.
 			 */
-			if (unlikely(ops->mode == MTD_OPS_RAW))
+			if (unlikely(ops->mode == MTD_OPS_RAW)) {
 				ret = chip->ecc.read_page_raw(mtd, chip, bufpoi,
 							      oob_required,
 							      page);
+				nand_setup_on_die_ecc_micron(mtd, 1);
+			}
 			else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
 				 !oob)
 				ret = chip->ecc.read_subpage(mtd, chip,
@@ -1926,9 +1931,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
 	page = realpage & chip->pagemask;
 
 	while (1) {
-		if (ops->mode == MTD_OPS_RAW)
+		if (ops->mode == MTD_OPS_RAW) {
+			nand_setup_on_die_ecc_micron(mtd, 0);
 			ret = chip->ecc.read_oob_raw(mtd, chip, page);
-		else
+			nand_setup_on_die_ecc_micron(mtd, 1);
+		} else
 			ret = chip->ecc.read_oob(mtd, chip, page);
 
 		if (ret < 0)
@@ -2271,6 +2278,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 	else
 		subpage = 0;
 
+	if (unlikely(raw))
+		nand_setup_on_die_ecc_micron(mtd, 0);
+
 	chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
 
 	if (unlikely(raw))
@@ -2283,7 +2293,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 		status = chip->ecc.write_page(mtd, chip, buf, oob_required);
 
 	if (status < 0)
-		return status;
+		goto out;
 
 	/*
 	 * Cached progamming disabled for now. Not sure if it's worth the
@@ -2303,14 +2313,22 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
 			status = chip->errstat(mtd, chip, FL_WRITING, status,
 					       page);
 
-		if (status & NAND_STATUS_FAIL)
-			return -EIO;
+		if (status & NAND_STATUS_FAIL) {
+			status = -EIO;
+			goto out;
+		}
 	} else {
 		chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1);
 		status = chip->waitfunc(mtd, chip);
 	}
 
-	return 0;
+	status = 0;
+
+out:
+	if (unlikely(raw))
+		nand_setup_on_die_ecc_micron(mtd, 1);
+
+	return status;
 }
 
 /**
@@ -2632,9 +2650,11 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 
 	nand_fill_oob(mtd, ops->oobbuf, ops->ooblen, ops);
 
-	if (ops->mode == MTD_OPS_RAW)
+	if (ops->mode == MTD_OPS_RAW) {
+		nand_setup_on_die_ecc_micron(mtd, 0);
 		status = chip->ecc.write_oob_raw(mtd, chip, page & chip->pagemask);
-	else
+		nand_setup_on_die_ecc_micron(mtd, 1);
+	} else
 		status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
 
 	chip->select_chip(mtd, -1);
-- 
2.3.4




More information about the linux-mtd mailing list