blob: be1d19b4ffa5982efc2da1631eddb493b7fe5efe [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Kyungmin Parkf6d5e252008-11-19 16:20:36 +01002/*
3 * Simple MTD partitioning layer
4 *
Heiko Schocherf5895d12014-06-24 10:10:04 +02005 * Copyright © 2000 Nicolas Pitre <nico@fluxnic.net>
6 * Copyright © 2002 Thomas Gleixner <gleixner@linutronix.de>
7 * Copyright © 2000-2010 David Woodhouse <dwmw2@infradead.org>
Kyungmin Parkf6d5e252008-11-19 16:20:36 +01008 *
Kyungmin Parkf6d5e252008-11-19 16:20:36 +01009 */
10
Heiko Schocherf5895d12014-06-24 10:10:04 +020011#ifndef __UBOOT__
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070013#include <dm/devres.h>
Heiko Schocherf5895d12014-06-24 10:10:04 +020014#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/slab.h>
18#include <linux/list.h>
19#include <linux/kmod.h>
20#endif
21
Kyungmin Parkf6d5e252008-11-19 16:20:36 +010022#include <malloc.h>
Simon Glassc06c1be2020-05-10 11:40:08 -060023#include <linux/bug.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090024#include <linux/errno.h>
Heiko Schocherf5895d12014-06-24 10:10:04 +020025#include <linux/compat.h>
26#include <ubi_uboot.h>
Kyungmin Parkf6d5e252008-11-19 16:20:36 +010027
Kyungmin Parkf6d5e252008-11-19 16:20:36 +010028#include <linux/mtd/mtd.h>
29#include <linux/mtd/partitions.h>
Heiko Schocherf5895d12014-06-24 10:10:04 +020030#include <linux/err.h>
Miquel Raynal6f381d52018-09-29 12:58:25 +020031#include <linux/sizes.h>
Heiko Schocherf5895d12014-06-24 10:10:04 +020032
33#include "mtdcore.h"
Kyungmin Parkf6d5e252008-11-19 16:20:36 +010034
Heiko Schocherf5895d12014-06-24 10:10:04 +020035#ifndef __UBOOT__
36static DEFINE_MUTEX(mtd_partitions_mutex);
37#else
38DEFINE_MUTEX(mtd_partitions_mutex);
39#endif
Kyungmin Parkf6d5e252008-11-19 16:20:36 +010040
Heiko Schocherf5895d12014-06-24 10:10:04 +020041#ifdef __UBOOT__
42/* from mm/util.c */
43
44/**
45 * kstrdup - allocate space for and copy an existing string
46 * @s: the string to duplicate
47 * @gfp: the GFP mask used in the kmalloc() call when allocating memory
48 */
49char *kstrdup(const char *s, gfp_t gfp)
50{
51 size_t len;
52 char *buf;
53
54 if (!s)
55 return NULL;
56
57 len = strlen(s) + 1;
58 buf = kmalloc(len, gfp);
59 if (buf)
60 memcpy(buf, s, len);
61 return buf;
62}
63#endif
64
Miquel Raynal6f381d52018-09-29 12:58:25 +020065#define MTD_SIZE_REMAINING (~0LLU)
66#define MTD_OFFSET_NOT_SPECIFIED (~0LLU)
67
Boris Brezillon7dfad312018-12-02 10:54:30 +010068bool mtd_partitions_used(struct mtd_info *master)
69{
70 struct mtd_info *slave;
71
72 list_for_each_entry(slave, &master->partitions, node) {
73 if (slave->usecount)
74 return true;
75 }
76
77 return false;
78}
79
Miquel Raynal6f381d52018-09-29 12:58:25 +020080/**
81 * mtd_parse_partition - Parse @mtdparts partition definition, fill @partition
82 * with it and update the @mtdparts string pointer.
83 *
84 * The partition name is allocated and must be freed by the caller.
85 *
86 * This function is widely inspired from part_parse (mtdparts.c).
87 *
88 * @mtdparts: String describing the partition with mtdparts command syntax
89 * @partition: MTD partition structure to fill
90 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010091 * Return: 0 on success, an error otherwise.
Miquel Raynal6f381d52018-09-29 12:58:25 +020092 */
93static int mtd_parse_partition(const char **_mtdparts,
94 struct mtd_partition *partition)
95{
96 const char *mtdparts = *_mtdparts;
97 const char *name = NULL;
98 int name_len;
99 char *buf;
100
101 /* Ensure the partition structure is empty */
102 memset(partition, 0, sizeof(struct mtd_partition));
103
104 /* Fetch the partition size */
105 if (*mtdparts == '-') {
106 /* Assign all remaining space to this partition */
107 partition->size = MTD_SIZE_REMAINING;
108 mtdparts++;
109 } else {
110 partition->size = ustrtoull(mtdparts, (char **)&mtdparts, 0);
111 if (partition->size < SZ_4K) {
112 printf("Minimum partition size 4kiB, %lldB requested\n",
113 partition->size);
114 return -EINVAL;
115 }
116 }
117
118 /* Check for the offset */
119 partition->offset = MTD_OFFSET_NOT_SPECIFIED;
120 if (*mtdparts == '@') {
121 mtdparts++;
122 partition->offset = ustrtoull(mtdparts, (char **)&mtdparts, 0);
123 }
124
125 /* Now look for the name */
126 if (*mtdparts == '(') {
127 name = ++mtdparts;
128 mtdparts = strchr(name, ')');
129 if (!mtdparts) {
130 printf("No closing ')' found in partition name\n");
131 return -EINVAL;
132 }
133 name_len = mtdparts - name + 1;
134 if ((name_len - 1) == 0) {
135 printf("Empty partition name\n");
136 return -EINVAL;
137 }
138 mtdparts++;
139 } else {
140 /* Name will be of the form size@offset */
141 name_len = 22;
142 }
143
144 /* Check if the partition is read-only */
145 if (strncmp(mtdparts, "ro", 2) == 0) {
146 partition->mask_flags |= MTD_WRITEABLE;
147 mtdparts += 2;
148 }
149
150 /* Check for a potential next partition definition */
151 if (*mtdparts == ',') {
152 if (partition->size == MTD_SIZE_REMAINING) {
153 printf("No partitions allowed after a fill-up\n");
154 return -EINVAL;
155 }
156 ++mtdparts;
157 } else if ((*mtdparts == ';') || (*mtdparts == '\0')) {
158 /* NOP */
159 } else {
160 printf("Unexpected character '%c' in mtdparts\n", *mtdparts);
161 return -EINVAL;
162 }
163
164 /*
165 * Allocate a buffer for the name and either copy the provided name or
166 * auto-generate it with the form 'size@offset'.
167 */
168 buf = malloc(name_len);
169 if (!buf)
170 return -ENOMEM;
171
172 if (name)
173 strncpy(buf, name, name_len - 1);
174 else
175 snprintf(buf, name_len, "0x%08llx@0x%08llx",
176 partition->size, partition->offset);
177
178 buf[name_len - 1] = '\0';
179 partition->name = buf;
180
181 *_mtdparts = mtdparts;
182
183 return 0;
184}
185
186/**
187 * mtd_parse_partitions - Create a partition array from an mtdparts definition
188 *
189 * Stateless function that takes a @parent MTD device, a string @_mtdparts
190 * describing the partitions (with the "mtdparts" command syntax) and creates
191 * the corresponding MTD partition structure array @_parts. Both the name and
192 * the structure partition itself must be freed freed, the caller may use
193 * @mtd_free_parsed_partitions() for this purpose.
194 *
195 * @parent: MTD device which contains the partitions
196 * @_mtdparts: Pointer to a string describing the partitions with "mtdparts"
197 * command syntax.
198 * @_parts: Allocated array containing the partitions, must be freed by the
199 * caller.
200 * @_nparts: Size of @_parts array.
201 *
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100202 * Return: 0 on success, an error otherwise.
Miquel Raynal6f381d52018-09-29 12:58:25 +0200203 */
204int mtd_parse_partitions(struct mtd_info *parent, const char **_mtdparts,
205 struct mtd_partition **_parts, int *_nparts)
206{
207 struct mtd_partition partition = {}, *parts;
208 const char *mtdparts = *_mtdparts;
Martin Kaistra982c4602020-07-13 14:40:02 +0200209 uint64_t cur_off = 0, cur_sz = 0;
Miquel Raynal6f381d52018-09-29 12:58:25 +0200210 int nparts = 0;
211 int ret, idx;
212 u64 sz;
213
214 /* First, iterate over the partitions until we know their number */
215 while (mtdparts[0] != '\0' && mtdparts[0] != ';') {
216 ret = mtd_parse_partition(&mtdparts, &partition);
217 if (ret)
218 return ret;
219
220 free((char *)partition.name);
221 nparts++;
222 }
223
224 /* Allocate an array of partitions to give back to the caller */
225 parts = malloc(sizeof(*parts) * nparts);
226 if (!parts) {
227 printf("Not enough space to save partitions meta-data\n");
228 return -ENOMEM;
229 }
230
231 /* Iterate again over each partition to save the data in our array */
232 for (idx = 0; idx < nparts; idx++) {
233 ret = mtd_parse_partition(_mtdparts, &parts[idx]);
234 if (ret)
235 return ret;
236
237 if (parts[idx].size == MTD_SIZE_REMAINING)
238 parts[idx].size = parent->size - cur_sz;
239 cur_sz += parts[idx].size;
240
241 sz = parts[idx].size;
242 if (sz < parent->writesize || do_div(sz, parent->writesize)) {
243 printf("Partition size must be a multiple of %d\n",
244 parent->writesize);
245 return -EINVAL;
246 }
247
248 if (parts[idx].offset == MTD_OFFSET_NOT_SPECIFIED)
249 parts[idx].offset = cur_off;
250 cur_off += parts[idx].size;
251
252 parts[idx].ecclayout = parent->ecclayout;
253 }
254
255 /* Offset by one mtdparts to point to the next device if any */
256 if (*_mtdparts[0] == ';')
257 (*_mtdparts)++;
258
259 *_parts = parts;
260 *_nparts = nparts;
261
262 return 0;
263}
264
265/**
266 * mtd_free_parsed_partitions - Free dynamically allocated partitions
267 *
268 * Each successful call to @mtd_parse_partitions must be followed by a call to
269 * @mtd_free_parsed_partitions to free any allocated array during the parsing
270 * process.
271 *
272 * @parts: Array containing the partitions that will be freed.
273 * @nparts: Size of @parts array.
274 */
275void mtd_free_parsed_partitions(struct mtd_partition *parts,
276 unsigned int nparts)
277{
278 int i;
279
280 for (i = 0; i < nparts; i++)
281 free((char *)parts[i].name);
282
283 free(parts);
284}
285
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100286/*
287 * MTD methods which simply translate the effective address and pass through
288 * to the _real_ device.
289 */
290
Stefan Roese586b3a62009-05-11 16:03:55 +0200291static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
292 size_t *retlen, u_char *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100293{
Stefan Roese586b3a62009-05-11 16:03:55 +0200294 struct mtd_ecc_stats stats;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100295 int res;
296
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200297 stats = mtd->parent->ecc_stats;
298 res = mtd->parent->_read(mtd->parent, from + mtd->offset, len,
299 retlen, buf);
Paul Burton700a76c2013-09-04 15:16:56 +0100300 if (unlikely(mtd_is_eccerr(res)))
301 mtd->ecc_stats.failed +=
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200302 mtd->parent->ecc_stats.failed - stats.failed;
Paul Burton700a76c2013-09-04 15:16:56 +0100303 else
304 mtd->ecc_stats.corrected +=
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200305 mtd->parent->ecc_stats.corrected - stats.corrected;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100306 return res;
307}
Heiko Schocherf5895d12014-06-24 10:10:04 +0200308
309#ifndef __UBOOT__
310static int part_point(struct mtd_info *mtd, loff_t from, size_t len,
311 size_t *retlen, void **virt, resource_size_t *phys)
312{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200313 return mtd->parent->_point(mtd->parent, from + mtd->offset, len,
314 retlen, virt, phys);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200315}
316
317static int part_unpoint(struct mtd_info *mtd, loff_t from, size_t len)
318{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200319 return mtd->parent->_unpoint(mtd->parent, from + mtd->offset, len);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200320}
321#endif
322
323static unsigned long part_get_unmapped_area(struct mtd_info *mtd,
324 unsigned long len,
325 unsigned long offset,
326 unsigned long flags)
327{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200328 offset += mtd->offset;
329 return mtd->parent->_get_unmapped_area(mtd->parent, len, offset, flags);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200330}
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100331
332static int part_read_oob(struct mtd_info *mtd, loff_t from,
Stefan Roese586b3a62009-05-11 16:03:55 +0200333 struct mtd_oob_ops *ops)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100334{
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100335 int res;
336
337 if (from >= mtd->size)
338 return -EINVAL;
339 if (ops->datbuf && from + ops->len > mtd->size)
340 return -EINVAL;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200341
342 /*
343 * If OOB is also requested, make sure that we do not read past the end
344 * of this partition.
345 */
346 if (ops->oobbuf) {
347 size_t len, pages;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100348
Heiko Schocherf5895d12014-06-24 10:10:04 +0200349 if (ops->mode == MTD_OPS_AUTO_OOB)
350 len = mtd->oobavail;
351 else
352 len = mtd->oobsize;
353 pages = mtd_div_by_ws(mtd->size, mtd);
354 pages -= mtd_div_by_ws(from, mtd);
355 if (ops->ooboffs + ops->ooblen > pages * len)
356 return -EINVAL;
357 }
358
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200359 res = mtd->parent->_read_oob(mtd->parent, from + mtd->offset, ops);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100360 if (unlikely(res)) {
Sergey Lapin3a38a552013-01-14 03:46:50 +0000361 if (mtd_is_bitflip(res))
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100362 mtd->ecc_stats.corrected++;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000363 if (mtd_is_eccerr(res))
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100364 mtd->ecc_stats.failed++;
365 }
366 return res;
367}
368
Stefan Roese586b3a62009-05-11 16:03:55 +0200369static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
370 size_t len, size_t *retlen, u_char *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100371{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200372 return mtd->parent->_read_user_prot_reg(mtd->parent, from, len,
373 retlen, buf);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100374}
375
Heiko Schocher081fe9e2014-07-15 16:08:43 +0200376static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
377 size_t *retlen, struct otp_info *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100378{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200379 return mtd->parent->_get_user_prot_info(mtd->parent, len, retlen,
380 buf);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100381}
382
Stefan Roese586b3a62009-05-11 16:03:55 +0200383static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
384 size_t len, size_t *retlen, u_char *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100385{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200386 return mtd->parent->_read_fact_prot_reg(mtd->parent, from, len,
387 retlen, buf);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100388}
389
Heiko Schocher081fe9e2014-07-15 16:08:43 +0200390static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
391 size_t *retlen, struct otp_info *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100392{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200393 return mtd->parent->_get_fact_prot_info(mtd->parent, len, retlen,
394 buf);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100395}
396
Stefan Roese586b3a62009-05-11 16:03:55 +0200397static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
398 size_t *retlen, const u_char *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100399{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200400 return mtd->parent->_write(mtd->parent, to + mtd->offset, len,
401 retlen, buf);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200402}
403
404static int part_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
405 size_t *retlen, const u_char *buf)
406{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200407 return mtd->parent->_panic_write(mtd->parent, to + mtd->offset, len,
408 retlen, buf);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100409}
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100410
411static int part_write_oob(struct mtd_info *mtd, loff_t to,
Stefan Roese586b3a62009-05-11 16:03:55 +0200412 struct mtd_oob_ops *ops)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100413{
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100414 if (to >= mtd->size)
415 return -EINVAL;
416 if (ops->datbuf && to + ops->len > mtd->size)
417 return -EINVAL;
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200418 return mtd->parent->_write_oob(mtd->parent, to + mtd->offset, ops);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100419}
420
Stefan Roese586b3a62009-05-11 16:03:55 +0200421static int part_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
422 size_t len, size_t *retlen, u_char *buf)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100423{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200424 return mtd->parent->_write_user_prot_reg(mtd->parent, from, len,
425 retlen, buf);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100426}
427
Stefan Roese586b3a62009-05-11 16:03:55 +0200428static int part_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
429 size_t len)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100430{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200431 return mtd->parent->_lock_user_prot_reg(mtd->parent, from, len);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200432}
433
434#ifndef __UBOOT__
435static int part_writev(struct mtd_info *mtd, const struct kvec *vecs,
436 unsigned long count, loff_t to, size_t *retlen)
437{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200438 return mtd->parent->_writev(mtd->parent, vecs, count,
439 to + mtd->offset, retlen);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100440}
Heiko Schocherf5895d12014-06-24 10:10:04 +0200441#endif
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100442
Stefan Roese586b3a62009-05-11 16:03:55 +0200443static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100444{
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100445 int ret;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000446
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200447 instr->addr += mtd->offset;
Marek Behún2e7d7622021-10-05 15:56:05 +0200448
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200449 ret = mtd->parent->_erase(mtd->parent, instr);
Marek Behún2e7d7622021-10-05 15:56:05 +0200450 if (ret && instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
451 instr->fail_addr -= mtd->offset;
452
453 instr->addr -= mtd->offset;
454
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100455 return ret;
456}
457
Stefan Roese586b3a62009-05-11 16:03:55 +0200458static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100459{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200460 return mtd->parent->_lock(mtd->parent, ofs + mtd->offset, len);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100461}
462
Stefan Roese586b3a62009-05-11 16:03:55 +0200463static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100464{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200465 return mtd->parent->_unlock(mtd->parent, ofs + mtd->offset, len);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100466}
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100467
Heiko Schocherf5895d12014-06-24 10:10:04 +0200468static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
469{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200470 return mtd->parent->_is_locked(mtd->parent, ofs + mtd->offset, len);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200471}
472
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100473static void part_sync(struct mtd_info *mtd)
474{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200475 mtd->parent->_sync(mtd->parent);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200476}
477
478#ifndef __UBOOT__
479static int part_suspend(struct mtd_info *mtd)
480{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200481 return mtd->parent->_suspend(mtd->parent);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200482}
483
484static void part_resume(struct mtd_info *mtd)
485{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200486 mtd->parent->_resume(mtd->parent);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100487}
Heiko Schocherf5895d12014-06-24 10:10:04 +0200488#endif
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100489
Ezequiel Garciafc9d57c2014-05-21 19:06:12 -0300490static int part_block_isreserved(struct mtd_info *mtd, loff_t ofs)
491{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200492 ofs += mtd->offset;
493 return mtd->parent->_block_isreserved(mtd->parent, ofs);
Ezequiel Garciafc9d57c2014-05-21 19:06:12 -0300494}
495
Stefan Roese586b3a62009-05-11 16:03:55 +0200496static int part_block_isbad(struct mtd_info *mtd, loff_t ofs)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100497{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200498 ofs += mtd->offset;
499 return mtd->parent->_block_isbad(mtd->parent, ofs);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100500}
501
Stefan Roese586b3a62009-05-11 16:03:55 +0200502static int part_block_markbad(struct mtd_info *mtd, loff_t ofs)
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100503{
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100504 int res;
505
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200506 ofs += mtd->offset;
507 res = mtd->parent->_block_markbad(mtd->parent, ofs);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100508 if (!res)
509 mtd->ecc_stats.badblocks++;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100510 return res;
511}
512
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200513static inline void free_partition(struct mtd_info *p)
Heiko Schocherf5895d12014-06-24 10:10:04 +0200514{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200515 kfree(p->name);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200516 kfree(p);
517}
518
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100519/*
520 * This function unregisters and destroy all slave MTD objects which are
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200521 * attached to the given master MTD object, recursively.
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100522 */
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200523static int do_del_mtd_partitions(struct mtd_info *master)
524{
525 struct mtd_info *slave, *next;
526 int ret, err = 0;
527
528 list_for_each_entry_safe(slave, next, &master->partitions, node) {
529 if (mtd_has_partitions(slave))
530 del_mtd_partitions(slave);
531
532 debug("Deleting %s MTD partition\n", slave->name);
533 ret = del_mtd_device(slave);
534 if (ret < 0) {
535 printf("Error when deleting partition \"%s\" (%d)\n",
536 slave->name, ret);
537 err = ret;
538 continue;
539 }
540
541 list_del(&slave->node);
542 free_partition(slave);
543 }
544
545 return err;
546}
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100547
548int del_mtd_partitions(struct mtd_info *master)
549{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200550 int ret;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100551
Miquel Raynalf78a12b2018-08-16 17:30:19 +0200552 debug("Deleting MTD partitions on \"%s\":\n", master->name);
553
Heiko Schocherf5895d12014-06-24 10:10:04 +0200554 mutex_lock(&mtd_partitions_mutex);
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200555 ret = do_del_mtd_partitions(master);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200556 mutex_unlock(&mtd_partitions_mutex);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100557
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200558 return ret;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100559}
560
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200561static struct mtd_info *allocate_partition(struct mtd_info *master,
562 const struct mtd_partition *part,
563 int partno, uint64_t cur_offset)
Stefan Roese586b3a62009-05-11 16:03:55 +0200564{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200565 struct mtd_info *slave;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200566 char *name;
Stefan Roese586b3a62009-05-11 16:03:55 +0200567
568 /* allocate the partition structure */
569 slave = kzalloc(sizeof(*slave), GFP_KERNEL);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200570 name = kstrdup(part->name, GFP_KERNEL);
571 if (!name || !slave) {
Stefan Roese586b3a62009-05-11 16:03:55 +0200572 printk(KERN_ERR"memory allocation error while creating partitions for \"%s\"\n",
Heiko Schocherf5895d12014-06-24 10:10:04 +0200573 master->name);
574 kfree(name);
575 kfree(slave);
576 return ERR_PTR(-ENOMEM);
Stefan Roese586b3a62009-05-11 16:03:55 +0200577 }
Stefan Roese586b3a62009-05-11 16:03:55 +0200578
579 /* set up the MTD object for this partition */
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200580 slave->type = master->type;
581 slave->flags = master->flags & ~part->mask_flags;
582 slave->size = part->size;
583 slave->writesize = master->writesize;
584 slave->writebufsize = master->writebufsize;
585 slave->oobsize = master->oobsize;
586 slave->oobavail = master->oobavail;
587 slave->subpage_sft = master->subpage_sft;
Stefan Roese586b3a62009-05-11 16:03:55 +0200588
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200589 slave->name = name;
590 slave->owner = master->owner;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200591#ifndef __UBOOT__
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200592 slave->backing_dev_info = master->backing_dev_info;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200593
594 /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
595 * to have the same data be in two different partitions.
596 */
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200597 slave->dev.parent = master->dev.parent;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200598#endif
Stefan Roese586b3a62009-05-11 16:03:55 +0200599
Boris Brezillon6c20df72018-08-16 17:29:59 +0200600 if (master->_read)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200601 slave->_read = part_read;
Boris Brezillon6c20df72018-08-16 17:29:59 +0200602 if (master->_write)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200603 slave->_write = part_write;
Stefan Roese586b3a62009-05-11 16:03:55 +0200604
Heiko Schocherf5895d12014-06-24 10:10:04 +0200605 if (master->_panic_write)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200606 slave->_panic_write = part_panic_write;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200607
608#ifndef __UBOOT__
609 if (master->_point && master->_unpoint) {
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200610 slave->_point = part_point;
611 slave->_unpoint = part_unpoint;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200612 }
613#endif
614
615 if (master->_get_unmapped_area)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200616 slave->_get_unmapped_area = part_get_unmapped_area;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000617 if (master->_read_oob)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200618 slave->_read_oob = part_read_oob;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000619 if (master->_write_oob)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200620 slave->_write_oob = part_write_oob;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000621 if (master->_read_user_prot_reg)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200622 slave->_read_user_prot_reg = part_read_user_prot_reg;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000623 if (master->_read_fact_prot_reg)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200624 slave->_read_fact_prot_reg = part_read_fact_prot_reg;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000625 if (master->_write_user_prot_reg)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200626 slave->_write_user_prot_reg = part_write_user_prot_reg;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000627 if (master->_lock_user_prot_reg)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200628 slave->_lock_user_prot_reg = part_lock_user_prot_reg;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000629 if (master->_get_user_prot_info)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200630 slave->_get_user_prot_info = part_get_user_prot_info;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000631 if (master->_get_fact_prot_info)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200632 slave->_get_fact_prot_info = part_get_fact_prot_info;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000633 if (master->_sync)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200634 slave->_sync = part_sync;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200635#ifndef __UBOOT__
636 if (!partno && !master->dev.class && master->_suspend &&
637 master->_resume) {
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200638 slave->_suspend = part_suspend;
639 slave->_resume = part_resume;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200640 }
641 if (master->_writev)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200642 slave->_writev = part_writev;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200643#endif
Sergey Lapin3a38a552013-01-14 03:46:50 +0000644 if (master->_lock)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200645 slave->_lock = part_lock;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000646 if (master->_unlock)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200647 slave->_unlock = part_unlock;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200648 if (master->_is_locked)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200649 slave->_is_locked = part_is_locked;
Ezequiel Garciafc9d57c2014-05-21 19:06:12 -0300650 if (master->_block_isreserved)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200651 slave->_block_isreserved = part_block_isreserved;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000652 if (master->_block_isbad)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200653 slave->_block_isbad = part_block_isbad;
Sergey Lapin3a38a552013-01-14 03:46:50 +0000654 if (master->_block_markbad)
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200655 slave->_block_markbad = part_block_markbad;
656 slave->_erase = part_erase;
657 slave->parent = master;
Stefan Roese586b3a62009-05-11 16:03:55 +0200658 slave->offset = part->offset;
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200659 INIT_LIST_HEAD(&slave->partitions);
660 INIT_LIST_HEAD(&slave->node);
Stefan Roese586b3a62009-05-11 16:03:55 +0200661
662 if (slave->offset == MTDPART_OFS_APPEND)
663 slave->offset = cur_offset;
664 if (slave->offset == MTDPART_OFS_NXTBLK) {
665 slave->offset = cur_offset;
666 if (mtd_mod_by_eb(cur_offset, master) != 0) {
667 /* Round up to next erasesize */
668 slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200669 debug("Moving partition %d: "
670 "0x%012llx -> 0x%012llx\n", partno,
671 (unsigned long long)cur_offset, (unsigned long long)slave->offset);
672 }
673 }
674 if (slave->offset == MTDPART_OFS_RETAIN) {
675 slave->offset = cur_offset;
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200676 if (master->size - slave->offset >= slave->size) {
677 slave->size = master->size - slave->offset
678 - slave->size;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200679 } else {
680 debug("mtd partition \"%s\" doesn't have enough space: %#llx < %#llx, disabled\n",
681 part->name, master->size - slave->offset,
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200682 slave->size);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200683 /* register to preserve ordering */
684 goto out_register;
Stefan Roese586b3a62009-05-11 16:03:55 +0200685 }
686 }
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200687 if (slave->size == MTDPART_SIZ_FULL)
688 slave->size = master->size - slave->offset;
Stefan Roese586b3a62009-05-11 16:03:55 +0200689
Heiko Schocherf5895d12014-06-24 10:10:04 +0200690 debug("0x%012llx-0x%012llx : \"%s\"\n", (unsigned long long)slave->offset,
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200691 (unsigned long long)(slave->offset + slave->size), slave->name);
Stefan Roese586b3a62009-05-11 16:03:55 +0200692
693 /* let's do some sanity checks */
694 if (slave->offset >= master->size) {
695 /* let's register it anyway to preserve ordering */
696 slave->offset = 0;
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200697 slave->size = 0;
Stefan Roese586b3a62009-05-11 16:03:55 +0200698 printk(KERN_ERR"mtd: partition \"%s\" is out of reach -- disabled\n",
699 part->name);
700 goto out_register;
701 }
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200702 if (slave->offset + slave->size > master->size) {
703 slave->size = master->size - slave->offset;
Stefan Roese586b3a62009-05-11 16:03:55 +0200704 printk(KERN_WARNING"mtd: partition \"%s\" extends beyond the end of device \"%s\" -- size truncated to %#llx\n",
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200705 part->name, master->name, slave->size);
Stefan Roese586b3a62009-05-11 16:03:55 +0200706 }
707 if (master->numeraseregions > 1) {
708 /* Deal with variable erase size stuff */
709 int i, max = master->numeraseregions;
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200710 u64 end = slave->offset + slave->size;
Stefan Roese586b3a62009-05-11 16:03:55 +0200711 struct mtd_erase_region_info *regions = master->eraseregions;
712
713 /* Find the first erase regions which is part of this
714 * partition. */
715 for (i = 0; i < max && regions[i].offset <= slave->offset; i++)
716 ;
717 /* The loop searched for the region _behind_ the first one */
Heiko Schocherf5895d12014-06-24 10:10:04 +0200718 if (i > 0)
719 i--;
Stefan Roese586b3a62009-05-11 16:03:55 +0200720
721 /* Pick biggest erasesize */
722 for (; i < max && regions[i].offset < end; i++) {
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200723 if (slave->erasesize < regions[i].erasesize)
724 slave->erasesize = regions[i].erasesize;
Stefan Roese586b3a62009-05-11 16:03:55 +0200725 }
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200726 WARN_ON(slave->erasesize == 0);
Stefan Roese586b3a62009-05-11 16:03:55 +0200727 } else {
728 /* Single erase size */
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200729 slave->erasesize = master->erasesize;
Stefan Roese586b3a62009-05-11 16:03:55 +0200730 }
731
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200732 if ((slave->flags & MTD_WRITEABLE) &&
733 mtd_mod_by_eb(slave->offset, slave)) {
Stefan Roese586b3a62009-05-11 16:03:55 +0200734 /* Doesn't start on a boundary of major erase size */
735 /* FIXME: Let it be writable if it is on a boundary of
736 * _minor_ erase size though */
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200737 slave->flags &= ~MTD_WRITEABLE;
Stefan Roese586b3a62009-05-11 16:03:55 +0200738 printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
739 part->name);
740 }
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200741 if ((slave->flags & MTD_WRITEABLE) &&
742 mtd_mod_by_eb(slave->size, slave)) {
743 slave->flags &= ~MTD_WRITEABLE;
Stefan Roese586b3a62009-05-11 16:03:55 +0200744 printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
745 part->name);
746 }
747
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200748 slave->ecclayout = master->ecclayout;
749 slave->ecc_step_size = master->ecc_step_size;
750 slave->ecc_strength = master->ecc_strength;
751 slave->bitflip_threshold = master->bitflip_threshold;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200752
Sergey Lapin3a38a552013-01-14 03:46:50 +0000753 if (master->_block_isbad) {
Stefan Roese586b3a62009-05-11 16:03:55 +0200754 uint64_t offs = 0;
755
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200756 while (offs < slave->size) {
Sergey Lapin3a38a552013-01-14 03:46:50 +0000757 if (mtd_block_isbad(master, offs + slave->offset))
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200758 slave->ecc_stats.badblocks++;
759 offs += slave->erasesize;
Stefan Roese586b3a62009-05-11 16:03:55 +0200760 }
761 }
762
763out_register:
Stefan Roese586b3a62009-05-11 16:03:55 +0200764 return slave;
765}
766
Heiko Schocherb24c4272014-07-15 16:08:42 +0200767#ifndef __UBOOT__
Heiko Schocherf5895d12014-06-24 10:10:04 +0200768int mtd_add_partition(struct mtd_info *master, const char *name,
769 long long offset, long long length)
770{
771 struct mtd_partition part;
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200772 struct mtd_info *p, *new;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200773 uint64_t start, end;
774 int ret = 0;
775
776 /* the direct offset is expected */
777 if (offset == MTDPART_OFS_APPEND ||
778 offset == MTDPART_OFS_NXTBLK)
779 return -EINVAL;
780
781 if (length == MTDPART_SIZ_FULL)
782 length = master->size - offset;
783
784 if (length <= 0)
785 return -EINVAL;
786
787 part.name = name;
788 part.size = length;
789 part.offset = offset;
790 part.mask_flags = 0;
791 part.ecclayout = NULL;
792
793 new = allocate_partition(master, &part, -1, offset);
794 if (IS_ERR(new))
795 return PTR_ERR(new);
796
797 start = offset;
798 end = offset + length;
799
800 mutex_lock(&mtd_partitions_mutex);
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200801 list_for_each_entry(p, &master->partitions, node) {
802 if (start >= p->offset &&
803 (start < (p->offset + p->size)))
804 goto err_inv;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200805
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200806 if (end >= p->offset &&
807 (end < (p->offset + p->size)))
808 goto err_inv;
809 }
Heiko Schocherf5895d12014-06-24 10:10:04 +0200810
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200811 list_add_tail(&new->node, &master->partitions);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200812 mutex_unlock(&mtd_partitions_mutex);
813
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200814 add_mtd_device(new);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200815
816 return ret;
817err_inv:
818 mutex_unlock(&mtd_partitions_mutex);
819 free_partition(new);
820 return -EINVAL;
821}
822EXPORT_SYMBOL_GPL(mtd_add_partition);
823
824int mtd_del_partition(struct mtd_info *master, int partno)
825{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200826 struct mtd_info *slave, *next;
Heiko Schocherf5895d12014-06-24 10:10:04 +0200827 int ret = -EINVAL;
828
829 mutex_lock(&mtd_partitions_mutex);
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200830 list_for_each_entry_safe(slave, next, &master->partitions, node)
831 if (slave->index == partno) {
832 ret = del_mtd_device(slave);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200833 if (ret < 0)
834 break;
835
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200836 list_del(&slave->node);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200837 free_partition(slave);
838 break;
839 }
840 mutex_unlock(&mtd_partitions_mutex);
841
842 return ret;
843}
844EXPORT_SYMBOL_GPL(mtd_del_partition);
Heiko Schocherb24c4272014-07-15 16:08:42 +0200845#endif
Heiko Schocherf5895d12014-06-24 10:10:04 +0200846
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100847/*
848 * This function, given a master MTD object and a partition table, creates
849 * and registers slave MTD objects which are bound to the master according to
850 * the partition definitions.
Stefan Roese586b3a62009-05-11 16:03:55 +0200851 *
852 * We don't register the master, or expect the caller to have done so,
853 * for reasons of data integrity.
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100854 */
855
856int add_mtd_partitions(struct mtd_info *master,
857 const struct mtd_partition *parts,
858 int nbparts)
859{
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200860 struct mtd_info *slave;
Stefan Roese586b3a62009-05-11 16:03:55 +0200861 uint64_t cur_offset = 0;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100862 int i;
863
Joe Hershberger47550fc2013-04-08 10:32:49 +0000864 debug("Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100865
866 for (i = 0; i < nbparts; i++) {
Heiko Schocherf5895d12014-06-24 10:10:04 +0200867 slave = allocate_partition(master, parts + i, i, cur_offset);
868 if (IS_ERR(slave))
869 return PTR_ERR(slave);
870
871 mutex_lock(&mtd_partitions_mutex);
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200872 list_add_tail(&slave->node, &master->partitions);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200873 mutex_unlock(&mtd_partitions_mutex);
874
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200875 add_mtd_device(slave);
Heiko Schocherf5895d12014-06-24 10:10:04 +0200876
Miquel Raynal6382e0c2018-09-29 12:58:27 +0200877 cur_offset = slave->offset + slave->size;
Kyungmin Parkf6d5e252008-11-19 16:20:36 +0100878 }
879
880 return 0;
881}
Heiko Schocherf5895d12014-06-24 10:10:04 +0200882
Marek Behún544a8c92021-05-26 14:08:19 +0200883#if CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL)
884int add_mtd_partitions_of(struct mtd_info *master)
885{
886 ofnode parts, child;
887 int i = 0;
888
Patrice Chotardc1315f02022-03-21 09:13:37 +0100889 if (!master->dev && !ofnode_valid(master->flash_node))
Marek Behún544a8c92021-05-26 14:08:19 +0200890 return 0;
891
Patrice Chotardc1315f02022-03-21 09:13:37 +0100892 if (master->dev)
893 parts = ofnode_find_subnode(mtd_get_ofnode(master), "partitions");
894 else
895 parts = ofnode_find_subnode(master->flash_node, "partitions");
896
Simon Glass2e4938b2022-09-06 20:27:17 -0600897 if (!ofnode_valid(parts) || !ofnode_is_enabled(parts) ||
Marek Behún544a8c92021-05-26 14:08:19 +0200898 !ofnode_device_is_compatible(parts, "fixed-partitions"))
899 return 0;
900
901 ofnode_for_each_subnode(child, parts) {
902 struct mtd_partition part = { 0 };
903 struct mtd_info *slave;
Pali Rohár004ab832022-05-13 22:24:51 +0200904 fdt_addr_t offset;
905 fdt_size_t size;
Marek Behún544a8c92021-05-26 14:08:19 +0200906
Simon Glass2e4938b2022-09-06 20:27:17 -0600907 if (!ofnode_is_enabled(child))
Marek Behún544a8c92021-05-26 14:08:19 +0200908 continue;
909
910 offset = ofnode_get_addr_size_index_notrans(child, 0, &size);
911 if (offset == FDT_ADDR_T_NONE || !size) {
912 debug("Missing partition offset/size on \"%s\" partition\n",
913 master->name);
914 continue;
915 }
916
917 part.name = ofnode_read_string(child, "label");
918 if (!part.name)
919 part.name = ofnode_read_string(child, "name");
920
921 /*
922 * .mask_flags is used to remove flags in allocate_partition(),
923 * so when "read-only" is present, we add MTD_WRITABLE to the
924 * mask, and so MTD_WRITABLE will be removed on partition
925 * allocation
926 */
927 if (ofnode_read_bool(child, "read-only"))
928 part.mask_flags |= MTD_WRITEABLE;
929 if (ofnode_read_bool(child, "lock"))
930 part.mask_flags |= MTD_POWERUP_LOCK;
931
932 part.offset = offset;
933 part.size = size;
934 part.ecclayout = master->ecclayout;
935
936 slave = allocate_partition(master, &part, i++, 0);
937 if (IS_ERR(slave))
938 return PTR_ERR(slave);
939
940 mutex_lock(&mtd_partitions_mutex);
941 list_add_tail(&slave->node, &master->partitions);
942 mutex_unlock(&mtd_partitions_mutex);
943
944 add_mtd_device(slave);
945 }
946
947 return 0;
948}
949#endif /* CONFIG_IS_ENABLED(DM) && CONFIG_IS_ENABLED(OF_CONTROL) */
950
Heiko Schocherf5895d12014-06-24 10:10:04 +0200951#ifndef __UBOOT__
952static DEFINE_SPINLOCK(part_parser_lock);
953static LIST_HEAD(part_parsers);
954
955static struct mtd_part_parser *get_partition_parser(const char *name)
956{
957 struct mtd_part_parser *p, *ret = NULL;
958
959 spin_lock(&part_parser_lock);
960
961 list_for_each_entry(p, &part_parsers, list)
962 if (!strcmp(p->name, name) && try_module_get(p->owner)) {
963 ret = p;
964 break;
965 }
966
967 spin_unlock(&part_parser_lock);
968
969 return ret;
970}
971
972#define put_partition_parser(p) do { module_put((p)->owner); } while (0)
973
974void register_mtd_parser(struct mtd_part_parser *p)
975{
976 spin_lock(&part_parser_lock);
977 list_add(&p->list, &part_parsers);
978 spin_unlock(&part_parser_lock);
979}
980EXPORT_SYMBOL_GPL(register_mtd_parser);
981
982void deregister_mtd_parser(struct mtd_part_parser *p)
983{
984 spin_lock(&part_parser_lock);
985 list_del(&p->list);
986 spin_unlock(&part_parser_lock);
987}
988EXPORT_SYMBOL_GPL(deregister_mtd_parser);
989
990/*
991 * Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
992 * are changing this array!
993 */
994static const char * const default_mtd_part_types[] = {
995 "cmdlinepart",
996 "ofpart",
997 NULL
998};
999
1000/**
1001 * parse_mtd_partitions - parse MTD partitions
1002 * @master: the master partition (describes whole MTD device)
1003 * @types: names of partition parsers to try or %NULL
1004 * @pparts: array of partitions found is returned here
1005 * @data: MTD partition parser-specific data
1006 *
1007 * This function tries to find partition on MTD device @master. It uses MTD
1008 * partition parsers, specified in @types. However, if @types is %NULL, then
1009 * the default list of parsers is used. The default list contains only the
1010 * "cmdlinepart" and "ofpart" parsers ATM.
1011 * Note: If there are more then one parser in @types, the kernel only takes the
1012 * partitions parsed out by the first parser.
1013 *
1014 * This function may return:
1015 * o a negative error code in case of failure
1016 * o zero if no partitions were found
1017 * o a positive number of found partitions, in which case on exit @pparts will
1018 * point to an array containing this number of &struct mtd_info objects.
1019 */
1020int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
1021 struct mtd_partition **pparts,
1022 struct mtd_part_parser_data *data)
1023{
1024 struct mtd_part_parser *parser;
1025 int ret = 0;
1026
1027 if (!types)
1028 types = default_mtd_part_types;
1029
1030 for ( ; ret <= 0 && *types; types++) {
1031 parser = get_partition_parser(*types);
1032 if (!parser && !request_module("%s", *types))
1033 parser = get_partition_parser(*types);
1034 if (!parser)
1035 continue;
1036 ret = (*parser->parse_fn)(master, pparts, data);
1037 put_partition_parser(parser);
1038 if (ret > 0) {
1039 printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n",
1040 ret, parser->name, master->name);
1041 break;
1042 }
1043 }
1044 return ret;
1045}
1046#endif
1047
Heiko Schocherf5895d12014-06-24 10:10:04 +02001048/* Returns the size of the entire flash chip */
1049uint64_t mtd_get_device_size(const struct mtd_info *mtd)
1050{
Miquel Raynal6382e0c2018-09-29 12:58:27 +02001051 if (mtd_is_partition(mtd))
1052 return mtd->parent->size;
Heiko Schocherf5895d12014-06-24 10:10:04 +02001053
Miquel Raynal6382e0c2018-09-29 12:58:27 +02001054 return mtd->size;
Heiko Schocherf5895d12014-06-24 10:10:04 +02001055}
1056EXPORT_SYMBOL_GPL(mtd_get_device_size);