Skip to contentSkip to conversation

Implement nand_extent_skip_bad

PATCH New Pantelis Antoniou 2 participants 5 messages Dec 10, 2012 – Dec 11, 2012

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Implement nand_extent_skip_bad

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.

---
 drivers/mtd/nand/nand_util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
 include/nand.h               |  2 ++
 2 files changed, 52 insertions(+)
drivers/mtd/nand/nand_util.c +50 -0
index 2ba0c5e..a25a4cb 100644
@@ -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
 
 /**
include/nand.h +2 -0
index dded4e2..710c11a 100644
@@ -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);
Signature · 1 line
1.7.12
#1 lore raw

PATCH 1/1 Implement nand_extent_skip_bad

Quoted 8 lines · Pantelis Antoniou

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.

s/extend/extent/

Quoted 25 lines
---
 drivers/mtd/nand/nand_util.c | 50  
++++++++++++++++++++++++++++++++++++++++++++
 include/nand.h               |  2 ++
 2 files changed, 52 insertions(+)
drivers/mtd/nand/nand_util.c +5 -0
index 2ba0c5e..a25a4cb 100644
@@ -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

Quoted 8 lines

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

Would it be better to return this information from existing read/write functions -- either instead of or in addition to exporting this functionality?

Quoted 29 lines

+loff_t nand_extent_skip_bad(nand_info_t *nand, loff_t offset, size_t length)

drivers/mtd/nand/nand_util.c +6 -0
+{
+	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",

drivers/mtd/nand/nand_util.c +8 -0
+				__func__);
+		return (loff_t)-1;
+	}
+
+	while (length > 0) {
+
+		if (offset >= nand->size) {
+			printf("%s: offset >= nand->size (%llx >=  

%llx)\n",

drivers/mtd/nand/nand_util.c +11 -0
+					__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))

drivers/mtd/nand/nand_util.c int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, · line 735

Quoted 10 lines
drivers/mtd/nand/nand_util.c +10 -0
+			length -= block_len;
+		else
+			debug("%s: bad block at %llx (left %x)\n",
+					__func__, block_start, length);
+
+		offset += block_len;
+	}
+
+	return offset;
+}

This seems duplicative of check_skip_len().

-Scott

#2 lore raw

PATCH 1/1 Implement nand_extent_skip_bad

Hi Scott,

Quoted 11 lines · Scott Wood
Quoted 7 lines · Pantelis Antoniou

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.

s/extend/extent/

Yeah.

Quoted 19 lines
Quoted 19 lines

---
drivers/mtd/nand/nand_util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++
include/nand.h | 2 ++

2 files changed, 52 insertions(+)
drivers/mtd/nand/nand_util.c +7 -0
index 2ba0c5e..a25a4cb 100644
@@ -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.
Quoted 9 lines

drivers/mtd/nand/nand_util.c int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, · line 699

Quoted 6 lines
drivers/mtd/nand/nand_util.c +6 -0
+ *
+ * @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
+ */

Would it be better to return this information from existing read/write functions -- either instead of or in addition to exporting this functionality?

Yes it would. However that would require modifying all callers, which would be a hard sell when there's only one user of it.

Quoted 30 lines
Quoted 30 lines
drivers/mtd/nand/nand_util.c +30 -0
+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);
Quoted 9 lines

drivers/mtd/nand/nand_util.c int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, · line 735

Quoted 6 lines
drivers/mtd/nand/nand_util.c +6 -0
+
+		offset += block_len;
+	}
+
+	return offset;
+}

This seems duplicative of check_skip_len().

It is. check_skip_len doesn't return the information I need. I could modify check_skip_len with an extra parameter if that's going to be OK with you.

Quoted 1 line

-Scott

Regards

-- Pantelis

#3 lore raw

PATCH 1/1 Implement nand_extent_skip_bad

Quoted 20 lines · Pantelis Antoniou

Hi Scott,

Quoted 5 lines · Scott Wood
Quoted 5 lines

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

Quoted 1 line
Quoted 1 line

+ * instead as long as the extend is short enough to fit even

after skipping the

Quoted 8 lines
Quoted 7 lines

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

Quoted 7 lines
Quoted 1 line

Would it be better to return this information from existing

read/write functions -- either instead of or in addition to exporting this functionality?

Quoted 1 line

Yes it would. However that would require modifying all callers, which would be a hard sell when there's only one user of it.

There aren't that many callers, and it's all common code (so no issue with testing on obscure hardware).

Quoted 6 lines
Quoted 2 lines

This seems duplicative of check_skip_len().

It is. check_skip_len doesn't return the information I need. I could modify check_skip_len with
an extra parameter if that's going to be OK with you.

Yes, please modify check_skip_len() instead.

-Scott

#4 lore raw

PATCH 1/1 Implement nand_extent_skip_bad

Hi Scott,

Quoted 23 lines · Scott Wood
Quoted 16 lines · Pantelis Antoniou

Hi Scott,

Quoted 14 lines · Scott Wood
Quoted 13 lines

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

Quoted 3 lines
Quoted 2 lines

Would it be better to return this information from existing read/write functions -- either instead of or in addition to exporting this functionality?

Yes it would. However that would require modifying all callers, which would be a hard sell when there's only one user of it.

There aren't that many callers, and it's all common code (so no issue with testing on obscure hardware).

Quoted 8 lines
Quoted 4 lines
Quoted 2 lines

This seems duplicative of check_skip_len().

It is. check_skip_len doesn't return the information I need. I could modify check_skip_len with an extra parameter if that's going to be OK with you.

Yes, please modify check_skip_len() instead.

-Scott

Nice, hope I'll get around doing it today or tomorrow.

Regards

-- Pantelis