Skip to contentSkip to conversation

mtd: nand: omap: Fix BCH bit correction

PATCH In review Daniel Schultz 2 participants 9 messages Jun 6, 2017 – Jun 13, 2017

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 mtd: nand: omap: Fix BCH bit correction

After commit dec7b4d2bf9 was applied our barebox only corrected the first 512 Bytes of NAND pages.

This patch separates between Hamming and BCH when finding out the eccsteps, because BCH always works with 2kB pages.

Before this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 5 @ 1796
nand0.barebox: Flipping bit 6 @ 1258
nand0.barebox: Flipping bit 5 @ 1062
nand0.barebox: Flipping bit 2 @ 1399
nand0.barebox: Flipping bit 6 @ 1243
No bitflips found on block 0, offset 0x00000000 barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 872
nand0.barebox: Flipping bit 4 @ 252
nand0.barebox: Flipping bit 3 @ 568
nand0.barebox: Flipping bit 2 @ 247
nand0.barebox: Flipping bit 5 @ 401
page at block 0, offset 0x00000000 has 3 bitflips

After this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 1962
nand0.barebox: Flipping bit 0 @ 1563
nand0.barebox: Flipping bit 0 @ 1808
nand0.barebox: Flipping bit 6 @ 1460
nand0.barebox: Flipping bit 7 @ 2034
page at block 0, offset 0x00000000 has 5 bitflips barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 1 @ 1352
nand0.barebox: Flipping bit 7 @ 1542
nand0.barebox: Flipping bit 2 @ 1021
nand0.barebox: Flipping bit 7 @ 691
nand0.barebox: Flipping bit 6 @ 1196
page at block 0, offset 0x00000000 has 10 bitflips, needs cleanup

---
 drivers/mtd/nand/nand_omap_gpmc.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +9 -2
index 05c8486..61220da 100644
@@ -302,10 +302,17 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 	unsigned int err_loc[8];
 	int bitflip_count;
 	int bch_max_err;
+	int eccsteps;
 
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
 	int eccsize = oinfo->nand.ecc.bytes;
+	if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)
+		if ((nand->ecc.mode == NAND_ECC_HW) &&
+				(nand->ecc.size == 2048))
+			eccsteps = 4;
+		else
+			eccsteps = 1;
+	else
+		eccsteps = oinfo->nand.ecc.steps;
 
 	switch (oinfo->ecc_mode) {
 	case OMAP_ECC_BCH8_CODE_HW:
Signature · 7 lines
1.9.1


_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#1 lore raw

+Cc Matt Reimer <[email protected]>

Quoted 50 lines · Daniel Schultz

After commit dec7b4d2bf9 was applied our barebox only corrected the first 512 Bytes of NAND pages.

This patch separates between Hamming and BCH when finding out the eccsteps, because BCH always works with 2kB pages.

Before this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 5 @ 1796
nand0.barebox: Flipping bit 6 @ 1258
nand0.barebox: Flipping bit 5 @ 1062
nand0.barebox: Flipping bit 2 @ 1399
nand0.barebox: Flipping bit 6 @ 1243
No bitflips found on block 0, offset 0x00000000 barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 872
nand0.barebox: Flipping bit 4 @ 252
nand0.barebox: Flipping bit 3 @ 568
nand0.barebox: Flipping bit 2 @ 247
nand0.barebox: Flipping bit 5 @ 401
page at block 0, offset 0x00000000 has 3 bitflips

After this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 1962
nand0.barebox: Flipping bit 0 @ 1563
nand0.barebox: Flipping bit 0 @ 1808
nand0.barebox: Flipping bit 6 @ 1460
nand0.barebox: Flipping bit 7 @ 2034
page at block 0, offset 0x00000000 has 5 bitflips barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 1 @ 1352
nand0.barebox: Flipping bit 7 @ 1542
nand0.barebox: Flipping bit 2 @ 1021
nand0.barebox: Flipping bit 7 @ 691
nand0.barebox: Flipping bit 6 @ 1196
page at block 0, offset 0x00000000 has 10 bitflips, needs cleanup

---
 drivers/mtd/nand/nand_omap_gpmc.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +0 -0
index 05c8486..61220da 100644

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 308

Quoted 9 lines
drivers/mtd/nand/nand_omap_gpmc.c +2 -2
@@ -302,10 +302,17 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 	unsigned int err_loc[8];
 	int bitflip_count;
 	int bch_max_err;
+	int eccsteps;
 
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
 	int eccsize = oinfo->nand.ecc.bytes;
+	if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)

This is wrong. When in Hamming ECC mode you shouldn't get into this function. The test should always fail.

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 313

Quoted 5 lines
drivers/mtd/nand/nand_omap_gpmc.c +5 -0
+		if ((nand->ecc.mode == NAND_ECC_HW) &&
+				(nand->ecc.size == 2048))
+			eccsteps = 4;
+		else
+			eccsteps = 1;

The question is why ecc.size is set to the wrong value in the first place:

	case OMAP_ECC_BCH8_CODE_HW:
		...
		oinfo->nand.ecc.size     = 512 * 4;

This seems to be wrong. The BCH controller works in 512 Byte chunks, so ecc.size should be 512. This would make the special cases in omap_correct_bch() unnecessary.

In dec7b4d2bf9 Matt said:

|  The fix is to pull over a bit of code from the kernel's
|  omap_correct_data() that sets eccsteps = 4 when the page size is 2048
|  bytes and hardware ECC is being used.

In fact, this piece is in the kernel code:

	/* Ex NAND_ECC_HW12_2048 */
	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
			(info->nand.ecc.size  == 2048))
		blockCnt = 4;
	else
		blockCnt = 1;

