aboutsummaryrefslogtreecommitdiff
path: root/libflash/ecc.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/ecc.c
parent5e10de0c32edc997407ef1911946f700e30ffd5e (diff)
downloadskiboot-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/ecc.c')
-rw-r--r--libflash/ecc.c67
1 files changed, 57 insertions, 10 deletions
diff --git a/libflash/ecc.c b/libflash/ecc.c
index 61084cc..8ab1f31 100644
--- a/libflash/ecc.c
+++ b/libflash/ecc.c
@@ -126,6 +126,15 @@ static uint8_t eccverify(uint64_t data, uint8_t ecc)
return syndromematrix[eccgenerate(data) ^ ecc];
}
+/* IBM bit ordering */
+static inline uint64_t eccflipbit(uint64_t data, uint8_t bit)
+{
+ if (bit > 63)
+ return data;
+
+ return data ^ (1ul << (63 - bit));
+}
+
/**
* Copy data from an input buffer with ECC to an output buffer without ECC.
* Correct it along the way and check for errors.
@@ -141,10 +150,10 @@ static uint8_t eccverify(uint64_t data, uint8_t ecc)
* @retval UE - Data is uncorrectable.
* @retval all others - which bit was corrected.
*/
-uint8_t eccmemcpy(uint64_t *dst, uint64_t *src, uint32_t len)
+uint8_t memcpy_from_ecc(uint64_t *dst, struct ecc64 *src, uint32_t len)
{
- beint64_t *data;
- uint8_t *ecc;
+ beint64_t data;
+ uint8_t ecc;
uint32_t i;
uint8_t badbit;
@@ -159,22 +168,60 @@ uint8_t eccmemcpy(uint64_t *dst, uint64_t *src, uint32_t len)
len >>= 3;
for (i = 0; i < len; i++) {
- data = (beint64_t *)((uint8_t *)src + i * 9);
- ecc = (uint8_t *)data + 8;
+ data = (src + i)->data;
+ ecc = (src + i)->ecc;
- badbit = eccverify(be64_to_cpu(*data), *ecc);
+ badbit = eccverify(be64_to_cpu(data), ecc);
if (badbit == UE) {
FL_ERR("ECC: uncorrectable error: %016lx %02x\n",
- (long unsigned int)be64_to_cpu(*data), *ecc);
+ (long unsigned int)be64_to_cpu(data), ecc);
return badbit;
}
- *dst = *data;
+ *dst = data;
if (badbit <= UE)
FL_INF("ECC: correctable error: %i\n", badbit);
if (badbit < 64)
- *dst = (uint64_t)cpu_to_be64(be64_to_cpu(*data) ^
- (1ul << (63 - badbit)));
+ *dst = (uint64_t)be64_to_cpu(eccflipbit(be64_to_cpu(data), badbit));
dst++;
}
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;
+}