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

Commit f5bbdacc authored by Thomas Gleixner's avatar Thomas Gleixner Committed by David Woodhouse
Browse files

[MTD] NAND Modularize read function



Split the core of the read function out and implement
seperate handling functions for software and hardware
ECC.

Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 9577f44a
Loading
Loading
Loading
Loading
+3 −1
Original line number Original line Diff line number Diff line
@@ -968,12 +968,14 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign
	return 0;
	return 0;
}
}


static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
				u_char *read_ecc, u_char *isnull)
{
{
	int i, ret = 0;
	int i, ret = 0;
	struct nand_chip *this = mtd->priv;
	struct nand_chip *this = mtd->priv;
	struct doc_priv *doc = this->priv;
	struct doc_priv *doc = this->priv;
	void __iomem *docptr = doc->virtadr;
	void __iomem *docptr = doc->virtadr;
	uint8_t calc_ecc[6];
	volatile u_char dummy;
	volatile u_char dummy;
	int emptymatch = 1;
	int emptymatch = 1;


+227 −221
Original line number Original line Diff line number Diff line
@@ -976,256 +976,224 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *chip, int p
#endif
#endif


/**
/**
 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
 * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
 * @mtd:	MTD device structure
 * @mtd:	mtd info structure
 * @from:	offset to read from
 * @chip:	nand chip info structure
 * @len:	number of bytes to read
 * @buf:	buffer to store read data
 * @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, uint8_t *buf)
static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
				uint8_t *buf)
{
{
	return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
	int i, eccsize = chip->ecc.size;
	int eccbytes = chip->ecc.bytes;
	int eccsteps = chip->ecc.steps;
	uint8_t *p = buf;
	uint8_t *ecc_calc = chip->oob_buf + mtd->oobsize;
	uint8_t *ecc_code = ecc_calc + mtd->oobsize;
	int *eccpos = chip->autooob->eccpos;

	chip->read_buf(mtd, buf, mtd->writesize);
	chip->read_buf(mtd, chip->oob_buf, mtd->oobsize);

	if (chip->ecc.mode == NAND_ECC_NONE)
		return 0;

	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
		chip->ecc.calculate(mtd, p, &ecc_calc[i]);

	for (i = 0; i < chip->ecc.total; i++)
		ecc_code[i] = chip->oob_buf[eccpos[i]];

	eccsteps = chip->ecc.steps;
	p = buf;

	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
		int stat;

		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
		if (stat == -1)
			mtd->ecc_stats.failed++;
		else
			mtd->ecc_stats.corrected += stat;
	}
	return 0;
}
}


/**
/**
 * nand_do_read_ecc - [MTD Interface] Read data with ECC
 * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
 * @mtd:	MTD device structure
 * @mtd:	mtd info structure
 * @from:	offset to read from
 * @chip:	nand chip info structure
 * @len:	number of bytes to read
 * @buf:	buffer to store read data
 * @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
 * Not for syndrome calculating ecc controllers which need a special oob layout
 */
 */
int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
		     size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags)
				uint8_t *buf)
{
{

	int i, eccsize = chip->ecc.size;
	int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
	int eccbytes = chip->ecc.bytes;
	int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
	int eccsteps = chip->ecc.steps;
	struct nand_chip *chip = mtd->priv;
	uint8_t *p = buf;
	uint8_t *data_poi, *oob_data = oob_buf;
	uint8_t *ecc_calc = chip->oob_buf + mtd->oobsize;
	uint8_t ecc_calc[32];
	uint8_t *ecc_code = ecc_calc + mtd->oobsize;
	uint8_t ecc_code[32];
	int *eccpos = chip->autooob->eccpos;
	int eccmode, eccsteps;

	int *oob_config, datidx;
	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
	int blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
		chip->ecc.hwctl(mtd, NAND_ECC_READ);
	int eccbytes;
		chip->read_buf(mtd, p, eccsize);
	int compareecc = 1;
		chip->ecc.calculate(mtd, p, &ecc_calc[i]);
	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;
	}
	}
	chip->read_buf(mtd, chip->oob_buf, mtd->oobsize);


	/* Grab the lock and see if the device is available */
	for (i = 0; i < chip->ecc.total; i++)
	if (flags & NAND_GET_DEVICE)
		ecc_code[i] = chip->oob_buf[eccpos[i]];
		nand_get_device(chip, mtd, FL_READING);

	/* Autoplace of oob data ? Use the default placement scheme */
	if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
		oobsel = chip->autooob;

	eccmode = oobsel->useecc ? chip->ecc.mode : NAND_ECC_NONE;
	oob_config = oobsel->eccpos;


	/* Select the NAND device */
	eccsteps = chip->ecc.steps;
	chipnr = (int)(from >> chip->chip_shift);
	p = buf;
	chip->select_chip(mtd, chipnr);

	/* First we calculate the starting page */
	realpage = (int)(from >> chip->page_shift);
	page = realpage & chip->pagemask;

	/* Get raw starting column */
	col = from & (mtd->writesize - 1);

	end = mtd->writesize;
	ecc = chip->ecc.size;
	eccbytes = chip->ecc.bytes;

	if ((eccmode == NAND_ECC_NONE) || (chip->options & NAND_HWECC_SYNDROME))
		compareecc = 0;

	oobreadlen = mtd->oobsize;
	if (chip->options & NAND_HWECC_SYNDROME)
		oobreadlen -= oobsel->eccbytes;


	/* Loop until all data read */
	for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
	while (read < len) {
		int stat;


		int aligned = (!col && (len - read) >= end);
		stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
		/*
		if (stat == -1)
		 * If the read is not page aligned, we have to read into data buffer
			mtd->ecc_stats.failed++;
		 * due to ecc, else we read into return buffer direct
		 */
		if (aligned)
			data_poi = &buf[read];
		else
		else
			data_poi = chip->data_buf;
			mtd->ecc_stats.corrected += stat;
	}
	return 0;
}


		/* Check, if we have this page in the buffer
/**
 * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
 * @mtd:	mtd info structure
 * @chip:	nand chip info structure
 * @buf:	buffer to store read data
 *
 *
		 * FIXME: Make it work when we must provide oob data too,
 * The hw generator calculates the error syndrome automatically. Therefor
		 * check the usage of data_buf oob field
 * we need a special oob layout and .
 */
 */
		if (realpage == chip->pagebuf && !oob_buf) {
static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
			/* aligned read ? */
				   uint8_t *buf)
			if (aligned)
{
				memcpy(data_poi, chip->data_buf, end);
	int i, eccsize = chip->ecc.size;
			goto readdata;
	int eccbytes = chip->ecc.bytes;
		}
	int eccsteps = chip->ecc.steps;

	uint8_t *p = buf;
		/* Check, if we must send the read command */
	uint8_t *oob = chip->oob_buf;
		if (sndcmd) {
			chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
			sndcmd = 0;
		}


		/* get oob area, if we have no oob buffer from fs-driver */
	for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
		if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
		int stat;
			oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
			oob_data = &chip->data_buf[end];


		eccsteps = chip->ecc.steps;
		chip->ecc.hwctl(mtd, NAND_ECC_READ);
		chip->read_buf(mtd, p, eccsize);


		switch (eccmode) {
		if (chip->ecc.prepad) {
		case NAND_ECC_NONE:{
			chip->read_buf(mtd, oob, chip->ecc.prepad);
				/* No ECC, Read in a page */
			oob += chip->ecc.prepad;
				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;
				}
				chip->read_buf(mtd, data_poi, end);
				break;
		}
		}


		case NAND_ECC_SOFT:	/* Software ECC 3/256: Read in a page + oob data */
		chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
			chip->read_buf(mtd, data_poi, end);
		chip->read_buf(mtd, oob, eccbytes);
			for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
		stat = chip->ecc.correct(mtd, p, oob, NULL);
				chip->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
			break;


		default:
		if (stat == -1)
			for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
			mtd->ecc_stats.failed++;
				chip->ecc.hwctl(mtd, NAND_ECC_READ);
		else
				chip->read_buf(mtd, &data_poi[datidx], ecc);
			mtd->ecc_stats.corrected += stat;


				/* HW ecc with syndrome calculation must read the
		oob += eccbytes;
				 * syndrome from flash immidiately after the data */

				if (!compareecc) {
		if (chip->ecc.postpad) {
					/* Some hw ecc generators need to know when the
			chip->read_buf(mtd, oob, chip->ecc.postpad);
					 * syndrome is read from flash */
			oob += chip->ecc.postpad;
					chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
					chip->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 = chip->ecc.correct(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 {
					chip->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
		}
		}
	}
	}
			break;

	/* Calculate remaining oob bytes */
	i = oob - chip->oob_buf;
	if (i)
		chip->read_buf(mtd, oob, i);

	return 0;
}
}


		/* read oobdata */
