056f5177fa28014a26d1b9cb99160c874e48661d
[openwrt.git] / target / linux / lantiq / patches-3.10 / 0100-mtd-split.patch
1 --- a/arch/mips/lantiq/xway/Makefile
2 +++ b/arch/mips/lantiq/xway/Makefile
3 @@ -1,6 +1,6 @@
4  obj-y := prom.o sysctrl.o clk.o reset.o dma.o gptu.o dcdc.o
5  
6 -obj-y += vmmc.o
7 +obj-y += vmmc.o mtd_split.o
8  
9  obj-$(CONFIG_PCI) += ath_eep.o rt_eep.o pci-ath-fixup.o
10  
11 --- /dev/null
12 +++ b/arch/mips/lantiq/xway/mtd_split.c
13 @@ -0,0 +1,129 @@
14 +#include <linux/magic.h>
15 +#include <linux/root_dev.h>
16 +#include <linux/mtd/mtd.h>
17 +#include <linux/mtd/partitions.h>
18 +
19 +#define ROOTFS_SPLIT_NAME "rootfs_data"
20 +
21 +struct squashfs_super_block {
22 +       __le32 s_magic;
23 +       __le32 pad0[9];
24 +       __le64 bytes_used;
25 +};
26 +
27 +static void split_brnimage_kernel(struct mtd_info *master, const char *name,
28 +                                       int offset, int size)
29 +{
30 +       unsigned long buf[4];
31 +       // Assume at most 2MB of kernel image
32 +       unsigned long end = offset + (2 << 20);
33 +       unsigned long part_size = offset + 0x400 - 12;
34 +       size_t len;
35 +       int ret;
36 +
37 +       if (strcmp(name, "rootfs") != 0)
38 +               return;
39 +       while (part_size < end) {
40 +               long size_min = part_size - 0x400 - 12 - offset;
41 +               long size_max = part_size + 12 - offset;
42 +               ret = mtd_read(master, part_size, 16, &len, (void *)buf);
43 +               if (ret || len != 16)
44 +                       return;
45 +
46 +               if (le32_to_cpu(buf[0]) < size_min ||
47 +                               le32_to_cpu(buf[0]) > size_max) {
48 +                       part_size += 0x400;
49 +                       continue;
50 +               }
51 +
52 +               if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC) {
53 +                       part_size += 12 - offset;
54 +                       __mtd_add_partition(master, "rootfs", offset + part_size,
55 +                                                   size - part_size, false);
56 +                       return;
57 +               }
58 +               part_size += 0x400;
59 +       }
60 +}
61 +
62 +static void split_eva_kernel(struct mtd_info *master, const char *name,
63 +                               int offset, int size)
64 +{
65 +#define EVA_MAGIC   0xfeed1281
66 +       unsigned long magic = 0;
67 +       unsigned long part_size = 0, p;
68 +       size_t len;
69 +       int ret;
70 +
71 +       if (strcmp(name, CONFIG_MTD_SPLIT_FIRMWARE_NAME) != 0)
72 +               return;
73 +
74 +       ret = mtd_read(master, offset, 4, &len, (void *)&magic);
75 +       if (ret || len != sizeof(magic))
76 +               return;
77 +
78 +       if (le32_to_cpu(magic) != EVA_MAGIC)
79 +               return;
80 +
81 +       ret = mtd_read(master, offset + 4, 4, &len, (void *)&part_size);
82 +       if (ret || len != sizeof(part_size))
83 +               return;
84 +
85 +       p = part_size = le32_to_cpu(part_size) + 0x18;
86 +       p &= ~0xffff;
87 +       p += 0x10000;
88 +
89 +       ret = mtd_read(master, offset + p, 4, &len, (void *)&magic);
90 +       if (ret || len != sizeof(magic))
91 +               return;
92 +
93 +       if (magic == SQUASHFS_MAGIC)
94 +               part_size = p + 0x100;
95 +       else
96 +               part_size = mtd_pad_erasesize(master, offset, len);
97 +
98 +       if (part_size + master->erasesize > size)
99 +               return;
100 +
101 +       __mtd_add_partition(master, "rootfs", offset + part_size,
102 +                           size - part_size, false);
103 +}
104 +
105 +static void split_tplink_kernel(struct mtd_info *master, const char *name,
106 +                               int offset, int size)
107 +{
108 +#define TPLINK_MAGIC   0x00000002
109 +       unsigned long magic = 0;
110 +       unsigned long part_size = 0;
111 +       size_t len;
112 +       int ret;
113 +
114 +       if (strcmp(name, CONFIG_MTD_SPLIT_FIRMWARE_NAME) != 0)
115 +               return;
116 +
117 +       ret = mtd_read(master, offset, 4, &len, (void *)&magic);
118 +       if (ret || len != sizeof(magic))
119 +               return;
120 +
121 +       if (le32_to_cpu(magic) != TPLINK_MAGIC)
122 +               return;
123 +
124 +       ret = mtd_read(master, offset + 0x78, 4, &len, (void *)&part_size);
125 +       if (ret || len != sizeof(part_size))
126 +               return;
127 +
128 +       part_size = be32_to_cpu(part_size) + 0x200;
129 +       if (part_size + master->erasesize > size)
130 +               return;
131 +
132 +       __mtd_add_partition(master, "rootfs", offset + part_size,
133 +                           size - part_size, false);
134 +}
135 +
136 +void arch_split_mtd_part(struct mtd_info *master, const char *name,
137 +                               int offset, int size)
138 +{
139 +       split_tplink_kernel(master, name, offset, size);
140 +       split_eva_kernel(master, name, offset, size);
141 +       split_brnimage_kernel(master, name, offset, size);
142 +}
143 --- a/include/linux/mtd/partitions.h
144 +++ b/include/linux/mtd/partitions.h
145 @@ -89,12 +89,17 @@ extern int deregister_mtd_parser(struct
146  int mtd_is_partition(const struct mtd_info *mtd);
147  int mtd_add_partition(struct mtd_info *master, char *name,
148                       long long offset, long long length);
149 +int __mtd_add_partition(struct mtd_info *master, char *name,
150 +                   long long offset, long long length, bool dup_check);
151 +
152  int mtd_del_partition(struct mtd_info *master, int partno);
153  struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
154  uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
155  uint64_t mtd_get_device_size(const struct mtd_info *mtd);
156 -extern void __weak arch_split_mtd_part(struct mtd_info *master,
157 -                                      const char *name, int offset, int size);
158 +void __weak arch_split_mtd_part(struct mtd_info *master,
159 +                                      const char *name, int offset, int size);
160 +unsigned long
161 +mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len);
162  
163  int parse_mtd_partitions_by_type(struct mtd_info *master,
164                                  enum mtd_parser_type type,
165 --- a/drivers/mtd/mtdpart.c
166 +++ b/drivers/mtd/mtdpart.c
167 @@ -616,7 +616,7 @@ out_register:
168  }
169  
170  
171 -static int
172 +int
173  __mtd_add_partition(struct mtd_info *master, char *name,
174                     long long offset, long long length, bool dup_check)
175  {
176 @@ -737,7 +737,7 @@ run_parsers_by_type(struct mtd_part *sla
177         return nr_parts;
178  }
179  
180 -static inline unsigned long
181 +unsigned long
182  mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
183  {
184         unsigned long mask = mtd->erasesize - 1;
185 @@ -806,7 +806,6 @@ static void split_uimage(struct mtd_info
186                 return;
187  
188         len = be32_to_cpu(hdr.size) + 0x40;
189 -       len = mtd_pad_erasesize(master, part->offset, len);
190         if (len + master->erasesize > part->mtd.size)
191                 return;
192