diff mbox

[U-Boot,2/3,v4] nand_util: drop trailing all-0xff pages if requested

Message ID 8a497e85f311e373169c35d62c58281ab0eddb00.1308083237.git.bengardiner@nanometrics.ca
State Accepted
Commit 169d54d8b33b4d06d6f215e2b312a0b18f7909dc
Headers show

Commit Message

Ben Gardiner June 14, 2011, 8:35 p.m. UTC
Add a flag to nand_read_skip_bad() such that if true, any trailing
pages in an eraseblock whose contents are entirely 0xff will be
dropped.

The implementation is via a new drop_ffs() function which is
based on the function of the same name from the ubiformat
utility by Artem Bityutskiy.

This is as-per the reccomendations of the UBI FAQ [1]

Signed-off-by: Ben Gardiner <bengardiner@nanometrics.ca>
CC: Artem Bityutskiy <dedekind1@gmail.com>
Acked-by: Detlev Zundel <dzu@denx.de>
CC: Scott Wood <scottwood@freescale.com>

[1] http://www.linux-mtd.infradead.org/doc/ubi.html#L_flasher_algo

---

Scott,

I did not add your Acked-by because to handle the possible unaligned
input length I opted to return min() instead of dropping the alignment
fixup entire as had been agreed upon in correspondence. I found in
testing that removing the alignment resulted in corruption of the NAND.

This behaviour was found to fix both UBI and JFFS2 images written to
cleanly erased NAND partitions on da850evm.

Changes since v3:
 * rebased onto nand-flash/next
 * remove uneccessary cast (Scott Wood)
 * added Detlev's Acked-by
 * prevent access past end of buffer using min() (Scott Wood)
Changes since v2:
 * moved the copyright header addition of nand_util to this patch from
   patch 'cmd_nand: add nand write.trimffs command'
 * Did not add Detlev's Acked-by because of movement of copyright header
Changes since v1:
 * rebased to HEAD of git://git.denx.de/u-boot-nand-flash.git : ff7b4a0
   ("env_nand: zero-initialize variable nand_erase_options")
 * wrap the new functionality in a CONFIG_CMD_NAND_TRIMFFS ifdef to
   reduce size impact of new feature

---
 drivers/mtd/nand/nand_util.c |   40 +++++++++++++++++++++++++++++++++++++---
 include/nand.h               |    1 +
 2 files changed, 38 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index e4ef858..81bf366 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -11,6 +11,9 @@ 
  *		nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com)
  *			       and Thomas Gleixner (tglx@linutronix.de)
  *
+ * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by
+ * Artem Bityutskiy <dedekind1@gmail.com> from mtd-utils
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -436,6 +439,29 @@  static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length)
 	return ret;
 }
 
+#ifdef CONFIG_CMD_NAND_TRIMFFS
+static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
+			const size_t *len)
+{
+	size_t i, l = *len;
+
+	for (i = l - 1; i >= 0; i--)
+		if (buf[i] != 0xFF)
+			break;
+
+	/* The resulting length must be aligned to the minimum flash I/O size */
+	l = i + 1;
+	l = (l + nand->writesize - 1) / nand->writesize;
+	l *=  nand->writesize;
+
+	/*
+	 * since the input length may be unaligned, prevent access past the end
+	 * of the buffer
+	 */
+	return min(l, *len);
+}
+#endif
+
 /**
  * nand_write_skip_bad:
  *
@@ -502,7 +528,7 @@  int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 		return -EINVAL;
 	}
 
-	if (!need_skip) {
+	if (!need_skip && !(flags & WITH_DROP_FFS)) {
 		rval = nand_write (nand, offset, length, buffer);
 		if (rval == 0)
 			return 0;
@@ -515,7 +541,7 @@  int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 
 	while (left_to_write > 0) {
 		size_t block_offset = offset & (nand->erasesize - 1);
-		size_t write_size;
+		size_t write_size, truncated_write_size;
 
 		WATCHDOG_RESET ();
 
@@ -561,7 +587,15 @@  int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 		else
 #endif
 		{
-			rval = nand_write (nand, offset, &write_size, p_buffer);
+			truncated_write_size = write_size;
+#ifdef CONFIG_CMD_NAND_TRIMFFS
+			if (flags & WITH_DROP_FFS)
+				truncated_write_size = drop_ffs(nand, p_buffer,
+						&write_size);
+#endif
+
+			rval = nand_write(nand, offset, &truncated_write_size,
+					p_buffer);
 			offset += write_size;
 			p_buffer += write_size;
 		}
diff --git a/include/nand.h b/include/nand.h
index c5818f1..8d94b5c 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -118,6 +118,7 @@  int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 #define WITH_YAFFS_OOB	(1 << 0) /* whether write with yaffs format. This flag
 				  * is a 'mode' meaning it cannot be mixed with
 				  * other flags */
+#define WITH_DROP_FFS	(1 << 1) /* drop trailing all-0xff pages */
 
 int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 			u_char *buffer, int flags);