Merge tag 'rslib-v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 5 Jun 2018 17:48:05 +0000 (10:48 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 5 Jun 2018 17:48:05 +0000 (10:48 -0700)
Pull reed-salomon library updates from Kees Cook:
 "Refactors rslib and callers to provide a per-instance allocation area
  instead of performing VLAs on the stack"

* tag 'rslib-v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux:
  rslib: Allocate decoder buffers to avoid VLAs
  mtd: rawnand: diskonchip: Allocate rs control per instance
  rslib: Split rs control struct
  rslib: Simplify error path
  rslib: Remove GPL boilerplate
  rslib: Add SPDX identifiers
  rslib: Cleanup top level comments
  rslib: Cleanup whitespace damage
  dm/verity_fec: Use GFP aware reed solomon init
  rslib: Add GFP aware init function

drivers/md/dm-verity-fec.c
drivers/mtd/nand/raw/cafe_nand.c
drivers/mtd/nand/raw/diskonchip.c
include/linux/rslib.h
lib/reed_solomon/decode_rs.c
lib/reed_solomon/encode_rs.c
lib/reed_solomon/reed_solomon.c

index 86405869f1aff4b51f77ca00c5411e049bdeebb6..684af08d07478cb4652ad6642fc99d9bc3be189f 100644 (file)
@@ -570,7 +570,7 @@ static void *fec_rs_alloc(gfp_t gfp_mask, void *pool_data)
 {
        struct dm_verity *v = (struct dm_verity *)pool_data;
 
-       return init_rs(8, 0x11d, 0, 1, v->fec->roots);
+       return init_rs_gfp(8, 0x11d, 0, 1, v->fec->roots, gfp_mask);
 }
 
 static void fec_rs_free(void *element, void *pool_data)
