All of lore.kernel.org
 help / color / mirror / Atom feed
From: Philippe REYNES <philippe.reynes@softathome.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH] drivers: nand: brcmnand: fix nand_chip ecc layout structure
Date: Thu, 5 Sep 2019 14:46:28 +0200 (CEST)	[thread overview]
Message-ID: <959468415.910920.1567687588359.JavaMail.zimbra@softathome.com> (raw)
In-Reply-To: <20190904175114.37018-1-william.zhang@broadcom.com>


> The current brcmnand driver is based on 4.18 linux kernel which uses
> mtd_set_ooblayout to set ecc layout. But nand base code in u-boot is from
> old kernel which does not use this new API and expect nand_chip.ecc.layout
> structure to be set. This cause nand_scan_tail function running into a bug
> check if the device has a different oob size than the default ones.
> 
> This patch ports the brcmstb_choose_ecc_layout function from kernel 4.6.7
> that supports the ecc layout struture and replaces the mtd_set_ooblayout
> method
> 
> Signed-off-by: William Zhang <william.zhang@broadcom.com>

Good catch, I've missed it when I have ported this driver to u-boot.

Reviewed-by: Philippe Reynes <philippe.reynes@softathome.com>

> ---
> drivers/mtd/nand/raw/brcmnand/brcmnand.c | 260 +++++++++--------------
> 1 file changed, 104 insertions(+), 156 deletions(-)
> 
> diff --git a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> index faa6da42d5..0745929253 100644
> --- a/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> +++ b/drivers/mtd/nand/raw/brcmnand/brcmnand.c
> @@ -888,183 +888,131 @@ static inline bool is_hamming_ecc(struct
> brcmnand_controller *ctrl,
> }
> 
> /*
> - * Set mtd->ooblayout to the appropriate mtd_ooblayout_ops given
> - * the layout/configuration.
> - * Returns -ERRCODE on failure.
> + * Returns a nand_ecclayout strucutre for the given layout/configuration.
> + * Returns NULL on failure.
> */
> -static int brcmnand_hamming_ooblayout_ecc(struct mtd_info *mtd, int section,
> - struct mtd_oob_region *oobregion)
> +static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
> + struct brcmnand_host *host)
> {
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - struct brcmnand_host *host = nand_get_controller_data(chip);
> - struct brcmnand_cfg *cfg = &host->hwcfg;
> - int sas = cfg->spare_area_size << cfg->sector_size_1k;
> - int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
> -
> - if (section >= sectors)
> - return -ERANGE;
> -
> - oobregion->offset = (section * sas) + 6;
> - oobregion->length = 3;
> -
> - return 0;
> -}
> -
> -static int brcmnand_hamming_ooblayout_free(struct mtd_info *mtd, int section,
> - struct mtd_oob_region *oobregion)
> -{
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - struct brcmnand_host *host = nand_get_controller_data(chip);
> struct brcmnand_cfg *cfg = &host->hwcfg;
> - int sas = cfg->spare_area_size << cfg->sector_size_1k;
> - int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
> + int i, j;
> + struct nand_ecclayout *layout;
> + int req;
> + int sectors;
> + int sas;
> + int idx1, idx2;
> 
> - if (section >= sectors * 2)
> - return -ERANGE;
> -
> - oobregion->offset = (section / 2) * sas;
> -
> - if (section & 1) {
> - oobregion->offset += 9;
> - oobregion->length = 7;
> - } else {
> - oobregion->length = 6;
> -
> - /* First sector of each page may have BBI */
> - if (!section) {
> - /*
> - * Small-page NAND use byte 6 for BBI while large-page
> - * NAND use byte 0.
> - */
> - if (cfg->page_size > 512)
> - oobregion->offset++;
> - oobregion->length--;
> +#ifndef __UBOOT__
> + layout = devm_kzalloc(&host->pdev->dev, sizeof(*layout), GFP_KERNEL);
> +#else
> + layout = devm_kzalloc(host->pdev, sizeof(*layout), GFP_KERNEL);
> +#endif
> + if (!layout)
> + return NULL;
> +
> + sectors = cfg->page_size / (512 << cfg->sector_size_1k);
> + sas = cfg->spare_area_size << cfg->sector_size_1k;
> +
> + /* Hamming */
> + if (is_hamming_ecc(host->ctrl, cfg)) {
> + for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
> + /* First sector of each page may have BBI */
> + if (i == 0) {
> + layout->oobfree[idx2].offset = i * sas + 1;
> + /* Small-page NAND use byte 6 for BBI */
> + if (cfg->page_size == 512)
> + layout->oobfree[idx2].offset--;
> + layout->oobfree[idx2].length = 5;
> + } else {
> + layout->oobfree[idx2].offset = i * sas;
> + layout->oobfree[idx2].length = 6;
> + }
> + idx2++;
> + layout->eccpos[idx1++] = i * sas + 6;
> + layout->eccpos[idx1++] = i * sas + 7;
> + layout->eccpos[idx1++] = i * sas + 8;
> + layout->oobfree[idx2].offset = i * sas + 9;
> + layout->oobfree[idx2].length = 7;
> + idx2++;
> + /* Leave zero-terminated entry for OOBFREE */
> + if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
> + idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
> + break;
> }
> - }
> -
> - return 0;
> -}
> -
> -static const struct mtd_ooblayout_ops brcmnand_hamming_ooblayout_ops = {
> - .ecc = brcmnand_hamming_ooblayout_ecc,
> - .free = brcmnand_hamming_ooblayout_free,
> -};
> -
> -static int brcmnand_bch_ooblayout_ecc(struct mtd_info *mtd, int section,
> - struct mtd_oob_region *oobregion)
> -{
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - struct brcmnand_host *host = nand_get_controller_data(chip);
> - struct brcmnand_cfg *cfg = &host->hwcfg;
> - int sas = cfg->spare_area_size << cfg->sector_size_1k;
> - int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
> -
> - if (section >= sectors)
> - return -ERANGE;
> 
> - oobregion->offset = (section * (sas + 1)) - chip->ecc.bytes;
> - oobregion->length = chip->ecc.bytes;
> -
> - return 0;
> -}
> -
> -static int brcmnand_bch_ooblayout_free_lp(struct mtd_info *mtd, int section,
> - struct mtd_oob_region *oobregion)
> -{
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - struct brcmnand_host *host = nand_get_controller_data(chip);
> - struct brcmnand_cfg *cfg = &host->hwcfg;
> - int sas = cfg->spare_area_size << cfg->sector_size_1k;
> - int sectors = cfg->page_size / (512 << cfg->sector_size_1k);
> -
> - if (section >= sectors)
> - return -ERANGE;
> -
> - if (sas <= chip->ecc.bytes)
> - return 0;
> -
> - oobregion->offset = section * sas;
> - oobregion->length = sas - chip->ecc.bytes;
> -
> - if (!section) {
> - oobregion->offset++;
> - oobregion->length--;
> + return layout;
> }
> 
> - return 0;
> -}
> -
> -static int brcmnand_bch_ooblayout_free_sp(struct mtd_info *mtd, int section,
> - struct mtd_oob_region *oobregion)
> -{
> - struct nand_chip *chip = mtd_to_nand(mtd);
> - struct brcmnand_host *host = nand_get_controller_data(chip);
> - struct brcmnand_cfg *cfg = &host->hwcfg;
> - int sas = cfg->spare_area_size << cfg->sector_size_1k;
> + /*
> + * CONTROLLER_VERSION:
> + * < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
> + * >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
> + * But we will just be conservative.
> + */
> + req = DIV_ROUND_UP(ecc_level * 14, 8);
> + if (req >= sas) {
> + dev_err(&host->pdev->dev,
> + "error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
> + req, sas);
> + return NULL;
> + }
> 
> - if (section > 1 || sas - chip->ecc.bytes < 6 ||
> - (section && sas - chip->ecc.bytes == 6))
> - return -ERANGE;
> + layout->eccbytes = req * sectors;
> + for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
> + for (j = sas - req; j < sas && idx1 <
> + MTD_MAX_ECCPOS_ENTRIES_LARGE; j++, idx1++)
> + layout->eccpos[idx1] = i * sas + j;
> 
> - if (!section) {
> - oobregion->offset = 0;
> - oobregion->length = 5;
> - } else {
> - oobregion->offset = 6;
> - oobregion->length = sas - chip->ecc.bytes - 6;
> + /* First sector of each page may have BBI */
> + if (i == 0) {
> + if (cfg->page_size == 512 && (sas - req >= 6)) {
> + /* Small-page NAND use byte 6 for BBI */
> + layout->oobfree[idx2].offset = 0;
> + layout->oobfree[idx2].length = 5;
> + idx2++;
> + if (sas - req > 6) {
> + layout->oobfree[idx2].offset = 6;
> + layout->oobfree[idx2].length =
> + sas - req - 6;
> + idx2++;
> + }
> + } else if (sas > req + 1) {
> + layout->oobfree[idx2].offset = i * sas + 1;
> + layout->oobfree[idx2].length = sas - req - 1;
> + idx2++;
> + }
> + } else if (sas > req) {
> + layout->oobfree[idx2].offset = i * sas;
> + layout->oobfree[idx2].length = sas - req;
> + idx2++;
> + }
> + /* Leave zero-terminated entry for OOBFREE */
> + if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
> + idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
> + break;
> }
> 
> - return 0;
> + return layout;
> }
> 
> -static const struct mtd_ooblayout_ops brcmnand_bch_lp_ooblayout_ops = {
> - .ecc = brcmnand_bch_ooblayout_ecc,
> - .free = brcmnand_bch_ooblayout_free_lp,
> -};
> -
> -static const struct mtd_ooblayout_ops brcmnand_bch_sp_ooblayout_ops = {
> - .ecc = brcmnand_bch_ooblayout_ecc,
> - .free = brcmnand_bch_ooblayout_free_sp,
> -};
> -
> -static int brcmstb_choose_ecc_layout(struct brcmnand_host *host)
> +static struct nand_ecclayout *brcmstb_choose_ecc_layout(
> + struct brcmnand_host *host)
> {
> + struct nand_ecclayout *layout;
> struct brcmnand_cfg *p = &host->hwcfg;
> - struct mtd_info *mtd = nand_to_mtd(&host->chip);
> - struct nand_ecc_ctrl *ecc = &host->chip.ecc;
> unsigned int ecc_level = p->ecc_level;
> - int sas = p->spare_area_size << p->sector_size_1k;
> - int sectors = p->page_size / (512 << p->sector_size_1k);
> 
> if (p->sector_size_1k)
> ecc_level <<= 1;
> 
> - if (is_hamming_ecc(host->ctrl, p)) {
> - ecc->bytes = 3 * sectors;
> - mtd_set_ooblayout(mtd, &brcmnand_hamming_ooblayout_ops);
> - return 0;
> - }
> -
> - /*
> - * CONTROLLER_VERSION:
> - * < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
> - * >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
> - * But we will just be conservative.
> - */
> - ecc->bytes = DIV_ROUND_UP(ecc_level * 14, 8);
> - if (p->page_size == 512)
> - mtd_set_ooblayout(mtd, &brcmnand_bch_sp_ooblayout_ops);
> - else
> - mtd_set_ooblayout(mtd, &brcmnand_bch_lp_ooblayout_ops);
> -
> - if (ecc->bytes >= sas) {
> + layout = brcmnand_create_layout(ecc_level, host);
> + if (!layout) {
> dev_err(&host->pdev->dev,
> - "error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
> - ecc->bytes, sas);
> - return -EINVAL;
> + "no proper ecc_layout for this NAND cfg\n");
> + return NULL;
> }
> 
> - return 0;
> + return layout;
> }
> 
> static void brcmnand_wp(struct mtd_info *mtd, int wp)
> @@ -2383,9 +2331,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host,
> ofnode dn)
> /* only use our internal HW threshold */
> mtd->bitflip_threshold = 1;
> 
> - ret = brcmstb_choose_ecc_layout(host);
> - if (ret)
> - return ret;
> + chip->ecc.layout = brcmstb_choose_ecc_layout(host);
> + if (!chip->ecc.layout)
> + return -ENXIO;
> 
> ret = nand_scan_tail(mtd);
> if (ret)
> --
> 2.18.0

  reply	other threads:[~2019-09-05 12:46 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-09-04 17:51 [U-Boot] [PATCH] drivers: nand: brcmnand: fix nand_chip ecc layout structure William Zhang
2019-09-05 12:46 ` Philippe REYNES [this message]
2019-10-18 11:36 ` Daniel Schwierzeck
2019-10-20 23:40   ` William Zhang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=959468415.910920.1567687588359.JavaMail.zimbra@softathome.com \
    --to=philippe.reynes@softathome.com \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.