[PATCH 1/1] mtd-utils: flash_erase: Add flash erase chip

Larisa Ileana Grigore larisa.grigore at nxp.com
Fri Apr 23 16:07:04 BST 2021


Some flash types support full erase chip command which can reduce the
flash erase time. Try first to erase the entire flash and fall back
to the old method if the operation fails.

Signed-off-by: Larisa Ileana Grigore <larisa.grigore at nxp.com>
---
 include/libmtd.h         | 15 +++++++
 lib/libmtd.c             | 26 ++++++++---
 misc-utils/flash_erase.c | 95 ++++++++++++++++++++++++++++++----------
 3 files changed, 106 insertions(+), 30 deletions(-)

diff --git a/include/libmtd.h b/include/libmtd.h
index cc24af8..6ab0de5 100644
--- a/include/libmtd.h
+++ b/include/libmtd.h
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2008, 2009 Nokia Corporation
+ * Copyright 2021 NXP
  *
  * 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
@@ -174,6 +175,20 @@ int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb);
  */
 int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb);
 
+/**
+ * mtd_unlock_multi - unlock eraseblocks.
+ * @desc: MTD library descriptor
+ * @mtd: MTD device description object
+ * @fd: MTD device node file descriptor
+ * @eb: index of first eraseblock to unlock
+ * @blocks: the number of eraseblocks to unlock
+ *
+ * This function unlocks @blocks starting at eraseblock @eb.
+ * Returns %0 in case of success and %-1 in case of failure.
+ */
+int mtd_unlock_multi(const struct mtd_dev_info *mtd, int fd, int eb,
+		     int blocks);
+
 /**
  * mtd_erase - erase multiple eraseblocks.
  * @desc: MTD library descriptor
diff --git a/lib/libmtd.c b/lib/libmtd.c
index 9d8d0e8..c1022cf 100644
--- a/lib/libmtd.c
+++ b/lib/libmtd.c
@@ -1,6 +1,7 @@
 /*
  * Copyright (c) International Business Machines Corp., 2006
  * Copyright (C) 2009 Nokia Corporation
+ * Copyright 2021 NXP
  *
  * 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
@@ -831,8 +832,8 @@ static int mtd_valid_erase_block(const struct mtd_dev_info *mtd, int eb)
 	return 0;
 }
 
-static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
-		     const char *sreq)
+static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb,
+		     int blocks, int req, const char *sreq)
 {
 	int ret;
 	struct erase_info_user ei;
@@ -841,8 +842,14 @@ static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
 	if (ret)
 		return ret;
 
+	if (blocks > 1) {
+		ret = mtd_valid_erase_block(mtd, eb + blocks - 1);
+		if (ret)
+			return ret;
+	}
+
 	ei.start = eb * mtd->eb_size;
-	ei.length = mtd->eb_size;
+	ei.length = mtd->eb_size * blocks;
 
 	ret = ioctl(fd, req, &ei);
 	if (ret < 0)
@@ -850,16 +857,23 @@ static int mtd_xlock(const struct mtd_dev_info *mtd, int fd, int eb, int req,
 
 	return 0;
 }
-#define mtd_xlock(mtd, fd, eb, req) mtd_xlock(mtd, fd, eb, req, #req)
+#define mtd_xlock(mtd, fd, eb, blocks, req) \
+	mtd_xlock(mtd, fd, eb, blocks, req, #req)
 
 int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb)
 {
-	return mtd_xlock(mtd, fd, eb, MEMLOCK);
+	return mtd_xlock(mtd, fd, eb, 1, MEMLOCK);
 }
 
 int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb)
 {
-	return mtd_xlock(mtd, fd, eb, MEMUNLOCK);
+	return mtd_xlock(mtd, fd, eb, 1, MEMUNLOCK);
+}
+
+int mtd_unlock_multi(const struct mtd_dev_info *mtd, int fd, int eb,
+		     int blocks)
+{
+	return mtd_xlock(mtd, fd, eb, blocks, MEMUNLOCK);
 }
 
 int mtd_erase_multi(libmtd_t desc, const struct mtd_dev_info *mtd,
diff --git a/misc-utils/flash_erase.c b/misc-utils/flash_erase.c
index a7fc6a6..49a880f 100644
--- a/misc-utils/flash_erase.c
+++ b/misc-utils/flash_erase.c
@@ -2,6 +2,7 @@
 
    Copyright (C) 2000 Arcom Control System Ltd
    Copyright (C) 2010 Mike Frysinger <vapier at gentoo.org>
+   Copyright 2021 NXP
 
    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
@@ -50,11 +51,10 @@ static int unlock;		/* unlock sectors before erasing */
 static struct jffs2_unknown_node cleanmarker;
 int target_endian = __BYTE_ORDER;
 
-static void show_progress(struct mtd_dev_info *mtd, off_t start, int eb,
-			  int eb_start, int eb_cnt)
+static void show_progress(off_t start, int eb, int eb_start, int eb_cnt, int step)
 {
 	bareverbose(!quiet, "\rErasing %d Kibyte @ %llx -- %2i %% complete ",
-		mtd->eb_size / 1024, (unsigned long long)start, ((eb - eb_start) * 100) / eb_cnt);
+		step / 1024, (unsigned long long)start, ((eb - eb_start) * 100) / eb_cnt);
 	fflush(stdout);
 }
 
