⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand_bbt.c

📁 This is for bad block management in nand controller
💻 C
📖 第 1 页 / 共 4 页
字号:
	if (td->options & NAND_BBT_PERCHIP)
		chips = this->numchips;
	else
		chips = 1;

	for (i = 0; i < chips; i++) {
		writeops = 0;
		rd = NULL;
		rd2 = NULL;
		/* Per chip or per device ? */
		chipsel = (td->options & NAND_BBT_PERCHIP) ? i : -1;
		/* Mirrored table available ? */
		if (md) {
			if (td->pages[i] == -1 && md->pages[i] == -1) {
				writeops = 0x03;
				goto create;
			}

			if (td->pages[i] == -1) {
				rd = md;
				td->version[i] = md->version[i];
				writeops = 1;
				goto writecheck;
			}

			if (md->pages[i] == -1) {
				rd = td;
				md->version[i] = td->version[i];
				writeops = 2;
				goto writecheck;
			}

			if (td->version[i] == md->version[i]) {
				rd = td;
				if (!(td->options & NAND_BBT_VERSION))
					rd2 = md;
				goto writecheck;
			}

			if (((int8_t) (td->version[i] - md->version[i])) > 0) {
				rd = td;
				md->version[i] = td->version[i];
				writeops = 2;
			} else {
				rd = md;
				td->version[i] = md->version[i];
				writeops = 1;
			}

			goto writecheck;

		} else {
			if (td->pages[i] == -1) {
				writeops = 0x01;
				goto create;
			}
			rd = td;
			goto writecheck;
		}
create:
		/* Create the bad block table by scanning the device ? */
		if (!(td->options & NAND_BBT_CREATE))
			continue;

		/* Create the table in memory by scanning the chip(s) */
		nand_create_bbt (mtd, buf, bd, chipsel);

		td->version[i] = 1;
		if (md)
			md->version[i] = 1;
writecheck:
		/* read back first ? */
		if (rd)
			nand_read_abs_bbt (mtd, buf, rd, chipsel);
		/* If they weren't versioned, read both. */
		if (rd2)
			nand_read_abs_bbt (mtd, buf, rd2, chipsel);

		/* Write the bad block table to the device ? */
		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
			res = nand_write_bbt (mtd, buf, td, md, chipsel);
			if (res < 0)
				return res;
		}

		/* Write the mirror bad block table to the device ? */
		if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
			res = nand_write_bbt (mtd, buf, md, td, chipsel);
			if (res < 0)
				return res;
		}
	}
	return 0;
}

/**
 * mark_bbt_regions - [GENERIC] mark the bad block table regions
 * @mtd:	MTD device structure
 * @td:		bad block table descriptor
 *
 * The bad block table regions are marked as "bad" to prevent
 * accidental erasures / writes. The regions are identified by
 * the mark 0x02.
*/
static void mark_bbt_region (struct mtd_info *mtd, struct nand_bbt_descr *td)
{
	struct nand_chip *this = mtd->priv;
	int i, j, chips, block, nrblocks, update;
	uint8_t oldval, newval;

	/* Do we have a bbt per chip ? */
	if (td->options & NAND_BBT_PERCHIP) {
		chips = this->numchips;
		nrblocks = (int)(this->chipSize >> this->bbt_erase_shift);
	} else {
		chips = 1;
		nrblocks = __ll_low(__ll_RightShift(this->mtdSize, this->bbt_erase_shift));
	}

	for (i = 0; i < chips; i++) {
		if ((td->options & NAND_BBT_ABSPAGE) ||
		    !(td->options & NAND_BBT_WRITE)) {
			if (td->pages[i] == -1)
				continue;
			block = td->pages[i] >> (this->bbt_erase_shift - this->page_shift);
			block <<= 1;
			oldval = this->bbt[(block >> 3)];
			newval = oldval | (0x2 << (block & 0x06));
			this->bbt[(block >> 3)] = newval;
			if ((oldval != newval) && td->reserved_block_code)
				nand_update_bbt(mtd, block << (this->bbt_erase_shift - 1));
			continue;
		}
		update = 0;
		if (td->options & NAND_BBT_LASTBLOCK)
			block = ((i + 1) * nrblocks) - td->maxblocks;
		else
			block = i * nrblocks;
		block <<= 1;
		for (j = 0; j < td->maxblocks; j++) {
			oldval = this->bbt[(block >> 3)];
			newval = oldval | (0x2 << (block & 0x06));
			this->bbt[(block >> 3)] = newval;
			if (oldval != newval)
				update = 1;
			block += 2;
		}
		/* If we want reserved blocks to be recorded to flash, and some
		   new ones have been marked, then we need to update the stored
		   bbts.  This should only happen once. */
		if (update && td->reserved_block_code)
			nand_update_bbt(mtd, (block - 2) << (this->bbt_erase_shift - 1));
	}
}

