Hi Lee,

On Wed, Aug 27, 2014 at 01:42:24PM +0100, Lee Jones wrote:
> This is the BBT format ST use internally.  It has to be used on boards
> which were flashed with or actively use ST's tooling and boards which
> are booted using ST's bootloaders.
> 
> Signed-off-by: Lee Jones <lee.jo...@linaro.org>
> ---
>  drivers/mtd/nand/Kconfig        |   8 +
>  drivers/mtd/nand/Makefile       |   1 +
>  drivers/mtd/nand/stm_nand_bbt.c | 601 
> ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 610 insertions(+)
>  create mode 100644 drivers/mtd/nand/stm_nand_bbt.c
> 
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 2738eec..5c04ec1 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -520,4 +520,12 @@ config MTD_NAND_STM_BCH
>       help
>         Adds support for the STMicroelectronics NANDi BCH Controller.
>  
> +config MTD_NAND_STM_BCH_BBT
> +     tristate "STMicroelectronics: NANDi BCH Controller Bad Block Table 
> support"
> +     default MTD_NAND_STM_BCH
> +     help
> +       Adds support for the STMicroelectronics Bad Block Table support.
> +       If you are using a device which has has already been initialised
> +       by ST or using their tooling/bootloaders, leave this enabled.
> +
>  endif # MTD_NAND
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index 60f374b..5ef0462 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -47,6 +47,7 @@ obj-$(CONFIG_MTD_NAND_MPC5121_NFC)  += mpc5121_nfc.o
>  obj-$(CONFIG_MTD_NAND_RICOH)         += r852.o
>  obj-$(CONFIG_MTD_NAND_JZ4740)                += jz4740_nand.o
>  obj-$(CONFIG_MTD_NAND_STM_BCH)               += stm_nand_bch.o stm_nand_dt.o
> +obj-$(CONFIG_MTD_NAND_STM_BCH_BBT)   += stm_nand_bbt.o
>  obj-$(CONFIG_MTD_NAND_GPMI_NAND)     += gpmi-nand/
>  obj-$(CONFIG_MTD_NAND_XWAY)          += xway_nand.o
>  obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
> diff --git a/drivers/mtd/nand/stm_nand_bbt.c b/drivers/mtd/nand/stm_nand_bbt.c
> new file mode 100644
> index 0000000..242bffd
> --- /dev/null
> +++ b/drivers/mtd/nand/stm_nand_bbt.c
> @@ -0,0 +1,601 @@
> +/*
> + * Support for STMicroelectronics Bad Block Table (BBT)
> + *
> + * Copyright (c) 2014 STMicroelectronics Limited
> + *
> + * Authors: Angus Clark <angus.cl...@st.com>
> + *       Lee Jones <lee.jo...@linaro.org>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */

Can you provide some sort of prose summary of your BBT format? Maybe
here at the top of the file, like with nand_bbt.c. Or a separate doc in
Documentation/mtd/nand/, if you think that's more appropriate.

