Hello OpenWrt developers,

this is a cross-platform issue where I need your expertise.

As I build for Orion with kernel symbols the kernel is normally bigger
than the 1MB mtd partition.
That's why I'm interested in having support for flexible kernel sizes.
This would also allow people to reduce kernel size and gain more JFFS2
space.

While following the OpenWrt development I came across ticket #8781,
where in comment #6 [1] it was hinted to the Lantiq platform that
provides a patch [2] that splits a "linux" partition into a "rootfs"
partition after the uImage.
Unfortuantely that patch from the Lantiq platform bricked my device.
Reason was that it does not deal correctly with the Endianness of the
uImage header.
In my case (Linksys WRT350N v2, platform Orion/ARM) the kernel and
rootfs partition got so huge, that my U-Boot partition at the end of the
flash was overwritten during boot.
Hence I did a rework of that patch, which is attached (and also inline
for comments).

As I'm not a hardware and/or Linux guru I do not know if this reworked
patch is 100% correct, although I tried to keep it totally close to the
generic rootfs_split.patch [3].
I couldn't test it on devices with a different Endianness than my
Linksys WRT350N v2 [4].
Still the code has no size checks against the parent mtd, because the
generic rootfs_split.patch has also none.

It would be great if you could review the reworked patch and maybe add
it to the generic patches.
Maybe someone could also verify it on the Lantiq platform.
Or is a script solution as described in ticket #8781 the preferred way?
Or how is it done for the WRT54G devices?

To enable the patch add "CONFIG_MTD_UIMAGE_SPLIT=y" to your platform's
config-default.
The uImage must be padded to the erase size of the device, and the
rootfs must be following immediately behind it.

Tip: To test new code which can destroy your flash, boot a ramdisk
build. This way no writes are done to the flash. - Now I know.

Thanks for your time and reading
Maddes

P.S.:
a) Maybe CONFIG_MTD_LINUX_UIMAGE_SPLIT would be a better fitting name
for the config setting.
b) I also attach the changes for the Orion platform generic subtarget to
enable the new uImage/"linux" split.

[1] https://dev.openwrt.org/ticket/8781#comment:6
[2]
https://dev.openwrt.org/browser/trunk/target/linux/lantiq/patches-3.0/210-mtd_uimage_split.patch
[3]
https://dev.openwrt.org/browser/trunk/target/linux/generic/patches-3.0/400-rootfs_split.patch
[4] http://wiki.openwrt.org/toh/linksys/wrt350nv2


--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -41,6 +41,10 @@ config MTD_ROOTFS_SPLIT
        bool "Automatically split 'rootfs' partition for squashfs"
        default y

+config MTD_UIMAGE_SPLIT
+       bool "Automatically split 'linux' partition with uImage for rootfs"
+       default y
+
 config MTD_REDBOOT_PARTS
        tristate "RedBoot partition table parsing"
        ---help---
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -13,7 +13,7 @@ extern struct mtd_info *__mtd_next_devic
 extern int add_mtd_device(struct mtd_info *mtd);
 extern int del_mtd_device(struct mtd_info *mtd);
 extern int add_mtd_partitions(struct mtd_info *, const struct
mtd_partition *,
-                             int);
+                             int, int, struct mtd_info *);
 extern int del_mtd_partitions(struct mtd_info *);

 #define mtd_for_each_device(mtd)                       \
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -446,7 +446,7 @@ int mtd_device_register(struct mtd_info
                        const struct mtd_partition *parts,
                        int nr_parts)
 {
-       return parts ? add_mtd_partitions(master, parts, nr_parts) :
+       return parts ? add_mtd_partitions(master, parts, nr_parts, 0, NULL) :
                add_mtd_device(master);
 }
 EXPORT_SYMBOL_GPL(mtd_device_register);
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -861,6 +861,196 @@ static int refresh_rootfs_split(struct m
 }
 #endif /* CONFIG_MTD_ROOTFS_SPLIT */

+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+/*
+ * adopted from OpenWrt's generic patch rootfs_split.patch
+ */
+
+#define UIMAGE_SPLIT_NAME "rootfs"
+#define UIMAGE_REMOVED_NAME "<removed>"
+
+/*
+ * image header format as described in U-Boot's include/image.h
+ * see
http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=blob;f=include/image.h
+ */
+#define IH_MAGIC       0x27051956      /* Image Magic Number           */
+#define IH_NMLEN               32      /* Image Name Length            */
+/*
+ * Legacy format image header,
+ * all data in network byte order (aka natural aka bigendian).
+ */
+typedef struct image_header {
+       uint32_t        ih_magic;       /* Image Header Magic Number    */
+       uint32_t        ih_hcrc;        /* Image Header CRC Checksum    */
+       uint32_t        ih_time;        /* Image Creation Timestamp     */
+       uint32_t        ih_size;        /* Image Data Size              */
+       uint32_t        ih_load;        /* Data  Load  Address          */
+       uint32_t        ih_ep;          /* Entry Point Address          */
+       uint32_t        ih_dcrc;        /* Image Data CRC Checksum      */
+       uint8_t         ih_os;          /* Operating System             */
+       uint8_t         ih_arch;        /* CPU architecture             */
+       uint8_t         ih_type;        /* Image Type                   */
+       uint8_t         ih_comp;        /* Compression Type             */
+       uint8_t         ih_name[IH_NMLEN];      /* Image Name           */
+} image_header_t;
+
+static int split_uimage(struct mtd_info *master, int offset, int
*split_offset)
+{
+/*
+ * adopted from OpenWrt's split_squashfs() in drivers/mtd/mtdpart.c
+ */
+       struct image_header ih;
+       int len, ret;
+
+       ret = master->read(master, offset, sizeof(ih), &len, (void *) &ih);
+       if (ret || (len != sizeof(ih))) {
+               printk(KERN_ALERT "split_uimage: error occured while reading "
+                       "from \"%s\"\n", master->name);
+               return -EINVAL;
+       }
+
+       if (IH_MAGIC != be32_to_cpu(ih.ih_magic) ) {
+               printk(KERN_ALERT "split_uimage: no uimage found in \"%s\"\n",
+                       master->name);
+               *split_offset = 0;
+               return 0;
+       }
+
+       if (be32_to_cpu(ih.ih_size) <= 0) {
+               printk(KERN_ALERT "split_uimage: uimage is empty in \"%s\"\n",
+                       master->name);
+               *split_offset = 0;
+               return 0;
+       }
+
+       len = be32_to_cpu(ih.ih_size);
+       len += sizeof(ih);
+       len += (offset & 0x000fffff);
+       len +=  (master->erasesize - 1);
+       len &= ~(master->erasesize - 1);
+       len -= (offset & 0x000fffff);
+       *split_offset = offset + len;
+
+       return 0;
+}
+
+static int split_rootfs(struct mtd_info *master, struct mtd_info
*rpart, const struct mtd_partition *part)
+{
+/*
+ * adopted from OpenWrt's split_rootfs_data() in drivers/mtd/mtdpart.c
+ */
+       struct mtd_partition *dpart;
+/*     struct mtd_part *slave = NULL; */
+       struct mtd_part *spart;
+       int ret, split_offset = 0;
+
+       spart = PART(rpart);
+       ret = split_uimage(master, spart->offset, &split_offset);
+       if (ret)
+               return ret;
+
+       if (split_offset <= 0)
+               return 0;
+
+       dpart = kmalloc(sizeof(*part)+sizeof(UIMAGE_SPLIT_NAME)+1, GFP_KERNEL);
+       if (dpart == NULL) {
+               printk(KERN_INFO "split_rootfs: no memory for partition 
\"%s\"\n",
+                       UIMAGE_SPLIT_NAME);
+               return -ENOMEM;
+       }
+
+       memcpy(dpart, part, sizeof(*part));
+       dpart->name = (unsigned char *)&dpart[1];
+       strcpy(dpart->name, UIMAGE_SPLIT_NAME);
+
+       dpart->size = rpart->size - (split_offset - spart->offset);
+       dpart->offset = split_offset;
+
+       if (dpart == NULL)
+               return 1;
+
+       printk(KERN_INFO "mtd: partition \"%s\" created automatically,
ofs=%llX, len=%llX \n",
+               UIMAGE_SPLIT_NAME, dpart->offset, dpart->size);
+
+/* TODO: the following is almost done in add_mtd_partitions()
+// TODO/difference: split_offset here vs. cur_offset in add_mtd_partitions.
+//                  only used for allocate_partition() call, function
defined here in mtdpart.c
+//                  only used in allocate_partition() if slave->offset
is MTDPART_OFS_APPEND or MTDPART_OFS_NXTBLK
+       slave = allocate_partition(master, dpart, 0, split_offset);
+       if (IS_ERR(slave))
+               return PTR_ERR(slave);
+       mutex_lock(&mtd_partitions_mutex);
+       list_add(&slave->list, &mtd_partitions);
+       mutex_unlock(&mtd_partitions_mutex);
+
+       add_mtd_device(&slave->mtd);
+
+// TODO: add_mtd_partitions() was enhanced to accept rpart as
additional parameter
+//       here rpart is &slave->mtd of calling add_mtd_partitions()
+       rpart->split = &slave->mtd;
+*/
+
+       add_mtd_partitions(master, dpart, 1, split_offset, rpart);
+
+       return 0;
+}
+
+static int refresh_linux_split(struct mtd_info *mtd)
+{
+/*
+ * adopted from OpenWrt's refresh_rootfs_split() in drivers/mtd/mtdpart.c
+ */
+       struct mtd_partition tpart;
+       struct mtd_part *part;
+       char *name;
+       //int index = 0;
+       int offset, size;
+       int ret;
+
+       part = PART(mtd);
+
+       /* check for the new uimage offset first */
+       ret = split_uimage(part->master, part->offset, &offset);
+       if (ret)
+               return ret;
+
+       if ((offset > 0) && !mtd->split) {
+               printk(KERN_INFO "%s: creating new split partition for 
\"%s\"\n",
__func__, mtd->name);
+               /* if we don't have a uimage split partition, create a new one 
*/
+               tpart.name = (char *) mtd->name;
+               tpart.size = mtd->size;
+               tpart.offset = part->offset;
+
+               return split_rootfs(part->master, &part->mtd, &tpart);
+       } else if ((offset > 0) && mtd->split) {
+               /* update the offsets of the existing partition */
+               size = mtd->size + part->offset - offset;
+
+               part = PART(mtd->split);
+               part->offset = offset;
+               part->mtd.size = size;
+               printk(KERN_INFO "%s: %s partition \"" UIMAGE_SPLIT_NAME "\", 
offset:
0x%06x (0x%06x)\n",
+                       __func__, (!strcmp(part->mtd.name, UIMAGE_SPLIT_NAME) ? 
"updating" :
"creating"),
+                       (u32) part->offset, (u32) part->mtd.size);
+               name = kmalloc(sizeof(UIMAGE_SPLIT_NAME) + 1, GFP_KERNEL);
+               strcpy(name, UIMAGE_SPLIT_NAME);
+               part->mtd.name = name;
+       } else if ((offset <= 0) && mtd->split) {
+               printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__,
mtd->split->name);
+
+               /* mark existing partition as removed */
+               part = PART(mtd->split);
+               name = kmalloc(sizeof(UIMAGE_SPLIT_NAME) + 1, GFP_KERNEL);
+               strcpy(name, UIMAGE_REMOVED_NAME);
+               part->mtd.name = name;
+               part->offset = 0;
+               part->mtd.size = 0;
+       }
+
+       return 0;
+}
+#endif /* CONFIG_MTD_UIMAGE_SPLIT */
+
 /*
  * 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
@@ -872,17 +1062,24 @@ static int refresh_rootfs_split(struct m

 int add_mtd_partitions(struct mtd_info *master,
                       const struct mtd_partition *parts,
-                      int nbparts)
+                      int nbparts,
+                       int split_offset,
+                       struct mtd_info *rpart)
 {
        struct mtd_part *slave;
-       uint64_t cur_offset = 0;
+       uint64_t cur_offset = split_offset;
        int i;
-#ifdef CONFIG_MTD_ROOTFS_SPLIT
+#if defined(CONFIG_MTD_ROOTFS_SPLIT) || defined(CONFIG_MTD_UIMAGE_SPLIT)
        int ret;
 #endif

        printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts,
master->name);

+       if ((rpart != NULL) && (nbparts > 1)) {
+               printk(KERN_WARNING "add_mtd_partitions: %d splits, only first 
one
will be linked to parent \"%s\"\n",
+                       nbparts, rpart->name);
+       }
+
        for (i = 0; i < nbparts; i++) {
                slave = allocate_partition(master, parts + i, i, cur_offset);
                if (IS_ERR(slave))
@@ -894,6 +1091,18 @@ int add_mtd_partitions(struct mtd_info *

                add_mtd_device(&slave->mtd);

+               if ((rpart != NULL) && (i == 0)) {
+                       rpart->split = &slave->mtd;
+               }
+
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+               if (!strcmp(parts[i].name, "linux")) {
+                       ret = split_rootfs(master, &slave->mtd, &parts[i]);
+                       /* if (ret == 0)
+                        *      j++; */
+               }
+#endif
+
                if (!strcmp(parts[i].name, "rootfs")) {
 #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
                        if (ROOT_DEV == 0) {
@@ -937,6 +1146,11 @@ int mtd_device_refresh(struct mtd_info *
                refresh_rootfs_split(mtd);
 #endif

+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+       if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "linux"))
+               refresh_linux_split(mtd);
+#endif
+
        return 0;
 }
 EXPORT_SYMBOL_GPL(mtd_device_refresh);
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -41,6 +41,10 @@ config MTD_ROOTFS_SPLIT
 	bool "Automatically split 'rootfs' partition for squashfs"
 	default y
 