index d8c8c9d1e6405e72fe8b416de14744e6d00ee2a7..d721f489b38bcd07a9141782c5942e93d99e727f 100644 (file)
@@ -394,12 +394,13 @@ static int cafe_nand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 
                for (i=0; i<8; i+=2) {
                        uint32_t tmp = cafe_readl(cafe, NAND_ECC_SYN01 + (i*2));
-                       syn[i] = cafe->rs->index_of[tmp & 0xfff];
-                       syn[i+1] = cafe->rs->index_of[(tmp >> 16) & 0xfff];
+
+                       syn[i] = cafe->rs->codec->index_of[tmp & 0xfff];
+                       syn[i+1] = cafe->rs->codec->index_of[(tmp >> 16) & 0xfff];
                }
 
                n = decode_rs16(cafe->rs, NULL, NULL, 1367, syn, 0, pos, 0,
-                               pat);
+                               pat);
 
                for (i = 0; i < n; i++) {
                        int p = pos[i];
index 86a258de0b7552d3ad1b8da8def8dec3ce1574a5..2b7b2b982b773db58366a4e524f88bd5be3a8a17 100644 (file)
@@ -66,6 +66,7 @@ struct doc_priv {
        int curchip;
        int mh0_page;
        int mh1_page;
+       struct rs_control *rs_decoder;
        struct mtd_info *nextdoc;
 
        /* Handle the last stage of initialization (BBT scan, partitioning) */
@@ -123,9 +124,6 @@ MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe
 /* Number of symbols */
 #define NN 1023
 
-/* the Reed Solomon control structure */
-static struct rs_control *rs_decoder;
-
 /*
  * The HW decoder in the DoC ASIC's provides us a error syndrome,
  * which we must convert to a standard syndrome usable by the generic
@@ -140,6 +138,7 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
        int i, j, nerr, errpos[8];
        uint8_t parity;
        uint16_t ds[4], s[5], tmp, errval[8], syn[4];
+       struct rs_codec *cd = rs->codec;
 
        memset(syn, 0, sizeof(syn));
        /* Convert the ecc bytes into words */
@@ -160,15 +159,15 @@ static int doc_ecc_decode(struct rs_control *rs, uint8_t *data, uint8_t *ecc)
        for (j = 1; j < NROOTS; j++) {
                if (ds[j] == 0)
                        continue;
-               tmp = rs->index_of[ds[j]];
+               tmp = cd->index_of[ds[j]];
                for (i = 0; i < NROOTS; i++)
-                       s[i] ^= rs->alpha_to[rs_modnn(rs, tmp + (FCR + i) * j)];
+                       s[i] ^= cd->alpha_to[rs_modnn(cd, tmp + (FCR + i) * j)];
        }
 
        /* Calc syn[i] = s[i] / alpha^(v + i) */
        for (i = 0; i < NROOTS; i++) {
                if (s[i])
-                       syn[i] = rs_modnn(rs, rs->index_of[s[i]] + (NN - FCR - i));
+                       syn[i] = rs_modnn(cd, cd->index_of[s[i]] + (NN - FCR - i));
        }
        /* Call the decoder library */
        nerr = decode_rs16(rs, NULL, NULL, 1019, syn, 0, errpos, 0, errval);
@@ -930,7 +929,7 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
                                calc_ecc[i] = ReadDOC_(docptr, DoC_ECCSyndrome0 + i);
                }
 
-               ret = doc_ecc_decode(rs_decoder, dat, calc_ecc);
+               ret = doc_ecc_decode(doc->rs_decoder, dat, calc_ecc);
                if (ret > 0)
                        pr_err("doc200x_correct_data corrected %d errors\n",
                               ret);
@@ -1421,10 +1420,10 @@ static inline int __init doc2001plus_init(struct mtd_info *mtd)
 
 static int __init doc_probe(unsigned long physadr)
 {
+       struct nand_chip *nand = NULL;
+       struct doc_priv *doc = NULL;
        unsigned char ChipID;
        struct mtd_info *mtd;
-       struct nand_chip *nand;
-       struct doc_priv *doc;
        void __iomem *virtadr;
        unsigned char save_control;
        unsigned char tmp, tmpb, tmpc;
@@ -1561,8 +1560,25 @@ static int __init doc_probe(unsigned long physadr)
                goto fail;
        }
 
+
+       /*
+        * Allocate a RS codec instance
+        *
+        * Symbolsize is 10 (bits)
+        * Primitve polynomial is x^10+x^3+1
+        * First consecutive root is 510
+        * Primitve element to generate roots = 1
+        * Generator polinomial degree = 4
+        */
+       doc = (struct doc_priv *) (nand + 1);
+       doc->rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
+       if (!doc->rs_decoder) {
+               pr_err("DiskOnChip: Could not create a RS codec\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
        mtd                     = nand_to_mtd(nand);
-       doc                     = (struct doc_priv *) (nand + 1);
        nand->bbt_td            = (struct nand_bbt_descr *) (doc + 1);
        nand->bbt_md            = nand->bbt_td + 1;
 
@@ -1612,7 +1628,6 @@ static int __init doc_probe(unsigned long physadr)
                   haven't yet added it.  This is handled without incident by
                   mtd_device_unregister, as far as I can tell. */
                nand_release(mtd);
-               kfree(nand);
                goto fail;
        }
 
@@ -1625,6 +1640,9 @@ static int __init doc_probe(unsigned long physadr)
           actually a DiskOnChip.  */
        WriteDOC(save_control, virtadr, DOCControl);
  fail:
+       if (doc)
+               free_rs(doc->rs_decoder);
+       kfree(nand);
        iounmap(virtadr);
 
 error_ioremap:
@@ -1647,6 +1665,7 @@ static void release_nanddoc(void)
                nand_release(mtd);
                iounmap(doc->virtadr);
                release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
+               free_rs(doc->rs_decoder);
                kfree(nand);
        }
 }
