All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
@ 2008-07-06 16:28 Harald Welte
  2008-07-07 18:47 ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Harald Welte @ 2008-07-06 16:28 UTC (permalink / raw)
  To: u-boot

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. 

Signed-off-by: Harald Welte <laforge@openmoko.org>

Index: u-boot/common/Makefile
===================================================================
--- u-boot.orig/common/Makefile
+++ 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
Index: u-boot/common/cmd_dynenv.c
===================================================================
--- /dev/null
+++ u-boot/common/cmd_dynenv.c
@@ -0,0 +1,106 @@
+/*
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <environment.h>
+#include <nand.h>
+#include <asm/errno.h>
+#include "cmd_nand.h"
+
+#if defined(CFG_ENV_OFFSET_OOB)
+
+int do_dynenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	struct mtd_info *mtd = &nand_info[0];
+	int ret, size = 8;
+	uint8_t *buf;
+
+	char *cmd = argv[1];
+
+	buf = malloc(mtd->oobsize);
+	if (!buf)
+		return -ENOMEM;
+
+	ret = mtd->read_oob(mtd, 8, size, (size_t *) &size, (u_char *) buf);
+	if (!strcmp(cmd, "get")) {
+
+		if (buf[0] == 'E' && buf[1] == 'N' &&
+		    buf[2] == 'V' && buf[3] == '0')
+			printf("0x%08x\n", *((u_int32_t *) &buf[4]));
+		else
+			printf("No dynamic environment marker in OOB block 0\n");
+
+	} else if (!strcmp(cmd, "set")) {
+		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) < 0) {
+			printf("Offset or partition name expected\n");
+			goto fail;
+		}
+		if (!ret) {
+			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;
+				}
+		}
+		memcpy(buf+4, &addr, 4);
+
+		printf("%02x %02x %02x %02x - %02x %02x %02x %02x\n",
+			buf[0], buf[1], buf[2], buf[3],
+			buf[4], buf[5], buf[6], buf[7]);
+
+		ret = mtd->write_oob(mtd, 8, size, (size_t *) &size, (u_char *) buf);
+		if (!ret)
+			CFG_ENV_OFFSET = addr;
+	} else
+		goto usage;
+
+	free(buf);
+	return ret;
+
+usage:
+	printf("Usage:\n%s\n", cmdtp->usage);
+fail:
+	free(buf);
+	return 1;
+}
+
+U_BOOT_CMD(dynenv, 3, 1, do_dynenv,
+	"dynenv  - dynamically placed (NAND) environment\n",
+	"dynenv set off	- set enviromnent offset\n"
+	"dynenv get	- get environment offset\n");
+
+#endif /* CFG_ENV_OFFSET_OOB */
Index: u-boot/common/env_nand.c
===================================================================
--- u-boot.orig/common/env_nand.c
+++ 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);
Index: u-boot/common/environment.c
===================================================================
--- u-boot.orig/common/environment.c
+++ 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.
Index: u-boot/include/environment.h
===================================================================
--- u-boot.orig/include/environment.h
+++ 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
Index: u-boot/common/cmd_nand.h
===================================================================
--- /dev/null
+++ u-boot/common/cmd_nand.h
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <werner@openmoko.org>
+ *
+ * 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 */
Index: u-boot/common/cmd_nand.c
===================================================================
--- u-boot.orig/common/cmd_nand.c
+++ 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;
-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-06 16:28 [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset Harald Welte
@ 2008-07-07 18:47 ` Scott Wood
  2008-07-08  0:09   ` Harald Welte
  0 siblings, 1 reply; 104+ messages in thread
From: Scott Wood @ 2008-07-07 18:47 UTC (permalink / raw)
  To: u-boot

On Mon, Jul 07, 2008 at 12:28:12AM +0800, Harald Welte wrote:
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-07 18:47 ` Scott Wood
@ 2008-07-08  0:09   ` Harald Welte
  2008-07-08 16:05     ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Harald Welte @ 2008-07-08  0:09 UTC (permalink / raw)
  To: u-boot

On Mon, Jul 07, 2008 at 01:47:24PM -0500, Scott Wood wrote:
> On Mon, Jul 07, 2008 at 12:28:12AM +0800, Harald Welte wrote:
> > 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,
-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-08  0:09   ` Harald Welte
@ 2008-07-08 16:05     ` Scott Wood
  2008-07-08 21:12       ` Wolfgang Denk
                         ` (3 more replies)
  0 siblings, 4 replies; 104+ messages in thread
From: Scott Wood @ 2008-07-08 16:05 UTC (permalink / raw)
  To: u-boot

Harald Welte wrote:
> On Mon, Jul 07, 2008 at 01:47:24PM -0500, Scott Wood wrote:
>> 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.

Fair enough...

> 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 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-08 16:05     ` Scott Wood
@ 2008-07-08 21:12       ` Wolfgang Denk
  2008-07-09  0:23         ` Harald Welte
  2008-07-09  0:18       ` [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset Harald Welte
                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 104+ messages in thread
From: Wolfgang Denk @ 2008-07-08 21:12 UTC (permalink / raw)
  To: u-boot

In message <48739036.2080806@freescale.com> you wrote:
>
> > 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

-- 
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.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-08 16:05     ` Scott Wood
  2008-07-08 21:12       ` Wolfgang Denk
@ 2008-07-09  0:18       ` Harald Welte
  2008-07-09  5:28       ` Harald Welte
  2008-07-09  8:11       ` [U-Boot-Users] [PATCH] " Harald Welte
  3 siblings, 0 replies; 104+ messages in thread
From: Harald Welte @ 2008-07-09  0:18 UTC (permalink / raw)
  To: u-boot

On Tue, Jul 08, 2008 at 11:05:10AM -0500, Scott Wood wrote:
>> 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.

>> 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.

-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-08 21:12       ` Wolfgang Denk
@ 2008-07-09  0:23         ` Harald Welte
  2008-07-09  7:05           ` Wolfgang Denk
  0 siblings, 1 reply; 104+ messages in thread
From: Harald Welte @ 2008-07-09  0:23 UTC (permalink / raw)
  To: u-boot

On Tue, Jul 08, 2008 at 11:12:31PM +0200, Wolfgang Denk wrote:
> In message <48739036.2080806@freescale.com> you wrote:
> >
> > > 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?

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,
-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-08 16:05     ` Scott Wood
  2008-07-08 21:12       ` Wolfgang Denk
  2008-07-09  0:18       ` [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset Harald Welte
@ 2008-07-09  5:28       ` Harald Welte
  2008-07-09  7:07         ` Harald Welte
  2008-07-09  8:11       ` [U-Boot-Users] [PATCH] " Harald Welte
  3 siblings, 1 reply; 104+ messages in thread
From: Harald Welte @ 2008-07-09  5:28 UTC (permalink / raw)
  To: u-boot

Hi again!

On Tue, Jul 08, 2008 at 11:05:10AM -0500, Scott Wood wrote:

>> 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 :)

>> 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,
-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-09  0:23         ` Harald Welte
@ 2008-07-09  7:05           ` Wolfgang Denk
  2008-07-09  7:25             ` Harald Welte
  0 siblings, 1 reply; 104+ messages in thread
From: Wolfgang Denk @ 2008-07-09  7:05 UTC (permalink / raw)
  To: u-boot

In message <20080709002357.GS25698@prithivi.gnumonks.org> 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?

> 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

-- 
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?]

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-09  5:28       ` Harald Welte
@ 2008-07-09  7:07         ` Harald Welte
  0 siblings, 0 replies; 104+ messages in thread
From: Harald Welte @ 2008-07-09  7:07 UTC (permalink / raw)
  To: u-boot

On Wed, Jul 09, 2008 at 01:28:42PM +0800, Harald Welte wrote:
> >> 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.
-- 
- Harald Welte <laforge@gnumonks.org>           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 

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-09  7:05           ` Wolfgang Denk
@ 2008-07-09  7:25             ` Harald Welte
  2008-07-09  8:04               ` Wolfgang Denk
  0 siblings, 1 reply; 104+ messages in thread
From: Harald Welte @ 2008-07-09  7:25 UTC (permalink / raw)
  To: u-boot

On Wed, Jul 09, 2008 at 09:05:24AM +0200, Wolfgang Denk wrote:
> In message <20080709002357.GS25698@prithivi.gnumonks.org> 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?

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.

> > 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.

-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone
-------------- next part --------------
commit e05835df019027391f58f9d8ce5e1257d6924798
Author: Harald Welte <laforge@openmoko.org>
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 <laforge@openmoko.org>

diff --git a/board/neo1973/gta01/gta01.c b/board/neo1973/gta01/gta01.c
index 598574a..206a0d4 100644
--- a/board/neo1973/gta01/gta01.c
+++ b/board/neo1973/gta01/gta01.c
@@ -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 };
+
+
diff --git a/board/qt2410/qt2410.c b/board/qt2410/qt2410.c
index 8c0e77f..9b3df4e 100644
--- a/board/qt2410/qt2410.c
+++ b/board/qt2410/qt2410.c
@@ -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 };
+
diff --git a/common/cmd_dynenv.c b/common/cmd_dynenv.c
index 4dd6148..91f7623 100644
--- a/common/cmd_dynenv.c
+++ b/common/cmd_dynenv.c
@@ -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;
 		}
diff --git a/common/cmd_jffs2.c b/common/cmd_jffs2.c
index 1b67e73..ca7d5a6 100644
--- a/common/cmd_jffs2.c
+++ b/common/cmd_jffs2.c
@@ -1838,6 +1838,29 @@ static struct part_info* jffs2_part_info(struct mtd_device *dev, unsigned int pa
 	return NULL;
 }
 
+/* Return the 'net size' of the partition (i.e. excluding any bad blocks) */
+unsigned int nand_net_part_size(struct part_info *part)
+{
+	struct mtd_info *mtd;
+	unsigned int offs;
+	unsigned int bb_delta = 0;
+
+	if (!part || !part->dev || !part->dev->id ||
+	    part->dev->id->num >= CFG_MAX_NAND_DEVICE)
+		return 0;
+
+ 	mtd = &nand_info[part->dev->id->num];
+
+	for (offs = part->offset; offs < part->offset + part->size;
+	     offs += mtd->erasesize) {
+		if (nand_isbad_bbt(mtd, offs, 0))
+			bb_delta += mtd->erasesize;
+	}
+
+	return part->size - bb_delta;
+}
+
+
 /***************************************************/
 /* U-boot commands				   */
 /***************************************************/
@@ -2129,6 +2152,30 @@ int do_jffs2_mtdparts(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
 	printf ("Usage:\n%s\n", cmdtp->usage);
 	return 1;
 }
+
+#if defined(CONFIG_NAND_DYNPART)
+extern int nand_create_mtd_dynpart(struct mtd_info *mtd);
+
+int do_dynpart(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	extern void dfu_update_strings(void);
+
+#if 0
+	int i = simple_strtoul(argv[1], NULL, 0);
+	if (i >= CFG_MAX_NAND_DEVICE)
+		return -EINVAL;
+#endif
+	nand_create_mtd_dynpart(&nand_info[0]);
+
+#ifdef CONFIG_USBD_DFU
+	dfu_update_strings();
+#endif
+
+	return 0;
+}
+#endif /* CONFIG_NAND_DYNPART */
+
+
 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
 
 /***************************************************/
@@ -2194,6 +2241,15 @@ U_BOOT_CMD(
 	"<name>     := '(' NAME ')'\n"
 	"<ro-flag>  := when set to 'ro' makes partition read-only (not used, passed to kernel)\n"
 );
+
+#if defined(CONFIG_NAND_DYNPART)
+U_BOOT_CMD(
+	dynpart, 1,	1,	do_dynpart,
+	"dynpart\t- dynamically calculate partition table based on BBT\n",
+	"\n"
+	"    - sets 'mtdparts' according to BBT\n");
+#endif /* CONFIG_NAND_DYNPART */
+
 #endif /* #ifdef CONFIG_JFFS2_CMDLINE */
 
 /***************************************************/
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 7977060..bb46f34 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -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)) {
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 19a9bc2..748b266 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -1044,9 +1044,86 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
 	switch ((int)res) {
 	case 0x00:	return 0;
 	case 0x01:	return 1;
+	case 0x03:	return 1;
 	case 0x02:	return allowbbt ? 0 : 1;
 	}
 	return 1;
 }
 
