blob: e5fdc8b9e856851114df25fb7bb0100ad8eb797e [file] [log] [blame]
Thomas Gleixnerdc8f9232018-04-22 18:23:50 +02001// SPDX-License-Identifier: GPL-2.0
Thomas Gleixner03ead842005-11-07 11:15:37 +00002/*
Thomas Gleixner3413e182018-04-22 18:23:49 +02003 * Generic Reed Solomon encoder / decoder library
Thomas Gleixner03ead842005-11-07 11:15:37 +00004 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
6 *
7 * Reed Solomon code lifted from reed solomon library written by Phil Karn
8 * Copyright 2002 Phil Karn, KA9Q
9 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 * Description:
Thomas Gleixner03ead842005-11-07 11:15:37 +000011 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070012 * The generic Reed Solomon library provides runtime configurable
13 * encoding / decoding of RS codes.
Thomas Gleixner21633982018-04-22 18:23:53 +020014 *
15 * Each user must call init_rs to get a pointer to a rs_control structure
16 * for the given rs parameters. The control struct is unique per instance.
17 * It points to a codec which can be shared by multiple control structures.
18 * If a codec is newly allocated then the polynomial arrays for fast
19 * encoding / decoding are built. This can take some time so make sure not
20 * to call this function from a time critical path. Usually a module /
21 * driver should initialize the necessary rs_control structure on module /
22 * driver init and release it on exit.
23 *
24 * The encoding puts the calculated syndrome into a given syndrome buffer.
25 *
26 * The decoding is a two step process. The first step calculates the
27 * syndrome over the received (data + syndrome) and calls the second stage,
28 * which does the decoding / error correction itself. Many hw encoders
29 * provide a syndrome calculation over the received data + syndrome and can
30 * call the second stage directly.
Linus Torvalds1da177e2005-04-16 15:20:36 -070031 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/errno.h>
33#include <linux/kernel.h>
34#include <linux/init.h>
35#include <linux/module.h>
36#include <linux/rslib.h>
37#include <linux/slab.h>
Arjan van de Ven97d1f152006-03-23 03:00:24 -080038#include <linux/mutex.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070039
Thomas Gleixner45888b42018-04-22 18:23:55 +020040enum {
41 RS_DECODE_LAMBDA,
42 RS_DECODE_SYN,
43 RS_DECODE_B,
44 RS_DECODE_T,
45 RS_DECODE_OMEGA,
46 RS_DECODE_ROOT,
47 RS_DECODE_REG,
48 RS_DECODE_LOC,
49 RS_DECODE_NUM_BUFFERS
50};
51
Thomas Gleixner21633982018-04-22 18:23:53 +020052/* This list holds all currently allocated rs codec structures */
53static LIST_HEAD(codec_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -070054/* Protection for the list */
Arjan van de Ven97d1f152006-03-23 03:00:24 -080055static DEFINE_MUTEX(rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Thomas Gleixner03ead842005-11-07 11:15:37 +000057/**
Thomas Gleixner21633982018-04-22 18:23:53 +020058 * codec_init - Initialize a Reed-Solomon codec
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 * @symsize: symbol size, bits (1-8)
60 * @gfpoly: Field generator polynomial coefficients
Segher Boessenkoold7e5a542007-05-02 12:18:41 +020061 * @gffunc: Field generator function
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 * @fcr: first root of RS code generator polynomial, index form
63 * @prim: primitive element to generate polynomial roots
64 * @nroots: RS code generator polynomial degree (number of roots)
Thomas Gleixner83a530e2018-04-22 18:23:46 +020065 * @gfp: GFP_ flags for allocations
Linus Torvalds1da177e2005-04-16 15:20:36 -070066 *
Thomas Gleixner21633982018-04-22 18:23:53 +020067 * Allocate a codec structure and the polynom arrays for faster
Randy Dunlap9dc65572006-06-25 05:49:14 -070068 * en/decoding. Fill the arrays according to the given parameters.
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 */
Thomas Gleixner21633982018-04-22 18:23:53 +020070static struct rs_codec *codec_init(int symsize, int gfpoly, int (*gffunc)(int),
71 int fcr, int prim, int nroots, gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -070072{
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 int i, j, sr, root, iprim;
Thomas Gleixner21633982018-04-22 18:23:53 +020074 struct rs_codec *rs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075
Thomas Gleixnera85e1262018-04-22 18:23:52 +020076 rs = kzalloc(sizeof(*rs), gfp);
Thomas Gleixner83a530e2018-04-22 18:23:46 +020077 if (!rs)
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 return NULL;
79
80 INIT_LIST_HEAD(&rs->list);
81
82 rs->mm = symsize;
83 rs->nn = (1 << symsize) - 1;
84 rs->fcr = fcr;
85 rs->prim = prim;
86 rs->nroots = nroots;
87 rs->gfpoly = gfpoly;
Segher Boessenkoold7e5a542007-05-02 12:18:41 +020088 rs->gffunc = gffunc;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
90 /* Allocate the arrays */
Kees Cook6da2ec52018-06-12 13:55:00 -070091 rs->alpha_to = kmalloc_array(rs->nn + 1, sizeof(uint16_t), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 if (rs->alpha_to == NULL)
Thomas Gleixnera85e1262018-04-22 18:23:52 +020093 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Kees Cook6da2ec52018-06-12 13:55:00 -070095 rs->index_of = kmalloc_array(rs->nn + 1, sizeof(uint16_t), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 if (rs->index_of == NULL)
Thomas Gleixnera85e1262018-04-22 18:23:52 +020097 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Kees Cook6da2ec52018-06-12 13:55:00 -070099 rs->genpoly = kmalloc_array(rs->nroots + 1, sizeof(uint16_t), gfp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 if(rs->genpoly == NULL)
Thomas Gleixnera85e1262018-04-22 18:23:52 +0200101 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700102
103 /* Generate Galois field lookup tables */
104 rs->index_of[0] = rs->nn; /* log(zero) = -inf */
105 rs->alpha_to[rs->nn] = 0; /* alpha**-inf = 0 */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200106 if (gfpoly) {
107 sr = 1;
108 for (i = 0; i < rs->nn; i++) {
109 rs->index_of[sr] = i;
110 rs->alpha_to[i] = sr;
111 sr <<= 1;
112 if (sr & (1 << symsize))
113 sr ^= gfpoly;
114 sr &= rs->nn;
115 }
116 } else {
117 sr = gffunc(0);
118 for (i = 0; i < rs->nn; i++) {
119 rs->index_of[sr] = i;
120 rs->alpha_to[i] = sr;
121 sr = gffunc(sr);
122 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 }
124 /* If it's not primitive, exit */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200125 if(sr != rs->alpha_to[0])
Thomas Gleixnera85e1262018-04-22 18:23:52 +0200126 goto err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127
128 /* Find prim-th root of 1, used in decoding */
129 for(iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
130 /* prim-th root of 1, index form */
131 rs->iprim = iprim / prim;
132
133 /* Form RS code generator polynomial from its roots */
134 rs->genpoly[0] = 1;
135 for (i = 0, root = fcr * prim; i < nroots; i++, root += prim) {
136 rs->genpoly[i + 1] = 1;
137 /* Multiply rs->genpoly[] by @**(root + x) */
138 for (j = i; j > 0; j--) {
139 if (rs->genpoly[j] != 0) {
Thomas Gleixner03ead842005-11-07 11:15:37 +0000140 rs->genpoly[j] = rs->genpoly[j -1] ^
141 rs->alpha_to[rs_modnn(rs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142 rs->index_of[rs->genpoly[j]] + root)];
143 } else
144 rs->genpoly[j] = rs->genpoly[j - 1];
145 }
146 /* rs->genpoly[0] can never be zero */
Thomas Gleixner03ead842005-11-07 11:15:37 +0000147 rs->genpoly[0] =
148 rs->alpha_to[rs_modnn(rs,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149 rs->index_of[rs->genpoly[0]] + root)];
150 }
151 /* convert rs->genpoly[] to index form for quicker encoding */
152 for (i = 0; i <= nroots; i++)
153 rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
Thomas Gleixner21633982018-04-22 18:23:53 +0200154
155 rs->users = 1;
156 list_add(&rs->list, &codec_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 return rs;
158
Thomas Gleixnera85e1262018-04-22 18:23:52 +0200159err:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 kfree(rs->genpoly);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 kfree(rs->index_of);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 kfree(rs->alpha_to);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 kfree(rs);
164 return NULL;
165}
166
167
Thomas Gleixner03ead842005-11-07 11:15:37 +0000168/**
Thomas Gleixner21633982018-04-22 18:23:53 +0200169 * free_rs - Free the rs control structure
170 * @rs: The control structure which is not longer used by the
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171 * caller
Thomas Gleixner21633982018-04-22 18:23:53 +0200172 *
173 * Free the control structure. If @rs is the last user of the associated
174 * codec, free the codec as well.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 */
176void free_rs(struct rs_control *rs)
177{
Thomas Gleixner21633982018-04-22 18:23:53 +0200178 struct rs_codec *cd;
179
180 if (!rs)
181 return;
182
183 cd = rs->codec;
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800184 mutex_lock(&rslistlock);
Thomas Gleixner21633982018-04-22 18:23:53 +0200185 cd->users--;
186 if(!cd->users) {
187 list_del(&cd->list);
188 kfree(cd->alpha_to);
189 kfree(cd->index_of);
190 kfree(cd->genpoly);
191 kfree(cd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 }
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800193 mutex_unlock(&rslistlock);
Thomas Gleixner21633982018-04-22 18:23:53 +0200194 kfree(rs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195}
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200196EXPORT_SYMBOL_GPL(free_rs);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197
Thomas Gleixner03ead842005-11-07 11:15:37 +0000198/**
Thomas Gleixner21633982018-04-22 18:23:53 +0200199 * init_rs_internal - Allocate rs control, find a matching codec or allocate a new one
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 * @symsize: the symbol size (number of bits)
201 * @gfpoly: the extended Galois field generator polynomial coefficients,
202 * with the 0th coefficient in the low order bit. The polynomial
203 * must be primitive;
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200204 * @gffunc: pointer to function to generate the next field element,
205 * or the multiplicative identity element if given 0. Used
206 * instead of gfpoly if gfpoly is 0
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200207 * @fcr: the first consecutive root of the rs code generator polynomial
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208 * in index form
209 * @prim: primitive element to generate polynomial roots
210 * @nroots: RS code generator polynomial degree (number of roots)
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200211 * @gfp: GFP_ flags for allocations
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 */
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200213static struct rs_control *init_rs_internal(int symsize, int gfpoly,
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200214 int (*gffunc)(int), int fcr,
215 int prim, int nroots, gfp_t gfp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216{
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200217 struct list_head *tmp;
218 struct rs_control *rs;
Thomas Gleixner45888b42018-04-22 18:23:55 +0200219 unsigned int bsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220
221 /* Sanity checks */
222 if (symsize < 1)
223 return NULL;
224 if (fcr < 0 || fcr >= (1<<symsize))
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200225 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 if (prim <= 0 || prim >= (1<<symsize))
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200227 return NULL;
Thomas Gleixner03ead842005-11-07 11:15:37 +0000228 if (nroots < 0 || nroots >= (1<<symsize))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 return NULL;
Thomas Gleixner03ead842005-11-07 11:15:37 +0000230
Thomas Gleixner45888b42018-04-22 18:23:55 +0200231 /*
232 * The decoder needs buffers in each control struct instance to
233 * avoid variable size or large fixed size allocations on
234 * stack. Size the buffers to arrays of [nroots + 1].
235 */
236 bsize = sizeof(uint16_t) * RS_DECODE_NUM_BUFFERS * (nroots + 1);
237 rs = kzalloc(sizeof(*rs) + bsize, gfp);
Thomas Gleixner21633982018-04-22 18:23:53 +0200238 if (!rs)
239 return NULL;
240
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800241 mutex_lock(&rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242
243 /* Walk through the list and look for a matching entry */
Thomas Gleixner21633982018-04-22 18:23:53 +0200244 list_for_each(tmp, &codec_list) {
245 struct rs_codec *cd = list_entry(tmp, struct rs_codec, list);
246
247 if (symsize != cd->mm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 continue;
Thomas Gleixner21633982018-04-22 18:23:53 +0200249 if (gfpoly != cd->gfpoly)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 continue;
Thomas Gleixner21633982018-04-22 18:23:53 +0200251 if (gffunc != cd->gffunc)
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200252 continue;
Thomas Gleixner21633982018-04-22 18:23:53 +0200253 if (fcr != cd->fcr)
Thomas Gleixner03ead842005-11-07 11:15:37 +0000254 continue;
Thomas Gleixner21633982018-04-22 18:23:53 +0200255 if (prim != cd->prim)
Thomas Gleixner03ead842005-11-07 11:15:37 +0000256 continue;
Thomas Gleixner21633982018-04-22 18:23:53 +0200257 if (nroots != cd->nroots)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258 continue;
259 /* We have a matching one already */
Thomas Gleixner21633982018-04-22 18:23:53 +0200260 cd->users++;
261 rs->codec = cd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 goto out;
263 }
264
265 /* Create a new one */
Thomas Gleixner21633982018-04-22 18:23:53 +0200266 rs->codec = codec_init(symsize, gfpoly, gffunc, fcr, prim, nroots, gfp);
267 if (!rs->codec) {
268 kfree(rs);
269 rs = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700270 }
Thomas Gleixner03ead842005-11-07 11:15:37 +0000271out:
Arjan van de Ven97d1f152006-03-23 03:00:24 -0800272 mutex_unlock(&rslistlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 return rs;
274}
275
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200276/**
Thomas Gleixner21633982018-04-22 18:23:53 +0200277 * init_rs_gfp - Create a RS control struct and initialize it
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200278 * @symsize: the symbol size (number of bits)
279 * @gfpoly: the extended Galois field generator polynomial coefficients,
280 * with the 0th coefficient in the low order bit. The polynomial
281 * must be primitive;
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200282 * @fcr: the first consecutive root of the rs code generator polynomial
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200283 * in index form
284 * @prim: primitive element to generate polynomial roots
285 * @nroots: RS code generator polynomial degree (number of roots)
Matthew Wilcox8dd99872018-07-03 12:43:54 -0700286 * @gfp: Memory allocation flags.
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200287 */
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200288struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
289 int nroots, gfp_t gfp)
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200290{
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200291 return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots, gfp);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200292}
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200293EXPORT_SYMBOL_GPL(init_rs_gfp);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200294
295/**
Thomas Gleixner21633982018-04-22 18:23:53 +0200296 * init_rs_non_canonical - Allocate rs control struct for fields with
297 * non-canonical representation
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200298 * @symsize: the symbol size (number of bits)
299 * @gffunc: pointer to function to generate the next field element,
300 * or the multiplicative identity element if given 0. Used
301 * instead of gfpoly if gfpoly is 0
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200302 * @fcr: the first consecutive root of the rs code generator polynomial
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200303 * in index form
304 * @prim: primitive element to generate polynomial roots
305 * @nroots: RS code generator polynomial degree (number of roots)
306 */
307struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
Thomas Gleixnercc4b86e42018-04-22 18:23:48 +0200308 int fcr, int prim, int nroots)
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200309{
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200310 return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots,
311 GFP_KERNEL);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200312}
Thomas Gleixner83a530e2018-04-22 18:23:46 +0200313EXPORT_SYMBOL_GPL(init_rs_non_canonical);
Segher Boessenkoold7e5a542007-05-02 12:18:41 +0200314
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315#ifdef CONFIG_REED_SOLOMON_ENC8
Thomas Gleixner03ead842005-11-07 11:15:37 +0000316/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700317 * encode_rs8 - Calculate the parity for data values (8bit data width)
Thomas Gleixner21633982018-04-22 18:23:53 +0200318 * @rsc: the rs control structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 * @data: data field of a given type
Thomas Gleixner03ead842005-11-07 11:15:37 +0000320 * @len: data length
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 * @par: parity data, must be initialized by caller (usually all 0)
322 * @invmsk: invert data mask (will be xored on data)
323 *
324 * The parity uses a uint16_t data type to enable
325 * symbol size > 8. The calling code must take care of encoding of the
326 * syndrome result for storage itself.
327 */
Thomas Gleixner21633982018-04-22 18:23:53 +0200328int encode_rs8(struct rs_control *rsc, uint8_t *data, int len, uint16_t *par,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700329 uint16_t invmsk)
330{
331#include "encode_rs.c"
332}
333EXPORT_SYMBOL_GPL(encode_rs8);
334#endif
335
336#ifdef CONFIG_REED_SOLOMON_DEC8
Thomas Gleixner03ead842005-11-07 11:15:37 +0000337/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338 * decode_rs8 - Decode codeword (8bit data width)
Thomas Gleixner21633982018-04-22 18:23:53 +0200339 * @rsc: the rs control structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 * @data: data field of a given type
341 * @par: received parity data field
342 * @len: data length
343 * @s: syndrome data field (if NULL, syndrome is calculated)
344 * @no_eras: number of erasures
345 * @eras_pos: position of erasures, can be NULL
346 * @invmsk: invert data mask (will be xored on data, not on parity!)
347 * @corr: buffer to store correction bitmask on eras_pos
348 *
349 * The syndrome and parity uses a uint16_t data type to enable
350 * symbol size > 8. The calling code must take care of decoding of the
351 * syndrome result and the received parity before calling this code.
Thomas Gleixner45888b42018-04-22 18:23:55 +0200352 *
353 * Note: The rs_control struct @rsc contains buffers which are used for
354 * decoding, so the caller has to ensure that decoder invocations are
355 * serialized.
356 *
Jörn Engeleb684502007-10-20 23:16:32 +0200357 * Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 */
Thomas Gleixner21633982018-04-22 18:23:53 +0200359int decode_rs8(struct rs_control *rsc, uint8_t *data, uint16_t *par, int len,
Thomas Gleixner03ead842005-11-07 11:15:37 +0000360 uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 uint16_t *corr)
362{
363#include "decode_rs.c"
364}
365EXPORT_SYMBOL_GPL(decode_rs8);
366#endif
367
368#ifdef CONFIG_REED_SOLOMON_ENC16
369/**
370 * encode_rs16 - Calculate the parity for data values (16bit data width)
Thomas Gleixner21633982018-04-22 18:23:53 +0200371 * @rsc: the rs control structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 * @data: data field of a given type
Thomas Gleixner03ead842005-11-07 11:15:37 +0000373 * @len: data length
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 * @par: parity data, must be initialized by caller (usually all 0)
375 * @invmsk: invert data mask (will be xored on data, not on parity!)
376 *
377 * Each field in the data array contains up to symbol size bits of valid data.
378 */
Thomas Gleixner21633982018-04-22 18:23:53 +0200379int encode_rs16(struct rs_control *rsc, uint16_t *data, int len, uint16_t *par,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380 uint16_t invmsk)
381{
382#include "encode_rs.c"
383}
384EXPORT_SYMBOL_GPL(encode_rs16);
385#endif
386
387#ifdef CONFIG_REED_SOLOMON_DEC16
Thomas Gleixner03ead842005-11-07 11:15:37 +0000388/**
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 * decode_rs16 - Decode codeword (16bit data width)
Thomas Gleixner21633982018-04-22 18:23:53 +0200390 * @rsc: the rs control structure
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 * @data: data field of a given type
392 * @par: received parity data field
393 * @len: data length
394 * @s: syndrome data field (if NULL, syndrome is calculated)
395 * @no_eras: number of erasures
396 * @eras_pos: position of erasures, can be NULL
Thomas Gleixner03ead842005-11-07 11:15:37 +0000397 * @invmsk: invert data mask (will be xored on data, not on parity!)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 * @corr: buffer to store correction bitmask on eras_pos
399 *
400 * Each field in the data array contains up to symbol size bits of valid data.
Thomas Gleixner45888b42018-04-22 18:23:55 +0200401 *
402 * Note: The rc_control struct @rsc contains buffers which are used for
403 * decoding, so the caller has to ensure that decoder invocations are
404 * serialized.
405 *
Jörn Engeleb684502007-10-20 23:16:32 +0200406 * Returns the number of corrected bits or -EBADMSG for uncorrectable errors.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700407 */
Thomas Gleixner21633982018-04-22 18:23:53 +0200408int decode_rs16(struct rs_control *rsc, uint16_t *data, uint16_t *par, int len,
Thomas Gleixner03ead842005-11-07 11:15:37 +0000409 uint16_t *s, int no_eras, int *eras_pos, uint16_t invmsk,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 uint16_t *corr)
411{
412#include "decode_rs.c"
413}
414EXPORT_SYMBOL_GPL(decode_rs16);
415#endif
416
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417MODULE_LICENSE("GPL");
418MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
419MODULE_AUTHOR("Phil Karn, Thomas Gleixner");
420