[PATCH] [MTD] [NAND] nand_ecc.c: adding support for 512 byte ecc
Singh, Vimal
vimalsingh at ti.com
Thu Aug 21 06:51:34 EDT 2008
Hi Frans,
Frans Meulenbroeks wrote:
> This patch for nand_ecc.c fixes three issues
>
> - fix code so it also works on big endian architectures
> - added a printk in case of an uncorrectable ecc error
> - strenghten the test for correctable errors (decreasing the chance
> that multiple bit faults by accident will be seen as correctable)
>
> Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks at gmail.com>
>
> diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c
> index a8e8413..d99e569 100644
We can make this to support for 512 byte ecc calculation and correction also.
It can be helpful, particularly in cases where hardware ecc option is present and is using 512 byte ecc, to make software ecc and hardware ecc compatible. So that switching could be possible at run time i.e. both can be used by switching at load time.
I have prepared a patch on top of your latest patch.
Please review it and provide your comments on this.
----
Thanks and Regards,
vimal singh
Signed-off-by: Vimal Singh <vimalsingh at ti.com>
Index: linux-omap-2.6/drivers/mtd/nand/nand_ecc.c
===================================================================
--- linux-omap-2.6.orig/drivers/mtd/nand/nand_ecc.c 2008-08-21 10:33:30.000000000 +0530
+++ linux-omap-2.6/drivers/mtd/nand/nand_ecc.c 2008-08-21 10:50:39.000000000 +0530
@@ -42,6 +42,8 @@
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
#include <linux/mtd/nand_ecc.h>
#include <asm/byteorder.h>
#else
@@ -158,10 +160,11 @@
{
int i;
const uint32_t *bp = (uint32_t *)buf;
+ /* 256 or 512 bytes/ecc */
+ uint32_t j =(((struct nand_chip *)mtd->priv)->ecc.size)/256;
uint32_t cur; /* current value in buffer */
- /* rp0..rp15 are the various accumulated parities (per byte) */
+ /* rp0..rp15..rp17 are the various accumulated parities (per byte) */
uint32_t rp0, rp1, rp2, rp3, rp4, rp5, rp6, rp7;
- uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15;
+ uint32_t rp8, rp9, rp10, rp11, rp12, rp13, rp14, rp15, rp16, rp17;
uint32_t par; /* the cumulative parity for all data */
uint32_t tmppar; /* the cumulative parity for this iteration;
for rp12 and rp14 at the end of the loop */
@@ -173,6 +176,8 @@
rp10 = 0;
rp12 = 0;
rp14 = 0;
+ if (j == 2)
+ rp16 = 0;
/*
* The loop is unrolled a number of times;
@@ -184,7 +189,7 @@
* needed for calculating rp12, rp14 and par
* also used as a performance improvement for rp6, rp8 and rp10
*/
- for (i = 0; i < 4; i++) {
+ for (i = 0; i < 4*j; i++) {
cur = *bp++;
tmppar = cur;
rp4 ^= cur;
@@ -247,6 +252,8 @@
rp12 ^= tmppar;
if ((i & 0x2) == 0)
rp14 ^= tmppar;
+ if (j == 2 && (i & 0x4) == 0)
+ rp16 ^= tmppar;
}
/*
@@ -273,6 +280,11 @@
rp14 ^= (rp14 >> 16);
rp14 ^= (rp14 >> 8);
rp14 &= 0xff;
+ if (j == 2) {
+ rp16 ^= (rp16 >> 16);
+ rp16 ^= (rp16 >> 8);
+ rp16 &= 0xff;
+ }
/*
* we also need to calculate the row parity for rp0..rp3
@@ -329,6 +341,8 @@
rp11 = (par ^ rp10) & 0xff;
rp13 = (par ^ rp12) & 0xff;
rp15 = (par ^ rp14) & 0xff;
+ if (j == 2)
+ rp17 = (par ^ rp16) & 0xff;
/*
* Finally calculate the ecc bits.
@@ -375,14 +389,25 @@
(invparity[rp9] << 1) |
(invparity[rp8]);
#endif
- code[2] =
- (invparity[par & 0xf0] << 7) |
- (invparity[par & 0x0f] << 6) |
- (invparity[par & 0xcc] << 5) |
- (invparity[par & 0x33] << 4) |
- (invparity[par & 0xaa] << 3) |
- (invparity[par & 0x55] << 2) |
- 3;
+ if (j == 1)
+ code[2] =
+ (invparity[par & 0xf0] << 7) |
+ (invparity[par & 0x0f] << 6) |
+ (invparity[par & 0xcc] << 5) |
+ (invparity[par & 0x33] << 4) |
+ (invparity[par & 0xaa] << 3) |
+ (invparity[par & 0x55] << 2) |
+ 3;
+ else if (j == 2)
+ code[2] =
+ (invparity[par & 0xf0] << 7) |
+ (invparity[par & 0x0f] << 6) |
+ (invparity[par & 0xcc] << 5) |
+ (invparity[par & 0x33] << 4) |
+ (invparity[par & 0xaa] << 3) |
+ (invparity[par & 0x55] << 2) |
+ (invparity[rp17] << 1) |
+ (invparity[rp16] << 0);
return 0;
}
EXPORT_SYMBOL(nand_calculate_ecc);
@@ -401,6 +426,7 @@
{
unsigned char b0, b1, b2;
unsigned char byte_addr, bit_addr;
+ /* 256 or 512 bytes/ecc */
+ uint32_t j = (((struct nand_chip *)mtd->priv)->ecc.size)/256;
/*
* b0 to b2 indicate which bit is faulty (if any)
@@ -426,7 +452,8 @@
if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) &&
(((b1 ^ (b1 >> 1)) & 0x55) == 0x55) &&
- (((b2 ^ (b2 >> 1)) & 0x54) == 0x54)) { /* single bit error */
+ ((j == 1 && ((b2 ^ (b2 >> 1)) & 0x54) == 0x54) ||
+ (j == 2 && ((b2 ^ (b2 >> 1)) & 0x55) == 0x55))) {
+ /* single bit error */
/*
* rp15/13/11/9/7/5/3/1 indicate which byte is the faulty byte
* cp 5/3/1 indicate the faulty bit.
@@ -443,7 +470,10 @@
* We could also do addressbits[b2] >> 1 but for the
* performace it does not make any difference
*/
- byte_addr = (addressbits[b1] << 4) + addressbits[b0];
+ if (j == 1)
+ byte_addr = (addressbits[b1] << 4) + addressbits[b0];
+ else if (j == 2)
+ byte_addr = (addressbits[b2 & 0x3] << 8) +
+ (addressbits[b1] << 4) + addressbits[b0];
bit_addr = addressbits[b2 >> 2];
/* flip the bit */
buf[byte_addr] ^= (1 << bit_addr);
More information about the linux-mtd
mailing list