I just suspect this is never used, because ecc.size is correctly set to 512 in all cases. Then ecc.steps results in 4 for 2k page sizes and the framework correctly iterates over the ecc steps.

Please give the attached test a try. It's completely untested.

Sascha

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

From 34bbcd911513e9031786a3c0f12e83ee9e904b42 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <[email protected]>
Date: Wed, 7 Jun 2017 08:42:06 +0200
Subject: [PATCH] mtd: nand_omap_gpmc: Fix ecc size

The ECC size for BCH correction is always 512 byte. Correct the ecc.size for the OMAP_ECC_BCH8_CODE_HW mode from 2048 to 512. This change will let the framework iterate over the 4 ecc steps and we no longer need special cases in omap_correct_bch().

---
 drivers/mtd/nand/nand_omap_gpmc.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +3 -4
index e18ce6358a..a35ed1f093 100644
@@ -303,8 +303,7 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 	int bitflip_count;
 	int bch_max_err;
 
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
+	int eccsteps = nand->ecc.steps;
 	int eccsize = oinfo->nand.ecc.bytes;
 
 	switch (oinfo->ecc_mode) {
@@ -765,8 +764,8 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
 					offset - omap_oobinfo.eccbytes;
 		break;
 	case OMAP_ECC_BCH8_CODE_HW:
-		oinfo->nand.ecc.bytes    = 13 * 4;
-		oinfo->nand.ecc.size     = 512 * 4;
+		oinfo->nand.ecc.bytes    = 13;
+		oinfo->nand.ecc.size     = 512;
 		oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
 		omap_oobinfo.oobfree->offset = offset;
 		omap_oobinfo.oobfree->length = minfo->oobsize -
Signature · 13 lines
2.11.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 |

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#2 lore raw
Quoted 98 lines · Sascha Hauer

+Cc Matt Reimer <[email protected]>

Quoted 50 lines · Daniel Schultz

After commit dec7b4d2bf9 was applied our barebox only corrected the first 512 Bytes of NAND pages.

This patch separates between Hamming and BCH when finding out the eccsteps, because BCH always works with 2kB pages.

Before this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 5 @ 1796
nand0.barebox: Flipping bit 6 @ 1258
nand0.barebox: Flipping bit 5 @ 1062
nand0.barebox: Flipping bit 2 @ 1399
nand0.barebox: Flipping bit 6 @ 1243
No bitflips found on block 0, offset 0x00000000 barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 872
nand0.barebox: Flipping bit 4 @ 252
nand0.barebox: Flipping bit 3 @ 568
nand0.barebox: Flipping bit 2 @ 247
nand0.barebox: Flipping bit 5 @ 401
page at block 0, offset 0x00000000 has 3 bitflips

After this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 1962
nand0.barebox: Flipping bit 0 @ 1563
nand0.barebox: Flipping bit 0 @ 1808
nand0.barebox: Flipping bit 6 @ 1460
nand0.barebox: Flipping bit 7 @ 2034
page at block 0, offset 0x00000000 has 5 bitflips barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 1 @ 1352
nand0.barebox: Flipping bit 7 @ 1542
nand0.barebox: Flipping bit 2 @ 1021
nand0.barebox: Flipping bit 7 @ 691
nand0.barebox: Flipping bit 6 @ 1196
page at block 0, offset 0x00000000 has 10 bitflips, needs cleanup

---
 drivers/mtd/nand/nand_omap_gpmc.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +0 -0
index 05c8486..61220da 100644

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 308

Quoted 9 lines
drivers/mtd/nand/nand_omap_gpmc.c +2 -2
@@ -302,10 +302,17 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 	unsigned int err_loc[8];
 	int bitflip_count;
 	int bch_max_err;
+	int eccsteps;
 
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
 	int eccsize = oinfo->nand.ecc.bytes;
+	if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)

This is wrong. When in Hamming ECC mode you shouldn't get into this function. The test should always fail.

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 313

Quoted 5 lines
drivers/mtd/nand/nand_omap_gpmc.c +5 -0
+		if ((nand->ecc.mode == NAND_ECC_HW) &&
+				(nand->ecc.size == 2048))
+			eccsteps = 4;
+		else
+			eccsteps = 1;

The question is why ecc.size is set to the wrong value in the first place:

	case OMAP_ECC_BCH8_CODE_HW:
		...
		oinfo->nand.ecc.size     = 512 * 4;

This seems to be wrong. The BCH controller works in 512 Byte chunks, so ecc.size should be 512. This would make the special cases in omap_correct_bch() unnecessary.

In dec7b4d2bf9 Matt said:

|  The fix is to pull over a bit of code from the kernel's
|  omap_correct_data() that sets eccsteps = 4 when the page size is 2048
|  bytes and hardware ECC is being used.

In fact, this piece is in the kernel code:

	/* Ex NAND_ECC_HW12_2048 */
	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
			(info->nand.ecc.size  == 2048))
		blockCnt = 4;
	else
		blockCnt = 1;
Quoted 5 lines

I just suspect this is never used, because ecc.size is correctly set to 512 in all cases. Then ecc.steps results in 4 for 2k page sizes and the framework correctly iterates over the ecc steps.

Please give the attached test a try. It's completely untested.

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Sascha

Signature · 9 lines
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 |

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#3 lore raw
Quoted 103 lines · Sascha Hauer
Quoted 102 lines · Sascha Hauer

+Cc Matt Reimer <[email protected]>

Quoted 50 lines · Daniel Schultz

After commit dec7b4d2bf9 was applied our barebox only corrected the first 512 Bytes of NAND pages.

This patch separates between Hamming and BCH when finding out the eccsteps, because BCH always works with 2kB pages.

