From 89aaa5dc801c05e1d11141fa7d0789b072bde655 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=98yvind=20Harboe?= <oyvind.harboe@zylin.com>
Date: Tue, 14 Dec 2010 20:24:10 +0100
Subject: [PATCH] flash_erase: wip to add NOR skip erased block option

---
 flash_erase.c |   53 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 52 insertions(+), 1 deletions(-)

diff --git a/flash_erase.c b/flash_erase.c
index 1a7b52e..1000397 100644
--- a/flash_erase.c
+++ b/flash_erase.c
@@ -46,6 +46,7 @@ static int quiet;		/* true -- don't output progress */
 static int jffs2;		/* format for jffs2 usage */
 static int noskipbad;		/* do not skip bad blocks */
 static int unlock;		/* unlock sectors before erasing */
+static int skip_erased;		/* Skip erased NOR flash blocks, including cleanmarker check */
 
 static struct jffs2_unknown_node cleanmarker;
 int target_endian = __BYTE_ORDER;
@@ -68,6 +69,7 @@ static void display_help (void)
 			"  -N, --noskipbad   don't skip bad blocks\n"
 			"  -u, --unlock      unlock sectors before erasing\n"
 			"  -q, --quiet       display progress messages\n"
+			"  -s, --skip-erased skip erased NOR sectors\n"
 			"      --silent      same as --quiet\n"
 			"      --help        display this help and exit\n"
 			"      --version     output version information and exit\n",
@@ -104,7 +106,7 @@ int main(int argc, char *argv[])
 	 */
 	for (;;) {
 		int option_index = 0;
-		static const char *short_options = "jNqu";
+		static const char *short_options = "sjNqu";
 		static const struct option long_options[] = {
 			{"help", no_argument, 0, 0},
 			{"version", no_argument, 0, 0},
@@ -113,6 +115,7 @@ int main(int argc, char *argv[])
 			{"quiet", no_argument, 0, 'q'},
 			{"silent", no_argument, 0, 'q'},
 			{"unlock", no_argument, 0, 'u'},
+			{"skip-erased", no_argument, 0, 's'},
 
 			{0, 0, 0, 0},
 		};
@@ -145,6 +148,9 @@ int main(int argc, char *argv[])
 		case 'u':
 			unlock = 1;
 			break;
+		case 's':
+			skip_erased = 1;
+			break;
 		case '?':
 			error = 1;
 			break;
@@ -250,8 +256,53 @@ int main(int argc, char *argv[])
 			}
 		}
 
+		/* Can we skip this one if it is already erased?
+		 * Perhaps NAND performance could be improved by adding support for
+		 * those cleanmarkers as well?
+		 *
+		 * Currently this only works with JFFS2 NOR clean markers
+		 */
+		int skip = 0;
+		if (skip_erased && !isNAND) {
+			uint8_t *tmp = malloc(mtd.eb_size);
+			if (tmp == NULL) {
+			  return errmsg("Out of memory");
+			}
+			ssize_t actual = pread(fd, tmp, mtd.eb_size, offset);
+			if (actual != mtd.eb_size) {
+			  return errmsg("%s: MTD read failure: %s", mtd_device, strerror(errno));
+			}
+			ssize_t i = 0;
+			int ok = 1;
+
+			if (jffs2) {
+				ok = memcmp(tmp, &cleanmarker, sizeof (cleanmarker)) == 0;
+				i = sizeof (cleanmarker);
+			}
+
+			if (ok)
+			{
+				for (; i < mtd.eb_size; i++)
+				{
+					if (tmp[i] != 0xff)
+						break;
+				}
+				if (i == mtd.eb_size)
+				{
+					/* Yup! we can skip! Here we could improve things by
+					 * adding support for NAND cleanmarkers
+					 */
+					skip = 1;
+				}
+			}
+			free(tmp);
+		}
+
 		show_progress(&mtd, offset, eb, eb_start, eb_cnt);
 
+		if (skip)
+			continue;
+
 		if (unlock) {
 			if (mtd_unlock(&mtd, fd, eb) != 0) {
 				sys_errmsg("%s: MTD unlock failure", mtd_device);
-- 
1.7.0.4
