diff options
author | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-05-25 04:07:16 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-05-25 07:45:27 -0400 |
commit | f5bbdacc41939f89d8ccb18dd79cd9b21c0cb75d (patch) | |
tree | c9e45db9701c41c842282b0432d915cc9facc013 /drivers | |
parent | 9577f44a899cf4acb9e381c8946307b72153cd15 (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')
-rw-r--r-- | drivers/mtd/nand/diskonchip.c | 4 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 448 | ||||
-rw-r--r-- | drivers/mtd/nand/rtc_from4.c | 62 |
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 | ||
971 | static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) | 971 | static 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 | */ |
989 | static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, uint8_t *buf) | 984 | static 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 | */ |
1010 | int nand_do_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, | 1030 | static 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 | */ | ||
1075 | static 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); | 1131 | int 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 | */ | ||
1237 | static 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 | */ |
447 | static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page) | 447 | static 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; |