Skip to contentSkip to conversation

Support dynamic/patched NAND ENV offset

PATCH RESEND Superseded Harald Welte 7 participants 104 messages Jul 6, 2008 – Sep 18, 2010 1 message not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Hi!

I've first sent this on Feb 17, 2007. Unfortunately no reply was received. I think this is a quite useful feature, since a compile time offset into the NAND flash for the environment just doesn't work well with bad blocks ;)

This is the current version of the patch. I'd love to see it included. Thanks!

---

This patch adds support for CFG_ENV_OFFSET_PATCHED and CFG_ENV_OFFSET_OOB.

Both try to solve the problem of fixing the environment location in NAND flash at compile time, which doesn't work well if the NAND flash has a bad block at exactly that location.

CFG_ENV_OFFSET_PATCHED puts the environment in a global variable. You can then use the linker script to put that variable to a fixed location in the u-boot image. Then you can use bianry patching during the production flash process.

The idea of CFG_ENV_OFFSET_OOB is to store the environment offset in the NAND OOB data of block 0. We can do this in case the vendor makes a guarantee that block 0 never is a factory-default bad block.

common/Makefile +1 -0
Index: u-boot/common/Makefile
===================================================================
@@ -55,6 +55,7 @@
 COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o
 COBJS-$(CONFIG_CMD_DOC) += cmd_doc.o
 COBJS-$(CONFIG_CMD_DTT) += cmd_dtt.o
+COBJS-y += cmd_dynenv.o
 COBJS-y += cmd_eeprom.o
 COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
 COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
common/cmd_dynenv.c new file +106 -0

106 lines not on this page · raw message

common/env_nand.c +27 -0
Index: u-boot/common/env_nand.c
===================================================================
@@ -292,6 +292,33 @@
 	int crc1_ok = 0, crc2_ok = 0;
 	env_t *tmp_env1, *tmp_env2;
 
+#if defined(CFG_ENV_OFFSET_OOB)
+	struct mtd_info *mtd = &nand_info[0];
+	struct nand_chip *this = mtd->priv;
+	int buf_len;
+	uint8_t *buf;
+
+	buf_len = (1 << this->bbt_erase_shift);
+	buf_len += (buf_len >> this->page_shift) * mtd->oobsize;
+	buf = malloc(buf_len);
+	if (!buf)
+		return;
+
+	nand_read_raw(mtd, buf, 0, mtd->oobblock, mtd->oobsize);
+	if (buf[mtd->oobblock + 8 + 0] == 'E' &&
+	    buf[mtd->oobblock + 8 + 1] == 'N' &&
+	    buf[mtd->oobblock + 8 + 2] == 'V' &&
+	    buf[mtd->oobblock + 8 + 3] == '0') {
+		CFG_ENV_OFFSET = *((unsigned long *) &buf[mtd->oobblock + 8 + 4]);
+		/* fall through to the normal environment reading code below */
+		free(buf);
+		puts("Found Environment offset in OOB..\n");
+	} else {
+		free(buf);
+		return use_default();
+	}
+#endif
+
 	total = CFG_ENV_SIZE;
 
 	tmp_env1 = (env_t *) malloc(CFG_ENV_SIZE);
common/environment.c +6 -0
Index: u-boot/common/environment.c
===================================================================
@@ -29,6 +29,12 @@
 #undef	__ASSEMBLY__
 #include <environment.h>
 
+#if defined(CFG_ENV_OFFSET_PATCHED)
+unsigned long env_offset = CFG_ENV_OFFSET_PATCHED;
+#elif defined(CFG_ENV_OFFSET_OOB)
+unsigned long env_offset = CFG_ENV_OFFSET_OOB;
+#endif
+
 /*
  * Handle HOSTS that have prepended
  * crap on symbol names, not TARGETS.
include/environment.h +5 -0
Index: u-boot/include/environment.h
===================================================================
@@ -70,6 +70,10 @@
 #endif	/* CFG_ENV_IS_IN_FLASH */
 
 #if defined(CFG_ENV_IS_IN_NAND)
+#if defined(CFG_ENV_OFFSET_PATCHED) || defined(CFG_ENV_OFFSET_OOB)
+extern unsigned long env_offset;
+#define CFG_ENV_OFFSET env_offset
+#else
 # ifndef CFG_ENV_OFFSET
 #  error "Need to define CFG_ENV_OFFSET when using CFG_ENV_IS_IN_NAND"
 # endif
@@ -82,6 +86,7 @@
 # ifdef CFG_ENV_IS_EMBEDDED
 #  define ENV_IS_EMBEDDED	1
 # endif
+#endif /* CFG_ENV_NAND_PATCHED */
 #endif /* CFG_ENV_IS_IN_NAND */
 
 #ifdef USE_HOSTCC
common/cmd_nand.h new file +33 -0
Index: u-boot/common/cmd_nand.h
===================================================================
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef CMD_NAND_H
+#define CMD_NAND_H
+
+#include <nand.h>
+
+
+/* common/cmd_nand.c */
+int arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off,
+  ulong *size);
+
+#endif /* CMD_NAND_H */
common/cmd_nand.c +1 -1
Index: u-boot/common/cmd_nand.c
===================================================================
@@ -90,7 +90,7 @@
 	return (*p != '\0' && *endptr == '\0') ? 1 : 0;
 }
 
-static int
+int
 arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
 {
 	int idx = nand_curr_device;
Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#1 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 4 lines · Harald Welte

I've first sent this on Feb 17, 2007. Unfortunately no reply was received. I think this is a quite useful feature, since a compile time offset into the NAND flash for the environment just doesn't work well with bad blocks ;)

It works if you allow room for bad blocks within each partition, and treat the environment as its own partition. Current u-boot supports skipping bad blocks within a desginated environment region.

-Scott

#2 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 9 lines · Scott Wood
Quoted 4 lines · Harald Welte

I've first sent this on Feb 17, 2007. Unfortunately no reply was received. I think this is a quite useful feature, since a compile time offset into the NAND flash for the environment just doesn't work well with bad blocks ;)

It works if you allow room for bad blocks within each partition, and treat the environment as its own partition. Current u-boot supports skipping bad blocks within a desginated environment region.

which wastes a lot of space, if you have something like a 128kByte erase-block-size (like most 2kByte page size NAND's today)... so if you want to have redundancy and use some spare blocks you will end up with something on the order of 512kByte of wasted flash space to store a couple of hundreds of bytes environment. Not very elegant.

Furthermore, if you want to make sure it always works with any of your components that are within the spec of the manufacturer, then you will waste even more. The problem is that a new virgin component e.g. a 64MByte flash from Samsung can have already as many as 1.3MBytes of bad blocks. There is no guarantee that they are all within one of your partitions. So to only cope with factory bad blocks, you would have to have 1.3MBytes of spare space in each of your partitions! Don't you think that's a bit too much waste of space? (you can read the full rationale at http://wiki.openmoko.org/wiki/NAND_bad_blocks)

So I'd say that having the address of the environment block stored in the out-of-band area of the first block (which is always guaranteed to be good by the manufacturer) sounds like a much more elegant solution.

Therefore, I still believe that such a feature is useful and should be merged into u-boot. If there are problems with my particular implementation, I'm happy to address them.

I also have another patchset for what I call 'dynpart' support, i.e. the dynamic calculation of a unit-specific partition table that ensures the net size of partitions are as per spec, no matter how many of the factory default blocks are located where. So it would even support NAND devices with a worse spec than the ones that we were using.

Cheers,

Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#3 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 11 lines · Harald Welte
Quoted 3 lines · Scott Wood

It works if you allow room for bad blocks within each partition, and treat the environment as its own partition. Current u-boot supports skipping bad blocks within a desginated environment region.

which wastes a lot of space, if you have something like a 128kByte erase-block-size (like most 2kByte page size NAND's today)... so if you want to have redundancy and use some spare blocks you will end up with something on the order of 512kByte of wasted flash space to store a couple of hundreds of bytes environment. Not very elegant.

Quoted 5 lines

Furthermore, if you want to make sure it always works with any of your components that are within the spec of the manufacturer, then you will waste even more. The problem is that a new virgin component e.g. a 64MByte flash from Samsung can have already as many as 1.3MBytes of bad blocks.

Fair enough...

Quoted 3 lines

Therefore, I still believe that such a feature is useful and should be merged into u-boot. If there are problems with my particular implementation, I'm happy to address them.

Can you base it off of the testing branch of the u-boot-nand-flash repo?

Quoted 5 lines

I also have another patchset for what I call 'dynpart' support, i.e. the dynamic calculation of a unit-specific partition table that ensures the net size of partitions are as per spec, no matter how many of the factory default blocks are located where. So it would even support NAND devices with a worse spec than the ones that we were using.

Interesting... Would such a patch eliminate the need for this one, by making the environment a dynamic partition? Is there any (plan for) Linux support?

-Scott

#4 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 10 lines · In message <[email protected]> you wrote:
Quoted 6 lines

I also have another patchset for what I call 'dynpart' support, i.e. the dynamic calculation of a unit-specific partition table that ensures the net size of partitions are as per spec, no matter how many of the factory default blocks are located where. So it would even support NAND devices with a worse spec than the ones that we were using.

Interesting... Would such a patch eliminate the need for this one, by making the environment a dynamic partition? Is there any (plan for) Linux support?

What's the relation of this to the mtdparts handling in U-Boot and Linux?

Best regards,

Wolfgang Denk

Signature · 4 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Mistakes are often the stepping stones to utter failure.
#5 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 8 lines · Wolfgang Denk
Quoted 7 lines · In message <[email protected]> you wrote:
Quoted 6 lines

I also have another patchset for what I call 'dynpart' support, i.e. the dynamic calculation of a unit-specific partition table that ensures the net size of partitions are as per spec, no matter how many of the factory default blocks are located where. So it would even support NAND devices with a worse spec than the ones that we were using.

Quoted 6 lines
Quoted 3 lines

Interesting... Would such a patch eliminate the need for this one, by making the environment a dynamic partition? Is there any (plan for) Linux support?

What's the relation of this to the mtdparts handling in U-Boot and Linux?

see my other mail in this thread (just posted).

More precisely, the flow of events in a full dynenv + dynpart setup (like the three openmoko devices so far) is:

1) u-boot creates a bad block table as part of the production process of the device
2) afterwards, the device-unique partition table is created (net partition sizes as per board-level spec), including an environment partition.
3) the standard regular partition table is stored in the environment
4) the environment including the mtdparts variable is saved to the env partition
5) the nand flash offset to the environment partition is stored in the out-of-band area of the first (known-always-good) nand flash block

During boot, the regular mechanism of passing 'mtdparts' to the kernel is used.

This was the most elegant scheme that I could come up with to support a large number of factory-bad blocks at any given location in the flash while still keeping the amount of overhead per partition low.

Cheers,

Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#6 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 9 lines · In message <[email protected]> you wrote:

More precisely, the flow of events in a full dynenv + dynpart setup (like the three openmoko devices so far) is:

1) u-boot creates a bad block table as part of the production process of the device
2) afterwards, the device-unique partition table is created (net partition sizes as per board-level spec), including an environment partition.

How do you "create" the partition table? Do you use the "mtdparts" command for this?

Quoted 1 line

3) the standard regular partition table is stored in the environment

How do you store it? In the same way as "mtdparts" is working?

Best regards,

Wolfgang Denk

Signature · 6 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
... Jesus cried with a loud voice: Lazarus, come forth; the bug  hath
been  found  and  thy  program  runneth.  And  he  that was dead came
forth...                              -- John 11:43-44 [version 2.0?]
#7 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 5 lines · Wolfgang Denk
Quoted 4 lines · In message <[email protected]> you wrote:

More precisely, the flow of events in a full dynenv + dynpart setup (like the three openmoko devices so far) is:

Quoted 8 lines
Quoted 5 lines

1) u-boot creates a bad block table as part of the production process of the device
2) afterwards, the device-unique partition table is created (net partition sizes as per board-level spec), including an environment partition.

How do you "create" the partition table? Do you use the "mtdparts" command for this?

There is a new 'dynpart' command, which when executed uses the compile-time board-level net partiton sizes, combined with the bad-block-table to generate the device-specific 'dynamic' partition table. The result is stored in the mtdparts environment variable. Everything else is standard u-boot/kernel behaviour.

Please see the attached patch (just for reference, not inclusion yet) for the details of the implementation. This code was used successfully in the production/flashing of a couple of thousand devices, using the Samsung NAND flash chips I mentioned (up to 1.3MByte of bad blocks within 64MByte of total flash). We have seen quite a number of different device-specific partition tables, and everything has worked fine so far.

Just like with the 'dynenv' patch, I think it is something quite useful (if not neccessarry) for the economic large-scale production of NAND-flash only devices. We can always talk about the implementation details, and I'm willing to address any feedback regarding it.

Quoted 3 lines
Quoted 1 line

3) the standard regular partition table is stored in the environment

How do you store it? In the same way as "mtdparts" is working?

yes.

Signature · 25 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
-------------- next part --------------
commit e05835df019027391f58f9d8ce5e1257d6924798
Author: Harald Welte <[email protected]>
Date:   Fri Apr 11 14:26:48 2008 +0100

    nand-dynamic_partitions.patch
    This patch adds support for 'dynamic partitions'.  This basically
    works as follows:
    * The nand code generates a bad-block-table at the first scan of the chip
    * The dynamic partition code calculates the raw partition sizes based on
      the bad block table.  E.g. if you have a partition of size 0x30000, and there are
      two bad blocks (0x4000 each) in it, the raw size will increase to 0x38000, and the
      following partitions get shifted towards the end of flash.
    
    Please note that currently the desired partition sizes are stored at compile-time
    in an array in drivers/nand/nand_bbt.c, so this definitely needs to change before
    submitting/merging upstream.
    
    In order to calculate the partiton map (and set mtdparts accordingly), you can use
    the 'dynpart' command at the prompt.  Use 'saveenv' to make the setting permanent.
    
    Signed-off-by: Harald Welte <[email protected]>
board/neo1973/gta01/gta01.c +11 -0
index 598574a..206a0d4 100644
@@ -494,3 +494,14 @@ void neo1973_led(int led, int on)
 }
 
 
+
+/* The sum of all part_size[]s must equal to the NAND size, i.e., 0x4000000.
+   "initrd" is sized such that it can hold two uncompressed 16 bit 640*480
+   images: 640*480*2*2 = 1228800 < 1245184. */
+
+unsigned int dynpart_size[] = {
+    CFG_UBOOT_SIZE, 0x4000, 0x200000, 0xa0000, 0x3d5c000-CFG_UBOOT_SIZE, 0 };
+char *dynpart_names[] = {
+    "u-boot", "u-boot_env", "kernel", "splash", "rootfs", NULL };
+
+
board/qt2410/qt2410.c +6 -0
index 8c0e77f..9b3df4e 100644
@@ -150,3 +150,9 @@ int dram_init (void)
 
 	return 0;
 }
+
+unsigned int dynpart_size[] = {
+    CFG_UBOOT_SIZE, 0x4000, 0x200000, 0xa0000, 0x3d5c000-CFG_UBOOT_SIZE, 0 };
+char *dynpart_names[] = {
+    "u-boot", "u-boot_env", "kernel", "splash", "rootfs", NULL };
+
common/cmd_dynenv.c +1 -1
index 4dd6148..91f7623 100644
@@ -60,7 +60,7 @@ int do_dynenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 		buf[2] = 'V';
 		buf[3] = '0';
 
-		if (arg_off_size(argc-2, argv+2, mtd, &addr, &dummy) < 0) {
+		if (arg_off_size(argc-2, argv+2, mtd, &addr, &dummy, 1) < 0) {
 			printf("Offset or partition name expected\n");
 			goto fail;
 		}
common/cmd_jffs2.c +56 -0

74 lines not on this page · raw message

common/cmd_nand.c +14 -7
index 7977060..bb46f34 100644
@@ -93,7 +93,7 @@ static inline int str2long(char *p, ulong *num)
 }
 
 int
-arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size)
+arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size, int net)
 {
 	int idx = nand_curr_device;
 #if defined(CONFIG_CMD_JFFS2) && defined(CONFIG_JFFS2_CMDLINE)
@@ -114,10 +114,17 @@ arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, ulong *size)
 					printf("'%s' is not a number\n", argv[1]);
 					return -1;
 				}
-				if (*size > part->size)
-					*size = part->size;
+				if (*size > part->size) {
+					if (net)
+						*size = nand_net_part_size(part);
+					else
+						*size = part->size;
+				}
 			} else {
-				*size = part->size;
+				if (net)
+					*size = nand_net_part_size(part);
+				else
+					*size = part->size;
 			}
 			idx = dev->id->num;
 			*nand = nand_info[idx];
@@ -257,7 +264,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 
 		printf("\nNAND %s: ", scrub ? "scrub" : "erase");
 		/* skip first two or three arguments, look for offset and size */
-		if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
+		if (arg_off_size(argc - o, argv + o, nand, &off, &size, 0) != 0)
 			return 1;
 
 		memset(&opts, 0, sizeof(opts));
@@ -319,7 +326,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 
 		read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
 		printf("\nNAND %s: ", read ? "read" : "write");
-		if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
+		if (arg_off_size(argc - 3, argv + 3, nand, &off, &size, 1) != 0)
 			return 1;
 
 		s = strchr(cmd, '.');
@@ -441,7 +448,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 	}
 
 	if (strcmp(cmd, "unlock") == 0) {
-		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
+		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size, 0) < 0)
 			return 1;
 
 		if (!nand_unlock(nand, off, size)) {
drivers/mtd/nand/nand_bbt.c +77 -0

86 lines not on this page · raw message

include/configs/neo1973_gta01.h +9 -3
index 2122fd5..6638d8d 100644
@@ -92,6 +92,7 @@
 #define CONFIG_CMD_BSP
 #define CONFIG_CMD_ELF
 #define CONFIG_CMD_MISC
+#define CONFIG_CMD_JFFS2
 #define CONFIG_CMD_DIAG
 #define CONFIG_CMD_SAVES
 #define CONFIG_CMD_NAND
@@ -201,13 +202,13 @@
 #define CONFIG_FAT		1
 #define CONFIG_SUPPORT_VFAT
 
-#if 0
+#if 1
 /* JFFS2 driver */
 #define CONFIG_JFFS2_CMDLINE	1
 #define CONFIG_JFFS2_NAND	1
 #define CONFIG_JFFS2_NAND_DEV	0
-#define CONFIG_JFFS2_NAND_OFF	0x634000
-#define CONFIG_JFFS2_NAND_SIZE	0x39cc000
+//#define CONFIG_JFFS2_NAND_OFF	0x634000
+//#define CONFIG_JFFS2_NAND_SIZE	0x39cc000
 #endif
 
 /* ATAG configuration */
@@ -249,4 +250,9 @@
 #define CONFIG_DRIVER_PCF50606		1
 #define CONFIG_RTC_PCF50606		1
 
+#define MTDIDS_DEFAULT	"nand0=neo1973-nand"
+#define MTPARTS_DEFAULT	"neo1973-nand:256k(u-boot),16k(u-boot_env),2M(kernel),640k(splash),-(jffs2)"
+#define CFG_NAND_DYNPART_MTD_KERNEL_NAME "neo1973-nand"
+#define CONFIG_NAND_DYNPART
+
 #endif	/* __CONFIG_H */
include/configs/qt2410.h +2 -0
index bd21ae3..06c4972 100644
@@ -275,5 +275,7 @@
 
 #define MTDIDS_DEFAULT		"nand0=qt2410-nand"
 #define MTPARTS_DEFAULT		"qt2410-nand:192k(u-boot),8k(u-boot_env),2M(kernel),2M(splash),-(jffs2)"
+#define CFG_NAND_DYNPART_MTD_KERNEL_NAME "qt2410-nand"
+#define CONFIG_NAND_DYNPART
 
 #endif	/* __CONFIG_H */
include/util.h +1 -1
index c1ded14..7f3ac3b 100644
@@ -28,6 +28,6 @@
 
 /* common/cmd_nand.c */
 int arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off,
-  ulong *size);
+  ulong *size, int net);
 
 #endif /* UTIL_H */
#8 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 9 lines · In message <[email protected]> you wrote:
Quoted 3 lines

How do you "create" the partition table? Do you use the "mtdparts" command for this?

There is a new 'dynpart' command, which when executed uses the compile-time board-level net partiton sizes, combined with the bad-block-table to generate the device-specific 'dynamic' partition table. The result is stored in the mtdparts environment variable. Everything else is standard u-boot/kernel behaviour.

Maybe the new command should be implemented as subcommand to the "mtdparts" command so we have just one interface to manipulate the "mtdparts" variable.

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

3) the standard regular partition table is stored in the environment

How do you store it? In the same way as "mtdparts" is working?

yes.

Thanks.

Best regards,

Wolfgang Denk

Signature · 5 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
America has been discovered before, but it has always been hushed up.
- Oscar Wilde
#9 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Hi Wolfgang,

thanks again for your quick response. This is really encouraging me to continue merging/submitting at the same pace ;)

Quoted 11 lines · Wolfgang Denk
Quoted 9 lines · In message <[email protected]> you wrote:
Quoted 3 lines

How do you "create" the partition table? Do you use the "mtdparts" command for this?

There is a new 'dynpart' command, which when executed uses the compile-time board-level net partiton sizes, combined with the bad-block-table to generate the device-specific 'dynamic' partition table. The result is stored in the mtdparts environment variable. Everything else is standard u-boot/kernel behaviour.

Quoted 3 lines

Maybe the new command should be implemented as subcommand to the "mtdparts" command so we have just one interface to manipulate the "mtdparts" variable.

ok, no problem with that, I will change this before re-sending the patch (against u-boot-nand-flash/testing).

Cheers,

Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#10 lore raw

[U-Boot] mtdparts: add bad-block skipping

In reply to Wolfgang Denk

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

These new commands can be useful when gang programming NAND chips where the gang programmer is capable only of skipping bad blocks. One can use a master image that contains images of each of the partitions padded-out to their spec'd sizes; when u-boot first comes up 'mtdparts default; mtdparts spread' (or a seq of 'mtdpart add.e' commands) will produce a partition table that matches what was put their by the gang-programmer.

It can also be useful when doing in-situ programming with u-boot as the flash programmer as demonstrated by the openmoko project's use of the 'dynpart' command [2] upon which this patch series was based.

---

NOTE: I'm not sure what to call the new subcommands, I chose 'spread' because of the way it changes the existing mtdparts variable; however, I am open to suggestions for a different name. I chose add.e/add.i because of the behaviour of the write.e/write.i commands; however, I am once again open to suggestion.

Testing was performed in the u-boot-omap-l1 tree [3]. Here is an example u-boot console session to demonstrate how the commands work:

---

U-Boot > nand bad

Device 0 bad blocks:
062c0000
0a140000
128a0000
12e20000
18bc0000
1ff80000
1ffa0000
1ffc0000
1ffe0000
U-Boot > mtdparts default
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)
U-Boot >
U-Boot > mtdparts spread
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.e nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b)

U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.i nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdparts del rootfs_b
U-Boot > mtdparts add nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)

---

Here are the MAKEALL results:

./MAKEALL arm on master
--------------------- SUMMARY ----------------------------
Boards compiled: 150
Boards with warnings or errors: 47 ( shannon evb4510 lpc2292sodimm modnet50 SMN42 guruplug mv88f6281gtw_ge netstar openrd_base rd6281a sheevaplug suen3 afeb9260 at91cap9adk at91rm9200dk at91rm9200ek at91sam9260ek at91sam9261ek at91sam9263ek at91sam9g10ek at91sam9g20ek at91sam9m10g45ek at91sam9rlek cmc_pu2 CPUAT91 CPU9260 CPU9G20 csb637 eb_cpux9k2 kb9202 meesc mp2usb m501sk otc570 pm9261 pm9263 SBC35_A9G20 TNY_A9260 TNY_A9G20 actux1 actux2 actux3 actux4 ixdp425 ixdpg425 pdnb3 scpu )
----------------------------------------------------------

./MAKEALL arm with this patch series applied
--------------------- SUMMARY ----------------------------
Boards compiled: 150
Boards with warnings or errors: 47 ( shannon evb4510 lpc2292sodimm modnet50 SMN42 guruplug mv88f6281gtw_ge netstar openrd_base rd6281a sheevaplug suen3 afeb9260 at91cap9adk at91rm9200dk at91rm9200ek at91sam9260ek at91sam9261ek at91sam9263ek at91sam9g10ek at91sam9g20ek at91sam9m10g45ek at91sam9rlek cmc_pu2 CPUAT91 CPU9260 CPU9G20 csb637 eb_cpux9k2 kb9202 meesc mp2usb m501sk otc570 pm9261 pm9263 SBC35_A9G20 TNY_A9260 TNY_A9G20 actux1 actux2 actux3 actux4 ixdp425 ixdpg425 pdnb3 scpu )
----------------------------------------------------------

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549
[2] http://wiki.openmoko.org/wiki/NAND_bad_blocks
[3] git://arago-project.org/git/people/sekhar/u-boot-omapl1.git

#11 lore raw

[U-Boot] mtdparts: add bad-block skipping

Dear Ben Gardiner,

Quoted 8 lines · In message <[email protected]> you…

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

Has this been tested on NOR flash devices, too?

Best regards,

Wolfgang Denk

Signature · 6 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Life is a process, not a principle, a mystery  to  be  lived,  not  a
problem to be solved. - Gerard Straub, television producer and author
(stolen from Frank Herbert??)
#12 lore raw

[U-Boot] mtdparts: add bad-block skipping

In reply to Ben Gardiner

Dear Ben Gardiner,

Quoted 4 lines · In message <[email protected]> you…

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

Can we have a configuration that is neutral to the memory footprint for such boards that don't want to use any of the new features? It seems the patches always add ~ 200 bytes to the code size (on PowerPC).

Best regards,

Wolfgang Denk

Signature · 7 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Computers make excellent and efficient servants, but I have  no  wish
to  serve under them. Captain, a starship also runs on loyalty to one
man. And nothing can replace it or him.
	-- Spock, "The Ultimate Computer", stardate 4729.4
#13 lore raw

[U-Boot] mtdparts: add bad-block skipping

Dear Wolfgang Denk,

Quoted 1 line · Wolfgang Denk

Has this been tested on NOR flash devices, too?

No, I'm sorry it hasn't -- but I'm glad you asked. On a closer look I think the changes in this patch series could result in the dereference of a null pointer when using a NOR flash device. The features are centered around calls to mtd->block_isbad() and I don't think this function pointer is set for NOR flash devices. I will add 'if(mtd->block_isbad())' checks to the code to prevent the potential dereference of a null pointer and resubmit.

Quoted 4 lines · Wolfgang Denk

Can we have a configuration that is neutral to the memory footprint for such boards that don't want to use any of the new features? It seems the patches always add ~ 200 bytes to the code size (on PowerPC).

Yes, absolutely. I think that it is patch 2/4 which does not have the surrounding ifdefs of the other patches. I will make the changes in that patch conditional on a CONFIG_ define and resubmit shortly.

I was supposed to double check the image sizes before and after the patch -- as is directed in your wiki instructions, sorry for the omission. I will include a summary of the size differences in powerpc images with the resubmission of this patch series -- along with a './MAKEALL powerpc' output -- also as directed in your wiki instructions.

Best Regards,

Ben Gardiner

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#14 lore raw

v2 cover mtdparts: add bad-block skipping

In reply to Ben Gardiner

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

These new commands can be useful when gang programming NAND chips where the gang programmer is capable only of skipping bad blocks. One can use a master image that contains images of each of the partitions padded-out to their spec'd sizes; when u-boot first comes up 'mtdparts default; mtdparts spread' (or a seq of 'mtdpart add.e' commands) will produce a partition table that matches what was put there by the gang-programmer.

It can also be useful when doing in-situ programming with u-boot being the flash programmer as demonstrated by the openmoko project's use of the 'dynpart' command [2] upon which this patch series was based.

---

Changes in v2:
* formating: spaces after 'if' and for
* printing net partition sizes feature is now conditional on the new CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES macro; patch 2/4 was adding 264 bytes to the virtlab2 build -- now it adds 0 bytes -- see below for more binary size impact details
* changed the net_part_size method to return the net size instead of using an output variable
* checking mtd->block_isbad function pointer before dereferencing
* there were some trailing whitespace errors when applying 3/4 and 4/4 that I have fixed now

NOTE: I'm not sure what to call the new subcommands, I chose 'spread' because of the way it changes the existing mtdparts variable; however, I am open to suggestions for a different name. I chose add.e/add.i because of the behaviour of the write.e/write.i commands; however, I am again open to suggestions.

Testing was performed in the u-boot-omap-l1 tree [3]. Here is an example u-boot console session to demonstrate how the commands work:

-------------------------------------------------------------------------------
U-Boot > mtdparts default
U-Boot > nand bad

Device 0 bad blocks:
062c0000
0a140000
128a0000
12e20000
18bc0000
1ff80000
1ffa0000
1ffc0000
1ffe0000
U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07020000      0x07000000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07ae0000      0
 6: initrd_b            0x00400000      0x00400000      0x07ee0000      0
 7: rootfs_b            0x07020000      0x07000000 (!)  0x082e0000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdparts spread
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07040000      0x07020000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07b00000      0
 6: initrd_b            0x00400000      0x00400000      0x07f00000      0
 7: rootfs_b            0x07040000      0x07020000 (!)  0x08300000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.e nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b)

U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.i nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdparts del rootfs_b
U-Boot > mtdparts add nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)
-------------------------------------------------------------------------------

Here are the MAKEALL results:

./MAKEALL arm on master
--------------------- SUMMARY ----------------------------
Boards compiled: 150
Boards with warnings or errors: 47 ( shannon evb4510 lpc2292sodimm modnet50 SMN42 guruplug mv88f6281gtw_ge netstar openrd_base rd6281a sheevaplug suen3 afeb9260 at91cap9adk at91rm9200dk at91rm9200ek at91sam9260ek at91sam9261ek at91sam9263ek at91sam9g10ek at91sam9g20ek at91sam9m10g45ek at91sam9rlek cmc_pu2 CPUAT91 CPU9260 CPU9G20 csb637 eb_cpux9k2 kb9202 meesc mp2usb m501sk otc570 pm9261 pm9263 SBC35_A9G20 TNY_A9260 TNY_A9G20 actux1 actux2 actux3 actux4 ixdp425 ixdpg425 pdnb3 scpu )
----------------------------------------------------------

./MAKEALL arm with this patch series applied
--------------------- SUMMARY ----------------------------
Boards compiled: 150
Boards with warnings or errors: 47 ( shannon evb4510 lpc2292sodimm modnet50 SMN42 guruplug mv88f6281gtw_ge netstar openrd_base rd6281a sheevaplug suen3 afeb9260 at91cap9adk at91rm9200dk at91rm9200ek at91sam9260ek at91sam9261ek at91sam9263ek at91sam9g10ek at91sam9g20ek at91sam9m10g45ek at91sam9rlek cmc_pu2 CPUAT91 CPU9260 CPU9G20 csb637 eb_cpux9k2 kb9202 meesc mp2usb m501sk otc570 pm9261 pm9263 SBC35_A9G20 TNY_A9260 TNY_A9G20 actux1 actux2 actux3 actux4 ixdp425 ixdpg425 pdnb3 scpu )
----------------------------------------------------------

