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