Skip to content

Commit 80fe603

Browse files
committed
mtd: nand: ecc-bch: Stop using raw NAND structures
This code is meant to be reused by the SPI-NAND core. Now that the driver has been cleaned and reorganized, use a generic ECC engine object to store the driver's data instead of accessing members of the nand_chip structure. Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com> Link: https://lore.kernel.org/linux-mtd/20200929230124.31491-9-miquel.raynal@bootlin.com
1 parent ea146d7 commit 80fe603

File tree

3 files changed

+98
-79
lines changed

3 files changed

+98
-79
lines changed

drivers/mtd/nand/ecc-sw-bch.c

Lines changed: 40 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,8 @@
1111
#include <linux/module.h>
1212
#include <linux/slab.h>
1313
#include <linux/bitops.h>
14-
#include <linux/mtd/mtd.h>
15-
#include <linux/mtd/rawnand.h>
1614
#include <linux/mtd/nand.h>
1715
#include <linux/mtd/nand-ecc-sw-bch.h>
18-
#include <linux/bch.h>
19-
20-
/**
21-
* struct nand_bch_control - private NAND BCH control structure
22-
* @bch: BCH control structure
23-
* @errloc: error location array
24-
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
25-
*/
26-
struct nand_bch_control {
27-
struct bch_control *bch;
28-
unsigned int *errloc;
29-
unsigned char *eccmask;
30-
};
3116

3217
/**
3318
* nand_ecc_sw_bch_calculate - Calculate the ECC corresponding to a data block
@@ -38,16 +23,15 @@ struct nand_bch_control {
3823
int nand_ecc_sw_bch_calculate(struct nand_device *nand,
3924
const unsigned char *buf, unsigned char *code)
4025
{
41-
struct nand_chip *chip = mtd_to_nand(nanddev_to_mtd(nand));
42-
struct nand_bch_control *nbc = chip->ecc.priv;
26+
struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
4327
unsigned int i;
4428

45-
memset(code, 0, chip->ecc.bytes);
46-
bch_encode(nbc->bch, buf, chip->ecc.size, code);
29+
memset(code, 0, engine_conf->code_size);
30+
bch_encode(engine_conf->bch, buf, nand->ecc.ctx.conf.step_size, code);
4731

4832
/* apply mask so that an erased page is a valid codeword */
49-
for (i = 0; i < chip->ecc.bytes; i++)
50-
code[i] ^= nbc->eccmask[i];
33+
for (i = 0; i < engine_conf->code_size; i++)
34+
code[i] ^= engine_conf->eccmask[i];
5135