./MAKEALL powerpc with this patch series applied --------------------- SUMMARY ----------------------------
Boards compiled: 354
Boards with warnings or errors: 15 ( MVBC_P BMW caddy2 MPC8536DS MPC8536DS_NAND MPC8536DS_SDCARD MPC8536DS_SPIFLASH MPC8544DS P2020DS P2020DS_36BIT PM854 AP1000 EVB64260 P3G4 ZUMA )
----------------------------------------------------------

The binary size impact was checked using the da830evm config + NAND enabled for arm and the virtlab2 config for ppc. The entire patch series saves 64 bytes on arm and 4 bytes on ppc -- due to the regrouping of calls in 1/4. With all the config options introduced in this series enabled the patch series adds 1096 bytes on arm and 260 bytes on ppc.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549
[2] http://wiki.openmoko.org/wiki/NAND_bad_blocks
[3] git://arago-project.org/git/people/sekhar/u-boot-omapl1.git

#15 lore raw

v3 cover mtdparts: add bad-block skipping

[PATCH v3 1/4] mtdparts: regroup calls to get_mtd_device_nm [PATCH v3 2/4] mtdparts: show net size in mtdparts list [PATCH v3 3/4] mtdparts: add new sub-command "spread" [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks

 cmd_mtdparts.c |  256 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 237 insertions(+), 19 deletions(-)

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

These new commands can be useful when gang programming NAND chips where the gang programmer is capable only of skipping bad blocks. One can use a master image that contains images of each of the partitions padded-out to their spec'd sizes; when u-boot first comes up 'mtdparts default; mtdparts spread' (or a seq of 'mtdpart add.e' commands) will produce a partition table that matches what was put there by the gang-programmer.

It can also be useful when doing in-situ programming with u-boot being the flash programmer as demonstrated by the openmoko project's use of the 'dynpart' command [2] upon which this patch series was based.

---

V2:
* formating: spaces after 'if' and for
* printing net partition sizes feature is now conditional on the new CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES macro; patch 2/4 was adding 264 bytes to the virtlab2 build -- now it adds 0 bytes -- see below for more binary size impact details
* changed the net_part_size method to return the net size instead of using an output variable
* checking mtd->block_isbad function pointer before dereferencing
* there were some trailing whitespace errors when applying 3/4 and 4/4 that I have fixed now

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* more checkpatch fixes
* adding openmoko to the copyright statements in cmd_mtdparts.c

NOTE: I'm not sure what to call the new subcommands, I chose 'spread' because of the way it changes the existing mtdparts variable; however, I am open to suggestions for a different name. I chose add.e/add.i because of the behaviour of the write.e/write.i commands; however, I am again open to suggestions.

Testing was performed in the u-boot-omap-l1 tree [3]. Here is an example u-boot console session to demonstrate how the commands work:

-------------------------------------------------------------------------------
U-Boot > mtdparts default
U-Boot > nand bad

Device 0 bad blocks:
062c0000
0a140000
128a0000
12e20000
18bc0000
1ff80000
1ffa0000
1ffc0000
1ffe0000
U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07020000      0x07000000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07ae0000      0
 6: initrd_b            0x00400000      0x00400000      0x07ee0000      0
 7: rootfs_b            0x07020000      0x07000000 (!)  0x082e0000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdparts spread
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07040000      0x07020000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07b00000      0
 6: initrd_b            0x00400000      0x00400000      0x07f00000      0
 7: rootfs_b            0x07040000      0x07020000 (!)  0x08300000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.e nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b)

U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.i nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdparts del rootfs_b
U-Boot > mtdparts add nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)
-------------------------------------------------------------------------------

I verified the patches with checkpatch. The checkpatch.pl output follows:

total: 0 errors, 0 warnings, 71 lines checked

0001-PATCH-v3-1-4-mtdparts-regroup-calls-to-get_mtd_devic.patch has no obvious style problems and is ready for submission.
total: 0 errors, 0 warnings, 85 lines checked

0002-PATCH-v3-2-4-mtdparts-show-net-size-in-mtdparts-list.patch has no obvious style problems and is ready for submission.
total: 0 errors, 0 warnings, 148 lines checked

0003-PATCH-v3-3-4-mtdparts-add-new-sub-command-spread.patch has no obvious style problems and is ready for submission.
total: 0 errors, 0 warnings, 69 lines checked

0004-PATCH-v3-4-4-mtdparts-new-add.e-add-part-skipping-ba.patch has no obvious style problems and is ready for submission.

I tested the binary size and compiler warnings on ARM9 and 8xx with the following commands:

#checkout u-boot/master, apply changes to da850evm_config for testing, #commit
./MAKEALL ARM9 2>&1 > ../makeall-master.log
./MAKEALL 8xx 2>&1 > ../makeall-master.log
#apply patches, commit
./MAKEALL ARM9 2>&1 > ../makeall-spread.log
./MAKEALL 8xx 2>&1 > ../makeall-8xx-spread.log
diff -burp ../makeall-8xx-master.log ../makeall-8xx-spread.log diff -burp ../makeall-master.log ../makeall-spread.log

The diff output of the 8xx build shows all binaries text sections decreased in size -- except for kmsupx4 and mgsuvd which appear larger but are the same size when built manually:
@@ -45,7 +45,7 @@ Configuring for FLAGADM board...
121164 9096 14388 144648 23508 ./u-boot
Configuring for FPS850L board...
text data bss dec hex filename

- 233060	  12636	  25472	 271168	  42340	./u-boot
+ 233036	  12632	  25472	 271140	  42324	./u-boot

Configuring for GEN860T board...
text data bss dec hex filename
207072 32432 18752 258256 3f0d0 ./u-boot
@@ -102,7 +102,7 @@ Configuring for lwmon board...
214504 34208 218388 467100 7209c ./u-boot
Configuring for kmsupx4 board...
text data bss dec hex filename

- 274920	  19924	  28748	 323592	  4f008	./u-boot
+ 274936	  19920	  28748	 323604	  4f014	./u-boot

Configuring for MBX board...
text data bss dec hex filename
104736 7388 13016 125140 1e8d4 ./u-boot
@@ -111,7 +111,7 @@ Configuring for MBX860T board...
92380 6424 13172 111976 1b568 ./u-boot
Configuring for mgsuvd board...
text data bss dec hex filename

- 277012	  20048	  28752	 325812	  4f8b4	./u-boot
+ 277028	  20044	  28752	 325824	  4f8c0	./u-boot

Configuring for MHPC board...
text data bss dec hex filename
150944 21984 16776 189704 2e508 ./u-boot
@@ -201,19 +201,19 @@ Configuring for TOP860 board...
160456 27360 17336 205152 32160 ./u-boot
Configuring for TQM823L board...
text data bss dec hex filename

- 256664	  13888	  25700	 296252	  4853c	./u-boot
+ 256640	  13884	  25700	 296224	  48520	./u-boot
 Configuring for TQM823L_LCD board...
    text	   data	    bss	    dec	    hex	filename
- 265408	  29636	  25732	 320776	  4e508	./u-boot
+ 265384	  29632	  25732	 320748	  4e4ec	./u-boot
 Configuring for TQM850L board...
    text	   data	    bss	    dec	    hex	filename
- 256544	  13868	  25700	 296112	  484b0	./u-boot
+ 256520	  13864	  25700	 296084	  48494	./u-boot
 Configuring for TQM855L board...
    text	   data	    bss	    dec	    hex	filename
- 258544	  13964	  27236	 299744	  492e0	./u-boot
+ 258520	  13960	  27236	 299716	  492c4	./u-boot
 Configuring for TQM860L board...
    text	   data	    bss	    dec	    hex	filename
- 258592	  13972	  27236	 299800	  49318	./u-boot
+ 258568	  13968	  27236	 299772	  492fc	./u-boot

Configuring for TQM885D board...
text data bss dec hex filename
209964 14680 26052 250696 3d348 ./u-boot

The diff output of the ARM9 build shows a decrease in text size for all but the da850evm config in which the feature introduced by this patch series were enabled:
@@ -48,7 +48,7 @@ Configuring for da830evm board...
147617 4888 295320 447825 6d551 ./u-boot
Configuring for da850evm board...
text data bss dec hex filename

- 198497	  10332	 296608	 505437	  7b65d	./u-boot
+ 199590	  10332	 296608	 506530	  7baa2	./u-boot

Configuring for edb9301 board...
text data bss dec hex filename
133899 3772 213400 351071 55b5f ./u-boot
@@ -83,13 +83,13 @@ kirkwood_egiga.c:620: warning: dereferen
166164 8214 260736 435114 6a3aa ./u-boot
Configuring for imx27lite board...

    text	   data	    bss	    dec	    hex	filename
- 195862	   9876	 236052	 441790	  6bdbe	./u-boot
+ 195784	   9876	 236052	 441712	  6bd70	./u-boot
 Configuring for lpd7a400 board...
    text	   data	    bss	    dec	    hex	filename
   96349	   3368	  14496	 114213	  1be25	./u-boot
 Configuring for magnesium board...
    text	   data	    bss	    dec	    hex	filename
- 195897	   9892	 236052	 441841	  6bdf1	./u-boot
+ 195819	   9892	 236052	 441763	  6bda3	./u-boot

Configuring for mv88f6281gtw_ge board...
kirkwood_egiga.c: In function 'kwgbe_recv':
kirkwood_egiga.c:620: warning: dereferencing type-punned pointer will break strict-aliasing rules
@@ -100,10 +100,10 @@ Configuring for mx1ads board...
105339 3740 14580 123659 1e30b ./u-boot
Configuring for mx1fs2 board...

    text	   data	    bss	    dec	    hex	filename
-  97987	   3240	   4124	 105351	  19b87	./u-boot
+  97921	   3240	   4124	 105285	  19b45	./u-boot
 Configuring for netstar board...
    text	   data	    bss	    dec	    hex	filename
- 173323	   8060	  14688	 196071	  2fde7	./u-boot
+ 173269	   8060	  14688	 196017	  2fdb1	./u-boot

Configuring for nhk8815 board...
text data bss dec hex filename
175012 10436 37144 222592 36580 ./u-boot
@@ -129,7 +129,7 @@ Configuring for openrd_base board...
kirkwood_egiga.c: In function 'kwgbe_recv':
kirkwood_egiga.c:620: warning: dereferencing type-punned pointer will break strict-aliasing rules

    text	   data	    bss	    dec	    hex	filename
- 302083	   9002	 286656	 597741	  91eed	./u-boot
+ 302055	   9002	 286656	 597713	  91ed1	./u-boot

Configuring for rd6281a board...
kirkwood_egiga.c: In function 'kwgbe_recv':
kirkwood_egiga.c:620: warning: dereferencing type-punned pointer will break strict-aliasing rules
@@ -145,7 +145,7 @@ Configuring for sheevaplug board...
kirkwood_egiga.c: In function 'kwgbe_recv':
kirkwood_egiga.c:620: warning: dereferencing type-punned pointer will break strict-aliasing rules

    text	   data	    bss	    dec	    hex	filename
- 319712	   8990	 286784	 615486	  9643e	./u-boot
+ 319684	   8990	 286784	 615458	  96422	./u-boot

Configuring for smdk2400 board...
text data bss dec hex filename
97632 3440 14500 115572 1c374 ./u-boot
@@ -168,10 +168,10 @@ Configuring for suen3 board...
kirkwood_egiga.c: In function 'kwgbe_recv':
kirkwood_egiga.c:620: warning: dereferencing type-punned pointer will break strict-aliasing rules
text data bss dec hex filename

- 244086	  12716	  25128	 281930	  44d4a	./u-boot
+ 244054	  12716	  25128	 281898	  44d2a	./u-boot
 Configuring for trab board...
    text	   data	    bss	    dec	    hex	filename
- 217847	  14027	 424192	 656066	  a02c2	./u-boot
+ 217781	  14027	 424192	 656000	  a0280	./u-boot

Configuring for VCMA9 board...
text data bss dec hex filename
177726 7504 261900 447130 6d29a ./u-boot
@@ -189,7 +189,7 @@ Variant:: PB926EJ-S
85977 2920 12132 101029 18aa5 ./u-boot
Configuring for voiceblue board...

    text	   data	    bss	    dec	    hex	filename
- 143684	   4708	  18916	 167308	  28d8c	./u-boot
+ 143614	   4708	  18916	 167238	  28d46	./u-boot

Configuring for davinci_dvevm board...
text data bss dec hex filename
178646 5500 297984 482130 75b52 ./u-boot
@@ -204,13 +204,13 @@ Configuring for davinci_sonata board...
145390 5296 55068 205754 323ba ./u-boot
Configuring for davinci_dm355evm board...

    text	   data	    bss	    dec	    hex	filename
- 207288	   8516	  40864	 256668	  3ea9c	./u-boot
+ 207252	   8516	  40864	 256632	  3ea78	./u-boot
 Configuring for davinci_dm355leopard board...
    text	   data	    bss	    dec	    hex	filename
- 206398	   7904	  40864	 255166	  3e4be	./u-boot
+ 206362	   7904	  40864	 255130	  3e49a	./u-boot
 Configuring for davinci_dm365evm board...
    text	   data	    bss	    dec	    hex	filename
- 243459	   8704	 297752	 549915	  8641b	./u-boot
+ 243423	   8704	 297752	 549879	  863f7	./u-boot

Configuring for davinci_dm6467evm board...
text data bss dec hex filename
91806 4776 26100 122682 1df3a ./u-boot

The binary size impact was checked in a couple specific cases also: using the da830evm config + NAND enabled for arm and the virtlab2 config for ppc. In these cases the entire patch series saves 64 bytes on arm and 4 bytes on ppc -- due to the regrouping of calls in 1/4. With all the config options introduced in this series enabled the patch series adds 1096 bytes on arm and 260 bytes on ppc.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549
[2] http://wiki.openmoko.org/wiki/NAND_bad_blocks
[3] git://arago-project.org/git/people/sekhar/u-boot-omapl1.git

#16 lore raw

v3 cover mtdparts: add bad-block skipping

Hi Wolfgang,

I rebased the mtdparts bad block skipping patches and reposted a v3 series [1] in the hopes that it would be considered for inclusion into v2010.09 . I hope that I have addressed the concerns you raised in your reviews [2] [3].

I said this earlier to Scott Wood: I am very much a novice here so I hope it is not rude of me to ask: is there any chance of having the "[PATCH v3 0/4] mtdparts: add bad-block skipping" [1] series included in v2010.09?
Are there any concerns with respect to the functionality that this patch provides?
Is there anything else that I can provide to help with getting this patch included?

Best Regards,
Ben Gardiner

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/80843
[2] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79418
[3] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79419

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#17 lore raw

v4 cover mtdparts: add bad-block skipping

In reply to Ben Gardiner

[PATCH v4 1/4] mtdparts: regroup calls to get_mtd_device_nm [PATCH v4 2/4] mtdparts: show net size in mtdparts list [PATCH v4 3/4] mtdparts: add new sub-command "spread" [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks

 common/cmd_mtdparts.c |  268 +++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 246 insertions(+), 22 deletions(-)

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

These new commands can be useful when gang programming NAND chips where the gang programmer is capable only of skipping bad blocks. One can use a master image that contains images of each of the partitions padded-out to their spec'd sizes; when u-boot first comes up 'mtdparts default; mtdparts spread' (or a seq of 'mtdpart add.spread' commands) will produce a partition table that matches what was put there by the gang-programmer.

It can also be useful when doing in-situ programming with u-boot being the flash programmer as demonstrated by the openmoko project's use of the 'dynpart' command [2] upon which this patch series was based.

CC Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549
[2] http://wiki.openmoko.org/wiki/NAND_bad_blocks

---

V2:
* formating: spaces after 'if' and for
* printing net partition sizes feature is now conditional on the new CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES macro; patch 2/4 was adding 264 bytes to the virtlab2 build -- now it adds 0 bytes -- see below for more binary size impact details
* changed the net_part_size method to return the net size instead of using an output variable
* checking mtd->block_isbad function pointer before dereferencing
* there were some trailing whitespace errors when applying 3/4 and 4/4 that I have fixed now

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* more checkpatch fixes
* adding openmoko to the copyright statements in cmd_mtdparts.c

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* re-grouped list_partition #ifdefs into one
* removed changelog and my (C) from file header
* added source of port to the commit message
* fixed multi-line comment style
* indentation only by tabs
* check for s == NULL when looking for '.' in command
* do not include support for the '.i' synonym
* rename to 'add.spread' to match 'mtdparts spread' as per Scott Wood's suggestion.

Testing was performed with da850evm.h plus NAND enabled. Here is an example u-boot console session to demonstrate how the commands work:

-------------------------------------------------------------------------------
U-Boot > mtdparts default
U-Boot > nand bad

Device 0 bad blocks:
062c0000
0a140000
128a0000
12e20000
18bc0000
1ff80000
1ffa0000
1ffc0000
1ffe0000
U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07020000      0x07000000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07ae0000      0
 6: initrd_b            0x00400000      0x00400000      0x07ee0000      0
 7: rootfs_b            0x07020000      0x07000000 (!)  0x082e0000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdparts spread
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07040000      0x07020000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07b00000      0
 6: initrd_b            0x00400000      0x00400000      0x07f00000      0
 7: rootfs_b            0x07040000      0x07020000 (!)  0x08300000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.spread nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b)

U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.spread nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdparts del rootfs_b
U-Boot > mtdparts add nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)
-------------------------------------------------------------------------------

I verified the patches with checkpatch.

I tested the binary size and compiler warnings on ARM9 and 8xx. The patch series saves 24 bytes of text on 8xx and 54 bytes of text on arm9 -- when none of the config options are enabled. When the config options are enabled, text grows by 1023 bytes on arm9.

#18 lore raw

v5 cover mtdparts: add bad-block skipping

Ben Gardiner (5):
mtdparts: regroup calls to get_mtd_device_nm
mtd: add an mtd method for get_len_incl_bad()
mtdparts: show net size in mtdparts list
mtdparts: add new sub-command "spread"
mtdparts: new add.spread: add part skipping bad blocks

 common/cmd_mtdparts.c        |  263 ++++++++++++++++++++++++++++++++++++-----
 drivers/mtd/mtdcore.c        |   45 +++++++
 drivers/mtd/nand/nand_util.c |    6 +
 include/linux/mtd/mtd.h      |    4 +-
 4 files changed, 285 insertions(+), 33 deletions(-)

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

These new commands can be useful when gang programming NAND chips where the gang programmer is capable only of skipping bad blocks. One can use a master image that contains images of each of the partitions padded-out to their spec'd sizes; when u-boot first comes up 'mtdparts default; mtdparts spread' (or a seq of 'mtdpart add.spread' commands) will produce a partition table that matches what was put there by the gang-programmer.

It can also be useful when doing in-situ programming with u-boot being the flash programmer as demonstrated by the openmoko project's use of the 'dynpart' command [2] upon which this patch series was based.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549
[2] http://wiki.openmoko.org/wiki/NAND_bad_blocks

---

V2:
* formating: spaces after 'if' and for
* printing net partition sizes feature is now conditional on the new CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES macro; patch 2/4 was adding 264 bytes to the virtlab2 build -- now it adds 0 bytes -- see below for more binary size impact details
* changed the net_part_size method to return the net size instead of using an output variable
* checking mtd->block_isbad function pointer before dereferencing
* there were some trailing whitespace errors when applying 3/4 and 4/4 that I have fixed now

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* more checkpatch fixes
* adding openmoko to the copyright statements in cmd_mtdparts.c

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* re-grouped list_partition #ifdefs into one
* removed changelog and my (C) from file header
* added source of port to the commit message
* fixed multi-line comment style
* indentation only by tabs
* check for s == NULL when looking for '.' in command
* do not include support for the '.i' synonym
* rename to 'add.spread' to match 'mtdparts spread' as per Scott Wood's suggestion.

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered patches; V5 introduces patch 2/5
* return uint64_t instead of u32 for net_size
* do a quick if((cond) return
* calculate net_size by adding-up good blocks instead of subtracting bad blocks
* try to strike a balance; reuse more code between the branches of #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) in print_partition_table
* don't push dangling lines to the right
* fix spelling errors in comments
* more hanging arguments alignment
* refactor the spread_partition function so that it delegates the bad-block counting to the mtd_get_len_incl_bad function -- as per Scott Woods' suggestion.
* don't reproduce the same call to spread_partitions on either side of the check for existing device -- as per Scott Wood's comments.

Testing was performed with da850evm.h plus NAND enabled. Here is an example u-boot console session to demonstrate how the commands work:

-------------------------------------------------------------------------------
U-Boot > mtdparts default
U-Boot > nand bad

Device 0 bad blocks:
062c0000
0a140000
128a0000
12e20000
18bc0000
1ff80000
1ffa0000
1ffc0000
1ffe0000
U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07020000      0x07000000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07ae0000      0
 6: initrd_b            0x00400000      0x00400000      0x07ee0000      0
 7: rootfs_b            0x07020000      0x07000000 (!)  0x082e0000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdparts spread
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07040000      0x07020000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07b00000      0
 6: initrd_b            0x00400000      0x00400000      0x07f00000      0
 7: rootfs_b            0x07040000      0x07020000 (!)  0x08300000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.spread nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b)

U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.spread nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdparts del rootfs_b
U-Boot > mtdparts add nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)
-------------------------------------------------------------------------------

I verified the patches with checkpatch.

I confirmed that MAKEALL for 'ARM9' and '8xx' did not introduce any additional warnings.

I tested the binary size and compiler warnings on ARM9 and 8xx. The patch series saves 24 bytes of text on 8xx and 74 bytes of text on arm9 -- when none of the config options are enabled. When the config options are enabled, text grows by 1321 bytes on arm9.

#19 lore raw

PATCH v5 2/5 mtd: add an mtd method for get_len_incl_bad()

The logic to 'spread' mtd partitions needs to calculate the length in the mtd device, including bad blocks.

This patch introduces a new function, mtd_get_len_incl_bad that can return both the length including bad blocks and whether that length was truncated on the device. This new function will be used by the mtdparts spread command later in this series. The definition of the function is #ifdef'd out in configurations that do not use the new 'mtdparts spread' command.

---

Note: the mtd_get_len_incl_bad() function could also be used by the get_len_incl_bad() function in nand_util.c except for the fact that boards can enable NAND support without enabling MTD support. A note has been added to get_len_incl_bad() to remind us to refactor when/if MTD support is available whenever NAND support is enabled.

V5:
* introduced in v5 of this patchset

---
 drivers/mtd/mtdcore.c        |   44 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/nand_util.c |    6 +++++
 include/linux/mtd/mtd.h      |    4 ++-
 3 files changed, 53 insertions(+), 1 deletions(-)
drivers/mtd/mtdcore.c +44 -0
index 6eb52ed..cb86657 100644
@@ -142,3 +142,47 @@ void put_mtd_device(struct mtd_info *mtd)
 	c = --mtd->usecount;
 	BUG_ON(c < 0);
 }
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+/**
+ * mtd_get_len_incl_bad
+ *
+ * Check if length including bad blocks fits into device.
+ *
+ * @param mtd an MTD device
+ * @param offset offset in flash
+ * @param length image length
+ * @return image length including bad blocks in *len_incl_bad and whether or not
+ *         the length returned was truncated in *truncated
+ */
+void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+			  const uint64_t length, uint64_t *len_incl_bad,
+			  int *truncated)
+{
+	*truncated = 0;
+	*len_incl_bad = 0;
+
+	if (!mtd->block_isbad) {
+		*len_incl_bad = length;
+		return;
+	}
+
+	uint64_t len_excl_bad = 0;
+	uint64_t block_len;
+
+	while (len_excl_bad < length) {
+		block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
+
+		if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
+			len_excl_bad += block_len;
+
+		*len_incl_bad += block_len;
+		offset       += block_len;
+
+		if (offset >= mtd->size) {
+			*truncated = 1;
+			break;
+		}
+	}
+}
+#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
drivers/mtd/nand/nand_util.c +6 -0
index 29c42f7..622237f 100644
@@ -435,6 +435,12 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 static size_t get_len_incl_bad (nand_info_t *nand, loff_t offset,
 				const size_t length)
 {
+	/*
+	 * TODO: replace this implementation with a call to
+	 * mtd_get_len_incl_bad((struct mtd_info *) nand, ...)
+	 * when CONFIG_MTD_DEVICE is required for NAND support
+	 */
+
 	size_t len_incl_bad = 0;
 	size_t len_excl_bad = 0;
 	size_t block_len;
include/linux/mtd/mtd.h +3 -1
index 16556c4..8e8ec7c 100644
@@ -259,7 +259,9 @@ extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
 extern struct mtd_info *get_mtd_device_nm(const char *name);
 
 extern void put_mtd_device(struct mtd_info *mtd);
-
+extern void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+				 const uint64_t length, uint64_t *len_incl_bad,
+				 int *truncated);
 /* XXX U-BOOT XXX */
 #if 0
 struct mtd_notifier {
Signature · 1 line
1.7.0.4
#20 lore raw

PATCH v5 2/5 mtd: add an mtd method for get_len_incl_bad()

Quoted 69 lines · On Mon, 30 Aug 2010 13:38:57 -0400 Ben Gardiner <[email protected]>…

The logic to 'spread' mtd partitions needs to calculate the length in the mtd device, including bad blocks.

This patch introduces a new function, mtd_get_len_incl_bad that can return both the length including bad blocks and whether that length was truncated on the device. This new function will be used by the mtdparts spread command later in this series. The definition of the function is #ifdef'd out in configurations that do not use the new 'mtdparts spread' command.

---

Note: the mtd_get_len_incl_bad() function could also be used by the get_len_incl_bad() function in nand_util.c except for the fact that boards can enable NAND support without enabling MTD support. A note has been added to get_len_incl_bad() to remind us to refactor when/if MTD support is available whenever NAND support is enabled.

V5:
* introduced in v5 of this patchset

---
 drivers/mtd/mtdcore.c        |   44 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/nand_util.c |    6 +++++
 include/linux/mtd/mtd.h      |    4 ++-
 3 files changed, 53 insertions(+), 1 deletions(-)
drivers/mtd/mtdcore.c +32 -0
index 6eb52ed..cb86657 100644
@@ -142,3 +142,47 @@ void put_mtd_device(struct mtd_info *mtd)
 	c = --mtd->usecount;
 	BUG_ON(c < 0);
 }
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+/**
+ * mtd_get_len_incl_bad
+ *
+ * Check if length including bad blocks fits into device.
+ *
+ * @param mtd an MTD device
+ * @param offset offset in flash
+ * @param length image length
+ * @return image length including bad blocks in *len_incl_bad and whether or not
+ *         the length returned was truncated in *truncated
+ */
+void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+			  const uint64_t length, uint64_t *len_incl_bad,
+			  int *truncated)
+{
+	*truncated = 0;
+	*len_incl_bad = 0;
+
+	if (!mtd->block_isbad) {
+		*len_incl_bad = length;
+		return;
+	}
+
+	uint64_t len_excl_bad = 0;
+	uint64_t block_len;
+
+	while (len_excl_bad < length) {
+		block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
+
+		if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1)))

drivers/mtd/mtdcore.c void put_mtd_device(struct mtd_info *mtd) · line 186

Quoted 10 lines
drivers/mtd/mtdcore.c +10 -0
+			len_excl_bad += block_len;
+
+		*len_incl_bad += block_len;
+		offset       += block_len;
+
+		if (offset >= mtd->size) {
+			*truncated = 1;
+			break;
+		}
+	}

If this function is called with offset == mtd->size, you should return length zero and truncated, without calling block_isbad().

-Scott

#21 lore raw

PATCH v5 2/5 mtd: add an mtd method for get_len_incl_bad()

Quoted 26 lines · Scott Wood
Quoted 24 lines · On Mon, 30 Aug 2010 13:38:57 -0400 Ben Gardiner <[email protected]>…
(quoted diff) +24 -0
+void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+ ? ? ? ? ? ? ? ? ? ? ? const uint64_t length, uint64_t *len_incl_bad,
+ ? ? ? ? ? ? ? ? ? ? ? int *truncated)
+{
+ ? ? *truncated = 0;
+ ? ? *len_incl_bad = 0;
+
+ ? ? if (!mtd->block_isbad) {
+ ? ? ? ? ? ? *len_incl_bad = length;
+ ? ? ? ? ? ? return;
+ ? ? }
+
+ ? ? uint64_t len_excl_bad = 0;
+ ? ? uint64_t block_len;
+
+ ? ? while (len_excl_bad < length) {
+ ? ? ? ? ? ? block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
+
+ ? ? ? ? ? ? if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
+ ? ? ? ? ? ? ? ? ? ? len_excl_bad += block_len;
+
+ ? ? ? ? ? ? *len_incl_bad += block_len;
+ ? ? ? ? ? ? offset ? ? ? += block_len;
+
Quoted 8 lines
Quoted 5 lines

+ ? ? ? ? ? ? if (offset >= mtd->size) {
+ ? ? ? ? ? ? ? ? ? ? *truncated = 1;
+ ? ? ? ? ? ? ? ? ? ? break;
+ ? ? ? ? ? ? }
+ ? ? }

If this function is called with offset == mtd->size, you should return length zero and truncated, without calling block_isbad().

Good point. Will do.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#22 lore raw

PATCH v6 2/5 mtd: add an mtd method for get_len_incl_bad()

In reply to Ben Gardiner

The logic to 'spread' mtd partitions needs to calculate the length in the mtd device, including bad blocks.

This patch introduces a new function, mtd_get_len_incl_bad that can return both the length including bad blocks and whether that length was truncated on the device. This new function will be used by the mtdparts spread command later in this series. The definition of the function is #ifdef'd out in configurations that do not use the new 'mtdparts spread' command.

---

Note: the mtd_get_len_incl_bad() function could also be used by the get_len_incl_bad() function in nand_util.c except for the fact that boards can enable NAND support without enabling MTD support. A note has been added to get_len_incl_bad() to remind us to refactor when/if MTD support is available whenever NAND support is enabled.

V5:
* introduced in v5 of this patchset

V6:
* return zero length and truncated if mtd_get_len_incl_bad is called with offset>=size -- as per Scott Wood's review comments

---
 drivers/mtd/mtdcore.c        |   49 ++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/nand_util.c |    6 +++++
 include/linux/mtd/mtd.h      |    4 ++-
 3 files changed, 58 insertions(+), 1 deletions(-)
drivers/mtd/mtdcore.c +49 -0
index 6eb52ed..78f2a08 100644
@@ -142,3 +142,52 @@ void put_mtd_device(struct mtd_info *mtd)
 	c = --mtd->usecount;
 	BUG_ON(c < 0);
 }
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+/**
+ * mtd_get_len_incl_bad
+ *
+ * Check if length including bad blocks fits into device.
+ *
+ * @param mtd an MTD device
+ * @param offset offset in flash
+ * @param length image length
+ * @return image length including bad blocks in *len_incl_bad and whether or not
+ *         the length returned was truncated in *truncated
+ */
+void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+			  const uint64_t length, uint64_t *len_incl_bad,
+			  int *truncated)
+{
+	*truncated = 0;
+	*len_incl_bad = 0;
+
+	if (offset >= mtd->size) {
+		*truncated = 1;
+		return;
+	}
+
+	if (!mtd->block_isbad) {
+		*len_incl_bad = length;
+		return;
+	}
+
+	uint64_t len_excl_bad = 0;
+	uint64_t block_len;
+
+	while (len_excl_bad < length) {
+		block_len = mtd->erasesize - (offset & (mtd->erasesize - 1));
+
+		if (!mtd->block_isbad(mtd, offset & ~(mtd->erasesize - 1)))
+			len_excl_bad += block_len;
+
+		*len_incl_bad += block_len;
+		offset       += block_len;
+
+		if (offset >= mtd->size) {
+			*truncated = 1;
+			break;
+		}
+	}
+}
+#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
drivers/mtd/nand/nand_util.c +6 -0
index 29c42f7..622237f 100644
@@ -435,6 +435,12 @@ int nand_unlock(struct mtd_info *mtd, ulong start, ulong length)
 static size_t get_len_incl_bad (nand_info_t *nand, loff_t offset,
 				const size_t length)
 {
+	/*
+	 * TODO: replace this implementation with a call to
+	 * mtd_get_len_incl_bad((struct mtd_info *) nand, ...)
+	 * when CONFIG_MTD_DEVICE is required for NAND support
+	 */
+
 	size_t len_incl_bad = 0;
 	size_t len_excl_bad = 0;
 	size_t block_len;
include/linux/mtd/mtd.h +3 -1
index 16556c4..8e8ec7c 100644
@@ -259,7 +259,9 @@ extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num);
 extern struct mtd_info *get_mtd_device_nm(const char *name);
 
 extern void put_mtd_device(struct mtd_info *mtd);
