Commit 5a0edb25 authored by Brian Norris's avatar Brian Norris Committed by David Woodhouse

mtd: nand: refactor chip->block_markbad interface

The chip->block_markbad pointer should really only be responsible for
writing a bad block marker for new bad blocks. It should not take care
of BBT-related functionality, nor should it handle bookkeeping of bad
block stats.

This patch refactors the 3 users of the block_markbad interface (plus
the default nand_base implementation) so that the common code is kept in
nand_block_markbad_lowlevel(). It removes some inconsistencies between
the various implementations and should allow for more centralized
improvements in the future.

Because gpmi-nand no longer needs the nand_update_bbt() function, let's
stop exporting it as well.
Signed-off-by: default avatarBrian Norris <computersforpeace@gmail.com>
Acked-by: Huang Shijie <b32955@freescale.com> (for gpmi-nand parts)
Signed-off-by: default avatarArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 39dbb029
...@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
struct nand_chip *nand = mtd->priv; struct nand_chip *nand = mtd->priv;
struct docg4_priv *doc = nand->priv; struct docg4_priv *doc = nand->priv;
struct nand_bbt_descr *bbtd = nand->badblock_pattern; struct nand_bbt_descr *bbtd = nand->badblock_pattern;
int block = (int)(ofs >> nand->bbt_erase_shift);
int page = (int)(ofs >> nand->page_shift); int page = (int)(ofs >> nand->page_shift);
uint32_t g4_addr = mtd_to_docg4_address(page, 0); uint32_t g4_addr = mtd_to_docg4_address(page, 0);
...@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1108,9 +1107,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
if (buf == NULL) if (buf == NULL)
return -ENOMEM; return -ENOMEM;
/* update bbt in memory */
nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
/* write bit-wise negation of pattern to oob buffer */ /* write bit-wise negation of pattern to oob buffer */
memset(nand->oob_poi, 0xff, mtd->oobsize); memset(nand->oob_poi, 0xff, mtd->oobsize);
for (i = 0; i < bbtd->len; i++) for (i = 0; i < bbtd->len; i++)
...@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
write_page_prologue(mtd, g4_addr); write_page_prologue(mtd, g4_addr);
docg4_write_page(mtd, nand, buf, 1); docg4_write_page(mtd, nand, buf, 1);
ret = pageprog(mtd); ret = pageprog(mtd);
if (!ret)
mtd->ecc_stats.badblocks++;
kfree(buf); kfree(buf);
......
...@@ -1148,43 +1148,31 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -1148,43 +1148,31 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
{ {
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
struct gpmi_nand_data *this = chip->priv; struct gpmi_nand_data *this = chip->priv;
int block, ret = 0; int ret = 0;
uint8_t *block_mark; uint8_t *block_mark;
int column, page, status, chipnr; int column, page, status, chipnr;
/* Get block number */ chipnr = (int)(ofs >> chip->chip_shift);
block = (int)(ofs >> chip->bbt_erase_shift); chip->select_chip(mtd, chipnr);
if (chip->bbt)
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
/* Do we have a flash based bad block table ? */ column = this->swap_block_mark ? mtd->writesize : 0;
if (chip->bbt_options & NAND_BBT_USE_FLASH)
ret = nand_update_bbt(mtd, ofs);
else {
chipnr = (int)(ofs >> chip->chip_shift);
chip->select_chip(mtd, chipnr);
column = this->swap_block_mark ? mtd->writesize : 0; /* Write the block mark. */
block_mark = this->data_buffer_dma;
block_mark[0] = 0; /* bad block marker */
/* Write the block mark. */ /* Shift to get page */
block_mark = this->data_buffer_dma; page = (int)(ofs >> chip->page_shift);
block_mark[0] = 0; /* bad block marker */
/* Shift to get page */ chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
page = (int)(ofs >> chip->page_shift); chip->write_buf(mtd, block_mark, 1);
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page); status = chip->waitfunc(mtd, chip);
chip->write_buf(mtd, block_mark, 1); if (status & NAND_STATUS_FAIL)
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); ret = -EIO;
status = chip->waitfunc(mtd, chip); chip->select_chip(mtd, -1);
if (status & NAND_STATUS_FAIL)
ret = -EIO;
chip->select_chip(mtd, -1);
}
if (!ret)
mtd->ecc_stats.badblocks++;
return ret; return ret;
} }
......
...@@ -324,13 +324,58 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) ...@@ -324,13 +324,58 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
} }
/** /**
* nand_default_block_markbad - [DEFAULT] mark a block bad * nand_default_block_markbad - [DEFAULT] mark a block bad via bad block marker
* @mtd: MTD device structure * @mtd: MTD device structure
* @ofs: offset from device start * @ofs: offset from device start
* *
* This is the default implementation, which can be overridden by a hardware * This is the default implementation, which can be overridden by a hardware
* specific driver. We try operations in the following order, according to our * specific driver. It provides the details for writing a bad block marker to a
* bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH): * block.
*/
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
{
struct nand_chip *chip = mtd->priv;
struct mtd_oob_ops ops;
uint8_t buf[2] = { 0, 0 };
int ret = 0, res, i = 0;
ops.datbuf = NULL;
ops.oobbuf = buf;
ops.ooboffs = chip->badblockpos;
if (chip->options & NAND_BUSWIDTH_16) {
ops.ooboffs &= ~0x01;
ops.len = ops.ooblen = 2;
} else {
ops.len = ops.ooblen = 1;
}
ops.mode = MTD_OPS_PLACE_OOB;
/* Write to first/last page(s) if necessary */
if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
ofs += mtd->erasesize - mtd->writesize;
do {
res = nand_do_write_oob(mtd, ofs, &ops);
if (!ret)
ret = res;
i++;
ofs += mtd->writesize;
} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
return ret;
}
/**
* nand_block_markbad_lowlevel - mark a block bad
* @mtd: MTD device structure
* @ofs: offset from device start
*
* This function performs the generic NAND bad block marking steps (i.e., bad
* block table(s) and/or marker(s)). We only allow the hardware driver to
* specify how to write bad block markers to OOB (chip->block_markbad).
*
* 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 * (1) erase the affected block, to allow OOB marker to be written cleanly
* (2) update in-memory BBT * (2) update in-memory BBT
* (3) write bad block marker to OOB area of affected block * (3) write bad block marker to OOB area of affected block
...@@ -338,11 +383,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip) ...@@ -338,11 +383,10 @@ static int nand_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
* Note that we retain the first error encountered in (3) or (4), finish the * Note that we retain the first error encountered in (3) or (4), finish the
* procedures, and dump the error in the end. * procedures, and dump the error in the end.
*/ */
static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
{ {
struct nand_chip *chip = mtd->priv; struct nand_chip *chip = mtd->priv;
uint8_t buf[2] = { 0, 0 }; int block, res, ret = 0;
int block, res, ret = 0, i = 0;
int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM); int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
if (write_oob) { if (write_oob) {
...@@ -364,34 +408,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -364,34 +408,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* Write bad block marker to OOB */ /* Write bad block marker to OOB */
if (write_oob) { if (write_oob) {
struct mtd_oob_ops ops;
loff_t wr_ofs = ofs;
nand_get_device(mtd, FL_WRITING); nand_get_device(mtd, FL_WRITING);
ret = chip->block_markbad(mtd, ofs);
ops.datbuf = NULL;
ops.oobbuf = buf;
ops.ooboffs = chip->badblockpos;
if (chip->options & NAND_BUSWIDTH_16) {
ops.ooboffs &= ~0x01;
ops.len = ops.ooblen = 2;
} else {
ops.len = ops.ooblen = 1;
}
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 {
res = nand_do_write_oob(mtd, wr_ofs, &ops);
if (!ret)
ret = res;
i++;
wr_ofs += mtd->writesize;
} while ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) && i < 2);
nand_release_device(mtd); nand_release_device(mtd);
} }
...@@ -2683,7 +2701,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs) ...@@ -2683,7 +2701,6 @@ static int nand_block_isbad(struct mtd_info *mtd, loff_t offs)
*/ */
static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
{ {
struct nand_chip *chip = mtd->priv;
int ret; int ret;
ret = nand_block_isbad(mtd, ofs); ret = nand_block_isbad(mtd, ofs);
...@@ -2694,7 +2711,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -2694,7 +2711,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
return ret; return ret;
} }
return chip->block_markbad(mtd, ofs); return nand_block_markbad_lowlevel(mtd, ofs);
} }
/** /**
......
...@@ -1392,4 +1392,3 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt) ...@@ -1392,4 +1392,3 @@ int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt)
EXPORT_SYMBOL(nand_scan_bbt); EXPORT_SYMBOL(nand_scan_bbt);
EXPORT_SYMBOL(nand_default_bbt); EXPORT_SYMBOL(nand_default_bbt);
EXPORT_SYMBOL_GPL(nand_update_bbt);
...@@ -42,7 +42,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -42,7 +42,7 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
{ {
struct mtd_oob_ops ops; struct mtd_oob_ops ops;
struct sm_oob oob; struct sm_oob oob;
int ret, error = 0; int ret;
memset(&oob, -1, SM_OOB_SIZE); memset(&oob, -1, SM_OOB_SIZE);
oob.block_status = 0x0F; oob.block_status = 0x0F;
...@@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs) ...@@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
printk(KERN_NOTICE printk(KERN_NOTICE
"sm_common: can't mark sector at %i as bad\n", "sm_common: can't mark sector at %i as bad\n",
(int)ofs); (int)ofs);
error = -EIO; return -EIO;
} else }
mtd->ecc_stats.badblocks++;
return error; return 0;
} }
static struct nand_flash_dev nand_smartmedia_flash_ids[] = { static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment