diff options
Diffstat (limited to 'target/linux/mediatek/patches/1006-rootfs-split.patch')
-rw-r--r-- | target/linux/mediatek/patches/1006-rootfs-split.patch | 788 |
1 files changed, 788 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches/1006-rootfs-split.patch b/target/linux/mediatek/patches/1006-rootfs-split.patch new file mode 100644 index 0000000..e6bc21d --- /dev/null +++ b/target/linux/mediatek/patches/1006-rootfs-split.patch @@ -0,0 +1,788 @@ +Index: linux-3.10.20/drivers/mtd/Makefile +=================================================================== +--- linux-3.10.20.orig/drivers/mtd/Makefile ++++ linux-3.10.20/drivers/mtd/Makefile +@@ -4,7 +4,12 @@ + + # Core functionality. + obj-$(CONFIG_MTD) += mtd.o +-mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o ++mtd-y += mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o ++mtd-$(CONFIG_MTD_SPLIT) += mtdsplit.o ++mtd-$(CONFIG_MTD_SPLIT_SEAMA_FW) += mtdsplit_seama.o ++mtd-$(CONFIG_MTD_SPLIT_SQUASHFS_ROOT) += mtdsplit_squashfs.o ++mtd-$(CONFIG_MTD_SPLIT_UIMAGE_FW) += mtdsplit_uimage.o ++mtd-$(CONFIG_MTD_SPLIT_LZMA_FW) += mtdsplit_lzma.o + + obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o + obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o +Index: linux-3.10.20/drivers/mtd/Kconfig +=================================================================== +--- linux-3.10.20.orig/drivers/mtd/Kconfig ++++ linux-3.10.20/drivers/mtd/Kconfig +@@ -12,6 +12,68 @@ menuconfig MTD + + if MTD + ++if SUPPORT_OPENWRT ++menu "OpenWrt specific MTD options" ++ ++config MTD_ROOTFS_ROOT_DEV ++ bool "Automatically set 'rootfs' partition to be root filesystem" ++ default n ++ ++config MTD_ROOTFS_SPLIT ++ bool "Automatically split 'rootfs' partition for squashfs" ++ select MTD_SPLIT ++ default n ++ ++config MTD_SPLIT_FIRMWARE ++ bool "Automatically split firmware partition for kernel+rootfs" ++ default n ++ ++config MTD_SPLIT_FIRMWARE_NAME ++ string "Firmware partition name" ++ depends on MTD_SPLIT_FIRMWARE ++ default "firmware" ++ default n ++ ++config MTD_UIMAGE_SPLIT ++ bool "Enable split support for firmware partitions containing a uImage" ++ depends on MTD_SPLIT_FIRMWARE ++ default n ++ ++comment "Rootfs partition parsers" ++ ++config MTD_SPLIT_SQUASHFS_ROOT ++ bool "Squashfs based root partition parser" ++ select MTD_SPLIT ++ default n ++ help ++ This provides a parsing function which allows to detect the ++ offset and size of the unused portion of a rootfs partition ++ containing a squashfs. ++comment "Firmware partition parsers" ++ ++config MTD_SPLIT_SEAMA_FW ++ bool "Seama firmware parser" ++ select MTD_SPLIT ++ default n ++ ++config MTD_SPLIT_UIMAGE_FW ++ bool "uImage based firmware partition parser" ++ select MTD_SPLIT ++ default n ++ ++config MTD_SPLIT_LZMA_FW ++ bool "LZMA compressed kernel based firmware partition parser" ++ select MTD_SPLIT ++ default n ++ ++config MTD_SPLIT ++ def_bool n ++ depends on SUPPORT_OPENWRT ++ help ++ Generic MTD split support. ++ ++endmenu ++endif # SUPPORT_OPENWRT + config MTD_TESTS + tristate "MTD tests support (DANGEROUS)" + depends on m +@@ -309,10 +371,10 @@ config MTD_SWAP + OOB. + + config MTK_MTD_NOR +- depends on ARCH_MT7623 ++ depends on ARCH_MT7623 + tristate "MTK NOR Flash Support" + help +- Support MTK NOR flash controller. ++ Support MTK NOR flash controller. + + + +Index: linux-3.10.20/drivers/mtd/mtdpart.c +=================================================================== +--- linux-3.10.20.orig/drivers/mtd/mtdpart.c ++++ linux-3.10.20/drivers/mtd/mtdpart.c +@@ -29,10 +29,16 @@ + #include <linux/kmod.h> + #include <linux/mtd/mtd.h> + #include <linux/mtd/partitions.h> ++#if defined(CONFIG_SUPPORT_OPENWRT) ++#include <linux/magic.h> ++#endif + #include <linux/err.h> + + #include "mtdcore.h" +- ++#if defined(CONFIG_SUPPORT_OPENWRT) ++#include "mtdsplit.h" ++#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */ ++#endif + #define DYNAMIC_CHANGE_MTD_WRITEABLE + #ifdef DYNAMIC_CHANGE_MTD_WRITEABLE //wschen 2011-01-05 + #include <linux/proc_fs.h> +@@ -60,6 +66,10 @@ struct mtd_part { + struct list_head list; + }; + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part); ++#endif ++ + /* + * Given a pointer to the MTD object in the mtd_part structure, we can retrieve + * the pointer to that structure with this macro. +@@ -243,12 +253,61 @@ static int part_erase(struct mtd_info *m + struct mtd_part *part = PART(mtd); + int ret; + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ instr->partial_start = false; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ size_t readlen = 0; ++ u64 mtd_ofs; ++ ++ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC); ++ if (!instr->erase_buf) ++ return -ENOMEM; ++ ++ mtd_ofs = part->offset + instr->addr; ++ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->addr -= instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ instr->addr + part->offset, ++ part->master->erasesize, ++ &readlen, instr->erase_buf); ++ ++ instr->partial_start = true; ++ } else { ++ mtd_ofs = part->offset + part->mtd.size; ++ instr->erase_buf_ofs = part->master->erasesize - ++ do_div(mtd_ofs, part->master->erasesize); ++ ++ if (instr->erase_buf_ofs > 0) { ++ instr->len += instr->erase_buf_ofs; ++ ret = mtd_read(part->master, ++ part->offset + instr->addr + ++ instr->len - part->master->erasesize, ++ part->master->erasesize, &readlen, ++ instr->erase_buf); ++ } else { ++ ret = 0; ++ } ++ } ++ if (ret < 0) { ++ kfree(instr->erase_buf); ++ return ret; ++ } ++ ++ } ++#endif ++ + instr->addr += part->offset; + ret = part->master->_erase(part->master, instr); + if (ret) { + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ if (mtd->flags & MTD_ERASE_PARTIAL) ++ kfree(instr->erase_buf); ++#endif + } + return ret; + } +@@ -257,7 +316,27 @@ void mtd_erase_callback(struct erase_inf + { + if (instr->mtd->_erase == part_erase) { + struct mtd_part *part = PART(instr->mtd); ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ size_t wrlen = 0; + ++ if (instr->mtd->flags & MTD_ERASE_PARTIAL) { ++ if (instr->partial_start) { ++ part->master->_write(part->master, ++ instr->addr, instr->erase_buf_ofs, ++ &wrlen, instr->erase_buf); ++ instr->addr += instr->erase_buf_ofs; ++ } else { ++ instr->len -= instr->erase_buf_ofs; ++ part->master->_write(part->master, ++ instr->addr + instr->len, ++ instr->erase_buf_ofs, &wrlen, ++ instr->erase_buf + ++ part->master->erasesize - ++ instr->erase_buf_ofs); ++ } ++ kfree(instr->erase_buf); ++ } ++#endif + if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN) + instr->fail_addr -= part->offset; + instr->addr -= part->offset; +@@ -276,7 +355,17 @@ static int part_lock(struct mtd_info *mt + static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) + { + struct mtd_part *part = PART(mtd); ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ ofs += part->offset; ++ if (mtd->flags & MTD_ERASE_PARTIAL) { ++ /* round up len to next erasesize and round down offset to prev block */ ++ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize; ++ ofs &= ~(part->master->erasesize - 1); ++ } ++ return part->master->_unlock(part->master, ofs, len); ++#else + return part->master->_unlock(part->master, ofs + part->offset, len); ++#endif + } + + static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len) +@@ -450,6 +539,14 @@ static struct mtd_part *allocate_partiti + if (slave->offset == MTDPART_OFS_APPEND) + slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ /* Round up to next erasesize */ ++ slave->offset = mtd_roundup_to_eb(cur_offset, master); ++ if (slave->offset != cur_offset) ++ printk(KERN_NOTICE "Moving partition %d: " ++ "0x%012llx -> 0x%012llx\n", partno, ++ (unsigned long long)cur_offset, (unsigned long long)slave->offset); ++#else + slave->offset = cur_offset; + if (mtd_mod_by_eb(cur_offset, master) != 0) { + /* Round up to next erasesize */ +@@ -458,6 +555,7 @@ static struct mtd_part *allocate_partiti + "0x%012llx -> 0x%012llx\n", partno, + (unsigned long long)cur_offset, (unsigned long long)slave->offset); + } ++#endif + } + if (slave->offset == MTDPART_OFS_RETAIN) { + slave->offset = cur_offset; +@@ -518,6 +616,29 @@ static struct mtd_part *allocate_partiti + slave->mtd.erasesize = master->erasesize; + } + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ if ((slave->mtd.flags & MTD_WRITEABLE) && ++ mtd_mod_by_eb(slave->offset, &slave->mtd)) { ++ /* Doesn't start on a boundary of major erase size */ ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ if (((u32) slave->mtd.size) > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; ++ } ++ if ((slave->mtd.flags & MTD_WRITEABLE) && ++ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) { ++ slave->mtd.flags |= MTD_ERASE_PARTIAL; ++ ++ if ((u32) slave->mtd.size > master->erasesize) ++ slave->mtd.flags &= ~MTD_WRITEABLE; ++ else ++ slave->mtd.erasesize = slave->mtd.size; ++ } ++ if ((slave->mtd.flags & (MTD_ERASE_PARTIAL|MTD_WRITEABLE)) == MTD_ERASE_PARTIAL) ++ printk(KERN_WARNING"mtd: partition \"%s\" must either start or end on erase block boundary or be smaller than an erase block -- forcing read-only\n", ++ part->name); ++#else + if ((slave->mtd.flags & MTD_WRITEABLE) && + mtd_mod_by_eb(slave->offset, &slave->mtd)) { + /* Doesn't start on a boundary of major erase size */ +@@ -533,6 +654,7 @@ static struct mtd_part *allocate_partiti + printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n", + part->name); + } ++#endif + + slave->mtd.ecclayout = master->ecclayout; + slave->mtd.ecc_strength = master->ecc_strength; +@@ -552,6 +674,74 @@ out_register: + return slave; + } + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++static int ++__mtd_add_partition(struct mtd_info *master, char *name, ++ long long offset, long long length, bool dup_check) ++{ ++ struct mtd_partition part; ++ struct mtd_part *p, *new; ++ uint64_t start, end; ++ int ret = 0; ++ ++ /* the direct offset is expected */ ++ if (offset == MTDPART_OFS_APPEND || ++ offset == MTDPART_OFS_NXTBLK) ++ return -EINVAL; ++ ++ if (length == MTDPART_SIZ_FULL) ++ length = master->size - offset; ++ ++ if (length <= 0) ++ return -EINVAL; ++ ++ part.name = name; ++ part.size = length; ++ part.offset = offset; ++ part.mask_flags = 0; ++ part.ecclayout = NULL; ++ ++ new = allocate_partition(master, &part, -1, offset); ++ if (IS_ERR(new)) ++ return PTR_ERR(new); ++ ++ start = offset; ++ end = offset + length; ++ ++ mutex_lock(&mtd_partitions_mutex); ++ if (dup_check) { ++ list_for_each_entry(p, &mtd_partitions, list) ++ if (p->master == master) { ++ if ((start >= p->offset) && ++ (start < (p->offset + p->mtd.size))) ++ goto err_inv; ++ ++ if ((end >= p->offset) && ++ (end < (p->offset + p->mtd.size))) ++ goto err_inv; ++ } ++ } ++ ++ list_add(&new->list, &mtd_partitions); ++ mutex_unlock(&mtd_partitions_mutex); ++ ++ add_mtd_device(&new->mtd); ++ mtd_partition_split(master, new); ++ ++ return ret; ++err_inv: ++ mutex_unlock(&mtd_partitions_mutex); ++ free_partition(new); ++ return -EINVAL; ++} ++EXPORT_SYMBOL_GPL(mtd_add_partition); ++ ++int mtd_add_partition(struct mtd_info *master, char *name, ++ long long offset, long long length) ++{ ++ return __mtd_add_partition(master, name, offset, length, true); ++} ++#else /* CONFIG_SUPPORT_OPENWRT */ + int mtd_add_partition(struct mtd_info *master, char *name, + long long offset, long long length) + { +@@ -608,6 +798,7 @@ err_inv: + return -EINVAL; + } + EXPORT_SYMBOL_GPL(mtd_add_partition); ++#endif /* CONFIG_SUPPORT_OPENWRT */ + + int mtd_del_partition(struct mtd_info *master, int partno) + { +@@ -632,6 +823,164 @@ int mtd_del_partition(struct mtd_info *m + } + EXPORT_SYMBOL_GPL(mtd_del_partition); + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++static int ++run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type) ++{ ++ struct mtd_partition *parts; ++ int nr_parts; ++ int i; ++ ++ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, &parts, ++ NULL); ++ if (nr_parts <= 0) ++ return nr_parts; ++ ++ if (WARN_ON(!parts)) ++ return 0; ++ ++ for (i = 0; i < nr_parts; i++) { ++ /* adjust partition offsets */ ++ parts[i].offset += slave->offset; ++ ++ __mtd_add_partition(slave->master, ++ parts[i].name, ++ parts[i].offset, ++ parts[i].size, ++ false); ++ } ++ ++ kfree(parts); ++ ++ return nr_parts; ++} ++ ++static inline unsigned long ++mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len) ++{ ++ unsigned long mask = mtd->erasesize - 1; ++ ++ len += offset & mask; ++ len = (len + mask) & ~mask; ++ len -= offset & mask; ++ return len; ++} ++ ++static int split_squashfs(struct mtd_info *master, int offset, int *split_offset) ++{ ++ size_t squashfs_len; ++ int len, ret; ++ ++ ret = mtd_get_squashfs_len(master, offset, &squashfs_len); ++ if (ret) ++ return ret; ++ ++ len = mtd_pad_erasesize(master, offset, squashfs_len); ++ *split_offset = offset + len; ++ ++ return 0; ++} ++ ++static void split_rootfs_data(struct mtd_info *master, struct mtd_part *part) ++{ ++ unsigned int split_offset = 0; ++ unsigned int split_size; ++ int ret; ++ ++ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS); ++ if (ret > 0) ++ return; ++ ++ ret = split_squashfs(master, part->offset, &split_offset); ++ if (ret) ++ return; ++ ++ if (split_offset <= 0) ++ return; ++ ++ split_size = part->mtd.size - (split_offset - part->offset); ++ printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=0x%x, len=0x%x\n", ++ ROOTFS_SPLIT_NAME, split_offset, split_size); ++ ++ __mtd_add_partition(master, ROOTFS_SPLIT_NAME, split_offset, ++ split_size, false); ++} ++ ++#define UBOOT_MAGIC 0x27051956 ++ ++static void split_uimage(struct mtd_info *master, struct mtd_part *part) ++{ ++ struct { ++ __be32 magic; ++ __be32 pad0[2]; ++ __be32 size; ++ __be32 pad1[4]; ++ __be32 name[7]; ++ __be32 kern_size; ++ } hdr; ++ size_t len; ++ ++ if (mtd_read(master, part->offset, sizeof(hdr), &len, (void *) &hdr)) ++ return; ++ ++ if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC)) ++ return; ++ ++ if (hdr.kern_size != 0 && hdr.name[0] == 0) ++ len = be32_to_cpu(hdr.kern_size); ++ else ++ len = be32_to_cpu(hdr.size) + 0x40; ++ ++ __mtd_add_partition(master, "rootfs", part->offset + len, ++ part->mtd.size - len, false); ++} ++ ++#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME ++#else ++#define SPLIT_FIRMWARE_NAME "unused" ++#endif ++ ++static void split_firmware(struct mtd_info *master, struct mtd_part *part) ++{ ++ int ret; ++ ++ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE); ++ if (ret > 0) ++ return; ++ ++ if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT)) ++ split_uimage(master, part); ++} ++ ++void __weak arch_split_mtd_part(struct mtd_info *master, const char *name, ++ int offset, int size) ++{ ++} ++ ++static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part) ++{ ++ static int rootfs_found = 0; ++ ++ if (rootfs_found) ++ return; ++ ++ if (!strcmp(part->mtd.name, "rootfs")) { ++ rootfs_found = 1; ++ ++ if (config_enabled(CONFIG_MTD_ROOTFS_SPLIT)) ++ split_rootfs_data(master, part); ++ } ++ ++ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) && ++ config_enabled(CONFIG_MTD_SPLIT_FIRMWARE)) ++ split_firmware(master, part); ++ ++ arch_split_mtd_part(master, part->mtd.name, part->offset, ++ part->mtd.size); ++} ++#endif /* CONFIG_SUPPORT_OPENWRT */ ++ + /* + * This function, given a master MTD object and a partition table, creates + * and registers slave MTD objects which are bound to the master according to +@@ -661,7 +1010,9 @@ int add_mtd_partitions(struct mtd_info * + mutex_unlock(&mtd_partitions_mutex); + + add_mtd_device(&slave->mtd); +- ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ mtd_partition_split(master, slave); ++#endif + cur_offset = slave->offset + slave->mtd.size; + } + #ifdef DYNAMIC_CHANGE_MTD_WRITEABLE //wschen 2011-01-05 +@@ -692,6 +1043,32 @@ static struct mtd_part_parser *get_parti + + #define put_partition_parser(p) do { module_put((p)->owner); } while (0) + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++static struct mtd_part_parser * ++get_partition_parser_by_type(enum mtd_parser_type type, ++ struct mtd_part_parser *start) ++{ ++ struct mtd_part_parser *p, *ret = NULL; ++ ++ spin_lock(&part_parser_lock); ++ ++ p = list_prepare_entry(start, &part_parsers, list); ++ if (start) ++ put_partition_parser(start); ++ ++ list_for_each_entry_continue(p, &part_parsers, list) { ++ if (p->type == type && try_module_get(p->owner)) { ++ ret = p; ++ break; ++ } ++ } ++ ++ spin_unlock(&part_parser_lock); ++ ++ return ret; ++} ++#endif ++ + int register_mtd_parser(struct mtd_part_parser *p) + { + spin_lock(&part_parser_lock); +@@ -768,6 +1145,40 @@ int parse_mtd_partitions(struct mtd_info + return ret; + } + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data) ++{ ++ struct mtd_part_parser *prev = NULL; ++ int ret = 0; ++ ++ while (1) { ++ struct mtd_part_parser *parser; ++ ++ parser = get_partition_parser_by_type(type, prev); ++ if (!parser) ++ break; ++ ++ ret = (*parser->parse_fn)(master, pparts, data); ++ ++ if (ret > 0) { ++ put_partition_parser(parser); ++ printk(KERN_NOTICE ++ "%d %s partitions found on MTD device %s\n", ++ ret, parser->name, master->name); ++ break; ++ } ++ ++ prev = parser; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type); ++#endif /* CONFIG_SUPPORT_OPENWRT */ ++ + int mtd_is_partition(const struct mtd_info *mtd) + { + struct mtd_part *part; +@@ -785,6 +1196,26 @@ int mtd_is_partition(const struct mtd_in + } + EXPORT_SYMBOL_GPL(mtd_is_partition); + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return (struct mtd_info *)mtd; ++ ++ return PART(mtd)->master; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_master); ++ ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd) ++{ ++ if (!mtd_is_partition(mtd)) ++ return 0; ++ ++ return PART(mtd)->offset; ++} ++EXPORT_SYMBOL_GPL(mtdpart_get_offset); ++#endif /* CONFIG_SUPPORT_OPENWRT */ ++ + #ifdef CONFIG_MTK_MTD_NAND + u64 mtd_partition_start_address(struct mtd_info *mtd) + { +Index: linux-3.10.20/include/linux/mtd/map.h +=================================================================== +--- linux-3.10.20.orig/include/linux/mtd/map.h ++++ linux-3.10.20/include/linux/mtd/map.h +@@ -365,7 +365,7 @@ static inline map_word map_word_load_par + bitpos = (map_bankwidth(map)-1-i)*8; + #endif + orig.x[0] &= ~(0xff << bitpos); +- orig.x[0] |= buf[i-start] << bitpos; ++ orig.x[0] |= (unsigned long)buf[i-start] << bitpos; + } + } + return orig; +@@ -384,7 +384,7 @@ static inline map_word map_word_ff(struc + + if (map_bankwidth(map) < MAP_FF_LIMIT) { + int bw = 8 * map_bankwidth(map); +- r.x[0] = (1 << bw) - 1; ++ r.x[0] = (1UL << bw) - 1; + } else { + for (i=0; i<map_words(map); i++) + r.x[i] = ~0UL; +Index: linux-3.10.20/include/linux/mtd/mtd.h +=================================================================== +--- linux-3.10.20.orig/include/linux/mtd/mtd.h ++++ linux-3.10.20/include/linux/mtd/mtd.h +@@ -74,6 +74,9 @@ struct erase_info { + u_long priv; + u_char state; + struct erase_info *next; ++ u8 *erase_buf; ++ u32 erase_buf_ofs; ++ bool partial_start; + }; + + struct mtd_erase_region_info { +@@ -347,6 +350,26 @@ static inline uint32_t mtd_mod_by_eb(uin + return do_div(sz, mtd->erasesize); + } + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round up to next erase block */ ++ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize; ++} ++ ++static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd) ++{ ++ if (mtd_mod_by_eb(sz, mtd) == 0) ++ return sz; ++ ++ /* Round down to the start of the current erase block */ ++ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize; ++} ++#endif ++ + static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd) + { + if (mtd->writesize_shift) +Index: linux-3.10.20/include/linux/mtd/nand.h +=================================================================== +--- linux-3.10.20.orig/include/linux/mtd/nand.h ++++ linux-3.10.20/include/linux/mtd/nand.h +@@ -679,6 +679,7 @@ struct platform_nand_chip { + unsigned int options; + unsigned int bbt_options; + const char **part_probe_types; ++ int (*chip_fixup)(struct mtd_info *mtd); + }; + + /* Keep gcc happy */ +Index: linux-3.10.20/include/linux/mtd/partitions.h +=================================================================== +--- linux-3.10.20.orig/include/linux/mtd/partitions.h ++++ linux-3.10.20/include/linux/mtd/partitions.h +@@ -68,12 +68,23 @@ struct mtd_part_parser_data { + * Functions dealing with the various ways of partitioning the space + */ + ++#if defined(CONFIG_SUPPORT_OPENWRT) ++enum mtd_parser_type { ++ MTD_PARSER_TYPE_DEVICE = 0, ++ MTD_PARSER_TYPE_ROOTFS, ++ MTD_PARSER_TYPE_FIRMWARE, ++}; ++#endif ++ + struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, + struct mtd_part_parser_data *); ++#if defined(CONFIG_SUPPORT_OPENWRT) ++ enum mtd_parser_type type; ++#endif + }; + + extern int register_mtd_parser(struct mtd_part_parser *parser); +@@ -83,6 +94,18 @@ int mtd_is_partition(const struct mtd_in + int mtd_add_partition(struct mtd_info *master, char *name, + long long offset, long long length); + int mtd_del_partition(struct mtd_info *master, int partno); ++#if defined(CONFIG_SUPPORT_OPENWRT) ++struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd); ++uint64_t mtdpart_get_offset(const struct mtd_info *mtd); ++#endif + uint64_t mtd_get_device_size(const struct mtd_info *mtd); ++#if defined(CONFIG_SUPPORT_OPENWRT) ++extern void __weak arch_split_mtd_part(struct mtd_info *master, ++ const char *name, int offset, int size); + ++int parse_mtd_partitions_by_type(struct mtd_info *master, ++ enum mtd_parser_type type, ++ struct mtd_partition **pparts, ++ struct mtd_part_parser_data *data); ++#endif + #endif |