Lines Matching +full:nand +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.
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()
369 engine_conf->sm_order); in nand_ecc_sw_hamming_calculate()
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()
462 engine_conf->sm_order); in nand_ecc_sw_hamming_correct()
466 int nand_ecc_sw_hamming_init_ctx(struct nand_device *nand) in nand_ecc_sw_hamming_init_ctx() argument
468 struct nand_ecc_props *conf = &nand->ecc.ctx.conf; in nand_ecc_sw_hamming_init_ctx()
470 struct mtd_info *mtd = nanddev_to_mtd(nand); in nand_ecc_sw_hamming_init_ctx()
473 if (!mtd->ooblayout) { in nand_ecc_sw_hamming_init_ctx()
474 switch (mtd->oobsize) { in nand_ecc_sw_hamming_init_ctx()
485 return -ENOTSUPP; in nand_ecc_sw_hamming_init_ctx()
489 conf->engine_type = NAND_ECC_ENGINE_TYPE_SOFT; in nand_ecc_sw_hamming_init_ctx()
490 conf->algo = NAND_ECC_ALGO_HAMMING; in nand_ecc_sw_hamming_init_ctx()
491 conf->step_size = nand->ecc.user_conf.step_size; in nand_ecc_sw_hamming_init_ctx()
492 conf->strength = 1; in nand_ecc_sw_hamming_init_ctx()
495 if (conf->step_size != 256 && conf->step_size != 512) in nand_ecc_sw_hamming_init_ctx()
496 conf->step_size = 256; in nand_ecc_sw_hamming_init_ctx()
500 return -ENOMEM; in nand_ecc_sw_hamming_init_ctx()
502 ret = nand_ecc_init_req_tweaking(&engine_conf->req_ctx, nand); in nand_ecc_sw_hamming_init_ctx()
506 engine_conf->code_size = 3; in nand_ecc_sw_hamming_init_ctx()
507 engine_conf->calc_buf = kzalloc(mtd->oobsize, GFP_KERNEL); in nand_ecc_sw_hamming_init_ctx()
508 engine_conf->code_buf = kzalloc(mtd->oobsize, GFP_KERNEL); in nand_ecc_sw_hamming_init_ctx()
509 if (!engine_conf->calc_buf || !engine_conf->code_buf) { in nand_ecc_sw_hamming_init_ctx()
510 ret = -ENOMEM; in nand_ecc_sw_hamming_init_ctx()
514 nand->ecc.ctx.priv = engine_conf; in nand_ecc_sw_hamming_init_ctx()
515 nand->ecc.ctx.nsteps = mtd->writesize / conf->step_size; in nand_ecc_sw_hamming_init_ctx()
516 nand->ecc.ctx.total = nand->ecc.ctx.nsteps * engine_conf->code_size; in nand_ecc_sw_hamming_init_ctx()
521 nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx); in nand_ecc_sw_hamming_init_ctx()
522 kfree(engine_conf->calc_buf); in nand_ecc_sw_hamming_init_ctx()
523 kfree(engine_conf->code_buf); in nand_ecc_sw_hamming_init_ctx()
531 void nand_ecc_sw_hamming_cleanup_ctx(struct nand_device *nand) in nand_ecc_sw_hamming_cleanup_ctx() argument
533 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_cleanup_ctx()
536 nand_ecc_cleanup_req_tweaking(&engine_conf->req_ctx); in nand_ecc_sw_hamming_cleanup_ctx()
537 kfree(engine_conf->calc_buf); in nand_ecc_sw_hamming_cleanup_ctx()
538 kfree(engine_conf->code_buf); in nand_ecc_sw_hamming_cleanup_ctx()
544 static int nand_ecc_sw_hamming_prepare_io_req(struct nand_device *nand, in nand_ecc_sw_hamming_prepare_io_req() argument
547 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_prepare_io_req()
548 struct mtd_info *mtd = nanddev_to_mtd(nand); in nand_ecc_sw_hamming_prepare_io_req()
549 int eccsize = nand->ecc.ctx.conf.step_size; in nand_ecc_sw_hamming_prepare_io_req()
550 int eccbytes = engine_conf->code_size; in nand_ecc_sw_hamming_prepare_io_req()
551 int eccsteps = nand->ecc.ctx.nsteps; in nand_ecc_sw_hamming_prepare_io_req()
552 int total = nand->ecc.ctx.total; in nand_ecc_sw_hamming_prepare_io_req()
553 u8 *ecccalc = engine_conf->calc_buf; in nand_ecc_sw_hamming_prepare_io_req()
558 if (req->mode == MTD_OPS_RAW) in nand_ecc_sw_hamming_prepare_io_req()
561 /* This engine does not provide BBM/free OOB bytes protection */ in nand_ecc_sw_hamming_prepare_io_req()
562 if (!req->datalen) in nand_ecc_sw_hamming_prepare_io_req()
565 nand_ecc_tweak_req(&engine_conf->req_ctx, req); in nand_ecc_sw_hamming_prepare_io_req()
568 if (req->type == NAND_PAGE_READ) in nand_ecc_sw_hamming_prepare_io_req()
571 /* Preparation for page write: derive the ECC bytes and place them */ in nand_ecc_sw_hamming_prepare_io_req()
572 for (i = 0, data = req->databuf.out; in nand_ecc_sw_hamming_prepare_io_req()
574 eccsteps--, i += eccbytes, data += eccsize) in nand_ecc_sw_hamming_prepare_io_req()
575 nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]); in nand_ecc_sw_hamming_prepare_io_req()
577 return mtd_ooblayout_set_eccbytes(mtd, ecccalc, (void *)req->oobbuf.out, in nand_ecc_sw_hamming_prepare_io_req()
581 static int nand_ecc_sw_hamming_finish_io_req(struct nand_device *nand, in nand_ecc_sw_hamming_finish_io_req() argument
584 struct nand_ecc_sw_hamming_conf *engine_conf = nand->ecc.ctx.priv; in nand_ecc_sw_hamming_finish_io_req()
585 struct mtd_info *mtd = nanddev_to_mtd(nand); in nand_ecc_sw_hamming_finish_io_req()
586 int eccsize = nand->ecc.ctx.conf.step_size; in nand_ecc_sw_hamming_finish_io_req()
587 int total = nand->ecc.ctx.total; in nand_ecc_sw_hamming_finish_io_req()
588 int eccbytes = engine_conf->code_size; in nand_ecc_sw_hamming_finish_io_req()
589 int eccsteps = nand->ecc.ctx.nsteps; in nand_ecc_sw_hamming_finish_io_req()
590 u8 *ecccalc = engine_conf->calc_buf; in nand_ecc_sw_hamming_finish_io_req()
591 u8 *ecccode = engine_conf->code_buf; in nand_ecc_sw_hamming_finish_io_req()
593 u8 *data = req->databuf.in; in nand_ecc_sw_hamming_finish_io_req()
597 if (req->mode == MTD_OPS_RAW) in nand_ecc_sw_hamming_finish_io_req()
600 /* This engine does not provide BBM/free OOB bytes protection */ in nand_ecc_sw_hamming_finish_io_req()
601 if (!req->datalen) in nand_ecc_sw_hamming_finish_io_req()
605 if (req->type == NAND_PAGE_WRITE) { in nand_ecc_sw_hamming_finish_io_req()
606 nand_ecc_restore_req(&engine_conf->req_ctx, req); in nand_ecc_sw_hamming_finish_io_req()
610 /* Finish a page read: retrieve the (raw) ECC bytes*/ in nand_ecc_sw_hamming_finish_io_req()
611 ret = mtd_ooblayout_get_eccbytes(mtd, ecccode, req->oobbuf.in, 0, in nand_ecc_sw_hamming_finish_io_req()
616 /* Calculate the ECC bytes */ in nand_ecc_sw_hamming_finish_io_req()
617 for (i = 0; eccsteps; eccsteps--, i += eccbytes, data += eccsize) in nand_ecc_sw_hamming_finish_io_req()
618 nand_ecc_sw_hamming_calculate(nand, data, &ecccalc[i]); in nand_ecc_sw_hamming_finish_io_req()
621 for (eccsteps = nand->ecc.ctx.nsteps, i = 0, data = req->databuf.in; in nand_ecc_sw_hamming_finish_io_req()
623 eccsteps--, i += eccbytes, data += eccsize) { in nand_ecc_sw_hamming_finish_io_req()
624 int stat = nand_ecc_sw_hamming_correct(nand, data, in nand_ecc_sw_hamming_finish_io_req()
628 mtd->ecc_stats.failed++; in nand_ecc_sw_hamming_finish_io_req()
630 mtd->ecc_stats.corrected += stat; in nand_ecc_sw_hamming_finish_io_req()
635 nand_ecc_restore_req(&engine_conf->req_ctx, req); in nand_ecc_sw_hamming_finish_io_req()
659 MODULE_DESCRIPTION("NAND software Hamming ECC support");