From 169d54d8b33b4d06d6f215e2b312a0b18f7909dc Mon Sep 17 00:00:00 2001 From: Ben Gardiner Date: Tue, 14 Jun 2011 16:35:06 -0400 Subject: nand_util: drop trailing all-0xff pages if requested Add a flag to nand_read_skip_bad() such that if true, any trailing pages in an eraseblock whose contents are entirely 0xff will be dropped. The implementation is via a new drop_ffs() function which is based on the function of the same name from the ubiformat utility by Artem Bityutskiy. This is as-per the reccomendations of the UBI FAQ [1] [1] http://www.linux-mtd.infradead.org/doc/ubi.html#L_flasher_algo Signed-off-by: Ben Gardiner CC: Artem Bityutskiy Acked-by: Detlev Zundel CC: Scott Wood Signed-off-by: Scott Wood --- drivers/mtd/nand/nand_util.c | 40 +++++++++++++++++++++++++++++++++++++--- include/nand.h | 1 + 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/drivers/mtd/nand/nand_util.c b/drivers/mtd/nand/nand_util.c index e4ef8588a7..81bf366159 100644 --- a/drivers/mtd/nand/nand_util.c +++ b/drivers/mtd/nand/nand_util.c @@ -11,6 +11,9 @@ * nandwrite.c by Steven J. Hill (sjhill@realitydiluted.com) * and Thomas Gleixner (tglx@linutronix.de) * + * Copyright (C) 2008 Nokia Corporation: drop_ffs() function by + * Artem Bityutskiy from mtd-utils + * * See file CREDITS for list of people who contributed to this * project. * @@ -436,6 +439,29 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length) return ret; } +#ifdef CONFIG_CMD_NAND_TRIMFFS +static size_t drop_ffs(const nand_info_t *nand, const u_char *buf, + const size_t *len) +{ + size_t i, l = *len; + + for (i = l - 1; i >= 0; i--) + if (buf[i] != 0xFF) + break; + + /* The resulting length must be aligned to the minimum flash I/O size */ + l = i + 1; + l = (l + nand->writesize - 1) / nand->writesize; + l *= nand->writesize; + + /* + * since the input length may be unaligned, prevent access past the end + * of the buffer + */ + return min(l, *len); +} +#endif + /** * nand_write_skip_bad: * @@ -502,7 +528,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, return -EINVAL; } - if (!need_skip) { + if (!need_skip && !(flags & WITH_DROP_FFS)) { rval = nand_write (nand, offset, length, buffer); if (rval == 0) return 0; @@ -515,7 +541,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, while (left_to_write > 0) { size_t block_offset = offset & (nand->erasesize - 1); - size_t write_size; + size_t write_size, truncated_write_size; WATCHDOG_RESET (); @@ -561,7 +587,15 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, else #endif { - rval = nand_write (nand, offset, &write_size, p_buffer); + truncated_write_size = write_size; +#ifdef CONFIG_CMD_NAND_TRIMFFS + if (flags & WITH_DROP_FFS) + truncated_write_size = drop_ffs(nand, p_buffer, + &write_size); +#endif + + rval = nand_write(nand, offset, &truncated_write_size, + p_buffer); offset += write_size; p_buffer += write_size; } diff --git a/include/nand.h b/include/nand.h index c5818f179d..8d94b5cbd7 100644 --- a/include/nand.h +++ b/include/nand.h @@ -118,6 +118,7 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, #define WITH_YAFFS_OOB (1 << 0) /* whether write with yaffs format. This flag * is a 'mode' meaning it cannot be mixed with * other flags */ +#define WITH_DROP_FFS (1 << 1) /* drop trailing all-0xff pages */ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length, u_char *buffer, int flags); -- cgit v1.2.3