aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/testing/sysfs-class-mtd7
-rw-r--r--drivers/mtd/devices/docg3.c6
-rw-r--r--drivers/mtd/mtdcore.c14
-rw-r--r--drivers/mtd/mtdpart.c12
-rw-r--r--drivers/mtd/nand/alauda.c4
-rw-r--r--drivers/mtd/nand/nand_base.c18
-rw-r--r--drivers/mtd/onenand/onenand_base.c6
-rw-r--r--include/linux/mtd/nand.h3
8 files changed, 51 insertions, 19 deletions
diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd
index 78835080856a..db1ad7e34fc3 100644
--- a/Documentation/ABI/testing/sysfs-class-mtd
+++ b/Documentation/ABI/testing/sysfs-class-mtd
@@ -167,7 +167,10 @@ Description:
167 block degradation, but high enough to avoid the consequences of 167 block degradation, but high enough to avoid the consequences of
168 a persistent return value of -EUCLEAN on devices where sticky 168 a persistent return value of -EUCLEAN on devices where sticky
169 bitflips occur. Note that if bitflip_threshold exceeds 169 bitflips occur. Note that if bitflip_threshold exceeds
170 ecc_strength, -EUCLEAN is never returned by the read functions. 170 ecc_strength, -EUCLEAN is never returned by mtd_read().
171 Conversely, if bitflip_threshold is zero, -EUCLEAN is always
172 returned, absent a hard error.
171 173
172 This is generally applicable only to NAND flash devices with ECC 174 This is generally applicable only to NAND flash devices with ECC
173 capability. It is ignored on devices lacking ECC capability. 175 capability. It is ignored on devices lacking ECC capability;
176 i.e., devices for which ecc_strength is zero.
diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c
index 8272c02668d6..65d22a0439c6 100644
--- a/drivers/mtd/devices/docg3.c
+++ b/drivers/mtd/devices/docg3.c
@@ -850,6 +850,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
850 u8 *buf = ops->datbuf; 850 u8 *buf = ops->datbuf;
851 size_t len, ooblen, nbdata, nboob; 851 size_t len, ooblen, nbdata, nboob;
852 u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1; 852 u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
853 int max_bitflips = 0;
853 854
854 if (buf) 855 if (buf)
855 len = ops->len; 856 len = ops->len;
@@ -876,7 +877,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
876 ret = 0; 877 ret = 0;
877 skip = from % DOC_LAYOUT_PAGE_SIZE; 878 skip = from % DOC_LAYOUT_PAGE_SIZE;
878 mutex_lock(&docg3->cascade->lock); 879 mutex_lock(&docg3->cascade->lock);
879 while (!ret && (len > 0 || ooblen > 0)) { 880 while (ret >= 0 && (len > 0 || ooblen > 0)) {
880 calc_block_sector(from - skip, &block0, &block1, &page, &ofs, 881 calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
881 docg3->reliable); 882 docg3->reliable);
882 nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip); 883 nbdata = min_t(size_t, len, DOC_LAYOUT_PAGE_SIZE - skip);
@@ -936,7 +937,8 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
936 } 937 }
937 if (ret > 0) { 938 if (ret > 0) {
938 mtd->ecc_stats.corrected += ret; 939 mtd->ecc_stats.corrected += ret;
939 ret = -EUCLEAN; 940 max_bitflips = max(max_bitflips, ret);
941 ret = max_bitflips;
940 } 942 }
941 } 943 }
942 944
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 6a7cba1e24e6..575730744fdb 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -800,12 +800,24 @@ EXPORT_SYMBOL_GPL(mtd_get_unmapped_area);
800int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, 800int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
801 u_char *buf) 801 u_char *buf)
802{ 802{
803 int ret_code;
803 *retlen = 0; 804 *retlen = 0;
804 if (from < 0 || from > mtd->size || len > mtd->size - from) 805 if (from < 0 || from > mtd->size || len > mtd->size - from)
805 return -EINVAL; 806 return -EINVAL;
806 if (!len) 807 if (!len)
807 return 0; 808 return 0;
808 return mtd->_read(mtd, from, len, retlen, buf); 809
810 /*
811 * In the absence of an error, drivers return a non-negative integer
812 * representing the maximum number of bitflips that were corrected on
813 * any one ecc region (if applicable; zero otherwise).
814 */
815 ret_code = mtd->_read(mtd, from, len, retlen, buf);
816 if (unlikely(ret_code < 0))
817 return ret_code;
818 if (mtd->ecc_strength == 0)
819 return 0; /* device lacks ecc */
820 return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
809} 821}
810EXPORT_SYMBOL_GPL(mtd_read); 822EXPORT_SYMBOL_GPL(mtd_read);
811 823
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index ec75d44e0253..d518e4db8a0b 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -67,12 +67,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
67 stats = part->master->ecc_stats; 67 stats = part->master->ecc_stats;
68 res = part->master->_read(part->master, from + part->offset, len, 68 res = part->master->_read(part->master, from + part->offset, len,
69 retlen, buf); 69 retlen, buf);
70 if (unlikely(res)) { 70 if (unlikely(mtd_is_eccerr(res)))
71 if (mtd_is_bitflip(res)) 71 mtd->ecc_stats.failed +=
72 mtd->ecc_stats.corrected += part->master->ecc_stats.corrected - stats.corrected; 72 part->master->ecc_stats.failed - stats.failed;
73 if (mtd_is_eccerr(res)) 73 else
74 mtd->ecc_stats.failed += part->master->ecc_stats.failed - stats.failed; 74 mtd->ecc_stats.corrected +=
75 } 75 part->master->ecc_stats.corrected - stats.corrected;
76 return res; 76 return res;
77} 77}
78 78
diff --git a/drivers/mtd/nand/alauda.c b/drivers/mtd/nand/alauda.c
index 4f20e1d8bef1..60a0dfdb0808 100644
--- a/drivers/mtd/nand/alauda.c
+++ b/drivers/mtd/nand/alauda.c
@@ -414,7 +414,7 @@ static int alauda_bounce_read(struct mtd_info *mtd, loff_t from, size_t len,
414 } 414 }
415 err = 0; 415 err = 0;
416 if (corrected) 416 if (corrected)
417 err = -EUCLEAN; 417 err = 1; /* return max_bitflips per ecc step */
418 if (uncorrected) 418 if (uncorrected)
419 err = -EBADMSG; 419 err = -EBADMSG;
420out: 420out:
@@ -446,7 +446,7 @@ static int alauda_read(struct mtd_info *mtd, loff_t from, size_t len,
446 } 446 }
447 err = 0; 447 err = 0;
448 if (corrected) 448 if (corrected)
449 err = -EUCLEAN; 449 err = 1; /* return max_bitflips per ecc step */
450 if (uncorrected) 450 if (uncorrected)
451 err = -EBADMSG; 451 err = -EBADMSG;
452 return err; 452 return err;
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 9f5d339a3610..640f1f8159e8 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1486,6 +1486,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1486 mtd->oobavail : mtd->oobsize; 1486 mtd->oobavail : mtd->oobsize;
1487 1487
1488 uint8_t *bufpoi, *oob, *buf; 1488 uint8_t *bufpoi, *oob, *buf;
1489 unsigned int max_bitflips = 0;
1489 1490
1490 stats = mtd->ecc_stats; 1491 stats = mtd->ecc_stats;
1491 1492
@@ -1513,7 +1514,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1513 sndcmd = 0; 1514 sndcmd = 0;
1514 } 1515 }
1515 1516
1516 /* Now read the page into the buffer */ 1517 /*
1518 * Now read the page into the buffer. Absent an error,
1519 * the read methods return max bitflips per ecc step.
1520 */
1517 if (unlikely(ops->mode == MTD_OPS_RAW)) 1521 if (unlikely(ops->mode == MTD_OPS_RAW))
1518 ret = chip->ecc.read_page_raw(mtd, chip, 1522 ret = chip->ecc.read_page_raw(mtd, chip,
1519 bufpoi, page); 1523 bufpoi, page);
@@ -1530,15 +1534,19 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1530 break; 1534 break;
1531 } 1535 }
1532 1536
1537 max_bitflips = max_t(unsigned int, max_bitflips, ret);
1538
1533 /* Transfer not aligned data */ 1539 /* Transfer not aligned data */
1534 if (!aligned) { 1540 if (!aligned) {
1535 if (!NAND_SUBPAGE_READ(chip) && !oob && 1541 if (!NAND_SUBPAGE_READ(chip) && !oob &&
1536 !(mtd->ecc_stats.failed - stats.failed) && 1542 !(mtd->ecc_stats.failed - stats.failed) &&
1537 (ops->mode != MTD_OPS_RAW)) 1543 (ops->mode != MTD_OPS_RAW)) {
1538 chip->pagebuf = realpage; 1544 chip->pagebuf = realpage;
1539 else 1545 chip->pagebuf_bitflips = ret;
1546 } else {
1540 /* Invalidate page cache */ 1547 /* Invalidate page cache */
1541 chip->pagebuf = -1; 1548 chip->pagebuf = -1;
1549 }
1542 memcpy(buf, chip->buffers->databuf + col, bytes); 1550 memcpy(buf, chip->buffers->databuf + col, bytes);
1543 } 1551 }
1544 1552
@@ -1571,6 +1579,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1571 } else { 1579 } else {
1572 memcpy(buf, chip->buffers->databuf + col, bytes); 1580 memcpy(buf, chip->buffers->databuf + col, bytes);
1573 buf += bytes; 1581 buf += bytes;
1582 max_bitflips = max_t(unsigned int, max_bitflips,
1583 chip->pagebuf_bitflips);
1574 } 1584 }
1575 1585
1576 readlen -= bytes; 1586 readlen -= bytes;
@@ -1609,7 +1619,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
1609 if (mtd->ecc_stats.failed - stats.failed) 1619 if (mtd->ecc_stats.failed - stats.failed)
1610 return -EBADMSG; 1620 return -EBADMSG;
1611 1621
1612 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 1622 return max_bitflips;
1613} 1623}
1614 1624
1615/** 1625/**
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index b3ce12ef359e..7153e0d27101 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1201,7 +1201,8 @@ static int onenand_mlc_read_ops_nolock(struct mtd_info *mtd, loff_t from,
1201 if (mtd->ecc_stats.failed - stats.failed) 1201 if (mtd->ecc_stats.failed - stats.failed)
1202 return -EBADMSG; 1202 return -EBADMSG;
1203 1203
1204 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 1204 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1205 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
1205} 1206}
1206 1207
1207/** 1208/**
@@ -1333,7 +1334,8 @@ static int onenand_read_ops_nolock(struct mtd_info *mtd, loff_t from,
1333 if (mtd->ecc_stats.failed - stats.failed) 1334 if (mtd->ecc_stats.failed - stats.failed)
1334 return -EBADMSG; 1335 return -EBADMSG;
1335 1336
1336 return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; 1337 /* return max bitflips per ecc step; ONENANDs correct 1 bit only */
1338 return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0;
1337} 1339}
1338 1340
1339/** 1341/**
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 1482340d3d9f..2829e8be3a62 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -459,6 +459,8 @@ struct nand_buffers {
459 * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1 459 * @pagemask: [INTERN] page number mask = number of (pages / chip) - 1
460 * @pagebuf: [INTERN] holds the pagenumber which is currently in 460 * @pagebuf: [INTERN] holds the pagenumber which is currently in
461 * data_buf. 461 * data_buf.
462 * @pagebuf_bitflips: [INTERN] holds the bitflip count for the page which is
463 * currently in data_buf.
462 * @subpagesize: [INTERN] holds the subpagesize 464 * @subpagesize: [INTERN] holds the subpagesize
463 * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded), 465 * @onfi_version: [INTERN] holds the chip ONFI version (BCD encoded),
464 * non 0 if ONFI supported. 466 * non 0 if ONFI supported.
@@ -519,6 +521,7 @@ struct nand_chip {
519 uint64_t chipsize; 521 uint64_t chipsize;
520 int pagemask; 522 int pagemask;
521 int pagebuf; 523 int pagebuf;
524 unsigned int pagebuf_bitflips;
522 int subpagesize; 525 int subpagesize;
523 uint8_t cellinfo; 526 uint8_t cellinfo;
524 int badblockpos; 527 int badblockpos;