firewall: update to git head
[openwrt.git] / target / linux / lantiq / patches-3.7 / 0300-owrt-mtd-split.patch
1 From 2a295753a10823a47542c779a25bbb1f52c71281 Mon Sep 17 00:00:00 2001
2 From: John Crispin <blogic@openwrt.org>
3 Date: Fri, 3 Aug 2012 10:27:13 +0200
4 Subject: [PATCH 19/25] owrt mtd split
5
6 ---
7  .../mips/include/asm/mach-lantiq/xway/lantiq_soc.h |    1 +
8  arch/mips/lantiq/setup.c                           |    7 +
9  drivers/mtd/Kconfig                                |    4 +
10  drivers/mtd/mtdpart.c                              |  173 +++++++++++++++++++-
11  4 files changed, 184 insertions(+), 1 deletions(-)
12
13 --- a/drivers/mtd/Kconfig
14 +++ b/drivers/mtd/Kconfig
15 @@ -31,6 +31,10 @@ config MTD_ROOTFS_SPLIT
16         bool "Automatically split 'rootfs' partition for squashfs"
17         default y
18  
19 +config MTD_UIMAGE_SPLIT
20 +       bool "Automatically split 'linux' partition into 'kernel' and 'rootfs'"
21 +       default y
22 +
23  config MTD_REDBOOT_PARTS
24         tristate "RedBoot partition table parsing"
25         ---help---
26 --- a/drivers/mtd/mtdpart.c
27 +++ b/drivers/mtd/mtdpart.c
28 @@ -844,6 +844,168 @@ static int refresh_rootfs_split(struct m
29  }
30  #endif /* CONFIG_MTD_ROOTFS_SPLIT */
31  
32 +#ifdef CONFIG_MTD_UIMAGE_SPLIT
33 +static unsigned long find_uimage_size(struct mtd_info *mtd,
34 +                                     unsigned long offset)
35 +{
36 +#define UBOOT_MAGIC    0x56190527
37 +       unsigned long magic = 0;
38 +       unsigned long temp;
39 +       size_t len;
40 +       int ret;
41 +
42 +       ret = mtd_read(mtd, offset, 4, &len, (void *)&magic);
43 +       if (ret || len != sizeof(magic))
44 +               return 0;
45 +
46 +       if (le32_to_cpu(magic) != UBOOT_MAGIC)
47 +               return 0;
48 +
49 +       ret = mtd_read(mtd, offset + 12, 4, &len, (void *)&temp);
50 +       if (ret || len != sizeof(temp))
51 +               return 0;
52 +
53 +       return temp + 0x40;
54 +}
55 +
56 +static unsigned long find_eva_size(struct mtd_info *mtd,
57 +                                     unsigned long offset)
58 +{
59 +#define EVA_MAGIC      0xfeed1281
60 +       unsigned long magic = 0;
61 +       unsigned long temp;
62 +       size_t len;
63 +       int ret;
64 +
65 +       ret = mtd_read(mtd, offset, 4, &len, (void *)&magic);
66 +       if (ret || len != sizeof(magic))
67 +               return 0;
68 +
69 +       if (le32_to_cpu(magic) != EVA_MAGIC)
70 +               return 0;
71 +
72 +       ret = mtd_read(mtd, offset + 4, 4, &len, (void *)&temp);
73 +       if (ret || len != sizeof(temp))
74 +               return 0;
75 +
76 +       /* add eva header size */
77 +       temp = le32_to_cpu(temp) + 0x18;
78 +
79 +       temp &= ~0xffff;
80 +       temp += 0x10000;
81 +       return temp;
82 +}
83 +
84 +static int detect_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
85 +{
86 +       unsigned long temp;
87 +       size_t len;
88 +       int ret;
89 +
90 +       ret = mtd_read(mtd, offset, 4, &len, (void *)&temp);
91 +       if (ret || len != sizeof(temp))
92 +               return 0;
93 +
94 +
95 +       return le32_to_cpu(temp) == SQUASHFS_MAGIC;
96 +}
97 +
98 +static int detect_eva_squashfs_partition(struct mtd_info *mtd, unsigned long offset)
99 +{
100 +       unsigned long temp;
101 +       size_t len;
102 +       int ret;
103 +
104 +       ret = mtd_read(mtd, offset, 4, &len, (void *)&temp);
105 +       if (ret || len != sizeof(temp))
106 +               return 0;
107 +
108 +       return be32_to_cpu(temp) == SQUASHFS_MAGIC;
109 +}
110 +
111 +static unsigned long find_brnimage_size(struct mtd_info *mtd,
112 +                                       unsigned long offset)
113 +{
114 +       unsigned long buf[4];
115 +       // Assume at most 2MB of kernel image
116 +       unsigned long end = offset + (2 << 20);
117 +       unsigned long ptr = offset + 0x400 - 12;
118 +       size_t len;
119 +       int ret;
120 +
121 +       while (ptr < end) {
122 +               long size_min = ptr - 0x400 - 12 - offset;
123 +               long size_max = ptr + 12 - offset;
124 +               ret = mtd_read(mtd, ptr, 16, &len, (void *)buf);
125 +               if (ret || len != 16)
126 +                       return 0;
127 +
128 +               if (le32_to_cpu(buf[0]) < size_min ||
129 +                   le32_to_cpu(buf[0]) > size_max) {
130 +                       ptr += 0x400;
131 +                       continue;
132 +               }
133 +
134 +               if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC)
135 +                       return ptr + 12 - offset;
136 +
137 +               ptr += 0x400;
138 +       }
139 +
140 +       return 0;
141 +}
142 +
143 +static int split_uimage(struct mtd_info *mtd,
144 +                       const struct mtd_partition *part)
145 +{
146 +       static struct mtd_partition split_partitions[] = {
147 +               {
148 +                       .name = "kernel",
149 +                       .offset = 0x0,
150 +                       .size = 0x0,
151 +               }, {
152 +                       .name = "rootfs",
153 +                       .offset = 0x0,
154 +                       .size = 0x0,
155 +               },
156 +       };
157 +
158 +       split_partitions[0].size = find_uimage_size(mtd, part->offset);
159 +       if (!split_partitions[0].size) {
160 +               split_partitions[0].size = find_eva_size(mtd, part->offset);
161 +               if (!split_partitions[0].size) {
162 +                       split_partitions[0].size = find_brnimage_size(mtd, part->offset);
163 +                       if (!split_partitions[0].size) {
164 +                               printk(KERN_NOTICE "no uImage or brnImage or eva found in linux partition\n");
165 +                               return -1;
166 +                       }
167 +               }
168 +       }
169 +
170 +       if (detect_eva_squashfs_partition(mtd,
171 +                                      part->offset
172 +                                      + split_partitions[0].size)) {
173 +               split_partitions[0].size += 0x100;
174 +               pr_info("found eva dummy squashfs behind kernel\n");
175 +       } else if (!detect_squashfs_partition(mtd,
176 +                                      part->offset
177 +                                      + split_partitions[0].size)) {
178 +               split_partitions[0].size &= ~(mtd->erasesize - 1);
179 +               split_partitions[0].size += mtd->erasesize;
180 +       } else {
181 +               pr_info("found squashfs behind kernel\n");
182 +       }
183 +
184 +       split_partitions[0].offset = part->offset;
185 +       split_partitions[1].offset = part->offset + split_partitions[0].size;
186 +       split_partitions[1].size = part->size - split_partitions[0].size;
187 +
188 +       add_mtd_partitions(mtd, split_partitions, 2);
189 +
190 +       return 0;
191 +}
192 +#endif
193 +
194  /*
195   * This function, given a master MTD object and a partition table, creates
196   * and registers slave MTD objects which are bound to the master according to
197 @@ -860,7 +1022,7 @@ int add_mtd_partitions(struct mtd_info *
198         struct mtd_part *slave;
199         uint64_t cur_offset = 0;
200         int i;
201 -#ifdef CONFIG_MTD_ROOTFS_SPLIT
202 +#if defined(CONFIG_MTD_ROOTFS_SPLIT) || defined(CONFIG_MTD_UIMAGE_SPLIT)
203         int ret;
204  #endif
205  
206 @@ -877,6 +1039,15 @@ int add_mtd_partitions(struct mtd_info *
207  
208                 add_mtd_device(&slave->mtd);
209  
210 +#ifdef CONFIG_MTD_UIMAGE_SPLIT
211 +               if (!strcmp(parts[i].name, "linux")) {
212 +                       ret = split_uimage(master, &parts[i]);
213 +
214 +                       if (ret)
215 +                               printk(KERN_WARNING "Can't split linux partition\n");
216 +               }
217 +#endif
218 +
219                 if (!strcmp(parts[i].name, "rootfs")) {
220  #ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
221                         if (ROOT_DEV == 0) {