summaryrefslogtreecommitdiff
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/mtdcore.c14
-rw-r--r--drivers/mtd/mtdpart.c12
-rw-r--r--drivers/mtd/nand/nand_base.c18
-rw-r--r--drivers/mtd/onenand/onenand_base.c3
4 files changed, 35 insertions, 12 deletions
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 49c0814..deda5f2 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -217,11 +217,23 @@ int mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
int mtd_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen,
u_char *buf)
{
+ int ret_code;
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->ecc_strength == 0)
+ return 0; /* device lacks ecc */
+ return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
}
int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen,
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 9dfe7bb..146ce11 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -53,12 +53,12 @@ static int part_read(struct mtd_info *mtd, loff_t from, size_t len,
stats = part->master->ecc_stats;
res = mtd_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;
}
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 9e05cef..d4d586c 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1238,6 +1238,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;
@@ -1265,7 +1266,10 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
- /* 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,
oob_required,
@@ -1284,15 +1288,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_HAS_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);
}
@@ -1310,6 +1318,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;
@@ -1341,7 +1351,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;
}
/**
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index ddfe7e7..067f8ef 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -969,7 +969,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;
}
/**