blob: 880fcdaf334687f2a75335b5f3e2637a3bc49401 [file] [log] [blame]
Thomas Gleixner03ead842005-11-07 11:15:37 +00001/*
Thomas Gleixner3413e182018-04-22 18:23:49 +02002 * Generic Reed Solomon encoder / decoder library
Thomas Gleixner03ead842005-11-07 11:15:37 +00003 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
5 *
6 * Reed Solomon code lifted from reed solomon library written by Phil Karn
7 * Copyright 2002 Phil Karn, KA9Q
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 *
13 * Description:
Thomas Gleixner03ead842005-11-07 11:15:37 +000014 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 * The generic Reed Solomon library provides runtime configurable
16 * encoding / decoding of RS codes.
17 * Each user must call init_rs to get a pointer to a rs_control
18 * structure for the given rs parameters. This structure is either
19 * generated or a already available matching control structure is used.
20 * If a structure is generated then the polynomial arrays for
21 * fast encoding / decoding are built. This can take some time so
22 * make sure not to call this function from a time critical path.
Thomas Gleixner03ead842005-11-07 11:15:37 +000023 * Usually a module / driver should initialize the necessary
Linus Torvalds1da177e2005-04-16 15:20:36 -070024 * rs_control structure on module / driver init and release it
25 * on exit.
Thomas Gleixner03ead842005-11-07 11:15:37 +000026 * The encoding puts the calculated syndrome into a given syndrome
27 * buffer.
Linus Torvalds1da177e2005-04-16 15:20:36 -070028 * The decoding is a two step process. The first step calculates
29 * the syndrome over the received (data + syndrome) and calls the
30 * second stage, which does the decoding / error correction itself.
31 * Many hw encoders provide a syndrome calculation over the received
32 * data + syndrome and can call the second stage directly.
Linus Torvalds1da177e2005-04-16 15:20:36 -070033 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include <linux/errno.h>
35#include <linux/kernel.h>
36#include <linux/init.h>
37#include <linux/module.h>
38#include <linux/rslib.h>
39#include <linux/slab.h>
Arjan van de Ven97d1f152006-03-23 03:00:24 -080040#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
42/* This list holds all currently allocated rs control structures */
43static LIST_HEAD (rslist);
44/* Protection for the list */
Arjan van de Ven97d1f152006-03-23 03:00:24 -080045static DEFINE_MUTEX(rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Thomas Gleixner03ead842005-11-07 11:15:37 +000047/**
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 * rs_init - Initialize a Reed-Solomon codec
Linus Torvalds1da177e2005-04-16 15:20:36 -070049 * @symsize: symbol size, bits (1-8)
50 * @gfpoly: Field generator polynomial coefficients
Segher Boessenkoold7e5a542007-05-02 12:18:41 +020051 * @gffunc: Field generator function
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 * @fcr: first root of RS code generator polynomial, index form
53 * @prim: primitive element to generate polynomial roots
54 * @nroots: RS code generator polynomial degree (number of roots)
Thomas Gleixner83a530e2018-04-22 18:23:46 +020055 * @gfp: GFP_ flags for allocations
Linus Torvalds1da177e2005-04-16 15:20:36 -070056 *
57 * Allocate a control structure and the polynom arrays for faster
Randy Dunlap9dc65572006-06-25 05:49:14 -070058 * en/decoding. Fill the arrays according to the given parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +020060static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
Thomas Gleixner83a530e2018-04-22 18:23:46 +020061 int fcr, int prim, int nroots, gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
63 struct rs_control *rs;
64 int i, j, sr, root, iprim;
65
66 /* Allocate the control structure */
Thomas Gleixner83a530e2018-04-22 18:23:46 +020067 rs = kmalloc(sizeof(*rs), gfp);
68 if (!rs)
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 return NULL;
70
71 INIT_LIST_HEAD(&rs->list);
72
73 rs->mm = symsize;
74 rs->nn = (1 << symsize) - 1;
75 rs->fcr = fcr;
76 rs->prim = prim;
77 rs->nroots = nroots;
78 rs->gfpoly = gfpoly;
Segher Boessenkoold7e5a542007-05-02 12:18:41 +020079 rs->gffunc = gffunc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080
81 /* Allocate the arrays */
Thomas Gleixner83a530e2018-04-22 18:23:46 +020082 rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 if (rs->alpha_to == NULL)
84 goto errrs;
85
Thomas Gleixner83a530e2018-04-22 18:23:46 +020086 rs->index_of = kmalloc(sizeof(uint16_t) * (rs->nn + 1), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 if (rs->index_of == NULL)
88 goto erralp;
89
Thomas Gleixner83a530e2018-04-22 18:23:46 +020090 rs->genpoly = kmalloc(sizeof(uint16_t) * (rs->nroots + 1), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 if(rs->genpoly == NULL)
92 goto erridx;
93
94 /* Generate Galois field lookup tables */
95 rs->index_of[0] = rs->nn; /* log(zero) = -inf */
96 rs->alpha_to[rs->nn] = 0; /* alpha**-inf = 0 */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +020097 if (gfpoly) {
98 sr = 1;
99 for (i = 0; i < rs->nn; i++) {
100 rs->index_of[sr] = i;
101 rs->alpha_to[i] = sr;
102 sr <<= 1;
103 if (sr & (1 << symsize))
104 sr ^= gfpoly;
105 sr &= rs->nn;
106 }
107 } else {
108 sr = gffunc(0);
109 for (i = 0; i < rs->nn; i++) {
110 rs->index_of[sr] = i;
111 rs->alpha_to[i] = sr;
112 sr = gffunc(sr);
113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 }
115 /* If it's not primitive, exit */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200116 if(sr != rs->alpha_to[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 goto errpol;
118
119 /* Find prim-th root of 1, used in decoding */
120 for(iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
121 /* prim-th root of 1, index form */
122 rs->iprim = iprim / prim;
123
124 /* Form RS code generator polynomial from its roots */
125 rs->genpoly[0] = 1;
126 for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
127 rs->genpoly[i + 1] = 1;
128 /* Multiply rs->genpoly[] by @**(root + x) */
129 for (j = i; j > 0; j--) {
130 if (rs->genpoly[j] != 0) {
Thomas Gleixner03ead842005-11-07 11:15:37 +0000131 rs->genpoly[j] = rs->genpoly[j -1] ^
132 rs->alpha_to[rs_modnn(rs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 rs->index_of[rs->genpoly[j]] + root)];
134 } else
135 rs->genpoly[j] = rs->genpoly[j - 1];
136 }
137 /* rs->genpoly[0] can never be zero */
Thomas Gleixner03ead842005-11-07 11:15:37 +0000138 rs->genpoly[0] =
139 rs->alpha_to[rs_modnn(rs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140 rs->index_of[rs->genpoly[0]] + root)];
141 }
142 /* convert rs->genpoly[] to index form for quicker encoding */
143 for (i = 0; i <= nroots; i++)
144 rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
145 return rs;
146
147 /* Error exit */
148errpol:
149 kfree(rs->genpoly);
150erridx:
151 kfree(rs->index_of);
152erralp:
153 kfree(rs->alpha_to);
154errrs:
155 kfree(rs);
156 return NULL;
157}
158
159
Thomas Gleixner03ead842005-11-07 11:15:37 +0000160/**
Randy Dunlap9dc65572006-06-25 05:49:14 -0700161 * free_rs - Free the rs control structure, if it is no longer used
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 * @rs: the control structure which is not longer used by the
163 * caller
164 */
165void free_rs(struct rs_control *rs)
166{
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800167 mutex_lock(&rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 rs->users--;
169 if(!rs->users) {
170 list_del(&rs->list);
171 kfree(rs->alpha_to);
172 kfree(rs->index_of);
173 kfree(rs->genpoly);
174 kfree(rs);
175 }
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800176 mutex_unlock(&rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177}
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200178EXPORT_SYMBOL_GPL(free_rs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179
Thomas Gleixner03ead842005-11-07 11:15:37 +0000180/**
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200181 * init_rs_internal - Find a matching or allocate a new rs control structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700182 * @symsize: the symbol size (number of bits)
183 * @gfpoly: the extended Galois field generator polynomial coefficients,
184 * with the 0th coefficient in the low order bit. The polynomial
185 * must be primitive;
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200186 * @gffunc: pointer to function to generate the next field element,
187 * or the multiplicative identity element if given 0. Used
188 * instead of gfpoly if gfpoly is 0
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200189 * @fcr: the first consecutive root of the rs code generator polynomial
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 * in index form
191 * @prim: primitive element to generate polynomial roots
192 * @nroots: RS code generator polynomial degree (number of roots)
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200193 * @gfp: GFP_ flags for allocations
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200195static struct rs_control *init_rs_internal(int symsize, int gfpoly,
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200196 int (*gffunc)(int), int fcr,
197 int prim, int nroots, gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200199 struct list_head *tmp;
200 struct rs_control *rs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201
202 /* Sanity checks */
203 if (symsize < 1)
204 return NULL;
205 if (fcr < 0 || fcr >= (1<<symsize))
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200206 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 if (prim <= 0 || prim >= (1<<symsize))
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200208 return NULL;
Thomas Gleixner03ead842005-11-07 11:15:37 +0000209 if (nroots < 0 || nroots >= (1<<symsize))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210 return NULL;
Thomas Gleixner03ead842005-11-07 11:15:37 +0000211
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800212 mutex_lock(&rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700213
214 /* Walk through the list and look for a matching entry */
215 list_for_each(tmp, &rslist) {
216 rs = list_entry(tmp, struct rs_control, list);
217 if (symsize != rs->mm)
218 continue;
219 if (gfpoly != rs->gfpoly)
220 continue;
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200221 if (gffunc != rs->gffunc)
222 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 if (fcr != rs->fcr)
Thomas Gleixner03ead842005-11-07 11:15:37 +0000224 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 if (prim != rs->prim)
Thomas Gleixner03ead842005-11-07 11:15:37 +0000226 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 if (nroots != rs->nroots)
228 continue;
229 /* We have a matching one already */
230 rs->users++;
231 goto out;
232 }
233
234 /* Create a new one */
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200235 rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots, gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236 if (rs) {
237 rs->users = 1;
238 list_add(&rs->list, &rslist);
239 }
Thomas Gleixner03ead842005-11-07 11:15:37 +0000240out:
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800241 mutex_unlock(&rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 return rs;
243}
244
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200245/**
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200246 * init_rs_gfp - Find a matching or allocate a new rs control structure
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200247 * @symsize: the symbol size (number of bits)
248 * @gfpoly: the extended Galois field generator polynomial coefficients,
249 * with the 0th coefficient in the low order bit. The polynomial
250 * must be primitive;
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200251 * @fcr: the first consecutive root of the rs code generator polynomial
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200252 * in index form
253 * @prim: primitive element to generate polynomial roots
254 * @nroots: RS code generator polynomial degree (number of roots)
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200255 * @gfp: GFP_ flags for allocations
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200256 */
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200257struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
258 int nroots, gfp_t gfp)
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200259{
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200260 return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots, gfp);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200261}
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200262EXPORT_SYMBOL_GPL(init_rs_gfp);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200263
264/**
265 * init_rs_non_canonical - Find a matching or allocate a new rs control
266 * structure, for fields with non-canonical
267 * representation
268 * @symsize: the symbol size (number of bits)
269 * @gffunc: pointer to function to generate the next field element,
270 * or the multiplicative identity element if given 0. Used
271 * instead of gfpoly if gfpoly is 0
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200272 * @fcr: the first consecutive root of the rs code generator polynomial
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200273 * in index form
274 * @prim: primitive element to generate polynomial roots
275 * @nroots: RS code generator polynomial degree (number of roots)
276 */
277struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200278 int fcr, int prim, int nroots)
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200279{
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200280 return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots,
281 GFP_KERNEL);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200282}
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200283EXPORT_SYMBOL_GPL(init_rs_non_canonical);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285#ifdef CONFIG_REED_SOLOMON_ENC8
Thomas Gleixner03ead842005-11-07 11:15:37 +0000286/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 * encode_rs8 - Calculate the parity for data values (8bit data width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288 * @rs: the rs control structure
289 * @data: data field of a given type
Thomas Gleixner03ead842005-11-07 11:15:37 +0000290 * @len: data length
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 * @par: parity data, must be initialized by caller (usually all 0)
292 * @invmsk: invert data mask (will be xored on data)
293 *
294 * The parity uses a uint16_t data type to enable
295 * symbol size > 8. The calling code must take care of encoding of the
296 * syndrome result for storage itself.
297 */
Thomas Gleixner03ead842005-11-07 11:15:37 +0000298int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 uint16_t invmsk)
300{
301#include "encode_rs.c"
302}
303EXPORT_SYMBOL_GPL(encode_rs8);
304#endif
305
306#ifdef CONFIG_REED_SOLOMON_DEC8
Thomas Gleixner03ead842005-11-07 11:15:37 +0000307/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 * decode_rs8 - Decode codeword (8bit data width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 * @rs: the rs control structure
310 * @data: data field of a given type
311 * @par: received parity data field
312 * @len: data length
313 * @s: syndrome data field (if NULL, syndrome is calculated)
314 * @no_eras: number of erasures
315 * @eras_pos: position of erasures, can be NULL
316 * @invmsk: invert data mask (will be xored on data, not on parity!)
317 * @corr: buffer to store correction bitmask on eras_pos
318 *
319 * The syndrome and parity uses a uint16_t data type to enable
320 * symbol size > 8. The calling code must take care of decoding of the
321 * syndrome result and the received parity before calling this code.
Jörn Engeleb684502007-10-20 23:16:32 +0200322 * Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323 */
324int decode_rs8(struct rs_control *rs, uint8_t *data, uint16_t *par, int len,
Thomas Gleixner03ead842005-11-07 11:15:37 +0000325 uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326 uint16_t *corr)
327{
328#include "decode_rs.c"
329}
330EXPORT_SYMBOL_GPL(decode_rs8);
331#endif
332
333#ifdef CONFIG_REED_SOLOMON_ENC16
334/**
335 * encode_rs16 - Calculate the parity for data values (16bit data width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700336 * @rs: the rs control structure
337 * @data: data field of a given type
Thomas Gleixner03ead842005-11-07 11:15:37 +0000338 * @len: data length
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 * @par: parity data, must be initialized by caller (usually all 0)
340 * @invmsk: invert data mask (will be xored on data, not on parity!)
341 *
342 * Each field in the data array contains up to symbol size bits of valid data.
343 */
Thomas Gleixner03ead842005-11-07 11:15:37 +0000344int encode_rs16(struct rs_control *rs, uint16_t *data, int len, uint16_t *par,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345 uint16_t invmsk)
346{
347#include "encode_rs.c"
348}
349EXPORT_SYMBOL_GPL(encode_rs16);
350#endif
351
352#ifdef CONFIG_REED_SOLOMON_DEC16
Thomas Gleixner03ead842005-11-07 11:15:37 +0000353/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700354 * decode_rs16 - Decode codeword (16bit data width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355 * @rs: the rs control structure
356 * @data: data field of a given type
357 * @par: received parity data field
358 * @len: data length
359 * @s: syndrome data field (if NULL, syndrome is calculated)
360 * @no_eras: number of erasures
361 * @eras_pos: position of erasures, can be NULL
Thomas Gleixner03ead842005-11-07 11:15:37 +0000362 * @invmsk: invert data mask (will be xored on data, not on parity!)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700363 * @corr: buffer to store correction bitmask on eras_pos
364 *
365 * Each field in the data array contains up to symbol size bits of valid data.
Jörn Engeleb684502007-10-20 23:16:32 +0200366 * Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 */
368int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
Thomas Gleixner03ead842005-11-07 11:15:37 +0000369 uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 uint16_t *corr)
371{
372#include "decode_rs.c"
373}
374EXPORT_SYMBOL_GPL(decode_rs16);
375#endif
376
Linus Torvalds1da177e2005-04-16 15:20:36 -0700377MODULE_LICENSE("GPL");
378MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
379MODULE_AUTHOR("Phil Karn, Thomas Gleixner");
380