aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-05-25 04:07:16 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-05-25 07:45:27 -0400
commitf5bbdacc41939f89d8ccb18dd79cd9b21c0cb75d (patch)
treec9e45db9701c41c842282b0432d915cc9facc013 /drivers/mtd
parent9577f44a899cf4acb9e381c8946307b72153cd15 (diff)
[MTD] NAND Modularize read function
Split the core of the read function out and implement seperate handling functions for software and hardware ECC. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/nand/diskonchip.c4
-rw-r--r--drivers/mtd/nand/nand_base.c448
-rw-r--r--drivers/mtd/nand/rtc_from4.c62
3 files changed, 267 insertions, 247 deletions
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 2ec9080e2b14..83af6f05cd00 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -968,12 +968,14 @@ static int doc200x_calculate_ecc(struct mtd_info *mtd, const u_char *dat, unsign
968 return 0; 968 return 0;
969} 969}
970 970
971static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) 971static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat,
972 u_char *read_ecc, u_char *isnull)
972{ 973{
973 int i, ret = 0; 974 int i, ret = 0;
974 struct nand_chip *this = mtd->priv; 975 struct nand_chip *this = mtd->priv;
975 struct doc_priv *doc = this->priv; 976 struct doc_priv *doc = this->priv;
976 void __iomem *docptr = doc->virtadr; 977 void __iomem *docptr = doc->virtadr;
978 uint8_t calc_ecc[6];
977 volatile u_char dummy; 979 volatile u_char dummy;
978 int emptymatch = 1; 980 int emptymatch = 1;
979 981
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 49bca242610b..21fce2bce4b2 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -976,256 +976,224 @@ static int nand_verify_pages(struct mtd_info *mtd, struct nand_chip *chip, int p
976#endif 976#endif
977 977
978/** 978/**
979 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc 979 * nand_read_page_swecc - {REPLACABLE] software ecc based page read function
980 * @mtd: MTD device structure 980 * @mtd: mtd info structure
981 * @from: offset to read from 981 * @chip: nand chip info structure
982 * @len: number of bytes to read 982 * @buf: buffer to store read data
983 * @retlen: pointer to variable to store the number of read bytes
984 * @buf: the databuffer to put data
985 *
986 * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
987 * and flags = 0xff
988 */ 983 */
989static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) 984static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
985 uint8_t *buf)
990{ 986{
991 return nand_do_read_ecc(mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff); 987 int i, eccsize = chip->ecc.size;
988 int eccbytes = chip->ecc.bytes;
989 int eccsteps = chip->ecc.steps;
990 uint8_t *p = buf;
991 uint8_t *ecc_calc = chip->oob_buf + mtd->oobsize;
992 uint8_t *ecc_code = ecc_calc + mtd->oobsize;
993 int *eccpos = chip->autooob->eccpos;
994
995 chip->read_buf(mtd, buf, mtd->writesize);
996 chip->read_buf(mtd, chip->oob_buf, mtd->oobsize);
997
998 if (chip->ecc.mode == NAND_ECC_NONE)
999 return 0;
1000
1001 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize)
1002 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1003
1004 for (i = 0; i < chip->ecc.total; i++)
1005 ecc_code[i] = chip->oob_buf[eccpos[i]];
1006
1007 eccsteps = chip->ecc.steps;
1008 p = buf;
1009
1010 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1011 int stat;
1012
1013 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
1014 if (stat == -1)
1015 mtd->ecc_stats.failed++;
1016 else
1017 mtd->ecc_stats.corrected += stat;
1018 }
1019 return 0;
992} 1020}
993 1021
994/** 1022/**
995 * nand_do_read_ecc - [MTD Interface] Read data with ECC 1023 * nand_read_page_hwecc - {REPLACABLE] hardware ecc based page read function
996 * @mtd: MTD device structure 1024 * @mtd: mtd info structure
997 * @from: offset to read from 1025 * @chip: nand chip info structure
998 * @len: number of bytes to read 1026 * @buf: buffer to store read data
999 * @retlen: pointer to variable to store the number of read bytes
1000 * @buf: the databuffer to put data
1001 * @oob_buf: filesystem supplied oob data buffer (can be NULL)
1002 * @oobsel: oob selection structure
1003 * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
1004 * and how many corrected error bits are acceptable:
1005 * bits 0..7 - number of tolerable errors
1006 * bit 8 - 0 == do not get/release chip, 1 == get/release chip
1007 * 1027 *
1008 * NAND read with ECC 1028 * Not for syndrome calculating ecc controllers which need a special oob layout
1009 */ 1029 */
1010int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, 1030static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
1011 size_t *retlen, uint8_t *buf, uint8_t *oob_buf, struct nand_oobinfo *oobsel, int flags) 1031 uint8_t *buf)
1012{ 1032{
1013 1033 int i, eccsize = chip->ecc.size;
1014 int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1; 1034 int eccbytes = chip->ecc.bytes;
1015 int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; 1035 int eccsteps = chip->ecc.steps;
1016 struct nand_chip *chip = mtd->priv; 1036 uint8_t *p = buf;
1017 uint8_t *data_poi, *oob_data = oob_buf; 1037 uint8_t *ecc_calc = chip->oob_buf + mtd->oobsize;
1018 uint8_t ecc_calc[32]; 1038 uint8_t *ecc_code = ecc_calc + mtd->oobsize;
1019 uint8_t ecc_code[32]; 1039 int *eccpos = chip->autooob->eccpos;
1020 int eccmode, eccsteps; 1040
1021 int *oob_config, datidx; 1041 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1022 int blockcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; 1042 chip->ecc.hwctl(mtd, NAND_ECC_READ);
1023 int eccbytes; 1043 chip->read_buf(mtd, p, eccsize);
1024 int compareecc = 1; 1044 chip->ecc.calculate(mtd, p, &ecc_calc[i]);
1025 int oobreadlen;
1026
1027 DEBUG(MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int)from, (int)len);
1028
1029 /* Do not allow reads past end of device */
1030 if ((from + len) > mtd->size) {
1031 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n");
1032 *retlen = 0;
1033 return -EINVAL;
1034 } 1045 }
1046 chip->read_buf(mtd, chip->oob_buf, mtd->oobsize);
1035 1047
1036 /* Grab the lock and see if the device is available */ 1048 for (i = 0; i < chip->ecc.total; i++)
1037 if (flags & NAND_GET_DEVICE) 1049 ecc_code[i] = chip->oob_buf[eccpos[i]];
1038 nand_get_device(chip, mtd, FL_READING);
1039 1050
1040 /* Autoplace of oob data ? Use the default placement scheme */ 1051 eccsteps = chip->ecc.steps;
1041 if (oobsel->useecc == MTD_NANDECC_AUTOPLACE) 1052 p = buf;
1042 oobsel = chip->autooob;
1043 1053
1044 eccmode = oobsel->useecc ? chip->ecc.mode : NAND_ECC_NONE; 1054 for (i = 0 ; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1045 oob_config = oobsel->eccpos; 1055 int stat;
1046 1056
1047 /* Select the NAND device */ 1057 stat = chip->ecc.correct(mtd, p, &ecc_code[i], &ecc_calc[i]);
1048 chipnr = (int)(from >> chip->chip_shift); 1058 if (stat == -1)
1049 chip->select_chip(mtd, chipnr); 1059 mtd->ecc_stats.failed++;
1050 1060 else
1051 /* First we calculate the starting page */ 1061 mtd->ecc_stats.corrected += stat;
1052 realpage = (int)(from >> chip->page_shift); 1062 }
1053 page = realpage & chip->pagemask; 1063 return 0;
1064}
1054 1065
1055 /* Get raw starting column */ 1066/**
1056 col = from & (mtd->writesize - 1); 1067 * nand_read_page_syndrome - {REPLACABLE] hardware ecc syndrom based page read
1068 * @mtd: mtd info structure
1069 * @chip: nand chip info structure
1070 * @buf: buffer to store read data
1071 *
1072 * The hw generator calculates the error syndrome automatically. Therefor
1073 * we need a special oob layout and .
1074 */
1075static int nand_read_page_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
1076 uint8_t *buf)
1077{
1078 int i, eccsize = chip->ecc.size;
1079 int eccbytes = chip->ecc.bytes;
1080 int eccsteps = chip->ecc.steps;
1081 uint8_t *p = buf;
1082 uint8_t *oob = chip->oob_buf;
1057 1083
1058 end = mtd->writesize; 1084 for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
1059 ecc = chip->ecc.size; 1085 int stat;
1060 eccbytes = chip->ecc.bytes;
1061 1086
1062 if ((eccmode == NAND_ECC_NONE) || (chip->options & NAND_HWECC_SYNDROME)) 1087 chip->ecc.hwctl(mtd, NAND_ECC_READ);
1063 compareecc = 0; 1088 chip->read_buf(mtd, p, eccsize);
1064 1089
1065 oobreadlen = mtd->oobsize; 1090 if (chip->ecc.prepad) {
1066 if (chip->options & NAND_HWECC_SYNDROME) 1091 chip->read_buf(mtd, oob, chip->ecc.prepad);
1067 oobreadlen -= oobsel->eccbytes; 1092 oob += chip->ecc.prepad;
1093 }
1068 1094
1069 /* Loop until all data read */ 1095 chip->ecc.hwctl(mtd, NAND_ECC_READSYN);
1070 while (read < len) { 1096 chip->read_buf(mtd, oob, eccbytes);
1097 stat = chip->ecc.correct(mtd, p, oob, NULL);
1071 1098
1072 int aligned = (!col && (len - read) >= end); 1099 if (stat == -1)
1073 /* 1100 mtd->ecc_stats.failed++;
1074 * If the read is not page aligned, we have to read into data buffer
1075 * due to ecc, else we read into return buffer direct
1076 */
1077 if (aligned)
1078 data_poi = &buf[read];
1079 else 1101 else
1080 data_poi = chip->data_buf; 1102 mtd->ecc_stats.corrected += stat;
1081 1103
1082 /* Check, if we have this page in the buffer 1104 oob += eccbytes;
1083 *
1084 * FIXME: Make it work when we must provide oob data too,
1085 * check the usage of data_buf oob field
1086 */
1087 if (realpage == chip->pagebuf && !oob_buf) {
1088 /* aligned read ? */
1089 if (aligned)
1090 memcpy(data_poi, chip->data_buf, end);
1091 goto readdata;
1092 }
1093 1105
1094 /* Check, if we must send the read command */ 1106 if (chip->ecc.postpad) {
1095 if (sndcmd) { 1107 chip->read_buf(mtd, oob, chip->ecc.postpad);
1096 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); 1108 oob += chip->ecc.postpad;
1097 sndcmd = 0;
1098 } 1109 }
1110 }
1099 1111
1100 /* get oob area, if we have no oob buffer from fs-driver */ 1112 /* Calculate remaining oob bytes */
1101 if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE || 1113 i = oob - chip->oob_buf;
1102 oobsel->useecc == MTD_NANDECC_AUTOPL_USR) 1114 if (i)
1103 oob_data = &chip->data_buf[end]; 1115 chip->read_buf(mtd, oob, i);
1104
1105 eccsteps = chip->ecc.steps;
1106
1107 switch (eccmode) {
1108 case NAND_ECC_NONE:{
1109 /* No ECC, Read in a page */
1110 static unsigned long lastwhinge = 0;
1111 if ((lastwhinge / HZ) != (jiffies / HZ)) {
1112 printk(KERN_WARNING
1113 "Reading data from NAND FLASH without ECC is not recommended\n");
1114 lastwhinge = jiffies;
1115 }
1116 chip->read_buf(mtd, data_poi, end);
1117 break;
1118 }
1119 1116
1120 case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ 1117 return 0;
1121 chip->read_buf(mtd, data_poi, end); 1118}
1122 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += 3, datidx += ecc)
1123 chip->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
1124 break;
1125 1119
1126 default: 1120/**
1127 for (i = 0, datidx = 0; eccsteps; eccsteps--, i += eccbytes, datidx += ecc) { 1121 * nand_do_read - [Internal] Read data with ECC
1128 chip->ecc.hwctl(mtd, NAND_ECC_READ); 1122 *
1129 chip->read_buf(mtd, &data_poi[datidx], ecc); 1123 * @mtd: MTD device structure
1130 1124 * @from: offset to read from
1131 /* HW ecc with syndrome calculation must read the 1125 * @len: number of bytes to read
1132 * syndrome from flash immidiately after the data */ 1126 * @retlen: pointer to variable to store the number of read bytes
1133 if (!compareecc) { 1127 * @buf: the databuffer to put data
1134 /* Some hw ecc generators need to know when the 1128 *
1135 * syndrome is read from flash */ 1129 * Internal function. Called with chip held.
1136 chip->ecc.hwctl(mtd, NAND_ECC_READSYN); 1130 */
1137 chip->read_buf(mtd, &oob_data[i], eccbytes); 1131int nand_do_read(struct mtd_info *mtd, loff_t from, size_t len,
1138 /* We calc error correction directly, it checks the hw 1132 size_t *retlen, uint8_t *buf)
1139 * generator for an error, reads back the syndrome and 1133{
1140 * does the error correction on the fly */ 1134 int chipnr, page, realpage, col, bytes, aligned;
1141 ecc_status = chip->ecc.correct(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]); 1135 struct nand_chip *chip = mtd->priv;
1142 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { 1136 struct mtd_ecc_stats stats;
1143 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " 1137 int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1;
1144 "Failed ECC read, page 0x%08x on chip %d\n", page, chipnr); 1138 int sndcmd = 1;
1145 ecc_failed++; 1139 int ret = 0;
1146 } 1140 uint32_t readlen = len;
1147 } else { 1141 uint8_t *bufpoi;
1148 chip->ecc.calculate(mtd, &data_poi[datidx], &ecc_calc[i]);
1149 }
1150 }
1151 break;
1152 }
1153 1142
1154 /* read oobdata */ 1143 stats = mtd->ecc_stats;
1155 chip->read_buf(mtd, &oob_data[mtd->oobsize - oobreadlen], oobreadlen);
1156 1144
1157 /* Skip ECC check, if not requested (ECC_NONE or HW_ECC with syndromes) */ 1145 chipnr = (int)(from >> chip->chip_shift);
1158 if (!compareecc) 1146 chip->select_chip(mtd, chipnr);
1159 goto readoob;
1160 1147
1161 /* Pick the ECC bytes out of the oob data */ 1148 realpage = (int)(from >> chip->page_shift);
1162 for (j = 0; j < oobsel->eccbytes; j++) 1149 page = realpage & chip->pagemask;
1163 ecc_code[j] = oob_data[oob_config[j]];
1164 1150
1165 /* correct data, if necessary */ 1151 col = (int)(from & (mtd->writesize - 1));
1166 for (i = 0, j = 0, datidx = 0; i < chip->ecc.steps; i++, datidx += ecc) {
1167 ecc_status = chip->ecc.correct(mtd, &data_poi[datidx], &ecc_code[j], &ecc_calc[j]);
1168 1152
1169 /* Get next chunk of ecc bytes */ 1153 while(1) {
1170 j += eccbytes; 1154 bytes = min(mtd->writesize - col, readlen);
1155 aligned = (bytes == mtd->writesize);
1171 1156
1172 /* Check, if we have a fs supplied oob-buffer, 1157 /* Is the current page in the buffer ? */
1173 * This is the legacy mode. Used by YAFFS1 1158 if (realpage != chip->pagebuf) {
1174 * Should go away some day 1159 bufpoi = aligned ? buf : chip->data_buf;
1175 */
1176 if (oob_buf && oobsel->useecc == MTD_NANDECC_PLACE) {
1177 int *p = (int *)(&oob_data[mtd->oobsize]);
1178 p[i] = ecc_status;
1179 }
1180 1160
1181 if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) { 1161 if (likely(sndcmd)) {
1182 DEBUG(MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); 1162 chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
1183 ecc_failed++; 1163 sndcmd = 0;
1184 } 1164 }
1185 }
1186 1165
1187 readoob: 1166 /* Now read the page into the buffer */
1188 /* check, if we have a fs supplied oob-buffer */ 1167 ret = chip->ecc.read_page(mtd, chip, bufpoi);
1189 if (oob_buf) { 1168 if (ret < 0)
1190 /* without autoplace. Legacy mode used by YAFFS1 */
1191 switch (oobsel->useecc) {
1192 case MTD_NANDECC_AUTOPLACE:
1193 case MTD_NANDECC_AUTOPL_USR:
1194 /* Walk through the autoplace chunks */
1195 for (i = 0; oobsel->oobfree[i][1]; i++) {
1196 int from = oobsel->oobfree[i][0];
1197 int num = oobsel->oobfree[i][1];
1198 memcpy(&oob_buf[oob], &oob_data[from], num);
1199 oob += num;
1200 }
1201 break; 1169 break;
1202 case MTD_NANDECC_PLACE: 1170
1203 /* YAFFS1 legacy mode */ 1171 /* Transfer not aligned data */
1204 oob_data += chip->ecc.steps * sizeof(int); 1172 if (!aligned) {
1205 default: 1173 chip->pagebuf = realpage;
1206 oob_data += mtd->oobsize; 1174 memcpy(buf, chip->data_buf + col, bytes);
1175 }
1176
1177 if (!(chip->options & NAND_NO_READRDY)) {
1178 /*
1179 * Apply delay or wait for ready/busy pin. Do
1180 * this before the AUTOINCR check, so no
1181 * problems arise if a chip which does auto
1182 * increment is marked as NOAUTOINCR by the
1183 * board driver.
1184 */
1185 if (!chip->dev_ready)
1186 udelay(chip->chip_delay);
1187 else
1188 nand_wait_ready(mtd);
1207 } 1189 }
1208 }
1209 readdata:
1210 /* Partial page read, transfer data into fs buffer */
1211 if (!aligned) {
1212 for (j = col; j < end && read < len; j++)
1213 buf[read++] = data_poi[j];
1214 chip->pagebuf = realpage;
1215 } else 1190 } else
1216 read += mtd->writesize; 1191 memcpy(buf, chip->data_buf + col, bytes);
1217 1192
1218 /* Apply delay or wait for ready/busy pin 1193 buf += bytes;
1219 * Do this before the AUTOINCR check, so no problems 1194 readlen -= bytes;
1220 * arise if a chip which does auto increment
1221 * is marked as NOAUTOINCR by the board driver.
1222 */
1223 if (!chip->dev_ready)
1224 udelay(chip->chip_delay);
1225 else
1226 nand_wait_ready(mtd);
1227 1195
1228 if (read == len) 1196 if (!readlen)
1229 break; 1197 break;
1230 1198
1231 /* For subsequent reads align to page boundary. */ 1199 /* For subsequent reads align to page boundary. */
@@ -1240,24 +1208,51 @@ int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len,
1240 chip->select_chip(mtd, -1); 1208 chip->select_chip(mtd, -1);
1241 chip->select_chip(mtd, chipnr); 1209 chip->select_chip(mtd, chipnr);
1242 } 1210 }
1211
1243 /* Check, if the chip supports auto page increment 1212 /* Check, if the chip supports auto page increment
1244 * or if we have hit a block boundary. 1213 * or if we have hit a block boundary.
1245 */ 1214 */
1246 if (!NAND_CANAUTOINCR(chip) || !(page & blockcheck)) 1215 if (!NAND_CANAUTOINCR(chip) || !(page & blkcheck))
1247 sndcmd = 1; 1216 sndcmd = 1;
1248 } 1217 }
1249 1218
1250 /* Deselect and wake up anyone waiting on the device */ 1219 *retlen = len - (size_t) readlen;
1251 if (flags & NAND_GET_DEVICE)
1252 nand_release_device(mtd);
1253 1220
1254 /* 1221 if (ret)
1255 * Return success, if no ECC failures, else -EBADMSG 1222 return ret;
1256 * fs driver will take care of that, because 1223
1257 * retlen == desired len and result == -EBADMSG 1224 return mtd->ecc_stats.failed - stats.failed ? -EBADMSG : 0;
1258 */ 1225}
1259 *retlen = read; 1226
1260 return ecc_failed ? -EBADMSG : 0; 1227/**
1228 * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
1229 * @mtd: MTD device structure
1230 * @from: offset to read from
1231 * @len: number of bytes to read
1232 * @retlen: pointer to variable to store the number of read bytes
1233 * @buf: the databuffer to put data
1234 *
1235 * Get hold of the chip and call nand_do_read
1236 */
1237static int nand_read(struct mtd_info *mtd, loff_t from, size_t len,
1238 size_t *retlen, uint8_t *buf)
1239{
1240 int ret;
1241
1242 *retlen = 0;
1243 /* Do not allow reads past end of device */
1244 if ((from + len) > mtd->size)
1245 return -EINVAL;
1246 if (!len)
1247 return 0;
1248
1249 nand_get_device(mtd->priv, mtd, FL_READING);
1250
1251 ret = nand_do_read(mtd, from, len, retlen, buf);
1252
1253 nand_release_device(mtd);
1254
1255 return ret;
1261} 1256}
1262 1257
1263/** 1258/**
@@ -2417,6 +2412,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2417 */ 2412 */
2418 switch (chip->ecc.mode) { 2413 switch (chip->ecc.mode) {
2419 case NAND_ECC_HW: 2414 case NAND_ECC_HW:
2415 /* Use standard hwecc read page function ? */
2416 if (!chip->ecc.read_page)
2417 chip->ecc.read_page = nand_read_page_hwecc;
2418
2420 case NAND_ECC_HW_SYNDROME: 2419 case NAND_ECC_HW_SYNDROME:
2421 if (!chip->ecc.calculate || !chip->ecc.correct || 2420 if (!chip->ecc.calculate || !chip->ecc.correct ||
2422 !chip->ecc.hwctl) { 2421 !chip->ecc.hwctl) {
@@ -2424,6 +2423,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2424 "Hardware ECC not possible\n"); 2423 "Hardware ECC not possible\n");
2425 BUG(); 2424 BUG();
2426 } 2425 }
2426 /* Use standard syndrome read page function ? */
2427 if (!chip->ecc.read_page)
2428 chip->ecc.read_page = nand_read_page_syndrome;
2429
2427 if (mtd->writesize >= chip->ecc.size) 2430 if (mtd->writesize >= chip->ecc.size)
2428 break; 2431 break;
2429 printk(KERN_WARNING "%d byte HW ECC not possible on " 2432 printk(KERN_WARNING "%d byte HW ECC not possible on "
@@ -2434,6 +2437,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2434 case NAND_ECC_SOFT: 2437 case NAND_ECC_SOFT:
2435 chip->ecc.calculate = nand_calculate_ecc; 2438 chip->ecc.calculate = nand_calculate_ecc;
2436 chip->ecc.correct = nand_correct_data; 2439 chip->ecc.correct = nand_correct_data;
2440 chip->ecc.read_page = nand_read_page_swecc;
2437 chip->ecc.size = 256; 2441 chip->ecc.size = 256;
2438 chip->ecc.bytes = 3; 2442 chip->ecc.bytes = 3;
2439 break; 2443 break;
@@ -2441,6 +2445,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2441 case NAND_ECC_NONE: 2445 case NAND_ECC_NONE:
2442 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. " 2446 printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
2443 "This is not recommended !!\n"); 2447 "This is not recommended !!\n");
2448 chip->ecc.read_page = nand_read_page_swecc;
2444 chip->ecc.size = mtd->writesize; 2449 chip->ecc.size = mtd->writesize;
2445 chip->ecc.bytes = 0; 2450 chip->ecc.bytes = 0;
2446 break; 2451 break;
@@ -2459,6 +2464,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
2459 printk(KERN_WARNING "Invalid ecc parameters\n"); 2464 printk(KERN_WARNING "Invalid ecc parameters\n");
2460 BUG(); 2465 BUG();
2461 } 2466 }
2467 chip->ecc.total = chip->ecc.steps * chip->ecc.bytes;
2462 2468
2463 /* Initialize state */ 2469 /* Initialize state */
2464 chip->state = FL_READY; 2470 chip->state = FL_READY;
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index 6c97bfaea19a..b7083104a05b 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -444,7 +444,8 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
444 * note: see pages 34..37 of data sheet for details. 444 * note: see pages 34..37 of data sheet for details.
445 * 445 *
446 */ 446 */
447static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) 447static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this,
448 int state, int status, int page)
448{ 449{
449 int er_stat = 0; 450 int er_stat = 0;
450 int rtn, retlen; 451 int rtn, retlen;
@@ -455,39 +456,50 @@ static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int s
455 this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1); 456 this->cmdfunc(mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
456 457
457 if (state == FL_ERASING) { 458 if (state == FL_ERASING) {
459
458 for (i = 0; i < 4; i++) { 460 for (i = 0; i < 4; i++) {
459 if (status & 1 << (i + 1)) { 461 if (!(status & 1 << (i + 1)))
460 this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1); 462 continue;
461 rtn = this->read_byte(mtd); 463 this->cmdfunc(mtd, (NAND_CMD_STATUS_ERROR + i + 1),
462 this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); 464 -1, -1);
463 if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { 465 rtn = this->read_byte(mtd);
464 er_stat |= 1 << (i + 1); /* err_ecc_not_avail */ 466 this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
465 } 467
466 } 468 /* err_ecc_not_avail */
469 if (!(rtn & ERR_STAT_ECC_AVAILABLE))
470 er_stat |= 1 << (i + 1);
467 } 471 }
472
468 } else if (state == FL_WRITING) { 473 } else if (state == FL_WRITING) {
474
475 unsigned long corrected = mtd->ecc_stats.corrected;
476
469 /* single bank write logic */ 477 /* single bank write logic */
470 this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1); 478 this->cmdfunc(mtd, NAND_CMD_STATUS_ERROR, -1, -1);
471 rtn = this->read_byte(mtd); 479 rtn = this->read_byte(mtd);
472 this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1); 480 this->cmdfunc(mtd, NAND_CMD_STATUS_RESET, -1, -1);
481
473 if (!(rtn & ERR_STAT_ECC_AVAILABLE)) { 482 if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
474 er_stat |= 1 << 1; /* err_ecc_not_avail */ 483 /* err_ecc_not_avail */
475 } else { 484 er_stat |= 1 << 1;
476 len = mtd->writesize; 485 goto out;
477 buf = kmalloc(len, GFP_KERNEL);
478 if (!buf) {
479 printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");
480 er_stat = 1; /* if we can't check, assume failed */
481 } else {
482 /* recovery read */
483 /* page read */
484 rtn = nand_do_read_ecc(mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
485 if (rtn) { /* if read failed or > 1-bit error corrected */
486 er_stat |= 1 << 1; /* ECC read failed */
487 }
488 kfree(buf);
489 }
490 } 486 }
487
488 len = mtd->writesize;
489 buf = kmalloc(len, GFP_KERNEL);
490 if (!buf) {
491 printk(KERN_ERR "rtc_from4_errstat: Out of memory!\n");
492 er_stat = 1;
493 goto out;
494 }
495
496 /* recovery read */
497 rtn = nand_do_read(mtd, page, len, &retlen, buf);
498
499 /* if read failed or > 1-bit error corrected */
500 if (rtn || (mtd->ecc_stats.corrected - corrected) > 1) {
501 er_stat |= 1 << 1;
502 kfree(buf);
491 } 503 }
492 504
493 rtn = status; 505 rtn = status;