[Skiboot] [RFC PATCH 2/3] libflash: add ecc write code
Cyril Bur
cyrilbur at gmail.com
Thu Mar 5 20:39:24 AEDT 2015
From: Cyril Bur <cyril.bur at au1.ibm.com>
This adds an eccmemcpy to go from non ecc buffer to a buffer containing ecc
bytes. This also creates the libflash interfaces.
Signed-off-by: Cyril Bur <cyril.bur at au1.ibm.com>
---
libflash/ecc.c | 39 +++++++++++++++++++++++++++
libflash/ecc.h | 2 ++
libflash/libflash.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++
libflash/libflash.h | 4 +++
4 files changed, 121 insertions(+)
diff --git a/libflash/ecc.c b/libflash/ecc.c
index f8fcb9f..cfb7ad3 100644
--- a/libflash/ecc.c
+++ b/libflash/ecc.c
@@ -178,3 +178,42 @@ uint8_t memcpy_from_ecc(uint64_t *dst, struct ecc64 *src, uint32_t len)
}
return GD;
}
+
+/**
+ * Copy data from an input buffer without ECC to an output buffer with ECC.
+ *
+ * @dst: destination buffer with ECC
+ * @src: source buffer without ECC
+ * @len: number of bytes of data to copy (without ecc, length of src).
+ * Note: dst must be big enough to hold ecc bytes as well.
+ Must be 8 byte aligned.
+ *
+ * @return: eccBitfield.
+ *
+ * @retval GD - Success.
+ * @retval UE - Length is not 8 byte aligned.
+ */
+uint8_t memcpy_to_ecc(struct ecc64 *dst, const uint64_t *src, uint32_t len)
+{
+ struct ecc64 ecc_word;
+ uint32_t i;
+
+ if (len & 0x7) {
+ /* TODO: we could problably handle this */
+ FL_ERR("Data to add ECC bytes to must be 8 byte aligned length: %i\n",
+ len);
+ return UE;
+ }
+
+ /* Handle in chunks of 8 bytes, so adjust the length */
+ len >>= 3;
+
+ for (i = 0; i < len; i++) {
+ ecc_word.ecc = eccgenerate(be64_to_cpu(*(src + i)));
+ ecc_word.data = *(src + i);
+
+ *(dst + i) = ecc_word;
+ }
+
+ return GD;
+}
diff --git a/libflash/ecc.h b/libflash/ecc.h
index 62eec54..d58ec3e 100644
--- a/libflash/ecc.h
+++ b/libflash/ecc.h
@@ -44,6 +44,8 @@ struct ecc64 {
extern uint8_t memcpy_from_ecc(uint64_t *dst, struct ecc64 *src, uint32_t len);
+extern uint8_t memcpy_to_ecc(struct ecc64 *dst, const uint64_t *src, uint32_t len);
+
/*
* Calculate the size of a buffer if ECC is added
*
diff --git a/libflash/libflash.c b/libflash/libflash.c
index c2a1c69..cae62ec 100644
--- a/libflash/libflash.c
+++ b/libflash/libflash.c
@@ -180,6 +180,56 @@ err:
free(bufecc);
return rc;
}
+
+/*
+ * This provides a wrapper around flash_write on ECCed data
+ * len is length of data without ECC attached
+ */
+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;
+}
+
static void fl_get_best_erase(struct flash_chip *c, uint32_t dst, uint32_t size,
uint32_t *chunk, uint8_t *cmd)
{
@@ -491,6 +541,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)
{
diff --git a/libflash/libflash.h b/libflash/libflash.h
index c7d7040..51584da 100644
--- a/libflash/libflash.h
+++ b/libflash/libflash.h
@@ -76,8 +76,12 @@ int flash_read_corrected(struct flash_chip *c, uint32_t pos, void *buf,
int flash_erase(struct flash_chip *c, uint32_t dst, uint32_t size);
int flash_write(struct flash_chip *c, uint32_t dst, const void *src,
uint32_t size, bool verify);
+int flash_write_corrected(struct flash_chip *c, uint32_t dst, const void *src,
+ uint32_t size, bool verify, bool ecc);
int flash_smart_write(struct flash_chip *c, uint32_t dst, const void *src,
uint32_t size);
+int flash_smart_write_corrected(struct flash_chip *c, uint32_t dst, const void *src,
+ uint32_t size, bool ecc);
/* chip erase may not be supported by all chips/controllers, get ready
* for FLASH_ERR_CHIP_ER_NOT_SUPPORTED
--
1.9.1
More information about the Skiboot
mailing list