diff options
author | Cyril Bur <cyril.bur@au1.ibm.com> | 2015-03-12 17:42:06 +1100 |
---|---|---|
committer | Stewart Smith <stewart@linux.vnet.ibm.com> | 2015-03-17 17:58:03 +1100 |
commit | 672f26aeae18352e1fe8e4c7030cf1e338188487 (patch) | |
tree | a6f4cd3262216e7f2744e164bfa685cc48a87eb6 /libflash/libflash.c | |
parent | 5e10de0c32edc997407ef1911946f700e30ffd5e (diff) | |
download | skiboot-672f26aeae18352e1fe8e4c7030cf1e338188487.zip skiboot-672f26aeae18352e1fe8e4c7030cf1e338188487.tar.gz skiboot-672f26aeae18352e1fe8e4c7030cf1e338188487.tar.bz2 |
libflash: Improved ECC interface
This patch is twofold.
1. Improves the low level ecc memcpy code to better
specify that we're reading/writing buffers with ecc bytes.
2. Improves/creates the libflash interfaces for ecc.
This patch also includes some tests
Signed-off-by: Cyril Bur <cyril.bur@au1.ibm.com>
Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'libflash/libflash.c')
-rw-r--r-- | libflash/libflash.c | 76 |
1 files changed, 74 insertions, 2 deletions
diff --git a/libflash/libflash.c b/libflash/libflash.c index 2886fc7..a229668 100644 --- a/libflash/libflash.c +++ b/libflash/libflash.c @@ -139,7 +139,7 @@ int flash_read(struct flash_chip *c, uint32_t pos, void *buf, uint32_t len) int flash_read_corrected(struct flash_chip *c, uint32_t pos, void *buf, uint32_t len, bool ecc) { - uint64_t *bufecc; + struct ecc64 *bufecc; uint32_t copylen; int rc; uint8_t ret; @@ -162,7 +162,7 @@ int flash_read_corrected(struct flash_chip *c, uint32_t pos, void *buf, goto err; /* Extract data from ECCed data */ - ret = eccmemcpy(buf, bufecc, copylen); + ret = memcpy_from_ecc(buf, bufecc, copylen); if (ret == UE) { rc = FLASH_ERR_ECC_INVALID; goto err; @@ -180,6 +180,7 @@ err: free(bufecc); return rc; } + static void fl_get_best_erase(struct flash_chip *c, uint32_t dst, uint32_t size, uint32_t *chunk, uint8_t *cmd) { @@ -384,6 +385,51 @@ int flash_write(struct flash_chip *c, uint32_t dst, const void *src, return 0; } +int flash_write_corrected(struct flash_chip *c, uint32_t pos, const void *buf, + uint32_t len, bool verify, bool ecc) +{ + struct ecc64 *bufecc; + uint32_t copylen; + int rc; + uint8_t ret; + + if (!ecc) + return flash_write(c, pos, buf, len, verify); + + /* 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); + + /* Add the ecc byte to the data */ + ret = memcpy_to_ecc(bufecc, buf, BUFFER_SIZE_MINUS_ECC(copylen)); + if (ret == UE) { + rc = FLASH_ERR_ECC_INVALID; + goto err; + } + + /* Write ECCed data to the flash */ + rc = flash_write(c, pos, bufecc, copylen, verify); + if (rc) + goto err; + + /* Update for next copy */ + len -= BUFFER_SIZE_MINUS_ECC(copylen); + buf = (uint8_t *)buf + BUFFER_SIZE_MINUS_ECC(copylen); + pos += copylen; + } + + rc = 0; + +err: + free(bufecc); + return rc; +} + enum sm_comp_res { sm_no_change, sm_need_write, @@ -491,6 +537,32 @@ int flash_smart_write(struct flash_chip *c, uint32_t dst, const void *src, return 0; } +int flash_smart_write_corrected(struct flash_chip *c, uint32_t dst, const void *src, + uint32_t size, bool ecc) +{ + struct ecc64 *buf; + int rc; + + if (!ecc) + return flash_smart_write(c, dst, src, size); + + buf = malloc(ECC_BUFFER_SIZE(size)); + if (!buf) + return FLASH_ERR_MALLOC_FAILED; + + rc = memcpy_to_ecc(buf, src, size); + if (rc != GD) { + rc = FLASH_ERR_ECC_INVALID; + goto out; + } + + rc = flash_smart_write(c, dst, buf, ECC_BUFFER_SIZE(size)); + +out: + free(buf); + return rc; +} + static int fl_chip_id(struct spi_flash_ctrl *ct, uint8_t *id_buf, uint32_t *id_size) { |