/**
 * nand_scan_bbt - [NAND Interface] scan, find, read and maybe create bad block table(s)
 * @mtd:	MTD device structure
 * @bd:		descriptor for the good/bad block search pattern
 *
 * The function checks, if a bad block table(s) is/are already
 * available. If not it scans the device for manufacturer
 * marked good / bad blocks and writes the bad block table(s) to
 * the selected place.
 *
 * The bad block table memory is allocated here. It must be freed
 * by calling the nand_free_bbt function.
 *
*/
int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
	struct nand_chip *this = mtd->priv;
	int len, res = 0;
	uint8_t *buf;
	struct nand_bbt_descr *td = this->bbt_td;
	struct nand_bbt_descr *md = this->bbt_md;

	len = __ll_low(__ll_RightShift(this->mtdSize, this->bbt_erase_shift + 2));
	/* Allocate memory (2bit per block) */
//printk("nand_scan_bbt: Allocating %d byte buffer\n", len);

	this->bbt = (uint8_t*) NAND_malloc (len);

	if (!this->bbt) 
	{
		printk (KERN_ERR "nand_scan_bbt: Out of memory, bbt_erase_shift=%d, len=%d\n", 
			this->bbt_erase_shift, len);
		return -ENOMEM;
	
	}
	/* Clear the memory bad block table */
	memset (this->bbt, 0x00, len);

	/* If no primary table decriptor is given, scan the device
	 * to build a memory based bad block table
	 */
	if (!td) {
		if ((res = nand_memory_bbt(mtd, bd))) {
			printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
			NAND_free(this->bbt);
			this->bbt = NULL;
		}
		return res;
	}

	/* Allocate a temporary buffer for one eraseblock incl. oob */
	len = (1 << this->bbt_erase_shift);
//printk("%s: len before OOB = %08x\n", __FUNCTION__, len);
	len += (len >> this->page_shift) * (mtd->oobsize);
//printk("%s: Inc OOB - Allocating %08x byte buffer\n", __FUNCTION__, len);
	buf = NAND_malloc (len);
	if (!buf) {
		printk (KERN_ERR "%s: Out of memory 2, bbt_erase_shift=%d, len=%dx\n", 
			__FUNCTION__, this->bbt_erase_shift, len  );
		
		NAND_free (this->bbt);
		
		this->bbt = NULL;
		return -ENOMEM;
	}

	/* Is the bbt at a given page ? */
	if (td->options & NAND_BBT_ABSPAGE) {
		res = nand_read_abs_bbts (mtd, buf, td, md);
	} else {
		/* Search the bad block table using a pattern in oob */
		res = nand_search_read_bbts (mtd, buf, td, md);
	}

	if (res)
		res = nand_check_create (mtd, buf, bd);

	/* Prevent the bbt regions from erasing / writing */
	mark_bbt_region (mtd, td);
	if (md)
		mark_bbt_region (mtd, md);

	NAND_free (buf);
	return res;
}


/**
 * nand_update_bbt - [NAND Interface] update bad block table(s)
 * @mtd:	MTD device structure
 * @offs:	the offset of the newly marked block
 *
 * The function updates the bad block table(s)
*/
int nand_update_bbt (struct mtd_info *mtd, loff_t offs)
{
	struct nand_chip *this = mtd->priv;
	int len, res = 0, writeops = 0;
	int chip, chipsel;
	uint8_t *buf;
	struct nand_bbt_descr *td = this->bbt_td;
	struct nand_bbt_descr *md = this->bbt_md;

DEBUG(MTD_DEBUG_LEVEL3, "-->%s offs=%s\n", __FUNCTION__, __ll_sprintf(NandBBTMsg, offs));
	if (!this->bbt || !td)
		return -EINVAL;

	len = __ll_low(__ll_RightShift(this->mtdSize, (this->bbt_erase_shift + 2)));
	/* Allocate a temporary buffer for one eraseblock incl. oob */
	len = (1 << this->bbt_erase_shift);
	len += (len >> this->page_shift) * mtd->oobsize;
	buf = NAND_malloc (len);
	if (!buf) {
		printk (KERN_ERR "nand_update_bbt: Out of memory\n");
		return -ENOMEM;
	}

	writeops = md != NULL ? 0x03 : 0x01;

	/* Do we have a bbt per chip ? */
	if (td->options & NAND_BBT_PERCHIP) {
		chip = (int) (offs >> this->chip_shift);
		chipsel = chip;
	} else {
		chip = 0;
		chipsel = -1;
	}

	td->version[chip]++;
	if (md)
		md->version[chip]++;

	/* Write the bad block table to the device ? */
	if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {
		res = nand_write_bbt (mtd, buf, td, md, chipsel);
		if (res < 0)
			goto out;
	}
	/* Write the mirror bad block table to the device ? */
	if ((writeops & 0x02) && md && (md->options & NAND_BBT_WRITE)) {
		res = nand_write_bbt (mtd, buf, md, td, chipsel);
	}

out:
	NAND_free (buf);
	return res;
}

/* Define some generic bad / good block scan pattern which are used
 * while scanning a device for factory marked good / bad blocks. */
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };

static struct nand_bbt_descr smallpage_memorybased = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 5,
	.len = 1,
	.pattern = scan_ff_pattern
};