/**
		chip->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
 * nand_do_read - [Internal] 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
 *
 * Internal function. Called with chip held.
 */
int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
		 size_t *retlen, uint8_t *buf)
{
	int chipnr, page, realpage, col, bytes, aligned;
	struct nand_chip *chip = mtd->priv;
	struct mtd_ecc_stats stats;
	int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
	int sndcmd = 1;
	int ret = 0;
	uint32_t readlen = len;
	uint8_t *bufpoi;

	stats = mtd->ecc_stats;


		/* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */
	chipnr = (int)(from >> chip->chip_shift);
		if (!compareecc)
	chip->select_chip(mtd, chipnr);
			goto readoob;


		/* Pick the ECC bytes out of the oob data */
	realpage = (int)(from >> chip->page_shift);
		for (j = 0; j < oobsel->eccbytes; j++)
	page = realpage & chip->pagemask;
			ecc_code[j] = oob_data[oob_config[j]];


		/* correct data, if necessary */
	col = (int)(from & (mtd->writesize - 1));
		for (i = 0, j = 0, datidx = 0; i < chip->ecc.steps; i++, datidx += ecc) {
			ecc_status = chip->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);


			/* Get next chunk of ecc bytes */
	while(1) {
			j += eccbytes;
		bytes = min(mtd->writesize - col, readlen);
		aligned = (bytes == mtd->writesize);


			/* Check, if we have a fs supplied oob-buffer,
		/* Is the current page in the buffer ? */
			 * This is the legacy mode. Used by YAFFS1
		if (realpage != chip->pagebuf) {
			 * Should go away some day
			bufpoi = aligned ? buf : chip->data_buf;
			 */
			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))) {
			if (likely(sndcmd)) {
				DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
				chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
				ecc_failed++;
				sndcmd = 0;
			}
			}
			}


	      readoob:
			/* Now read the page into the buffer */
		/* check, if we have a fs supplied oob-buffer */
			ret = chip->ecc.read_page(mtd, chip, bufpoi);
		if (oob_buf) {
			if (ret < 0)
			/* 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;
				break;
			case MTD_NANDECC_PLACE:

				/* YAFFS1 legacy mode */
			/* Transfer not aligned data */
				oob_data += chip->ecc.steps * sizeof(int);
			default:
				oob_data += mtd->oobsize;
			}
		}
	readdata:
		/* Partial page read, transfer data into fs buffer */
			if (!aligned) {
			if (!aligned) {
			for (j = col; j < end && read < len; j++)
				buf[read++] = data_poi[j];
				chip->pagebuf = realpage;
				chip->pagebuf = realpage;
		} else
				memcpy(buf, chip->data_buf + col, bytes);
			read += mtd->writesize;
			}


		/* Apply delay or wait for ready/busy pin
			if (!(chip->options & NAND_NO_READRDY)) {
		 * Do this before the AUTOINCR check, so no problems
				/*
		 * arise if a chip which does auto increment
				 * Apply delay or wait for ready/busy pin. Do
		 * is marked as NOAUTOINCR by the board driver.
				 * 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 (!chip->dev_ready)
				if (!chip->dev_ready)
					udelay(chip->chip_delay);
					udelay(chip->chip_delay);
				else
				else
					nand_wait_ready(mtd);
					nand_wait_ready(mtd);
			}
		} else
			memcpy(buf, chip->data_buf + col, bytes);


		if (read == len)
		buf += bytes;
		readlen -= bytes;

		if (!readlen)
			break;
			break;


		/* For subsequent reads align to page boundary. */
		/* For subsequent reads align to page boundary. */