+config MTD_UIMAGE_SPLIT
+	bool "Automatically split 'linux' partition with uImage for rootfs"
+	default y
+
 config MTD_REDBOOT_PARTS
 	tristate "RedBoot partition table parsing"
 	---help---
--- a/drivers/mtd/mtdcore.h
+++ b/drivers/mtd/mtdcore.h
@@ -13,7 +13,7 @@ extern struct mtd_info *__mtd_next_devic
 extern int add_mtd_device(struct mtd_info *mtd);
 extern int del_mtd_device(struct mtd_info *mtd);
 extern int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *,
-			      int);
+			      int, int, struct mtd_info *);
 extern int del_mtd_partitions(struct mtd_info *);
 
 #define mtd_for_each_device(mtd)			\
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -446,7 +446,7 @@ int mtd_device_register(struct mtd_info
 			const struct mtd_partition *parts,
 			int nr_parts)
 {
-	return parts ? add_mtd_partitions(master, parts, nr_parts) :
+	return parts ? add_mtd_partitions(master, parts, nr_parts, 0, NULL) :
 		add_mtd_device(master);
 }
 EXPORT_SYMBOL_GPL(mtd_device_register);
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -861,6 +861,196 @@ static int refresh_rootfs_split(struct m
 }
 #endif /* CONFIG_MTD_ROOTFS_SPLIT */
 
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+/*
+ * adopted from OpenWrt's generic patch rootfs_split.patch
+ */
+
+#define UIMAGE_SPLIT_NAME "rootfs"
+#define UIMAGE_REMOVED_NAME "<removed>"
+
+/*
+ * image header format as described in U-Boot's include/image.h
+ * see http://git.denx.de/cgi-bin/gitweb.cgi?p=u-boot.git;a=blob;f=include/image.h
+ */
+#define IH_MAGIC	0x27051956	/* Image Magic Number		*/
+#define IH_NMLEN		32	/* Image Name Length		*/
+/*
+ * Legacy format image header,
+ * all data in network byte order (aka natural aka bigendian).
+ */
+typedef struct image_header {
+	uint32_t	ih_magic;	/* Image Header Magic Number	*/
+	uint32_t	ih_hcrc;	/* Image Header CRC Checksum	*/
+	uint32_t	ih_time;	/* Image Creation Timestamp	*/
+	uint32_t	ih_size;	/* Image Data Size		*/
+	uint32_t	ih_load;	/* Data	 Load  Address		*/
+	uint32_t	ih_ep;		/* Entry Point Address		*/
+	uint32_t	ih_dcrc;	/* Image Data CRC Checksum	*/
+	uint8_t		ih_os;		/* Operating System		*/
+	uint8_t		ih_arch;	/* CPU architecture		*/
+	uint8_t		ih_type;	/* Image Type			*/
+	uint8_t		ih_comp;	/* Compression Type		*/
+	uint8_t		ih_name[IH_NMLEN];	/* Image Name		*/
+} image_header_t;
+
+static int split_uimage(struct mtd_info *master, int offset, int *split_offset)
+{
+/*
+ * adopted from OpenWrt's split_squashfs() in drivers/mtd/mtdpart.c
+ */
+	struct image_header ih;
+	int len, ret;
+
+	ret = master->read(master, offset, sizeof(ih), &len, (void *) &ih);
+	if (ret || (len != sizeof(ih))) {
+		printk(KERN_ALERT "split_uimage: error occured while reading "
+			"from \"%s\"\n", master->name);
+		return -EINVAL;
+	}
+
+	if (IH_MAGIC != be32_to_cpu(ih.ih_magic) ) {
+		printk(KERN_ALERT "split_uimage: no uimage found in \"%s\"\n",
+			master->name);
+		*split_offset = 0;
+		return 0;
+	}
+
+	if (be32_to_cpu(ih.ih_size) <= 0) {
+		printk(KERN_ALERT "split_uimage: uimage is empty in \"%s\"\n",
+			master->name);
+		*split_offset = 0;
+		return 0;
+	}
+
+	len = be32_to_cpu(ih.ih_size);
+	len += sizeof(ih);
+	len += (offset & 0x000fffff);
+	len +=  (master->erasesize - 1);
+	len &= ~(master->erasesize - 1);
+	len -= (offset & 0x000fffff);
+	*split_offset = offset + len;
+
+	return 0;
+}
+
+static int split_rootfs(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part)
+{
+/*
+ * adopted from OpenWrt's split_rootfs_data() in drivers/mtd/mtdpart.c
+ */
+	struct mtd_partition *dpart;
+/*	struct mtd_part *slave = NULL; */
+	struct mtd_part *spart;
+	int ret, split_offset = 0;
+
+	spart = PART(rpart);
+	ret = split_uimage(master, spart->offset, &split_offset);
+	if (ret)
+		return ret;
+
+	if (split_offset <= 0)
+		return 0;
+
+	dpart = kmalloc(sizeof(*part)+sizeof(UIMAGE_SPLIT_NAME)+1, GFP_KERNEL);
+	if (dpart == NULL) {
+		printk(KERN_INFO "split_rootfs: no memory for partition \"%s\"\n",
+			UIMAGE_SPLIT_NAME);
+		return -ENOMEM;
+	}
+
+	memcpy(dpart, part, sizeof(*part));
+	dpart->name = (unsigned char *)&dpart[1];
+	strcpy(dpart->name, UIMAGE_SPLIT_NAME);
+
+	dpart->size = rpart->size - (split_offset - spart->offset);
+	dpart->offset = split_offset;
+
+	if (dpart == NULL)
+		return 1;
+
+	printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%llX, len=%llX \n",
+		UIMAGE_SPLIT_NAME, dpart->offset, dpart->size);
+
+/* TODO: the following is almost done in add_mtd_partitions()
+// TODO/difference: split_offset here vs. cur_offset in add_mtd_partitions.
+//                  only used for allocate_partition() call, function defined here in mtdpart.c
+//                  only used in allocate_partition() if slave->offset is MTDPART_OFS_APPEND or MTDPART_OFS_NXTBLK
+	slave = allocate_partition(master, dpart, 0, split_offset);
+	if (IS_ERR(slave))
+		return PTR_ERR(slave);
+	mutex_lock(&mtd_partitions_mutex);
+	list_add(&slave->list, &mtd_partitions);
+	mutex_unlock(&mtd_partitions_mutex);
+
+	add_mtd_device(&slave->mtd);
+
+// TODO: add_mtd_partitions() was enhanced to accept rpart as additional parameter
+//       here rpart is &slave->mtd of calling add_mtd_partitions()
+	rpart->split = &slave->mtd;
+*/
+
+	add_mtd_partitions(master, dpart, 1, split_offset, rpart); 
+
+	return 0;
+}
+
+static int refresh_linux_split(struct mtd_info *mtd)
+{
+/*
+ * adopted from OpenWrt's refresh_rootfs_split() in drivers/mtd/mtdpart.c
+ */
+	struct mtd_partition tpart;
+	struct mtd_part *part;
+	char *name;
+	//int index = 0;
+	int offset, size;
+	int ret;
+
+	part = PART(mtd);
+
+	/* check for the new uimage offset first */
+	ret = split_uimage(part->master, part->offset, &offset);
+	if (ret)
+		return ret;
+
+	if ((offset > 0) && !mtd->split) {
+		printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
+		/* if we don't have a uimage split partition, create a new one */
+		tpart.name = (char *) mtd->name;
+		tpart.size = mtd->size;
+		tpart.offset = part->offset;
+
+		return split_rootfs(part->master, &part->mtd, &tpart);
+	} else if ((offset > 0) && mtd->split) {
+		/* update the offsets of the existing partition */
+		size = mtd->size + part->offset - offset;
+
+		part = PART(mtd->split);
+		part->offset = offset;
+		part->mtd.size = size;
+		printk(KERN_INFO "%s: %s partition \"" UIMAGE_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
+			__func__, (!strcmp(part->mtd.name, UIMAGE_SPLIT_NAME) ? "updating" : "creating"),
+			(u32) part->offset, (u32) part->mtd.size);
+		name = kmalloc(sizeof(UIMAGE_SPLIT_NAME) + 1, GFP_KERNEL);
+		strcpy(name, UIMAGE_SPLIT_NAME);
+		part->mtd.name = name;
+	} else if ((offset <= 0) && mtd->split) {
+		printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
+
+		/* mark existing partition as removed */
+		part = PART(mtd->split);
+		name = kmalloc(sizeof(UIMAGE_SPLIT_NAME) + 1, GFP_KERNEL);
+		strcpy(name, UIMAGE_REMOVED_NAME);
+		part->mtd.name = name;
+		part->offset = 0;
+		part->mtd.size = 0;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_MTD_UIMAGE_SPLIT */
+
 /*
  * 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
@@ -872,17 +1062,24 @@ static int refresh_rootfs_split(struct m
 
 int add_mtd_partitions(struct mtd_info *master,
 		       const struct mtd_partition *parts,
-		       int nbparts)
+		       int nbparts,
+			int split_offset,
+			struct mtd_info *rpart)
 {
 	struct mtd_part *slave;
-	uint64_t cur_offset = 0;
+	uint64_t cur_offset = split_offset;
 	int i;
-#ifdef CONFIG_MTD_ROOTFS_SPLIT
+#if defined(CONFIG_MTD_ROOTFS_SPLIT) || defined(CONFIG_MTD_UIMAGE_SPLIT)
 	int ret;
 #endif
 
 	printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
 
+	if ((rpart != NULL) && (nbparts > 1)) {
+		printk(KERN_WARNING "add_mtd_partitions: %d splits, only first one will be linked to parent \"%s\"\n",
+			nbparts, rpart->name);
+	}
+
 	for (i = 0; i < nbparts; i++) {
 		slave = allocate_partition(master, parts + i, i, cur_offset);
 		if (IS_ERR(slave))
@@ -894,6 +1091,18 @@ int add_mtd_partitions(struct mtd_info *
 
 		add_mtd_device(&slave->mtd);
 
+		if ((rpart != NULL) && (i == 0)) {
+			rpart->split = &slave->mtd;
+		}
+
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+		if (!strcmp(parts[i].name, "linux")) {
+			ret = split_rootfs(master, &slave->mtd, &parts[i]);
+			/* if (ret == 0)
+			 * 	j++; */
+		}
+#endif
+
 		if (!strcmp(parts[i].name, "rootfs")) {
 #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
 			if (ROOT_DEV == 0) {
@@ -937,6 +1146,11 @@ int mtd_device_refresh(struct mtd_info *
 		refresh_rootfs_split(mtd);
 #endif
 
+#ifdef CONFIG_MTD_UIMAGE_SPLIT
+	if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "linux"))
+		refresh_linux_split(mtd);
+#endif
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(mtd_device_refresh);
Index: target/linux/orion/config-default
===================================================================
--- target/linux/orion/config-default	(revision 28299)
+++ target/linux/orion/config-default	(working copy)
@@ -246,3 +246,4 @@ CONFIG_WAN=y
 # CONFIG_XIP_KERNEL is not set
 CONFIG_ZBOOT_ROM_BSS=0x0
 CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_MTD_UIMAGE_SPLIT=y
Index: target/linux/orion/image/generic.mk
===================================================================
--- target/linux/orion/image/generic.mk	(revision 28299)
+++ target/linux/orion/image/generic.mk	(working copy)
@@ -43,10 +43,19 @@ endef
 define Image/Build/Linksys
 	# Orion Linksys Images
  # sysupgrade image
+ifeq ($(CONFIG_MTD_UIMAGE_SPLIT),y)
+	### padding uImage to erase size (as CONFIG_MTD_UIMAGE_SPLIT is enabled)
 	( \
+		dd if="${KDIR}/$2-uImage" bs=64k conv=sync; \
+		dd if="${KDIR}/root.$1" bs=64k conv=sync; \
+	) > "${BIN_DIR}/openwrt-$2-$1.img"
+else
+	### padding uImage to kernel size
+	( \
 		dd if="${KDIR}/$2-uImage" bs=$5 conv=sync; \
 		dd if="${KDIR}/root.$1" bs=64k conv=sync; \
 	) > "${BIN_DIR}/openwrt-$2-$1.img"
+endif
  # recovery image and webupgrade image for stock firmware
 	rm -rf "${TMP_DIR}/$2_webupgrade"
 	mkdir "${TMP_DIR}/$2_webupgrade"
Index: target/linux/orion/patches/100-wrt350nv2_openwrt_partition_map.patch
===================================================================
--- target/linux/orion/patches/100-wrt350nv2_openwrt_partition_map.patch	(revision 28299)
+++ target/linux/orion/patches/100-wrt350nv2_openwrt_partition_map.patch	(working copy)
@@ -1,21 +1,34 @@
 --- a/arch/arm/mach-orion5x/wrt350n-v2-setup.c
 +++ b/arch/arm/mach-orion5x/wrt350n-v2-setup.c
-@@ -135,11 +135,11 @@ static struct mtd_partition wrt350n_v2_n
+@@ -133,14 +133,24 @@
+ 
+ static struct mtd_partition wrt350n_v2_nor_flash_partitions[] = {
  	{
++#ifdef CONFIG_MTD_UIMAGE_SPLIT
++ 		.name		= "linux",
++#else
  		.name		= "kernel",
++#endif
  		.offset		= 0x00000000,
 -		.size		= 0x00760000,
++#ifdef CONFIG_MTD_UIMAGE_SPLIT
++		.size		= 0x00750000,	// exclude area with eRcOmM signature
++#else
 +		.size		= 0x00100000,	// change to kernel mtd size here (1/3)
++#endif
  	}, {
++#ifndef CONFIG_MTD_UIMAGE_SPLIT
  		.name		= "rootfs",
 -		.offset		= 0x001a0000,
 -		.size		= 0x005c0000,
 +		.offset		= 0x00100000,	// change to kernel mtd size here (2/3)
 +		.size		= 0x00650000,	// adopt to kernel mtd size here (3/3) = 0x00750000 - <kernel mtd size>
  	}, {
++#endif
  		.name		= "lang",
  		.offset		= 0x00760000,
-@@ -152,6 +152,14 @@ static struct mtd_partition wrt350n_v2_n
+ 		.size		= 0x00040000,
+@@ -152,6 +162,14 @@ static struct mtd_partition wrt350n_v2_n
  		.name		= "u-boot",
  		.offset		= 0x007c0000,
  		.size		= 0x00040000,
_______________________________________________
openwrt-devel mailing list
openwrt-devel@lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel

Reply via email to