mtd/drivers/mtd/nand diskonchip.c,1.35,1.36

gleixner at infradead.org gleixner at infradead.org
Fri Oct 1 17:46:19 EDT 2004


Update of /home/cvs/mtd/drivers/mtd/nand
In directory phoenix.infradead.org:/tmp/cvs-serv8258

Modified Files:
	diskonchip.c 
Log Message:
Use the generic RS-library for error correction

Index: diskonchip.c
===================================================================
RCS file: /home/cvs/mtd/drivers/mtd/nand/diskonchip.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -u -r1.35 -r1.36
--- diskonchip.c	16 Sep 2004 23:27:14 -0000	1.35
+++ diskonchip.c	1 Oct 2004 21:46:16 -0000	1.36
@@ -8,7 +8,12 @@
  * Author: David Woodhouse <dwmw2 at infradead.org>
  * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown at ieee.org>
  * Diskonchip Millennium Plus support by Kalev Lember <kalev at smartlink.ee>
- *
+ * 
+ * Error correction code lifted from the old docecc code
+ * Author: Fabrice Bellard (fabrice.bellard at netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx at linutronix.de>
+ *  
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
  * $Id$
@@ -18,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
+#include <linux/rslib.h>
 #include <asm/io.h>
 
 #include <linux/mtd/mtd.h>
@@ -120,6 +126,105 @@
 MODULE_PARM(doc_config_location, "l");
 MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
 
+
+/* Sector size for HW ECC */
+#define SECTOR_SIZE 512
+/* The sector bytes are packed into NB_DATA 10 bit words */
+#define NB_DATA (((SECTOR_SIZE + 1) * 8 + 6) / 10)
+/* the Reed Solomon control structure */
+static struct rs_control *rs_decoder;
+
+/* 
+ * The HW decoder in the DoC ASIC's provides us a error syndrome,
+ * which we must convert to a standard syndrom usable by the generic
+ * Reed-Solomon library code.
+ *
+ * Fabrice Bellard figured this out in the old docecc code. I added
+ * some comments, improved a minor bit and converted it to make use
+ * of the generic Reed-Solomon libary. tglx
+ */
+static int doc_ecc_decode (struct rs_control *rs, uint8_t *data, uint8_t *ecc)
+{
+	int i, j, nerr, errpos[8];
+	uint8_t parity;
+	uint16_t ds[4], s[5], tmp, errval[8], syn[4];
+
+	/* Convert the ecc bytes into words */
+	ds[0] = ((ecc[4] & 0xff) >> 0) | ((ecc[5] & 0x03) << 8);
+	ds[1] = ((ecc[5] & 0xfc) >> 2) | ((ecc[2] & 0x0f) << 6);
+	ds[2] = ((ecc[2] & 0xf0) >> 4) | ((ecc[3] & 0x3f) << 4);
+	ds[3] = ((ecc[3] & 0xc0) >> 6) | ((ecc[0] & 0xff) << 2);
+	parity = ecc[1];
+
+	/* Initialize the syndrom buffer */
+	for (i = 0; i < NROOTS; i++)
+		s[i] = ds[0];
+	/* 
+	 *  Evaluate 
+	 *  s[i] = ds[3]x^3 + ds[2]x^2 + ds[1]x^1 + ds[0]
+	 *  where x = alpha^(FCR + i)
+	 */
+	for(j = 1; j < NROOTS; j++) {
+		if(ds[j] == 0)
+			continue;
+		tmp = INDEX_OF[ds[j]];
+		for(i = 0; i < NROOTS; i++)
+			s[i] ^= ALPHA_TO[MODNN(tmp + (FCR + i) * j)];
+	}
+
+	/* Calc s[i] = s[i] / alpha^(v + i) */
+	for (i = 0; i < NROOTS; i++) {
+		if (syn[i])
+ 			syn[i] = MODNN(INDEX_OF[s[i]] + (NN - FCR - i));
+	}
+	/* Call the decoder library */
+	nerr = decode_rs16 (rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
+
+	/* Incorrectable errors ? */
+	if (nerr < 0)
+		return nerr;
+
+	/* 
+	 * Correct the errors. The bitpositions are a bit of magic,
+	 * but they are given by the design of the de/encoder circuit
+	 * in the DoC ASIC's.
+	 */
+	for(i = 0;i < nerr; i++) {
+		int index, bitpos, pos = 1015 - errpos[i];
+		uint8_t val;
+		if (pos >= NB_DATA && pos < 1019)
+			continue;
+		if (pos < NB_DATA) {
+			/* extract bit position (MSB first) */
+			pos = 10 * (NB_DATA - 1 - pos) - 6;
+			/* now correct the following 10 bits. At most two bytes
+			   can be modified since pos is even */
+			index = (pos >> 3) ^ 1;
+			bitpos = pos & 7;
+			if ((index >= 0 && index < SECTOR_SIZE) || 
+			    index == (SECTOR_SIZE + 1)) {
+				val = (uint8_t) (errval[i] >> (2 + bitpos));
+				parity ^= val;
+				if (index < SECTOR_SIZE)
+					data[index] ^= val;
+			}
+			index = ((pos >> 3) + 1) ^ 1;
+			bitpos = (bitpos + 10) & 7;
+			if (bitpos == 0)
+				bitpos = 8;
+			if ((index >= 0 && index < SECTOR_SIZE) || 
+			    index == (SECTOR_SIZE + 1)) {
+				val = (uint8_t)(errval[i] << (8 - bitpos));
+				parity ^= val;
+				if (index < SECTOR_SIZE)
+					data[index] ^= val;
+			}
+		}
+	}
+	/* If the parity is wrong, no rescue possible */
+	return parity ? -1 : nerr;
+}
+
 static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 {
 	volatile char dummy;
@@ -916,7 +1021,7 @@
 		   erased block, in which case the ECC will not come out right.
 		   We'll suppress the error and tell the caller everything's
 		   OK.  Because it is. */
-		if (!emptymatch) ret = doc_decode_ecc (dat, calc_ecc);
+		if (!emptymatch) ret = doc_ecc_decode (rs_decoder, dat, calc_ecc);
 		if (ret > 0)
 			printk(KERN_ERR "doc200x_correct_data corrected %d errors\n", ret);
 	}	
@@ -1591,6 +1696,23 @@
 	return ret;
 }
 
+static void release_nanddoc(void)
+{
+ 	struct mtd_info *mtd, *nextmtd;
+	struct nand_chip *nand;
+	struct doc_priv *doc;
+
+	for (mtd = doclist; mtd; mtd = nextmtd) {
+		nand = mtd->priv;
+		doc = (void *)nand->priv;
+
+		nextmtd = doc->nextdoc;
+		nand_release(mtd);
+		iounmap((void *)doc->virtadr);
+		kfree(mtd);
+	}
+}
+
 int __init init_nanddoc(void)
 {
 	int i;
@@ -1609,23 +1731,34 @@
 		printk(KERN_INFO "No valid DiskOnChip devices found\n");
 		return -ENODEV;
 	}
+
+	/* We could create the decoder on demand, if memory is a concern.
+	 * This way we have it handy, if an error happens 
+	 *
+	 * Symbolsize is 10 (bits)
+	 * Primitve polynomial is x^10+x^3+1
+	 * first consecutive root is 510
+	 * primitve element to generate roots = 1
+	 * generator polinomial degree = 4
+	 */
+	rs_decoder = init_rs (10, 0x409, 510, 1, 4);
+ 	if (!rs_decoder) {
+		printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
+		release_nanddoc();
+		return -ENOMEM;
+	}
+
 	return 0;
 }
 
 void __exit cleanup_nanddoc(void)
 {
-	struct mtd_info *mtd, *nextmtd;
-	struct nand_chip *nand;
-	struct doc_priv *doc;
+	/* Cleanup the nand/DoC resources */
+	release_nanddoc();
 
-	for (mtd = doclist; mtd; mtd = nextmtd) {
-		nand = mtd->priv;
-		doc = (void *)nand->priv;
-
-		nextmtd = doc->nextdoc;
-		nand_release(mtd);
-		iounmap((void *)doc->virtadr);
-		kfree(mtd);
+	/* Free the reed solomon resources */
+	if (rs_decoder) {
+		free_rs(rs_decoder);
 	}
 }
 





More information about the linux-mtd-cvs mailing list