aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand
diff options
context:
space:
mode:
authorDavid A. Marlin <dmarlin@redhat.com>2005-01-23 22:07:46 -0500
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-05-23 06:08:59 -0400
commit068e3c0a002c79a5e3cc7c42cb749c4bb126288c (patch)
treefdf2db2edf03c4520a204476b0edc652ae2c9c47 /drivers/mtd/nand
parent99f2a8aea18c9779c141050c6f95a8f1da63bbe4 (diff)
[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 <dmarlin@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd/nand')
-rw-r--r--drivers/mtd/nand/nand_base.c65
1 files changed, 54 insertions, 11 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 9f7c42ceecfa..7094dd5716dc 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -42,6 +42,10 @@
42 * a "device recovery" operation must be performed when power is restored 42 * a "device recovery" operation must be performed when power is restored
43 * to ensure correct operation. 43 * to ensure correct operation.
44 * 44 *
45 * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
46 * perform extra error status checks on erase and write failures. This required
47 * adding a wrapper function for nand_read_ecc.
48 *
45 * Credits: 49 * Credits:
46 * David Woodhouse for adding multichip support 50 * David Woodhouse for adding multichip support
47 * 51 *
@@ -55,7 +59,7 @@
55 * The AG-AND chips have nice features for speed improvement, 59 * The AG-AND chips have nice features for speed improvement,
56 * which are not supported yet. Read / program 4 pages in one go. 60 * which are not supported yet. Read / program 4 pages in one go.
57 * 61 *
58 * $Id: nand_base.c,v 1.129 2005/01/23 18:30:50 dmarlin Exp $ 62 * $Id: nand_base.c,v 1.130 2005/01/24 03:07:43 dmarlin Exp $
59 * 63 *
60 * This program is free software; you can redistribute it and/or modify 64 * This program is free software; you can redistribute it and/or modify
61 * it under the terms of the GNU General Public License version 2 as 65 * it under the terms of the GNU General Public License version 2 as
@@ -896,6 +900,12 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
896 if (!cached) { 900 if (!cached) {
897 /* call wait ready function */ 901 /* call wait ready function */
898 status = this->waitfunc (mtd, this, FL_WRITING); 902 status = this->waitfunc (mtd, this, FL_WRITING);
903
904 /* See if operation failed and additional status checks are available */
905 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
906 status = this->errstat(mtd, this, FL_WRITING, status, page);
907 }
908
899 /* See if device thinks it succeeded */ 909 /* See if device thinks it succeeded */
900 if (status & NAND_STATUS_FAIL) { 910 if (status & NAND_STATUS_FAIL) {
901 DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); 911 DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
@@ -1022,23 +1032,24 @@ out:
1022#endif 1032#endif
1023 1033
1024/** 1034/**
1025 * nand_read - [MTD Interface] MTD compability function for nand_read_ecc 1035 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
1026 * @mtd: MTD device structure 1036 * @mtd: MTD device structure
1027 * @from: offset to read from 1037 * @from: offset to read from
1028 * @len: number of bytes to read 1038 * @len: number of bytes to read
1029 * @retlen: pointer to variable to store the number of read bytes 1039 * @retlen: pointer to variable to store the number of read bytes
1030 * @buf: the databuffer to put data 1040 * @buf: the databuffer to put data
1031 * 1041 *
1032 * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL 1042 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
1033*/ 1043 * and flags = 0xff
1044 */
1034static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) 1045static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
1035{ 1046{
1036 return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL); 1047 return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, NULL, 0xff);
1037} 1048}
1038 1049
1039 1050
1040/** 1051/**
1041 * nand_read_ecc - [MTD Interface] Read data with ECC 1052 * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
1042 * @mtd: MTD device structure 1053 * @mtd: MTD device structure
1043 * @from: offset to read from 1054 * @from: offset to read from
1044 * @len: number of bytes to read 1055 * @len: number of bytes to read
@@ -1047,11 +1058,35 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
1047 * @oob_buf: filesystem supplied oob data buffer 1058 * @oob_buf: filesystem supplied oob data buffer
1048 * @oobsel: oob selection structure 1059 * @oobsel: oob selection structure
1049 * 1060 *
1050 * NAND read with ECC 1061 * This function simply calls nand_do_read_ecc with flags = 0xff
1051 */ 1062 */
1052static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, 1063static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1053 size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) 1064 size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
1054{ 1065{
1066 return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
1067}
1068
1069
1070/**
1071 * nand_do_read_ecc - [MTD Interface] Read data with ECC
1072 * @mtd: MTD device structure
1073 * @from: offset to read from
1074 * @len: number of bytes to read
1075 * @retlen: pointer to variable to store the number of read bytes
1076 * @buf: the databuffer to put data
1077 * @oob_buf: filesystem supplied oob data buffer
1078 * @oobsel: oob selection structure
1079 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1080 * and how many corrected error bits are acceptable:
1081 * bits 0..7 - number of tolerable errors
1082 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1083 *
1084 * NAND read with ECC
1085 */
1086int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1087 size_t * retlen, u_char * buf, u_char * oob_buf,
1088 struct nand_oobinfo *oobsel, int flags)
1089{
1055 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; 1090 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
1056 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; 1091 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
1057 struct nand_chip *this = mtd->priv; 1092 struct nand_chip *this = mtd->priv;
@@ -1076,7 +1111,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1076 } 1111 }
1077 1112
1078 /* Grab the lock and see if the device is available */ 1113 /* Grab the lock and see if the device is available */
1079 nand_get_device (this, mtd, FL_READING); 1114 if (flags & NAND_GET_DEVICE)
1115 nand_get_device (this, mtd, FL_READING);
1080 1116
1081 /* use userspace supplied oobinfo, if zero */ 1117 /* use userspace supplied oobinfo, if zero */
1082 if (oobsel == NULL) 1118 if (oobsel == NULL)
@@ -1180,7 +1216,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1180 /* We calc error correction directly, it checks the hw 1216 /* We calc error correction directly, it checks the hw
1181 * generator for an error, reads back the syndrome and 1217 * generator for an error, reads back the syndrome and
1182 * does the error correction on the fly */ 1218 * does the error correction on the fly */
1183 if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) { 1219 ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
1220 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
1184 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " 1221 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
1185 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); 1222 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
1186 ecc_failed++; 1223 ecc_failed++;
@@ -1219,7 +1256,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1219 p[i] = ecc_status; 1256 p[i] = ecc_status;
1220 } 1257 }
1221 1258
1222 if (ecc_status == -1) { 1259 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
1223 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); 1260 DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
1224 ecc_failed++; 1261 ecc_failed++;
1225 } 1262 }
@@ -1289,7 +1326,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
1289 } 1326 }
1290 1327
1291 /* Deselect and wake up anyone waiting on the device */ 1328 /* Deselect and wake up anyone waiting on the device */
1292 nand_release_device(mtd); 1329 if (flags & NAND_GET_DEVICE)
1330 nand_release_device(mtd);
1293 1331
1294 /* 1332 /*
1295 * Return success, if no ECC failures, else -EBADMSG 1333 * Return success, if no ECC failures, else -EBADMSG
@@ -2103,6 +2141,11 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
2103 2141
2104 status = this->waitfunc (mtd, this, FL_ERASING); 2142 status = this->waitfunc (mtd, this, FL_ERASING);
2105 2143
2144 /* See if operation failed and additional status checks are available */
2145 if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
2146 status = this->errstat(mtd, this, FL_ERASING, status, page);
2147 }
2148
2106 /* See if block erase succeeded */ 2149 /* See if block erase succeeded */
2107 if (status & NAND_STATUS_FAIL) { 2150 if (status & NAND_STATUS_FAIL) {
2108 DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); 2151 DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);