+#if defined(CONFIG_NAND_DYNPART)
+
+extern unsigned int dynpart_size[];
+extern char *dynpart_names[];
+
+#define MTDPARTS_MAX_SIZE 512
+
+
+static int skip_offs(const struct nand_chip *this, unsigned int offs)
+{
+	int block = (int) (offs >> (this->bbt_erase_shift - 1));
+	u_int8_t bbt = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
+
+	return bbt == 3;
+}
+
+int nand_create_mtd_dynpart(struct mtd_info *mtd)
+{
+	struct nand_chip *this = mtd->priv;
+	int part;
+	char *mtdparts;
+	unsigned int cur_offs = 0;
+
+	mtdparts = malloc(MTDPARTS_MAX_SIZE); /* FIXME: bounds checking */
+	if (!mtdparts)
+		return -ENOMEM;
+
+	sprintf(mtdparts, "mtdparts=" CFG_NAND_DYNPART_MTD_KERNEL_NAME ":");
+
+	for (part = 0; dynpart_size[part] != 0; part++) {
+		unsigned int bb_delta = 0;
+		unsigned int offs = 0;
+		char mtdpart[32];
+
+		for (offs = cur_offs;
+		     offs < cur_offs + dynpart_size[part] + bb_delta;
+		     offs += mtd->erasesize) {
+			if (skip_offs(this, offs))
+				bb_delta += mtd->erasesize;
+		}
+
+		/*
+		 * Absorb bad blocks immediately following this partition also
+		 * into the partition, in order to make next partition start
+		 * with a good block. This simplifies handling of the
+		 * environment partition.
+		 */
+		while (offs < this->chipsize && skip_offs(this, offs)) {
+			bb_delta += mtd->erasesize;
+			offs += mtd->erasesize;
+		}
+
+		if (cur_offs + dynpart_size[part] + bb_delta > this->chipsize)
+			dynpart_size[part] = this->chipsize - cur_offs - bb_delta;
+#if 0
+		printf("partition %u: start = 0x%08x, end=%08x size=%08x, size_inc_bb=%08x\n",
+			part, cur_offs, cur_offs + dynpart_size[part] + bb_delta,
+			dynpart_size[part], dynpart_size[part] + bb_delta);
+#endif
+		cur_offs += dynpart_size[part] + bb_delta;
+		sprintf(mtdpart, "0x%.8x(%.16s),", dynpart_size[part] + bb_delta,
+			dynpart_names[part]);
+		mtdpart[sizeof(mtdpart)-1] = '\0';
+		strncat(mtdparts, mtdpart,
+		    MTDPARTS_MAX_SIZE-strlen(mtdparts)-1);
+	}
+
+	mtdparts[strlen(mtdparts)-1] = '\0';
+	printf("mtdparts %s\n", mtdparts);
+	setenv("mtdparts", mtdparts);
+
+	free(mtdparts);
+	return 0;
+}
+#endif /* CONFIG_NAND_DYNPART */
+
 #endif
diff --git a/include/configs/neo1973_gta01.h b/include/configs/neo1973_gta01.h
index 2122fd5..6638d8d 100644
--- a/include/configs/neo1973_gta01.h
+++ b/include/configs/neo1973_gta01.h
@@ -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 */
diff --git a/include/configs/qt2410.h b/include/configs/qt2410.h
index bd21ae3..06c4972 100644
--- a/include/configs/qt2410.h
+++ b/include/configs/qt2410.h
@@ -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 */
diff --git a/include/util.h b/include/util.h
index c1ded14..7f3ac3b 100644
--- a/include/util.h
+++ b/include/util.h
@@ -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 */

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-09  7:25             ` Harald Welte
@ 2008-07-09  8:04               ` Wolfgang Denk
  2008-07-09 12:13                 ` Harald Welte
                                   ` (5 more replies)
  0 siblings, 6 replies; 104+ messages in thread
From: Wolfgang Denk @ 2008-07-09  8:04 UTC (permalink / raw)
  To: u-boot

In message <20080709072510.GY25698@prithivi.gnumonks.org> you wrote:
> 
> > 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.

> > > 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

-- 
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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH] Support dynamic/patched NAND ENV offset
  2008-07-08 16:05     ` Scott Wood
                         ` (2 preceding siblings ...)
  2008-07-09  5:28       ` Harald Welte
@ 2008-07-09  8:11       ` Harald Welte
  2008-07-11 17:28         ` Scott Wood
  3 siblings, 1 reply; 104+ messages in thread
From: Harald Welte @ 2008-07-09  8:11 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Harald Welte <laforge@openmoko.org>

diff --git a/common/Makefile b/common/Makefile
index ecf755f..d1d50bf 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -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
diff --git a/common/cmd_dynenv.c b/common/cmd_dynenv.c
new file mode 100644
index 0000000..8fd21c1
--- /dev/null
+++ b/common/cmd_dynenv.c
@@ -0,0 +1,121 @@
+/*
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * (C) Copyright 2008 Harald Welte <laforge@openmoko.org>
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <environment.h>
+#include <nand.h>
+#include "cmd_nand.h"
+#include <asm/errno.h>
+
+#if defined(CFG_ENV_OFFSET_OOB)
+
+int do_dynenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	struct mtd_info *mtd = &nand_info[0];
+	int ret, size = 8;
+	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;
+	ops.ooboffs = 0;
+	ops.ooblen = mtd->oobsize;
+	ops.oobbuf = buf;
+	ops.datbuf = buf;
+	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')
+			printf("0x%08x\n", *((u_int32_t *) &buf[4]));
+		else
+			printf("No dynamic environment marker in OOB block 0\n");
+
+	} else if (!strcmp(cmd, "set")) {
+		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) {
+			printf("Offset or partition name expected\n");
+			goto fail;
+		}
+		if (!ret) {
+			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;
+				}
+		}
+		memcpy(buf+4, &addr, 4);
+
+		printf("%02x %02x %02x %02x - %02x %02x %02x %02x\n",
+			buf[0], buf[1], buf[2], buf[3],
+			buf[4], buf[5], buf[6], buf[7]);
+
+		ops.mode = MTD_OOB_RAW;
+		ops.ooboffs = 0;
+		ops.ooblen = mtd->oobsize;
+		ops.oobbuf = buf;
+		ops.datbuf = buf;
+		ops.len = size;
+		ret = mtd->write_oob(mtd, 8, &ops);
+		if (!ret)
+			CFG_ENV_OFFSET = addr;
+	} else
+		goto usage;
+
+	free(buf);
+	return ret;
+
+usage:
+	printf("Usage:\n%s\n", cmdtp->usage);
+fail:
+	free(buf);
+	return 1;
+}
+
+U_BOOT_CMD(dynenv, 3, 1, do_dynenv,
+	"dynenv  - dynamically placed (NAND) environment\n",
+	"dynenv set off	- set enviromnent offset\n"
+	"dynenv get	- get environment offset\n");
+
+#endif /* CFG_ENV_OFFSET_OOB */
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 7c26ceb..a72e553 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -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;
diff --git a/common/cmd_nand.h b/common/cmd_nand.h
new file mode 100644
index 0000000..bedcda9
--- /dev/null
+++ b/common/cmd_nand.h
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <werner@openmoko.org>
+ *
+ * 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 */
diff --git a/common/env_nand.c b/common/env_nand.c
index 1fe874a..14ea480 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -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);
diff --git a/common/environment.c b/common/environment.c
index 3b9914f..50d5210 100644
--- a/common/environment.c
+++ b/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.
diff --git a/include/environment.h b/include/environment.h
index bf9f669..3256044 100644
--- a/include/environment.h
+++ b/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

-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset
  2008-07-09  8:04               ` Wolfgang Denk
@ 2008-07-09 12:13                 ` Harald Welte
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
                                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 104+ messages in thread
From: Harald Welte @ 2008-07-09 12:13 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

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

On Wed, Jul 09, 2008 at 10:04:47AM +0200, Wolfgang Denk wrote:
> In message <20080709072510.GY25698@prithivi.gnumonks.org> you wrote:
> > 
> > > 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.

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

Cheers,
-- 
- Harald Welte <laforge@openmoko.org>          	        http://openmoko.org/
============================================================================
Software for the world's first truly open Free Software mobile phone

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot-Users] [PATCH] Support dynamic/patched NAND ENV offset
  2008-07-09  8:11       ` [U-Boot-Users] [PATCH] " Harald Welte
@ 2008-07-11 17:28         ` Scott Wood
  2010-05-17 21:04           ` [U-Boot] [PATCH] NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
  0 siblings, 1 reply; 104+ messages in thread
From: Scott Wood @ 2008-07-11 17:28 UTC (permalink / raw)
  To: u-boot

On Wed, Jul 09, 2008 at 04:11:29PM +0800, Harald Welte wrote:
> +#if defined(CFG_ENV_OFFSET_OOB)

Can you push this conditional into the Makefile?

> +int do_dynenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
> +{
> +	struct mtd_info *mtd = &nand_info[0];
> +	int ret, size = 8;
> +	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.

> +	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?

> +	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().

> +			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.

> +		else
> +			printf("No dynamic environment marker in OOB block 0\n");
> +
> +	} else if (!strcmp(cmd, "set")) {

No blank lines at beginning/end of blocks.

> +		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).

> +			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"?

> +			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...

> +		ret = mtd->write_oob(mtd, 8, &ops);
> +		if (!ret)
> +			CFG_ENV_OFFSET = addr;

And silently fail if write_oob fails?

> diff --git a/common/cmd_nand.c b/common/cmd_nand.c
> index 7c26ceb..a72e553 100644
> --- a/common/cmd_nand.c
> +++ b/common/cmd_nand.c
> @@ -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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH] NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB)
  2008-07-11 17:28         ` Scott Wood
@ 2010-05-17 21:04           ` Ben Gardiner
  2010-05-26 22:58             ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-05-17 21:04 UTC (permalink / raw)
  To: u-boot

This is a re-submission of the patch by Harald Welte <laforge@openmoko.org>
with minor modifications for rebase and changes as suggested by Scott Wood
<scottwood@freescale.com> 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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
 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

diff --git a/common/Makefile b/common/Makefile
index dbf7a05..83520d7 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -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
diff --git a/common/cmd_dynenv.c b/common/cmd_dynenv.c
new file mode 100644
index 0000000..5167875
--- /dev/null
+++ b/common/cmd_dynenv.c
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Harald Welte <laforge@openmoko.org>
+ * (C) Copyright 2008 Harald Welte <laforge@openmoko.org>
+ *
+ * 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
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <environment.h>
+#include <nand.h>
+#include "cmd_nand.h"
+#include <asm/errno.h>
+
+unsigned long env_offset;
+
+int do_dynenv(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+	int ret;
+	uint32_t *oob_buf;
+
+	char *cmd = argv[1];
+
+	if (!strcmp(cmd, "get")) {
+		ret = get_dynenv(&CONFIG_ENV_OFFSET);
+		if(!ret) {
+			printf("0x%08lx\n", CONFIG_ENV_OFFSET);
+		}
+		else {
+			return 1;
+		}
+	}
+	else if (!strcmp(cmd, "set")) {
+		ulong addr, dummy_size;
+		struct mtd_info *mtd = &nand_info[0];
+		struct mtd_oob_ops ops;
+
+		if (argc < 3)
+			goto usage;
+
+		if (nand_arg_off_size(argc-2, argv + 2, mtd, &addr, &dummy_size, 1) < 0) {
+			printf("Offset or partition name expected\n");
+			return 1;
+		}
+
+		if(mtd->oobavail < CONFIG_ENV_OFFSET_SIZE){
+			printf("Insufficient available OOB bytes: %d OOB bytes available but %d required for dynenv support\n",mtd->oobavail,8);
+		}
+
+		oob_buf = malloc(mtd->oobsize);
+		if(!oob_buf)
+			return -ENOMEM;
+
+		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");
+				goto fail;
+			}
+		}
+		oob_buf[1] = addr;
+
+		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;
+		}
+
+		free(oob_buf);
+	} else
+		goto usage;
+
+	return ret;
+
+fail:
+	free(oob_buf);
+	return 1;
+usage:
+	cmd_usage(cmdtp);
+	return 1;
+}
+
+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
diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index 9b0c930..7575904 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -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)) {
diff --git a/common/cmd_nand.h b/common/cmd_nand.h
new file mode 100644
index 0000000..023ed4f
--- /dev/null
+++ b/common/cmd_nand.h
@@ -0,0 +1,33 @@
+/*
+ * cmd_nand.h - Convenience functions
+ *
+ * (C) Copyright 2006-2007 OpenMoko, Inc.
+ * Author: Werner Almesberger <werner@openmoko.org>
+ *
+ * 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 */
diff --git a/common/env_nand.c b/common/env_nand.c
index a15a950..ee55877 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -38,6 +38,7 @@
 #include <linux/stddef.h>
 #include <malloc.h>
 #include <nand.h>
+#include <asm/errno.h>
 
 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
 #define CMD_SAVEENV
@@ -288,6 +289,46 @@ int readenv (size_t offset, u_char * buf)
 	return 0;
 }
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+int get_dynenv(unsigned long *result)
+{
+	struct mtd_info *mtd = &nand_info[0];
+	struct mtd_oob_ops ops;
+	uint32_t *oob_buf;
+	int ret;
+
+	oob_buf = malloc(mtd->oobsize);
+	if(!oob_buf)
+		return -ENOMEM;
+
+	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);
+
+	if(!ret) {
+		if(oob_buf[0] == ENV_OOB_MARKER) {
+			*result = oob_buf[1];
+		}
+		else {
+			printf("No dynamic environment marker in OOB block 0\n");
+			ret = -ENOENT;
+			goto fail;
+		}
+	}
+	else {
+		printf("error reading OOB block 0\n");
+	}
+fail:
+	free(oob_buf);
+
+	return ret;
+}
+#endif
+
 #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);
