int mtd_ooblayout_ecc(struct mtd_info *mtd, int section,
struct mtd_oob_region *oobecc)
{
- int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
-
memset(oobecc, 0, sizeof(*oobecc));
if (!mtd || section < 0)
return -EINVAL;
- if (!mtd->ecclayout)
+ if (!mtd->ooblayout || !mtd->ooblayout->ecc)
return -ENOTSUPP;
- /*
- * This logic allows us to reuse the ->ecclayout information and
- * expose them as ECC regions (as done for the OOB free regions).
- *
- * TODO: this should be dropped as soon as we get rid of the
- * ->ecclayout field.
- */
- for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
- eccpos = mtd->ecclayout->eccpos[eccbyte];
-
- if (eccbyte < mtd->ecclayout->eccbytes - 1) {
- int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
-
- if (eccpos + 1 == neccpos) {
- length++;
- continue;
- }
- }
-
- if (section == cursection)
- break;
-
- length = 0;
- cursection++;
- }
-
- if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
- return -ERANGE;
-
- oobecc->length = length + 1;
- oobecc->offset = eccpos - length;
-
- return 0;
+ return mtd->ooblayout->ecc(mtd, section, oobecc);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_ecc);
if (!mtd || section < 0)
return -EINVAL;
- if (!mtd->ecclayout)
+ if (!mtd->ooblayout || !mtd->ooblayout->free)
return -ENOTSUPP;
- if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE)
- return -ERANGE;
-
- oobfree->offset = mtd->ecclayout->oobfree[section].offset;
- oobfree->length = mtd->ecclayout->oobfree[section].length;
-
- return 0;
+ return mtd->ooblayout->free(mtd, section, oobfree);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_free);
}
EXPORT_SYMBOL_GPL(mtd_ooblayout_count_eccbytes);
+/**
+ * mtd_ecclayout_ecc - Default ooblayout_ecc iterator implementation
+ * @mtd: MTD device structure
+ * @section: ECC section. Depending on the layout you may have all the ECC
+ * bytes stored in a single contiguous section, or one section
+ * per ECC chunk (and sometime several sections for a single ECC
+ * ECC chunk)
+ * @oobecc: OOB region struct filled with the appropriate ECC position
+ * information
+ *
+ * This function is just a wrapper around the mtd->ecclayout field and is
+ * here to ease the transition to the mtd_ooblayout_ops approach.
+ * All it does is convert the layout->eccpos information into proper oob
+ * region definitions.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ecclayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobecc)
+{
+ int eccbyte = 0, cursection = 0, length = 0, eccpos = 0;
+
+ if (!mtd->ecclayout)
+ return -ENOTSUPP;
+
+ /*
+ * This logic allows us to reuse the ->ecclayout information and
+ * expose them as ECC regions (as done for the OOB free regions).
+ *
+ * TODO: this should be dropped as soon as we get rid of the
+ * ->ecclayout field.
+ */
+ for (eccbyte = 0; eccbyte < mtd->ecclayout->eccbytes; eccbyte++) {
+ eccpos = mtd->ecclayout->eccpos[eccbyte];
+
+ if (eccbyte < mtd->ecclayout->eccbytes - 1) {
+ int neccpos = mtd->ecclayout->eccpos[eccbyte + 1];
+
+ if (eccpos + 1 == neccpos) {
+ length++;
+ continue;
+ }
+ }
+
+ if (section == cursection)
+ break;
+
+ length = 0;
+ cursection++;
+ }
+
+ if (cursection != section || eccbyte >= mtd->ecclayout->eccbytes)
+ return -ERANGE;
+
+ oobecc->length = length + 1;
+ oobecc->offset = eccpos - length;
+
+ return 0;
+}
+
+/**
+ * mtd_ecclayout_ecc - Default ooblayout_free iterator implementation
+ * @mtd: MTD device structure
+ * @section: Free section. Depending on the layout you may have all the free
+ * bytes stored in a single contiguous section, or one section
+ * per ECC chunk (and sometime several sections for a single ECC
+ * ECC chunk)
+ * @oobfree: OOB region struct filled with the appropriate free position
+ * information
+ *
+ * This function is just a wrapper around the mtd->ecclayout field and is
+ * here to ease the transition to the mtd_ooblayout_ops approach.
+ * All it does is convert the layout->oobfree information into proper oob
+ * region definitions.
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+static int mtd_ecclayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobfree)
+{
+ struct nand_ecclayout *layout = mtd->ecclayout;
+
+ if (!layout)
+ return -ENOTSUPP;
+
+ if (section >= MTD_MAX_OOBFREE_ENTRIES_LARGE ||
+ !layout->oobfree[section].length)
+ return -ERANGE;
+
+ oobfree->offset = layout->oobfree[section].offset;
+ oobfree->length = layout->oobfree[section].length;
+
+ return 0;
+}
+
+static const struct mtd_ooblayout_ops mtd_ecclayout_wrapper_ops = {
+ .ecc = mtd_ecclayout_ecc,
+ .free = mtd_ecclayout_free,
+};
+
+/**
+ * mtd_set_ecclayout - Attach an ecclayout to an MTD device
+ * @mtd: MTD device structure
+ * @ecclayout: The ecclayout to attach to the device
+ *
+ * Returns zero on success, a negative error code otherwise.
+ */
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout)
+{
+ if (!mtd || !ecclayout)
+ return;
+
+ mtd->ecclayout = ecclayout;
+ mtd_set_ooblayout(mtd, &mtd_ecclayout_wrapper_ops);
+}
+EXPORT_SYMBOL_GPL(mtd_set_ecclayout);
+
/*
* Method to access the protection register area, present in some flash
* devices. The user data is one time programmable but the factory data is read
return res;
}
+static int part_ooblayout_ecc(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+
+ return mtd_ooblayout_ecc(part->master, section, oobregion);
+}
+
+static int part_ooblayout_free(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobregion)
+{
+ struct mtd_part *part = mtd_to_part(mtd);
+
+ return mtd_ooblayout_free(part->master, section, oobregion);
+}
+
+static const struct mtd_ooblayout_ops part_ooblayout_ops = {
+ .ecc = part_ooblayout_ecc,
+ .free = part_ooblayout_free,
+};
+
static inline void free_partition(struct mtd_part *p)
{
kfree(p->mtd.name);
part->name);
}
- mtd_set_ecclayout(&slave->mtd, master->ecclayout);
+ mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
slave->mtd.ecc_step_size = master->ecc_step_size;
slave->mtd.ecc_strength = master->ecc_strength;
slave->mtd.bitflip_threshold = master->bitflip_threshold;
* similar, smaller struct nand_ecclayout_user (in mtd-abi.h) that is retained
* for export to user-space via the ECCGETLAYOUT ioctl.
* nand_ecclayout should be expandable in the future simply by the above macros.
+ *
+ * This structure is now deprecated, you should use struct nand_ecclayout_ops
+ * to describe your OOB layout.
*/
struct nand_ecclayout {
__u32 eccbytes;
u32 length;
};
+/*
+ * struct mtd_ooblayout_ops - NAND OOB layout operations
+ * @ecc: function returning an ECC region in the OOB area.
+ * Should return -ERANGE if %section exceeds the total number of
+ * ECC sections.
+ * @free: function returning a free region in the OOB area.
+ * Should return -ERANGE if %section exceeds the total number of
+ * free sections.
+ */
+struct mtd_ooblayout_ops {
+ int (*ecc)(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobecc);
+ int (*free)(struct mtd_info *mtd, int section,
+ struct mtd_oob_region *oobfree);
+};
+
struct module; /* only needed for owner field in mtd_info */
struct mtd_info {
const char *name;
int index;
- /* ECC layout structure pointer - read only! */
+ /* [Deprecated] ECC layout structure pointer - read only! */
struct nand_ecclayout *ecclayout;
+ /* OOB layout description */
+ const struct mtd_ooblayout_ops *ooblayout;
+
/* the ecc step size. */
unsigned int ecc_step_size;
int mtd_ooblayout_count_freebytes(struct mtd_info *mtd);
int mtd_ooblayout_count_eccbytes(struct mtd_info *mtd);
-static inline void mtd_set_ecclayout(struct mtd_info *mtd,
- struct nand_ecclayout *ecclayout)
+void mtd_set_ecclayout(struct mtd_info *mtd, struct nand_ecclayout *ecclayout);
+
+static inline void mtd_set_ooblayout(struct mtd_info *mtd,
+ const struct mtd_ooblayout_ops *ooblayout)
{
- mtd->ecclayout = ecclayout;
+ mtd->ooblayout = ooblayout;
}
static inline void mtd_set_of_node(struct mtd_info *mtd,