public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
From: Vitaly Wool <vwool@ru.mvista.com>
To: linux-mtd@lists.infradead.org
Subject: NAND/ HW ECC problem
Date: Mon, 19 Sep 2005 17:40:24 +0400	[thread overview]
Message-ID: <432EBFC8.3090803@ru.mvista.com> (raw)

[-- Attachment #1: Type: text/plain, Size: 1033 bytes --]

Greetings,

we're currently working on NAND flash driver implementation for a new 
ARM926-based board. The flash controller is SanDisk's MLC, and the the 
requirement is to use hardware ECC capabilities provided by this controller.

We've come across several hardships with generic MTD NAND stuff carrying 
out this task.

First, it turned to be necessary to add one more ECC type 
(NAND_ECC_HW10_512): this controller stores 10 ECC data bytes after each 
512-byte block. Also the need to change size of eccpos array off of 
nand_oobinfo structure arose: for flashes with 2K-sector, this turned to 
be 40 bytes for each sector.

The serious problem we came across also was that nand_write_page doesn't 
follow the free bytes reference for OOB to write ECC data what was 
obviously wrong. As far as I understand, the DoC flashes have specific 
mechanism for handling that, so he legacy variant was left for the DoC, 
dunno whether it's right.

Attached is the patch suggested to fix the problems described.

Best regards,
   Vitaly



[-- Attachment #2: nand-ecc.patch --]
[-- Type: text/plain, Size: 3298 bytes --]

Index: linux-2.6.10/drivers/mtd/nand/nand_base.c
===================================================================
--- linux-2.6.10.orig/drivers/mtd/nand/nand_base.c
+++ linux-2.6.10/drivers/mtd/nand/nand_base.c
@@ -904,11 +904,17 @@ static int nand_write_page (struct mtd_i
 		}
 		break;
 	}
-										
+
 	/* Write out OOB data */
-	if (this->options & NAND_HWECC_SYNDROME)
-		this->write_buf(mtd, &oob_buf[oobsel->eccbytes], mtd->oobsize - oobsel->eccbytes);
-	else 
+	if (this->options & NAND_HWECC_SYNDROME) 
+		if (mtd->ecctype != MTD_ECC_RS_DiskOnChip ) 
+			for (i = 0; oobsel->oobfree[i][1]; i++ ) 
+		    		this->write_buf (mtd, 
+						 oob_buf+oobsel->oobfree[i][0],
+			    			 oobsel->oobfree[i][1] );
+		else /* DiskOnChip legacy ECC */
+			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 */
@@ -1247,8 +1253,15 @@ int nand_do_read_ecc (struct mtd_info *m
 			break;						
 		}
 
+		
 		/* read oobdata */
-		this->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
+		if (mtd->ecctype != MTD_ECC_RS_DiskOnChip )
+			for (i = 0; oobsel->oobfree[i][1]; i++ ) 
+		    		this->read_buf (mtd, 
+						oob_data+oobsel->oobfree[i][0],
+			    			oobsel->oobfree[i][1] );
+		else /* legacy DiskOnChip ECC */
+			 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)
@@ -2542,6 +2555,7 @@ int nand_scan (struct mtd_info *mtd, int
 			this->eccsize = 2048;
 		break;
 
+	case NAND_ECC_HW10_512:
 	case NAND_ECC_HW3_512: 
 	case NAND_ECC_HW6_512: 
 	case NAND_ECC_HW8_512: 
@@ -2578,7 +2592,9 @@ int nand_scan (struct mtd_info *mtd, int
 	switch (this->eccmode) {
 	case NAND_ECC_HW12_2048:
 		this->eccbytes += 4;
-	case NAND_ECC_HW8_512: 
+	case NAND_ECC_HW10_512: 
+		this->eccbytes += 2;		
+    	case NAND_ECC_HW8_512: 
 		this->eccbytes += 2;
 	case NAND_ECC_HW6_512: 
 		this->eccbytes += 3;
@@ -2600,6 +2616,7 @@ int nand_scan (struct mtd_info *mtd, int
 	case NAND_ECC_HW3_512:
 	case NAND_ECC_HW6_512:
 	case NAND_ECC_HW8_512:
+	case NAND_ECC_HW10_512:
 		this->eccsteps = mtd->oobblock / 512;
 		break;
 	case NAND_ECC_HW3_256:
Index: linux-2.6.10/include/mtd/mtd-abi.h
===================================================================
--- linux-2.6.10.orig/include/mtd/mtd-abi.h
+++ linux-2.6.10/include/mtd/mtd-abi.h
@@ -115,7 +115,7 @@ struct nand_oobinfo {
 	uint32_t useecc;
 	uint32_t eccbytes;
 	uint32_t oobfree[8][2];
-	uint32_t eccpos[32];
+	uint32_t eccpos[40];
 };
 
 #endif /* __MTD_ABI_H__ */
Index: linux-2.6.10/include/linux/mtd/nand.h
===================================================================
--- linux-2.6.10.orig/include/linux/mtd/nand.h
+++ linux-2.6.10/include/linux/mtd/nand.h
@@ -161,8 +161,10 @@ extern int nand_read_raw (struct mtd_inf
 #define NAND_ECC_HW6_512	4
 /* Hardware ECC 8 byte ECC per 512 Byte data */
 #define NAND_ECC_HW8_512	6
+/* SanDisk MLC: 10 bytes ECC per 512 Byte data */
+#define NAND_ECC_HW10_512	7
 /* Hardware ECC 12 byte ECC per 2048 Byte data */
-#define NAND_ECC_HW12_2048	7
+#define NAND_ECC_HW12_2048	8
 
 /*
  * Constants for Hardware ECC

             reply	other threads:[~2005-09-19 13:40 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-19 13:40 Vitaly Wool [this message]
2005-09-19 20:40 ` NAND/ HW ECC problem Thomas Gleixner
2005-09-19 21:40   ` Vitaly Wool
2005-09-19 21:43     ` Thomas Gleixner
2005-09-20  9:19   ` Vitaly Wool
2005-09-20 10:04     ` Thomas Gleixner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=432EBFC8.3090803@ru.mvista.com \
    --to=vwool@ru.mvista.com \
    --cc=linux-mtd@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox