aboutsummaryrefslogtreecommitdiff
path: root/libflash
diff options
context:
space:
mode:
authorMichael Neuling <mikey@neuling.org>2015-02-20 11:37:53 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-02-23 13:35:48 +1100
commit3e13d4c9dbf4f45f70348509d666f5db19546787 (patch)
treefa60aada576a10b4e734351d894e11b46b61d933 /libflash
parent8f22127ec50e6fa946f09af1e610b38555f11edd (diff)
downloadskiboot-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>
Diffstat (limited to 'libflash')
-rw-r--r--libflash/libffs.c52
-rw-r--r--libflash/libffs.h4
-rw-r--r--libflash/libflash.h1
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;