Branch data Line data Source code
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-2019 IBM Corp.
6 : : */
7 : :
8 : : #include <stdint.h>
9 : : #include <inttypes.h>
10 : : #include <string.h>
11 : :
12 : : #include <ccan/endian/endian.h>
13 : :
14 : : #include "libflash.h"
15 : : #include "ecc.h"
16 : :
17 : : /* Bit field identifiers for syndrome calculations. */
18 : : enum eccbitfields
19 : : {
20 : : GD = 0xff, //< Good, ECC matches.
21 : : UE = 0xfe, //< Uncorrectable.
22 : : E0 = 71, //< Error in ECC bit 0
23 : : E1 = 70, //< Error in ECC bit 1
24 : : E2 = 69, //< Error in ECC bit 2
25 : : E3 = 68, //< Error in ECC bit 3
26 : : E4 = 67, //< Error in ECC bit 4
27 : : E5 = 66, //< Error in ECC bit 5
28 : : E6 = 65, //< Error in ECC bit 6
29 : : E7 = 64 //< Error in ECC bit 7
30 : : /* 0-63 Correctable bit in byte */
31 : : };
32 : :
33 : : /*
34 : : * Matrix used for ECC calculation.
35 : : *
36 : : * Each row of this is the set of data word bits that are used for
37 : : * the calculation of the corresponding ECC bit. The parity of the
38 : : * bitset is the value of the ECC bit.
39 : : *
40 : : * ie. ECC[n] = eccMatrix[n] & data
41 : : *
42 : : * Note: To make the math easier (and less shifts in resulting code),
43 : : * row0 = ECC7. HW numbering is MSB, order here is LSB.
44 : : *
45 : : * These values come from the HW design of the ECC algorithm.
46 : : */
47 : : static uint64_t eccmatrix[] = {
48 : : 0x0000e8423c0f99ffull,
49 : : 0x00e8423c0f99ff00ull,
50 : : 0xe8423c0f99ff0000ull,
51 : : 0x423c0f99ff0000e8ull,
52 : : 0x3c0f99ff0000e842ull,
53 : : 0x0f99ff0000e8423cull,
54 : : 0x99ff0000e8423c0full,
55 : : 0xff0000e8423c0f99ull
56 : : };
57 : :
58 : : /**
59 : : * Syndrome calculation matrix.
60 : : *
61 : : * Maps syndrome to flipped bit.
62 : : *
63 : : * To perform ECC correction, this matrix is a look-up of the bit
64 : : * that is bad based on the binary difference of the good and bad
65 : : * ECC. This difference is called the "syndrome".
66 : : *
67 : : * When a particular bit is on in the data, it cause a column from
68 : : * eccMatrix being XOR'd into the ECC field. This column is the
69 : : * "effect" of each bit. If a bit is flipped in the data then its
70 : : * "effect" is missing from the ECC. You can calculate ECC on unknown
71 : : * quality data and compare the ECC field between the calculated
72 : : * value and the stored value. If the difference is zero, then the
73 : : * data is clean. If the difference is non-zero, you look up the
74 : : * difference in the syndrome table to identify the "effect" that
75 : : * is missing, which is the bit that is flipped.
76 : : *
77 : : * Notice that ECC bit flips are recorded by a single "effect"
78 : : * bit (ie. 0x1, 0x2, 0x4, 0x8 ...) and double bit flips are identified
79 : : * by the UE status in the table.
80 : : *
81 : : * Bits are in MSB order.
82 : : */
83 : : static enum eccbitfields syndromematrix[] = {
84 : : GD, E7, E6, UE, E5, UE, UE, 47, E4, UE, UE, 37, UE, 35, 39, UE,
85 : : E3, UE, UE, 48, UE, 30, 29, UE, UE, 57, 27, UE, 31, UE, UE, UE,
86 : : E2, UE, UE, 17, UE, 18, 40, UE, UE, 58, 22, UE, 21, UE, UE, UE,
87 : : UE, 16, 49, UE, 19, UE, UE, UE, 23, UE, UE, UE, UE, 20, UE, UE,
88 : : E1, UE, UE, 51, UE, 46, 9, UE, UE, 34, 10, UE, 32, UE, UE, 36,
89 : : UE, 62, 50, UE, 14, UE, UE, UE, 13, UE, UE, UE, UE, UE, UE, UE,
90 : : UE, 61, 8, UE, 41, UE, UE, UE, 11, UE, UE, UE, UE, UE, UE, UE,
91 : : 15, UE, UE, UE, UE, UE, UE, UE, UE, UE, 12, UE, UE, UE, UE, UE,
92 : : E0, UE, UE, 55, UE, 45, 43, UE, UE, 56, 38, UE, 1, UE, UE, UE,
93 : : UE, 25, 26, UE, 2, UE, UE, UE, 24, UE, UE, UE, UE, UE, 28, UE,
94 : : UE, 59, 54, UE, 42, UE, UE, 44, 6, UE, UE, UE, UE, UE, UE, UE,
95 : : 5, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE,
96 : : UE, 63, 53, UE, 0, UE, UE, UE, 33, UE, UE, UE, UE, UE, UE, UE,
97 : : 3, UE, UE, 52, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE,
98 : : 7, UE, UE, UE, UE, UE, UE, UE, UE, 60, UE, UE, UE, UE, UE, UE,
99 : : UE, UE, UE, UE, 4, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE, UE,
100 : : };
101 : :
102 : : /**
103 : : * Create the ECC field corresponding to a 8-byte data field
104 : : *
105 : : * @data: The 8 byte data to generate ECC for.
106 : : * @return: The 1 byte ECC corresponding to the data.
107 : : */
108 : 0 : static uint8_t eccgenerate(uint64_t data)
109 : : {
110 : 0 : int i;
111 : 0 : uint8_t result = 0;
112 : :
113 : 0 : for (i = 0; i < 8; i++)
114 : 0 : result |= __builtin_parityll(eccmatrix[i] & data) << i;
115 : :
116 : 0 : return result;
117 : : }
118 : :
119 : : /**
120 : : * Verify the data and ECC match or indicate how they are wrong.
121 : : *
122 : : * @data: The data to check ECC on.
123 : : * @ecc: The [supposed] ECC for the data.
124 : : *
125 : : * @return: eccBitfield or 0-64.
126 : : *
127 : : * @retval GD - Indicates the data is good (matches ECC).
128 : : * @retval UE - Indicates the data is uncorrectable.
129 : : * @retval all others - Indication of which bit is incorrect.
130 : : */
131 : 0 : static enum eccbitfields eccverify(uint64_t data, uint8_t ecc)
132 : : {
133 : 0 : return syndromematrix[eccgenerate(data) ^ ecc];
134 : : }
135 : :
136 : : /* IBM bit ordering */
137 : 0 : static inline uint64_t eccflipbit(uint64_t data, uint8_t bit)
138 : : {
139 : 0 : if (bit > 63)
140 : : return data;
141 : :
142 : 0 : return data ^ (1ul << (63 - bit));
143 : : }
144 : :
145 : 0 : static int eccbyte(beint64_t *dst, struct ecc64 *src)
146 : : {
147 : 0 : uint8_t ecc, badbit;
148 : 0 : uint64_t data;
149 : :
150 : 0 : data = be64_to_cpu(src->data);
151 : 0 : ecc = src->ecc;
152 : :
153 : 0 : badbit = eccverify(data, ecc);
154 : 0 : if (badbit == UE) {
155 : 0 : FL_ERR("ECC: uncorrectable error: %016llx %02x\n", (unsigned long long int)data, ecc);
156 : 0 : return badbit;
157 : : }
158 : 0 : if (badbit <= UE)
159 : 0 : FL_INF("ECC: correctable error: %i\n", badbit);
160 : 0 : if (badbit < 64)
161 : 0 : *dst = cpu_to_be64(eccflipbit(data, badbit));
162 : : else
163 : 0 : *dst = cpu_to_be64(data);
164 : :
165 : : return 0;
166 : : }
167 : :
168 : 0 : static beint64_t *inc_beint64_by(const void *p, uint64_t i)
169 : : {
170 : 0 : return (beint64_t *)(((char *)p) + i);
171 : : }
172 : :
173 : 0 : static uint64_t *inc_uint64_by(const void *p, uint64_t i)
174 : : {
175 : 0 : return (uint64_t *)(((char *)p) + i);
176 : : }
177 : :
178 : 0 : static struct ecc64 *inc_ecc64_by(struct ecc64 *p, uint64_t i)
179 : : {
180 : 0 : return (struct ecc64 *)(((char *)p) + i);
181 : : }
182 : :
183 : 0 : static uint64_t whole_ecc_bytes(uint64_t i)
184 : : {
185 : 0 : return i & ~(BYTES_PER_ECC - 1);
186 : : }
187 : :
188 : : static uint64_t whole_ecc_structs(uint64_t i)
189 : : {
190 : 0 : return whole_ecc_bytes(i) >> 3;
191 : : }
192 : :
193 : : /**
194 : : * Copy data from an input buffer with ECC to an output buffer without ECC.
195 : : * Correct it along the way and check for errors.
196 : : *
197 : : * @dst: destination buffer without ECC
198 : : * @src: source buffer with ECC
199 : : * @len: number of bytes of data to copy (without ecc).
200 : : * Must be 8 byte aligned.
201 : : *
202 : : * @return: Success or error
203 : : *
204 : : * @retval: 0 - success
205 : : * @retfal: other - fail
206 : : */
207 : 0 : int memcpy_from_ecc(beint64_t *dst, struct ecc64 *src, uint64_t len)
208 : : {
209 : 0 : uint32_t i;
210 : :
211 : 0 : if (len & 0x7) {
212 : : /* TODO: we could probably handle this */
213 : 0 : FL_ERR("ECC data length must be 8 byte aligned length:%" PRIx64 "\n",
214 : : len);
215 : 0 : return -1;
216 : : }
217 : :
218 : : /* Handle in chunks of 8 bytes, so adjust the length */
219 : 0 : len >>= 3;
220 : :
221 : 0 : for (i = 0; i < len; i++) {
222 : 0 : int rc;
223 : 0 : rc = eccbyte(dst, src + i);
224 : 0 : if (rc)
225 : 0 : return rc;
226 : 0 : dst++;
227 : : }
228 : : return 0;
229 : : }
230 : :
231 : : /**
232 : : * Copy data from an input buffer with ECC to an output buffer without ECC.
233 : : * Correct it along the way and check for errors.
234 : : *
235 : : * Unlike memcmp_from_ecc() which requires that the first byte into
236 : : * dst be the first byte in src (which must also be aligned to a
237 : : * struct ecc64 struct boundary) this function can cope with the first
238 : : * byte in dst not being the first byte in src.
239 : : *
240 : : * Note: src MUST still be aligned to a struct ecc64 otherwise ECC
241 : : * calculations are impossible.
242 : : *
243 : : * The alignment parameter species the number of bytes present at the
244 : : * start of src that should be skipped and not written to dst. Once
245 : : * again, these bytes must be in src otherwise the ECC cannot be
246 : : * checked.
247 : : *
248 : : * len also doesn't have any value limitation for this function. Of
249 : : * course src must contain an exact multiple of struct ecc64 otherwise
250 : : * ECC calculation cannot be performed but this function won't copy
251 : : * the entirety of the last src data word if len is not mutiple of 8
252 : : *
253 : : * @dst: destination buffer without ECC
254 : : * @src: source buffer with ECC
255 : : * @len: number of bytes of data to copy (without ecc).
256 : : * @alignment: number of leading bytes in src which shouldn't be
257 : : * copied to dst
258 : : * @return: Success or error
259 : : *
260 : : * @retval: 0 - success
261 : : * @retfal: other - fail
262 : : */
263 : 0 : int memcpy_from_ecc_unaligned(beint64_t *dst, struct ecc64 *src,
264 : : uint64_t len, uint8_t alignment)
265 : : {
266 : 0 : char data[BYTES_PER_ECC];
267 : 0 : uint8_t bytes_wanted;
268 : 0 : int rc;
269 : :
270 : 0 : if (alignment > 8)
271 : : return -1;
272 : :
273 : 0 : bytes_wanted = BYTES_PER_ECC - alignment;
274 : :
275 : : /*
276 : : * Only actually do the first calculation if an alignment is
277 : : * required - otherwise jump straight to memcpy_from_ecc()
278 : : */
279 : 0 : if (alignment) {
280 : 0 : rc = eccbyte((beint64_t *)data, src);
281 : 0 : if (rc)
282 : : return rc;
283 : :
284 : 0 : memcpy(dst, &data[alignment], bytes_wanted);
285 : :
286 : 0 : src = inc_ecc64_by(src, sizeof(struct ecc64));
287 : 0 : dst = inc_beint64_by(dst, bytes_wanted);
288 : 0 : len -= bytes_wanted;
289 : : }
290 : :
291 : 0 : if (len >= BYTES_PER_ECC) {
292 : 0 : rc = memcpy_from_ecc(dst, src, whole_ecc_bytes(len));
293 : 0 : if (rc)
294 : : return rc;
295 : :
296 : : /*
297 : : * It helps to let the compiler to the pointer arithmetic
298 : : * here, (dst and src are different types)
299 : : */
300 : 0 : dst += whole_ecc_structs(len);
301 : 0 : src += whole_ecc_structs(len);
302 : 0 : len -= whole_ecc_bytes(len);
303 : : }
304 : :
305 : 0 : if (len) {
306 : 0 : rc = eccbyte((beint64_t *)data, src);
307 : 0 : if (rc)
308 : : return rc;
309 : :
310 : 0 : memcpy(dst, data, len);
311 : : }
312 : :
313 : : return 0;
314 : : }
315 : :
316 : : /**
317 : : * Copy data from an input buffer without ECC to an output buffer with ECC.
318 : : *
319 : : * @dst: destination buffer with ECC
320 : : * @src: source buffer without ECC
321 : : * @len: number of bytes of data to copy (without ecc, length of src).
322 : : * Note: dst must be big enough to hold ecc bytes as well.
323 : : * Must be 8 byte aligned.
324 : : *
325 : : * @return: success or failure
326 : : *
327 : : * @retval: 0 - success
328 : : * @retfal: other - fail
329 : : */
330 : 0 : int memcpy_to_ecc(struct ecc64 *dst, const beint64_t *src, uint64_t len)
331 : : {
332 : 0 : struct ecc64 ecc_word;
333 : 0 : uint64_t i;
334 : :
335 : 0 : if (len & 0x7) {
336 : : /* TODO: we could probably handle this */
337 : 0 : FL_ERR("Data to add ECC bytes to must be 8 byte aligned length: %"
338 : : PRIx64 "\n", len);
339 : 0 : return -1;
340 : : }
341 : :
342 : : /* Handle in chunks of 8 bytes, so adjust the length */
343 : 0 : len >>= 3;
344 : :
345 : 0 : for (i = 0; i < len; i++) {
346 : 0 : ecc_word.ecc = eccgenerate(be64_to_cpu(*(src + i)));
347 : 0 : ecc_word.data = *(src + i);
348 : :
349 : 0 : *(dst + i) = ecc_word;
350 : : }
351 : :
352 : : return 0;
353 : : }
354 : :
355 : : /**
356 : : * Copy data from an input buffer without ECC to an output buffer with ECC.
357 : : *
358 : : * Unlike memcmp_to_ecc() which requires that the first byte in src be
359 : : * the first byte of a struct ecc64 structure this function does not
360 : : * have this requirement.
361 : : *
362 : : * Like memcpy_to_ecc_unaligned() the alignment parameter specfies the
363 : : * number of bytes in the first src word that are missing and would be
364 : : * required to form a struct ecc64 structure.
365 : : *
366 : : * It must be noted here that extra work IN THE CALLER must be done
367 : : * if your data is unaligned. In order to peform ECC calculations
368 : : * whatever portions of the ecc words are missing in src must be in
369 : : * dst.
370 : : *
371 : : * For example, if there is an alignment value of 1 then this means
372 : : * there is 1 byte (of the total of 8 bytes) missing in src which is
373 : : * needed to calculate the first ECC byte. Therefore the first byte of
374 : : * dst MUST CONTAIN IT!
375 : : *
376 : : * The same problem exists for the end of the buffer where src may not
377 : : * end exactly aligned, if this is the case dst must contain the
378 : : * required bytes to calculate the last ECC byte - they should be in
379 : : * dst where they would normally be found if src did contain those
380 : : * bytes.
381 : : *
382 : : * @dst: destination buffer with ECC
383 : : * @src: source buffer without ECC
384 : : * @len: number of bytes of data to copy (without ecc, length of src).
385 : : * @alignment: The number of bytes 'missing' from the start of src to
386 : : * be struct ecc64 aligned
387 : : *
388 : : * Note: dst must be big enough to hold ecc bytes as well.
389 : : * Must be 8 byte aligned.
390 : : *
391 : : * @return: success or failure
392 : : *
393 : : * @retval: 0 - success
394 : : * @retfal: other - fail
395 : : */
396 : :
397 : 0 : int memcpy_to_ecc_unaligned(struct ecc64 *dst, const beint64_t *src,
398 : : uint64_t len, uint8_t alignment)
399 : : {
400 : 0 : struct ecc64 ecc_word;
401 : 0 : uint8_t bytes_wanted;
402 : 0 : int rc;
403 : :
404 : 0 : bytes_wanted = BYTES_PER_ECC - alignment;
405 : :
406 : : /*
407 : : * Only actually do the first calculation if an alignment is
408 : : * required - otherwise jump straight to memcpy_to_ecc()
409 : : */
410 : 0 : if (alignment) {
411 : 0 : ecc_word.data = dst->data;
412 : 0 : memcpy(inc_uint64_by(&ecc_word.data, alignment), src, bytes_wanted);
413 : :
414 : 0 : ecc_word.ecc = eccgenerate(be64_to_cpu(ecc_word.data));
415 : 0 : memcpy(dst, inc_ecc64_by(&ecc_word, alignment),
416 : : sizeof(struct ecc64) - alignment);
417 : :
418 : 0 : dst = inc_ecc64_by(dst, sizeof(struct ecc64) - alignment);
419 : 0 : src = inc_beint64_by(src, bytes_wanted);
420 : 0 : len -= bytes_wanted;
421 : : }
422 : :
423 : 0 : if (len >= BYTES_PER_ECC) {
424 : 0 : rc = memcpy_to_ecc(dst, src, whole_ecc_bytes(len));
425 : 0 : if (rc)
426 : : return rc;
427 : :
428 : : /*
429 : : * It helps to let the compiler to the pointer arithmetic
430 : : * here, (dst and src are different types)
431 : : */
432 : 0 : dst += whole_ecc_structs(len);
433 : 0 : src += whole_ecc_structs(len);
434 : 0 : len -= whole_ecc_bytes(len);
435 : : }
436 : :
437 : 0 : if (len) {
438 : 0 : bytes_wanted = BYTES_PER_ECC - len;
439 : :
440 : 0 : ecc_word.data = *src;
441 : 0 : memcpy(inc_uint64_by(&ecc_word.data, len), inc_ecc64_by(dst, len),
442 : : bytes_wanted);
443 : 0 : ecc_word.ecc = eccgenerate(be64_to_cpu(ecc_word.data));
444 : :
445 : 0 : *dst = ecc_word;
446 : : }
447 : :
448 : : return 0;
449 : : }
|