[U-Boot] [PATCH] [nand] Implement nand_extent_skip_bad

Pantelis Antoniou panto at antoniou-consulting.com
Mon Dec 10 16:24:24 CET 2012


When accessing nand any bad blocks encountered are skipped, with no
indication about the amount of bad blocks encountered.
While this is normally fine, when you have to write a large amount
of data in chunks, you need to account for the skipped amount due
to the presence of the bad blocks.

nand_extend_skip_bad() returns the offset where the next access
should occur.

Signed-off-by: Pantelis Antoniou <panto at antoniou-consulting.com>
---
 drivers/mtd/nand/nand_util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 include/nand.h               |  2 ++
 2 files changed, 52 insertions(+)

diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c
index 2ba0c5e..a25a4cb 100644
--- a/drivers/mtd/nand/nand_util.c
+++ b/drivers/mtd/nand/nand_util.c
@@ -684,6 +684,56 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
 	return 0;
 }
 
+/**
+ * nand_extent_skip_bad:
+ *
+ * Find the extent of a chunk, return the offset where it ends
+ * Blocks that are marked bad are skipped and the next block is examined
+ * instead as long as the extend is short enough to fit even after skipping the
+ * bad blocks.
+ *
+ * @param nand NAND device
+ * @param offset offset in flash
+ * @param length extend length
+ * @return next offset in case of success (loff_t)-1 on error
+ */
+loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length)
+{
+	size_t block_len, block_off;
+	loff_t block_start;
+
+	if ((offset & (nand->writesize - 1)) != 0) {
+		printf ("%s: Attempt to check extend non page aligned data\n",
+				__func__);
+		return (loff_t)-1;
+	}
+
+	while (length > 0) {
+
+		if (offset >= nand->size) {
+			printf("%s: offset >= nand->size (%llx >= %llx)\n",
+					__func__, offset, nand->size);
+			return (loff_t)-1;
+		}
+
+		block_start = offset & ~(loff_t)(nand->erasesize - 1);
+		block_off = offset & (nand->erasesize - 1);
+		block_len = nand->erasesize - block_off;
+		if (block_len > length)		/* left over */
+			block_len = length;
+
+		if (!nand_block_isbad(nand, block_start))
+			length -= block_len;
+		else
+			debug("%s: bad block at %llx (left %x)\n",
+					__func__, block_start, length);
+
+		offset += block_len;
+	}
+
+	return offset;
+}
+
 #ifdef CONFIG_CMD_NAND_TORTURE
 
 /**
diff --git a/include/nand.h b/include/nand.h
index dded4e2..710c11a 100644
--- a/include/nand.h
+++ b/include/nand.h
@@ -168,3 +168,5 @@ __attribute__((noreturn)) void nand_boot(void);
 #define ENV_OFFSET_SIZE 8
 int get_nand_env_oob(nand_info_t *nand, unsigned long *result);
 #endif
+
+loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length);
-- 
1.7.12



More information about the U-Boot mailing list