-
+extern void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
+				 const uint64_t length, uint64_t *len_incl_bad,
+				 int *truncated);
 /* XXX U-BOOT XXX */
 #if 0
 struct mtd_notifier {
Signature · 1 line
1.7.0.4

A message that is not in the archive (sent off-list or not yet received): [email protected]

#24 lore raw

PATCH v5 3/5 mtdparts: show net size in mtdparts list

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

CC Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>

---

V2:
* formatting: spaces after 'if' and 'for'
* the entire new feature is conditional on a macro, there is now a zero-byte binary size impact when the macro is not defined.
* return the net parition size directly from net_part_size instead of using an output variable

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix line length over 80 chars
* update copyright of cmd_mtdparts.c

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* removed copyright statement and changelog from file header
* re-grouped list_partition #ifdefs into one
* fixed multi-line comment style

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 2/4 to 3/5
* return uint64_t instead of u32 for net_size
* do a quick if((cond) return
* calculate net_size by adding-up good blocks instead of subtracting bad blocks
* try to strike a balance; reuse more code between the branches of #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) in print_partition_table

---
 common/cmd_mtdparts.c |   74 +++++++++++++++++++++++++++++++++++++++++++-----
 drivers/mtd/mtdcore.c |    5 ++-
 2 files changed, 69 insertions(+), 10 deletions(-)
common/cmd_mtdparts.c +66 -8
index 772ad54..a8912ed 100644
@@ -1215,38 +1215,96 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
  */
-static void list_partitions(void)
+static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+	uint64_t gross_size, trailing_bad_size = 0;
+	int truncated = 0;
+
+	mtd_get_len_incl_bad(mtd, part->offset, part->size, &gross_size,
+			     &truncated);
+
+	if (!truncated) {
+			mtd_get_len_incl_bad(mtd, part->offset + part->size,
+					     mtd->erasesize, &trailing_bad_size,
+					     &truncated);
+			trailing_bad_size -= mtd->erasesize;
+	}
+
+	return part->size - (gross_size - trailing_bad_size - part->size);
+}
+#endif
+
+static void print_partition_table(void)
 {
 	struct list_head *dentry, *pentry;
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
 
-	debug("\n---list_partitions---\n");
-	list_for_each(dentry, &devices) {
+list_for_each(dentry, &devices) {
 		dev = list_entry(dentry, struct mtd_device, link);
+		/* list partitions for given device */
+		part_num = 0;
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		struct mtd_info *mtd;
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+
+		printf("\ndevice %s%d <%s>, # parts = %d\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				dev->id->mtd_id, dev->num_parts);
+		printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+		list_for_each(pentry, &dev->parts) {
+			u32 net_size;
+			char *size_note;
+
+			part = list_entry(pentry, struct part_info, link);
+			net_size = net_part_size(mtd, part);
+			size_note = part->size == net_size ? " " : " (!)";
+			printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+					part_num, part->name, part->size,
+					net_size, size_note, part->offset,
+					part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
 				MTD_DEV_TYPE(dev->id->type), dev->id->num,
 				dev->id->mtd_id, dev->num_parts);
 		printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
 
-		/* list partitions for given device */
-		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
 			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
 					part_num, part->name, part->size,
 					part->offset, part->mask_flags);
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 			part_num++;
 		}
 	}
+
 	if (list_empty(&devices))
 		printf("no partitions defined\n");
+}
+
+/**
+ * Format and print out a partition list for each device from global device
+ * list.
+ */
+static void list_partitions(void)
+{
+	struct part_info *part;
+
+	debug("\n---list_partitions---\n");
+	print_partition_table();
 
 	/* current_mtd_dev is not NULL only when we have non empty device list */
 	if (current_mtd_dev) {
drivers/mtd/mtdcore.c +3 -2
index cb86657..211b993 100644
@@ -143,7 +143,8 @@ void put_mtd_device(struct mtd_info *mtd)
 	BUG_ON(c < 0);
 }
 
-#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD) || \
+    defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**
  * mtd_get_len_incl_bad
  *
@@ -185,4 +186,4 @@ void mtd_get_len_incl_bad(struct mtd_info *mtd, uint64_t offset,
 		}
 	}
 }
-#endif /* defined(CONFIG_CMD_MTDPARTS_SPREAD) */
+#endif
Signature · 1 line
1.7.0.4
#25 lore raw

PATCH v5 3/5 mtdparts: show net size in mtdparts list

Quoted 17 lines · On Mon, 30 Aug 2010 13:38:58 -0400 Ben Gardiner <[email protected]>…
common/cmd_mtdparts.c +12 -3
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
  */
-static void list_partitions(void)
+static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+	uint64_t gross_size, trailing_bad_size = 0;
+	int truncated = 0;
+
+	mtd_get_len_incl_bad(mtd, part->offset, part->size, &gross_size,

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1241

Quoted 10 lines
common/cmd_mtdparts.c +10 -0
+			     &truncated);
+
+	if (!truncated) {
+			mtd_get_len_incl_bad(mtd, part->offset + part->size,
+					     mtd->erasesize, &trailing_bad_size,
+					     &truncated);
+			trailing_bad_size -= mtd->erasesize;
+	}
+
+	return part->size - (gross_size - trailing_bad_size - part->size);

I'm not sure I follow the logic here...

You're trying to find net size given gross size, but you first treat the gross size as a net size and get the gross size of *that*.

If it was truncated, then you'll return a value that
is still probably greater than the partition's true net size. For example, suppose you called this on the final partition, which includes at least one bad block (or the BBT, which is marked bad). mtd_get_len_incl_bad() will return the full partition size and set truncated. You'll end up with part->size - (part->size - 0 - part->size), which evaluates to part->size. The function should have returned something less than part->size.

If it was not truncated, suppose the partition had two bad blocks, and the next partition had its second block bad. mtd_get_len_incl_bad() will return part->size plus 3, since it ran into the next partition's bad block. The second call to mtd_get_len_incl_bad() will return one block, since it never got to the next partition's second block. Thus net_part_size() will return part->size - ((part->size + 3) - 0 - part->size), or part->size - 3. The right answer was part->size - 2.

I don't think a net-to-gross transformation is useful as a base for a gross-to-net transformation.

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1252