@@ -1240,24 +1208,51 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
			chip->select_chip(mtd, -1);
			chip->select_chip(mtd, -1);
			chip->select_chip(mtd, chipnr);
			chip->select_chip(mtd, chipnr);
		}
		}

		/* Check, if the chip supports auto page increment
		/* Check, if the chip supports auto page increment
		 * or if we have hit a block boundary.
		 * or if we have hit a block boundary.
		 */
		 */
		if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck))
		if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
			sndcmd = 1;
			sndcmd = 1;
	}
	}


	/* Deselect and wake up anyone waiting on the device */
	*retlen = len - (size_t) readlen;
	if (flags & NAND_GET_DEVICE)
		nand_release_device(mtd);


	/*
	if (ret)
	 * Return success, if no ECC failures, else -EBADMSG
		return ret;
	 * fs driver will take care of that, because

	 * retlen == desired len and result == -EBADMSG
	return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0;
}

/**
 * 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
 *
 * Get hold of the chip and call nand_do_read
 */
 */
	*retlen = read;
static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
	return ecc_failed ? -EBADMSG : 0;
		     size_t *retlen, uint8_t *buf)
{
	int ret;

	*retlen = 0;
	/* Do not allow reads past end of device */
	if ((from + len) > mtd->size)
		return -EINVAL;
	if (!len)
		return 0;

	nand_get_device(mtd->priv, mtd, FL_READING);

	ret = nand_do_read(mtd, from, len, retlen, buf);

	nand_release_device(mtd);

	return ret;
}
}


