diff options
author | frans <fransmeulenbroeks@gmail.com> | 2008-08-20 15:11:50 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-08-20 15:58:56 -0400 |
commit | 1077be58ad7baadd86e47e8b4f6209fa5b6364a5 (patch) | |
tree | d1e9a09005c1f4acaba9f40d58ce87d878bf2e1d /drivers/mtd | |
parent | 75caf6b5acc6b895df9bdd36db631220e1096e9f (diff) |
[MTD] [NAND] nand_ecc.c: fix big endian, strengthen test, add printk
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
- strengthen the test for correctable errors (decreasing the chance
that multiple bit faults by accident will be seen as correctable)
Note: the big endian code is only tested in a testbed (running on big endian
hardware) as I cannot rebuild and test a big endian kernel at the moment.
However the only thing that can go wrong is if <asm/byteorder.h> does not
give __BIG_ENDIAN in that case. In my eyes very unlikely.
Signed-off-by: Frans Meulenbroeks <fransmeulenbroeks@gmail.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/nand/nand_ecc.c | 44 |
1 files changed, 33 insertions, 11 deletions
diff --git a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c index a8e8413ca2bc..d99e569e999f 100644 --- a/drivers/mtd/nand/nand_ecc.c +++ b/drivers/mtd/nand/nand_ecc.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/kernel.h> | 43 | #include <linux/kernel.h> |
44 | #include <linux/module.h> | 44 | #include <linux/module.h> |
45 | #include <linux/mtd/nand_ecc.h> | 45 | #include <linux/mtd/nand_ecc.h> |
46 | #include <asm/byteorder.h> | ||
46 | #else | 47 | #else |
47 | #include <stdint.h> | 48 | #include <stdint.h> |
48 | struct mtd_info; | 49 | struct mtd_info; |
@@ -51,6 +52,9 @@ struct mtd_info; | |||
51 | #define MODULE_LICENSE(x) /* x */ | 52 | #define MODULE_LICENSE(x) /* x */ |
52 | #define MODULE_AUTHOR(x) /* x */ | 53 | #define MODULE_AUTHOR(x) /* x */ |
53 | #define MODULE_DESCRIPTION(x) /* x */ | 54 | #define MODULE_DESCRIPTION(x) /* x */ |
55 | |||
56 | #define printk printf | ||
57 | #define KERN_ERR "" | ||
54 | #endif | 58 | #endif |
55 | 59 | ||
56 | /* | 60 | /* |
@@ -273,24 +277,38 @@ int nand_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, | |||
273 | /* | 277 | /* |
274 | * we also need to calculate the row parity for rp0..rp3 | 278 | * we also need to calculate the row parity for rp0..rp3 |
275 | * This is present in par, because par is now | 279 | * This is present in par, because par is now |
276 | * rp3 rp3 rp2 rp2 | 280 | * rp3 rp3 rp2 rp2 in little endian and |
281 | * rp2 rp2 rp3 rp3 in big endian | ||
277 | * as well as | 282 | * as well as |
278 | * rp1 rp0 rp1 rp0 | 283 | * rp1 rp0 rp1 rp0 in little endian and |
284 | * rp0 rp1 rp0 rp1 in big endian | ||
279 | * First calculate rp2 and rp3 | 285 | * First calculate rp2 and rp3 |
280 | * (and yes: rp2 = (par ^ rp3) & 0xff; but doing that did not | ||
281 | * give a performance improvement) | ||
282 | */ | 286 | */ |
287 | #ifdef __BIG_ENDIAN | ||
288 | rp2 = (par >> 16); | ||
289 | rp2 ^= (rp2 >> 8); | ||
290 | rp2 &= 0xff; | ||
291 | rp3 = par & 0xffff; | ||
292 | rp3 ^= (rp3 >> 8); | ||
293 | rp3 &= 0xff; | ||
294 | #else | ||
283 | rp3 = (par >> 16); | 295 | rp3 = (par >> 16); |
284 | rp3 ^= (rp3 >> 8); | 296 | rp3 ^= (rp3 >> 8); |
285 | rp3 &= 0xff; | 297 | rp3 &= 0xff; |
286 | rp2 = par & 0xffff; | 298 | rp2 = par & 0xffff; |
287 | rp2 ^= (rp2 >> 8); | 299 | rp2 ^= (rp2 >> 8); |
288 | rp2 &= 0xff; | 300 | rp2 &= 0xff; |
301 | #endif | ||
289 | 302 | ||
290 | /* reduce par to 16 bits then calculate rp1 and rp0 */ | 303 | /* reduce par to 16 bits then calculate rp1 and rp0 */ |
291 | par ^= (par >> 16); | 304 | par ^= (par >> 16); |
305 | #ifdef __BIG_ENDIAN | ||
306 | rp0 = (par >> 8) & 0xff; | ||
307 | rp1 = (par & 0xff); | ||
308 | #else | ||
292 | rp1 = (par >> 8) & 0xff; | 309 | rp1 = (par >> 8) & 0xff; |
293 | rp0 = (par & 0xff); | 310 | rp0 = (par & 0xff); |
311 | #endif | ||
294 | 312 | ||
295 | /* finally reduce par to 8 bits */ | 313 | /* finally reduce par to 8 bits */ |
296 | par ^= (par >> 8); | 314 | par ^= (par >> 8); |
@@ -381,7 +399,6 @@ EXPORT_SYMBOL(nand_calculate_ecc); | |||
381 | int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | 399 | int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, |
382 | unsigned char *read_ecc, unsigned char *calc_ecc) | 400 | unsigned char *read_ecc, unsigned char *calc_ecc) |
383 | { | 401 | { |
384 | int nr_bits; | ||
385 | unsigned char b0, b1, b2; | 402 | unsigned char b0, b1, b2; |
386 | unsigned char byte_addr, bit_addr; | 403 | unsigned char byte_addr, bit_addr; |
387 | 404 | ||
@@ -401,14 +418,15 @@ int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | |||
401 | 418 | ||
402 | /* check if there are any bitfaults */ | 419 | /* check if there are any bitfaults */ |
403 | 420 | ||
404 | /* count nr of bits; use table lookup, faster than calculating it */ | ||
405 | nr_bits = bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]; | ||
406 | |||
407 | /* repeated if statements are slightly more efficient than switch ... */ | 421 | /* repeated if statements are slightly more efficient than switch ... */ |
408 | /* ordered in order of likelihood */ | 422 | /* ordered in order of likelihood */ |
409 | if (nr_bits == 0) | 423 | |
424 | if ((b0 | b1 | b2) == 0) | ||
410 | return 0; /* no error */ | 425 | return 0; /* no error */ |
411 | if (nr_bits == 11) { /* correctable error */ | 426 | |
427 | if ((((b0 ^ (b0 >> 1)) & 0x55) == 0x55) && | ||
428 | (((b1 ^ (b1 >> 1)) & 0x55) == 0x55) && | ||
429 | (((b2 ^ (b2 >> 1)) & 0x54) == 0x54)) { /* single bit error */ | ||
412 | /* | 430 | /* |
413 | * rp15/13/11/9/7/5/3/1 indicate which byte is the faulty byte | 431 | * rp15/13/11/9/7/5/3/1 indicate which byte is the faulty byte |
414 | * cp 5/3/1 indicate the faulty bit. | 432 | * cp 5/3/1 indicate the faulty bit. |
@@ -430,9 +448,13 @@ int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, | |||
430 | /* flip the bit */ | 448 | /* flip the bit */ |
431 | buf[byte_addr] ^= (1 << bit_addr); | 449 | buf[byte_addr] ^= (1 << bit_addr); |
432 | return 1; | 450 | return 1; |
451 | |||
433 | } | 452 | } |
434 | if (nr_bits == 1) | 453 | /* count nr of bits; use table lookup, faster than calculating it */ |
454 | if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1) | ||
435 | return 1; /* error in ecc data; no action needed */ | 455 | return 1; /* error in ecc data; no action needed */ |
456 | |||
457 | printk(KERN_ERR "uncorrectable error : "); | ||
436 | return -1; | 458 | return -1; |
437 | } | 459 | } |
438 | EXPORT_SYMBOL(nand_correct_data); | 460 | EXPORT_SYMBOL(nand_correct_data); |