xref: /openbmc/linux/lib/reed_solomon/decode_rs.c (revision 0898782247ae533d1f4e47a06bc5d4870931b284)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Generic Reed Solomon encoder / decoder library
4   *
5   * Copyright 2002, Phil Karn, KA9Q
6   * May be used under the terms of the GNU General Public License (GPL)
7   *
8   * Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
9   *
10   * Generic data width independent code which is included by the wrappers.
11   */
12  {
13  	struct rs_codec *rs = rsc->codec;
14  	int deg_lambda, el, deg_omega;
15  	int i, j, r, k, pad;
16  	int nn = rs->nn;
17  	int nroots = rs->nroots;
18  	int fcr = rs->fcr;
19  	int prim = rs->prim;
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;
24  	int count = 0;
25  	int num_corrected;
26  	uint16_t msk = (uint16_t) rs->nn;
27  
28  	/*
29  	 * The decoder buffers are in the rs control struct. They are
30  	 * arrays sized [nroots + 1]
31  	 */
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);
40  
41  	/* Check length parameter for validity */
42  	pad = nn - nroots - len;
43  	BUG_ON(pad < 0 || pad >= nn - nroots);
44  
45  	/* Does the caller provide the syndrome ? */
46  	if (s != NULL) {
47  		for (i = 0; i < nroots; i++) {
48  			/* The syndrome is in index form,
49  			 * so nn represents zero
50  			 */
51  			if (s[i] != nn)
52  				goto decode;
53  		}
54  
55  		/* syndrome is zero, no errors to correct  */
56  		return 0;
57  	}
58  
59  	/* form the syndromes; i.e., evaluate data(x) at roots of
60  	 * g(x) */
61  	for (i = 0; i < nroots; i++)
62  		syn[i] = (((uint16_t) data[0]) ^ invmsk) & msk;
63  
64  	for (j = 1; j < len; j++) {
65  		for (i = 0; i < nroots; i++) {
66  			if (syn[i] == 0) {
67  				syn[i] = (((uint16_t) data[j]) ^
68  					  invmsk) & msk;
69  			} else {
70  				syn[i] = ((((uint16_t) data[j]) ^
71  					   invmsk) & msk) ^
72  					alpha_to[rs_modnn(rs, index_of[syn[i]] +
73  						       (fcr + i) * prim)];
74  			}
75  		}
76  	}
77  
78  	for (j = 0; j < nroots; j++) {
79  		for (i = 0; i < nroots; i++) {
80  			if (syn[i] == 0) {
81  				syn[i] = ((uint16_t) par[j]) & msk;
82  			} else {
83  				syn[i] = (((uint16_t) par[j]) & msk) ^
84  					alpha_to[rs_modnn(rs, index_of[syn[i]] +
85  						       (fcr+i)*prim)];
86  			}
87  		}
88  	}
89  	s = syn;
90  
91  	/* Convert syndromes to index form, checking for nonzero condition */
92  	syn_error = 0;
93  	for (i = 0; i < nroots; i++) {
94  		syn_error |= s[i];
95  		s[i] = index_of[s[i]];
96  	}
97  
98  	if (!syn_error) {
99  		/* if syndrome is zero, data[] is a codeword and there are no
100  		 * errors to correct. So return data[] unmodified
101  		 */
102  		return 0;
103  	}
104  
105   decode:
106  	memset(&lambda[1], 0, nroots * sizeof(lambda[0]));
107  	lambda[0] = 1;
108  
109  	if (no_eras > 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]];
117  				if (tmp != nn) {
118  					lambda[j] ^=
119  						alpha_to[rs_modnn(rs, u + tmp)];
120  				}
121  			}
122  		}
123  	}
124  
125  	for (i = 0; i < nroots + 1; i++)
126  		b[i] = index_of[lambda[i]];
127  
128  	/*
129  	 * Begin Berlekamp-Massey algorithm to determine error+erasure
130  	 * locator polynomial
131  	 */
132  	r = no_eras;
133  	el = no_eras;
134  	while (++r <= nroots) {	/* r is the step number */
135  		/* Compute discrepancy at the r-th step in poly-form */
136  		discr_r = 0;
137  		for (i = 0; i < r; i++) {
138  			if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
139  				discr_r ^=
140  					alpha_to[rs_modnn(rs,
141  							  index_of[lambda[i]] +
142  							  s[r - i - 1])];
143  			}
144  		}
145  		discr_r = index_of[discr_r];	/* Index form */
146  		if (discr_r == nn) {
147  			/* 2 lines below: B(x) <-- x*B(x) */
148  			memmove (&b[1], b, nroots * sizeof (b[0]));
149  			b[0] = nn;
150  		} else {
151  			/* 7 lines below: T(x) <-- lambda(x)-discr_r*x*b(x) */
152  			t[0] = lambda[0];
153  			for (i = 0; i < nroots; i++) {
154  				if (b[i] != nn) {
155  					t[i + 1] = lambda[i + 1] ^
156  						alpha_to[rs_modnn(rs, discr_r +
157  								  b[i])];
158  				} else
159  					t[i + 1] = lambda[i + 1];
160  			}
161  			if (2 * el <= r + no_eras - 1) {
162  				el = r + no_eras - el;
163  				/*
164  				 * 2 lines below: B(x) <-- inv(discr_r) *
165  				 * lambda(x)
166  				 */
167  				for (i = 0; i <= nroots; i++) {
168  					b[i] = (lambda[i] == 0) ? nn :
169  						rs_modnn(rs, index_of[lambda[i]]
170  							 - discr_r + nn);
171  				}
172  			} else {
173  				/* 2 lines below: B(x) <-- x*B(x) */
174  				memmove(&b[1], b, nroots * sizeof(b[0]));
175  				b[0] = nn;
176  			}
177  			memcpy(lambda, t, (nroots + 1) * sizeof(t[0]));
178  		}
179  	}
180  
181  	/* Convert lambda to index form and compute deg(lambda(x)) */
182  	deg_lambda = 0;
183  	for (i = 0; i < nroots + 1; i++) {
184  		lambda[i] = index_of[lambda[i]];
185  		if (lambda[i] != nn)
186  			deg_lambda = i;
187  	}
188  
189  	if (deg_lambda == 0) {
190  		/*
191  		 * deg(lambda) is zero even though the syndrome is non-zero
192  		 * => uncorrectable error detected
193  		 */
194  		return -EBADMSG;
195  	}
196  
197  	/* Find roots of error+erasure locator polynomial by Chien search */
198  	memcpy(&reg[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--) {
203  			if (reg[j] != nn) {
204  				reg[j] = rs_modnn(rs, reg[j] + j);
205  				q ^= alpha_to[reg[j]];
206  			}
207  		}
208  		if (q != 0)
209  			continue;	/* Not a root */
210  
211  		if (k < pad) {
212  			/* Impossible error location. Uncorrectable error. */
213  			return -EBADMSG;
214  		}
215  
216  		/* store root (index-form) and error location number */
217  		root[count] = i;
218  		loc[count] = k;
219  		/* If we've already found max possible roots,
220  		 * abort the search to save time
221  		 */
222  		if (++count == deg_lambda)
223  			break;
224  	}
225  	if (deg_lambda != count) {
226  		/*
227  		 * deg(lambda) unequal to number of roots => uncorrectable
228  		 * error detected
229  		 */
230  		return -EBADMSG;
231  	}
232  	/*
233  	 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
234  	 * x**nroots). in index form. Also find deg(omega).
235  	 */
236  	deg_omega = deg_lambda - 1;
237  	for (i = 0; i <= deg_omega; i++) {
238  		tmp = 0;
239  		for (j = i; j >= 0; j--) {
240  			if ((s[i - j] != nn) && (lambda[j] != nn))
241  				tmp ^=
242  				    alpha_to[rs_modnn(rs, s[i - j] + lambda[j])];
243  		}
244  		omega[i] = index_of[tmp];
245  	}
246  
247  	/*
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
251  	 */
252  	num_corrected = 0;
253  	for (j = count - 1; j >= 0; j--) {
254  		num1 = 0;
255  		for (i = deg_omega; i >= 0; i--) {
256  			if (omega[i] != nn)
257  				num1 ^= alpha_to[rs_modnn(rs, omega[i] +
258  							i * root[j])];
259  		}
260  
261  		if (num1 == 0) {
262  			/* Nothing to correct at this position */
263  			b[j] = 0;
264  			continue;
265  		}
266  
267  		num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
268  		den = 0;
269  
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] +
275  						       i * root[j])];
276  			}
277  		}
278  
279  		b[j] = alpha_to[rs_modnn(rs, index_of[num1] +
280  					       index_of[num2] +
281  					       nn - index_of[den])];
282  		num_corrected++;
283  	}
284  
285  	/*
286  	 * We compute the syndrome of the 'error' and check that it matches
287  	 * the syndrome of the received word
288  	 */
289  	for (i = 0; i < nroots; i++) {
290  		tmp = 0;
291  		for (j = 0; j < count; j++) {
292  			if (b[j] == 0)
293  				continue;
294  
295  			k = (fcr + i) * prim * (nn-loc[j]-1);
296  			tmp ^= alpha_to[rs_modnn(rs, index_of[b[j]] + k)];
297  		}
298  
299  		if (tmp != alpha_to[s[i]])
300  			return -EBADMSG;
301  	}
302  
303  	/*
304  	 * Store the error correction pattern, if a
305  	 * correction buffer is available
306  	 */
307  	if (corr && eras_pos) {
308  		j = 0;
309  		for (i = 0; i < count; i++) {
310  			if (b[i]) {
311  				corr[j] = b[i];
312  				eras_pos[j++] = loc[i] - pad;
313  			}
314  		}
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];
320  			else
321  				par[loc[i] - pad - len] ^= b[i];
322  		}
323  	}
324  
325  	return  num_corrected;
326  }
327