[MTD] NAND modularize ECC
[pandora-kernel.git] / drivers / mtd / nand / nand_base.c
index 37db98a..98792ec 100644 (file)
@@ -879,9 +879,9 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
 {
        int i, status;
        uint8_t ecc_code[32];
-       int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
+       int eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
        int *oob_config = oobsel->eccpos;
-       int datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
+       int datidx = 0, eccidx = 0, eccsteps = this->ecc.steps;
        int eccbytes = 0;
 
        /* FIXME: Enable cached programming */
@@ -901,20 +901,20 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
                /* Software ecc 3/256, write all */
        case NAND_ECC_SOFT:
                for (; eccsteps; eccsteps--) {
-                       this->calculate_ecc(mtd, &this->data_poi[datidx], ecc_code);
+                       this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
                        for (i = 0; i < 3; i++, eccidx++)
                                oob_buf[oob_config[eccidx]] = ecc_code[i];
-                       datidx += this->eccsize;
+                       datidx += this->ecc.size;
                }
                this->write_buf(mtd, this->data_poi, mtd->oobblock);
                break;
        default:
-               eccbytes = this->eccbytes;
+               eccbytes = this->ecc.bytes;
                for (; eccsteps; eccsteps--) {
                        /* 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, &this->data_poi[datidx], ecc_code);
+                       this->ecc.hwctl(mtd, NAND_ECC_WRITE);
+                       this->write_buf(mtd, &this->data_poi[datidx], this->ecc.size);
+                       this->ecc.calculate(mtd, &this->data_poi[datidx], ecc_code);
                        for (i = 0; i < eccbytes; i++, eccidx++)
                                oob_buf[oob_config[eccidx]] = ecc_code[i];
                        /* If the hardware ecc provides syndromes then
@@ -922,7 +922,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *this, int pag
                         * the data bytes (words) */
                        if (this->options & NAND_HWECC_SYNDROME)
                                this->write_buf(mtd, ecc_code, eccbytes);
-                       datidx += this->eccsize;
+                       datidx += this->ecc.size;
                }
                break;
        }
@@ -1155,7 +1155,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
        if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
                oobsel = this->autooob;
 
-       eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE;
+       eccmode = oobsel->useecc ? this->ecc.mode : NAND_ECC_NONE;
        oob_config = oobsel->eccpos;
 
        /* Select the NAND device */
@@ -1170,8 +1170,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
        col = from & (mtd->oobblock - 1);
 
        end = mtd->oobblock;
-       ecc = this->eccsize;
-       eccbytes = this->eccbytes;
+       ecc = this->ecc.size;
+       eccbytes = this->ecc.bytes;
 
        if ((eccmode == NAND_ECC_NONE) || (this->options & NAND_HWECC_SYNDROME))
                compareecc = 0;
@@ -1216,7 +1216,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                        oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
                        oob_data = &this->data_buf[end];
 