Quoted 13 lines
common/cmd_mtdparts.c +5 -2
+}
+#endif
+
+static void print_partition_table(void)
 {
 	struct list_head *dentry, *pentry;
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
 
-	debug("\n---list_partitions---\n");
-	list_for_each(dentry, &devices) {
+list_for_each(dentry, &devices) {

Wrong indentation.

Quoted 30 lines
common/cmd_mtdparts.c +25 -0
 		dev = list_entry(dentry, struct mtd_device, link);
+		/* list partitions for given device */
+		part_num = 0;
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		struct mtd_info *mtd;
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+
+		printf("\ndevice %s%d <%s>, # parts = %d\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				dev->id->mtd_id, dev->num_parts);
+		printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+		list_for_each(pentry, &dev->parts) {
+			u32 net_size;
+			char *size_note;
+
+			part = list_entry(pentry, struct part_info, link);
+			net_size = net_part_size(mtd, part);
+			size_note = part->size == net_size ? " " : " (!)";
+			printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+					part_num, part->name, part->size,
+					net_size, size_note, part->offset,
+					part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
 				MTD_DEV_TYPE(dev->id->type), dev->id->num,
 				dev->id->mtd_id, dev->num_parts);
 		printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1289

Quoted 10 lines
common/cmd_mtdparts.c +1 -3
 
-		/* list partitions for given device */
-		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
 			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
 					part_num, part->name, part->size,
 					part->offset, part->mask_flags);
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */

I'll let Wolfgang speak up if this really is how he wants it done, but this seems like too much duplication to me. And what if someone else wants to add another optional field, do we end up with 4 versions? Then 8 versions the next time?

Is this really worth ifdeffing at all?

Quoted 5 lines
drivers/mtd/mtdcore.c +0 -0
index cb86657..211b993 100644

drivers/mtd/mtdcore.c void put_mtd_device(struct mtd_info *mtd) · line 150

Quoted 9 lines
drivers/mtd/mtdcore.c +2 -1
@@ -143,7 +143,8 @@ void put_mtd_device(struct mtd_info *mtd)
 	BUG_ON(c < 0);
 }
 
-#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD) || \
+    defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**
  * mtd_get_len_incl_bad
  *

Let's avoid stuff like this -- I'd define the function unconditionally. IMHO, the right solution to saving space from unused functions is function-sections/gc-sections.

-Scott

#26 lore raw

PATCH v5 3/5 mtdparts: show net size in mtdparts list

Quoted 53 lines · Scott Wood
Quoted 17 lines · On Mon, 30 Aug 2010 13:38:58 -0400 Ben Gardiner <[email protected]>…

+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
?/**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
? */

(quoted diff) +6 -1
-static void list_partitions(void)
+static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+ ? ? uint64_t gross_size, trailing_bad_size = 0;
+ ? ? int truncated = 0;
+
+ ? ? mtd_get_len_incl_bad(mtd, part->offset, part->size, &gross_size,

Review

Quoted 10 lines
(quoted diff) +10 -0
+ ? ? ? ? ? ? ? ? ? ? ? ? ?&truncated);
+
+ ? ? if (!truncated) {
+ ? ? ? ? ? ? ? ? ? ? mtd_get_len_incl_bad(mtd, part->offset + part->size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?mtd->erasesize, &trailing_bad_size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?&truncated);
+ ? ? ? ? ? ? ? ? ? ? trailing_bad_size -= mtd->erasesize;
+ ? ? }
+
+ ? ? return part->size - (gross_size - trailing_bad_size - part->size);

I'm not sure I follow the logic here...

You're trying to find net size given gross size, but you first treat the gross size as a net size and get the gross size of *that*.

If it was truncated, then you'll return a value that
is still probably greater than the partition's true net size. ?For example, suppose you called this on the final partition, which includes at least one bad block (or the BBT, which is marked bad). mtd_get_len_incl_bad() will return the full partition size and set truncated. ?You'll end up with part->size - (part->size - 0 - part->size), which evaluates to part->size. ?The function should have returned something less than part->size.

If it was not truncated, suppose the partition had two bad blocks, and the next partition had its second block bad. ?mtd_get_len_incl_bad() will return part->size plus 3, since it ran into the next partition's bad block. ?The second call to mtd_get_len_incl_bad() will return one block, since it never got to the next partition's second block. ?Thus net_part_size() will return part->size - ((part->size + 3) - 0 - part->size), or part->size - 3. ?The right answer was part->size - 2.

Quoted 2 lines

I don't think a net-to-gross transformation is useful as a base for a gross-to-net transformation.

Right -- I was trying to maximize reuse of the new function but failed. But you're right that it just isn't suitable for reuse here. I'll go back to counting good blocks.

Quoted 10 lines
Quoted 10 lines
common/cmd_mtdparts.c +4 -0
+}
+#endif
+
+static void print_partition_table(void)

?{
? ? ? struct list_head *dentry, *pentry;
? ? ? struct part_info *part;
? ? ? struct mtd_device *dev;
? ? ? int part_num;

Quoted 5 lines
Quoted 3 lines

- ? ? debug("\n---list_partitions---\n");
- ? ? list_for_each(dentry, &devices) {
+list_for_each(dentry, &devices) {

Wrong indentation.

Sorry.

Quoted 31 lines
Quoted 31 lines

? ? ? ? ? ? ? dev = list_entry(dentry, struct mtd_device, link);
+ ? ? ? ? ? ? /* list partitions for given device */
+ ? ? ? ? ? ? part_num = 0;

(quoted diff) +23 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ ? ? ? ? ? ? struct mtd_info *mtd;
+
+ ? ? ? ? ? ? if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ ? ? ? ? ? ? ? ? ? ? return;
+
+ ? ? ? ? ? ? printf("\ndevice %s%d <%s>, # parts = %d\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev->id->mtd_id, dev->num_parts);
+ ? ? ? ? ? ? printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+ ? ? ? ? ? ? list_for_each(pentry, &dev->parts) {
+ ? ? ? ? ? ? ? ? ? ? u32 net_size;
+ ? ? ? ? ? ? ? ? ? ? char *size_note;
+
+ ? ? ? ? ? ? ? ? ? ? part = list_entry(pentry, struct part_info, link);
+ ? ? ? ? ? ? ? ? ? ? net_size = net_part_size(mtd, part);
+ ? ? ? ? ? ? ? ? ? ? size_note = part->size == net_size ? " " : " (!)";
+ ? ? ? ? ? ? ? ? ? ? printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part_num, part->name, part->size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? net_size, size_note, part->offset,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */

? ? ? ? ? ? ? printf("\ndevice %s%d <%s>, # parts = %d\n",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? MTD_DEV_TYPE(dev->id->type), dev->id->num, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev->id->mtd_id, dev->num_parts); ? ? ? ? ? ? ? printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");

Quoted 14 lines

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1289

Quoted 9 lines

- ? ? ? ? ? ? /* list partitions for given device */
- ? ? ? ? ? ? part_num = 0;
? ? ? ? ? ? ? list_for_each(pentry, &dev->parts) {
? ? ? ? ? ? ? ? ? ? ? part = list_entry(pentry, struct part_info, link); ? ? ? ? ? ? ? ? ? ? ? printf("%2d: %-20s0x%08x\t0x%08x\t%d\n", ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part_num, part->name, part->size, ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part->offset, part->mask_flags);

common/cmd_mtdparts.c +1 -1
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */

I'll let Wolfgang speak up if this really is how he wants it done, but this seems like too much duplication to me. ?And what if someone else wants to add another optional field, do we end up with 4 versions? Then 8 versions the next time?

Yes it doesn't scale well with the number of fields printed -- see below.

Quoted 8 lines
Quoted 8 lines
drivers/mtd/mtdcore.c +0 -0
index cb86657..211b993 100644
@@ -143,7 +143,8 @@ void put_mtd_device(struct mtd_info *mtd)
 ? ? ? BUG_ON(c < 0);
 ?}
 
Quoted 10 lines
Quoted 6 lines
drivers/mtd/mtdcore.c +2 -1
-#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD) || \
+ ? ?defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)

?/**
? * mtd_get_len_incl_bad
? *

Let's avoid stuff like this -- I'd define the function unconditionally. ?IMHO, the right solution to saving space from unused functions is function-sections/gc-sections.

I'm really glad for all your input on these patches -- your patience with my endless revisions appears equally as endless.

But I'm not sure what I'm supposed to do with this block now since Wolfgang Denk <[email protected]> has asked for me to 1) not use a bunch of #ifdefs to define the field [1] 2) not introduce changes that increase the code size on boards that do not enable this feature [2] ... and you have asked me to do the opposite in both cases here.

I will definitely re-spin a v6 with all of the mistakes you have pointed out fixed. But I think I have to stick with zero-impact-on-size patch and the minimal #ifdefs there since Wolfgang Denk <[email protected]> has asked for that specifically.

Best Regards,
Ben Gardiner

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/82208
[2] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79419

---
Nanometrics Inc.
http://www.nanometrics.ca

#27 lore raw

PATCH v5 3/5 mtdparts: show net size in mtdparts list

Quoted 5 lines · On Tue, 31 Aug 2010 09:51:15 -0400 Ben Gardiner <[email protected]>…

But I'm not sure what I'm supposed to do with this block now since Wolfgang Denk <[email protected]> has asked for me to 1) not use a bunch of #ifdefs to define the field [1] 2) not introduce changes that increase the code size on boards that do not enable this feature [2] ... and you have asked me to do the opposite in both cases here.

Sometimes a request seems perfectly reasonable until you see what the consequences are. :-)

Wolfgang, how do you want this to be handled?

-Scott

#28 lore raw

PATCH v6 3/5 mtdparts: show net size in mtdparts list

In reply to Ben Gardiner

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

CC Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>

---

V2:
* formatting: spaces after 'if' and 'for'
* the entire new feature is conditional on a macro, there is now a zero-byte binary size impact when the macro is not defined.
* return the net parition size directly from net_part_size instead of using an output variable

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix line length over 80 chars
* update copyright of cmd_mtdparts.c

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* removed copyright statement and changelog from file header
* re-grouped list_partition #ifdefs into one
* fixed multi-line comment style

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 2/4 to 3/5
* return uint64_t instead of u32 for net_size
* do a quick if((cond) return
* calculate net_size by adding-up good blocks instead of subtracting bad blocks
* try to strike a balance; reuse more code between the branches of #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) in print_partition_table

V6:
* fix indentation on list_entry
* don't use mtd_get_len_incl_bad to get net_size anymore as it was a bad idea. Just count up the good blocks.

---
 common/cmd_mtdparts.c |   68 +++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 61 insertions(+), 7 deletions(-)
common/cmd_mtdparts.c +61 -7
index 772ad54..266844f 100644
@@ -1215,38 +1215,92 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
  */
-static void list_partitions(void)
+static uint64_t net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+	if (!mtd->block_isbad)
+		return part->size;
+
+	uint64_t i, net_size = 0;
+
+	for (i = 0; i < part->size; i += mtd->erasesize) {
+		if (!mtd->block_isbad(mtd, part->offset + i))
+			net_size += mtd->erasesize;
+	}
+	return net_size;
+}
+#endif
+
+static void print_partition_table(void)
 {
 	struct list_head *dentry, *pentry;
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
 
-	debug("\n---list_partitions---\n");
 	list_for_each(dentry, &devices) {
 		dev = list_entry(dentry, struct mtd_device, link);
+		/* list partitions for given device */
+		part_num = 0;
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		struct mtd_info *mtd;
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+
+		printf("\ndevice %s%d <%s>, # parts = %d\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				dev->id->mtd_id, dev->num_parts);
+		printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+		list_for_each(pentry, &dev->parts) {
+			u32 net_size;
+			char *size_note;
+
+			part = list_entry(pentry, struct part_info, link);
+			net_size = net_part_size(mtd, part);
+			size_note = part->size == net_size ? " " : " (!)";
+			printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+					part_num, part->name, part->size,
+					net_size, size_note, part->offset,
+					part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
 				MTD_DEV_TYPE(dev->id->type), dev->id->num,
 				dev->id->mtd_id, dev->num_parts);
 		printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
 
-		/* list partitions for given device */
-		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
 			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
 					part_num, part->name, part->size,
 					part->offset, part->mask_flags);
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 			part_num++;
 		}
 	}
+
 	if (list_empty(&devices))
 		printf("no partitions defined\n");
+}
+
+/**
+ * Format and print out a partition list for each device from global device
+ * list.
+ */
+static void list_partitions(void)
+{
+	struct part_info *part;
+
+	debug("\n---list_partitions---\n");
+	print_partition_table();
 
 	/* current_mtd_dev is not NULL only when we have non empty device list */
 	if (current_mtd_dev) {
Signature · 1 line
1.7.0.4
#29 lore raw

v6 cover mtdparts: add bad-block skipping

In reply to Ben Gardiner

Ben Gardiner (5):
mtdparts: regroup calls to get_mtd_device_nm
mtd: add an mtd method for get_len_incl_bad()
mtdparts: show net size in mtdparts list
mtdparts: add new sub-command "spread"
mtdparts: new add.spread: add part skipping bad blocks

 common/cmd_mtdparts.c        |  260 +++++++++++++++++++++++++++++++++++++-----
 drivers/mtd/mtdcore.c        |   49 ++++++++
 drivers/mtd/nand/nand_util.c |    6 +
 include/linux/mtd/mtd.h      |    4 +-
 4 files changed, 287 insertions(+), 32 deletions(-)

This patch series is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> [1]. I started with Harald's original patch and migrated it to a new mtdparts sub-command and added an interface to the new functionality via a 'mtdparts add' variant.

I tried to keep it at the level of the mtd subsystem. Whereas the dynparts patch was limited to NAND flashes, I believe this patch will work on any mtd device that can report bad blocks.

These new commands can be useful when gang programming NAND chips where the gang programmer is capable only of skipping bad blocks. One can use a master image that contains images of each of the partitions padded-out to their spec'd sizes; when u-boot first comes up 'mtdparts default; mtdparts spread' (or a seq of 'mtdpart add.spread' commands) will produce a partition table that matches what was put there by the gang-programmer.

It can also be useful when doing in-situ programming with u-boot being the flash programmer as demonstrated by the openmoko project's use of the 'dynpart' command [2] upon which this patch series was based.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549
[2] http://wiki.openmoko.org/wiki/NAND_bad_blocks

---

V2:
* formating: spaces after 'if' and for
* printing net partition sizes feature is now conditional on the new CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES macro; patch 2/4 was adding 264 bytes to the virtlab2 build -- now it adds 0 bytes -- see below for more binary size impact details
* changed the net_part_size method to return the net size instead of using an output variable
* checking mtd->block_isbad function pointer before dereferencing
* there were some trailing whitespace errors when applying 3/4 and 4/4 that I have fixed now

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* more checkpatch fixes
* adding openmoko to the copyright statements in cmd_mtdparts.c

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* re-grouped list_partition #ifdefs into one
* removed changelog and my (C) from file header
* added source of port to the commit message
* fixed multi-line comment style
* indentation only by tabs
* check for s == NULL when looking for '.' in command
* do not include support for the '.i' synonym
* rename to 'add.spread' to match 'mtdparts spread' as per Scott Wood's suggestion.

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered patches; V5 introduces patch 2/5
* return uint64_t instead of u32 for net_size
* do a quick if((cond) return
* calculate net_size by adding-up good blocks instead of subtracting bad blocks
* try to strike a balance; reuse more code between the branches of #if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) in print_partition_table
* don't push dangling lines to the right
* fix spelling errors in comments
* more hanging arguments alignment
* refactor the spread_partition function so that it delegates the bad-block counting to the mtd_get_len_incl_bad function -- as per Scott Woods' suggestion.
* don't reproduce the same call to spread_partitions on either side of the check for existing device -- as per Scott Wood's comments.

V6:
* return zero length and truncated if mtd_get_len_incl_bad is called with offset>=size -- as per Scott Wood's review comments
* fix indentation on list_entry
* don't use mtd_get_len_incl_bad to get net_size anymore as it was a bad idea. Just count up the good blocks.
* check truncated return value to handle trying to absorb bad blocks past the end of the device -- as per Scott Wood's review comments

Testing was performed with da850evm.h plus NAND enabled. Here is an example u-boot console session to demonstrate how the commands work:

-------------------------------------------------------------------------------
U-Boot > mtdparts default
U-Boot > nand bad

Device 0 bad blocks:
062c0000
0a140000
128a0000
12e20000
18bc0000
1ff80000
1ffa0000
1ffc0000
1ffe0000
U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07020000      0x07000000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07ae0000      0
 6: initrd_b            0x00400000      0x00400000      0x07ee0000      0
 7: rootfs_b            0x07020000      0x07000000 (!)  0x082e0000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdparts spread
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot > mtdparts

device nand0 <davinci_nand.1>, # parts = 11
#: name size net size offset
mask_flags

 0: zero                0x000c0000      0x000c0000      0x00000000      1
 1: conf                0x00200000      0x00200000      0x000c0000      0
 2: kernel_a            0x00400000      0x00400000      0x002c0000      0
 3: initrd_a            0x00400000      0x00400000      0x006c0000      0
 4: rootfs_a            0x07040000      0x07020000 (!)  0x00ac0000      0
 5: kernel_b            0x00400000      0x00400000      0x07b00000      0
 6: initrd_b            0x00400000      0x00400000      0x07f00000      0
 7: rootfs_b            0x07040000      0x07020000 (!)  0x08300000      0

active partition: nand0,0 - (zero) 0x00020000 @ 0x00000000

defaults:
mtdids : nand0=davinci_nand.1
mtdparts: mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a), 4m(initrd_a),112m(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b) U-Boot >
U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.spread nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b)

U-Boot > mtdpart del rootfs_b
U-Boot > mtdpart add.spread nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),114816k(rootfs_b) U-Boot >
U-Boot > mtdparts del rootfs_b
U-Boot > mtdparts add nand0 112m rootfs_b
U-Boot > print mtdparts mtdparts=mtdparts=davinci_nand.1:768k(zero)ro,2m(conf),4m(kernel_a),4m(initrd_a) ,114816k(rootfs_a),4m(kernel_b),4m(initrd_b),112m(rootfs_b)
-------------------------------------------------------------------------------

I verified the patches with checkpatch.

I confirmed that MAKEALL for 'ARM9' and '8xx' did not introduce any additional warnings.

I tested the binary size and compiler warnings on ARM9 and 8xx. The patch series saves 24 bytes of text on 8xx and 30 bytes of text on arm9 -- when none of the config options are enabled. When the config options are enabled, text grows by 1413 bytes on arm9.

#30 lore raw

v6 cover mtdparts: add bad-block skipping

Quoted 7 lines · Ben Gardiner

Ben Gardiner (5):
mtdparts: regroup calls to get_mtd_device_nm
mtd: add an mtd method for get_len_incl_bad()
mtdparts: show net size in mtdparts list
mtdparts: add new sub-command "spread"
mtdparts: new add.spread: add part skipping bad blocks

Quoted 5 lines
 common/cmd_mtdparts.c        |  260 +++++++++++++++++++++++++++++++++++++-----
 drivers/mtd/mtdcore.c        |   49 ++++++++
 drivers/mtd/nand/nand_util.c |    6 +
 include/linux/mtd/mtd.h      |    4 +-
 4 files changed, 287 insertions(+), 32 deletions(-)

Applied to u-boot-nand-flash next

Sent a followup patch for a couple minor issues.

-Scott

#31 lore raw

PATCH v4 1/4 mtdparts: regroup calls to get_mtd_device_nm

In reply to Ben Gardiner

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

---

V2:
* formatting: add space after 'if'
* added acked-by tag as requested by Stefan

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* fixed multi-line comment style

---
 common/cmd_mtdparts.c |   45 ++++++++++++++++++++++++++++++---------------
 1 files changed, 30 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +30 -15
index ceec5a9..772ad54 100644
@@ -286,6 +286,29 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/**
+ * Produce a mtd_info given a type and num.
+ *
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +320,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, mtd_dev);
+	if (get_mtd_info(id->type, id->num, &mtd))
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +702,17 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 /**
  * Check device number to be within valid range for given device type.
  *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
  * @return 0 if device is valid, 1 otherwise
  */
 int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if (get_mtd_info(type, num, &mtd))
 		return 1;
-	}
 
 	*size = mtd->size;
 
Signature · 1 line
1.7.0.4
#32 lore raw

PATCH v4 2/4 mtdparts: show net size in mtdparts list

In reply to Ben Gardiner

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

---

V2:
* formatting: spaces after 'if' and 'for'
* the entire new feature is conditional on a macro, there is now a zero-byte binary size impact when the macro is not defined.
* return the net parition size directly from net_part_size instead of using an output variable

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix line length over 80 chars
* update copyright of cmd_mtdparts.c

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* removed copyright statement and changelog from file header
* re-grouped list_partition #ifdefs into one
* fixed multi-line comment style

---
 common/cmd_mtdparts.c |   70 +++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 65 insertions(+), 5 deletions(-)
common/cmd_mtdparts.c +65 -5
index 772ad54..500a38e 100644
@@ -1215,18 +1215,65 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
  */
-static void list_partitions(void)
+static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+	if (mtd->block_isbad) {
+		u32 i, bb_delta = 0;
+
+		for (i = 0; i < part->size; i += mtd->erasesize) {
+			if (mtd->block_isbad(mtd, part->offset + i))
+				bb_delta += mtd->erasesize;
+		}
+
+		return part->size - bb_delta;
+	} else {
+		return part->size;
+	}
+}
+#endif
+
+static void print_partition_table(void)
 {
 	struct list_head *dentry, *pentry;
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
 
-	debug("\n---list_partitions---\n");
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+	list_for_each(dentry, &devices) {
+		struct mtd_info *mtd;
+
+		dev = list_entry(dentry, struct mtd_device, link);
+		printf("\ndevice %s%d <%s>, # parts = %d\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				dev->id->mtd_id, dev->num_parts);
+		printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+
+		/* list partitions for given device */
+		part_num = 0;
+		list_for_each(pentry, &dev->parts) {
+			u32 net_size;
+			char *size_note;
+
+			part = list_entry(pentry, struct part_info, link);
+			net_size = net_part_size(mtd, part);
+			size_note = part->size == net_size ? " " : " (!)";
+			printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+					part_num, part->name, part->size,
+					net_size, size_note, part->offset,
+					part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 	list_for_each(dentry, &devices) {
 		dev = list_entry(dentry, struct mtd_device, link);
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
@@ -1241,12 +1288,25 @@ static void list_partitions(void)
 			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
 					part_num, part->name, part->size,
 					part->offset, part->mask_flags);
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 			part_num++;
 		}
 	}
+
 	if (list_empty(&devices))
 		printf("no partitions defined\n");
+}
+
+/**
+ * Format and print out a partition list for each device from global device
+ * list.
+ */
+static void list_partitions(void)
+{
+	struct part_info *part;
+
+	debug("\n---list_partitions---\n");
+	print_partition_table();
 
 	/* current_mtd_dev is not NULL only when we have non empty device list */
 	if (current_mtd_dev) {
Signature · 1 line
1.7.0.4
#33 lore raw

PATCH v4 2/4 mtdparts: show net size in mtdparts list

Quoted 10 lines · Ben Gardiner
common/cmd_mtdparts.c +1 -0
index 772ad54..500a38e 100644
@@ -1215,18 +1215,65 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
 /**

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1226

Quoted 10 lines
common/cmd_mtdparts.c +6 -3
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
  */
-static void list_partitions(void)
+static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)

Don't assume partition size fits in 32 bits. part->size is uint64_t.

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1236

Quoted 10 lines
common/cmd_mtdparts.c +10 -0
+{
+	if (mtd->block_isbad) {
+		u32 i, bb_delta = 0;
+
+		for (i = 0; i < part->size; i += mtd->erasesize) {
+			if (mtd->block_isbad(mtd, part->offset + i))
+				bb_delta += mtd->erasesize;
+		}
+
+		return part->size - bb_delta;

Seems like it'd be slightly simpler to just count up the good blocks, rather than count the bad blocks and subtract.

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1239

Quoted 3 lines
common/cmd_mtdparts.c +3 -0
+	} else {
+		return part->size;
+	}

It's usually more readable to do this:

if (can't do this)

	return;

do this;

than this

if (can do this)

	do this;
else
	don't;

When "do this" is more than a line or two, and there's nothing else to be done in the function afterward.

Quoted 42 lines
common/cmd_mtdparts.c +31 -1
+}
+#endif
+
+static void print_partition_table(void)
 {
 	struct list_head *dentry, *pentry;
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
 
-	debug("\n---list_partitions---\n");
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+	list_for_each(dentry, &devices) {
+		struct mtd_info *mtd;
+
+		dev = list_entry(dentry, struct mtd_device, link);
+		printf("\ndevice %s%d <%s>, # parts = %d\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				dev->id->mtd_id, dev->num_parts);
+		printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+
+		/* list partitions for given device */
+		part_num = 0;
+		list_for_each(pentry, &dev->parts) {
+			u32 net_size;
+			char *size_note;
+
+			part = list_entry(pentry, struct part_info, link);
+			net_size = net_part_size(mtd, part);
+			size_note = part->size == net_size ? " " : " (!)";
+			printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+					part_num, part->name, part->size,
+					net_size, size_note, part->offset,
+					part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
 	list_for_each(dentry, &devices) {
 		dev = list_entry(dentry, struct mtd_device, link);
 		printf("\ndevice %s%d <%s>, # parts = %d\n",

common/cmd_mtdparts.c static void list_partitions(void) · line 1291

Quoted 5 lines
common/cmd_mtdparts.c +1 -1
@@ -1241,12 +1288,25 @@ static void list_partitions(void)
 			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
 					part_num, part->name, part->size,
 					part->offset, part->mask_flags);
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */

Is there any way you could share more of this between the two branches?

-Scott

#34 lore raw

PATCH v4 2/4 mtdparts: show net size in mtdparts list

Hi Scott,

Thank you for reviewing patches 2-4.

Quoted 9 lines · Scott Wood
Quoted 8 lines · Ben Gardiner
common/cmd_mtdparts.c +0 -0
index 772ad54..500a38e 100644
@@ -1215,18 +1215,65 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 ? ? ? return ret;
 ?}
 
Quoted 14 lines

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1226

Quoted 12 lines
common/cmd_mtdparts.c +1 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)

?/**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
? */

common/cmd_mtdparts.c +1 -1
-static void list_partitions(void)
+static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)

Don't assume partition size fits in 32 bits. ?part->size is uint64_t.

My mistake.

Quoted 5 lines
Quoted 5 lines
common/cmd_mtdparts.c +5 -0
+{
+ ? ? if (mtd->block_isbad) {
+ ? ? ? ? ? ? u32 i, bb_delta = 0;
+
+ ? ? ? ? ? ? for (i = 0; i < part->size; i += mtd->erasesize) {
Quoted 8 lines
Quoted 5 lines

+ ? ? ? ? ? ? ? ? ? ? if (mtd->block_isbad(mtd, part->offset + i))
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? bb_delta += mtd->erasesize;
+ ? ? ? ? ? ? }
+
+ ? ? ? ? ? ? return part->size - bb_delta;

Seems like it'd be slightly simpler to just count up the good blocks, rather than count the bad blocks and subtract.

Will do.

Quoted 13 lines
Quoted 3 lines

+ ? ? } else {
+ ? ? ? ? ? ? return part->size;
+ ? ? }

It's usually more readable to do this:

if (can't do this)
? ? ? ?return;

do this;

than this

Quoted 7 lines

if (can do this)
? ? ? ?do this;
else
? ? ? ?don't;

When "do this" is more than a line or two, and there's nothing else to be done in the function afterward.

Right. I think you told me this in the env.oob review also. I'll keep this in mind for future submissions.

Quoted 41 lines
Quoted 41 lines
common/cmd_mtdparts.c +4 -0
+}
+#endif
+
+static void print_partition_table(void)

?{
? ? ? struct list_head *dentry, *pentry;
? ? ? struct part_info *part;
? ? ? struct mtd_device *dev;
? ? ? int part_num;

- ? ? debug("\n---list_partitions---\n");

common/cmd_mtdparts.c +27 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ ? ? list_for_each(dentry, &devices) {
+ ? ? ? ? ? ? struct mtd_info *mtd;
+
+ ? ? ? ? ? ? dev = list_entry(dentry, struct mtd_device, link);
+ ? ? ? ? ? ? printf("\ndevice %s%d <%s>, # parts = %d\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? dev->id->mtd_id, dev->num_parts);
+ ? ? ? ? ? ? printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+ ? ? ? ? ? ? if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ ? ? ? ? ? ? ? ? ? ? return;
+
+ ? ? ? ? ? ? /* list partitions for given device */
+ ? ? ? ? ? ? part_num = 0;
+ ? ? ? ? ? ? list_for_each(pentry, &dev->parts) {
+ ? ? ? ? ? ? ? ? ? ? u32 net_size;
+ ? ? ? ? ? ? ? ? ? ? char *size_note;
+
+ ? ? ? ? ? ? ? ? ? ? part = list_entry(pentry, struct part_info, link);
+ ? ? ? ? ? ? ? ? ? ? net_size = net_part_size(mtd, part);
+ ? ? ? ? ? ? ? ? ? ? size_note = part->size == net_size ? " " : " (!)";
+ ? ? ? ? ? ? ? ? ? ? printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part_num, part->name, part->size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? net_size, size_note, part->offset,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part->mask_flags);
+#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */

? ? ? list_for_each(dentry, &devices) {
? ? ? ? ? ? ? dev = list_entry(dentry, struct mtd_device, link); ? ? ? ? ? ? ? printf("\ndevice %s%d <%s>, # parts = %d\n",

Quoted 8 lines

common/cmd_mtdparts.c static void list_partitions(void) · line 1291

Quoted 6 lines
common/cmd_mtdparts.c +1 -1
@@ -1241,12 +1288,25 @@ static void list_partitions(void)
 ? ? ? ? ? ? ? ? ? ? ? printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part_num, part->name, part->size,
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part->offset, part->mask_flags);
-
+#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */

Is there any way you could share more of this between the two branches?

I definitely could. :)

I had everything-possible shared between the branches in v3 but I think I took it too far since:

Quoted 2 lines · Wolfgang Denk

This is way too much #ifdef's here. Please separate the code and use a single #ifdef only.

I'll try my best to strike a balance here in v5.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#35 lore raw

PATCH v4 2/4 mtdparts: show net size in mtdparts list

In reply to Scott Wood
Quoted 9 lines · Scott Wood
Quoted 8 lines · Ben Gardiner
common/cmd_mtdparts.c +0 -0
index 772ad54..500a38e 100644
@@ -1215,18 +1215,65 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 ? ? ? return ret;
 ?}
 
Quoted 14 lines

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1226

Quoted 12 lines
common/cmd_mtdparts.c +1 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)

?/**
- * Format and print out a partition list for each device from global device
- * list.
+ * Get the net size (w/o bad blocks) of the given partition.
+ *
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
? */

common/cmd_mtdparts.c +1 -1
-static void list_partitions(void)
+static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)

Don't assume partition size fits in 32 bits. ?part->size is uint64_t.

I understand that (at some point) we need to support part->size uint64_t but the HEAD of u-boot [1], u-boot-nand-flash/master [2] and u-boot-nand-flash/next [3] have u32 for part->size. Changing this to uint64_t would require reformatting the list_partitions size column as a 64bit hex number -- as would treating the net_size there as a uint64_t. This would be a change with impact of greater scope than intended with this patchset.

I hope it will be acceptable to do the net_part_size return as uin64_t and continue treating both the part->size and net_size as u32?

Best Regards,
Ben Gardiner

[1] http://git.denx.de/?p=u-boot.git;a=blob;f=include/jffs2/load_kernel.h;h=906eb3d3cdbe9f5b539c6341c873ed87de876be5;hb=HEAD#l49
[2] http://git.denx.de/?p=u-boot/u-boot-nand-flash.git;a=blob;f=include/jffs2/load_kernel.h;h=906eb3d3cdbe9f5b539c6341c873ed87de876be5;hb=refs/heads/master#l49
[3] http://git.denx.de/?p=u-boot/u-boot-nand-flash.git;a=blob;f=include/jffs2/load_kernel.h;h=906eb3d3cdbe9f5b539c6341c873ed87de876be5;hb=refs/heads/next#l49

---
Nanometrics Inc.
http://www.nanometrics.ca

#36 lore raw

PATCH v4 2/4 mtdparts: show net size in mtdparts list

Quoted 6 lines · Ben Gardiner
Quoted 1 line · Scott Wood

Don't assume partition size fits in 32 bits. part->size is uint64_t.

I understand that (at some point) we need to support part->size uint64_t but the HEAD of u-boot [1], u-boot-nand-flash/master [2] and u-boot-nand-flash/next [3] have u32 for part->size.

I see, I was looking at mtd_partition, not part_info. Why are we using jffs2's partition struct for anything other than jffs2? Why does jffs2 have its own partition struct at all?

-Scott

#37 lore raw

PATCH v4 2/4 mtdparts: show net size in mtdparts list

Quoted 7 lines · Scott Wood
Quoted 6 lines · Ben Gardiner
Quoted 2 lines · On Thu, Aug 26, 2010 at 2:57 PM, Scott Wood<[email protected]> ?wrote:

Don't assume partition size fits in 32 bits. ?part->size is uint64_t.

Quoted 7 lines
Quoted 3 lines

I understand that (at some point) we need to support part->size uint64_t but the HEAD of u-boot [1], ?u-boot-nand-flash/master [2] and u-boot-nand-flash/next [3] have u32 for part->size.

I see, I was looking at mtd_partition, not part_info. ?Why are we using jffs2's partition struct for anything other than jffs2? ?Why does jffs2 have its own partition struct at all?

I don't know why. I can only offer the following information:

Cscope says that include/jffs2/load_kernel.h is the file in which part_info is defined.

'git blame' indicates that part_info has been used in common/cmd_mtdparts.c since 68d7d65100e84df00bca971c114092731b441090 when Stefan Roese <[email protected]> extracted the command from common/cmd_jffs2.c

The users of mtd_partition (add_one_partition and add_mtd_partitions) are called from ubi_dev_scan where the mtd_partition structure is intialized from a part_info structure.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#38 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

In reply to Ben Gardiner

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

This patch is based on a port of the 'dynnamic partitions' feature by Harald Welte <[email protected]>; ported from commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git. Whereas Harald's feature used a compile-time array to specify partitions, the feature introduced by this patch uses the mtdparts environment variable.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed
* check for null mtd->block_isbad before dereferencing

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* update copyright statement of cmd_mtdparts.c to include openmoko's copyright of the 'dynamic partitions' functionality using commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git as reference.

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* fixed multi-line comment style
* removed changelog and my (C) from file header
* added source of port to the commit message
* fixed multi-line comment style
* indentation only by tabs

---
 common/cmd_mtdparts.c |  117 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 116 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +116 -1
index 500a38e..7e2e232 100644
@@ -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 <[email protected]>
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -1430,6 +1433,105 @@ 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 parition would start on a
+ * good blcok 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,
+							 u32 *next_offset)
+{
+	if (!mtd->block_isbad)
+		goto out;
+
+	u32 i, bb_delta = 0;
+
+	for (i = part->offset; i - bb_delta < part->offset + part->size;
+						i += mtd->erasesize) {
+		if (mtd->block_isbad(mtd, i))
+			bb_delta += mtd->erasesize;
+	}
+
+	/*
+	 * Absorb bad blocks immeadiately following this
+	 * partition also into the partition, such that
+	 * the next partition starts with a good block.
+	 */
+	while (i < mtd->size && mtd->block_isbad(mtd, i)) {
+		bb_delta += mtd->erasesize;
+		i += mtd->erasesize;
+	}
+
+	if (part->offset + part->size + bb_delta > mtd->size) {
+		part->size = mtd->size - part->offset - bb_delta;
+		printf("truncated partition %s to %d bytes\n", part->name,
+							      part->size);
+	}
+
+	part->size += bb_delta;
+
+out:
+	*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;
+	u32 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 at 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.
@@ -1920,6 +2022,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);
 }
 
@@ -1943,7 +2050,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"
Signature · 1 line
1.7.0.4
#39 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1448

Quoted 2 lines · Ben Gardiner
common/cmd_mtdparts.c +2 -0
+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+							 u32 *next_offset)

As in patch 2, change u32 to uint64_t.

Quoted 11 lines
common/cmd_mtdparts.c +11 -0
+{
+	if (!mtd->block_isbad)
+		goto out;
+
+	u32 i, bb_delta = 0;
+
+	for (i = part->offset; i - bb_delta < part->offset + part->size;
+						i += mtd->erasesize) {
+		if (mtd->block_isbad(mtd, i))
+			bb_delta += mtd->erasesize;
+	}

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1469

Quoted 10 lines
common/cmd_mtdparts.c +10 -0
+
+	/*
+	 * Absorb bad blocks immeadiately following this
+	 * partition also into the partition, such that
+	 * the next partition starts with a good block.
+	 */
+	while (i < mtd->size && mtd->block_isbad(mtd, i)) {
+		bb_delta += mtd->erasesize;
+		i += mtd->erasesize;
+	}

Could this be refactored with get_len_incl_bad()? It should return both the updated length and a flag indicating whether it was truncated.

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1514

Quoted 5 lines
common/cmd_mtdparts.c +5 -0
+			debug("spread_partitions: device = %s%d, partition %d ="
+				" (%s) 0x%08x at 0x%08x\n",
+				MTD_DEV_TYPE(dev->id->type), dev->id->num,
+				part_num, part->name, part->size,
+						    part->offset);

Why the extra indent on that last line?

IMHO, it's also nicer to line up continuation lines like this:

debug("spread_partitions..."

      " (%s) ..."
      MTD_DEV...
      part_num...
      part->offset);

-Scott

#40 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 5 lines · Scott Wood
Quoted 2 lines · Ben Gardiner

+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?u32 *next_offset)

As in patch 2, change u32 to uint64_t.

Ok.

Quoted 16 lines
Quoted 16 lines
(quoted diff) +16 -0
+{
+ ? ? if (!mtd->block_isbad)
+ ? ? ? ? ? ? goto out;
+
+ ? ? u32 i, bb_delta = 0;
+
+ ? ? for (i = part->offset; i - bb_delta < part->offset + part->size;
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i += mtd->erasesize) {
+ ? ? ? ? ? ? if (mtd->block_isbad(mtd, i))
+ ? ? ? ? ? ? ? ? ? ? bb_delta += mtd->erasesize;
+ ? ? }
+
+ ? ? /*
+ ? ? ?* Absorb bad blocks immeadiately following this
+ ? ? ?* partition also into the partition, such that
+ ? ? ?* the next partition starts with a good block.
Quoted 8 lines
Quoted 5 lines

+ ? ? ?*/
+ ? ? while (i < mtd->size && mtd->block_isbad(mtd, i)) {
+ ? ? ? ? ? ? bb_delta += mtd->erasesize;
+ ? ? ? ? ? ? i += mtd->erasesize;
+ ? ? }

Could this be refactored with get_len_incl_bad()? ?It should return both the updated length and a flag indicating whether it was truncated.

Yes, I think so. Good point.

Quoted 8 lines
Quoted 5 lines

+ ? ? ? ? ? ? ? ? ? ? debug("spread_partitions: device = %s%d, partition %d ="
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? " (%s) 0x%08x at 0x%08x\n",
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? MTD_DEV_TYPE(dev->id->type), dev->id->num,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? part_num, part->name, part->size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part->offset);

Why the extra indent on that last line?

Quoted 7 lines

IMHO, it's also nicer to line up continuation lines like this:

debug("spread_partitions..."
? ? ?" (%s) ..."
? ? ?MTD_DEV...
? ? ?part_num...
? ? ?part->offset);

Right. I think I forgot also about this formatting requirement which you pointed out in the env.oob review. I'll get it right soon enough.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#41 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 26 lines · Ben Gardiner
Quoted 16 lines · Scott Wood
Quoted 16 lines
(quoted diff) +16 -0
+{
+ ? ? if (!mtd->block_isbad)
+ ? ? ? ? ? ? goto out;
+
+ ? ? u32 i, bb_delta = 0;
+
+ ? ? for (i = part->offset; i - bb_delta < part->offset + part->size;
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? i += mtd->erasesize) {
+ ? ? ? ? ? ? if (mtd->block_isbad(mtd, i))
+ ? ? ? ? ? ? ? ? ? ? bb_delta += mtd->erasesize;
+ ? ? }
+
+ ? ? /*
+ ? ? ?* Absorb bad blocks immeadiately following this
+ ? ? ?* partition also into the partition, such that
+ ? ? ?* the next partition starts with a good block.
Quoted 8 lines
Quoted 5 lines

+ ? ? ?*/
+ ? ? while (i < mtd->size && mtd->block_isbad(mtd, i)) {
+ ? ? ? ? ? ? bb_delta += mtd->erasesize;
+ ? ? ? ? ? ? i += mtd->erasesize;
+ ? ? }

Could this be refactored with get_len_incl_bad()? ?It should return both the updated length and a flag indicating whether it was truncated.

Quoted 1 line

Yes, I think so. Good point.

I have performed a refactoring but I have reached an impasse: the 'mtdparts spread' command is written for mtd devices whereas the get_len_incl_bad() function is for NAND devices. I extracted a function, mtd_get_len_incl_bad(), to which both the spread_partition and nand_utils.c:get_len_incl_bad() function then delegated. But since a board may have NAND enabled but not MTD_DEVICE (i.e. guruplug) I get link errors sometimes. ATM I'm thinking of leaving the original implementation of get_len_incl_bad in an #else. An alternative is to move 'mtdparts spread' to 'nand mtdparts.spread' -- only OneNAND and NAND devices (currently) have bad_block functions.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#42 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 7 lines · Ben Gardiner

On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner <[email protected]> wrote:
I have performed a refactoring but I have reached an impasse: the 'mtdparts spread' command is written for mtd devices whereas the get_len_incl_bad() function is for NAND devices. I extracted a function, mtd_get_len_incl_bad(), to which both the spread_partition and nand_utils.c:get_len_incl_bad() function then delegated.

I figured the NAND code could just call the MTD-ized get_len_incl_bad() directly.

Quoted 2 lines

But since a board may have NAND enabled but not MTD_DEVICE (i.e. guruplug) I get link errors sometimes.

Grr... Eventually we ought to make NAND depend on MTD_DEVICE. It's 808 bytes currently in my build, but if we could get rid of/reduce specialized client code, it could more than make up for it.

For now, I guess don't worry about sharing the code.

Quoted 4 lines

ATM I'm thinking of leaving the original
implementation of get_len_incl_bad in an #else. An alternative is to move 'mtdparts spread' to 'nand mtdparts.spread' -- only OneNAND and NAND devices (currently) have bad_block functions.

There's too much duplication between NAND and OneNAND as is; I'd rather do it at the MTD layer.

-Scott

#43 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 8 lines · Scott Wood
Quoted 6 lines · Ben Gardiner

On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner <[email protected]> ?wrote:
But since a board may have NAND enabled but not MTD_DEVICE (i.e. guruplug) I get
link errors sometimes.

Quoted 5 lines

Grr... Eventually we ought to make NAND depend on MTD_DEVICE. ?It's 808 bytes currently in my build, but if we could get rid of/reduce specialized client code, it could more than make up for it.

For now, I guess don't worry about sharing the code.

Ok -- thanks, Scott. I'll re-spin on Monday.

Quoted 7 lines
Quoted 4 lines

ATM I'm thinking of leaving the original
implementation of get_len_incl_bad in an #else. An alternative is to move 'mtdparts spread' to 'nand mtdparts.spread' -- only OneNAND and NAND devices (currently) have bad_block functions.

There's too much duplication between NAND and OneNAND as is; I'd rather do it at the MTD layer.

Whew -- I'm glad I don't have to migrate all of the patches to new files. :)

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#44 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

In reply to Scott Wood
Quoted 16 lines · Scott Wood
Quoted 7 lines · Ben Gardiner

On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner <[email protected]> wrote:
I have performed a refactoring but I have reached an impasse: the 'mtdparts spread' command is written for mtd devices whereas the get_len_incl_bad() function is for NAND devices. I extracted a function, mtd_get_len_incl_bad(), to which both the spread_partition and nand_utils.c:get_len_incl_bad() function then delegated.

I figured the NAND code could just call the MTD-ized get_len_incl_bad() directly.

Quoted 3 lines

But since a board may have NAND enabled but not MTD_DEVICE (i.e. guruplug) I get
link errors sometimes.

Quoted 5 lines

Grr... Eventually we ought to make NAND depend on MTD_DEVICE. It's 808 bytes currently in my build, but if we could get rid of/reduce specialized client code, it could more than make up for it.

For now, I guess don't worry about sharing the code.

Plus, I've got some changes to the NAND command/util code I'm about to send out that touch this -- if sharing is going to be a pain, I can go back to the version that only passes back "fits with bad blocks", "fits with no bad blocks", or "doesn't fit", and doesn't deal with 64-bit sizes because it's only used by read/write which is limited by pointer size. That simpler version is 128 bytes smaller in my build.

-Scott

#45 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 9 lines · Scott Wood
Quoted 1 line · Scott Wood

For now, I guess don't worry about sharing the code.

Plus, I've got some changes to the NAND command/util code I'm about to send out that touch this -- if sharing is going to be a pain, I can go back to the version that only passes back "fits with bad blocks", "fits with no bad blocks", or "doesn't fit", and doesn't deal with 64-bit sizes because it's only used by read/write which is limited by pointer size. ?That simpler version is 128 bytes smaller in my build.

I imagine you don't have to go back. I wouldn't want to make the merge harder; but as long as there is a way to get the the size-including-bad-blocks and truncation status given an offset and target size. Please continue your work and I'll find a way to make 'mtdparts spread' fit with it after your post..

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#46 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 4 lines · On Fri, 27 Aug 2010 23:59:13 -0400 Ben Gardiner <[email protected]>…
Quoted 3 lines · Scott Wood
Quoted 1 line · Scott Wood

For now, I guess don't worry about sharing the code.

Quoted 8 lines
Quoted 6 lines

Plus, I've got some changes to the NAND command/util code I'm about to send out that touch this -- if sharing is going to be a pain, I can go back to the version that only passes back "fits with bad blocks", "fits with no bad blocks", or "doesn't fit", and doesn't deal with 64-bit sizes because it's only used by read/write which is limited by pointer size. ?That simpler version is 128 bytes smaller in my build.

I imagine you don't have to go back.

I already did; it's smaller and slightly simpler for what it currently needs to do. It would still be easy to switch to using the MTD function later.

-Scott

#47 lore raw

PATCH v4 3/4 mtdparts: add new sub-command "spread"

Quoted 14 lines · Scott Wood
Quoted 11 lines · On Fri, 27 Aug 2010 23:59:13 -0400 Ben Gardiner <[email protected]>…
Quoted 9 lines · Scott Wood
Quoted 1 line · Scott Wood

For now, I guess don't worry about sharing the code.

Plus, I've got some changes to the NAND command/util code I'm about to send out that touch this -- if sharing is going to be a pain, I can go back to the version that only passes back "fits with bad blocks", "fits with no bad blocks", or "doesn't fit", and doesn't deal with 64-bit sizes because it's only used by read/write which is limited by pointer size. ?That simpler version is 128 bytes smaller in my build.

Quoted 5 lines
Quoted 1 line

I imagine you don't have to go back.

I already did; it's smaller and slightly simpler for what it currently needs to do. ?It would still be easy to switch to using the MTD function later.

Ok, no problem. If you're interested in taking this series through the nand-testing tree I would be happy to rebase this series and integrate with your MTD changes.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#48 lore raw

PATCH v5 4/5 mtdparts: add new sub-command "spread"

In reply to Ben Gardiner

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

This patch is based on a port of the 'dynnamic partitions' feature by Harald Welte <[email protected]>; ported from commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git. Whereas Harald's feature used a compile-time array to specify partitions, the feature introduced by this patch uses the mtdparts environment variable.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed
* check for null mtd->block_isbad before dereferencing

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* update copyright statement of cmd_mtdparts.c to include openmoko's copyright of the 'dynamic partitions' functionality using commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git as reference.

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* fixed multi-line comment style
* removed changelog and my (C) from file header
* added source of port to the commit message
* fixed multi-line comment style
* indentation only by tabs

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 3/4 to 4/5
* use uint64_t for net_size
* don't push dangling lines to the right
* offsets to uint64_t
* fix spelling errors in comments
* more hanging arguments alignment
* refactor the spread_partition function so that it delegates the bad-block counting to the mtd_get_len_incl_bad function -- as per Scott Woods' suggestion.

---
 common/cmd_mtdparts.c |  110 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 109 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +109 -1
index a8912ed..fb8c77b 100644
@@ -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 <[email protected]>
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -1428,6 +1431,98 @@ 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);
+		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 at 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.
@@ -1918,6 +2013,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);
 }
 
@@ -1941,7 +2041,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"
Signature · 1 line
1.7.0.4
#49 lore raw

PATCH v5 4/5 mtdparts: add new sub-command "spread"

Quoted 4 lines · On Mon, 30 Aug 2010 13:38:59 -0400 Ben Gardiner <[email protected]>…
common/cmd_mtdparts.c +4 -0
+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+			     uint64_t *next_offset)
+{
+	uint64_t net_size, padding_size = 0;

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1458

Quoted 10 lines
common/cmd_mtdparts.c +10 -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.
+	 */

Why is the first block of a partition special?

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1462

Quoted 4 lines
common/cmd_mtdparts.c +4 -0
+	if (!truncated) {
+		mtd_get_len_incl_bad(mtd, part->offset + net_size,
+				     mtd->erasesize, &padding_size, &truncated);
+		padding_size -= mtd->erasesize;

What if this is the last partition? You're relying on an implementation quick (bug?) that mtd_get_len_incl_bad() will let you exceed the device size by a block if you start there. If it returned the more expected zero in such a case, you'll end up subtracting a block from net_size.

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1465

Quoted 3 lines
common/cmd_mtdparts.c +3 -0
+	}
+
+	if (truncated) {

} else {

-Scott

#50 lore raw

PATCH v5 4/5 mtdparts: add new sub-command "spread"

Quoted 10 lines · On Mon, 30 Aug 2010 16:01:05 -0500 Scott Wood <[email protected]> wrote:

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1462

Quoted 4 lines · On Mon, 30 Aug 2010 13:38:59 -0400 Ben Gardiner <[email protected]>…
common/cmd_mtdparts.c +4 -0
+	if (!truncated) {
+		mtd_get_len_incl_bad(mtd, part->offset + net_size,
+				     mtd->erasesize, &padding_size, &truncated);
+		padding_size -= mtd->erasesize;

What if this is the last partition? You're relying on an implementation quick (bug?)

Grr, s/quick/quirk/

-Scot

#51 lore raw

PATCH v5 4/5 mtdparts: add new sub-command "spread"

In reply to Scott Wood
Quoted 19 lines · Scott Wood
Quoted 4 lines · On Mon, 30 Aug 2010 13:38:59 -0400 Ben Gardiner <[email protected]>…
(quoted diff) +4 -0
+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+ ? ? ? ? ? ? ? ? ? ? ? ? ?uint64_t *next_offset)
+{
+ ? ? uint64_t net_size, padding_size = 0;

Review

Quoted 10 lines
(quoted diff) +10 -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.
+ ? ? ?*/

Why is the first block of a partition special?

This (arbitrary) decision to re-assign the bad-blocks that would normally be at the start of the next partition to the end of this partition is carried forward from the design of Harald Welte <[email protected]> from the openmoko u-boot feature [1].

Since the behaviour of the read and write commands (as you well know) is to skip bad blocks, the same end result of any read or write would be obtained regardless of whether the bad-blocks were assigned to the end of this partition or the start of the the next partition -- I think this is what you are getting at with your question: there is nothing special about the first block of a partition.

One particular advantage to assigning these bad blocks to the end of the partitions is that reads and writes on any partitions occurring later during the execution of u-boot (and of Linux if the same mtdparts are passed as a boot variable) will not have to skip immediately past the bad block(s) at the beginning of the partition.

I can easily reverse the behaviour here to keep the bad blocks at the beginning of the current partition if that is what you would prefer. But unless you say so I will keep it as-is to preserve the design from openmoko.

Quoted 10 lines
Quoted 4 lines

+ ? ? if (!truncated) {
+ ? ? ? ? ? ? mtd_get_len_incl_bad(mtd, part->offset + net_size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?mtd->erasesize, &padding_size, &truncated);
+ ? ? ? ? ? ? padding_size -= mtd->erasesize;

What if this is the last partition? ?You're relying on an implementation quick (bug?) that mtd_get_len_incl_bad() will let you exceed the device size by a block if you start there. ?If it returned the more expected zero in such a case, you'll end up subtracting a block from net_size.

Quoted 3 lines · Scott Wood

On Mon, 30 Aug 2010 16:01:05 -0500
Scott Wood <[email protected]> wrote:
Grr, s/quick/quirk/

Got it.

You're absolutely right I will add an additional check of the truncated return value.

Best Regards,
Ben Gardiner

[1] http://git.openmoko.org/?p=u-boot.git;a=commitdiff;h=e05835df019027391f58f9d8ce5e1257d6924798

---
Nanometrics Inc.
http://www.nanometrics.ca

#52 lore raw

PATCH v6 4/5 mtdparts: add new sub-command "spread"

In reply to Ben Gardiner

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

This patch is based on a port of the 'dynnamic partitions' feature by Harald Welte <[email protected]>; ported from commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git. Whereas Harald's feature used a compile-time array to specify partitions, the feature introduced by this patch uses the mtdparts environment variable.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed
* check for null mtd->block_isbad before dereferencing

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* update copyright statement of cmd_mtdparts.c to include openmoko's copyright of the 'dynamic partitions' functionality using commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git as reference.

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* fixed multi-line comment style
* removed changelog and my (C) from file header
* added source of port to the commit message
* fixed multi-line comment style
* indentation only by tabs

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 3/4 to 4/5
* use uint64_t for net_size
* don't push dangling lines to the right
* offsets to uint64_t
* fix spelling errors in comments
* more hanging arguments alignment
* refactor the spread_partition function so that it delegates the bad-block counting to the mtd_get_len_incl_bad function -- as per Scott Woods' suggestion.

V6:
* check truncated return value to handle trying to absorb bad blocks past the end of the device -- as per Scott Wood's review comments

---
 common/cmd_mtdparts.c |  113 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 112 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +112 -1
index 266844f..347e409 100644
@@ -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 <[email protected]>
+ *
  *   $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 at 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"
Signature · 1 line
1.7.0.4
#53 lore raw

PATCH v4 4/4 mtdparts: new add.spread: add part skipping bad blocks

In reply to Ben Gardiner

This patch adds a new 'mtdparts add' variant: add.spread. This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

CC Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* updating copyright to include addition of add.e command

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* removed changelog from file header
* check for s == NULL when looking for '.' in command
* do not include support for the '.i' synonym
* rename to 'add.spread' to match 'mtdparts spread' as per Scott Wood's suggestion.

---
 common/cmd_mtdparts.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +35 -1
index 7e2e232..6e42eff 100644
@@ -1959,9 +1959,14 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+	if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
 #define PART_ADD_DESC_MAXLEN 64
 		char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		char *s;
+		struct mtd_info *mtd;
+		u32 next_offset;
+#endif
 		u8 type, num, len;
 		struct mtd_device *dev;
 		struct mtd_device *dev_tmp;
@@ -1996,11 +2001,36 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
 				dev->id->num, dev->id->mtd_id);
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		s = strchr(argv[1], '.');
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+#endif
+
 		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (s && !strcmp(s, ".spread")) {
+				p = list_entry(dev->parts.next,
+					       struct part_info, link);
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n", p->name,
+								    p->size);
+			}
+#endif
 			device_add(dev);
 		} else {
 			/* merge new partition with existing ones*/
 			p = list_entry(dev->parts.next, struct part_info, link);
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (s && !strcmp(s, ".spread")) {
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n", p->name,
+								    p->size);
+			}
+#endif
 			if (part_add(dev_tmp, p) != 0) {
 				device_del(dev);
 				return 1;
@@ -2049,6 +2079,10 @@ U_BOOT_CMD(
 	"    - delete partition (e.g. part-id = nand0,1)\n"
 	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
 	"    - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif
 	"mtdparts default\n"
 	"    - reset partition table to defaults\n"
 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
Signature · 1 line
1.7.0.4
#54 lore raw

PATCH v4 4/4 mtdparts: new add.spread: add part skipping bad blocks

common/cmd_mtdparts.c int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 2013

Quoted 10 lines · Ben Gardiner
common/cmd_mtdparts.c +9 -0
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		s = strchr(argv[1], '.');
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+#endif
+
 		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (s && !strcmp(s, ".spread")) {

No need for the strchr, just do "if (!strcmp(&argv[1][3], ".spread"))".

Quoted 10 lines
common/cmd_mtdparts.c +8 -0
+				p = list_entry(dev->parts.next,
+					       struct part_info, link);
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n", p->name,
+								    p->size);
+			}
+#endif
 			device_add(dev);
 		} else {

common/cmd_mtdparts.c int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 2033

Quoted 10 lines
common/cmd_mtdparts.c +8 -0
 			/* merge new partition with existing ones*/
 			p = list_entry(dev->parts.next, struct part_info, link);
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (s && !strcmp(s, ".spread")) {
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n", p->name,
+								    p->size);
+			}
+#endif

Don't duplicate this on both sides of the "if"; instead do something like:

p = list_entry(dev->parts.next...);

if (!strcmp(&argv[1][3], ".spread"))

	spread_partition(mtd, p, &next_offset);
if ((dev_tmp = ...) {
	device_add(dev);
} else if (part_add(dev_tmp, p)) {
	device_del(dev);
	return 1;
}

-Scott

#55 lore raw

PATCH v4 4/4 mtdparts: new add.spread: add part skipping bad blocks

Quoted 13 lines · Scott Wood
Quoted 10 lines · Ben Gardiner
common/cmd_mtdparts.c +7 -0
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ ? ? ? ? ? ? s = strchr(argv[1], '.');
+
+ ? ? ? ? ? ? if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ ? ? ? ? ? ? ? ? ? ? return 1;
+#endif
+

? ? ? ? ? ? ? if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) { +#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ ? ? ? ? ? ? ? ? ? ? if (s && !strcmp(s, ".spread")) {

No need for the strchr, just do "if (!strcmp(&argv[1][3], ".spread"))".

Thanks for pointing that out -- I see it now.

Quoted 28 lines
Quoted 12 lines

+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? p = list_entry(dev->parts.next,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?struct part_info, link);
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? spread_partition(mtd, p, &next_offset);

(quoted diff) +5 -0
+
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? debug("increased %s to %d bytes\n", p->name,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? p->size);
+ ? ? ? ? ? ? ? ? ? ? }
+#endif

? ? ? ? ? ? ? ? ? ? ? device_add(dev);
? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? /* merge new partition with existing ones*/ ? ? ? ? ? ? ? ? ? ? ? p = list_entry(dev->parts.next, struct part_info, link);

Review

Quoted 8 lines
(quoted diff) +8 -0
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+ ? ? ? ? ? ? ? ? ? ? if (s && !strcmp(s, ".spread")) {
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? spread_partition(mtd, p, &next_offset);
+
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? debug("increased %s to %d bytes\n", p->name,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? p->size);
+ ? ? ? ? ? ? ? ? ? ? }
+#endif

Don't duplicate this on both sides of the "if"; instead do something like:

p = list_entry(dev->parts.next...);

if (!strcmp(&argv[1][3], ".spread"))
? ? ? ?spread_partition(mtd, p, &next_offset);

Quoted 6 lines

if ((dev_tmp = ...) {
? ? ? ?device_add(dev);
} else if (part_add(dev_tmp, p)) {
? ? ? ?device_del(dev);
? ? ? ?return 1;
}

Ok, I'll give it a shot.

Thank you again for your review and detailed comments. I appreciate you taking the time to help me get these patches prepared. I will integrate your comments on patches 2-4 shortly.

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#56 lore raw

PATCH v5 5/5 mtdparts: new add.spread: add part skipping bad blocks

In reply to Ben Gardiner

This patch adds a new 'mtdparts add' variant: add.spread. This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

CC Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* updating copyright to include addition of add.e command

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* removed changelog from file header
* check for s == NULL when looking for '.' in command
* do not include support for the '.i' synonym
* rename to 'add.spread' to match 'mtdparts spread' as per Scott Wood's suggestion.

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 4/4 to 5/5
* don't reproduce the same call to spread_partitions on either side of the check for existing device -- as per Scott Wood's comments.

---
 common/cmd_mtdparts.c |   34 ++++++++++++++++++++++++++--------
 1 files changed, 26 insertions(+), 8 deletions(-)
common/cmd_mtdparts.c +26 -8
index fb8c77b..d8cda77 100644
@@ -1950,9 +1950,13 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+	if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
 #define PART_ADD_DESC_MAXLEN 64
 		char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		struct mtd_info *mtd;
+		uint64_t next_offset;
+#endif
 		u8 type, num, len;
 		struct mtd_device *dev;
 		struct mtd_device *dev_tmp;
@@ -1987,15 +1991,25 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
 				dev->id->num, dev->id->mtd_id);
 
-		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+		p = list_entry(dev->parts.next, struct part_info, link);
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+
+		if (!strcmp(&argv[1][3], ".spread")) {
+			spread_partition(mtd, p, &next_offset);
+			debug("increased %s to %d bytes\n", p->name, p->size);
+		}
+#endif
+
+		dev_tmp = device_find(dev->id->type, dev->id->num);
+		if (dev_tmp == NULL) {
 			device_add(dev);
-		} else {
+		} else if (part_add(dev_tmp, p) != 0) {
 			/* merge new partition with existing ones*/
-			p = list_entry(dev->parts.next, struct part_info, link);
-			if (part_add(dev_tmp, p) != 0) {
-				device_del(dev);
-				return 1;
-			}
+			device_del(dev);
+			return 1;
 		}
 
 		if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
@@ -2040,6 +2054,10 @@ U_BOOT_CMD(
 	"    - delete partition (e.g. part-id = nand0,1)\n"
 	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
 	"    - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif
 	"mtdparts default\n"
 	"    - reset partition table to defaults\n"
 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
Signature · 1 line
1.7.0.4
#57 lore raw

PATCH v6 5/5 mtdparts: new add.spread: add part skipping bad blocks

This patch adds a new 'mtdparts add' variant: add.spread. This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

CC Wolfgang Denk <[email protected]>
CC Scott Wood <[email protected]>

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* updating copyright to include addition of add.e command

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* removed changelog from file header
* check for s == NULL when looking for '.' in command
* do not include support for the '.i' synonym
* rename to 'add.spread' to match 'mtdparts spread' as per Scott Wood's suggestion.

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 4/4 to 5/5
* don't reproduce the same call to spread_partitions on either side of the check for existing device -- as per Scott Wood's comments.

V6:
* unchanged

---
 common/cmd_mtdparts.c |   34 ++++++++++++++++++++++++++--------
 1 files changed, 26 insertions(+), 8 deletions(-)
common/cmd_mtdparts.c +26 -8
index 347e409..17865b7 100644
@@ -1949,9 +1949,13 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+	if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
 #define PART_ADD_DESC_MAXLEN 64
 		char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		struct mtd_info *mtd;
+		uint64_t next_offset;
+#endif
 		u8 type, num, len;
 		struct mtd_device *dev;
 		struct mtd_device *dev_tmp;
@@ -1986,15 +1990,25 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
 				dev->id->num, dev->id->mtd_id);
 
-		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+		p = list_entry(dev->parts.next, struct part_info, link);
+
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+
+		if (!strcmp(&argv[1][3], ".spread")) {
+			spread_partition(mtd, p, &next_offset);
+			debug("increased %s to %d bytes\n", p->name, p->size);
+		}
+#endif
+
+		dev_tmp = device_find(dev->id->type, dev->id->num);
+		if (dev_tmp == NULL) {
 			device_add(dev);
-		} else {
+		} else if (part_add(dev_tmp, p) != 0) {
 			/* merge new partition with existing ones*/
-			p = list_entry(dev->parts.next, struct part_info, link);
-			if (part_add(dev_tmp, p) != 0) {
-				device_del(dev);
-				return 1;
-			}
+			device_del(dev);
+			return 1;
 		}
 
 		if (generate_mtdparts_save(last_parts, MTDPARTS_MAXLEN) != 0) {
@@ -2039,6 +2053,10 @@ U_BOOT_CMD(
 	"    - delete partition (e.g. part-id = nand0,1)\n"
 	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
 	"    - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.spread <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif
 	"mtdparts default\n"
 	"    - reset partition table to defaults\n"
 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
Signature · 1 line
1.7.0.4
#58 lore raw

PATCH v3 1/4 mtdparts: regroup calls to get_mtd_device_nm

In reply to Ben Gardiner

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

---

V2:
* formatting: add space after 'if'
* added acked-by tag as requested by Stefan

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git

---
 common/cmd_mtdparts.c |   43 ++++++++++++++++++++++++++++---------------
 1 files changed, 28 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +28 -15
index 447486b..f1bed95 100644
@@ -286,6 +286,27 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/** Produce a mtd_info given a type and num
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +318,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, mtd_dev);
+	if (get_mtd_info(id->type, id->num, &mtd))
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +700,17 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 /**
  * Check device number to be within valid range for given device type.
  *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
  * @return 0 if device is valid, 1 otherwise
  */
 int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if (get_mtd_info(type, num, &mtd))
 		return 1;
-	}
 
 	*size = mtd->size;
 
Signature · 1 line
1.7.0.4
#59 lore raw

PATCH v5 1/5 mtdparts: regroup calls to get_mtd_device_nm

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

---

V2:
* formatting: add space after 'if'
* added acked-by tag as requested by Stefan

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* fixed multi-line comment style

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 1/4 to 1/5

---
 common/cmd_mtdparts.c |   45 ++++++++++++++++++++++++++++++---------------
 1 files changed, 30 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +30 -15
index ceec5a9..772ad54 100644
@@ -286,6 +286,29 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/**
+ * Produce a mtd_info given a type and num.
+ *
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +320,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, mtd_dev);
+	if (get_mtd_info(id->type, id->num, &mtd))
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +702,17 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 /**
  * Check device number to be within valid range for given device type.
  *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
  * @return 0 if device is valid, 1 otherwise
  */
 int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if (get_mtd_info(type, num, &mtd))
 		return 1;
-	}
 
 	*size = mtd->size;
 
Signature · 1 line
1.7.0.4
#60 lore raw

PATCH v6 1/5 mtdparts: regroup calls to get_mtd_device_nm

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

---

V2:
* formatting: add space after 'if'
* added acked-by tag as requested by Stefan

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git

V4:
* rebased to b417260d871d4d8d336c160d95ed40cc8c0fb0fa of
git://git.denx.de/u-boot.git
* fixed multi-line comment style

V5:
* rebased to 962ad59e25640e586e2bceabf67a628a27f8f508 of
git://git.denx.de/u-boot.git
* renumbered from 1/4 to 1/5

V6:
* unchanged

---
 common/cmd_mtdparts.c |   45 ++++++++++++++++++++++++++++++---------------
 1 files changed, 30 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +30 -15
index ceec5a9..772ad54 100644
@@ -286,6 +286,29 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/**
+ * Produce a mtd_info given a type and num.
+ *
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +320,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, mtd_dev);
+	if (get_mtd_info(id->type, id->num, &mtd))
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +702,17 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 /**
  * Check device number to be within valid range for given device type.
  *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
  * @return 0 if device is valid, 1 otherwise
  */
 int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if (get_mtd_info(type, num, &mtd))
 		return 1;
-	}
 
 	*size = mtd->size;
 
Signature · 1 line
1.7.0.4
#61 lore raw

PATCH v3 2/4 mtdparts: show net size in mtdparts list

In reply to Ben Gardiner

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

---

V2:
* formatting: spaces after 'if' and 'for'
* the entire new feature is conditional on a macro, there is now a zero-byte binary size impact when the macro is not defined.
* return the net parition size directly from net_part_size instead of using an output variable

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix line length over 80 chars
* update copyright of cmd_mtdparts.c

---
 common/cmd_mtdparts.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 53 insertions(+), 2 deletions(-)
common/cmd_mtdparts.c +53 -2
index f1bed95..84acd62 100644
@@ -15,6 +15,10 @@
  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
  *   kernel tree.
  *
+ * (C) Copyright 2010
+ * Ben Gardiner, Nanometrics Inc., <[email protected]>
+ *   Added net partition size output to mtdparts list command
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -1213,6 +1217,29 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+/** get the net size (w/o bad blocks) of the given partition
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
+ */
+static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+	if (mtd->block_isbad) {
+		u32 i, bb_delta = 0;
+
+		for (i = 0; i < part->size; i += mtd->erasesize) {
+			if (mtd->block_isbad(mtd, part->offset + i))
+				bb_delta += mtd->erasesize;
+		}
+
+		return part->size - bb_delta;
+	} else {
+		return part->size;
+	}
+}
+#endif
+
 /**
  * Format and print out a partition list for each device from global device
  * list.
@@ -1223,6 +1250,10 @@ static void list_partitions(void)
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+	struct mtd_info *mtd;
+	u32 net_size;
+#endif
 
 	debug("\n---list_partitions---\n");
 	list_for_each(dentry, &devices) {
@@ -1230,14 +1261,34 @@ static void list_partitions(void)
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
 				MTD_DEV_TYPE(dev->id->type), dev->id->num,
 				dev->id->mtd_id, dev->num_parts);
-		printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
+		printf(" #: name\t\tsize\t\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		"net size\t"
+#endif
+		"offset\t\tmask_flags\n");
+
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+#endif
 
 		/* list partitions for given device */
 		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
