Re: [U-Boot] [RFC 04/11] mtd/nand: add page status table (pst)
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 = 0x; + 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
[U-Boot] [RFC 04/11] mtd/nand: add page status table (pst)
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 = 0x; + 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