1 // SPDX-License-Identifier: GPL-2.0
3 * Generic Reed Solomon encoder / decoder library
5 * Copyright 2002, Phil Karn, KA9Q
6 * May be used under the terms of the GNU General Public License (GPL)
8 * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
10 * Generic data width independent code which is included by the wrappers.
13 struct rs_codec
*rs
= rsc
->codec
;
14 int deg_lambda
, el
, deg_omega
;
17 int nroots
= rs
->nroots
;
20 int iprim
= rs
->iprim
;
21 uint16_t *alpha_to
= rs
->alpha_to
;
22 uint16_t *index_of
= rs
->index_of
;
23 uint16_t u
, q
, tmp
, num1
, num2
, den
, discr_r
, syn_error
;
26 uint16_t msk
= (uint16_t) rs
->nn
;
29 * The decoder buffers are in the rs control struct. They are
30 * arrays sized [nroots + 1]
32 uint16_t *lambda
= rsc
->buffers
+ RS_DECODE_LAMBDA
* (nroots
+ 1);
33 uint16_t *syn
= rsc
->buffers
+ RS_DECODE_SYN
* (nroots
+ 1);
34 uint16_t *b
= rsc
->buffers
+ RS_DECODE_B
* (nroots
+ 1);
35 uint16_t *t
= rsc
->buffers
+ RS_DECODE_T
* (nroots
+ 1);
36 uint16_t *omega
= rsc
->buffers
+ RS_DECODE_OMEGA
* (nroots
+ 1);
37 uint16_t *root
= rsc
->buffers
+ RS_DECODE_ROOT
* (nroots
+ 1);
38 uint16_t *reg
= rsc
->buffers
+ RS_DECODE_REG
* (nroots
+ 1);
39 uint16_t *loc
= rsc
->buffers
+ RS_DECODE_LOC
* (nroots
+ 1);
41 /* Check length parameter for validity */
42 pad
= nn
- nroots
- len
;
43 BUG_ON(pad
< 0 || pad
>= nn
- nroots
);
45 /* Does the caller provide the syndrome ? */
47 for (i
= 0; i
< nroots
; i
++) {
48 /* The syndrome is in index form,
49 * so nn represents zero
55 /* syndrome is zero, no errors to correct */
59 /* form the syndromes; i.e., evaluate data(x) at roots of
61 for (i
= 0; i
< nroots
; i
++)
62 syn
[i
] = (((uint16_t) data
[0]) ^ invmsk
) & msk
;
64 for (j
= 1; j
< len
; j
++) {
65 for (i
= 0; i
< nroots
; i
++) {
67 syn
[i
] = (((uint16_t) data
[j
]) ^
70 syn
[i
] = ((((uint16_t) data
[j
]) ^
72 alpha_to
[rs_modnn(rs
, index_of
[syn
[i
]] +
78 for (j
= 0; j
< nroots
; j
++) {
79 for (i
= 0; i
< nroots
; i
++) {
81 syn
[i
] = ((uint16_t) par
[j
]) & msk
;
83 syn
[i
] = (((uint16_t) par
[j
]) & msk
) ^
84 alpha_to
[rs_modnn(rs
, index_of
[syn
[i
]] +
91 /* Convert syndromes to index form, checking for nonzero condition */
93 for (i
= 0; i
< nroots
; i
++) {
95 s
[i
] = index_of
[s
[i
]];
99 /* if syndrome is zero, data[] is a codeword and there are no
100 * errors to correct. So return data[] unmodified
106 memset(&lambda
[1], 0, nroots
* sizeof(lambda
[0]));
110 /* Init lambda to be the erasure locator polynomial */
111 lambda
[1] = alpha_to
[rs_modnn(rs
,
112 prim
* (nn
- 1 - (eras_pos
[0] + pad
)))];
113 for (i
= 1; i
< no_eras
; i
++) {
114 u
= rs_modnn(rs
, prim
* (nn
- 1 - (eras_pos
[i
] + pad
)));
115 for (j
= i
+ 1; j
> 0; j
--) {
116 tmp
= index_of
[lambda
[j
- 1]];
119 alpha_to
[rs_modnn(rs
, u
+ tmp
)];
125 for (i
= 0; i
< nroots
+ 1; i
++)
126 b
[i
] = index_of
[lambda
[i
]];
129 * Begin Berlekamp-Massey algorithm to determine error+erasure
134 while (++r
<= nroots
) { /* r is the step number */
135 /* Compute discrepancy at the r-th step in poly-form */
137 for (i
= 0; i
< r
; i
++) {
138 if ((lambda
[i
] != 0) && (s
[r
- i
- 1] != nn
)) {
140 alpha_to
[rs_modnn(rs
,
141 index_of
[lambda
[i
]] +
145 discr_r
= index_of
[discr_r
]; /* Index form */
147 /* 2 lines below: B(x) <-- x*B(x) */
148 memmove (&b
[1], b
, nroots
* sizeof (b
[0]));
151 /* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
153 for (i
= 0; i
< nroots
; i
++) {
155 t
[i
+ 1] = lambda
[i
+ 1] ^
156 alpha_to
[rs_modnn(rs
, discr_r
+
159 t
[i
+ 1] = lambda
[i
+ 1];
161 if (2 * el
<= r
+ no_eras
- 1) {
162 el
= r
+ no_eras
- el
;
164 * 2 lines below: B(x) <-- inv(discr_r) *
167 for (i
= 0; i
<= nroots
; i
++) {
168 b
[i
] = (lambda
[i
] == 0) ? nn
:
169 rs_modnn(rs
, index_of
[lambda
[i
]]
173 /* 2 lines below: B(x) <-- x*B(x) */
174 memmove(&b
[1], b
, nroots
* sizeof(b
[0]));
177 memcpy(lambda
, t
, (nroots
+ 1) * sizeof(t
[0]));
181 /* Convert lambda to index form and compute deg(lambda(x)) */
183 for (i
= 0; i
< nroots
+ 1; i
++) {
184 lambda
[i
] = index_of
[lambda
[i
]];
189 if (deg_lambda
== 0) {
191 * deg(lambda) is zero even though the syndrome is non-zero
192 * => uncorrectable error detected
197 /* Find roots of error+erasure locator polynomial by Chien search */
198 memcpy(®
[1], &lambda
[1], nroots
* sizeof(reg
[0]));
199 count
= 0; /* Number of roots of lambda(x) */
200 for (i
= 1, k
= iprim
- 1; i
<= nn
; i
++, k
= rs_modnn(rs
, k
+ iprim
)) {
201 q
= 1; /* lambda[0] is always 0 */
202 for (j
= deg_lambda
; j
> 0; j
--) {
204 reg
[j
] = rs_modnn(rs
, reg
[j
] + j
);
205 q
^= alpha_to
[reg
[j
]];
209 continue; /* Not a root */
212 /* Impossible error location. Uncorrectable error. */
216 /* store root (index-form) and error location number */
219 /* If we've already found max possible roots,
220 * abort the search to save time
222 if (++count
== deg_lambda
)
225 if (deg_lambda
!= count
) {
227 * deg(lambda) unequal to number of roots => uncorrectable
233 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
234 * x**nroots). in index form. Also find deg(omega).
236 deg_omega
= deg_lambda
- 1;
237 for (i
= 0; i
<= deg_omega
; i
++) {
239 for (j
= i
; j
>= 0; j
--) {
240 if ((s
[i
- j
] != nn
) && (lambda
[j
] != nn
))
242 alpha_to
[rs_modnn(rs
, s
[i
- j
] + lambda
[j
])];
244 omega
[i
] = index_of
[tmp
];
248 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
249 * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
250 * Note: we reuse the buffer for b to store the correction pattern
253 for (j
= count
- 1; j
>= 0; j
--) {
255 for (i
= deg_omega
; i
>= 0; i
--) {
257 num1
^= alpha_to
[rs_modnn(rs
, omega
[i
] +
262 /* Nothing to correct at this position */
267 num2
= alpha_to
[rs_modnn(rs
, root
[j
] * (fcr
- 1) + nn
)];
270 /* lambda[i+1] for i even is the formal derivative
271 * lambda_pr of lambda[i] */
272 for (i
= min(deg_lambda
, nroots
- 1) & ~1; i
>= 0; i
-= 2) {
273 if (lambda
[i
+ 1] != nn
) {
274 den
^= alpha_to
[rs_modnn(rs
, lambda
[i
+ 1] +
279 b
[j
] = alpha_to
[rs_modnn(rs
, index_of
[num1
] +
281 nn
- index_of
[den
])];
286 * We compute the syndrome of the 'error' and check that it matches
287 * the syndrome of the received word
289 for (i
= 0; i
< nroots
; i
++) {
291 for (j
= 0; j
< count
; j
++) {
295 k
= (fcr
+ i
) * prim
* (nn
-loc
[j
]-1);
296 tmp
^= alpha_to
[rs_modnn(rs
, index_of
[b
[j
]] + k
)];
299 if (tmp
!= alpha_to
[s
[i
]])
304 * Store the error correction pattern, if a
305 * correction buffer is available
307 if (corr
&& eras_pos
) {
309 for (i
= 0; i
< count
; i
++) {
312 eras_pos
[j
++] = loc
[i
] - pad
;
315 } else if (data
&& par
) {
316 /* Apply error to data and parity */
317 for (i
= 0; i
< count
; i
++) {
318 if (loc
[i
] < (nn
- nroots
))
319 data
[loc
[i
] - pad
] ^= b
[i
];
321 par
[loc
[i
] - pad
- len
] ^= b
[i
];
325 return num_corrected
;