aboutsummaryrefslogtreecommitdiff
path: root/lib/reed_solomon
diff options
context:
space:
mode:
Diffstat (limited to 'lib/reed_solomon')
-rw-r--r--lib/reed_solomon/Makefile2
-rw-r--r--lib/reed_solomon/decode_rs.c41
-rw-r--r--lib/reed_solomon/encode_rs.c14
-rw-r--r--lib/reed_solomon/reed_solomon.c171
4 files changed, 138 insertions, 90 deletions
diff --git a/lib/reed_solomon/Makefile b/lib/reed_solomon/Makefile
index 747a2de2934..c3d7136827e 100644
--- a/lib/reed_solomon/Makefile
+++ b/lib/reed_solomon/Makefile
@@ -1,5 +1,5 @@
#
-# This is a modified version of reed solomon lib,
+# This is a modified version of reed solomon lib,
#
obj-$(CONFIG_REED_SOLOMON) += reed_solomon.o
diff --git a/lib/reed_solomon/decode_rs.c b/lib/reed_solomon/decode_rs.c
index d401decd628..0ec3f257ffd 100644
--- a/lib/reed_solomon/decode_rs.c
+++ b/lib/reed_solomon/decode_rs.c
@@ -1,22 +1,22 @@
-/*
+/*
* lib/reed_solomon/decode_rs.c
*
* Overview:
* Generic Reed Solomon encoder / decoder library
- *
+ *
* Copyright 2002, Phil Karn, KA9Q
* May be used under the terms of the GNU General Public License (GPL)
*
* Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: decode_rs.c,v 1.6 2004/10/22 15:41:47 gleixner Exp $
+ * $Id: decode_rs.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
*
*/
-/* Generic data width independent code which is included by the
+/* Generic data width independent code which is included by the
* wrappers.
*/
-{
+{
int deg_lambda, el, deg_omega;
int i, j, r, k, pad;
int nn = rs->nn;
@@ -39,11 +39,10 @@
/* Check length parameter for validity */
pad = nn - nroots - len;
- if (pad < 0 || pad >= nn)
- return -ERANGE;
-
+ BUG_ON(pad < 0 || pad >= nn);
+
/* Does the caller provide the syndrome ? */
- if (s != NULL)
+ if (s != NULL)
goto decode;
/* form the syndromes; i.e., evaluate data(x) at roots of
@@ -54,11 +53,11 @@
for (j = 1; j < len; j++) {
for (i = 0; i < nroots; i++) {
if (syn[i] == 0) {
- syn[i] = (((uint16_t) data[j]) ^
+ syn[i] = (((uint16_t) data[j]) ^
invmsk) & msk;
} else {
syn[i] = ((((uint16_t) data[j]) ^
- invmsk) & msk) ^
+ invmsk) & msk) ^
alpha_to[rs_modnn(rs, index_of[syn[i]] +
(fcr + i) * prim)];
}
@@ -70,7 +69,7 @@
if (syn[i] == 0) {
syn[i] = ((uint16_t) par[j]) & msk;
} else {
- syn[i] = (((uint16_t) par[j]) & msk) ^
+ syn[i] = (((uint16_t) par[j]) & msk) ^
alpha_to[rs_modnn(rs, index_of[syn[i]] +
(fcr+i)*prim)];
}
@@ -99,14 +98,14 @@
if (no_eras > 0) {
/* Init lambda to be the erasure locator polynomial */
- lambda[1] = alpha_to[rs_modnn(rs,
+ lambda[1] = alpha_to[rs_modnn(rs,
prim * (nn - 1 - eras_pos[0]))];
for (i = 1; i < no_eras; i++) {
u = rs_modnn(rs, prim * (nn - 1 - eras_pos[i]));
for (j = i + 1; j > 0; j--) {
tmp = index_of[lambda[j - 1]];
if (tmp != nn) {
- lambda[j] ^=
+ lambda[j] ^=
alpha_to[rs_modnn(rs, u + tmp)];
}
}
@@ -127,8 +126,8 @@
discr_r = 0;
for (i = 0; i < r; i++) {
if ((lambda[i] != 0) && (s[r - i - 1] != nn)) {
- discr_r ^=
- alpha_to[rs_modnn(rs,
+ discr_r ^=
+ alpha_to[rs_modnn(rs,
index_of[lambda[i]] +
s[r - i - 1])];
}
@@ -143,7 +142,7 @@
t[0] = lambda[0];
for (i = 0; i < nroots; i++) {
if (b[i] != nn) {
- t[i + 1] = lambda[i + 1] ^
+ t[i + 1] = lambda[i + 1] ^
alpha_to[rs_modnn(rs, discr_r +
b[i])];
} else
@@ -203,7 +202,7 @@
* deg(lambda) unequal to number of roots => uncorrectable
* error detected
*/
- count = -1;
+ count = -EBADMSG;
goto finish;
}
/*
@@ -229,7 +228,7 @@
num1 = 0;
for (i = deg_omega; i >= 0; i--) {
if (omega[i] != nn)
- num1 ^= alpha_to[rs_modnn(rs, omega[i] +
+ num1 ^= alpha_to[rs_modnn(rs, omega[i] +
i * root[j])];
}
num2 = alpha_to[rs_modnn(rs, root[j] * (fcr - 1) + nn)];
@@ -239,13 +238,13 @@
* lambda_pr of lambda[i] */
for (i = min(deg_lambda, nroots - 1) & ~1; i >= 0; i -= 2) {
if (lambda[i + 1] != nn) {
- den ^= alpha_to[rs_modnn(rs, lambda[i + 1] +
+ den ^= alpha_to[rs_modnn(rs, lambda[i + 1] +
i * root[j])];
}
}
/* Apply error to data */
if (num1 != 0 && loc[j] >= pad) {
- uint16_t cor = alpha_to[rs_modnn(rs,index_of[num1] +
+ 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
diff --git a/lib/reed_solomon/encode_rs.c b/lib/reed_solomon/encode_rs.c
index 237bf65ae88..0b5b1a6728e 100644
--- a/lib/reed_solomon/encode_rs.c
+++ b/lib/reed_solomon/encode_rs.c
@@ -1,19 +1,19 @@
-/*
+/*
* lib/reed_solomon/encode_rs.c
*
* Overview:
* Generic Reed Solomon encoder / decoder library
- *
+ *
* Copyright 2002, Phil Karn, KA9Q
* May be used under the terms of the GNU General Public License (GPL)
*
* Adaption to the kernel by Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: encode_rs.c,v 1.4 2004/10/22 15:41:47 gleixner Exp $
+ * $Id: encode_rs.c,v 1.5 2005/11/07 11:14:59 gleixner Exp $
*
*/
-/* Generic data width independent code which is included by the
+/* Generic data width independent code which is included by the
* wrappers.
* int encode_rsX (struct rs_control *rs, uintX_t *data, int len, uintY_t *par)
*/
@@ -35,16 +35,16 @@
for (i = 0; i < len; i++) {
fb = index_of[((((uint16_t) data[i])^invmsk) & msk) ^ par[0]];
/* feedback term is non-zero */
- if (fb != nn) {
+ if (fb != nn) {
for (j = 1; j < nroots; j++) {
- par[j] ^= alpha_to[rs_modnn(rs, fb +
+ par[j] ^= alpha_to[rs_modnn(rs, fb +
genpoly[nroots - j])];
}
}
/* Shift */
memmove(&par[0], &par[1], sizeof(uint16_t) * (nroots - 1));
if (fb != nn) {
- par[nroots - 1] = alpha_to[rs_modnn(rs,
+ par[nroots - 1] = alpha_to[rs_modnn(rs,
fb + genpoly[0])];
} else {
par[nroots - 1] = 0;
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index 6604e3b1940..06d04cfa933 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -1,22 +1,22 @@
-/*
- * lib/reed_solomon/rslib.c
+/*
+ * lib/reed_solomon/reed_solomon.c
*
* Overview:
* Generic Reed Solomon encoder / decoder library
- *
+ *
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
* Reed Solomon code lifted from reed solomon library written by Phil Karn
* Copyright 2002 Phil Karn, KA9Q
*
- * $Id: rslib.c,v 1.5 2004/10/22 15:41:47 gleixner Exp $
+ * $Id: rslib.c,v 1.7 2005/11/07 11:14:59 gleixner Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Description:
- *
+ *
* The generic Reed Solomon library provides runtime configurable
* encoding / decoding of RS codes.
* Each user must call init_rs to get a pointer to a rs_control
@@ -25,11 +25,11 @@
* If a structure is generated then the polynomial arrays for
* fast encoding / decoding are built. This can take some time so
* make sure not to call this function from a time critical path.
- * Usually a module / driver should initialize the necessary
+ * Usually a module / driver should initialize the necessary
* rs_control structure on module / driver init and release it
* on exit.
- * The encoding puts the calculated syndrome into a given syndrome
- * buffer.
+ * The encoding puts the calculated syndrome into a given syndrome
+ * buffer.
* The decoding is a two step process. The first step calculates
* the syndrome over the received (data + syndrome) and calls the
* second stage, which does the decoding / error correction itself.
@@ -44,27 +44,27 @@
#include <linux/module.h>
#include <linux/rslib.h>
#include <linux/slab.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
/* This list holds all currently allocated rs control structures */
static LIST_HEAD (rslist);
/* Protection for the list */
-static DECLARE_MUTEX(rslistlock);
+static DEFINE_MUTEX(rslistlock);
-/**
+/**
* rs_init - Initialize a Reed-Solomon codec
- *
* @symsize: symbol size, bits (1-8)
* @gfpoly: Field generator polynomial coefficients
+ * @gffunc: Field generator function
* @fcr: first root of RS code generator polynomial, index form
* @prim: primitive element to generate polynomial roots
* @nroots: RS code generator polynomial degree (number of roots)
*
* Allocate a control structure and the polynom arrays for faster
- * en/decoding. Fill the arrays according to the given parameters
+ * en/decoding. Fill the arrays according to the given parameters.
*/
-static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
- int prim, int nroots)
+static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
+ int fcr, int prim, int nroots)
{
struct rs_control *rs;
int i, j, sr, root, iprim;
@@ -82,6 +82,7 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
rs->prim = prim;
rs->nroots = nroots;
rs->gfpoly = gfpoly;
+ rs->gffunc = gffunc;
/* Allocate the arrays */
rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
@@ -99,17 +100,26 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
/* Generate Galois field lookup tables */
rs->index_of[0] = rs->nn; /* log(zero) = -inf */
rs->alpha_to[rs->nn] = 0; /* alpha**-inf = 0 */
- sr = 1;
- for (i = 0; i < rs->nn; i++) {
- rs->index_of[sr] = i;
- rs->alpha_to[i] = sr;
- sr <<= 1;
- if (sr & (1 << symsize))
- sr ^= gfpoly;
- sr &= rs->nn;
+ if (gfpoly) {
+ sr = 1;
+ for (i = 0; i < rs->nn; i++) {
+ rs->index_of[sr] = i;
+ rs->alpha_to[i] = sr;
+ sr <<= 1;
+ if (sr & (1 << symsize))
+ sr ^= gfpoly;
+ sr &= rs->nn;
+ }
+ } else {
+ sr = gffunc(0);
+ for (i = 0; i < rs->nn; i++) {
+ rs->index_of[sr] = i;
+ rs->alpha_to[i] = sr;
+ sr = gffunc(sr);
+ }
}
/* If it's not primitive, exit */
- if(sr != 1)
+ if(sr != rs->alpha_to[0])
goto errpol;
/* Find prim-th root of 1, used in decoding */
@@ -124,15 +134,15 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int fcr,
/* Multiply rs->genpoly[] by @**(root + x) */
for (j = i; j > 0; j--) {
if (rs->genpoly[j] != 0) {
- rs->genpoly[j] = rs->genpoly[j -1] ^
- rs->alpha_to[rs_modnn(rs,
+ rs->genpoly[j] = rs->genpoly[j -1] ^
+ rs->alpha_to[rs_modnn(rs,
rs->index_of[rs->genpoly[j]] + root)];
} else
rs->genpoly[j] = rs->genpoly[j - 1];
}
/* rs->genpoly[0] can never be zero */
- rs->genpoly[0] =
- rs->alpha_to[rs_modnn(rs,
+ rs->genpoly[0] =
+ rs->alpha_to[rs_modnn(rs,
rs->index_of[rs->genpoly[0]] + root)];
}
/* convert rs->genpoly[] to index form for quicker encoding */
@@ -153,15 +163,14 @@ errrs:
}
-/**
- * free_rs - Free the rs control structure, if its not longer used
- *
+/**
+ * free_rs - Free the rs control structure, if it is no longer used
* @rs: the control structure which is not longer used by the
* caller
*/
void free_rs(struct rs_control *rs)
{
- down(&rslistlock);
+ mutex_lock(&rslistlock);
rs->users--;
if(!rs->users) {
list_del(&rs->list);
@@ -170,23 +179,26 @@ void free_rs(struct rs_control *rs)
kfree(rs->genpoly);
kfree(rs);
}
- up(&rslistlock);
+ mutex_unlock(&rslistlock);
}
-/**
- * init_rs - Find a matching or allocate a new rs control structure
- *
+/**
+ * init_rs_internal - Find a matching or allocate a new rs control structure
* @symsize: the symbol size (number of bits)
* @gfpoly: the extended Galois field generator polynomial coefficients,
* with the 0th coefficient in the low order bit. The polynomial
* must be primitive;
- * @fcr: the first consecutive root of the rs code generator polynomial
+ * @gffunc: pointer to function to generate the next field element,
+ * or the multiplicative identity element if given 0. Used
+ * instead of gfpoly if gfpoly is 0
+ * @fcr: the first consecutive root of the rs code generator polynomial
* in index form
* @prim: primitive element to generate polynomial roots
* @nroots: RS code generator polynomial degree (number of roots)
*/
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
- int nroots)
+static struct rs_control *init_rs_internal(int symsize, int gfpoly,
+ int (*gffunc)(int), int fcr,
+ int prim, int nroots)
{
struct list_head *tmp;
struct rs_control *rs;
@@ -198,10 +210,10 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
return NULL;
if (prim <= 0 || prim >= (1<<symsize))
return NULL;
- if (nroots < 0 || nroots >= (1<<symsize) || nroots > 8)
+ if (nroots < 0 || nroots >= (1<<symsize))
return NULL;
-
- down(&rslistlock);
+
+ mutex_lock(&rslistlock);
/* Walk through the list and look for a matching entry */
list_for_each(tmp, &rslist) {
@@ -210,10 +222,12 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
continue;
if (gfpoly != rs->gfpoly)
continue;
+ if (gffunc != rs->gffunc)
+ continue;
if (fcr != rs->fcr)
- continue;
+ continue;
if (prim != rs->prim)
- continue;
+ continue;
if (nroots != rs->nroots)
continue;
/* We have a matching one already */
@@ -222,23 +236,58 @@ struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
}
/* Create a new one */
- rs = rs_init(symsize, gfpoly, fcr, prim, nroots);
+ rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots);
if (rs) {
rs->users = 1;
list_add(&rs->list, &rslist);
}
-out:
- up(&rslistlock);
+out:
+ mutex_unlock(&rslistlock);
return rs;
}
+/**
+ * init_rs - Find a matching or allocate a new rs control structure
+ * @symsize: the symbol size (number of bits)
+ * @gfpoly: the extended Galois field generator polynomial coefficients,
+ * with the 0th coefficient in the low order bit. The polynomial
+ * must be primitive;
+ * @fcr: the first consecutive root of the rs code generator polynomial
+ * in index form
+ * @prim: primitive element to generate polynomial roots
+ * @nroots: RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
+ int nroots)
+{
+ return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots);
+}
+
+/**
+ * init_rs_non_canonical - Find a matching or allocate a new rs control
+ * structure, for fields with non-canonical
+ * representation
+ * @symsize: the symbol size (number of bits)
+ * @gffunc: pointer to function to generate the next field element,
+ * or the multiplicative identity element if given 0. Used
+ * instead of gfpoly if gfpoly is 0
+ * @fcr: the first consecutive root of the rs code generator polynomial
+ * in index form
+ * @prim: primitive element to generate polynomial roots
+ * @nroots: RS code generator polynomial degree (number of roots)
+ */
+struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
+ int fcr, int prim, int nroots)
+{
+ return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots);
+}
+
#ifdef CONFIG_REED_SOLOMON_ENC8
-/**
+/**
* encode_rs8 - Calculate the parity for data values (8bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
- * @len: data length
+ * @len: data length
* @par: parity data, must be initialized by caller (usually all 0)
* @invmsk: invert data mask (will be xored on data)
*
@@ -246,7 +295,7 @@ out:
* symbol size > 8. The calling code must take care of encoding of the
* syndrome result for storage itself.
*/
-int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
+int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
uint16_t invmsk)
{
#include "encode_rs.c"
@@ -255,9 +304,8 @@ EXPORT_SYMBOL_GPL(encode_rs8);
#endif
#ifdef CONFIG_REED_SOLOMON_DEC8
-/**
+/**
* decode_rs8 - Decode codeword (8bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
* @par: received parity data field
@@ -271,9 +319,10 @@ EXPORT_SYMBOL_GPL(encode_rs8);
* The syndrome and parity uses a uint16_t data type to enable
* symbol size > 8. The calling code must take care of decoding of the
* syndrome result and the received parity before calling this code.
+ * Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
*/
int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
- uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+ uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
uint16_t *corr)
{
#include "decode_rs.c"
@@ -284,16 +333,15 @@ EXPORT_SYMBOL_GPL(decode_rs8);
#ifdef CONFIG_REED_SOLOMON_ENC16
/**
* encode_rs16 - Calculate the parity for data values (16bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
- * @len: data length
+ * @len: data length
* @par: parity data, must be initialized by caller (usually all 0)
* @invmsk: invert data mask (will be xored on data, not on parity!)
*
* Each field in the data array contains up to symbol size bits of valid data.
*/
-int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
+int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
uint16_t invmsk)
{
#include "encode_rs.c"
@@ -302,9 +350,8 @@ EXPORT_SYMBOL_GPL(encode_rs16);
#endif
#ifdef CONFIG_REED_SOLOMON_DEC16
-/**
+/**
* decode_rs16 - Decode codeword (16bit data width)
- *
* @rs: the rs control structure
* @data: data field of a given type
* @par: received parity data field
@@ -312,13 +359,14 @@ EXPORT_SYMBOL_GPL(encode_rs16);
* @s: syndrome data field (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!)
+ * @invmsk: invert data mask (will be xored on data, not on parity!)
* @corr: buffer to store correction bitmask on eras_pos
*
* Each field in the data array contains up to symbol size bits of valid data.
+ * Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
*/
int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
- uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
+ uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
uint16_t *corr)
{
#include "decode_rs.c"
@@ -327,6 +375,7 @@ EXPORT_SYMBOL_GPL(decode_rs16);
#endif
EXPORT_SYMBOL_GPL(init_rs);
+EXPORT_SYMBOL_GPL(init_rs_non_canonical);
EXPORT_SYMBOL_GPL(free_rs);
MODULE_LICENSE("GPL");