vserver 1.9.5.x5
[linux-2.6.git] / drivers / mtd / nand / diskonchip.c
index 0f7dedd..02135c3 100644 (file)
@@ -8,16 +8,23 @@
  * Author: David Woodhouse <dwmw2@infradead.org>
  * Additional Diskonchip 2000 and Millennium support by Dan Brown <dan_brown@ieee.org>
  * Diskonchip Millennium Plus support by Kalev Lember <kalev@smartlink.ee>
- *
+ * 
+ * Error correction code lifted from the old docecc code
+ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) 
+ * Copyright (C) 2000 Netgem S.A.
+ * converted to the generic Reed-Solomon library by Thomas Gleixner <tglx@linutronix.de>
+ *  
  * Interface to generic NAND code for M-Systems DiskOnChip devices
  *
- * $Id: diskonchip.c,v 1.34 2004/08/09 19:41:12 dbrown Exp $
+ * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
  */
 
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
+#include <linux/rslib.h>
+#include <linux/moduleparam.h>
 #include <asm/io.h>
 
 #include <linux/mtd/mtd.h>
@@ -62,7 +69,7 @@ static unsigned long __initdata doc_locations[] = {
 static struct mtd_info *doclist = NULL;
 
 struct doc_priv {
-       unsigned long virtadr;
+       void __iomem *virtadr;
        unsigned long physadr;
        u_char ChipID;
        u_char CDSNControl;
@@ -96,28 +103,136 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd);
 static void doc200x_select_chip(struct mtd_info *mtd, int chip);
 
 static int debug=0;
-MODULE_PARM(debug, "i");
+module_param(debug, int, 0);
 
 static int try_dword=1;
-MODULE_PARM(try_dword, "i");
+module_param(try_dword, int, 0);
 
 static int no_ecc_failures=0;
-MODULE_PARM(no_ecc_failures, "i");
+module_param(no_ecc_failures, int, 0);
 
+#ifdef CONFIG_MTD_PARTITIONS
 static int no_autopart=0;
-MODULE_PARM(no_autopart, "i");
+module_param(no_autopart, int, 0);
+#endif
 
 #ifdef MTD_NAND_DISKONCHIP_BBTWRITE
 static int inftl_bbt_write=1;
 #else
 static int inftl_bbt_write=0;
 #endif
-MODULE_PARM(inftl_bbt_write, "i");
+module_param(inftl_bbt_write, int, 0);
 
 static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
-MODULE_PARM(doc_config_location, "l");
+module_param(doc_config_location, ulong, 0);
 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)
