Lines Matching +full:nand +full:- +full:no +full:- +full:ecc +full:- +full:engine

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * This file contains an ECC algorithm that detects and corrects 1 bit
9 * Completely replaces the previous ECC implementation which was written by:
14 * can be found in Documentation/driver-api/mtd/nand_ecc.rst
20 #include <linux/mtd/nand.h>
21 #include <linux/mtd/nand-ecc-sw-hamming.h>
75 * addressbits is a lookup table to filter out the bits from the xor-ed
76 * ECC data that identify the faulty location.
294 * leaving it out gives slightly worse results. No idea why, probably in ecc_sw_hamming_calculate()
307 * Finally calculate the ECC bits. in ecc_sw_hamming_calculate()
357 * nand_ecc_sw_hamming_calculate - Calculate 3-byte ECC for 256/512-byte block
358 * @nand: NAND device
360 * @code: Output buffer with ECC
362 int nand_ecc_sw_hamming_calculate(struct nand_device *nand, in nand_ecc_sw_hamming_calculate() argument
365 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_calculate()
366 unsigned int step_size = nand->ecc.ctx.conf.step_size; in nand_ecc_sw_hamming_calculate()
367 bool sm_order = engine_conf ? engine_conf->sm_order : false; in nand_ecc_sw_hamming_calculate()
402 return 0; /* no error */ in ecc_sw_hamming_correct()
438 return 1; /* error in ECC data; no action needed */ in ecc_sw_hamming_correct()
440 pr_err("%s: uncorrectable ECC error\n", __func__); in ecc_sw_hamming_correct()
441 return -EBADMSG; in ecc_sw_hamming_correct()
446 * nand_ecc_sw_hamming_correct - Detect and correct bit error(s)
447 * @nand: NAND device
449 * @read_ecc: ECC bytes read from the chip
450 * @calc_ecc: ECC calculated from the raw data
452 * Detect and correct up to 1 bit error per 256/512-byte block.
454 int nand_ecc_sw_hamming_correct(struct nand_device *nand, unsigned char *buf, in nand_ecc_sw_hamming_correct() argument
458 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_correct()
459 unsigned int step_size = nand->ecc.ctx.conf.step_size; in nand_ecc_sw_hamming_correct()
460 bool sm_order = engine_conf ? engine_conf->sm_order : false; in nand_ecc_sw_hamming_correct()
467 int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand) in nand_ecc_sw_hamming_init_ctx() argument
469 struct nand_ecc_props *conf = &nand->ecc.ctx.conf; in nand_ecc_sw_hamming_init_ctx()
471 struct mtd_info *mtd = nanddev_to_mtd(nand); in nand_ecc_sw_hamming_init_ctx()
474 if (!mtd->ooblayout) { in nand_ecc_sw_hamming_init_ctx()
475 switch (mtd->oobsize) { in nand_ecc_sw_hamming_init_ctx()
486 return -ENOTSUPP; in nand_ecc_sw_hamming_init_ctx()
490 conf->engine_type = NAND_ECC_ENGINE_TYPE_SOFT; in nand_ecc_sw_hamming_init_ctx()
491 conf->algo = NAND_ECC_ALGO_HAMMING; in nand_ecc_sw_hamming_init_ctx()
492 conf->step_size = nand->ecc.user_conf.step_size; in nand_ecc_sw_hamming_init_ctx()
493 conf->strength = 1; in nand_ecc_sw_hamming_init_ctx()
496 if (conf->step_size != 256 && conf->step_size != 512) in nand_ecc_sw_hamming_init_ctx()
497 conf->step_size = 256; in nand_ecc_sw_hamming_init_ctx()
501 return -ENOMEM; in nand_ecc_sw_hamming_init_ctx()
503 ret = nand_ecc_init_req_tweaking(&engine_conf->req_ctx, nand); in nand_ecc_sw_hamming_init_ctx()
507 engine_conf->code_size = 3; in nand_ecc_sw_hamming_init_ctx()
508 engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL); in nand_ecc_sw_hamming_init_ctx()
509 engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL); in nand_ecc_sw_hamming_init_ctx()
510 if (!engine_conf->calc_buf || !engine_conf->code_buf) { in nand_ecc_sw_hamming_init_ctx()
511 ret = -ENOMEM; in nand_ecc_sw_hamming_init_ctx()
515 nand->ecc.ctx.priv = engine_conf; in nand_ecc_sw_hamming_init_ctx()
516 nand->ecc.ctx.nsteps = mtd->writesize / conf->step_size; in nand_ecc_sw_hamming_init_ctx()
517 nand->ecc.ctx.total = nand->ecc.ctx.nsteps * engine_conf->code_size; in nand_ecc_sw_hamming_init_ctx()
522 nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx); in nand_ecc_sw_hamming_init_ctx()
523 kfree(engine_conf->calc_buf); in nand_ecc_sw_hamming_init_ctx()
524 kfree(engine_conf->code_buf); in nand_ecc_sw_hamming_init_ctx()
532 void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand) in nand_ecc_sw_hamming_cleanup_ctx() argument
534 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_cleanup_ctx()
537 nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx); in nand_ecc_sw_hamming_cleanup_ctx()
538 kfree(engine_conf->calc_buf); in nand_ecc_sw_hamming_cleanup_ctx()
539 kfree(engine_conf->code_buf); in nand_ecc_sw_hamming_cleanup_ctx()
545 static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand, in nand_ecc_sw_hamming_prepare_io_req() argument
548 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_prepare_io_req()
549 struct mtd_info *mtd = nanddev_to_mtd(nand); in nand_ecc_sw_hamming_prepare_io_req()
550 int eccsize = nand->ecc.ctx.conf.step_size; in nand_ecc_sw_hamming_prepare_io_req()
551 int eccbytes = engine_conf->code_size; in nand_ecc_sw_hamming_prepare_io_req()
552 int eccsteps = nand->ecc.ctx.nsteps; in nand_ecc_sw_hamming_prepare_io_req()
553 int total = nand->ecc.ctx.total; in nand_ecc_sw_hamming_prepare_io_req()
554 u8 *ecccalc = engine_conf->calc_buf; in nand_ecc_sw_hamming_prepare_io_req()
559 if (req->mode == MTD_OPS_RAW) in nand_ecc_sw_hamming_prepare_io_req()
562 /* This engine does not provide BBM/free OOB bytes protection */ in nand_ecc_sw_hamming_prepare_io_req()
563 if (!req->datalen) in nand_ecc_sw_hamming_prepare_io_req()
566 nand_ecc_tweak_req(&engine_conf->req_ctx, req); in nand_ecc_sw_hamming_prepare_io_req()
568 /* No more preparation for page read */ in nand_ecc_sw_hamming_prepare_io_req()
569 if (req->type == NAND_PAGE_READ) in nand_ecc_sw_hamming_prepare_io_req()
572 /* Preparation for page write: derive the ECC bytes and place them */ in nand_ecc_sw_hamming_prepare_io_req()
573 for (i = 0, data = req->databuf.out; in nand_ecc_sw_hamming_prepare_io_req()
575 eccsteps--, i += eccbytes, data += eccsize) in nand_ecc_sw_hamming_prepare_io_req()
576 nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]); in nand_ecc_sw_hamming_prepare_io_req()
578 return mtd_ooblayout_set_eccbytes(mtd, ecccalc, (void *)req->oobbuf.out, in nand_ecc_sw_hamming_prepare_io_req()
582 static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, in nand_ecc_sw_hamming_finish_io_req() argument
585 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_finish_io_req()
586 struct mtd_info *mtd = nanddev_to_mtd(nand); in nand_ecc_sw_hamming_finish_io_req()
587 int eccsize = nand->ecc.ctx.conf.step_size; in nand_ecc_sw_hamming_finish_io_req()
588 int total = nand->ecc.ctx.total; in nand_ecc_sw_hamming_finish_io_req()
589 int eccbytes = engine_conf->code_size; in nand_ecc_sw_hamming_finish_io_req()
590 int eccsteps = nand->ecc.ctx.nsteps; in nand_ecc_sw_hamming_finish_io_req()
591 u8 *ecccalc = engine_conf->calc_buf; in nand_ecc_sw_hamming_finish_io_req()
592 u8 *ecccode = engine_conf->code_buf; in nand_ecc_sw_hamming_finish_io_req()
594 u8 *data = req->databuf.in; in nand_ecc_sw_hamming_finish_io_req()
598 if (req->mode == MTD_OPS_RAW) in nand_ecc_sw_hamming_finish_io_req()
601 /* This engine does not provide BBM/free OOB bytes protection */ in nand_ecc_sw_hamming_finish_io_req()
602 if (!req->datalen) in nand_ecc_sw_hamming_finish_io_req()
605 /* No more preparation for page write */ in nand_ecc_sw_hamming_finish_io_req()
606 if (req->type == NAND_PAGE_WRITE) { in nand_ecc_sw_hamming_finish_io_req()
607 nand_ecc_restore_req(&engine_conf->req_ctx, req); in nand_ecc_sw_hamming_finish_io_req()
611 /* Finish a page read: retrieve the (raw) ECC bytes*/ in nand_ecc_sw_hamming_finish_io_req()
612 ret = mtd_ooblayout_get_eccbytes(mtd, ecccode, req->oobbuf.in, 0, in nand_ecc_sw_hamming_finish_io_req()
617 /* Calculate the ECC bytes */ in nand_ecc_sw_hamming_finish_io_req()
618 for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize) in nand_ecc_sw_hamming_finish_io_req()
619 nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]); in nand_ecc_sw_hamming_finish_io_req()
622 for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in; in nand_ecc_sw_hamming_finish_io_req()
624 eccsteps--, i += eccbytes, data += eccsize) { in nand_ecc_sw_hamming_finish_io_req()
625 int stat = nand_ecc_sw_hamming_correct(nand, data, in nand_ecc_sw_hamming_finish_io_req()
629 mtd->ecc_stats.failed++; in nand_ecc_sw_hamming_finish_io_req()
631 mtd->ecc_stats.corrected += stat; in nand_ecc_sw_hamming_finish_io_req()
636 nand_ecc_restore_req(&engine_conf->req_ctx, req); in nand_ecc_sw_hamming_finish_io_req()
660 MODULE_DESCRIPTION("NAND software Hamming ECC support");