Prepare v2024.10
[platform/kernel/u-boot.git] / cmd / mtdparts.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2002
4  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5  *
6  * (C) Copyright 2002
7  * Robert Schwebel, Pengutronix, <r.schwebel@pengutronix.de>
8  *
9  * (C) Copyright 2003
10  * Kai-Uwe Bloem, Auerswald GmbH & Co KG, <linux-development@auerswald.de>
11  *
12  * (C) Copyright 2005
13  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
14  *
15  *   Added support for reading flash partition table from environment.
16  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
17  *   kernel tree.
18  *
19  * (C) Copyright 2008
20  * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org>
21  *
22  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
23  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
24  */
25
26 /*
27  * Three environment variables are used by the parsing routines:
28  *
29  * 'partition' - keeps current partition identifier
30  *
31  * partition  := <part-id>
32  * <part-id>  := <dev-id>,part_num
33  *
34  *
35  * 'mtdids' - linux kernel mtd device id <-> u-boot device id mapping
36  *
37  * mtdids=<idmap>[,<idmap>,...]
38  *
39  * <idmap>    := <dev-id>=<mtd-id>
40  * <dev-id>   := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>
41  * <dev-num>  := mtd device number, 0...
42  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
43  *
44  *
45  * 'mtdparts' - partition list
46  *
47  * mtdparts=[mtdparts=]<mtd-def>[;<mtd-def>...]
48  *
49  * <mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]
50  * <mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)
51  * <part-def> := <size>[@<offset>][<name>][<ro-flag>]
52  * <size>     := standard linux memsize OR '-' to denote all remaining space
53  * <offset>   := partition start offset within the device
54  * <name>     := '(' NAME ')'
55  * <ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)
56  *
57  * Notes:
58  * - each <mtd-id> used in mtdparts must albo exist in 'mtddis' mapping
59  * - if the above variables are not set defaults for a given target are used
60  *
61  * Examples:
62  *
63  * 1 NOR Flash, with 1 single writable partition:
64  * mtdids=nor0=edb7312-nor
65  * mtdparts=[mtdparts=]edb7312-nor:-
66  *
67  * 1 NOR Flash with 2 partitions, 1 NAND with one
68  * mtdids=nor0=edb7312-nor,nand0=edb7312-nand
69  * mtdparts=[mtdparts=]edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
70  *
71  */
72
73 #include <command.h>
74 #include <env.h>
75 #include <log.h>
76 #include <malloc.h>
77 #include <asm/global_data.h>
78 #include <jffs2/load_kernel.h>
79 #include <linux/list.h>
80 #include <linux/ctype.h>
81 #include <linux/err.h>
82 #include <linux/mtd/mtd.h>
83
84 #if defined(CONFIG_CMD_NAND)
85 #include <linux/mtd/rawnand.h>
86 #include <nand.h>
87 #endif
88
89 #if defined(CONFIG_CMD_ONENAND)
90 #include <linux/mtd/onenand.h>
91 #include <onenand_uboot.h>
92 #endif
93
94 DECLARE_GLOBAL_DATA_PTR;
95
96 /* special size referring to all the remaining space in a partition */
97 #define SIZE_REMAINING          (~0llu)
98
99 /* special offset value, it is used when not provided by user
100  *
101  * this value is used temporarily during parsing, later such offests
102  * are recalculated */
103 #define OFFSET_NOT_SPECIFIED    (~0llu)
104
105 /* minimum partition size */
106 #define MIN_PART_SIZE           4096
107
108 /* this flag needs to be set in part_info struct mask_flags
109  * field for read-only partitions */
110 #define MTD_WRITEABLE_CMD               1
111
112 /* default values for mtdids and mtdparts variables */
113 #ifdef CONFIG_MTDIDS_DEFAULT
114 #define MTDIDS_DEFAULT CONFIG_MTDIDS_DEFAULT
115 #else
116 #define MTDIDS_DEFAULT NULL
117 #endif
118 #ifdef CONFIG_MTDPARTS_DEFAULT
119 #define MTDPARTS_DEFAULT CONFIG_MTDPARTS_DEFAULT
120 #else
121 #define MTDPARTS_DEFAULT NULL
122 #endif
123
124 #if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
125 extern void board_mtdparts_default(const char **mtdids, const char **mtdparts);
126 #endif
127 static const char *mtdids_default = MTDIDS_DEFAULT;
128 static const char *mtdparts_default = MTDPARTS_DEFAULT;
129
130 /* copies of last seen 'mtdids', 'mtdparts' and 'partition' env variables */
131 #define MTDIDS_MAXLEN           128
132 #define MTDPARTS_MAXLEN         512
133 #define PARTITION_MAXLEN        16
134 static char last_ids[MTDIDS_MAXLEN + 1];
135 static char last_parts[MTDPARTS_MAXLEN + 1];
136 static char last_partition[PARTITION_MAXLEN + 1];
137
138 /* low level jffs2 cache cleaning routine */
139 extern void jffs2_free_cache(struct part_info *part);
140
141 /* mtdids mapping list, filled by parse_ids() */
142 static struct list_head mtdids;
143
144 /* device/partition list, parse_cmdline() parses into here */
145 static struct list_head devices;
146
147 /* current active device and partition number */
148 struct mtd_device *current_mtd_dev = NULL;
149 u8 current_mtd_partnum = 0;
150
151 u8 use_defaults;
152
153 static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num);
154
155 /* command line only routines */
156 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len);
157 static int device_del(struct mtd_device *dev);
158
159 /**
160  * Parses a string into a number.  The number stored at ptr is
161  * potentially suffixed with K (for kilobytes, or 1024 bytes),
162  * M (for megabytes, or 1048576 bytes), or G (for gigabytes, or
163  * 1073741824).  If the number is suffixed with K, M, or G, then
164  * the return value is the number multiplied by one kilobyte, one
165  * megabyte, or one gigabyte, respectively.
166  *
167  * @param ptr where parse begins
168  * @param retptr output pointer to next char after parse completes (output)
169  * Return: resulting unsigned int
170  */
171 static u64 memsize_parse (const char *const ptr, const char **retptr)
172 {
173         u64 ret = simple_strtoull(ptr, (char **)retptr, 0);
174
175         switch (**retptr) {
176                 case 'G':
177                 case 'g':
178                         ret <<= 10;
179                         /* Fallthrough */
180                 case 'M':
181                 case 'm':
182                         ret <<= 10;
183                         /* Fallthrough */
184                 case 'K':
185                 case 'k':
186                         ret <<= 10;
187                         (*retptr)++;
188                         /* Fallthrough */
189                 default:
190                         break;
191         }
192
193         return ret;
194 }
195
196 /**
197  * Format string describing supplied size. This routine does the opposite job
198  * to memsize_parse(). Size in bytes is converted to string and if possible
199  * shortened by using k (kilobytes), m (megabytes) or g (gigabytes) suffix.
200  *
201  * Note, that this routine does not check for buffer overflow, it's the caller
202  * who must assure enough space.
203  *
204  * @param buf output buffer
205  * @param size size to be converted to string
206  */
207 static void memsize_format(char *buf, u64 size)
208 {
209 #define SIZE_GB ((u32)1024*1024*1024)
210 #define SIZE_MB ((u32)1024*1024)
211 #define SIZE_KB ((u32)1024)
212
213         if ((size % SIZE_GB) == 0)
214                 sprintf(buf, "%llug", size/SIZE_GB);
215         else if ((size % SIZE_MB) == 0)
216                 sprintf(buf, "%llum", size/SIZE_MB);
217         else if (size % SIZE_KB == 0)
218                 sprintf(buf, "%lluk", size/SIZE_KB);
219         else
220                 sprintf(buf, "%llu", size);
221 }
222
223 /**
224  * This routine does global indexing of all partitions. Resulting index for
225  * current partition is saved in 'mtddevnum'. Current partition name in
226  * 'mtddevname'.
227  */
228 static void index_partitions(void)
229 {
230         u16 mtddevnum;
231         struct part_info *part;
232         struct list_head *dentry;
233         struct mtd_device *dev;
234
235         debug("--- index partitions ---\n");
236
237         if (current_mtd_dev) {
238                 mtddevnum = 0;
239                 list_for_each(dentry, &devices) {
240                         dev = list_entry(dentry, struct mtd_device, link);
241                         if (dev == current_mtd_dev) {
242                                 mtddevnum += current_mtd_partnum;
243                                 env_set_ulong("mtddevnum", mtddevnum);
244                                 debug("=> mtddevnum %d,\n", mtddevnum);
245                                 break;
246                         }
247                         mtddevnum += dev->num_parts;
248                 }
249
250                 part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
251                 if (part) {
252                         env_set("mtddevname", part->name);
253
254                         debug("=> mtddevname %s\n", part->name);
255                 } else {
256                         env_set("mtddevname", NULL);
257
258                         debug("=> mtddevname NULL\n");
259                 }
260         } else {
261                 env_set("mtddevnum", NULL);
262                 env_set("mtddevname", NULL);
263
264                 debug("=> mtddevnum NULL\n=> mtddevname NULL\n");
265         }
266 }
267
268 /**
269  * Save current device and partition in environment variable 'partition'.
270  */
271 static void current_save(void)
272 {
273         char buf[16];
274
275         debug("--- current_save ---\n");
276
277         if (current_mtd_dev) {
278                 sprintf(buf, "%s%d,%d", MTD_DEV_TYPE(current_mtd_dev->id->type),
279                                         current_mtd_dev->id->num, current_mtd_partnum);
280
281                 env_set("partition", buf);
282                 strncpy(last_partition, buf, 16);
283
284                 debug("=> partition %s\n", buf);
285         } else {
286                 env_set("partition", NULL);
287                 last_partition[0] = '\0';
288
289                 debug("=> partition NULL\n");
290         }
291         index_partitions();
292 }
293
294 /**
295  * Produce a mtd_info given a type and num.
296  *
297  * @param type mtd type
298  * @param num mtd number
299  * @param mtd a pointer to an mtd_info instance (output)
300  * Return: 0 if device is valid, 1 otherwise
301  */
302 static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
303 {
304         char mtd_dev[16];
305
306         sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
307         *mtd = get_mtd_device_nm(mtd_dev);
308         if (IS_ERR(*mtd)) {
309                 printf("Device %s not found!\n", mtd_dev);
310                 return 1;
311         }
312         put_mtd_device(*mtd);
313
314         return 0;
315 }
316
317 /**
318  * Performs sanity check for supplied flash partition.
319  * Table of existing MTD flash devices is searched and partition device
320  * is located. Alignment with the granularity of nand erasesize is verified.
321  *
322  * @param id of the parent device
323  * @param part partition to validate
324  * Return: 0 if partition is valid, 1 otherwise
325  */
326 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
327 {
328         struct mtd_info *mtd = NULL;
329         int i, j;
330         ulong start;
331         u64 offset, size;
332
333         if (get_mtd_info(id->type, id->num, &mtd))
334                 return 1;
335
336         part->sector_size = mtd->erasesize;
337
338         if (!mtd->numeraseregions) {
339                 /*
340                  * Only one eraseregion (NAND, SPI-NAND, OneNAND or uniform NOR),
341                  * checking for alignment is easy here
342                  */
343                 offset = part->offset;
344                 if (do_div(offset, mtd->erasesize)) {
345                         printf("%s%d: partition (%s) start offset"
346                                "alignment incorrect\n",
347                                MTD_DEV_TYPE(id->type), id->num, part->name);
348                         return 1;
349                 }
350
351                 size = part->size;
352                 if (do_div(size, mtd->erasesize)) {
353                         printf("%s%d: partition (%s) size alignment incorrect\n",
354                                MTD_DEV_TYPE(id->type), id->num, part->name);
355                         return 1;
356                 }
357         } else {
358                 /*
359                  * Multiple eraseregions (non-uniform NOR),
360                  * checking for alignment is more complex here
361                  */
362
363                 /* Check start alignment */
364                 for (i = 0; i < mtd->numeraseregions; i++) {
365                         start = mtd->eraseregions[i].offset;
366                         for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
367                                 if (part->offset == start)
368                                         goto start_ok;
369                                 start += mtd->eraseregions[i].erasesize;
370                         }
371                 }
372
373                 printf("%s%d: partition (%s) start offset alignment incorrect\n",
374                        MTD_DEV_TYPE(id->type), id->num, part->name);
375                 return 1;
376
377         start_ok:
378
379                 /* Check end/size alignment */
380                 for (i = 0; i < mtd->numeraseregions; i++) {
381                         start = mtd->eraseregions[i].offset;
382                         for (j = 0; j < mtd->eraseregions[i].numblocks; j++) {
383                                 if ((part->offset + part->size) == start)
384                                         goto end_ok;
385                                 start += mtd->eraseregions[i].erasesize;
386                         }
387                 }
388                 /* Check last sector alignment */
389                 if ((part->offset + part->size) == start)
390                         goto end_ok;
391
392                 printf("%s%d: partition (%s) size alignment incorrect\n",
393                        MTD_DEV_TYPE(id->type), id->num, part->name);
394                 return 1;
395
396         end_ok:
397                 return 0;
398         }
399
400         return 0;
401 }
402
403 /**
404  * Performs sanity check for supplied partition. Offset and size are
405  * verified to be within valid range. Partition type is checked and
406  * part_validate_eraseblock() is called with the argument of part.
407  *
408  * @param id of the parent device
409  * @param part partition to validate
410  * Return: 0 if partition is valid, 1 otherwise
411  */
412 static int part_validate(struct mtdids *id, struct part_info *part)
413 {
414         if (part->size == SIZE_REMAINING)
415                 part->size = id->size - part->offset;
416
417         if (part->offset > id->size) {
418                 printf("%s: offset %08llx beyond flash size %08llx\n",
419                                 id->mtd_id, part->offset, id->size);
420                 return 1;
421         }
422
423         if ((part->offset + part->size) <= part->offset) {
424                 printf("%s%d: partition (%s) size too big\n",
425                                 MTD_DEV_TYPE(id->type), id->num, part->name);
426                 return 1;
427         }
428
429         if (part->offset + part->size > id->size) {
430                 printf("%s: partitioning exceeds flash size\n", id->mtd_id);
431                 return 1;
432         }
433
434         /*
435          * Now we need to check if the partition starts and ends on
436          * sector (eraseblock) regions
437          */
438         return part_validate_eraseblock(id, part);
439 }
440
441 /**
442  * Delete selected partition from the partition list of the specified device.
443  *
444  * @param dev device to delete partition from
445  * @param part partition to delete
446  * Return: 0 on success, 1 otherwise
447  */
448 static int part_del(struct mtd_device *dev, struct part_info *part)
449 {
450         u8 current_save_needed = 0;
451
452         /* if there is only one partition, remove whole device */
453         if (dev->num_parts == 1)
454                 return device_del(dev);
455
456         /* otherwise just delete this partition */
457
458         if (dev == current_mtd_dev) {
459                 /* we are modyfing partitions for the current device,
460                  * update current */
461                 struct part_info *curr_pi;
462                 curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum);
463
464                 if (curr_pi) {
465                         if (curr_pi == part) {
466                                 printf("current partition deleted, resetting current to 0\n");
467                                 current_mtd_partnum = 0;
468                         } else if (part->offset <= curr_pi->offset) {
469                                 current_mtd_partnum--;
470                         }
471                         current_save_needed = 1;
472                 }
473         }
474
475         list_del(&part->link);
476         free(part);
477         dev->num_parts--;
478
479         if (current_save_needed > 0)
480                 current_save();
481         else
482                 index_partitions();
483
484         return 0;
485 }
486
487 /**
488  * Delete all partitions from parts head list, free memory.
489  *
490  * @param head list of partitions to delete
491  */
492 static void part_delall(struct list_head *head)
493 {
494         struct list_head *entry, *n;
495         struct part_info *part_tmp;
496
497         /* clean tmp_list and free allocated memory */
498         list_for_each_safe(entry, n, head) {
499                 part_tmp = list_entry(entry, struct part_info, link);
500
501                 list_del(entry);
502                 free(part_tmp);
503         }
504 }
505
506 /**
507  * Add new partition to the supplied partition list. Make sure partitions are
508  * sorted by offset in ascending order.
509  *
510  * @param head list this partition is to be added to
511  * @param new partition to be added
512  */
513 static int part_sort_add(struct mtd_device *dev, struct part_info *part)
514 {
515         struct list_head *entry;
516         struct part_info *new_pi, *curr_pi;
517
518         /* link partition to parrent dev */
519         part->dev = dev;
520
521         if (list_empty(&dev->parts)) {
522                 debug("part_sort_add: list empty\n");
523                 list_add(&part->link, &dev->parts);
524                 dev->num_parts++;
525                 index_partitions();
526                 return 0;
527         }
528
529         new_pi = list_entry(&part->link, struct part_info, link);
530
531         /* get current partition info if we are updating current device */
532         curr_pi = NULL;
533         if (dev == current_mtd_dev)
534                 curr_pi = mtd_part_info(current_mtd_dev, current_mtd_partnum);
535
536         list_for_each(entry, &dev->parts) {
537                 struct part_info *pi;
538
539                 pi = list_entry(entry, struct part_info, link);
540
541                 /* be compliant with kernel cmdline, allow only one partition at offset zero */
542                 if ((new_pi->offset == pi->offset) && (pi->offset == 0)) {
543                         printf("cannot add second partition at offset 0\n");
544                         return 1;
545                 }
546
547                 if (new_pi->offset <= pi->offset) {
548                         list_add_tail(&part->link, entry);
549                         dev->num_parts++;
550
551                         if (curr_pi && (pi->offset <= curr_pi->offset)) {
552                                 /* we are modyfing partitions for the current
553                                  * device, update current */
554                                 current_mtd_partnum++;
555                                 current_save();
556                         } else {
557                                 index_partitions();
558                         }
559                         return 0;
560                 }
561         }
562
563         list_add_tail(&part->link, &dev->parts);
564         dev->num_parts++;
565         index_partitions();
566         return 0;
567 }
568
569 /**
570  * Add provided partition to the partition list of a given device.
571  *
572  * @param dev device to which partition is added
573  * @param part partition to be added
574  * Return: 0 on success, 1 otherwise
575  */
576 static int part_add(struct mtd_device *dev, struct part_info *part)
577 {
578         /* verify alignment and size */
579         if (part_validate(dev->id, part) != 0)
580                 return 1;
581
582         /* partition is ok, add it to the list */
583         if (part_sort_add(dev, part) != 0)
584                 return 1;
585
586         return 0;
587 }
588
589 /**
590  * Parse one partition definition, allocate memory and return pointer to this
591  * location in retpart.
592  *
593  * @param partdef pointer to the partition definition string i.e. <part-def>
594  * @param ret output pointer to next char after parse completes (output)
595  * @param retpart pointer to the allocated partition (output)
596  * Return: 0 on success, 1 otherwise
597  */
598 static int part_parse(const char *const partdef, const char **ret, struct part_info **retpart)
599 {
600         struct part_info *part;
601         u64 size;
602         u64 offset;
603         const char *name;
604         int name_len;
605         unsigned int mask_flags;
606         const char *p;
607
608         p = partdef;
609         *retpart = NULL;
610         *ret = NULL;
611
612         /* fetch the partition size */
613         if (*p == '-') {
614                 /* assign all remaining space to this partition */
615                 debug("'-': remaining size assigned\n");
616                 size = SIZE_REMAINING;
617                 p++;
618         } else {
619                 size = memsize_parse(p, &p);
620                 if (size < MIN_PART_SIZE) {
621                         printf("partition size too small (%llx)\n", size);
622                         return 1;
623                 }
624         }
625
626         /* check for offset */
627         offset = OFFSET_NOT_SPECIFIED;
628         if (*p == '@') {
629                 p++;
630                 offset = memsize_parse(p, &p);
631         }
632
633         /* now look for the name */
634         if (*p == '(') {
635                 name = ++p;
636                 if ((p = strchr(name, ')')) == NULL) {
637                         printf("no closing ) found in partition name\n");
638                         return 1;
639                 }
640                 name_len = p - name + 1;
641                 if ((name_len - 1) == 0) {
642                         printf("empty partition name\n");
643                         return 1;
644                 }
645                 p++;
646         } else {
647                 /* 0x00000000@0x00000000 */
648                 name_len = 22;
649                 name = NULL;
650         }
651
652         /* test for options */
653         mask_flags = 0;
654         if (strncmp(p, "ro", 2) == 0) {
655                 mask_flags |= MTD_WRITEABLE_CMD;
656                 p += 2;
657         }
658
659         /* check for next partition definition */
660         if (*p == ',') {
661                 if (size == SIZE_REMAINING) {
662                         *ret = NULL;
663                         printf("no partitions allowed after a fill-up partition\n");
664                         return 1;
665                 }
666                 *ret = ++p;
667         } else if ((*p == ';') || (*p == '\0')) {
668                 *ret = p;
669         } else {
670                 printf("unexpected character '%c' at the end of partition\n", *p);
671                 *ret = NULL;
672                 return 1;
673         }
674
675         /*  allocate memory */
676         part = (struct part_info *)malloc(sizeof(struct part_info) + name_len);
677         if (!part) {
678                 printf("out of memory\n");
679                 return 1;
680         }
681         memset(part, 0, sizeof(struct part_info) + name_len);
682         part->size = size;
683         part->offset = offset;
684         part->mask_flags = mask_flags;
685         part->name = (char *)(part + 1);
686
687         if (name) {
688                 /* copy user provided name */
689                 strncpy(part->name, name, name_len - 1);
690                 part->auto_name = 0;
691         } else {
692                 /* auto generated name in form of size@offset */
693                 snprintf(part->name, name_len, "0x%08llx@0x%08llx", size, offset);
694                 part->auto_name = 1;
695         }
696
697         part->name[name_len - 1] = '\0';
698         INIT_LIST_HEAD(&part->link);
699
700         debug("+ partition: name %-22s size 0x%08llx offset 0x%08llx mask flags %d\n",
701                         part->name, part->size,
702                         part->offset, part->mask_flags);
703
704         *retpart = part;
705         return 0;
706 }
707
708 /**
709  * Check device number to be within valid range for given device type.
710  *
711  * @param type mtd type
712  * @param num mtd number
713  * @param size a pointer to the size of the mtd device (output)
714  * Return: 0 if device is valid, 1 otherwise
715  */
716 static int mtd_device_validate(u8 type, u8 num, u64 *size)
717 {
718         struct mtd_info *mtd = NULL;
719
720         if (get_mtd_info(type, num, &mtd))
721                 return 1;
722
723         *size = mtd->size;
724
725         return 0;
726 }
727
728 /**
729  * Delete all mtd devices from a supplied devices list, free memory allocated for
730  * each device and delete all device partitions.
731  *
732  * Return: 0 on success, 1 otherwise
733  */
734 static int device_delall(struct list_head *head)
735 {
736         struct list_head *entry, *n;
737         struct mtd_device *dev_tmp;
738
739         /* clean devices list */
740         list_for_each_safe(entry, n, head) {
741                 dev_tmp = list_entry(entry, struct mtd_device, link);
742                 list_del(entry);
743                 part_delall(&dev_tmp->parts);
744                 free(dev_tmp);
745         }
746         INIT_LIST_HEAD(&devices);
747
748         return 0;
749 }
750
751 /**
752  * If provided device exists it's partitions are deleted, device is removed
753  * from device list and device memory is freed.
754  *
755  * @param dev device to be deleted
756  * Return: 0 on success, 1 otherwise
757  */
758 static int device_del(struct mtd_device *dev)
759 {
760         part_delall(&dev->parts);
761         list_del(&dev->link);
762         free(dev);
763
764         if (dev == current_mtd_dev) {
765                 /* we just deleted current device */
766                 if (list_empty(&devices)) {
767                         current_mtd_dev = NULL;
768                 } else {
769                         /* reset first partition from first dev from the
770                          * devices list as current */
771                         current_mtd_dev = list_entry(devices.next, struct mtd_device, link);
772                         current_mtd_partnum = 0;
773                 }
774                 current_save();
775                 return 0;
776         }
777
778         index_partitions();
779         return 0;
780 }
781
782 /**
783  * Search global device list and return pointer to the device of type and num
784  * specified.
785  *
786  * @param type device type
787  * @param num device number
788  * Return: NULL if requested device does not exist
789  */
790 struct mtd_device *device_find(u8 type, u8 num)
791 {
792         struct list_head *entry;
793         struct mtd_device *dev_tmp;
794
795         list_for_each(entry, &devices) {
796                 dev_tmp = list_entry(entry, struct mtd_device, link);
797
798                 if ((dev_tmp->id->type == type) && (dev_tmp->id->num == num))
799                         return dev_tmp;
800         }
801
802         return NULL;
803 }
804
805 /**
806  * Add specified device to the global device list.
807  *
808  * @param dev device to be added
809  */
810 static void device_add(struct mtd_device *dev)
811 {
812         u8 current_save_needed = 0;
813
814         if (list_empty(&devices)) {
815                 current_mtd_dev = dev;
816                 current_mtd_partnum = 0;
817                 current_save_needed = 1;
818         }
819
820         list_add_tail(&dev->link, &devices);
821
822         if (current_save_needed > 0)
823                 current_save();
824         else
825                 index_partitions();
826 }
827
828 /**
829  * Parse device type, name and mtd-id. If syntax is ok allocate memory and
830  * return pointer to the device structure.
831  *
832  * @param mtd_dev pointer to the device definition string i.e. <mtd-dev>
833  * @param ret output pointer to next char after parse completes (output)
834  * @param retdev pointer to the allocated device (output)
835  * Return: 0 on success, 1 otherwise
836  */
837 static int device_parse(const char *const mtd_dev, const char **ret, struct mtd_device **retdev)
838 {
839         struct mtd_device *dev;
840         struct part_info *part;
841         struct mtdids *id;
842         const char *mtd_id;
843         unsigned int mtd_id_len;
844         const char *p;
845         const char *pend;
846         LIST_HEAD(tmp_list);
847         struct list_head *entry, *n;
848         u16 num_parts;
849         u64 offset;
850         int err = 1;
851
852         debug("===device_parse===\n");
853
854         assert(retdev);
855         *retdev = NULL;
856
857         if (ret)
858                 *ret = NULL;
859
860         /* fetch <mtd-id> */
861         mtd_id = p = mtd_dev;
862         if (!(p = strchr(mtd_id, ':'))) {
863                 printf("no <mtd-id> identifier\n");
864                 return 1;
865         }
866         mtd_id_len = p - mtd_id + 1;
867         p++;
868
869         /* verify if we have a valid device specified */
870         if ((id = id_find_by_mtd_id(mtd_id, mtd_id_len - 1)) == NULL) {
871                 printf("invalid mtd device '%.*s'\n", mtd_id_len - 1, mtd_id);
872                 return 1;
873         }
874
875         pend = strchr(p, ';');
876         debug("dev type = %d (%s), dev num = %d, mtd-id = %s\n",
877                         id->type, MTD_DEV_TYPE(id->type),
878                         id->num, id->mtd_id);
879         debug("parsing partitions %.*s\n", (int)(pend ? pend - p : strlen(p)), p);
880
881         /* parse partitions */
882         num_parts = 0;
883
884         offset = 0;
885         if ((dev = device_find(id->type, id->num)) != NULL) {
886                 /* if device already exists start at the end of the last partition */
887                 part = list_entry(dev->parts.prev, struct part_info, link);
888                 offset = part->offset + part->size;
889         }
890
891         while (p && (*p != '\0') && (*p != ';')) {
892                 err = 1;
893                 if ((part_parse(p, &p, &part) != 0) || (!part))
894                         break;
895
896                 /* calculate offset when not specified */
897                 if (part->offset == OFFSET_NOT_SPECIFIED)
898                         part->offset = offset;
899                 else
900                         offset = part->offset;
901
902                 /* verify alignment and size */
903                 if (part_validate(id, part) != 0)
904                         break;
905
906                 offset += part->size;
907
908                 /* partition is ok, add it to the list */
909                 list_add_tail(&part->link, &tmp_list);
910                 num_parts++;
911                 err = 0;
912         }
913         if (err == 1) {
914                 part_delall(&tmp_list);
915                 return 1;
916         }
917
918         debug("\ntotal partitions: %d\n", num_parts);
919
920         /* check for next device presence */
921         if (p) {
922                 if (*p == ';') {
923                         if (ret)
924                                 *ret = ++p;
925                 } else if (*p == '\0') {
926                         if (ret)
927                                 *ret = p;
928                 } else {
929                         printf("unexpected character '%c' at the end of device\n", *p);
930                         if (ret)
931                                 *ret = NULL;
932                         return 1;
933                 }
934         }
935
936         /* allocate memory for mtd_device structure */
937         if ((dev = (struct mtd_device *)malloc(sizeof(struct mtd_device))) == NULL) {
938                 printf("out of memory\n");
939                 return 1;
940         }
941         memset(dev, 0, sizeof(struct mtd_device));
942         dev->id = id;
943         dev->num_parts = 0; /* part_sort_add increments num_parts */
944         INIT_LIST_HEAD(&dev->parts);
945         INIT_LIST_HEAD(&dev->link);
946
947         /* move partitions from tmp_list to dev->parts */
948         list_for_each_safe(entry, n, &tmp_list) {
949                 part = list_entry(entry, struct part_info, link);
950                 list_del(entry);
951                 if (part_sort_add(dev, part) != 0) {
952                         device_del(dev);
953                         return 1;
954                 }
955         }
956
957         *retdev = dev;
958
959         debug("===\n\n");
960         return 0;
961 }
962
963 /**
964  * Initialize global device list.
965  *
966  * Return: 0 on success, 1 otherwise
967  */
968 static int mtd_devices_init(void)
969 {
970         last_parts[0] = '\0';
971         current_mtd_dev = NULL;
972         current_save();
973
974         return device_delall(&devices);
975 }
976
977 /*
978  * Search global mtdids list and find id of requested type and number.
979  *
980  * Return: pointer to the id if it exists, NULL otherwise
981  */
982 static struct mtdids* id_find(u8 type, u8 num)
983 {
984         struct list_head *entry;
985         struct mtdids *id;
986
987         list_for_each(entry, &mtdids) {
988                 id = list_entry(entry, struct mtdids, link);
989
990                 if ((id->type == type) && (id->num == num))
991                         return id;
992         }
993
994         return NULL;
995 }
996
997 /**
998  * Search global mtdids list and find id of a requested mtd_id.
999  *
1000  * Note: first argument is not null terminated.
1001  *
1002  * @param mtd_id string containing requested mtd_id
1003  * @param mtd_id_len length of supplied mtd_id
1004  * Return: pointer to the id if it exists, NULL otherwise
1005  */
1006 static struct mtdids* id_find_by_mtd_id(const char *mtd_id, unsigned int mtd_id_len)
1007 {
1008         struct list_head *entry;
1009         struct mtdids *id;
1010
1011         debug("--- id_find_by_mtd_id: '%.*s' (len = %d)\n",
1012                         mtd_id_len, mtd_id, mtd_id_len);
1013
1014         list_for_each(entry, &mtdids) {
1015                 id = list_entry(entry, struct mtdids, link);
1016
1017                 debug("entry: '%s' (len = %zu)\n",
1018                                 id->mtd_id, strlen(id->mtd_id));
1019
1020                 if (mtd_id_len != strlen(id->mtd_id))
1021                         continue;
1022                 if (strncmp(id->mtd_id, mtd_id, mtd_id_len) == 0)
1023                         return id;
1024         }
1025
1026         return NULL;
1027 }
1028
1029 /**
1030  * Parse device id string <dev-id> := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>,
1031  * return device type and number.
1032  *
1033  * @param id string describing device id
1034  * @param ret_id output pointer to next char after parse completes (output)
1035  * @param dev_type parsed device type (output)
1036  * @param dev_num parsed device number (output)
1037  * Return: 0 on success, 1 otherwise
1038  */
1039 int mtd_id_parse(const char *id, const char **ret_id, u8 *dev_type,
1040                  u8 *dev_num)
1041 {
1042         const char *p = id;
1043
1044         *dev_type = 0;
1045         if (strncmp(p, "nand", 4) == 0) {
1046                 *dev_type = MTD_DEV_TYPE_NAND;
1047                 p += 4;
1048         } else if (strncmp(p, "nor", 3) == 0) {
1049                 *dev_type = MTD_DEV_TYPE_NOR;
1050                 p += 3;
1051         } else if (strncmp(p, "onenand", 7) == 0) {
1052                 *dev_type = MTD_DEV_TYPE_ONENAND;
1053                 p += 7;
1054         } else if (strncmp(p, "spi-nand", 8) == 0) {
1055                 *dev_type = MTD_DEV_TYPE_SPINAND;
1056                 p += 8;
1057         } else {
1058                 printf("incorrect device type in %s\n", id);
1059                 return 1;
1060         }
1061
1062         if (!isdigit(*p)) {
1063                 printf("incorrect device number in %s\n", id);
1064                 return 1;
1065         }
1066
1067         *dev_num = simple_strtoul(p, (char **)&p, 0);
1068         if (ret_id)
1069                 *ret_id = p;
1070         return 0;
1071 }
1072
1073 /**
1074  * Process all devices and generate corresponding mtdparts string describing
1075  * all partitions on all devices.
1076  *
1077  * @param buf output buffer holding generated mtdparts string (output)
1078  * @param buflen buffer size
1079  * Return: 0 on success, 1 otherwise
1080  */
1081 static int generate_mtdparts(char *buf, u32 buflen)
1082 {
1083         struct list_head *pentry, *dentry;
1084         struct mtd_device *dev;
1085         struct part_info *part, *prev_part;
1086         char *p = buf;
1087         char tmpbuf[32];
1088         u64 size, offset;
1089         u32 len, part_cnt;
1090         u32 maxlen = buflen - 1;
1091
1092         debug("--- generate_mtdparts ---\n");
1093
1094         if (list_empty(&devices)) {
1095                 buf[0] = '\0';
1096                 return 0;
1097         }
1098
1099         list_for_each(dentry, &devices) {
1100                 dev = list_entry(dentry, struct mtd_device, link);
1101
1102                 /* copy mtd_id */
1103                 len = strlen(dev->id->mtd_id) + 1;
1104                 if (len > maxlen)
1105                         goto cleanup;
1106                 memcpy(p, dev->id->mtd_id, len - 1);
1107                 p += len - 1;
1108                 *(p++) = ':';
1109                 maxlen -= len;
1110
1111                 /* format partitions */
1112                 prev_part = NULL;
1113                 part_cnt = 0;
1114                 list_for_each(pentry, &dev->parts) {
1115                         part = list_entry(pentry, struct part_info, link);
1116                         size = part->size;
1117                         offset = part->offset;
1118                         part_cnt++;
1119
1120                         /* partition size */
1121                         memsize_format(tmpbuf, size);
1122                         len = strlen(tmpbuf);
1123                         if (len > maxlen)
1124                                 goto cleanup;
1125                         memcpy(p, tmpbuf, len);
1126                         p += len;
1127                         maxlen -= len;
1128
1129                         /* add offset only when there is a gap between
1130                          * partitions */
1131                         if ((!prev_part && (offset != 0)) ||
1132                                         (prev_part && ((prev_part->offset + prev_part->size) != part->offset))) {
1133
1134                                 memsize_format(tmpbuf, offset);
1135                                 len = strlen(tmpbuf) + 1;
1136                                 if (len > maxlen)
1137                                         goto cleanup;
1138                                 *(p++) = '@';
1139                                 memcpy(p, tmpbuf, len - 1);
1140                                 p += len - 1;
1141                                 maxlen -= len;
1142                         }
1143
1144                         /* copy name only if user supplied */
1145                         if(!part->auto_name) {
1146                                 len = strlen(part->name) + 2;
1147                                 if (len > maxlen)
1148                                         goto cleanup;
1149
1150                                 *(p++) = '(';
1151                                 memcpy(p, part->name, len - 2);
1152                                 p += len - 2;
1153                                 *(p++) = ')';
1154                                 maxlen -= len;
1155                         }
1156
1157                         /* ro mask flag */
1158                         if (part->mask_flags && MTD_WRITEABLE_CMD) {
1159                                 len = 2;
1160                                 if (len > maxlen)
1161                                         goto cleanup;
1162                                 *(p++) = 'r';
1163                                 *(p++) = 'o';
1164                                 maxlen -= 2;
1165                         }
1166
1167                         /* print ',' separator if there are other partitions
1168                          * following */
1169                         if (dev->num_parts > part_cnt) {
1170                                 if (1 > maxlen)
1171                                         goto cleanup;
1172                                 *(p++) = ',';
1173                                 maxlen--;
1174                         }
1175                         prev_part = part;
1176                 }
1177                 /* print ';' separator if there are other devices following */
1178                 if (dentry->next != &devices) {
1179                         if (1 > maxlen)
1180                                 goto cleanup;
1181                         *(p++) = ';';
1182                         maxlen--;
1183                 }
1184         }
1185
1186         /* we still have at least one char left, as we decremented maxlen at
1187          * the begining */
1188         *p = '\0';
1189
1190         return 0;
1191
1192 cleanup:
1193         last_parts[0] = '\0';
1194         return 1;
1195 }
1196
1197 /**
1198  * Call generate_mtdparts to process all devices and generate corresponding
1199  * mtdparts string, save it in mtdparts environment variable.
1200  *
1201  * @param buf output buffer holding generated mtdparts string (output)
1202  * @param buflen buffer size
1203  * Return: 0 on success, 1 otherwise
1204  */
1205 static int generate_mtdparts_save(char *buf, u32 buflen)
1206 {
1207         int ret;
1208
1209         ret = generate_mtdparts(buf, buflen);
1210
1211         if ((buf[0] != '\0') && (ret == 0))
1212                 env_set("mtdparts", buf);
1213         else
1214                 env_set("mtdparts", NULL);
1215
1216         return ret;
1217 }
1218
1219 #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
1220 /**
1221  * Get the net size (w/o bad blocks) of the given partition.
1222  *
1223  * @param mtd the mtd info
1224  * @param part the partition
1225  * Return: the calculated net size of this partition
1226  */
1227 static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part)
1228 {
1229         uint64_t i, net_size = 0;
1230
1231         if (!mtd->_block_isbad)
1232                 return part->size;
1233
1234         for (i = 0; i < part->size; i += mtd->erasesize) {
1235                 if (!mtd->_block_isbad(mtd, part->offset + i))
1236                         net_size += mtd->erasesize;
1237         }
1238
1239         return net_size;
1240 }
1241 #endif
1242
1243 static void print_partition_table(void)
1244 {
1245         struct list_head *dentry, *pentry;
1246         struct part_info *part;
1247         struct mtd_device *dev;
1248         int part_num;
1249
1250         list_for_each(dentry, &devices) {
1251                 dev = list_entry(dentry, struct mtd_device, link);
1252                 /* list partitions for given device */
1253                 part_num = 0;
1254 #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
1255                 struct mtd_info *mtd;
1256
1257                 if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
1258                         return;
1259
1260                 printf("\ndevice %s%d <%s>, # parts = %d\n",
1261                                 MTD_DEV_TYPE(dev->id->type), dev->id->num,
1262                                 dev->id->mtd_id, dev->num_parts);
1263                 printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
1264
1265                 list_for_each(pentry, &dev->parts) {
1266                         u32 net_size;
1267                         char *size_note;
1268
1269                         part = list_entry(pentry, struct part_info, link);
1270                         net_size = net_part_size(mtd, part);
1271                         size_note = part->size == net_size ? " " : " (!)";
1272                         printf("%2d: %-20s0x%08llx\t0x%08x%s\t0x%08llx\t%d\n",
1273                                         part_num, part->name, part->size,
1274                                         net_size, size_note, part->offset,
1275                                         part->mask_flags);
1276 #else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
1277                 printf("\ndevice %s%d <%s>, # parts = %d\n",
1278                                 MTD_DEV_TYPE(dev->id->type), dev->id->num,
1279                                 dev->id->mtd_id, dev->num_parts);
1280                 printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
1281
1282                 list_for_each(pentry, &dev->parts) {
1283                         part = list_entry(pentry, struct part_info, link);
1284                         printf("%2d: %-20s0x%08llx\t0x%08llx\t%d\n",
1285                                         part_num, part->name, part->size,
1286                                         part->offset, part->mask_flags);
1287 #endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
1288                         part_num++;
1289                 }
1290         }
1291
1292         if (list_empty(&devices))
1293                 printf("no partitions defined\n");
1294 }
1295
1296 /**
1297  * Format and print out a partition list for each device from global device
1298  * list.
1299  */
1300 static void list_partitions(void)
1301 {
1302         struct part_info *part;
1303
1304         debug("\n---list_partitions---\n");
1305         print_partition_table();
1306
1307         /* current_mtd_dev is not NULL only when we have non empty device list */
1308         if (current_mtd_dev) {
1309                 part = mtd_part_info(current_mtd_dev, current_mtd_partnum);
1310                 if (part) {
1311                         printf("\nactive partition: %s%d,%d - (%s) 0x%08llx @ 0x%08llx\n",
1312                                         MTD_DEV_TYPE(current_mtd_dev->id->type),
1313                                         current_mtd_dev->id->num, current_mtd_partnum,
1314                                         part->name, part->size, part->offset);
1315                 } else {
1316                         printf("could not get current partition info\n\n");
1317                 }
1318         }
1319
1320         printf("\ndefaults:\n");
1321         printf("mtdids  : %s\n",
1322                 mtdids_default ? mtdids_default : "none");
1323         /*
1324          * Using printf() here results in printbuffer overflow
1325          * if default mtdparts string is greater than console
1326          * printbuffer. Use puts() to prevent system crashes.
1327          */
1328         puts("mtdparts: ");
1329         puts(mtdparts_default ? mtdparts_default : "none");
1330         puts("\n");
1331 }
1332
1333 /**
1334  * Given partition identifier in form of <dev_type><dev_num>,<part_num> find
1335  * corresponding device and verify partition number.
1336  *
1337  * @param id string describing device and partition or partition name
1338  * @param dev pointer to the requested device (output)
1339  * @param part_num verified partition number (output)
1340  * @param part pointer to requested partition (output)
1341  * Return: 0 on success, 1 otherwise
1342  */
1343 int find_dev_and_part(const char *id, struct mtd_device **dev,
1344                 u8 *part_num, struct part_info **part)
1345 {
1346         struct list_head *dentry, *pentry;
1347         u8 type, dnum, pnum;
1348         const char *p;
1349
1350         debug("--- find_dev_and_part ---\nid = %s\n", id);
1351
1352         list_for_each(dentry, &devices) {
1353                 *part_num = 0;
1354                 *dev = list_entry(dentry, struct mtd_device, link);
1355                 list_for_each(pentry, &(*dev)->parts) {
1356                         *part = list_entry(pentry, struct part_info, link);
1357                         if (strcmp((*part)->name, id) == 0)
1358                                 return 0;
1359                         (*part_num)++;
1360                 }
1361         }
1362
1363         p = id;
1364         *dev = NULL;
1365         *part = NULL;
1366         *part_num = 0;
1367
1368         if (mtd_id_parse(p, &p, &type, &dnum) != 0)
1369                 return 1;
1370
1371         if ((*p++ != ',') || (*p == '\0')) {
1372                 printf("no partition number specified\n");
1373                 return 1;
1374         }
1375         pnum = simple_strtoul(p, (char **)&p, 0);
1376         if (*p != '\0') {
1377                 printf("unexpected trailing character '%c'\n", *p);
1378                 return 1;
1379         }
1380
1381         if ((*dev = device_find(type, dnum)) == NULL) {
1382                 printf("no such device %s%d\n", MTD_DEV_TYPE(type), dnum);
1383                 return 1;
1384         }
1385
1386         if ((*part = mtd_part_info(*dev, pnum)) == NULL) {
1387                 printf("no such partition\n");
1388                 *dev = NULL;
1389                 return 1;
1390         }
1391
1392         *part_num = pnum;
1393
1394         return 0;
1395 }
1396
1397 /**
1398  * Find and delete partition. For partition id format see find_dev_and_part().
1399  *
1400  * @param id string describing device and partition
1401  * Return: 0 on success, 1 otherwise
1402  */
1403 static int delete_partition(const char *id)
1404 {
1405         u8 pnum;
1406         struct mtd_device *dev;
1407         struct part_info *part;
1408
1409         if (find_dev_and_part(id, &dev, &pnum, &part) == 0) {
1410
1411                 debug("delete_partition: device = %s%d, partition %d = (%s) 0x%08llx@0x%08llx\n",
1412                                 MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum,
1413                                 part->name, part->size, part->offset);
1414
1415                 if (part_del(dev, part) != 0)
1416                         return 1;
1417
1418                 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
1419                         printf("generated mtdparts too long, resetting to null\n");
1420                         return 1;
1421                 }
1422                 return 0;
1423         }
1424
1425         printf("partition %s not found\n", id);
1426         return 1;
1427 }
1428
1429 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
1430 /**
1431  * Increase the size of the given partition so that it's net size is at least
1432  * as large as the size member and such that the next partition would start on a
1433  * good block if it were adjacent to this partition.
1434  *
1435  * @param mtd the mtd device
1436  * @param part the partition
1437  * @param next_offset pointer to the offset of the next partition after this
1438  *                    partition's size has been modified (output)
1439  */
1440 static void spread_partition(struct mtd_info *mtd, struct part_info *part,
1441                              uint64_t *next_offset)
1442 {
1443         uint64_t net_size, padding_size = 0;
1444         int truncated;
1445
1446         mtd_get_len_incl_bad(mtd, part->offset, part->size, &net_size,
1447                              &truncated);
1448
1449         /*
1450          * Absorb bad blocks immediately following this
1451          * partition also into the partition, such that
1452          * the next partition starts with a good block.
1453          */
1454         if (!truncated) {
1455                 mtd_get_len_incl_bad(mtd, part->offset + net_size,
1456                                      mtd->erasesize, &padding_size, &truncated);
1457                 if (truncated)
1458                         padding_size = 0;
1459                 else
1460                         padding_size -= mtd->erasesize;
1461         }
1462
1463         if (truncated) {
1464                 printf("truncated partition %s to %lld bytes\n", part->name,
1465                        (uint64_t) net_size + padding_size);
1466         }
1467
1468         part->size = net_size + padding_size;
1469         *next_offset = part->offset + part->size;
1470 }
1471
1472 /**
1473  * Adjust all of the partition sizes, such that all partitions are at least
1474  * as big as their mtdparts environment variable sizes and they each start
1475  * on a good block.
1476  *
1477  * Return: 0 on success, 1 otherwise
1478  */
1479 static int spread_partitions(void)
1480 {
1481         struct list_head *dentry, *pentry;
1482         struct mtd_device *dev;
1483         struct part_info *part;
1484         struct mtd_info *mtd;
1485         int part_num;
1486         uint64_t cur_offs;
1487
1488         list_for_each(dentry, &devices) {
1489                 dev = list_entry(dentry, struct mtd_device, link);
1490
1491                 if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
1492                         return 1;
1493
1494                 part_num = 0;
1495                 cur_offs = 0;
1496                 list_for_each(pentry, &dev->parts) {
1497                         part = list_entry(pentry, struct part_info, link);
1498
1499                         debug("spread_partitions: device = %s%d, partition %d ="
1500                                 " (%s) 0x%08llx@0x%08llx\n",
1501                                 MTD_DEV_TYPE(dev->id->type), dev->id->num,
1502                                 part_num, part->name, part->size,
1503                                 part->offset);
1504
1505                         if (cur_offs > part->offset)
1506                                 part->offset = cur_offs;
1507
1508                         spread_partition(mtd, part, &cur_offs);
1509
1510                         part_num++;
1511                 }
1512         }
1513
1514         index_partitions();
1515
1516         if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
1517                 printf("generated mtdparts too long, resetting to null\n");
1518                 return 1;
1519         }
1520         return 0;
1521 }
1522 #endif /* CONFIG_CMD_MTDPARTS_SPREAD */
1523
1524 /**
1525  * The mtdparts variable tends to be long. If we need to access it
1526  * before the env is relocated, then we need to use our own stack
1527  * buffer.  gd->env_buf will be too small.
1528  *
1529  * @param buf temporary buffer pointer MTDPARTS_MAXLEN long
1530  * Return: mtdparts variable string, NULL if not found
1531  */
1532 static const char *env_get_mtdparts(char *buf)
1533 {
1534         if (gd->flags & GD_FLG_ENV_READY)
1535                 return env_get("mtdparts");
1536         if (env_get_f("mtdparts", buf, MTDPARTS_MAXLEN) != -1)
1537                 return buf;
1538         return NULL;
1539 }
1540
1541 /**
1542  * Accept character string describing mtd partitions and call device_parse()
1543  * for each entry. Add created devices to the global devices list.
1544  *
1545  * @param mtdparts string specifing mtd partitions
1546  * Return: 0 on success, 1 otherwise
1547  */
1548 static int parse_mtdparts(const char *const mtdparts)
1549 {
1550         const char *p;
1551         struct mtd_device *dev;
1552         int err = 1;
1553         char tmp_parts[MTDPARTS_MAXLEN];
1554
1555         debug("\n---parse_mtdparts---\nmtdparts = %s\n\n", mtdparts);
1556
1557         /* delete all devices and partitions */
1558         if (mtd_devices_init() != 0) {
1559                 printf("could not initialise device list\n");
1560                 return err;
1561         }
1562
1563         /* re-read 'mtdparts' variable, mtd_devices_init may be updating env */
1564         p = env_get_mtdparts(tmp_parts);
1565         if (!p)
1566                 p = mtdparts;
1567
1568         /* Skip the useless prefix, if any */
1569         if (strncmp(p, "mtdparts=", 9) == 0)
1570                 p += 9;
1571
1572         while (*p != '\0') {
1573                 err = 1;
1574                 if ((device_parse(p, &p, &dev) != 0) || (!dev))
1575                         break;
1576
1577                 debug("+ device: %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
1578                                 dev->id->num, dev->id->mtd_id);
1579
1580                 /* check if parsed device is already on the list */
1581                 if (device_find(dev->id->type, dev->id->num) != NULL) {
1582                         printf("device %s%d redefined, please correct mtdparts variable\n",
1583                                         MTD_DEV_TYPE(dev->id->type), dev->id->num);
1584                         break;
1585                 }
1586
1587                 list_add_tail(&dev->link, &devices);
1588                 err = 0;
1589         }
1590         if (err == 1) {
1591                 free(dev);
1592                 device_delall(&devices);
1593         }
1594
1595         return err;
1596 }
1597
1598 /**
1599  * Parse provided string describing mtdids mapping (see file header for mtdids
1600  * variable format). Allocate memory for each entry and add all found entries
1601  * to the global mtdids list.
1602  *
1603  * @param ids mapping string
1604  * Return: 0 on success, 1 otherwise
1605  */
1606 static int parse_mtdids(const char *const ids)
1607 {
1608         const char *p = ids;
1609         const char *mtd_id;
1610         int mtd_id_len;
1611         struct mtdids *id;
1612         struct list_head *entry, *n;
1613         struct mtdids *id_tmp;
1614         u8 type, num;
1615         u64 size;
1616         int ret = 1;
1617
1618         debug("\n---parse_mtdids---\nmtdids = %s\n\n", ids);
1619
1620         /* clean global mtdids list */
1621         list_for_each_safe(entry, n, &mtdids) {
1622                 id_tmp = list_entry(entry, struct mtdids, link);
1623                 debug("mtdids del: %d %d\n", id_tmp->type, id_tmp->num);
1624                 list_del(entry);
1625                 free(id_tmp);
1626         }
1627         last_ids[0] = '\0';
1628         INIT_LIST_HEAD(&mtdids);
1629
1630         while(p && (*p != '\0')) {
1631
1632                 ret = 1;
1633                 /* parse 'nor'|'nand'|'onenand'|'spi-nand'<dev-num> */
1634                 if (mtd_id_parse(p, &p, &type, &num) != 0)
1635                         break;
1636
1637                 if (*p != '=') {
1638                         printf("mtdids: incorrect <dev-num>\n");
1639                         break;
1640                 }
1641                 p++;
1642
1643                 /* check if requested device exists */
1644                 if (mtd_device_validate(type, num, &size) != 0)
1645                         return 1;
1646
1647                 /* locate <mtd-id> */
1648                 mtd_id = p;
1649                 if ((p = strchr(mtd_id, ',')) != NULL) {
1650                         mtd_id_len = p - mtd_id + 1;
1651                         p++;
1652                 } else {
1653                         mtd_id_len = strlen(mtd_id) + 1;
1654                 }
1655                 if (mtd_id_len == 0) {
1656                         printf("mtdids: no <mtd-id> identifier\n");
1657                         break;
1658                 }
1659
1660                 /* check if this id is already on the list */
1661                 int double_entry = 0;
1662                 list_for_each(entry, &mtdids) {
1663                         id_tmp = list_entry(entry, struct mtdids, link);
1664                         if ((id_tmp->type == type) && (id_tmp->num == num)) {
1665                                 double_entry = 1;
1666                                 break;
1667                         }
1668                 }
1669                 if (double_entry) {
1670                         printf("device id %s%d redefined, please correct mtdids variable\n",
1671                                         MTD_DEV_TYPE(type), num);
1672                         break;
1673                 }
1674
1675                 /* allocate mtdids structure */
1676                 if (!(id = (struct mtdids *)malloc(sizeof(struct mtdids) + mtd_id_len))) {
1677                         printf("out of memory\n");
1678                         break;
1679                 }
1680                 memset(id, 0, sizeof(struct mtdids) + mtd_id_len);
1681                 id->num = num;
1682                 id->type = type;
1683                 id->size = size;
1684                 id->mtd_id = (char *)(id + 1);
1685                 strncpy(id->mtd_id, mtd_id, mtd_id_len - 1);
1686                 id->mtd_id[mtd_id_len - 1] = '\0';
1687                 INIT_LIST_HEAD(&id->link);
1688
1689                 debug("+ id %s%d\t%16lld bytes\t%s\n",
1690                                 MTD_DEV_TYPE(id->type), id->num,
1691                                 id->size, id->mtd_id);
1692
1693                 list_add_tail(&id->link, &mtdids);
1694                 ret = 0;
1695         }
1696         if (ret == 1) {
1697                 /* clean mtdids list and free allocated memory */
1698                 list_for_each_safe(entry, n, &mtdids) {
1699                         id_tmp = list_entry(entry, struct mtdids, link);
1700                         list_del(entry);
1701                         free(id_tmp);
1702                 }
1703                 return 1;
1704         }
1705
1706         return 0;
1707 }
1708
1709 /**
1710  * Parse and initialize global mtdids mapping and create global
1711  * device/partition list.
1712  *
1713  * Return: 0 on success, 1 otherwise
1714  */
1715 int mtdparts_init(void)
1716 {
1717         static int initialized = 0;
1718         const char *ids, *parts;
1719         const char *current_partition;
1720         int ids_changed;
1721         char tmp_ep[PARTITION_MAXLEN + 1];
1722         char tmp_parts[MTDPARTS_MAXLEN];
1723
1724         debug("\n---mtdparts_init---\n");
1725         if (!initialized) {
1726                 INIT_LIST_HEAD(&mtdids);
1727                 INIT_LIST_HEAD(&devices);
1728                 memset(last_ids, 0, sizeof(last_ids));
1729                 memset(last_parts, 0, sizeof(last_parts));
1730                 memset(last_partition, 0, sizeof(last_partition));
1731 #if defined(CONFIG_SYS_MTDPARTS_RUNTIME)
1732                 board_mtdparts_default(&mtdids_default, &mtdparts_default);
1733 #endif
1734                 use_defaults = 1;
1735                 initialized = 1;
1736         }
1737
1738         /* get variables */
1739         ids = env_get("mtdids");
1740         parts = env_get_mtdparts(tmp_parts);
1741         current_partition = env_get("partition");
1742
1743         /* save it for later parsing, cannot rely on current partition pointer
1744          * as 'partition' variable may be updated during init */
1745         memset(tmp_parts, 0, sizeof(tmp_parts));
1746         memset(tmp_ep, 0, sizeof(tmp_ep));
1747         if (current_partition)
1748                 strncpy(tmp_ep, current_partition, PARTITION_MAXLEN);
1749
1750         debug("last_ids  : %s\n", last_ids);
1751         debug("env_ids   : %s\n", ids);
1752         debug("last_parts: %s\n", last_parts);
1753         debug("env_parts : %s\n\n", parts);
1754
1755         debug("last_partition : %s\n", last_partition);
1756         debug("env_partition  : %s\n", current_partition);
1757
1758         /* if mtdids variable is empty try to use defaults */
1759         if (!ids) {
1760                 if (mtdids_default) {
1761                         debug("mtdids variable not defined, using default\n");
1762                         ids = mtdids_default;
1763                         env_set("mtdids", (char *)ids);
1764                 } else {
1765                         printf("mtdids not defined, no default present\n");
1766                         return 1;
1767                 }
1768         }
1769         if (strlen(ids) > MTDIDS_MAXLEN - 1) {
1770                 printf("mtdids too long (> %d)\n", MTDIDS_MAXLEN);
1771                 return 1;
1772         }
1773
1774         /* use defaults when mtdparts variable is not defined
1775          * once mtdparts is saved environment, drop use_defaults flag */
1776         if (!parts) {
1777                 if (mtdparts_default && use_defaults) {
1778                         parts = mtdparts_default;
1779                         if (env_set("mtdparts", (char *)parts) == 0)
1780                                 use_defaults = 0;
1781                 } else
1782                         printf("mtdparts variable not set, see 'help mtdparts'\n");
1783         }
1784
1785         if (parts && (strlen(parts) > MTDPARTS_MAXLEN - 1)) {
1786                 printf("mtdparts too long (> %d)\n", MTDPARTS_MAXLEN);
1787                 return 1;
1788         }
1789
1790         /* check if we have already parsed those mtdids */
1791         if ((last_ids[0] != '\0') && (strcmp(last_ids, ids) == 0)) {
1792                 ids_changed = 0;
1793         } else {
1794                 ids_changed = 1;
1795
1796                 if (parse_mtdids(ids) != 0) {
1797                         mtd_devices_init();
1798                         return 1;
1799                 }
1800
1801                 /* ok it's good, save new ids */
1802                 strncpy(last_ids, ids, MTDIDS_MAXLEN);
1803         }
1804
1805         /* parse partitions if either mtdparts or mtdids were updated */
1806         if (parts && ((last_parts[0] == '\0') || ((strcmp(last_parts, parts) != 0)) || ids_changed)) {
1807                 if (parse_mtdparts(parts) != 0)
1808                         return 1;
1809
1810                 if (list_empty(&devices)) {
1811                         printf("mtdparts_init: no valid partitions\n");
1812                         return 1;
1813                 }
1814
1815                 /* ok it's good, save new parts */
1816                 strncpy(last_parts, parts, MTDPARTS_MAXLEN);
1817
1818                 /* reset first partition from first dev from the list as current */
1819                 current_mtd_dev = list_entry(devices.next, struct mtd_device, link);
1820                 current_mtd_partnum = 0;
1821                 current_save();
1822
1823                 debug("mtdparts_init: current_mtd_dev  = %s%d, current_mtd_partnum = %d\n",
1824                                 MTD_DEV_TYPE(current_mtd_dev->id->type),
1825                                 current_mtd_dev->id->num, current_mtd_partnum);
1826         }
1827
1828         /* mtdparts variable was reset to NULL, delete all devices/partitions */
1829         if (!parts && (last_parts[0] != '\0'))
1830                 return mtd_devices_init();
1831
1832         /* do not process current partition if mtdparts variable is null */
1833         if (!parts)
1834                 return 0;
1835
1836         /* is current partition set in environment? if so, use it */
1837         if ((tmp_ep[0] != '\0') && (strcmp(tmp_ep, last_partition) != 0)) {
1838                 struct part_info *p;
1839                 struct mtd_device *cdev;
1840                 u8 pnum;
1841
1842                 debug("--- getting current partition: %s\n", tmp_ep);
1843
1844                 if (find_dev_and_part(tmp_ep, &cdev, &pnum, &p) == 0) {
1845                         current_mtd_dev = cdev;
1846                         current_mtd_partnum = pnum;
1847                         current_save();
1848                 }
1849         } else if (env_get("partition") == NULL) {
1850                 debug("no partition variable set, setting...\n");
1851                 current_save();
1852         }
1853
1854         return 0;
1855 }
1856
1857 /**
1858  * Return pointer to the partition of a requested number from a requested
1859  * device.
1860  *
1861  * @param dev device that is to be searched for a partition
1862  * @param part_num requested partition number
1863  * Return: pointer to the part_info, NULL otherwise
1864  */
1865 static struct part_info* mtd_part_info(struct mtd_device *dev, unsigned int part_num)
1866 {
1867         struct list_head *entry;
1868         struct part_info *part;
1869         int num;
1870
1871         if (!dev)
1872                 return NULL;
1873
1874         debug("\n--- mtd_part_info: partition number %d for device %s%d (%s)\n",
1875                         part_num, MTD_DEV_TYPE(dev->id->type),
1876                         dev->id->num, dev->id->mtd_id);
1877
1878         if (part_num >= dev->num_parts) {
1879                 printf("invalid partition number %d for device %s%d (%s)\n",
1880                                 part_num, MTD_DEV_TYPE(dev->id->type),
1881                                 dev->id->num, dev->id->mtd_id);
1882                 return NULL;
1883         }
1884
1885         /* locate partition number, return it */
1886         num = 0;
1887         list_for_each(entry, &dev->parts) {
1888                 part = list_entry(entry, struct part_info, link);
1889
1890                 if (part_num == num++) {
1891                         return part;
1892                 }
1893         }
1894
1895         return NULL;
1896 }
1897
1898 /***************************************************/
1899 /* U-Boot commands                                 */
1900 /***************************************************/
1901 /* command line only */
1902 /**
1903  * Routine implementing u-boot chpart command. Sets new current partition based
1904  * on the user supplied partition id. For partition id format see find_dev_and_part().
1905  *
1906  * @param cmdtp command internal data
1907  * @param flag command flag
1908  * @param argc number of arguments supplied to the command
1909  * @param argv arguments list
1910  * Return: 0 on success, 1 otherwise
1911  */
1912 static int do_chpart(struct cmd_tbl *cmdtp, int flag, int argc,
1913                      char *const argv[])
1914 {
1915 /* command line only */
1916         struct mtd_device *dev;
1917         struct part_info *part;
1918         u8 pnum;
1919
1920         if (mtdparts_init() !=0)
1921                 return 1;
1922
1923         if (argc < 2) {
1924                 printf("no partition id specified\n");
1925                 return 1;
1926         }
1927
1928         if (find_dev_and_part(argv[1], &dev, &pnum, &part) != 0)
1929                 return 1;
1930
1931         current_mtd_dev = dev;
1932         current_mtd_partnum = pnum;
1933         current_save();
1934
1935         printf("partition changed to %s%d,%d\n",
1936                         MTD_DEV_TYPE(dev->id->type), dev->id->num, pnum);
1937
1938         return 0;
1939 }
1940
1941 /**
1942  * Routine implementing u-boot mtdparts command. Initialize/update default global
1943  * partition list and process user partition request (list, add, del).
1944  *
1945  * @param cmdtp command internal data
1946  * @param flag command flag
1947  * @param argc number of arguments supplied to the command
1948  * @param argv arguments list
1949  * Return: 0 on success, 1 otherwise
1950  */
1951 static int do_mtdparts(struct cmd_tbl *cmdtp, int flag, int argc,
1952                        char *const argv[])
1953 {
1954         if (argc == 2) {
1955                 if (strcmp(argv[1], "default") == 0) {
1956                         env_set("mtdids", NULL);
1957                         env_set("mtdparts", NULL);
1958                         env_set("partition", NULL);
1959                         use_defaults = 1;
1960
1961                         mtdparts_init();
1962                         return 0;
1963                 } else if (strcmp(argv[1], "delall") == 0) {
1964                         /* this may be the first run, initialize lists if needed */
1965                         mtdparts_init();
1966
1967                         env_set("mtdparts", NULL);
1968
1969                         /* mtd_devices_init() calls current_save() */
1970                         return mtd_devices_init();
1971                 }
1972         }
1973
1974         /* make sure we are in sync with env variables */
1975         if (mtdparts_init() != 0)
1976                 return 1;
1977
1978         if (argc == 1) {
1979                 list_partitions();
1980                 return 0;
1981         }
1982
1983         /* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
1984         if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
1985 #define PART_ADD_DESC_MAXLEN 64
1986                 char tmpbuf[PART_ADD_DESC_MAXLEN];
1987 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
1988                 struct mtd_info *mtd;
1989                 uint64_t next_offset;
1990 #endif
1991                 u8 type, num, len;
1992                 struct mtd_device *dev;
1993                 struct mtd_device *dev_tmp;
1994                 struct mtdids *id;
1995                 struct part_info *p;
1996
1997                 if (mtd_id_parse(argv[2], NULL, &type, &num) != 0)
1998                         return 1;
1999
2000                 if ((id = id_find(type, num)) == NULL) {
2001                         printf("no such device %s defined in mtdids variable\n", argv[2]);
2002                         return 1;
2003                 }
2004
2005                 len = strlen(id->mtd_id) + 1;   /* 'mtd_id:' */
2006                 len += strlen(argv[3]);         /* size@offset */
2007                 len += strlen(argv[4]) + 2;     /* '(' name ')' */
2008                 if (argv[5] && (strlen(argv[5]) == 2))
2009                         len += 2;               /* 'ro' */
2010
2011                 if (len >= PART_ADD_DESC_MAXLEN) {
2012                         printf("too long partition description\n");
2013                         return 1;
2014                 }
2015                 sprintf(tmpbuf, "%s:%s(%s)%s",
2016                                 id->mtd_id, argv[3], argv[4], argv[5] ? argv[5] : "");
2017                 debug("add tmpbuf: %s\n", tmpbuf);
2018
2019                 if ((device_parse(tmpbuf, NULL, &dev) != 0) || (!dev))
2020                         return 1;
2021
2022                 debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
2023                                 dev->id->num, dev->id->mtd_id);
2024
2025                 p = list_entry(dev->parts.next, struct part_info, link);
2026
2027 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
2028                 if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
2029                         return 1;
2030
2031                 if (!strcmp(&argv[1][3], ".spread")) {
2032                         spread_partition(mtd, p, &next_offset);
2033                         debug("increased %s to %llu bytes\n", p->name, p->size);
2034                 }
2035 #endif
2036
2037                 dev_tmp = device_find(dev->id->type, dev->id->num);
2038                 if (dev_tmp == NULL) {
2039                         device_add(dev);
2040                 } else if (part_add(dev_tmp, p) != 0) {
2041                         /* merge new partition with existing ones*/
2042                         device_del(dev);
2043                         return 1;
2044                 }
2045
2046                 if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
2047                         printf("generated mtdparts too long, resetting to null\n");
2048                         return 1;
2049                 }
2050
2051                 return 0;
2052         }
2053
2054         /* mtdparts del part-id */
2055         if ((argc == 3) && (strcmp(argv[1], "del") == 0)) {
2056                 debug("del: part-id = %s\n", argv[2]);
2057
2058                 return delete_partition(argv[2]);
2059         }
2060
2061 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
2062         if ((argc == 2) && (strcmp(argv[1], "spread") == 0))
2063                 return spread_partitions();
2064 #endif /* CONFIG_CMD_MTDPARTS_SPREAD */
2065
2066         return CMD_RET_USAGE;
2067 }
2068
2069 /***************************************************/
2070 U_BOOT_CMD(
2071         chpart, 2,      0,      do_chpart,
2072         "change active partition of a MTD device",
2073         "part-id\n"
2074         "    - change active partition (e.g. part-id = nand0,1) of a MTD device"
2075 );
2076
2077 U_BOOT_LONGHELP(mtdparts,
2078         "\n"
2079         "    - list partition table\n"
2080         "mtdparts delall\n"
2081         "    - delete all partitions\n"
2082         "mtdparts del part-id\n"
2083         "    - delete partition (e.g. part-id = nand0,1)\n"
2084         "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
2085         "    - add partition\n"
2086 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
2087         "mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
2088         "    - add partition, padding size by skipping bad blocks\n"
2089 #endif
2090         "mtdparts default\n"
2091         "    - reset partition table to defaults\n"
2092 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
2093         "mtdparts spread\n"
2094         "    - adjust the sizes of the partitions so they are\n"
2095         "      at least as big as the mtdparts variable specifies\n"
2096         "      and they each start on a good block\n\n"
2097 #else
2098         "\n"
2099 #endif /* CONFIG_CMD_MTDPARTS_SPREAD */
2100         "-----\n\n"
2101         "this command uses three environment variables:\n\n"
2102         "'partition' - keeps current partition identifier\n\n"
2103         "partition  := <part-id>\n"
2104         "<part-id>  := <dev-id>,part_num\n\n"
2105         "'mtdids' - linux kernel mtd device id <-> u-boot device id mapping\n\n"
2106         "mtdids=<idmap>[,<idmap>,...]\n\n"
2107         "<idmap>    := <dev-id>=<mtd-id>\n"
2108         "<dev-id>   := 'nand'|'nor'|'onenand'|'spi-nand'<dev-num>\n"
2109         "<dev-num>  := mtd device number, 0...\n"
2110         "<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n\n"
2111         "'mtdparts' - partition list\n\n"
2112         "mtdparts=mtdparts=<mtd-def>[;<mtd-def>...]\n\n"
2113         "<mtd-def>  := <mtd-id>:<part-def>[,<part-def>...]\n"
2114         "<mtd-id>   := unique device tag used by linux kernel to find mtd device (mtd->name)\n"
2115         "<part-def> := <size>[@<offset>][<name>][<ro-flag>]\n"
2116         "<size>     := standard linux memsize OR '-' to denote all remaining space\n"
2117         "<offset>   := partition start offset within the device\n"
2118         "<name>     := '(' NAME ')'\n"
2119         "<ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)");
2120
2121 U_BOOT_CMD(
2122         mtdparts,       6,      0,      do_mtdparts,
2123         "define flash/nand partitions", mtdparts_help_text
2124 );
2125 /***************************************************/