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 <rich...@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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to