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

📄 nand_bbt.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
			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) */		create_bbt(mtd, buf, bd, chipsel);		td->version[i] = 1;		if (md)			md->version[i] = 1;	writecheck:		/* read back first ? */		if (rd)			read_abs_bbt(mtd, buf, rd, chipsel);		/* If they weren't versioned, read both. */		if (rd2)			read_abs_bbt(mtd, buf, rd2, chipsel);		/* Write the bad block table to the device ? */		if ((writeops & 0x01) && (td->options & NAND_BBT_WRITE)) {			res = 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 = 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 = (int)(mtd->size >> 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 = mtd->size >> (this->bbt_erase_shift + 2);	/* Allocate memory (2bit per block) and clear the memory bad block table */	this->bbt = kzalloc(len, GFP_KERNEL);	if (!this->bbt) {		printk(KERN_ERR "nand_scan_bbt: Out of memory\n");		return -ENOMEM;	}	/* 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");			kfree(this->bbt);			this->bbt = NULL;		}		return res;	}	/* Allocate a temporary buffer for one eraseblock incl. oob */	len = (1 << this->bbt_erase_shift);	len += (len >> this->page_shift) * mtd->oobsize;	buf = vmalloc(len);	if (!buf) {		printk(KERN_ERR "nand_bbt: Out of memory\n");		kfree(this->bbt);		this->bbt = NULL;		return -ENOMEM;	}	/* Is the bbt at a given page ? */	if (td->options & NAND_BBT_ABSPAGE) {		res = read_abs_bbts(mtd, buf, td, md);	} else {		/* Search the bad block table using a pattern in oob */		res = search_read_bbts(mtd, buf, td, md);	}	if (res)		res = check_create(mtd, buf, bd);	/* Prevent the bbt regions from erasing / writing */	mark_bbt_region(mtd, td);	if (md)		mark_bbt_region(mtd, md);	vfree(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;	if (!this->bbt || !td)		return -EINVAL;	len = mtd->size >> (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 = kmalloc(len, GFP_KERNEL);	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 = 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 = write_bbt(mtd, buf, md, td, chipsel);	} out:	kfree(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 = 0,	.offs = 0,	.len = 2,	.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};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' };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 =	8,	.len = 4,	.veroffs = 12,	.maxblocks = 4,	.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 =	8,	.len = 4,	.veroffs = 12,	.maxblocks = 4,	.pattern = mirror_pattern};/** * nand_default_bbt - [NAND Interface] Select a default bad block table for the device * @mtd:	MTD device structure * * This function selects the default bad block table * support for the device and calls the nand_scan_bbt function **/int nand_default_bbt(struct mtd_info *mtd){	struct nand_chip *this = mtd->priv;	/* Default for AG-AND. We must use a flash based	 * bad block table as the devices have factory marked	 * _good_ blocks. Erasing those blocks leads to loss	 * of the good / bad information, so we _must_ store	 * this information in a good / bad table during	 * startup	 */	if (this->options & NAND_IS_AND) {		/* Use the default pattern descriptors */		if (!this->bbt_td) {			this->bbt_td = &bbt_main_descr;			this->bbt_md = &bbt_mirror_descr;		}		this->options |= NAND_USE_FLASH_BBT;		return nand_scan_bbt(mtd, &agand_flashbased);	}	/* Is a flash based bad block table requested ? */	if (this->options & NAND_USE_FLASH_BBT) {		/* Use the default pattern descriptors */		if (!this->bbt_td) {			this->bbt_td = &bbt_main_descr;			this->bbt_md = &bbt_mirror_descr;		}		if (!this->badblock_pattern) {			this->badblock_pattern = (mtd->writesize > 512) ? &largepage_flashbased : &smallpage_flashbased;		}	} else {		this->bbt_td = NULL;		this->bbt_md = NULL;		if (!this->badblock_pattern) {			this->badblock_pattern = (mtd->writesize > 512) ?			    &largepage_memorybased : &smallpage_memorybased;		}	}	return nand_scan_bbt(mtd, this->badblock_pattern);}/** * nand_isbad_bbt - [NAND Interface] Check if a block is bad * @mtd:	MTD device structure * @offs:	offset in the device * @allowbbt:	allow access to bad block table region **/int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt){	struct nand_chip *this = mtd->priv;	int block;	uint8_t res;	/* Get block number * 2 */	block = (int)(offs >> (this->bbt_erase_shift - 1));	res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;	DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",	      (unsigned int)offs, block >> 1, res);	switch ((int)res) {	case 0x00:		return 0;	case 0x01:		return 1;	case 0x02:		return allowbbt ? 0 : 1;	}	return 1;}EXPORT_SYMBOL(nand_scan_bbt);EXPORT_SYMBOL(nand_default_bbt);

⌨️ 快捷键说明

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