-			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+			net_size = net_part_size(mtd, part);
+#endif
+			printf("%2d: %-20s0x%08x\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+					"0x%08x%s\t"
+#endif
+					"0x%08x\t%d\n",
 					part_num, part->name, part->size,
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+					net_size,
+					part->size == net_size ? " " : " (!)",
+#endif
 					part->offset, part->mask_flags);
 
 			part_num++;
Signature · 1 line
1.7.0.4
#62 lore raw

PATCH v3 2/4 mtdparts: show net size in mtdparts list

Dear Ben Gardiner,

Quoted 16 lines · In message <[email protected]> you…

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

---

V2:
* formatting: spaces after 'if' and 'for'
* the entire new feature is conditional on a macro, there is now a zero-byte binary size impact when the macro is not defined.
* return the net parition size directly from net_part_size instead of using an output variable

Quoted 5 lines

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix line length over 80 chars
* update copyright of cmd_mtdparts.c

That was a bad idea. We do not add change logs to files, because we have the full history of changes in git.

common/cmd_mtdparts.c line 21

Quoted 10 lines
common/cmd_mtdparts.c +4 -0
@@ -15,6 +15,10 @@
  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
  *   kernel tree.
  *
+ * (C) Copyright 2010
+ * Ben Gardiner, Nanometrics Inc., <[email protected]>
+ *   Added net partition size output to mtdparts list command
+ *

NAK for this hunk.

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1225

Quoted 6 lines
common/cmd_mtdparts.c +6 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+/** get the net size (w/o bad blocks) of the given partition
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
+ */

Incorrect multiline comment style.

common/cmd_mtdparts.c static void list_partitions(void) · line 1268

Quoted 5 lines
common/cmd_mtdparts.c +5 -0
+		printf(" #: name\t\tsize\t\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		"net size\t"
+#endif
+		"offset\t\tmask_flags\n");

Incorrect indentation.

Quoted 13 lines
common/cmd_mtdparts.c +7 -1
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+#endif
 
 		/* list partitions for given device */
 		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
-			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+			net_size = net_part_size(mtd, part);
+#endif

common/cmd_mtdparts.c static void list_partitions(void) · line 1291

Quoted 10 lines
common/cmd_mtdparts.c +9 -0
+			printf("%2d: %-20s0x%08x\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+					"0x%08x%s\t"
+#endif
+					"0x%08x\t%d\n",
 					part_num, part->name, part->size,
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+					net_size,
+					part->size == net_size ? " " : " (!)",
+#endif

This is way too much #ifdef's here. Please separate the code and use a single #ifdef only.

Best regards,

Wolfgang Denk

Signature · 7 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Quote from the Boss after overriding the decision of a task force  he
created  to  find  a  solution:  "I'm  sorry  if  I ever gave you the
impression your input would have any effect on my  decision  for  the
outcome of this project!"
#63 lore raw

PATCH v3 2/4 mtdparts: show net size in mtdparts list

Dear Wolfgang,

Quoted 4 lines · Wolfgang Denk
Quoted 1 line

* update copyright of cmd_mtdparts.c

That was a bad idea. We do not add change logs to files, because we have the full history of changes in git.

just to clearly understand your point: Your objection is against the

Quoted 1 line
Quoted 1 line

+ * Added net partition size output to mtdparts list command

in the file itself, as it should be a changelog. Your objection is (I hope) not against the author claiming copyright in the source code file itself, right?

Copyright claims are something that you can hardly deny any author in the work itself - particularly since the majority of distributions are made as tarballs that do not contain the full git history.

While even in the US there is now no legal requirement anymore to have this copyright notice to claim copyright, it is still common practise and a good idea. I definitely can confirm this from the actual GPL enforcement work that I've been doing, where you have to substantiate the fact that you actually do have copyright... and when the source file contains such indication, it is pretty straight forward. If you'd have to explain the workings of a revision control system and how to extract this information first, it will be significantly more complex.

Regards,
Harald

Signature · 4 lines
- Harald Welte <[email protected]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)
#64 lore raw

PATCH v3 2/4 mtdparts: show net size in mtdparts list

Dear Harald Welte,

Quoted 7 lines · In message <[email protected]> you wrote:
Quoted 4 lines · Wolfgang Denk
Quoted 1 line

* update copyright of cmd_mtdparts.c

That was a bad idea. We do not add change logs to files, because we have the full history of changes in git.

Quoted 7 lines

just to clearly understand your point: Your objection is against the

Quoted 1 line
Quoted 1 line

+ * Added net partition size output to mtdparts list command

in the file itself, as it should be a changelog. Your objection is (I hope) not against the author claiming copyright in the source code file itself, right?

Correct.

Quoted 3 lines

Copyright claims are something that you can hardly deny any author in the work itself - particularly since the majority of distributions are made as tarballs that do not contain the full git history.

Agreed - at least for any significant contribution to the code. I don't think you mean that eauch author of a 10 line patch to a 1000 line file shouldbe added to the list of copyright holders?

In this respect, the patch we're discussing here is a bit on the
border: it's adding some 1...2% to the code size of this file, and the code is not exactly challanging. I would not have asked to have my own (C) added in a similar situation.

But to make things clear: My objection was against adding change log information.

Best regards,

Wolfgang Denk

Signature · 5 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
It is a good thing for an uneducated man to read books of quotations.
                        - Sir Winston Churchill _My Early Life_ ch. 9
#65 lore raw

PATCH v3 2/4 mtdparts: show net size in mtdparts list

In reply to Wolfgang Denk

Hi Wolfgang,

Thank you for the review comments. Could you give me some more details on how you would like the following resolved?

Quoted 21 lines · Wolfgang Denk

Dear Ben Gardiner,

Quoted 18 lines · In message <[email protected]> you…
common/cmd_mtdparts.c +4 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ ? ? ? ? ? ? if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+ ? ? ? ? ? ? ? ? ? ? return;
+#endif

? ? ? ? ? ? ? /* list partitions for given device */
? ? ? ? ? ? ? part_num = 0;
? ? ? ? ? ? ? list_for_each(pentry, &dev->parts) {
? ? ? ? ? ? ? ? ? ? ? part = list_entry(pentry, struct part_info, link);
- ? ? ? ? ? ? ? ? ? ? printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",

common/cmd_mtdparts.c +8 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ ? ? ? ? ? ? ? ? ? ? net_size = net_part_size(mtd, part);
+#endif
+ ? ? ? ? ? ? ? ? ? ? printf("%2d: %-20s0x%08x\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "0x%08x%s\t"
+#endif
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "0x%08x\t%d\n",
Quoted 8 lines

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1241

Quoted 5 lines

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part_num, part->name, part->size,

common/cmd_mtdparts.c +4 -0
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? net_size,
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? part->size == net_size ? " " : " (!)",
+#endif

This is way too much #ifdef's here. Please separate the code and use a single #ifdef only.

Would it be acceptable to do something like the following?

static void print_partition_table(...)
{
#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
...
#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
...
#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ }

/**
* Format and print out a partition list for each device from global device
* list.
*/
static void list_partitions(void)
{
...

print_partition_table(...)

/* current_mtd_dev is not NULL only when we have non empty device list */

	if (current_mtd_dev) {

...

puts("mtdparts: ");
puts(mtdparts_default ? mtdparts_default : "none"); puts("\n");
}

Best Regards,

Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#66 lore raw

PATCH v3 2/4 mtdparts: show net size in mtdparts list

Dear Ben Gardiner,

Quoted 11 lines · In message <[email protected]> you…

Would it be acceptable to do something like the following?

static void print_partition_table(...)
{
#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
...
#else /* !defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */
...
#endif /* defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES) */ }

If the whole body of the funtion is affectted, you better do:

	#if defined(xxx)
	static void print_partition_table(...)
	{
	    ...
	}
	#else
	static void print_partition_table(...)
	{
	    ...
	}
	#endif

Best regards,

Wolfgang Denk

Signature · 8 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
The alternative to genuflecting before the  god  of  code-bumming  is
finding  a  better  algorithm.  It should be clear that none such was
available. If your code is too slow, you must make it faster.  If  no
better algorithm is available, you must trim cycles.
                                 - td at alice.UUCP (Tom Duff) 29 Aug 88
#67 lore raw

PATCH v3 3/4 mtdparts: add new sub-command "spread"

In reply to Ben Gardiner

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed
* check for null mtd->block_isbad before dereferencing

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* update copyright statement of cmd_mtdparts.c to include openmoko's copyright of the 'dynamic partitions' functionality using commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git as reference.

---
 common/cmd_mtdparts.c |  122 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 120 insertions(+), 2 deletions(-)
common/cmd_mtdparts.c +120 -2
index 84acd62..c1adbd4 100644
@@ -15,9 +15,17 @@
  *   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 <[email protected]>
+ *   Add support for 'dynamic partitions.' Net partition sizes specified at
+ *   compile time where the layout in flash is adjusted in the presence of bad
+ *   blocks.
+ *
  * (C) Copyright 2010
  * Ben Gardiner, Nanometrics Inc., <[email protected]>
- *   Added net partition size output to mtdparts list command
+ *   Added net partition size output to mtdparts list command.
+ *   Ported 'dynamic partitions' support to current u-boot 'mtdparts spread'
+ *   command. Current mtdparts variable is now used as input.
  *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
@@ -1419,6 +1427,103 @@ 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 parition would start on a
+ * good blcok 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,
+							 u32 *next_offset)
+{
+	if (!mtd->block_isbad)
+		goto out;
+
+	u32 i, bb_delta = 0;
+
+	for (i = part->offset;
+	    i - bb_delta < part->offset + part->size;
+	    i += mtd->erasesize) {
+		if (mtd->block_isbad(mtd, i))
+			bb_delta += mtd->erasesize;
+	}
+
+	/* Absorb bad blocks immeadiately following this
+	  * partition also into the partition, such that
+	  * the next partition starts with a good block.
+	  */
+	while (i < mtd->size && mtd->block_isbad(mtd, i)) {
+		bb_delta += mtd->erasesize;
+		i += mtd->erasesize;
+	}
+
+	if (part->offset + part->size + bb_delta > mtd->size) {
+		part->size = mtd->size - part->offset - bb_delta;
+		printf("truncated partition %s to %d bytes\n", part->name,
+							      part->size);
+	}
+
+	part->size += bb_delta;
+
+out:
+	*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;
+	u32 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 at 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.
@@ -1909,6 +2014,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 */
+
 	cmd_usage(cmdtp);
 	return 1;
 }
@@ -1933,7 +2043,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"
Signature · 1 line
1.7.0.4
#68 lore raw

PATCH v3 3/4 mtdparts: add new sub-command "spread"

Dear Ben Gardiner,

Quoted 21 lines · In message <[email protected]> you…

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed
* check for null mtd->block_isbad before dereferencing

Quoted 8 lines

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* update copyright statement of cmd_mtdparts.c to include openmoko's copyright of the 'dynamic partitions' functionality using commit e05835df019027391f58f9d8ce5e1257d6924798 of
git://git.openmoko.org/u-boot.git as reference.

NAK. Please add this to the commit message, and add Harald's SoB line instead.

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1438

Quoted 9 lines
common/cmd_mtdparts.c +9 -0
+#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 parition would start on a
+ * good blcok 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)
+ */

Incorrect multiline comment style.

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1452

Quoted 6 lines
common/cmd_mtdparts.c +6 -0
+	for (i = part->offset;
+	    i - bb_delta < part->offset + part->size;
+	    i += mtd->erasesize) {
+		if (mtd->block_isbad(mtd, i))
+			bb_delta += mtd->erasesize;
+	}

Indentation by TAB only, please.

common/cmd_mtdparts.c static int delete_partition(const char *id) · line 1457

Quoted 4 lines
common/cmd_mtdparts.c +4 -0
+	/* Absorb bad blocks immeadiately following this
+	  * partition also into the partition, such that
+	  * the next partition starts with a good block.
+	  */

Incorrect multiline comment style. More follow. Please fix globally.

Best regards,

Wolfgang Denk

Signature · 5 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"There was no difference between  the  behavior  of  a  god  and  the
operations of pure chance..."   - Thomas Pynchon, _Gravity's Rainbow_
#69 lore raw

PATCH v3 4/4 mtdparts: new add.e: add part skipping bad blocks

In reply to Ben Gardiner

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i). This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* updating copyright to include addition of add.e command

---
 common/cmd_mtdparts.c |   38 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 37 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +37 -1
index c1adbd4..d57f9ad 100644
@@ -26,6 +26,8 @@
  *   Added net partition size output to mtdparts list command.
  *   Ported 'dynamic partitions' support to current u-boot 'mtdparts spread'
  *   command. Current mtdparts variable is now used as input.
+ *   Add the 'add.e' mtdparts command. Dynamic partitions can be added one at
+ *   a time -- specified by size only.
  *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
@@ -1951,9 +1953,14 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 	}
 
 	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+	if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
 #define PART_ADD_DESC_MAXLEN 64
 		char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		char *s;
+		struct mtd_info *mtd;
+		u32 next_offset;
+#endif
 		u8 type, num, len;
 		struct mtd_device *dev;
 		struct mtd_device *dev_tmp;
@@ -1988,11 +1995,36 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
 				dev->id->num, dev->id->mtd_id);
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		s = strchr(argv[1], '.');
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+#endif
+
 		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {
+				p = list_entry(dev->parts.next,
+					       struct part_info, link);
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n", p->name,
+								    p->size);
+			}
+#endif
 			device_add(dev);
 		} else {
 			/* merge new partition with existing ones*/
 			p = list_entry(dev->parts.next, struct part_info, link);
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n", p->name,
+								    p->size);
+			}
+#endif
 			if (part_add(dev_tmp, p) != 0) {
 				device_del(dev);
 				return 1;
@@ -2042,6 +2074,10 @@ U_BOOT_CMD(
 	"    - delete partition (e.g. part-id = nand0,1)\n"
 	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
 	"    - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.e <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif
 	"mtdparts default\n"
 	"    - reset partition table to defaults\n"
 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
Signature · 1 line
1.7.0.4
#70 lore raw

PATCH v3 4/4 mtdparts: new add.e: add part skipping bad blocks

Dear Ben Gardiner,

Quoted 13 lines · In message <[email protected]> you…

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i). This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

---

V2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed

Quoted 5 lines

V3:
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* fix more checkpatch errors
* updating copyright to include addition of add.e command

NAK for this like for the previous patches.

common/cmd_mtdparts.c int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 1999

Quoted 2 lines
common/cmd_mtdparts.c +2 -0
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		s = strchr(argv[1], '.');

s == NULL if there is no '.' in the argument.

common/cmd_mtdparts.c int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) · line 2007

Quoted 7 lines
common/cmd_mtdparts.c +6 -0
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+#endif
+
 		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {

So here you might dereference a NULL pointer. Sounds like a Bad Thing to me. Please add error checking / handling.

common/cmd_mtdparts.c U_BOOT_CMD( · line 2080

Quoted 4 lines
common/cmd_mtdparts.c +4 -0
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.e <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif

Also document the ".i" version.

Best regards,

Wolfgang Denk

Signature · 7 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
I usually tell my classes "if you are using @ and [] together in this
class, you will almost certainly NOT get what you want. That's  going
down  the wrong tunnel. There's no cheese at the end of that tunnel."
         -- Randal L. Schwartz in <[email protected]>
#71 lore raw

PATCH v2 1/4 mtdparts: regroup calls to get_mtd_device_nm

In reply to Ben Gardiner

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

---
Changes in v2:
* formatting: add space after 'if'
* added acked-by tag as requested by Stefan

---
 common/cmd_mtdparts.c |   43 ++++++++++++++++++++++++++++---------------
 1 files changed, 28 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +28 -15
index 116e637..a6eeb41 100644
@@ -286,6 +286,27 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/** Produce a mtd_info given a type and num
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +318,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, mtd_dev);
+	if (get_mtd_info(id->type, id->num, &mtd))
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +700,17 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 /**
  * Check device number to be within valid range for given device type.
  *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
  * @return 0 if device is valid, 1 otherwise
  */
 int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if (get_mtd_info(type, num, &mtd))
 		return 1;
-	}
 
 	*size = mtd->size;
 
Signature · 1 line
1.7.0.4
#72 lore raw

PATCH v2 2/4 mtdparts: show net size in mtdparts list

In reply to Ben Gardiner

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

---
Changes in v2:
* formatting: spaces after 'if' and 'for'
* the entire new feature is conditional on a macro, there is now a zero-byte binary size impact when the macro is not defined.
* return the net parition size directly from net_part_size instead of using an output variable

---
 common/cmd_mtdparts.c |   50 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 48 insertions(+), 2 deletions(-)
common/cmd_mtdparts.c +48 -2
index a6eeb41..b36aac2 100644
@@ -1213,6 +1213,29 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+/** get the net size (w/o bad blocks) of the given partition
+ * @param mtd the mtd info
+ * @param part the partition
+ * @return the calculated net size of this partition
+ */
+static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)
+{
+	if (mtd->block_isbad) {
+		u32 i, bb_delta = 0;
+
+		for (i = 0; i < part->size; i += mtd->erasesize) {
+			if (mtd->block_isbad(mtd, part->offset + i))
+				bb_delta += mtd->erasesize;
+		}
+
+		return part->size - bb_delta;
+	} else {
+		return part->size;
+	}
+}
+#endif
+
 /**
  * Format and print out a partition list for each device from global device
  * list.
@@ -1223,6 +1246,10 @@ static void list_partitions(void)
 	struct part_info *part;
 	struct mtd_device *dev;
 	int part_num;
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+	struct mtd_info *mtd;
+	u32 net_size;
+#endif
 
 	debug("\n---list_partitions---\n");
 	list_for_each(dentry, &devices) {
@@ -1230,14 +1257,33 @@ static void list_partitions(void)
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
 				MTD_DEV_TYPE(dev->id->type), dev->id->num,
 				dev->id->mtd_id, dev->num_parts);
-		printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
+		printf(" #: name\t\tsize\t\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		"net size\t"
+#endif
+		"offset\t\tmask_flags\n");
+
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
+#endif
 
 		/* list partitions for given device */
 		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
