diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/mtd/nand/nand_base.c | 46 | 
1 files changed, 31 insertions, 15 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 05f8243ed1d3..13a56d3e8aec 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -392,15 +392,23 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)   * @ofs: offset from device start   *   * This is the default implementation, which can be overridden by a hardware - * specific driver. + * specific driver. We try operations in the following order, according to our + * bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): + *  (1) erase the affected block, to allow OOB marker to be written cleanly + *  (2) update in-memory BBT + *  (3) write bad block marker to OOB area of affected block + *  (4) update flash-based BBT + * Note that we retain the first error encountered in (3) or (4), finish the + * procedures, and dump the error in the end.  */  static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  {  	struct nand_chip *chip = mtd->priv;  	uint8_t buf[2] = { 0, 0 }; -	int block, ret, i = 0; +	int block, res, ret = 0, i = 0; +	int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); -	if (!(chip->bbt_options & NAND_BBT_USE_FLASH)) { +	if (write_oob) {  		struct erase_info einfo;  		/* Attempt erase before marking OOB */ @@ -413,23 +421,17 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  	/* Get block number */  	block = (int)(ofs >> chip->bbt_erase_shift); +	/* Mark block bad in memory-based BBT */  	if (chip->bbt)  		chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1); -	/* Do we have a flash based bad block table? */ -	if (chip->bbt_options & NAND_BBT_USE_FLASH) -		ret = nand_update_bbt(mtd, ofs); -	else { +	/* Write bad block marker to OOB */ +	if (write_oob) {  		struct mtd_oob_ops ops;  		loff_t wr_ofs = ofs;  		nand_get_device(chip, mtd, FL_WRITING); -		/* -		 * Write to first/last page(s) if necessary. If we write to more -		 * than one location, the first error encountered quits the -		 * procedure. -		 */  		ops.datbuf = NULL;  		ops.oobbuf = buf;  		ops.ooboffs = chip->badblockpos; @@ -441,18 +443,28 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)  		}  		ops.mode = MTD_OPS_PLACE_OOB; +		/* Write to first/last page(s) if necessary */  		if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)  			wr_ofs += mtd->erasesize - mtd->writesize;  		do { -			ret = nand_do_write_oob(mtd, wr_ofs, &ops); +			res = nand_do_write_oob(mtd, wr_ofs, &ops); +			if (!ret) +				ret = res;  			i++;  			wr_ofs += mtd->writesize; -		} while (!ret && (chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && -				i < 2); +		} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);  		nand_release_device(mtd);  	} + +	/* Update flash-based bad block table */ +	if (chip->bbt_options & NAND_BBT_USE_FLASH) { +		res = nand_update_bbt(mtd, ofs); +		if (!ret) +			ret = res; +	} +  	if (!ret)  		mtd->ecc_stats.badblocks++; @@ -3260,6 +3272,10 @@ int nand_scan_tail(struct mtd_info *mtd)  	int i;  	struct nand_chip *chip = mtd->priv; +	/* New bad blocks should be marked in OOB, flash-based BBT, or both */ +	BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) && +			!(chip->bbt_options & NAND_BBT_USE_FLASH)); +  	if (!(chip->options & NAND_OWN_BUFFERS))  		chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);  	if (!chip->buffers)  | 