@@ -1655,27 +1674,12 @@ static int __init init_nanddoc(void)
 {
        int i, ret = 0;
 
-       /* We could create the decoder on demand, if memory is a concern.
-        * This way we have it handy, if an error happens
-        *
-        * Symbolsize is 10 (bits)
-        * Primitve polynomial is x^10+x^3+1
-        * first consecutive root is 510
-        * primitve element to generate roots = 1
-        * generator polinomial degree = 4
-        */
-       rs_decoder = init_rs(10, 0x409, FCR, 1, NROOTS);
-       if (!rs_decoder) {
-               pr_err("DiskOnChip: Could not create a RS decoder\n");
-               return -ENOMEM;
-       }
-
        if (doc_config_location) {
                pr_info("Using configured DiskOnChip probe address 0x%lx\n",
                        doc_config_location);
                ret = doc_probe(doc_config_location);
                if (ret < 0)
-                       goto outerr;
+                       return ret;
        } else {
                for (i = 0; (doc_locations[i] != 0xffffffff); i++) {
                        doc_probe(doc_locations[i]);
@@ -1686,11 +1690,7 @@ static int __init init_nanddoc(void)
        if (!doclist) {
                pr_info("No valid DiskOnChip devices found\n");
                ret = -ENODEV;
-               goto outerr;
        }
-       return 0;
- outerr:
-       free_rs(rs_decoder);
        return ret;
 }
 
@@ -1698,11 +1698,6 @@ static void __exit cleanup_nanddoc(void)
 {
        /* Cleanup the nand/DoC resources */
        release_nanddoc();
-
-       /* Free the reed solomon resources */
-       if (rs_decoder) {
-               free_rs(rs_decoder);
-       }
 }
 
 module_init(init_nanddoc);
index 746580c1939c028d8f8ef8dc6bb460e5ed6dfc17..5974cedd008c345a3261229e30ca7e290d388d76 100644 (file)
@@ -1,28 +1,21 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * include/linux/rslib.h
- *
- * Overview:
- *   Generic Reed Solomon encoder / decoder library
+ * Generic Reed Solomon encoder / decoder library
  *
  * Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
  *
  * RS code lifted from reed solomon library written by Phil Karn
  * Copyright 2002 Phil Karn, KA9Q
- *
- * $Id: rslib.h,v 1.4 2005/11/07 11:14:52 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.
  */
-
 #ifndef _RSLIB_H_
 #define _RSLIB_H_
 
 #include <linux/list.h>
+#include <linux/types.h>       /* for gfp_t */
+#include <linux/gfp.h>         /* for GFP_KERNEL */
 
 /**
- * struct rs_control - rs control structure
+ * struct rs_codec - rs codec data
  *
  * @mm:                Bits per symbol
  * @nn:                Symbols per block (= (1<<mm)-1)
  * @gfpoly:    The primitive generator polynominal
  * @gffunc:    Function to generate the field, if non-canonical representation
  * @users:     Users of this structure
- * @list:      List entry for the rs control list
+ * @list:      List entry for the rs codec list
 */
-struct rs_control {
-       int             mm;
-       int             nn;
+struct rs_codec {
+       int             mm;
+       int             nn;
        uint16_t        *alpha_to;
        uint16_t        *index_of;
        uint16_t        *genpoly;
-       int             nroots;
-       int             fcr;
-       int             prim;
-       int             iprim;
+       int             nroots;
+       int             fcr;
+       int             prim;
+       int             iprim;
        int             gfpoly;
        int             (*gffunc)(int);
        int             users;
        struct list_head list;
 };
 
+/**
+ * struct rs_control - rs control structure per instance
+ * @codec:     The codec used for this instance
+ * @buffers:   Internal scratch buffers used in calls to decode_rs()
+ */
+struct rs_control {
+       struct rs_codec *codec;
+       uint16_t        buffers[0];
+};
+
 /* General purpose RS codec, 8-bit data width, symbol width 1-15 bit  */
 #ifdef CONFIG_REED_SOLOMON_ENC8
 int encode_rs8(struct rs_control *rs, uint8_t *data, int len, uint16_t *par,
@@ -76,18 +79,37 @@ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
                uint16_t *corr);
 #endif
 
-/* Create or get a matching rs control structure */
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
-                          int nroots);
+struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
+                              int nroots, gfp_t gfp);
+
+/**
+ * init_rs - Create a RS control struct and initialize it
+ *  @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)
+ *
+ * Allocations use GFP_KERNEL.
+ */
+static inline struct rs_control *init_rs(int symsize, int gfpoly, int fcr,
+                                        int prim, int nroots)
+{
+       return init_rs_gfp(symsize, gfpoly, fcr, prim, nroots, GFP_KERNEL);
+}
+
 struct rs_control *init_rs_non_canonical(int symsize, int (*func)(int),
-                                         int fcr, int prim, int nroots);
+                                        int fcr, int prim, int nroots);
 
 /* Release a rs control structure */
 void free_rs(struct rs_control *rs);
 
 /** modulo replacement for galois field arithmetics
  *
- *  @rs:       the rs control structure
+ *  @rs:       Pointer to the RS codec
  *  @x:                the value to reduce
  *
  *  where
@@ -97,7 +119,7 @@ void free_rs(struct rs_control *rs);
  *  Simple arithmetic modulo would return a wrong result for values
  *  >= 3 * rs->nn
 */