+/* Number of roots */
+#define NROOTS 4
+/* First consective root */
+#define FCR 510
+/* Number of symbols */
+#define NN 1023
+
+/* 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 = rs->index_of[ds[j]];
+               for(i = 0; i < NROOTS; i++)
+                       s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
+       }
+
+       /* Calc s[i] = s[i] / alpha^(v + i) */
+       for (i = 0; i < NROOTS; i++) {
+               if (syn[i])
+                       syn[i] = rs_modnn(rs, rs->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;
@@ -139,7 +254,7 @@ static void DoC_Delay(struct doc_priv *doc, unsigned short cycles)
 /* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */
 static int _DoC_WaitReady(struct doc_priv *doc)
 {
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        unsigned long timeo = jiffies + (HZ * 10);
 
        if(debug) printk("_DoC_WaitReady...\n");
@@ -169,7 +284,7 @@ static int _DoC_WaitReady(struct doc_priv *doc)
 
 static inline int DoC_WaitReady(struct doc_priv *doc)
 {
-       unsigned long docptr = doc->virtadr;
+        void __iomem *docptr = doc->virtadr;
        int ret = 0;
 
        if (DoC_is_MillenniumPlus(doc)) {
@@ -194,8 +309,8 @@ static inline int DoC_WaitReady(struct doc_priv *doc)
 static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        if(debug)printk("write_byte %02x\n", datum);
        WriteDOC(datum, docptr, CDSNSlowIO);
@@ -205,8 +320,8 @@ static void doc2000_write_byte(struct mtd_info *mtd, u_char datum)
 static u_char doc2000_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        u_char ret;
 
        ReadDOC(docptr, CDSNSlowIO);
@@ -220,8 +335,8 @@ static void doc2000_writebuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
        if (debug)printk("writebuf of %d bytes: ", len);
        for (i=0; i < len; i++) {
@@ -236,8 +351,8 @@ static void doc2000_readbuf(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("readbuf of %d bytes: ", len);
@@ -251,8 +366,8 @@ static void doc2000_readbuf_dword(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug) printk("readbuf_dword of %d bytes: ", len);
@@ -272,8 +387,8 @@ static int doc2000_verifybuf(struct mtd_info *mtd,
                              const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        for (i=0; i < len; i++)
@@ -285,7 +400,7 @@ static int doc2000_verifybuf(struct mtd_info *mtd,
 static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        uint16_t ret;
 
        doc200x_select_chip(mtd, nr);
@@ -305,7 +420,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
                        uint32_t dword;
                        uint8_t byte[4];
                } ident;
-               unsigned long docptr = doc->virtadr;
+               void __iomem *docptr = doc->virtadr;
 
                doc200x_hwcontrol(mtd, NAND_CTL_SETCLE);
                doc2000_write_byte(mtd, NAND_CMD_READID);
@@ -327,7 +442,7 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
 static void __init doc2000_count_chips(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        uint16_t mfrid;
        int i;
 
@@ -348,7 +463,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd)
 
 static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
 {
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
 
        int status;
        
@@ -363,8 +478,8 @@ static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
 static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        WriteDOC(datum, docptr, CDSNSlowIO);
        WriteDOC(datum, docptr, Mil_CDSN_IO);
@@ -374,8 +489,8 @@ static void doc2001_write_byte(struct mtd_info *mtd, u_char datum)
 static u_char doc2001_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        //ReadDOC(docptr, CDSNSlowIO);
        /* 11.4.5 -- delay twice to allow extended length cycle */
@@ -389,8 +504,8 @@ static void doc2001_writebuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        for (i=0; i < len; i++)
@@ -403,8 +518,8 @@ static void doc2001_readbuf(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        /* Start read pipeline */
@@ -421,8 +536,8 @@ static int doc2001_verifybuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        /* Start read pipeline */
@@ -441,8 +556,8 @@ static int doc2001_verifybuf(struct mtd_info *mtd,
 static u_char doc2001plus_read_byte(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        u_char ret;
 
         ReadDOC(docptr, Mplus_ReadPipeInit);
@@ -456,8 +571,8 @@ static void doc2001plus_writebuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("writebuf of %d bytes: ", len);
@@ -473,8 +588,8 @@ static void doc2001plus_readbuf(struct mtd_info *mtd,
                            u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("readbuf of %d bytes: ", len);
@@ -503,8 +618,8 @@ static int doc2001plus_verifybuf(struct mtd_info *mtd,
                             const u_char *buf, int len)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
 
        if (debug)printk("verifybuf of %d bytes: ", len);
@@ -529,8 +644,8 @@ static int doc2001plus_verifybuf(struct mtd_info *mtd,
 static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int floor = 0;
 
        if(debug)printk("select chip (%d)\n", chip);
@@ -555,8 +670,8 @@ static void doc2001plus_select_chip(struct mtd_info *mtd, int chip)
 static void doc200x_select_chip(struct mtd_info *mtd, int chip)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int floor = 0;
 
        if(debug)printk("select chip (%d)\n", chip);
@@ -582,8 +697,8 @@ static void doc200x_select_chip(struct mtd_info *mtd, int chip)
 static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        switch(cmd) {
        case NAND_CTL_SETNCE:
@@ -620,8 +735,8 @@ static void doc200x_hwcontrol(struct mtd_info *mtd, int cmd)
 static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        /*
         * Must terminate write pipeline before sending any commands
@@ -724,8 +839,8 @@ static void doc2001plus_command (struct mtd_info *mtd, unsigned command, int col
 static int doc200x_dev_ready(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        if (DoC_is_MillenniumPlus(doc)) {
                /* 11.4.2 -- must NOP four times before checking FR/B# */
@@ -762,8 +877,8 @@ static int doc200x_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
 static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        /* Prime the ECC engine */
        switch(mode) {
@@ -781,8 +896,8 @@ static void doc200x_enable_hwecc(struct mtd_info *mtd, int mode)
 static void doc2001plus_enable_hwecc(struct mtd_info *mtd, int mode)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
 
        /* Prime the ECC engine */
        switch(mode) {
@@ -802,8 +917,8 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
                                 unsigned char *ecc_code)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        int i;
        int emptymatch = 1;
 
@@ -860,8 +975,8 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
 {
        int i, ret = 0;
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
-       unsigned long docptr = doc->virtadr;
+       struct doc_priv *doc = this->priv;
+        void __iomem *docptr = doc->virtadr;
        volatile u_char dummy;
        int emptymatch = 1;
        
@@ -914,7 +1029,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
                   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);
        }       
@@ -948,7 +1063,7 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
                                     const char *id, int findmirror)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
        int ret;
        size_t retlen;
@@ -991,7 +1106,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
                                struct mtd_partition *parts)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        int ret = 0;
        u_char *buf;
        struct NFTLMediaHeader *mh;
@@ -1087,7 +1202,7 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
                                 struct mtd_partition *parts)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        int ret = 0;
        u_char *buf;
        struct INFTLMediaHeader *mh;
@@ -1212,7 +1327,7 @@ static int __init nftl_scan_bbt(struct mtd_info *mtd)
 {
        int ret, numparts;
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        struct mtd_partition parts[2];
 
        memset((char *) parts, 0, sizeof(parts));
@@ -1251,7 +1366,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
 {
        int ret, numparts;
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
        struct mtd_partition parts[5];
 
        if (this->numchips > doc->chips_per_floor) {
@@ -1310,7 +1425,7 @@ static int __init inftl_scan_bbt(struct mtd_info *mtd)
 static inline int __init doc2000_init(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
 
        this->write_byte = doc2000_write_byte;
        this->read_byte = doc2000_read_byte;
@@ -1328,7 +1443,7 @@ static inline int __init doc2000_init(struct mtd_info *mtd)
 static inline int __init doc2001_init(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
 
        this->write_byte = doc2001_write_byte;
        this->read_byte = doc2001_read_byte;
@@ -1360,7 +1475,7 @@ static inline int __init doc2001_init(struct mtd_info *mtd)
 static inline int __init doc2001plus_init(struct mtd_info *mtd)
 {
        struct nand_chip *this = mtd->priv;
-       struct doc_priv *doc = (void *)this->priv;
+       struct doc_priv *doc = this->priv;
 
        this->write_byte = NULL;
        this->read_byte = doc2001plus_read_byte;
@@ -1385,13 +1500,13 @@ static inline int __init doc_probe(unsigned long physadr)
        struct mtd_info *mtd;
        struct nand_chip *nand;
        struct doc_priv *doc;
-       unsigned long virtadr;
+       void __iomem *virtadr;
        unsigned char save_control;
        unsigned char tmp, tmpb, tmpc;
        int reg, len, numchips;
        int ret = 0;
 
-       virtadr = (unsigned long)ioremap(physadr, DOC_IOREMAP_LEN);
+       virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
        if (!virtadr) {
                printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
                return -EIO;
@@ -1482,7 +1597,7 @@ static inline int __init doc_probe(unsigned long physadr)
                unsigned char oldval;
                unsigned char newval;
                nand = mtd->priv;
-               doc = (void *)nand->priv;
+               doc = nand->priv;
                /* Use the alias resolution register to determine if this is
                   in fact the same DOC aliased to a new address.  If writes
                   to one chip's alias resolution register change the value on
@@ -1518,7 +1633,7 @@ static inline int __init doc_probe(unsigned long physadr)
              sizeof(struct nand_chip) +
              sizeof(struct doc_priv) +
              (2 * sizeof(struct nand_bbt_descr));
-       mtd = kmalloc(len, GFP_KERNEL);
+       mtd =  kmalloc(len, GFP_KERNEL);
        if (!mtd) {
                printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
                ret = -ENOMEM;
@@ -1531,10 +1646,10 @@ static inline int __init doc_probe(unsigned long physadr)
        nand->bbt_td            = (struct nand_bbt_descr *) (doc + 1);
        nand->bbt_md            = nand->bbt_td + 1;
 
-       mtd->priv               = (void *) nand;
+       mtd->priv               = nand;
        mtd->owner              = THIS_MODULE;
 
-       nand->priv              = (void *) doc;
+       nand->priv              = doc;
        nand->select_chip       = doc200x_select_chip;
        nand->hwcontrol         = doc200x_hwcontrol;
        nand->dev_ready         = doc200x_dev_ready;
@@ -1543,7 +1658,7 @@ static inline int __init doc_probe(unsigned long physadr)
        nand->enable_hwecc      = doc200x_enable_hwecc;
        nand->calculate_ecc     = doc200x_calculate_ecc;
        nand->correct_data      = doc200x_correct_data;
-       //nand->data_buf
+
        nand->autooob           = &doc200x_oobinfo;
        nand->eccmode           = NAND_ECC_HW6_512;
        nand->options           = NAND_USE_FLASH_BBT | NAND_HWECC_SYNDROME;
@@ -1585,17 +1700,51 @@ notfound:
           actually a DiskOnChip.  */
        WriteDOC(save_control, virtadr, DOCControl);
 fail:
-       iounmap((void *)virtadr);
+       iounmap(virtadr);
        return ret;
 }
 
-int __init init_nanddoc(void)
+static void release_nanddoc(void)
 {
-       int i;
+       struct mtd_info *mtd, *nextmtd;
+       struct nand_chip *nand;
+       struct doc_priv *doc;
+
+       for (mtd = doclist; mtd; mtd = nextmtd) {
+               nand = mtd->priv;
+               doc = nand->priv;
+
+               nextmtd = doc->nextdoc;
+               nand_release(mtd);
+               iounmap(doc->virtadr);
+               kfree(mtd);
+       }
+}
+
+static int __init init_nanddoc(void)
+{
+       int i, ret = 0;
+
+       /* 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, FCR, 1, NROOTS);
+       if (!rs_decoder) {
+               printk (KERN_ERR "DiskOnChip: Could not create a RS decoder\n");
+               return -ENOMEM;
+       }
 
        if (doc_config_location) {
                printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location);
-               return doc_probe(doc_config_location);
+               ret = doc_probe(doc_config_location);
+               if (ret < 0)
+                       goto outerr;
        } else {
                for (i=0; (doc_locations[i] != 0xffffffff); i++) {
                        doc_probe(doc_locations[i]);
@@ -1605,25 +1754,23 @@ int __init init_nanddoc(void)
           found, so the user knows we at least tried. */
        if (!doclist) {
                printk(KERN_INFO "No valid DiskOnChip devices found\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto outerr;
        }
        return 0;
+outerr:
+       free_rs(rs_decoder);
+       return ret;
 }
 
-void __exit cleanup_nanddoc(void)
+static void __exit cleanup_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;
+       /* Cleanup the nand/DoC resources */
+       release_nanddoc();
 
-               nextmtd = doc->nextdoc;
-               nand_release(mtd);
-               iounmap((void *)doc->virtadr);
-               kfree(mtd);
+       /* Free the reed solomon resources */
+       if (rs_decoder) {
+               free_rs(rs_decoder);
        }
 }