root/lib/reed_solomon/test_rslib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. free_ws
  2. alloc_ws
  3. get_rcw_we
  4. fix_err
  5. compute_syndrome
  6. test_uc
  7. ex_rs_helper
  8. exercise_rs
  9. test_bc
  10. exercise_rs_bc
  11. run_exercise
  12. test_rslib_init
  13. test_rslib_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Tests for Generic Reed Solomon encoder / decoder library
   4  *
   5  * Written by Ferdinand Blomqvist
   6  * Based on previous work by Phil Karn, KA9Q
   7  */
   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>
  14 
  15 enum verbosity {
  16         V_SILENT,
  17         V_PROGRESS,
  18         V_CSUMMARY
  19 };
  20 
  21 enum method {
  22         CORR_BUFFER,
  23         CALLER_SYNDROME,
  24         IN_PLACE
  25 };
  26 
  27 #define __param(type, name, init, msg)          \
  28         static type name = init;                \
  29         module_param(name, type, 0444);         \
  30         MODULE_PARM_DESC(name, msg)
  31 
  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");
  35 
  36 struct etab {
  37         int     symsize;
  38         int     genpoly;
  39         int     fcs;
  40         int     prim;
  41         int     nroots;
  42         int     ntrials;
  43 };
  44 
  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      },
  58         {0, 0, 0, 0, 0, 0},
  59 };
  60 
  61 
  62 struct estat {
  63         int     dwrong;
  64         int     irv;
  65         int     wepos;
  66         int     nwords;
  67 };
  68 
  69 struct bcstat {
  70         int     rfail;
  71         int     rsuccess;
  72         int     noncw;
  73         int     nwords;
  74 };
  75 
  76 struct wspace {
  77         uint16_t        *c;             /* sent codeword */
  78         uint16_t        *r;             /* received word */
  79         uint16_t        *s;             /* syndrome */
  80         uint16_t        *corr;          /* correction buffer */
  81         int             *errlocs;
  82         int             *derrlocs;
  83 };
  84 
  85 struct pad {
  86         int     mult;
  87         int     shift;
  88 };
  89 
  90 static struct pad pad_coef[] = {
  91         { 0, 0 },
  92         { 1, 2 },
  93         { 1, 1 },
  94         { 3, 2 },
  95         { 1, 0 },
  96 };
  97 
  98 static void free_ws(struct wspace *ws)
  99 {
 100         if (!ws)
 101                 return;
 102 
 103         kfree(ws->errlocs);
 104         kfree(ws->c);
 105         kfree(ws);
 106 }
 107 
 108 static struct wspace *alloc_ws(struct rs_codec *rs)
 109 {
 110         int nroots = rs->nroots;
 111         struct wspace *ws;
 112         int nn = rs->nn;
 113 
 114         ws = kzalloc(sizeof(*ws), GFP_KERNEL);
 115         if (!ws)
 116                 return NULL;
 117 
 118         ws->c = kmalloc_array(2 * (nn + nroots),
 119                                 sizeof(uint16_t), GFP_KERNEL);
 120         if (!ws->c)
 121                 goto err;
 122 
 123         ws->r = ws->c + nn;
 124         ws->s = ws->r + nn;
 125         ws->corr = ws->s + nroots;
 126 
 127         ws->errlocs = kmalloc_array(nn + nroots, sizeof(int), GFP_KERNEL);
 128         if (!ws->errlocs)
 129                 goto err;
 130 
 131         ws->derrlocs = ws->errlocs + nn;
 132         return ws;
 133 
 134 err:
 135         free_ws(ws);
 136         return NULL;
 137 }
 138 
 139 
 140 /*
 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:
 144  *
 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.
 148  *
 149  * Returns the number of corrupted symbols.
 150  */
 151 static int get_rcw_we(struct rs_control *rs, struct wspace *ws,
 152                         int len, int errs, int eras)
 153 {
 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;
 159         uint16_t *c = ws->c;
 160         uint16_t *r = ws->r;
 161         int errval;
 162         int errloc;
 163         int i;
 164 
 165         /* Load c with random data and encode */
 166         for (i = 0; i < dlen; i++)
 167                 c[i] = prandom_u32() & nn;
 168 
 169         memset(c + dlen, 0, nroots * sizeof(*c));
 170         encode_rs16(rs, c, dlen, c + dlen, 0);
 171 
 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));
 176 
 177         /* Generating random errors */
 178         for (i = 0; i < errs; i++) {
 179                 do {
 180                         /* Error value must be nonzero */
 181                         errval = prandom_u32() & nn;
 182                 } while (errval == 0);
 183 
 184                 do {
 185                         /* Must not choose the same location twice */
 186                         errloc = prandom_u32() % len;
 187                 } while (errlocs[errloc] != 0);
 188 
 189                 errlocs[errloc] = 1;
 190                 r[errloc] ^= errval;
 191         }
 192 
 193         /* Generating random erasures */
 194         for (i = 0; i < eras; i++) {
 195                 do {
 196                         /* Must not choose the same location twice */
 197                         errloc = prandom_u32() % len;
 198                 } while (errlocs[errloc] != 0);
 199 
 200                 derrlocs[i] = errloc;
 201 
 202                 if (ewsc && (prandom_u32() & 1)) {
 203                         /* Erasure with the symbol intact */
 204                         errlocs[errloc] = 2;
 205                 } else {
 206                         /* Erasure with corrupted symbol */
 207                         do {
 208                                 /* Error value must be nonzero */
 209                                 errval = prandom_u32() & nn;
 210                         } while (errval == 0);
 211 
 212                         errlocs[errloc] = 1;
 213                         r[errloc] ^= errval;
 214                         errs++;
 215                 }
 216         }
 217 
 218         return errs;
 219 }
 220 
 221 static void fix_err(uint16_t *data, int nerrs, uint16_t *corr, int *errlocs)
 222 {
 223         int i;
 224 
 225         for (i = 0; i < nerrs; i++)
 226                 data[errlocs[i]] ^= corr[i];
 227 }
 228 
 229 static void compute_syndrome(struct rs_control *rsc, uint16_t *data,
 230                                 int len, uint16_t *syn)
 231 {
 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;
 236         int prim = rs->prim;
 237         int fcr = rs->fcr;
 238         int i, j;
 239 
 240         /* Calculating syndrome */
 241         for (i = 0; i < nroots; i++) {
 242                 syn[i] = data[0];
 243                 for (j = 1; j < len; j++) {
 244                         if (syn[i] == 0) {
 245                                 syn[i] = data[j];
 246                         } else {
 247                                 syn[i] = data[j] ^
 248                                         alpha_to[rs_modnn(rs, index_of[syn[i]]
 249                                                 + (fcr + i) * prim)];
 250                         }
 251                 }
 252         }
 253 
 254         /* Convert to index form */
 255         for (i = 0; i < nroots; i++)
 256                 syn[i] = rs->index_of[syn[i]];
 257 }
 258 
 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)
 263 {
 264         int dlen = len - rs->codec->nroots;
 265         int *derrlocs = ws->derrlocs;
 266         int *errlocs = ws->errlocs;
 267         uint16_t *corr = ws->corr;
 268         uint16_t *c = ws->c;
 269         uint16_t *r = ws->r;
 270         uint16_t *s = ws->s;
 271         int derrs, nerrs;
 272         int i, j;
 273 
 274         for (j = 0; j < trials; j++) {
 275                 nerrs = get_rcw_we(rs, ws, len, errs, eras);
 276 
 277                 switch (method) {
 278                 case CORR_BUFFER:
 279                         derrs = decode_rs16(rs, r, r + dlen, dlen,
 280                                         NULL, eras, derrlocs, 0, corr);
 281                         fix_err(r, derrs, corr, derrlocs);
 282                         break;
 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);
 288                         break;
 289                 case IN_PLACE:
 290                         derrs = decode_rs16(rs, r, r + dlen, dlen,
 291                                         NULL, eras, derrlocs, 0, NULL);
 292                         break;
 293                 default:
 294                         continue;
 295                 }
 296 
 297                 if (derrs != nerrs)
 298                         stat->irv++;
 299 
 300                 if (method != IN_PLACE) {
 301                         for (i = 0; i < derrs; i++) {
 302                                 if (errlocs[derrlocs[i]] != 1)
 303                                         stat->wepos++;
 304                         }
 305                 }
 306 
 307                 if (memcmp(r, c, len * sizeof(*r)))
 308                         stat->dwrong++;
 309         }
 310         stat->nwords += trials;
 311 }
 312 
 313 static int ex_rs_helper(struct rs_control *rs, struct wspace *ws,
 314                         int len, int trials, int method)
 315 {
 316         static const char * const desc[] = {
 317                 "Testing correction buffer interface...",
 318                 "Testing with caller provided syndrome...",
 319                 "Testing in-place interface..."
 320         };
 321 
 322         struct estat stat = {0, 0, 0, 0};
 323         int nroots = rs->codec->nroots;
 324         int errs, eras, retval;
 325 
 326         if (v >= V_PROGRESS)
 327                 pr_info("  %s\n", desc[method]);
 328 
 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);
 332 
 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);
 340         }
 341 
 342         retval = stat.dwrong + stat.wepos + stat.irv;
 343         if (retval && v >= V_PROGRESS)
 344                 pr_warn("    FAIL: %d decoding failures!\n", retval);
 345 
 346         return retval;
 347 }
 348 
 349 static int exercise_rs(struct rs_control *rs, struct wspace *ws,
 350                        int len, int trials)
 351 {
 352 
 353         int retval = 0;
 354         int i;
 355 
 356         if (v >= V_PROGRESS)
 357                 pr_info("Testing up to error correction capacity...\n");
 358 
 359         for (i = 0; i <= IN_PLACE; i++)
 360                 retval |= ex_rs_helper(rs, ws, len, trials, i);
 361 
 362         return retval;
 363 }
 364 
 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,
 368                 struct wspace *ws)
 369 {
 370         int nroots = rs->codec->nroots;
 371         int dlen = len - nroots;
 372         int *derrlocs = ws->derrlocs;
 373         uint16_t *corr = ws->corr;
 374         uint16_t *r = ws->r;
 375         int derrs, j;
 376 
 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);
 382 
 383                 if (derrs >= 0) {
 384                         stat->rsuccess++;
 385 
 386                         /*
 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
 393                          * not.
 394                          */
 395                         memset(corr, 0, nroots * sizeof(*corr));
 396                         encode_rs16(rs, r, dlen, corr, 0);
 397 
 398                         if (memcmp(r + dlen, corr, nroots * sizeof(*corr)))
 399                                 stat->noncw++;
 400                 } else {
 401                         stat->rfail++;
 402                 }
 403         }
 404         stat->nwords += trials;
 405 }
 406 
 407 static int exercise_rs_bc(struct rs_control *rs, struct wspace *ws,
 408                           int len, int trials)
 409 {
 410         struct bcstat stat = {0, 0, 0, 0};
 411         int nroots = rs->codec->nroots;
 412         int errs, eras, cutoff;
 413 
 414         if (v >= V_PROGRESS)
 415                 pr_info("Testing beyond error correction capacity...\n");
 416 
 417         for (errs = 1; errs <= nroots; errs++) {
 418                 eras = nroots - 2 * errs + 1;
 419                 if (eras < 0)
 420                         eras = 0;
 421 
 422                 cutoff = nroots <= len - errs ? nroots : len - errs;
 423                 for (; eras <= cutoff; eras++)
 424                         test_bc(rs, len, errs, eras, trials, &stat, ws);
 425         }
 426 
 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);
 434         }
 435 
 436         if (stat.noncw && v >= V_PROGRESS)
 437                 pr_warn("    FAIL: %d silent failures!\n", stat.noncw);
 438 
 439         return stat.noncw;
 440 }
 441 
 442 static int run_exercise(struct etab *e)
 443 {
 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;
 449         int prev_pad = -1;
 450         struct wspace *ws;
 451         int i;
 452 
 453         rsc = init_rs(e->symsize, e->genpoly, e->fcs, e->prim, e->nroots);
 454         if (!rsc)
 455                 return retval;
 456 
 457         ws = alloc_ws(rsc->codec);
 458         if (!ws)
 459                 goto err;
 460 
 461         retval = 0;
 462         for (i = 0; i < ARRAY_SIZE(pad_coef); i++) {
 463                 int pad = (pad_coef[i].mult * max_pad) >> pad_coef[i].shift;
 464                 int len = nn - pad;
 465 
 466                 if (pad == prev_pad)
 467                         continue;
 468 
 469                 prev_pad = pad;
 470                 if (v >= V_PROGRESS) {
 471                         pr_info("Testing (%d,%d)_%d code...\n",
 472                                         len, kk - pad, nn + 1);
 473                 }
 474 
 475                 retval |= exercise_rs(rsc, ws, len, e->ntrials);
 476                 if (bc)
 477                         retval |= exercise_rs_bc(rsc, ws, len, e->ntrials);
 478         }
 479 
 480         free_ws(ws);
 481 
 482 err:
 483         free_rs(rsc);
 484         return retval;
 485 }
 486 
 487 static int __init test_rslib_init(void)
 488 {
 489         int i, fail = 0;
 490 
 491         for (i = 0; Tab[i].symsize != 0 ; i++) {
 492                 int retval;
 493 
 494                 retval = run_exercise(Tab + i);
 495                 if (retval < 0)
 496                         return -ENOMEM;
 497 
 498                 fail |= retval;
 499         }
 500 
 501         if (fail)
 502                 pr_warn("rslib: test failed\n");
 503         else
 504                 pr_info("rslib: test ok\n");
 505 
 506         return -EAGAIN; /* Fail will directly unload the module */
 507 }
 508 
 509 static void __exit test_rslib_exit(void)
 510 {
 511 }
 512 
 513 module_init(test_rslib_init)
 514 module_exit(test_rslib_exit)
 515 
 516 MODULE_LICENSE("GPL");
 517 MODULE_AUTHOR("Ferdinand Blomqvist");
 518 MODULE_DESCRIPTION("Reed-Solomon library test");

/* [<][>][^][v][top][bottom][index][help] */