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@xxxxxxxxxxxxxxxxxx> --- drivers/mtd/nand/sunxi_nand.c | 114 +++++++++++++++++++----------------------- 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 1c03eee..4b9d984 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -212,12 +212,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; }; /* @@ -1257,6 +1254,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) @@ -1266,7 +1314,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; @@ -1295,7 +1342,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)) { @@ -1303,9 +1349,7 @@ static int sunxi_nand_hw_common_ecc_ctrl_init(struct mtd_info *mtd, goto err; } - layout->eccbytes = (ecc->bytes * nsectors); - - ecc->layout = layout; + mtd_set_ooblayout(mtd, &sunxi_nand_ooblayout_ops); ecc->priv = data; return 0; @@ -1325,9 +1369,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); @@ -1336,40 +1377,6 @@ static int sunxi_nand_hw_ecc_ctrl_init(struct mtd_info *mtd, ecc->read_page = sunxi_nfc_hw_ecc_read_page; ecc->write_page = sunxi_nfc_hw_ecc_write_page; - 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; } @@ -1378,9 +1385,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); @@ -1391,15 +1395,6 @@ static int sunxi_nand_hw_syndrome_ecc_ctrl_init(struct mtd_info *mtd, ecc->read_page = sunxi_nfc_hw_syndrome_ecc_read_page; ecc->write_page = sunxi_nfc_hw_syndrome_ecc_write_page; - 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; } @@ -1411,7 +1406,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; } @@ -1445,10 +1439,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: -- 2.5.0