-static inline int rs_modnn(struct rs_control *rs, int x)
+static inline int rs_modnn(struct rs_codec *rs, int x)
 {
        while (x >= rs->nn) {
                x -= rs->nn;
index 0ec3f257ffdf9d38b96dad16276e7b3164f13e63..1db74eb098d0eb6e8123d07ed4be795a09bf82ce 100644 (file)
@@ -1,22 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * lib/reed_solomon/decode_rs.c
- *
- * Overview:
- *   Generic Reed Solomon encoder / decoder library
+ * 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.7 2005/11/07 11:14:59 gleixner Exp $
- *
- */
-
-/* Generic data width independent code which is included by the
- * wrappers.
+ * Generic data width independent code which is included by the wrappers.
  */
 {
+       struct rs_codec *rs = rsc->codec;
        int deg_lambda, el, deg_omega;
        int i, j, r, k, pad;
        int nn = rs->nn;
        uint16_t *alpha_to = rs->alpha_to;
        uint16_t *index_of = rs->index_of;
        uint16_t u, q, tmp, num1, num2, den, discr_r, syn_error;
-       /* Err+Eras Locator poly and syndrome poly The maximum value
-        * of nroots is 8. So the necessary stack size will be about
-        * 220 bytes max.
-        */
-       uint16_t lambda[nroots + 1], syn[nroots];
-       uint16_t b[nroots + 1], t[nroots + 1], omega[nroots + 1];
-       uint16_t root[nroots], reg[nroots + 1], loc[nroots];
        int count = 0;
        uint16_t msk = (uint16_t) rs->nn;
 
+       /*
+        * The decoder buffers are in the rs control struct. They are
+        * arrays sized [nroots + 1]
+        */
+       uint16_t *lambda = rsc->buffers + RS_DECODE_LAMBDA * (nroots + 1);
+       uint16_t *syn = rsc->buffers + RS_DECODE_SYN * (nroots + 1);
+       uint16_t *b = rsc->buffers + RS_DECODE_B * (nroots + 1);
+       uint16_t *t = rsc->buffers + RS_DECODE_T * (nroots + 1);
+       uint16_t *omega = rsc->buffers + RS_DECODE_OMEGA * (nroots + 1);
+       uint16_t *root = rsc->buffers + RS_DECODE_ROOT * (nroots + 1);
+       uint16_t *reg = rsc->buffers + RS_DECODE_REG * (nroots + 1);
+       uint16_t *loc = rsc->buffers + RS_DECODE_LOC * (nroots + 1);
+
        /* Check length parameter for validity */
        pad = nn - nroots - len;
        BUG_ON(pad < 0 || pad >= nn);
index 0b5b1a6728ec03892078689ab6f651ab873550d5..9112d46e869ee1fcbd14ba6ce7d34a7c6e475c60 100644 (file)
@@ -1,23 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * lib/reed_solomon/encode_rs.c
- *
- * Overview:
- *   Generic Reed Solomon encoder / decoder library
+ * 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.5 2005/11/07 11:14:59 gleixner Exp $
- *
- */
-
-/* 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)
+ * Generic data width independent code which is included by the wrappers.
  */
 {
+       struct rs_codec *rs = rsc->codec;
        int i, j, pad;
        int nn = rs->nn;
        int nroots = rs->nroots;
index 06d04cfa93390e1ac13d0348876ba3045ebf594a..dfcf54242fb92f50d544169b7c723b81e78f1984 100644 (file)
@@ -1,43 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
- * lib/reed_solomon/reed_solomon.c
- *
- * Overview:
- *   Generic Reed Solomon encoder / decoder library
+ * 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.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
- * structure for the given rs parameters. This structure is either
- * generated or a already available matching control structure is used.
- * 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
- * rs_control structure on module / driver init and release it
- * on exit.
- * 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.
- * Many hw encoders provide a syndrome calculation over the received
- * data + syndrome and can call the second stage directly.
  *
+ * Each user must call init_rs to get a pointer to a rs_control structure
+ * for the given rs parameters. The control struct is unique per instance.
+ * It points to a codec which can be shared by multiple control structures.
+ * If a codec is newly allocated 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 rs_control structure on module /
+ * driver init and release it on exit.
+ *
+ * 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.  Many hw encoders
+ * provide a syndrome calculation over the received data + syndrome and can
+ * call the second stage directly.
  */
-
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 
-/* This list holds all currently allocated rs control structures */
-static LIST_HEAD (rslist);
+enum {
+       RS_DECODE_LAMBDA,
+       RS_DECODE_SYN,
+       RS_DECODE_B,
+       RS_DECODE_T,
+       RS_DECODE_OMEGA,
+       RS_DECODE_ROOT,
+       RS_DECODE_REG,
+       RS_DECODE_LOC,
+       RS_DECODE_NUM_BUFFERS
+};
+
+/* This list holds all currently allocated rs codec structures */
+static LIST_HEAD(codec_list);
 /* Protection for the list */
 static DEFINE_MUTEX(rslistlock);
 
 /**
- * rs_init - Initialize a Reed-Solomon codec
+ * codec_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)
+ * @gfp:       GFP_ flags for allocations
  *
- * Allocate a control structure and the polynom arrays for faster
+ * Allocate a codec structure and the polynom arrays for faster
  * en/decoding. Fill the arrays according to the given parameters.
  */
-static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
-                                  int fcr, int prim, int nroots)
+static struct rs_codec *codec_init(int symsize, int gfpoly, int (*gffunc)(int),
+                                  int fcr, int prim, int nroots, gfp_t gfp)
 {
-       struct rs_control *rs;
        int i, j, sr, root, iprim;
+       struct rs_codec *rs;
 
-       /* Allocate the control structure */
-       rs = kmalloc(sizeof (struct rs_control), GFP_KERNEL);
-       if (rs == NULL)
+       rs = kzalloc(sizeof(*rs), gfp);
+       if (!rs)
                return NULL;
 
        INIT_LIST_HEAD(&rs->list);
@@ -85,17 +88,17 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
        rs->gffunc = gffunc;
 
        /* Allocate the arrays */
-       rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
+       rs->alpha_to = kmalloc(sizeof(uint16_t) * (rs->nn + 1), gfp);
        if (rs->alpha_to == NULL)
-               goto errrs;
+               goto err;
 
-       rs->index_of = kmalloc(sizeof(uint16_t) * (rs->nn + 1), GFP_KERNEL);
+       rs->index_of = kmalloc(sizeof(uint16_t) * (rs->nn + 1), gfp);
        if (rs->index_of == NULL)
-               goto erralp;
+               goto err;
 
-       rs->genpoly = kmalloc(sizeof(uint16_t) * (rs->nroots + 1), GFP_KERNEL);
+       rs->genpoly = kmalloc(sizeof(uint16_t) * (rs->nroots + 1), gfp);
        if(rs->genpoly == NULL)
-               goto erridx;
+               goto err;
 
        /* Generate Galois field lookup tables */
        rs->index_of[0] = rs->nn;       /* log(zero) = -inf */
@@ -120,7 +123,7 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
        }
        /* If it's not primitive, exit */
        if(sr != rs->alpha_to[0])
-               goto errpol;
+               goto err;
 
        /* Find prim-th root of 1, used in decoding */
        for(iprim = 1; (iprim % prim) != 0; iprim += rs->nn);
@@ -148,42 +151,52 @@ static struct rs_control *rs_init(int symsize, int gfpoly, int (*gffunc)(int),
        /* convert rs->genpoly[] to index form for quicker encoding */
        for (i = 0; i <= nroots; i++)
                rs->genpoly[i] = rs->index_of[rs->genpoly[i]];
+
+       rs->users = 1;
+       list_add(&rs->list, &codec_list);
        return rs;
 
-       /* Error exit */
-errpol:
+err:
        kfree(rs->genpoly);
-erridx:
        kfree(rs->index_of);
-erralp:
        kfree(rs->alpha_to);
-errrs:
        kfree(rs);
        return NULL;
 }
 
 
 /**
- *  free_rs - Free the rs control structure, if it is no longer used
- *  @rs:       the control structure which is not longer used by the
+ *  free_rs - Free the rs control structure
+ *  @rs:       The control structure which is not longer used by the
  *             caller
+ *
+ * Free the control structure. If @rs is the last user of the associated
+ * codec, free the codec as well.
  */
 void free_rs(struct rs_control *rs)
 {
+       struct rs_codec *cd;
+
+       if (!rs)
+               return;
+
+       cd = rs->codec;
        mutex_lock(&rslistlock);
-       rs->users--;
-       if(!rs->users) {
-               list_del(&rs->list);
-               kfree(rs->alpha_to);
-               kfree(rs->index_of);
-               kfree(rs->genpoly);
-               kfree(rs);
+       cd->users--;
+       if(!cd->users) {
+               list_del(&cd->list);
+               kfree(cd->alpha_to);
+               kfree(cd->index_of);
+               kfree(cd->genpoly);
+               kfree(cd);
        }
        mutex_unlock(&rslistlock);
+       kfree(rs);
 }
+EXPORT_SYMBOL_GPL(free_rs);
 
 /**
- * init_rs_internal - Find a matching or allocate a new rs control structure
+ * init_rs_internal - Allocate rs control, find a matching codec or allocate a new one
  *  @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
@@ -191,55 +204,69 @@ void free_rs(struct rs_control *rs)
  *  @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
+ *  @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)
+ *  @gfp:      GFP_ flags for allocations
  */
 static struct rs_control *init_rs_internal(int symsize, int gfpoly,
-                                           int (*gffunc)(int), int fcr,
-                                           int prim, int nroots)
+                                          int (*gffunc)(int), int fcr,
+                                          int prim, int nroots, gfp_t gfp)
 {
-       struct list_head        *tmp;
-       struct rs_control       *rs;
+       struct list_head *tmp;
+       struct rs_control *rs;
+       unsigned int bsize;
 
        /* Sanity checks */
        if (symsize < 1)
                return NULL;
        if (fcr < 0 || fcr >= (1<<symsize))
-               return NULL;
+               return NULL;
        if (prim <= 0 || prim >= (1<<symsize))
-               return NULL;
+               return NULL;
        if (nroots < 0 || nroots >= (1<<symsize))
                return NULL;
 
+       /*
+        * The decoder needs buffers in each control struct instance to
+        * avoid variable size or large fixed size allocations on
+        * stack. Size the buffers to arrays of [nroots + 1].
+        */
+       bsize = sizeof(uint16_t) * RS_DECODE_NUM_BUFFERS * (nroots + 1);
+       rs = kzalloc(sizeof(*rs) + bsize, gfp);
+       if (!rs)
+               return NULL;
+
        mutex_lock(&rslistlock);
 
        /* Walk through the list and look for a matching entry */
-       list_for_each(tmp, &rslist) {
-               rs = list_entry(tmp, struct rs_control, list);
-               if (symsize != rs->mm)
+       list_for_each(tmp, &codec_list) {
+               struct rs_codec *cd = list_entry(tmp, struct rs_codec, list);
+
+               if (symsize != cd->mm)
                        continue;
-               if (gfpoly != rs->gfpoly)
+               if (gfpoly != cd->gfpoly)
                        continue;
-               if (gffunc != rs->gffunc)
+               if (gffunc != cd->gffunc)
                        continue;
-               if (fcr != rs->fcr)
+               if (fcr != cd->fcr)
                        continue;
-               if (prim != rs->prim)
+               if (prim != cd->prim)
                        continue;
-               if (nroots != rs->nroots)
+               if (nroots != cd->nroots)
                        continue;
                /* We have a matching one already */
-               rs->users++;
+               cd->users++;
+               rs->codec = cd;
                goto out;
        }
 
        /* Create a new one */
-       rs = rs_init(symsize, gfpoly, gffunc, fcr, prim, nroots);
-       if (rs) {
-               rs->users = 1;
-               list_add(&rs->list, &rslist);
+       rs->codec = codec_init(symsize, gfpoly, gffunc, fcr, prim, nroots, gfp);
+       if (!rs->codec) {
+               kfree(rs);
+               rs = NULL;
        }
 out:
        mutex_unlock(&rslistlock);
@@ -247,45 +274,48 @@ out:
 }
 
 /**
- * init_rs - Find a matching or allocate a new rs control structure
+ * init_rs_gfp - Create a RS control struct and initialize it
  *  @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
+ *  @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)
+ *  @gfp:      GFP_ flags for allocations
  */
-struct rs_control *init_rs(int symsize, int gfpoly, int fcr, int prim,
-                           int nroots)
+struct rs_control *init_rs_gfp(int symsize, int gfpoly, int fcr, int prim,
+                              int nroots, gfp_t gfp)
 {
-       return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots);
+       return init_rs_internal(symsize, gfpoly, NULL, fcr, prim, nroots, gfp);
 }
+EXPORT_SYMBOL_GPL(init_rs_gfp);
 
 /**
- * init_rs_non_canonical - Find a matching or allocate a new rs control
- *                         structure, for fields with non-canonical
- *                         representation
+ * init_rs_non_canonical - Allocate rs control struct 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
+ *  @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)
+                                        int fcr, int prim, int nroots)
 {
-       return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots);
+       return init_rs_internal(symsize, 0, gffunc, fcr, prim, nroots,
+                               GFP_KERNEL);
 }
+EXPORT_SYMBOL_GPL(init_rs_non_canonical);
 
 #ifdef CONFIG_REED_SOLOMON_ENC8
 /**
  *  encode_rs8 - Calculate the parity for data values (8bit data width)
- *  @rs      the rs control structure
+ *  @rsc:      the rs control structure
  *  @data:     data field of a given type
  *  @len:      data length
  *  @par:      parity data, must be initialized by caller (usually all 0)
@@ -295,7 +325,7 @@ struct rs_control *init_rs_non_canonical(int symsize, int (*gffunc)(int),
  *  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 *rsc, uint8_t *data, int len, uint16_t *par,
               uint16_t invmsk)
 {
 #include "encode_rs.c"
@@ -306,7 +336,7 @@ EXPORT_SYMBOL_GPL(encode_rs8);
 #ifdef CONFIG_REED_SOLOMON_DEC8
 /**
  *  decode_rs8 - Decode codeword (8bit data width)
- *  @rs      the rs control structure
+ *  @rsc:      the rs control structure
  *  @data:     data field of a given type
  *  @par:      received parity data field
  *  @len:      data length
@@ -319,9 +349,14 @@ 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.
+ *
+ *  Note: The rs_control struct @rsc contains buffers which are used for
+ *  decoding, so the caller has to ensure that decoder invocations are
+ *  serialized.
+ *
  *  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,
+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,
               uint16_t *corr)
 {
@@ -333,7 +368,7 @@ 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
+ *  @rsc:      the rs control structure
  *  @data:     data field of a given type
  *  @len:      data length
  *  @par:      parity data, must be initialized by caller (usually all 0)
@@ -341,7 +376,7 @@ EXPORT_SYMBOL_GPL(decode_rs8);
  *
  *  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 *rsc, uint16_t *data, int len, uint16_t *par,
        uint16_t invmsk)
 {
 #include "encode_rs.c"
@@ -352,7 +387,7 @@ EXPORT_SYMBOL_GPL(encode_rs16);
 #ifdef CONFIG_REED_SOLOMON_DEC16
 /**
  *  decode_rs16 - Decode codeword (16bit data width)
- *  @rs      the rs control structure
+ *  @rsc:      the rs control structure
  *  @data:     data field of a given type
  *  @par:      received parity data field
  *  @len:      data length
@@ -363,9 +398,14 @@ EXPORT_SYMBOL_GPL(encode_rs16);
  *  @corr:     buffer to store correction bitmask on eras_pos
  *
  *  Each field in the data array contains up to symbol size bits of valid data.
+ *
+ *  Note: The rc_control struct @rsc contains buffers which are used for
+ *  decoding, so the caller has to ensure that decoder invocations are
+ *  serialized.
+ *
  *  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,
+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,
                uint16_t *corr)
 {
@@ -374,10 +414,6 @@ int decode_rs16(struct rs_control *rs, uint16_t *data, uint16_t *par, int len,
 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");
 MODULE_DESCRIPTION("Reed Solomon encoder/decoder");
 MODULE_AUTHOR("Phil Karn, Thomas Gleixner");