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: Brian Norris <computersforpeace@gmail.com> Acked-by: Huang Shijie <b32955@freescale.com> (for gpmi-nand parts) Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
This commit is contained in:
parent
39dbb02998
commit
5a0edb251a
5 changed files with 72 additions and 75 deletions
|
@ -1093,7 +1093,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
struct nand_chip *nand = mtd->priv;
|
||||
struct docg4_priv *doc = nand->priv;
|
||||
struct nand_bbt_descr *bbtd = nand->badblock_pattern;
|
||||
int block = (int)(ofs >> nand->bbt_erase_shift);
|
||||
int page = (int)(ofs >> nand->page_shift);
|
||||
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)
|
|||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* update bbt in memory */
|
||||
nand->bbt[block / 4] |= 0x01 << ((block & 0x03) * 2);
|
||||
|
||||
/* write bit-wise negation of pattern to oob buffer */
|
||||
memset(nand->oob_poi, 0xff, mtd->oobsize);
|
||||
for (i = 0; i < bbtd->len; i++)
|
||||
|
@ -1120,8 +1116,6 @@ static int docg4_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
write_page_prologue(mtd, g4_addr);
|
||||
docg4_write_page(mtd, nand, buf, 1);
|
||||
ret = pageprog(mtd);
|
||||
if (!ret)
|
||||
mtd->ecc_stats.badblocks++;
|
||||
|
||||
kfree(buf);
|
||||
|
||||
|
|
|
@ -1148,43 +1148,31 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
struct gpmi_nand_data *this = chip->priv;
|
||||
int block, ret = 0;
|
||||
int ret = 0;
|
||||
uint8_t *block_mark;
|
||||
int column, page, status, chipnr;
|
||||
|
||||
/* Get block number */
|
||||
block = (int)(ofs >> chip->bbt_erase_shift);
|
||||
if (chip->bbt)
|
||||
chip->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
|
||||
chipnr = (int)(ofs >> chip->chip_shift);
|
||||
chip->select_chip(mtd, chipnr);
|
||||
|
||||
/* Do we have a flash based bad block table ? */
|
||||
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;
|
||||
|
||||
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. */
|
||||
block_mark = this->data_buffer_dma;
|
||||
block_mark[0] = 0; /* bad block marker */
|
||||
/* Shift to get page */
|
||||
page = (int)(ofs >> chip->page_shift);
|
||||
|
||||
/* Shift to get page */
|
||||
page = (int)(ofs >> chip->page_shift);
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
|
||||
chip->write_buf(mtd, block_mark, 1);
|
||||
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
|
||||
chip->cmdfunc(mtd, NAND_CMD_SEQIN, column, page);
|
||||
chip->write_buf(mtd, block_mark, 1);
|
||||
chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
if (status & NAND_STATUS_FAIL)
|
||||
ret = -EIO;
|
||||
|
||||
status = chip->waitfunc(mtd, chip);
|
||||
if (status & NAND_STATUS_FAIL)
|
||||
ret = -EIO;
|
||||
|
||||
chip->select_chip(mtd, -1);
|
||||
}
|
||||
if (!ret)
|
||||
mtd->ecc_stats.badblocks++;
|
||||
chip->select_chip(mtd, -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
* @ofs: offset from device start
|
||||
*
|
||||
* This is the default implementation, which can be overridden by a hardware
|
||||
* specific driver. We try operations in the following order, according to our
|
||||
* bbt_options (NAND_BBT_NO_OOB_BBM and NAND_BBT_USE_FLASH):
|
||||
* specific driver. It provides the details for writing a bad block marker to a
|
||||
* 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
|
||||
* (2) update in-memory BBT
|
||||
* (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)
|
|||
* 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)
|
||||
static int nand_block_markbad_lowlevel(struct mtd_info *mtd, loff_t ofs)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
uint8_t buf[2] = { 0, 0 };
|
||||
int block, res, ret = 0, i = 0;
|
||||
int block, res, ret = 0;
|
||||
int write_oob = !(chip->bbt_options & NAND_BBT_NO_OOB_BBM);
|
||||
|
||||
if (write_oob) {
|
||||
|
@ -364,34 +408,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
|
||||
/* Write bad block marker to OOB */
|
||||
if (write_oob) {
|
||||
struct mtd_oob_ops ops;
|
||||
loff_t wr_ofs = ofs;
|
||||
|
||||
nand_get_device(mtd, FL_WRITING);
|
||||
|
||||
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);
|
||||
|
||||
ret = chip->block_markbad(mtd, ofs);
|
||||
nand_release_device(mtd);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
struct nand_chip *chip = mtd->priv;
|
||||
int ret;
|
||||
|
||||
ret = nand_block_isbad(mtd, ofs);
|
||||
|
@ -2694,7 +2711,7 @@ static int nand_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
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)
|
|||
|
||||
EXPORT_SYMBOL(nand_scan_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)
|
|||
{
|
||||
struct mtd_oob_ops ops;
|
||||
struct sm_oob oob;
|
||||
int ret, error = 0;
|
||||
int ret;
|
||||
|
||||
memset(&oob, -1, SM_OOB_SIZE);
|
||||
oob.block_status = 0x0F;
|
||||
|
@ -61,11 +61,10 @@ static int sm_block_markbad(struct mtd_info *mtd, loff_t ofs)
|
|||
printk(KERN_NOTICE
|
||||
"sm_common: can't mark sector at %i as bad\n",
|
||||
(int)ofs);
|
||||
error = -EIO;
|
||||
} else
|
||||
mtd->ecc_stats.badblocks++;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return error;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nand_flash_dev nand_smartmedia_flash_ids[] = {
|
||||
|
|
Loading…
Reference in a new issue