@ -4077,6 +4077,226 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
}
EXPORT_SYMBOL ( nand_scan_ident ) ;
/**
* nand_check_ecc_caps - check the sanity of preset ECC settings
* @ chip : nand chip info structure
* @ caps : ECC caps info structure
* @ oobavail : OOB size that the ECC engine can use
*
* When ECC step size and strength are already set , check if they are supported
* by the controller and the calculated ECC bytes fit within the chip ' s OOB .
* On success , the calculated ECC bytes is set .
*/
int nand_check_ecc_caps ( struct nand_chip * chip ,
const struct nand_ecc_caps * caps , int oobavail )
{
struct mtd_info * mtd = nand_to_mtd ( chip ) ;
const struct nand_ecc_step_info * stepinfo ;
int preset_step = chip - > ecc . size ;
int preset_strength = chip - > ecc . strength ;
int nsteps , ecc_bytes ;
int i , j ;
if ( WARN_ON ( oobavail < 0 ) )
return - EINVAL ;
if ( ! preset_step | | ! preset_strength )
return - ENODATA ;
nsteps = mtd - > writesize / preset_step ;
for ( i = 0 ; i < caps - > nstepinfos ; i + + ) {
stepinfo = & caps - > stepinfos [ i ] ;
if ( stepinfo - > stepsize ! = preset_step )
continue ;
for ( j = 0 ; j < stepinfo - > nstrengths ; j + + ) {
if ( stepinfo - > strengths [ j ] ! = preset_strength )
continue ;
ecc_bytes = caps - > calc_ecc_bytes ( preset_step ,
preset_strength ) ;
if ( WARN_ON_ONCE ( ecc_bytes < 0 ) )
return ecc_bytes ;
if ( ecc_bytes * nsteps > oobavail ) {
pr_err ( " ECC (step, strength) = (%d, %d) does not fit in OOB " ,
preset_step , preset_strength ) ;
return - ENOSPC ;
}
chip - > ecc . bytes = ecc_bytes ;
return 0 ;
}
}
pr_err ( " ECC (step, strength) = (%d, %d) not supported on this controller " ,
preset_step , preset_strength ) ;
return - ENOTSUPP ;
}
EXPORT_SYMBOL_GPL ( nand_check_ecc_caps ) ;
/**
* nand_match_ecc_req - meet the chip ' s requirement with least ECC bytes
* @ chip : nand chip info structure
* @ caps : ECC engine caps info structure
* @ oobavail : OOB size that the ECC engine can use
*
* If a chip ' s ECC requirement is provided , try to meet it with the least
* number of ECC bytes ( i . e . with the largest number of OOB - free bytes ) .
* On success , the chosen ECC settings are set .
*/
int nand_match_ecc_req ( struct nand_chip * chip ,
const struct nand_ecc_caps * caps , int oobavail )
{
struct mtd_info * mtd = nand_to_mtd ( chip ) ;
const struct nand_ecc_step_info * stepinfo ;
int req_step = chip - > ecc_step_ds ;
int req_strength = chip - > ecc_strength_ds ;
int req_corr , step_size , strength , nsteps , ecc_bytes , ecc_bytes_total ;
int best_step , best_strength , best_ecc_bytes ;
int best_ecc_bytes_total = INT_MAX ;
int i , j ;
if ( WARN_ON ( oobavail < 0 ) )
return - EINVAL ;
/* No information provided by the NAND chip */
if ( ! req_step | | ! req_strength )
return - ENOTSUPP ;
/* number of correctable bits the chip requires in a page */
req_corr = mtd - > writesize / req_step * req_strength ;
for ( i = 0 ; i < caps - > nstepinfos ; i + + ) {
stepinfo = & caps - > stepinfos [ i ] ;
step_size = stepinfo - > stepsize ;
for ( j = 0 ; j < stepinfo - > nstrengths ; j + + ) {
strength = stepinfo - > strengths [ j ] ;
/*
* If both step size and strength are smaller than the
* chip ' s requirement , it is not easy to compare the
* resulted reliability .
*/
if ( step_size < req_step & & strength < req_strength )
continue ;
if ( mtd - > writesize % step_size )
continue ;
nsteps = mtd - > writesize / step_size ;
ecc_bytes = caps - > calc_ecc_bytes ( step_size , strength ) ;
if ( WARN_ON_ONCE ( ecc_bytes < 0 ) )
continue ;
ecc_bytes_total = ecc_bytes * nsteps ;
if ( ecc_bytes_total > oobavail | |
strength * nsteps < req_corr )
continue ;
/*
* We assume the best is to meet the chip ' s requrement
* with the least number of ECC bytes .
*/
if ( ecc_bytes_total < best_ecc_bytes_total ) {
best_ecc_bytes_total = ecc_bytes_total ;
best_step = step_size ;
best_strength = strength ;
best_ecc_bytes = ecc_bytes ;
}
}
}
if ( best_ecc_bytes_total = = INT_MAX )
return - ENOTSUPP ;
chip - > ecc . size = best_step ;
chip - > ecc . strength = best_strength ;
chip - > ecc . bytes = best_ecc_bytes ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( nand_match_ecc_req ) ;
/**
* nand_maximize_ecc - choose the max ECC strength available
* @ chip : nand chip info structure
* @ caps : ECC engine caps info structure
* @ oobavail : OOB size that the ECC engine can use
*
* Choose the max ECC strength that is supported on the controller , and can fit
* within the chip ' s OOB . On success , the chosen ECC settings are set .
*/
int nand_maximize_ecc ( struct nand_chip * chip ,
const struct nand_ecc_caps * caps , int oobavail )
{
struct mtd_info * mtd = nand_to_mtd ( chip ) ;
const struct nand_ecc_step_info * stepinfo ;
int step_size , strength , nsteps , ecc_bytes , corr ;
int best_corr = 0 ;
int best_step = 0 ;
int best_strength , best_ecc_bytes ;
int i , j ;
if ( WARN_ON ( oobavail < 0 ) )
return - EINVAL ;
for ( i = 0 ; i < caps - > nstepinfos ; i + + ) {
stepinfo = & caps - > stepinfos [ i ] ;
step_size = stepinfo - > stepsize ;
/* If chip->ecc.size is already set, respect it */
if ( chip - > ecc . size & & step_size ! = chip - > ecc . size )
continue ;
for ( j = 0 ; j < stepinfo - > nstrengths ; j + + ) {
strength = stepinfo - > strengths [ j ] ;
if ( mtd - > writesize % step_size )
continue ;
nsteps = mtd - > writesize / step_size ;
ecc_bytes = caps - > calc_ecc_bytes ( step_size , strength ) ;
if ( WARN_ON_ONCE ( ecc_bytes < 0 ) )
continue ;
if ( ecc_bytes * nsteps > oobavail )
continue ;
corr = strength * nsteps ;
/*
* If the number of correctable bits is the same ,
* bigger step_size has more reliability .
*/
if ( corr > best_corr | |
( corr = = best_corr & & step_size > best_step ) ) {
best_corr = corr ;
best_step = step_size ;
best_strength = strength ;
best_ecc_bytes = ecc_bytes ;
}
}
}
if ( ! best_corr )
return - ENOTSUPP ;
chip - > ecc . size = best_step ;
chip - > ecc . strength = best_strength ;
chip - > ecc . bytes = best_ecc_bytes ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( nand_maximize_ecc ) ;
/*
* Check if the chip configuration meet the datasheet requirements .