Commit 9994bb3f authored by Miquel Raynal's avatar Miquel Raynal

mtd: nand: ecc-bch: Create the software BCH engine

Let's continue introducing the generic ECC engine abstraction in the
NAND subsystem by instantiating a first ECC engine: the software
BCH one.

While at it, make a very tidy ecc_sw_bch_init() function and move all
the sanity checks and user input management in
nand_ecc_sw_bch_init_ctx(). This second helper will be called from the
raw RAND core.
Signed-off-by: default avatarMiquel Raynal <miquel.raynal@bootlin.com>
Link: https://lore.kernel.org/linux-mtd/20200929230124.31491-10-miquel.raynal@bootlin.com
parent 80fe6031
This diff is collapsed.
......@@ -5150,17 +5150,11 @@ int rawnand_sw_bch_init(struct nand_chip *chip)
base->ecc.user_conf.step_size = chip->ecc.size;
base->ecc.user_conf.strength = chip->ecc.strength;
engine_conf = kzalloc(sizeof(*engine_conf), GFP_KERNEL);
if (!engine_conf)
return -ENOMEM;
engine_conf->code_size = chip->ecc.bytes;
base->ecc.ctx.priv = engine_conf;
ret = nand_ecc_sw_bch_init(base);
ret = nand_ecc_sw_bch_init_ctx(base);
if (ret)
kfree(base->ecc.ctx.priv);
return ret;
engine_conf = base->ecc.ctx.priv;
chip->ecc.size = base->ecc.ctx.conf.step_size;
chip->ecc.strength = base->ecc.ctx.conf.strength;
......@@ -5168,7 +5162,7 @@ int rawnand_sw_bch_init(struct nand_chip *chip)
chip->ecc.steps = engine_conf->nsteps;
chip->ecc.bytes = engine_conf->code_size;
return ret;
return 0;
}
EXPORT_SYMBOL(rawnand_sw_bch_init);
......@@ -5194,9 +5188,7 @@ void rawnand_sw_bch_cleanup(struct nand_chip *chip)
{
struct nand_device *base = &chip->base;
nand_ecc_sw_bch_cleanup(base);
kfree(base->ecc.ctx.priv);
nand_ecc_sw_bch_cleanup_ctx(base);
}
EXPORT_SYMBOL(rawnand_sw_bch_cleanup);
......@@ -5308,51 +5300,15 @@ static int nand_set_ecc_soft_ops(struct nand_chip *chip)
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
/*
* Board driver should supply ecc.size and ecc.strength
* values to select how many bits are correctable.
* Otherwise, default to 4 bits for large page devices.
*/
if (!ecc->size && (mtd->oobsize >= 64)) {
ecc->size = 512;
ecc->strength = 4;
}
/*
* if no ecc placement scheme was provided pickup the default
* large page one.
*/
if (!mtd->ooblayout) {
/* handle large page devices only */
if (mtd->oobsize < 64) {
WARN(1, "OOB layout is required when using software BCH on small pages\n");
return -EINVAL;
}
mtd_set_ooblayout(mtd, nand_get_large_page_ooblayout());
}
/*
* We can only maximize ECC config when the default layout is
* used, otherwise we don't know how many bytes can really be
* used.
*/
if (mtd->ooblayout == nand_get_large_page_ooblayout() &&
nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH) {
int steps, bytes;
/* Always prefer 1k blocks over 512bytes ones */
ecc->size = 1024;
steps = mtd->writesize / ecc->size;
if (nanddev->ecc.user_conf.flags & NAND_ECC_MAXIMIZE_STRENGTH &&
mtd->ooblayout != nand_get_large_page_ooblayout())
nanddev->ecc.user_conf.flags &= ~NAND_ECC_MAXIMIZE_STRENGTH;
/* Reserve 2 bytes for the BBM */
bytes = (mtd->oobsize - 2) / steps;
ecc->strength = bytes * 8 / fls(8 * ecc->size);
}
/* See the software BCH ECC initialization for details */
ecc->bytes = 0;
ret = rawnand_sw_bch_init(chip);
if (ret) {
WARN(1, "BCH ECC initialization failed!\n");
......
......@@ -13,8 +13,8 @@
/**
* struct nand_ecc_sw_bch_conf - private software BCH ECC engine structure
* @reqooblen: Save the actual user OOB length requested before overwriting it
* @spare_oobbuf: Spare OOB buffer if none is provided
* @req_ctx: Save request context and tweak the original request to fit the
* engine needs
* @code_size: Number of bytes needed to store a code (one code per step)
* @nsteps: Number of steps
* @calc_buf: Buffer to use when calculating ECC bytes
......@@ -24,8 +24,7 @@
* @eccmask: XOR ecc mask, allows erased pages to be decoded as valid
*/
struct nand_ecc_sw_bch_conf {
unsigned int reqooblen;
void *spare_oobbuf;
struct nand_ecc_req_tweak_ctx req_ctx;
unsigned int code_size;
unsigned int nsteps;
u8 *calc_buf;
......@@ -41,8 +40,9 @@ int nand_ecc_sw_bch_calculate(struct nand_device *nand,
const unsigned char *buf, unsigned char *code);
int nand_ecc_sw_bch_correct(struct nand_device *nand, unsigned char *buf,
unsigned char *read_ecc, unsigned char *calc_ecc);
int nand_ecc_sw_bch_init(struct nand_device *nand);
void nand_ecc_sw_bch_cleanup(struct nand_device *nand);
int nand_ecc_sw_bch_init_ctx(struct nand_device *nand);
void nand_ecc_sw_bch_cleanup_ctx(struct nand_device *nand);
struct nand_ecc_engine *nand_ecc_sw_bch_get_engine(void);
#else /* !CONFIG_MTD_NAND_ECC_SW_BCH */
......@@ -61,12 +61,12 @@ static inline int nand_ecc_sw_bch_correct(struct nand_device *nand,
return -ENOTSUPP;
}
static inline int nand_ecc_sw_bch_init(struct nand_device *nand)
static inline int nand_ecc_sw_bch_init_ctx(struct nand_device *nand)
{
return -ENOTSUPP;
}
static inline void nand_ecc_sw_bch_cleanup(struct nand_device *nand) {}
static inline void nand_ecc_sw_bch_cleanup_ctx(struct nand_device *nand) {}
#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
......
......@@ -278,6 +278,15 @@ int nand_ecc_finish_io_req(struct nand_device *nand,
struct nand_page_io_req *req);
bool nand_ecc_is_strong_enough(struct nand_device *nand);
#if IS_ENABLED(CONFIG_MTD_NAND_ECC_SW_BCH)
struct nand_ecc_engine *nand_ecc_sw_bch_get_engine(void);
#else
static inline struct nand_ecc_engine *nand_ecc_sw_bch_get_engine(void)
{
return NULL;
}
#endif /* CONFIG_MTD_NAND_ECC_SW_BCH */
/**
* struct nand_ecc_req_tweak_ctx - Help for automatically tweaking requests
* @orig_req: Pointer to the original IO request
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment