Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -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);

+16 −28
Original line number Diff line number Diff line
@@ -1148,19 +1148,10 @@ 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);

	/* 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);

@@ -1182,9 +1173,6 @@ static int gpmi_block_markbad(struct mtd_info *mtd, loff_t ofs)
		ret = -EIO;

	chip->select_chip(mtd, -1);
	}
	if (!ret)
		mtd->ecc_stats.badblocks++;

	return ret;
}
+52 −35
Original line number Diff line number Diff line
@@ -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);
}

/**
+0 −1
Original line number Diff line number Diff line
@@ -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);
+4 −5
Original line number Diff line number Diff line
@@ -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[] = {