+	if(!ret) {
+		/* fall through to the normal environment reading code below */
+		printf("Found Environment offset in OOB..\n");
+	} else {
+		return use_default();
+	}
+#endif
+	
 	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 */
 }
 #endif /* CONFIG_ENV_OFFSET_REDUND */
diff --git a/include/environment.h b/include/environment.h
index b9924fd..03b6c92 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -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)
diff --git a/include/nand.h b/include/nand.h
index 2a81597..29238c8 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -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
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH] NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB)
  2010-05-17 21:04           ` [U-Boot] [PATCH] NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
@ 2010-05-26 22:58             ` Scott Wood
  2010-05-26 23:38               ` Ben Gardiner
  2010-05-31 21:29               ` [U-Boot] [PATCH v2] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
  0 siblings, 2 replies; 104+ messages in thread
From: Scott Wood @ 2010-05-26 22:58 UTC (permalink / raw)
  To: u-boot

On Mon, May 17, 2010 at 05:04:30PM -0400, Ben Gardiner wrote:
> diff --git a/common/cmd_dynenv.c b/common/cmd_dynenv.c
> new file mode 100644
> index 0000000..5167875
> --- /dev/null
> +++ b/common/cmd_dynenv.c
> @@ -0,0 +1,112 @@
> +/*
> + * (C) Copyright 2006-2007 OpenMoko, Inc.
> + * Author: Harald Welte <laforge@openmoko.org>
> + * (C) Copyright 2008 Harald Welte <laforge@openmoko.org>

Is this correct and up-to-date?

> +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().

> +		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).

> +			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.

> +		}
> +
> +		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().

> +		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?

> +		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.

> +
> +		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?

> +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.

> diff --git a/common/cmd_nand.h b/common/cmd_nand.h
> new file mode 100644
> index 0000000..023ed4f
> --- /dev/null
> +++ b/common/cmd_nand.h
> @@ -0,0 +1,33 @@
> +/*
> + * cmd_nand.h - Convenience functions
> + *
> + * (C) Copyright 2006-2007 OpenMoko, Inc.
> + * Author: Werner Almesberger <werner@openmoko.org>

Is this really the right copyright/authorship for this file?

> +#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.

> +	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).

> +		}
> +		else {

} else {

>  #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?

>  	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.

>  #endif /* CONFIG_ENV_OFFSET_REDUND */
> diff --git a/include/environment.h b/include/environment.h
> index b9924fd..03b6c92 100644
> --- a/include/environment.h
> +++ b/include/environment.h
> @@ -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

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).

> +#define CONFIG_ENV_OFFSET_SIZE 8

Why is this configurable?

-Scott

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH] NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB)
  2010-05-26 22:58             ` Scott Wood
@ 2010-05-26 23:38               ` Ben Gardiner
  2010-05-31 21:29               ` [U-Boot] [PATCH v2] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-05-26 23:38 UTC (permalink / raw)
  To: u-boot

Thank you for the thorough review, Scott.

On Wed, May 26, 2010 at 6:58 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, May 17, 2010 at 05:04:30PM -0400, Ben Gardiner wrote:
>> diff --git a/common/cmd_dynenv.c b/common/cmd_dynenv.c
>> new file mode 100644
>> index 0000000..5167875
>> --- /dev/null
>> +++ b/common/cmd_dynenv.c
>> @@ -0,0 +1,112 @@
>> +/*
>> + * (C) Copyright 2006-2007 OpenMoko, Inc.
>> + * Author: Harald Welte <laforge@openmoko.org>
>> + * (C) Copyright 2008 Harald Welte <laforge@openmoko.org>
>
> 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.

>> +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' ?

>> + ? ? ? ? ? ? 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

>> + ? ? ? ? ? ? ? ? ? ? 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 :)

>> + ? ? ? ? ? ? }
>> +
>> + ? ? ? ? ? ? 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

>> + ? ? ? ? ? ? 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?

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)

>> + ? ? ? ? ? ? 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.
>
>> +
>> + ? ? ? ? ? ? free(oob_buf);
>> + ? ? } else
>> + ? ? ? ? ? ? goto usage;
>
> Likewise.

will do

> 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.

>> +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.

>> diff --git a/common/cmd_nand.h b/common/cmd_nand.h
>> new file mode 100644
>> index 0000000..023ed4f
>> --- /dev/null
>> +++ b/common/cmd_nand.h
>> @@ -0,0 +1,33 @@
>> +/*
>> + * cmd_nand.h - Convenience functions
>> + *
>> + * (C) Copyright 2006-2007 OpenMoko, Inc.
>> + * Author: Werner Almesberger <werner@openmoko.org>
>
> 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.

>> + ? ? 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

>> + ? ? ? ? ? ? }
>> + ? ? ? ? ? ? else {
>
> } else {
>
>> ?#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?

 Yeah... it's pretty weird, I'll subs env_offset here. :)

>> ? ? ? 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

>> ?#endif /* CONFIG_ENV_OFFSET_REDUND */
>> diff --git a/include/environment.h b/include/environment.h
>> index b9924fd..03b6c92 100644
>> --- a/include/environment.h
>> +++ b/include/environment.h
>> @@ -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
>
> 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

>> +#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

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v2] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-05-26 22:58             ` Scott Wood
  2010-05-26 23:38               ` Ben Gardiner
@ 2010-05-31 21:29               ` Ben Gardiner
  2010-06-30 21:32                 ` [U-Boot] [PATCH v3] " Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-05-31 21:29 UTC (permalink / raw)
  To: u-boot

This is a re-submission of the patch by Harald Welte
<laforge@openmoko.org> with modifications to make it a sub-command and changes
as suggested by Scott Wood <scottwood@freescale.com> 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

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
 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(-)

diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index f611fd7..5af5b9e 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -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,
diff --git a/common/env_nand.c b/common/env_nand.c
index a15a950..2289eb2 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -38,6 +38,7 @@
 #include <linux/stddef.h>
 #include <malloc.h>
 #include <nand.h>
+#include <asm/errno.h>
 
 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
 #define CMD_SAVEENV
@@ -288,6 +289,40 @@ int readenv (size_t offset, u_char * buf)
 	return 0;
 }
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
+{
+	struct mtd_oob_ops ops;
+	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+	int ret;
+
+	ops.datbuf = NULL;
+	ops.mode = MTD_OOB_AUTO;
+	ops.ooboffs = 0;
+	ops.ooblen = ENV_OFFSET_SIZE;
+	ops.oobbuf = (void *) oob_buf;
+
+	ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
+
+	if (!ret) {
+		if (oob_buf[0] == ENV_OOB_MARKER) {
+			*result = oob_buf[1] * nand->erasesize;
+		} else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
+			*result = oob_buf[1];
+		} else {
+			printf("No dynamic environment marker in OOB block 0\n");
+			ret = -ENOENT;
+			goto fail;
+		}
+	}
+	else {
+		printf("error reading OOB block 0\n");
+	}
+fail:
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_ENV_OFFSET_REDUND
 void env_relocate_spec (void)
 {
@@ -357,6 +392,16 @@ void env_relocate_spec (void)
 #if !defined(ENV_IS_EMBEDDED)
 	int ret;
 
+#if defined(CONFIG_ENV_OFFSET_OOB)
+	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
+	if(!ret) {
+		/* fall through to the normal environment reading code below */
+		printf("Found Environment offset in OOB..\n");
+	} else {
+		return use_default();
+	}
+#endif
+	
 	ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
 	if (ret)
 		return use_default();
diff --git a/include/environment.h b/include/environment.h
index b9924fd..9820d23 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -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)
diff --git a/include/nand.h b/include/nand.h
index 2a81597..8bdf419 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -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
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] mtdparts: add bad-block skipping
  2008-07-09  8:04               ` Wolfgang Denk
  2008-07-09 12:13                 ` Harald Welte
@ 2010-06-01 20:23                 ` Ben Gardiner
  2010-06-01 22:20                   ` Wolfgang Denk
                                     ` (6 more replies)
  2010-06-01 20:23                 ` [U-Boot] [PATCH 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
                                   ` (3 subsequent siblings)
  5 siblings, 7 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-01 20:23 UTC (permalink / raw)
  To: u-boot

