1 // SPDX-License-Identifier: GPL-2.0
3 * Tests for Generic Reed Solomon encoder / decoder library
5 * Written by Ferdinand Blomqvist
6 * Based on previous work by Phil Karn, KA9Q
8 #include <linux/rslib.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
12 #include <linux/random.h>
13 #include <linux/slab.h>
27 #define __param(type, name, init, msg) \
28 static type name = init; \
29 module_param(name, type, 0444); \
30 MODULE_PARM_DESC(name, msg)
32 __param(int, v, V_PROGRESS, "Verbosity level");
33 __param(int, ewsc, 1, "Erasures without symbol corruption");
34 __param(int, bc, 1, "Test for correct behaviour beyond error correction capacity");
45 /* List of codes to test */
46 static struct etab Tab[] = {
47 {2, 0x7, 1, 1, 1, 100000 },
48 {3, 0xb, 1, 1, 2, 100000 },
49 {3, 0xb, 1, 1, 3, 100000 },
50 {3, 0xb, 2, 1, 4, 100000 },
51 {4, 0x13, 1, 1, 4, 10000 },
52 {5, 0x25, 1, 1, 6, 1000 },
53 {6, 0x43, 3, 1, 8, 1000 },
54 {7, 0x89, 1, 1, 14, 500 },
55 {8, 0x11d, 1, 1, 30, 100 },
56 {8, 0x187, 112, 11, 32, 100 },
57 {9, 0x211, 1, 1, 33, 80 },
77 uint16_t *c; /* sent codeword */
78 uint16_t *r; /* received word */
79 uint16_t *s; /* syndrome */
80 uint16_t *corr; /* correction buffer */
90 static struct pad pad_coef[] = {
98 static void free_ws(struct wspace *ws)
108 static struct wspace *alloc_ws(struct rs_codec *rs)
110 int nroots = rs->nroots;
114 ws = kzalloc(sizeof(*ws), GFP_KERNEL);
118 ws->c = kmalloc_array(2 * (nn + nroots),
119 sizeof(uint16_t), GFP_KERNEL);
125 ws->corr = ws->s + nroots;
127 ws->errlocs = kmalloc_array(nn + nroots, sizeof(int), GFP_KERNEL);
131 ws->derrlocs = ws->errlocs + nn;
141 * Generates a random codeword and stores it in c. Generates random errors and
142 * erasures, and stores the random word with errors in r. Erasure positions are
143 * stored in derrlocs, while errlocs has one of three values in every position:
145 * 0 if there is no error in this position;
146 * 1 if there is a symbol error in this position;
147 * 2 if there is an erasure without symbol corruption.
149 * Returns the number of corrupted symbols.
151 static int get_rcw_we(struct rs_control *rs, struct wspace *ws,
152 int len, int errs, int eras)
154 int nroots = rs->codec->nroots;
155 int *derrlocs = ws->derrlocs;
156 int *errlocs = ws->errlocs;
157 int dlen = len - nroots;
158 int nn = rs->codec->nn;
165 /* Load c with random data and encode */
166 for (i = 0; i < dlen; i++)
167 c[i] = get_random_u32() & nn;
169 memset(c + dlen, 0, nroots * sizeof(*c));
170 encode_rs16(rs, c, dlen, c + dlen, 0);
172 /* Make copyand add errors and erasures */
173 memcpy(r, c, len * sizeof(*r));
174 memset(errlocs, 0, len * sizeof(*errlocs));
175 memset(derrlocs, 0, nroots * sizeof(*derrlocs));
177 /* Generating random errors */
178 for (i = 0; i < errs; i++) {
180 /* Error value must be nonzero */
181 errval = get_random_u32() & nn;
182 } while (errval == 0);
185 /* Must not choose the same location twice */
186 errloc = prandom_u32_max(len);
187 } while (errlocs[errloc] != 0);
193 /* Generating random erasures */
194 for (i = 0; i < eras; i++) {
196 /* Must not choose the same location twice */
197 errloc = prandom_u32_max(len);
198 } while (errlocs[errloc] != 0);
200 derrlocs[i] = errloc;
202 if (ewsc && prandom_u32_max(2)) {
203 /* Erasure with the symbol intact */
206 /* Erasure with corrupted symbol */
208 /* Error value must be nonzero */
209 errval = get_random_u32() & nn;
210 } while (errval == 0);
221 static void fix_err(uint16_t *data, int nerrs, uint16_t *corr, int *errlocs)
225 for (i = 0; i < nerrs; i++)
226 data[errlocs[i]] ^= corr[i];
229 static void compute_syndrome(struct rs_control *rsc, uint16_t *data,
230 int len, uint16_t *syn)
232 struct rs_codec *rs = rsc->codec;
233 uint16_t *alpha_to = rs->alpha_to;
234 uint16_t *index_of = rs->index_of;
235 int nroots = rs->nroots;
240 /* Calculating syndrome */
241 for (i = 0; i < nroots; i++) {
243 for (j = 1; j < len; j++) {
248 alpha_to[rs_modnn(rs, index_of[syn[i]]
249 + (fcr + i) * prim)];
254 /* Convert to index form */
255 for (i = 0; i < nroots; i++)
256 syn[i] = rs->index_of[syn[i]];
259 /* Test up to error correction capacity */
260 static void test_uc(struct rs_control *rs, int len, int errs,
261 int eras, int trials, struct estat *stat,
262 struct wspace *ws, int method)
264 int dlen = len - rs->codec->nroots;
265 int *derrlocs = ws->derrlocs;
266 int *errlocs = ws->errlocs;
267 uint16_t *corr = ws->corr;
274 for (j = 0; j < trials; j++) {
275 nerrs = get_rcw_we(rs, ws, len, errs, eras);
279 derrs = decode_rs16(rs, r, r + dlen, dlen,
280 NULL, eras, derrlocs, 0, corr);
281 fix_err(r, derrs, corr, derrlocs);
283 case CALLER_SYNDROME:
284 compute_syndrome(rs, r, len, s);
285 derrs = decode_rs16(rs, NULL, NULL, dlen,
286 s, eras, derrlocs, 0, corr);
287 fix_err(r, derrs, corr, derrlocs);
290 derrs = decode_rs16(rs, r, r + dlen, dlen,
291 NULL, eras, derrlocs, 0, NULL);
300 if (method != IN_PLACE) {
301 for (i = 0; i < derrs; i++) {
302 if (errlocs[derrlocs[i]] != 1)
307 if (memcmp(r, c, len * sizeof(*r)))
310 stat->nwords += trials;
313 static int ex_rs_helper(struct rs_control *rs, struct wspace *ws,
314 int len, int trials, int method)
316 static const char * const desc[] = {
317 "Testing correction buffer interface...",
318 "Testing with caller provided syndrome...",
319 "Testing in-place interface..."
322 struct estat stat = {0, 0, 0, 0};
323 int nroots = rs->codec->nroots;
324 int errs, eras, retval;
327 pr_info(" %s\n", desc[method]);
329 for (errs = 0; errs <= nroots / 2; errs++)
330 for (eras = 0; eras <= nroots - 2 * errs; eras++)
331 test_uc(rs, len, errs, eras, trials, &stat, ws, method);
333 if (v >= V_CSUMMARY) {
334 pr_info(" Decodes wrong: %d / %d\n",
335 stat.dwrong, stat.nwords);
336 pr_info(" Wrong return value: %d / %d\n",
337 stat.irv, stat.nwords);
338 if (method != IN_PLACE)
339 pr_info(" Wrong error position: %d\n", stat.wepos);
342 retval = stat.dwrong + stat.wepos + stat.irv;
343 if (retval && v >= V_PROGRESS)
344 pr_warn(" FAIL: %d decoding failures!\n", retval);
349 static int exercise_rs(struct rs_control *rs, struct wspace *ws,
357 pr_info("Testing up to error correction capacity...\n");
359 for (i = 0; i <= IN_PLACE; i++)
360 retval |= ex_rs_helper(rs, ws, len, trials, i);
365 /* Tests for correct behaviour beyond error correction capacity */
366 static void test_bc(struct rs_control *rs, int len, int errs,
367 int eras, int trials, struct bcstat *stat,
370 int nroots = rs->codec->nroots;
371 int dlen = len - nroots;
372 int *derrlocs = ws->derrlocs;
373 uint16_t *corr = ws->corr;
377 for (j = 0; j < trials; j++) {
378 get_rcw_we(rs, ws, len, errs, eras);
379 derrs = decode_rs16(rs, r, r + dlen, dlen,
380 NULL, eras, derrlocs, 0, corr);
381 fix_err(r, derrs, corr, derrlocs);
387 * We check that the returned word is actually a
388 * codeword. The obvious way to do this would be to
389 * compute the syndrome, but we don't want to replicate
390 * that code here. However, all the codes are in
391 * systematic form, and therefore we can encode the
392 * returned word, and see whether the parity changes or
395 memset(corr, 0, nroots * sizeof(*corr));
396 encode_rs16(rs, r, dlen, corr, 0);
398 if (memcmp(r + dlen, corr, nroots * sizeof(*corr)))
404 stat->nwords += trials;
407 static int exercise_rs_bc(struct rs_control *rs, struct wspace *ws,
410 struct bcstat stat = {0, 0, 0, 0};
411 int nroots = rs->codec->nroots;
412 int errs, eras, cutoff;
415 pr_info("Testing beyond error correction capacity...\n");
417 for (errs = 1; errs <= nroots; errs++) {
418 eras = nroots - 2 * errs + 1;
422 cutoff = nroots <= len - errs ? nroots : len - errs;
423 for (; eras <= cutoff; eras++)
424 test_bc(rs, len, errs, eras, trials, &stat, ws);
427 if (v >= V_CSUMMARY) {
428 pr_info(" decoder gives up: %d / %d\n",
429 stat.rfail, stat.nwords);
430 pr_info(" decoder returns success: %d / %d\n",
431 stat.rsuccess, stat.nwords);
432 pr_info(" not a codeword: %d / %d\n",
433 stat.noncw, stat.rsuccess);
436 if (stat.noncw && v >= V_PROGRESS)
437 pr_warn(" FAIL: %d silent failures!\n", stat.noncw);
442 static int run_exercise(struct etab *e)
444 int nn = (1 << e->symsize) - 1;
445 int kk = nn - e->nroots;
446 struct rs_control *rsc;
447 int retval = -ENOMEM;
448 int max_pad = kk - 1;
453 rsc = init_rs(e->symsize, e->genpoly, e->fcs, e->prim, e->nroots);
457 ws = alloc_ws(rsc->codec);
462 for (i = 0; i < ARRAY_SIZE(pad_coef); i++) {
463 int pad = (pad_coef[i].mult * max_pad) >> pad_coef[i].shift;
470 if (v >= V_PROGRESS) {
471 pr_info("Testing (%d,%d)_%d code...\n",
472 len, kk - pad, nn + 1);
475 retval |= exercise_rs(rsc, ws, len, e->ntrials);
477 retval |= exercise_rs_bc(rsc, ws, len, e->ntrials);
487 static int __init test_rslib_init(void)
491 for (i = 0; Tab[i].symsize != 0 ; i++) {
494 retval = run_exercise(Tab + i);
502 pr_warn("rslib: test failed\n");
504 pr_info("rslib: test ok\n");
506 return -EAGAIN; /* Fail will directly unload the module */
509 static void __exit test_rslib_exit(void)
513 module_init(test_rslib_init)
514 module_exit(test_rslib_exit)
516 MODULE_LICENSE("GPL");
517 MODULE_AUTHOR("Ferdinand Blomqvist");
518 MODULE_DESCRIPTION("Reed-Solomon library test");