-			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+			net_size = net_part_size(mtd, part);
+#endif
+			printf("%2d: %-20s0x%08x\t"
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+					"0x%08x%s\t"
+#endif
+					"0x%08x\t%d\n",
 					part_num, part->name, part->size,
+#if defined(CONFIG_CMD_MTDPARTS_SHOW_NET_SIZES)
+					net_size, part->size == net_size ? " " : " (!)",
+#endif
 					part->offset, part->mask_flags);
 
 			part_num++;
Signature · 1 line
1.7.0.4
#73 lore raw

PATCH v2 3/4 mtdparts: add new sub-command "spread"

In reply to Ben Gardiner

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

---
Changes in v2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed
* check for null mtd->block_isbad before dereferencing

---
 common/cmd_mtdparts.c |  111 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 110 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +110 -1
index b36aac2..c52374d 100644
@@ -1414,6 +1414,100 @@ 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 parition would start on a
+ * good blcok 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, u32 *next_offset)
+{
+	if(!mtd->block_isbad)
+		goto out;
+
+	u32 i, bb_delta = 0;
+
+	for (i = part->offset;
+	    i - bb_delta < part->offset + part->size;
+	    i += mtd->erasesize) {
+		if (mtd->block_isbad(mtd, i))
+			bb_delta += mtd->erasesize;
+	}
+
+	/* Absorb bad blocks immeadiately following this
+	  * partition also into the partition, such that
+	  * the next partition starts with a good block.
+	  */
+	while(i < mtd->size && mtd->block_isbad(mtd, i)) {
+		bb_delta += mtd->erasesize;
+		i += mtd->erasesize;
+	}
+
+	if (part->offset + part->size + bb_delta > mtd->size) {
+		part->size = mtd->size - part->offset - bb_delta;
+		printf("truncated partition %s to %d bytes\n", part->name, part->size);
+	}
+
+	part->size += bb_delta;
+
+out:
+	*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;
+	u32 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 at 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.
@@ -1904,6 +1998,13 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *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 */
+
 	cmd_usage(cmdtp);
 	return 1;
 }
@@ -1928,7 +2029,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"
Signature · 1 line
1.7.0.4
#74 lore raw

PATCH v2 4/4 mtdparts: new add.e: add part skipping bad blocks

In reply to Ben Gardiner

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i). This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

---
Changes in v2:
* formatting: spaces after 'if' and 'for'
* trailing whitespace removed

---
 common/cmd_mtdparts.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +35 -1
index c52374d..c4da06e 100644
@@ -1935,9 +1935,14 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 	}
 
 	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+	if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
 #define PART_ADD_DESC_MAXLEN 64
 		char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		char *s;
+		struct mtd_info *mtd;
+		u32 next_offset;
+#endif
 		u8 type, num, len;
 		struct mtd_device *dev;
 		struct mtd_device *dev_tmp;
@@ -1972,11 +1977,36 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 		debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
 				dev->id->num, dev->id->mtd_id);
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		s = strchr(argv[1], '.');
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+#endif
+
 		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {
+				p = list_entry(dev->parts.next,
+					       struct part_info, link);
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n",p->name,
+								  p->size);
+			}
+#endif
 			device_add(dev);
 		} else {
 			/* merge new partition with existing ones*/
 			p = list_entry(dev->parts.next, struct part_info, link);
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n",p->name,
+								  p->size);
+			}
+#endif
 			if (part_add(dev_tmp, p) != 0) {
 				device_del(dev);
 				return 1;
@@ -2028,6 +2058,10 @@ U_BOOT_CMD(
 	"    - delete partition (e.g. part-id = nand0,1)\n"
 	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
 	"    - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.e <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif
 	"mtdparts default\n"
 	"    - reset partition table to defaults\n"
 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
Signature · 1 line
1.7.0.4
#75 lore raw

PATCH v2 4/4 mtdparts: new add.e: add part skipping bad blocks

Quoted 1 line · On Wed, 2 Jun 2010 11:58:39 -0400 Ben Gardiner <[email protected]>…

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i).

Why multiple ways to say the same thing, in a new command with no legacy to be compatible with?

Even on the commands where .e and .i used to do something, that's now the default, and the suffix is unnecessary. So I don't see any need to mimic the syntax.

What do "e" and "i" even stand for? It looks like they were "for compatibility with older units" even when first committed.

-Scott

#76 lore raw

PATCH v2 4/4 mtdparts: new add.e: add part skipping bad blocks

Hi Scott,

Quoted 7 lines · Scott Wood
Quoted 1 line · On Wed, 2 Jun 2010 11:58:39 -0400 Ben Gardiner <[email protected]>…

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i).

Why multiple ways to say the same thing, in a new command with no legacy to be compatible with?

Just mimicking the add syntax.

Quoted 3 lines

Even on the commands where .e and .i used to do something, that's now the default, and the suffix is unnecessary. ?So I don't see any need to mimic the syntax.

Ok. No objection here.

Quoted 2 lines

What do "e" and "i" even stand for? ?It looks like they were "for compatibility with older units" even when first committed.

I don't really know. Should I stick with 'add.e' or would you prefer 'add.spread' 'add.skip' or something else?

Best Regards,
Ben Gardiner

---
Nanometrics Inc.
http://www.nanometrics.ca

#77 lore raw

PATCH v2 4/4 mtdparts: new add.e: add part skipping bad blocks

Quoted 17 lines · On Mon, 9 Aug 2010 14:39:20 -0400 Ben Gardiner <[email protected]>…

Hi Scott,

Quoted 7 lines · Scott Wood
Quoted 1 line · On Wed, 2 Jun 2010 11:58:39 -0400 Ben Gardiner <[email protected]>…

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i).

Why multiple ways to say the same thing, in a new command with no legacy to be compatible with?

Just mimicking the add syntax.

Quoted 3 lines

Even on the commands where .e and .i used to do something, that's now the default, and the suffix is unnecessary. ?So I don't see any need to mimic the syntax.

Quoted 7 lines

Ok. No objection here.

Quoted 2 lines

What do "e" and "i" even stand for? ?It looks like they were "for compatibility with older units" even when first committed.

I don't really know. Should I stick with 'add.e' or would you prefer 'add.spread' 'add.skip' or something else?

".spread" is nice if it matches what the "mtdparts spread" command does to existing partitions, but ".skip" might make sense in other contexts that we want to be consistent with. For instance, we probably want to do something with the "nand erase" command to differentiate clearing space for a certain amount of data (e.g. $filesize) versus erasing a partition (where the bad blocks should already be included in the size).

Since the consistency arguments mostly cancel out, I'd go with ".spread", since it's different from read/write/erase in that you're not quite skipping anything, but incorporating room for the bad blocks into the partition.

-Scott

#78 lore raw

PATCH v2 1/4 mtdparts: regroup calls to get_mtd_device_nm

In reply to Wolfgang Denk

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

---
 common/cmd_mtdparts.c |   43 ++++++++++++++++++++++++++++---------------
 1 files changed, 28 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +28 -15
index 116e637..7a9768f 100644
@@ -286,6 +286,27 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/** Produce a mtd_info given a type and num
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +318,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info *part)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, mtd_dev);
+	if(get_mtd_info(id->type, id->num, &mtd))
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +700,17 @@ static int part_parse(const char *const partdef, const char **ret, struct part_i
 /**
  * Check device number to be within valid range for given device type.
  *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
  * @return 0 if device is valid, 1 otherwise
  */
 int mtd_device_validate(u8 type, u8 num, u32 *size)
 {
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if(get_mtd_info(type, num, &mtd))
 		return 1;
-	}
 
 	*size = mtd->size;
 
Signature · 1 line
1.7.0.4
#79 lore raw

PATCH 1/4 mtdparts: regroup calls to get_mtd_device_nm

Quoted 5 lines · On Tuesday 01 June 2010 22:23:44 Ben Gardiner wrote:

The get_mtd_device_nm function is called in a couple places and the string that is passed to it is not really used after the calls.

This patch regroups the calls to this function into a new function, get_mtd_info.

Thanks. Some nitpicking comments below.

Quoted 41 lines
---
 common/cmd_mtdparts.c |   43 ++++++++++++++++++++++++++++---------------
 1 files changed, 28 insertions(+), 15 deletions(-)
common/cmd_mtdparts.c +21 -0
index 116e637..7a9768f 100644
@@ -286,6 +286,27 @@ static void current_save(void)
 	index_partitions();
 }
 
+
+/** Produce a mtd_info given a type and num
+ * @param type mtd type
+ * @param num mtd number
+ * @param mtd a pointer to an mtd_info instance (output)
+ * @return 0 if device is valid, 1 otherwise
+ */
+static int get_mtd_info(u8 type, u8 num, struct mtd_info **mtd)
+{
+	char mtd_dev[16];
+
+	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
+	*mtd = get_mtd_device_nm(mtd_dev);
+	if (IS_ERR(*mtd)) {
+		printf("Device %s not found!\n", mtd_dev);
+		return 1;
+	}
+
+	return 0;
+}
+
 /**
  * Performs sanity check for supplied flash partition.
  * Table of existing MTD flash devices is searched and partition device
@@ -297,17 +318,12 @@ static void current_save(void)
  */
 static int part_validate_eraseblock(struct mtdids *id, struct part_info
 *part) {

common/cmd_mtdparts.c static void current_save(void) · line 308

Quoted 10 lines
common/cmd_mtdparts.c +1 -6
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 	int i, j;
 	ulong start;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(id->type), id->num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Partition %s not found on device %s!\n", part->name, 

mtd_dev);

common/cmd_mtdparts.c static void current_save(void) · line 325

Quoted 1 line
common/cmd_mtdparts.c +1 -0
+	if(get_mtd_info(id->type, id->num, &mtd))

Space after "if" please.

Quoted 17 lines
common/cmd_mtdparts.c +0 -1
 		return 1;
-	}
 
 	part->sector_size = mtd->erasesize;
 
@@ -684,20 +700,17 @@ static int part_parse(const char *const partdef,

const char **ret, struct part_i /**
* Check device number to be within valid range for given device type. *
- * @param dev device to validate
+ * @param type mtd type
+ * @param num mtd number
+ * @param size a pointer to the size of the mtd device (output)
* @return 0 if device is valid, 1 otherwise
*/
int mtd_device_validate(u8 type, u8 num, u32 *size)
{

common/cmd_mtdparts.c static int part_parse(const char *const partdef, const char **ret, struct part_i · line 712

Quoted 9 lines
common/cmd_mtdparts.c +2 -6
-	struct mtd_info *mtd;
-	char mtd_dev[16];
+	struct mtd_info *mtd = NULL;
 
-	sprintf(mtd_dev, "%s%d", MTD_DEV_TYPE(type), num);
-	mtd = get_mtd_device_nm(mtd_dev);
-	if (IS_ERR(mtd)) {
-		printf("Device %s not found!\n", mtd_dev);
+	if(get_mtd_info(type, num, &mtd))

Again, space after "if".

Please respin this patch and add my:

Thanks.

Cheers,
Stefan

--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: office at denx.de

#80 lore raw

PATCH v2 2/4 mtdparts: show net size in mtdparts list

In reply to Wolfgang Denk

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

---
 common/cmd_mtdparts.c |   28 ++++++++++++++++++++++++++--
 1 files changed, 26 insertions(+), 2 deletions(-)
common/cmd_mtdparts.c +26 -2
index 7a9768f..24d27b9 100644
@@ -1213,6 +1213,23 @@ static int generate_mtdparts_save(char *buf, u32 buflen)
 	return ret;
 }
 
+/** get the net size (w/o bad blocks) of the given partition
+ * @param mtd the mtd info
+ * @param part the partition
+ * @param net_size the calculated net size of this partition (output)
+ */
+static void net_part_size(struct mtd_info *mtd, struct part_info *part, u32 *net_size)
+{
+	u32 i, bb_delta = 0;
+
+	for(i = 0; i < part->size; i += mtd->erasesize) {
+		if(mtd->block_isbad(mtd, part->offset + i))
+			bb_delta += mtd->erasesize;
+	}
+
+	*net_size = part->size - bb_delta;
+}
+
 /**
  * Format and print out a partition list for each device from global device
  * list.
@@ -1222,7 +1239,9 @@ static void list_partitions(void)
 	struct list_head *dentry, *pentry;
 	struct part_info *part;
 	struct mtd_device *dev;
+	struct mtd_info *mtd;
 	int part_num;
+	u32 net_size;
 
 	debug("\n---list_partitions---\n");
 	list_for_each(dentry, &devices) {
@@ -1230,14 +1249,19 @@ static void list_partitions(void)
 		printf("\ndevice %s%d <%s>, # parts = %d\n",
 				MTD_DEV_TYPE(dev->id->type), dev->id->num,
 				dev->id->mtd_id, dev->num_parts);
-		printf(" #: name\t\tsize\t\toffset\t\tmask_flags\n");
+		printf(" #: name\t\tsize\t\tnet size\toffset\t\tmask_flags\n");
+
+		if(get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return;
 
 		/* list partitions for given device */
 		part_num = 0;
 		list_for_each(pentry, &dev->parts) {
 			part = list_entry(pentry, struct part_info, link);
-			printf("%2d: %-20s0x%08x\t0x%08x\t%d\n",
+			net_part_size(mtd,part,&net_size);
+			printf("%2d: %-20s0x%08x\t0x%08x%s\t0x%08x\t%d\n",
 					part_num, part->name, part->size,
+					net_size, part->size == net_size ? " " : " (!)",
 					part->offset, part->mask_flags);
 
 			part_num++;
Signature · 1 line
1.7.0.4
#81 lore raw

PATCH 2/4 mtdparts: show net size in mtdparts list

Quoted 3 lines · On Tuesday 01 June 2010 22:23:45 Ben Gardiner wrote:

This patch adds an additional column to the output of list_partitions. The additional column will contain the net size and a '(!)' beside it if the net size is not equal to the partition size.

Please find some comments below.

Quoted 15 lines
---
 common/cmd_mtdparts.c |   28 ++++++++++++++++++++++++++--
 1 files changed, 26 insertions(+), 2 deletions(-)
common/cmd_mtdparts.c +2 -0
index 7a9768f..24d27b9 100644
@@ -1213,6 +1213,23 @@ static int generate_mtdparts_save(char *buf, u32
 buflen) return ret;
 }
 
+/** get the net size (w/o bad blocks) of the given partition
+ * @param mtd the mtd info

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 · line 1227

Quoted 10 lines
common/cmd_mtdparts.c +9 -0
+ * @param part the partition
+ * @param net_size the calculated net size of this partition (output)
+ */
+static void net_part_size(struct mtd_info *mtd, struct part_info *part,
 u32 *net_size)
+{
+	u32 i, bb_delta = 0;
+
+	for(i = 0; i < part->size; i += mtd->erasesize) {
+		if(mtd->block_isbad(mtd, part->offset + i))

Please add spaces after "for" and "if".

common/cmd_mtdparts.c static int generate_mtdparts_save(char *buf, u32 buflen) · line 1231

Quoted 5 lines
common/cmd_mtdparts.c +5 -0
+			bb_delta += mtd->erasesize;
+	}
+
+	*net_size = part->size - bb_delta;
+}

Why don't you return net_size instead:

static u32 net_part_size(struct mtd_info *mtd, struct part_info *part)

{
	...
	return part->size - bb_delta;
}

Thanks.

Cheers,
Stefan

--
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-0 Fax: (+49)-8142-66989-80 Email: office at denx.de

#82 lore raw

PATCH v2 3/4 mtdparts: add new sub-command "spread"

In reply to Wolfgang Denk

This patch introduces the 'spread' sub-command of the mtdparts command. This command will modify the existing mtdparts variable by increasing the size of the partitions such that 1) each partition's net size is at least as large as the size specified in the mtdparts variable and 2) each partition starts on a good block.

The new subcommand is implemented by iterating over the mtd device partitions and collecting a bad blocks count in each -- including any trailing bad blocks -- and then modifying that partitions's part_info structure and checking if the modification affects the next partition.

---

This patch is based on the idea of Harald Welte <[email protected]> and the comments of Wolfgang Denk <[email protected]> in the review at
http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549 .

---
 common/cmd_mtdparts.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 105 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +105 -1
index 24d27b9..ae5e97d 100644
@@ -1392,6 +1392,95 @@ 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 parition would start on a
+ * good blcok 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, u32 *next_offset)
+{
+	u32 i, bb_delta = 0;
+
+	for(i = part->offset;
+	    i - bb_delta < part->offset + part->size;
+	    i += mtd->erasesize) {
+		if(mtd->block_isbad(mtd, i))
+			bb_delta += mtd->erasesize;
+	}
+
+	/* Absorb bad blocks immeadiately following this
+	  * partition also into the partition, such that
+	  * the next partition starts with a good block.
+	  */
+	while(i < mtd->size && mtd->block_isbad(mtd, i)) {
+		bb_delta += mtd->erasesize;
+		i += mtd->erasesize;
+	}
+
+	if(part->offset + part->size + bb_delta > mtd->size) {
+		part->size = mtd->size - part->offset - bb_delta;
+		printf("truncated partition %s to %d bytes\n", part->name, part->size);
+	}
+
+	part->size += bb_delta;
+	*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;
+	u32 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 at 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.
@@ -1882,6 +1971,13 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *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 */
+
 	cmd_usage(cmdtp);
 	return 1;
 }
@@ -1906,7 +2002,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"
Signature · 1 line
1.7.0.4
#83 lore raw

PATCH v2 4/4 mtdparts: new add.e: add part skipping bad blocks

In reply to Wolfgang Denk

This patch adds a new 'mtdparts add' variant: add.e (with a synomym add.i). This command variant adds a new partition to the mtdparts variable but also increases the partitions size by skipping bad blocks and aggregating any additional bad blocks found at the end of the partition.

---
 common/cmd_mtdparts.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)
common/cmd_mtdparts.c +35 -1
index ae5e97d..9ff33a7 100644
@@ -1908,9 +1908,14 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 	}
 
 	/* mtdparts add <mtd-dev> <size>[@<offset>] <name> [ro] */
-	if (((argc == 5) || (argc == 6)) && (strcmp(argv[1], "add") == 0)) {
+	if (((argc == 5) || (argc == 6)) && (strncmp(argv[1], "add", 3) == 0)) {
 #define PART_ADD_DESC_MAXLEN 64
 		char tmpbuf[PART_ADD_DESC_MAXLEN];
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		char *s;
+		struct mtd_info *mtd;
+		u32 next_offset;
+#endif
 		u8 type, num, len;
 		struct mtd_device *dev;
 		struct mtd_device *dev_tmp;
@@ -1945,11 +1950,36 @@ int do_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 		debug("+ %s\t%d\t%s\n", MTD_DEV_TYPE(dev->id->type),
 				dev->id->num, dev->id->mtd_id);
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+		s = strchr(argv[1], '.');
+
+		if(get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+#endif
+				
 		if ((dev_tmp = device_find(dev->id->type, dev->id->num)) == NULL) {
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {
+				p = list_entry(dev->parts.next,
+					       struct part_info, link);
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n",p->name,
+								  p->size);
+			}
+#endif
 			device_add(dev);
 		} else {
 			/* merge new partition with existing ones*/
 			p = list_entry(dev->parts.next, struct part_info, link);
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+			if (!strcmp(s, ".e") || !strcmp(s, ".i")) {
+				spread_partition(mtd, p, &next_offset);
+
+				debug("increased %s to %d bytes\n",p->name,
+								  p->size);
+			}
+#endif
 			if (part_add(dev_tmp, p) != 0) {
 				device_del(dev);
 				return 1;
@@ -2001,6 +2031,10 @@ U_BOOT_CMD(
 	"    - delete partition (e.g. part-id = nand0,1)\n"
 	"mtdparts add <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
 	"    - add partition\n"
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+	"mtdparts add.e <mtd-dev> <size>[@<offset>] [<name>] [ro]\n"
+	"    - add partition, padding size by skipping bad blocks\n"
+#endif
 	"mtdparts default\n"
 	"    - reset partition table to defaults\n"
 #if defined(CONFIG_CMD_MTDPARTS_SPREAD)
Signature · 1 line
1.7.0.4
#84 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

In reply to Scott Wood
Quoted 5 lines · Scott Wood
Quoted 3 lines

Therefore, I still believe that such a feature is useful and should be merged into u-boot. If there are problems with my particular implementation, I'm happy to address them.

Can you base it off of the testing branch of the u-boot-nand-flash repo?

Will do. Probably by tomorrow.

Quoted 9 lines
Quoted 5 lines

I also have another patchset for what I call 'dynpart' support, i.e. the dynamic calculation of a unit-specific partition table that ensures the net size of partitions are as per spec, no matter how many of the factory default blocks are located where. So it would even support NAND devices with a worse spec than the ones that we were using.

Interesting... Would such a patch eliminate the need for this one, by making the environment a dynamic partition? Is there any (plan for) Linux support?

no, the dynamic partition table is calculated once and then stored in the environment. Therefore, the environment has to be either stored outside the NAND flash, or located by the OOB marker. Therefore, the dynpart patch bases on top of the dynenv patch.

Linux has no need to support it, since it gets the device-unique partition table passed by the standard commandline mtdparts mechanism.

Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#85 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

In reply to Scott Wood

Hi again!

Quoted 5 lines · Scott Wood
Quoted 3 lines

Therefore, I still believe that such a feature is useful and should be merged into u-boot. If there are problems with my particular implementation, I'm happy to address them.

Can you base it off of the testing branch of the u-boot-nand-flash repo?

I just tried it, and the patch actually applies cleanly to the
nand-flash/testing branch. So feel free to go ahead and merge :)

Quoted 5 lines
Quoted 5 lines

I also have another patchset for what I call 'dynpart' support, i.e. the dynamic calculation of a unit-specific partition table that ensures the net size of partitions are as per spec, no matter how many of the factory default blocks are located where. So it would even support NAND devices with a worse spec than the ones that we were using.

I'll base that also on top of nand-flash/testing and submit later. Will probably need some generalization for the board-level integration.

Cheers,

Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#86 lore raw

PATCH RESEND 1/1 Support dynamic/patched NAND ENV offset

Quoted 8 lines · Harald Welte
Quoted 5 lines
Quoted 3 lines

Therefore, I still believe that such a feature is useful and should be merged into u-boot. If there are problems with my particular implementation, I'm happy to address them.

Can you base it off of the testing branch of the u-boot-nand-flash repo?

I just tried it, and the patch actually applies cleanly to the
nand-flash/testing branch. So feel free to go ahead and merge :)

sorry, my fault. cleanly applying patch doesn't mean it actually compiles and/or uses the api's correctly.

I'm sending an updated patch ASAP.

Signature · 11 lines
- Harald Welte <[email protected]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://lists.denx.de/pipermail/u-boot/attachments/20080709/9675e5a4/attachment.pgp 
#87 lore raw

PATCH 1/1 Support dynamic/patched NAND ENV offset

In reply to Scott Wood

Hi Scott!

This is now the 'dynenv' patch based on the u-boot-nand-flash/testing git tree:

==========================

NAND: Support dynamic location of enviromnent (CFG_ENV_OFFSET_OOB)

This patch enables the environment parttion to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

With this patch and CFG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

This patch introduces the 'dynenv' command, which can be called from the u-boot command line. 'dynenv get' reads the address of the environment partition from the OOB data, 'dynenv set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name.

common/Makefile +1 -0
index ecf755f..d1d50bf 100644
@@ -55,6 +55,7 @@ endif
 COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o
 COBJS-$(CONFIG_CMD_DOC) += cmd_doc.o
 COBJS-$(CONFIG_CMD_DTT) += cmd_dtt.o
+COBJS-y += cmd_dynenv.o
 COBJS-y += cmd_eeprom.o
 COBJS-$(CONFIG_CMD_ELF) += cmd_elf.o
 COBJS-$(CONFIG_CMD_EXT2) += cmd_ext2.o
common/cmd_dynenv.c new file +121 -0

121 lines not on this page · raw message

common/cmd_nand.c +1 -1
index 7c26ceb..a72e553 100644
@@ -101,7 +101,7 @@ static inline int str2long(char *p, ulong *num)
 	return (*p != '\0' && *endptr == '\0') ? 1 : 0;
 }
 
-static int
+int
 arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
 {
 	int idx = nand_curr_device;
common/cmd_nand.h new file +33 -0
new file mode 100644
index 0000000..bedcda9
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef CMD_NAND_H
+#define CMD_NAND_H
+
+#include <nand.h>
+
+
+/* common/cmd_nand.c */
+int arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off,
+  ulong *size, int net);
+
+#endif /* CMD_NAND_H */
common/env_nand.c +27 -0
index 1fe874a..14ea480 100644
@@ -292,6 +292,33 @@ void env_relocate_spec (void)
 	int crc1_ok = 0, crc2_ok = 0;
 	env_t *tmp_env1, *tmp_env2;
 
+#if defined(CFG_ENV_OFFSET_OOB)
+	struct mtd_info *mtd = &nand_info[0];
+	struct nand_chip *this = mtd->priv;
+	int buf_len;
+	uint8_t *buf;
+
+	buf_len = (1 << this->bbt_erase_shift);
+	buf_len += (buf_len >> this->page_shift) * mtd->oobsize;
+	buf = malloc(buf_len);
+	if (!buf)
+		return;
+
+	nand_read_raw(mtd, buf, 0, mtd->oobblock, mtd->oobsize);
+	if (buf[mtd->oobblock + 8 + 0] == 'E' &&
+	    buf[mtd->oobblock + 8 + 1] == 'N' &&
+	    buf[mtd->oobblock + 8 + 2] == 'V' &&
+	    buf[mtd->oobblock + 8 + 3] == '0') {
+		CFG_ENV_OFFSET = *((unsigned long *) &buf[mtd->oobblock + 8 + 4]);
+		/* fall through to the normal environment reading code below */
+		free(buf);
+		puts("Found Environment offset in OOB..\n");
+	} else {
+		free(buf);
+		return use_default();
+	}
+#endif
+
 	total = CFG_ENV_SIZE;
 
 	tmp_env1 = (env_t *) malloc(CFG_ENV_SIZE);
common/environment.c +6 -0
index 3b9914f..50d5210 100644
@@ -29,6 +29,12 @@
 #undef	__ASSEMBLY__
 #include <environment.h>
 
+#if defined(CFG_ENV_OFFSET_PATCHED)
+unsigned long env_offset = CFG_ENV_OFFSET_PATCHED;
+#elif defined(CFG_ENV_OFFSET_OOB)
+unsigned long env_offset = CFG_ENV_OFFSET_OOB;
+#endif
+
 /*
  * Handle HOSTS that have prepended
  * crap on symbol names, not TARGETS.
include/environment.h +5 -0
index bf9f669..3256044 100644
@@ -70,6 +70,10 @@
 #endif	/* CFG_ENV_IS_IN_FLASH */
 
 #if defined(CFG_ENV_IS_IN_NAND)
+#if defined(CFG_ENV_OFFSET_PATCHED) || defined(CFG_ENV_OFFSET_OOB)
+extern unsigned long env_offset;
+#define CFG_ENV_OFFSET env_offset
+#else
 # ifndef CFG_ENV_OFFSET
 #  error "Need to define CFG_ENV_OFFSET when using CFG_ENV_IS_IN_NAND"
 # endif
@@ -82,6 +86,7 @@
 # ifdef CFG_ENV_IS_EMBEDDED
 #  define ENV_IS_EMBEDDED	1
 # endif
+#endif /* CFG_ENV_NAND_PATCHED */
 #endif /* CFG_ENV_IS_IN_NAND */
 
 #ifdef USE_HOSTCC
Signature · 3 lines
- Harald Welte <[email protected]>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
#88 lore raw

PATCH 1/1 Support dynamic/patched NAND ENV offset

Quoted 1 line · Harald Welte

+#if defined(CFG_ENV_OFFSET_OOB)

Can you push this conditional into the Makefile?

Quoted 4 lines
common/cmd_dynenv.c new file +4 -0
+int do_dynenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	struct mtd_info *mtd = &nand_info[0];
+	int ret, size = 8;

common/cmd_dynenv.c line 45

Quoted 10 lines
common/cmd_dynenv.c new file +10 -0
+	struct mtd_oob_ops ops;
+	uint8_t *buf;
+
+	char *cmd = argv[1];
+
+	buf = malloc(mtd->oobsize);
+	if (!buf)
+		return -ENOMEM;
+
+	ops.mode = MTD_OOB_RAW;

Use MTD_OOB_AUTO, or else you'll conflict with bad block markers, ECC, etc.

common/cmd_dynenv.c line 49

Quoted 4 lines
common/cmd_dynenv.c new file +4 -0
+	ops.ooboffs = 0;
+	ops.ooblen = mtd->oobsize;
+	ops.oobbuf = buf;
+	ops.datbuf = buf;

You're passing the same buffer for data and oob? And the buffer is only oob-sized?

common/cmd_dynenv.c line 56

Quoted 7 lines
common/cmd_dynenv.c new file +7 -0
+	ops.len = size;
+
+	ret = mtd->read_oob(mtd, 8, &ops);
+	if (!strcmp(cmd, "get")) {
+
+		if (buf[0] == 'E' && buf[1] == 'N' &&
+		    buf[2] == 'V' && buf[3] == '0')

Use strcmp().

common/cmd_dynenv.c line 57

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+			printf("0x%08x\n", *((u_int32_t *) &buf[4]));

This violates C99 aliasing rules, and could cause unaligned accesses (likewise elsewhere).

Use a union, or just declare it as uint32_t or u32 (not u_int32_t) and cast to char for strcmp() or define the magic value as an integer rather than a string.

The last option is probably the best, in terms of keeping code simple and small.

common/cmd_dynenv.c line 61

Quoted 4 lines
common/cmd_dynenv.c new file +4 -0
+		else
+			printf("No dynamic environment marker in OOB block 0\n");
+
+	} else if (!strcmp(cmd, "set")) {

No blank lines at beginning/end of blocks.

common/cmd_dynenv.c line 72

Quoted 11 lines
common/cmd_dynenv.c new file +11 -0
+		unsigned long addr, dummy;
+
+		if (argc < 3)
+			goto usage;
+
+		buf[0] = 'E';
+		buf[1] = 'N';
+		buf[2] = 'V';
+		buf[3] = '0';
+
+		if (arg_off_size(argc-2, argv+2, mtd, &addr, &dummy, 1) < 0) {

Spaces around operators (here and elsewhere).

common/cmd_dynenv.c line 76

Quoted 4 lines
common/cmd_dynenv.c new file +4 -0
+			printf("Offset or partition name expected\n");
+			goto fail;
+		}
+		if (!ret) {

Why are you checking the success of read_oob here, and not for "get"?

common/cmd_dynenv.c line 87

Quoted 11 lines
common/cmd_dynenv.c new file +11 -0
+			uint8_t tmp[4];
+			int i;
+
+			memcpy(&tmp, &addr, 4);
+			for (i = 0; i != 4; i++)
+				if (tmp[i] & ~buf[i+4]) {
+					printf("ERROR: erase OOB block to "
+					  "write this value\n");
+					goto fail;
+				}
+		}

This would be much simpler if you used integer accesses on a u32 array.

What does "erase OOB block" mean? Don't you mean "erase block zero"?

Are you really intending to support changing the location multiple times per erase, as long as bits are only cleared? Sure, it's technically possible, but still...

common/cmd_dynenv.c line 102

Quoted 3 lines
common/cmd_dynenv.c new file +3 -0
+		ret = mtd->write_oob(mtd, 8, &ops);
+		if (!ret)
+			CFG_ENV_OFFSET = addr;

And silently fail if write_oob fails?

common/cmd_nand.c static inline int str2long(char *p, ulong *num) · line 105

Quoted 11 lines
common/cmd_nand.c +1 -1
index 7c26ceb..a72e553 100644
@@ -101,7 +101,7 @@ static inline int str2long(char *p, ulong *num)
 	return (*p != '\0' && *endptr == '\0') ? 1 : 0;
 }
 
-static int
+int
 arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)

This is too generic a name for a global function that is NAND-specific.

-Scott

#89 lore raw

PATCH 1/1 NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB)

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> in
http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43916.

