4.9-stable review patch. If anyone has any objections, please let me know. ------------------ From: Alexander Couzens <lynxis@xxxxxxx> commit 6a623e07694437ad09f382a13f76cffc32239a7f upstream. The old 1-bit hamming layout requires ECC data to be placed at a fixed offset, and not necessarily at the end of the OOB area. Add this old layout back in order to fix legacy setups. Fixes: 41b207a70d3a ("mtd: nand: implement the default mtd_ooblayout_ops") Signed-off-by: Alexander Couzens <lynxis@xxxxxxx> Acked-by: Boris Brezillon <boris.brezillon@xxxxxxxxxxxxxxxxxx> Signed-off-by: Brian Norris <computersforpeace@xxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> --- drivers/mtd/nand/nand_base.c | 70 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -138,6 +138,74 @@ const struct mtd_ooblayout_ops nand_oobl }; EXPORT_SYMBOL_GPL(nand_ooblayout_lp_ops); +/* + * Support the old "large page" layout used for 1-bit Hamming ECC where ECC + * are placed at a fixed offset. + */ +static int nand_ooblayout_ecc_lp_hamming(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (section) + return -ERANGE; + + switch (mtd->oobsize) { + case 64: + oobregion->offset = 40; + break; + case 128: + oobregion->offset = 80; + break; + default: + return -EINVAL; + } + + oobregion->length = ecc->total; + if (oobregion->offset + oobregion->length > mtd->oobsize) + return -ERANGE; + + return 0; +} + +static int nand_ooblayout_free_lp_hamming(struct mtd_info *mtd, int section, + struct mtd_oob_region *oobregion) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + int ecc_offset = 0; + + if (section < 0 || section > 1) + return -ERANGE; + + switch (mtd->oobsize) { + case 64: + ecc_offset = 40; + break; + case 128: + ecc_offset = 80; + break; + default: + return -EINVAL; + } + + if (section == 0) { + oobregion->offset = 2; + oobregion->length = ecc_offset - 2; + } else { + oobregion->offset = ecc_offset + ecc->total; + oobregion->length = mtd->oobsize - oobregion->offset; + } + + return 0; +} + +const struct mtd_ooblayout_ops nand_ooblayout_lp_hamming_ops = { + .ecc = nand_ooblayout_ecc_lp_hamming, + .free = nand_ooblayout_free_lp_hamming, +}; + static int check_offs_len(struct mtd_info *mtd, loff_t ofs, uint64_t len) { @@ -4565,7 +4633,7 @@ int nand_scan_tail(struct mtd_info *mtd) break; case 64: case 128: - mtd_set_ooblayout(mtd, &nand_ooblayout_lp_ops); + mtd_set_ooblayout(mtd, &nand_ooblayout_lp_hamming_ops); break; default: WARN(1, "No oob scheme defined for oobsize %d\n",