summaryrefslogtreecommitdiffstats
path: root/libflash/libflash.c
diff options
context:
space:
mode:
authorCyril Bur <cyril.bur@au1.ibm.com>2015-03-12 17:42:06 +1100
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-03-17 17:58:03 +1100
commit672f26aeae18352e1fe8e4c7030cf1e338188487 (patch)
treea6f4cd3262216e7f2744e164bfa685cc48a87eb6 /libflash/libflash.c
parent5e10de0c32edc997407ef1911946f700e30ffd5e (diff)
downloadblackbird-skiboot-672f26aeae18352e1fe8e4c7030cf1e338188487.tar.gz
blackbird-skiboot-672f26aeae18352e1fe8e4c7030cf1e338188487.zip
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.c76
1 files changed, 74 insertions, 2 deletions
diff --git a/libflash/libflash.c b/libflash/libflash.c
index 2886fc75..a229668e 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)
{
OpenPOWER on IntegriCloud