diff options
| author | Christian Hitz <christian.hitz@aizo.com> | 2011-10-12 09:32:04 +0200 | 
|---|---|---|
| committer | Scott Wood <scottwood@freescale.com> | 2012-01-26 16:09:02 -0600 | 
| commit | ff8a8a718341e42af8642f01ce630d4a77c58f82 (patch) | |
| tree | 8ac126183a33a36fbd818dc05ee01dc3aa629751 /drivers/mtd/nand/nand_bbt.c | |
| parent | 2a8e0fc8b3dc31a3c571e439fbf04b882c8986be (diff) | |
| download | olio-uboot-2014.01-ff8a8a718341e42af8642f01ce630d4a77c58f82.tar.xz olio-uboot-2014.01-ff8a8a718341e42af8642f01ce630d4a77c58f82.zip | |
nand: Merge changes to BBT from Linux nand driver
[backport from linux commit 02f8c6aee8df3cdc935e9bdd4f2d020306035dbe]
This patch synchronizes the nand driver with the Linux 3.0 state.
Signed-off-by: Christian Hitz <christian.hitz@aizo.com>
Cc: Scott Wood <scottwood@freescale.com>
Signed-off-by: Scott Wood <scottwood@freescale.com>
Diffstat (limited to 'drivers/mtd/nand/nand_bbt.c')
| -rw-r--r-- | drivers/mtd/nand/nand_bbt.c | 427 | 
1 files changed, 328 insertions, 99 deletions
| diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c index ded652be3..2b730e09c 100644 --- a/drivers/mtd/nand/nand_bbt.c +++ b/drivers/mtd/nand/nand_bbt.c @@ -13,27 +13,36 @@   * Description:   *   * When nand_scan_bbt is called, then it tries to find the bad block table - * depending on the options in the bbt descriptor(s). If a bbt is found - * then the contents are read and the memory based bbt is created. If a - * mirrored bbt is selected then the mirror is searched too and the - * versions are compared. If the mirror has a greater version number - * than the mirror bbt is used to build the memory based bbt. + * depending on the options in the BBT descriptor(s). If no flash based BBT + * (NAND_USE_FLASH_BBT) is specified then the device is scanned for factory + * marked good / bad blocks. This information is used to create a memory BBT. + * Once a new bad block is discovered then the "factory" information is updated + * on the device. + * If a flash based BBT is specified then the function first tries to find the + * BBT on flash. If a BBT is found then the contents are read and the memory + * based BBT is created. If a mirrored BBT is selected then the mirror is + * searched too and the versions are compared. If the mirror has a greater + * version number than the mirror BBT is used to build the memory based BBT.   * If the tables are not versioned, then we "or" the bad block information. - * If one of the bbt's is out of date or does not exist it is (re)created. - * If no bbt exists at all then the device is scanned for factory marked + * If one of the BBTs is out of date or does not exist it is (re)created. + * If no BBT exists at all then the device is scanned for factory marked   * good / bad blocks and the bad block tables are created.   * - * For manufacturer created bbts like the one found on M-SYS DOC devices - * the bbt is searched and read but never created + * For manufacturer created BBTs like the one found on M-SYS DOC devices + * the BBT is searched and read but never created   * - * The autogenerated bad block table is located in the last good blocks + * The auto generated bad block table is located in the last good blocks   * of the device. The table is mirrored, so it can be updated eventually. - * The table is marked in the oob area with an ident pattern and a version - * number which indicates which of both tables is more up to date. + * The table is marked in the OOB area with an ident pattern and a version + * number which indicates which of both tables is more up to date. If the NAND + * controller needs the complete OOB area for the ECC information then the + * option NAND_USE_FLASH_BBT_NO_OOB should be used: it moves the ident pattern + * and the version byte into the data area and the OOB area will remain + * untouched.   *   * The table uses 2 bits per block - * 11b:	block is good - * 00b:	block is factory marked bad + * 11b:		block is good + * 00b:		block is factory marked bad   * 01b, 10b:	block is marked bad due to wear   *   * The memory bad block table uses the following scheme: @@ -55,9 +64,21 @@  #include <linux/mtd/compat.h>  #include <linux/mtd/mtd.h>  #include <linux/mtd/nand.h> +#include <linux/mtd/nand_ecc.h> +#include <linux/bitops.h>  #include <asm/errno.h> +static int check_pattern_no_oob(uint8_t *buf, struct nand_bbt_descr *td) +{ +	int ret; + +	ret = memcmp(buf, td->pattern, td->len); +	if (!ret) +		return ret; +	return -1; +} +  /**   * check_pattern - [GENERIC] check if a pattern is in the buffer   * @buf:	the buffer to search @@ -76,6 +97,9 @@ static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_desc  	int i, end = 0;  	uint8_t *p = buf; +	if (td->options & NAND_BBT_NO_OOB) +		return check_pattern_no_oob(buf, td); +  	end = paglen + td->offs;  	if (td->options & NAND_BBT_SCANEMPTY) {  		for (i = 0; i < end; i++) { @@ -91,6 +115,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; @@ -122,36 +168,74 @@ 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;  }  /** + * add_marker_len - compute the length of the marker in data area + * @td:		BBT descriptor used for computation + * + * The length will be 0 if the markeris located in OOB area. + */ +static u32 add_marker_len(struct nand_bbt_descr *td) +{ +	u32 len; + +	if (!(td->options & NAND_BBT_NO_OOB)) +		return 0; + +	len = td->len; +	if (td->options & NAND_BBT_VERSION) +		len++; +	return len; +} + +/**   * read_bbt - [GENERIC] Read the bad block table starting from page   * @mtd:	MTD device structure   * @buf:	temporary buffer   * @page:	the starting page   * @num:	the number of bbt descriptors to read - * @bits:	number of bits per block + * @td:		the bbt describtion table   * @offs:	offset in the memory table - * @reserved_block_code:	Pattern to identify reserved blocks   *   * Read the bad block table starting from page.   *   */  static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num, -		    int bits, int offs, int reserved_block_code) +		struct nand_bbt_descr *td, int offs)  {  	int res, i, j, act = 0;  	struct nand_chip *this = mtd->priv;  	size_t retlen, len, totlen;  	loff_t from; +	int bits = td->options & NAND_BBT_NRBITS_MSK;  	uint8_t msk = (uint8_t) ((1 << bits) - 1); +	u32 marker_len; +	int reserved_block_code = td->reserved_block_code;  	totlen = (num * bits) >> 3; +	marker_len = add_marker_len(td);  	from = ((loff_t) page) << this->page_shift;  	while (totlen) {  		len = min(totlen, (size_t) (1 << this->bbt_erase_shift)); +		if (marker_len) { +			/* +			 * In case the BBT marker is not in the OOB area it +			 * will be just in the first page. +			 */ +			len -= marker_len; +			from += marker_len; +			marker_len = 0; +		}  		res = mtd->read(mtd, from, len, &retlen, buf);  		if (res < 0) {  			if (retlen != len) { @@ -170,9 +254,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  					continue;  				if (reserved_block_code && (tmp == reserved_block_code)) {  					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%012llx\n", -						(loff_t)((offs << 2) + -						(act >> 1)) << -						this->bbt_erase_shift); +					       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);  					mtd->ecc_stats.bbtblocks++;  					continue; @@ -180,8 +262,7 @@ static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,  				/* Leave it for now, if its matured we can move this  				 * message to MTD_DEBUG_LEVEL0 */  				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%012llx\n", -					(loff_t)((offs << 2) + (act >> 1)) << -					this->bbt_erase_shift); +				       (loff_t)((offs << 2) + (act >> 1)) << this->bbt_erase_shift);  				/* Factory marked bad or worn out ? */  				if (tmp == 0)  					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06); @@ -211,20 +292,21 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  {  	struct nand_chip *this = mtd->priv;  	int res = 0, i; -	int bits; -	bits = td->options & NAND_BBT_NRBITS_MSK;  	if (td->options & NAND_BBT_PERCHIP) {  		int offs = 0;  		for (i = 0; i < this->numchips; i++) {  			if (chip == -1 || chip == i) -				res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code); +				res = read_bbt(mtd, buf, td->pages[i], +					this->chipsize >> this->bbt_erase_shift, +					td, offs);  			if (res)  				return res;  			offs += this->chipsize >> (this->bbt_erase_shift + 2);  		}  	} else { -		res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code); +		res = read_bbt(mtd, buf, td->pages[0], +				mtd->size >> this->bbt_erase_shift, td, 0);  		if (res)  			return res;  	} @@ -232,21 +314,64 @@ static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  }  /* + * BBT marker is in the first page, no OOB. + */ +static int scan_read_raw_data(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +			 struct nand_bbt_descr *td) +{ +	size_t retlen; +	size_t len; + +	len = td->len; +	if (td->options & NAND_BBT_VERSION) +		len++; + +	return mtd->read(mtd, offs, len, &retlen, buf); +} + +/*   * Scan read raw data from flash   */ -static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +static int scan_read_raw_oob(struct mtd_info *mtd, uint8_t *buf, loff_t offs,  			 size_t len)  {  	struct mtd_oob_ops ops; +	int res;  	ops.mode = MTD_OOB_RAW;  	ops.ooboffs = 0;  	ops.ooblen = mtd->oobsize; -	ops.oobbuf = buf; -	ops.datbuf = buf; -	ops.len = len; -	return mtd->read_oob(mtd, offs, &ops); + +	while (len > 0) { +		if (len <= mtd->writesize) { +			ops.oobbuf = buf + len; +			ops.datbuf = buf; +			ops.len = len; +			return mtd->read_oob(mtd, offs, &ops); +		} else { +			ops.oobbuf = buf + mtd->writesize; +			ops.datbuf = buf; +			ops.len = mtd->writesize; +			res = mtd->read_oob(mtd, offs, &ops); + +			if (res) +				return res; +		} + +		buf += mtd->oobsize + mtd->writesize; +		len -= mtd->writesize; +	} +	return 0; +} + +static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs, +			 size_t len, struct nand_bbt_descr *td) +{ +	if (td->options & NAND_BBT_NO_OOB) +		return scan_read_raw_data(mtd, buf, offs, td); +	else +		return scan_read_raw_oob(mtd, buf, offs, len);  }  /* @@ -267,6 +392,15 @@ static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,  	return mtd->write_oob(mtd, offs, &ops);  } +static u32 bbt_get_ver_offs(struct mtd_info *mtd, struct nand_bbt_descr *td) +{ +	u32 ver_offs = td->veroffs; + +	if (!(td->options & NAND_BBT_NO_OOB)) +		ver_offs += mtd->writesize; +	return ver_offs; +} +  /**   * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page   * @mtd:	MTD device structure @@ -285,18 +419,18 @@ static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,  	/* Read the primary version, if available */  	if (td->options & NAND_BBT_VERSION) { -		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << -				this->page_shift, mtd->writesize); -		td->version[0] = buf[mtd->writesize + td->veroffs]; +		scan_read_raw(mtd, buf, (loff_t)td->pages[0] << this->page_shift, +			      mtd->writesize, td); +		td->version[0] = buf[bbt_get_ver_offs(mtd, td)];  		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",  		       td->pages[0], td->version[0]);  	}  	/* Read the mirror version, if available */  	if (md && (md->options & NAND_BBT_VERSION)) { -		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << -				this->page_shift, mtd->writesize); -		md->version[0] = buf[mtd->writesize + md->veroffs]; +		scan_read_raw(mtd, buf, (loff_t)md->pages[0] << this->page_shift, +			      mtd->writesize, td); +		md->version[0] = buf[bbt_get_ver_offs(mtd, md)];  		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",  		       md->pages[0], md->version[0]);  	} @@ -312,7 +446,7 @@ static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,  {  	int ret, j; -	ret = scan_read_raw(mtd, buf, offs, readlen); +	ret = scan_read_raw_oob(mtd, buf, offs, readlen);  	if (ret)  		return ret; @@ -376,16 +510,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  	loff_t from;  	size_t readlen; -	MTDDEBUG (MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n"); +	MTDDEBUG(MTD_DEBUG_LEVEL0, "Scanning device for bad blocks\n");  	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 */ @@ -415,9 +547,14 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		from = (loff_t)startblock << (this->bbt_erase_shift - 1);  	} +	if (this->options & NAND_BBT_SCANLASTPAGE) +		from += mtd->erasesize - (mtd->writesize * len); +  	for (i = startblock; i < numblocks;) {  		int ret; +		BUG_ON(bd->options & NAND_BBT_NO_OOB); +  		if (bd->options & NAND_BBT_SCANALLPAGES)  			ret = scan_block_full(mtd, bd, from, buf, readlen,  					      scanlen, len); @@ -429,7 +566,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (ret) {  			this->bbt[i >> 3] |= 0x03 << (i & 0x6); -			MTDDEBUG (MTD_DEBUG_LEVEL0, +			MTDDEBUG(MTD_DEBUG_LEVEL0,  				  "Bad eraseblock %d at 0x%012llx\n",  				  i >> 1, (unsigned long long)from);  			mtd->ecc_stats.badblocks++; @@ -497,11 +634,12 @@ static int search_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr  			loff_t offs = (loff_t)actblock << this->bbt_erase_shift;  			/* Read first page */ -			scan_read_raw(mtd, buf, offs, mtd->writesize); +			scan_read_raw(mtd, buf, offs, mtd->writesize, td);  			if (!check_pattern(buf, scanlen, mtd->writesize, td)) {  				td->pages[i] = actblock << blocktopage;  				if (td->options & NAND_BBT_VERSION) { -					td->version[i] = buf[mtd->writesize + td->veroffs]; +					offs = bbt_get_ver_offs(mtd, td); +					td->version[i] = buf[offs];  				}  				break;  			} @@ -685,12 +823,26 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  			memset(&buf[offs], 0xff, (size_t) (numblocks >> sft));  			ooboffs = len + (pageoffs * mtd->oobsize); +		} else if (td->options & NAND_BBT_NO_OOB) { +			ooboffs = 0; +			offs = td->len; +			/* the version byte */ +			if (td->options & NAND_BBT_VERSION) +				offs++; +			/* Calc length */ +			len = (size_t) (numblocks >> sft); +			len += offs; +			/* Make it page aligned ! */ +			len = ALIGN(len, mtd->writesize); +			/* Preset the buffer with 0xff */ +			memset(buf, 0xff, len); +			/* Pattern is located at the begin of first page */ +			memcpy(buf, td->pattern, td->len);  		} else {  			/* Calc length */  			len = (size_t) (numblocks >> sft);  			/* Make it page aligned ! */ -			len = (len + (mtd->writesize - 1)) & -				~(mtd->writesize - 1); +			len = ALIGN(len, mtd->writesize);  			/* Preset the buffer with 0xff */  			memset(buf, 0xff, len +  			       (len >> this->page_shift)* mtd->oobsize); @@ -724,13 +876,14 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,  		if (res < 0)  			goto outerr; -		res = scan_write_bbt(mtd, to, len, buf, &buf[len]); +		res = scan_write_bbt(mtd, to, len, buf, +				td->options & NAND_BBT_NO_OOB ? NULL : +				&buf[len]);  		if (res < 0)  			goto outerr; -		printk(KERN_DEBUG "Bad block table written to 0x%012llx, " -		       "version 0x%02X\n", (unsigned long long)to, -		       td->version[chip]); +		printk(KERN_DEBUG "Bad block table written to 0x%012llx, version " +		       "0x%02X\n", (unsigned long long)to, td->version[chip]);  		/* Mark it as used */  		td->pages[chip] = page; @@ -791,7 +944,7 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  		rd2 = NULL;  		/* Per chip or per device ? */  		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1; -		/* Mirrored table avilable ? */ +		/* Mirrored table available ? */  		if (md) {  			if (td->pages[i] == -1 && md->pages[i] == -1) {  				writeops = 0x03; @@ -845,7 +998,8 @@ static int check_create(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc  			continue;  		/* Create the table in memory by scanning the chip(s) */ -		create_bbt(mtd, buf, bd, chipsel); +		if (!(this->options & NAND_CREATE_EMPTY_BBT)) +			create_bbt(mtd, buf, bd, chipsel);  		td->version[i] = 1;  		if (md) @@ -910,8 +1064,7 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  			newval = oldval | (0x2 << (block & 0x06));  			this->bbt[(block >> 3)] = newval;  			if ((oldval != newval) && td->reserved_block_code) -				nand_update_bbt(mtd, (loff_t)block << -					(this->bbt_erase_shift - 1)); +				nand_update_bbt(mtd, (loff_t)block << (this->bbt_erase_shift - 1));  			continue;  		}  		update = 0; @@ -932,9 +1085,56 @@ static void mark_bbt_region(struct mtd_info *mtd, struct nand_bbt_descr *td)  		   new ones have been marked, then we need to update the stored  		   bbts.  This should only happen once. */  		if (update && td->reserved_block_code) -			nand_update_bbt(mtd, (loff_t)(block - 2) << -				(this->bbt_erase_shift - 1)); +			nand_update_bbt(mtd, (loff_t)(block - 2) << (this->bbt_erase_shift - 1)); +	} +} + +/** + * verify_bbt_descr - verify the bad block description + * @mtd:	MTD device structure + * @bd:		the table to verify + * + * This functions performs a few sanity checks on the bad block description + * table. + */ +static void verify_bbt_descr(struct mtd_info *mtd, struct nand_bbt_descr *bd) +{ +	struct nand_chip *this = mtd->priv; +	u32 pattern_len; +	u32 bits; +	u32 table_size; + +	if (!bd) +		return; + +	pattern_len = bd->len; +	bits = bd->options & NAND_BBT_NRBITS_MSK; + +	BUG_ON((this->options & NAND_USE_FLASH_BBT_NO_OOB) && +			!(this->options & NAND_USE_FLASH_BBT)); +	BUG_ON(!bits); + +	if (bd->options & NAND_BBT_VERSION) +		pattern_len++; + +	if (bd->options & NAND_BBT_NO_OOB) { +		BUG_ON(!(this->options & NAND_USE_FLASH_BBT)); +		BUG_ON(!(this->options & NAND_USE_FLASH_BBT_NO_OOB)); +		BUG_ON(bd->offs); +		if (bd->options & NAND_BBT_VERSION) +			BUG_ON(bd->veroffs != bd->len); +		BUG_ON(bd->options & NAND_BBT_SAVECONTENT);  	} + +	if (bd->options & NAND_BBT_PERCHIP) +		table_size = this->chipsize >> this->bbt_erase_shift; +	else +		table_size = mtd->size >> this->bbt_erase_shift; +	table_size >>= 3; +	table_size *= bits; +	if (bd->options & NAND_BBT_NO_OOB) +		table_size += pattern_len; +	BUG_ON(table_size > (1 << this->bbt_erase_shift));  }  /** @@ -978,6 +1178,8 @@ int nand_scan_bbt(struct mtd_info *mtd, struct nand_bbt_descr *bd)  		}  		return res;  	} +	verify_bbt_descr(mtd, td); +	verify_bbt_descr(mtd, md);  	/* Allocate a temporary buffer for one eraseblock incl. oob */  	len = (1 << this->bbt_erase_shift); @@ -1073,34 +1275,6 @@ 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, -	.len = 1, -	.pattern = scan_ff_pattern -}; - -static struct nand_bbt_descr largepage_flashbased = { -	.options = NAND_BBT_SCAN2NDPAGE, -	.offs = 0, -	.len = 2, -	.pattern = scan_ff_pattern -}; -  static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };  static struct nand_bbt_descr agand_flashbased = { @@ -1135,6 +1309,59 @@ static struct nand_bbt_descr bbt_mirror_descr = {  	.pattern = mirror_pattern  }; +static struct nand_bbt_descr bbt_main_no_bbt_descr = { +	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE +		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP +		| NAND_BBT_NO_OOB, +	.len = 4, +	.veroffs = 4, +	.maxblocks = 4, +	.pattern = bbt_pattern +}; + +static struct nand_bbt_descr bbt_mirror_no_bbt_descr = { +	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE +		| NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP +		| NAND_BBT_NO_OOB, +	.len = 4, +	.veroffs = 4, +	.maxblocks = 4, +	.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. + * + */ +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 @@ -1168,20 +1395,22 @@ int nand_default_bbt(struct mtd_info *mtd)  	if (this->options & NAND_USE_FLASH_BBT) {  		/* Use the default pattern descriptors */  		if (!this->bbt_td) { -			this->bbt_td = &bbt_main_descr; -			this->bbt_md = &bbt_mirror_descr; -		} -		if (!this->badblock_pattern) { -			this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased; +			if (this->options & NAND_USE_FLASH_BBT_NO_OOB) { +				this->bbt_td = &bbt_main_no_bbt_descr; +				this->bbt_md = &bbt_mirror_no_bbt_descr; +			} else { +				this->bbt_td = &bbt_main_descr; +				this->bbt_md = &bbt_mirror_descr; +			}  		}  	} 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);  } @@ -1202,8 +1431,8 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)  	block = (int)(offs >> (this->bbt_erase_shift - 1));  	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03; -	MTDDEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: " -	          "(block %d) 0x%02x\n", (unsigned int)offs, res, block >> 1); +	MTDDEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n", +	      (unsigned int)offs, block >> 1, res);  	switch ((int)res) {  	case 0x00: |