@ -30,29 +30,12 @@
# include "mtdcore.h"
/* Our partition linked list */
static LIST_HEAD ( mtd_partitions ) ;
# ifndef __UBOOT__
static DEFINE_MUTEX ( mtd_partitions_mutex ) ;
# else
DEFINE_MUTEX ( mtd_partitions_mutex ) ;
# endif
/* Our partition node structure */
struct mtd_part {
struct mtd_info mtd ;
struct mtd_info * master ;
uint64_t offset ;
struct list_head list ;
} ;
/*
* Given a pointer to the MTD object in the mtd_part structure , we can retrieve
* the pointer to that structure with this macro .
*/
# define PART(x) ((struct mtd_part *)(x))
# ifdef __UBOOT__
/* from mm/util.c */
@ -294,19 +277,18 @@ void mtd_free_parsed_partitions(struct mtd_partition *parts,
static int part_read ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , u_char * buf )
{
struct mtd_part * part = PART ( mtd ) ;
struct mtd_ecc_stats stats ;
int res ;
stats = part - > master - > ecc_stats ;
res = part - > master - > _read ( part - > master , from + part - > offset , len ,
retlen , buf ) ;
stats = mtd - > parent - > ecc_stats ;
res = mtd - > parent - > _read ( mtd - > parent , from + mtd - > offset , len ,
retlen , buf ) ;
if ( unlikely ( mtd_is_eccerr ( res ) ) )
mtd - > ecc_stats . failed + =
part - > master - > ecc_stats . failed - stats . failed ;
mtd - > parent - > ecc_stats . failed - stats . failed ;
else
mtd - > ecc_stats . corrected + =
part - > master - > ecc_stats . corrected - stats . corrected ;
mtd - > parent - > ecc_stats . corrected - stats . corrected ;
return res ;
}
@ -314,17 +296,13 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
static int part_point ( struct mtd_info * mtd , loff_t from , size_t len ,
size_t * retlen , void * * virt , resource_size_t * phys )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _point ( part - > master , from + part - > offset , len ,
retlen , virt , phys ) ;
return mtd - > parent - > _point ( mtd - > parent , from + mtd - > offset , len ,
retlen , virt , phys ) ;
}
static int part_unpoint ( struct mtd_info * mtd , loff_t from , size_t len )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _unpoint ( part - > master , from + part - > offset , len ) ;
return mtd - > parent - > _unpoint ( mtd - > parent , from + mtd - > offset , len ) ;
}
# endif
@ -333,17 +311,13 @@ static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
unsigned long offset ,
unsigned long flags )
{
struct mtd_part * part = PART ( mtd ) ;
offset + = part - > offset ;
return part - > master - > _get_unmapped_area ( part - > master , len , offset ,
flags ) ;
offset + = mtd - > offset ;
return mtd - > parent - > _get_unmapped_area ( mtd - > parent , len , offset , flags ) ;
}
static int part_read_oob ( struct mtd_info * mtd , loff_t from ,
struct mtd_oob_ops * ops )
{
struct mtd_part * part = PART ( mtd ) ;
int res ;
if ( from > = mtd - > size )
@ -368,7 +342,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
return - EINVAL ;
}
res = part - > master - > _read_oob ( part - > master , from + part - > offset , ops ) ;
res = mtd - > parent - > _read_oob ( mtd - > parent , from + mtd - > offset , ops ) ;
if ( unlikely ( res ) ) {
if ( mtd_is_bitflip ( res ) )
mtd - > ecc_stats . corrected + + ;
@ -381,99 +355,87 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from,
static int part_read_user_prot_reg ( struct mtd_info * mtd , loff_t from ,
size_t len , size_t * retlen , u_char * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _read_user_prot_reg ( part - > master , from , len ,
retlen , buf ) ;
return mtd - > parent - > _read_user_prot_reg ( mtd - > parent , from , len ,
retlen , buf ) ;
}
static int part_get_user_prot_info ( struct mtd_info * mtd , size_t len ,
size_t * retlen , struct otp_info * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _get_user_prot_info ( part - > master , len , retlen ,
buf ) ;
return mtd - > parent - > _get_user_prot_info ( mtd - > parent , len , retlen ,
buf ) ;
}
static int part_read_fact_prot_reg ( struct mtd_info * mtd , loff_t from ,
size_t len , size_t * retlen , u_char * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _read_fact_prot_reg ( part - > master , from , len ,
retlen , buf ) ;
return mtd - > parent - > _read_fact_prot_reg ( mtd - > parent , from , len ,
retlen , buf ) ;
}
static int part_get_fact_prot_info ( struct mtd_info * mtd , size_t len ,
size_t * retlen , struct otp_info * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _get_fact_prot_info ( part - > master , len , retlen ,
buf ) ;
return mtd - > parent - > _get_fact_prot_info ( mtd - > parent , len , retlen ,
buf ) ;
}
static int part_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const u_char * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _write ( part - > master , to + part - > offset , len ,
retlen , buf ) ;
return mtd - > parent - > _write ( mtd - > parent , to + mtd - > offset , len ,
retlen , buf ) ;
}
static int part_panic_write ( struct mtd_info * mtd , loff_t to , size_t len ,
size_t * retlen , const u_char * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _panic_write ( part - > master , to + part - > offset , len ,
retlen , buf ) ;
return mtd - > parent - > _panic_write ( mtd - > parent , to + mtd - > offset , len ,
retlen , buf ) ;
}
static int part_write_oob ( struct mtd_info * mtd , loff_t to ,
struct mtd_oob_ops * ops )
{
struct mtd_part * part = PART ( mtd ) ;
if ( to > = mtd - > size )
return - EINVAL ;
if ( ops - > datbuf & & to + ops - > len > mtd - > size )
return - EINVAL ;
return part - > master - > _write_oob ( part - > master , to + part - > offset , ops ) ;
return mtd - > parent - > _write_oob ( mtd - > parent , to + mtd - > offset , ops ) ;
}
static int part_write_user_prot_reg ( struct mtd_info * mtd , loff_t from ,
size_t len , size_t * retlen , u_char * buf )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _write_user_prot_reg ( part - > master , from , len ,
retlen , buf ) ;
return mtd - > parent - > _write_user_prot_reg ( mtd - > parent , from , len ,
retlen , buf ) ;
}
static int part_lock_user_prot_reg ( struct mtd_info * mtd , loff_t from ,
size_t len )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _lock_user_prot_reg ( part - > master , from , len ) ;
return mtd - > parent - > _lock_user_prot_reg ( mtd - > parent , from , len ) ;
}
# ifndef __UBOOT__
static int part_writev ( struct mtd_info * mtd , const struct kvec * vecs ,
unsigned long count , loff_t to , size_t * retlen )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _writev ( part - > master , vecs , count ,
to + part - > offset , retlen ) ;
return mtd - > parent - > _writev ( mtd - > parent , vecs , count ,
to + mtd - > offset , retlen ) ;
}
# endif
static int part_erase ( struct mtd_info * mtd , struct erase_info * instr )
{
struct mtd_part * part = PART ( mtd ) ;
int ret ;
instr - > addr + = part - > offset ;
ret = part - > master - > _erase ( part - > master , instr ) ;
instr - > addr + = mtd - > offset ;
ret = mtd - > parent - > _erase ( mtd - > parent , instr ) ;
if ( ret ) {
if ( instr - > fail_addr ! = MTD_FAIL_ADDR_UNKNOWN )
instr - > fail_addr - = part - > offset ;
instr - > addr - = part - > offset ;
instr - > fail_addr - = mtd - > offset ;
instr - > addr - = mtd - > offset ;
}
return ret ;
}
@ -481,11 +443,9 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
void mtd_erase_callback ( struct erase_info * instr )
{
if ( instr - > mtd - > _erase = = part_erase ) {
struct mtd_part * part = PART ( instr - > mtd ) ;
if ( instr - > fail_addr ! = MTD_FAIL_ADDR_UNKNOWN )
instr - > fail_addr - = part - > offset ;
instr - > addr - = part - > offset ;
instr - > fail_addr - = instr - > mtd - > offset ;
instr - > addr - = instr - > mtd - > offset ;
}
if ( instr - > callback )
instr - > callback ( instr ) ;
@ -494,107 +454,112 @@ EXPORT_SYMBOL_GPL(mtd_erase_callback);
static int part_lock ( struct mtd_info * mtd , loff_t ofs , uint64_t len )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _lock ( part - > master , ofs + part - > offset , len ) ;
return mtd - > parent - > _lock ( mtd - > parent , ofs + mtd - > offset , len ) ;
}
static int part_unlock ( struct mtd_info * mtd , loff_t ofs , uint64_t len )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _unlock ( part - > master , ofs + part - > offset , len ) ;
return mtd - > parent - > _unlock ( mtd - > parent , ofs + mtd - > offset , len ) ;
}
static int part_is_locked ( struct mtd_info * mtd , loff_t ofs , uint64_t len )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _is_locked ( part - > master , ofs + part - > offset , len ) ;
return mtd - > parent - > _is_locked ( mtd - > parent , ofs + mtd - > offset , len ) ;
}
static void part_sync ( struct mtd_info * mtd )
{
struct mtd_part * part = PART ( mtd ) ;
part - > master - > _sync ( part - > master ) ;
mtd - > parent - > _sync ( mtd - > parent ) ;
}
# ifndef __UBOOT__
static int part_suspend ( struct mtd_info * mtd )
{
struct mtd_part * part = PART ( mtd ) ;
return part - > master - > _suspend ( part - > master ) ;
return mtd - > parent - > _suspend ( mtd - > parent ) ;
}
static void part_resume ( struct mtd_info * mtd )
{
struct mtd_part * part = PART ( mtd ) ;
part - > master - > _resume ( part - > master ) ;
mtd - > parent - > _resume ( mtd - > parent ) ;
}
# endif
static int part_block_isreserved ( struct mtd_info * mtd , loff_t ofs )
{
struct mtd_part * part = PART ( mtd ) ;
ofs + = part - > offset ;
return part - > master - > _block_isreserved ( part - > master , ofs ) ;
ofs + = mtd - > offset ;
return mtd - > parent - > _block_isreserved ( mtd - > parent , ofs ) ;
}
static int part_block_isbad ( struct mtd_info * mtd , loff_t ofs )
{
struct mtd_part * part = PART ( mtd ) ;
ofs + = part - > offset ;
return part - > master - > _block_isbad ( part - > master , ofs ) ;
ofs + = mtd - > offset ;
return mtd - > parent - > _block_isbad ( mtd - > parent , ofs ) ;
}
static int part_block_markbad ( struct mtd_info * mtd , loff_t ofs )
{
struct mtd_part * part = PART ( mtd ) ;
int res ;
ofs + = part - > offset ;
res = part - > master - > _block_markbad ( part - > master , ofs ) ;
ofs + = mtd - > offset ;
res = mtd - > parent - > _block_markbad ( mtd - > parent , ofs ) ;
if ( ! res )
mtd - > ecc_stats . badblocks + + ;
return res ;
}
static inline void free_partition ( struct mtd_part * p )
static inline void free_partition ( struct mtd_info * p )
{
kfree ( p - > mtd . name ) ;
kfree ( p - > name ) ;
kfree ( p ) ;
}
/*
* This function unregisters and destroy all slave MTD objects which are
* attached to the given master MTD object .
* attached to the given master MTD object , recursively .
*/
static int do_del_mtd_partitions ( struct mtd_info * master )
{
struct mtd_info * slave , * next ;
int ret , err = 0 ;
list_for_each_entry_safe ( slave , next , & master - > partitions , node ) {
if ( mtd_has_partitions ( slave ) )
del_mtd_partitions ( slave ) ;
debug ( " Deleting %s MTD partition \n " , slave - > name ) ;
ret = del_mtd_device ( slave ) ;
if ( ret < 0 ) {
printf ( " Error when deleting partition \" %s \" (%d) \n " ,
slave - > name , ret ) ;
err = ret ;
continue ;
}
list_del ( & slave - > node ) ;
free_partition ( slave ) ;
}
return err ;
}
int del_mtd_partitions ( struct mtd_info * master )
{
struct mtd_part * slave , * next ;
int ret , err = 0 ;
int ret ;
debug ( " Deleting MTD partitions on \" %s \" : \n " , master - > name ) ;
mutex_lock ( & mtd_partitions_mutex ) ;
list_for_each_entry_safe ( slave , next , & mtd_partitions , list )
if ( slave - > master = = master ) {
ret = del_mtd_device ( & slave - > mtd ) ;
if ( ret < 0 ) {
err = ret ;
continue ;
}
list_del ( & slave - > list ) ;
free_partition ( slave ) ;
}
ret = do_del_mtd_partitions ( master ) ;
mutex_unlock ( & mtd_partitions_mutex ) ;
return err ;
return ret ;
}
static struct mtd_part * allocate_partition ( struct mtd_info * master ,
const struct mtd_partition * part , int partno ,
uint64_t cur_offset )
static struct mtd_info * allocate_partition ( struct mtd_info * master ,
const struct mtd_partition * part ,
int partno , uint64_t cur_offset )
{
struct mtd_part * slave ;
struct mtd_info * slave ;
char * name ;
/* allocate the partition structure */
@ -609,85 +574,87 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
}
/* set up the MTD object for this partition */
slave - > mtd . type = master - > type ;
slave - > mtd . flags = master - > flags & ~ part - > mask_flags ;
slave - > mtd . size = part - > size ;
slave - > mtd . writesize = master - > writesize ;
slave - > mtd . writebufsize = master - > writebufsize ;
slave - > mtd . oobsize = master - > oobsize ;
slave - > mtd . oobavail = master - > oobavail ;
slave - > mtd . subpage_sft = master - > subpage_sft ;
slave - > mtd . name = name ;
slave - > mtd . owner = master - > owner ;
slave - > type = master - > type ;
slave - > flags = master - > flags & ~ part - > mask_flags ;
slave - > size = part - > size ;
slave - > writesize = master - > writesize ;
slave - > writebufsize = master - > writebufsize ;
slave - > oobsize = master - > oobsize ;
slave - > oobavail = master - > oobavail ;
slave - > subpage_sft = master - > subpage_sft ;
slave - > name = name ;
slave - > owner = master - > owner ;
# ifndef __UBOOT__
slave - > mtd . backing_dev_info = master - > backing_dev_info ;
slave - > backing_dev_info = master - > backing_dev_info ;
/* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
* to have the same data be in two different partitions .
*/
slave - > mtd . dev . parent = master - > dev . parent ;
slave - > dev . parent = master - > dev . parent ;
# endif
if ( master - > _read )
slave - > mtd . _read = part_read ;
slave - > _read = part_read ;
if ( master - > _write )
slave - > mtd . _write = part_write ;
slave - > _write = part_write ;
if ( master - > _panic_write )
slave - > mtd . _panic_write = part_panic_write ;
slave - > _panic_write = part_panic_write ;
# ifndef __UBOOT__
if ( master - > _point & & master - > _unpoint ) {
slave - > mtd . _point = part_point ;
slave - > mtd . _unpoint = part_unpoint ;
slave - > _point = part_point ;
slave - > _unpoint = part_unpoint ;
}
# endif
if ( master - > _get_unmapped_area )
slave - > mtd . _get_unmapped_area = part_get_unmapped_area ;
slave - > _get_unmapped_area = part_get_unmapped_area ;
if ( master - > _read_oob )
slave - > mtd . _read_oob = part_read_oob ;
slave - > _read_oob = part_read_oob ;
if ( master - > _write_oob )
slave - > mtd . _write_oob = part_write_oob ;
slave - > _write_oob = part_write_oob ;
if ( master - > _read_user_prot_reg )
slave - > mtd . _read_user_prot_reg = part_read_user_prot_reg ;
slave - > _read_user_prot_reg = part_read_user_prot_reg ;
if ( master - > _read_fact_prot_reg )
slave - > mtd . _read_fact_prot_reg = part_read_fact_prot_reg ;
slave - > _read_fact_prot_reg = part_read_fact_prot_reg ;
if ( master - > _write_user_prot_reg )
slave - > mtd . _write_user_prot_reg = part_write_user_prot_reg ;
slave - > _write_user_prot_reg = part_write_user_prot_reg ;
if ( master - > _lock_user_prot_reg )
slave - > mtd . _lock_user_prot_reg = part_lock_user_prot_reg ;
slave - > _lock_user_prot_reg = part_lock_user_prot_reg ;
if ( master - > _get_user_prot_info )
slave - > mtd . _get_user_prot_info = part_get_user_prot_info ;
slave - > _get_user_prot_info = part_get_user_prot_info ;
if ( master - > _get_fact_prot_info )
slave - > mtd . _get_fact_prot_info = part_get_fact_prot_info ;
slave - > _get_fact_prot_info = part_get_fact_prot_info ;
if ( master - > _sync )
slave - > mtd . _sync = part_sync ;
slave - > _sync = part_sync ;
# ifndef __UBOOT__
if ( ! partno & & ! master - > dev . class & & master - > _suspend & &
master - > _resume ) {
slave - > mtd . _suspend = part_suspend ;
slave - > mtd . _resume = part_resume ;
slave - > _suspend = part_suspend ;
slave - > _resume = part_resume ;
}
if ( master - > _writev )
slave - > mtd . _writev = part_writev ;
slave - > _writev = part_writev ;
# endif
if ( master - > _lock )
slave - > mtd . _lock = part_lock ;
slave - > _lock = part_lock ;
if ( master - > _unlock )
slave - > mtd . _unlock = part_unlock ;
slave - > _unlock = part_unlock ;
if ( master - > _is_locked )
slave - > mtd . _is_locked = part_is_locked ;
slave - > _is_locked = part_is_locked ;
if ( master - > _block_isreserved )
slave - > mtd . _block_isreserved = part_block_isreserved ;
slave - > _block_isreserved = part_block_isreserved ;
if ( master - > _block_isbad )
slave - > mtd . _block_isbad = part_block_isbad ;
slave - > _block_isbad = part_block_isbad ;
if ( master - > _block_markbad )
slave - > mtd . _block_markbad = part_block_markbad ;
slave - > mtd . _erase = part_erase ;
slave - > master = master ;
slave - > _block_markbad = part_block_markbad ;
slave - > _erase = part_erase ;
slave - > parent = master ;
slave - > offset = part - > offset ;
INIT_LIST_HEAD ( & slave - > partitions ) ;
INIT_LIST_HEAD ( & slave - > node ) ;
if ( slave - > offset = = MTDPART_OFS_APPEND )
slave - > offset = cur_offset ;
@ -703,41 +670,41 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
}
if ( slave - > offset = = MTDPART_OFS_RETAIN ) {
slave - > offset = cur_offset ;
if ( master - > size - slave - > offset > = slave - > mtd . size ) {
slave - > mtd . size = master - > size - slave - > offset
- slave - > mtd . size ;
if ( master - > size - slave - > offset > = slave - > size ) {
slave - > size = master - > size - slave - > offset
- slave - > size ;
} else {
debug ( " mtd partition \" %s \" doesn't have enough space: %#llx < %#llx, disabled \n " ,
part - > name , master - > size - slave - > offset ,
slave - > mtd . size ) ;
slave - > size ) ;
/* register to preserve ordering */
goto out_register ;
}
}
if ( slave - > mtd . size = = MTDPART_SIZ_FULL )
slave - > mtd . size = master - > size - slave - > offset ;
if ( slave - > size = = MTDPART_SIZ_FULL )
slave - > size = master - > size - slave - > offset ;
debug ( " 0x%012llx-0x%012llx : \" %s \" \n " , ( unsigned long long ) slave - > offset ,
( unsigned long long ) ( slave - > offset + slave - > mtd . size ) , slave - > mtd . name ) ;
( unsigned long long ) ( slave - > offset + slave - > size ) , slave - > name ) ;
/* let's do some sanity checks */
if ( slave - > offset > = master - > size ) {
/* let's register it anyway to preserve ordering */
slave - > offset = 0 ;
slave - > mtd . size = 0 ;
slave - > size = 0 ;
printk ( KERN_ERR " mtd: partition \" %s \" is out of reach -- disabled \n " ,
part - > name ) ;
goto out_register ;
}
if ( slave - > offset + slave - > mtd . size > master - > size ) {
slave - > mtd . size = master - > size - slave - > offset ;
if ( slave - > offset + slave - > size > master - > size ) {
slave - > size = master - > size - slave - > offset ;
printk ( KERN_WARNING " mtd: partition \" %s \" extends beyond the end of device \" %s \" -- size truncated to %#llx \n " ,
part - > name , master - > name , ( unsigned long long ) slave - > mtd . size ) ;
part - > name , master - > name , slave - > size ) ;
}
if ( master - > numeraseregions > 1 ) {
/* Deal with variable erase size stuff */
int i , max = master - > numeraseregions ;
u64 end = slave - > offset + slave - > mtd . size ;
u64 end = slave - > offset + slave - > size ;
struct mtd_erase_region_info * regions = master - > eraseregions ;
/* Find the first erase regions which is part of this
@ -750,44 +717,43 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
/* Pick biggest erasesize */
for ( ; i < max & & regions [ i ] . offset < end ; i + + ) {
if ( slave - > mtd . erasesize < regions [ i ] . erasesize ) {
slave - > mtd . erasesize = regions [ i ] . erasesize ;
}
if ( slave - > erasesize < regions [ i ] . erasesize )
slave - > erasesize = regions [ i ] . erasesize ;
}
BUG _ON( slave - > mtd . erasesize = = 0 ) ;
WARN _ON( slave - > erasesize = = 0 ) ;
} else {
/* Single erase size */
slave - > mtd . erasesize = master - > erasesize ;
slave - > erasesize = master - > erasesize ;
}
if ( ( slave - > mtd . flags & MTD_WRITEABLE ) & &
mtd_mod_by_eb ( slave - > offset , & slave - > mtd ) ) {
if ( ( slave - > flags & MTD_WRITEABLE ) & &
mtd_mod_by_eb ( slave - > offset , slave ) ) {
/* Doesn't start on a boundary of major erase size */
/* FIXME: Let it be writable if it is on a boundary of
* _minor_ erase size though */
slave - > mtd . flags & = ~ MTD_WRITEABLE ;
slave - > flags & = ~ MTD_WRITEABLE ;
printk ( KERN_WARNING " mtd: partition \" %s \" doesn't start on an erase block boundary -- force read-only \n " ,
part - > name ) ;
}
if ( ( slave - > mtd . flags & MTD_WRITEABLE ) & &
mtd_mod_by_eb ( slave - > mtd . size , & slave - > mtd ) ) {
slave - > mtd . flags & = ~ MTD_WRITEABLE ;
if ( ( slave - > flags & MTD_WRITEABLE ) & &
mtd_mod_by_eb ( slave - > size , slave ) ) {
slave - > flags & = ~ MTD_WRITEABLE ;
printk ( KERN_WARNING " mtd: partition \" %s \" doesn't end on an erase block -- force read-only \n " ,
part - > name ) ;
}
slave - > mtd . ecclayout = master - > ecclayout ;
slave - > mtd . ecc_step_size = master - > ecc_step_size ;
slave - > mtd . ecc_strength = master - > ecc_strength ;
slave - > mtd . bitflip_threshold = master - > bitflip_threshold ;
slave - > ecclayout = master - > ecclayout ;
slave - > ecc_step_size = master - > ecc_step_size ;
slave - > ecc_strength = master - > ecc_strength ;
slave - > bitflip_threshold = master - > bitflip_threshold ;
if ( master - > _block_isbad ) {
uint64_t offs = 0 ;
while ( offs < slave - > mtd . size ) {
while ( offs < slave - > size ) {
if ( mtd_block_isbad ( master , offs + slave - > offset ) )
slave - > mtd . ecc_stats . badblocks + + ;
offs + = slave - > mtd . erasesize ;
slave - > ecc_stats . badblocks + + ;
offs + = slave - > erasesize ;
}
}
@ -800,7 +766,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
long long offset , long long length )
{
struct mtd_partition part ;
struct mtd_part * p , * new ;
struct mtd_info * p , * new ;
uint64_t start , end ;
int ret = 0 ;
@ -829,21 +795,20 @@ int mtd_add_partition(struct mtd_info *master, const char *name,
end = offset + length ;
mutex_lock ( & mtd_partitions_mutex ) ;
list_for_each_entry ( p , & mtd_partitions , list )
if ( p - > master = = master ) {
if ( ( start > = p - > offset ) & &
( start < ( p - > offset + p - > mtd . size ) ) )
goto err_inv ;
if ( ( end > = p - > offset ) & &
( end < ( p - > offset + p - > mtd . size ) ) )
goto err_inv ;
}
list_for_each_entry ( p , & master - > partitions , node ) {
if ( start > = p - > offset & &
( start < ( p - > offset + p - > size ) ) )
goto err_inv ;
if ( end > = p - > offset & &
( end < ( p - > offset + p - > size ) ) )
goto err_inv ;
}
list_add ( & new - > list , & mtd_ partitions) ;
list_add_tail ( & new - > node , & master - > partitions ) ;
mutex_unlock ( & mtd_partitions_mutex ) ;
add_mtd_device ( & new - > mtd ) ;
add_mtd_device ( new ) ;
return ret ;
err_inv :
@ -855,18 +820,17 @@ EXPORT_SYMBOL_GPL(mtd_add_partition);
int mtd_del_partition ( struct mtd_info * master , int partno )
{
struct mtd_part * slave , * next ;
struct mtd_info * slave , * next ;
int ret = - EINVAL ;
mutex_lock ( & mtd_partitions_mutex ) ;
list_for_each_entry_safe ( slave , next , & mtd_partitions , list )
if ( ( slave - > master = = master ) & &
( slave - > mtd . index = = partno ) ) {
ret = del_mtd_device ( & slave - > mtd ) ;
list_for_each_entry_safe ( slave , next , & master - > partitions , node )
if ( slave - > index = = partno ) {
ret = del_mtd_device ( slave ) ;
if ( ret < 0 )
break ;
list_del ( & slave - > list ) ;
list_del ( & slave - > node ) ;
free_partition ( slave ) ;
break ;
}
@ -890,20 +854,10 @@ int add_mtd_partitions(struct mtd_info *master,
const struct mtd_partition * parts ,
int nbparts )
{
struct mtd_part * slave ;
struct mtd_info * slave ;
uint64_t cur_offset = 0 ;
int i ;
# ifdef __UBOOT__
/*
* Need to init the list here , since LIST_INIT ( ) does not
* work on platforms where relocation has problems ( like MIPS
* & PPC ) .
*/
if ( mtd_partitions . next = = NULL )
INIT_LIST_HEAD ( & mtd_partitions ) ;
# endif
debug ( " Creating %d MTD partitions on \" %s \" : \n " , nbparts , master - > name ) ;
for ( i = 0 ; i < nbparts ; i + + ) {
@ -912,12 +866,12 @@ int add_mtd_partitions(struct mtd_info *master,
return PTR_ERR ( slave ) ;
mutex_lock ( & mtd_partitions_mutex ) ;
list_add ( & slave - > list , & mtd_ partitions) ;
list_add_tail ( & slave - > node , & master - > partitions ) ;
mutex_unlock ( & mtd_partitions_mutex ) ;
add_mtd_device ( & slave - > mtd ) ;
add_mtd_device ( slave ) ;
cur_offset = slave - > offset + slave - > mtd . size ;
cur_offset = slave - > offset + slave - > size ;
}
return 0 ;
@ -1020,29 +974,12 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
}
# endif
int mtd_is_partition ( const struct mtd_info * mtd )
{
struct mtd_part * part ;
int ispart = 0 ;
mutex_lock ( & mtd_partitions_mutex ) ;
list_for_each_entry ( part , & mtd_partitions , list )
if ( & part - > mtd = = mtd ) {
ispart = 1 ;
break ;
}
mutex_unlock ( & mtd_partitions_mutex ) ;
return ispart ;
}
EXPORT_SYMBOL_GPL ( mtd_is_partition ) ;
/* Returns the size of the entire flash chip */
uint64_t mtd_get_device_size ( const struct mtd_info * mtd )
{
if ( ! mtd_is_partition ( mtd ) )
return mtd - > size ;
if ( mtd_is_partition ( mtd ) )
return mtd - > parent - > size ;
return PART ( mtd ) - > master - > size ;
return mtd - > size ;
}
EXPORT_SYMBOL_GPL ( mtd_get_device_size ) ;