[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