Implement nand_extent_skip_bad
Subsystems (2)
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
@@ -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
@@ -168,3 +168,5 @@ __attribute__((noreturn)) void nand_boot(void);#define ENV_OFFSET_SIZE 8int 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
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
Signed-off-by Pantelis Antoniou <[email protected]>--- drivers/mtd/nand/nand_util.c | 50 ++++++++++++++++++++++++++++++++++++++++++++ include/nand.h | 2 ++ 2 files changed, 52 insertions(+)drivers/mtd/nand/nand_util.c +5
-0@@ -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 aligneddata\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
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
Signed-off-by Pantelis Antoniou <[email protected]>---
drivers/mtd/nand/nand_util.c| 50 ++++++++++++++++++++++++++++++++++++++++++++include/nand.h| 2 ++2 files changed, 52 insertions(+)drivers/mtd/nand/nand_util.c +7
-0@@ -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
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 isexamined
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_lendoesn't return the information I need. I could modifycheck_skip_lenwith
an extra parameter if that's going to be OK with you.
Yes, please modify check_skip_len() instead.
-Scott
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_lendoesn't return the information I need. I could modifycheck_skip_lenwith 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