xref: /linux/drivers/mtd/parsers/cmdlinepart.c (revision c771600c6af14749609b49565ffb4cac2959710d)
1fd534e9bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * Read flash partition table from command line
41da177e4SLinus Torvalds  *
5a1452a37SDavid Woodhouse  * Copyright © 2002      SYSGO Real-Time Solutions GmbH
6a1452a37SDavid Woodhouse  * Copyright © 2002-2010 David Woodhouse <dwmw2@infradead.org>
7a1452a37SDavid Woodhouse  *
81da177e4SLinus Torvalds  * The format for the command line is as follows:
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * mtdparts=<mtddef>[;<mtddef]
111da177e4SLinus Torvalds  * <mtddef>  := <mtd-id>:<partdef>[,<partdef>]
12568d841bSBoris Brezillon  * <partdef> := <size>[@<offset>][<name>][ro][lk][slc]
131da177e4SLinus Torvalds  * <mtd-id>  := unique name used in mapping driver/device (mtd->name)
141da177e4SLinus Torvalds  * <size>    := standard linux memsize OR "-" to denote all remaining space
15ea8b8e27SChristopher Cordahi  *              size is automatically truncated at end of device
1629f63f65SGeert Uytterhoeven  *              if specified or truncated size is 0 the part is skipped
17ea8b8e27SChristopher Cordahi  * <offset>  := standard linux memsize
18ea8b8e27SChristopher Cordahi  *              if omitted the part will immediately follow the previous part
19ea8b8e27SChristopher Cordahi  *              or 0 if the first part
201da177e4SLinus Torvalds  * <name>    := '(' NAME ')'
21bd6ce5efSChristopher Cordahi  *              NAME will appear in /proc/mtd
221da177e4SLinus Torvalds  *
23ea8b8e27SChristopher Cordahi  * <size> and <offset> can be specified such that the parts are out of order
24ea8b8e27SChristopher Cordahi  * in physical memory and may even overlap.
25ea8b8e27SChristopher Cordahi  *
26ea8b8e27SChristopher Cordahi  * The parts are assigned MTD numbers in the order they are specified in the
27ea8b8e27SChristopher Cordahi  * command line regardless of their order in physical memory.
28ea8b8e27SChristopher Cordahi  *
291da177e4SLinus Torvalds  * Examples:
301da177e4SLinus Torvalds  *
311da177e4SLinus Torvalds  * 1 NOR Flash, with 1 single writable partition:
321da177e4SLinus Torvalds  * edb7312-nor:-
331da177e4SLinus Torvalds  *
341da177e4SLinus Torvalds  * 1 NOR Flash with 2 partitions, 1 NAND with one
351da177e4SLinus Torvalds  * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
361da177e4SLinus Torvalds  */
371da177e4SLinus Torvalds 
38ecb43e0aSBrian Norris #define pr_fmt(fmt)	"mtd: " fmt
39ecb43e0aSBrian Norris 
401da177e4SLinus Torvalds #include <linux/kernel.h>
411da177e4SLinus Torvalds #include <linux/slab.h>
421da177e4SLinus Torvalds #include <linux/mtd/mtd.h>
431da177e4SLinus Torvalds #include <linux/mtd/partitions.h>
44a0e5cc58SPaul Gortmaker #include <linux/module.h>
459e0606fcSArtem Bityutskiy #include <linux/err.h>
461da177e4SLinus Torvalds 
471da177e4SLinus Torvalds /* special size referring to all the remaining space in a partition */
486f9f59eeSHuang Shijie #define SIZE_REMAINING ULLONG_MAX
496f9f59eeSHuang Shijie #define OFFSET_CONTINUOUS ULLONG_MAX
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds struct cmdline_mtd_partition {
521da177e4SLinus Torvalds 	struct cmdline_mtd_partition *next;
531da177e4SLinus Torvalds 	char *mtd_id;
541da177e4SLinus Torvalds 	int num_parts;
551da177e4SLinus Torvalds 	struct mtd_partition *parts;
561da177e4SLinus Torvalds };
571da177e4SLinus Torvalds 
581da177e4SLinus Torvalds /* mtdpart_setup() parses into here */
591da177e4SLinus Torvalds static struct cmdline_mtd_partition *partitions;
601da177e4SLinus Torvalds 
618abc0d4aSPeter Meerwald /* the command line passed to mtdpart_setup() */
62f5f172dcSLubomir Rintel static char *mtdparts;
631da177e4SLinus Torvalds static char *cmdline;
64aa3c5dc5SArtem Bityutskiy static int cmdline_parsed;
651da177e4SLinus Torvalds 
661da177e4SLinus Torvalds /*
671da177e4SLinus Torvalds  * Parse one partition definition for an MTD. Since there can be many
681da177e4SLinus Torvalds  * comma separated partition definitions, this function calls itself
691da177e4SLinus Torvalds  * recursively until no more partition definitions are found. Nice side
701da177e4SLinus Torvalds  * effect: the memory to keep the mtd_partition structs and the names
711da177e4SLinus Torvalds  * is allocated upon the last definition being found. At that point the
721da177e4SLinus Torvalds  * syntax has been verified ok.
731da177e4SLinus Torvalds  */
newpart(char * s,char ** retptr,int * num_parts,int this_part,unsigned char ** extra_mem_ptr,int extra_mem_size)741da177e4SLinus Torvalds static struct mtd_partition * newpart(char *s,
751da177e4SLinus Torvalds 				      char **retptr,
761da177e4SLinus Torvalds 				      int *num_parts,
771da177e4SLinus Torvalds 				      int this_part,
781da177e4SLinus Torvalds 				      unsigned char **extra_mem_ptr,
791da177e4SLinus Torvalds 				      int extra_mem_size)
801da177e4SLinus Torvalds {
811da177e4SLinus Torvalds 	struct mtd_partition *parts;
826f9f59eeSHuang Shijie 	unsigned long long size, offset = OFFSET_CONTINUOUS;
831da177e4SLinus Torvalds 	char *name;
841da177e4SLinus Torvalds 	int name_len;
851da177e4SLinus Torvalds 	unsigned char *extra_mem;
861da177e4SLinus Torvalds 	char delim;
87568d841bSBoris Brezillon 	unsigned int mask_flags, add_flags;
881da177e4SLinus Torvalds 
891da177e4SLinus Torvalds 	/* fetch the partition size */
90fac0077cSArtem Bityutskiy 	if (*s == '-') {
91fac0077cSArtem Bityutskiy 		/* assign all remaining space to this partition */
921da177e4SLinus Torvalds 		size = SIZE_REMAINING;
931da177e4SLinus Torvalds 		s++;
94fac0077cSArtem Bityutskiy 	} else {
951da177e4SLinus Torvalds 		size = memparse(s, &s);
96d855d23bSBrian Norris 		if (!size) {
97ecb43e0aSBrian Norris 			pr_err("partition has size 0\n");
989e0606fcSArtem Bityutskiy 			return ERR_PTR(-EINVAL);
991da177e4SLinus Torvalds 		}
1001da177e4SLinus Torvalds 	}
1011da177e4SLinus Torvalds 
1021da177e4SLinus Torvalds 	/* fetch partition name and flags */
1031da177e4SLinus Torvalds 	mask_flags = 0; /* this is going to be a regular partition */
104568d841bSBoris Brezillon 	add_flags = 0;
1051da177e4SLinus Torvalds 	delim = 0;
106fac0077cSArtem Bityutskiy 
1071da177e4SLinus Torvalds 	/* check for offset */
108fac0077cSArtem Bityutskiy 	if (*s == '@') {
1091da177e4SLinus Torvalds 		s++;
1101da177e4SLinus Torvalds 		offset = memparse(s, &s);
1111da177e4SLinus Torvalds 	}
112fac0077cSArtem Bityutskiy 
1131da177e4SLinus Torvalds 	/* now look for name */
1141da177e4SLinus Torvalds 	if (*s == '(')
1151da177e4SLinus Torvalds 		delim = ')';
1161da177e4SLinus Torvalds 
117fac0077cSArtem Bityutskiy 	if (delim) {
1181da177e4SLinus Torvalds 		char *p;
1191da177e4SLinus Torvalds 
1201da177e4SLinus Torvalds 		name = ++s;
121ed262c4fSAdrian Bunk 		p = strchr(name, delim);
122fac0077cSArtem Bityutskiy 		if (!p) {
123ecb43e0aSBrian Norris 			pr_err("no closing %c found in partition name\n", delim);
1249e0606fcSArtem Bityutskiy 			return ERR_PTR(-EINVAL);
1251da177e4SLinus Torvalds 		}
1261da177e4SLinus Torvalds 		name_len = p - name;
1271da177e4SLinus Torvalds 		s = p + 1;
128fac0077cSArtem Bityutskiy 	} else {
1291da177e4SLinus Torvalds 		name = NULL;
1301da177e4SLinus Torvalds 		name_len = 13; /* Partition_000 */
1311da177e4SLinus Torvalds 	}
1321da177e4SLinus Torvalds 
1331da177e4SLinus Torvalds 	/* record name length for memory allocation later */
1341da177e4SLinus Torvalds 	extra_mem_size += name_len + 1;
1351da177e4SLinus Torvalds 
1361da177e4SLinus Torvalds 	/* test for options */
137fac0077cSArtem Bityutskiy 	if (strncmp(s, "ro", 2) == 0) {
1381da177e4SLinus Torvalds 		mask_flags |= MTD_WRITEABLE;
1391da177e4SLinus Torvalds 		s += 2;
1401da177e4SLinus Torvalds 	}
1411da177e4SLinus Torvalds 
142e619a75fSJustin Treon 	/* if lk is found do NOT unlock the MTD partition*/
143fac0077cSArtem Bityutskiy 	if (strncmp(s, "lk", 2) == 0) {
144e619a75fSJustin Treon 		mask_flags |= MTD_POWERUP_LOCK;
145e619a75fSJustin Treon 		s += 2;
146e619a75fSJustin Treon 	}
147e619a75fSJustin Treon 
148568d841bSBoris Brezillon 	/* if slc is found use emulated SLC mode on this partition*/
149568d841bSBoris Brezillon 	if (!strncmp(s, "slc", 3)) {
150568d841bSBoris Brezillon 		add_flags |= MTD_SLC_ON_MLC_EMULATION;
151568d841bSBoris Brezillon 		s += 3;
152568d841bSBoris Brezillon 	}
153568d841bSBoris Brezillon 
1541da177e4SLinus Torvalds 	/* test if more partitions are following */
155fac0077cSArtem Bityutskiy 	if (*s == ',') {
156fac0077cSArtem Bityutskiy 		if (size == SIZE_REMAINING) {
157ecb43e0aSBrian Norris 			pr_err("no partitions allowed after a fill-up partition\n");
1589e0606fcSArtem Bityutskiy 			return ERR_PTR(-EINVAL);
1591da177e4SLinus Torvalds 		}
1601da177e4SLinus Torvalds 		/* more partitions follow, parse them */
161ed262c4fSAdrian Bunk 		parts = newpart(s + 1, &s, num_parts, this_part + 1,
162ed262c4fSAdrian Bunk 				&extra_mem, extra_mem_size);
1639e0606fcSArtem Bityutskiy 		if (IS_ERR(parts))
1649e0606fcSArtem Bityutskiy 			return parts;
165fac0077cSArtem Bityutskiy 	} else {
166fac0077cSArtem Bityutskiy 		/* this is the last partition: allocate space for all */
1671da177e4SLinus Torvalds 		int alloc_size;
1681da177e4SLinus Torvalds 
1691da177e4SLinus Torvalds 		*num_parts = this_part + 1;
1701da177e4SLinus Torvalds 		alloc_size = *num_parts * sizeof(struct mtd_partition) +
1711da177e4SLinus Torvalds 			     extra_mem_size;
172fac0077cSArtem Bityutskiy 
17395b93a0cSBurman Yan 		parts = kzalloc(alloc_size, GFP_KERNEL);
1741da177e4SLinus Torvalds 		if (!parts)
1759e0606fcSArtem Bityutskiy 			return ERR_PTR(-ENOMEM);
1761da177e4SLinus Torvalds 		extra_mem = (unsigned char *)(parts + *num_parts);
1771da177e4SLinus Torvalds 	}
178fac0077cSArtem Bityutskiy 
17934c81907SGeert Uytterhoeven 	/*
18034c81907SGeert Uytterhoeven 	 * enter this partition (offset will be calculated later if it is
18134c81907SGeert Uytterhoeven 	 * OFFSET_CONTINUOUS at this point)
18234c81907SGeert Uytterhoeven 	 */
1831da177e4SLinus Torvalds 	parts[this_part].size = size;
1841da177e4SLinus Torvalds 	parts[this_part].offset = offset;
1851da177e4SLinus Torvalds 	parts[this_part].mask_flags = mask_flags;
186568d841bSBoris Brezillon 	parts[this_part].add_flags = add_flags;
1871da177e4SLinus Torvalds 	if (name)
18880b7e928SWolfram Sang 		strscpy(extra_mem, name, name_len + 1);
1891da177e4SLinus Torvalds 	else
1901da177e4SLinus Torvalds 		sprintf(extra_mem, "Partition_%03d", this_part);
1911da177e4SLinus Torvalds 	parts[this_part].name = extra_mem;
1921da177e4SLinus Torvalds 	extra_mem += name_len + 1;
1931da177e4SLinus Torvalds 
1942538af03SCsókás, Bence 	pr_debug("partition %d: name <%s>, offset %llx, size %llx, mask flags %x\n",
195fac0077cSArtem Bityutskiy 	     this_part, parts[this_part].name, parts[this_part].offset,
1962538af03SCsókás, Bence 	     parts[this_part].size, parts[this_part].mask_flags);
1971da177e4SLinus Torvalds 
1981da177e4SLinus Torvalds 	/* return (updated) pointer to extra_mem memory */
1991da177e4SLinus Torvalds 	if (extra_mem_ptr)
2001da177e4SLinus Torvalds 		*extra_mem_ptr = extra_mem;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	/* return (updated) pointer command line string */
2031da177e4SLinus Torvalds 	*retptr = s;
2041da177e4SLinus Torvalds 
2051da177e4SLinus Torvalds 	/* return partition table */
2061da177e4SLinus Torvalds 	return parts;
2071da177e4SLinus Torvalds }
2081da177e4SLinus Torvalds 
2091da177e4SLinus Torvalds /*
2101da177e4SLinus Torvalds  * Parse the command line.
2111da177e4SLinus Torvalds  */
mtdpart_setup_real(char * s)2121da177e4SLinus Torvalds static int mtdpart_setup_real(char *s)
2131da177e4SLinus Torvalds {
2141da177e4SLinus Torvalds 	cmdline_parsed = 1;
2151da177e4SLinus Torvalds 
2161da177e4SLinus Torvalds 	for( ; s != NULL; )
2171da177e4SLinus Torvalds 	{
2181da177e4SLinus Torvalds 		struct cmdline_mtd_partition *this_mtd;
2191da177e4SLinus Torvalds 		struct mtd_partition *parts;
220fac0077cSArtem Bityutskiy 		int mtd_id_len, num_parts;
221639a8243SSven Eckelmann 		char *p, *mtd_id, *semicol, *open_parenth;
222eb13fa02SBoris Brezillon 
223eb13fa02SBoris Brezillon 		/*
224eb13fa02SBoris Brezillon 		 * Replace the first ';' by a NULL char so strrchr can work
225eb13fa02SBoris Brezillon 		 * properly.
226eb13fa02SBoris Brezillon 		 */
227eb13fa02SBoris Brezillon 		semicol = strchr(s, ';');
228eb13fa02SBoris Brezillon 		if (semicol)
229eb13fa02SBoris Brezillon 			*semicol = '\0';
2301da177e4SLinus Torvalds 
231639a8243SSven Eckelmann 		/*
232639a8243SSven Eckelmann 		 * make sure that part-names with ":" will not be handled as
233639a8243SSven Eckelmann 		 * part of the mtd-id with an ":"
234639a8243SSven Eckelmann 		 */
235639a8243SSven Eckelmann 		open_parenth = strchr(s, '(');
236639a8243SSven Eckelmann 		if (open_parenth)
237639a8243SSven Eckelmann 			*open_parenth = '\0';
238639a8243SSven Eckelmann 
2391da177e4SLinus Torvalds 		mtd_id = s;
240fac0077cSArtem Bityutskiy 
241eb13fa02SBoris Brezillon 		/*
242eb13fa02SBoris Brezillon 		 * fetch <mtd-id>. We use strrchr to ignore all ':' that could
243eb13fa02SBoris Brezillon 		 * be present in the MTD name, only the last one is interpreted
244eb13fa02SBoris Brezillon 		 * as an <mtd-id>/<part-definition> separator.
245eb13fa02SBoris Brezillon 		 */
246eb13fa02SBoris Brezillon 		p = strrchr(s, ':');
247eb13fa02SBoris Brezillon 
248639a8243SSven Eckelmann 		/* Restore the '(' now. */
249639a8243SSven Eckelmann 		if (open_parenth)
250639a8243SSven Eckelmann 			*open_parenth = '(';
251639a8243SSven Eckelmann 
252eb13fa02SBoris Brezillon 		/* Restore the ';' now. */
253eb13fa02SBoris Brezillon 		if (semicol)
254eb13fa02SBoris Brezillon 			*semicol = ';';
255eb13fa02SBoris Brezillon 
256fac0077cSArtem Bityutskiy 		if (!p) {
257ecb43e0aSBrian Norris 			pr_err("no mtd-id\n");
2589e0606fcSArtem Bityutskiy 			return -EINVAL;
2591da177e4SLinus Torvalds 		}
2601da177e4SLinus Torvalds 		mtd_id_len = p - mtd_id;
2611da177e4SLinus Torvalds 
2622538af03SCsókás, Bence 		pr_debug("parsing <%s>\n", p+1);
2631da177e4SLinus Torvalds 
2641da177e4SLinus Torvalds 		/*
2651da177e4SLinus Torvalds 		 * parse one mtd. have it reserve memory for the
2661da177e4SLinus Torvalds 		 * struct cmdline_mtd_partition and the mtd-id string.
2671da177e4SLinus Torvalds 		 */
2681da177e4SLinus Torvalds 		parts = newpart(p + 1,		/* cmdline */
2691da177e4SLinus Torvalds 				&s,		/* out: updated cmdline ptr */
2701da177e4SLinus Torvalds 				&num_parts,	/* out: number of parts */
2711da177e4SLinus Torvalds 				0,		/* first partition */
2721da177e4SLinus Torvalds 				(unsigned char**)&this_mtd, /* out: extra mem */
273be76c5fbSJoern Engel 				mtd_id_len + 1 + sizeof(*this_mtd) +
274be76c5fbSJoern Engel 				sizeof(void*)-1 /*alignment*/);
275fac0077cSArtem Bityutskiy 		if (IS_ERR(parts)) {
2761da177e4SLinus Torvalds 			/*
2771da177e4SLinus Torvalds 			 * An error occurred. We're either:
2781da177e4SLinus Torvalds 			 * a) out of memory, or
2791da177e4SLinus Torvalds 			 * b) in the middle of the partition spec
2801da177e4SLinus Torvalds 			 * Either way, this mtd is hosed and we're
2811da177e4SLinus Torvalds 			 * unlikely to succeed in parsing any more
2821da177e4SLinus Torvalds 			 */
2839e0606fcSArtem Bityutskiy 			 return PTR_ERR(parts);
2841da177e4SLinus Torvalds 		 }
2851da177e4SLinus Torvalds 
286be76c5fbSJoern Engel 		/* align this_mtd */
287be76c5fbSJoern Engel 		this_mtd = (struct cmdline_mtd_partition *)
288be76c5fbSJoern Engel 				ALIGN((unsigned long)this_mtd, sizeof(void *));
2891da177e4SLinus Torvalds 		/* enter results */
2901da177e4SLinus Torvalds 		this_mtd->parts = parts;
2911da177e4SLinus Torvalds 		this_mtd->num_parts = num_parts;
2921da177e4SLinus Torvalds 		this_mtd->mtd_id = (char*)(this_mtd + 1);
29380b7e928SWolfram Sang 		strscpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1);
2941da177e4SLinus Torvalds 
2951da177e4SLinus Torvalds 		/* link into chain */
2961da177e4SLinus Torvalds 		this_mtd->next = partitions;
2971da177e4SLinus Torvalds 		partitions = this_mtd;
2981da177e4SLinus Torvalds 
2992538af03SCsókás, Bence 		pr_debug("mtdid=<%s> num_parts=<%d>\n",
3002538af03SCsókás, Bence 		     this_mtd->mtd_id, this_mtd->num_parts);
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds 
3031da177e4SLinus Torvalds 		/* EOS - we're done */
3041da177e4SLinus Torvalds 		if (*s == 0)
3051da177e4SLinus Torvalds 			break;
3061da177e4SLinus Torvalds 
3071da177e4SLinus Torvalds 		/* does another spec follow? */
308fac0077cSArtem Bityutskiy 		if (*s != ';') {
309ecb43e0aSBrian Norris 			pr_err("bad character after partition (%c)\n", *s);
3109e0606fcSArtem Bityutskiy 			return -EINVAL;
3111da177e4SLinus Torvalds 		}
3121da177e4SLinus Torvalds 		s++;
3131da177e4SLinus Torvalds 	}
314fac0077cSArtem Bityutskiy 
3159e0606fcSArtem Bityutskiy 	return 0;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds 
3181da177e4SLinus Torvalds /*
3191da177e4SLinus Torvalds  * Main function to be called from the MTD mapping driver/device to
3201da177e4SLinus Torvalds  * obtain the partitioning information. At this point the command line
3211da177e4SLinus Torvalds  * arguments will actually be parsed and turned to struct mtd_partition
3221da177e4SLinus Torvalds  * information. It returns partitions for the requested mtd device, or
3231da177e4SLinus Torvalds  * the first one in the chain if a NULL mtd_id is passed in.
3241da177e4SLinus Torvalds  */
parse_cmdline_partitions(struct mtd_info * master,const struct mtd_partition ** pparts,struct mtd_part_parser_data * data)3251da177e4SLinus Torvalds static int parse_cmdline_partitions(struct mtd_info *master,
326b9adf469SBrian Norris 				    const struct mtd_partition **pparts,
327c7975330SDmitry Eremin-Solenikov 				    struct mtd_part_parser_data *data)
3281da177e4SLinus Torvalds {
3296f9f59eeSHuang Shijie 	unsigned long long offset;
3309e0606fcSArtem Bityutskiy 	int i, err;
3311da177e4SLinus Torvalds 	struct cmdline_mtd_partition *part;
33236560d25SDavid Howells 	const char *mtd_id = master->name;
3331da177e4SLinus Torvalds 
3341da177e4SLinus Torvalds 	/* parse command line */
3359e0606fcSArtem Bityutskiy 	if (!cmdline_parsed) {
3369e0606fcSArtem Bityutskiy 		err = mtdpart_setup_real(cmdline);
3379e0606fcSArtem Bityutskiy 		if (err)
3389e0606fcSArtem Bityutskiy 			return err;
3399e0606fcSArtem Bityutskiy 	}
3401da177e4SLinus Torvalds 
341438db5a9SShmulik Ladkani 	/*
342438db5a9SShmulik Ladkani 	 * Search for the partition definition matching master->name.
343438db5a9SShmulik Ladkani 	 * If master->name is not set, stop at first partition definition.
344438db5a9SShmulik Ladkani 	 */
345fac0077cSArtem Bityutskiy 	for (part = partitions; part; part = part->next) {
346438db5a9SShmulik Ladkani 		if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id)))
347438db5a9SShmulik Ladkani 			break;
348438db5a9SShmulik Ladkani 	}
349438db5a9SShmulik Ladkani 
350438db5a9SShmulik Ladkani 	if (!part)
351438db5a9SShmulik Ladkani 		return 0;
352438db5a9SShmulik Ladkani 
353fac0077cSArtem Bityutskiy 	for (i = 0, offset = 0; i < part->num_parts; i++) {
354b175d03dSAtsushi Nemoto 		if (part->parts[i].offset == OFFSET_CONTINUOUS)
3551da177e4SLinus Torvalds 			part->parts[i].offset = offset;
3561da177e4SLinus Torvalds 		else
3571da177e4SLinus Torvalds 			offset = part->parts[i].offset;
358fac0077cSArtem Bityutskiy 
3591da177e4SLinus Torvalds 		if (part->parts[i].size == SIZE_REMAINING)
3601da177e4SLinus Torvalds 			part->parts[i].size = master->size - offset;
361fac0077cSArtem Bityutskiy 
362ebf4f070SChristopher Cordahi 		if (offset + part->parts[i].size > master->size) {
363ecb43e0aSBrian Norris 			pr_warn("%s: partitioning exceeds flash size, truncating\n",
364ebf4f070SChristopher Cordahi 				part->mtd_id);
365ebf4f070SChristopher Cordahi 			part->parts[i].size = master->size - offset;
366ebf4f070SChristopher Cordahi 		}
367ebf4f070SChristopher Cordahi 		offset += part->parts[i].size;
368ebf4f070SChristopher Cordahi 
3697baf0426SShmulik Ladkani 		if (part->parts[i].size == 0) {
370ecb43e0aSBrian Norris 			pr_warn("%s: skipping zero sized partition\n",
3717baf0426SShmulik Ladkani 				part->mtd_id);
3727baf0426SShmulik Ladkani 			part->num_parts--;
373438db5a9SShmulik Ladkani 			memmove(&part->parts[i], &part->parts[i + 1],
3747baf0426SShmulik Ladkani 				sizeof(*part->parts) * (part->num_parts - i));
375e25e0a4dSChristopher Cordahi 			i--;
3767baf0426SShmulik Ladkani 		}
3771da177e4SLinus Torvalds 	}
378fac0077cSArtem Bityutskiy 
379438db5a9SShmulik Ladkani 	*pparts = kmemdup(part->parts, sizeof(*part->parts) * part->num_parts,
38017b536ccSAtsushi Nemoto 			  GFP_KERNEL);
38117b536ccSAtsushi Nemoto 	if (!*pparts)
38217b536ccSAtsushi Nemoto 		return -ENOMEM;
383fac0077cSArtem Bityutskiy 
3841da177e4SLinus Torvalds 	return part->num_parts;
3851da177e4SLinus Torvalds }
3861da177e4SLinus Torvalds 
3871da177e4SLinus Torvalds 
3881da177e4SLinus Torvalds /*
3891da177e4SLinus Torvalds  * This is the handler for our kernel parameter, called from
3901da177e4SLinus Torvalds  * main.c::checksetup(). Note that we can not yet kmalloc() anything,
3911da177e4SLinus Torvalds  * so we only save the commandline for later processing.
3921da177e4SLinus Torvalds  *
3931da177e4SLinus Torvalds  * This function needs to be visible for bootloaders.
3941da177e4SLinus Torvalds  */
mtdpart_setup(char * s)395f5f172dcSLubomir Rintel static int __init mtdpart_setup(char *s)
3961da177e4SLinus Torvalds {
3971da177e4SLinus Torvalds 	cmdline = s;
3981da177e4SLinus Torvalds 	return 1;
3991da177e4SLinus Torvalds }
4001da177e4SLinus Torvalds 
4011da177e4SLinus Torvalds __setup("mtdparts=", mtdpart_setup);
4021da177e4SLinus Torvalds 
4031da177e4SLinus Torvalds static struct mtd_part_parser cmdline_parser = {
4041da177e4SLinus Torvalds 	.parse_fn = parse_cmdline_partitions,
4051da177e4SLinus Torvalds 	.name = "cmdlinepart",
4061da177e4SLinus Torvalds };
4071da177e4SLinus Torvalds 
cmdline_parser_init(void)4081da177e4SLinus Torvalds static int __init cmdline_parser_init(void)
4091da177e4SLinus Torvalds {
410f5f172dcSLubomir Rintel 	if (mtdparts)
411f5f172dcSLubomir Rintel 		mtdpart_setup(mtdparts);
4126e14a61dSAxel Lin 	register_mtd_parser(&cmdline_parser);
4136e14a61dSAxel Lin 	return 0;
4141da177e4SLinus Torvalds }
4151da177e4SLinus Torvalds 
cmdline_parser_exit(void)416422f3890SLubomir Rintel static void __exit cmdline_parser_exit(void)
417422f3890SLubomir Rintel {
418422f3890SLubomir Rintel 	deregister_mtd_parser(&cmdline_parser);
419422f3890SLubomir Rintel }
420422f3890SLubomir Rintel 
4211da177e4SLinus Torvalds module_init(cmdline_parser_init);
422422f3890SLubomir Rintel module_exit(cmdline_parser_exit);
4231da177e4SLinus Torvalds 
424f5f172dcSLubomir Rintel MODULE_PARM_DESC(mtdparts, "Partitioning specification");
425f5f172dcSLubomir Rintel module_param(mtdparts, charp, 0);
426f5f172dcSLubomir Rintel 
4271da177e4SLinus Torvalds MODULE_LICENSE("GPL");
4281da177e4SLinus Torvalds MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
4291da177e4SLinus Torvalds MODULE_DESCRIPTION("Command line configuration of MTD partitions");
430