This patch series is based on the idea of Harald Welte <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> [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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 1/4] mtdparts: regroup calls to get_mtd_device_nm
  2008-07-09  8:04               ` Wolfgang Denk
  2008-07-09 12:13                 ` Harald Welte
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
@ 2010-06-01 20:23                 ` Ben Gardiner
  2010-06-02  7:06                   ` Stefan Roese
  2010-06-01 20:23                 ` [U-Boot] [PATCH 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
                                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-06-01 20:23 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
 common/cmd_mtdparts.c |   43 ++++++++++++++++++++++++++++---------------
 1 files changed, 28 insertions(+), 15 deletions(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 116e637..7a9768f 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 2/4] mtdparts: show net size in mtdparts list
  2008-07-09  8:04               ` Wolfgang Denk
                                   ` (2 preceding siblings ...)
  2010-06-01 20:23                 ` [U-Boot] [PATCH 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
@ 2010-06-01 20:23                 ` Ben Gardiner
  2010-06-02  7:15                   ` Stefan Roese
  2010-06-01 20:23                 ` [U-Boot] [PATCH 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
  2010-06-01 20:23                 ` [U-Boot] [PATCH 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
  5 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-06-01 20:23 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
 common/cmd_mtdparts.c |   28 ++++++++++++++++++++++++++--
 1 files changed, 26 insertions(+), 2 deletions(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 7a9768f..24d27b9 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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++;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 3/4] mtdparts: add new sub-command "spread"
  2008-07-09  8:04               ` Wolfgang Denk
                                   ` (3 preceding siblings ...)
  2010-06-01 20:23                 ` [U-Boot] [PATCH 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-06-01 20:23                 ` Ben Gardiner
  2010-06-01 20:23                 ` [U-Boot] [PATCH 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
  5 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-01 20:23 UTC (permalink / raw)
  To: u-boot

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 <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> in the review at
http://article.gmane.org/gmane.comp.boot-loaders.u-boot/43549 .

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
 common/cmd_mtdparts.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 105 insertions(+), 1 deletions(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 24d27b9..ae5e97d 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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"
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 4/4] mtdparts: new add.e: add part skipping bad blocks
  2008-07-09  8:04               ` Wolfgang Denk
                                   ` (4 preceding siblings ...)
  2010-06-01 20:23                 ` [U-Boot] [PATCH 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
@ 2010-06-01 20:23                 ` Ben Gardiner
  5 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-01 20:23 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
 common/cmd_mtdparts.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index ae5e97d..9ff33a7 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] mtdparts: add bad-block skipping
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
@ 2010-06-01 22:20                   ` Wolfgang Denk
  2010-06-01 22:34                   ` Wolfgang Denk
                                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 104+ messages in thread
From: Wolfgang Denk @ 2010-06-01 22:20 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <1275423827-5803-1-git-send-email-bengardiner@nanometrics.ca> you wrote:
> This patch series is based on the idea of Harald Welte <laforge@gnumonks.org>
> and the comments of Wolfgang Denk <wd@denx.de> [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

-- 
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??)

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] mtdparts: add bad-block skipping
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
  2010-06-01 22:20                   ` Wolfgang Denk
@ 2010-06-01 22:34                   ` Wolfgang Denk
  2010-06-02  5:08                     ` Ben Gardiner
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
                                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 104+ messages in thread
From: Wolfgang Denk @ 2010-06-01 22:34 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <1275423827-5803-1-git-send-email-bengardiner@nanometrics.ca> you wrote:
> This patch series is based on the idea of Harald Welte <laforge@gnumonks.org>
> and the comments of Wolfgang Denk <wd@denx.de> [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

-- 
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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] mtdparts: add bad-block skipping
  2010-06-01 22:34                   ` Wolfgang Denk
@ 2010-06-02  5:08                     ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-02  5:08 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang Denk,

On Tue, Jun 1, 2010 at 6:20 PM, Wolfgang Denk <wd@denx.de> wrote:
> 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.

On Tue, Jun 1, 2010 at 6:34 PM, Wolfgang Denk <wd@denx.de> wrote:
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 1/4] mtdparts: regroup calls to get_mtd_device_nm
  2010-06-01 20:23                 ` [U-Boot] [PATCH 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
@ 2010-06-02  7:06                   ` Stefan Roese
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Roese @ 2010-06-02  7:06 UTC (permalink / raw)
  To: u-boot

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.
 
> Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
> ---
>  common/cmd_mtdparts.c |   43 ++++++++++++++++++++++++++++---------------
>  1 files changed, 28 insertions(+), 15 deletions(-)
> 
> diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
> index 116e637..7a9768f 100644
> --- a/common/cmd_mtdparts.c
> +++ b/common/cmd_mtdparts.c
> @@ -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))

Space after "if" please.

>  		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))

Again, space after "if".

Please respin this patch and add my:

Acked-by: Stefan Roese <sr@denx.de>

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 2/4] mtdparts: show net size in mtdparts list
  2010-06-01 20:23                 ` [U-Boot] [PATCH 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-06-02  7:15                   ` Stefan Roese
  0 siblings, 0 replies; 104+ messages in thread
From: Stefan Roese @ 2010-06-02  7:15 UTC (permalink / raw)
  To: u-boot

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.
 
> Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
> ---
>  common/cmd_mtdparts.c |   28 ++++++++++++++++++++++++++--
>  1 files changed, 26 insertions(+), 2 deletions(-)
> 
> diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
> index 7a9768f..24d27b9 100644
> --- a/common/cmd_mtdparts.c
> +++ b/common/cmd_mtdparts.c
> @@ -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))

Please add spaces after "for" and "if".

> +			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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 0/4 v2] mtdparts: add bad-block skipping
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
  2010-06-01 22:20                   ` Wolfgang Denk
  2010-06-01 22:34                   ` Wolfgang Denk
@ 2010-06-02 15:58                   ` Ben Gardiner
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
                                       ` (4 more replies)
  2010-06-02 15:58                   ` [U-Boot] [PATCH 1/4 v2] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
                                     ` (3 subsequent siblings)
  6 siblings, 5 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-02 15:58 UTC (permalink / raw)
  To: u-boot

This patch series is based on the idea of Harald Welte <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> [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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 1/4 v2] mtdparts: regroup calls to get_mtd_device_nm
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
                                     ` (2 preceding siblings ...)
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
@ 2010-06-02 15:58                   ` Ben Gardiner
  2010-06-02 15:58                   ` [U-Boot] [PATCH 2/4 v2] mtdparts: show net size in mtdparts list Ben Gardiner
                                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-02 15:58 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Acked-by: Stefan Roese <sr@denx.de>
---
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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 116e637..a6eeb41 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 2/4 v2] mtdparts: show net size in mtdparts list
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
                                     ` (3 preceding siblings ...)
  2010-06-02 15:58                   ` [U-Boot] [PATCH 1/4 v2] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
@ 2010-06-02 15:58                   ` Ben Gardiner
  2010-06-02 15:58                   ` [U-Boot] [PATCH 3/4 v2] mtdparts: add new sub-command "spread" Ben Gardiner
  2010-06-02 15:58                   ` [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
  6 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-02 15:58 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index a6eeb41..b36aac2 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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++;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 3/4 v2] mtdparts: add new sub-command "spread"
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
                                     ` (4 preceding siblings ...)
  2010-06-02 15:58                   ` [U-Boot] [PATCH 2/4 v2] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-06-02 15:58                   ` Ben Gardiner
  2010-06-02 15:58                   ` [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
  6 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-02 15:58 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index b36aac2..c52374d 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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"
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks
  2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
                                     ` (5 preceding siblings ...)
  2010-06-02 15:58                   ` [U-Boot] [PATCH 3/4 v2] mtdparts: add new sub-command "spread" Ben Gardiner
@ 2010-06-02 15:58                   ` Ben Gardiner
  2010-08-09 18:25                     ` Scott Wood
  6 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-06-02 15:58 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
---
Changes in v2:
 * formatting: spaces after 'if' and 'for'
 * trailing whitespace removed

---
 common/cmd_mtdparts.c |   36 +++++++++++++++++++++++++++++++++++-
 1 files changed, 35 insertions(+), 1 deletions(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index c52374d..c4da06e 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-05-31 21:29               ` [U-Boot] [PATCH v2] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
@ 2010-06-30 21:32                 ` Ben Gardiner
  2010-06-30 21:41                   ` Wolfgang Denk
                                     ` (2 more replies)
  0 siblings, 3 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-06-30 21:32 UTC (permalink / raw)
  To: u-boot

This is a re-submission of the patch by Harald Welte
<laforge@openmoko.org> with minor modifications for rebase and changes
as suggested by Scott Wood <scottwood@freescale.com> [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

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>

---
 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(-)

diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index f611fd7..5af5b9e 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -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,
diff --git a/common/env_nand.c b/common/env_nand.c
index a15a950..2289eb2 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -38,6 +38,7 @@
 #include <linux/stddef.h>
 #include <malloc.h>
 #include <nand.h>
+#include <asm/errno.h>
 
 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
 #define CMD_SAVEENV
@@ -288,6 +289,40 @@ int readenv (size_t offset, u_char * buf)
 	return 0;
 }
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
+{
+	struct mtd_oob_ops ops;
+	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+	int ret;
+
+	ops.datbuf = NULL;
+	ops.mode = MTD_OOB_AUTO;
+	ops.ooboffs = 0;
+	ops.ooblen = ENV_OFFSET_SIZE;
+	ops.oobbuf = (void *) oob_buf;
+
+	ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
+
+	if (!ret) {
+		if (oob_buf[0] == ENV_OOB_MARKER) {
+			*result = oob_buf[1] * nand->erasesize;
+		} else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
+			*result = oob_buf[1];
+		} else {
+			printf("No dynamic environment marker in OOB block 0\n");
+			ret = -ENOENT;
+			goto fail;
+		}
+	}
+	else {
+		printf("error reading OOB block 0\n");
+	}
+fail:
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_ENV_OFFSET_REDUND
 void env_relocate_spec (void)
 {
@@ -357,6 +392,16 @@ void env_relocate_spec (void)
 #if !defined(ENV_IS_EMBEDDED)
 	int ret;
 
+#if defined(CONFIG_ENV_OFFSET_OOB)
+	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
+	if(!ret) {
+		/* fall through to the normal environment reading code below */
+		printf("Found Environment offset in OOB..\n");
+	} else {
+		return use_default();
+	}
+#endif
+	
 	ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
 	if (ret)
 		return use_default();
diff --git a/include/environment.h b/include/environment.h
index b9924fd..9820d23 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -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)
diff --git a/include/nand.h b/include/nand.h
index 2a81597..8bdf419 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -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
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-06-30 21:32                 ` [U-Boot] [PATCH v3] " Ben Gardiner
@ 2010-06-30 21:41                   ` Wolfgang Denk
  2010-07-01  4:09                     ` Ben Gardiner
  2010-07-01  3:37                   ` Vipin KUMAR
  2010-07-01  7:17                   ` Harald Welte
  2 siblings, 1 reply; 104+ messages in thread
From: Wolfgang Denk @ 2010-06-30 21:41 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <1277933528-8335-1-git-send-email-bengardiner@nanometrics.ca> you wrote:
> This is a re-submission of the patch by Harald Welte
> <laforge@openmoko.org> with minor modifications for rebase and changes
> as suggested by Scott Wood <scottwood@freescale.com> [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.

Does this work with redundant environment in NAND?

Best regards,

Wolfgang Denk

-- 
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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-06-30 21:32                 ` [U-Boot] [PATCH v3] " Ben Gardiner
  2010-06-30 21:41                   ` Wolfgang Denk
@ 2010-07-01  3:37                   ` Vipin KUMAR
  2010-07-01  5:29                     ` Ben Gardiner
  2010-07-01  7:17                   ` Harald Welte
  2 siblings, 1 reply; 104+ messages in thread
From: Vipin KUMAR @ 2010-07-01  3:37 UTC (permalink / raw)
  To: u-boot

On 7/1/2010 3:02 AM, Ben Gardiner wrote:
> This is a re-submission of the patch by Harald Welte
> <laforge@openmoko.org> with minor modifications for rebase and changes
> as suggested by Scott Wood <scottwood@freescale.com> [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.
> 

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-06-30 21:41                   ` Wolfgang Denk
@ 2010-07-01  4:09                     ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-01  4:09 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 30, 2010 at 5:41 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Ben Gardiner,
>
> In message <1277933528-8335-1-git-send-email-bengardiner@nanometrics.ca> you wrote:
>> This is a re-submission of the patch by Harald Welte
>> <laforge@openmoko.org> with minor modifications for rebase and changes
>> as suggested by Scott Wood <scottwood@freescale.com> [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.
>
> 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

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-01  3:37                   ` Vipin KUMAR
@ 2010-07-01  5:29                     ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-01  5:29 UTC (permalink / raw)
  To: u-boot

On Wed, Jun 30, 2010 at 11:37 PM, Vipin KUMAR <vipin.kumar@st.com> wrote:
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-06-30 21:32                 ` [U-Boot] [PATCH v3] " Ben Gardiner
  2010-06-30 21:41                   ` Wolfgang Denk
  2010-07-01  3:37                   ` Vipin KUMAR
@ 2010-07-01  7:17                   ` Harald Welte
  2010-07-05 13:57                     ` Ben Gardiner
  2010-07-05 17:27                     ` [U-Boot] [PATCH v4] " Ben Gardiner
  2 siblings, 2 replies; 104+ messages in thread
From: Harald Welte @ 2010-07-01  7:17 UTC (permalink / raw)
  To: u-boot

Dear Ben,

thanks again for moving those patches forward.

However,

> diff --git a/common/cmd_nand.c b/common/cmd_nand.c
> index f611fd7..5af5b9e 100644
> --- a/common/cmd_nand.c
> +++ b/common/cmd_nand.c
> @@ -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
-- 
- Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-01  7:17                   ` Harald Welte
@ 2010-07-05 13:57                     ` Ben Gardiner
  2010-07-05 17:27                     ` [U-Boot] [PATCH v4] " Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 13:57 UTC (permalink / raw)
  To: u-boot

Dear Harald,

On Thu, Jul 1, 2010 at 3:17 AM, Harald Welte <laforge@gnumonks.org> wrote:
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-01  7:17                   ` Harald Welte
  2010-07-05 13:57                     ` Ben Gardiner
@ 2010-07-05 17:27                     ` Ben Gardiner
  2010-07-12 16:17                       ` Ben Gardiner
  2010-07-13 19:26                       ` Scott Wood
  1 sibling, 2 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 17:27 UTC (permalink / raw)
  To: u-boot

This is a re-submission of the patch by Harald Welte
<laforge@openmoko.org> with minor modifications for rebase and changes
as suggested by Scott Wood <scottwood@freescale.com> [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

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Acked-by: Harald Welte <laforge@gnumonks.org>

---

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 <laforge@gnumonks.org> 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(-)

diff --git a/common/cmd_nand.c b/common/cmd_nand.c
index ea80555..a4c67c1 100644
--- a/common/cmd_nand.c
+++ b/common/cmd_nand.c
@@ -4,6 +4,10 @@
  * (c) 1999 Machine Vision Holdings, Inc.
  * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
  *
+ * 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,
diff --git a/common/env_nand.c b/common/env_nand.c
index 50bc111..47d9848 100644
--- a/common/env_nand.c
+++ b/common/env_nand.c
@@ -38,6 +38,7 @@
 #include <linux/stddef.h>
 #include <malloc.h>
 #include <nand.h>
+#include <asm/errno.h>
 
 #if defined(CONFIG_CMD_SAVEENV) && defined(CONFIG_CMD_NAND)
 #define CMD_SAVEENV
@@ -284,6 +285,40 @@ int readenv (size_t offset, u_char * buf)
 	return 0;
 }
 
+#ifdef CONFIG_ENV_OFFSET_OOB
+int get_nand_env_oob(nand_info_t *nand, unsigned long *result)
+{
+	struct mtd_oob_ops ops;
+	uint32_t oob_buf[ENV_OFFSET_SIZE/sizeof(uint32_t)];
+	int ret;
+
+	ops.datbuf = NULL;
+	ops.mode = MTD_OOB_AUTO;
+	ops.ooboffs = 0;
+	ops.ooblen = ENV_OFFSET_SIZE;
+	ops.oobbuf = (void *) oob_buf;
+
+	ret = nand->read_oob(nand, ENV_OFFSET_SIZE, &ops);
+
+	if (!ret) {
+		if (oob_buf[0] == ENV_OOB_MARKER) {
+			*result = oob_buf[1] * nand->erasesize;
+		} else if (oob_buf[0] == ENV_OOB_MARKER_OLD) {
+			*result = oob_buf[1];
+		} else {
+			printf("No dynamic environment marker in OOB block 0"
+									"\n");
+			ret = -ENOENT;
+			goto fail;
+		}
+	} else {
+		printf("error reading OOB block 0\n");
+	}
+fail:
+	return ret;
+}
+#endif
+
 #ifdef CONFIG_ENV_OFFSET_REDUND
 void env_relocate_spec (void)
 {
@@ -353,6 +388,17 @@ void env_relocate_spec (void)
 #if !defined(ENV_IS_EMBEDDED)
 	int ret;
 
+#if defined(CONFIG_ENV_OFFSET_OOB)
+	ret = get_nand_env_oob(&nand_info[0], &nand_env_oob_offset);
+	/* If unable to read environment offset from NAND OOB then fall through
+	 * to the normal environment reading code below
+	 */
+	if (!ret)
+		printf("Found Environment offset in OOB..\n");
+	else
+		return use_default();
+#endif
+
 	ret = readenv(CONFIG_ENV_OFFSET, (u_char *) env_ptr);
 	if (ret)
 		return use_default();
diff --git a/include/environment.h b/include/environment.h
index 203f731..fbccf6a 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -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)
diff --git a/include/nand.h b/include/nand.h
index 2a81597..8bdf419 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -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
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 0/4] mtdparts: add bad-block skipping
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
@ 2010-07-05 21:43                     ` Ben Gardiner
  2010-07-12 19:06                       ` Ben Gardiner
                                         ` (5 more replies)
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
                                       ` (3 subsequent siblings)
  4 siblings, 6 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 21:43 UTC (permalink / raw)
  To: u-boot

[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 <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> [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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>

---

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 1/4] mtdparts: regroup calls to get_mtd_device_nm
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
@ 2010-07-05 21:43                     ` Ben Gardiner
  2010-08-30 17:38                       ` [U-Boot] [PATCH v5 1/5] " Ben Gardiner
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
                                       ` (2 subsequent siblings)
  4 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 21:43 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Acked-by: Stefan Roese <sr@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 447486b..f1bed95 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
@ 2010-07-05 21:43                     ` Ben Gardiner
  2010-08-07 20:08                       ` Wolfgang Denk
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
  4 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 21:43 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index f1bed95..84acd62 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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., <bengardiner@nanometrics.ca>
+ *   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++;
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 3/4] mtdparts: add new sub-command "spread"
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
                                       ` (2 preceding siblings ...)
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-07-05 21:43                     ` Ben Gardiner
  2010-08-07 20:12                       ` Wolfgang Denk
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
  4 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 21:43 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Harald Welte <laforge@gnumonks.org>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 84acd62..c1adbd4 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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 <laforge@openmoko.org>
+ *   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., <bengardiner@nanometrics.ca>
- *   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"
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks
  2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
                                       ` (3 preceding siblings ...)
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
@ 2010-07-05 21:43                     ` Ben Gardiner
  2010-08-07 20:16                       ` Wolfgang Denk
  4 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-07-05 21:43 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index c1adbd4..d57f9ad 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-05 17:27                     ` [U-Boot] [PATCH v4] " Ben Gardiner
@ 2010-07-12 16:17                       ` Ben Gardiner
  2010-07-12 16:19                         ` Scott Wood
  2010-07-13 19:26                       ` Scott Wood
  1 sibling, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-07-12 16:17 UTC (permalink / raw)
  To: u-boot

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-12 16:17                       ` Ben Gardiner
@ 2010-07-12 16:19                         ` Scott Wood
  0 siblings, 0 replies; 104+ messages in thread
From: Scott Wood @ 2010-07-12 16:19 UTC (permalink / raw)
  To: u-boot

On Mon, 12 Jul 2010 12:17:23 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 0/4] mtdparts: add bad-block skipping
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
@ 2010-07-12 19:06                       ` Ben Gardiner
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 " Ben Gardiner
                                         ` (4 subsequent siblings)
  5 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-12 19:06 UTC (permalink / raw)
  To: u-boot

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-05 17:27                     ` [U-Boot] [PATCH v4] " Ben Gardiner
  2010-07-12 16:17                       ` Ben Gardiner
@ 2010-07-13 19:26                       ` Scott Wood
  2010-07-13 21:17                         ` Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-07-13 19:26 UTC (permalink / raw)
  To: u-boot

I thought I sent this yesterday when applying the patch, but I guess not...

On Mon, Jul 05, 2010 at 01:27:07PM -0400, Ben Gardiner wrote:
> This is a re-submission of the patch by Harald Welte
> <laforge@openmoko.org> with minor modifications for rebase and changes
> as suggested by Scott Wood <scottwood@freescale.com> [1] [2].

Applied to u-boot-nand-flash.

I sent a followup patch for some minor formatting issues.

> 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.

> @@ -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.

> ---
>  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(-)
> 
> diff --git a/common/cmd_nand.c b/common/cmd_nand.c
> index ea80555..a4c67c1 100644
> --- a/common/cmd_nand.c
> +++ b/common/cmd_nand.c
> @@ -4,6 +4,10 @@
>   * (c) 1999 Machine Vision Holdings, Inc.
>   * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
>   *
> + * 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;

Might want to switch to loff_t, even though arg_off_size won't actually let
you enter a 64-bit offset yet.

> diff --git a/include/environment.h b/include/environment.h
> index 203f731..fbccf6a 100644
> --- a/include/environment.h
> +++ b/include/environment.h
> @@ -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

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB)
  2010-07-13 19:26                       ` Scott Wood
@ 2010-07-13 21:17                         ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-07-13 21:17 UTC (permalink / raw)
  To: u-boot

On Tue, Jul 13, 2010 at 3:26 PM, Scott Wood <scottwood@freescale.com> wrote:
> I thought I sent this yesterday when applying the patch, but I guess not...
>
> On Mon, Jul 05, 2010 at 01:27:07PM -0400, Ben Gardiner wrote:
>> This is a re-submission of the patch by Harald Welte
>> <laforge@openmoko.org> with minor modifications for rebase and changes
>> as suggested by Scott Wood <scottwood@freescale.com> [1] [2].
>
> Applied to u-boot-nand-flash.
>
> I sent a followup patch for some minor formatting issues.

Thank you, Scott.

>> 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.
>
>> @@ -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.

>> ---
>> ?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(-)
>>
>> diff --git a/common/cmd_nand.c b/common/cmd_nand.c
>> index ea80555..a4c67c1 100644
>> --- a/common/cmd_nand.c
>> +++ b/common/cmd_nand.c
>> @@ -4,6 +4,10 @@
>> ? * (c) 1999 Machine Vision Holdings, Inc.
>> ? * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org>
>> ? *
>> + * 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;
>
> 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.

>> diff --git a/include/environment.h b/include/environment.h
>> index 203f731..fbccf6a 100644
>> --- a/include/environment.h
>> +++ b/include/environment.h
>> @@ -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
>
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-08-07 20:08                       ` Wolfgang Denk
  2010-08-08  4:06                         ` Harald Welte
  2010-08-09 14:45                         ` Ben Gardiner
  0 siblings, 2 replies; 104+ messages in thread
From: Wolfgang Denk @ 2010-08-07 20:08 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <1278366212-24023-3-git-send-email-bengardiner@nanometrics.ca> you 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.
> 
> Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
> CC: Wolfgang Denk <wd@denx.de>
> 
> ---
> 
> 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

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

> --- a/common/cmd_mtdparts.c
> +++ b/common/cmd_mtdparts.c
> @@ -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., <bengardiner@nanometrics.ca>
> + *   Added net partition size output to mtdparts list command
> + *

NAK for this hunk.

> +#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.


> +		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.

> +#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

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

Best regards,

Wolfgang Denk

-- 
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!"

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 3/4] mtdparts: add new sub-command "spread"
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
@ 2010-08-07 20:12                       ` Wolfgang Denk
  0 siblings, 0 replies; 104+ messages in thread
From: Wolfgang Denk @ 2010-08-07 20:12 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <1278366212-24023-4-git-send-email-bengardiner@nanometrics.ca> you wrote:
> 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.
> 
> Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
> CC: Harald Welte <laforge@gnumonks.org>
> 
> ---
> 
> 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.

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


> +#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.

> +	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.

> +	/* 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

-- 
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_

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
@ 2010-08-07 20:16                       ` Wolfgang Denk
  0 siblings, 0 replies; 104+ messages in thread
From: Wolfgang Denk @ 2010-08-07 20:16 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <1278366212-24023-5-git-send-email-bengardiner@nanometrics.ca> you wrote:
> 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.
> 
> Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
> 
> ---
> 
> 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

NAK for this like for the previous patches.


> +#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
> +		s = strchr(argv[1], '.');

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

> +		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.

> +#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

-- 
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 <8czptuomey.fsf@gadget.cscaper.com>

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list
  2010-08-07 20:08                       ` Wolfgang Denk
@ 2010-08-08  4:06                         ` Harald Welte
  2010-08-08 13:16                           ` Wolfgang Denk
  2010-08-09 14:45                         ` Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Harald Welte @ 2010-08-08  4:06 UTC (permalink / raw)
  To: u-boot

Dear Wolfgang,

On Sat, Aug 07, 2010 at 10:08:50PM +0200, Wolfgang Denk wrote:
> >  * 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 

> > + *   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
-- 
- Harald Welte <laforge@gnumonks.org>           http://laforge.gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
                                                  (ETSI EN 300 175-7 Ch. A6)

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list
  2010-08-08  4:06                         ` Harald Welte
@ 2010-08-08 13:16                           ` Wolfgang Denk
  0 siblings, 0 replies; 104+ messages in thread
From: Wolfgang Denk @ 2010-08-08 13:16 UTC (permalink / raw)
  To: u-boot

Dear Harald Welte,

In message <20100808040649.GI12062@prithivi.gnumonks.org> you wrote:
> 
> On Sat, Aug 07, 2010 at 10:08:50PM +0200, Wolfgang Denk wrote:
> > >  * 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 
> 
> > > + *   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.

> 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

-- 
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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list
  2010-08-07 20:08                       ` Wolfgang Denk
  2010-08-08  4:06                         ` Harald Welte
@ 2010-08-09 14:45                         ` Ben Gardiner
  2010-09-18 19:42                           ` Wolfgang Denk
  1 sibling, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 14:45 UTC (permalink / raw)
  To: u-boot

Hi Wolfgang,

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

On Sat, Aug 7, 2010 at 4:08 PM, Wolfgang Denk <wd@denx.de> wrote:
> Dear Ben Gardiner,
>
> In message <1278366212-24023-3-git-send-email-bengardiner@nanometrics.ca> you wrote:
>> +#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
>
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks
  2010-06-02 15:58                   ` [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
@ 2010-08-09 18:25                     ` Scott Wood
  2010-08-09 18:39                       ` Ben Gardiner
  0 siblings, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-09 18:25 UTC (permalink / raw)
  To: u-boot

On Wed, 2 Jun 2010 11:58:39 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks
  2010-08-09 18:25                     ` Scott Wood
@ 2010-08-09 18:39                       ` Ben Gardiner
  2010-08-09 18:51                         ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 18:39 UTC (permalink / raw)
  To: u-boot

Hi Scott,

On Mon, Aug 9, 2010 at 2:25 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Wed, 2 Jun 2010 11:58:39 -0400
> Ben Gardiner <bengardiner@nanometrics.ca> wrote:
>
>> 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.

> 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.

> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks
  2010-08-09 18:39                       ` Ben Gardiner
@ 2010-08-09 18:51                         ` Scott Wood
  0 siblings, 0 replies; 104+ messages in thread
From: Scott Wood @ 2010-08-09 18:51 UTC (permalink / raw)
  To: u-boot

On Mon, 9 Aug 2010 14:39:20 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> Hi Scott,
> 
> On Mon, Aug 9, 2010 at 2:25 PM, Scott Wood <scottwood@freescale.com> wrote:
> > On Wed, 2 Jun 2010 11:58:39 -0400
> > Ben Gardiner <bengardiner@nanometrics.ca> wrote:
> >
> >> 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.
> 
> > 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.
> 
> > 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 0/4] mtdparts: add bad-block skipping
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
  2010-07-12 19:06                       ` Ben Gardiner
@ 2010-08-09 20:43                       ` Ben Gardiner
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 0/5] " Ben Gardiner
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
                                         ` (3 subsequent siblings)
  5 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 20:43 UTC (permalink / raw)
  To: u-boot

[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 <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> [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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

[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.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 1/4] mtdparts: regroup calls to get_mtd_device_nm
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
  2010-07-12 19:06                       ` Ben Gardiner
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 " Ben Gardiner
@ 2010-08-09 20:43                       ` Ben Gardiner
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
                                         ` (2 subsequent siblings)
  5 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 20:43 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Acked-by: Stefan Roese <sr@denx.de>
CC: Wolfgang Denk <wd@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index ceec5a9..772ad54 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
                                         ` (2 preceding siblings ...)
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
@ 2010-08-09 20:43                       ` Ben Gardiner
  2010-08-26 18:57                         ` Scott Wood
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
  2010-08-09 20:44                       ` [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks Ben Gardiner
  5 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 20:43 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 772ad54..500a38e 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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) {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
                                         ` (3 preceding siblings ...)
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-08-09 20:43                       ` Ben Gardiner
  2010-08-26 21:12                         ` Scott Wood
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 4/5] " Ben Gardiner
  2010-08-09 20:44                       ` [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks Ben Gardiner
  5 siblings, 2 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 20:43 UTC (permalink / raw)
  To: u-boot

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 <laforge@gnumonks.org>; 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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Signed-off-by: Harald Welte <laforge@gnumonks.org>
CC: Wolfgang Denk <wd@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 500a38e..7e2e232 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -15,6 +15,9 @@
  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
  *   kernel tree.
  *
+ * (C) Copyright 2008
+ * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org>
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -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"
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
                                         ` (4 preceding siblings ...)
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
@ 2010-08-09 20:44                       ` Ben Gardiner
  2010-08-26 22:26                         ` Scott Wood
  2010-08-30 17:39                         ` [U-Boot] [PATCH v5 5/5] " Ben Gardiner
  5 siblings, 2 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-09 20:44 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 7e2e232..6e42eff 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-08-26 18:57                         ` Scott Wood
  2010-08-27 13:51                           ` Ben Gardiner
  2010-08-27 15:44                           ` Ben Gardiner
  0 siblings, 2 replies; 104+ messages in thread
From: Scott Wood @ 2010-08-26 18:57 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 09, 2010 at 04:43:58PM -0400, Ben Gardiner wrote:
> diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
> index 772ad54..500a38e 100644
> --- a/common/cmd_mtdparts.c
> +++ b/common/cmd_mtdparts.c
> @@ -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)

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

> +{
> +	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.

> +	} 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.

> +}
> +#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) */

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

-Scott

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
@ 2010-08-26 21:12                         ` Scott Wood
  2010-08-27 13:51                           ` Ben Gardiner
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 4/5] " Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-26 21:12 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 09, 2010 at 04:43:59PM -0400, Ben Gardiner wrote:
> +static void spread_partition(struct mtd_info *mtd, struct part_info *part,
> +							 u32 *next_offset)