/**
/**
@@ -2417,6 +2412,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
	 */
	 */
	switch (chip->ecc.mode) {
	switch (chip->ecc.mode) {
	case NAND_ECC_HW:
	case NAND_ECC_HW:
		/* Use standard hwecc read page function ? */
		if (!chip->ecc.read_page)
			chip->ecc.read_page = nand_read_page_hwecc;

	case NAND_ECC_HW_SYNDROME:
	case NAND_ECC_HW_SYNDROME:
		if (!chip->ecc.calculate || !chip->ecc.correct ||
		if (!chip->ecc.calculate || !chip->ecc.correct ||
		    !chip->ecc.hwctl) {
		    !chip->ecc.hwctl) {
@@ -2424,6 +2423,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
			       "Hardware ECC not possible\n");
			       "Hardware ECC not possible\n");
			BUG();
			BUG();
		}
		}
		/* Use standard syndrome read page function ? */
		if (!chip->ecc.read_page)
			chip->ecc.read_page = nand_read_page_syndrome;

		if (mtd->writesize >= chip->ecc.size)
		if (mtd->writesize >= chip->ecc.size)
			break;
			break;
		printk(KERN_WARNING "%d byte HW ECC not possible on "
		printk(KERN_WARNING "%d byte HW ECC not possible on "
@@ -2434,6 +2437,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
	case NAND_ECC_SOFT:
	case NAND_ECC_SOFT:
		chip->ecc.calculate = nand_calculate_ecc;
		chip->ecc.calculate = nand_calculate_ecc;
		chip->ecc.correct = nand_correct_data;
		chip->ecc.correct = nand_correct_data;
		chip->ecc.read_page = nand_read_page_swecc;
		chip->ecc.size = 256;
		chip->ecc.size = 256;
		chip->ecc.bytes = 3;
		chip->ecc.bytes = 3;
		break;
		break;
@@ -2441,6 +2445,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
	case NAND_ECC_NONE:
	case NAND_ECC_NONE:
		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
		       "This is not recommended !!\n");
		       "This is not recommended !!\n");
		chip->ecc.read_page = nand_read_page_swecc;
		chip->ecc.size = mtd->writesize;
		chip->ecc.size = mtd->writesize;
		chip->ecc.bytes = 0;
		chip->ecc.bytes = 0;
		break;
		break;
