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