As in patch 2, change u32 to uint64_t.

> +{
> +	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;
> +	}

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

> +			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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks
  2010-08-09 20:44                       ` [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks Ben Gardiner
@ 2010-08-26 22:26                         ` Scott Wood
  2010-08-27 13:52                           ` Ben Gardiner
  2010-08-30 17:39                         ` [U-Boot] [PATCH v5 5/5] " Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-26 22:26 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 09, 2010 at 04:44:00PM -0400, Ben Gardiner wrote:
> +#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"))".

> +				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

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list
  2010-08-26 18:57                         ` Scott Wood
@ 2010-08-27 13:51                           ` Ben Gardiner
  2010-08-27 15:44                           ` Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 13:51 UTC (permalink / raw)
  To: u-boot

Hi Scott,

Thank you for reviewing patches 2-4.

On Thu, Aug 26, 2010 at 2:57 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, Aug 09, 2010 at 04:43:58PM -0400, Ben Gardiner wrote:
>> diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
>> index 772ad54..500a38e 100644
>> --- a/common/cmd_mtdparts.c
>> +++ b/common/cmd_mtdparts.c
>> @@ -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)
>
> Don't assume partition size fits in 32 bits. ?part->size is uint64_t.

My mistake.

>> +{
>> + ? ? 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.

Will do.

>> + ? ? } 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.

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

>> +}
>> +#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) */
>
> 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:

On Sat, Aug 7, 2010 at 4:08 PM, Wolfgang Denk <wd@denx.de> wrote:
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-26 21:12                         ` Scott Wood
@ 2010-08-27 13:51                           ` Ben Gardiner
  2010-08-27 21:36                             ` Ben Gardiner
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 13:51 UTC (permalink / raw)
  To: u-boot

On Thu, Aug 26, 2010 at 5:12 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, Aug 09, 2010 at 04:43:59PM -0400, Ben Gardiner wrote:
>> +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.

>> +{
>> + ? ? 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;
>> + ? ? }
>
> 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.

>> + ? ? ? ? ? ? ? ? ? ? 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);

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks
  2010-08-26 22:26                         ` Scott Wood
@ 2010-08-27 13:52                           ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 13:52 UTC (permalink / raw)
  To: u-boot

On Thu, Aug 26, 2010 at 6:26 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, Aug 09, 2010 at 04:44:00PM -0400, Ben Gardiner wrote:
>> +#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.

>> + ? ? ? ? ? ? ? ? ? ? ? ? ? ? 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
>
> 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;
> }

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list
  2010-08-26 18:57                         ` Scott Wood
  2010-08-27 13:51                           ` Ben Gardiner
@ 2010-08-27 15:44                           ` Ben Gardiner
  2010-08-27 16:02                             ` Scott Wood
  1 sibling, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 15:44 UTC (permalink / raw)
  To: u-boot

On Thu, Aug 26, 2010 at 2:57 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, Aug 09, 2010 at 04:43:58PM -0400, Ben Gardiner wrote:
>> diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
>> index 772ad54..500a38e 100644
>> --- a/common/cmd_mtdparts.c
>> +++ b/common/cmd_mtdparts.c
>> @@ -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)
>
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list
  2010-08-27 15:44                           ` Ben Gardiner
@ 2010-08-27 16:02                             ` Scott Wood
  2010-08-27 16:45                               ` Ben Gardiner
  0 siblings, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-27 16:02 UTC (permalink / raw)
  To: u-boot

On 08/27/2010 10:44 AM, Ben Gardiner wrote:
> On Thu, Aug 26, 2010 at 2:57 PM, Scott Wood<scottwood@freescale.com>  wrote:
>> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list
  2010-08-27 16:02                             ` Scott Wood
@ 2010-08-27 16:45                               ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 16:45 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 27, 2010 at 12:02 PM, Scott Wood <scottwood@freescale.com> wrote:
> On 08/27/2010 10:44 AM, Ben Gardiner wrote:
>>
>> On Thu, Aug 26, 2010 at 2:57 PM, Scott Wood<scottwood@freescale.com>
>> ?wrote:
>>>
>>> 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?

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 <sr@denx.de> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-27 13:51                           ` Ben Gardiner
@ 2010-08-27 21:36                             ` Ben Gardiner
  2010-08-27 21:46                               ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 21:36 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner
<bengardiner@nanometrics.ca> wrote:
> On Thu, Aug 26, 2010 at 5:12 PM, Scott Wood <scottwood@freescale.com> wrote:
>>> +{
>>> + ? ? 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;
>>> + ? ? }
>>
>> 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.

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-27 21:36                             ` Ben Gardiner
@ 2010-08-27 21:46                               ` Scott Wood
  2010-08-27 21:52                                 ` Ben Gardiner
  2010-08-27 21:59                                 ` Scott Wood
  0 siblings, 2 replies; 104+ messages in thread
From: Scott Wood @ 2010-08-27 21:46 UTC (permalink / raw)
  To: u-boot

On 08/27/2010 04:36 PM, Ben Gardiner wrote:
> On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner
> <bengardiner@nanometrics.ca>  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.

> 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.

> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-27 21:46                               ` Scott Wood
@ 2010-08-27 21:52                                 ` Ben Gardiner
  2010-08-27 21:59                                 ` Scott Wood
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-27 21:52 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 27, 2010 at 5:46 PM, Scott Wood <scottwood@freescale.com> wrote:
> On 08/27/2010 04:36 PM, Ben Gardiner wrote:
>>
>> On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner
>> <bengardiner@nanometrics.ca> ?wrote:
>> 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.

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

>> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-27 21:46                               ` Scott Wood
  2010-08-27 21:52                                 ` Ben Gardiner
@ 2010-08-27 21:59                                 ` Scott Wood
  2010-08-28  3:59                                   ` Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-27 21:59 UTC (permalink / raw)
  To: u-boot

On 08/27/2010 04:46 PM, Scott Wood wrote:
> On 08/27/2010 04:36 PM, Ben Gardiner wrote:
>> On Fri, Aug 27, 2010 at 9:51 AM, Ben Gardiner
>> <bengardiner@nanometrics.ca> 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.
>
>> 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.

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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-27 21:59                                 ` Scott Wood
@ 2010-08-28  3:59                                   ` Ben Gardiner
  2010-08-30 20:24                                     ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-28  3:59 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 27, 2010 at 5:59 PM, Scott Wood <scottwood@freescale.com> wrote:
> On 08/27/2010 04:46 PM, Scott Wood wrote:
>> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 0/5] mtdparts: add bad-block skipping
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 " Ben Gardiner
@ 2010-08-30 17:38                         ` Ben Gardiner
  2010-08-30 17:38                           ` [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad() Ben Gardiner
                                             ` (2 more replies)
  0 siblings, 3 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 17:38 UTC (permalink / raw)
  To: u-boot

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 <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> [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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>

[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.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 1/5] mtdparts: regroup calls to get_mtd_device_nm
  2010-07-05 21:43                     ` [U-Boot] [PATCH v3 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
@ 2010-08-30 17:38                       ` Ben Gardiner
  2010-08-31 21:48                         ` [U-Boot] [PATCH v6 " Ben Gardiner
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 17:38 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Acked-by: Stefan Roese <sr@denx.de>
CC: Wolfgang Denk <wd@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index ceec5a9..772ad54 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad()
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 0/5] " Ben Gardiner
@ 2010-08-30 17:38                           ` Ben Gardiner
  2010-08-30 20:57                             ` Scott Wood
  2010-08-31 21:48                             ` [U-Boot] [PATCH v6 " Ben Gardiner
       [not found]                           ` <1283185640-0-git-send-email-bengardiner@nanometrics.ca>
  2010-08-31 21:47                           ` [U-Boot] [PATCH v6 0/5] mtdparts: add bad-block skipping Ben Gardiner
  2 siblings, 2 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 17:38 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner<bengardiner@nanometrics.ca>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 6eb52ed..cb86657 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -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) */
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 29c42f7..622237f 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -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;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 16556c4..8e8ec7c 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -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 {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list
       [not found]                           ` <1283185640-0-git-send-email-bengardiner@nanometrics.ca>
@ 2010-08-30 17:38                             ` Ben Gardiner
  2010-08-30 20:50                               ` Scott Wood
  2010-08-31 21:48                               ` [U-Boot] [PATCH v6 " Ben Gardiner
  0 siblings, 2 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 17:38 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>
---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 772ad54..a8912ed 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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) {
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index cb86657..211b993 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -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
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 4/5] mtdparts: add new sub-command "spread"
  2010-08-09 20:43                       ` [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
  2010-08-26 21:12                         ` Scott Wood
@ 2010-08-30 17:38                         ` Ben Gardiner
  2010-08-30 21:01                           ` Scott Wood
  2010-08-31 21:48                           ` [U-Boot] [PATCH v6 " Ben Gardiner
  1 sibling, 2 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 17:38 UTC (permalink / raw)
  To: u-boot

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 <laforge@gnumonks.org>; 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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Signed-off-by: Harald Welte <laforge@gnumonks.org>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index a8912ed..fb8c77b 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -15,6 +15,9 @@
  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
  *   kernel tree.
  *
+ * (C) Copyright 2008
+ * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org>
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -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"
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 5/5] mtdparts: new add.spread: add part skipping bad blocks
  2010-08-09 20:44                       ` [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks Ben Gardiner
  2010-08-26 22:26                         ` Scott Wood
@ 2010-08-30 17:39                         ` Ben Gardiner
  2010-08-31 21:48                           ` [U-Boot] [PATCH v6 " Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 17:39 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index fb8c77b..d8cda77 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-28  3:59                                   ` Ben Gardiner
@ 2010-08-30 20:24                                     ` Scott Wood
  2010-08-30 20:30                                       ` Ben Gardiner
  0 siblings, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-30 20:24 UTC (permalink / raw)
  To: u-boot

On Fri, 27 Aug 2010 23:59:13 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> On Fri, Aug 27, 2010 at 5:59 PM, Scott Wood <scottwood@freescale.com> wrote:
> > On 08/27/2010 04:46 PM, Scott Wood wrote:
> >> 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 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread"
  2010-08-30 20:24                                     ` Scott Wood
@ 2010-08-30 20:30                                       ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-30 20:30 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 30, 2010 at 4:24 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Fri, 27 Aug 2010 23:59:13 -0400
> Ben Gardiner <bengardiner@nanometrics.ca> wrote:
>
>> On Fri, Aug 27, 2010 at 5:59 PM, Scott Wood <scottwood@freescale.com> wrote:
>> > On 08/27/2010 04:46 PM, Scott Wood wrote:
>> >> 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 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list
  2010-08-30 17:38                             ` [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list Ben Gardiner
@ 2010-08-30 20:50                               ` Scott Wood
  2010-08-31 13:51                                 ` Ben Gardiner
  2010-08-31 21:48                               ` [U-Boot] [PATCH v6 " Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-30 20:50 UTC (permalink / raw)
  To: u-boot

On Mon, 30 Aug 2010 13:38:58 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> +#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);

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.

> +}
> +#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.

>  		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) */

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?

> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
> index cb86657..211b993 100644
> --- a/drivers/mtd/mtdcore.c
> +++ b/drivers/mtd/mtdcore.c
> @@ -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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad()
  2010-08-30 17:38                           ` [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad() Ben Gardiner
@ 2010-08-30 20:57                             ` Scott Wood
  2010-08-31 13:50                               ` Ben Gardiner
  2010-08-31 21:48                             ` [U-Boot] [PATCH v6 " Ben Gardiner
  1 sibling, 1 reply; 104+ messages in thread
From: Scott Wood @ 2010-08-30 20:57 UTC (permalink / raw)
  To: u-boot

On Mon, 30 Aug 2010 13:38:57 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> 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.
> 
> Signed-off-by: Ben Gardiner<bengardiner@nanometrics.ca>
> CC: Scott Wood <scottwood@freescale.com>
> 
> ---
> 
> 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(-)
> 
> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
> index 6eb52ed..cb86657 100644
> --- a/drivers/mtd/mtdcore.c
> +++ b/drivers/mtd/mtdcore.c
> @@ -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;
> +		}
> +	}

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

-Scott

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 4/5] mtdparts: add new sub-command "spread"
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 4/5] " Ben Gardiner
@ 2010-08-30 21:01                           ` Scott Wood
  2010-08-30 21:05                             ` Scott Wood
  2010-08-31 13:51                             ` Ben Gardiner
  2010-08-31 21:48                           ` [U-Boot] [PATCH v6 " Ben Gardiner
  1 sibling, 2 replies; 104+ messages in thread
From: Scott Wood @ 2010-08-30 21:01 UTC (permalink / raw)
  To: u-boot

On Mon, 30 Aug 2010 13:38:59 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> +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.
> +	 */

Why is the first block of a partition special?

> +	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.

> +	}
> +
> +	if (truncated) {

} else {

-Scott

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 4/5] mtdparts: add new sub-command "spread"
  2010-08-30 21:01                           ` Scott Wood
@ 2010-08-30 21:05                             ` Scott Wood
  2010-08-31 13:51                             ` Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Scott Wood @ 2010-08-30 21:05 UTC (permalink / raw)
  To: u-boot

On Mon, 30 Aug 2010 16:01:05 -0500
Scott Wood <scottwood@freescale.com> wrote:

> On Mon, 30 Aug 2010 13:38:59 -0400
> Ben Gardiner <bengardiner@nanometrics.ca> wrote:
> 
> > +	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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad()
  2010-08-30 20:57                             ` Scott Wood
@ 2010-08-31 13:50                               ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 13:50 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 30, 2010 at 4:57 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, 30 Aug 2010 13:38:57 -0400
> Ben Gardiner <bengardiner@nanometrics.ca> wrote:
>> +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;
>> + ? ? ? ? ? ? }
>> + ? ? }
>
> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list
  2010-08-30 20:50                               ` Scott Wood
@ 2010-08-31 13:51                                 ` Ben Gardiner
  2010-08-31 15:57                                   ` Scott Wood
  0 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 13:51 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 30, 2010 at 4:50 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, 30 Aug 2010 13:38:58 -0400
> Ben Gardiner <bengardiner@nanometrics.ca> wrote:
>
>> +#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);
>
> 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.

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.

>> +}
>> +#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.

Sorry.

>> ? ? ? ? ? ? ? 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) */
>
> 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.

>> diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
>> index cb86657..211b993 100644
>> --- a/drivers/mtd/mtdcore.c
>> +++ b/drivers/mtd/mtdcore.c
>> @@ -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.

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 <wd@denx.de> 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 <wd@denx.de> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 4/5] mtdparts: add new sub-command "spread"
  2010-08-30 21:01                           ` Scott Wood
  2010-08-30 21:05                             ` Scott Wood
@ 2010-08-31 13:51                             ` Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 13:51 UTC (permalink / raw)
  To: u-boot

On Mon, Aug 30, 2010 at 5:01 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, 30 Aug 2010 13:38:59 -0400
> Ben Gardiner <bengardiner@nanometrics.ca> wrote:
>
>> +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.
>> + ? ? ?*/
>
> 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
<laforge@gnumonks.org> 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.

>> + ? ? 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.

On Mon, Aug 30, 2010 at 5:05 PM, Scott Wood <scottwood@freescale.com> wrote:
> On Mon, 30 Aug 2010 16:01:05 -0500
> Scott Wood <scottwood@freescale.com> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list
  2010-08-31 13:51                                 ` Ben Gardiner
@ 2010-08-31 15:57                                   ` Scott Wood
  0 siblings, 0 replies; 104+ messages in thread
From: Scott Wood @ 2010-08-31 15:57 UTC (permalink / raw)
  To: u-boot

On Tue, 31 Aug 2010 09:51:15 -0400
Ben Gardiner <bengardiner@nanometrics.ca> wrote:

> But I'm not sure what I'm supposed to do with this block now since
> Wolfgang Denk <wd@denx.de> 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

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 0/5] mtdparts: add bad-block skipping
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 0/5] " Ben Gardiner
  2010-08-30 17:38                           ` [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad() Ben Gardiner
       [not found]                           ` <1283185640-0-git-send-email-bengardiner@nanometrics.ca>
@ 2010-08-31 21:47                           ` Ben Gardiner
  2010-09-09 20:54                             ` Scott Wood
  2 siblings, 1 reply; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 21:47 UTC (permalink / raw)
  To: u-boot

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 <laforge@gnumonks.org>
and the comments of Wolfgang Denk <wd@denx.de> [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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>

[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.

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 1/5] mtdparts: regroup calls to get_mtd_device_nm
  2010-08-30 17:38                       ` [U-Boot] [PATCH v5 1/5] " Ben Gardiner
@ 2010-08-31 21:48                         ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 21:48 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Acked-by: Stefan Roese <sr@denx.de>
CC: Wolfgang Denk <wd@denx.de>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index ceec5a9..772ad54 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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;
 
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 2/5] mtd: add an mtd method for get_len_incl_bad()
  2010-08-30 17:38                           ` [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad() Ben Gardiner
  2010-08-30 20:57                             ` Scott Wood
@ 2010-08-31 21:48                             ` Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 21:48 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner<bengardiner@nanometrics.ca>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 6eb52ed..78f2a08 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -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) */
diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 29c42f7..622237f 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -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;
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index 16556c4..8e8ec7c 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -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 {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 3/5] mtdparts: show net size in mtdparts list
  2010-08-30 17:38                             ` [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list Ben Gardiner
  2010-08-30 20:50                               ` Scott Wood
@ 2010-08-31 21:48                               ` Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 21:48 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 772ad54..266844f 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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) {
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 4/5] mtdparts: add new sub-command "spread"
  2010-08-30 17:38                         ` [U-Boot] [PATCH v5 4/5] " Ben Gardiner
  2010-08-30 21:01                           ` Scott Wood
@ 2010-08-31 21:48                           ` Ben Gardiner
  1 sibling, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 21:48 UTC (permalink / raw)
  To: u-boot

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 <laforge@gnumonks.org>; 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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
Signed-off-by: Harald Welte <laforge@gnumonks.org>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 266844f..347e409 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -15,6 +15,9 @@
  *   Parsing routines are based on driver/mtd/cmdline.c from the linux 2.4
  *   kernel tree.
  *
+ * (C) Copyright 2008
+ * Harald Welte, OpenMoko, Inc., Harald Welte <laforge@openmoko.org>
+ *
  *   $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
  *   Copyright 2002 SYSGO Real-Time Solutions GmbH
  *
@@ -1424,6 +1427,101 @@ static int delete_partition(const char *id)
 	return 1;
 }
 
+#if defined(CONFIG_CMD_MTDPARTS_SPREAD)
+/**
+ * Increase the size of the given partition so that it's net size is at least
+ * as large as the size member and such that the next partition would start on a
+ * good block if it were adjacent to this partition.
+ *
+ * @param mtd the mtd device
+ * @param part the partition
+ * @param next_offset pointer to the offset of the next partition after this
+ *                    partition's size has been modified (output)
+ */
+static void spread_partition(struct mtd_info *mtd, struct part_info *part,
+			     uint64_t *next_offset)
+{
+	uint64_t net_size, padding_size = 0;
+	int truncated;
+
+	mtd_get_len_incl_bad(mtd, part->offset, part->size, &net_size,
+			     &truncated);
+
+	/*
+	 * Absorb bad blocks immediately following this
+	 * partition also into the partition, such that
+	 * the next partition starts with a good block.
+	 */
+	if (!truncated) {
+		mtd_get_len_incl_bad(mtd, part->offset + net_size,
+				     mtd->erasesize, &padding_size, &truncated);
+		if (truncated)
+			padding_size = 0;
+		else
+			padding_size -= mtd->erasesize;
+	}
+
+	if (truncated) {
+		printf("truncated partition %s to %lld bytes\n", part->name,
+		       (uint64_t) net_size + padding_size);
+	}
+
+	part->size = net_size + padding_size;
+	*next_offset = part->offset + part->size;
+}
+
+/**
+ * Adjust all of the partition sizes, such that all partitions are at least
+ * as big as their mtdparts environment variable sizes and they each start
+ * on a good block.
+ *
+ * @return 0 on success, 1 otherwise
+ */
+static int spread_partitions(void)
+{
+	struct list_head *dentry, *pentry;
+	struct mtd_device *dev;
+	struct part_info *part;
+	struct mtd_info *mtd;
+	int part_num;
+	uint64_t cur_offs;
+
+	list_for_each(dentry, &devices) {
+		dev = list_entry(dentry, struct mtd_device, link);
+
+		if (get_mtd_info(dev->id->type, dev->id->num, &mtd))
+			return 1;
+
+		part_num = 0;
+		cur_offs = 0;
+		list_for_each(pentry, &dev->parts) {
+			part = list_entry(pentry, struct part_info, link);
+
+			debug("spread_partitions: device = %s%d, partition %d ="
+				" (%s) 0x%08x 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"
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 5/5] mtdparts: new add.spread: add part skipping bad blocks
  2010-08-30 17:39                         ` [U-Boot] [PATCH v5 5/5] " Ben Gardiner
@ 2010-08-31 21:48                           ` Ben Gardiner
  0 siblings, 0 replies; 104+ messages in thread
From: Ben Gardiner @ 2010-08-31 21:48 UTC (permalink / raw)
  To: u-boot

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.

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Wolfgang Denk <wd@denx.de>
CC: Scott Wood <scottwood@freescale.com>

---

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(-)

diff --git a/common/cmd_mtdparts.c b/common/cmd_mtdparts.c
index 347e409..17865b7 100644
--- a/common/cmd_mtdparts.c
+++ b/common/cmd_mtdparts.c
@@ -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)
-- 
1.7.0.4

^ permalink raw reply related	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v6 0/5] mtdparts: add bad-block skipping
  2010-08-31 21:47                           ` [U-Boot] [PATCH v6 0/5] mtdparts: add bad-block skipping Ben Gardiner
@ 2010-09-09 20:54                             ` Scott Wood
  0 siblings, 0 replies; 104+ messages in thread
From: Scott Wood @ 2010-09-09 20:54 UTC (permalink / raw)
  To: u-boot

On Tue, Aug 31, 2010 at 05:47:59PM -0400, Ben Gardiner wrote:
> 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(-)

Applied to u-boot-nand-flash next

Sent a followup patch for a couple minor issues.

-Scott

^ permalink raw reply	[flat|nested] 104+ messages in thread

* [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list
  2010-08-09 14:45                         ` Ben Gardiner
@ 2010-09-18 19:42                           ` Wolfgang Denk
  0 siblings, 0 replies; 104+ messages in thread
From: Wolfgang Denk @ 2010-09-18 19:42 UTC (permalink / raw)
  To: u-boot

Dear Ben Gardiner,

In message <AANLkTim8N9jxbSO_UzcDYX6ta+qkfa-ABO4GMpC2m771@mail.gmail.com> you wrote:
>
> 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

-- 
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

^ permalink raw reply	[flat|nested] 104+ messages in thread

end of thread, other threads:[~2010-09-18 19:42 UTC | newest]

Thread overview: 104+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-07-06 16:28 [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset Harald Welte
2008-07-07 18:47 ` Scott Wood
2008-07-08  0:09   ` Harald Welte
2008-07-08 16:05     ` Scott Wood
2008-07-08 21:12       ` Wolfgang Denk
2008-07-09  0:23         ` Harald Welte
2008-07-09  7:05           ` Wolfgang Denk
2008-07-09  7:25             ` Harald Welte
2008-07-09  8:04               ` Wolfgang Denk
2008-07-09 12:13                 ` Harald Welte
2010-06-01 20:23                 ` [U-Boot] mtdparts: add bad-block skipping Ben Gardiner
2010-06-01 22:20                   ` Wolfgang Denk
2010-06-01 22:34                   ` Wolfgang Denk
2010-06-02  5:08                     ` Ben Gardiner
2010-06-02 15:58                   ` [U-Boot] [PATCH 0/4 v2] " Ben Gardiner
2010-07-05 21:43                     ` [U-Boot] [PATCH v3 0/4] " Ben Gardiner
2010-07-12 19:06                       ` Ben Gardiner
2010-08-09 20:43                       ` [U-Boot] [PATCH v4 " Ben Gardiner
2010-08-30 17:38                         ` [U-Boot] [PATCH v5 0/5] " Ben Gardiner
2010-08-30 17:38                           ` [U-Boot] [PATCH v5 2/5] mtd: add an mtd method for get_len_incl_bad() Ben Gardiner
2010-08-30 20:57                             ` Scott Wood
2010-08-31 13:50                               ` Ben Gardiner
2010-08-31 21:48                             ` [U-Boot] [PATCH v6 " Ben Gardiner
     [not found]                           ` <1283185640-0-git-send-email-bengardiner@nanometrics.ca>
2010-08-30 17:38                             ` [U-Boot] [PATCH v5 3/5] mtdparts: show net size in mtdparts list Ben Gardiner
2010-08-30 20:50                               ` Scott Wood
2010-08-31 13:51                                 ` Ben Gardiner
2010-08-31 15:57                                   ` Scott Wood
2010-08-31 21:48                               ` [U-Boot] [PATCH v6 " Ben Gardiner
2010-08-31 21:47                           ` [U-Boot] [PATCH v6 0/5] mtdparts: add bad-block skipping Ben Gardiner
2010-09-09 20:54                             ` Scott Wood
2010-08-09 20:43                       ` [U-Boot] [PATCH v4 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
2010-08-09 20:43                       ` [U-Boot] [PATCH v4 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
2010-08-26 18:57                         ` Scott Wood
2010-08-27 13:51                           ` Ben Gardiner
2010-08-27 15:44                           ` Ben Gardiner
2010-08-27 16:02                             ` Scott Wood
2010-08-27 16:45                               ` Ben Gardiner
2010-08-09 20:43                       ` [U-Boot] [PATCH v4 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
2010-08-26 21:12                         ` Scott Wood
2010-08-27 13:51                           ` Ben Gardiner
2010-08-27 21:36                             ` Ben Gardiner
2010-08-27 21:46                               ` Scott Wood
2010-08-27 21:52                                 ` Ben Gardiner
2010-08-27 21:59                                 ` Scott Wood
2010-08-28  3:59                                   ` Ben Gardiner
2010-08-30 20:24                                     ` Scott Wood
2010-08-30 20:30                                       ` Ben Gardiner
2010-08-30 17:38                         ` [U-Boot] [PATCH v5 4/5] " Ben Gardiner
2010-08-30 21:01                           ` Scott Wood
2010-08-30 21:05                             ` Scott Wood
2010-08-31 13:51                             ` Ben Gardiner
2010-08-31 21:48                           ` [U-Boot] [PATCH v6 " Ben Gardiner
2010-08-09 20:44                       ` [U-Boot] [PATCH v4 4/4] mtdparts: new add.spread: add part skipping bad blocks Ben Gardiner
2010-08-26 22:26                         ` Scott Wood
2010-08-27 13:52                           ` Ben Gardiner
2010-08-30 17:39                         ` [U-Boot] [PATCH v5 5/5] " Ben Gardiner
2010-08-31 21:48                           ` [U-Boot] [PATCH v6 " Ben Gardiner
2010-07-05 21:43                     ` [U-Boot] [PATCH v3 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
2010-08-30 17:38                       ` [U-Boot] [PATCH v5 1/5] " Ben Gardiner
2010-08-31 21:48                         ` [U-Boot] [PATCH v6 " Ben Gardiner
2010-07-05 21:43                     ` [U-Boot] [PATCH v3 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
2010-08-07 20:08                       ` Wolfgang Denk
2010-08-08  4:06                         ` Harald Welte
2010-08-08 13:16                           ` Wolfgang Denk
2010-08-09 14:45                         ` Ben Gardiner
2010-09-18 19:42                           ` Wolfgang Denk
2010-07-05 21:43                     ` [U-Boot] [PATCH v3 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
2010-08-07 20:12                       ` Wolfgang Denk
2010-07-05 21:43                     ` [U-Boot] [PATCH v3 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
2010-08-07 20:16                       ` Wolfgang Denk
2010-06-02 15:58                   ` [U-Boot] [PATCH 1/4 v2] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
2010-06-02 15:58                   ` [U-Boot] [PATCH 2/4 v2] mtdparts: show net size in mtdparts list Ben Gardiner
2010-06-02 15:58                   ` [U-Boot] [PATCH 3/4 v2] mtdparts: add new sub-command "spread" Ben Gardiner
2010-06-02 15:58                   ` [U-Boot] [PATCH 4/4 v2] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
2010-08-09 18:25                     ` Scott Wood
2010-08-09 18:39                       ` Ben Gardiner
2010-08-09 18:51                         ` Scott Wood
2010-06-01 20:23                 ` [U-Boot] [PATCH 1/4] mtdparts: regroup calls to get_mtd_device_nm Ben Gardiner
2010-06-02  7:06                   ` Stefan Roese
2010-06-01 20:23                 ` [U-Boot] [PATCH 2/4] mtdparts: show net size in mtdparts list Ben Gardiner
2010-06-02  7:15                   ` Stefan Roese
2010-06-01 20:23                 ` [U-Boot] [PATCH 3/4] mtdparts: add new sub-command "spread" Ben Gardiner
2010-06-01 20:23                 ` [U-Boot] [PATCH 4/4] mtdparts: new add.e: add part skipping bad blocks Ben Gardiner
2008-07-09  0:18       ` [U-Boot-Users] [PATCH, resend] Support dynamic/patched NAND ENV offset Harald Welte
2008-07-09  5:28       ` Harald Welte
2008-07-09  7:07         ` Harald Welte
2008-07-09  8:11       ` [U-Boot-Users] [PATCH] " Harald Welte
2008-07-11 17:28         ` Scott Wood
2010-05-17 21:04           ` [U-Boot] [PATCH] NAND: Support dynamic location of enviromnent (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
2010-05-26 22:58             ` Scott Wood
2010-05-26 23:38               ` Ben Gardiner
2010-05-31 21:29               ` [U-Boot] [PATCH v2] NAND: environment offset in OOB (CONFIG_ENV_OFFSET_OOB) Ben Gardiner
2010-06-30 21:32                 ` [U-Boot] [PATCH v3] " Ben Gardiner
2010-06-30 21:41                   ` Wolfgang Denk
2010-07-01  4:09                     ` Ben Gardiner
2010-07-01  3:37                   ` Vipin KUMAR
2010-07-01  5:29                     ` Ben Gardiner
2010-07-01  7:17                   ` Harald Welte
2010-07-05 13:57                     ` Ben Gardiner
2010-07-05 17:27                     ` [U-Boot] [PATCH v4] " Ben Gardiner
2010-07-12 16:17                       ` Ben Gardiner
2010-07-12 16:19                         ` Scott Wood
2010-07-13 19:26                       ` Scott Wood
2010-07-13 21:17                         ` Ben Gardiner

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.