kernel: add linux 5.10 support
[openwrt/staging/wigyori.git] / target / linux / generic / pending-5.10 / 400-mtd-mtdsplit-support.patch
1 --- a/drivers/mtd/Kconfig
2 +++ b/drivers/mtd/Kconfig
3 @@ -12,6 +12,25 @@ menuconfig MTD
4
5 if MTD
6
7 +menu "OpenWrt specific MTD options"
8 +
9 +config MTD_ROOTFS_ROOT_DEV
10 + bool "Automatically set 'rootfs' partition to be root filesystem"
11 + default y
12 +
13 +config MTD_SPLIT_FIRMWARE
14 + bool "Automatically split firmware partition for kernel+rootfs"
15 + default y
16 +
17 +config MTD_SPLIT_FIRMWARE_NAME
18 + string "Firmware partition name"
19 + depends on MTD_SPLIT_FIRMWARE
20 + default "firmware"
21 +
22 +source "drivers/mtd/mtdsplit/Kconfig"
23 +
24 +endmenu
25 +
26 config MTD_TESTS
27 tristate "MTD tests support (DANGEROUS)"
28 depends on m
29 --- a/drivers/mtd/mtdpart.c
30 +++ b/drivers/mtd/mtdpart.c
31 @@ -15,10 +15,12 @@
32 #include <linux/kmod.h>
33 #include <linux/mtd/mtd.h>
34 #include <linux/mtd/partitions.h>
35 +#include <linux/magic.h>
36 #include <linux/err.h>
37 #include <linux/of.h>
38
39 #include "mtdcore.h"
40 +#include "mtdsplit/mtdsplit.h"
41
42 /*
43 * MTD methods which simply translate the effective address and pass through
44 @@ -236,6 +238,146 @@ static int mtd_add_partition_attrs(struc
45 return ret;
46 }
47
48 +static DEFINE_SPINLOCK(part_parser_lock);
49 +static LIST_HEAD(part_parsers);
50 +
51 +static struct mtd_part_parser *mtd_part_parser_get(const char *name)
52 +{
53 + struct mtd_part_parser *p, *ret = NULL;
54 +
55 + spin_lock(&part_parser_lock);
56 +
57 + list_for_each_entry(p, &part_parsers, list)
58 + if (!strcmp(p->name, name) && try_module_get(p->owner)) {
59 + ret = p;
60 + break;
61 + }
62 +
63 + spin_unlock(&part_parser_lock);
64 +
65 + return ret;
66 +}
67 +
68 +static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
69 +{
70 + module_put(p->owner);
71 +}
72 +
73 +static struct mtd_part_parser *
74 +get_partition_parser_by_type(enum mtd_parser_type type,
75 + struct mtd_part_parser *start)
76 +{
77 + struct mtd_part_parser *p, *ret = NULL;
78 +
79 + spin_lock(&part_parser_lock);
80 +
81 + p = list_prepare_entry(start, &part_parsers, list);
82 + if (start)
83 + mtd_part_parser_put(start);
84 +
85 + list_for_each_entry_continue(p, &part_parsers, list) {
86 + if (p->type == type && try_module_get(p->owner)) {
87 + ret = p;
88 + break;
89 + }
90 + }
91 +
92 + spin_unlock(&part_parser_lock);
93 +
94 + return ret;
95 +}
96 +
97 +static int parse_mtd_partitions_by_type(struct mtd_info *master,
98 + enum mtd_parser_type type,
99 + const struct mtd_partition **pparts,
100 + struct mtd_part_parser_data *data)
101 +{
102 + struct mtd_part_parser *prev = NULL;
103 + int ret = 0;
104 +
105 + while (1) {
106 + struct mtd_part_parser *parser;
107 +
108 + parser = get_partition_parser_by_type(type, prev);
109 + if (!parser)
110 + break;
111 +
112 + ret = (*parser->parse_fn)(master, pparts, data);
113 +
114 + if (ret > 0) {
115 + mtd_part_parser_put(parser);
116 + printk(KERN_NOTICE
117 + "%d %s partitions found on MTD device %s\n",
118 + ret, parser->name, master->name);
119 + break;
120 + }
121 +
122 + prev = parser;
123 + }
124 +
125 + return ret;
126 +}
127 +
128 +static int
129 +run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
130 +{
131 + struct mtd_partition *parts;
132 + int nr_parts;
133 + int i;
134 +
135 + nr_parts = parse_mtd_partitions_by_type(child, type, (const struct mtd_partition **)&parts,
136 + NULL);
137 + if (nr_parts <= 0)
138 + return nr_parts;
139 +
140 + if (WARN_ON(!parts))
141 + return 0;
142 +
143 + for (i = 0; i < nr_parts; i++) {
144 + /* adjust partition offsets */
145 + parts[i].offset += child->part.offset;
146 +
147 + mtd_add_partition(child->parent,
148 + parts[i].name,
149 + parts[i].offset,
150 + parts[i].size);
151 + }
152 +
153 + kfree(parts);
154 +
155 + return nr_parts;
156 +}
157 +
158 +#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
159 +#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
160 +#else
161 +#define SPLIT_FIRMWARE_NAME "unused"
162 +#endif
163 +
164 +static void split_firmware(struct mtd_info *master, struct mtd_info *part)
165 +{
166 + run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
167 +}
168 +
169 +static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
170 +{
171 + static int rootfs_found = 0;
172 +
173 + if (rootfs_found)
174 + return;
175 +
176 + if (!strcmp(part->name, "rootfs")) {
177 + run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
178 +
179 + rootfs_found = 1;
180 + }
181 +
182 + if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
183 + !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
184 + !of_find_property(mtd_get_of_node(part), "compatible", NULL))
185 + split_firmware(master, part);
186 +}
187 +
188 int mtd_add_partition(struct mtd_info *parent, const char *name,
189 long long offset, long long length)
190 {
191 @@ -274,6 +416,7 @@ int mtd_add_partition(struct mtd_info *p
192 if (ret)
193 goto err_remove_part;
194
195 + mtd_partition_split(parent, child);
196 mtd_add_partition_attrs(child);
197
198 return 0;
199 @@ -422,6 +565,7 @@ int add_mtd_partitions(struct mtd_info *
200 goto err_del_partitions;
201 }
202
203 + mtd_partition_split(master, child);
204 mtd_add_partition_attrs(child);
205
206 /* Look for subpartitions */
207 @@ -438,31 +582,6 @@ err_del_partitions:
208 return ret;
209 }
210
211 -static DEFINE_SPINLOCK(part_parser_lock);
212 -static LIST_HEAD(part_parsers);
213 -
214 -static struct mtd_part_parser *mtd_part_parser_get(const char *name)
215 -{
216 - struct mtd_part_parser *p, *ret = NULL;
217 -
218 - spin_lock(&part_parser_lock);
219 -
220 - list_for_each_entry(p, &part_parsers, list)
221 - if (!strcmp(p->name, name) && try_module_get(p->owner)) {
222 - ret = p;
223 - break;
224 - }
225 -
226 - spin_unlock(&part_parser_lock);
227 -
228 - return ret;
229 -}
230 -
231 -static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
232 -{
233 - module_put(p->owner);
234 -}
235 -
236 /*
237 * Many partition parsers just expected the core to kfree() all their data in
238 * one chunk. Do that by default.
239 --- a/include/linux/mtd/partitions.h
240 +++ b/include/linux/mtd/partitions.h
241 @@ -75,6 +75,12 @@ struct mtd_part_parser_data {
242 * Functions dealing with the various ways of partitioning the space
243 */
244
245 +enum mtd_parser_type {
246 + MTD_PARSER_TYPE_DEVICE = 0,
247 + MTD_PARSER_TYPE_ROOTFS,
248 + MTD_PARSER_TYPE_FIRMWARE,
249 +};
250 +
251 struct mtd_part_parser {
252 struct list_head list;
253 struct module *owner;
254 @@ -83,6 +89,7 @@ struct mtd_part_parser {
255 int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
256 struct mtd_part_parser_data *);
257 void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
258 + enum mtd_parser_type type;
259 };
260
261 /* Container for passing around a set of parsed partitions */
262 --- a/drivers/mtd/Makefile
263 +++ b/drivers/mtd/Makefile
264 @@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
265
266 obj-y += parsers/
267
268 +obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
269 +
270 # 'Users' - code which presents functionality to userspace.
271 obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
272 obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
273 --- a/include/linux/mtd/mtd.h
274 +++ b/include/linux/mtd/mtd.h
275 @@ -608,6 +608,24 @@ static inline void mtd_align_erase_req(s
276 req->len += mtd->erasesize - mod;
277 }
278
279 +static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
280 +{
281 + if (mtd_mod_by_eb(sz, mtd) == 0)
282 + return sz;
283 +
284 + /* Round up to next erase block */
285 + return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
286 +}
287 +
288 +static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
289 +{
290 + if (mtd_mod_by_eb(sz, mtd) == 0)
291 + return sz;
292 +
293 + /* Round down to the start of the current erase block */
294 + return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
295 +}
296 +
297 static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
298 {
299 if (mtd->writesize_shift)
300 @@ -680,6 +698,13 @@ extern void __put_mtd_device(struct mtd_
301 extern struct mtd_info *get_mtd_device_nm(const char *name);
302 extern void put_mtd_device(struct mtd_info *mtd);
303
304 +static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
305 +{
306 + if (!mtd_is_partition(mtd))
307 + return 0;
308 +
309 + return mtd->part.offset;
310 +}
311
312 struct mtd_notifier {
313 void (*add)(struct mtd_info *mtd);