]> git.sur5r.net Git - u-boot/blobdiff - common/cmd_mtdparts.c
mtdparts: add new sub-command "spread"
[u-boot] / common / cmd_mtdparts.c
index 266844f14604a1488f634aefb6f440bdede3fbe3..347e40997a90f13fc9415f5d29217ef0d5acd66b 100644 (file)
@@ -15,6 +15,9 @@
  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
  *   kernel tree.
  *
+ * (C) Copyright 2008
+ * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org>
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -1424,6 +1427,101 @@ static int delete_partition(const char *id)
        return 1;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+/**
+ * Increase the size of the given partition so that it's net size is at least
+ * as large as the size member and such that the next partition would start on a
+ * good block if it were adjacent to this partition.
+ *
+ * @param mtd the mtd device
+ * @param part the partition
+ * @param next_offset pointer to the offset of the next partition after this
+ *                    partition's size has been modified (output)
+ */
+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+                            uint64_t *next_offset)
+{
+       uint64_t net_size, padding_size = 0;
+       int truncated;
+
+       mtd_get_len_incl_bad(mtd, part->offset, part->size, &net_size,
+                            &truncated);
+
+       /*
+        * Absorb bad blocks immediately following this
+        * partition also into the partition, such that
+        * the next partition starts with a good block.
+        */
+       if (!truncated) {
+               mtd_get_len_incl_bad(mtd, part->offset + net_size,
+                                    mtd->erasesize, &padding_size, &truncated);
+               if (truncated)
+                       padding_size = 0;
+               else
+                       padding_size -= mtd->erasesize;
+       }
+
+       if (truncated) {
+               printf("truncated partition %s to %lld bytes\n", part->name,
+                      (uint64_t) net_size + padding_size);
+       }
+
+       part->size = net_size + padding_size;
+       *next_offset = part->offset + part->size;
+}
+
+/**
+ * Adjust all of the partition sizes, such that all partitions are at least
+ * as big as their mtdparts environment variable sizes and they each start
+ * on a good block.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int spread_partitions(void)
+{
+       struct list_head *dentry, *pentry;
+       struct mtd_device *dev;
+       struct part_info *part;
+       struct mtd_info *mtd;
+       int part_num;
+       uint64_t cur_offs;
+
+       list_for_each(dentry, &devices) {
+               dev = list_entry(dentry, struct mtd_device, link);
+
+               if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+                       return 1;
+
+               part_num = 0;
+               cur_offs = 0;
+               list_for_each(pentry, &dev->parts) {
+                       part = list_entry(pentry, struct part_info, link);
+
+                       debug("spread_partitions: device = %s%d, partition %d ="
+                               " (%s) 0x%08x@0x%08x\n",
+                               MTD_DEV_TYPE(dev->id->type), dev->id->num,
+                               part_num, part->name, part->size,
+                               part->offset);
+
+                       if (cur_offs > part->offset)
+                               part->offset = cur_offs;
+
+                       spread_partition(mtd, part, &cur_offs);
+
+                       part_num++;
+               }
+       }
+
+       index_partitions();
+
+       if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
+               printf("generated mtdparts too long, reseting to null\n");
+               return 1;
+       }
+       return 0;
+}
+#endif /* CONFIG_CMD_MTDPARTS_SPREAD */
+
 /**
  * Accept character string describing mtd partitions and call device_parse()
  * for each entry. Add created devices to the global devices list.
@@ -1914,6 +2012,11 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
                return delete_partition(argv[2]);
        }
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+       if ((argc == 2) && (strcmp(argv[1], "spread") == 0))
+               return spread_partitions();
+#endif /* CONFIG_CMD_MTDPARTS_SPREAD */
+
        return cmd_usage(cmdtp);
 }
 
@@ -1937,7 +2040,15 @@ U_BOOT_CMD(
        "mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
        "    - add partition\n"
        "mtdparts default\n"
-       "    - reset partition table to defaults\n\n"
+       "    - reset partition table to defaults\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+       "mtdparts spread\n"
+       "    - adjust the sizes of the partitions so they are\n"
+       "      at least as big as the mtdparts variable specifies\n"
+       "      and they each start on a good block\n\n"
+#else
+       "\n"
+#endif /* CONFIG_CMD_MTDPARTS_SPREAD */
        "-----\n\n"
        "this command uses three environment variables:\n\n"
        "'partition' - keeps current partition identifier\n\n"