cregit-Linux how code gets into the kernel

Release 4.7 drivers/mtd/nand/nand_bch.c

Directory: drivers/mtd/nand
/*
 * This file provides ECC correction for more than 1 bit per block of data,
 * using binary BCH codes. It relies on the generic BCH library lib/bch.c.
 *
 * Copyright © 2011 Ivan Djelic <ivan.djelic@parrot.com>
 *
 * This file is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 or (at your option) any
 * later version.
 *
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this file; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 */

#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/nand_bch.h>
#include <linux/bch.h>

/**
 * struct nand_bch_control - private NAND BCH control structure
 * @bch:       BCH control structure
 * @errloc:    error location array
 * @eccmask:   XOR ecc mask, allows erased pages to be decoded as valid
 */

struct nand_bch_control {
	
struct bch_control   *bch;
	
unsigned int         *errloc;
	
unsigned char        *eccmask;
};

/**
 * nand_bch_calculate_ecc - [NAND Interface] Calculate ECC for data block
 * @mtd:        MTD block structure
 * @buf:        input buffer with raw data
 * @code:       output buffer with ECC
 */

int nand_bch_calculate_ecc(struct mtd_info *mtd, const unsigned char *buf, unsigned char *code) { const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int i; memset(code, 0, chip->ecc.bytes); encode_bch(nbc->bch, buf, chip->ecc.size, code); /* apply mask so that an erased page is a valid codeword */ for (i = 0; i < chip->ecc.bytes; i++) code[i] ^= nbc->eccmask[i]; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
ivan djelicivan djelic10797.27%150.00%
boris brezillonboris brezillon32.73%150.00%
Total110100.00%2100.00%

EXPORT_SYMBOL(nand_bch_calculate_ecc); /** * nand_bch_correct_data - [NAND Interface] Detect and correct bit error(s) * @mtd: MTD block structure * @buf: raw data read from the chip * @read_ecc: ECC from the chip * @calc_ecc: the ECC calculated from raw data * * Detect and correct bit errors for a data byte block */
int nand_bch_correct_data(struct mtd_info *mtd, unsigned char *buf, unsigned char *read_ecc, unsigned char *calc_ecc) { const struct nand_chip *chip = mtd_to_nand(mtd); struct nand_bch_control *nbc = chip->ecc.priv; unsigned int *errloc = nbc->errloc; int i, count; count = decode_bch(nbc->bch, NULL, chip->ecc.size, read_ecc, calc_ecc, NULL, errloc); if (count > 0) { for (i = 0; i < count; i++) { if (errloc[i] < (chip->ecc.size*8)) /* error is located in data, correct it */ buf[errloc[i] >> 3] ^= (1 << (errloc[i] & 7)); /* else error in ecc, no action needed */ pr_debug("%s: corrected bitflip %u\n", __func__, errloc[i]); } } else if (count < 0) { printk(KERN_ERR "ecc unrecoverable error\n"); count = -EBADMSG; } return count; }

Contributors

PersonTokensPropCommitsCommitProp
ivan djelicivan djelic18197.31%125.00%
boris brezillonboris brezillon42.15%250.00%
brian norrisbrian norris10.54%125.00%
Total186100.00%4100.00%

EXPORT_SYMBOL(nand_bch_correct_data); /** * nand_bch_init - [NAND Interface] Initialize NAND BCH error correction * @mtd: MTD block structure * * Returns: * a pointer to a new NAND BCH control structure, or NULL upon failure * * Initialize NAND BCH error correction. Parameters @eccsize and @eccbytes * are used to compute BCH parameters m (Galois field order) and t (error * correction capability). @eccbytes should be equal to the number of bytes * required to store m*t bits, where m is such that 2^m-1 > @eccsize*8. * * Example: to configure 4 bit correction per 512 bytes, you should pass * @eccsize = 512 (thus, m=13 is the smallest integer such that 2^m-1 > 512*8) * @eccbytes = 7 (7 bytes are required to store m*t = 13*4 = 52 bits) */
struct nand_bch_control *nand_bch_init(struct mtd_info *mtd) { struct nand_chip *nand = mtd_to_nand(mtd); unsigned int m, t, eccsteps, i; struct nand_bch_control *nbc = NULL; unsigned char *erased_page; unsigned int eccsize = nand->ecc.size; unsigned int eccbytes = nand->ecc.bytes; unsigned int eccstrength = nand->ecc.strength; if (!eccbytes && eccstrength) { eccbytes = DIV_ROUND_UP(eccstrength * fls(8 * eccsize), 8); nand->ecc.bytes = eccbytes; } if (!eccsize || !eccbytes) { printk(KERN_WARNING "ecc parameters not supplied\n"); goto fail; } m = fls(1+8*eccsize); t = (eccbytes*8)/m; nbc = kzalloc(sizeof(*nbc), GFP_KERNEL); if (!nbc) goto fail; nbc->bch = init_bch(m, t, 0); if (!nbc->bch) goto fail; /* verify that eccbytes has the expected value */ if (nbc->bch->ecc_bytes != eccbytes) { printk(KERN_WARNING "invalid eccbytes %u, should be %u\n", eccbytes, nbc->bch->ecc_bytes); goto fail; } eccsteps = mtd->writesize/eccsize; /* Check that we have an oob layout description. */ if (!mtd->ooblayout) { pr_warn("missing oob scheme"); goto fail; } /* sanity checks */ if (8*(eccsize+eccbytes) >= (1 << m)) { printk(KERN_WARNING "eccsize %u is too large\n", eccsize); goto fail; } /* * ecc->steps and ecc->total might be used by mtd->ooblayout->ecc(), * which is called by mtd_ooblayout_count_eccbytes(). * Make sure they are properly initialized before calling * mtd_ooblayout_count_eccbytes(). * FIXME: we should probably rework the sequencing in nand_scan_tail() * to avoid setting those fields twice. */ nand->ecc.steps = eccsteps; nand->ecc.total = eccsteps * eccbytes; if (mtd_ooblayout_count_eccbytes(mtd) != (eccsteps*eccbytes)) { printk(KERN_WARNING "invalid ecc layout\n"); goto fail; } nbc->eccmask = kmalloc(eccbytes, GFP_KERNEL); nbc->errloc = kmalloc(t*sizeof(*nbc->errloc), GFP_KERNEL); if (!nbc->eccmask || !nbc->errloc) goto fail; /* * compute and store the inverted ecc of an erased ecc block */ erased_page = kmalloc(eccsize, GFP_KERNEL); if (!erased_page) goto fail; memset(erased_page, 0xff, eccsize); memset(nbc->eccmask, 0, eccbytes); encode_bch(nbc->bch, erased_page, eccsize, nbc->eccmask); kfree(erased_page); for (i = 0; i < eccbytes; i++) nbc->eccmask[i] ^= 0xff; if (!eccstrength) nand->ecc.strength = (eccbytes * 8) / fls(8 * eccsize); return nbc; fail: nand_bch_free(nbc); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
ivan djelicivan djelic35774.07%120.00%
boris brezillonboris brezillon12425.73%360.00%
brian norrisbrian norris10.21%120.00%
Total482100.00%5100.00%

EXPORT_SYMBOL(nand_bch_init); /** * nand_bch_free - [NAND Interface] Release NAND BCH ECC resources * @nbc: NAND BCH control structure */
void nand_bch_free(struct nand_bch_control *nbc) { if (nbc) { free_bch(nbc->bch); kfree(nbc->errloc); kfree(nbc->eccmask); kfree(nbc); } }

Contributors

PersonTokensPropCommitsCommitProp
ivan djelicivan djelic42100.00%1100.00%
Total42100.00%1100.00%

EXPORT_SYMBOL(nand_bch_free); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ivan Djelic <ivan.djelic@parrot.com>"); MODULE_DESCRIPTION("NAND software BCH ECC support");

Overall Contributors

PersonTokensPropCommitsCommitProp
ivan djelicivan djelic77385.13%112.50%
boris brezillonboris brezillon13314.65%562.50%
brian norrisbrian norris20.22%225.00%
Total908100.00%8100.00%
Directory: drivers/mtd/nand
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}