2019-05-20 19:08:14 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2005-04-16 15:20:36 -07:00
/*
2008-08-15 23:14:31 +02:00
* This file contains an ECC algorithm that detects and corrects 1 bit
* errors in a 256 byte block of data .
2005-04-16 15:20:36 -07:00
*
2008-08-16 11:01:31 +01:00
* Copyright © 2008 Koninklijke Philips Electronics NV .
* Author : Frans Meulenbroeks
2005-04-16 15:20:36 -07:00
*
2008-08-15 23:14:31 +02: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
2019-06-18 16:40:16 -03:00
* can be found in Documentation / driver - api / mtd / nand_ecc . rst
2005-04-16 15:20:36 -07:00
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/module.h>
2008-08-23 18:18:34 +02:00
# include <linux/mtd/mtd.h>
2017-08-04 17:29:10 +02:00
# include <linux/mtd/rawnand.h>
2005-04-16 15:20:36 -07:00
# include <linux/mtd/nand_ecc.h>
2008-08-20 21:11:50 +02:00
# include <asm/byteorder.h>
2008-08-15 23:14:31 +02:00
/*
* 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-16 15:20:36 -07:00
/*
2008-08-15 23:14:31 +02: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-16 15:20:36 -07:00
*/
2008-08-15 23:14:31 +02: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-23 14:12:08 -07:00
* ECC data that identify the faulty location .
2008-08-15 23:14:31 +02: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-16 15:20:36 -07:00
} ;
/**
2009-10-22 16:53:32 +09:00
* __nand_calculate_ecc - [ NAND Interface ] Calculate 3 - byte ECC for 256 / 512 - byte
2008-08-23 18:18:34 +02:00
* block
2008-08-20 22:32:08 +01:00
* @ buf : input buffer with raw data
2011-06-23 14:12:08 -07:00
* @ eccsize : data bytes per ECC step ( 256 or 512 )
2008-08-20 22:32:08 +01:00
* @ code : output buffer with ECC
2018-09-04 16:23:28 +02:00
* @ sm_order : Smart Media byte ordering
2005-04-16 15:20:36 -07:00
*/
2009-10-22 16:53:32 +09:00
void __nand_calculate_ecc ( const unsigned char * buf , unsigned int eccsize ,
2018-09-04 16:23:28 +02:00
unsigned char * code , bool sm_order )
2005-04-16 15:20:36 -07:00
{
2006-05-23 11:32:45 +02:00
int i ;
2008-08-15 23:14:31 +02:00
const uint32_t * bp = ( uint32_t * ) buf ;
2008-08-23 18:18:34 +02:00
/* 256 or 512 bytes/ecc */
2009-10-22 16:53:32 +09:00
const uint32_t eccsize_mult = eccsize > > 8 ;
2008-08-15 23:14:31 +02:00
uint32_t cur ; /* current value in buffer */
2008-08-23 18:18:34 +02:00
/* rp0..rp15..rp17 are the various accumulated parities (per byte) */
2008-08-15 23:14:31 +02:00
uint32_t rp0 , rp1 , rp2 , rp3 , rp4 , rp5 , rp6 , rp7 ;
2008-08-23 18:18:34 +02:00
uint32_t rp8 , rp9 , rp10 , rp11 , rp12 , rp13 , rp14 , rp15 , rp16 ;
treewide: Remove uninitialized_var() usage
Using uninitialized_var() is dangerous as it papers over real bugs[1]
(or can in the future), and suppresses unrelated compiler warnings
(e.g. "unused variable"). If the compiler thinks it is uninitialized,
either simply initialize the variable or make compiler changes.
In preparation for removing[2] the[3] macro[4], remove all remaining
needless uses with the following script:
git grep '\buninitialized_var\b' | cut -d: -f1 | sort -u | \
xargs perl -pi -e \
's/\buninitialized_var\(([^\)]+)\)/\1/g;
s:\s*/\* (GCC be quiet|to make compiler happy) \*/$::g;'
drivers/video/fbdev/riva/riva_hw.c was manually tweaked to avoid
pathological white-space.
No outstanding warnings were found building allmodconfig with GCC 9.3.0
for x86_64, i386, arm64, arm, powerpc, powerpc64le, s390x, mips, sparc64,
alpha, and m68k.
[1] https://lore.kernel.org/lkml/20200603174714.192027-1-glider@google.com/
[2] https://lore.kernel.org/lkml/CA+55aFw+Vbj0i=1TGqCR5vQkCzWJ0QxK6CernOU6eedsudAixw@mail.gmail.com/
[3] https://lore.kernel.org/lkml/CA+55aFwgbgqhbp1fkxvRKEpzyR5J8n1vKT1VZdz9knmPuXhOeg@mail.gmail.com/
[4] https://lore.kernel.org/lkml/CA+55aFz2500WfbKXAx8s67wrm9=yVJu65TpLgN_ybYNv0VEOKA@mail.gmail.com/
Reviewed-by: Leon Romanovsky <leonro@mellanox.com> # drivers/infiniband and mlx4/mlx5
Acked-by: Jason Gunthorpe <jgg@mellanox.com> # IB
Acked-by: Kalle Valo <kvalo@codeaurora.org> # wireless drivers
Reviewed-by: Chao Yu <yuchao0@huawei.com> # erofs
Signed-off-by: Kees Cook <keescook@chromium.org>
2020-06-03 13:09:38 -07:00
uint32_t rp17 ;
2008-08-15 23:14:31 +02:00
uint32_t par ; /* the cumulative parity for all data */
uint32_t tmppar ; /* the cumulative parity for this iteration;
2008-08-23 18:18:34 +02:00
for rp12 , rp14 and rp16 at the end of the
loop */
2008-08-15 23:14:31 +02:00
par = 0 ;
rp4 = 0 ;
rp6 = 0 ;
rp8 = 0 ;
rp10 = 0 ;
rp12 = 0 ;
rp14 = 0 ;
2008-08-23 18:18:34 +02:00
rp16 = 0 ;
2008-08-15 23:14:31 +02: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 18:18:34 +02:00
* needed for calculating rp12 , rp14 , rp16 and par
2008-08-15 23:14:31 +02:00
* also used as a performance improvement for rp6 , rp8 and rp10
*/
2008-08-23 18:18:34 +02:00
for ( i = 0 ; i < eccsize_mult < < 2 ; i + + ) {
2008-08-15 23:14:31 +02: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 11:15:49 +00:00
2008-08-15 23:14:31 +02: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 11:15:49 +00:00
2008-08-15 23:14:31 +02: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 11:15:49 +00:00
2008-08-15 23:14:31 +02: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 18:18:34 +02:00
if ( eccsize_mult = = 2 & & ( i & 0x4 ) = = 0 )
rp16 ^ = tmppar ;
2005-04-16 15:20:36 -07:00
}
2005-11-07 11:15:49 +00:00
2008-08-15 23:14:31 +02:00
/*
* handle the fact that we use longword operations
2008-08-23 18:18:34 +02: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-15 23:14:31 +02: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 18:18:34 +02:00
if ( eccsize_mult = = 2 ) {
rp16 ^ = ( rp16 > > 16 ) ;
rp16 ^ = ( rp16 > > 8 ) ;
rp16 & = 0xff ;
}
2008-08-15 23:14:31 +02:00
/*
* we also need to calculate the row parity for rp0 . . rp3
* This is present in par , because par is now
2008-08-20 21:11:50 +02:00
* rp3 rp3 rp2 rp2 in little endian and
* rp2 rp2 rp3 rp3 in big endian
2008-08-15 23:14:31 +02:00
* as well as
2008-08-20 21:11:50 +02:00
* rp1 rp0 rp1 rp0 in little endian and
* rp0 rp1 rp0 rp1 in big endian
2008-08-15 23:14:31 +02:00
* First calculate rp2 and rp3
*/
2008-08-20 21:11:50 +02:00
# ifdef __BIG_ENDIAN
rp2 = ( par > > 16 ) ;
rp2 ^ = ( rp2 > > 8 ) ;
rp2 & = 0xff ;
rp3 = par & 0xffff ;
rp3 ^ = ( rp3 > > 8 ) ;
rp3 & = 0xff ;
# else
2008-08-15 23:14:31 +02:00
rp3 = ( par > > 16 ) ;
rp3 ^ = ( rp3 > > 8 ) ;
rp3 & = 0xff ;
rp2 = par & 0xffff ;
rp2 ^ = ( rp2 > > 8 ) ;
rp2 & = 0xff ;
2008-08-20 21:11:50 +02:00
# endif
2008-08-15 23:14:31 +02:00
/* reduce par to 16 bits then calculate rp1 and rp0 */
par ^ = ( par > > 16 ) ;
2008-08-20 21:11:50 +02:00
# ifdef __BIG_ENDIAN
rp0 = ( par > > 8 ) & 0xff ;
rp1 = ( par & 0xff ) ;
# else
2008-08-15 23:14:31 +02:00
rp1 = ( par > > 8 ) & 0xff ;
rp0 = ( par & 0xff ) ;
2008-08-20 21:11:50 +02:00
# endif
2008-08-15 23:14:31 +02:00
/* finally reduce par to 8 bits */
par ^ = ( par > > 8 ) ;
par & = 0xff ;
/*
2008-08-23 18:18:34 +02:00
* and calculate rp5 . . rp15 . . rp17
2008-08-15 23:14:31 +02: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 18:18:34 +02:00
if ( eccsize_mult = = 2 )
rp17 = ( par ^ rp16 ) & 0xff ;
2008-08-15 23:14:31 +02:00
/*
2011-06-23 14:12:08 -07:00
* Finally calculate the ECC bits .
2008-08-15 23:14:31 +02: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
*/
2018-09-04 16:23:28 +02:00
if ( sm_order ) {
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 ] ) ;
} else {
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 ] ) ;
}
2008-08-23 18:18:34 +02: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 16:53:32 +09:00
}
EXPORT_SYMBOL ( __nand_calculate_ecc ) ;
/**
* nand_calculate_ecc - [ NAND Interface ] Calculate 3 - byte ECC for 256 / 512 - byte
* block
2018-09-06 14:05:21 +02:00
* @ chip : NAND chip object
2009-10-22 16:53:32 +09:00
* @ buf : input buffer with raw data
* @ code : output buffer with ECC
*/
2018-09-06 14:05:18 +02:00
int nand_calculate_ecc ( struct nand_chip * chip , const unsigned char * buf ,
2009-10-22 16:53:32 +09:00
unsigned char * code )
{
2018-09-04 16:23:28 +02:00
bool sm_order = chip - > ecc . options & NAND_ECC_SOFT_HAMMING_SM_ORDER ;
__nand_calculate_ecc ( buf , chip - > ecc . size , code , sm_order ) ;
2009-10-22 16:53:32 +09:00
2005-04-16 15:20:36 -07:00
return 0 ;
}
2006-05-23 11:32:45 +02:00
EXPORT_SYMBOL ( nand_calculate_ecc ) ;
2005-04-16 15:20:36 -07:00
/**
2009-09-05 01:20:43 +09:00
* __nand_correct_data - [ NAND Interface ] Detect and correct bit error ( s )
2008-08-20 22:32:08 +01:00
* @ buf : raw data read from the chip
2005-04-16 15:20:36 -07:00
* @ read_ecc : ECC from the chip
* @ calc_ecc : the ECC calculated from raw data
2011-06-23 14:12:08 -07:00
* @ eccsize : data bytes per ECC step ( 256 or 512 )
2018-09-04 16:23:28 +02:00
* @ sm_order : Smart Media byte order
2005-04-16 15:20:36 -07:00
*
2009-09-05 01:20:43 +09:00
* Detect and correct a 1 bit error for eccsize byte block
2005-04-16 15:20:36 -07:00
*/
2009-09-05 01:20:43 +09:00
int __nand_correct_data ( unsigned char * buf ,
unsigned char * read_ecc , unsigned char * calc_ecc ,
2018-09-04 16:23:28 +02:00
unsigned int eccsize , bool sm_order )
2005-04-16 15:20:36 -07:00
{
2009-02-23 13:46:08 +05:30
unsigned char b0 , b1 , b2 , bit_addr ;
unsigned int byte_addr ;
2008-08-23 18:18:34 +02:00
/* 256 or 512 bytes/ecc */
2009-09-05 01:20:43 +09:00
const uint32_t eccsize_mult = eccsize > > 8 ;
2006-05-23 11:32:45 +02:00
2008-08-15 23:14:31 +02: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
*/
2018-09-04 16:23:28 +02:00
if ( sm_order ) {
b0 = read_ecc [ 0 ] ^ calc_ecc [ 0 ] ;
b1 = read_ecc [ 1 ] ^ calc_ecc [ 1 ] ;
} else {
b0 = read_ecc [ 1 ] ^ calc_ecc [ 1 ] ;
b1 = read_ecc [ 0 ] ^ calc_ecc [ 0 ] ;
}
2008-08-15 23:14:31 +02:00
b2 = read_ecc [ 2 ] ^ calc_ecc [ 2 ] ;
2006-05-23 11:32:45 +02:00
2008-08-15 23:14:31 +02:00
/* check if there are any bitfaults */
2006-05-23 11:32:45 +02:00
2008-08-15 23:14:31 +02:00
/* repeated if statements are slightly more efficient than switch ... */
/* ordered in order of likelihood */
2008-08-20 21:11:50 +02:00
if ( ( b0 | b1 | b2 ) = = 0 )
2008-08-16 11:01:31 +01:00
return 0 ; /* no error */
2008-08-20 21:11:50 +02:00
if ( ( ( ( b0 ^ ( b0 > > 1 ) ) & 0x55 ) = = 0x55 ) & &
( ( ( b1 ^ ( b1 > > 1 ) ) & 0x55 ) = = 0x55 ) & &
2008-08-23 18:18:34 +02:00
( ( eccsize_mult = = 1 & & ( ( b2 ^ ( b2 > > 1 ) ) & 0x54 ) = = 0x54 ) | |
( eccsize_mult = = 2 & & ( ( b2 ^ ( b2 > > 1 ) ) & 0x55 ) = = 0x55 ) ) ) {
/* single bit error */
2008-08-15 23:14:31 +02:00
/*
2008-08-23 18:18:34 +02: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-15 23:14:31 +02: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 13:09:05 -02:00
* performance it does not make any difference
2008-08-15 23:14:31 +02:00
*/
2008-08-23 18:18:34 +02: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-15 23:14:31 +02:00
bit_addr = addressbits [ b2 > > 2 ] ;
/* flip the bit */
buf [ byte_addr ] ^ = ( 1 < < bit_addr ) ;
2008-08-16 11:01:31 +01:00
return 1 ;
2008-08-20 21:11:50 +02:00
2005-04-16 15:20:36 -07:00
}
2008-08-20 21:11:50 +02:00
/* count nr of bits; use table lookup, faster than calculating it */
if ( ( bitsperbyte [ b0 ] + bitsperbyte [ b1 ] + bitsperbyte [ b2 ] ) = = 1 )
2011-06-23 14:12:08 -07:00
return 1 ; /* error in ECC data; no action needed */
2008-08-20 21:11:50 +02:00
2014-04-08 10:19:48 -07:00
pr_err ( " %s: uncorrectable ECC error \n " , __func__ ) ;
2015-12-30 20:32:03 +01:00
return - EBADMSG ;
2005-04-16 15:20:36 -07:00
}
2009-09-05 01:20:43 +09:00
EXPORT_SYMBOL ( __nand_correct_data ) ;
/**
* nand_correct_data - [ NAND Interface ] Detect and correct bit error ( s )
2018-09-06 14:05:19 +02:00
* @ chip : NAND chip object
2009-09-05 01:20:43 +09:00
* @ 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
*/
2018-09-06 14:05:19 +02:00
int nand_correct_data ( struct nand_chip * chip , unsigned char * buf ,
2009-09-05 01:20:43 +09:00
unsigned char * read_ecc , unsigned char * calc_ecc )
{
2018-09-04 16:23:28 +02:00
bool sm_order = chip - > ecc . options & NAND_ECC_SOFT_HAMMING_SM_ORDER ;
return __nand_correct_data ( buf , read_ecc , calc_ecc , chip - > ecc . size ,
sm_order ) ;
2009-09-05 01:20:43 +09:00
}
2005-04-16 15:20:36 -07:00
EXPORT_SYMBOL ( nand_correct_data ) ;
MODULE_LICENSE ( " GPL " ) ;
2008-08-15 23:14:31 +02:00
MODULE_AUTHOR ( " Frans Meulenbroeks <fransmeulenbroeks@gmail.com> " ) ;
2005-04-16 15:20:36 -07:00
MODULE_DESCRIPTION ( " Generic NAND ECC support " ) ;