static struct nand_bbt_descr largepage_memorybased = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 0,
	.len = 2,
	.pattern = scan_ff_pattern
};

/*
static struct nand_bbt_descr mlc_4kpage_memorybased = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 0,
	.len = 1,
	.pattern = scan_ff_pattern
};
*/

static struct nand_bbt_descr smallpage_flashbased = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 5,
	.len = 1,
	.pattern = scan_ff_pattern
};

static struct nand_bbt_descr largepage_flashbased = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 0,
	.len = 2,
	.pattern = scan_ff_pattern
};

/* 2K & 4K page MLC NAND use same pattern */
static struct nand_bbt_descr mlc_flashbased = {
	.options = NAND_BBT_SCAN2NDPAGE,
	.offs = 0,
	.len = 1,
	.pattern = scan_ff_pattern
};


static uint8_t scan_agand_pattern[] = { 0x1C, 0x71, 0xC7, 0x1C, 0x71, 0xC7 };

static struct nand_bbt_descr agand_flashbased = {
	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
	.offs = 0x20,
	.len = 6,
	.pattern = scan_agand_pattern
};

/* Generic flash bbt decriptors
*/
static uint8_t bbt_pattern[] = {'B', 'b', 't', '0' };
static uint8_t mirror_pattern[] = {'1', 't', 'b', 'B' };

/*
 * THT: We only have 1 chip per device
 */
static struct nand_bbt_descr bbt_main_descr = {
	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
		| NAND_BBT_2BIT | NAND_BBT_VERSION /*| NAND_BBT_PERCHIP */,
	.offs =	9, /* THT: Changed from 8 */
	.len = 4,
	.veroffs = 13, /* THT: Changed from 12 */
	.maxblocks = 4, /* THT: Will update later, based on 1MB partition reserved for BBT */
	.pattern = bbt_pattern
};

static struct nand_bbt_descr bbt_mirror_descr = {
	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
		| NAND_BBT_2BIT | NAND_BBT_VERSION /* | NAND_BBT_PERCHIP */,
	.offs =	9, /* THT: Changed from 8 */
	.len = 4,
	.veroffs = 13,  /* THT: Changed from 12 */
	.maxblocks = 4,
	.pattern = mirror_pattern
};

static struct nand_bbt_descr bbt_mlc_main_descr = {
	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
		| NAND_BBT_2BIT | NAND_BBT_VERSION /*| NAND_BBT_PERCHIP */,
	.offs =	1, 
	.len = 4,
	.veroffs = 5, /* THT: Changed from 12 */
	.maxblocks = 8, /* THT: Will update later, based on 4MB partition reserved for BBT */
	.pattern = bbt_pattern
};

static struct nand_bbt_descr bbt_mlc_mirror_descr = {
	.options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
		| NAND_BBT_2BIT | NAND_BBT_VERSION /* | NAND_BBT_PERCHIP */,
	.offs =	1, /* THT: Changed from 8 */
	.len = 4,
	.veroffs = 5,  /* THT: Changed from 12 */
	.maxblocks = 8,
	.pattern = mirror_pattern
};



static int nand_displayBBT(struct mtd_info* mtd)
{
	struct nand_chip *this = mtd->priv;
	L_OFF_T bOffset, bOffsetStart, bOffsetEnd;
	//unsigned char oobbuf[64];
	//struct nand_oobinfo oobsel;
	int res;

	bOffsetStart = 0;
	bOffsetEnd = __ll_sub(this->mtdSize, __ll_constructor(0, 1 << 20)); // Skip BBT itself

	printk(KERN_INFO "----- Contents of BBT -----\n");
	for (bOffset=bOffsetStart; __ll_is_less(bOffset, bOffsetEnd); bOffset = __ll_add32(bOffset, mtd->erasesize)) {
		res = this->isbad_bbt(mtd, bOffset, 1);
		if (res) {
			printk(KERN_INFO "Bad block at %s\n", __ll_sprintf(NandBBTMsg, bOffset));
		}
	}
	printk(KERN_INFO "----- END Contents of BBT -----\n");
	return 0;
}

#if 1
// Remove this block in production builds.

/*
 * Process nand= kernel command arg, BEFORE building/reading BBT table.
 * Currently, the only accepted command is CLEARBBT, which in itself is a dangerous activity.
 * The user is assumed to know what he is doing.
 */
static void nand_preprocessKernelArg(struct mtd_info *mtd)
{
	struct nand_chip *this = mtd->priv;
#ifdef MTD_LARGE
	int ret, needBBT; 
	uint64_t bOffset, bOffsetStart=0, bOffsetEnd=0;
#else
	int bOffset, ret, needBBT, bOffsetStart=0, bOffsetEnd=0;
#endif
	//int page;

#ifdef MTD_LARGE
PRINTK("%s: gClearBBT=%d, size=%016llx, erasesize=%08x\n", __FUNCTION__, gClearBBT, MTD_SIZE(mtd), mtd->erasesize);
#else
PRINTK("%s: gClearBBT=%d, size=%08x, erasesize=%08x\n", __FUNCTION__, gClearBBT, mtd->size, mtd->erasesize);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -