From patchwork Sun Mar 11 21:21:13 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Dunn X-Patchwork-Id: 146277 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from merlin.infradead.org (merlin.infradead.org [IPv6:2001:4978:20e::2]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 93E87B6FB7 for ; Tue, 13 Mar 2012 09:43:01 +1100 (EST) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1S7DwM-0000p5-Du; Mon, 12 Mar 2012 22:42:06 +0000 Received: from bombadil.infradead.org ([2001:4830:2446:ff00:4687:fcff:fea6:5117]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1S7BbW-0003DN-6e for linux-mtd@merlin.infradead.org; Mon, 12 Mar 2012 20:12:26 +0000 Received: from smtp.newsguy.com ([74.209.136.69]) by bombadil.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1S6rAK-0005W1-Ki for linux-mtd@lists.infradead.org; Sun, 11 Mar 2012 22:23:01 +0000 Received: from localhost.localdomain (77.sub-166-250-2.myvzw.com [166.250.2.77]) by smtp.newsguy.com (8.14.3/8.14.3) with ESMTP id q2BMLdlK067897 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Sun, 11 Mar 2012 15:22:44 -0700 (PDT) (envelope-from mikedunn@newsguy.com) From: Mike Dunn To: linux-mtd@lists.infradead.org Subject: [PATCH 4/4] MTD: drivers return max_bitflips, mtd returns -EUCLEAN Date: Sun, 11 Mar 2012 14:21:13 -0700 Message-Id: <1331500873-9792-5-git-send-email-mikedunn@newsguy.com> X-Mailer: git-send-email 1.7.3.4 In-Reply-To: <1331500873-9792-1-git-send-email-mikedunn@newsguy.com> References: <1331500873-9792-1-git-send-email-mikedunn@newsguy.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20120311_182300_795325_2CCD6388 X-CRM114-Status: GOOD ( 19.75 ) X-Spam-Score: -1.9 (-) X-Spam-Report: SpamAssassin version 3.3.2 on bombadil.infradead.org summary: Content analysis details: (-1.9 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: Mike Dunn X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-mtd-bounces@lists.infradead.org Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The drivers' read methods, absent an error, return a non-negative integer indicating the maximum number of bit errors that were corrected in any one writesize region. MTD returns -EUCLEAN if this is >= euclean_threshold, 0 otherwise. Note that this is a subtle change to the driver interface. This and the preceeding patches in this set were tested ubi on top of the nandsim and docg4 devices, running the ubi test io_basic from mtd-utils. Signed-off-by: Mike Dunn --- We may want to also change the name of the macro mtd_is_bitflip(), since this is not really correctly named anymore. drivers/mtd/devices/docg3.c | 4 +++- drivers/mtd/mtdcore.c | 35 ++++++++++++++++++++++++++++++++++- drivers/mtd/mtdpart.c | 25 +++++++++++++------------ drivers/mtd/nand/alauda.c | 4 ++-- drivers/mtd/nand/nand_base.c | 14 ++++++++++++-- drivers/mtd/onenand/onenand_base.c | 6 ++++-- include/linux/mtd/mtd.h | 10 +--------- 7 files changed, 69 insertions(+), 29 deletions(-) diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 886ca0f..95ea33e 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -854,6 +854,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; @@ -938,7 +939,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; } } diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 5bbd717..6871658 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -789,12 +789,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 writesize region (typically a NAND page). + */ + ret_code = mtd->_read(mtd, from, len, retlen, buf); + + if (unlikely(ret_code < 0)) + return ret_code; + + return ret_code >= mtd->euclean_threshold ? -EUCLEAN : 0; } EXPORT_SYMBOL_GPL(mtd_read); @@ -835,6 +847,27 @@ int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, } EXPORT_SYMBOL_GPL(mtd_panic_write); +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) +{ + int ret_code; + ops->retlen = ops->oobretlen = 0; + if (!mtd->_read_oob) + return -EOPNOTSUPP; + + /* + * In the absence of an error, drivers return a non-negative integer + * representing the maximum number of bitflips that were corrected on + * any one writesize region (typically a NAND page). + */ + ret_code = mtd->_read_oob(mtd, from, ops); + + if (unlikely(ret_code < 0)) + return ret_code; + + return ret_code >= mtd->euclean_threshold ? -EUCLEAN : 0; +} +EXPORT_SYMBOL_GPL(mtd_read_oob); + /* * Method to access the protection register area, present in some flash * devices. The user data is one time programmable but the factory data is read diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index 9651c06..24022ce 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, 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; } @@ -108,6 +108,7 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops) { struct mtd_part *part = PART(mtd); + struct mtd_ecc_stats stats = part->master->ecc_stats; int res; if (from >= mtd->size) @@ -133,12 +134,12 @@ static int part_read_oob(struct mtd_info *mtd, loff_t from, } res = part->master->_read_oob(part->master, from + part->offset, ops); - if (unlikely(res)) { - if (mtd_is_bitflip(res)) - mtd->ecc_stats.corrected++; - if (mtd_is_eccerr(res)) - mtd->ecc_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/alauda.c b/drivers/mtd/nand/alauda.c index 4f20e1d..7e59e83 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, } err = 0; if (corrected) - err = -EUCLEAN; + err = 1; /* return max bitflips per page */ 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 page */ if (uncorrected) err = -EBADMSG; return err; diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 8008853..e2bf003 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1469,6 +1469,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, uint32_t oobreadlen = ops->ooblen; uint32_t max_oobsize = ops->mode == MTD_OPS_AUTO_OOB ? mtd->oobavail : mtd->oobsize; + unsigned int max_bitflips = 0; uint8_t *bufpoi, *oob, *buf; @@ -1491,6 +1492,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, /* Is the current page in the buffer? */ if (realpage != chip->pagebuf || oob) { + unsigned int prev_corrected = mtd->ecc_stats.corrected; + bufpoi = aligned ? buf : chip->buffers->databuf; if (likely(sndcmd)) { @@ -1553,6 +1556,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, else nand_wait_ready(mtd); } + max_bitflips = max(max_bitflips, + mtd->ecc_stats.corrected - + prev_corrected); } else { memcpy(buf, chip->buffers->databuf + col, bytes); buf += bytes; @@ -1594,7 +1600,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; } /** @@ -1782,6 +1788,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, int readlen = ops->ooblen; int len; uint8_t *buf = ops->oobbuf; + unsigned int max_bitflips = 0; pr_debug("%s: from = 0x%08Lx, len = %i\n", __func__, (unsigned long long)from, readlen); @@ -1816,6 +1823,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, page = realpage & chip->pagemask; while (1) { + unsigned int prev_corrected = mtd->ecc_stats.corrected; if (ops->mode == MTD_OPS_RAW) sndcmd = chip->ecc.read_oob_raw(mtd, chip, page, sndcmd); else @@ -1836,6 +1844,8 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, else nand_wait_ready(mtd); } + max_bitflips = max(max_bitflips, + mtd->ecc_stats.corrected - prev_corrected); readlen -= len; if (!readlen) @@ -1865,7 +1875,7 @@ static int nand_do_read_oob(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 3d781b8..177b0a5 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, if (mtd->ecc_stats.failed - stats.failed) return -EBADMSG; - return mtd->ecc_stats.corrected - stats.corrected ? -EUCLEAN : 0; + /* return max bitflips per page; 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 page; ONENANDs correct 1 bit only */ + return mtd->ecc_stats.corrected != stats.corrected ? 1 : 0; } /** diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h index 20b5c40..b0c78f4 100644 --- a/include/linux/mtd/mtd.h +++ b/include/linux/mtd/mtd.h @@ -262,15 +262,7 @@ int mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); int mtd_panic_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - -static inline int mtd_read_oob(struct mtd_info *mtd, loff_t from, - struct mtd_oob_ops *ops) -{ - ops->retlen = ops->oobretlen = 0; - if (!mtd->_read_oob) - return -EOPNOTSUPP; - return mtd->_read_oob(mtd, from, ops); -} +int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops); static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)