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

📄 nand_base.c

📁 老版本的mtd-snap
💻 C
📖 第 1 页 / 共 5 页
字号:
		for (; eccsteps; eccsteps--) {			this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);			for (i = 0; i < 3; i++, eccidx++)				oob_buf[oob_config[eccidx]] = ecc_code[i];			datidx += this->eccsize;		}		this->write_buf(mtd, this->data_poi, mtd->oobblock);		break;	default:		eccbytes = this->eccbytes;		for (; eccsteps; eccsteps--) {			/* enable hardware ecc logic for write */			this->enable_hwecc(mtd, NAND_ECC_WRITE);			this->write_buf(mtd, &this->data_poi[datidx], this->eccsize);			this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);			for (i = 0; i < eccbytes; i++, eccidx++)				oob_buf[oob_config[eccidx]] = ecc_code[i];			/* If the hardware ecc provides syndromes then			 * the ecc code must be written immidiately after			 * the data bytes (words) */			if (this->options & NAND_HWECC_SYNDROME)				this->write_buf(mtd, ecc_code, eccbytes);			datidx += this->eccsize;		}		break;	}											/* Write out OOB data */	if (this->options & NAND_HWECC_SYNDROME)		this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);	else 		this->write_buf(mtd, oob_buf, mtd->oobsize);	/* Send command to actually program the data */	this->cmdfunc (mtd, cached ? NAND_CMD_CACHEDPROG : NAND_CMD_PAGEPROG, -1, -1);	if (!cached) {		/* call wait ready function */		status = this->waitfunc (mtd, this, FL_WRITING);		/* See if operation failed and additional status checks are available */		if ((status & NAND_STATUS_FAIL) && (this->errstat)) {			status = this->errstat(mtd, this, FL_WRITING, status, page);		}		/* See if device thinks it succeeded */		if (status & NAND_STATUS_FAIL) {			DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);			return -EIO;		}	} else {		/* FIXME: Implement cached programming ! */		/* wait until cache is ready*/		// status = this->waitfunc (mtd, this, FL_CACHEDRPG);	}	return 0;	}#ifdef CONFIG_MTD_NAND_VERIFY_WRITE/** * nand_verify_pages - [GENERIC] verify the chip contents after a write * @mtd:	MTD device structure * @this:	NAND chip structure * @page: 	startpage inside the chip, must be called with (page & this->pagemask) * @numpages:	number of pages to verify * @oob_buf:	out of band data buffer * @oobsel:	out of band selecttion structre * @chipnr:	number of the current chip * @oobmode:	1 = full buffer verify, 0 = ecc only * * The NAND device assumes that it is always writing to a cleanly erased page. * Hence, it performs its internal write verification only on bits that  * transitioned from 1 to 0. The device does NOT verify the whole page on a * byte by byte basis. It is possible that the page was not completely erased  * or the page is becoming unusable due to wear. The read with ECC would catch  * the error later when the ECC page check fails, but we would rather catch  * it early in the page write stage. Better to write no data than invalid data. */static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int page, int numpages, 	u_char *oob_buf, struct nand_oobinfo *oobsel, int chipnr, int oobmode){	int 	i, j, datidx = 0, oobofs = 0, res = -EIO;	int	eccsteps = this->eccsteps;	int	hweccbytes; 	u_char 	oobdata[64];	hweccbytes = (this->options & NAND_HWECC_SYNDROME) ? (oobsel->eccbytes / eccsteps) : 0;	/* Send command to read back the first page */	this->cmdfunc (mtd, NAND_CMD_READ0, 0, page);	for(;;) {		for (j = 0; j < eccsteps; j++) {			/* Loop through and verify the data */			if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->eccsize)) {				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);				goto out;			}			datidx += mtd->eccsize;			/* Have we a hw generator layout ? */			if (!hweccbytes)				continue;			if (this->verify_buf(mtd, &this->oob_buf[oobofs], hweccbytes)) {				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);				goto out;			}			oobofs += hweccbytes;		}		/* check, if we must compare all data or if we just have to		 * compare the ecc bytes		 */		if (oobmode) {			if (this->verify_buf(mtd, &oob_buf[oobofs], mtd->oobsize - hweccbytes * eccsteps)) {				DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);				goto out;			}		} else {			/* Read always, else autoincrement fails */			this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);			if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {				int ecccnt = oobsel->eccbytes;						for (i = 0; i < ecccnt; i++) {					int idx = oobsel->eccpos[i];					if (oobdata[idx] != oob_buf[oobofs + idx] ) {						DEBUG (MTD_DEBUG_LEVEL0,					       	"%s: Failed ECC write "						"verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i);						goto out;					}				}			}			}		oobofs += mtd->oobsize - hweccbytes * eccsteps;		page++;		numpages--;		/* Apply delay or wait for ready/busy pin 		 * Do this before the AUTOINCR check, so no problems		 * arise if a chip which does auto increment		 * is marked as NOAUTOINCR by the board driver.		 * Do this also before returning, so the chip is		 * ready for the next command.		*/		if (!this->dev_ready) 			udelay (this->chip_delay);		else			nand_wait_ready(mtd);		/* All done, return happy */		if (!numpages)			return 0;							/* Check, if the chip supports auto page increment */ 		if (!NAND_CANAUTOINCR(this))			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);	}	/* 	 * Terminate the read command. We come here in case of an error	 * So we must issue a reset command.	 */out:	 	this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);	return res;}#endif/** * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd:	MTD device structure * @from:	offset to read from * @len:	number of bytes to read * @retlen:	pointer to variable to store the number of read bytes * @buf:	the databuffer to put data * * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL * and flags = 0xff */static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf){	return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);}/** * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc * @mtd:	MTD device structure * @from:	offset to read from * @len:	number of bytes to read * @retlen:	pointer to variable to store the number of read bytes * @buf:	the databuffer to put data * @oob_buf:	filesystem supplied oob data buffer * @oobsel:	oob selection structure * * This function simply calls nand_do_read_ecc with flags = 0xff */static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,			  size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel){	/* use userspace supplied oobinfo, if zero */	if (oobsel == NULL)		oobsel = &mtd->oobinfo;	return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);}/** * nand_do_read_ecc - [MTD Interface] Read data with ECC * @mtd:	MTD device structure * @from:	offset to read from * @len:	number of bytes to read * @retlen:	pointer to variable to store the number of read bytes * @buf:	the databuffer to put data * @oob_buf:	filesystem supplied oob data buffer (can be NULL) * @oobsel:	oob selection structure * @flags:	flag to indicate if nand_get_device/nand_release_device should be preformed *		and how many corrected error bits are acceptable: *		  bits 0..7 - number of tolerable errors *		  bit  8    - 0 == do not get/release chip, 1 == get/release chip * * NAND read with ECC */int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,			     size_t * retlen, u_char * buf, u_char * oob_buf, 			     struct nand_oobinfo *oobsel, int flags){	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;	struct nand_chip *this = mtd->priv;	u_char *data_poi, *oob_data = oob_buf;	u_char ecc_calc[32];	u_char ecc_code[32];        int eccmode, eccsteps;	int	*oob_config, datidx;	int	blockcheck = (1 << (this->phys_erase_shift - this->page_shift)) - 1;	int	eccbytes;	int	compareecc = 1;	int	oobreadlen;	DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);	/* Do not allow reads past end of device */	if ((from + len) > mtd->size) {		DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");		*retlen = 0;		return -EINVAL;	}	/* Grab the lock and see if the device is available */	if (flags & NAND_GET_DEVICE)		nand_get_device (this, mtd, FL_READING);	/* Autoplace of oob data ? Use the default placement scheme */	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)		oobsel = this->autooob;			eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;	oob_config = oobsel->eccpos;	/* Select the NAND device */	chipnr = (int)(from >> this->chip_shift);	this->select_chip(mtd, chipnr);	/* First we calculate the starting page */	realpage = (int) (from >> this->page_shift);	page = realpage & this->pagemask;	/* Get raw starting column */	col = from & (mtd->oobblock - 1);	end = mtd->oobblock;	ecc = this->eccsize;	eccbytes = this->eccbytes;		if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))		compareecc = 0;	oobreadlen = mtd->oobsize;	if (this->options & NAND_HWECC_SYNDROME) 		oobreadlen -= oobsel->eccbytes;	/* Loop until all data read */	while (read < len) {				int aligned = (!col && (len - read) >= end);		/* 		 * If the read is not page aligned, we have to read into data buffer		 * due to ecc, else we read into return buffer direct		 */		if (aligned)			data_poi = &buf[read];		else 			data_poi = this->data_buf;				/* Check, if we have this page in the buffer 		 *		 * FIXME: Make it work when we must provide oob data too,		 * check the usage of data_buf oob field		 */		if (realpage == this->pagebuf && !oob_buf) {			/* aligned read ? */			if (aligned)				memcpy (data_poi, this->data_buf, end);			goto readdata;		}		/* Check, if we must send the read command */		if (sndcmd) {			this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page);			sndcmd = 0;		}			/* get oob area, if we have no oob buffer from fs-driver */		if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||			oobsel->useecc == MTD_NANDECC_AUTOPL_USR)			oob_data = &this->data_buf[end];		eccsteps = this->eccsteps;				switch (eccmode) {		case NAND_ECC_NONE: {	/* No ECC, Read in a page */			static unsigned long lastwhinge = 0;			if ((lastwhinge / HZ) != (jiffies / HZ)) {				printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n");				lastwhinge = jiffies;			}			this->read_buf(mtd, data_poi, end);			break;		}					case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */			this->read_buf(mtd, data_poi, end);			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=3, datidx += ecc) 				this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);			break;			default:			for (i = 0, datidx = 0; eccsteps; eccsteps--, i+=eccbytes, datidx += ecc) {				this->enable_hwecc(mtd, NAND_ECC_READ);				this->read_buf(mtd, &data_poi[datidx], ecc);				/* HW ecc with syndrome calculation must read the				 * syndrome from flash immidiately after the data */				if (!compareecc) {					/* Some hw ecc generators need to know when the					 * syndrome is read from flash */					this->enable_hwecc(mtd, NAND_ECC_READSYN);					this->read_buf(mtd, &oob_data[i], eccbytes);					/* We calc error correction directly, it checks the hw					 * generator for an error, reads back the syndrome and					 * does the error correction on the fly */					ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);					if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {						DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 							"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);						ecc_failed++;					}				} else {					this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);				}				}			break;								}		/* read oobdata */		this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);		/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */		if (!compareecc)			goto readoob;					/* Pick the ECC bytes out of the oob data */		for (j = 0; j < oobsel->eccbytes; j++)			ecc_code[j] = oob_data[oob_config[j]];		/* correct data, if neccecary */		for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {			ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);						/* Get next chunk of ecc bytes */			j += eccbytes;						/* Check, if we have a fs supplied oob-buffer, 			 * This is the legacy mode. Used by YAFFS1			 * Should go away some day			 */			if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) { 				int *p = (int *)(&oob_data[mtd->oobsize]);				p[i] = ecc_status;			}						if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {					DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);				ecc_failed++;			}		}			readoob:		/* check, if we have a fs supplied oob-buffer */		if (oob_buf) {			/* without autoplace. Legacy mode used by YAFFS1 */			switch(oobsel->useecc) {			case MTD_NANDECC_AUTOPLACE:			case MTD_NANDECC_AUTOPL_USR:				/* Walk through the autoplace chunks */				for (i = 0; oobsel->oobfree[i][1]; i++) {					int from = oobsel->oobfree[i][0];					int num = oobsel->oobfree[i][1];					memcpy(&oob_buf[oob], &oob_data[from], num);					oob += num;				}				break;			case MTD_NANDECC_PLACE:				/* YAFFS1 legacy mode */				oob_data += this->eccsteps * sizeof (int);			default:				oob_data += mtd->oobsize;			}		}	readdata:		/* Partial page read, transfer data into fs buffer */		if (!aligned) { 			for (j = col; j < end && read < len; j++)				buf[read++] = data_poi[j];			this->pagebuf = realpage;			} else					read += mtd->oobblock;		/* Apply delay or wait for ready/busy pin 		 * Do this before the AUTOINCR check, so no problems		 * arise if a chip which does auto increment		 * is marked as NOAUTOINCR by the board driver.		*/		if (!this->dev_ready) 			udelay (this->chip_delay);

⌨️ 快捷键说明

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