diff options
author | David A. Marlin <dmarlin@redhat.com> | 2005-01-23 22:07:46 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 06:08:59 -0400 |
commit | 068e3c0a002c79a5e3cc7c42cb749c4bb126288c (patch) | |
tree | fdf2db2edf03c4520a204476b0edc652ae2c9c47 /drivers/mtd/nand/nand_base.c | |
parent | 99f2a8aea18c9779c141050c6f95a8f1da63bbe4 (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/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 65 |
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 | */ | ||
1034 | static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) | 1045 | static 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 | */ |
1052 | static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, | 1063 | static 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 | */ | ||
1086 | int 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); |