This patch was made against master branch of
git://git.denx.de/u-boot-nand-flash.git with the recent patch from Wolfgang Denk to fix the undefined __aeabi_unwind_cpp_pr0() problem:
http://download.gmane.org/gmane.comp.boot-loaders.u-boot/78612/78613

Testing was performed with the patch applied to the master branch of
git://arago-project.org/git/people/sekhar/u-boot-omapl1.git , which is forked from uboot's v2009.11 a200a7c04d89853d2a1395b96d8ca5e3dd754551 tag -- this is because the board I am actually using -- the da850 / OMAP L138 -- does not have config.

This patch enables the environment parttion to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

This patch introduces the 'dynenv' command, which can be called from the u-boot command line. 'dynenv get' reads the address of the environment partition from the OOB data, 'dynenv set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name.

---
 common/Makefile       |    1 +
 common/cmd_dynenv.c   |  112 +++++++++++++++++++++++++++++++++++++++++++++++++
 common/cmd_nand.c     |   10 ++--
 common/cmd_nand.h     |   33 ++++++++++++++
 common/env_nand.c     |   52 +++++++++++++++++++++++
 include/environment.h |   21 +++++++---
 include/nand.h        |    6 +++
 7 files changed, 224 insertions(+), 11 deletions(-)
 create mode 100644 common/cmd_dynenv.c
 create mode 100644 common/cmd_nand.h
common/Makefile +1 -0
index dbf7a05..83520d7 100644
@@ -85,6 +85,7 @@ COBJS-$(CONFIG_CMD_DIAG) += cmd_diag.o
 endif
 COBJS-$(CONFIG_CMD_DISPLAY) += cmd_display.o
 COBJS-$(CONFIG_CMD_DTT) += cmd_dtt.o
+COBJS-$(CONFIG_ENV_OFFSET_OOB) += cmd_dynenv.o
 COBJS-$(CONFIG_CMD_ECHO) += cmd_echo.o
 COBJS-$(CONFIG_ENV_IS_IN_EEPROM) += cmd_eeprom.o
 COBJS-$(CONFIG_CMD_EEPROM) += cmd_eeprom.o
common/cmd_dynenv.c new file +112 -0

113 lines not on this page · raw message

common/cmd_nand.c +5 -5
index 9b0c930..7575904 100644
@@ -89,8 +89,8 @@ static inline int str2long(char *p, ulong *num)
 	return (*p != '\0' && *endptr == '\0') ? 1 : 0;
 }
 
-static int
-arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
+int
+nand_arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off, size_t *size)
 {
 	int idx = nand_curr_device;
 #if defined(CONFIG_CMD_MTDPARTS)
@@ -305,7 +305,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 
 		printf("\nNAND %s: ", scrub ? "scrub" : "erase");
 		/* skip first two or three arguments, look for offset and size */
-		if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
+		if (nand_arg_off_size(argc - o, argv + o, nand, &off, &size) != 0)
 			return 1;
 
 		memset(&opts, 0, sizeof(opts));
@@ -372,7 +372,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 
 		read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */
 		printf("\nNAND %s: ", read ? "read" : "write");
-		if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
+		if (nand_arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0)
 			return 1;
 
 		s = strchr(cmd, '.');
@@ -462,7 +462,7 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 	}
 
 	if (strcmp(cmd, "unlock") == 0) {
-		if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
+		if (nand_arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0)
 			return 1;
 
 		if (!nand_unlock(nand, off, size)) {
common/cmd_nand.h new file +33 -0
new file mode 100644
index 0000000..023ed4f
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#ifndef CMD_NAND_H
+#define CMD_NAND_H
+
+#include <nand.h>
+
+
+/* common/cmd_nand.c */
+int nand_arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off,
+  ulong *size, int net);
+
+#endif /* CMD_NAND_H */
common/env_nand.c +52 -0

76 lines not on this page · raw message

include/environment.h +15 -6
index b9924fd..03b6c92 100644
@@ -74,15 +74,24 @@
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 
 #if defined(CONFIG_ENV_IS_IN_NAND)
-# ifndef CONFIG_ENV_OFFSET
-#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
+# if defined(CONFIG_ENV_OFFSET_OOB)
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB is set"
+#  endif
+extern unsigned long env_offset;
+#  undef CONFIG_ENV_OFFSET
+#  define CONFIG_ENV_OFFSET env_offset
+# else
+#  ifndef CONFIG_ENV_OFFSET
+#   error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
+#  endif
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#  endif
+# endif /* CONFIG_ENV_OFFSET_OOB */
 # ifndef CONFIG_ENV_SIZE
 #  error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_NAND"
 # endif
-# ifdef CONFIG_ENV_OFFSET_REDUND
-#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT
-# endif
 #endif /* CONFIG_ENV_IS_IN_NAND */
 
 #if defined(CONFIG_ENV_IS_IN_MG_DISK)
include/nand.h +6 -0
index 2a81597..29238c8 100644
@@ -130,3 +130,9 @@ void board_nand_select_device(struct nand_chip *nand, int chip);
 __attribute__((noreturn)) void nand_boot(void);
 
 #endif
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+#define ENV_OOB_MARKER 0x30564e45 //"ENV0" in little-endian
+#define CONFIG_ENV_OFFSET_SIZE 8
+int get_dynenv(unsigned long *result);
+#endif
Signature · 1 line
1.7.0.4
#90 lore raw

PATCH 1/1 NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB)

common/cmd_dynenv.c line 4

Quoted 10 lines · Ben Gardiner
common/cmd_dynenv.c new file +4 -0
new file mode 100644
index 0000000..5167875
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Harald Welte <[email protected]>
+ * (C) Copyright 2008 Harald Welte <[email protected]>

Is this correct and up-to-date?

common/cmd_dynenv.c line 30

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+unsigned long env_offset;

This is a pretty generic name for something NAND-specific -- as is "dynenv".

Maybe this should be a nand subcommand? Putting it in cmd_nand.c would also eliminate the need to export arg_off_size().

common/cmd_dynenv.c line 61

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+		if(mtd->oobavail < CONFIG_ENV_OFFSET_SIZE){

Please put a space after "if" and before the opening brace (in fact, there's no need for the braces@all on this one-liner).

common/cmd_dynenv.c line 62

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+			printf("Insufficient available OOB bytes: %d OOB bytes available but %d required for dynenv support\n",mtd->oobavail,8);

Keep lines under 80 columns (both in source code and in output), and put spaces after commas.

common/cmd_dynenv.c line 67

Quoted 5 lines
common/cmd_dynenv.c new file +5 -0
+		}
+
+		oob_buf = malloc(mtd->oobsize);
+		if(!oob_buf)
+			return -ENOMEM;

Let the user know it didn't work?

You only really need 8 bytes, why not just put it on the stack? Likewise in get_dynenv().

common/cmd_dynenv.c line 81

Quoted 13 lines
common/cmd_dynenv.c new file +13 -0
+		ops.datbuf = NULL;
+		ops.mode = MTD_OOB_AUTO;
+		ops.ooboffs = 0;
+		ops.ooblen = CONFIG_ENV_OFFSET_SIZE;
+		ops.oobbuf = (void *) oob_buf;
+
+		ret = mtd->read_oob(mtd, CONFIG_ENV_OFFSET_SIZE, &ops);
+		oob_buf[0] = ENV_OOB_MARKER;
+
+		if (!ret) {
+			if(addr & ~oob_buf[1]) {
+				printf("ERROR: erase OOB block 0 to "
+					  "write this value\n");

You cannot erase OOB without erasing the entire block, so this message is a little confusing.

Do you really expect to make use of the ability to set a new address without erasing, if it only clears bits?

common/cmd_dynenv.c line 93

Quoted 7 lines
common/cmd_dynenv.c new file +7 -0
+		ret = mtd->write_oob(mtd, CONFIG_ENV_OFFSET_SIZE, &ops);
+		if (!ret)
+			CONFIG_ENV_OFFSET = addr;
+		else {
+			printf("Error writing OOB block 0\n");
+			goto fail;
+		}

If you put braces on one side of the else, put them on both.

common/cmd_dynenv.c line 97

Quoted 4 lines
common/cmd_dynenv.c new file +4 -0
+
+		free(oob_buf);
+	} else
+		goto usage;

Likewise.

Is there anything you can do on "dynenv set" so that the user won't have to reboot after setting the dynenv to be able to saveenv into the new environment?

common/cmd_dynenv.c line 112

Quoted 5 lines
common/cmd_dynenv.c new file +4 -0
+U_BOOT_CMD(dynenv, 4, 1, do_dynenv,
+	"dynenv  - dynamically placed (NAND) environment",
+	"set off	- set enviromnent offset\n"
+	"dynenv get	- get environment offset");
\ No newline at end of file

Please put a newline at the end of the file.

common/cmd_nand.h line 5

Quoted 11 lines
common/cmd_nand.h new file +5 -0
new file mode 100644
index 0000000..023ed4f
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <[email protected]>

Is this really the right copyright/authorship for this file?

common/cmd_nand.h line 31

Quoted 9 lines
common/cmd_nand.h new file +9 -0
+#ifndef CMD_NAND_H
+#define CMD_NAND_H
+
+#include <nand.h>
+
+
+/* common/cmd_nand.c */
+int nand_arg_off_size(int argc, char *argv[], nand_info_t *nand, ulong *off,
+  ulong *size, int net);

Just put it in nand.h.

common/cmd_nand.h line 17

Quoted 3 lines
common/cmd_nand.h new file +3 -0
+	if(!ret) {
+		if(oob_buf[0] == ENV_OOB_MARKER) {
+			*result = oob_buf[1];

Should probably encode the environment location as a block number, rather than as a byte, for flashes larger than 4GiB (there are other places in the environment handling where this won't work, but let's not add more).

common/cmd_nand.h line 19

Quoted 2 lines
common/cmd_nand.h new file +2 -0
+		}
+		else {

} else {

common/cmd_nand.h void env_relocate_spec (void) · line 402

Quoted 9 lines
common/cmd_nand.h new file +2 -0
 #ifdef CONFIG_ENV_OFFSET_REDUND
 void env_relocate_spec (void)
 {
@@ -357,12 +398,23 @@ void env_relocate_spec (void)
 #if !defined(ENV_IS_EMBEDDED)
 	int ret;
 
+#if defined(CONFIG_ENV_OFFSET_OOB)
+	ret = get_dynenv(&CONFIG_ENV_OFFSET);

Taking the address of a macro looks really weird. This will only work if the macro is defined as env_offset, so why not just use env_offset?

common/cmd_nand.h void env_relocate_spec (void) · line 410

Quoted 8 lines
common/cmd_nand.h new file +1 -0
 	ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
 	if (ret)
 		return use_default();
 
 	if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
 		return use_default();
+
 #endif /* ! ENV_IS_EMBEDDED */

Unrelated whitespace change, please leave out.

Quoted 9 lines
common/cmd_nand.h new file +0 -0
 #endif /* CONFIG_ENV_OFFSET_REDUND */
include/environment.h +0 -0
index b9924fd..03b6c92 100644
@@ -74,15 +74,24 @@
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 
 #if defined(CONFIG_ENV_IS_IN_NAND)

include/environment.h line 83

Quoted 10 lines
include/environment.h +7 -3
-# ifndef CONFIG_ENV_OFFSET
-#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
+# if defined(CONFIG_ENV_OFFSET_OOB)
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB is set"
+#  endif
+extern unsigned long env_offset;
+#  undef CONFIG_ENV_OFFSET
+#  define CONFIG_ENV_OFFSET env_offset

Don't undef CONFIG_ENV_OFFSET, we want the build to fail if the user tries to do it both ways (just like if CONFIG_ENV_OFFSET_REDUND is specified).

include/environment.h line 84

Quoted 1 line
include/environment.h +1 -0
+#define CONFIG_ENV_OFFSET_SIZE 8

Why is this configurable?

-Scott

#91 lore raw

PATCH 1/1 NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB)

Thank you for the thorough review, Scott.

Quoted 13 lines · Scott Wood

common/cmd_dynenv.c line 4

Quoted 10 lines · Ben Gardiner
common/cmd_dynenv.c new file +4 -0
new file mode 100644
index 0000000..5167875
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Harald Welte <[email protected]>
+ * (C) Copyright 2008 Harald Welte <[email protected]>

Is this correct and up-to-date?

The code was taken from Harald's patches he submitted to the mailing list. I didn't do much to them except to re-factor the 'get' functionality. Should I have added myself / my organization to the copyright list? I figured my changes were not enough to warrant the additional attribution of copyright.

Quoted 7 lines

common/cmd_dynenv.c line 30

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+unsigned long env_offset;

This is a pretty generic name for something NAND-specific -- as is "dynenv".

Maybe this should be a nand subcommand? ?Putting it in cmd_nand.c would also eliminate the need to export arg_off_size().

I'm glad you brought this up. I was wondering if the command might be better suited under the nand command -- I agree that it would eliminate the export of arg_off_size and all the renames, which would be very nice. Would 'nand dynenv' do? How about 'nand env.oob' ?

Quoted 4 lines

common/cmd_dynenv.c line 6

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+ ? ? ? ? ? ? if(mtd->oobavail < CONFIG_ENV_OFFSET_SIZE){

Please put a space after "if" and before the opening brace (in fact, there's no need for the braces at all on this one-liner).

will do

Quoted 4 lines

common/cmd_dynenv.c line 7

Quoted 1 line
common/cmd_dynenv.c new file +1 -0
+ ? ? ? ? ? ? ? ? ? ? printf("Insufficient available OOB bytes: %d OOB bytes available but %d required for dynenv support\n",mtd->oobavail,8);

Keep lines under 80 columns (both in source code and in output), and put spaces after commas.

sorry about that, I should know better :)

Quoted 10 lines

common/cmd_dynenv.c line 12

Quoted 5 lines
common/cmd_dynenv.c new file +5 -0
+ ? ? ? ? ? ? }
+
+ ? ? ? ? ? ? oob_buf = malloc(mtd->oobsize);
+ ? ? ? ? ? ? if(!oob_buf)
+ ? ? ? ? ? ? ? ? ? ? return -ENOMEM;

Let the user know it didn't work?

You only really need 8 bytes, why not just put it on the stack? ?Likewise in get_dynenv().

good ideas

Quoted 17 lines

common/cmd_dynenv.c line 25

Quoted 13 lines
common/cmd_dynenv.c new file +13 -0
+ ? ? ? ? ? ? ops.datbuf = NULL;
+ ? ? ? ? ? ? ops.mode = MTD_OOB_AUTO;
+ ? ? ? ? ? ? ops.ooboffs = 0;
+ ? ? ? ? ? ? ops.ooblen = CONFIG_ENV_OFFSET_SIZE;
+ ? ? ? ? ? ? ops.oobbuf = (void *) oob_buf;
+
+ ? ? ? ? ? ? ret = mtd->read_oob(mtd, CONFIG_ENV_OFFSET_SIZE, &ops);
+ ? ? ? ? ? ? oob_buf[0] = ENV_OOB_MARKER;
+
+ ? ? ? ? ? ? if (!ret) {
+ ? ? ? ? ? ? ? ? ? ? if(addr & ~oob_buf[1]) {
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? printf("ERROR: erase OOB block 0 to "
+ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "write this value\n");

You cannot erase OOB without erasing the entire block, so this message is a little confusing.

Quoted 2 lines

Do you really expect to make use of the ability to set a new address without erasing, if it only clears bits?

No, I suppose not. The main use-case seems to be 'dynenv set' on a freshly erased nand when using u-boot for programming. OTOH I have noticed that (one of) the nand erase utility that comes with the TI OMAP L138 EVM erases the NAND w/o erasing the OOB; so it was useful during testing to know if I was able to write the correct value to the OOB. I could replace this with a read-back check to accomplish the same task -- this will also make 'set' commit the new offset 'live' (see below)

Quoted 8 lines

common/cmd_dynenv.c line 32

Quoted 7 lines
common/cmd_dynenv.c new file +7 -0
+ ? ? ? ? ? ? ret = mtd->write_oob(mtd, CONFIG_ENV_OFFSET_SIZE, &ops);
+ ? ? ? ? ? ? if (!ret)
+ ? ? ? ? ? ? ? ? ? ? CONFIG_ENV_OFFSET = addr;
+ ? ? ? ? ? ? else {
+ ? ? ? ? ? ? ? ? ? ? printf("Error writing OOB block 0\n");
+ ? ? ? ? ? ? ? ? ? ? goto fail;
+ ? ? ? ? ? ? }
Quoted 8 lines

If you put braces on one side of the else, put them on both.

common/cmd_dynenv.c line 36

Quoted 4 lines
common/cmd_dynenv.c new file +4 -0
+
+ ? ? ? ? ? ? free(oob_buf);
+ ? ? } else
+ ? ? ? ? ? ? goto usage;

Likewise.

will do

Quoted 3 lines

Is there anything you can do on "dynenv set" so that the user won't have to reboot after setting the dynenv to be able to saveenv into the new environment?

Good catch. Yes I think this could also be handled by replacing the OOB bit-check with a call and check of the 'dynenv get' command after set. In this way the global variable that has been swapped inplace of CONFIG_ENV_OFFSET will have the value of the newly set dynamic environment.

Quoted 7 lines

common/cmd_dynenv.c line 40

Quoted 5 lines
common/cmd_dynenv.c new file +4 -0
+U_BOOT_CMD(dynenv, 4, 1, do_dynenv,
+ ? ? "dynenv ?- dynamically placed (NAND) environment",
+ ? ? "set off ? ? ? ?- set enviromnent offset\n"
+ ? ? "dynenv get ? ? - get environment offset");
\ No newline at end of file

Please put a newline at the end of the file.

sorry I really should have caught that one.

Quoted 5 lines
Quoted 5 lines
common/cmd_nand.h new file +0 -0
new file mode 100644
index 0000000..023ed4f
Quoted 8 lines

common/cmd_nand.h line 5

Quoted 6 lines
common/cmd_nand.h new file +5 -0
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <[email protected]>

Is this really the right copyright/authorship for this file?

see answer above; but this file will be removed in the next version since I will stick the dynenv command under the nand command.

Quoted 7 lines

common/cmd_nand.h line 8

Quoted 3 lines
common/cmd_nand.h new file +3 -0
+ ? ? if(!ret) {
+ ? ? ? ? ? ? if(oob_buf[0] == ENV_OOB_MARKER) {
+ ? ? ? ? ? ? ? ? ? ? *result = oob_buf[1];

Should probably encode the environment location as a block number, rather than as a byte, for flashes larger than 4GiB (there are other places in the environment handling where this won't work, but let's not add more).

good idea

Quoted 12 lines

common/cmd_nand.h line 10

Quoted 2 lines
common/cmd_nand.h new file +2 -0
+ ? ? ? ? ? ? }
+ ? ? ? ? ? ? else {

} else {

Quoted 7 lines

?#ifdef CONFIG_ENV_OFFSET_REDUND
?void env_relocate_spec (void)
?{

common/cmd_nand.h new file +0 -0
@@ -357,12 +398,23 @@ void env_relocate_spec (void)
 ?#if !defined(ENV_IS_EMBEDDED)
 ? ? ? int ret;
 
Quoted 5 lines

common/cmd_nand.h void env_relocate_spec (void) · line 402

Quoted 2 lines
common/cmd_nand.h new file +2 -0
+#if defined(CONFIG_ENV_OFFSET_OOB)
+ ? ? ret = get_dynenv(&CONFIG_ENV_OFFSET);

Taking the address of a macro looks really weird. ?This will only work if the macro is defined as env_offset, so why not just use env_offset?

Yeah... it's pretty weird, I'll subs env_offset here. :)

Quoted 10 lines
Quoted 8 lines
common/cmd_nand.h new file +1 -0
 ? ? ? ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
 ? ? ? if (ret)
 ? ? ? ? ? ? ? return use_default();
 
 ? ? ? if (crc32(0, env_ptr->data, ENV_SIZE) != env_ptr->crc)
 ? ? ? ? ? ? ? return use_default();
+

?#endif /* ! ENV_IS_EMBEDDED */

Unrelated whitespace change, please leave out.

will do

Quoted 8 lines
Quoted 8 lines

?#endif /* CONFIG_ENV_OFFSET_REDUND */

include/environment.h +0 -0
index b9924fd..03b6c92 100644
@@ -74,15 +74,24 @@

?#endif ? ? ? /* CONFIG_ENV_IS_IN_FLASH */

Quoted 14 lines

include/environment.h

Quoted 11 lines

?#if defined(CONFIG_ENV_IS_IN_NAND)

include/environment.h +7 -3
-# ifndef CONFIG_ENV_OFFSET
-# ?error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
+# if defined(CONFIG_ENV_OFFSET_OOB)
+# ?ifdef CONFIG_ENV_OFFSET_REDUND
+# ? error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB is set"
+# ?endif
+extern unsigned long env_offset;
+# ?undef CONFIG_ENV_OFFSET
+# ?define CONFIG_ENV_OFFSET env_offset

Don't undef CONFIG_ENV_OFFSET, we want the build to fail if the user tries to do it both ways (just like if CONFIG_ENV_OFFSET_REDUND is specified).

will do

Quoted 3 lines
Quoted 1 line

+#define CONFIG_ENV_OFFSET_SIZE 8

Why is this configurable?

Can't think of a good reason. I'll just make a #define in a restricted scope to avoid magic number 8.

Best Regards,
Ben Gardiner

Signature · 4 lines
Ben Gardiner
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca
#92 lore raw

PATCH v2 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

In reply to Scott Wood

This is a re-submission of the patch by Harald Welte <[email protected]> with modifications to make it a sub-command and changes as suggested by Scott Wood <[email protected]> in
http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43916.

This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

This patch introduces the 'nand env.oob' command, which can be called from the u-boot command line. 'nand env.oob get' reads the address of the environment partition from the OOB data,
'nand env.oob set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name.

---

Changes in v2:
* don't use generic names for the env-offset global and the comand
* make a sub-command of the nand command
* store the offset in units of eraseblocks
* allocate oob write/read buffers on stack
* verify write of new offset
* make setting new offset affect the live values
* update copyright of file
* use the global variable instead of the macro in address statements
* don't make the oob used bytes configurable
* don't undef CONFIG_ENV_OFFSET

Tested with the da850 support patch series from Sudhakar Rjashekhara [1]

./MAKEALL arm on master
--------------------- SUMMARY ----------------------------
Boards compiled: 150
Boards with warnings or errors: 47 ( shannon evb4510 lpc2292sodimm modnet50 SMN42 guruplug mv88f6281gtw_ge netstar openrd_base rd6281a sheevaplug suen3 afeb9260 at91cap9adk at91rm9200dk at91rm9200ek at91sam9260ek at91sam9261ek at91sam9263ek at91sam9g10ek at91sam9g20ek at91sam9m10g45ek at91sam9rlek cmc_pu2 CPUAT91 CPU9260 CPU9G20 csb637 eb_cpux9k2 kb9202 meesc mp2usb m501sk otc570 pm9261 pm9263 SBC35_A9G20 TNY_A9260 TNY_A9G20 actux1 actux2 actux3 actux4 ixdp425 ixdpg425 pdnb3 scpu )
----------------------------------------------------------

./MAKEALL arm with the patch
--------------------- SUMMARY ----------------------------
Boards compiled: 150
Boards with warnings or errors: 47 ( shannon evb4510 lpc2292sodimm modnet50 SMN42 guruplug mv88f6281gtw_ge netstar openrd_base rd6281a sheevaplug suen3 afeb9260 at91cap9adk at91rm9200dk at91rm9200ek at91sam9260ek at91sam9261ek at91sam9263ek at91sam9g10ek at91sam9g20ek at91sam9m10g45ek at91sam9rlek cmc_pu2 CPUAT91 CPU9260 CPU9G20 csb637 eb_cpux9k2 kb9202 meesc mp2usb m501sk otc570 pm9261 pm9263 SBC35_A9G20 TNY_A9260 TNY_A9G20 actux1 actux2 actux3 actux4 ixdp425 ixdpg425 pdnb3 scpu )
----------------------------------------------------------

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/78947

---
 common/cmd_nand.c     |  107 ++++++++++++++++++++++++++++++++++++++++++++++++-
 common/env_nand.c     |   45 ++++++++++++++++++++
 include/environment.h |   20 ++++++---
 include/nand.h        |    9 ++++
 4 files changed, 174 insertions(+), 7 deletions(-)
common/cmd_nand.c +106 -1
index f611fd7..5af5b9e 100644
@@ -6,6 +6,8 @@
  *
  * Added 16-bit nand support
  * (C) 2004 Texas Instruments
+ * Added env offset in OOB
+ * (C) 2010 Nanometrics, Inc.
  */
 
 #include <common.h>
@@ -193,6 +195,91 @@ static void do_nand_status(nand_info_t *nand)
 }
 #endif
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;
+
+int do_nand_env_oob(cmd_tbl_t *cmdtp, nand_info_t *nand,
+		                 int argc, char *argv[])
+{
+	int ret;
+	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+
+	char *cmd = argv[1];
+
+	if (!strcmp(cmd, "get")) {
+		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+		if (!ret) {
+			printf("0x%08lx\n", nand_env_oob_offset);
+		}
+		else {
+			return 1;
+		}
+	} else if (!strcmp(cmd, "set")) {
+		ulong addr;
+		size_t dummy_size;
+		struct mtd_oob_ops ops;
+
+		if (argc < 3)
+			goto usage;
+
+		if (arg_off_size(argc-2, argv + 2, nand, &addr,
+						  &dummy_size) < 0) {
+			printf("Offset or partition name expected\n");
+			return 1;
+		}
+
+		if (nand->oobavail < ENV_OFFSET_SIZE) {
+			printf("Insufficient available OOB bytes: %d OOB bytes"
+			     " available but %d required for env.oob support\n"
+					       ,nand->oobavail,ENV_OFFSET_SIZE);
+			return 1;
+		}
+
+		if ((addr & (nand->erasesize - 1)) != 0) {
+			printf("Environment offset must be block-aligned\n");
+			return 1;
+		}
+
+		ops.datbuf = NULL;
+		ops.mode = MTD_OOB_AUTO;
+		ops.ooboffs = 0;
+		ops.ooblen = ENV_OFFSET_SIZE;
+		ops.oobbuf = (void *) oob_buf;
+
+		oob_buf[0] = ENV_OOB_MARKER;
+		oob_buf[1] = addr / nand->erasesize;
+
+		ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
+		if (!ret) {
+			ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+			if (ret) {
+				printf("Error reading env offset in OOB\n");
+				return ret;
+			}
+
+			if (addr != nand_env_oob_offset) {
+				printf("Verification of env offset in OOB "
+				       "failed: 0x%08lx expected but got "
+				       "0x%08lx\n", addr, nand_env_oob_offset);
+				return 1;
+			}
+		} else {
+			printf("Error writing OOB block 0\n");
+			return ret;
+		}
+	} else {
+		goto usage;
+	}
+
+	return ret;
+
+usage:
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+#endif
+
 static void nand_print_info(int idx)
 {
 	nand_info_t *nand = &nand_info[idx];
@@ -272,9 +359,20 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 	    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
 	    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
 	    strcmp(cmd, "biterr") != 0 &&
-	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
+	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0
+#ifdef CONFIG_ENV_OFFSET_OOB
+	    && strcmp(cmd, "env.oob") != 0
+#endif
+	    )
 		goto usage;
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+	/* this command operates only on the first nand device */
+	if (strcmp(cmd,"env.oob") == 0) {
+	      return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1);
+	}
+#endif
+
 	/* the following commands operate on the current device */
 	if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
 	    !nand_info[nand_curr_device].name) {
@@ -502,6 +600,13 @@ U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
 	"    bring nand to lock state or display locked pages\n"
 	"nand unlock [offset] [size] - unlock section"
 #endif
+#ifdef CONFIG_ENV_OFFSET_OOB
+	"\n"
+	"nand env.oob - environment offset in OOB of block 0 of"
+	"    first device.\n"
+	"nand env.oob set off|partition - set enviromnent offset\n"
+	"nand env.oob get - get environment offset"
+#endif
 );
 
 static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
common/env_nand.c +45 -0

63 lines not on this page · raw message

include/environment.h +14 -6
index b9924fd..9820d23 100644
@@ -74,15 +74,23 @@
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 
 #if defined(CONFIG_ENV_IS_IN_NAND)
-# ifndef CONFIG_ENV_OFFSET
-#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
+# if defined(CONFIG_ENV_OFFSET_OOB)
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB is set"
+#  endif
+extern unsigned long nand_env_oob_offset;
+#  define CONFIG_ENV_OFFSET nand_env_oob_offset
+# else
+#  ifndef CONFIG_ENV_OFFSET
+#   error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
+#  endif
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#  endif
+# endif /* CONFIG_ENV_OFFSET_OOB */
 # ifndef CONFIG_ENV_SIZE
 #  error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_NAND"
 # endif
-# ifdef CONFIG_ENV_OFFSET_REDUND
-#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT
-# endif
 #endif /* CONFIG_ENV_IS_IN_NAND */
 
 #if defined(CONFIG_ENV_IS_IN_MG_DISK)
include/nand.h +9 -0
index 2a81597..8bdf419 100644
@@ -130,3 +130,12 @@ void board_nand_select_device(struct nand_chip *nand, int chip);
 __attribute__((noreturn)) void nand_boot(void);
 
 #endif
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+#define ENV_OOB_MARKER 0x30425645 /*"EVB0" in little-endian -- offset is stored
+				    as block number*/
+#define ENV_OOB_MARKER_OLD 0x30564e45 /*"ENV0" in little-endian -- offset is
+					stored as byte number */
+#define ENV_OFFSET_SIZE 8
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result);
+#endif
Signature · 1 line
1.7.0.4
#93 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

This patch introduces the 'nand env.oob' command, which can be called from the u-boot command line. 'nand env.oob get' reads the address of the environment partition from the OOB data,
'nand env.oob set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43916
[2] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79195

---

Changes in v3:
* updated commit message
* rebased to 39ddd10b046fb791f47281ffb2100be01909ad72 of
git://git.denx.de/u-boot.git
* tested using small config changes to include/configs/da850evm.h

Changes in v2:
* don't use generic names for the env-offset global and the comand
* make a sub-command of the nand command
* store the offset in units of eraseblocks
* allocate oob write/read buffers on stack
* verify write of new offset
* make setting new offset affect the live values
* update copyright of file
* use the global variable instead of the macro in address statements
* don't make the oob used bytes configurable
* don't undef CONFIG_ENV_OFFSET

---
 common/cmd_nand.c     |  107 ++++++++++++++++++++++++++++++++++++++++++++++++-
 common/env_nand.c     |   45 ++++++++++++++++++++
 include/environment.h |   20 ++++++---
 include/nand.h        |    9 ++++
 4 files changed, 174 insertions(+), 7 deletions(-)
common/cmd_nand.c +106 -1
index f611fd7..5af5b9e 100644
@@ -6,6 +6,8 @@
  *
  * Added 16-bit nand support
  * (C) 2004 Texas Instruments
+ * Added env offset in OOB
+ * (C) 2010 Nanometrics, Inc.
  */
 
 #include <common.h>
@@ -193,6 +195,91 @@ static void do_nand_status(nand_info_t *nand)
 }
 #endif
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;
+
+int do_nand_env_oob(cmd_tbl_t *cmdtp, nand_info_t *nand,
+		                 int argc, char *argv[])
+{
+	int ret;
+	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+
+	char *cmd = argv[1];
+
+	if (!strcmp(cmd, "get")) {
+		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+		if (!ret) {
+			printf("0x%08lx\n", nand_env_oob_offset);
+		}
+		else {
+			return 1;
+		}
+	} else if (!strcmp(cmd, "set")) {
+		ulong addr;
+		size_t dummy_size;
+		struct mtd_oob_ops ops;
+
+		if (argc < 3)
+			goto usage;
+
+		if (arg_off_size(argc-2, argv + 2, nand, &addr,
+						  &dummy_size) < 0) {
+			printf("Offset or partition name expected\n");
+			return 1;
+		}
+
+		if (nand->oobavail < ENV_OFFSET_SIZE) {
+			printf("Insufficient available OOB bytes: %d OOB bytes"
+			     " available but %d required for env.oob support\n"
+					       ,nand->oobavail,ENV_OFFSET_SIZE);
+			return 1;
+		}
+
+		if ((addr & (nand->erasesize - 1)) != 0) {
+			printf("Environment offset must be block-aligned\n");
+			return 1;
+		}
+
+		ops.datbuf = NULL;
+		ops.mode = MTD_OOB_AUTO;
+		ops.ooboffs = 0;
+		ops.ooblen = ENV_OFFSET_SIZE;
+		ops.oobbuf = (void *) oob_buf;
+
+		oob_buf[0] = ENV_OOB_MARKER;
+		oob_buf[1] = addr / nand->erasesize;
+
+		ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
+		if (!ret) {
+			ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+			if (ret) {
+				printf("Error reading env offset in OOB\n");
+				return ret;
+			}
+
+			if (addr != nand_env_oob_offset) {
+				printf("Verification of env offset in OOB "
+				       "failed: 0x%08lx expected but got "
+				       "0x%08lx\n", addr, nand_env_oob_offset);
+				return 1;
+			}
+		} else {
+			printf("Error writing OOB block 0\n");
+			return ret;
+		}
+	} else {
+		goto usage;
+	}
+
+	return ret;
+
+usage:
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+#endif
+
 static void nand_print_info(int idx)
 {
 	nand_info_t *nand = &nand_info[idx];
@@ -272,9 +359,20 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
 	    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
 	    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
 	    strcmp(cmd, "biterr") != 0 &&
-	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
+	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0
+#ifdef CONFIG_ENV_OFFSET_OOB
+	    && strcmp(cmd, "env.oob") != 0
+#endif
+	    )
 		goto usage;
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+	/* this command operates only on the first nand device */
+	if (strcmp(cmd,"env.oob") == 0) {
+	      return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1);
+	}
+#endif
+
 	/* the following commands operate on the current device */
 	if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
 	    !nand_info[nand_curr_device].name) {
@@ -502,6 +600,13 @@ U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
 	"    bring nand to lock state or display locked pages\n"
 	"nand unlock [offset] [size] - unlock section"
 #endif
+#ifdef CONFIG_ENV_OFFSET_OOB
+	"\n"
+	"nand env.oob - environment offset in OOB of block 0 of"
+	"    first device.\n"
+	"nand env.oob set off|partition - set enviromnent offset\n"
+	"nand env.oob get - get environment offset"
+#endif
 );
 
 static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
common/env_nand.c +45 -0

63 lines not on this page · raw message

include/environment.h +14 -6
index b9924fd..9820d23 100644
@@ -74,15 +74,23 @@
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 
 #if defined(CONFIG_ENV_IS_IN_NAND)
-# ifndef CONFIG_ENV_OFFSET
-#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
+# if defined(CONFIG_ENV_OFFSET_OOB)
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB is set"
+#  endif
+extern unsigned long nand_env_oob_offset;
+#  define CONFIG_ENV_OFFSET nand_env_oob_offset
+# else
+#  ifndef CONFIG_ENV_OFFSET
+#   error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
+#  endif
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#  endif
+# endif /* CONFIG_ENV_OFFSET_OOB */
 # ifndef CONFIG_ENV_SIZE
 #  error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_NAND"
 # endif
-# ifdef CONFIG_ENV_OFFSET_REDUND
-#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT
-# endif
 #endif /* CONFIG_ENV_IS_IN_NAND */
 
 #if defined(CONFIG_ENV_IS_IN_MG_DISK)
include/nand.h +9 -0
index 2a81597..8bdf419 100644
@@ -130,3 +130,12 @@ void board_nand_select_device(struct nand_chip *nand, int chip);
 __attribute__((noreturn)) void nand_boot(void);
 
 #endif
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+#define ENV_OOB_MARKER 0x30425645 /*"EVB0" in little-endian -- offset is stored
+				    as block number*/
+#define ENV_OOB_MARKER_OLD 0x30564e45 /*"ENV0" in little-endian -- offset is
+					stored as byte number */
+#define ENV_OFFSET_SIZE 8
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result);
+#endif
Signature · 1 line
1.7.0.4
#94 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Dear Ben Gardiner,

Quoted 13 lines · In message <[email protected]> you…

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

Quoted 5 lines

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

Does this work with redundant environment in NAND?

Best regards,

Wolfgang Denk

Signature · 6 lines
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
One of the advantages of being a captain is being able to ask for ad-
vice without necessarily having to take it.
	-- Kirk, "Dagger of the Mind", stardate 2715.2
#95 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Quoted 16 lines · Wolfgang Denk

Dear Ben Gardiner,

Quoted 13 lines · In message <[email protected]> you…

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. ?The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

Quoted 7 lines
Quoted 5 lines

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

Does this work with redundant environment in NAND?

Currently the use of CONFIG_ENV_OFFSET_OOB and CONFIG_ENV_OFFSET_REDUND is disabled. I think it could work when the env is in its own NAND partition (i.e. !ENV_IS_EMBEDDED and !CONFIG_NAND_ENV_DST).

We could require that the redundant env is CONFIG_ENV_SIZE after the offset specified in the OOB or that two offsets are store in the OOB area. The latter requires that the OOB size is large enough to store two offsets. The former requires that CONFIG_ENV_SIZE is a multiple of the erase block size and perhaps additional skip-if-bad-block behaviour.

Furthermore, to implement env.oob compatibility with redundant environments I believe that the use of the CONFIG_ENV_OFFSET_REDUND macro needs to be split into a 'use redundant env' macro and a 'value of redundant env offset' macro so that we don't have to redefine CONFIG_ENV_OFFSET_REDUND. For instance, I would change saveenv in env_nand.c to look something like:

---

#ifdef CONFIG_USE_ENV_REDUND
int saveenv(void)
{
...

                ret = writeenv(CONFIG_ENV_OFFSET_REDUND, (u_char *) env_ptr);

---

I see that compatibility of this feature with redundant environments would definitely increase its utility. Can I put that into a second patch series and leave this patch as-is to be considered for inclusion? Would you prefer that I re-spin this patch into a series that includes support for redundant environment?

Best Regards,
Ben Gardiner

Signature · 3 lines
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca
#96 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

In reply to Ben Gardiner
Quoted 19 lines · Ben Gardiner

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

Quoted 6 lines

This patch introduces the 'nand env.oob' command, which can be called from the u-boot command line. 'nand env.oob get' reads the address of the environment partition from the OOB data,
'nand env.oob set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name.

Hello Ben,

This is a nice idea. I see that the logic needs 8bytes at offset 0 in block 0 oob area. This means that it would also overwrite the offset 5 (which is the bad block marker in case of small page devices) and offset 0 (bad block marker in large page devs)

Am I missing something here

Regards
Vipin

#97 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Quoted 8 lines · Vipin KUMAR

Hello Ben,

This is a nice idea. I see that the logic needs 8bytes at offset 0 in block 0 oob area. This means that it would also overwrite the offset 5 (which is the bad block marker in case of small page devices) and offset 0 (bad block marker in large page devs)

Am I missing something here

I can't take credit for the idea -- it is Harald's.

The original patch from Harald Welte wrote the env offset to bytes 8..15 explicitly. The location in the OOB to which the env offset is written was made implicit when I ported to write_oob using struct mtd_oob_ops with mode MTD_OOB_AUTO as suggested by Scott Wood in the review of Harald's patch [1].

With MTD_OOB_AUTO the reads+writes should be performed automatically in the 'free' region of the OOB (specified by the .oobfree member of nand_ecclayout). At least that's what is supposed to be happening... I welcome any further concerns that you may have.

Best Regards,

Ben Gardiner

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43916

--
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#98 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

In reply to Ben Gardiner

Dear Ben,

thanks again for moving those patches forward.

However,

common/cmd_nand.c line 11

Quoted 11 lines
common/cmd_nand.c +2 -0
index f611fd7..5af5b9e 100644
@@ -6,6 +6,8 @@
  *
  * Added 16-bit nand support
  * (C) 2004 Texas Instruments
+ * Added env offset in OOB
+ * (C) 2010 Nanometrics, Inc.
  */

I think if you add a (C) statement to code that is based on my work, I believei it is fair to add a (C) statement for OpenMoko Inc. for whom I was working at that time. After all, they hold the copyright to the original OOB environment offset (and have licensed the code under GPL)

Thanks for your consideration,
Harald

Signature · 4 lines
- Harald Welte <[email protected]>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)
#99 lore raw

PATCH v3 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Dear Harald,

Quoted 4 lines · Harald Welte

I think if you add a (C) statement to code that is based on my work, I believei it is fair to add a (C) statement for OpenMoko Inc. for whom I was working at that time. ?After all, they hold the copyright to the original OOB environment offset (and have licensed the code under GPL)

You're right -- I'm sorry for that omission. It was not intentional.

Thank you for pointing this out. I will add the "(C) Copyright 2006-2007 OpenMoko, Inc." statement found currently in the openmoko u-boot tree [1] with remark "'dynenv' Dynamic environment offset in NAND OOB" and post an updated patch shortly.

Best Regards,

Ben Gardiner

[1] http://git.openmoko.org/?p=u-boot.git;a=blob_plain;f=common/cmd_dynenv.c;hb=refs/heads/mokopatches

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#100 lore raw

PATCH v4 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

In reply to Harald Welte

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

This patch enables the environment partition to have a run-time dynamic location (offset) in the NAND flash. The reason for this is simply that all NAND flashes have factory-default bad blocks, and a fixed compile time offset would mean that sometimes the environment partition would live inside factory bad blocks. Since the number of factory default blocks can be quite high (easily 1.3MBytes in current standard components), it is not economic to keep that many spare blocks inside the environment partition.

With this patch and CONFIG_ENV_OFFSET_OOB enabled, the location of the environment partition is stored in the out-of-band (OOB) data of the first block in flash. Since the first block is where most systems boot from, the vendors guarantee that the first block is not a factory default block.

This patch introduces the 'nand env.oob' command, which can be called from the u-boot command line. 'nand env.oob get' reads the address of the environment partition from the OOB data, 'nand env.oob set {offset,partition-name}' allows the setting of the marker by specifying a numeric offset or a partition name.

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43916
[2] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79195

---

Changes in v4:
* Added 'Acked-by Harald Welte' with permission.
* rebased to 54841ab50c20d6fa6c9cc3eb826989da3a22d934 of
git://git.denx.de/u-boot.git
* adding OpenMoko copyright statement as requested by Harald Welte <[email protected]> in review
* committing forgotten fixes for checkpath errors -- only two warnings remain, both of which are not applicable
* fix warning created by passing const pointer to the do_nand_env_oob function which did not declare argv as a const pointer

Changes in v3:
* updated commit message
* rebased to 39ddd10b046fb791f47281ffb2100be01909ad72 of
git://git.denx.de/u-boot.git
* tested using small config changes to include/configs/da850evm.h

Changes in v2:
* don't use generic names for the env-offset global and the comand
* make a sub-command of the nand command
* store the offset in units of eraseblocks
* allocate oob write/read buffers on stack
* verify write of new offset
* make setting new offset affect the live values
* update copyright of file
* use the global variable instead of the macro in address statements
* don't make the oob used bytes configurable
* don't undef CONFIG_ENV_OFFSET

I verified the patch with checkpath.pl. The checkpatch.pl output follows:

WARNING: suspect code indent for conditional statements (8, 14)
+ if (strcmp(cmd, "env.oob") == 0)
+ return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1);

