On Fri,  5 Jun 2015 13:52:37 +0200
Roy Spliet <r.spl...@ultimaker.com> wrote:

Ditto (this work hasn't been accepted in Linux).

> From: yassin <yassinjaf...@gmail.com>
> 
> Signed-off-by: Roy Spliet <r.spl...@ultimaker.com>
> ---
>  drivers/mtd/nand/nand_base.c | 154 
> +++++++++++++++++++++++++++++++++++++++++++
>  include/linux/mtd/nand.h     |  21 ++++++
>  2 files changed, 175 insertions(+)
> 
> diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
> index dbeb092..1c514a0 100644
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
> @@ -1185,6 +1185,138 @@ EXPORT_SYMBOL(nand_lock);
>  #endif
>  
>  /**
> + * nand_page_is_empty - check wether a NAND page contains only FFs
> + * @mtd:     mtd info
> + * @data:    data buffer
> + * @oob:     oob buffer
> + *
> + * Reads the data stored in the databuf buffer and check if it contains only
> + * FFs.
> + *
> + * Return true if it does else return false.
> + */
> +bool nand_page_is_empty(struct mtd_info *mtd, void *data, void *oob)
> +{
> +     u8 *buf;
> +     int length;
> +     u32 pattern = 0xffffffff;
> +     int bitflips = 0;
> +     int cnt;
> +
> +     buf = data;
> +     length = mtd->writesize;
> +     while (length) {
> +             cnt = length < sizeof(pattern) ? length : sizeof(pattern);
> +             if (memcmp(&pattern, buf, cnt)) {
> +                     int i;
> +                     for (i = 0; i < cnt * 8; i++) {
> +                             if (!(buf[i / 8] &
> +                                   (1 << (i % 8)))) {
> +                                     bitflips++;
> +                                     if (bitflips > mtd->ecc_strength)
> +                                             return false;
> +                             }
> +                     }
> +             }
> +
> +             buf += sizeof(pattern);
> +             length -= sizeof(pattern);
> +     }
> +
> +     buf = oob;
> +     length = mtd->oobsize;
> +     while (length) {
> +             cnt = length < sizeof(pattern) ? length : sizeof(pattern);
> +             if (memcmp(&pattern, buf, cnt)) {
> +                     int i;
> +                     for (i = 0; i < cnt * 8; i++) {
> +                             if (!(buf[i / 8] &
> +                                   (1 << (i % 8)))) {
> +                                     bitflips++;
> +                                     if (bitflips > mtd->ecc_strength)
> +                                             return false;
> +                             }
> +                     }
> +             }
> +
> +             buf += sizeof(pattern);
> +             length -= sizeof(pattern);
> +     }
> +
> +     return true;
> +}
> +EXPORT_SYMBOL(nand_page_is_empty);
> +
> +/**
> + * nand_page_get_status - retrieve page status from the page status table 
> (pst)
> + * @mtd:     mtd info
> + * @page:    page you want to get status on
> + *
> + * Return the page status.
> + */
> +int nand_page_get_status(struct mtd_info *mtd, int page)
> +{
> +     struct nand_chip *chip = mtd->priv;
> +     u8 shift = (page % 4) * 2;
> +     uint64_t offset = page / 4;
> +     int ret = NAND_PAGE_STATUS_UNKNOWN;
> +
> +     if (chip->pst)
> +             ret = (chip->pst[offset] >> shift) & 0x3;
> +
> +     return ret;
> +}
> +EXPORT_SYMBOL(nand_page_get_status);
> +
> +/**
> + * nand_page_set_status - assign page status from in the page status table
> + * @mtd:     mtd info
> + * @page:    page you want to get status on
> + * @status:  new status to assign
> + */
> +void nand_page_set_status(struct mtd_info *mtd, int page,
> +                       enum nand_page_status status)
> +{
> +     struct nand_chip *chip = mtd->priv;
> +     u8 shift;
> +     uint64_t offset;
> +
> +     if (!chip->pst)
> +             return;
> +
> +     shift = (page % 4) * 2;
> +     offset = page / 4;
> +     chip->pst[offset] &= ~(0x3 << shift);
> +     chip->pst[offset] |= (status & 0x3) << shift;
> +}
> +EXPORT_SYMBOL(nand_page_set_status);
> +
> +/**
> + * nand_pst_create - create a page status table
> + * @mtd:     mtd info
> + *
> + * Allocate a page status table and assign it to the mtd device.
> + *
> + * Returns 0 in case of success or -ERRNO in case of error.
> + */
> +int nand_pst_create(struct mtd_info *mtd)
> +{
> +     struct nand_chip *chip = mtd->priv;
> +
> +     if (chip->pst)
> +             return 0;
> +
> +     chip->pst = kzalloc(mtd->size >>
> +                         (chip->page_shift + mtd->subpage_sft + 2),
> +                         GFP_KERNEL);
> +     if (!chip->pst)
> +             return -ENOMEM;
> +
> +     return 0;
> +}
> +EXPORT_SYMBOL(nand_pst_create);
> +
> +/**
>   * nand_read_page_raw - [INTERN] read raw page data without ecc
>   * @mtd: mtd info structure
>   * @chip: nand chip info structure
> @@ -2521,6 +2653,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, 
> loff_t to,
>               int bytes = mtd->writesize;
>               int cached = writelen > bytes && page != blockmask;
>               uint8_t *wbuf = buf;
> +             int subpage;
>  
>               WATCHDOG_RESET();
>               /* Partial page write? */
> @@ -2547,6 +2680,14 @@ static int nand_do_write_ops(struct mtd_info *mtd, 
> loff_t to,
>               if (ret)
>                       break;
>  
> +             for (subpage = column / chip->subpagesize;
> +                  subpage < (column + writelen) / chip->subpagesize;
> +                  subpage++)
> +                     nand_page_set_status(mtd,
> +                                          (page << mtd->subpage_sft) +
> +                                          subpage,
> +                                          NAND_PAGE_FILLED);
> +
>               writelen -= bytes;
>               if (!writelen)
>                       break;
> @@ -2804,6 +2945,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct 
> erase_info *instr,
>       int page, status, pages_per_block, ret, chipnr;
>       struct nand_chip *chip = mtd->priv;
>       loff_t len;
> +     int i;
>  
>       pr_debug("%s: start = 0x%012llx, len = %llu\n",
>                       __func__, (unsigned long long)instr->addr,
> @@ -2880,6 +3022,18 @@ int nand_erase_nand(struct mtd_info *mtd, struct 
> erase_info *instr,
>                       goto erase_exit;
>               }
>  
> +             for (i = 0; i < pages_per_block; i++) {
> +                     int subpage;
> +                     for (subpage = 0;
> +                          subpage < 1 << mtd->subpage_sft;
> +                          subpage++) {
> +                             nand_page_set_status(mtd,
> +                                     ((page + i) << mtd->subpage_sft) +
> +                                     subpage,
> +                                     NAND_PAGE_EMPTY);
> +                     }
> +             }
> +
>               /* Increment page address and decrement length */
>               len -= (1ULL << chip->phys_erase_shift);
>               page += pages_per_block;
> diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
> index 0cdb3b9..ef6a783 100644
> --- a/include/linux/mtd/nand.h
> +++ b/include/linux/mtd/nand.h
> @@ -547,6 +547,24 @@ struct nand_ecc_ctrl {
>                       int page);
>  };
>  
> +/*
> + * Constants for page status
> + */
> +enum nand_page_status {
> +     NAND_PAGE_STATUS_UNKNOWN,
> +     NAND_PAGE_EMPTY,
> +     NAND_PAGE_FILLED,
> +};
> +
> +bool nand_page_is_empty(struct mtd_info *mtd, void *data, void *oob);
> +
> +int nand_page_get_status(struct mtd_info *mtd, int page);
> +
> +void nand_page_set_status(struct mtd_info *mtd, int page,
> +                       enum nand_page_status status);
> +
> +int nand_pst_create(struct mtd_info *mtd);
> +
>  /**
>   * struct nand_buffers - buffer structure for read/write
>   * @ecccalc: buffer pointer for calculated ECC, size is oobsize.
> @@ -660,6 +678,7 @@ struct nand_buffers {
>   * @bbt_md:          [REPLACEABLE] bad block table mirror descriptor
>   * @badblock_pattern:        [REPLACEABLE] bad block scan pattern used for 
> initial
>   *                   bad block scan.
> + * @pst:             [INTERN] page status table
>   * @controller:              [REPLACEABLE] a pointer to a hardware controller
>   *                   structure which is shared among multiple independent
>   *                   devices.
> @@ -750,6 +769,8 @@ struct nand_chip {
>  
>       struct nand_bbt_descr *badblock_pattern;
>  
> +     uint8_t *pst;
> +
>       void *priv;
>  };
>  



-- 
Boris Brezillon, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to