2005-04-17 02:20:36 +04:00
/*
2008-08-16 01:14:31 +04:00
* This file contains an ECC algorithm that detects and corrects 1 bit
* errors in a 256 byte block of data .
2005-04-17 02:20:36 +04:00
*
* drivers / mtd / nand / nand_ecc . c
*
2008-08-16 14:01:31 +04:00
* Copyright © 2008 Koninklijke Philips Electronics NV .
* Author : Frans Meulenbroeks
2005-04-17 02:20:36 +04:00
*
2008-08-16 01:14:31 +04:00
* Completely replaces the previous ECC implementation which was written by :
* Steven J . Hill ( sjhill @ realitydiluted . com )
* Thomas Gleixner ( tglx @ linutronix . de )
*
* Information on how this algorithm works and how it was developed
2008-08-16 14:01:31 +04:00
* can be found in Documentation / mtd / nand_ecc . txt
2006-05-23 13:32:45 +04:00
*
2005-04-17 02:20:36 +04:00
* This file is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 or ( at your option ) any
* later version .
2005-11-07 14:15:49 +03:00
*
2005-04-17 02:20:36 +04:00
* This file is distributed in the hope that it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License
* for more details .
2005-11-07 14:15:49 +03:00
*
2005-04-17 02:20:36 +04:00
* You should have received a copy of the GNU General Public License along
* with this file ; if not , write to the Free Software Foundation , Inc . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA .
2005-11-07 14:15:49 +03:00
*
2005-04-17 02:20:36 +04:00
*/
2008-08-16 01:14:31 +04:00
/*
* The STANDALONE macro is useful when running the code outside the kernel
* e . g . when running the code in a testbed or a benchmark program .
* When STANDALONE is used , the module related macros are commented out
* as well as the linux include files .
2008-08-16 14:01:31 +04:00
* Instead a private definition of mtd_info is given to satisfy the compiler
2008-08-16 01:14:31 +04:00
* ( the code does not use mtd_info , so the code does not care )
*/
# ifndef STANDALONE
2005-04-17 02:20:36 +04:00
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/module.h>
2008-08-23 20:18:34 +04:00
# include <linux/mtd/mtd.h>
# include <linux/mtd/nand.h>
2005-04-17 02:20:36 +04:00
# include <linux/mtd/nand_ecc.h>
2008-08-20 23:11:50 +04:00
# include <asm/byteorder.h>
2008-08-16 01:14:31 +04:00
# else
2008-08-16 14:01:31 +04:00
# include <stdint.h>
struct mtd_info ;
2008-08-16 01:14:31 +04:00
# define EXPORT_SYMBOL(x) /* x */
# define MODULE_LICENSE(x) /* x */
# define MODULE_AUTHOR(x) /* x */
# define MODULE_DESCRIPTION(x) /* x */
2008-08-20 23:11:50 +04:00
2013-01-12 14:34:27 +04:00
# define pr_err printf
2008-08-16 01:14:31 +04:00
# endif
/*
* invparity is a 256 byte table that contains the odd parity
* for each byte . So if the number of bits in a byte is even ,
* the array element is 1 , and when the number of bits is odd
* the array eleemnt is 0.
*/
static const char invparity [ 256 ] = {
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
0 , 1 , 1 , 0 , 1 , 0 , 0 , 1 , 1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 ,
1 , 0 , 0 , 1 , 0 , 1 , 1 , 0 , 0 , 1 , 1 , 0 , 1 , 0 , 0 , 1
} ;
2005-04-17 02:20:36 +04:00
/*
2008-08-16 01:14:31 +04:00
* bitsperbyte contains the number of bits per byte
* this is only used for testing and repairing parity
* ( a precalculated value slightly improves performance )
2005-04-17 02:20:36 +04:00
*/
2008-08-16 01:14:31 +04:00
static const char bitsperbyte [ 256 ] = {
0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 ,
1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 ,
1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 ,
2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 ,
1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 ,
2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 ,
2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 ,
3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 ,
1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 ,
2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 ,
2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 ,
3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 ,
2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 ,
3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 ,
3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 ,
4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 , 5 , 6 , 6 , 7 , 6 , 7 , 7 , 8 ,
} ;
/*
* addressbits is a lookup table to filter out the bits from the xor - ed
2011-06-24 01:12:08 +04:00
* ECC data that identify the faulty location .
2008-08-16 01:14:31 +04:00
* this is only used for repairing parity
* see the comments in nand_correct_data for more details
*/
static const char addressbits [ 256 ] = {
0x00 , 0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x01 ,
0x02 , 0x02 , 0x03 , 0x03 , 0x02 , 0x02 , 0x03 , 0x03 ,
0x00 , 0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x01 ,
0x02 , 0x02 , 0x03 , 0x03 , 0x02 , 0x02 , 0x03 , 0x03 ,
0x04 , 0x04 , 0x05 , 0x05 , 0x04 , 0x04 , 0x05 , 0x05 ,
0x06 , 0x06 , 0x07 , 0x07 , 0x06 , 0x06 , 0x07 , 0x07 ,
0x04 , 0x04 , 0x05 , 0x05 , 0x04 , 0x04 , 0x05 , 0x05 ,
0x06 , 0x06 , 0x07 , 0x07 , 0x06 , 0x06 , 0x07 , 0x07 ,
0x00 , 0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x01 ,
0x02 , 0x02 , 0x03 , 0x03 , 0x02 , 0x02 , 0x03 , 0x03 ,
0x00 , 0x00 , 0x01 , 0x01 , 0x00 , 0x00 , 0x01 , 0x01 ,
0x02 , 0x02 , 0x03 , 0x03 , 0x02 , 0x02 , 0x03 , 0x03 ,
0x04 , 0x04 , 0x05 , 0x05 , 0x04 , 0x04 , 0x05 , 0x05 ,
0x06 , 0x06 , 0x07 , 0x07 , 0x06 , 0x06 , 0x07 , 0x07 ,
0x04 , 0x04 , 0x05 , 0x05 , 0x04 , 0x04 , 0x05 , 0x05 ,
0x06 , 0x06 , 0x07 , 0x07 , 0x06 , 0x06 , 0x07 , 0x07 ,
0x08 , 0x08 , 0x09 , 0x09 , 0x08 , 0x08 , 0x09 , 0x09 ,
0x0a , 0x0a , 0x0b , 0x0b , 0x0a , 0x0a , 0x0b , 0x0b ,
0x08 , 0x08 , 0x09 , 0x09 , 0x08 , 0x08 , 0x09 , 0x09 ,
0x0a , 0x0a , 0x0b , 0x0b , 0x0a , 0x0a , 0x0b , 0x0b ,
0x0c , 0x0c , 0x0d , 0x0d , 0x0c , 0x0c , 0x0d , 0x0d ,
0x0e , 0x0e , 0x0f , 0x0f , 0x0e , 0x0e , 0x0f , 0x0f ,
0x0c , 0x0c , 0x0d , 0x0d , 0x0c , 0x0c , 0x0d , 0x0d ,
0x0e , 0x0e , 0x0f , 0x0f , 0x0e , 0x0e , 0x0f , 0x0f ,
0x08 , 0x08 , 0x09 , 0x09 , 0x08 , 0x08 , 0x09 , 0x09 ,
0x0a , 0x0a , 0x0b , 0x0b , 0x0a , 0x0a , 0x0b , 0x0b ,
0x08 , 0x08 , 0x09 , 0x09 , 0x08 , 0x08 , 0x09 , 0x09 ,
0x0a , 0x0a , 0x0b , 0x0b , 0x0a , 0x0a , 0x0b , 0x0b ,
0x0c , 0x0c , 0x0d , 0x0d , 0x0c , 0x0c , 0x0d , 0x0d ,
0x0e , 0x0e , 0x0f , 0x0f , 0x0e , 0x0e , 0x0f , 0x0f ,
0x0c , 0x0c , 0x0d , 0x0d , 0x0c , 0x0c , 0x0d , 0x0d ,
0x0e , 0x0e , 0x0f , 0x0f , 0x0e , 0x0e , 0x0f , 0x0f
2005-04-17 02:20:36 +04:00
} ;
/**
2009-10-22 11:53:32 +04:00
* __nand_calculate_ecc - [ NAND Interface ] Calculate 3 - byte ECC for 256 / 512 - byte
2008-08-23 20:18:34 +04:00
* block
2008-08-21 01:32:08 +04:00
* @ buf : input buffer with raw data
2011-06-24 01:12:08 +04:00
* @ eccsize : data bytes per ECC step ( 256 or 512 )
2008-08-21 01:32:08 +04:00
* @ code : output buffer with ECC
2005-04-17 02:20:36 +04:00
*/
2009-10-22 11:53:32 +04:00
void __nand_calculate_ecc ( const unsigned char * buf , unsigned int eccsize ,
2008-08-16 01:14:31 +04:00
unsigned char * code )
2005-04-17 02:20:36 +04:00
{
2006-05-23 13:32:45 +04:00
int i ;
2008-08-16 01:14:31 +04:00
const uint32_t * bp = ( uint32_t * ) buf ;
2008-08-23 20:18:34 +04:00
/* 256 or 512 bytes/ecc */
2009-10-22 11:53:32 +04:00
const uint32_t eccsize_mult = eccsize > > 8 ;
2008-08-16 01:14:31 +04:00
uint32_t cur ; /* current value in buffer */
2008-08-23 20:18:34 +04:00
/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
2008-08-16 01:14:31 +04:00
uint32_t rp0 , rp1 , rp2 , rp3 , rp4 , rp5 , rp6 , rp7 ;
2008-08-23 20:18:34 +04:00
uint32_t rp8 , rp9 , rp10 , rp11 , rp12 , rp13 , rp14 , rp15 , rp16 ;
uint32_t uninitialized_var ( rp17 ) ; /* to make compiler happy */
2008-08-16 01:14:31 +04:00
uint32_t par ; /* the cumulative parity for all data */
uint32_t tmppar ; /* the cumulative parity for this iteration;
2008-08-23 20:18:34 +04:00
for rp12 , rp14 and rp16 at the end of the
loop */
2008-08-16 01:14:31 +04:00
par = 0 ;
rp4 = 0 ;
rp6 = 0 ;
rp8 = 0 ;
rp10 = 0 ;
rp12 = 0 ;
rp14 = 0 ;
2008-08-23 20:18:34 +04:00
rp16 = 0 ;
2008-08-16 01:14:31 +04:00
/*
* The loop is unrolled a number of times ;
* This avoids if statements to decide on which rp value to update
* Also we process the data by longwords .
* Note : passing unaligned data might give a performance penalty .
* It is assumed that the buffers are aligned .
* tmppar is the cumulative sum of this iteration .
2008-08-23 20:18:34 +04:00
* needed for calculating rp12 , rp14 , rp16 and par
2008-08-16 01:14:31 +04:00
* also used as a performance improvement for rp6 , rp8 and rp10
*/
2008-08-23 20:18:34 +04:00
for ( i = 0 ; i < eccsize_mult < < 2 ; i + + ) {
2008-08-16 01:14:31 +04:00
cur = * bp + + ;
tmppar = cur ;
rp4 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp6 ^ = tmppar ;
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp8 ^ = tmppar ;
2005-11-07 14:15:49 +03:00
2008-08-16 01:14:31 +04:00
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
rp6 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp6 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp10 ^ = tmppar ;
2005-11-07 14:15:49 +03:00
2008-08-16 01:14:31 +04:00
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
rp6 ^ = cur ;
rp8 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp6 ^ = cur ;
rp8 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
rp8 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp8 ^ = cur ;
2005-11-07 14:15:49 +03:00
2008-08-16 01:14:31 +04:00
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
rp6 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp6 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
rp4 ^ = cur ;
cur = * bp + + ;
tmppar ^ = cur ;
par ^ = tmppar ;
if ( ( i & 0x1 ) = = 0 )
rp12 ^ = tmppar ;
if ( ( i & 0x2 ) = = 0 )
rp14 ^ = tmppar ;
2008-08-23 20:18:34 +04:00
if ( eccsize_mult = = 2 & & ( i & 0x4 ) = = 0 )
rp16 ^ = tmppar ;
2005-04-17 02:20:36 +04:00
}
2005-11-07 14:15:49 +03:00
2008-08-16 01:14:31 +04:00
/*
* handle the fact that we use longword operations
2008-08-23 20:18:34 +04:00
* we ' ll bring rp4 . . rp14 . . rp16 back to single byte entities by
* shifting and xoring first fold the upper and lower 16 bits ,
2008-08-16 01:14:31 +04:00
* then the upper and lower 8 bits .
*/
rp4 ^ = ( rp4 > > 16 ) ;
rp4 ^ = ( rp4 > > 8 ) ;
rp4 & = 0xff ;
rp6 ^ = ( rp6 > > 16 ) ;
rp6 ^ = ( rp6 > > 8 ) ;
rp6 & = 0xff ;
rp8 ^ = ( rp8 > > 16 ) ;
rp8 ^ = ( rp8 > > 8 ) ;
rp8 & = 0xff ;
rp10 ^ = ( rp10 > > 16 ) ;
rp10 ^ = ( rp10 > > 8 ) ;
rp10 & = 0xff ;
rp12 ^ = ( rp12 > > 16 ) ;
rp12 ^ = ( rp12 > > 8 ) ;
rp12 & = 0xff ;
rp14 ^ = ( rp14 > > 16 ) ;
rp14 ^ = ( rp14 > > 8 ) ;
rp14 & = 0xff ;
2008-08-23 20:18:34 +04:00
if ( eccsize_mult = = 2 ) {
rp16 ^ = ( rp16 > > 16 ) ;
rp16 ^ = ( rp16 > > 8 ) ;
rp16 & = 0xff ;
}
2008-08-16 01:14:31 +04:00
/*
* we also need to calculate the row parity for rp0 . . rp3
* This is present in par , because par is now
2008-08-20 23:11:50 +04:00
* rp3 rp3 rp2 rp2 in little endian and
* rp2 rp2 rp3 rp3 in big endian
2008-08-16 01:14:31 +04:00
* as well as
2008-08-20 23:11:50 +04:00
* rp1 rp0 rp1 rp0 in little endian and
* rp0 rp1 rp0 rp1 in big endian
2008-08-16 01:14:31 +04:00
* First calculate rp2 and rp3
*/
2008-08-20 23:11:50 +04:00
# ifdef __BIG_ENDIAN
rp2 = ( par > > 16 ) ;
rp2 ^ = ( rp2 > > 8 ) ;
rp2 & = 0xff ;
rp3 = par & 0xffff ;
rp3 ^ = ( rp3 > > 8 ) ;
rp3 & = 0xff ;
# else
2008-08-16 01:14:31 +04:00
rp3 = ( par > > 16 ) ;
rp3 ^ = ( rp3 > > 8 ) ;
rp3 & = 0xff ;
rp2 = par & 0xffff ;
rp2 ^ = ( rp2 > > 8 ) ;
rp2 & = 0xff ;
2008-08-20 23:11:50 +04:00
# endif
2008-08-16 01:14:31 +04:00
/* reduce par to 16 bits then calculate rp1 and rp0 */
par ^ = ( par > > 16 ) ;
2008-08-20 23:11:50 +04:00
# ifdef __BIG_ENDIAN
rp0 = ( par > > 8 ) & 0xff ;
rp1 = ( par & 0xff ) ;
# else
2008-08-16 01:14:31 +04:00
rp1 = ( par > > 8 ) & 0xff ;
rp0 = ( par & 0xff ) ;
2008-08-20 23:11:50 +04:00
# endif
2008-08-16 01:14:31 +04:00
/* finally reduce par to 8 bits */
par ^ = ( par > > 8 ) ;
par & = 0xff ;
/*
2008-08-23 20:18:34 +04:00
* and calculate rp5 . . rp15 . . rp17
2008-08-16 01:14:31 +04:00
* note that par = rp4 ^ rp5 and due to the commutative property
* of the ^ operator we can say :
* rp5 = ( par ^ rp4 ) ;
* The & 0xff seems superfluous , but benchmarking learned that
* leaving it out gives slightly worse results . No idea why , probably
* it has to do with the way the pipeline in pentium is organized .
*/
rp5 = ( par ^ rp4 ) & 0xff ;
rp7 = ( par ^ rp6 ) & 0xff ;
rp9 = ( par ^ rp8 ) & 0xff ;
rp11 = ( par ^ rp10 ) & 0xff ;
rp13 = ( par ^ rp12 ) & 0xff ;
rp15 = ( par ^ rp14 ) & 0xff ;
2008-08-23 20:18:34 +04:00
if ( eccsize_mult = = 2 )
rp17 = ( par ^ rp16 ) & 0xff ;
2008-08-16 01:14:31 +04:00
/*
2011-06-24 01:12:08 +04:00
* Finally calculate the ECC bits .
2008-08-16 01:14:31 +04:00
* Again here it might seem that there are performance optimisations
* possible , but benchmarks showed that on the system this is developed
* the code below is the fastest
*/
2006-11-27 15:35:49 +03:00
# ifdef CONFIG_MTD_NAND_ECC_SMC
2008-08-16 01:14:31 +04:00
code [ 0 ] =
( invparity [ rp7 ] < < 7 ) |
( invparity [ rp6 ] < < 6 ) |
( invparity [ rp5 ] < < 5 ) |
( invparity [ rp4 ] < < 4 ) |
( invparity [ rp3 ] < < 3 ) |
( invparity [ rp2 ] < < 2 ) |
( invparity [ rp1 ] < < 1 ) |
( invparity [ rp0 ] ) ;
code [ 1 ] =
( invparity [ rp15 ] < < 7 ) |
( invparity [ rp14 ] < < 6 ) |
( invparity [ rp13 ] < < 5 ) |
( invparity [ rp12 ] < < 4 ) |
( invparity [ rp11 ] < < 3 ) |
( invparity [ rp10 ] < < 2 ) |
( invparity [ rp9 ] < < 1 ) |
( invparity [ rp8 ] ) ;
2006-05-23 13:32:45 +04:00
# else
2008-08-16 01:14:31 +04:00
code [ 1 ] =
( invparity [ rp7 ] < < 7 ) |
( invparity [ rp6 ] < < 6 ) |
( invparity [ rp5 ] < < 5 ) |
( invparity [ rp4 ] < < 4 ) |
( invparity [ rp3 ] < < 3 ) |
( invparity [ rp2 ] < < 2 ) |
( invparity [ rp1 ] < < 1 ) |
( invparity [ rp0 ] ) ;
code [ 0 ] =
( invparity [ rp15 ] < < 7 ) |
( invparity [ rp14 ] < < 6 ) |
( invparity [ rp13 ] < < 5 ) |
( invparity [ rp12 ] < < 4 ) |
( invparity [ rp11 ] < < 3 ) |
( invparity [ rp10 ] < < 2 ) |
( invparity [ rp9 ] < < 1 ) |
( invparity [ rp8 ] ) ;
2006-05-23 13:32:45 +04:00
# endif
2008-08-23 20:18:34 +04:00
if ( eccsize_mult = = 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
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 ) ;
2009-10-22 11:53:32 +04:00
}
EXPORT_SYMBOL ( __nand_calculate_ecc ) ;
/**
* nand_calculate_ecc - [ NAND Interface ] Calculate 3 - byte ECC for 256 / 512 - byte
* block
* @ mtd : MTD block structure
* @ buf : input buffer with raw data
* @ code : output buffer with ECC
*/
int nand_calculate_ecc ( struct mtd_info * mtd , const unsigned char * buf ,
unsigned char * code )
{
__nand_calculate_ecc ( buf ,
( ( struct nand_chip * ) mtd - > priv ) - > ecc . size , code ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-05-23 13:32:45 +04:00
EXPORT_SYMBOL ( nand_calculate_ecc ) ;
2005-04-17 02:20:36 +04:00
/**
2009-09-04 20:20:43 +04:00
* __nand_correct_data - [ NAND Interface ] Detect and correct bit error ( s )
2008-08-21 01:32:08 +04:00
* @ buf : raw data read from the chip
2005-04-17 02:20:36 +04:00
* @ read_ecc : ECC from the chip
* @ calc_ecc : the ECC calculated from raw data
2011-06-24 01:12:08 +04:00
* @ eccsize : data bytes per ECC step ( 256 or 512 )
2005-04-17 02:20:36 +04:00
*
2009-09-04 20:20:43 +04:00
* Detect and correct a 1 bit error for eccsize byte block
2005-04-17 02:20:36 +04:00
*/
2009-09-04 20:20:43 +04:00
int __nand_correct_data ( unsigned char * buf ,
unsigned char * read_ecc , unsigned char * calc_ecc ,
unsigned int eccsize )
2005-04-17 02:20:36 +04:00
{
2009-02-23 11:16:08 +03:00
unsigned char b0 , b1 , b2 , bit_addr ;
unsigned int byte_addr ;
2008-08-23 20:18:34 +04:00
/* 256 or 512 bytes/ecc */
2009-09-04 20:20:43 +04:00
const uint32_t eccsize_mult = eccsize > > 8 ;
2006-05-23 13:32:45 +04:00
2008-08-16 01:14:31 +04:00
/*
* b0 to b2 indicate which bit is faulty ( if any )
* we might need the xor result more than once ,
* so keep them in a local var
*/
2006-11-27 15:35:49 +03:00
# ifdef CONFIG_MTD_NAND_ECC_SMC
2008-08-16 01:14:31 +04:00
b0 = read_ecc [ 0 ] ^ calc_ecc [ 0 ] ;
b1 = read_ecc [ 1 ] ^ calc_ecc [ 1 ] ;
2006-05-23 13:32:45 +04:00
# else
2008-08-16 01:14:31 +04:00
b0 = read_ecc [ 1 ] ^ calc_ecc [ 1 ] ;
b1 = read_ecc [ 0 ] ^ calc_ecc [ 0 ] ;
2006-05-23 13:32:45 +04:00
# endif
2008-08-16 01:14:31 +04:00
b2 = read_ecc [ 2 ] ^ calc_ecc [ 2 ] ;
2006-05-23 13:32:45 +04:00
2008-08-16 01:14:31 +04:00
/* check if there are any bitfaults */
2006-05-23 13:32:45 +04:00
2008-08-16 01:14:31 +04:00
/* repeated if statements are slightly more efficient than switch ... */
/* ordered in order of likelihood */
2008-08-20 23:11:50 +04:00
if ( ( b0 | b1 | b2 ) = = 0 )
2008-08-16 14:01:31 +04:00
return 0 ; /* no error */
2008-08-20 23:11:50 +04:00
if ( ( ( ( b0 ^ ( b0 > > 1 ) ) & 0x55 ) = = 0x55 ) & &
( ( ( b1 ^ ( b1 > > 1 ) ) & 0x55 ) = = 0x55 ) & &
2008-08-23 20:18:34 +04:00
( ( eccsize_mult = = 1 & & ( ( b2 ^ ( b2 > > 1 ) ) & 0x54 ) = = 0x54 ) | |
( eccsize_mult = = 2 & & ( ( b2 ^ ( b2 > > 1 ) ) & 0x55 ) = = 0x55 ) ) ) {
/* single bit error */
2008-08-16 01:14:31 +04:00
/*
2008-08-23 20:18:34 +04:00
* rp17 / rp15 / 13 / 11 / 9 / 7 / 5 / 3 / 1 indicate which byte is the faulty
* byte , cp 5 / 3 / 1 indicate the faulty bit .
2008-08-16 01:14:31 +04:00
* A lookup table ( called addressbits ) is used to filter
* the bits from the byte they are in .
* A marginal optimisation is possible by having three
* different lookup tables .
* One as we have now ( for b0 ) , one for b2
* ( that would avoid the > > 1 ) , and one for b1 ( with all values
* < < 4 ) . However it was felt that introducing two more tables
* hardly justify the gain .
*
* The b2 shift is there to get rid of the lowest two bits .
* We could also do addressbits [ b2 ] > > 1 but for the
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 18:09:05 +03:00
* performance it does not make any difference
2008-08-16 01:14:31 +04:00
*/
2008-08-23 20:18:34 +04:00
if ( eccsize_mult = = 1 )
byte_addr = ( addressbits [ b1 ] < < 4 ) + addressbits [ b0 ] ;
else
byte_addr = ( addressbits [ b2 & 0x3 ] < < 8 ) +
( addressbits [ b1 ] < < 4 ) + addressbits [ b0 ] ;
2008-08-16 01:14:31 +04:00
bit_addr = addressbits [ b2 > > 2 ] ;
/* flip the bit */
buf [ byte_addr ] ^ = ( 1 < < bit_addr ) ;
2008-08-16 14:01:31 +04:00
return 1 ;
2008-08-20 23:11:50 +04:00
2005-04-17 02:20:36 +04:00
}
2008-08-20 23:11:50 +04:00
/* count nr of bits; use table lookup, faster than calculating it */
if ( ( bitsperbyte [ b0 ] + bitsperbyte [ b1 ] + bitsperbyte [ b2 ] ) = = 1 )
2011-06-24 01:12:08 +04:00
return 1 ; /* error in ECC data; no action needed */
2008-08-20 23:11:50 +04:00
2014-04-08 21:19:48 +04:00
pr_err ( " %s: uncorrectable ECC error \n " , __func__ ) ;
2008-08-16 01:14:31 +04:00
return - 1 ;
2005-04-17 02:20:36 +04:00
}
2009-09-04 20:20:43 +04:00
EXPORT_SYMBOL ( __nand_correct_data ) ;
/**
* nand_correct_data - [ NAND Interface ] Detect and correct bit error ( s )
* @ mtd : MTD block structure
* @ buf : raw data read from the chip
* @ read_ecc : ECC from the chip
* @ calc_ecc : the ECC calculated from raw data
*
* Detect and correct a 1 bit error for 256 / 512 byte block
*/
int nand_correct_data ( struct mtd_info * mtd , unsigned char * buf ,
unsigned char * read_ecc , unsigned char * calc_ecc )
{
return __nand_correct_data ( buf , read_ecc , calc_ecc ,
( ( struct nand_chip * ) mtd - > priv ) - > ecc . size ) ;
}
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( nand_correct_data ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-08-16 01:14:31 +04:00
MODULE_AUTHOR ( " Frans Meulenbroeks <fransmeulenbroeks@gmail.com> " ) ;
2005-04-17 02:20:36 +04:00
MODULE_DESCRIPTION ( " Generic NAND ECC support " ) ;