@@ -88,6 +88,27 @@ static void display_version (void)
 			PROGRAM_NAME);
 }
 
+static void clear_marker(libmtd_t mtd_desc, struct mtd_dev_info *mtd, int fd,
+			 unsigned int eb, int cmlen, bool isNAND)
+{
+	off_t offset = (off_t)eb * mtd->eb_size;
+
+	/* write cleanmarker */
+	if (isNAND) {
+		if (mtd_write(mtd_desc, mtd, fd, eb, 0, NULL, 0, &cleanmarker, cmlen,
+				MTD_OPS_AUTO_OOB) != 0) {
+			sys_errmsg("%s: MTD writeoob failure", mtd_device);
+			return;
+		}
+	} else {
+		if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) {
+			sys_errmsg("%s: MTD write failure", mtd_device);
+			return;
+		}
+	}
+	verbose(!quiet, "%llx : Cleanmarker Updated.", (unsigned long long)offset);
+}
+
 int main(int argc, char *argv[])
 {
 	libmtd_t mtd_desc;
@@ -95,7 +116,7 @@ int main(int argc, char *argv[])
 	int fd, cmlen = 8;
 	unsigned long long start;
 	unsigned int eb, eb_start, eb_cnt;
-	bool isNAND;
+	bool isNAND, erase_chip = false;
 	int error = 0;
 	off_t offset = 0;
 
@@ -205,6 +226,47 @@ int main(int argc, char *argv[])
 	if (eb_cnt == 0)
 		eb_cnt = (mtd.size / mtd.eb_size) - eb_start;
 
+	if (eb_start == 0 && mtd.size == eb_cnt * mtd.eb_size)
+		erase_chip = true;
+
+	/* If MTD device may have bad eraseblocks,
+	 * erase one by one each sector
+	 */
+	if (noskipbad && mtd.bb_allowed)
+		erase_chip = false;
+
+	if (erase_chip) {
+		show_progress(0, eb_start, eb_start, eb_cnt, mtd.size);
+
+		if (unlock) {
+			if (mtd_unlock_multi(&mtd, fd, eb_start, eb_cnt) != 0) {
+				sys_errmsg("%s: MTD unlock entire chip failure." \
+					   "Trying one by one each sector.",
+					    mtd_device);
+				goto erase_each_sector;
+			}
+		}
+
+		if (mtd_erase_multi(mtd_desc, &mtd, fd, eb_start, eb_cnt) != 0) {
+			sys_errmsg("%s: MTD Erase entire chip failure" \
+				    "Trying one by one each sector.",
+				    mtd_device);
+			goto erase_each_sector;
+		}
+
+		show_progress(0, eb_start + eb_cnt, eb_start,
+			      eb_cnt, mtd.size);
+
+		if (!jffs2)
+			goto out;
+
+		/* write cleanmarker */
+		for (eb = eb_start; eb < eb_start + eb_cnt; eb++)
+			clear_marker(mtd_desc, &mtd, fd, eb, cmlen, isNAND);
+		goto out;
+	}
+
+erase_each_sector:
 	for (eb = eb_start; eb < eb_start + eb_cnt; eb++) {
 		offset = (off_t)eb * mtd.eb_size;
 
@@ -223,7 +285,7 @@ int main(int argc, char *argv[])
 			}
 		}
 
-		show_progress(&mtd, offset, eb, eb_start, eb_cnt);
+		show_progress(offset, eb, eb_start, eb_cnt, mtd.eb_size);
 
 		if (unlock) {
 			if (mtd_unlock(&mtd, fd, eb) != 0) {
@@ -237,26 +299,11 @@ int main(int argc, char *argv[])
 			continue;
 		}
 
-		/* format for JFFS2 ? */
-		if (!jffs2)
-			continue;
-
-		/* write cleanmarker */
-		if (isNAND) {
-			if (mtd_write(mtd_desc, &mtd, fd, eb, 0, NULL, 0, &cleanmarker, cmlen,
-					MTD_OPS_AUTO_OOB) != 0) {
-				sys_errmsg("%s: MTD writeoob failure", mtd_device);
-				continue;
-			}
-		} else {
-			if (pwrite(fd, &cleanmarker, sizeof(cleanmarker), (loff_t)offset) != sizeof(cleanmarker)) {
-				sys_errmsg("%s: MTD write failure", mtd_device);
-				continue;
-			}
-		}
-		verbose(!quiet, " Cleanmarker Updated.");
+		if (jffs2)
+			clear_marker(mtd_desc, &mtd, fd, eb, cmlen, isNAND);
 	}
-	show_progress(&mtd, offset, eb, eb_start, eb_cnt);
+	show_progress(offset, eb, eb_start, eb_cnt, mtd.eb_size);
+out:
 	bareverbose(!quiet, "\n");
 
 	return 0;
-- 
2.17.1




More information about the linux-mtd mailing list