LKML Archive on lore.kernel.org
help / color / mirror / Atom feed
* v4.4-stable: GPMI nand controller broken
@ 2018-05-04  6:56 Sascha Hauer
  2018-05-04 22:12 ` Greg KH
  0 siblings, 1 reply; 2+ messages in thread
From: Sascha Hauer @ 2018-05-04  6:56 UTC (permalink / raw)
  To: linux-mtd; +Cc: stable, linux-kernel, kernel

The following went into v4.4.120:

197190bc5c48 mtd: nand: gpmi: Fix failure when a erased page has a bitflip at BBM

This patch was backported to far for the stable tree. It only makes sense
(and only works) together with:

bd2e778c9ee3 gpmi-nand: Handle ECC Errors in erased pages

which first appeared in v4.7.

So either we revert 197190bc5c48 on the v4.4 stable tree or we apply the
attached patch which is a backport of bd2e778c9ee3 for v4.4.

I don't know which solution is prefered, personally I would prefer
applying the attached patch which is also a bugfix. Without it erased
pages may not be handled properly.

Sascha

---------------------------8<-------------------------------

>From ec42023a83778e524a024bdd25d970b8dc7a3966 Mon Sep 17 00:00:00 2001
From: Markus Pargmann <mpa@pengutronix.de>
Date: Mon, 25 Apr 2016 14:35:12 +0200
Subject: [PATCH] gpmi-nand: Handle ECC Errors in erased pages

ECC is only calculated for written pages. As erased pages are not
actively written the ECC is always invalid. For this purpose the
Hardware BCH unit is able to check for erased pages and does not raise
an ECC error in this case. This behaviour can be influenced using the
BCH_MODE register which sets the number of allowed bitflips in an erased
page. Unfortunately the unit is not capable of fixing the bitflips in
memory.

To avoid complete software checks for erased pages, we can simply check
buffers with uncorrectable ECC errors because we know that any erased
page with errors is uncorrectable by the BCH unit.

This patch adds the generic nand_check_erased_ecc_chunk() to gpmi-nand
to correct erased pages. To have the valid data in the buffer before
using them, this patch moves the read_page_swap_end() call before the
ECC status checking for-loop.

Fixes: 197190bc5c48 ("mtd: nand: gpmi: Fix failure when a erased page has a bitflip at BBM")
Signed-off-by: Markus Pargmann <mpa@pengutronix.de>
[Squashed patches by Stefan and Boris to check ECC area]
Tested-by: Stefan Christ <s.christ@phytec.de>
Acked-by: Han xu <han.xu@nxp.com>
Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
---
 drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 78 ++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 5 deletions(-)

diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index e2a239c1f40b..40a335c6b792 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1032,14 +1032,87 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 	/* Loop over status bytes, accumulating ECC status. */
 	status = auxiliary_virt + nfc_geo->auxiliary_status_offset;
 
+	read_page_swap_end(this, buf, nfc_geo->payload_size,
+			   this->payload_virt, this->payload_phys,
+			   nfc_geo->payload_size,
+			   payload_virt, payload_phys);
+
 	for (i = 0; i < nfc_geo->ecc_chunk_count; i++, status++) {
 		if ((*status == STATUS_GOOD) || (*status == STATUS_ERASED))
 			continue;
 
 		if (*status == STATUS_UNCORRECTABLE) {
+			int eccbits = nfc_geo->ecc_strength * nfc_geo->gf_len;
+			u8 *eccbuf = this->raw_buffer;
+			int offset, bitoffset;
+			int eccbytes;
+			int flips;
+
+			/* Read ECC bytes into our internal raw_buffer */
+			offset = nfc_geo->metadata_size * 8;
+			offset += ((8 * nfc_geo->ecc_chunk_size) + eccbits) * (i + 1);
+			offset -= eccbits;
+			bitoffset = offset % 8;
+			eccbytes = DIV_ROUND_UP(offset + eccbits, 8);
+			offset /= 8;
+			eccbytes -= offset;
+			chip->cmdfunc(mtd, NAND_CMD_RNDOUT, offset, -1);
+			chip->read_buf(mtd, eccbuf, eccbytes);
+
+			/*
+			 * ECC data are not byte aligned and we may have
+			 * in-band data in the first and last byte of
+			 * eccbuf. Set non-eccbits to one so that
+			 * nand_check_erased_ecc_chunk() does not count them
+			 * as bitflips.
+			 */
+			if (bitoffset)
+				eccbuf[0] |= GENMASK(bitoffset - 1, 0);
+
+			bitoffset = (bitoffset + eccbits) % 8;
+			if (bitoffset)
+				eccbuf[eccbytes - 1] |= GENMASK(7, bitoffset);
+
+			/*
+			 * The ECC hardware has an uncorrectable ECC status
+			 * code in case we have bitflips in an erased page. As
+			 * nothing was written into this subpage the ECC is
+			 * obviously wrong and we can not trust it. We assume
+			 * at this point that we are reading an erased page and
+			 * try to correct the bitflips in buffer up to
+			 * ecc_strength bitflips. If this is a page with random
+			 * data, we exceed this number of bitflips and have a
+			 * ECC failure. Otherwise we use the corrected buffer.
+			 */
+			if (i == 0) {
+				/* The first block includes metadata */
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						auxiliary_virt,
+						nfc_geo->metadata_size,
+						nfc_geo->ecc_strength);
+			} else {
+				flips = nand_check_erased_ecc_chunk(
+						buf + i * nfc_geo->ecc_chunk_size,
+						nfc_geo->ecc_chunk_size,
+						eccbuf, eccbytes,
+						NULL, 0,
+						nfc_geo->ecc_strength);
+			}
+
+			if (flips > 0) {
+				max_bitflips = max_t(unsigned int, max_bitflips,
+						     flips);
+				mtd->ecc_stats.corrected += flips;
+				continue;
+			}
+
 			mtd->ecc_stats.failed++;
 			continue;
 		}
+
 		mtd->ecc_stats.corrected += *status;
 		max_bitflips = max_t(unsigned int, max_bitflips, *status);
 	}
@@ -1062,11 +1135,6 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 		chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
 	}
 
-	read_page_swap_end(this, buf, nfc_geo->payload_size,
-			this->payload_virt, this->payload_phys,
-			nfc_geo->payload_size,
-			payload_virt, payload_phys);
-
 	return max_bitflips;
 }
 
-- 
2.17.0


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

* Re: v4.4-stable: GPMI nand controller broken
  2018-05-04  6:56 v4.4-stable: GPMI nand controller broken Sascha Hauer
@ 2018-05-04 22:12 ` Greg KH
  0 siblings, 0 replies; 2+ messages in thread
From: Greg KH @ 2018-05-04 22:12 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: linux-mtd, stable, linux-kernel, kernel

On Fri, May 04, 2018 at 08:56:21AM +0200, Sascha Hauer wrote:
> The following went into v4.4.120:
> 
> 197190bc5c48 mtd: nand: gpmi: Fix failure when a erased page has a bitflip at BBM
> 
> This patch was backported to far for the stable tree. It only makes sense
> (and only works) together with:
> 
> bd2e778c9ee3 gpmi-nand: Handle ECC Errors in erased pages
> 
> which first appeared in v4.7.
> 
> So either we revert 197190bc5c48 on the v4.4 stable tree or we apply the
> attached patch which is a backport of bd2e778c9ee3 for v4.4.
> 
> I don't know which solution is prefered, personally I would prefer
> applying the attached patch which is also a bugfix. Without it erased
> pages may not be handled properly.

I've now applied this bugfix, thanks!

greg k-h

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

end of thread, other threads:[~2018-05-04 22:12 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-04  6:56 v4.4-stable: GPMI nand controller broken Sascha Hauer
2018-05-04 22:12 ` Greg KH

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