diff options
Diffstat (limited to 'drivers/mtd/nand/nand_bbt.c')
| -rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 103 | 
1 files changed, 75 insertions, 28 deletions
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ad97c0ce73b..5fedf4a74f1 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -55,7 +55,6 @@  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h>  #include <linux/mtd/nand_ecc.h> -#include <linux/mtd/compatmac.h>  #include <linux/bitops.h>  #include <linux/delay.h>  #include <linux/vmalloc.h> @@ -93,6 +92,28 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc  			return -1;  	} +	/* Check both positions 1 and 6 for pattern? */ +	if (td->options & NAND_BBT_SCANBYTE1AND6) { +		if (td->options & NAND_BBT_SCANEMPTY) { +			p += td->len; +			end += NAND_SMALL_BADBLOCK_POS - td->offs; +			/* Check region between positions 1 and 6 */ +			for (i = 0; i < NAND_SMALL_BADBLOCK_POS - td->offs - td->len; +					i++) { +				if (*p++ != 0xff) +					return -1; +			} +		} +		else { +			p += NAND_SMALL_BADBLOCK_POS - td->offs; +		} +		/* Compare the pattern */ +		for (i = 0; i < td->len; i++) { +			if (p[i] != td->pattern[i]) +				return -1; +		} +	} +  	if (td->options & NAND_BBT_SCANEMPTY) {  		p += td->len;  		end += td->len; @@ -124,6 +145,13 @@ static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td)  		if (p[td->offs + i] != td->pattern[i])  			return -1;  	} +	/* Need to check location 1 AND 6? */ +	if (td->options & NAND_BBT_SCANBYTE1AND6) { +		for (i = 0; i < td->len; i++) { +			if (p[NAND_SMALL_BADBLOCK_POS + i] != td->pattern[i]) +				return -1; +		} +	}  	return 0;  } @@ -397,12 +425,10 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	if (bd->options & NAND_BBT_SCANALLPAGES)  		len = 1 << (this->bbt_erase_shift - this->page_shift); -	else { -		if (bd->options & NAND_BBT_SCAN2NDPAGE) -			len = 2; -		else -			len = 1; -	} +	else if (bd->options & NAND_BBT_SCAN2NDPAGE) +		len = 2; +	else +		len = 1;  	if (!(bd->options & NAND_BBT_SCANEMPTY)) {  		/* We need only read few bytes from the OOB area */ @@ -432,7 +458,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		from = (loff_t)startblock << (this->bbt_erase_shift - 1);  	} -	if (this->options & NAND_BB_LAST_PAGE) +	if (this->options & NAND_BBT_SCANLASTPAGE)  		from += mtd->erasesize - (mtd->writesize * len);  	for (i = startblock; i < numblocks;) { @@ -1092,30 +1118,16 @@ int nand_update_bbt(struct mtd_info *mtd, loff_t offs)   * while scanning a device for factory marked good / bad blocks. */  static uint8_t scan_ff_pattern[] = { 0xff, 0xff }; -static struct nand_bbt_descr smallpage_memorybased = { -	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 5, -	.len = 1, -	.pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr largepage_memorybased = { -	.options = 0, -	.offs = 0, -	.len = 2, -	.pattern = scan_ff_pattern -}; -  static struct nand_bbt_descr smallpage_flashbased = {  	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 5, +	.offs = NAND_SMALL_BADBLOCK_POS,  	.len = 1,  	.pattern = scan_ff_pattern  };  static struct nand_bbt_descr largepage_flashbased = {  	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 0, +	.offs = NAND_LARGE_BADBLOCK_POS,  	.len = 2,  	.pattern = scan_ff_pattern  }; @@ -1154,6 +1166,43 @@ static struct nand_bbt_descr bbt_mirror_descr = {  	.pattern = mirror_pattern  }; +#define BBT_SCAN_OPTIONS (NAND_BBT_SCANLASTPAGE | NAND_BBT_SCAN2NDPAGE | \ +		NAND_BBT_SCANBYTE1AND6) +/** + * nand_create_default_bbt_descr - [Internal] Creates a BBT descriptor structure + * @this:	NAND chip to create descriptor for + * + * This function allocates and initializes a nand_bbt_descr for BBM detection + * based on the properties of "this". The new descriptor is stored in + * this->badblock_pattern. Thus, this->badblock_pattern should be NULL when + * passed to this function. + * + * TODO: Handle other flags, replace other static structs + *        (e.g. handle NAND_BBT_FLASH for flash-based BBT, + *             replace smallpage_flashbased) + * + */ +static int nand_create_default_bbt_descr(struct nand_chip *this) +{ +	struct nand_bbt_descr *bd; +	if (this->badblock_pattern) { +		printk(KERN_WARNING "BBT descr already allocated; not replacing.\n"); +		return -EINVAL; +	} +	bd = kzalloc(sizeof(*bd), GFP_KERNEL); +	if (!bd) { +		printk(KERN_ERR "nand_create_default_bbt_descr: Out of memory\n"); +		return -ENOMEM; +	} +	bd->options = this->options & BBT_SCAN_OPTIONS; +	bd->offs = this->badblockpos; +	bd->len = (this->options & NAND_BUSWIDTH_16) ? 2 : 1; +	bd->pattern = scan_ff_pattern; +	bd->options |= NAND_BBT_DYNAMICSTRUCT; +	this->badblock_pattern = bd; +	return 0; +} +  /**   * nand_default_bbt - [NAND Interface] Select a default bad block table for the device   * @mtd:	MTD device structure @@ -1196,10 +1245,8 @@ int nand_default_bbt(struct mtd_info *mtd)  	} else {  		this->bbt_td = NULL;  		this->bbt_md = NULL; -		if (!this->badblock_pattern) { -			this->badblock_pattern = (mtd->writesize > 512) ? -			    &largepage_memorybased : &smallpage_memorybased; -		} +		if (!this->badblock_pattern) +			nand_create_default_bbt_descr(this);  	}  	return nand_scan_bbt(mtd, this->badblock_pattern);  }  |