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