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