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