-               eccsteps = this->eccsteps;
+               eccsteps = this->ecc.steps;
 
                switch (eccmode) {
                case NAND_ECC_NONE:{
@@ -1234,12 +1234,12 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                case NAND_ECC_SOFT:     /* Software ECC 3/256: Read in a page + oob data */
                        this->read_buf(mtd, data_poi, end);
                        for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
-                               this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
+                               this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
                        break;
 
                default:
                        for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) {
-                               this->enable_hwecc(mtd, NAND_ECC_READ);
+                               this->ecc.hwctl(mtd, NAND_ECC_READ);
                                this->read_buf(mtd, &data_poi[datidx], ecc);
 
                                /* HW ecc with syndrome calculation must read the
@@ -1247,19 +1247,19 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                                if (!compareecc) {
                                        /* Some hw ecc generators need to know when the
                                         * syndrome is read from flash */
-                                       this->enable_hwecc(mtd, NAND_ECC_READSYN);
+                                       this->ecc.hwctl(mtd, NAND_ECC_READSYN);
                                        this->read_buf(mtd, &oob_data[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 */
-                                       ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+                                       ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
                                        if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
                                                DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: "
                                                      "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
                                                ecc_failed++;
                                        }
                                } else {
-                                       this->calculate_ecc(mtd, &data_poi[datidx], &ecc_calc[i]);
+                                       this->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
                                }
                        }
                        break;
@@ -1277,8 +1277,8 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                        ecc_code[j] = oob_data[oob_config[j]];
 
                /* correct data, if necessary */
-               for (i = 0, j = 0, datidx = 0; i < this->eccsteps; i++, datidx += ecc) {
-                       ecc_status = this->correct_data(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
+               for (i = 0, j = 0, datidx = 0; i < this->ecc.steps; i++, datidx += ecc) {
+                       ecc_status = this->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
 
                        /* Get next chunk of ecc bytes */
                        j += eccbytes;
@@ -1315,7 +1315,7 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
                                break;
                        case MTD_NANDECC_PLACE:
                                /* YAFFS1 legacy mode */
-                               oob_data += this->eccsteps * sizeof(int);
+                               oob_data += this->ecc.steps * sizeof(int);
                        default:
                                oob_data += mtd->oobsize;
                        }
@@ -2648,99 +2648,49 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
         * check ECC mode, default to software if 3byte/512byte hardware ECC is
         * selected and we have 256 byte pagesize fallback to software ECC
         */
-       this->eccsize = 256;
-       this->eccbytes = 3;
-
-       switch (this->eccmode) {
-       case NAND_ECC_HW12_2048:
-               if (mtd->oobblock < 2048) {
-                       printk(KERN_WARNING "2048 byte HW ECC not possible on "
-                              "%d byte page size, fallback to SW ECC\n",
-                              mtd->oobblock);
-                       this->eccmode = NAND_ECC_SOFT;
-                       this->calculate_ecc = nand_calculate_ecc;
-                       this->correct_data = nand_correct_data;
-               } else
-                       this->eccsize = 2048;
-               break;
-
-       case NAND_ECC_HW3_512:
-       case NAND_ECC_HW6_512:
-       case NAND_ECC_HW8_512:
-               if (mtd->oobblock == 256) {
-                       printk(KERN_WARNING "512 byte HW ECC not possible on "
-                              "256 Byte pagesize, fallback to SW ECC \n");
-                       this->eccmode = NAND_ECC_SOFT;
-                       this->calculate_ecc = nand_calculate_ecc;
-                       this->correct_data = nand_correct_data;
-               } else
-                       this->eccsize = 512;    /* set eccsize to 512 */
-               break;
+       switch (this->ecc.mode) {
+       case NAND_ECC_HW:
+       case NAND_ECC_HW_SYNDROME:
+               if (!this->ecc.calculate || !this->ecc.correct ||
+                   !this->ecc.hwctl) {
+                       printk(KERN_WARNING "No ECC functions supplied, "
+                              "Hardware ECC not possible\n");
+                       BUG();
+               }
+               if (mtd->oobblock >= this->ecc.size)
+                       break;
+               printk(KERN_WARNING "%d byte HW ECC not possible on "
+                      "%d byte page size, fallback to SW ECC\n",
+                      this->ecc.size, mtd->oobblock);
+               this->ecc.mode = NAND_ECC_SOFT;
 
-       case NAND_ECC_HW3_256:
+       case NAND_ECC_SOFT:
+               this->ecc.calculate = nand_calculate_ecc;
+               this->ecc.correct = nand_correct_data;
+               this->ecc.size = 256;
+               this->ecc.bytes = 3;
                break;
 
        case NAND_ECC_NONE:
                printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
                       "This is not recommended !!\n");
-               this->eccmode = NAND_ECC_NONE;
+               this->ecc.size = mtd->oobblock;
+               this->ecc.bytes = 0;
                break;
-
-       case NAND_ECC_SOFT:
-               this->calculate_ecc = nand_calculate_ecc;
-               this->correct_data = nand_correct_data;
-               break;
-
        default:
                printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
-                      this->eccmode);
-               BUG();
-       }
-
-       /*
-        * Check hardware ecc function availability and adjust number of ecc
-        * bytes per calculation step
-        */
-       switch (this->eccmode) {
-       case NAND_ECC_HW12_2048:
-               this->eccbytes += 4;
-       case NAND_ECC_HW8_512:
-               this->eccbytes += 2;
-       case NAND_ECC_HW6_512:
-               this->eccbytes += 3;
-       case NAND_ECC_HW3_512:
-       case NAND_ECC_HW3_256:
-               if (this->calculate_ecc && this->correct_data &&
-                   this->enable_hwecc)
-                       break;
-               printk(KERN_WARNING "No ECC functions supplied, "
-                      "Hardware ECC not possible\n");
+                      this->ecc.mode);
                BUG();
        }
 
-       mtd->eccsize = this->eccsize;
-
        /*
         * Set the number of read / write steps for one page depending on ECC
         * mode
         */
-       switch (this->eccmode) {
-       case NAND_ECC_HW12_2048:
-               this->eccsteps = mtd->oobblock / 2048;
-               break;
-       case NAND_ECC_HW3_512:
-       case NAND_ECC_HW6_512:
-       case NAND_ECC_HW8_512:
-               this->eccsteps = mtd->oobblock / 512;
-               break;
-       case NAND_ECC_HW3_256:
-       case NAND_ECC_SOFT:
-               this->eccsteps = mtd->oobblock / 256;
-               break;
-
-       case NAND_ECC_NONE:
-               this->eccsteps = 1;
-               break;
+       this->ecc.steps = mtd->oobblock / this->ecc.size;
+       if(this->ecc.steps * this->ecc.size != mtd->oobblock) {
+               printk(KERN_WARNING "Invalid ecc parameters\n");
+               BUG();
        }
 
        /* Initialize state, waitqueue and spinlock */