mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-22 12:54:37 +00:00
nand: Add verification functions
Add nand_verify() and nand_verify_page_oob(). nand_verify() verifies NAND contents against an arbitrarily sized buffer using ECC while nand_verify_page_oob() verifies a NAND page's contents and OOB. Signed-off-by: Peter Tyser <ptyser@xes-inc.com> Tested-by: Heiko Schocher <hs@denx.de> Acked-by: Heiko Schocher <hs@denx.de>
This commit is contained in:
parent
800772a1a6
commit
59b5a2ad83
2 changed files with 100 additions and 1 deletions
|
@ -463,6 +463,87 @@ static size_t drop_ffs(const nand_info_t *nand, const u_char *buf,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nand_verify_page_oob:
|
||||||
|
*
|
||||||
|
* Verify a page of NAND flash, including the OOB.
|
||||||
|
* Reads page of NAND and verifies the contents and OOB against the
|
||||||
|
* values in ops.
|
||||||
|
*
|
||||||
|
* @param nand NAND device
|
||||||
|
* @param ops MTD operations, including data to verify
|
||||||
|
* @param ofs offset in flash
|
||||||
|
* @return 0 in case of success
|
||||||
|
*/
|
||||||
|
int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops, loff_t ofs)
|
||||||
|
{
|
||||||
|
int rval;
|
||||||
|
struct mtd_oob_ops vops;
|
||||||
|
size_t verlen = nand->writesize + nand->oobsize;
|
||||||
|
|
||||||
|
memcpy(&vops, ops, sizeof(vops));
|
||||||
|
|
||||||
|
vops.datbuf = malloc(verlen);
|
||||||
|
|
||||||
|
if (!vops.datbuf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
vops.oobbuf = vops.datbuf + nand->writesize;
|
||||||
|
|
||||||
|
rval = mtd_read_oob(nand, ofs, &vops);
|
||||||
|
if (!rval)
|
||||||
|
rval = memcmp(ops->datbuf, vops.datbuf, vops.len);
|
||||||
|
if (!rval)
|
||||||
|
rval = memcmp(ops->oobbuf, vops.oobbuf, vops.ooblen);
|
||||||
|
|
||||||
|
free(vops.datbuf);
|
||||||
|
|
||||||
|
return rval ? -EIO : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nand_verify:
|
||||||
|
*
|
||||||
|
* Verify a region of NAND flash.
|
||||||
|
* Reads NAND in page-sized chunks and verifies the contents against
|
||||||
|
* the contents of a buffer. The offset into the NAND must be
|
||||||
|
* page-aligned, and the function doesn't handle skipping bad blocks.
|
||||||
|
*
|
||||||
|
* @param nand NAND device
|
||||||
|
* @param ofs offset in flash
|
||||||
|
* @param len buffer length
|
||||||
|
* @param buf buffer to read from
|
||||||
|
* @return 0 in case of success
|
||||||
|
*/
|
||||||
|
int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf)
|
||||||
|
{
|
||||||
|
int rval = 0;
|
||||||
|
size_t verofs;
|
||||||
|
size_t verlen = nand->writesize;
|
||||||
|
uint8_t *verbuf = malloc(verlen);
|
||||||
|
|
||||||
|
if (!verbuf)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* Read the NAND back in page-size groups to limit malloc size */
|
||||||
|
for (verofs = ofs; verofs < ofs + len;
|
||||||
|
verofs += verlen, buf += verlen) {
|
||||||
|
verlen = min(nand->writesize, (uint32_t)(ofs + len - verofs));
|
||||||
|
rval = nand_read(nand, verofs, &verlen, verbuf);
|
||||||
|
if (!rval || (rval == -EUCLEAN))
|
||||||
|
rval = memcmp(buf, verbuf, verlen);
|
||||||
|
|
||||||
|
if (rval)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(verbuf);
|
||||||
|
|
||||||
|
return rval ? -EIO : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nand_write_skip_bad:
|
* nand_write_skip_bad:
|
||||||
*
|
*
|
||||||
|
@ -501,7 +582,7 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
|
|
||||||
#ifdef CONFIG_CMD_NAND_YAFFS
|
#ifdef CONFIG_CMD_NAND_YAFFS
|
||||||
if (flags & WITH_YAFFS_OOB) {
|
if (flags & WITH_YAFFS_OOB) {
|
||||||
if (flags & ~WITH_YAFFS_OOB)
|
if (flags & (~WITH_YAFFS_OOB & ~WITH_WR_VERIFY))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
int pages;
|
int pages;
|
||||||
|
@ -554,6 +635,10 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
|
|
||||||
if (!need_skip && !(flags & WITH_DROP_FFS)) {
|
if (!need_skip && !(flags & WITH_DROP_FFS)) {
|
||||||
rval = nand_write(nand, offset, length, buffer);
|
rval = nand_write(nand, offset, length, buffer);
|
||||||
|
|
||||||
|
if ((flags & WITH_WR_VERIFY) && !rval)
|
||||||
|
rval = nand_verify(nand, offset, *length, buffer);
|
||||||
|
|
||||||
if (rval == 0)
|
if (rval == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
@ -601,6 +686,11 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
ops.oobbuf = ops.datbuf + pagesize;
|
ops.oobbuf = ops.datbuf + pagesize;
|
||||||
|
|
||||||
rval = mtd_write_oob(nand, offset, &ops);
|
rval = mtd_write_oob(nand, offset, &ops);
|
||||||
|
|
||||||
|
if ((flags & WITH_WR_VERIFY) && !rval)
|
||||||
|
rval = nand_verify_page_oob(nand,
|
||||||
|
&ops, offset);
|
||||||
|
|
||||||
if (rval != 0)
|
if (rval != 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -620,6 +710,11 @@ int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
|
|
||||||
rval = nand_write(nand, offset, &truncated_write_size,
|
rval = nand_write(nand, offset, &truncated_write_size,
|
||||||
p_buffer);
|
p_buffer);
|
||||||
|
|
||||||
|
if ((flags & WITH_WR_VERIFY) && !rval)
|
||||||
|
rval = nand_verify(nand, offset,
|
||||||
|
truncated_write_size, p_buffer);
|
||||||
|
|
||||||
offset += write_size;
|
offset += write_size;
|
||||||
p_buffer += write_size;
|
p_buffer += write_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,11 +108,15 @@ int nand_read_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
* is a 'mode' meaning it cannot be mixed with
|
* is a 'mode' meaning it cannot be mixed with
|
||||||
* other flags */
|
* other flags */
|
||||||
#define WITH_DROP_FFS (1 << 1) /* drop trailing all-0xff pages */
|
#define WITH_DROP_FFS (1 << 1) /* drop trailing all-0xff pages */
|
||||||
|
#define WITH_WR_VERIFY (1 << 2) /* verify data was written correctly */
|
||||||
|
|
||||||
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
int nand_write_skip_bad(nand_info_t *nand, loff_t offset, size_t *length,
|
||||||
size_t *actual, loff_t lim, u_char *buffer, int flags);
|
size_t *actual, loff_t lim, u_char *buffer, int flags);
|
||||||
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
|
int nand_erase_opts(nand_info_t *meminfo, const nand_erase_options_t *opts);
|
||||||
int nand_torture(nand_info_t *nand, loff_t offset);
|
int nand_torture(nand_info_t *nand, loff_t offset);
|
||||||
|
int nand_verify_page_oob(nand_info_t *nand, struct mtd_oob_ops *ops,
|
||||||
|
loff_t ofs);
|
||||||
|
int nand_verify(nand_info_t *nand, loff_t ofs, size_t len, u_char *buf);
|
||||||
|
|
||||||
#define NAND_LOCK_STATUS_TIGHT 0x01
|
#define NAND_LOCK_STATUS_TIGHT 0x01
|
||||||
#define NAND_LOCK_STATUS_UNLOCK 0x04
|
#define NAND_LOCK_STATUS_UNLOCK 0x04
|
||||||
|
|
Loading…
Add table
Reference in a new issue