diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 6eb52ed50c6..78f2a085411 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -142,3 +142,52 @@ void put_mtd_device(struct mtd_info *mtd) c = --mtd->usecount; BUG_ON(c < 0); } + +#if defined(CONFIG_CMD_MTDPARTS_SPREAD) +/** + * mtd_get_len_incl_bad + * + * Check if length including bad blocks fits into device. + * + * @param mtd an MTD device + * @param offset offset in flash + * @param length image length + * @return image length including bad blocks in *len_incl_bad and whether or not + * the length returned was truncated in *truncated + */ +void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset, + const uint64_t length, uint64_t *len_incl_bad, + int *truncated) +{ + *truncated = 0; + *len_incl_bad = 0; + + if (offset >= mtd->size) { + *truncated = 1; + return; + } + + if (!mtd->block_isbad) { + *len_incl_bad = length; + return; + } + + uint64_t len_excl_bad = 0; + uint64_t block_len; + + while (len_excl_bad < length) { + block_len = mtd->erasesize - (offset & (mtd->erasesize - 1)); + + if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1))) + len_excl_bad += block_len; + + *len_incl_bad += block_len; + offset += block_len; + + if (offset >= mtd->size) { + *truncated = 1; + break; + } + } +} +#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */ diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index f1cdf23aa01..3b18d7d6886 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -255,7 +255,9 @@ extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); extern struct mtd_info *get_mtd_device_nm(const char *name); extern void put_mtd_device(struct mtd_info *mtd); - +extern void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset, + const uint64_t length, uint64_t *len_incl_bad, + int *truncated); /* XXX U-BOOT XXX */ #if 0 struct mtd_notifier {