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

📄 nand_bbt.c

📁 基于linux-2.6.28的mtd驱动
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  drivers/mtd/nand_bbt.c * *  Overview: *   Bad block table support for the NAND driver * *  Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Description: * * When nand_scan_bbt is called, then it tries to find the bad block table * depending on the options in the bbt descriptor(s). If a bbt is found * then the contents are read and the memory based bbt is created. If a * mirrored bbt is selected then the mirror is searched too and the * versions are compared. If the mirror has a greater version number * than the mirror bbt is used to build the memory based bbt. * If the tables are not versioned, then we "or" the bad block information. * If one of the bbt's is out of date or does not exist it is (re)created. * If no bbt exists at all then the device is scanned for factory marked * good / bad blocks and the bad block tables are created. * * For manufacturer created bbts like the one found on M-SYS DOC devices * the bbt is searched and read but never created * * The autogenerated bad block table is located in the last good blocks * of the device. The table is mirrored, so it can be updated eventually. * The table is marked in the oob area with an ident pattern and a version * number which indicates which of both tables is more up to date. * * The table uses 2 bits per block * 11b: 	block is good * 00b: 	block is factory marked bad * 01b, 10b: 	block is marked bad due to wear * * The memory bad block table uses the following scheme: * 00b:		block is good * 01b:		block is marked bad due to wear * 10b:		block is reserved (to protect the bbt area) * 11b:		block is factory marked bad * * Multichip devices like DOC store the bad block info per floor. * * Following assumptions are made: * - bbts start at a page boundary, if autolocated on a block boundary * - the space necessary for a bbt in FLASH does not exceed a block boundary * */#include <linux/slab.h>#include <linux/types.h>#include <linux/mtd/mtd.h>#include <linux/mtd/nand.h>#include <linux/mtd/nand_ecc.h>#include <linux/mtd/compatmac.h>#include <linux/bitops.h>#include <linux/delay.h>#include <linux/vmalloc.h>/** * check_pattern - [GENERIC] check if a pattern is in the buffer * @buf:	the buffer to search * @len:	the length of buffer to search * @paglen:	the pagelength * @td:		search pattern descriptor * * Check for a pattern at the given place. Used to search bad block * tables and good / bad block identifiers. * If the SCAN_EMPTY option is set then check, if all bytes except the * pattern area contain 0xff **/static int check_pattern(uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td){	int i, end = 0;	uint8_t *p = buf;	end = paglen + td->offs;	if (td->options & NAND_BBT_SCANEMPTY) {		for (i = 0; i < end; i++) {			if (p[i] != 0xff)				return -1;		}	}	p += end;	/* Compare the pattern */	for (i = 0; i < td->len; i++) {		if (p[i] != td->pattern[i])			return -1;	}	if (td->options & NAND_BBT_SCANEMPTY) {		p += td->len;		end += td->len;		for (i = end; i < len; i++) {			if (*p++ != 0xff)				return -1;		}	}	return 0;}/** * check_short_pattern - [GENERIC] check if a pattern is in the buffer * @buf:	the buffer to search * @td:		search pattern descriptor * * Check for a pattern at the given place. Used to search bad block * tables and good / bad block identifiers. Same as check_pattern, but * no optional empty check **/static int check_short_pattern(uint8_t *buf, struct nand_bbt_descr *td){	int i;	uint8_t *p = buf;	/* Compare the pattern */	for (i = 0; i < td->len; i++) {		if (p[td->offs + i] != td->pattern[i])			return -1;	}	return 0;}/** * read_bbt - [GENERIC] Read the bad block table starting from page * @mtd:	MTD device structure * @buf:	temporary buffer * @page:	the starting page * @num:	the number of bbt descriptors to read * @bits:	number of bits per block * @offs:	offset in the memory table * @reserved_block_code:	Pattern to identify reserved blocks * * Read the bad block table starting from page. * */static int read_bbt(struct mtd_info *mtd, uint8_t *buf, int page, int num,		    int bits, int offs, int reserved_block_code){	int res, i, j, act = 0;	struct nand_chip *this = mtd->priv;	size_t retlen, len, totlen;	loff_t from;	uint8_t msk = (uint8_t) ((1 << bits) - 1);	totlen = (num * bits) >> 3;	from = ((loff_t) page) << this->page_shift;	while (totlen) {		len = min(totlen, (size_t) (1 << this->bbt_erase_shift));		res = mtd->read(mtd, from, len, &retlen, buf);		if (res < 0) {			if (retlen != len) {				printk(KERN_INFO "nand_bbt: Error reading bad block table\n");				return res;			}			printk(KERN_WARNING "nand_bbt: ECC error while reading bad block table\n");		}		/* Analyse data */		for (i = 0; i < len; i++) {			uint8_t dat = buf[i];			for (j = 0; j < 8; j += bits, act += 2) {				uint8_t tmp = (dat >> j) & msk;				if (tmp == msk)					continue;				if (reserved_block_code && (tmp == reserved_block_code)) {					printk(KERN_DEBUG "nand_read_bbt: Reserved block at 0x%08x\n",					       ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);					this->bbt[offs + (act >> 3)] |= 0x2 << (act & 0x06);					mtd->ecc_stats.bbtblocks++;					continue;				}				/* Leave it for now, if its matured we can move this				 * message to MTD_DEBUG_LEVEL0 */				printk(KERN_DEBUG "nand_read_bbt: Bad block at 0x%08x\n",				       ((offs << 2) + (act >> 1)) << this->bbt_erase_shift);				/* Factory marked bad or worn out ? */				if (tmp == 0)					this->bbt[offs + (act >> 3)] |= 0x3 << (act & 0x06);				else					this->bbt[offs + (act >> 3)] |= 0x1 << (act & 0x06);				mtd->ecc_stats.badblocks++;			}		}		totlen -= len;		from += len;	}	return 0;}/** * read_abs_bbt - [GENERIC] Read the bad block table starting at a given page * @mtd:	MTD device structure * @buf:	temporary buffer * @td:		descriptor for the bad block table * @chip:	read the table for a specific chip, -1 read all chips. *		Applies only if NAND_BBT_PERCHIP option is set * * Read the bad block table for all chips starting at a given page * We assume that the bbt bits are in consecutive order.*/static int read_abs_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *td, int chip){	struct nand_chip *this = mtd->priv;	int res = 0, i;	int bits;	bits = td->options & NAND_BBT_NRBITS_MSK;	if (td->options & NAND_BBT_PERCHIP) {		int offs = 0;		for (i = 0; i < this->numchips; i++) {			if (chip == -1 || chip == i)				res = read_bbt (mtd, buf, td->pages[i], this->chipsize >> this->bbt_erase_shift, bits, offs, td->reserved_block_code);			if (res)				return res;			offs += this->chipsize >> (this->bbt_erase_shift + 2);		}	} else {		res = read_bbt (mtd, buf, td->pages[0], mtd->size >> this->bbt_erase_shift, bits, 0, td->reserved_block_code);		if (res)			return res;	}	return 0;}/* * Scan read raw data from flash */static int scan_read_raw(struct mtd_info *mtd, uint8_t *buf, loff_t offs,			 size_t len){	struct mtd_oob_ops ops;	ops.mode = MTD_OOB_RAW;	ops.ooboffs = 0;	ops.ooblen = mtd->oobsize;	ops.oobbuf = buf;	ops.datbuf = buf;	ops.len = len;	return mtd->read_oob(mtd, offs, &ops);}/* * Scan write data with oob to flash */static int scan_write_bbt(struct mtd_info *mtd, loff_t offs, size_t len,			  uint8_t *buf, uint8_t *oob){	struct mtd_oob_ops ops;	ops.mode = MTD_OOB_PLACE;	ops.ooboffs = 0;	ops.ooblen = mtd->oobsize;	ops.datbuf = buf;	ops.oobbuf = oob;	ops.len = len;	return mtd->write_oob(mtd, offs, &ops);}/** * read_abs_bbts - [GENERIC] Read the bad block table(s) for all chips starting at a given page * @mtd:	MTD device structure * @buf:	temporary buffer * @td:		descriptor for the bad block table * @md:		descriptor for the bad block table mirror * * Read the bad block table(s) for all chips starting at a given page * We assume that the bbt bits are in consecutive order. **/static int read_abs_bbts(struct mtd_info *mtd, uint8_t *buf,			 struct nand_bbt_descr *td, struct nand_bbt_descr *md){	struct nand_chip *this = mtd->priv;	/* Read the primary version, if available */	if (td->options & NAND_BBT_VERSION) {		scan_read_raw(mtd, buf, td->pages[0] << this->page_shift,			      mtd->writesize);		td->version[0] = buf[mtd->writesize + td->veroffs];		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",		       td->pages[0], td->version[0]);	}	/* Read the mirror version, if available */	if (md && (md->options & NAND_BBT_VERSION)) {		scan_read_raw(mtd, buf, md->pages[0] << this->page_shift,			      mtd->writesize);		md->version[0] = buf[mtd->writesize + md->veroffs];		printk(KERN_DEBUG "Bad block table at page %d, version 0x%02X\n",		       md->pages[0], md->version[0]);	}	return 1;}/* * Scan a given block full */static int scan_block_full(struct mtd_info *mtd, struct nand_bbt_descr *bd,			   loff_t offs, uint8_t *buf, size_t readlen,			   int scanlen, int len){	int ret, j;	ret = scan_read_raw(mtd, buf, offs, readlen);	if (ret)		return ret;	for (j = 0; j < len; j++, buf += scanlen) {		if (check_pattern(buf, scanlen, mtd->writesize, bd))			return 1;	}	return 0;}/* * Scan a given block partially */static int scan_block_fast(struct mtd_info *mtd, struct nand_bbt_descr *bd,			   loff_t offs, uint8_t *buf, int len){	struct mtd_oob_ops ops;	int j, ret;	ops.ooblen = mtd->oobsize;	ops.oobbuf = buf;	ops.ooboffs = 0;	ops.datbuf = NULL;	ops.mode = MTD_OOB_PLACE;	for (j = 0; j < len; j++) {		/*		 * Read the full oob until read_oob is fixed to		 * handle single byte reads for 16 bit		 * buswidth		 */		ret = mtd->read_oob(mtd, offs, &ops);		if (ret)			return ret;		if (check_short_pattern(buf, bd))			return 1;		offs += mtd->writesize;	}	return 0;}/** * create_bbt - [GENERIC] Create a bad block table by scanning the device * @mtd:	MTD device structure * @buf:	temporary buffer * @bd:		descriptor for the good/bad block search pattern * @chip:	create the table for a specific chip, -1 read all chips. *		Applies only if NAND_BBT_PERCHIP option is set * * Create a bad block table by scanning the device * for the given good/bad block identify pattern */static int create_bbt(struct mtd_info *mtd, uint8_t *buf,	struct nand_bbt_descr *bd, int chip){	struct nand_chip *this = mtd->priv;	int i, numblocks, len, scanlen;	int startblock;	loff_t from;	size_t readlen;	printk(KERN_INFO "Scanning device for bad blocks\n");	if (bd->options & NAND_BBT_SCANALLPAGES)		len = 1 << (this->bbt_erase_shift - this->page_shift);	else {		if (bd->options & NAND_BBT_SCAN2NDPAGE)			len = 2;		else			len = 1;	}	if (!(bd->options & NAND_BBT_SCANEMPTY)) {		/* We need only read few bytes from the OOB area */		scanlen = 0;		readlen = bd->len;	} else {		/* Full page content should be read */		scanlen = mtd->writesize + mtd->oobsize;		readlen = len * mtd->writesize;	}	if (chip == -1) {		/* Note that numblocks is 2 * (real numblocks) here, see i+=2		 * below as it makes shifting and masking less painful */		numblocks = mtd->size >> (this->bbt_erase_shift - 1);		startblock = 0;		from = 0;	} else {		if (chip >= this->numchips) {			printk(KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",

⌨️ 快捷键说明

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