mtd: rawnand: micron: handle on-die "ECC-off" devices correctly [Linux 4.19.65]

This Linux kernel change "mtd: rawnand: micron: handle on-die “ECC-off” devices correctly" is included in the Linux 4.19.65 release. This change is authored by Marco Felsch <m.felsch [at] pengutronix.de> on Tue Jul 30 15:44:07 2019 +0200. The commit for this change in Linux stable tree is e7bb4c8 (patch) which is from upstream commit 8493b2a. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 8493b2a.

mtd: rawnand: micron: handle on-die "ECC-off" devices correctly

commit 8493b2a06fc5b77ef5c579dc32b12761f7b7a84c upstream.

Some devices are not supposed to support on-die ECC but experience
shows that internal ECC machinery can actually be enabled through the
"SET FEATURE (EFh)" command, even if a read of the "READ ID Parameter
Tables" returns that it is not.

Currently, the driver checks the "READ ID Parameter" field directly
after having enabled the feature. If the check fails it returns
immediately but leaves the ECC on. When using buggy chips like
MT29F2G08ABAGA and MT29F2G08ABBGA, all future read/program cycles will
go through the on-die ECC, confusing the host controller which is
supposed to be the one handling correction.

To address this in a common way we need to turn off the on-die ECC
directly after reading the "READ ID Parameter" and before checking the
"ECC status".

Cc: stable@vger.kernel.org
Fixes: dbc44edbf833 ("mtd: rawnand: micron: Fix on-die ECC detection logic")
Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 14 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/mtd/nand/raw/nand_micron.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/drivers/mtd/nand/raw/nand_micron.c b/drivers/mtd/nand/raw/nand_micron.c
index f5dc0a7..fb401c2 100644
--- a/drivers/mtd/nand/raw/nand_micron.c
+++ b/drivers/mtd/nand/raw/nand_micron.c
@@ -400,6 +400,14 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
        (chip->id.data[4] & MICRON_ID_INTERNAL_ECC_MASK) != 0x2)
        return MICRON_ON_DIE_UNSUPPORTED;

+   /*
+    * It seems that there are devices which do not support ECC officially.
+    * At least the MT29F2G08ABAGA / MT29F2G08ABBGA devices supports
+    * enabling the ECC feature but don't reflect that to the READ_ID table.
+    * So we have to guarantee that we disable the ECC feature directly
+    * after we did the READ_ID table command. Later we can evaluate the
+    * ECC_ENABLE support.
+    */
    ret = micron_nand_on_die_ecc_setup(chip, true);
    if (ret)
        return MICRON_ON_DIE_UNSUPPORTED;
@@ -408,13 +416,13 @@ static int micron_supports_on_die_ecc(struct nand_chip *chip)
    if (ret)
        return MICRON_ON_DIE_UNSUPPORTED;

-   if (!(id[4] & MICRON_ID_ECC_ENABLED))
-       return MICRON_ON_DIE_UNSUPPORTED;
-
    ret = micron_nand_on_die_ecc_setup(chip, false);
    if (ret)
        return MICRON_ON_DIE_UNSUPPORTED;

+   if (!(id[4] & MICRON_ID_ECC_ENABLED))
+       return MICRON_ON_DIE_UNSUPPORTED;
+
    ret = nand_readid_op(chip, 0, id, sizeof(id));
    if (ret)
        return MICRON_ON_DIE_UNSUPPORTED;

Leave a Reply

Your email address will not be published. Required fields are marked *