WARNING: Use #include <linux/errno.h> instead of <asm/errno.h> +#include <asm/errno.h>

total: 0 errors, 2 warnings, 247 lines checked

Neither of these warnings appear to be applicable.

I tested the binary size and compiler warnings on ARM9 and 8xx with the following commands:

#checkout u-boot/master, apply changes to da850evm_config for testing, #commit
./MAKEALL ARM9 2>&1 > ../makeall-master.log
./MAKEALL 8xx 2>&1 > ../makeall-master.log
#apply patch, commit
./MAKEALL ARM9 2>&1 > ../makeall-env_oob.log
./MAKEALL 8xx 2>&1 > ../makeall-8xx-env_oob.log
diff -burp ../makeall-8xx-master.log ../makeall-8xx-env_oob.log diff -burp ../makeall-master.log ../makeall-env_oob.log

The only output of the diff commands was in the modified da850evm_config. The diff shows the text section has grown by 1352 bytes with the feature introduced by this patch enabled.

@@ -48,7 +48,7 @@ Configuring for da830evm board...
147617 4888 295320 447825 6d551 ./u-boot
Configuring for da850evm board...
text data bss dec hex filename

- 198497          10332  296608  505437   7b65d ./u-boot
+ 199849          10332  296612  506793   7bba9 ./u-boot
 Configuring for edb9301 board...
    text           data     bss     dec     hex filename
  133899           3772  213400  351071   55b5f ./u-boot
---
 common/cmd_nand.c     |  107 ++++++++++++++++++++++++++++++++++++++++++++++++-
 common/env_nand.c     |   46 +++++++++++++++++++++
 include/environment.h |   21 +++++++---
 include/nand.h        |    9 ++++
 4 files changed, 176 insertions(+), 7 deletions(-)
common/cmd_nand.c +106 -1
index ea80555..a4c67c1 100644
@@ -4,6 +4,10 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <[email protected]>
  *
+ * Ported 'dynenv' to 'nand env.oob' command
+ * (C) 2010 Nanometrics, Inc.
+ * 'dynenv' -- Dynamic environment offset in NAND OOB
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
  * Added 16-bit nand support
  * (C) 2004 Texas Instruments
  */
@@ -193,6 +197,90 @@ static void do_nand_status(nand_info_t *nand)
 }
 #endif
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;
+
+int do_nand_env_oob(cmd_tbl_t *cmdtp, nand_info_t *nand,
+				 int argc, char * const argv[])
+{
+	int ret;
+	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+
+	char *cmd = argv[1];
+
+	if (!strcmp(cmd, "get")) {
+		ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+		if (!ret)
+			printf("0x%08lx\n", nand_env_oob_offset);
+		else
+			return 1;
+	} else if (!strcmp(cmd, "set")) {
+		ulong addr;
+		size_t dummy_size;
+		struct mtd_oob_ops ops;
+
+		if (argc < 3)
+			goto usage;
+
+		if (arg_off_size(argc-2, argv + 2, nand, &addr,
+						  &dummy_size) < 0) {
+			printf("Offset or partition name expected\n");
+			return 1;
+		}
+
+		if (nand->oobavail < ENV_OFFSET_SIZE) {
+			printf("Insufficient available OOB bytes: %d OOB bytes"
+			    " available but %d required for env.oob support\n",
+								nand->oobavail,
+							      ENV_OFFSET_SIZE);
+			return 1;
+		}
+
+		if ((addr & (nand->erasesize - 1)) != 0) {
+			printf("Environment offset must be block-aligned\n");
+			return 1;
+		}
+
+		ops.datbuf = NULL;
+		ops.mode = MTD_OOB_AUTO;
+		ops.ooboffs = 0;
+		ops.ooblen = ENV_OFFSET_SIZE;
+		ops.oobbuf = (void *) oob_buf;
+
+		oob_buf[0] = ENV_OOB_MARKER;
+		oob_buf[1] = addr / nand->erasesize;
+
+		ret = nand->write_oob(nand, ENV_OFFSET_SIZE, &ops);
+		if (!ret) {
+			ret = get_nand_env_oob(nand, &nand_env_oob_offset);
+			if (ret) {
+				printf("Error reading env offset in OOB\n");
+				return ret;
+			}
+
+			if (addr != nand_env_oob_offset) {
+				printf("Verification of env offset in OOB "
+				       "failed: 0x%08lx expected but got "
+				       "0x%08lx\n", addr, nand_env_oob_offset);
+				return 1;
+			}
+		} else {
+			printf("Error writing OOB block 0\n");
+			return ret;
+		}
+	} else {
+		goto usage;
+	}
+
+	return ret;
+
+usage:
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+#endif
+
 static void nand_print_info(int idx)
 {
 	nand_info_t *nand = &nand_info[idx];
@@ -272,9 +360,19 @@ int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
 	    strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 &&
 	    strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 &&
 	    strcmp(cmd, "biterr") != 0 &&
-	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 )
+	    strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0
+#ifdef CONFIG_ENV_OFFSET_OOB
+	    && strcmp(cmd, "env.oob") != 0
+#endif
+	    )
 		goto usage;
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+	/* this command operates only on the first nand device */
+	if (strcmp(cmd, "env.oob") == 0)
+	      return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1);
+#endif
+
 	/* the following commands operate on the current device */
 	if (nand_curr_device < 0 || nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE ||
 	    !nand_info[nand_curr_device].name) {
@@ -502,6 +600,13 @@ U_BOOT_CMD(nand, CONFIG_SYS_MAXARGS, 1, do_nand,
 	"    bring nand to lock state or display locked pages\n"
 	"nand unlock [offset] [size] - unlock section"
 #endif
+#ifdef CONFIG_ENV_OFFSET_OOB
+	"\n"
+	"nand env.oob - environment offset in OOB of block 0 of"
+	"    first device.\n"
+	"nand env.oob set off|partition - set enviromnent offset\n"
+	"nand env.oob get - get environment offset"
+#endif
 );
 
 static int nand_load_image(cmd_tbl_t *cmdtp, nand_info_t *nand,
common/env_nand.c +46 -0

64 lines not on this page · raw message

include/environment.h +15 -6
index 203f731..fbccf6a 100644
@@ -74,15 +74,24 @@
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 
 #if defined(CONFIG_ENV_IS_IN_NAND)
-# ifndef CONFIG_ENV_OFFSET
-#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
+# if defined(CONFIG_ENV_OFFSET_OOB)
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB"
+#   error "is set"
+#  endif
+extern unsigned long nand_env_oob_offset;
+#  define CONFIG_ENV_OFFSET nand_env_oob_offset
+# else
+#  ifndef CONFIG_ENV_OFFSET
+#   error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
+#  endif
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#  endif
+# endif /* CONFIG_ENV_OFFSET_OOB */
 # ifndef CONFIG_ENV_SIZE
 #  error "Need to define CONFIG_ENV_SIZE when using CONFIG_ENV_IS_IN_NAND"
 # endif
-# ifdef CONFIG_ENV_OFFSET_REDUND
-#  define CONFIG_SYS_REDUNDAND_ENVIRONMENT
-# endif
 #endif /* CONFIG_ENV_IS_IN_NAND */
 
 #if defined(CONFIG_ENV_IS_IN_MG_DISK)
include/nand.h +9 -0
index 2a81597..8bdf419 100644
@@ -130,3 +130,12 @@ void board_nand_select_device(struct nand_chip *nand, int chip);
 __attribute__((noreturn)) void nand_boot(void);
 
 #endif
+
+#ifdef CONFIG_ENV_OFFSET_OOB
+#define ENV_OOB_MARKER 0x30425645 /*"EVB0" in little-endian -- offset is stored
+				    as block number*/
+#define ENV_OOB_MARKER_OLD 0x30564e45 /*"ENV0" in little-endian -- offset is
+					stored as byte number */
+#define ENV_OFFSET_SIZE 8
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result);
+#endif
Signature · 1 line
1.7.0.4
#101 lore raw

PATCH v4 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Hi Scott,

I was hoping that the env OOB patch [1] would be considered for inclusion into this merge window [2] but I saw that your pull request on friday [3] did not include the patch. There has been no reply by you to version 2-4 of the patch but I believe that I successfully made the modifications requested by you in your review of version 1 of the patch [4].

I am still very much a novice in this list and I apologize if it is rude of me to ask: is there any chance for "[PATCH v4] NAND:
environment offset in OOB (CONFIG_ENV_OFFSET_OOB)" [1] to be included in v2010.09 via the u-boot-nand-flash tree?
Are there any concerns with respect to the functionality that this patch provides?
Is there anything else that I can provide to help with getting this patch included?

Best Regards,
Ben Gardiner

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/80832
[2] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/80606
[3] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/81004
[4] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/79195

---
Nanometrics Inc.
+1 (613) 592-6776 x239
http://www.nanometrics.ca

#102 lore raw

PATCH v4 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Quoted 8 lines · On Mon, 12 Jul 2010 12:17:23 -0400 Ben Gardiner <[email protected]>…

Hi Scott,

I was hoping that the env OOB patch [1] would be considered for inclusion into this merge window [2] but I saw that your pull request on friday [3] did not include the patch. There has been no reply by you to version 2-4 of the patch but I believe that I successfully made the modifications requested by you in your review of version 1 of the patch [4].

Sorry, I missed it -- I'll look at it today.

-Scott

#103 lore raw

PATCH v4 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

In reply to Ben Gardiner

I thought I sent this yesterday when applying the patch, but I guess not...

Quoted 3 lines · Ben Gardiner

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

Applied to u-boot-nand-flash.

I sent a followup patch for some minor formatting issues.

common/cmd_nand.c int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[]) · line 373

Quoted 5 lines

I verified the patch with checkpath.pl. The checkpatch.pl output follows:

WARNING: suspect code indent for conditional statements (8, 14)

common/cmd_nand.c +2 -0
+       if (strcmp(cmd, "env.oob") == 0)
+             return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1);

IMHO, "indent with tabs" is more important than "max 80 characters" -- but both can be met nicely using a continuation line.

Review Configuring for da830evm board... · line 54

Quoted 9 lines
(quoted diff) +1 -1
@@ -48,7 +48,7 @@ Configuring for da830evm board...
  147617           4888  295320  447825   6d551 ./u-boot
 Configuring for da850evm board...
    text           data     bss     dec     hex filename
- 198497          10332  296608  505437   7b65d ./u-boot
+ 199849          10332  296612  506793   7bba9 ./u-boot
 Configuring for edb9301 board...
    text           data     bss     dec     hex filename
  133899           3772  213400  351071   55b5f ./u-boot

Don't put patch fragments outside the patch itself, it confuses git.

Quoted 23 lines
---
 common/cmd_nand.c     |  107 ++++++++++++++++++++++++++++++++++++++++++++++++-
 common/env_nand.c     |   46 +++++++++++++++++++++
 include/environment.h |   21 +++++++---
 include/nand.h        |    9 ++++
 4 files changed, 176 insertions(+), 7 deletions(-)
common/cmd_nand.c +4 -0
index ea80555..a4c67c1 100644
@@ -4,6 +4,10 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <[email protected]>
  *
+ * Ported 'dynenv' to 'nand env.oob' command
+ * (C) 2010 Nanometrics, Inc.
+ * 'dynenv' -- Dynamic environment offset in NAND OOB
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
  * Added 16-bit nand support
  * (C) 2004 Texas Instruments
  */

common/cmd_nand.c static void do_nand_status(nand_info_t *nand) · line 201

Quoted 5 lines
common/cmd_nand.c +2 -0
@@ -193,6 +197,90 @@ static void do_nand_status(nand_info_t *nand)
 }
 #endif
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;

Might want to switch to loff_t, even though arg_off_size won't actually let you enter a 64-bit offset yet.

Quoted 7 lines
include/environment.h +0 -0
index 203f731..fbccf6a 100644
@@ -74,15 +74,24 @@
 #endif	/* CONFIG_ENV_IS_IN_FLASH */
 

include/environment.h line 82

Quoted 10 lines
include/environment.h +5 -3
 #if defined(CONFIG_ENV_IS_IN_NAND)
-# ifndef CONFIG_ENV_OFFSET
-#  error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
 
+# if defined(CONFIG_ENV_OFFSET_OOB)
+#  ifdef CONFIG_ENV_OFFSET_REDUND
+#   error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB"
+#   error "is set"
+#  endif

This could be supported pretty easily if we require the redundant env range to come immediately after the regular env range -- no need to track separate offsets.

-Scott

#104 lore raw

PATCH v4 1/1 NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)

Quoted 10 lines · Scott Wood

I thought I sent this yesterday when applying the patch, but I guess not...

Quoted 3 lines · Ben Gardiner

This is a re-submission of the patch by Harald Welte <[email protected]> with minor modifications for rebase and changes as suggested by Scott Wood <[email protected]> [1] [2].

Applied to u-boot-nand-flash.

I sent a followup patch for some minor formatting issues.

Thank you, Scott.

Quoted 9 lines
Quoted 5 lines

I verified the patch with checkpath.pl. The checkpatch.pl output follows:

WARNING: suspect code indent for conditional statements (8, 14)
+ ? ? ? if (strcmp(cmd, "env.oob") == 0)
+ ? ? ? ? ? ? return do_nand_env_oob(cmdtp, &nand_info[0], argc - 1, argv + 1);

IMHO, "indent with tabs" is more important than "max 80 characters" -- but both can be met nicely using a continuation line.

Quoted 11 lines
Quoted 9 lines
(quoted diff) +0 -0
@@ -48,7 +48,7 @@ Configuring for da830evm board...

? 147617 ? ? ? ? ? 4888 ?295320 ?447825 ? 6d551 ./u-boot ?Configuring for da850evm board...
? ? text ? ? ? ? ? data ? ? bss ? ? dec ? ? hex filename
- 198497 ? ? ? ? ?10332 ?296608 ?505437 ? 7b65d ./u-boot
+ 199849 ? ? ? ? ?10332 ?296612 ?506793 ? 7bba9 ./u-boot ?Configuring for edb9301 board...
? ? text ? ? ? ? ? data ? ? bss ? ? dec ? ? hex filename ? 133899 ? ? ? ? ? 3772 ?213400 ?351071 ? 55b5f ./u-boot

Don't put patch fragments outside the patch itself, it confuses git.

Thanks for the tips -- I appreciate it.

Quoted 26 lines
Quoted 26 lines

---

?common/cmd_nand.c ? ? | ?107 ++++++++++++++++++++++++++++++++++++++++++++++++-
?common/env_nand.c ? ? | ? 46 +++++++++++++++++++++
?include/environment.h | ? 21 +++++++---
?include/nand.h ? ? ? ?| ? ?9 ++++

?4 files changed, 176 insertions(+), 7 deletions(-)

common/cmd_nand.c +0 -0
index ea80555..a4c67c1 100644
@@ -4,6 +4,10 @@

? * (c) 1999 Machine Vision Holdings, Inc.
? * (c) 1999, 2000 David Woodhouse <[email protected]> ? *
+ * Ported 'dynenv' to 'nand env.oob' command
+ * (C) 2010 Nanometrics, Inc.
+ * 'dynenv' -- Dynamic environment offset in NAND OOB
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
? * Added 16-bit nand support
? * (C) 2004 Texas Instruments
? */

common/cmd_nand.c +0 -0
@@ -193,6 +197,90 @@ static void do_nand_status(nand_info_t *nand)
 ?}

?#endif

Quoted 5 lines

common/cmd_nand.c static void do_nand_status(nand_info_t *nand) · line 201

Quoted 2 lines
common/cmd_nand.c +2 -0
+#ifdef CONFIG_ENV_OFFSET_OOB
+unsigned long nand_env_oob_offset;

Might want to switch to loff_t, even though arg_off_size won't actually let you enter a 64-bit offset yet.

Sure. I can incorporate into the next patch series that introduces CONFIG_ENV_OFFSET_REDUND support.

Quoted 12 lines
Quoted 11 lines
include/environment.h +0 -0
index 203f731..fbccf6a 100644
@@ -74,15 +74,24 @@

?#endif ? ? ? /* CONFIG_ENV_IS_IN_FLASH */

?#if defined(CONFIG_ENV_IS_IN_NAND)

include/environment.h +0 -3
-# ifndef CONFIG_ENV_OFFSET
-# ?error "Need to define CONFIG_ENV_OFFSET when using CONFIG_ENV_IS_IN_NAND"
-# endif
Quoted 9 lines

include/environment.h

Quoted 5 lines
include/environment.h +5 -0
+# if defined(CONFIG_ENV_OFFSET_OOB)
+# ?ifdef CONFIG_ENV_OFFSET_REDUND
+# ? error "CONFIG_ENV_OFFSET_REDUND is not supported when CONFIG_ENV_OFFSET_OOB"
+# ? error "is set"
+# ?endif

This could be supported pretty easily if we require the redundant env range to come immediately after the regular env range -- no need to track separate offsets.

Ok. I like this option best also [1]. I'm not sure if I'll get to providing the next patch series this week.

Best Regards,

Ben Gardiner

[1] http://article.gmane.org/gmane.comp.boot-loaders.u-boot/80675

---
Nanometrics Inc.
http://www.nanometrics.ca