tree fdf2db2edf03c4520a204476b0edc652ae2c9c47
parent 99f2a8aea18c9779c141050c6f95a8f1da63bbe4
author David A. Marlin <[EMAIL PROTECTED]> Mon, 24 Jan 2005 03:07:46 +0000
committer Thomas Gleixner <[EMAIL PROTECTED]> Mon, 23 May 2005 12:08:59 +0200
[MTD] NAND Add optional ECC status check callback
Add optional hardware specific callback routine to perform extra error
status checks on erase and write failures for devices with hardware ECC.
Signed-off-by: David A. Marlin <[EMAIL PROTECTED]>
Signed-off-by: Thomas Gleixner <[EMAIL PROTECTED]>
drivers/mtd/nand/nand_base.c | 65 +++++++++++++++++++++++++++++++++++--------
include/linux/mtd/nand.h | 16 +++++++++-
2 files changed, 68 insertions(+), 13 deletions(-)
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -42,6 +42,10 @@
* a "device recovery" operation must be performed when power is
restored
* to ensure correct operation.
*
+ * 01-20-2005 dmarlin: added support for optional hardware specific callback
routine to
+ * perform extra error status checks on erase and write failures.
This required
+ * adding a wrapper function for nand_read_ecc.
+ *
* Credits:
* David Woodhouse for adding multichip support
*
@@ -55,7 +59,7 @@
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
- * $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $
+ * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -896,6 +900,12 @@ static int nand_write_page (struct mtd_i
if (!cached) {
/* call wait ready function */
status = this->waitfunc (mtd, this, FL_WRITING);
+
+ /* See if operation failed and additional status checks are
available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_WRITING, status,
page);
+ }
+
/* See if device thinks it succeeded */
if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page
0x%08x, ", __FUNCTION__, page);
@@ -1022,23 +1032,24 @@ out:
#endif
/**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
-*/
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel =
NULL
+ * and flags = 0xff
+ */
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *
retlen, u_char * buf)
{
- return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
+ return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
}
/**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for
nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
@@ -1047,11 +1058,35 @@ static int nand_read (struct mtd_info *m
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
*/
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf,
struct nand_oobinfo *oobsel)
{
+ return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel,
0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put data
+ * @oob_buf: filesystem supplied oob data buffer
+ * @oobsel: oob selection structure
+ * @flags: flag to indicate if nand_get_device/nand_release_device should
be preformed
+ * and how many corrected error bits are acceptable:
+ * bits 0..7 - number of tolerable errors
+ * bit 8 - 0 == do not get/release chip, 1 == get/release
chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob_buf,
+ struct nand_oobinfo *oobsel, int flags)
+{
int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
struct nand_chip *this = mtd->priv;
@@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_inf
}
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd, FL_READING);
+ if (flags & NAND_GET_DEVICE)
+ nand_get_device (this, mtd, FL_READING);
/* use userspace supplied oobinfo, if zero */
if (oobsel == NULL)
@@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_inf
/* We calc error correction directly,
it checks the hw
* generator for an error, reads back
the syndrome and
* does the error correction on the fly
*/
- if (this->correct_data(mtd,
&data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+ ecc_status = this->correct_data(mtd,
&data_poi[datidx], &oob_data[i], &ecc_code[i]);
+ if ((ecc_status == -1) || (ecc_status >
(flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0,
"nand_read_ecc: "
"Failed ECC read, page
0x%08x on chip %d\n", page, chipnr);
ecc_failed++;
@@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_inf
p[i] = ecc_status;
}
- if (ecc_status == -1) {
+ if ((ecc_status == -1) || (ecc_status > (flags &&
0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
"Failed ECC read, page 0x%08x\n", page);
ecc_failed++;
}
@@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_inf
}
/* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
+ if (flags & NAND_GET_DEVICE)
+ nand_release_device(mtd);
/*
* Return success, if no ECC failures, else -EBADMSG
@@ -2103,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mt
status = this->waitfunc (mtd, this, FL_ERASING);
+ /* See if operation failed and additional status checks are
available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_ERASING, status,
page);
+ }
+
/* See if block erase succeeded */
if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase,
page 0x%08x\n", page);
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -5,7 +5,7 @@
* Steven J. Hill <[EMAIL PROTECTED]>
* Thomas Gleixner <[EMAIL PROTECTED]>
*
- * $Id: nand.h,v 1.69 2005/01/17 18:29:18 dmarlin Exp $
+ * $Id: nand.h,v 1.70 2005/01/24 03:07:42 dmarlin Exp $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -50,6 +50,8 @@
* update of nand_chip structure description
* 01-17-2005 dmarlin added extended commands for AG-AND device and added
option
* for BBT_AUTO_REFRESH.
+ * 01-20-2005 dmarlin added optional pointer to hardware specific callback
for
+ * extra error status checks.
*/
#ifndef __LINUX_MTD_NAND_H
#define __LINUX_MTD_NAND_H
@@ -164,7 +166,7 @@ extern int nand_read_raw (struct mtd_inf
/*
* Constants for Hardware ECC
-*/
+ */
/* Reset Hardware ECC for read */
#define NAND_ECC_READ 0
/* Reset Hardware ECC for write */
@@ -172,6 +174,10 @@ extern int nand_read_raw (struct mtd_inf
/* Enable Hardware ECC before syndrom is read back from flash */
#define NAND_ECC_READSYN 2
+/* Bit mask for flags passed to do_nand_read_ecc */
+#define NAND_GET_DEVICE 0x80
+
+
/* Option constants for bizarre disfunctionality and real
* features
*/
@@ -308,6 +314,8 @@ struct nand_hw_control {
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial
bad block scan
* @controller: [OPTIONAL] a pointer to a hardware controller
structure which is shared among multiple independend devices
* @priv: [OPTIONAL] pointer to private chip date
+ * @errstat: [OPTIONAL] hardware specific function to perform
additional error status checks
+ * (determine if errors are correctable)
*/
struct nand_chip {
@@ -363,6 +371,7 @@ struct nand_chip {
struct nand_bbt_descr *badblock_pattern;
struct nand_hw_control *controller;
void *priv;
+ int (*errstat)(struct mtd_info *mtd, struct nand_chip
*this, int state, int status, int page);
};
/*
@@ -484,6 +493,9 @@ extern int nand_update_bbt (struct mtd_i
extern int nand_default_bbt (struct mtd_info *mtd);
extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr,
int allowbbt);
+extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob_buf,
+ struct nand_oobinfo *oobsel, int flags);
/*
* Constants for oob configuration
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html