5236
return 0;
5337
}
@@ -65,16 +49,16 @@ EXPORT_SYMBOL(nand_ecc_sw_bch_calculate);
6549
int nand_ecc_sw_bch_correct(struct nand_device *nand, unsigned char *buf,
6650
unsigned char *read_ecc, unsigned char *calc_ecc)
6751
{
68-
struct nand_chip *chip = mtd_to_nand(nanddev_to_mtd(nand));
69-
struct nand_bch_control *nbc = chip->ecc.priv;
70-
unsigned int *errloc = nbc->errloc;
52+
struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
53+
unsigned int step_size = nand->ecc.ctx.conf.step_size;
54+
unsigned int *errloc = engine_conf->errloc;
7155
int i, count;
7256

73-
count = bch_decode(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc,
74-
NULL, errloc);
57+
count = bch_decode(engine_conf->bch, NULL, step_size, read_ecc,
58+
calc_ecc, NULL, errloc);
7559
if (count > 0) {
7660
for (i = 0; i < count; i++) {
77-
if (errloc[i] < (chip->ecc.size * 8))
61+
if (errloc[i] < (step_size * 8))
7862
/* The error is in the data area: correct it */
7963
buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
8064

@@ -97,31 +81,30 @@ EXPORT_SYMBOL(nand_ecc_sw_bch_correct);
9781
*
9882
* Returns: a pointer to a new NAND BCH control structure, or NULL upon failure
9983
*
100-
* Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes
101-
* are used to compute the following BCH parameters:
84+
* Initialize NAND BCH error correction. @nand.ecc parameters 'step_size' and
85+
* 'bytes' are used to compute the following BCH parameters:
10286
* m, the Galois field order
10387
* t, the error correction capability
104-
* @eccbytes should be equal to the number of bytes required to store m * t
88+
* 'bytes' should be equal to the number of bytes required to store m * t
10589
* bits, where m is such that 2^m - 1 > step_size * 8.
10690
*
10791
* Example: to configure 4 bit correction per 512 bytes, you should pass
108-
* @eccsize = 512 (thus, m = 13 is the smallest integer such that 2^m - 1 > 512 * 8)
109-
* @eccbytes = 7 (7 bytes are required to store m * t = 13 * 4 = 52 bits)
92+
* step_size = 512 (thus, m = 13 is the smallest integer such that 2^m - 1 > 512 * 8)
93+
* bytes = 7 (7 bytes are required to store m * t = 13 * 4 = 52 bits)
11094
*/
11195
int nand_ecc_sw_bch_init(struct nand_device *nand)
11296
{
11397
struct mtd_info *mtd = nanddev_to_mtd(nand);
114-
struct nand_chip *chip = mtd_to_nand(mtd);
11598
unsigned int m, t, eccsteps, i;
116-
struct nand_bch_control *nbc = NULL;
99+
struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
117100
unsigned char *erased_page;
118-
unsigned int eccsize = chip->ecc.size;
119-
unsigned int eccbytes = chip->ecc.bytes;
120-
unsigned int eccstrength = chip->ecc.strength;
101+
unsigned int eccsize = nand->ecc.ctx.conf.step_size;
102+
unsigned int eccbytes = engine_conf->code_size;
103+
unsigned int eccstrength = nand->ecc.ctx.conf.strength;
121104

122105
if (!eccbytes && eccstrength) {
123106
eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8);
124-
chip->ecc.bytes = eccbytes;
107+
engine_conf->code_size = eccbytes;
125108
}
126109

127110
if (!eccsize || !eccbytes) {
@@ -132,20 +115,14 @@ int nand_ecc_sw_bch_init(struct nand_device *nand)
132115
m = fls(1+8*eccsize);
133116
t = (eccbytes*8)/m;
134117

135-
nbc = kzalloc(sizeof(*nbc), GFP_KERNEL);
136-
if (!nbc)
137-
return -ENOMEM;
138-
139-
chip->ecc.priv = nbc;
140-
141-
nbc->bch = bch_init(m, t, 0, false);
142-
if (!nbc->bch)
143-
goto fail;
118+
engine_conf->bch = bch_init(m, t, 0, false);
119+
if (!engine_conf->bch)
120+
return -EINVAL;
144121

145122
/* verify that eccbytes has the expected value */
146-
if (nbc->bch->ecc_bytes != eccbytes) {
123+
if (engine_conf->bch->ecc_bytes != eccbytes) {
147124
pr_warn("invalid eccbytes %u, should be %u\n",
148-
eccbytes, nbc->bch->ecc_bytes);
125+
eccbytes, engine_conf->bch->ecc_bytes);
149126
goto fail;
150127
}
151128

@@ -163,25 +140,15 @@ int nand_ecc_sw_bch_init(struct nand_device *nand)
163140
goto fail;
164141
}
165142

166-
/*
167-
* ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(),
168-
* which is called by mtd_ooblayout_count_eccbytes().
169-
* Make sure they are properly initialized before calling
170-
* mtd_ooblayout_count_eccbytes().
171-
* FIXME: we should probably rework the sequencing in nand_scan_tail()
172-
* to avoid setting those fields twice.
173-
*/
174-
chip->ecc.steps = eccsteps;
175-
chip->ecc.total = eccsteps * eccbytes;
176-
nand->base.ecc.ctx.total = chip->ecc.total;
177143
if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) {
178144
pr_warn("invalid ecc layout\n");
179145
goto fail;
180146
}
181147

182-
nbc->eccmask = kzalloc(eccbytes, GFP_KERNEL);
183-
nbc->errloc = kmalloc_array(t, sizeof(*nbc->errloc), GFP_KERNEL);
184-
if (!nbc->eccmask || !nbc->errloc)
148+
engine_conf->eccmask = kzalloc(eccbytes, GFP_KERNEL);
149+
engine_conf->errloc = kmalloc_array(t, sizeof(*engine_conf->errloc),
150+
GFP_KERNEL);
151+
if (!engine_conf->eccmask || !engine_conf->errloc)
185152
goto fail;
186153

187154
/*
@@ -192,14 +159,15 @@ int nand_ecc_sw_bch_init(struct nand_device *nand)
192159
goto fail;
193160

194161
memset(erased_page, 0xff, eccsize);
195-
bch_encode(nbc->bch, erased_page, eccsize, nbc->eccmask);
162+
bch_encode(engine_conf->bch, erased_page, eccsize,
163+
engine_conf->eccmask);
196164
kfree(erased_page);
197165

198166
for (i = 0; i < eccbytes; i++)
199-
nbc->eccmask[i] ^= 0xff;
167+
engine_conf->eccmask[i] ^= 0xff;
200168

201169
if (!eccstrength)
202-
chip->ecc.strength = (eccbytes * 8) / fls(8 * eccsize);
170+
nand->ecc.ctx.conf.strength = (eccbytes * 8) / fls(8 * eccsize);
203171

204172
return 0;
205173

@@ -216,14 +184,12 @@ EXPORT_SYMBOL(nand_ecc_sw_bch_init);
216184
*/
217185
void nand_ecc_sw_bch_cleanup(struct nand_device *nand)
218186
{
219-
struct nand_chip *chip = mtd_to_nand(nanddev_to_mtd(nand));
220-
struct nand_bch_control *nbc = chip->ecc.priv;
221-
222-
if (nbc) {
223-
bch_free(nbc->bch);
224-
kfree(nbc->errloc);
225-
kfree(nbc->eccmask);
226-
kfree(nbc);
187+
struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv;
188+
189+
if (engine_conf) {
190+
bch_free(engine_conf->bch);
191+
kfree(engine_conf->errloc);
192+
kfree(engine_conf->eccmask);
227193
}
228194
}
229195
EXPORT_SYMBOL(nand_ecc_sw_bch_cleanup);

drivers/mtd/nand/raw/nand_base.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5142,8 +5142,33 @@ static void nand_scan_ident_cleanup(struct nand_chip *chip)
51425142
int rawnand_sw_bch_init(struct nand_chip *chip)
51435143
{
51445144
struct nand_device *base = &chip->base;
5145+
struct nand_ecc_sw_bch_conf *engine_conf;
5146+
int ret;
5147+
5148+
base->ecc.user_conf.engine_type = NAND_ECC_ENGINE_TYPE_SOFT;
5149+
base->ecc.user_conf.algo = NAND_ECC_ALGO_BCH;
5150+
base->ecc.user_conf.step_size = chip->ecc.size;
5151+
base->ecc.user_conf.strength = chip->ecc.strength;
5152+
5153+
engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
5154+
if (!engine_conf)
5155+
return -ENOMEM;
5156+
5157+
engine_conf->code_size = chip->ecc.bytes;
5158+
5159+
base->ecc.ctx.priv = engine_conf;
51455160

5146-
return nand_ecc_sw_bch_init(base);
5161+
ret = nand_ecc_sw_bch_init(base);
5162+
if (ret)
5163+
kfree(base->ecc.ctx.priv);
5164+
5165+
chip->ecc.size = base->ecc.ctx.conf.step_size;
5166+
chip->ecc.strength = base->ecc.ctx.conf.strength;
5167+
chip->ecc.total = base->ecc.ctx.total;
5168+
chip->ecc.steps = engine_conf->nsteps;
5169+
chip->ecc.bytes = engine_conf->code_size;
5170+
5171+
return ret;
51475172
}
51485173
EXPORT_SYMBOL(rawnand_sw_bch_init);
51495174

@@ -5171,7 +5196,7 @@ void rawnand_sw_bch_cleanup(struct nand_chip *chip)
51715196

51725197
nand_ecc_sw_bch_cleanup(base);
51735198

5174-
chip->ecc.priv = NULL;
5199+
kfree(base->ecc.ctx.priv);
51755200
}
51765201
EXPORT_SYMBOL(rawnand_sw_bch_cleanup);
51775202

@@ -5794,15 +5819,18 @@ static int nand_scan_tail(struct nand_chip *chip)
57945819
* Set the number of read / write steps for one page depending on ECC
57955820
* mode.
57965821
*/
5797-
ecc->steps = mtd->writesize / ecc->size;
5822+
if (!ecc->steps)
5823+
ecc->steps = mtd->writesize / ecc->size;
57985824
if (ecc->steps * ecc->size != mtd->writesize) {
57995825
WARN(1, "Invalid ECC parameters\n");
58005826
ret = -EINVAL;
58015827
goto err_nand_manuf_cleanup;
58025828
}
58035829

5804-
ecc->total = ecc->steps * ecc->bytes;
5805-
chip->base.ecc.ctx.total = ecc->total;
5830+
if (!ecc->total) {
5831+
ecc->total = ecc->steps * ecc->bytes;
5832+
chip->base.ecc.ctx.total = ecc->total;
5833+
}
58065834

58075835
if (ecc->total > mtd->oobsize) {
58085836
WARN(1, "Total number of ECC bytes exceeded oobsize\n");

include/linux/mtd/nand-ecc-sw-bch.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,31 @@
99
#define __MTD_NAND_ECC_SW_BCH_H__
1010

1111
#include <linux/mtd/nand.h>
12+
#include <linux/bch.h>
13+
14+
/**
15+
* struct nand_ecc_sw_bch_conf - private software BCH ECC engine structure
16+
* @reqooblen: Save the actual user OOB length requested before overwriting it
17+
* @spare_oobbuf: Spare OOB buffer if none is provided
18+
* @code_size: Number of bytes needed to store a code (one code per step)
19+
* @nsteps: Number of steps
20+
* @calc_buf: Buffer to use when calculating ECC bytes
21+
* @code_buf: Buffer to use when reading (raw) ECC bytes from the chip
22+
* @bch: BCH control structure
23+
* @errloc: error location array
24+
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
25+
*/
26+
struct nand_ecc_sw_bch_conf {
27+
unsigned int reqooblen;
28+
void *spare_oobbuf;
29+
unsigned int code_size;
30+
unsigned int nsteps;
31+
u8 *calc_buf;
32+
u8 *code_buf;
33+
struct bch_control *bch;
34+
unsigned int *errloc;
35+
unsigned char *eccmask;
36+
};
1237

1338
#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)
1439

0 commit comments

Comments
 (0)