> +
> +#include <linux/mtd/stm_nand.h>
> +#include <linux/mtd/stm_nand_bbt.h>
> +#include <generated/utsrelease.h>
> +
> +/*
> + * Inband Bad Block Table (IBBT)
> + */
> +#define NAND_IBBT_NBLOCKS    4
> +#define NAND_IBBT_SIGLEN     4
> +#define NAND_IBBT_PRIMARY    0
> +#define NAND_IBBT_MIRROR     1
> +#define NAND_IBBT_SCHEMA     0x10
> +#define NAND_IBBT_BCH_SCHEMA 0x10
> +
> +static uint8_t ibbt_sigs[2][NAND_IBBT_SIGLEN] = {
> +     {'B', 'b', 't', '0'},
> +     {'1', 't', 'b', 'B'},
> +};
> +
> +static char *bbt_strs[] = {
> +     "primary",
> +     "mirror",
> +};
> +
> +/* IBBT header */
> +struct nand_ibbt_header {
> +     uint8_t signature[4];           /* "Bbt0" or "1tbB" signature */
> +     uint8_t version;                /* BBT version ("age") */
> +     uint8_t reserved[3];            /* padding */
> +     uint8_t schema[4];              /* "base" schema (x4) */
> +} __packed;
> +
> +/* Extend IBBT header with some stm-nand-bch niceties */
> +struct nand_ibbt_bch_header {
> +     struct nand_ibbt_header base;
> +     uint8_t schema[4];              /* "private" schema (x4) */
> +     uint8_t ecc_size[4];            /* ECC bytes (0, 32, 54) (x4) */
> +     char    author[64];             /* Arbitrary string for S/W to use */
> +} __packed;
> +
> +/*
> + * Bad Block Tables/Bad Block Markers
> + */
> +#define BBT_MARK_BAD_FACTORY 0x0
> +#define BBT_MARK_BAD_WEAR    0x1
> +#define BBT_MARK_GOOD                0x3
> +
> +static void bbt_set_block_mark(uint8_t *bbt, uint32_t block, uint8_t mark)
> +{
> +     unsigned int byte = block >> 2;
> +     unsigned int shift = (block & 0x3) << 1;
> +
> +     bbt[byte] &= ~(0x3 << shift);
> +     bbt[byte] |= ((mark & 0x3) << shift);
> +}
> +
> +static uint8_t bbt_get_block_mark(uint8_t *bbt, uint32_t block)
> +{
> +     unsigned int byte = block >> 2;
> +     unsigned int shift = (block & 0x3) << 1;
> +
> +     return (bbt[byte] >> shift) & 0x3;
> +}
> +
> +static int bbt_is_block_bad(uint8_t *bbt, uint32_t block)
> +{
> +     return bbt_get_block_mark(bbt, block) == BBT_MARK_GOOD ? 0 : 1;
> +}
> +
> +/* Scan page for BBM(s), according to specified BBT options */
> +static int nandi_scan_bad_block_markers_page(struct nandi_controller *nandi,
> +                                          uint32_t page)
> +{
> +     struct mtd_info *mtd = &nandi->info.mtd;
> +     struct nand_chip *chip = mtd->priv;
> +     uint8_t *oob_buf = nandi->oob_buf;
> +     int i, e;
> +
> +     /* Read the OOB area */
> +     flex_read_raw(nandi, page, mtd->writesize, oob_buf, mtd->oobsize);
> +
> +     if (oob_buf[chip->badblockpos] == 0xff)
> +             return 0;
> +
> +     /* Tolerate 'alien' Hamming Boot Mode ECC */
> +     e = 0;
> +     for (i = 0; i < mtd->oobsize; i += 16)
> +             e += hweight8(oob_buf[i + 3] ^ 'B');
> +     if (e <= 1)
> +             return 0;
> +
> +     /* Tolerate 'alien' Hamming AFM ECC */
> +     e = 0;
> +     for (i = 0; i < mtd->oobsize; i += 16) {
> +             e += hweight8(oob_buf[i + 3] ^ 'A');
> +             e += hweight8(oob_buf[i + 4] ^ 'F');
> +             e += hweight8(oob_buf[i + 5] ^ 'M');
> +             if (e <= 1)
> +                     return 0;
> +     }
> +
> +     return 1;
> +}
> +
> +/* Scan block for BBM(s), according to specified BBT options */
> +static int nandi_scan_bad_block_markers_block(struct nandi_controller *nandi,
> +                                           uint32_t block)
> +
> +{
> +     struct mtd_info *mtd = &nandi->info.mtd;
> +     struct nand_chip *chip = mtd->priv;
> +     uint32_t pages_per_block = mtd->erasesize >> chip->page_shift;
> +     uint32_t page = block << (chip->phys_erase_shift - chip->page_shift);
> +
> +     if (nandi_scan_bad_block_markers_page(nandi, page))
> +             return 1;
> +
> +     if ((chip->bbt_options & NAND_BBT_SCAN2NDPAGE) &&
> +         nandi_scan_bad_block_markers_page(nandi, page + 1))
> +             return 1;
> +
> +     if ((chip->bbt_options & NAND_BBT_SCANLASTPAGE) &&
> +         nandi_scan_bad_block_markers_page(nandi,
> +                                           page + pages_per_block - 1))
> +             return 1;
> +
> +     return 0;
> +}
> +
> +/* Scan for BBMs and build memory-resident BBT */
> +static int nandi_scan_build_bbt(struct nandi_controller *nandi,
> +                             struct nandi_bbt_info *bbt_info)
> +{
> +     struct mtd_info *mtd = &nandi->info.mtd;
> +     struct nand_chip *chip = mtd->priv;
> +     uint32_t page_size = mtd->writesize;
> +     uint8_t *bbt = bbt_info->bbt;
> +     uint32_t block;
> +
> +     dev_dbg(nandi->dev,
> +             "scan device for bad-block markers [bbt options = 0x%02x]\n",
> +             chip->bbt_options);
> +
> +     memset(bbt, 0xff, page_size);
> +     bbt_info->bbt_vers[0] = 0;
> +     bbt_info->bbt_vers[1] = 0;
> +     bbt_info->bbt_block[0] = nandi->blocks_per_device - 1;
> +     bbt_info->bbt_block[1] = nandi->blocks_per_device - 2;
> +
> +     for (block = 0; block < nandi->blocks_per_device; block++)
> +             if (nandi_scan_bad_block_markers_block(nandi, block))
> +                     bbt_set_block_mark(bbt, block, BBT_MARK_BAD_FACTORY);
> +
> +     return 0;
> +}
> +
> +/* Populate IBBT BCH Header */
> +static void bch_fill_ibbt_header(struct nandi_controller *nandi,
> +                              struct nand_ibbt_bch_header *ibbt_header,
> +                              int bak, uint8_t vers)
> +{
> +     const char author[] = "STLinux " UTS_RELEASE " (stm-nand-bch)";
> +
> +     memcpy(ibbt_header->base.signature, ibbt_sigs[bak], NAND_IBBT_SIGLEN);
> +     ibbt_header->base.version = vers;
> +     memset(ibbt_header->base.schema, NAND_IBBT_SCHEMA, 4);
> +
> +     memset(ibbt_header->schema, NAND_IBBT_SCHEMA, 4);
> +     memset(ibbt_header->ecc_size, bch_ecc_sizes[nandi->bch_ecc_mode], 4);
> +     memcpy(ibbt_header->author, author, sizeof(author));
> +}
> +
> +/* Write IBBT to Flash */
> +static int bch_write_bbt_data(struct nandi_controller *nandi,
> +                           struct nandi_bbt_info *bbt_info,
> +                           uint32_t block, int bak, uint8_t vers)
> +{
> +     struct nand_ibbt_bch_header *ibbt_header =
> +             (struct nand_ibbt_bch_header *)nandi->page_buf;
> +     struct nand_chip *chip = &nandi->info.chip;
> +     struct mtd_info *mtd = &nandi->info.mtd;
> +     uint32_t page_size = mtd->writesize;
> +     uint32_t block_size = mtd->erasesize;
> +     loff_t offs;
> +     size_t retlen;
> +     int ret;
> +
> +     nandi->cached_page = -1;
> +
> +     /* Write BBT contents to first page of block */
> +     offs = (loff_t)block << chip->phys_erase_shift;
> +     ret = mtd_write(mtd, offs, page_size, &retlen, bbt_info->bbt);
> +     if (ret)
> +             return ret;
> +
> +     /* Update IBBT header and write to last page of block */
> +     memset(ibbt_header, 0xff, mtd->writesize);
> +     bch_fill_ibbt_header(nandi, ibbt_header, bak, vers);
> +     offs += block_size - page_size;
> +     ret = mtd_write(mtd, offs, sizeof(*ibbt_header), &retlen,
> +                          (uint8_t *)ibbt_header);
> +     return ret;
> +}
> +
> +/*
> + * Update Flash-resident BBT:
> + *   erase/search suitable block, and write table data to Flash
> + */
> +static int bch_update_bbt(struct nandi_controller *nandi,
> +                      struct nandi_bbt_info *bbt_info,
> +                      int bak, uint8_t vers)
> +{
> +     struct nand_chip *chip = &nandi->info.chip;
> +     loff_t offs;
> +     uint32_t block;
> +     uint32_t block_lower;
> +     uint32_t block_other;
> +
> +     block_other = bbt_info->bbt_block[(bak+1)%2];
> +     block_lower = nandi->blocks_per_device - NAND_IBBT_NBLOCKS;
> +
> +     for (block = bbt_info->bbt_block[bak]; block >= block_lower;  block--) {
> +             offs = (loff_t)block << chip->phys_erase_shift;
> +
> +             /* Skip if block used by other table */
> +             if (block == block_other)
> +                     continue;
> +
> +             /* Skip if block is marked bad */
> +             if (bbt_is_block_bad(bbt_info->bbt, block))
> +                     continue;
> +
> +             /* Erase block, mark bad and skip on failure */
> +             if (bch_erase_block(nandi, offs) & NAND_STATUS_FAIL) {
> +                     dev_info(nandi->dev,
> +                              "failed to erase block [%u:0x%012llx] while 
> updating BBT\n",
> +                              block, offs);
> +                     vers++;
> +                     bbt_set_block_mark(bbt_info->bbt, block,
> +                                        BBT_MARK_BAD_WEAR);
> +                     continue;
> +             }
> +
> +             /* Write BBT, mark bad and skip on failure */
> +             if (bch_write_bbt_data(nandi, bbt_info, block, bak, vers)) {
> +                     dev_info(nandi->dev,
> +                              "failed to write BBT to block 
> [%u:0x%012llx]\n",
> +                              block, offs);
> +                     vers++;
> +                     bbt_set_block_mark(bbt_info->bbt, block,
> +                                        BBT_MARK_BAD_WEAR);
> +                     continue;
> +             }
> +
> +             /* Success */
> +             bbt_info->bbt_block[bak] = block;
> +             bbt_info->bbt_vers[bak] = vers;
> +             break;
> +     }
> +
> +     /* No space in BBT area */
> +     if (block < block_lower) {
> +             dev_err(nandi->dev, "no space left in BBT area\n");
> +             dev_err(nandi->dev, "failed to update %s BBT\n", bbt_strs[bak]);
> +             return -ENOSPC;
> +     }
> +
> +     dev_info(nandi->dev, "wrote BBT [%s:%u] at 0x%012llx [%u]\n",
> +              bbt_strs[bak], vers, offs, block);
> +
> +     return 0;
> +}
> +
> +#define NAND_IBBT_UPDATE_PRIMARY     0x1
> +#define NAND_IBBT_UPDATE_MIRROR              0x2
> +#define NAND_IBBT_UPDATE_BOTH                (NAND_IBBT_UPDATE_PRIMARY | \
> +                                      NAND_IBBT_UPDATE_MIRROR)
> +static char *bbt_update_strs[] = {
> +     "",
> +     "primary",
> +     "mirror",
> +     "both",
> +};
> +
> +/*
> + * Update Flash-resident BBT(s):
> + *   incrementing 'vers' number if required, and ensuring Primary
> + *   and Mirror are kept in sync
> + */
> +static int bch_update_bbts(struct nandi_controller *nandi,
> +                        struct nandi_bbt_info *bbt_info,
> +                        unsigned int update, uint8_t vers)
> +{
> +     int err;
> +
> +     dev_info(nandi->dev, "updating %s BBT(s)\n", bbt_update_strs[update]);
> +
> +     do {
> +             /* Update Primary if specified */
> +             if (update & NAND_IBBT_UPDATE_PRIMARY) {
> +                     err = bch_update_bbt(nandi, bbt_info, NAND_IBBT_PRIMARY,
> +                                          vers);
> +                     /* Bail out on error (e.g. no space left in BBT area) */
> +                     if (err)
> +                             return err;
> +
> +                     /*
> +                      * If update resulted in a new BBT version
> +                      * (e.g. Erase/Write fail on BBT block) update version
> +                      * here, and force update of other table.
> +                      */
> +                     if (bbt_info->bbt_vers[NAND_IBBT_PRIMARY] != vers) {
> +                             vers = bbt_info->bbt_vers[NAND_IBBT_PRIMARY];
> +                             update = NAND_IBBT_UPDATE_MIRROR;
> +                     }
> +             }
> +
> +             /* Update Mirror if specified */
> +             if (update & NAND_IBBT_UPDATE_MIRROR) {
> +                     err = bch_update_bbt(nandi, bbt_info, NAND_IBBT_MIRROR,
> +                                          vers);
> +                     /* Bail out on error (e.g. no space left in BBT area) */
> +                     if (err)
> +                             return err;
> +
> +                     /*
> +                      * If update resulted in a new BBT version
> +                      * (e.g. Erase/Write fail on BBT block) update version
> +                      * here, and force update of other table.
> +                      */
> +                     if (bbt_info->bbt_vers[NAND_IBBT_MIRROR] != vers) {
> +                             vers = bbt_info->bbt_vers[NAND_IBBT_MIRROR];
> +                             update = NAND_IBBT_UPDATE_PRIMARY;
> +                     }
> +             }
> +
> +             /* Continue, until Primary and Mirror versions are in sync */
> +     } while (bbt_info->bbt_vers[NAND_IBBT_PRIMARY] !=
> +              bbt_info->bbt_vers[NAND_IBBT_MIRROR]);
> +
> +     return 0;
> +}
> +
> +/* Scan block for IBBT signature */
> +static int bch_find_ibbt_sig(struct nandi_controller *nandi,
> +                          uint32_t block, int *bak, uint8_t *vers,
> +                          char *author)
> +{
> +     struct nand_chip *chip = &nandi->info.chip;
> +     struct mtd_info *mtd = &nandi->info.mtd;
> +     struct nand_ibbt_bch_header *ibbt_header;
> +     loff_t offs;
> +     uint8_t *buf = nandi->page_buf;
> +     int match_sig;
> +     unsigned int b;
> +     unsigned int i;
> +     size_t retlen;
> +     int ret;
> +
> +     nandi->cached_page = -1;
> +
> +     /* Load last page of block */
> +     offs = (loff_t)block << chip->phys_erase_shift;
> +     offs += mtd->erasesize - mtd->writesize;
> +     ret = mtd_read(mtd, offs, sizeof(*ibbt_header), &retlen, buf);
> +     if (ret < 0) {
> +             dev_info(nandi->dev,
> +                      "Uncorrectable ECC error while scanning BBT signature 
> at block %u [0x%012llx]\n",
> +                      block, offs);
> +             return 0;
> +     }
> +     ibbt_header = (struct nand_ibbt_bch_header *)buf;
> +
> +     /* Test IBBT signature */
> +     match_sig = 0;
> +     for (b = 0; b < 2 && !match_sig; b++) {
> +             match_sig = 1;
> +             for (i = 0; i < NAND_IBBT_SIGLEN; i++) {
> +                     if (ibbt_header->base.signature[i] != ibbt_sigs[b][i]) {
> +                             match_sig = 0;
> +                             break;
> +                     }
> +             }
> +
> +     }
> +
> +     if (!match_sig)
> +             return 0; /* Failed to match IBBT signature */
> +
> +     /* Test IBBT schema */
> +     for (i = 0; i < 4; i++)
> +             if (ibbt_header->base.schema[i] != NAND_IBBT_SCHEMA)
> +                     return 0;
> +
> +     /* Test IBBT BCH schema */
> +     for (i = 0; i < 4; i++)
> +             if (ibbt_header->schema[i] != NAND_IBBT_BCH_SCHEMA)
> +                     return 0;
> +
> +     /* We have a match */
> +     *vers = ibbt_header->base.version;
> +     *bak = b - 1;
> +     strncpy(author, ibbt_header->author, 64);
> +
> +     return 1;
> +}
> +
> +/* Search for and load Flash-resident BBT, updating Primary/Mirror if req'd 
> */
> +static int bch_load_bbt(struct nandi_controller *nandi,
> +                     struct nandi_bbt_info *bbt_info)
> +{
> +     struct nand_chip *chip = &nandi->info.chip;
> +     struct mtd_info *mtd = &nandi->info.mtd;
> +     uint32_t page_size = mtd->writesize;
> +     unsigned int update = 0;
> +     uint32_t block;
> +     loff_t offs;
> +     uint8_t vers;
> +     char author[64];
> +     size_t retlen;
> +     int ret;
> +     int bak;
> +
> +     dev_dbg(nandi->dev, "looking for Flash-resident BBTs\n");
> +
> +     bbt_info->bbt_block[0] = 0;
> +     bbt_info->bbt_block[1] = 0;
> +     bbt_info->bbt_vers[0] = 0;
> +     bbt_info->bbt_vers[1] = 0;
> +
> +     /* Look for IBBT signatures */
> +     for (block = nandi->blocks_per_device - NAND_IBBT_NBLOCKS;
> +          block < nandi->blocks_per_device;
> +          block++) {
> +             offs = (loff_t)block << chip->phys_erase_shift;
> +
> +             if (bch_find_ibbt_sig(nandi, block, &bak, &vers, author)) {
> +                     dev_dbg(nandi->dev,
> +                             "found BBT [%s:%u] at 0x%012llx [%u] (%s)\n",
> +                             bbt_strs[bak], vers, offs, block,
> +                             author);
> +
> +                     if (bbt_info->bbt_block[bak] == 0 ||
> +                         ((int8_t)(bbt_info->bbt_vers[bak] - vers)) < 0) {
> +                             bbt_info->bbt_block[bak] = block;
> +                             bbt_info->bbt_vers[bak] = vers;
> +                     }
> +             }
> +     }
> +
> +     /* What have we found? */
> +     if (bbt_info->bbt_block[0] == 0 && bbt_info->bbt_block[1] == 0) {
> +             /* no primary, no mirror: return error */
> +             return 1;
> +     } else if (bbt_info->bbt_block[0] == 0) {
> +             /* no primary: use mirror, update primary */
> +             bak = 1;
> +             update = NAND_IBBT_UPDATE_PRIMARY;
> +             bbt_info->bbt_block[0] = nandi->blocks_per_device - 1;
> +     } else if (bbt_info->bbt_block[1] == 0) {
> +             /* no mirror: use primary, update mirror */
> +             bak = 0;
> +             update = NAND_IBBT_UPDATE_MIRROR;
> +             bbt_info->bbt_block[1] = nandi->blocks_per_device - 1;
> +     } else if (bbt_info->bbt_vers[0] == bbt_info->bbt_vers[1]) {
> +             /* primary == mirror: use primary, no update required */
> +             bak = 0;
> +     } else if ((int8_t)(bbt_info->bbt_vers[1] -
> +                         bbt_info->bbt_vers[0]) < 0) {
> +             /* primary > mirror: use primary, update mirror */
> +             bak = 0;
> +             update = NAND_IBBT_UPDATE_MIRROR;
> +     } else {
> +             /* mirror > primary: use mirror, update primary */
> +             bak = 1;
> +             update = NAND_IBBT_UPDATE_PRIMARY;
> +     }
> +
> +     vers = bbt_info->bbt_vers[bak];
> +     block = bbt_info->bbt_block[bak];
> +     offs = (loff_t)block << chip->phys_erase_shift;
> +     dev_info(nandi->dev, "using BBT [%s:%u] at 0x%012llx [%u]\n",
> +              bbt_strs[bak], vers, offs, block);
> +
> +     /* Read BBT data */
> +     ret = mtd_read(mtd, offs, page_size, &retlen, bbt_info->bbt);
> +     if (ret < 0) {
> +             dev_err(nandi->dev,
> +                     "error while reading BBT %s:%u] at 0x%012llx [%u]\n",
> +                     bbt_strs[bak], vers, offs, block);
> +             return 1;
> +     }
> +
> +     /* Update other BBT if required */
> +     if (update)
> +             bch_update_bbts(nandi, bbt_info, update, vers);
> +
> +     return 0;
> +}
> +
> +int bch_scan_bbt(struct mtd_info *mtd)
> +{
> +     struct nand_chip *chip = mtd->priv;
> +     struct nandi_controller *nandi = chip->priv;
> +     struct nandi_bbt_info *bbt_info = &nandi->info.bbt_info;
> +     int err;
> +
> +     /* Load Flash-resident BBT */
> +     err = bch_load_bbt(nandi, bbt_info);
> +     if (err) {
> +             dev_warn(nandi->dev,
> +                     "failed to find BBTs:"
> +                     "  scanning device for bad-block markers\n");

checkpatch.pl complains:

WARNING: quoted string split across lines
#580: FILE: drivers/mtd/nand/stm_nand_bbt.c:526:
+                       "failed to find BBTs:"
+                       "  scanning device for bad-block markers\n");

> +
> +             /* Scan, build, and write BBT */
> +             nandi_scan_build_bbt(nandi, bbt_info);
> +             err = bch_update_bbts(nandi, bbt_info, NAND_IBBT_UPDATE_BOTH,
> +                                   bbt_info->bbt_vers[0] + 1);
> +             if (err)
> +                     return err;
> +     }
> +
> +     return 0;
> +}
> +
> +int bch_block_isbad(struct mtd_info *mtd, loff_t offs, int getchip)
> +{
> +     struct nand_chip *chip = mtd->priv;
> +     struct nandi_controller *nandi = chip->priv;
> +
> +     uint32_t block;
> +
> +     /* Check for invalid offset */
> +     if (offs > mtd->size)

Should be >=

> +             return -EINVAL;
> +
> +     block = offs >> chip->phys_erase_shift;
> +
> +     /* Protect blocks reserved for BBTs */
> +     if (block >= (nandi->blocks_per_device - NAND_IBBT_NBLOCKS))
> +             return 1;
> +
> +     return bbt_is_block_bad(nandi->info.bbt_info.bbt, block);
> +}
> +
> +int bch_block_markbad(struct mtd_info *mtd, loff_t offs)
> +{
> +     struct nand_chip *chip = mtd->priv;
> +     struct nandi_controller *nandi = chip->priv;
> +
> +     uint32_t block;
> +     int ret;
> +
> +     /* Mark bad */
> +     block = offs >> chip->phys_erase_shift;
> +     bbt_set_block_mark(nandi->info.bbt_info.bbt, block, BBT_MARK_BAD_WEAR);
> +
> +     /* Update BBTs, incrementing bbt_vers */
> +     ret = bch_update_bbts(nandi, &nandi->info.bbt_info,
> +                           NAND_IBBT_UPDATE_BOTH,
> +                           nandi->info.bbt_info.bbt_vers[0] + 1);
> +
> +     return ret;
> +}
> +
> +void nandi_dump_bad_blocks(struct nandi_controller *nandi)
> +{
> +     struct nand_chip *chip = &nandi->info.chip;
> +     int bad_count = 0;
> +     uint32_t block;
> +     uint8_t *bbt = nandi->info.bbt_info.bbt;
> +     uint8_t mark;
> +
> +     pr_info("BBT:\n");
> +     for (block = 0; block < nandi->blocks_per_device; block++) {
> +             mark = bbt_get_block_mark(bbt, block);
> +             if (mark != BBT_MARK_GOOD) {
> +                     pr_info("\t\tBlock 0x%08x [%05u] marked bad [%s]\n",
> +                             block << chip->phys_erase_shift, block,
> +                             (mark == BBT_MARK_BAD_FACTORY) ?
> +                             "Factory" : "Wear");
> +                     bad_count++;
> +             }
> +     }
> +     if (bad_count == 0)
> +             pr_info("\t\tNo bad blocks listed in BBT\n");
> +}
> +EXPORT_SYMBOL(nandi_dump_bad_blocks);

You're currently allowing this source file to be built as a module. So
you should probably specify some module information (MODULE_AUTHOR(),
MODULE_LICENSE(), MODULE_DESCRIPTION()). Or else maybe you should just
avoid the module issues, and just build all your source files into a
single module, a la nand_base.c + nand_bbt.c = nand.{o,ko}.

Brian
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to