mtd/drivers/mtd/nand nand_base.c,1.98,1.99
gleixner at infradead.org
gleixner at infradead.org
Wed Jun 16 17:09:55 EDT 2004
Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv6351
Modified Files:
nand_base.c
Log Message:
Support for hwecc generators which calc a syndrome on read
Index: nand_base.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/nand_base.c,v
retrieving revision 1.98
retrieving revision 1.99
diff -u -r1.98 -r1.99
--- nand_base.c 7 Jun 2004 19:56:48 -0000 1.98
+++ nand_base.c 16 Jun 2004 21:09:52 -0000 1.99
@@ -838,11 +838,18 @@
case NAND_ECC_HW3_512:
eccbytes += 3;
for (; eccsteps; eccsteps--) {
- this->enable_hwecc(mtd, NAND_ECC_WRITE); /* enable hardware ecc logic for write */
+ /* 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, NULL, 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;
@@ -853,7 +860,10 @@
}
/* Write out OOB data */
- this->write_buf(mtd, oob_buf, mtd->oobsize);
+ 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);
@@ -897,36 +907,50 @@
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, datidx = 0, oobofs = 0, res = -EIO;
- u_char oobdata[64];
+ 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(;;) {
-
- /* Loop through and verify the data */
- if (this->verify_buf(mtd, &this->data_poi[datidx], mtd->oobblock)) {
- DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page);
- goto out;
+ 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;
}
- datidx += mtd->oobblock;
+
/* 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)) {
+ 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);
+ this->read_buf(mtd, oobdata, mtd->oobsize - hweccbytes * eccsteps);
- if (oobsel->useecc != MTD_NANDECC_OFF) {
- int ecc_bytes = oobsel->eccbytes;
+ if (oobsel->useecc != MTD_NANDECC_OFF && !hweccbytes) {
+ int ecccnt = oobsel->eccbytes;
- for (i = 0; i < ecc_bytes; i++) {
+ for (i = 0; i < ecccnt; i++) {
int idx = oobsel->eccpos[i];
if (oobdata[idx] != oob_buf[oobofs + idx] ) {
DEBUG (MTD_DEBUG_LEVEL0,
@@ -937,7 +961,7 @@
}
}
}
- oobofs += mtd->oobsize;
+ oobofs += mtd->oobsize - hweccbytes * eccsteps;
page++;
numpages--;
if (!numpages)
@@ -1013,6 +1037,8 @@
int *oob_config, datidx;
int blockcheck = (mtd->erasesize >> this->page_shift) - 1;
int eccbytes = 3;
+ int compareecc = 1;
+ int oobreadlen;
DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len);
@@ -1057,9 +1083,17 @@
break;
case NAND_ECC_HW8_512: /* Hardware ECC 8 byte / 512 byte data */
eccbytes = 8;
+ break;
+ case NAND_ECC_NONE:
+ compareecc = 0;
break;
}
+ if (this->options & NAND_HWECC_SYNDROME)
+ compareecc = 0;
+
+ oobreadlen = (this->options & NAND_HWECC_SYNDROME) ? oobsel->eccbytes : mtd->oobsize;
+
/* Loop until all data read */
while (read < len) {
@@ -1121,7 +1155,23 @@
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);
- this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
+
+ /* 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, &ecc_calc[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 */
+ if (this->correct_data(mtd, &data_poi[datidx], &ecc_code[i], &ecc_calc[i]) == -1) {
+ DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
+ ecc_failed++;
+ }
+ } else
+ this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
}
break;
@@ -1131,11 +1181,11 @@
}
/* read oobdata */
- this->read_buf(mtd, oob_data, mtd->oobsize);
-
- /* Skip ECC, if not active */
- if (eccmode == NAND_ECC_NONE)
- goto readdata;
+ this->read_buf(mtd, oob_data, 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++)
@@ -1148,8 +1198,9 @@
/* Get next chunk of ecc bytes */
j += eccbytes;
- /* check, if we have a fs supplied oob-buffer,
+ /* 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_AUTOPLACE) {
int *p = (int *)(&oob_data[mtd->oobsize]);
@@ -1162,6 +1213,7 @@
}
}
+ readoob:
/* check, if we have a fs supplied oob-buffer */
if (oob_buf) {
/* without autoplace. Legacy mode used by YAFFS1 */
@@ -1178,7 +1230,7 @@
oob += mtd->oobavail;
}
}
-readdata:
+ readdata:
/* Partial page read, transfer data into fs buffer */
if (!aligned) {
for (j = col; j < end && read < len; j++)
@@ -2394,7 +2446,8 @@
this->eccsize = 512; /* set eccsize to 512 and fall through for function check */
case NAND_ECC_HW3_256:
- if (this->calculate_ecc && this->correct_data && this->enable_hwecc)
+ if ((this->calculate_ecc || (this->options & NAND_HWECC_SYNDROME)) &&
+ this->correct_data && this->enable_hwecc)
break;
printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n");
BUG();
More information about the linux-mtd-cvs
mailing list