diff options
author | Michael Neuling <mikey@neuling.org> | 2015-02-20 11:37:53 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-02-23 13:35:48 +1100 |
commit | 3e13d4c9dbf4f45f70348509d666f5db19546787 (patch) | |
tree | fa60aada576a10b4e734351d894e11b46b61d933 | |
parent | 8f22127ec50e6fa946f09af1e610b38555f11edd (diff) | |
download | skiboot-3e13d4c9dbf4f45f70348509d666f5db19546787.zip skiboot-3e13d4c9dbf4f45f70348509d666f5db19546787.tar.gz skiboot-3e13d4c9dbf4f45f70348509d666f5db19546787.tar.bz2 |
libffs: Add ffs_flash_read()
Add ffs_flash_read() which mimics flash_read() but handles ECC checking,
correction and uncorrectable errors.
Signed-off-by: Michael Neuling <mikey@neuling.org>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r-- | libflash/libffs.c | 52 | ||||
-rw-r--r-- | libflash/libffs.h | 4 | ||||
-rw-r--r-- | libflash/libflash.h | 1 |
3 files changed, 57 insertions, 0 deletions
diff --git a/libflash/libffs.c b/libflash/libffs.c index cfd5456..c28fd66 100644 --- a/libflash/libffs.c +++ b/libflash/libffs.c @@ -18,6 +18,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <ecc.h> #include <ccan/endian/endian.h> @@ -286,3 +287,54 @@ int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx, return 0; return flash_smart_write(ffs->chip, offset, ent, FFS_ENTRY_SIZE); } + +#define COPY_BUFFER_LENGTH 4096 + +/* + * This provides a wrapper around flash_read on ECCed data + * len is length of data without ECC attached + */ +int ffs_flash_read(struct flash_chip *c, uint32_t pos, void *buf, uint32_t len, + bool ecc) +{ + uint64_t *bufecc; + uint32_t copylen; + int rc; + uint8_t ret; + + if (!ecc) + return flash_read(c, pos, buf, len); + + /* Copy the buffer in chunks */ + bufecc = malloc(ECC_BUFFER_SIZE(COPY_BUFFER_LENGTH)); + if (!bufecc) + return FLASH_ERR_MALLOC_FAILED; + + while (len > 0) { + /* What's left to copy? */ + copylen = MIN(len, COPY_BUFFER_LENGTH); + + /* Read ECCed data from flash */ + rc = flash_read(c, pos, bufecc, ECC_BUFFER_SIZE(copylen)); + if (rc) + goto err; + + /* Extract data from ECCed data */ + ret = eccmemcpy(buf, bufecc, copylen); + if (ret == UE) { + rc = FLASH_ERR_ECC_INVALID; + goto err; + } + + /* Update for next copy */ + len -= copylen; + buf = (uint8_t *)buf + copylen; + pos += ECC_BUFFER_SIZE(copylen); + } + + return 0; + +err: + free(bufecc); + return rc; +} diff --git a/libflash/libffs.h b/libflash/libffs.h index 69e44bb..15ed3c5 100644 --- a/libflash/libffs.h +++ b/libflash/libffs.h @@ -32,6 +32,7 @@ struct ffs_handle; #define FFS_ERR_BAD_VERSION 101 #define FFS_ERR_BAD_CKSUM 102 #define FFS_ERR_PART_NOT_FOUND 103 +#define FFS_ERR_BAD_ECC 104 int ffs_open_flash(struct flash_chip *chip, uint32_t offset, uint32_t max_size, struct ffs_handle **ffs); @@ -52,5 +53,8 @@ int ffs_part_info(struct ffs_handle *ffs, uint32_t part_idx, int ffs_update_act_size(struct ffs_handle *ffs, uint32_t part_idx, uint32_t act_size); +int ffs_flash_read(struct flash_chip *c, uint32_t pos, void *buf, uint32_t len, + bool ecc); + #endif /* __LIBFFS_H */ diff --git a/libflash/libflash.h b/libflash/libflash.h index 31d3562..8e031dd 100644 --- a/libflash/libflash.h +++ b/libflash/libflash.h @@ -51,6 +51,7 @@ extern bool libflash_debug; #define FLASH_ERR_CHIP_ER_NOT_SUPPORTED 11 #define FLASH_ERR_CTRL_CMD_UNSUPPORTED 12 #define FLASH_ERR_CTRL_TIMEOUT 13 +#define FLASH_ERR_ECC_INVALID 14 /* Flash chip, opaque */ struct flash_chip; |