mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 19:11:53 +00:00
nand: Extend nand_(read|write)_skip_bad with *actual and limit parameters
We make these two functions take a size_t pointer to how much space was used on NAND to read or write the buffer (when reads/writes happen) so that bad blocks can be accounted for. We also make them take an loff_t limit on how much data can be read or written. This means that we can now catch the case of when writing to a partition would exceed the partition size due to bad blocks. To do this we also need to make check_skip_len count not just complete blocks used but partial ones as well. All callers of nand_(read|write)_skip_bad are adjusted to call these with the most sensible limits available. The changes were started by Pantelis and finished by Tom. Signed-off-by: Pantelis Antoniou <panto@antoniou-consulting.com> Signed-off-by: Tom Rini <trini@ti.com>
This commit is contained in:
parent
a24c3155db
commit
c39d6a0ea5
5 changed files with 97 additions and 33 deletions
|
@ -416,11 +416,13 @@ int nand_unlock(struct mtd_info *mtd, loff_t start, size_t length,
|
|||
* @param nand NAND device
|
||||
* @param offset offset in flash
|
||||
* @param length image length
|
||||
* @param used length of flash needed for the requested length
|
||||
* @return 0 if the image fits and there are no bad blocks
|
||||
* 1 if the image fits, but there are bad blocks
|
||||
* -1 if the image does not fit
|
||||
*/
|
||||
static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length)
|
||||
static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length,
|
||||
size_t *used)
|
||||
{
|
||||
size_t len_excl_bad = 0;
|
||||
int ret = 0;
|
||||
|
@ -442,8 +444,13 @@ static int check_skip_len(nand_info_t *nand, loff_t offset, size_t length)
|
|||
ret = 1;
|
||||
|
||||
offset += block_len;
|
||||
*used += block_len;
|
||||
}
|
||||
|
||||
/* If the length is not a multiple of block_len, adjust. */
|
||||
if (len_excl_bad > length)
|
||||
*used -= (len_excl_bad - length);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -476,23 +483,36 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
|
|||
* Write image to NAND flash.
|
||||
* Blocks that are marked bad are skipped and the is written to the next
|
||||
* block instead as long as the image is short enough to fit even after
|
||||
* skipping the bad blocks.
|
||||
* skipping the bad blocks. Due to bad blocks we may not be able to
|
||||
* perform the requested write. In the case where the write would
|
||||
* extend beyond the end of the NAND device, both length and actual (if
|
||||
* not NULL) are set to 0. In the case where the write would extend
|
||||
* beyond the limit we are passed, length is set to 0 and actual is set
|
||||
* to the required length.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param offset offset in flash
|
||||
* @param length buffer length
|
||||
* @param actual set to size required to write length worth of
|
||||
* buffer or 0 on error, if not NULL
|
||||
* @param lim maximum size that actual may be in order to not
|
||||
* exceed the buffer
|
||||
* @param buffer buffer to read from
|
||||
* @param flags flags modifying the behaviour of the write to NAND
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
u_char *buffer, int flags)
|
||||
size_t *actual, loff_t lim, u_char *buffer, int flags)
|
||||
{
|
||||
int rval = 0, blocksize;
|
||||
size_t left_to_write = *length;
|
||||
size_t used_for_write = 0;
|
||||
u_char *p_buffer = buffer;
|
||||
int need_skip;
|
||||
|
||||
if (actual)
|
||||
*actual = 0;
|
||||
|
||||
#ifdef CONFIG_CMD_NAND_YAFFS
|
||||
if (flags & WITH_YAFFS_OOB) {
|
||||
if (flags & ~WITH_YAFFS_OOB)
|
||||
|
@ -529,13 +549,23 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
need_skip = check_skip_len(nand, offset, *length);
|
||||
need_skip = check_skip_len(nand, offset, *length, &used_for_write);
|
||||
|
||||
if (actual)
|
||||
*actual = used_for_write;
|
||||
|
||||
if (need_skip < 0) {
|
||||
printf("Attempt to write outside the flash area\n");
|
||||
*length = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (used_for_write > lim) {
|
||||
puts("Size of write exceeds partition or device limit\n");
|
||||
*length = 0;
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
if (!need_skip && !(flags & WITH_DROP_FFS)) {
|
||||
rval = nand_write(nand, offset, length, buffer);
|
||||
if (rval == 0)
|
||||
|
@ -626,36 +656,58 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
|||
*
|
||||
* Read image from NAND flash.
|
||||
* Blocks that are marked bad are skipped and the next block is read
|
||||
* instead as long as the image is short enough to fit even after skipping the
|
||||
* bad blocks.
|
||||
* instead as long as the image is short enough to fit even after
|
||||
* skipping the bad blocks. Due to bad blocks we may not be able to
|
||||
* perform the requested read. In the case where the read would extend
|
||||
* beyond the end of the NAND device, both length and actual (if not
|
||||
* NULL) are set to 0. In the case where the read would extend beyond
|
||||
* the limit we are passed, length is set to 0 and actual is set to the
|
||||
* required length.
|
||||
*
|
||||
* @param nand NAND device
|
||||
* @param offset offset in flash
|
||||
* @param length buffer length, on return holds number of read bytes
|
||||
* @param actual set to size required to read length worth of buffer or 0
|
||||
* on error, if not NULL
|
||||
* @param lim maximum size that actual may be in order to not exceed the
|
||||
* buffer
|
||||
* @param buffer buffer to write to
|
||||
* @return 0 in case of success
|
||||
*/
|
||||
int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||
u_char *buffer)
|
||||
size_t *actual, loff_t lim, u_char *buffer)
|
||||
{
|
||||
int rval;
|
||||
size_t left_to_read = *length;
|
||||
size_t used_for_read = 0;
|
||||
u_char *p_buffer = buffer;
|
||||
int need_skip;
|
||||
|
||||
if ((offset & (nand->writesize - 1)) != 0) {
|
||||
printf("Attempt to read non page-aligned data\n");
|
||||
*length = 0;
|
||||
if (actual)
|
||||
*actual = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
need_skip = check_skip_len(nand, offset, *length);
|
||||
need_skip = check_skip_len(nand, offset, *length, &used_for_read);
|
||||
|
||||
if (actual)
|
||||
*actual = used_for_read;
|
||||
|
||||
if (need_skip < 0) {
|
||||
printf("Attempt to read outside the flash area\n");
|
||||
*length = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (used_for_read > lim) {
|
||||
puts("Size of read exceeds partition or device limit\n");
|
||||
*length = 0;
|
||||
return -EFBIG;
|
||||
}
|
||||
|
||||
if (!need_skip) {
|
||||
rval = nand_read(nand, offset, length, buffer);
|
||||
if (!rval || rval == -EUCLEAN)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue