Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mtd: create an mtd_ooblayout_ops struct to ease ECC layout definition

ECC layout definitions are currently exposed using the nand_ecclayout
struct which embeds oobfree and eccpos arrays with predefined size.
This approach was acceptable when NAND chips were providing relatively
small OOB regions, but MLC and TLC now provide OOB regions of several
hundreds of bytes, which implies a non negligible overhead for everybody
even those who only need to support legacy NANDs.

Create an mtd_ooblayout_ops interface providing the same functionality
(expose the ECC and oobfree layout) without the need for this huge
structure.

The mtd->ecclayout is now deprecated and should be replaced by the
equivalent mtd_ooblayout_ops. In the meantime we provide a wrapper around
the ->ecclayout field to ease migration to this new model.

Signed-off-by: Boris Brezillon <boris.brezillon@free-electrons.com>

+174 -52
+2 -2
drivers/mtd/mtdchar.c
··· 888 888 { 889 889 struct nand_oobinfo oi; 890 890 891 - if (!mtd->ecclayout) 891 + if (!mtd->ooblayout) 892 892 return -EOPNOTSUPP; 893 893 894 894 ret = get_oobinfo(mtd, &oi); ··· 982 982 { 983 983 struct nand_ecclayout_user *usrlay; 984 984 985 - if (!mtd->ecclayout) 985 + if (!mtd->ooblayout) 986 986 return -EOPNOTSUPP; 987 987 988 988 usrlay = kmalloc(sizeof(*usrlay), GFP_KERNEL);
+1 -1
drivers/mtd/mtdconcat.c
··· 777 777 778 778 } 779 779 780 - mtd_set_ecclayout(&concat->mtd, subdev[0]->ecclayout); 780 + mtd_set_ooblayout(&concat->mtd, subdev[0]->ooblayout); 781 781 782 782 concat->num_subdev = num_devs; 783 783 concat->mtd.name = name;
+121 -44
drivers/mtd/mtdcore.c
··· 1035 1035 int mtd_ooblayout_ecc(struct mtd_info *mtd, int section, 1036 1036 struct mtd_oob_region *oobecc) 1037 1037 { 1038 - int eccbyte = 0, cursection = 0, length = 0, eccpos = 0; 1039 - 1040 1038 memset(oobecc, 0, sizeof(*oobecc)); 1041 1039 1042 1040 if (!mtd || section < 0) 1043 1041 return -EINVAL; 1044 1042 1045 - if (!mtd->ecclayout) 1043 + if (!mtd->ooblayout || !mtd->ooblayout->ecc) 1046 1044 return -ENOTSUPP; 1047 1045 1048 - /* 1049 - * This logic allows us to reuse the ->ecclayout information and 1050 - * expose them as ECC regions (as done for the OOB free regions). 1051 - * 1052 - * TODO: this should be dropped as soon as we get rid of the 1053 - * ->ecclayout field. 1054 - */ 1055 - for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) { 1056 - eccpos = mtd->ecclayout->eccpos[eccbyte]; 1057 - 1058 - if (eccbyte < mtd->ecclayout->eccbytes - 1) { 1059 - int neccpos = mtd->ecclayout->eccpos[eccbyte + 1]; 1060 - 1061 - if (eccpos + 1 == neccpos) { 1062 - length++; 1063 - continue; 1064 - } 1065 - } 1066 - 1067 - if (section == cursection) 1068 - break; 1069 - 1070 - length = 0; 1071 - cursection++; 1072 - } 1073 - 1074 - if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes) 1075 - return -ERANGE; 1076 - 1077 - oobecc->length = length + 1; 1078 - oobecc->offset = eccpos - length; 1079 - 1080 - return 0; 1046 + return mtd->ooblayout->ecc(mtd, section, oobecc); 1081 1047 } 1082 1048 EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc); 1083 1049 ··· 1072 1106 if (!mtd || section < 0) 1073 1107 return -EINVAL; 1074 1108 1075 - if (!mtd->ecclayout) 1109 + if (!mtd->ooblayout || !mtd->ooblayout->free) 1076 1110 return -ENOTSUPP; 1077 1111 1078 - if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE) 1079 - return -ERANGE; 1080 - 1081 - oobfree->offset = mtd->ecclayout->oobfree[section].offset; 1082 - oobfree->length = mtd->ecclayout->oobfree[section].length; 1083 - 1084 - return 0; 1112 + return mtd->ooblayout->free(mtd, section, oobfree); 1085 1113 } 1086 1114 EXPORT_SYMBOL_GPL(mtd_ooblayout_free); 1087 1115 ··· 1375 1415 return mtd_ooblayout_count_bytes(mtd, mtd_ooblayout_ecc); 1376 1416 } 1377 1417 EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes); 1418 + 1419 + /** 1420 + * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation 1421 + * @mtd: MTD device structure 1422 + * @section: ECC section. Depending on the layout you may have all the ECC 1423 + * bytes stored in a single contiguous section, or one section 1424 + * per ECC chunk (and sometime several sections for a single ECC 1425 + * ECC chunk) 1426 + * @oobecc: OOB region struct filled with the appropriate ECC position 1427 + * information 1428 + * 1429 + * This function is just a wrapper around the mtd->ecclayout field and is 1430 + * here to ease the transition to the mtd_ooblayout_ops approach. 1431 + * All it does is convert the layout->eccpos information into proper oob 1432 + * region definitions. 1433 + * 1434 + * Returns zero on success, a negative error code otherwise. 1435 + */ 1436 + static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section, 1437 + struct mtd_oob_region *oobecc) 1438 + { 1439 + int eccbyte = 0, cursection = 0, length = 0, eccpos = 0; 1440 + 1441 + if (!mtd->ecclayout) 1442 + return -ENOTSUPP; 1443 + 1444 + /* 1445 + * This logic allows us to reuse the ->ecclayout information and 1446 + * expose them as ECC regions (as done for the OOB free regions). 1447 + * 1448 + * TODO: this should be dropped as soon as we get rid of the 1449 + * ->ecclayout field. 1450 + */ 1451 + for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) { 1452 + eccpos = mtd->ecclayout->eccpos[eccbyte]; 1453 + 1454 + if (eccbyte < mtd->ecclayout->eccbytes - 1) { 1455 + int neccpos = mtd->ecclayout->eccpos[eccbyte + 1]; 1456 + 1457 + if (eccpos + 1 == neccpos) { 1458 + length++; 1459 + continue; 1460 + } 1461 + } 1462 + 1463 + if (section == cursection) 1464 + break; 1465 + 1466 + length = 0; 1467 + cursection++; 1468 + } 1469 + 1470 + if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes) 1471 + return -ERANGE; 1472 + 1473 + oobecc->length = length + 1; 1474 + oobecc->offset = eccpos - length; 1475 + 1476 + return 0; 1477 + } 1478 + 1479 + /** 1480 + * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation 1481 + * @mtd: MTD device structure 1482 + * @section: Free section. Depending on the layout you may have all the free 1483 + * bytes stored in a single contiguous section, or one section 1484 + * per ECC chunk (and sometime several sections for a single ECC 1485 + * ECC chunk) 1486 + * @oobfree: OOB region struct filled with the appropriate free position 1487 + * information 1488 + * 1489 + * This function is just a wrapper around the mtd->ecclayout field and is 1490 + * here to ease the transition to the mtd_ooblayout_ops approach. 1491 + * All it does is convert the layout->oobfree information into proper oob 1492 + * region definitions. 1493 + * 1494 + * Returns zero on success, a negative error code otherwise. 1495 + */ 1496 + static int mtd_ecclayout_free(struct mtd_info *mtd, int section, 1497 + struct mtd_oob_region *oobfree) 1498 + { 1499 + struct nand_ecclayout *layout = mtd->ecclayout; 1500 + 1501 + if (!layout) 1502 + return -ENOTSUPP; 1503 + 1504 + if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE || 1505 + !layout->oobfree[section].length) 1506 + return -ERANGE; 1507 + 1508 + oobfree->offset = layout->oobfree[section].offset; 1509 + oobfree->length = layout->oobfree[section].length; 1510 + 1511 + return 0; 1512 + } 1513 + 1514 + static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = { 1515 + .ecc = mtd_ecclayout_ecc, 1516 + .free = mtd_ecclayout_free, 1517 + }; 1518 + 1519 + /** 1520 + * mtd_set_ecclayout - Attach an ecclayout to an MTD device 1521 + * @mtd: MTD device structure 1522 + * @ecclayout: The ecclayout to attach to the device 1523 + * 1524 + * Returns zero on success, a negative error code otherwise. 1525 + */ 1526 + void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout) 1527 + { 1528 + if (!mtd || !ecclayout) 1529 + return; 1530 + 1531 + mtd->ecclayout = ecclayout; 1532 + mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops); 1533 + } 1534 + EXPORT_SYMBOL_GPL(mtd_set_ecclayout); 1378 1535 1379 1536 /* 1380 1537 * Method to access the protection register area, present in some flash
+22 -1
drivers/mtd/mtdpart.c
··· 317 317 return res; 318 318 } 319 319 320 + static int part_ooblayout_ecc(struct mtd_info *mtd, int section, 321 + struct mtd_oob_region *oobregion) 322 + { 323 + struct mtd_part *part = mtd_to_part(mtd); 324 + 325 + return mtd_ooblayout_ecc(part->master, section, oobregion); 326 + } 327 + 328 + static int part_ooblayout_free(struct mtd_info *mtd, int section, 329 + struct mtd_oob_region *oobregion) 330 + { 331 + struct mtd_part *part = mtd_to_part(mtd); 332 + 333 + return mtd_ooblayout_free(part->master, section, oobregion); 334 + } 335 + 336 + static const struct mtd_ooblayout_ops part_ooblayout_ops = { 337 + .ecc = part_ooblayout_ecc, 338 + .free = part_ooblayout_free, 339 + }; 340 + 320 341 static inline void free_partition(struct mtd_part *p) 321 342 { 322 343 kfree(p->mtd.name); ··· 554 533 part->name); 555 534 } 556 535 557 - mtd_set_ecclayout(&slave->mtd, master->ecclayout); 536 + mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops); 558 537 slave->mtd.ecc_step_size = master->ecc_step_size; 559 538 slave->mtd.ecc_strength = master->ecc_strength; 560 539 slave->mtd.bitflip_threshold = master->bitflip_threshold;
+28 -4
include/linux/mtd/mtd.h
··· 101 101 * similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained 102 102 * for export to user-space via the ECCGETLAYOUT ioctl. 103 103 * nand_ecclayout should be expandable in the future simply by the above macros. 104 + * 105 + * This structure is now deprecated, you should use struct nand_ecclayout_ops 106 + * to describe your OOB layout. 104 107 */ 105 108 struct nand_ecclayout { 106 109 __u32 eccbytes; ··· 124 121 struct mtd_oob_region { 125 122 u32 offset; 126 123 u32 length; 124 + }; 125 + 126 + /* 127 + * struct mtd_ooblayout_ops - NAND OOB layout operations 128 + * @ecc: function returning an ECC region in the OOB area. 129 + * Should return -ERANGE if %section exceeds the total number of 130 + * ECC sections. 131 + * @free: function returning a free region in the OOB area. 132 + * Should return -ERANGE if %section exceeds the total number of 133 + * free sections. 134 + */ 135 + struct mtd_ooblayout_ops { 136 + int (*ecc)(struct mtd_info *mtd, int section, 137 + struct mtd_oob_region *oobecc); 138 + int (*free)(struct mtd_info *mtd, int section, 139 + struct mtd_oob_region *oobfree); 127 140 }; 128 141 129 142 struct module; /* only needed for owner field in mtd_info */ ··· 200 181 const char *name; 201 182 int index; 202 183 203 - /* ECC layout structure pointer - read only! */ 184 + /* [Deprecated] ECC layout structure pointer - read only! */ 204 185 struct nand_ecclayout *ecclayout; 186 + 187 + /* OOB layout description */ 188 + const struct mtd_ooblayout_ops *ooblayout; 205 189 206 190 /* the ecc step size. */ 207 191 unsigned int ecc_step_size; ··· 308 286 int mtd_ooblayout_count_freebytes(struct mtd_info *mtd); 309 287 int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd); 310 288 311 - static inline void mtd_set_ecclayout(struct mtd_info *mtd, 312 - struct nand_ecclayout *ecclayout) 289 + void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout); 290 + 291 + static inline void mtd_set_ooblayout(struct mtd_info *mtd, 292 + const struct mtd_ooblayout_ops *ooblayout) 313 293 { 314 - mtd->ecclayout = ecclayout; 294 + mtd->ooblayout = ooblayout; 315 295 } 316 296 317 297 static inline void mtd_set_of_node(struct mtd_info *mtd,