mirror of
https://github.com/ukui/kernel.git
synced 2026-03-09 10:07:04 -07:00
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
This commit is contained in:
@@ -1754,6 +1754,18 @@ config RBTREE_TEST
|
||||
A benchmark measuring the performance of the rbtree library.
|
||||
Also includes rbtree invariant checks.
|
||||
|
||||
config REED_SOLOMON_TEST
|
||||
tristate "Reed-Solomon library test"
|
||||
depends on DEBUG_KERNEL || m
|
||||
select REED_SOLOMON
|
||||
select REED_SOLOMON_ENC16
|
||||
select REED_SOLOMON_DEC16
|
||||
help
|
||||
This option enables the self-test function of rslib at boot,
|
||||
or at module load time.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config INTERVAL_TREE_TEST
|
||||
tristate "Interval tree test"
|
||||
depends on DEBUG_KERNEL
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
#
|
||||
|
||||
obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
|
||||
|
||||
obj-$(CONFIG_REED_SOLOMON_TEST) += test_rslib.o
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
uint16_t *index_of = rs->index_of;
|
||||
uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
|
||||
int count = 0;
|
||||
int num_corrected;
|
||||
uint16_t msk = (uint16_t) rs->nn;
|
||||
|
||||
/*
|
||||
@@ -39,11 +40,21 @@
|
||||
|
||||
/* Check length parameter for validity */
|
||||
pad = nn - nroots - len;
|
||||
BUG_ON(pad < 0 || pad >= nn);
|
||||
BUG_ON(pad < 0 || pad >= nn - nroots);
|
||||
|
||||
/* Does the caller provide the syndrome ? */
|
||||
if (s != NULL)
|
||||
goto decode;
|
||||
if (s != NULL) {
|
||||
for (i = 0; i < nroots; i++) {
|
||||
/* The syndrome is in index form,
|
||||
* so nn represents zero
|
||||
*/
|
||||
if (s[i] != nn)
|
||||
goto decode;
|
||||
}
|
||||
|
||||
/* syndrome is zero, no errors to correct */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* form the syndromes; i.e., evaluate data(x) at roots of
|
||||
* g(x) */
|
||||
@@ -88,8 +99,7 @@
|
||||
/* if syndrome is zero, data[] is a codeword and there are no
|
||||
* errors to correct. So return data[] unmodified
|
||||
*/
|
||||
count = 0;
|
||||
goto finish;
|
||||
return 0;
|
||||
}
|
||||
|
||||
decode:
|
||||
@@ -99,9 +109,9 @@
|
||||
if (no_eras > 0) {
|
||||
/* Init lambda to be the erasure locator polynomial */
|
||||
lambda[1] = alpha_to[rs_modnn(rs,
|
||||
prim * (nn - 1 - eras_pos[0]))];
|
||||
prim * (nn - 1 - (eras_pos[0] + pad)))];
|
||||
for (i = 1; i < no_eras; i++) {
|
||||
u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
|
||||
u = rs_modnn(rs, prim * (nn - 1 - (eras_pos[i] + pad)));
|
||||
for (j = i + 1; j > 0; j--) {
|
||||
tmp = index_of[lambda[j - 1]];
|
||||
if (tmp != nn) {
|
||||
@@ -175,6 +185,15 @@
|
||||
if (lambda[i] != nn)
|
||||
deg_lambda = i;
|
||||
}
|
||||
|
||||
if (deg_lambda == 0) {
|
||||
/*
|
||||
* deg(lambda) is zero even though the syndrome is non-zero
|
||||
* => uncorrectable error detected
|
||||
*/
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* Find roots of error+erasure locator polynomial by Chien search */
|
||||
memcpy(®[1], &lambda[1], nroots * sizeof(reg[0]));
|
||||
count = 0; /* Number of roots of lambda(x) */
|
||||
@@ -188,6 +207,12 @@
|
||||
}
|
||||
if (q != 0)
|
||||
continue; /* Not a root */
|
||||
|
||||
if (k < pad) {
|
||||
/* Impossible error location. Uncorrectable error. */
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/* store root (index-form) and error location number */
|
||||
root[count] = i;
|
||||
loc[count] = k;
|
||||
@@ -202,8 +227,7 @@
|
||||
* deg(lambda) unequal to number of roots => uncorrectable
|
||||
* error detected
|
||||
*/
|
||||
count = -EBADMSG;
|
||||
goto finish;
|
||||
return -EBADMSG;
|
||||
}
|
||||
/*
|
||||
* Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo
|
||||
@@ -223,7 +247,9 @@
|
||||
/*
|
||||
* Compute error values in poly-form. num1 = omega(inv(X(l))), num2 =
|
||||
* inv(X(l))**(fcr-1) and den = lambda_pr(inv(X(l))) all in poly-form
|
||||
* Note: we reuse the buffer for b to store the correction pattern
|
||||
*/
|
||||
num_corrected = 0;
|
||||
for (j = count - 1; j >= 0; j--) {
|
||||
num1 = 0;
|
||||
for (i = deg_omega; i >= 0; i--) {
|
||||
@@ -231,6 +257,13 @@
|
||||
num1 ^= alpha_to[rs_modnn(rs, omega[i] +
|
||||
i * root[j])];
|
||||
}
|
||||
|
||||
if (num1 == 0) {
|
||||
/* Nothing to correct at this position */
|
||||
b[j] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
|
||||
den = 0;
|
||||
|
||||
@@ -242,30 +275,52 @@
|
||||
i * root[j])];
|
||||
}
|
||||
}
|
||||
/* Apply error to data */
|
||||
if (num1 != 0 && loc[j] >= pad) {
|
||||
uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
|
||||
index_of[num2] +
|
||||
nn - index_of[den])];
|
||||
/* Store the error correction pattern, if a
|
||||
* correction buffer is available */
|
||||
if (corr) {
|
||||
corr[j] = cor;
|
||||
} else {
|
||||
/* If a data buffer is given and the
|
||||
* error is inside the message,
|
||||
* correct it */
|
||||
if (data && (loc[j] < (nn - nroots)))
|
||||
data[loc[j] - pad] ^= cor;
|
||||
|
||||
b[j] = alpha_to[rs_modnn(rs, index_of[num1] +
|
||||
index_of[num2] +
|
||||
nn - index_of[den])];
|
||||
num_corrected++;
|
||||
}
|
||||
|
||||
/*
|
||||
* We compute the syndrome of the 'error' and check that it matches
|
||||
* the syndrome of the received word
|
||||
*/
|
||||
for (i = 0; i < nroots; i++) {
|
||||
tmp = 0;
|
||||
for (j = 0; j < count; j++) {
|
||||
if (b[j] == 0)
|
||||
continue;
|
||||
|
||||
k = (fcr + i) * prim * (nn-loc[j]-1);
|
||||
tmp ^= alpha_to[rs_modnn(rs, index_of[b[j]] + k)];
|
||||
}
|
||||
|
||||
if (tmp != alpha_to[s[i]])
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the error correction pattern, if a
|
||||
* correction buffer is available
|
||||
*/
|
||||
if (corr && eras_pos) {
|
||||
j = 0;
|
||||
for (i = 0; i < count; i++) {
|
||||
if (b[i]) {
|
||||
corr[j] = b[i];
|
||||
eras_pos[j++] = loc[i] - pad;
|
||||
}
|
||||
}
|
||||
} else if (data && par) {
|
||||
/* Apply error to data and parity */
|
||||
for (i = 0; i < count; i++) {
|
||||
if (loc[i] < (nn - nroots))
|
||||
data[loc[i] - pad] ^= b[i];
|
||||
else
|
||||
par[loc[i] - pad - len] ^= b[i];
|
||||
}
|
||||
}
|
||||
|
||||
finish:
|
||||
if (eras_pos != NULL) {
|
||||
for (i = 0; i < count; i++)
|
||||
eras_pos[i] = loc[i] - pad;
|
||||
}
|
||||
return count;
|
||||
|
||||
return num_corrected;
|
||||
}
|
||||
|
||||
@@ -340,7 +340,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
|
||||
* @data: data field of a given type
|
||||
* @par: received parity data field
|
||||
* @len: data length
|
||||
* @s: syndrome data field (if NULL, syndrome is calculated)
|
||||
* @s: syndrome data field, must be in index form
|
||||
* (if NULL, syndrome is calculated)
|
||||
* @no_eras: number of erasures
|
||||
* @eras_pos: position of erasures, can be NULL
|
||||
* @invmsk: invert data mask (will be xored on data, not on parity!)
|
||||
@@ -354,7 +355,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
|
||||
* decoding, so the caller has to ensure that decoder invocations are
|
||||
* serialized.
|
||||
*
|
||||
* Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
|
||||
* Returns the number of corrected symbols or -EBADMSG for uncorrectable
|
||||
* errors. The count includes errors in the parity.
|
||||
*/
|
||||
int decode_rs8(struct rs_control *rsc, uint8_t *data, uint16_t *par, int len,
|
||||
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
|
||||
@@ -391,7 +393,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
|
||||
* @data: data field of a given type
|
||||
* @par: received parity data field
|
||||
* @len: data length
|
||||
* @s: syndrome data field (if NULL, syndrome is calculated)
|
||||
* @s: syndrome data field, must be in index form
|
||||
* (if NULL, syndrome is calculated)
|
||||
* @no_eras: number of erasures
|
||||
* @eras_pos: position of erasures, can be NULL
|
||||
* @invmsk: invert data mask (will be xored on data, not on parity!)
|
||||
@@ -403,7 +406,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
|
||||
* decoding, so the caller has to ensure that decoder invocations are
|
||||
* serialized.
|
||||
*
|
||||
* Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
|
||||
* Returns the number of corrected symbols or -EBADMSG for uncorrectable
|
||||
* errors. The count includes errors in the parity.
|
||||
*/
|
||||
int decode_rs16(struct rs_control *rsc, uint16_t *data, uint16_t *par, int len,
|
||||
uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user