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

Commit c3baf278 authored by Boris Brezillon's avatar Boris Brezillon
Browse files

mtd: nand_bbt: Move BBT block selection logic out of write_bbt()



This clarifies the write_bbt() function by removing the write label
and simplifying the error/exit path.

Signed-off-by: default avatarBoris Brezillon <boris.brezillon@free-electrons.com>
Tested-by: default avatarKyle Roeschley <kyle.roeschley@ni.com>
parent 57d419a4
Loading
Loading
Loading
Loading
+74 −36
Original line number Diff line number Diff line
@@ -604,6 +604,69 @@ static void search_read_bbts(struct mtd_info *mtd, uint8_t *buf,
		search_bbt(mtd, buf, md);
}

/**
 * get_bbt_block - Get the first valid eraseblock suitable to store a BBT
 * @this: the NAND device
 * @td: the BBT description
 * @md: the mirror BBT descriptor
 * @chip: the CHIP selector
 *
 * This functions returns a positive block number pointing a valid eraseblock
 * suitable to store a BBT (i.e. in the range reserved for BBT), or -ENOSPC if
 * all blocks are already used of marked bad. If td->pages[chip] was already
 * pointing to a valid block we re-use it, otherwise we search for the next
 * valid one.
 */
static int get_bbt_block(struct nand_chip *this, struct nand_bbt_descr *td,
			 struct nand_bbt_descr *md, int chip)
{
	int startblock, dir, page, numblocks, i;

	/*
	 * There was already a version of the table, reuse the page. This
	 * applies for absolute placement too, as we have the page number in
	 * td->pages.
	 */
	if (td->pages[chip] != -1)
		return td->pages[chip] >>
				(this->bbt_erase_shift - this->page_shift);

	numblocks = (int)(this->chipsize >> this->bbt_erase_shift);
	if (!(td->options & NAND_BBT_PERCHIP))
		numblocks *= this->numchips;

	/*
	 * Automatic placement of the bad block table. Search direction
	 * top -> down?
	 */
	if (td->options & NAND_BBT_LASTBLOCK) {
		startblock = numblocks * (chip + 1) - 1;
		dir = -1;
	} else {
		startblock = chip * numblocks;
		dir = 1;
	}

	for (i = 0; i < td->maxblocks; i++) {
		int block = startblock + dir * i;

		/* Check, if the block is bad */
		switch (bbt_get_entry(this, block)) {
		case BBT_BLOCK_WORN:
		case BBT_BLOCK_FACTORY_BAD:
			continue;
		}

		page = block << (this->bbt_erase_shift - this->page_shift);

		/* Check, if the block is used by the mirror table */
		if (!md || md->pages[chip] != page)
			return block;
	}

	return -ENOSPC;
}

/**
 * write_bbt - [GENERIC] (Re)write the bad block table
 * @mtd: MTD device structure
@@ -621,7 +684,7 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,
	struct nand_chip *this = mtd_to_nand(mtd);
	struct erase_info einfo;
	int i, res, chip = 0;
	int bits, startblock, dir, page, offs, numblocks, sft, sftmsk;
	int bits, page, offs, numblocks, sft, sftmsk;
	int nrchips, pageoffs, ooboffs;
	uint8_t msk[4];
	uint8_t rcode = td->reserved_block_code;
@@ -653,45 +716,20 @@ static int write_bbt(struct mtd_info *mtd, uint8_t *buf,

	/* Loop through the chips */
	for (; chip < nrchips; chip++) {
		/*
		 * There was already a version of the table, reuse the page
		 * This applies for absolute placement too, as we have the
		 * page nr. in td->pages.
		 */
		if (td->pages[chip] != -1) {
			page = td->pages[chip];
			goto write;
		int block;

		block = get_bbt_block(this, td, md, chip);
		if (block < 0) {
			pr_err("No space left to write bad block table\n");
			res = block;
			goto outerr;
		}

		/*
		 * Automatic placement of the bad block table. Search direction
		 * top -> down?
		 * get_bbt_block() returns a block number, shift the value to
		 * get a page number.
		 */
		if (td->options & NAND_BBT_LASTBLOCK) {
			startblock = numblocks * (chip + 1) - 1;
			dir = -1;
		} else {
			startblock = chip * numblocks;
			dir = 1;
		}

		for (i = 0; i < td->maxblocks; i++) {
			int block = startblock + dir * i;
			/* Check, if the block is bad */
			switch (bbt_get_entry(this, block)) {
			case BBT_BLOCK_WORN:
			case BBT_BLOCK_FACTORY_BAD:
				continue;
			}
			page = block <<
				(this->bbt_erase_shift - this->page_shift);
			/* Check, if the block is used by the mirror table */
			if (!md || md->pages[chip] != page)
				goto write;
		}
		pr_err("No space left to write bad block table\n");
		return -ENOSPC;
	write:
		page = block << (this->bbt_erase_shift - this->page_shift);

		/* Set up shift count and masks for the flash table */
		bits = td->options & NAND_BBT_NRBITS_MSK;