Before this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 5 @ 1796
nand0.barebox: Flipping bit 6 @ 1258
nand0.barebox: Flipping bit 5 @ 1062
nand0.barebox: Flipping bit 2 @ 1399
nand0.barebox: Flipping bit 6 @ 1243
No bitflips found on block 0, offset 0x00000000 barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 872
nand0.barebox: Flipping bit 4 @ 252
nand0.barebox: Flipping bit 3 @ 568
nand0.barebox: Flipping bit 2 @ 247
nand0.barebox: Flipping bit 5 @ 401
page at block 0, offset 0x00000000 has 3 bitflips

After this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 1962
nand0.barebox: Flipping bit 0 @ 1563
nand0.barebox: Flipping bit 0 @ 1808
nand0.barebox: Flipping bit 6 @ 1460
nand0.barebox: Flipping bit 7 @ 2034
page at block 0, offset 0x00000000 has 5 bitflips barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 1 @ 1352
nand0.barebox: Flipping bit 7 @ 1542
nand0.barebox: Flipping bit 2 @ 1021
nand0.barebox: Flipping bit 7 @ 691
nand0.barebox: Flipping bit 6 @ 1196
page at block 0, offset 0x00000000 has 10 bitflips, needs cleanup

---
 drivers/mtd/nand/nand_omap_gpmc.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +0 -0
index 05c8486..61220da 100644

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 308

Quoted 9 lines
drivers/mtd/nand/nand_omap_gpmc.c +2 -2
@@ -302,10 +302,17 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 	unsigned int err_loc[8];
 	int bitflip_count;
 	int bch_max_err;
+	int eccsteps;
 
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
 	int eccsize = oinfo->nand.ecc.bytes;
+	if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)

This is wrong. When in Hamming ECC mode you shouldn't get into this function. The test should always fail.

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 313

Quoted 5 lines
drivers/mtd/nand/nand_omap_gpmc.c +5 -0
+		if ((nand->ecc.mode == NAND_ECC_HW) &&
+				(nand->ecc.size == 2048))
+			eccsteps = 4;
+		else
+			eccsteps = 1;

The question is why ecc.size is set to the wrong value in the first place:

	case OMAP_ECC_BCH8_CODE_HW:
		...
		oinfo->nand.ecc.size     = 512 * 4;

This seems to be wrong. The BCH controller works in 512 Byte chunks, so ecc.size should be 512. This would make the special cases in omap_correct_bch() unnecessary.

In dec7b4d2bf9 Matt said:

|  The fix is to pull over a bit of code from the kernel's
|  omap_correct_data() that sets eccsteps = 4 when the page size is 2048
|  bytes and hardware ECC is being used.

In fact, this piece is in the kernel code:

	/* Ex NAND_ECC_HW12_2048 */
	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
			(info->nand.ecc.size  == 2048))
		blockCnt = 4;
	else
		blockCnt = 1;

I just suspect this is never used, because ecc.size is correctly set to 512 in all cases. Then ecc.steps results in 4 for 2k page sizes and the framework correctly iterates over the ecc steps.

Quoted 5 lines
Quoted 1 line

Please give the attached test a try. It's completely untested.

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Which then means omap_gpmc_read_page_bch_rom_mode() has to iterate over ecc.steps itself, just like the other read_page implementations in the framework do.

So long, enough of self-replying for now ;)

Sascha

Signature · 9 lines
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 |

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#4 lore raw

Hi Sascha,

Am 07.06.2017 um 08:53 schrieb Sascha Hauer:

Quoted 60 lines · Sascha Hauer
Quoted 59 lines · Sascha Hauer
Quoted 58 lines

+Cc Matt Reimer <[email protected]>

Quoted 55 lines · Daniel Schultz

After commit dec7b4d2bf9 was applied our barebox only corrected the first 512 Bytes of NAND pages.

This patch separates between Hamming and BCH when finding out the eccsteps, because BCH always works with 2kB pages.

Before this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 5 @ 1796
nand0.barebox: Flipping bit 6 @ 1258
nand0.barebox: Flipping bit 5 @ 1062
nand0.barebox: Flipping bit 2 @ 1399
nand0.barebox: Flipping bit 6 @ 1243
No bitflips found on block 0, offset 0x00000000 barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 872
nand0.barebox: Flipping bit 4 @ 252
nand0.barebox: Flipping bit 3 @ 568
nand0.barebox: Flipping bit 2 @ 247
nand0.barebox: Flipping bit 5 @ 401
page at block 0, offset 0x00000000 has 3 bitflips

After this patch:

barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 2 @ 1962
nand0.barebox: Flipping bit 0 @ 1563
nand0.barebox: Flipping bit 0 @ 1808
nand0.barebox: Flipping bit 6 @ 1460
nand0.barebox: Flipping bit 7 @ 2034
page at block 0, offset 0x00000000 has 5 bitflips barebox@Phytec phyCORE AM335x:/ nand_bitflip -r -n 5 /dev/nand0.barebox nand0.barebox: Flipping bit 1 @ 1352
nand0.barebox: Flipping bit 7 @ 1542
nand0.barebox: Flipping bit 2 @ 1021
nand0.barebox: Flipping bit 7 @ 691
nand0.barebox: Flipping bit 6 @ 1196
page at block 0, offset 0x00000000 has 10 bitflips, needs cleanup

---
  drivers/mtd/nand/nand_omap_gpmc.c | 11 +++++++++--
  1 file changed, 9 insertions(+), 2 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +1 -0
index 05c8486..61220da 100644
@@ -302,10 +302,17 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
  	unsigned int err_loc[8];
  	int bitflip_count;
  	int bch_max_err;
