Re: [U-Boot] [RFC 04/11] mtd/nand: add page status table (pst)

2015-06-14 Thread Boris Brezillon
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)

2015-06-05 Thread Roy Spliet
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