1 // SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
2 /*
3 * This is based on the hostboot ecc code
4 *
5 * Copyright 2013-2018 IBM Corp.
6 */
7
8 #ifndef __ECC_H
9 #define __ECC_H
10
11 #include <stdint.h>
12 #include <ccan/endian/endian.h>
13
14 struct ecc64 {
15 beint64_t data;
16 uint8_t ecc;
17 } __attribute__((__packed__));
18
19 extern int memcpy_from_ecc(beint64_t *dst, struct ecc64 *src, uint64_t len);
20 extern int memcpy_from_ecc_unaligned(beint64_t *dst, struct ecc64 *src, uint64_t len,
21 uint8_t alignment);
22
23 extern int memcpy_to_ecc(struct ecc64 *dst, const beint64_t *src, uint64_t len);
24 extern int memcpy_to_ecc_unaligned(struct ecc64 *dst, const beint64_t *src, uint64_t len,
25 uint8_t alignment);
26
27 /*
28 * Calculate the size of a buffer if ECC is added
29 *
30 * We add 1 byte of ecc for every 8 bytes of data. So we need to round up to 8
31 * bytes length and then add 1/8
32 */
33 #ifndef ALIGN_UP
34 #define ALIGN_UP(_v, _a) (((_v) + (_a) - 1) & ~((_a) - 1))
35 #endif
36
37 #define BYTES_PER_ECC 8
38
ecc_size(uint64_t len)39 static inline uint64_t ecc_size(uint64_t len)
40 {
41 return ALIGN_UP(len, BYTES_PER_ECC) >> 3;
42 }
43
ecc_buffer_size(uint64_t len)44 static inline uint64_t ecc_buffer_size(uint64_t len)
45 {
46 return ALIGN_UP(len, BYTES_PER_ECC) + ecc_size(len);
47 }
48
ecc_buffer_size_check(uint64_t len)49 static inline int ecc_buffer_size_check(uint64_t len)
50 {
51 return len % (BYTES_PER_ECC + 1);
52 }
53
ecc_buffer_size_minus_ecc(uint64_t len)54 static inline uint64_t ecc_buffer_size_minus_ecc(uint64_t len)
55 {
56 return len * BYTES_PER_ECC / (BYTES_PER_ECC + 1);
57 }
58
ecc_buffer_align(uint64_t start,uint64_t pos)59 static inline uint64_t ecc_buffer_align(uint64_t start, uint64_t pos)
60 {
61 return pos - ((pos - start) % (BYTES_PER_ECC + 1));
62 }
63
64 #endif
65