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
] = prandom_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
= prandom_u32() & nn
;
182 } while (errval
== 0);
185 /* Must not choose the same location twice */
186 errloc
= prandom_u32() % 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() % len
;
198 } while (errlocs
[errloc
] != 0);
200 derrlocs
[i
] = errloc
;
202 if (ewsc
&& (prandom_u32() & 1)) {
203 /* Erasure with the symbol intact */
206 /* Erasure with corrupted symbol */
208 /* Error value must be nonzero */
209 errval
= prandom_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 obious 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");