linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/4] mtd: nand: localize ECC failures per page
@ 2013-12-05 20:19 Brian Norris
  2013-12-05 20:19 ` [PATCH 2/4] mtd: nand: add ONFI vendor block for Micron Brian Norris
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Brian Norris @ 2013-12-05 20:19 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris

ECC failures can be tracked at the page level, not the do_read_ops level
(i.e., a potentially multi-page transaction).

This helps prepare for READ RETRY support.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 drivers/mtd/nand/nand_base.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index bd39f7b67906..239f1dacee58 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1420,7 +1420,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 {
 	int chipnr, page, realpage, col, bytes, aligned, oob_required;
 	struct nand_chip *chip = mtd->priv;
-	struct mtd_ecc_stats stats;
 	int ret = 0;
 	uint32_t readlen = ops->len;
 	uint32_t oobreadlen = ops->ooblen;
@@ -1430,7 +1429,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 	uint8_t *bufpoi, *oob, *buf;
 	unsigned int max_bitflips = 0;
 
-	stats = mtd->ecc_stats;
+	bool ecc_fail = false;
 
 	chipnr = (int)(from >> chip->chip_shift);
 	chip->select_chip(mtd, chipnr);
@@ -1445,6 +1444,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 	oob_required = oob ? 1 : 0;
 
 	while (1) {
+		unsigned int ecc_failures = mtd->ecc_stats.failed;
 		bytes = min(mtd->writesize - col, readlen);
 		aligned = (bytes == mtd->writesize);
 
@@ -1481,7 +1481,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 			/* Transfer not aligned data */
 			if (!aligned) {
 				if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
-				    !(mtd->ecc_stats.failed - stats.failed) &&
+				    !(mtd->ecc_stats.failed - ecc_failures) &&
 				    (ops->mode != MTD_OPS_RAW)) {
 					chip->pagebuf = realpage;
 					chip->pagebuf_bitflips = ret;
@@ -1511,6 +1511,9 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 				else
 					nand_wait_ready(mtd);
 			}
+
+			if (mtd->ecc_stats.failed - ecc_failures)
+				ecc_fail = true;
 		} else {
 			memcpy(buf, chip->buffers->databuf + col, bytes);
 			buf += bytes;
@@ -1545,7 +1548,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 	if (ret < 0)
 		return ret;
 
-	if (mtd->ecc_stats.failed - stats.failed)
+	if (ecc_fail)
 		return -EBADMSG;
 
 	return max_bitflips;
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/4] mtd: nand: add ONFI vendor block for Micron
  2013-12-05 20:19 [PATCH 1/4] mtd: nand: localize ECC failures per page Brian Norris
@ 2013-12-05 20:19 ` Brian Norris
  2013-12-05 20:19 ` [PATCH 3/4] mtd: nand: support Micron READ RETRY Brian Norris
  2013-12-05 20:20 ` [PATCH 4/4] mtd: nand: use __packed shorthand Brian Norris
  2 siblings, 0 replies; 6+ messages in thread
From: Brian Norris @ 2013-12-05 20:19 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 include/linux/mtd/nand.h | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index f3ea8daf08ee..029fe5948dc4 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -285,7 +285,8 @@ struct nand_onfi_params {
 	u8 reserved4[7];
 
 	/* vendor */
-	u8 reserved5[90];
+	__le16 vendor_revision;
+	u8 vendor[88];
 
 	__le16 crc;
 } __attribute__((packed));
@@ -326,6 +327,26 @@ struct onfi_ext_param_page {
 	 */
 } __packed;
 
+struct nand_onfi_vendor_micron {
+	u8 two_plane_read;
+	u8 read_cache;
+	u8 read_unique_id;
+	u8 dq_imped;
+	u8 dq_imped_num_settings;
+	u8 dq_imped_feat_addr;
+	u8 rb_pulldown_strength;
+	u8 rb_pulldown_strength_feat_addr;
+	u8 rb_pulldown_strength_num_settings;
+	u8 otp_mode;
+	u8 otp_page_start;
+	u8 otp_data_prot_addr;
+	u8 otp_num_pages;
+	u8 otp_feat_addr;
+	u8 read_retry_options;
+	u8 reserved[72];
+	u8 param_revision;
+} __packed;
+
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * @lock:               protection lock
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/4] mtd: nand: support Micron READ RETRY
  2013-12-05 20:19 [PATCH 1/4] mtd: nand: localize ECC failures per page Brian Norris
  2013-12-05 20:19 ` [PATCH 2/4] mtd: nand: add ONFI vendor block for Micron Brian Norris
@ 2013-12-05 20:19 ` Brian Norris
  2013-12-05 20:58   ` Brian Norris
  2013-12-05 20:20 ` [PATCH 4/4] mtd: nand: use __packed shorthand Brian Norris
  2 siblings, 1 reply; 6+ messages in thread
From: Brian Norris @ 2013-12-05 20:19 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris

MLC NAND can experience a large number of bitflips (beyond the
recommended correctability capacity) due to drifts in the voltage
threshold (Vt). These bitflips can cause ECC errors to occur well within
the expected lifetime of the flash. To account for this, some
manufacturers provide a mechanism for shifting the Vt threshold after a
corrupted read. Micron provides the necessary information via the ONFI
vendor-specific parameter block (to indicate how many read-retry modes
are available) and the ONFI {GET,SET}_FEATURES commands with a
vendor-specific feature address (to support reading/switching the
current read-retry mode).

The recommmended sequence is as follows:

  1. Perform PAGE_READ operation
  2. If no ECC error, we are done
  3. Run SET_FEATURES with feature address 89h, mode 1
  4. Retry PAGE_READ operation
  5. If ECC error and there are remaining supported modes, increment the
     mode and return to step 3. Otherwise, this is a true ECC error.
  6. Run SET_FEATURES with feature address 89h, mode 0, to return to the
     default state.

Tested on Micron MT29F32G08CBADA, suppors 8 read-retry modes.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
One thing I'm not sure about: do all relevant (i.e., ONFI-capable) NAND drivers
support SET_FEATURES properly? If not, then it's possible that this could break
nand_do_read_ops for such drivers. Not sure what the best method of handling
that would be.

 drivers/mtd/nand/nand_base.c | 71 +++++++++++++++++++++++++++++++++++++++++---
 include/linux/mtd/nand.h     |  6 ++++
 2 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 239f1dacee58..82efd819f31b 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1408,6 +1408,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
 }
 
 /**
+ * nand_set_read_retry - [INTERN] Set the READ RETRY mode
+ * @mtd: MTD device structure
+ * @retry_mode: the retry mode to use
+ *
+ * Some vendors supply a special command to shift the Vt threshold, to be used
+ * when there are too many bitflips in a page (i.e., ECC error). After setting
+ * a new threshold, the host should retry reading the page.
+ */
+static int nand_set_read_retry(struct mtd_info *mtd, int retry_mode)
+{
+	struct nand_chip *chip = mtd->priv;
+	uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
+
+	if (retry_mode >= chip->read_retries)
+		return -EINVAL;
+
+	if (chip->onfi_params.jedec_id == NAND_MFR_MICRON)
+		return chip->onfi_set_features(mtd, chip,
+				ONFI_FEATURE_ADDR_READ_RETRY, feature);
+
+	return -EOPNOTSUPP;
+}
+
+/**
  * nand_do_read_ops - [INTERN] Read data with ECC
  * @mtd: MTD device structure
  * @from: offset to read from
@@ -1429,6 +1453,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 	uint8_t *bufpoi, *oob, *buf;
 	unsigned int max_bitflips = 0;
 
+	int retry_mode = 0;
 	bool ecc_fail = false;
 
 	chipnr = (int)(from >> chip->chip_shift);
@@ -1492,8 +1517,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 				memcpy(buf, chip->buffers->databuf + col, bytes);
 			}
 
-			buf += bytes;
-
 			if (unlikely(oob)) {
 				int toread = min(oobreadlen, max_oobsize);
 
@@ -1512,8 +1535,27 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 					nand_wait_ready(mtd);
 			}
 
-			if (mtd->ecc_stats.failed - ecc_failures)
-				ecc_fail = true;
+			if (mtd->ecc_stats.failed - ecc_failures) {
+				retry_mode++;
+				if (retry_mode < chip->read_retries) {
+					pr_debug("ECC error; performing READ RETRY %d\n",
+							retry_mode);
+
+					ret = nand_set_read_retry(mtd,
+							retry_mode);
+					if (ret < 0)
+						break;
+
+					/* Reset failures */
+					mtd->ecc_stats.failed = ecc_failures;
+					continue;
+				} else {
+					/* No more retry modes; real failure */
+					ecc_fail = true;
+				}
+			}
+
+			buf += bytes;
 		} else {
 			memcpy(buf, chip->buffers->databuf + col, bytes);
 			buf += bytes;
@@ -1523,6 +1565,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
 		readlen -= bytes;
 
+		/* Reset to retry mode 0 */
+		if (retry_mode) {
+			ret = nand_set_read_retry(mtd, 0);
+			if (ret < 0)
+				break;
+			retry_mode = 0;
+		}
+
 		if (!readlen)
 			break;
 
@@ -2930,6 +2980,16 @@ ext_out:
 }
 
 /*
+ * Configure chip properties from Micron vendor-specific ONFI table
+ */
+static void nand_onfi_detect_micron(struct nand_chip *chip,
+		struct nand_onfi_params *p)
+{
+	struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
+	chip->read_retries = micron->read_retry_options;
+}
+
+/*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
 static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
@@ -3035,6 +3095,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
 		pr_warn("Could not retrieve ONFI ECC requirements\n");
 	}
 
+	if (p->jedec_id == NAND_MFR_MICRON)
+		nand_onfi_detect_micron(chip, p);
+
 	return 1;
 }
 
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 029fe5948dc4..6e579e90955e 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -219,6 +219,9 @@ struct nand_chip;
 /* ONFI feature address */
 #define ONFI_FEATURE_ADDR_TIMING_MODE	0x1
 
+/* Vendor-specific feature address (Micron) */
+#define ONFI_FEATURE_ADDR_READ_RETRY	0x89
+
 /* ONFI subfeature parameters length */
 #define ONFI_SUBFEATURE_PARAM_LEN	4
 
@@ -518,6 +521,7 @@ struct nand_buffers {
  *			non 0 if ONFI supported.
  * @onfi_params:	[INTERN] holds the ONFI page parameter when ONFI is
  *			supported, 0 otherwise.
+ * @read_retries:	[INTERN] the number of read retry modes supported
  * @onfi_set_features:	[REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features:	[REPLACEABLE] get the features for ONFI nand
  * @bbt:		[INTERN] bad block table pointer
@@ -589,6 +593,8 @@ struct nand_chip {
 	int onfi_version;
 	struct nand_onfi_params	onfi_params;
 
+	int read_retries;
+
 	flstate_t state;
 
 	uint8_t *oob_poi;
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 4/4] mtd: nand: use __packed shorthand
  2013-12-05 20:19 [PATCH 1/4] mtd: nand: localize ECC failures per page Brian Norris
  2013-12-05 20:19 ` [PATCH 2/4] mtd: nand: add ONFI vendor block for Micron Brian Norris
  2013-12-05 20:19 ` [PATCH 3/4] mtd: nand: support Micron READ RETRY Brian Norris
@ 2013-12-05 20:20 ` Brian Norris
  2 siblings, 0 replies; 6+ messages in thread
From: Brian Norris @ 2013-12-05 20:20 UTC (permalink / raw)
  To: linux-mtd; +Cc: Brian Norris

To be consistent with the rest of include/linux/mtd/nand.h, we should
use the __packed shorthand instead of __attribute__((packed)).

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
---
 include/linux/mtd/nand.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 6e579e90955e..32213a5a6705 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -292,7 +292,7 @@ struct nand_onfi_params {
 	u8 vendor[88];
 
 	__le16 crc;
-} __attribute__((packed));
+} __packed;
 
 #define ONFI_CRC_BASE	0x4F4E
 
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/4] mtd: nand: support Micron READ RETRY
  2013-12-05 20:19 ` [PATCH 3/4] mtd: nand: support Micron READ RETRY Brian Norris
@ 2013-12-05 20:58   ` Brian Norris
  2013-12-06  8:48     ` Huang Shijie
  0 siblings, 1 reply; 6+ messages in thread
From: Brian Norris @ 2013-12-05 20:58 UTC (permalink / raw)
  To: linux-mtd

Caught a simple bug when testing with a non-READ_RETRY NAND. See below.

On Thu, Dec 05, 2013 at 12:19:59PM -0800, Brian Norris wrote:
...
> One thing I'm not sure about: do all relevant (i.e., ONFI-capable) NAND drivers
> support SET_FEATURES properly? If not, then it's possible that this could break
> nand_do_read_ops for such drivers. Not sure what the best method of handling
> that would be.
...
> --- a/drivers/mtd/nand/nand_base.c
> +++ b/drivers/mtd/nand/nand_base.c
...
> @@ -1512,8 +1535,27 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
>  					nand_wait_ready(mtd);
>  			}
>  
> -			if (mtd->ecc_stats.failed - ecc_failures)
> -				ecc_fail = true;
> +			if (mtd->ecc_stats.failed - ecc_failures) {
> +				retry_mode++;

This increment shouldn't be done for all ECC failures, but only for
failures where there are remaining read-retry modes (i.e., flash that
support read retry).

> +				if (retry_mode < chip->read_retries) {
> +					pr_debug("ECC error; performing READ RETRY %d\n",
> +							retry_mode);
> +
> +					ret = nand_set_read_retry(mtd,
> +							retry_mode);
> +					if (ret < 0)
> +						break;
> +
> +					/* Reset failures */
> +					mtd->ecc_stats.failed = ecc_failures;
> +					continue;
> +				} else {
> +					/* No more retry modes; real failure */
> +					ecc_fail = true;
> +				}
> +			}
> +
> +			buf += bytes;
>  		} else {
>  			memcpy(buf, chip->buffers->databuf + col, bytes);
>  			buf += bytes;

I'll send a v2 with the following extra diff:

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 82efd819f31b..aeafcdce6cc0 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -1536,8 +1536,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 			}
 
 			if (mtd->ecc_stats.failed - ecc_failures) {
-				retry_mode++;
-				if (retry_mode < chip->read_retries) {
+				if (retry_mode + 1 < chip->read_retries) {
+					retry_mode++;
 					pr_debug("ECC error; performing READ RETRY %d\n",
 							retry_mode);
 
---

Brian

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 3/4] mtd: nand: support Micron READ RETRY
  2013-12-05 20:58   ` Brian Norris
@ 2013-12-06  8:48     ` Huang Shijie
  0 siblings, 0 replies; 6+ messages in thread
From: Huang Shijie @ 2013-12-06  8:48 UTC (permalink / raw)
  To: Brian Norris; +Cc: linux-mtd

On Thu, Dec 05, 2013 at 12:58:38PM -0800, Brian Norris wrote:
> Caught a simple bug when testing with a non-READ_RETRY NAND. See below.
> 
> On Thu, Dec 05, 2013 at 12:19:59PM -0800, Brian Norris wrote:
> ...
> > One thing I'm not sure about: do all relevant (i.e., ONFI-capable) NAND drivers
> > support SET_FEATURES properly? If not, then it's possible that this could break
> > nand_do_read_ops for such drivers. Not sure what the best method of handling
> > that would be.
> ...
> > --- a/drivers/mtd/nand/nand_base.c
> > +++ b/drivers/mtd/nand/nand_base.c
> ...
> > @@ -1512,8 +1535,27 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
> >  					nand_wait_ready(mtd);
> >  			}
> >  
> > -			if (mtd->ecc_stats.failed - ecc_failures)
> > -				ecc_fail = true;
> > +			if (mtd->ecc_stats.failed - ecc_failures) {
> > +				retry_mode++;
> 
> This increment shouldn't be done for all ECC failures, but only for
> failures where there are remaining read-retry modes (i.e., flash that
> support read retry).
> 
> > +				if (retry_mode < chip->read_retries) {
> > +					pr_debug("ECC error; performing READ RETRY %d\n",
> > +							retry_mode);
> > +
> > +					ret = nand_set_read_retry(mtd,
> > +							retry_mode);
> > +					if (ret < 0)
> > +						break;
> > +
> > +					/* Reset failures */
> > +					mtd->ecc_stats.failed = ecc_failures;
> > +					continue;
> > +				} else {
> > +					/* No more retry modes; real failure */
> > +					ecc_fail = true;
> > +				}
> > +			}
> > +
> > +			buf += bytes;
> >  		} else {
> >  			memcpy(buf, chip->buffers->databuf + col, bytes);
> >  			buf += bytes;
> 
> I'll send a v2 with the following extra diff:

I am glad you begin to add the read-retry support.

I ever planned to send out my read-retry patch set (which has been queued
in my hand for half of year) after I finish the
spi nor framework. 

I can not wait to review your V2 patch.

thanks
Huang Shijie

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-12-06  9:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-12-05 20:19 [PATCH 1/4] mtd: nand: localize ECC failures per page Brian Norris
2013-12-05 20:19 ` [PATCH 2/4] mtd: nand: add ONFI vendor block for Micron Brian Norris
2013-12-05 20:19 ` [PATCH 3/4] mtd: nand: support Micron READ RETRY Brian Norris
2013-12-05 20:58   ` Brian Norris
2013-12-06  8:48     ` Huang Shijie
2013-12-05 20:20 ` [PATCH 4/4] mtd: nand: use __packed shorthand Brian Norris

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).