[U-Boot] [PATCH 3/3] Create bad block aware partition table

Rohit Hagargundgi h.rohit at samsung.com
Thu Dec 11 15:28:42 CET 2008


The idea and most of the code is from the following thread
	http://lists.denx.de/pipermail/u-boot/2008-July/036604.html

The idea is that existing bad blocks can reduce the usable size in the partition.
User defines partition table only once but bad blocks are different on different chips.

The following command creates a new partition table based on 'mtdparts' variable
so that the usable size in the partition remains as desired by the user.
This is done by adding a good block to the partition for every bad block.
The last partition will bear the penalty for the bad blocks.

The new partition table is stored in environment variable 'newmtdparts'.

Signed-off-by: Rohit Hagargundgi <h.rohit at samsung.com>
---
 common/cmd_onenand.c |  151 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 151 insertions(+), 0 deletions(-)

diff --git a/common/cmd_onenand.c b/common/cmd_onenand.c
index e4e933c..8c687f2 100644
--- a/common/cmd_onenand.c
+++ b/common/cmd_onenand.c
@@ -23,8 +23,20 @@ extern struct onenand_chip onenand_chip;
 
 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
 
+#include <malloc.h>
 #include <jffs2/jffs2.h>
 
+#define MTDPARTS_MAXLEN		512
+
+/* this flag needs to be set in part_info struct mask_flags
+ * field for read-only partitions */
+#define MTD_WRITEABLE_CMD		1
+
+/* Name of last SLC partition of Flex-OneNAND
+ * Used when rebuilding a partition.
+ * For OneNAND, it is name of first partition.
+ */
+static char* last_slc_partition;
 /* parition handling routines */
 int mtdparts_init(void);
 int find_dev_and_part(const char *id, struct mtd_device **dev,
@@ -204,6 +216,136 @@ readout:
 	printf("Done\n");
 	return 0;
 }
