aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorfrans <fransmeulenbroeks@gmail.com>2008-08-20 15:11:50 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2008-08-20 15:58:56 -0400
commit1077be58ad7baadd86e47e8b4f6209fa5b6364a5 (patch)
treed1e9a09005c1f4acaba9f40d58ce87d878bf2e1d /drivers/mtd
parent75caf6b5acc6b895df9bdd36db631220e1096e9f (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.c44
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>
48struct mtd_info; 49struct 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);
381int nand_correct_data(struct mtd_info *mtd, unsigned char *buf, 399int 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}
438EXPORT_SYMBOL(nand_correct_data); 460EXPORT_SYMBOL(nand_correct_data);