X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmtd%2Fnand%2Fdiskonchip.c;h=02135c3ac29a0372f19a05784cb7da8e90f38245;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=0f7dedd6b88ecd95fd30d3ac761c11574478488d;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 0f7dedd6b..02135c3ac 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c @@ -8,16 +8,23 @@ * Author: David Woodhouse * Additional Diskonchip 2000 and Millennium support by Dan Brown * Diskonchip Millennium Plus support by Kalev Lember - * + * + * 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 + * * 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 #include #include #include +#include +#include #include #include @@ -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); } }