@@ -2459,6 +2464,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
		printk(KERN_WARNING "Invalid ecc parameters\n");
		printk(KERN_WARNING "Invalid ecc parameters\n");
		BUG();
		BUG();
	}
	}
	chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;


	/* Initialize state */
	/* Initialize state */
	chip->state = FL_READY;
	chip->state = FL_READY;
+37 −25
Original line number Original line Diff line number Diff line
@@ -444,7 +444,8 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
 * note: see pages 34..37 of data sheet for details.
 * note: see pages 34..37 of data sheet for details.
 *
 *
 */
 */
static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page)
static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,
			     int state, int status, int page)
{
{
	int er_stat = 0;
	int er_stat = 0;
	int rtn, retlen;
	int rtn, retlen;
@@ -455,40 +456,51 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int s
	this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
	this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1);


	if (state == FL_ERASING) {
	if (state == FL_ERASING) {

		for (i = 0; i < 4; i++) {
		for (i = 0; i < 4; i++) {
			if (status & 1 << (i + 1)) {
			if (!(status & 1 << (i + 1)))
				this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1);
				continue;
			this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1),
				      -1, -1);
			rtn = this->read_byte(mtd);
			rtn = this->read_byte(mtd);
			this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
			this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
				if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {

					er_stat |= 1 << (i + 1);	/* err_ecc_not_avail */
			/* err_ecc_not_avail */
				}
			if (!(rtn & ERR_STAT_ECC_AVAILABLE))
			}
				er_stat |= 1 << (i + 1);
		}
		}

	} else if (state == FL_WRITING) {
	} else if (state == FL_WRITING) {

		unsigned long corrected = mtd->ecc_stats.corrected;

		/* single bank write logic */
		/* single bank write logic */
		this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1);
		this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1);
		rtn = this->read_byte(mtd);
		rtn = this->read_byte(mtd);
		this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
		this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);

		if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
		if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
			er_stat |= 1 << 1;	/* err_ecc_not_avail */
			/* err_ecc_not_avail */
		} else {
			er_stat |= 1 << 1;
			goto out;
		}

		len = mtd->writesize;
		len = mtd->writesize;
		buf = kmalloc(len, GFP_KERNEL);
		buf = kmalloc(len, GFP_KERNEL);
		if (!buf) {
		if (!buf) {
			printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");
			printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");
				er_stat = 1;	/* if we can't check, assume failed */
			er_stat = 1;
			} else {
			goto out;
				/* recovery read */
				/* page read */
				rtn = nand_do_read_ecc(mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
				if (rtn) {	/* if read failed or > 1-bit error corrected */
					er_stat |= 1 << 1;	/* ECC read failed */
		}
		}

		/* recovery read */
		rtn = nand_do_read(mtd, page, len, &retlen, buf);

		/* if read failed or > 1-bit error corrected */
		if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) {
			er_stat |= 1 << 1;
		kfree(buf);
		kfree(buf);
	}
	}
		}
	}


	rtn = status;
	rtn = status;
	if (er_stat == 0) {	/* if ECC is available   */
	if (er_stat == 0) {	/* if ECC is available   */
+8 −8
Original line number Original line Diff line number Diff line
@@ -483,10 +483,10 @@ extern int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd);
extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_update_bbt(struct mtd_info *mtd, loff_t offs);
extern int nand_default_bbt(struct mtd_info *mtd);
extern int nand_default_bbt(struct mtd_info *mtd);
extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_isbad_bbt(struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
extern int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr,
extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
			   int allowbbt);
			     size_t * retlen, uint8_t * buf, uint8_t * oob_buf,
extern int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
			     struct nand_oobinfo *oobsel, int flags);
			size_t * retlen, uint8_t * buf);


/*
/*
* Constants for oob configuration
* Constants for oob configuration