Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'core-rslib-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull Reed-Solomon library updates from Thomas Gleixner:
"A cleanup and fixes series from Ferdinand Blomqvist who analyzed the
original Reed-Solomon library from Phil Karn on which the kernel
implementation is based on.

This comes with a test module which verifies all the various corner
cases for correctness"

* 'core-rslib-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
rslib: Make some functions static
rslib: Fix remaining decoder flaws
rslib: Update documentation
rslib: Fix handling of of caller provided syndrome
rslib: decode_rs: Code cleanup
rslib: decode_rs: Fix length parameter check
rslib: Fix decoding of shortened codes
rslib: Add tests for the encoder and decoder

+625 -36
+12
lib/Kconfig.debug
··· 1754 1754 A benchmark measuring the performance of the rbtree library. 1755 1755 Also includes rbtree invariant checks. 1756 1756 1757 + config REED_SOLOMON_TEST 1758 + tristate "Reed-Solomon library test" 1759 + depends on DEBUG_KERNEL || m 1760 + select REED_SOLOMON 1761 + select REED_SOLOMON_ENC16 1762 + select REED_SOLOMON_DEC16 1763 + help 1764 + This option enables the self-test function of rslib at boot, 1765 + or at module load time. 1766 + 1767 + If unsure, say N. 1768 + 1757 1769 config INTERVAL_TREE_TEST 1758 1770 tristate "Interval tree test" 1759 1771 depends on DEBUG_KERNEL
+1 -1
lib/reed_solomon/Makefile
··· 4 4 # 5 5 6 6 obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o 7 - 7 + obj-$(CONFIG_REED_SOLOMON_TEST) += test_rslib.o
+86 -31
lib/reed_solomon/decode_rs.c
··· 22 22 uint16_t *index_of = rs->index_of; 23 23 uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error; 24 24 int count = 0; 25 + int num_corrected; 25 26 uint16_t msk = (uint16_t) rs->nn; 26 27 27 28 /* ··· 40 39 41 40 /* Check length parameter for validity */ 42 41 pad = nn - nroots - len; 43 - BUG_ON(pad < 0 || pad >= nn); 42 + BUG_ON(pad < 0 || pad >= nn - nroots); 44 43 45 44 /* Does the caller provide the syndrome ? */ 46 - if (s != NULL) 47 - goto decode; 45 + if (s != NULL) { 46 + for (i = 0; i < nroots; i++) { 47 + /* The syndrome is in index form, 48 + * so nn represents zero 49 + */ 50 + if (s[i] != nn) 51 + goto decode; 52 + } 53 + 54 + /* syndrome is zero, no errors to correct */ 55 + return 0; 56 + } 48 57 49 58 /* form the syndromes; i.e., evaluate data(x) at roots of 50 59 * g(x) */ ··· 99 88 /* if syndrome is zero, data[] is a codeword and there are no 100 89 * errors to correct. So return data[] unmodified 101 90 */ 102 - count = 0; 103 - goto finish; 91 + return 0; 104 92 } 105 93 106 94 decode: ··· 109 99 if (no_eras > 0) { 110 100 /* Init lambda to be the erasure locator polynomial */ 111 101 lambda[1] = alpha_to[rs_modnn(rs, 112 - prim * (nn - 1 - eras_pos[0]))]; 102 + prim * (nn - 1 - (eras_pos[0] + pad)))]; 113 103 for (i = 1; i < no_eras; i++) { 114 - u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i])); 104 + u = rs_modnn(rs, prim * (nn - 1 - (eras_pos[i] + pad))); 115 105 for (j = i + 1; j > 0; j--) { 116 106 tmp = index_of[lambda[j - 1]]; 117 107 if (tmp != nn) { ··· 185 175 if (lambda[i] != nn) 186 176 deg_lambda = i; 187 177 } 178 + 179 + if (deg_lambda == 0) { 180 + /* 181 + * deg(lambda) is zero even though the syndrome is non-zero 182 + * => uncorrectable error detected 183 + */ 184 + return -EBADMSG; 185 + } 186 + 188 187 /* Find roots of error+erasure locator polynomial by Chien search */ 189 188 memcpy(&reg[1], &lambda[1], nroots * sizeof(reg[0])); 190 189 count = 0; /* Number of roots of lambda(x) */ ··· 207 188 } 208 189 if (q != 0) 209 190 continue; /* Not a root */ 191 + 192 + if (k < pad) { 193 + /* Impossible error location. Uncorrectable error. */ 194 + return -EBADMSG; 195 + } 196 + 210 197 /* store root (index-form) and error location number */ 211 198 root[count] = i; 212 199 loc[count] = k; ··· 227 202 * deg(lambda) unequal to number of roots => uncorrectable 228 203 * error detected 229 204 */ 230 - count = -EBADMSG; 231 - goto finish; 205 + return -EBADMSG; 232 206 } 233 207 /* 234 208 * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo ··· 247 223 /* 248 224 * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = 249 225 * inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form 226 + * Note: we reuse the buffer for b to store the correction pattern 250 227 */ 228 + num_corrected = 0; 251 229 for (j = count - 1; j >= 0; j--) { 252 230 num1 = 0; 253 231 for (i = deg_omega; i >= 0; i--) { ··· 257 231 num1 ^= alpha_to[rs_modnn(rs, omega[i] + 258 232 i * root[j])]; 259 233 } 234 + 235 + if (num1 == 0) { 236 + /* Nothing to correct at this position */ 237 + b[j] = 0; 238 + continue; 239 + } 240 + 260 241 num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)]; 261 242 den = 0; 262 243 ··· 275 242 i * root[j])]; 276 243 } 277 244 } 278 - /* Apply error to data */ 279 - if (num1 != 0 && loc[j] >= pad) { 280 - uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] + 281 - index_of[num2] + 282 - nn - index_of[den])]; 283 - /* Store the error correction pattern, if a 284 - * correction buffer is available */ 285 - if (corr) { 286 - corr[j] = cor; 287 - } else { 288 - /* If a data buffer is given and the 289 - * error is inside the message, 290 - * correct it */ 291 - if (data && (loc[j] < (nn - nroots))) 292 - data[loc[j] - pad] ^= cor; 245 + 246 + b[j] = alpha_to[rs_modnn(rs, index_of[num1] + 247 + index_of[num2] + 248 + nn - index_of[den])]; 249 + num_corrected++; 250 + } 251 + 252 + /* 253 + * We compute the syndrome of the 'error' and check that it matches 254 + * the syndrome of the received word 255 + */ 256 + for (i = 0; i < nroots; i++) { 257 + tmp = 0; 258 + for (j = 0; j < count; j++) { 259 + if (b[j] == 0) 260 + continue; 261 + 262 + k = (fcr + i) * prim * (nn-loc[j]-1); 263 + tmp ^= alpha_to[rs_modnn(rs, index_of[b[j]] + k)]; 264 + } 265 + 266 + if (tmp != alpha_to[s[i]]) 267 + return -EBADMSG; 268 + } 269 + 270 + /* 271 + * Store the error correction pattern, if a 272 + * correction buffer is available 273 + */ 274 + if (corr && eras_pos) { 275 + j = 0; 276 + for (i = 0; i < count; i++) { 277 + if (b[i]) { 278 + corr[j] = b[i]; 279 + eras_pos[j++] = loc[i] - pad; 293 280 } 281 + } 282 + } else if (data && par) { 283 + /* Apply error to data and parity */ 284 + for (i = 0; i < count; i++) { 285 + if (loc[i] < (nn - nroots)) 286 + data[loc[i] - pad] ^= b[i]; 287 + else 288 + par[loc[i] - pad - len] ^= b[i]; 294 289 } 295 290 } 296 291 297 - finish: 298 - if (eras_pos != NULL) { 299 - for (i = 0; i < count; i++) 300 - eras_pos[i] = loc[i] - pad; 301 - } 302 - return count; 303 - 292 + return num_corrected; 304 293 }
+8 -4
lib/reed_solomon/reed_solomon.c
··· 340 340 * @data: data field of a given type 341 341 * @par: received parity data field 342 342 * @len: data length 343 - * @s: syndrome data field (if NULL, syndrome is calculated) 343 + * @s: syndrome data field, must be in index form 344 + * (if NULL, syndrome is calculated) 344 345 * @no_eras: number of erasures 345 346 * @eras_pos: position of erasures, can be NULL 346 347 * @invmsk: invert data mask (will be xored on data, not on parity!) ··· 355 354 * decoding, so the caller has to ensure that decoder invocations are 356 355 * serialized. 357 356 * 358 - * Returns the number of corrected bits or -EBADMSG for uncorrectable errors. 357 + * Returns the number of corrected symbols or -EBADMSG for uncorrectable 358 + * errors. The count includes errors in the parity. 359 359 */ 360 360 int decode_rs8(struct rs_control *rsc, uint8_t *data, uint16_t *par, int len, 361 361 uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk, ··· 393 391 * @data: data field of a given type 394 392 * @par: received parity data field 395 393 * @len: data length 396 - * @s: syndrome data field (if NULL, syndrome is calculated) 394 + * @s: syndrome data field, must be in index form 395 + * (if NULL, syndrome is calculated) 397 396 * @no_eras: number of erasures 398 397 * @eras_pos: position of erasures, can be NULL 399 398 * @invmsk: invert data mask (will be xored on data, not on parity!) ··· 406 403 * decoding, so the caller has to ensure that decoder invocations are 407 404 * serialized. 408 405 * 409 - * Returns the number of corrected bits or -EBADMSG for uncorrectable errors. 406 + * Returns the number of corrected symbols or -EBADMSG for uncorrectable 407 + * errors. The count includes errors in the parity. 410 408 */ 411 409 int decode_rs16(struct rs_control *rsc, uint16_t *data, uint16_t *par, int len, 412 410 uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+518
lib/reed_solomon/test_rslib.c
··· 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");