mtd: nand: sunxi: switch to mtd_ooblayout_ops
authorBoris Brezillon <boris.brezillon@free-electrons.com>
Wed, 3 Feb 2016 19:05:13 +0000 (20:05 +0100)
committerBoris Brezillon <boris.brezillon@free-electrons.com>
Thu, 5 May 2016 21:51:48 +0000 (23:51 +0200)
Implementing the mtd_ooblayout_ops interface is the new way of exposing
ECC/OOB layout to MTD users.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>
drivers/mtd/nand/sunxi_nand.c

index b12ed83ebd564d0d5835f6849822f4a08537372b..1baf8983621063c5328df647a360468c7777b896 100644 (file)
@@ -211,12 +211,9 @@ struct sunxi_nand_chip_sel {
  * sunxi HW ECC infos: stores information related to HW ECC support
  *
  * @mode:      the sunxi ECC mode field deduced from ECC requirements
- * @layout:    the OOB layout depending on the ECC requirements and the
- *             selected ECC mode
  */
 struct sunxi_nand_hw_ecc {
        int mode;
-       struct nand_ecclayout layout;
 };
 
 /*
@@ -1436,6 +1433,57 @@ static int sunxi_nand_chip_init_timings(struct sunxi_nand_chip *chip,
        return sunxi_nand_chip_set_timings(chip, timings);
 }
 
+static int sunxi_nand_ooblayout_ecc(struct mtd_info *mtd, int section,
+                                   struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+       if (section >= ecc->steps)
+               return -ERANGE;
+
+       oobregion->offset = section * (ecc->bytes + 4) + 4;
+       oobregion->length = ecc->bytes;
+
+       return 0;
+}
+
+static int sunxi_nand_ooblayout_free(struct mtd_info *mtd, int section,
+                                    struct mtd_oob_region *oobregion)
+{
+       struct nand_chip *nand = mtd_to_nand(mtd);
+       struct nand_ecc_ctrl *ecc = &nand->ecc;
+
+       if (section > ecc->steps)
+               return -ERANGE;
+
+       /*
+        * The first 2 bytes are used for BB markers, hence we
+        * only have 2 bytes available in the first user data
+        * section.
+        */
+       if (!section && ecc->mode == NAND_ECC_HW) {
+               oobregion->offset = 2;
+               oobregion->length = 2;
+
+               return 0;
+       }
+
+       oobregion->offset = section * (ecc->bytes + 4);
+
+       if (section < ecc->steps)
+               oobregion->length = 4;
+       else
+               oobregion->offset = mtd->oobsize - oobregion->offset;
+
+       return 0;
+}
+
+static const struct mtd_ooblayout_ops sunxi_nand_ooblayout_ops = {
+       .ecc = sunxi_nand_ooblayout_ecc,
+       .free = sunxi_nand_ooblayout_free,
+};
+
 static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
                                              struct nand_ecc_ctrl *ecc,
                                              struct device_node *np)
@@ -1445,7 +1493,6 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
        struct sunxi_nand_chip *sunxi_nand = to_sunxi_nand(nand);
        struct sunxi_nfc *nfc = to_sunxi_nfc(sunxi_nand->nand.controller);
        struct sunxi_nand_hw_ecc *data;
-       struct nand_ecclayout *layout;
        int nsectors;
        int ret;
        int i;
@@ -1474,7 +1521,6 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
        /* HW ECC always work with even numbers of ECC bytes */
        ecc->bytes = ALIGN(ecc->bytes, 2);
 
-       layout = &data->layout;
        nsectors = mtd->writesize / ecc->size;
 
        if (mtd->oobsize < ((ecc->bytes + 4) * nsectors)) {
@@ -1482,11 +1528,9 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd,
                goto err;
        }
 
-       layout->eccbytes = (ecc->bytes * nsectors);
-
        ecc->read_oob = sunxi_nfc_hw_common_ecc_read_oob;
        ecc->write_oob = sunxi_nfc_hw_common_ecc_write_oob;
-       ecc->layout = layout;
+       mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops);
        ecc->priv = data;
 
        return 0;
@@ -1506,9 +1550,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
                                       struct nand_ecc_ctrl *ecc,
                                       struct device_node *np)
 {
-       struct nand_ecclayout *layout;
-       int nsectors;
-       int i, j;
        int ret;
 
        ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
@@ -1520,40 +1561,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd,
        ecc->read_oob_raw = nand_read_oob_std;
        ecc->write_oob_raw = nand_write_oob_std;
        ecc->read_subpage = sunxi_nfc_hw_ecc_read_subpage;
-       layout = ecc->layout;
-       nsectors = mtd->writesize / ecc->size;
-
-       for (i = 0; i < nsectors; i++) {
-               if (i) {
-                       layout->oobfree[i].offset =
-                               layout->oobfree[i - 1].offset +
-                               layout->oobfree[i - 1].length +
-                               ecc->bytes;
-                       layout->oobfree[i].length = 4;
-               } else {
-                       /*
-                        * The first 2 bytes are used for BB markers, hence we
-                        * only have 2 bytes available in the first user data
-                        * section.
-                        */
-                       layout->oobfree[i].length = 2;
-                       layout->oobfree[i].offset = 2;
-               }
-
-               for (j = 0; j < ecc->bytes; j++)
-                       layout->eccpos[(ecc->bytes * i) + j] =
-                                       layout->oobfree[i].offset +
-                                       layout->oobfree[i].length + j;
-       }
-
-       if (mtd->oobsize > (ecc->bytes + 4) * nsectors) {
-               layout->oobfree[nsectors].offset =
-                               layout->oobfree[nsectors - 1].offset +
-                               layout->oobfree[nsectors - 1].length +
-                               ecc->bytes;
-               layout->oobfree[nsectors].length = mtd->oobsize -
-                               ((ecc->bytes + 4) * nsectors);
-       }
 
        return 0;
 }
@@ -1562,9 +1569,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
                                                struct nand_ecc_ctrl *ecc,
                                                struct device_node *np)
 {
-       struct nand_ecclayout *layout;
-       int nsectors;
-       int i;
        int ret;
 
        ret = sunxi_nand_hw_common_ecc_ctrl_init(mtd, ecc, np);
@@ -1577,15 +1581,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd,
        ecc->read_oob_raw = nand_read_oob_syndrome;
        ecc->write_oob_raw = nand_write_oob_syndrome;
 
-       layout = ecc->layout;
-       nsectors = mtd->writesize / ecc->size;
-
-       for (i = 0; i < (ecc->bytes * nsectors); i++)
-               layout->eccpos[i] = i;
-
-       layout->oobfree[0].length = mtd->oobsize - i;
-       layout->oobfree[0].offset = i;
-
        return 0;
 }
 
@@ -1597,7 +1592,6 @@ static void sunxi_nand_ecc_cleanup(struct nand_ecc_ctrl *ecc)
                sunxi_nand_hw_common_ecc_ctrl_cleanup(ecc);
                break;
        case NAND_ECC_NONE:
-               kfree(ecc->layout);
        default:
                break;
        }
@@ -1631,10 +1625,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
                        return ret;
                break;
        case NAND_ECC_NONE:
-               ecc->layout = kzalloc(sizeof(*ecc->layout), GFP_KERNEL);
-               if (!ecc->layout)
-                       return -ENOMEM;
-               ecc->layout->oobfree[0].length = mtd->oobsize;
        case NAND_ECC_SOFT:
                break;
        default: