]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
mtd: driver _read() returns max_bitflips; mtd_read() returns -EUCLEAN
authorMike Dunn <mikedunn@newsguy.com>
Wed, 25 Apr 2012 19:06:11 +0000 (12:06 -0700)
committerArtem Bityutskiy <artem.bityutskiy@linux.intel.com>
Sun, 29 Apr 2012 19:22:29 +0000 (22:22 +0300)
The drivers _read() method, absent an error, return a non-negative integer
indicating the maximum number of bit errors that were corrected in any one
region comprising an ecc step.  MTD returns -EUCLEAN if this is >=
bitflip_threshold, 0 otherwise.  If bitflip_threshold is zero, the comparison is
not made since these devices lack ECC and always return zero in the non-error
case (thanks Brian) [1].  Note that this is a subtle change to the driver
interface.

This and the preceeding patches in this set were tested with ubi on top of the
nandsim and docg4 devices, running the ubi test io_basic from mtd-utils.

[1] http://lists.infradead.org/pipermail/linux-mtd/2012-March/040468.html

Signed-off-by: Mike Dunn <mikedunn@newsguy.com>
Signed-off-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
drivers/mtd/devices/docg3.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/alauda.c
drivers/mtd/nand/nand_base.c
drivers/mtd/onenand/onenand_base.c
include/linux/mtd/nand.h

index 34140312ddd4cf83ec19c05f4a877f9163bd66aa..7644d59d72bfc5e2a0abd3820780fb67e0437c04 100644 (file)
@@ -862,6 +862,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
        u8 *buf = ops->datbuf;
        size_t len, ooblen, nbdata, nboob;
        u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
+       int max_bitflips = 0;
 
        if (buf)
                len = ops->len;
@@ -948,7 +949,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
                        }
                        if (ret > 0) {
                                mtd->ecc_stats.corrected += ret;
-                               ret = -EUCLEAN;
+                               max_bitflips = max(max_bitflips, ret);
+                               ret = max_bitflips;
                        }
                }
 
index 6a7cba1e24e61fbff8965744923005e18c835319..b5bb628760d47e6fa8d51a2fc1dc8f55f023a593 100644 (file)
@@ -800,12 +800,24 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
 int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
             u_char *buf)
 {
+       int ret_code;
        *retlen = 0;
        if (from < 0 || from > mtd->size || len > mtd->size - from)
                return -EINVAL;
        if (!len)
                return 0;
-       return mtd->_read(mtd, from, len, retlen, buf);
+
+       /*
+        * In the absence of an error, drivers return a non-negative integer
+        * representing the maximum number of bitflips that were corrected on
+        * any one ecc region (if applicable; zero otherwise).
+        */
+       ret_code = mtd->_read(mtd, from, len, retlen, buf);
+       if (unlikely(ret_code < 0))
+               return ret_code;
+       if (mtd->bitflip_threshold == 0)
+               return 0;       /* device lacks ecc */
+       return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
 }
 EXPORT_SYMBOL_GPL(mtd_read);
 
index ec75d44e0253c3885df7aa90764ead18e027dca9..d518e4db8a0bf8665156fd2383ad40fcde0fe146 100644 (file)
@@ -67,12 +67,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
        stats = part->master->ecc_stats;
        res = part->master->_read(part->master, from + part->offset, len,
                                  retlen, buf);
-       if (unlikely(res)) {
-               if (mtd_is_bitflip(res))
-                       mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected;
-               if (mtd_is_eccerr(res))
-                       mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed;
-       }
+       if (unlikely(mtd_is_eccerr(res)))
+               mtd->ecc_stats.failed +=
+                       part->master->ecc_stats.failed - stats.failed;
+       else
+               mtd->ecc_stats.corrected +=
+                       part->master->ecc_stats.corrected - stats.corrected;
        return res;
 }
 
index 4f20e1d8bef10b43546bd64d51933c0ed010093d..60a0dfdb08087a55311ee7f2e53522ecde7baa17 100644 (file)
@@ -414,7 +414,7 @@ static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
        }
        err = 0;
        if (corrected)
-               err = -EUCLEAN;
+               err = 1;        /* return max_bitflips per ecc step */
        if (uncorrected)
                err = -EBADMSG;
 out:
@@ -446,7 +446,7 @@ static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
        }
        err = 0;
        if (corrected)
-               err = -EUCLEAN;
+               err = 1;        /* return max_bitflips per ecc step */
        if (uncorrected)
                err = -EBADMSG;
        return err;
index 9f5d339a361090b311f7271417417f8b70f02567..640f1f8159e8df3defad649b335ed25f296a2233 100644 (file)
@@ -1486,6 +1486,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                mtd->oobavail : mtd->oobsize;
 
        uint8_t *bufpoi, *oob, *buf;
+       unsigned int max_bitflips = 0;
 
        stats = mtd->ecc_stats;
 
@@ -1513,7 +1514,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                sndcmd = 0;
                        }
 
-                       /* Now read the page into the buffer */
+                       /*
+                        * Now read the page into the buffer.  Absent an error,
+                        * the read methods return max bitflips per ecc step.
+                        */
                        if (unlikely(ops->mode == MTD_OPS_RAW))
                                ret = chip->ecc.read_page_raw(mtd, chip,
                                                              bufpoi, page);
@@ -1530,15 +1534,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                break;
                        }
 
+                       max_bitflips = max_t(unsigned int, max_bitflips, ret);
+
                        /* Transfer not aligned data */
                        if (!aligned) {
                                if (!NAND_SUBPAGE_READ(chip) && !oob &&
                                    !(mtd->ecc_stats.failed - stats.failed) &&
-                                   (ops->mode != MTD_OPS_RAW))
+                                   (ops->mode != MTD_OPS_RAW)) {
                                        chip->pagebuf = realpage;
-                               else
+                                       chip->pagebuf_bitflips = ret;
+                               } else {
                                        /* Invalidate page cache */
                                        chip->pagebuf = -1;
+                               }
                                memcpy(buf, chip->buffers->databuf + col, bytes);
                        }
 
@@ -1571,6 +1579,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                } else {
                        memcpy(buf, chip->buffers->databuf + col, bytes);
                        buf += bytes;
+                       max_bitflips = max_t(unsigned int, max_bitflips,
+                                            chip->pagebuf_bitflips);
                }
 
                readlen -= bytes;
@@ -1609,7 +1619,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
-       return  mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+       return max_bitflips;
 }
 
 /**
index b3ce12ef359e83777280aff2b6f9fa9d58cc4dc9..7153e0d27101e3eed06ac17addcdbd4734c7ccc3 100644 (file)
@@ -1201,7 +1201,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
-       return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+       /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
+       return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
 }
 
 /**
@@ -1333,7 +1334,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
        if (mtd->ecc_stats.failed - stats.failed)
                return -EBADMSG;
 
-       return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0;
+       /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
+       return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
 }
 
 /**
index 1482340d3d9f5e0a6ba5d61a020b112320618362..2829e8be3a620771ff14c15e635d7fbcfd4fe5d6 100644 (file)
@@ -459,6 +459,8 @@ struct nand_buffers {
  * @pagemask:          [INTERN] page number mask = number of (pages / chip) - 1
  * @pagebuf:           [INTERN] holds the pagenumber which is currently in
  *                     data_buf.
+ * @pagebuf_bitflips:  [INTERN] holds the bitflip count for the page which is
+ *                     currently in data_buf.
  * @subpagesize:       [INTERN] holds the subpagesize
  * @onfi_version:      [INTERN] holds the chip ONFI version (BCD encoded),
  *                     non 0 if ONFI supported.
@@ -519,6 +521,7 @@ struct nand_chip {
        uint64_t chipsize;
        int pagemask;
        int pagebuf;
+       unsigned int pagebuf_bitflips;
        int subpagesize;
        uint8_t cellinfo;
        int badblockpos;