+
+/*
+ *rebuild_partition - 	Build new partition information for this partition
+ *			based on bad blocks present in it.
+ * @param mtd		MTD info structure
+ * @param part		partition info structure
+ * @param mtdparts	new partition information will be appended to this string
+ * @param cur_offs	Current offset in flash
+ */
+static unsigned rebuild_partition(struct mtd_info *mtd, struct part_info *part, char *mtdparts, unsigned cur_offs)
+{
+	unsigned int bb_delta = 0, erasesize = 0, bbcount = 0;
+	unsigned int offs, ro = 0;
+	char mtdpart[32];
+	unsigned partsize = part->size, last_partition = 0;
+	int parterasesize;
+
+	/* Flex-OneNAND support */
+	if (mtd->eraseregions) {
+		struct mtd_device *dev;
+		struct part_info *p;
+		u8 pnum;
+		struct onenand_chip *this = mtd->priv;
+
+		find_dev_and_part(last_slc_partition, &dev, &pnum, &p);
+
+		/*
+		 * parterasesize indicates eventual block size for this partition.
+		 * For all partitions which will be configured as SLC, partition
+		 * size is increased by SLC block size for every bad block.
+		 * For all partitions which will be configured as MLC, partition
+		 * size is increased by MLC block size for every bad block.
+		 */
+		if (part->offset > p->offset)
+			/* This partition will lie in MLC area */
+			parterasesize = 1 << this->erase_shift;
+		else
+			/* This partition will lie in SLC area */
+			parterasesize = 1 << (this->erase_shift - 1);
+	} else
+		parterasesize = mtd->erasesize;
+
+	for (offs = cur_offs; offs < cur_offs + partsize + bb_delta; offs += erasesize) {
+		if (offs == mtd->size)
+			/* This is the last partition */
+			break;
+		erasesize = get_erasesize(mtd, offs);
+		if (mtd->block_isbad(mtd, offs)) {
+			bb_delta += parterasesize;
+			bbcount++;
+		}
+	}
+
+	/*
+	 * Absorb bad blocks immediately following this partition also
+	 * into the partition, in order to make next partition start
+	 * with a good block.
+	 */
+	while (offs < mtd->size && mtd->block_isbad(mtd, offs)) {
+		erasesize = get_erasesize(mtd, offs);
+		bb_delta += parterasesize;
+		offs += erasesize;
+		bbcount++;
+	}
+
+	/* Fix partition size of last partition */
+	if (cur_offs + partsize + bb_delta >= mtd->size) {
+		partsize = mtd->size - cur_offs - bb_delta;
+		last_partition = 1;
+	}
+
+	printf(" %-20s  %-20u %d KB\n", part->name, bbcount,
+		 ((int) (partsize + bb_delta - part->size)/ 1024));
+
+	cur_offs += partsize + bb_delta;
+	if (part->mask_flags && MTD_WRITEABLE_CMD)
+		ro = 1;
+
+	if (last_partition)
+		sprintf(mtdpart, "-(%.16s)%s,", part->name, ro ? "ro" : "");
+	else
+		sprintf(mtdpart, "0x%.8x(%.16s)%s,", partsize + bb_delta,
+					part->name, ro ? "ro" : "");
+
+	mtdpart[sizeof(mtdpart) - 1] = '\0';
+	strncat(mtdparts, mtdpart, MTDPARTS_MAXLEN - strlen(mtdparts) - 1);
+	return cur_offs;
+}
+
+static int rebuild_mtdparts(char *part_name)
+{
+	struct mtd_info *mtd = &onenand_mtd;
+	char *newmtdparts;
+	struct list_head *entry;
+	unsigned cur_offs = 0;
+	struct mtd_device *dev;
+	struct part_info *p;
+	u8 pnum;
+
+	/* Check if partition table information is available */
+	if (mtdparts_init())
+		return -1;
+
+	/* For Flex-OneNAND, in addition to partition table,
+	 * last desired SLC partition information is also required.
+	 * User inputs last SLC partition name as parameter
+	 */
+	if (find_dev_and_part(part_name, &dev, &pnum, &p))
+		return -1;
+	last_slc_partition = part_name;
+
+	newmtdparts = malloc(MTDPARTS_MAXLEN);
+	if (!newmtdparts)
+		return -1;
+	sprintf(newmtdparts, "mtdparts=onenand:");
+
+	printf("%-20s  %-20s %-20s\n", " Partition Name", "Bad Blocks Count", "Partition Size Change");
+
+	list_for_each(entry, &dev->parts) {
+		p = list_entry(entry, struct part_info, link);
+		cur_offs = rebuild_partition(mtd, p, newmtdparts, cur_offs);
+	}
+
+	newmtdparts[strlen(newmtdparts) - 1] = '\0';
+	printf("\nnewmtdparts: %s\n", newmtdparts);
+	setenv("newmtdparts", newmtdparts);
+	free(newmtdparts);
+	return 0;
+}
+
 #endif
 
 /**
@@ -440,6 +582,10 @@ int do_onenand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 			}
 			return 0;
 		}
+
+		if (strcmp(argv[1], "rebuild") == 0)
+			/* Generate new mtdparts string taking care of bad blocks */
+			return rebuild_mtdparts(argv[2]);
 #endif
 		if (strncmp(argv[1], "setboundary", 11) == 0) {
 			unsigned die = simple_strtoul(argv[2], NULL, 0);
@@ -471,6 +617,11 @@ U_BOOT_CMD(
 	"onenand setboundary DIE BOUNDARY [LOCK] - "
 	"Change SLC boundary of Flex-OneNAND\n"
 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
+	"onenand rebuild <part-name>\n"
+	"    - create new partition table based on mtdparts taking care of bad blocks.\n"
+	"      For OneNAND, part-name is first partition name.\n"
+	"      For Flex-OneNAND, part-name is last SLC partition name.\n"
+	"      The new partition table is stored in environment variable newmtdparts\n"
 	"onenand partread <part-name> <addr> <len>\n"
 	"    - read image from  partition with length len to addr\n"
 	"onenand partwrite <part-name> <addr> <len>\n"
-- 
1.5.4.3



More information about the U-Boot mailing list