+	int eccsteps;
 
Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,

Quoted 4 lines
drivers/mtd/nand/nand_omap_gpmc.c +1 -2
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
  	int eccsize = oinfo->nand.ecc.bytes;
+	if (oinfo->ecc_mode == OMAP_ECC_HAMMING_CODE_HW_ROMCODE)

This is wrong. When in Hamming ECC mode you shouldn't get into this function. The test should always fail.

That's why I added this test. I don't know why this change was made [1]

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

drivers/mtd/nand/nand_omap_gpmc.c static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat, · line 313

Quoted 6 lines
drivers/mtd/nand/nand_omap_gpmc.c +5 -0
+		if ((nand->ecc.mode == NAND_ECC_HW) &&
+				(nand->ecc.size == 2048))
+			eccsteps = 4;
+		else
+			eccsteps = 1;

The question is why ecc.size is set to the wrong value in the first place:

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines
	case OMAP_ECC_BCH8_CODE_HW:
		...
		oinfo->nand.ecc.size     = 512 * 4;

This seems to be wrong. The BCH controller works in 512 Byte chunks, so ecc.size should be 512. This would make the special cases in omap_correct_bch() unnecessary.

Only OMAP_ECC_BCH8_CODE_HW_ROMCODE can call omap_gpmc_read_page_bch_rom_mode(). So, this should be no problem, but this multiplying is not in the kernel. Maybe this can affect older systems (OMAP_ECC_BCH8_CODE_HW is only used by old phycards).

Quoted 7 lines
Quoted 7 lines
Quoted 7 lines

In dec7b4d2bf9 Matt said:

|  The fix is to pull over a bit of code from the kernel's
|  omap_correct_data() that sets eccsteps = 4 when the page size is 2048
|  bytes and hardware ECC is being used.
Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

In fact, this piece is in the kernel code:

	/* Ex NAND_ECC_HW12_2048 */
	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
			(info->nand.ecc.size  == 2048))
		blockCnt = 4;
	else
		blockCnt = 1;

[1] since this is from the Hamming logic and not BCH.

This is a snippet from the linux-ti kernel:

         case OMAP_ECC_HAM1_CODE_HW: 

                 pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n"); 

                 nand_chip->ecc.mode             = NAND_ECC_HW; 

                 nand_chip->ecc.bytes            = 3; 

                 nand_chip->ecc.size             = 512; 

                 nand_chip->ecc.strength         = 1; 

                 nand_chip->ecc.calculate        = omap_calculate_ecc; 

                 nand_chip->ecc.hwctl            = omap_enable_hwecc; 

                 nand_chip->ecc.correct          = omap_correct_data; 

                 /* define ECC layout */ 

                 ecclayout->eccbytes             = nand_chip->ecc.bytes
		 ...

         case OMAP_ECC_BCH8_CODE_HW: 

                 nand_chip->ecc.mode           = NAND_ECC_HW; 

                 nand_chip->ecc.size           = 512; 

                 nand_chip->ecc.bytes          = 13 + 1; 

                 nand_chip->ecc.strength       = 8; 

                 nand_chip->ecc.hwctl          = omap_enable_hwecc_bch; 

                 nand_chip->ecc.correct        = omap_elm_correct_data; 

                 nand_chip->ecc.calculate      = 
omap_calculate_ecc_bch;
                 nand_chip->ecc.read_page      = omap_read_page_bch; 

                 nand_chip->ecc.write_page     = omap_write_page_bch;
Quoted 7 lines
Quoted 7 lines
Quoted 6 lines

I just suspect this is never used, because ecc.size is correctly set to 512 in all cases. Then ecc.steps results in 4 for 2k page sizes and the framework correctly iterates over the ecc steps.

Please give the attached test a try. It's completely untested.

Quoted 8 lines
Quoted 3 lines

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Which then means omap_gpmc_read_page_bch_rom_mode() has to iterate over ecc.steps itself, just like the other read_page implementations in the framework do.

So, the previous assignment of eccsteps was fine?

Quoted 4 lines

So long, enough of self-replying for now ;)

Sascha

Signature · 8 lines
Mit freundlichen Grüßen,
With best regards,
  Daniel Schultz

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#5 lore raw
Quoted 7 lines · Daniel Schultz

Hi Sascha,

Quoted 5 lines
Quoted 4 lines

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Quoted 5 lines
Quoted 4 lines

Which then means omap_gpmc_read_page_bch_rom_mode() has to iterate over ecc.steps itself, just like the other read_page implementations in the framework do.

So, the previous assignment of eccsteps was fine?

I just sent an updated patch(-series). Could you give it a try?

Sascha

Signature · 9 lines
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 |

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#6 lore raw

Hi,

Am 09.06.2017 um 11:08 schrieb Sascha Hauer:

Quoted 8 lines · Daniel Schultz
Quoted 7 lines

Hi Sascha,

Quoted 5 lines
Quoted 4 lines

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Quoted 8 lines
Quoted 5 lines
Quoted 4 lines

Which then means omap_gpmc_read_page_bch_rom_mode() has to iterate over ecc.steps itself, just like the other read_page implementations in the framework do.

So, the previous assignment of eccsteps was fine?

I just sent an updated patch(-series). Could you give it a try?

It works, but the current version only changes the local copy of the pointer. As a result of that it will only check the first 512 Bytes. I appended a double pointer workaround for this problem :)

omap_correct_data() also calls omap_correct_bch(). Does Barebox correct NAND partitions? I have never seen this. Maybe we need here also a loop.

From 2b104598933b00cd33a85333ce72a49de7230507 Mon Sep 17 00:00:00 2001
From: Daniel Schultz <[email protected]>
Date: Fri, 9 Jun 2017 15:15:30 +0200
Subject: [PATCH] Add double pointer to current OMAP NAND ECC patch stack

