/** * nand_ecc_sw_bch_correct - Detect, correct and report bit error(s) * @nand: NAND device * @buf: Raw data read from the chip * @read_ecc: ECC bytes from the chip * @calc_ecc: ECC calculated from the raw data * * Detect and correct bit errors for a data block.
*/ int nand_ecc_sw_bch_correct(struct nand_device *nand, unsignedchar *buf, unsignedchar *read_ecc, unsignedchar *calc_ecc)
{ struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; unsignedint step_size = nand->ecc.ctx.conf.step_size; unsignedint *errloc = engine_conf->errloc; int i, count;
count = bch_decode(engine_conf->bch, NULL, step_size, read_ecc,
calc_ecc, NULL, errloc); if (count > 0) { for (i = 0; i < count; i++) { if (errloc[i] < (step_size * 8)) /* The error is in the data area: correct it */
buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7));
/* Otherwise the error is in the ECC area: nothing to do */
pr_debug("%s: corrected bitflip %u\n", __func__,
errloc[i]);
}
} elseif (count < 0) {
pr_err("ECC unrecoverable error\n");
count = -EBADMSG;
}
/** * nand_ecc_sw_bch_init - Initialize software BCH ECC engine * @nand: NAND device * * Returns: a pointer to a new NAND BCH control structure, or NULL upon failure * * Initialize NAND BCH error correction. @nand.ecc parameters 'step_size' and * 'bytes' are used to compute the following BCH parameters: * m, the Galois field order * t, the error correction capability * 'bytes' should be equal to the number of bytes required to store m * t * bits, where m is such that 2^m - 1 > step_size * 8. * * Example: to configure 4 bit correction per 512 bytes, you should pass * step_size = 512 (thus, m = 13 is the smallest integer such that 2^m - 1 > 512 * 8) * bytes = 7 (7 bytes are required to store m * t = 13 * 4 = 52 bits)
*/ staticint nand_ecc_sw_bch_init(struct nand_device *nand)
{ struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; unsignedint eccsize = nand->ecc.ctx.conf.step_size; unsignedint eccbytes = engine_conf->code_size; unsignedint m, t, i; unsignedchar *erased_page; int ret;
m = fls(1 + (8 * eccsize));
t = (eccbytes * 8) / m;
engine_conf->bch = bch_init(m, t, 0, false); if (!engine_conf->bch) return -EINVAL;
engine_conf->eccmask = kzalloc(eccbytes, GFP_KERNEL);
engine_conf->errloc = kmalloc_array(t, sizeof(*engine_conf->errloc),
GFP_KERNEL); if (!engine_conf->eccmask || !engine_conf->errloc) {
ret = -ENOMEM; goto cleanup;
}
/* Compute and store the inverted ECC of an erased step */
erased_page = kmalloc(eccsize, GFP_KERNEL); if (!erased_page) {
ret = -ENOMEM; goto cleanup;
}
for (i = 0; i < eccbytes; i++)
engine_conf->eccmask[i] ^= 0xff;
/* Verify that the number of code bytes has the expected value */ if (engine_conf->bch->ecc_bytes != eccbytes) {
pr_err("Invalid number of ECC bytes: %u, expected: %u\n",
eccbytes, engine_conf->bch->ecc_bytes);
ret = -EINVAL; goto cleanup;
}
/* Sanity checks */ if (8 * (eccsize + eccbytes) >= (1 << m)) {
pr_err("ECC step size is too large (%u)\n", eccsize);
ret = -EINVAL; goto cleanup;
}
/* * Board driver should supply ECC size and ECC strength * values to select how many bits are correctable. * Otherwise, default to 512 bytes for large page devices and 256 for * small page devices.
*/ if (!conf->step_size) { if (mtd->oobsize >= 64)
conf->step_size = 512; else
conf->step_size = 256;
staticint nand_ecc_sw_bch_prepare_io_req(struct nand_device *nand, struct nand_page_io_req *req)
{ struct nand_ecc_sw_bch_conf *engine_conf = nand->ecc.ctx.priv; struct mtd_info *mtd = nanddev_to_mtd(nand); int eccsize = nand->ecc.ctx.conf.step_size; int eccbytes = engine_conf->code_size; int eccsteps = nand->ecc.ctx.nsteps; int total = nand->ecc.ctx.total;
u8 *ecccalc = engine_conf->calc_buf; const u8 *data; int i;
/* Nothing to do for a raw operation */ if (req->mode == MTD_OPS_RAW) return 0;
/* This engine does not provide BBM/free OOB bytes protection */ if (!req->datalen) return 0;
nand_ecc_tweak_req(&engine_conf->req_ctx, req);
/* No more preparation for page read */ if (req->type == NAND_PAGE_READ) return 0;
/* Preparation for page write: derive the ECC bytes and place them */ for (i = 0, data = req->databuf.out;
eccsteps;
eccsteps--, i += eccbytes, data += eccsize)
nand_ecc_sw_bch_calculate(nand, data, &ecccalc[i]);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.