14c6de856SChristian Hitz /* 24c6de856SChristian Hitz * Generic binary BCH encoding/decoding library 34c6de856SChristian Hitz * 4*5b8031ccSTom Rini * SPDX-License-Identifier: GPL-2.0 54c6de856SChristian Hitz * 64c6de856SChristian Hitz * Copyright © 2011 Parrot S.A. 74c6de856SChristian Hitz * 84c6de856SChristian Hitz * Author: Ivan Djelic <ivan.djelic@parrot.com> 94c6de856SChristian Hitz * 104c6de856SChristian Hitz * Description: 114c6de856SChristian Hitz * 124c6de856SChristian Hitz * This library provides runtime configurable encoding/decoding of binary 134c6de856SChristian Hitz * Bose-Chaudhuri-Hocquenghem (BCH) codes. 144c6de856SChristian Hitz * 154c6de856SChristian Hitz * Call init_bch to get a pointer to a newly allocated bch_control structure for 164c6de856SChristian Hitz * the given m (Galois field order), t (error correction capability) and 174c6de856SChristian Hitz * (optional) primitive polynomial parameters. 184c6de856SChristian Hitz * 194c6de856SChristian Hitz * Call encode_bch to compute and store ecc parity bytes to a given buffer. 204c6de856SChristian Hitz * Call decode_bch to detect and locate errors in received data. 214c6de856SChristian Hitz * 224c6de856SChristian Hitz * On systems supporting hw BCH features, intermediate results may be provided 234c6de856SChristian Hitz * to decode_bch in order to skip certain steps. See decode_bch() documentation 244c6de856SChristian Hitz * for details. 254c6de856SChristian Hitz * 264c6de856SChristian Hitz * Option CONFIG_BCH_CONST_PARAMS can be used to force fixed values of 274c6de856SChristian Hitz * parameters m and t; thus allowing extra compiler optimizations and providing 284c6de856SChristian Hitz * better (up to 2x) encoding performance. Using this option makes sense when 294c6de856SChristian Hitz * (m,t) are fixed and known in advance, e.g. when using BCH error correction 304c6de856SChristian Hitz * on a particular NAND flash device. 314c6de856SChristian Hitz * 324c6de856SChristian Hitz * Algorithmic details: 334c6de856SChristian Hitz * 344c6de856SChristian Hitz * Encoding is performed by processing 32 input bits in parallel, using 4 354c6de856SChristian Hitz * remainder lookup tables. 364c6de856SChristian Hitz * 374c6de856SChristian Hitz * The final stage of decoding involves the following internal steps: 384c6de856SChristian Hitz * a. Syndrome computation 394c6de856SChristian Hitz * b. Error locator polynomial computation using Berlekamp-Massey algorithm 404c6de856SChristian Hitz * c. Error locator root finding (by far the most expensive step) 414c6de856SChristian Hitz * 424c6de856SChristian Hitz * In this implementation, step c is not performed using the usual Chien search. 434c6de856SChristian Hitz * Instead, an alternative approach described in [1] is used. It consists in 444c6de856SChristian Hitz * factoring the error locator polynomial using the Berlekamp Trace algorithm 454c6de856SChristian Hitz * (BTA) down to a certain degree (4), after which ad hoc low-degree polynomial 464c6de856SChristian Hitz * solving techniques [2] are used. The resulting algorithm, called BTZ, yields 474c6de856SChristian Hitz * much better performance than Chien search for usual (m,t) values (typically 484c6de856SChristian Hitz * m >= 13, t < 32, see [1]). 494c6de856SChristian Hitz * 504c6de856SChristian Hitz * [1] B. Biswas, V. Herbert. Efficient root finding of polynomials over fields 514c6de856SChristian Hitz * of characteristic 2, in: Western European Workshop on Research in Cryptology 524c6de856SChristian Hitz * - WEWoRC 2009, Graz, Austria, LNCS, Springer, July 2009, to appear. 534c6de856SChristian Hitz * [2] [Zin96] V.A. Zinoviev. On the solution of equations of degree 10 over 544c6de856SChristian Hitz * finite fields GF(2^q). In Rapport de recherche INRIA no 2829, 1996. 554c6de856SChristian Hitz */ 564c6de856SChristian Hitz 574c6de856SChristian Hitz #include <common.h> 584c6de856SChristian Hitz #include <ubi_uboot.h> 594c6de856SChristian Hitz 604c6de856SChristian Hitz #include <linux/bitops.h> 614c6de856SChristian Hitz #include <asm/byteorder.h> 624c6de856SChristian Hitz #include <linux/bch.h> 634c6de856SChristian Hitz 644c6de856SChristian Hitz #if defined(CONFIG_BCH_CONST_PARAMS) 654c6de856SChristian Hitz #define GF_M(_p) (CONFIG_BCH_CONST_M) 664c6de856SChristian Hitz #define GF_T(_p) (CONFIG_BCH_CONST_T) 674c6de856SChristian Hitz #define GF_N(_p) ((1 << (CONFIG_BCH_CONST_M))-1) 684c6de856SChristian Hitz #else 694c6de856SChristian Hitz #define GF_M(_p) ((_p)->m) 704c6de856SChristian Hitz #define GF_T(_p) ((_p)->t) 714c6de856SChristian Hitz #define GF_N(_p) ((_p)->n) 724c6de856SChristian Hitz #endif 734c6de856SChristian Hitz 744c6de856SChristian Hitz #define BCH_ECC_WORDS(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 32) 754c6de856SChristian Hitz #define BCH_ECC_BYTES(_p) DIV_ROUND_UP(GF_M(_p)*GF_T(_p), 8) 764c6de856SChristian Hitz 774c6de856SChristian Hitz #ifndef dbg 784c6de856SChristian Hitz #define dbg(_fmt, args...) do {} while (0) 794c6de856SChristian Hitz #endif 804c6de856SChristian Hitz 814c6de856SChristian Hitz /* 824c6de856SChristian Hitz * represent a polynomial over GF(2^m) 834c6de856SChristian Hitz */ 844c6de856SChristian Hitz struct gf_poly { 854c6de856SChristian Hitz unsigned int deg; /* polynomial degree */ 864c6de856SChristian Hitz unsigned int c[0]; /* polynomial terms */ 874c6de856SChristian Hitz }; 884c6de856SChristian Hitz 894c6de856SChristian Hitz /* given its degree, compute a polynomial size in bytes */ 904c6de856SChristian Hitz #define GF_POLY_SZ(_d) (sizeof(struct gf_poly)+((_d)+1)*sizeof(unsigned int)) 914c6de856SChristian Hitz 924c6de856SChristian Hitz /* polynomial of degree 1 */ 934c6de856SChristian Hitz struct gf_poly_deg1 { 944c6de856SChristian Hitz struct gf_poly poly; 954c6de856SChristian Hitz unsigned int c[2]; 964c6de856SChristian Hitz }; 974c6de856SChristian Hitz 984c6de856SChristian Hitz /* 994c6de856SChristian Hitz * same as encode_bch(), but process input data one byte at a time 1004c6de856SChristian Hitz */ 1014c6de856SChristian Hitz static void encode_bch_unaligned(struct bch_control *bch, 1024c6de856SChristian Hitz const unsigned char *data, unsigned int len, 1034c6de856SChristian Hitz uint32_t *ecc) 1044c6de856SChristian Hitz { 1054c6de856SChristian Hitz int i; 1064c6de856SChristian Hitz const uint32_t *p; 1074c6de856SChristian Hitz const int l = BCH_ECC_WORDS(bch)-1; 1084c6de856SChristian Hitz 1094c6de856SChristian Hitz while (len--) { 1104c6de856SChristian Hitz p = bch->mod8_tab + (l+1)*(((ecc[0] >> 24)^(*data++)) & 0xff); 1114c6de856SChristian Hitz 1124c6de856SChristian Hitz for (i = 0; i < l; i++) 1134c6de856SChristian Hitz ecc[i] = ((ecc[i] << 8)|(ecc[i+1] >> 24))^(*p++); 1144c6de856SChristian Hitz 1154c6de856SChristian Hitz ecc[l] = (ecc[l] << 8)^(*p); 1164c6de856SChristian Hitz } 1174c6de856SChristian Hitz } 1184c6de856SChristian Hitz 1194c6de856SChristian Hitz /* 1204c6de856SChristian Hitz * convert ecc bytes to aligned, zero-padded 32-bit ecc words 1214c6de856SChristian Hitz */ 1224c6de856SChristian Hitz static void load_ecc8(struct bch_control *bch, uint32_t *dst, 1234c6de856SChristian Hitz const uint8_t *src) 1244c6de856SChristian Hitz { 1254c6de856SChristian Hitz uint8_t pad[4] = {0, 0, 0, 0}; 1264c6de856SChristian Hitz unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; 1274c6de856SChristian Hitz 1284c6de856SChristian Hitz for (i = 0; i < nwords; i++, src += 4) 1294c6de856SChristian Hitz dst[i] = (src[0] << 24)|(src[1] << 16)|(src[2] << 8)|src[3]; 1304c6de856SChristian Hitz 1314c6de856SChristian Hitz memcpy(pad, src, BCH_ECC_BYTES(bch)-4*nwords); 1324c6de856SChristian Hitz dst[nwords] = (pad[0] << 24)|(pad[1] << 16)|(pad[2] << 8)|pad[3]; 1334c6de856SChristian Hitz } 1344c6de856SChristian Hitz 1354c6de856SChristian Hitz /* 1364c6de856SChristian Hitz * convert 32-bit ecc words to ecc bytes 1374c6de856SChristian Hitz */ 1384c6de856SChristian Hitz static void store_ecc8(struct bch_control *bch, uint8_t *dst, 1394c6de856SChristian Hitz const uint32_t *src) 1404c6de856SChristian Hitz { 1414c6de856SChristian Hitz uint8_t pad[4]; 1424c6de856SChristian Hitz unsigned int i, nwords = BCH_ECC_WORDS(bch)-1; 1434c6de856SChristian Hitz 1444c6de856SChristian Hitz for (i = 0; i < nwords; i++) { 1454c6de856SChristian Hitz *dst++ = (src[i] >> 24); 1464c6de856SChristian Hitz *dst++ = (src[i] >> 16) & 0xff; 1474c6de856SChristian Hitz *dst++ = (src[i] >> 8) & 0xff; 1484c6de856SChristian Hitz *dst++ = (src[i] >> 0) & 0xff; 1494c6de856SChristian Hitz } 1504c6de856SChristian Hitz pad[0] = (src[nwords] >> 24); 1514c6de856SChristian Hitz pad[1] = (src[nwords] >> 16) & 0xff; 1524c6de856SChristian Hitz pad[2] = (src[nwords] >> 8) & 0xff; 1534c6de856SChristian Hitz pad[3] = (src[nwords] >> 0) & 0xff; 1544c6de856SChristian Hitz memcpy(dst, pad, BCH_ECC_BYTES(bch)-4*nwords); 1554c6de856SChristian Hitz } 1564c6de856SChristian Hitz 1574c6de856SChristian Hitz /** 1584c6de856SChristian Hitz * encode_bch - calculate BCH ecc parity of data 1594c6de856SChristian Hitz * @bch: BCH control structure 1604c6de856SChristian Hitz * @data: data to encode 1614c6de856SChristian Hitz * @len: data length in bytes 1624c6de856SChristian Hitz * @ecc: ecc parity data, must be initialized by caller 1634c6de856SChristian Hitz * 1644c6de856SChristian Hitz * The @ecc parity array is used both as input and output parameter, in order to 1654c6de856SChristian Hitz * allow incremental computations. It should be of the size indicated by member 1664c6de856SChristian Hitz * @ecc_bytes of @bch, and should be initialized to 0 before the first call. 1674c6de856SChristian Hitz * 1684c6de856SChristian Hitz * The exact number of computed ecc parity bits is given by member @ecc_bits of 1694c6de856SChristian Hitz * @bch; it may be less than m*t for large values of t. 1704c6de856SChristian Hitz */ 1714c6de856SChristian Hitz void encode_bch(struct bch_control *bch, const uint8_t *data, 1724c6de856SChristian Hitz unsigned int len, uint8_t *ecc) 1734c6de856SChristian Hitz { 1744c6de856SChristian Hitz const unsigned int l = BCH_ECC_WORDS(bch)-1; 1754c6de856SChristian Hitz unsigned int i, mlen; 1764c6de856SChristian Hitz unsigned long m; 1774c6de856SChristian Hitz uint32_t w, r[l+1]; 1784c6de856SChristian Hitz const uint32_t * const tab0 = bch->mod8_tab; 1794c6de856SChristian Hitz const uint32_t * const tab1 = tab0 + 256*(l+1); 1804c6de856SChristian Hitz const uint32_t * const tab2 = tab1 + 256*(l+1); 1814c6de856SChristian Hitz const uint32_t * const tab3 = tab2 + 256*(l+1); 1824c6de856SChristian Hitz const uint32_t *pdata, *p0, *p1, *p2, *p3; 1834c6de856SChristian Hitz 1844c6de856SChristian Hitz if (ecc) { 1854c6de856SChristian Hitz /* load ecc parity bytes into internal 32-bit buffer */ 1864c6de856SChristian Hitz load_ecc8(bch, bch->ecc_buf, ecc); 1874c6de856SChristian Hitz } else { 1884c6de856SChristian Hitz memset(bch->ecc_buf, 0, sizeof(r)); 1894c6de856SChristian Hitz } 1904c6de856SChristian Hitz 1914c6de856SChristian Hitz /* process first unaligned data bytes */ 1924c6de856SChristian Hitz m = ((unsigned long)data) & 3; 1934c6de856SChristian Hitz if (m) { 1944c6de856SChristian Hitz mlen = (len < (4-m)) ? len : 4-m; 1954c6de856SChristian Hitz encode_bch_unaligned(bch, data, mlen, bch->ecc_buf); 1964c6de856SChristian Hitz data += mlen; 1974c6de856SChristian Hitz len -= mlen; 1984c6de856SChristian Hitz } 1994c6de856SChristian Hitz 2004c6de856SChristian Hitz /* process 32-bit aligned data words */ 2014c6de856SChristian Hitz pdata = (uint32_t *)data; 2024c6de856SChristian Hitz mlen = len/4; 2034c6de856SChristian Hitz data += 4*mlen; 2044c6de856SChristian Hitz len -= 4*mlen; 2054c6de856SChristian Hitz memcpy(r, bch->ecc_buf, sizeof(r)); 2064c6de856SChristian Hitz 2074c6de856SChristian Hitz /* 2084c6de856SChristian Hitz * split each 32-bit word into 4 polynomials of weight 8 as follows: 2094c6de856SChristian Hitz * 2104c6de856SChristian Hitz * 31 ...24 23 ...16 15 ... 8 7 ... 0 2114c6de856SChristian Hitz * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt 2124c6de856SChristian Hitz * tttttttt mod g = r0 (precomputed) 2134c6de856SChristian Hitz * zzzzzzzz 00000000 mod g = r1 (precomputed) 2144c6de856SChristian Hitz * yyyyyyyy 00000000 00000000 mod g = r2 (precomputed) 2154c6de856SChristian Hitz * xxxxxxxx 00000000 00000000 00000000 mod g = r3 (precomputed) 2164c6de856SChristian Hitz * xxxxxxxx yyyyyyyy zzzzzzzz tttttttt mod g = r0^r1^r2^r3 2174c6de856SChristian Hitz */ 2184c6de856SChristian Hitz while (mlen--) { 2194c6de856SChristian Hitz /* input data is read in big-endian format */ 2204c6de856SChristian Hitz w = r[0]^cpu_to_be32(*pdata++); 2214c6de856SChristian Hitz p0 = tab0 + (l+1)*((w >> 0) & 0xff); 2224c6de856SChristian Hitz p1 = tab1 + (l+1)*((w >> 8) & 0xff); 2234c6de856SChristian Hitz p2 = tab2 + (l+1)*((w >> 16) & 0xff); 2244c6de856SChristian Hitz p3 = tab3 + (l+1)*((w >> 24) & 0xff); 2254c6de856SChristian Hitz 2264c6de856SChristian Hitz for (i = 0; i < l; i++) 2274c6de856SChristian Hitz r[i] = r[i+1]^p0[i]^p1[i]^p2[i]^p3[i]; 2284c6de856SChristian Hitz 2294c6de856SChristian Hitz r[l] = p0[l]^p1[l]^p2[l]^p3[l]; 2304c6de856SChristian Hitz } 2314c6de856SChristian Hitz memcpy(bch->ecc_buf, r, sizeof(r)); 2324c6de856SChristian Hitz 2334c6de856SChristian Hitz /* process last unaligned bytes */ 2344c6de856SChristian Hitz if (len) 2354c6de856SChristian Hitz encode_bch_unaligned(bch, data, len, bch->ecc_buf); 2364c6de856SChristian Hitz 2374c6de856SChristian Hitz /* store ecc parity bytes into original parity buffer */ 2384c6de856SChristian Hitz if (ecc) 2394c6de856SChristian Hitz store_ecc8(bch, ecc, bch->ecc_buf); 2404c6de856SChristian Hitz } 2414c6de856SChristian Hitz 2424c6de856SChristian Hitz static inline int modulo(struct bch_control *bch, unsigned int v) 2434c6de856SChristian Hitz { 2444c6de856SChristian Hitz const unsigned int n = GF_N(bch); 2454c6de856SChristian Hitz while (v >= n) { 2464c6de856SChristian Hitz v -= n; 2474c6de856SChristian Hitz v = (v & n) + (v >> GF_M(bch)); 2484c6de856SChristian Hitz } 2494c6de856SChristian Hitz return v; 2504c6de856SChristian Hitz } 2514c6de856SChristian Hitz 2524c6de856SChristian Hitz /* 2534c6de856SChristian Hitz * shorter and faster modulo function, only works when v < 2N. 2544c6de856SChristian Hitz */ 2554c6de856SChristian Hitz static inline int mod_s(struct bch_control *bch, unsigned int v) 2564c6de856SChristian Hitz { 2574c6de856SChristian Hitz const unsigned int n = GF_N(bch); 2584c6de856SChristian Hitz return (v < n) ? v : v-n; 2594c6de856SChristian Hitz } 2604c6de856SChristian Hitz 2614c6de856SChristian Hitz static inline int deg(unsigned int poly) 2624c6de856SChristian Hitz { 2634c6de856SChristian Hitz /* polynomial degree is the most-significant bit index */ 2644c6de856SChristian Hitz return fls(poly)-1; 2654c6de856SChristian Hitz } 2664c6de856SChristian Hitz 2674c6de856SChristian Hitz static inline int parity(unsigned int x) 2684c6de856SChristian Hitz { 2694c6de856SChristian Hitz /* 2704c6de856SChristian Hitz * public domain code snippet, lifted from 2714c6de856SChristian Hitz * http://www-graphics.stanford.edu/~seander/bithacks.html 2724c6de856SChristian Hitz */ 2734c6de856SChristian Hitz x ^= x >> 1; 2744c6de856SChristian Hitz x ^= x >> 2; 2754c6de856SChristian Hitz x = (x & 0x11111111U) * 0x11111111U; 2764c6de856SChristian Hitz return (x >> 28) & 1; 2774c6de856SChristian Hitz } 2784c6de856SChristian Hitz 2794c6de856SChristian Hitz /* Galois field basic operations: multiply, divide, inverse, etc. */ 2804c6de856SChristian Hitz 2814c6de856SChristian Hitz static inline unsigned int gf_mul(struct bch_control *bch, unsigned int a, 2824c6de856SChristian Hitz unsigned int b) 2834c6de856SChristian Hitz { 2844c6de856SChristian Hitz return (a && b) ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ 2854c6de856SChristian Hitz bch->a_log_tab[b])] : 0; 2864c6de856SChristian Hitz } 2874c6de856SChristian Hitz 2884c6de856SChristian Hitz static inline unsigned int gf_sqr(struct bch_control *bch, unsigned int a) 2894c6de856SChristian Hitz { 2904c6de856SChristian Hitz return a ? bch->a_pow_tab[mod_s(bch, 2*bch->a_log_tab[a])] : 0; 2914c6de856SChristian Hitz } 2924c6de856SChristian Hitz 2934c6de856SChristian Hitz static inline unsigned int gf_div(struct bch_control *bch, unsigned int a, 2944c6de856SChristian Hitz unsigned int b) 2954c6de856SChristian Hitz { 2964c6de856SChristian Hitz return a ? bch->a_pow_tab[mod_s(bch, bch->a_log_tab[a]+ 2974c6de856SChristian Hitz GF_N(bch)-bch->a_log_tab[b])] : 0; 2984c6de856SChristian Hitz } 2994c6de856SChristian Hitz 3004c6de856SChristian Hitz static inline unsigned int gf_inv(struct bch_control *bch, unsigned int a) 3014c6de856SChristian Hitz { 3024c6de856SChristian Hitz return bch->a_pow_tab[GF_N(bch)-bch->a_log_tab[a]]; 3034c6de856SChristian Hitz } 3044c6de856SChristian Hitz 3054c6de856SChristian Hitz static inline unsigned int a_pow(struct bch_control *bch, int i) 3064c6de856SChristian Hitz { 3074c6de856SChristian Hitz return bch->a_pow_tab[modulo(bch, i)]; 3084c6de856SChristian Hitz } 3094c6de856SChristian Hitz 3104c6de856SChristian Hitz static inline int a_log(struct bch_control *bch, unsigned int x) 3114c6de856SChristian Hitz { 3124c6de856SChristian Hitz return bch->a_log_tab[x]; 3134c6de856SChristian Hitz } 3144c6de856SChristian Hitz 3154c6de856SChristian Hitz static inline int a_ilog(struct bch_control *bch, unsigned int x) 3164c6de856SChristian Hitz { 3174c6de856SChristian Hitz return mod_s(bch, GF_N(bch)-bch->a_log_tab[x]); 3184c6de856SChristian Hitz } 3194c6de856SChristian Hitz 3204c6de856SChristian Hitz /* 3214c6de856SChristian Hitz * compute 2t syndromes of ecc polynomial, i.e. ecc(a^j) for j=1..2t 3224c6de856SChristian Hitz */ 3234c6de856SChristian Hitz static void compute_syndromes(struct bch_control *bch, uint32_t *ecc, 3244c6de856SChristian Hitz unsigned int *syn) 3254c6de856SChristian Hitz { 3264c6de856SChristian Hitz int i, j, s; 3274c6de856SChristian Hitz unsigned int m; 3284c6de856SChristian Hitz uint32_t poly; 3294c6de856SChristian Hitz const int t = GF_T(bch); 3304c6de856SChristian Hitz 3314c6de856SChristian Hitz s = bch->ecc_bits; 3324c6de856SChristian Hitz 3334c6de856SChristian Hitz /* make sure extra bits in last ecc word are cleared */ 3344c6de856SChristian Hitz m = ((unsigned int)s) & 31; 3354c6de856SChristian Hitz if (m) 3364c6de856SChristian Hitz ecc[s/32] &= ~((1u << (32-m))-1); 3374c6de856SChristian Hitz memset(syn, 0, 2*t*sizeof(*syn)); 3384c6de856SChristian Hitz 3394c6de856SChristian Hitz /* compute v(a^j) for j=1 .. 2t-1 */ 3404c6de856SChristian Hitz do { 3414c6de856SChristian Hitz poly = *ecc++; 3424c6de856SChristian Hitz s -= 32; 3434c6de856SChristian Hitz while (poly) { 3444c6de856SChristian Hitz i = deg(poly); 3454c6de856SChristian Hitz for (j = 0; j < 2*t; j += 2) 3464c6de856SChristian Hitz syn[j] ^= a_pow(bch, (j+1)*(i+s)); 3474c6de856SChristian Hitz 3484c6de856SChristian Hitz poly ^= (1 << i); 3494c6de856SChristian Hitz } 3504c6de856SChristian Hitz } while (s > 0); 3514c6de856SChristian Hitz 3524c6de856SChristian Hitz /* v(a^(2j)) = v(a^j)^2 */ 3534c6de856SChristian Hitz for (j = 0; j < t; j++) 3544c6de856SChristian Hitz syn[2*j+1] = gf_sqr(bch, syn[j]); 3554c6de856SChristian Hitz } 3564c6de856SChristian Hitz 3574c6de856SChristian Hitz static void gf_poly_copy(struct gf_poly *dst, struct gf_poly *src) 3584c6de856SChristian Hitz { 3594c6de856SChristian Hitz memcpy(dst, src, GF_POLY_SZ(src->deg)); 3604c6de856SChristian Hitz } 3614c6de856SChristian Hitz 3624c6de856SChristian Hitz static int compute_error_locator_polynomial(struct bch_control *bch, 3634c6de856SChristian Hitz const unsigned int *syn) 3644c6de856SChristian Hitz { 3654c6de856SChristian Hitz const unsigned int t = GF_T(bch); 3664c6de856SChristian Hitz const unsigned int n = GF_N(bch); 3674c6de856SChristian Hitz unsigned int i, j, tmp, l, pd = 1, d = syn[0]; 3684c6de856SChristian Hitz struct gf_poly *elp = bch->elp; 3694c6de856SChristian Hitz struct gf_poly *pelp = bch->poly_2t[0]; 3704c6de856SChristian Hitz struct gf_poly *elp_copy = bch->poly_2t[1]; 3714c6de856SChristian Hitz int k, pp = -1; 3724c6de856SChristian Hitz 3734c6de856SChristian Hitz memset(pelp, 0, GF_POLY_SZ(2*t)); 3744c6de856SChristian Hitz memset(elp, 0, GF_POLY_SZ(2*t)); 3754c6de856SChristian Hitz 3764c6de856SChristian Hitz pelp->deg = 0; 3774c6de856SChristian Hitz pelp->c[0] = 1; 3784c6de856SChristian Hitz elp->deg = 0; 3794c6de856SChristian Hitz elp->c[0] = 1; 3804c6de856SChristian Hitz 3814c6de856SChristian Hitz /* use simplified binary Berlekamp-Massey algorithm */ 3824c6de856SChristian Hitz for (i = 0; (i < t) && (elp->deg <= t); i++) { 3834c6de856SChristian Hitz if (d) { 3844c6de856SChristian Hitz k = 2*i-pp; 3854c6de856SChristian Hitz gf_poly_copy(elp_copy, elp); 3864c6de856SChristian Hitz /* e[i+1](X) = e[i](X)+di*dp^-1*X^2(i-p)*e[p](X) */ 3874c6de856SChristian Hitz tmp = a_log(bch, d)+n-a_log(bch, pd); 3884c6de856SChristian Hitz for (j = 0; j <= pelp->deg; j++) { 3894c6de856SChristian Hitz if (pelp->c[j]) { 3904c6de856SChristian Hitz l = a_log(bch, pelp->c[j]); 3914c6de856SChristian Hitz elp->c[j+k] ^= a_pow(bch, tmp+l); 3924c6de856SChristian Hitz } 3934c6de856SChristian Hitz } 3944c6de856SChristian Hitz /* compute l[i+1] = max(l[i]->c[l[p]+2*(i-p]) */ 3954c6de856SChristian Hitz tmp = pelp->deg+k; 3964c6de856SChristian Hitz if (tmp > elp->deg) { 3974c6de856SChristian Hitz elp->deg = tmp; 3984c6de856SChristian Hitz gf_poly_copy(pelp, elp_copy); 3994c6de856SChristian Hitz pd = d; 4004c6de856SChristian Hitz pp = 2*i; 4014c6de856SChristian Hitz } 4024c6de856SChristian Hitz } 4034c6de856SChristian Hitz /* di+1 = S(2i+3)+elp[i+1].1*S(2i+2)+...+elp[i+1].lS(2i+3-l) */ 4044c6de856SChristian Hitz if (i < t-1) { 4054c6de856SChristian Hitz d = syn[2*i+2]; 4064c6de856SChristian Hitz for (j = 1; j <= elp->deg; j++) 4074c6de856SChristian Hitz d ^= gf_mul(bch, elp->c[j], syn[2*i+2-j]); 4084c6de856SChristian Hitz } 4094c6de856SChristian Hitz } 4104c6de856SChristian Hitz dbg("elp=%s\n", gf_poly_str(elp)); 4114c6de856SChristian Hitz return (elp->deg > t) ? -1 : (int)elp->deg; 4124c6de856SChristian Hitz } 4134c6de856SChristian Hitz 4144c6de856SChristian Hitz /* 4154c6de856SChristian Hitz * solve a m x m linear system in GF(2) with an expected number of solutions, 4164c6de856SChristian Hitz * and return the number of found solutions 4174c6de856SChristian Hitz */ 4184c6de856SChristian Hitz static int solve_linear_system(struct bch_control *bch, unsigned int *rows, 4194c6de856SChristian Hitz unsigned int *sol, int nsol) 4204c6de856SChristian Hitz { 4214c6de856SChristian Hitz const int m = GF_M(bch); 4224c6de856SChristian Hitz unsigned int tmp, mask; 4234c6de856SChristian Hitz int rem, c, r, p, k, param[m]; 4244c6de856SChristian Hitz 4254c6de856SChristian Hitz k = 0; 4264c6de856SChristian Hitz mask = 1 << m; 4274c6de856SChristian Hitz 4284c6de856SChristian Hitz /* Gaussian elimination */ 4294c6de856SChristian Hitz for (c = 0; c < m; c++) { 4304c6de856SChristian Hitz rem = 0; 4314c6de856SChristian Hitz p = c-k; 4324c6de856SChristian Hitz /* find suitable row for elimination */ 4334c6de856SChristian Hitz for (r = p; r < m; r++) { 4344c6de856SChristian Hitz if (rows[r] & mask) { 4354c6de856SChristian Hitz if (r != p) { 4364c6de856SChristian Hitz tmp = rows[r]; 4374c6de856SChristian Hitz rows[r] = rows[p]; 4384c6de856SChristian Hitz rows[p] = tmp; 4394c6de856SChristian Hitz } 4404c6de856SChristian Hitz rem = r+1; 4414c6de856SChristian Hitz break; 4424c6de856SChristian Hitz } 4434c6de856SChristian Hitz } 4444c6de856SChristian Hitz if (rem) { 4454c6de856SChristian Hitz /* perform elimination on remaining rows */ 4464c6de856SChristian Hitz tmp = rows[p]; 4474c6de856SChristian Hitz for (r = rem; r < m; r++) { 4484c6de856SChristian Hitz if (rows[r] & mask) 4494c6de856SChristian Hitz rows[r] ^= tmp; 4504c6de856SChristian Hitz } 4514c6de856SChristian Hitz } else { 4524c6de856SChristian Hitz /* elimination not needed, store defective row index */ 4534c6de856SChristian Hitz param[k++] = c; 4544c6de856SChristian Hitz } 4554c6de856SChristian Hitz mask >>= 1; 4564c6de856SChristian Hitz } 4574c6de856SChristian Hitz /* rewrite system, inserting fake parameter rows */ 4584c6de856SChristian Hitz if (k > 0) { 4594c6de856SChristian Hitz p = k; 4604c6de856SChristian Hitz for (r = m-1; r >= 0; r--) { 4614c6de856SChristian Hitz if ((r > m-1-k) && rows[r]) 4624c6de856SChristian Hitz /* system has no solution */ 4634c6de856SChristian Hitz return 0; 4644c6de856SChristian Hitz 4654c6de856SChristian Hitz rows[r] = (p && (r == param[p-1])) ? 4664c6de856SChristian Hitz p--, 1u << (m-r) : rows[r-p]; 4674c6de856SChristian Hitz } 4684c6de856SChristian Hitz } 4694c6de856SChristian Hitz 4704c6de856SChristian Hitz if (nsol != (1 << k)) 4714c6de856SChristian Hitz /* unexpected number of solutions */ 4724c6de856SChristian Hitz return 0; 4734c6de856SChristian Hitz 4744c6de856SChristian Hitz for (p = 0; p < nsol; p++) { 4754c6de856SChristian Hitz /* set parameters for p-th solution */ 4764c6de856SChristian Hitz for (c = 0; c < k; c++) 4774c6de856SChristian Hitz rows[param[c]] = (rows[param[c]] & ~1)|((p >> c) & 1); 4784c6de856SChristian Hitz 4794c6de856SChristian Hitz /* compute unique solution */ 4804c6de856SChristian Hitz tmp = 0; 4814c6de856SChristian Hitz for (r = m-1; r >= 0; r--) { 4824c6de856SChristian Hitz mask = rows[r] & (tmp|1); 4834c6de856SChristian Hitz tmp |= parity(mask) << (m-r); 4844c6de856SChristian Hitz } 4854c6de856SChristian Hitz sol[p] = tmp >> 1; 4864c6de856SChristian Hitz } 4874c6de856SChristian Hitz return nsol; 4884c6de856SChristian Hitz } 4894c6de856SChristian Hitz 4904c6de856SChristian Hitz /* 4914c6de856SChristian Hitz * this function builds and solves a linear system for finding roots of a degree 4924c6de856SChristian Hitz * 4 affine monic polynomial X^4+aX^2+bX+c over GF(2^m). 4934c6de856SChristian Hitz */ 4944c6de856SChristian Hitz static int find_affine4_roots(struct bch_control *bch, unsigned int a, 4954c6de856SChristian Hitz unsigned int b, unsigned int c, 4964c6de856SChristian Hitz unsigned int *roots) 4974c6de856SChristian Hitz { 4984c6de856SChristian Hitz int i, j, k; 4994c6de856SChristian Hitz const int m = GF_M(bch); 5004c6de856SChristian Hitz unsigned int mask = 0xff, t, rows[16] = {0,}; 5014c6de856SChristian Hitz 5024c6de856SChristian Hitz j = a_log(bch, b); 5034c6de856SChristian Hitz k = a_log(bch, a); 5044c6de856SChristian Hitz rows[0] = c; 5054c6de856SChristian Hitz 5064c6de856SChristian Hitz /* buid linear system to solve X^4+aX^2+bX+c = 0 */ 5074c6de856SChristian Hitz for (i = 0; i < m; i++) { 5084c6de856SChristian Hitz rows[i+1] = bch->a_pow_tab[4*i]^ 5094c6de856SChristian Hitz (a ? bch->a_pow_tab[mod_s(bch, k)] : 0)^ 5104c6de856SChristian Hitz (b ? bch->a_pow_tab[mod_s(bch, j)] : 0); 5114c6de856SChristian Hitz j++; 5124c6de856SChristian Hitz k += 2; 5134c6de856SChristian Hitz } 5144c6de856SChristian Hitz /* 5154c6de856SChristian Hitz * transpose 16x16 matrix before passing it to linear solver 5164c6de856SChristian Hitz * warning: this code assumes m < 16 5174c6de856SChristian Hitz */ 5184c6de856SChristian Hitz for (j = 8; j != 0; j >>= 1, mask ^= (mask << j)) { 5194c6de856SChristian Hitz for (k = 0; k < 16; k = (k+j+1) & ~j) { 5204c6de856SChristian Hitz t = ((rows[k] >> j)^rows[k+j]) & mask; 5214c6de856SChristian Hitz rows[k] ^= (t << j); 5224c6de856SChristian Hitz rows[k+j] ^= t; 5234c6de856SChristian Hitz } 5244c6de856SChristian Hitz } 5254c6de856SChristian Hitz return solve_linear_system(bch, rows, roots, 4); 5264c6de856SChristian Hitz } 5274c6de856SChristian Hitz 5284c6de856SChristian Hitz /* 5294c6de856SChristian Hitz * compute root r of a degree 1 polynomial over GF(2^m) (returned as log(1/r)) 5304c6de856SChristian Hitz */ 5314c6de856SChristian Hitz static int find_poly_deg1_roots(struct bch_control *bch, struct gf_poly *poly, 5324c6de856SChristian Hitz unsigned int *roots) 5334c6de856SChristian Hitz { 5344c6de856SChristian Hitz int n = 0; 5354c6de856SChristian Hitz 5364c6de856SChristian Hitz if (poly->c[0]) 5374c6de856SChristian Hitz /* poly[X] = bX+c with c!=0, root=c/b */ 5384c6de856SChristian Hitz roots[n++] = mod_s(bch, GF_N(bch)-bch->a_log_tab[poly->c[0]]+ 5394c6de856SChristian Hitz bch->a_log_tab[poly->c[1]]); 5404c6de856SChristian Hitz return n; 5414c6de856SChristian Hitz } 5424c6de856SChristian Hitz 5434c6de856SChristian Hitz /* 5444c6de856SChristian Hitz * compute roots of a degree 2 polynomial over GF(2^m) 5454c6de856SChristian Hitz */ 5464c6de856SChristian Hitz static int find_poly_deg2_roots(struct bch_control *bch, struct gf_poly *poly, 5474c6de856SChristian Hitz unsigned int *roots) 5484c6de856SChristian Hitz { 5494c6de856SChristian Hitz int n = 0, i, l0, l1, l2; 5504c6de856SChristian Hitz unsigned int u, v, r; 5514c6de856SChristian Hitz 5524c6de856SChristian Hitz if (poly->c[0] && poly->c[1]) { 5534c6de856SChristian Hitz 5544c6de856SChristian Hitz l0 = bch->a_log_tab[poly->c[0]]; 5554c6de856SChristian Hitz l1 = bch->a_log_tab[poly->c[1]]; 5564c6de856SChristian Hitz l2 = bch->a_log_tab[poly->c[2]]; 5574c6de856SChristian Hitz 5584c6de856SChristian Hitz /* using z=a/bX, transform aX^2+bX+c into z^2+z+u (u=ac/b^2) */ 5594c6de856SChristian Hitz u = a_pow(bch, l0+l2+2*(GF_N(bch)-l1)); 5604c6de856SChristian Hitz /* 5614c6de856SChristian Hitz * let u = sum(li.a^i) i=0..m-1; then compute r = sum(li.xi): 5624c6de856SChristian Hitz * r^2+r = sum(li.(xi^2+xi)) = sum(li.(a^i+Tr(a^i).a^k)) = 5634c6de856SChristian Hitz * u + sum(li.Tr(a^i).a^k) = u+a^k.Tr(sum(li.a^i)) = u+a^k.Tr(u) 5644c6de856SChristian Hitz * i.e. r and r+1 are roots iff Tr(u)=0 5654c6de856SChristian Hitz */ 5664c6de856SChristian Hitz r = 0; 5674c6de856SChristian Hitz v = u; 5684c6de856SChristian Hitz while (v) { 5694c6de856SChristian Hitz i = deg(v); 5704c6de856SChristian Hitz r ^= bch->xi_tab[i]; 5714c6de856SChristian Hitz v ^= (1 << i); 5724c6de856SChristian Hitz } 5734c6de856SChristian Hitz /* verify root */ 5744c6de856SChristian Hitz if ((gf_sqr(bch, r)^r) == u) { 5754c6de856SChristian Hitz /* reverse z=a/bX transformation and compute log(1/r) */ 5764c6de856SChristian Hitz roots[n++] = modulo(bch, 2*GF_N(bch)-l1- 5774c6de856SChristian Hitz bch->a_log_tab[r]+l2); 5784c6de856SChristian Hitz roots[n++] = modulo(bch, 2*GF_N(bch)-l1- 5794c6de856SChristian Hitz bch->a_log_tab[r^1]+l2); 5804c6de856SChristian Hitz } 5814c6de856SChristian Hitz } 5824c6de856SChristian Hitz return n; 5834c6de856SChristian Hitz } 5844c6de856SChristian Hitz 5854c6de856SChristian Hitz /* 5864c6de856SChristian Hitz * compute roots of a degree 3 polynomial over GF(2^m) 5874c6de856SChristian Hitz */ 5884c6de856SChristian Hitz static int find_poly_deg3_roots(struct bch_control *bch, struct gf_poly *poly, 5894c6de856SChristian Hitz unsigned int *roots) 5904c6de856SChristian Hitz { 5914c6de856SChristian Hitz int i, n = 0; 5924c6de856SChristian Hitz unsigned int a, b, c, a2, b2, c2, e3, tmp[4]; 5934c6de856SChristian Hitz 5944c6de856SChristian Hitz if (poly->c[0]) { 5954c6de856SChristian Hitz /* transform polynomial into monic X^3 + a2X^2 + b2X + c2 */ 5964c6de856SChristian Hitz e3 = poly->c[3]; 5974c6de856SChristian Hitz c2 = gf_div(bch, poly->c[0], e3); 5984c6de856SChristian Hitz b2 = gf_div(bch, poly->c[1], e3); 5994c6de856SChristian Hitz a2 = gf_div(bch, poly->c[2], e3); 6004c6de856SChristian Hitz 6014c6de856SChristian Hitz /* (X+a2)(X^3+a2X^2+b2X+c2) = X^4+aX^2+bX+c (affine) */ 6024c6de856SChristian Hitz c = gf_mul(bch, a2, c2); /* c = a2c2 */ 6034c6de856SChristian Hitz b = gf_mul(bch, a2, b2)^c2; /* b = a2b2 + c2 */ 6044c6de856SChristian Hitz a = gf_sqr(bch, a2)^b2; /* a = a2^2 + b2 */ 6054c6de856SChristian Hitz 6064c6de856SChristian Hitz /* find the 4 roots of this affine polynomial */ 6074c6de856SChristian Hitz if (find_affine4_roots(bch, a, b, c, tmp) == 4) { 6084c6de856SChristian Hitz /* remove a2 from final list of roots */ 6094c6de856SChristian Hitz for (i = 0; i < 4; i++) { 6104c6de856SChristian Hitz if (tmp[i] != a2) 6114c6de856SChristian Hitz roots[n++] = a_ilog(bch, tmp[i]); 6124c6de856SChristian Hitz } 6134c6de856SChristian Hitz } 6144c6de856SChristian Hitz } 6154c6de856SChristian Hitz return n; 6164c6de856SChristian Hitz } 6174c6de856SChristian Hitz 6184c6de856SChristian Hitz /* 6194c6de856SChristian Hitz * compute roots of a degree 4 polynomial over GF(2^m) 6204c6de856SChristian Hitz */ 6214c6de856SChristian Hitz static int find_poly_deg4_roots(struct bch_control *bch, struct gf_poly *poly, 6224c6de856SChristian Hitz unsigned int *roots) 6234c6de856SChristian Hitz { 6244c6de856SChristian Hitz int i, l, n = 0; 6254c6de856SChristian Hitz unsigned int a, b, c, d, e = 0, f, a2, b2, c2, e4; 6264c6de856SChristian Hitz 6274c6de856SChristian Hitz if (poly->c[0] == 0) 6284c6de856SChristian Hitz return 0; 6294c6de856SChristian Hitz 6304c6de856SChristian Hitz /* transform polynomial into monic X^4 + aX^3 + bX^2 + cX + d */ 6314c6de856SChristian Hitz e4 = poly->c[4]; 6324c6de856SChristian Hitz d = gf_div(bch, poly->c[0], e4); 6334c6de856SChristian Hitz c = gf_div(bch, poly->c[1], e4); 6344c6de856SChristian Hitz b = gf_div(bch, poly->c[2], e4); 6354c6de856SChristian Hitz a = gf_div(bch, poly->c[3], e4); 6364c6de856SChristian Hitz 6374c6de856SChristian Hitz /* use Y=1/X transformation to get an affine polynomial */ 6384c6de856SChristian Hitz if (a) { 6394c6de856SChristian Hitz /* first, eliminate cX by using z=X+e with ae^2+c=0 */ 6404c6de856SChristian Hitz if (c) { 6414c6de856SChristian Hitz /* compute e such that e^2 = c/a */ 6424c6de856SChristian Hitz f = gf_div(bch, c, a); 6434c6de856SChristian Hitz l = a_log(bch, f); 6444c6de856SChristian Hitz l += (l & 1) ? GF_N(bch) : 0; 6454c6de856SChristian Hitz e = a_pow(bch, l/2); 6464c6de856SChristian Hitz /* 6474c6de856SChristian Hitz * use transformation z=X+e: 6484c6de856SChristian Hitz * z^4+e^4 + a(z^3+ez^2+e^2z+e^3) + b(z^2+e^2) +cz+ce+d 6494c6de856SChristian Hitz * z^4 + az^3 + (ae+b)z^2 + (ae^2+c)z+e^4+be^2+ae^3+ce+d 6504c6de856SChristian Hitz * z^4 + az^3 + (ae+b)z^2 + e^4+be^2+d 6514c6de856SChristian Hitz * z^4 + az^3 + b'z^2 + d' 6524c6de856SChristian Hitz */ 6534c6de856SChristian Hitz d = a_pow(bch, 2*l)^gf_mul(bch, b, f)^d; 6544c6de856SChristian Hitz b = gf_mul(bch, a, e)^b; 6554c6de856SChristian Hitz } 6564c6de856SChristian Hitz /* now, use Y=1/X to get Y^4 + b/dY^2 + a/dY + 1/d */ 6574c6de856SChristian Hitz if (d == 0) 6584c6de856SChristian Hitz /* assume all roots have multiplicity 1 */ 6594c6de856SChristian Hitz return 0; 6604c6de856SChristian Hitz 6614c6de856SChristian Hitz c2 = gf_inv(bch, d); 6624c6de856SChristian Hitz b2 = gf_div(bch, a, d); 6634c6de856SChristian Hitz a2 = gf_div(bch, b, d); 6644c6de856SChristian Hitz } else { 6654c6de856SChristian Hitz /* polynomial is already affine */ 6664c6de856SChristian Hitz c2 = d; 6674c6de856SChristian Hitz b2 = c; 6684c6de856SChristian Hitz a2 = b; 6694c6de856SChristian Hitz } 6704c6de856SChristian Hitz /* find the 4 roots of this affine polynomial */ 6714c6de856SChristian Hitz if (find_affine4_roots(bch, a2, b2, c2, roots) == 4) { 6724c6de856SChristian Hitz for (i = 0; i < 4; i++) { 6734c6de856SChristian Hitz /* post-process roots (reverse transformations) */ 6744c6de856SChristian Hitz f = a ? gf_inv(bch, roots[i]) : roots[i]; 6754c6de856SChristian Hitz roots[i] = a_ilog(bch, f^e); 6764c6de856SChristian Hitz } 6774c6de856SChristian Hitz n = 4; 6784c6de856SChristian Hitz } 6794c6de856SChristian Hitz return n; 6804c6de856SChristian Hitz } 6814c6de856SChristian Hitz 6824c6de856SChristian Hitz /* 6834c6de856SChristian Hitz * build monic, log-based representation of a polynomial 6844c6de856SChristian Hitz */ 6854c6de856SChristian Hitz static void gf_poly_logrep(struct bch_control *bch, 6864c6de856SChristian Hitz const struct gf_poly *a, int *rep) 6874c6de856SChristian Hitz { 6884c6de856SChristian Hitz int i, d = a->deg, l = GF_N(bch)-a_log(bch, a->c[a->deg]); 6894c6de856SChristian Hitz 6904c6de856SChristian Hitz /* represent 0 values with -1; warning, rep[d] is not set to 1 */ 6914c6de856SChristian Hitz for (i = 0; i < d; i++) 6924c6de856SChristian Hitz rep[i] = a->c[i] ? mod_s(bch, a_log(bch, a->c[i])+l) : -1; 6934c6de856SChristian Hitz } 6944c6de856SChristian Hitz 6954c6de856SChristian Hitz /* 6964c6de856SChristian Hitz * compute polynomial Euclidean division remainder in GF(2^m)[X] 6974c6de856SChristian Hitz */ 6984c6de856SChristian Hitz static void gf_poly_mod(struct bch_control *bch, struct gf_poly *a, 6994c6de856SChristian Hitz const struct gf_poly *b, int *rep) 7004c6de856SChristian Hitz { 7014c6de856SChristian Hitz int la, p, m; 7024c6de856SChristian Hitz unsigned int i, j, *c = a->c; 7034c6de856SChristian Hitz const unsigned int d = b->deg; 7044c6de856SChristian Hitz 7054c6de856SChristian Hitz if (a->deg < d) 7064c6de856SChristian Hitz return; 7074c6de856SChristian Hitz 7084c6de856SChristian Hitz /* reuse or compute log representation of denominator */ 7094c6de856SChristian Hitz if (!rep) { 7104c6de856SChristian Hitz rep = bch->cache; 7114c6de856SChristian Hitz gf_poly_logrep(bch, b, rep); 7124c6de856SChristian Hitz } 7134c6de856SChristian Hitz 7144c6de856SChristian Hitz for (j = a->deg; j >= d; j--) { 7154c6de856SChristian Hitz if (c[j]) { 7164c6de856SChristian Hitz la = a_log(bch, c[j]); 7174c6de856SChristian Hitz p = j-d; 7184c6de856SChristian Hitz for (i = 0; i < d; i++, p++) { 7194c6de856SChristian Hitz m = rep[i]; 7204c6de856SChristian Hitz if (m >= 0) 7214c6de856SChristian Hitz c[p] ^= bch->a_pow_tab[mod_s(bch, 7224c6de856SChristian Hitz m+la)]; 7234c6de856SChristian Hitz } 7244c6de856SChristian Hitz } 7254c6de856SChristian Hitz } 7264c6de856SChristian Hitz a->deg = d-1; 7274c6de856SChristian Hitz while (!c[a->deg] && a->deg) 7284c6de856SChristian Hitz a->deg--; 7294c6de856SChristian Hitz } 7304c6de856SChristian Hitz 7314c6de856SChristian Hitz /* 7324c6de856SChristian Hitz * compute polynomial Euclidean division quotient in GF(2^m)[X] 7334c6de856SChristian Hitz */ 7344c6de856SChristian Hitz static void gf_poly_div(struct bch_control *bch, struct gf_poly *a, 7354c6de856SChristian Hitz const struct gf_poly *b, struct gf_poly *q) 7364c6de856SChristian Hitz { 7374c6de856SChristian Hitz if (a->deg >= b->deg) { 7384c6de856SChristian Hitz q->deg = a->deg-b->deg; 7394c6de856SChristian Hitz /* compute a mod b (modifies a) */ 7404c6de856SChristian Hitz gf_poly_mod(bch, a, b, NULL); 7414c6de856SChristian Hitz /* quotient is stored in upper part of polynomial a */ 7424c6de856SChristian Hitz memcpy(q->c, &a->c[b->deg], (1+q->deg)*sizeof(unsigned int)); 7434c6de856SChristian Hitz } else { 7444c6de856SChristian Hitz q->deg = 0; 7454c6de856SChristian Hitz q->c[0] = 0; 7464c6de856SChristian Hitz } 7474c6de856SChristian Hitz } 7484c6de856SChristian Hitz 7494c6de856SChristian Hitz /* 7504c6de856SChristian Hitz * compute polynomial GCD (Greatest Common Divisor) in GF(2^m)[X] 7514c6de856SChristian Hitz */ 7524c6de856SChristian Hitz static struct gf_poly *gf_poly_gcd(struct bch_control *bch, struct gf_poly *a, 7534c6de856SChristian Hitz struct gf_poly *b) 7544c6de856SChristian Hitz { 7554c6de856SChristian Hitz struct gf_poly *tmp; 7564c6de856SChristian Hitz 7574c6de856SChristian Hitz dbg("gcd(%s,%s)=", gf_poly_str(a), gf_poly_str(b)); 7584c6de856SChristian Hitz 7594c6de856SChristian Hitz if (a->deg < b->deg) { 7604c6de856SChristian Hitz tmp = b; 7614c6de856SChristian Hitz b = a; 7624c6de856SChristian Hitz a = tmp; 7634c6de856SChristian Hitz } 7644c6de856SChristian Hitz 7654c6de856SChristian Hitz while (b->deg > 0) { 7664c6de856SChristian Hitz gf_poly_mod(bch, a, b, NULL); 7674c6de856SChristian Hitz tmp = b; 7684c6de856SChristian Hitz b = a; 7694c6de856SChristian Hitz a = tmp; 7704c6de856SChristian Hitz } 7714c6de856SChristian Hitz 7724c6de856SChristian Hitz dbg("%s\n", gf_poly_str(a)); 7734c6de856SChristian Hitz 7744c6de856SChristian Hitz return a; 7754c6de856SChristian Hitz } 7764c6de856SChristian Hitz 7774c6de856SChristian Hitz /* 7784c6de856SChristian Hitz * Given a polynomial f and an integer k, compute Tr(a^kX) mod f 7794c6de856SChristian Hitz * This is used in Berlekamp Trace algorithm for splitting polynomials 7804c6de856SChristian Hitz */ 7814c6de856SChristian Hitz static void compute_trace_bk_mod(struct bch_control *bch, int k, 7824c6de856SChristian Hitz const struct gf_poly *f, struct gf_poly *z, 7834c6de856SChristian Hitz struct gf_poly *out) 7844c6de856SChristian Hitz { 7854c6de856SChristian Hitz const int m = GF_M(bch); 7864c6de856SChristian Hitz int i, j; 7874c6de856SChristian Hitz 7884c6de856SChristian Hitz /* z contains z^2j mod f */ 7894c6de856SChristian Hitz z->deg = 1; 7904c6de856SChristian Hitz z->c[0] = 0; 7914c6de856SChristian Hitz z->c[1] = bch->a_pow_tab[k]; 7924c6de856SChristian Hitz 7934c6de856SChristian Hitz out->deg = 0; 7944c6de856SChristian Hitz memset(out, 0, GF_POLY_SZ(f->deg)); 7954c6de856SChristian Hitz 7964c6de856SChristian Hitz /* compute f log representation only once */ 7974c6de856SChristian Hitz gf_poly_logrep(bch, f, bch->cache); 7984c6de856SChristian Hitz 7994c6de856SChristian Hitz for (i = 0; i < m; i++) { 8004c6de856SChristian Hitz /* add a^(k*2^i)(z^(2^i) mod f) and compute (z^(2^i) mod f)^2 */ 8014c6de856SChristian Hitz for (j = z->deg; j >= 0; j--) { 8024c6de856SChristian Hitz out->c[j] ^= z->c[j]; 8034c6de856SChristian Hitz z->c[2*j] = gf_sqr(bch, z->c[j]); 8044c6de856SChristian Hitz z->c[2*j+1] = 0; 8054c6de856SChristian Hitz } 8064c6de856SChristian Hitz if (z->deg > out->deg) 8074c6de856SChristian Hitz out->deg = z->deg; 8084c6de856SChristian Hitz 8094c6de856SChristian Hitz if (i < m-1) { 8104c6de856SChristian Hitz z->deg *= 2; 8114c6de856SChristian Hitz /* z^(2(i+1)) mod f = (z^(2^i) mod f)^2 mod f */ 8124c6de856SChristian Hitz gf_poly_mod(bch, z, f, bch->cache); 8134c6de856SChristian Hitz } 8144c6de856SChristian Hitz } 8154c6de856SChristian Hitz while (!out->c[out->deg] && out->deg) 8164c6de856SChristian Hitz out->deg--; 8174c6de856SChristian Hitz 8184c6de856SChristian Hitz dbg("Tr(a^%d.X) mod f = %s\n", k, gf_poly_str(out)); 8194c6de856SChristian Hitz } 8204c6de856SChristian Hitz 8214c6de856SChristian Hitz /* 8224c6de856SChristian Hitz * factor a polynomial using Berlekamp Trace algorithm (BTA) 8234c6de856SChristian Hitz */ 8244c6de856SChristian Hitz static void factor_polynomial(struct bch_control *bch, int k, struct gf_poly *f, 8254c6de856SChristian Hitz struct gf_poly **g, struct gf_poly **h) 8264c6de856SChristian Hitz { 8274c6de856SChristian Hitz struct gf_poly *f2 = bch->poly_2t[0]; 8284c6de856SChristian Hitz struct gf_poly *q = bch->poly_2t[1]; 8294c6de856SChristian Hitz struct gf_poly *tk = bch->poly_2t[2]; 8304c6de856SChristian Hitz struct gf_poly *z = bch->poly_2t[3]; 8314c6de856SChristian Hitz struct gf_poly *gcd; 8324c6de856SChristian Hitz 8334c6de856SChristian Hitz dbg("factoring %s...\n", gf_poly_str(f)); 8344c6de856SChristian Hitz 8354c6de856SChristian Hitz *g = f; 8364c6de856SChristian Hitz *h = NULL; 8374c6de856SChristian Hitz 8384c6de856SChristian Hitz /* tk = Tr(a^k.X) mod f */ 8394c6de856SChristian Hitz compute_trace_bk_mod(bch, k, f, z, tk); 8404c6de856SChristian Hitz 8414c6de856SChristian Hitz if (tk->deg > 0) { 8424c6de856SChristian Hitz /* compute g = gcd(f, tk) (destructive operation) */ 8434c6de856SChristian Hitz gf_poly_copy(f2, f); 8444c6de856SChristian Hitz gcd = gf_poly_gcd(bch, f2, tk); 8454c6de856SChristian Hitz if (gcd->deg < f->deg) { 8464c6de856SChristian Hitz /* compute h=f/gcd(f,tk); this will modify f and q */ 8474c6de856SChristian Hitz gf_poly_div(bch, f, gcd, q); 8484c6de856SChristian Hitz /* store g and h in-place (clobbering f) */ 8494c6de856SChristian Hitz *h = &((struct gf_poly_deg1 *)f)[gcd->deg].poly; 8504c6de856SChristian Hitz gf_poly_copy(*g, gcd); 8514c6de856SChristian Hitz gf_poly_copy(*h, q); 8524c6de856SChristian Hitz } 8534c6de856SChristian Hitz } 8544c6de856SChristian Hitz } 8554c6de856SChristian Hitz 8564c6de856SChristian Hitz /* 8574c6de856SChristian Hitz * find roots of a polynomial, using BTZ algorithm; see the beginning of this 8584c6de856SChristian Hitz * file for details 8594c6de856SChristian Hitz */ 8604c6de856SChristian Hitz static int find_poly_roots(struct bch_control *bch, unsigned int k, 8614c6de856SChristian Hitz struct gf_poly *poly, unsigned int *roots) 8624c6de856SChristian Hitz { 8634c6de856SChristian Hitz int cnt; 8644c6de856SChristian Hitz struct gf_poly *f1, *f2; 8654c6de856SChristian Hitz 8664c6de856SChristian Hitz switch (poly->deg) { 8674c6de856SChristian Hitz /* handle low degree polynomials with ad hoc techniques */ 8684c6de856SChristian Hitz case 1: 8694c6de856SChristian Hitz cnt = find_poly_deg1_roots(bch, poly, roots); 8704c6de856SChristian Hitz break; 8714c6de856SChristian Hitz case 2: 8724c6de856SChristian Hitz cnt = find_poly_deg2_roots(bch, poly, roots); 8734c6de856SChristian Hitz break; 8744c6de856SChristian Hitz case 3: 8754c6de856SChristian Hitz cnt = find_poly_deg3_roots(bch, poly, roots); 8764c6de856SChristian Hitz break; 8774c6de856SChristian Hitz case 4: 8784c6de856SChristian Hitz cnt = find_poly_deg4_roots(bch, poly, roots); 8794c6de856SChristian Hitz break; 8804c6de856SChristian Hitz default: 8814c6de856SChristian Hitz /* factor polynomial using Berlekamp Trace Algorithm (BTA) */ 8824c6de856SChristian Hitz cnt = 0; 8834c6de856SChristian Hitz if (poly->deg && (k <= GF_M(bch))) { 8844c6de856SChristian Hitz factor_polynomial(bch, k, poly, &f1, &f2); 8854c6de856SChristian Hitz if (f1) 8864c6de856SChristian Hitz cnt += find_poly_roots(bch, k+1, f1, roots); 8874c6de856SChristian Hitz if (f2) 8884c6de856SChristian Hitz cnt += find_poly_roots(bch, k+1, f2, roots+cnt); 8894c6de856SChristian Hitz } 8904c6de856SChristian Hitz break; 8914c6de856SChristian Hitz } 8924c6de856SChristian Hitz return cnt; 8934c6de856SChristian Hitz } 8944c6de856SChristian Hitz 8954c6de856SChristian Hitz #if defined(USE_CHIEN_SEARCH) 8964c6de856SChristian Hitz /* 8974c6de856SChristian Hitz * exhaustive root search (Chien) implementation - not used, included only for 8984c6de856SChristian Hitz * reference/comparison tests 8994c6de856SChristian Hitz */ 9004c6de856SChristian Hitz static int chien_search(struct bch_control *bch, unsigned int len, 9014c6de856SChristian Hitz struct gf_poly *p, unsigned int *roots) 9024c6de856SChristian Hitz { 9034c6de856SChristian Hitz int m; 9044c6de856SChristian Hitz unsigned int i, j, syn, syn0, count = 0; 9054c6de856SChristian Hitz const unsigned int k = 8*len+bch->ecc_bits; 9064c6de856SChristian Hitz 9074c6de856SChristian Hitz /* use a log-based representation of polynomial */ 9084c6de856SChristian Hitz gf_poly_logrep(bch, p, bch->cache); 9094c6de856SChristian Hitz bch->cache[p->deg] = 0; 9104c6de856SChristian Hitz syn0 = gf_div(bch, p->c[0], p->c[p->deg]); 9114c6de856SChristian Hitz 9124c6de856SChristian Hitz for (i = GF_N(bch)-k+1; i <= GF_N(bch); i++) { 9134c6de856SChristian Hitz /* compute elp(a^i) */ 9144c6de856SChristian Hitz for (j = 1, syn = syn0; j <= p->deg; j++) { 9154c6de856SChristian Hitz m = bch->cache[j]; 9164c6de856SChristian Hitz if (m >= 0) 9174c6de856SChristian Hitz syn ^= a_pow(bch, m+j*i); 9184c6de856SChristian Hitz } 9194c6de856SChristian Hitz if (syn == 0) { 9204c6de856SChristian Hitz roots[count++] = GF_N(bch)-i; 9214c6de856SChristian Hitz if (count == p->deg) 9224c6de856SChristian Hitz break; 9234c6de856SChristian Hitz } 9244c6de856SChristian Hitz } 9254c6de856SChristian Hitz return (count == p->deg) ? count : 0; 9264c6de856SChristian Hitz } 9274c6de856SChristian Hitz #define find_poly_roots(_p, _k, _elp, _loc) chien_search(_p, len, _elp, _loc) 9284c6de856SChristian Hitz #endif /* USE_CHIEN_SEARCH */ 9294c6de856SChristian Hitz 9304c6de856SChristian Hitz /** 9314c6de856SChristian Hitz * decode_bch - decode received codeword and find bit error locations 9324c6de856SChristian Hitz * @bch: BCH control structure 9334c6de856SChristian Hitz * @data: received data, ignored if @calc_ecc is provided 9344c6de856SChristian Hitz * @len: data length in bytes, must always be provided 9354c6de856SChristian Hitz * @recv_ecc: received ecc, if NULL then assume it was XORed in @calc_ecc 9364c6de856SChristian Hitz * @calc_ecc: calculated ecc, if NULL then calc_ecc is computed from @data 9374c6de856SChristian Hitz * @syn: hw computed syndrome data (if NULL, syndrome is calculated) 9384c6de856SChristian Hitz * @errloc: output array of error locations 9394c6de856SChristian Hitz * 9404c6de856SChristian Hitz * Returns: 9414c6de856SChristian Hitz * The number of errors found, or -EBADMSG if decoding failed, or -EINVAL if 9424c6de856SChristian Hitz * invalid parameters were provided 9434c6de856SChristian Hitz * 9444c6de856SChristian Hitz * Depending on the available hw BCH support and the need to compute @calc_ecc 9454c6de856SChristian Hitz * separately (using encode_bch()), this function should be called with one of 9464c6de856SChristian Hitz * the following parameter configurations - 9474c6de856SChristian Hitz * 9484c6de856SChristian Hitz * by providing @data and @recv_ecc only: 9494c6de856SChristian Hitz * decode_bch(@bch, @data, @len, @recv_ecc, NULL, NULL, @errloc) 9504c6de856SChristian Hitz * 9514c6de856SChristian Hitz * by providing @recv_ecc and @calc_ecc: 9524c6de856SChristian Hitz * decode_bch(@bch, NULL, @len, @recv_ecc, @calc_ecc, NULL, @errloc) 9534c6de856SChristian Hitz * 9544c6de856SChristian Hitz * by providing ecc = recv_ecc XOR calc_ecc: 9554c6de856SChristian Hitz * decode_bch(@bch, NULL, @len, NULL, ecc, NULL, @errloc) 9564c6de856SChristian Hitz * 9574c6de856SChristian Hitz * by providing syndrome results @syn: 9584c6de856SChristian Hitz * decode_bch(@bch, NULL, @len, NULL, NULL, @syn, @errloc) 9594c6de856SChristian Hitz * 9604c6de856SChristian Hitz * Once decode_bch() has successfully returned with a positive value, error 9614c6de856SChristian Hitz * locations returned in array @errloc should be interpreted as follows - 9624c6de856SChristian Hitz * 9634c6de856SChristian Hitz * if (errloc[n] >= 8*len), then n-th error is located in ecc (no need for 9644c6de856SChristian Hitz * data correction) 9654c6de856SChristian Hitz * 9664c6de856SChristian Hitz * if (errloc[n] < 8*len), then n-th error is located in data and can be 9674c6de856SChristian Hitz * corrected with statement data[errloc[n]/8] ^= 1 << (errloc[n] % 8); 9684c6de856SChristian Hitz * 9694c6de856SChristian Hitz * Note that this function does not perform any data correction by itself, it 9704c6de856SChristian Hitz * merely indicates error locations. 9714c6de856SChristian Hitz */ 9724c6de856SChristian Hitz int decode_bch(struct bch_control *bch, const uint8_t *data, unsigned int len, 9734c6de856SChristian Hitz const uint8_t *recv_ecc, const uint8_t *calc_ecc, 9744c6de856SChristian Hitz const unsigned int *syn, unsigned int *errloc) 9754c6de856SChristian Hitz { 9764c6de856SChristian Hitz const unsigned int ecc_words = BCH_ECC_WORDS(bch); 9774c6de856SChristian Hitz unsigned int nbits; 9784c6de856SChristian Hitz int i, err, nroots; 9794c6de856SChristian Hitz uint32_t sum; 9804c6de856SChristian Hitz 9814c6de856SChristian Hitz /* sanity check: make sure data length can be handled */ 9824c6de856SChristian Hitz if (8*len > (bch->n-bch->ecc_bits)) 9834c6de856SChristian Hitz return -EINVAL; 9844c6de856SChristian Hitz 9854c6de856SChristian Hitz /* if caller does not provide syndromes, compute them */ 9864c6de856SChristian Hitz if (!syn) { 9874c6de856SChristian Hitz if (!calc_ecc) { 9884c6de856SChristian Hitz /* compute received data ecc into an internal buffer */ 9894c6de856SChristian Hitz if (!data || !recv_ecc) 9904c6de856SChristian Hitz return -EINVAL; 9914c6de856SChristian Hitz encode_bch(bch, data, len, NULL); 9924c6de856SChristian Hitz } else { 9934c6de856SChristian Hitz /* load provided calculated ecc */ 9944c6de856SChristian Hitz load_ecc8(bch, bch->ecc_buf, calc_ecc); 9954c6de856SChristian Hitz } 9964c6de856SChristian Hitz /* load received ecc or assume it was XORed in calc_ecc */ 9974c6de856SChristian Hitz if (recv_ecc) { 9984c6de856SChristian Hitz load_ecc8(bch, bch->ecc_buf2, recv_ecc); 9994c6de856SChristian Hitz /* XOR received and calculated ecc */ 10004c6de856SChristian Hitz for (i = 0, sum = 0; i < (int)ecc_words; i++) { 10014c6de856SChristian Hitz bch->ecc_buf[i] ^= bch->ecc_buf2[i]; 10024c6de856SChristian Hitz sum |= bch->ecc_buf[i]; 10034c6de856SChristian Hitz } 10044c6de856SChristian Hitz if (!sum) 10054c6de856SChristian Hitz /* no error found */ 10064c6de856SChristian Hitz return 0; 10074c6de856SChristian Hitz } 10084c6de856SChristian Hitz compute_syndromes(bch, bch->ecc_buf, bch->syn); 10094c6de856SChristian Hitz syn = bch->syn; 10104c6de856SChristian Hitz } 10114c6de856SChristian Hitz 10124c6de856SChristian Hitz err = compute_error_locator_polynomial(bch, syn); 10134c6de856SChristian Hitz if (err > 0) { 10144c6de856SChristian Hitz nroots = find_poly_roots(bch, 1, bch->elp, errloc); 10154c6de856SChristian Hitz if (err != nroots) 10164c6de856SChristian Hitz err = -1; 10174c6de856SChristian Hitz } 10184c6de856SChristian Hitz if (err > 0) { 10194c6de856SChristian Hitz /* post-process raw error locations for easier correction */ 10204c6de856SChristian Hitz nbits = (len*8)+bch->ecc_bits; 10214c6de856SChristian Hitz for (i = 0; i < err; i++) { 10224c6de856SChristian Hitz if (errloc[i] >= nbits) { 10234c6de856SChristian Hitz err = -1; 10244c6de856SChristian Hitz break; 10254c6de856SChristian Hitz } 10264c6de856SChristian Hitz errloc[i] = nbits-1-errloc[i]; 10274c6de856SChristian Hitz errloc[i] = (errloc[i] & ~7)|(7-(errloc[i] & 7)); 10284c6de856SChristian Hitz } 10294c6de856SChristian Hitz } 10304c6de856SChristian Hitz return (err >= 0) ? err : -EBADMSG; 10314c6de856SChristian Hitz } 10324c6de856SChristian Hitz 10334c6de856SChristian Hitz /* 10344c6de856SChristian Hitz * generate Galois field lookup tables 10354c6de856SChristian Hitz */ 10364c6de856SChristian Hitz static int build_gf_tables(struct bch_control *bch, unsigned int poly) 10374c6de856SChristian Hitz { 10384c6de856SChristian Hitz unsigned int i, x = 1; 10394c6de856SChristian Hitz const unsigned int k = 1 << deg(poly); 10404c6de856SChristian Hitz 10414c6de856SChristian Hitz /* primitive polynomial must be of degree m */ 10424c6de856SChristian Hitz if (k != (1u << GF_M(bch))) 10434c6de856SChristian Hitz return -1; 10444c6de856SChristian Hitz 10454c6de856SChristian Hitz for (i = 0; i < GF_N(bch); i++) { 10464c6de856SChristian Hitz bch->a_pow_tab[i] = x; 10474c6de856SChristian Hitz bch->a_log_tab[x] = i; 10484c6de856SChristian Hitz if (i && (x == 1)) 10494c6de856SChristian Hitz /* polynomial is not primitive (a^i=1 with 0<i<2^m-1) */ 10504c6de856SChristian Hitz return -1; 10514c6de856SChristian Hitz x <<= 1; 10524c6de856SChristian Hitz if (x & k) 10534c6de856SChristian Hitz x ^= poly; 10544c6de856SChristian Hitz } 10554c6de856SChristian Hitz bch->a_pow_tab[GF_N(bch)] = 1; 10564c6de856SChristian Hitz bch->a_log_tab[0] = 0; 10574c6de856SChristian Hitz 10584c6de856SChristian Hitz return 0; 10594c6de856SChristian Hitz } 10604c6de856SChristian Hitz 10614c6de856SChristian Hitz /* 10624c6de856SChristian Hitz * compute generator polynomial remainder tables for fast encoding 10634c6de856SChristian Hitz */ 10644c6de856SChristian Hitz static void build_mod8_tables(struct bch_control *bch, const uint32_t *g) 10654c6de856SChristian Hitz { 10664c6de856SChristian Hitz int i, j, b, d; 10674c6de856SChristian Hitz uint32_t data, hi, lo, *tab; 10684c6de856SChristian Hitz const int l = BCH_ECC_WORDS(bch); 10694c6de856SChristian Hitz const int plen = DIV_ROUND_UP(bch->ecc_bits+1, 32); 10704c6de856SChristian Hitz const int ecclen = DIV_ROUND_UP(bch->ecc_bits, 32); 10714c6de856SChristian Hitz 10724c6de856SChristian Hitz memset(bch->mod8_tab, 0, 4*256*l*sizeof(*bch->mod8_tab)); 10734c6de856SChristian Hitz 10744c6de856SChristian Hitz for (i = 0; i < 256; i++) { 10754c6de856SChristian Hitz /* p(X)=i is a small polynomial of weight <= 8 */ 10764c6de856SChristian Hitz for (b = 0; b < 4; b++) { 10774c6de856SChristian Hitz /* we want to compute (p(X).X^(8*b+deg(g))) mod g(X) */ 10784c6de856SChristian Hitz tab = bch->mod8_tab + (b*256+i)*l; 10794c6de856SChristian Hitz data = i << (8*b); 10804c6de856SChristian Hitz while (data) { 10814c6de856SChristian Hitz d = deg(data); 10824c6de856SChristian Hitz /* subtract X^d.g(X) from p(X).X^(8*b+deg(g)) */ 10834c6de856SChristian Hitz data ^= g[0] >> (31-d); 10844c6de856SChristian Hitz for (j = 0; j < ecclen; j++) { 10854c6de856SChristian Hitz hi = (d < 31) ? g[j] << (d+1) : 0; 10864c6de856SChristian Hitz lo = (j+1 < plen) ? 10874c6de856SChristian Hitz g[j+1] >> (31-d) : 0; 10884c6de856SChristian Hitz tab[j] ^= hi|lo; 10894c6de856SChristian Hitz } 10904c6de856SChristian Hitz } 10914c6de856SChristian Hitz } 10924c6de856SChristian Hitz } 10934c6de856SChristian Hitz } 10944c6de856SChristian Hitz 10954c6de856SChristian Hitz /* 10964c6de856SChristian Hitz * build a base for factoring degree 2 polynomials 10974c6de856SChristian Hitz */ 10984c6de856SChristian Hitz static int build_deg2_base(struct bch_control *bch) 10994c6de856SChristian Hitz { 11004c6de856SChristian Hitz const int m = GF_M(bch); 11014c6de856SChristian Hitz int i, j, r; 11024c6de856SChristian Hitz unsigned int sum, x, y, remaining, ak = 0, xi[m]; 11034c6de856SChristian Hitz 11044c6de856SChristian Hitz /* find k s.t. Tr(a^k) = 1 and 0 <= k < m */ 11054c6de856SChristian Hitz for (i = 0; i < m; i++) { 11064c6de856SChristian Hitz for (j = 0, sum = 0; j < m; j++) 11074c6de856SChristian Hitz sum ^= a_pow(bch, i*(1 << j)); 11084c6de856SChristian Hitz 11094c6de856SChristian Hitz if (sum) { 11104c6de856SChristian Hitz ak = bch->a_pow_tab[i]; 11114c6de856SChristian Hitz break; 11124c6de856SChristian Hitz } 11134c6de856SChristian Hitz } 11144c6de856SChristian Hitz /* find xi, i=0..m-1 such that xi^2+xi = a^i+Tr(a^i).a^k */ 11154c6de856SChristian Hitz remaining = m; 11164c6de856SChristian Hitz memset(xi, 0, sizeof(xi)); 11174c6de856SChristian Hitz 11184c6de856SChristian Hitz for (x = 0; (x <= GF_N(bch)) && remaining; x++) { 11194c6de856SChristian Hitz y = gf_sqr(bch, x)^x; 11204c6de856SChristian Hitz for (i = 0; i < 2; i++) { 11214c6de856SChristian Hitz r = a_log(bch, y); 11224c6de856SChristian Hitz if (y && (r < m) && !xi[r]) { 11234c6de856SChristian Hitz bch->xi_tab[r] = x; 11244c6de856SChristian Hitz xi[r] = 1; 11254c6de856SChristian Hitz remaining--; 11264c6de856SChristian Hitz dbg("x%d = %x\n", r, x); 11274c6de856SChristian Hitz break; 11284c6de856SChristian Hitz } 11294c6de856SChristian Hitz y ^= ak; 11304c6de856SChristian Hitz } 11314c6de856SChristian Hitz } 11324c6de856SChristian Hitz /* should not happen but check anyway */ 11334c6de856SChristian Hitz return remaining ? -1 : 0; 11344c6de856SChristian Hitz } 11354c6de856SChristian Hitz 11364c6de856SChristian Hitz static void *bch_alloc(size_t size, int *err) 11374c6de856SChristian Hitz { 11384c6de856SChristian Hitz void *ptr; 11394c6de856SChristian Hitz 11404c6de856SChristian Hitz ptr = kmalloc(size, GFP_KERNEL); 11414c6de856SChristian Hitz if (ptr == NULL) 11424c6de856SChristian Hitz *err = 1; 11434c6de856SChristian Hitz return ptr; 11444c6de856SChristian Hitz } 11454c6de856SChristian Hitz 11464c6de856SChristian Hitz /* 11474c6de856SChristian Hitz * compute generator polynomial for given (m,t) parameters. 11484c6de856SChristian Hitz */ 11494c6de856SChristian Hitz static uint32_t *compute_generator_polynomial(struct bch_control *bch) 11504c6de856SChristian Hitz { 11514c6de856SChristian Hitz const unsigned int m = GF_M(bch); 11524c6de856SChristian Hitz const unsigned int t = GF_T(bch); 11534c6de856SChristian Hitz int n, err = 0; 11544c6de856SChristian Hitz unsigned int i, j, nbits, r, word, *roots; 11554c6de856SChristian Hitz struct gf_poly *g; 11564c6de856SChristian Hitz uint32_t *genpoly; 11574c6de856SChristian Hitz 11584c6de856SChristian Hitz g = bch_alloc(GF_POLY_SZ(m*t), &err); 11594c6de856SChristian Hitz roots = bch_alloc((bch->n+1)*sizeof(*roots), &err); 11604c6de856SChristian Hitz genpoly = bch_alloc(DIV_ROUND_UP(m*t+1, 32)*sizeof(*genpoly), &err); 11614c6de856SChristian Hitz 11624c6de856SChristian Hitz if (err) { 11634c6de856SChristian Hitz kfree(genpoly); 11644c6de856SChristian Hitz genpoly = NULL; 11654c6de856SChristian Hitz goto finish; 11664c6de856SChristian Hitz } 11674c6de856SChristian Hitz 11684c6de856SChristian Hitz /* enumerate all roots of g(X) */ 11694c6de856SChristian Hitz memset(roots , 0, (bch->n+1)*sizeof(*roots)); 11704c6de856SChristian Hitz for (i = 0; i < t; i++) { 11714c6de856SChristian Hitz for (j = 0, r = 2*i+1; j < m; j++) { 11724c6de856SChristian Hitz roots[r] = 1; 11734c6de856SChristian Hitz r = mod_s(bch, 2*r); 11744c6de856SChristian Hitz } 11754c6de856SChristian Hitz } 11764c6de856SChristian Hitz /* build generator polynomial g(X) */ 11774c6de856SChristian Hitz g->deg = 0; 11784c6de856SChristian Hitz g->c[0] = 1; 11794c6de856SChristian Hitz for (i = 0; i < GF_N(bch); i++) { 11804c6de856SChristian Hitz if (roots[i]) { 11814c6de856SChristian Hitz /* multiply g(X) by (X+root) */ 11824c6de856SChristian Hitz r = bch->a_pow_tab[i]; 11834c6de856SChristian Hitz g->c[g->deg+1] = 1; 11844c6de856SChristian Hitz for (j = g->deg; j > 0; j--) 11854c6de856SChristian Hitz g->c[j] = gf_mul(bch, g->c[j], r)^g->c[j-1]; 11864c6de856SChristian Hitz 11874c6de856SChristian Hitz g->c[0] = gf_mul(bch, g->c[0], r); 11884c6de856SChristian Hitz g->deg++; 11894c6de856SChristian Hitz } 11904c6de856SChristian Hitz } 11914c6de856SChristian Hitz /* store left-justified binary representation of g(X) */ 11924c6de856SChristian Hitz n = g->deg+1; 11934c6de856SChristian Hitz i = 0; 11944c6de856SChristian Hitz 11954c6de856SChristian Hitz while (n > 0) { 11964c6de856SChristian Hitz nbits = (n > 32) ? 32 : n; 11974c6de856SChristian Hitz for (j = 0, word = 0; j < nbits; j++) { 11984c6de856SChristian Hitz if (g->c[n-1-j]) 11994c6de856SChristian Hitz word |= 1u << (31-j); 12004c6de856SChristian Hitz } 12014c6de856SChristian Hitz genpoly[i++] = word; 12024c6de856SChristian Hitz n -= nbits; 12034c6de856SChristian Hitz } 12044c6de856SChristian Hitz bch->ecc_bits = g->deg; 12054c6de856SChristian Hitz 12064c6de856SChristian Hitz finish: 12074c6de856SChristian Hitz kfree(g); 12084c6de856SChristian Hitz kfree(roots); 12094c6de856SChristian Hitz 12104c6de856SChristian Hitz return genpoly; 12114c6de856SChristian Hitz } 12124c6de856SChristian Hitz 12134c6de856SChristian Hitz /** 12144c6de856SChristian Hitz * init_bch - initialize a BCH encoder/decoder 12154c6de856SChristian Hitz * @m: Galois field order, should be in the range 5-15 12164c6de856SChristian Hitz * @t: maximum error correction capability, in bits 12174c6de856SChristian Hitz * @prim_poly: user-provided primitive polynomial (or 0 to use default) 12184c6de856SChristian Hitz * 12194c6de856SChristian Hitz * Returns: 12204c6de856SChristian Hitz * a newly allocated BCH control structure if successful, NULL otherwise 12214c6de856SChristian Hitz * 12224c6de856SChristian Hitz * This initialization can take some time, as lookup tables are built for fast 12234c6de856SChristian Hitz * encoding/decoding; make sure not to call this function from a time critical 12244c6de856SChristian Hitz * path. Usually, init_bch() should be called on module/driver init and 12254c6de856SChristian Hitz * free_bch() should be called to release memory on exit. 12264c6de856SChristian Hitz * 12274c6de856SChristian Hitz * You may provide your own primitive polynomial of degree @m in argument 12284c6de856SChristian Hitz * @prim_poly, or let init_bch() use its default polynomial. 12294c6de856SChristian Hitz * 12304c6de856SChristian Hitz * Once init_bch() has successfully returned a pointer to a newly allocated 12314c6de856SChristian Hitz * BCH control structure, ecc length in bytes is given by member @ecc_bytes of 12324c6de856SChristian Hitz * the structure. 12334c6de856SChristian Hitz */ 12344c6de856SChristian Hitz struct bch_control *init_bch(int m, int t, unsigned int prim_poly) 12354c6de856SChristian Hitz { 12364c6de856SChristian Hitz int err = 0; 12374c6de856SChristian Hitz unsigned int i, words; 12384c6de856SChristian Hitz uint32_t *genpoly; 12394c6de856SChristian Hitz struct bch_control *bch = NULL; 12404c6de856SChristian Hitz 12414c6de856SChristian Hitz const int min_m = 5; 12424c6de856SChristian Hitz const int max_m = 15; 12434c6de856SChristian Hitz 12444c6de856SChristian Hitz /* default primitive polynomials */ 12454c6de856SChristian Hitz static const unsigned int prim_poly_tab[] = { 12464c6de856SChristian Hitz 0x25, 0x43, 0x83, 0x11d, 0x211, 0x409, 0x805, 0x1053, 0x201b, 12474c6de856SChristian Hitz 0x402b, 0x8003, 12484c6de856SChristian Hitz }; 12494c6de856SChristian Hitz 12504c6de856SChristian Hitz #if defined(CONFIG_BCH_CONST_PARAMS) 12514c6de856SChristian Hitz if ((m != (CONFIG_BCH_CONST_M)) || (t != (CONFIG_BCH_CONST_T))) { 12524c6de856SChristian Hitz printk(KERN_ERR "bch encoder/decoder was configured to support " 12534c6de856SChristian Hitz "parameters m=%d, t=%d only!\n", 12544c6de856SChristian Hitz CONFIG_BCH_CONST_M, CONFIG_BCH_CONST_T); 12554c6de856SChristian Hitz goto fail; 12564c6de856SChristian Hitz } 12574c6de856SChristian Hitz #endif 12584c6de856SChristian Hitz if ((m < min_m) || (m > max_m)) 12594c6de856SChristian Hitz /* 12604c6de856SChristian Hitz * values of m greater than 15 are not currently supported; 12614c6de856SChristian Hitz * supporting m > 15 would require changing table base type 12624c6de856SChristian Hitz * (uint16_t) and a small patch in matrix transposition 12634c6de856SChristian Hitz */ 12644c6de856SChristian Hitz goto fail; 12654c6de856SChristian Hitz 12664c6de856SChristian Hitz /* sanity checks */ 12674c6de856SChristian Hitz if ((t < 1) || (m*t >= ((1 << m)-1))) 12684c6de856SChristian Hitz /* invalid t value */ 12694c6de856SChristian Hitz goto fail; 12704c6de856SChristian Hitz 12714c6de856SChristian Hitz /* select a primitive polynomial for generating GF(2^m) */ 12724c6de856SChristian Hitz if (prim_poly == 0) 12734c6de856SChristian Hitz prim_poly = prim_poly_tab[m-min_m]; 12744c6de856SChristian Hitz 12754c6de856SChristian Hitz bch = kzalloc(sizeof(*bch), GFP_KERNEL); 12764c6de856SChristian Hitz if (bch == NULL) 12774c6de856SChristian Hitz goto fail; 12784c6de856SChristian Hitz 12794c6de856SChristian Hitz bch->m = m; 12804c6de856SChristian Hitz bch->t = t; 12814c6de856SChristian Hitz bch->n = (1 << m)-1; 12824c6de856SChristian Hitz words = DIV_ROUND_UP(m*t, 32); 12834c6de856SChristian Hitz bch->ecc_bytes = DIV_ROUND_UP(m*t, 8); 12844c6de856SChristian Hitz bch->a_pow_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_pow_tab), &err); 12854c6de856SChristian Hitz bch->a_log_tab = bch_alloc((1+bch->n)*sizeof(*bch->a_log_tab), &err); 12864c6de856SChristian Hitz bch->mod8_tab = bch_alloc(words*1024*sizeof(*bch->mod8_tab), &err); 12874c6de856SChristian Hitz bch->ecc_buf = bch_alloc(words*sizeof(*bch->ecc_buf), &err); 12884c6de856SChristian Hitz bch->ecc_buf2 = bch_alloc(words*sizeof(*bch->ecc_buf2), &err); 12894c6de856SChristian Hitz bch->xi_tab = bch_alloc(m*sizeof(*bch->xi_tab), &err); 12904c6de856SChristian Hitz bch->syn = bch_alloc(2*t*sizeof(*bch->syn), &err); 12914c6de856SChristian Hitz bch->cache = bch_alloc(2*t*sizeof(*bch->cache), &err); 12924c6de856SChristian Hitz bch->elp = bch_alloc((t+1)*sizeof(struct gf_poly_deg1), &err); 12934c6de856SChristian Hitz 12944c6de856SChristian Hitz for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) 12954c6de856SChristian Hitz bch->poly_2t[i] = bch_alloc(GF_POLY_SZ(2*t), &err); 12964c6de856SChristian Hitz 12974c6de856SChristian Hitz if (err) 12984c6de856SChristian Hitz goto fail; 12994c6de856SChristian Hitz 13004c6de856SChristian Hitz err = build_gf_tables(bch, prim_poly); 13014c6de856SChristian Hitz if (err) 13024c6de856SChristian Hitz goto fail; 13034c6de856SChristian Hitz 13044c6de856SChristian Hitz /* use generator polynomial for computing encoding tables */ 13054c6de856SChristian Hitz genpoly = compute_generator_polynomial(bch); 13064c6de856SChristian Hitz if (genpoly == NULL) 13074c6de856SChristian Hitz goto fail; 13084c6de856SChristian Hitz 13094c6de856SChristian Hitz build_mod8_tables(bch, genpoly); 13104c6de856SChristian Hitz kfree(genpoly); 13114c6de856SChristian Hitz 13124c6de856SChristian Hitz err = build_deg2_base(bch); 13134c6de856SChristian Hitz if (err) 13144c6de856SChristian Hitz goto fail; 13154c6de856SChristian Hitz 13164c6de856SChristian Hitz return bch; 13174c6de856SChristian Hitz 13184c6de856SChristian Hitz fail: 13194c6de856SChristian Hitz free_bch(bch); 13204c6de856SChristian Hitz return NULL; 13214c6de856SChristian Hitz } 13224c6de856SChristian Hitz 13234c6de856SChristian Hitz /** 13244c6de856SChristian Hitz * free_bch - free the BCH control structure 13254c6de856SChristian Hitz * @bch: BCH control structure to release 13264c6de856SChristian Hitz */ 13274c6de856SChristian Hitz void free_bch(struct bch_control *bch) 13284c6de856SChristian Hitz { 13294c6de856SChristian Hitz unsigned int i; 13304c6de856SChristian Hitz 13314c6de856SChristian Hitz if (bch) { 13324c6de856SChristian Hitz kfree(bch->a_pow_tab); 13334c6de856SChristian Hitz kfree(bch->a_log_tab); 13344c6de856SChristian Hitz kfree(bch->mod8_tab); 13354c6de856SChristian Hitz kfree(bch->ecc_buf); 13364c6de856SChristian Hitz kfree(bch->ecc_buf2); 13374c6de856SChristian Hitz kfree(bch->xi_tab); 13384c6de856SChristian Hitz kfree(bch->syn); 13394c6de856SChristian Hitz kfree(bch->cache); 13404c6de856SChristian Hitz kfree(bch->elp); 13414c6de856SChristian Hitz 13424c6de856SChristian Hitz for (i = 0; i < ARRAY_SIZE(bch->poly_2t); i++) 13434c6de856SChristian Hitz kfree(bch->poly_2t[i]); 13444c6de856SChristian Hitz 13454c6de856SChristian Hitz kfree(bch); 13464c6de856SChristian Hitz } 13474c6de856SChristian Hitz } 1348