---
 drivers/mtd/nand/nand_omap_gpmc.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +12 -12
index 334014a..7608545 100644
@@ -292,8 +292,8 @@ static int omap_calculate_ecc(struct mtd_info *mtd, const uint8_t *dat,
 	return __omap_calculate_ecc(mtd, dat, ecc_code, 0);
 }
 
-static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
-			     uint8_t *read_ecc, uint8_t *calc_ecc)
+static int omap_correct_bch(struct mtd_info *mtd, uint8_t **dat,
+			     uint8_t **read_ecc, uint8_t **calc_ecc)
 {
 	struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
 	struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
@@ -328,14 +328,14 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 
 	/* check for any ecc error */
 	for (j = 0; (j < actual_eccsize) && (eccflag == 0); j++) {
-		if (calc_ecc[j] != 0) {
+		if ((*calc_ecc)[j] != 0) {
 			eccflag = 1;
 			break;
 		}
 	}
 
 	if (eccflag == 1) {
-		if (memcmp(calc_ecc, erased_ecc_vec, actual_eccsize) == 0) {
+		if (memcmp(*calc_ecc, erased_ecc_vec, actual_eccsize) == 0) {
 			/*
 			 * calc_ecc[] matches pattern for ECC
 			 * (all 0xff) so this is definitely
@@ -343,7 +343,7 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 			 */
 		} else {
 			bitflip_count = nand_check_erased_ecc_chunk(
-					dat, oinfo->nand.ecc.size, read_ecc,
+					*dat, oinfo->nand.ecc.size, *read_ecc,
 					eccsize, NULL, 0, bch_max_err);
 			if (bitflip_count < 0)
 				is_error_reported = true;
@@ -352,22 +352,22 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 
 	if (is_error_reported) {
 		bitflip_count = omap_gpmc_decode_bch(1,
-				calc_ecc, err_loc);
+				*calc_ecc, err_loc);
 		if (bitflip_count < 0)
 			return bitflip_count;
 
 		for (j = 0; j < bitflip_count; j++) {
 			if (err_loc[j] < 4096)
-				dat[err_loc[j] >> 3] ^=
+				(*dat)[err_loc[j] >> 3] ^=
 					1 << (err_loc[j] & 7);
 			/* else, not interested to correct ecc */
 		}
 	}
 
 	totalcount += bitflip_count;
-	calc_ecc = calc_ecc + actual_eccsize;
-	read_ecc = read_ecc + eccsize;
-	dat += 512;
+	*calc_ecc += actual_eccsize;
+	*read_ecc += eccsize;
+	*dat += 512;
 
 	return totalcount;
 }
@@ -449,7 +449,7 @@ static int omap_correct_data(struct mtd_info *mtd, uint8_t *dat,
 		 * this time with oob data.
 		 */
 		__omap_calculate_ecc(mtd, dat, calc_ecc, 0);
-		return omap_correct_bch(mtd, dat, read_ecc, calc_ecc);
+		return omap_correct_bch(mtd, &dat, &read_ecc, &calc_ecc);
 	default:
 		return -EINVAL;
 	}
@@ -705,7 +705,7 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
 	__omap_calculate_ecc(mtd, buf, ecc_calc, 1);
 
 	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-		stat = omap_correct_bch(mtd, buf, ecc_code, ecc_calc);
+		stat = omap_correct_bch(mtd, &buf, &ecc_code, &ecc_calc);
 		if (stat < 0) {
 			mtd->ecc_stats.failed++;
 		} else {
Signature · 6 lines
1.9.1

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#7 lore raw

Hi Daniel,

Quoted 15 lines · Daniel Schultz

Hi,

Am 09.06.2017 um 11:08 schrieb Sascha Hauer:

Quoted 12 lines · Daniel Schultz
Quoted 11 lines

Hi Sascha,

Quoted 9 lines
Quoted 4 lines

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Which then means omap_gpmc_read_page_bch_rom_mode() has to iterate over ecc.steps itself, just like the other read_page implementations in the framework do.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

So, the previous assignment of eccsteps was fine?

I just sent an updated patch(-series). Could you give it a try?

It works, but the current version only changes the local copy of the pointer. As a result of that it will only check the first 512 Bytes. I appended a double pointer workaround for this problem :)

The pointer should be incremented by the caller, not by omap_correct_bch().

Quoted 4 lines

omap_correct_data() also calls omap_correct_bch(). Does Barebox correct NAND partitions? I have never seen this. Maybe we need here also a loop.

The core already loops around eccsteps when calling ecc.correct.

I digged a bit further and this is what I can come up with. Anyway, I am getting less and less confident that the patch can work.

Please give it a try and see if it works. If it doesn't and we can't find out what's wrong I tend to take your original patch, although I still think this is the wrong solution.

Sascha

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

From 2c65a009dbcf2136e037f009b50306aa080e2920 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <[email protected]>
Date: Fri, 9 Jun 2017 10:45:21 +0200
Subject: [PATCH] mtd: nand_omap_gpmc: Fix ecc size

The ECC size for BCH correction is always 512 byte. Correct the ecc.size for the OMAP_ECC_BCH8_CODE_HW mode from 2048 to 512. This change will
let the framework iterate over the 4 ecc steps and we no longer need
special cases in omap_correct_bch().

---
 drivers/mtd/nand/nand_omap_gpmc.c | 130 +++++++++++++++++---------------------
 1 file changed, 57 insertions(+), 73 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +57 -73
index e18ce6358a..2e130bfd9a 100644
@@ -297,85 +297,59 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
 {
 	struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
 	struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
-	int i, j, eccflag, totalcount, actual_eccsize;
+	int j, eccflag;
 	const uint8_t *erased_ecc_vec;
 	unsigned int err_loc[8];
 	int bitflip_count;
 	int bch_max_err;
-
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
 	int eccsize = oinfo->nand.ecc.bytes;
+	bool is_error_reported = false;
 
-	switch (oinfo->ecc_mode) {
-	case OMAP_ECC_BCH8_CODE_HW:
-		eccsize /= eccsteps;
-		actual_eccsize = eccsize;
-		erased_ecc_vec = bch8_vector;
-		bch_max_err = BCH8_MAX_ERROR;
-		break;
-	case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
-		actual_eccsize = eccsize - 1;
-		erased_ecc_vec = bch8_vector;
-		bch_max_err = BCH8_MAX_ERROR;
-		break;
-	default:
-		dev_err(oinfo->pdev, "invalid driver configuration\n");
-		return -EINVAL;
-	}
-
-	totalcount = 0;
+	erased_ecc_vec = bch8_vector;
+	bch_max_err = BCH8_MAX_ERROR;
 
-	for (i = 0; i < eccsteps; i++) {
-		bool is_error_reported = false;
-		bitflip_count = 0;
-		eccflag = 0;
+	bitflip_count = 0;
+	eccflag = 0;
 
-		/* check for any ecc error */
-		for (j = 0; (j < actual_eccsize) && (eccflag == 0); j++) {
-			if (calc_ecc[j] != 0) {
-				eccflag = 1;
-				break;
-			}
-		}
-
-		if (eccflag == 1) {
-			if (memcmp(calc_ecc, erased_ecc_vec, actual_eccsize) == 0) {
-				/*
-				 * calc_ecc[] matches pattern for ECC
-				 * (all 0xff) so this is definitely
-				 * an erased-page
-				 */
-			} else {
-				bitflip_count = nand_check_erased_ecc_chunk(
-						dat, oinfo->nand.ecc.size, read_ecc,
-						eccsize, NULL, 0, bch_max_err);
-				if (bitflip_count < 0)
-					is_error_reported = true;
-			}
+	/* check for any ecc error */
+	for (j = 0; (j < eccsize) && (eccflag == 0); j++) {
+		if (calc_ecc[j] != 0) {
+			eccflag = 1;
+			break;
 		}
+	}
 
-		if (is_error_reported) {
-			bitflip_count = omap_gpmc_decode_bch(1,
-					calc_ecc, err_loc);
+	if (eccflag == 1) {
+		if (memcmp(calc_ecc, erased_ecc_vec, eccsize) == 0) {
+			/*
+			 * calc_ecc[] matches pattern for ECC
+			 * (all 0xff) so this is definitely
+			 * an erased-page
+			 */
+		} else {
+			bitflip_count = nand_check_erased_ecc_chunk(
+					dat, oinfo->nand.ecc.size, read_ecc,
+					eccsize, NULL, 0, bch_max_err);
 			if (bitflip_count < 0)
-				return bitflip_count;
-
-			for (j = 0; j < bitflip_count; j++) {
-				if (err_loc[j] < 4096)
-					dat[err_loc[j] >> 3] ^=
-						1 << (err_loc[j] & 7);
-				/* else, not interested to correct ecc */
-			}
+				is_error_reported = true;
 		}
+	}
 
-		totalcount += bitflip_count;
-		calc_ecc = calc_ecc + actual_eccsize;
-		read_ecc = read_ecc + eccsize;
-		dat += 512;
+	if (is_error_reported) {
+		bitflip_count = omap_gpmc_decode_bch(1,
+				calc_ecc, err_loc);
+		if (bitflip_count < 0)
+			return bitflip_count;
+
+		for (j = 0; j < bitflip_count; j++) {
+			if (err_loc[j] < 4096)
+				dat[err_loc[j] >> 3] ^=
+					1 << (err_loc[j] & 7);
+			/* else, not interested to correct ecc */
+		}
 	}
 
-	return totalcount;
+	return bitflip_count;
 }
 
 static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat,
@@ -667,6 +641,10 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
 	uint8_t *ecc_code = chip->buffers->ecccode;
 	uint32_t *eccpos = chip->ecc.layout->eccpos;
 	int stat, i;
+	unsigned int max_bitflips = 0;
+	int eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
 
 	writel(GPMC_ECC_SIZE_CONFIG_ECCSIZE1(0) |
 			GPMC_ECC_SIZE_CONFIG_ECCSIZE0(64),
@@ -706,13 +684,19 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
 
 	__omap_calculate_ecc(mtd, buf, ecc_calc, 1);
 
-	stat = omap_correct_bch(mtd, buf, ecc_code, ecc_calc);
-	if (stat < 0)
-		mtd->ecc_stats.failed++;
-	else
-		mtd->ecc_stats.corrected += stat;
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		stat = omap_correct_bch(mtd, p, ecc_code, ecc_calc);
+		ecc_code += eccsize + 1;
+		ecc_calc += eccsize;
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
 
-	return 0;
+	return max_bitflips;
 }
 
 static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
@@ -765,8 +749,8 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
 					offset - omap_oobinfo.eccbytes;
 		break;
 	case OMAP_ECC_BCH8_CODE_HW:
-		oinfo->nand.ecc.bytes    = 13 * 4;
-		oinfo->nand.ecc.size     = 512 * 4;
+		oinfo->nand.ecc.bytes    = 13;
+		oinfo->nand.ecc.size     = 512;
 		oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
 		omap_oobinfo.oobfree->offset = offset;
 		omap_oobinfo.oobfree->length = minfo->oobsize -
@@ -776,7 +760,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
 			omap_oobinfo.eccpos[i] = i + offset;
 		break;
 	case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
-		oinfo->nand.ecc.bytes    = 13 + 1;
+		oinfo->nand.ecc.bytes    = 13;
 		oinfo->nand.ecc.size     = 512;
 		oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
 		nand->ecc.read_page = omap_gpmc_read_page_bch_rom_mode;
Signature · 12 lines
2.11.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 |

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox
#8 lore raw

Hi Sascha,

Am 12.06.2017 um 15:41 schrieb Sascha Hauer:

Quoted 34 lines

Hi Daniel,

Quoted 15 lines · Daniel Schultz

Hi,

Am 09.06.2017 um 11:08 schrieb Sascha Hauer:

Quoted 12 lines · Daniel Schultz
Quoted 11 lines

Hi Sascha,

Quoted 9 lines
Quoted 4 lines

And can not work. Additionally eccsteps must be set to 1 in omap_correct_bch(). This effectively makes the loop in this function unnecessary which can then removed.

Which then means omap_gpmc_read_page_bch_rom_mode() has to iterate over ecc.steps itself, just like the other read_page implementations in the framework do.

Quoted 7 lines
Quoted 4 lines
Quoted 1 line

So, the previous assignment of eccsteps was fine?

I just sent an updated patch(-series). Could you give it a try?

It works, but the current version only changes the local copy of the pointer. As a result of that it will only check the first 512 Bytes. I appended a double pointer workaround for this problem :)

The pointer should be incremented by the caller, not by omap_correct_bch().

Quoted 4 lines

omap_correct_data() also calls omap_correct_bch(). Does Barebox correct NAND partitions? I have never seen this. Maybe we need here also a loop.

Quoted 9 lines

The core already loops around eccsteps when calling ecc.correct.

I digged a bit further and this is what I can come up with. Anyway, I am getting less and less confident that the patch can work.

Please give it a try and see if it works. If it doesn't and we can't find out what's wrong I tend to take your original patch, although I still think this is the wrong solution.

With these changes it works, but I only testes with nand_bitflip. Idk if there're better ways to test NAND ECC. However, after 6 bitflips on one subpage it will successfully boot in the backup partition, with less than 6 it will boot the bitflipped-partition.

Daniel

drivers/mtd/nand/nand_omap_gpmc.c +4 -4
index 2e130bf..9006e2e 100644
@@ -684,10 +684,10 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
 
        __omap_calculate_ecc(mtd, buf, ecc_calc, 1);
 
-       for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
-               stat = omap_correct_bch(mtd, p, ecc_code, ecc_calc);
-               ecc_code += eccsize + 1;
-               ecc_calc += eccsize;
+       for (i = 0; eccsteps; eccsteps--, i += eccbytes, buf += eccsize) {
+               stat = omap_correct_bch(mtd, buf, ecc_code, ecc_calc);
+               ecc_code += eccbytes + 1;
+               ecc_calc += eccbytes;
                if (stat < 0) {
                        mtd->ecc_stats.failed++;
                } else {
Quoted 205 lines

Sascha

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

From 2c65a009dbcf2136e037f009b50306aa080e2920 Mon Sep 17 00:00:00 2001
From: Sascha Hauer <[email protected]>
Date: Fri, 9 Jun 2017 10:45:21 +0200
Subject: [PATCH] mtd: nand_omap_gpmc: Fix ecc size

The ECC size for BCH correction is always 512 byte. Correct the ecc.size for the OMAP_ECC_BCH8_CODE_HW mode from 2048 to 512. This change will
let the framework iterate over the 4 ecc steps and we no longer need
special cases in omap_correct_bch().

---
  drivers/mtd/nand/nand_omap_gpmc.c | 130 +++++++++++++++++---------------------
  1 file changed, 57 insertions(+), 73 deletions(-)
drivers/mtd/nand/nand_omap_gpmc.c +57 -73
index e18ce6358a..2e130bfd9a 100644
@@ -297,85 +297,59 @@ static int omap_correct_bch(struct mtd_info *mtd, uint8_t *dat,
  {
  	struct nand_chip *nand = (struct nand_chip *)(mtd->priv);
  	struct gpmc_nand_info *oinfo = (struct gpmc_nand_info *)(nand->priv);
-	int i, j, eccflag, totalcount, actual_eccsize;
+	int j, eccflag;
  	const uint8_t *erased_ecc_vec;
  	unsigned int err_loc[8];
  	int bitflip_count;
  	int bch_max_err;
-
-	int eccsteps = (nand->ecc.mode == NAND_ECC_HW) &&
-			(nand->ecc.size == 2048) ? 4 : 1;
  	int eccsize = oinfo->nand.ecc.bytes;
+	bool is_error_reported = false;
 
-	switch (oinfo->ecc_mode) {
-	case OMAP_ECC_BCH8_CODE_HW:
-		eccsize /= eccsteps;
-		actual_eccsize = eccsize;
-		erased_ecc_vec = bch8_vector;
-		bch_max_err = BCH8_MAX_ERROR;
-		break;
-	case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
-		actual_eccsize = eccsize - 1;
-		erased_ecc_vec = bch8_vector;
-		bch_max_err = BCH8_MAX_ERROR;
-		break;
-	default:
-		dev_err(oinfo->pdev, "invalid driver configuration\n");
-		return -EINVAL;
-	}
-
-	totalcount = 0;
+	erased_ecc_vec = bch8_vector;
+	bch_max_err = BCH8_MAX_ERROR;
 
-	for (i = 0; i < eccsteps; i++) {
-		bool is_error_reported = false;
-		bitflip_count = 0;
-		eccflag = 0;
+	bitflip_count = 0;
+	eccflag = 0;
 
-		/* check for any ecc error */
-		for (j = 0; (j < actual_eccsize) && (eccflag == 0); j++) {
-			if (calc_ecc[j] != 0) {
-				eccflag = 1;
-				break;
-			}
-		}
-
-		if (eccflag == 1) {
-			if (memcmp(calc_ecc, erased_ecc_vec, actual_eccsize) == 0) {
-				/*
-				 * calc_ecc[] matches pattern for ECC
-				 * (all 0xff) so this is definitely
-				 * an erased-page
-				 */
-			} else {
-				bitflip_count = nand_check_erased_ecc_chunk(
-						dat, oinfo->nand.ecc.size, read_ecc,
-						eccsize, NULL, 0, bch_max_err);
-				if (bitflip_count < 0)
-					is_error_reported = true;
-			}
+	/* check for any ecc error */
+	for (j = 0; (j < eccsize) && (eccflag == 0); j++) {
+		if (calc_ecc[j] != 0) {
+			eccflag = 1;
+			break;
  		}
+	}
 
-		if (is_error_reported) {
-			bitflip_count = omap_gpmc_decode_bch(1,
-					calc_ecc, err_loc);
+	if (eccflag == 1) {
+		if (memcmp(calc_ecc, erased_ecc_vec, eccsize) == 0) {
+			/*
+			 * calc_ecc[] matches pattern for ECC
+			 * (all 0xff) so this is definitely
+			 * an erased-page
+			 */
+		} else {
+			bitflip_count = nand_check_erased_ecc_chunk(
+					dat, oinfo->nand.ecc.size, read_ecc,
+					eccsize, NULL, 0, bch_max_err);
  			if (bitflip_count < 0)
-				return bitflip_count;
-
-			for (j = 0; j < bitflip_count; j++) {
-				if (err_loc[j] < 4096)
-					dat[err_loc[j] >> 3] ^=
-						1 << (err_loc[j] & 7);
-				/* else, not interested to correct ecc */
-			}
+				is_error_reported = true;
  		}
+	}
 
-		totalcount += bitflip_count;
-		calc_ecc = calc_ecc + actual_eccsize;
-		read_ecc = read_ecc + eccsize;
-		dat += 512;
+	if (is_error_reported) {
+		bitflip_count = omap_gpmc_decode_bch(1,
+				calc_ecc, err_loc);
+		if (bitflip_count < 0)
+			return bitflip_count;
+
+		for (j = 0; j < bitflip_count; j++) {
+			if (err_loc[j] < 4096)
+				dat[err_loc[j] >> 3] ^=
+					1 << (err_loc[j] & 7);
+			/* else, not interested to correct ecc */
+		}
  	}
 
-	return totalcount;
+	return bitflip_count;
  }
 
  static int omap_correct_hamming(struct mtd_info *mtd, uint8_t *dat,
@@ -667,6 +641,10 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
  	uint8_t *ecc_code = chip->buffers->ecccode;
  	uint32_t *eccpos = chip->ecc.layout->eccpos;
  	int stat, i;
+	unsigned int max_bitflips = 0;
+	int eccsize = chip->ecc.size;
+	int eccbytes = chip->ecc.bytes;
+	int eccsteps = chip->ecc.steps;
 
  	writel(GPMC_ECC_SIZE_CONFIG_ECCSIZE1(0) |
  			GPMC_ECC_SIZE_CONFIG_ECCSIZE0(64),
@@ -706,13 +684,19 @@ static int omap_gpmc_read_page_bch_rom_mode(struct mtd_info *mtd,
 
  	__omap_calculate_ecc(mtd, buf, ecc_calc, 1);
 
-	stat = omap_correct_bch(mtd, buf, ecc_code, ecc_calc);
-	if (stat < 0)
-		mtd->ecc_stats.failed++;
-	else
-		mtd->ecc_stats.corrected += stat;
+	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
+		stat = omap_correct_bch(mtd, p, ecc_code, ecc_calc);
+		ecc_code += eccsize + 1;
+		ecc_calc += eccsize;
+		if (stat < 0) {
+			mtd->ecc_stats.failed++;
+		} else {
+			mtd->ecc_stats.corrected += stat;
+			max_bitflips = max_t(unsigned int, max_bitflips, stat);
+		}
+	}
 
-	return 0;
+	return max_bitflips;
  }
 
  static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
@@ -765,8 +749,8 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
  					offset - omap_oobinfo.eccbytes;
  		break;
  	case OMAP_ECC_BCH8_CODE_HW:
-		oinfo->nand.ecc.bytes    = 13 * 4;
-		oinfo->nand.ecc.size     = 512 * 4;
+		oinfo->nand.ecc.bytes    = 13;
+		oinfo->nand.ecc.size     = 512;
  		oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
  		omap_oobinfo.oobfree->offset = offset;
  		omap_oobinfo.oobfree->length = minfo->oobsize -
@@ -776,7 +760,7 @@ static int omap_gpmc_eccmode(struct gpmc_nand_info *oinfo,
  			omap_oobinfo.eccpos[i] = i + offset;
  		break;
  	case OMAP_ECC_BCH8_CODE_HW_ROMCODE:
-		oinfo->nand.ecc.bytes    = 13 + 1;
+		oinfo->nand.ecc.bytes    = 13;
  		oinfo->nand.ecc.size     = 512;
  		oinfo->nand.ecc.strength = BCH8_MAX_ERROR;
  		nand->ecc.read_page = omap_gpmc_read_page_bch_rom_mode;
Signature · 8 lines
Mit freundlichen Grüßen,
With best regards,
  Daniel Schultz

_______________________________________________
barebox mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/barebox