diff options
author | Thomas Gleixner <tglx@cruncher.tec.linutronix.de> | 2006-06-20 14:05:05 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@infradead.org> | 2006-06-20 15:31:24 -0400 |
commit | 7bc3312bef4d6f220812500c0de7868fb7625a41 (patch) | |
tree | 9ad49e850cdfe9868a19a37681bbf4d403e47ed3 | |
parent | 7e4178f90eec862affc97469118d5008bd1b5bda (diff) |
[MTD] NAND: Fix breakage all over the place
Following problems are addressed:
- wrong status caused early break out of nand_wait()
- removed the bogus status check in nand_wait() which
is a relict of the abandoned support for interrupted
erase.
- status check moved to the correct place in read_oob
- oob support for syndrom based ecc with strange layouts
- use given offset in the AUTOOOB based oob operations
Partially based on a patch from Vitaly Vool <vwool@ru.mvista.com>
Thanks to Savin Zlobec <savin@epico.si> for tracking down the
status problem.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | drivers/mtd/mtdchar.c | 8 | ||||
-rw-r--r-- | drivers/mtd/nand/diskonchip.c | 2 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 297 | ||||
-rw-r--r-- | include/linux/mtd/nand.h | 12 |
4 files changed, 231 insertions, 88 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 5dd0b8d72c8b..aa18d45b264b 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c | |||
@@ -504,12 +504,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
504 | return ret; | 504 | return ret; |
505 | 505 | ||
506 | ops.len = buf.length; | 506 | ops.len = buf.length; |
507 | ops.ooblen = mtd->oobsize; | 507 | ops.ooblen = buf.length; |
508 | ops.ooboffs = buf.start & (mtd->oobsize - 1); | 508 | ops.ooboffs = buf.start & (mtd->oobsize - 1); |
509 | ops.datbuf = NULL; | 509 | ops.datbuf = NULL; |
510 | ops.mode = MTD_OOB_PLACE; | 510 | ops.mode = MTD_OOB_PLACE; |
511 | 511 | ||
512 | if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs)) | 512 | if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs)) |
513 | return -EINVAL; | 513 | return -EINVAL; |
514 | 514 | ||
515 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); | 515 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); |
@@ -553,12 +553,12 @@ static int mtd_ioctl(struct inode *inode, struct file *file, | |||
553 | return ret; | 553 | return ret; |
554 | 554 | ||
555 | ops.len = buf.length; | 555 | ops.len = buf.length; |
556 | ops.ooblen = mtd->oobsize; | 556 | ops.ooblen = buf.length; |
557 | ops.ooboffs = buf.start & (mtd->oobsize - 1); | 557 | ops.ooboffs = buf.start & (mtd->oobsize - 1); |
558 | ops.datbuf = NULL; | 558 | ops.datbuf = NULL; |
559 | ops.mode = MTD_OOB_PLACE; | 559 | ops.mode = MTD_OOB_PLACE; |
560 | 560 | ||
561 | if (ops.ooboffs && ops.len > (ops.ooblen - ops.ooboffs)) | 561 | if (ops.ooboffs && ops.len > (mtd->oobsize - ops.ooboffs)) |
562 | return -EINVAL; | 562 | return -EINVAL; |
563 | 563 | ||
564 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); | 564 | ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); |
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c index 463e12ced1b3..6107f532855b 100644 --- a/drivers/mtd/nand/diskonchip.c +++ b/drivers/mtd/nand/diskonchip.c | |||
@@ -464,7 +464,7 @@ static void __init doc2000_count_chips(struct mtd_info *mtd) | |||
464 | printk(KERN_DEBUG "Detected %d chips per floor.\n", i); | 464 | printk(KERN_DEBUG "Detected %d chips per floor.\n", i); |
465 | } | 465 | } |
466 | 466 | ||
467 | static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) | 467 | static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this) |
468 | { | 468 | { |
469 | struct doc_priv *doc = this->priv; | 469 | struct doc_priv *doc = this->priv; |
470 | 470 | ||
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e74678e928cf..27083ed0a017 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -501,7 +501,6 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, | |||
501 | case NAND_CMD_ERASE2: | 501 | case NAND_CMD_ERASE2: |
502 | case NAND_CMD_SEQIN: | 502 | case NAND_CMD_SEQIN: |
503 | case NAND_CMD_STATUS: | 503 | case NAND_CMD_STATUS: |
504 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE); | ||
505 | return; | 504 | return; |
506 | 505 | ||
507 | case NAND_CMD_RESET: | 506 | case NAND_CMD_RESET: |
@@ -595,6 +594,7 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, | |||
595 | case NAND_CMD_ERASE1: | 594 | case NAND_CMD_ERASE1: |
596 | case NAND_CMD_ERASE2: | 595 | case NAND_CMD_ERASE2: |
597 | case NAND_CMD_SEQIN: | 596 | case NAND_CMD_SEQIN: |
597 | case NAND_CMD_RNDIN: | ||
598 | case NAND_CMD_STATUS: | 598 | case NAND_CMD_STATUS: |
599 | case NAND_CMD_DEPLETE1: | 599 | case NAND_CMD_DEPLETE1: |
600 | return; | 600 | return; |
@@ -621,6 +621,14 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, | |||
621 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; | 621 | while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) ; |
622 | return; | 622 | return; |
623 | 623 | ||
624 | case NAND_CMD_RNDOUT: | ||
625 | /* No ready / busy check necessary */ | ||
626 | chip->cmd_ctrl(mtd, NAND_CMD_RNDOUTSTART, | ||
627 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); | ||
628 | chip->cmd_ctrl(mtd, NAND_CMD_NONE, | ||
629 | NAND_NCE | NAND_CTRL_CHANGE); | ||
630 | return; | ||
631 | |||
624 | case NAND_CMD_READ0: | 632 | case NAND_CMD_READ0: |
625 | chip->cmd_ctrl(mtd, NAND_CMD_READSTART, | 633 | chip->cmd_ctrl(mtd, NAND_CMD_READSTART, |
626 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); | 634 | NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); |
@@ -689,18 +697,17 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | |||
689 | * nand_wait - [DEFAULT] wait until the command is done | 697 | * nand_wait - [DEFAULT] wait until the command is done |
690 | * @mtd: MTD device structure | 698 | * @mtd: MTD device structure |
691 | * @this: NAND chip structure | 699 | * @this: NAND chip structure |
692 | * @state: state to select the max. timeout value | ||
693 | * | 700 | * |
694 | * Wait for command done. This applies to erase and program only | 701 | * Wait for command done. This applies to erase and program only |
695 | * Erase can take up to 400ms and program up to 20ms according to | 702 | * Erase can take up to 400ms and program up to 20ms according to |
696 | * general NAND and SmartMedia specs | 703 | * general NAND and SmartMedia specs |
697 | * | 704 | * |
698 | */ | 705 | */ |
699 | static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state) | 706 | static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) |
700 | { | 707 | { |
701 | 708 | ||
702 | unsigned long timeo = jiffies; | 709 | unsigned long timeo = jiffies; |
703 | int status; | 710 | int status, state = chip->state; |
704 | 711 | ||
705 | if (state == FL_ERASING) | 712 | if (state == FL_ERASING) |
706 | timeo += (HZ * 400) / 1000; | 713 | timeo += (HZ * 400) / 1000; |
@@ -719,10 +726,6 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state) | |||
719 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | 726 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); |
720 | 727 | ||
721 | while (time_before(jiffies, timeo)) { | 728 | while (time_before(jiffies, timeo)) { |
722 | /* Check, if we were interrupted */ | ||
723 | if (chip->state != state) | ||
724 | return 0; | ||
725 | |||
726 | if (chip->dev_ready) { | 729 | if (chip->dev_ready) { |
727 | if (chip->dev_ready(mtd)) | 730 | if (chip->dev_ready(mtd)) |
728 | break; | 731 | break; |
@@ -909,12 +912,25 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob, | |||
909 | 912 | ||
910 | case MTD_OOB_AUTO: { | 913 | case MTD_OOB_AUTO: { |
911 | struct nand_oobfree *free = chip->ecc.layout->oobfree; | 914 | struct nand_oobfree *free = chip->ecc.layout->oobfree; |
912 | size_t bytes; | 915 | uint32_t boffs = 0, roffs = ops->ooboffs; |
916 | size_t bytes = 0; | ||
913 | 917 | ||
914 | for(; free->length && len; free++, len -= bytes) { | 918 | for(; free->length && len; free++, len -= bytes) { |
915 | bytes = min_t(size_t, len, free->length); | 919 | /* Read request not from offset 0 ? */ |
916 | 920 | if (unlikely(roffs)) { | |
917 | memcpy(oob, chip->oob_poi + free->offset, bytes); | 921 | if (roffs >= free->length) { |
922 | roffs -= free->length; | ||
923 | continue; | ||
924 | } | ||
925 | boffs = free->offset + roffs; | ||
926 | bytes = min_t(size_t, len, | ||
927 | (free->length - roffs)); | ||
928 | roffs = 0; | ||
929 | } else { | ||
930 | bytes = min_t(size_t, len, free->length); | ||
931 | boffs = free->offset; | ||
932 | } | ||
933 | memcpy(oob, chip->oob_poi + boffs, bytes); | ||
918 | oob += bytes; | 934 | oob += bytes; |
919 | } | 935 | } |
920 | return oob; | 936 | return oob; |
@@ -1084,6 +1100,145 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1084 | } | 1100 | } |
1085 | 1101 | ||
1086 | /** | 1102 | /** |
1103 | * nand_read_oob_std - [REPLACABLE] the most common OOB data read function | ||
1104 | * @mtd: mtd info structure | ||
1105 | * @chip: nand chip info structure | ||
1106 | * @page: page number to read | ||
1107 | * @sndcmd: flag whether to issue read command or not | ||
1108 | */ | ||
1109 | static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip, | ||
1110 | int page, int sndcmd) | ||
1111 | { | ||
1112 | if (sndcmd) { | ||
1113 | chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page); | ||
1114 | sndcmd = 0; | ||
1115 | } | ||
1116 | chip->read_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
1117 | return sndcmd; | ||
1118 | } | ||
1119 | |||
1120 | /** | ||
1121 | * nand_read_oob_syndrome - [REPLACABLE] OOB data read function for HW ECC | ||
1122 | * with syndromes | ||
1123 | * @mtd: mtd info structure | ||
1124 | * @chip: nand chip info structure | ||
1125 | * @page: page number to read | ||
1126 | * @sndcmd: flag whether to issue read command or not | ||
1127 | */ | ||
1128 | static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip, | ||
1129 | int page, int sndcmd) | ||
1130 | { | ||
1131 | uint8_t *buf = chip->oob_poi; | ||
1132 | int length = mtd->oobsize; | ||
1133 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | ||
1134 | int eccsize = chip->ecc.size; | ||
1135 | uint8_t *bufpoi = buf; | ||
1136 | int i, toread, sndrnd = 0, pos; | ||
1137 | |||
1138 | chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page); | ||
1139 | for (i = 0; i < chip->ecc.steps; i++) { | ||
1140 | if (sndrnd) { | ||
1141 | pos = eccsize + i * (eccsize + chunk); | ||
1142 | if (mtd->writesize > 512) | ||
1143 | chip->cmdfunc(mtd, NAND_CMD_RNDOUT, pos, -1); | ||
1144 | else | ||
1145 | chip->cmdfunc(mtd, NAND_CMD_READ0, pos, page); | ||
1146 | } else | ||
1147 | sndrnd = 1; | ||
1148 | toread = min_t(int, length, chunk); | ||
1149 | chip->read_buf(mtd, bufpoi, toread); | ||
1150 | bufpoi += toread; | ||
1151 | length -= toread; | ||
1152 | } | ||
1153 | if (length > 0) | ||
1154 | chip->read_buf(mtd, bufpoi, length); | ||
1155 | |||
1156 | return 1; | ||
1157 | } | ||
1158 | |||
1159 | /** | ||
1160 | * nand_write_oob_std - [REPLACABLE] the most common OOB data write function | ||
1161 | * @mtd: mtd info structure | ||
1162 | * @chip: nand chip info structure | ||
1163 | * @page: page number to write | ||
1164 | */ | ||
1165 | static int nand_write_oob_std(struct mtd_info *mtd, struct nand_chip *chip, | ||
1166 | int page) | ||
1167 | { | ||
1168 | int status = 0; | ||
1169 | const uint8_t *buf = chip->oob_poi; | ||
1170 | int length = mtd->oobsize; | ||
1171 | |||
1172 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, page); | ||
1173 | chip->write_buf(mtd, buf, length); | ||
1174 | /* Send command to program the OOB data */ | ||
1175 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
1176 | |||
1177 | status = chip->waitfunc(mtd, chip); | ||
1178 | |||
1179 | return status; | ||
1180 | } | ||
1181 | |||
1182 | /** | ||
1183 | * nand_write_oob_syndrome - [REPLACABLE] OOB data write function for HW ECC | ||
1184 | * with syndrome - only for large page flash ! | ||
1185 | * @mtd: mtd info structure | ||
1186 | * @chip: nand chip info structure | ||
1187 | * @page: page number to write | ||
1188 | */ | ||
1189 | static int nand_write_oob_syndrome(struct mtd_info *mtd, | ||
1190 | struct nand_chip *chip, int page) | ||
1191 | { | ||
1192 | int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad; | ||
1193 | int eccsize = chip->ecc.size, length = mtd->oobsize; | ||
1194 | int i, len, pos, status = 0, sndcmd = 0, steps = chip->ecc.steps; | ||
1195 | const uint8_t *bufpoi = chip->oob_poi; | ||
1196 | |||
1197 | /* | ||
1198 | * data-ecc-data-ecc ... ecc-oob | ||
1199 | * or | ||
1200 | * data-pad-ecc-pad-data-pad .... ecc-pad-oob | ||
1201 | */ | ||
1202 | if (!chip->ecc.prepad && !chip->ecc.postpad) { | ||
1203 | pos = steps * (eccsize + chunk); | ||
1204 | steps = 0; | ||
1205 | } else | ||
1206 | pos = eccsize + chunk; | ||
1207 | |||
1208 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, pos, page); | ||
1209 | for (i = 0; i < steps; i++) { | ||
1210 | if (sndcmd) { | ||
1211 | if (mtd->writesize <= 512) { | ||
1212 | uint32_t fill = 0xFFFFFFFF; | ||
1213 | |||
1214 | len = eccsize; | ||
1215 | while (len > 0) { | ||
1216 | int num = min_t(int, len, 4); | ||
1217 | chip->write_buf(mtd, (uint8_t *)&fill, | ||
1218 | num); | ||
1219 | len -= num; | ||
1220 | } | ||
1221 | } else { | ||
1222 | pos = eccsize + i * (eccsize + chunk); | ||
1223 | chip->cmdfunc(mtd, NAND_CMD_RNDIN, pos, -1); | ||
1224 | } | ||
1225 | } else | ||
1226 | sndcmd = 1; | ||
1227 | len = min_t(int, length, chunk); | ||
1228 | chip->write_buf(mtd, bufpoi, len); | ||
1229 | bufpoi += len; | ||
1230 | length -= len; | ||
1231 | } | ||
1232 | if (length > 0) | ||
1233 | chip->write_buf(mtd, bufpoi, length); | ||
1234 | |||
1235 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
1236 | status = chip->waitfunc(mtd, chip); | ||
1237 | |||
1238 | return status & NAND_STATUS_FAIL ? -EIO : 0; | ||
1239 | } | ||
1240 | |||
1241 | /** | ||
1087 | * nand_do_read_oob - [Intern] NAND read out-of-band | 1242 | * nand_do_read_oob - [Intern] NAND read out-of-band |
1088 | * @mtd: MTD device structure | 1243 | * @mtd: MTD device structure |
1089 | * @from: offset to read from | 1244 | * @from: offset to read from |
@@ -1094,11 +1249,11 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, | |||
1094 | static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | 1249 | static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, |
1095 | struct mtd_oob_ops *ops) | 1250 | struct mtd_oob_ops *ops) |
1096 | { | 1251 | { |
1097 | int col, page, realpage, chipnr, sndcmd = 1; | 1252 | int page, realpage, chipnr, sndcmd = 1; |
1098 | struct nand_chip *chip = mtd->priv; | 1253 | struct nand_chip *chip = mtd->priv; |
1099 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; | 1254 | int blkcheck = (1 << (chip->phys_erase_shift - chip->page_shift)) - 1; |
1100 | int direct, bytes, readlen = ops->len; | 1255 | int readlen = ops->len; |
1101 | uint8_t *bufpoi, *buf = ops->oobbuf; | 1256 | uint8_t *buf = ops->oobbuf; |
1102 | 1257 | ||
1103 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", | 1258 | DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n", |
1104 | (unsigned long long)from, readlen); | 1259 | (unsigned long long)from, readlen); |
@@ -1110,29 +1265,11 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from, | |||
1110 | realpage = (int)(from >> chip->page_shift); | 1265 | realpage = (int)(from >> chip->page_shift); |
1111 | page = realpage & chip->pagemask; | 1266 | page = realpage & chip->pagemask; |
1112 | 1267 | ||
1113 | if (ops->mode != MTD_OOB_AUTO) { | 1268 | chip->oob_poi = chip->buffers.oobrbuf; |
1114 | col = ops->ooboffs; | ||
1115 | direct = 1; | ||
1116 | } else { | ||
1117 | col = 0; | ||
1118 | direct = 0; | ||
1119 | } | ||
1120 | 1269 | ||
1121 | while(1) { | 1270 | while(1) { |
1122 | bytes = direct ? ops->ooblen : mtd->oobsize; | 1271 | sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd); |
1123 | bufpoi = direct ? buf : chip->buffers.oobrbuf; | 1272 | buf = nand_transfer_oob(chip, buf, ops); |
1124 | |||
1125 | if (likely(sndcmd)) { | ||
1126 | chip->cmdfunc(mtd, NAND_CMD_READOOB, col, page); | ||
1127 | sndcmd = 0; | ||
1128 | } | ||
1129 | |||
1130 | chip->read_buf(mtd, bufpoi, bytes); | ||
1131 | |||
1132 | if (unlikely(!direct)) | ||
1133 | buf = nand_transfer_oob(chip, buf, ops); | ||
1134 | else | ||
1135 | buf += ops->ooblen; | ||
1136 | 1273 | ||
1137 | readlen -= ops->ooblen; | 1274 | readlen -= ops->ooblen; |
1138 | if (!readlen) | 1275 | if (!readlen) |
@@ -1365,7 +1502,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
1365 | if (!cached || !(chip->options & NAND_CACHEPRG)) { | 1502 | if (!cached || !(chip->options & NAND_CACHEPRG)) { |
1366 | 1503 | ||
1367 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | 1504 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); |
1368 | status = chip->waitfunc(mtd, chip, FL_WRITING); | 1505 | status = chip->waitfunc(mtd, chip); |
1369 | /* | 1506 | /* |
1370 | * See if operation failed and additional status checks are | 1507 | * See if operation failed and additional status checks are |
1371 | * available | 1508 | * available |
@@ -1378,7 +1515,7 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, | |||
1378 | return -EIO; | 1515 | return -EIO; |
1379 | } else { | 1516 | } else { |
1380 | chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); | 1517 | chip->cmdfunc(mtd, NAND_CMD_CACHEDPROG, -1, -1); |
1381 | status = chip->waitfunc(mtd, chip, FL_WRITING); | 1518 | status = chip->waitfunc(mtd, chip); |
1382 | } | 1519 | } |
1383 | 1520 | ||
1384 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 1521 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE |
@@ -1411,11 +1548,25 @@ static uint8_t *nand_fill_oob(struct nand_chip *chip, uint8_t *oob, | |||
1411 | 1548 | ||
1412 | case MTD_OOB_AUTO: { | 1549 | case MTD_OOB_AUTO: { |
1413 | struct nand_oobfree *free = chip->ecc.layout->oobfree; | 1550 | struct nand_oobfree *free = chip->ecc.layout->oobfree; |
1414 | size_t bytes; | 1551 | uint32_t boffs = 0, woffs = ops->ooboffs; |
1552 | size_t bytes = 0; | ||
1415 | 1553 | ||
1416 | for(; free->length && len; free++, len -= bytes) { | 1554 | for(; free->length && len; free++, len -= bytes) { |
1417 | bytes = min_t(size_t, len, free->length); | 1555 | /* Write request not from offset 0 ? */ |
1418 | memcpy(chip->oob_poi + free->offset, oob, bytes); | 1556 | if (unlikely(woffs)) { |
1557 | if (woffs >= free->length) { | ||
1558 | woffs -= free->length; | ||
1559 | continue; | ||
1560 | } | ||
1561 | boffs = free->offset + woffs; | ||
1562 | bytes = min_t(size_t, len, | ||
1563 | (free->length - woffs)); | ||
1564 | woffs = 0; | ||
1565 | } else { | ||
1566 | bytes = min_t(size_t, len, free->length); | ||
1567 | boffs = free->offset; | ||
1568 | } | ||
1569 | memcpy(chip->oob_poi + woffs, oob, bytes); | ||
1419 | oob += bytes; | 1570 | oob += bytes; |
1420 | } | 1571 | } |
1421 | return oob; | 1572 | return oob; |
@@ -1532,7 +1683,7 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
1532 | if (!len) | 1683 | if (!len) |
1533 | return 0; | 1684 | return 0; |
1534 | 1685 | ||
1535 | nand_get_device(chip, mtd, FL_READING); | 1686 | nand_get_device(chip, mtd, FL_WRITING); |
1536 | 1687 | ||
1537 | chip->ops.len = len; | 1688 | chip->ops.len = len; |
1538 | chip->ops.datbuf = (uint8_t *)buf; | 1689 | chip->ops.datbuf = (uint8_t *)buf; |
@@ -1592,48 +1743,18 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to, | |||
1592 | if (page == chip->pagebuf) | 1743 | if (page == chip->pagebuf) |
1593 | chip->pagebuf = -1; | 1744 | chip->pagebuf = -1; |
1594 | 1745 | ||
1595 | if (ops->mode == MTD_OOB_AUTO || NAND_MUST_PAD(chip)) { | 1746 | chip->oob_poi = chip->buffers.oobwbuf; |
1596 | chip->oob_poi = chip->buffers.oobwbuf; | 1747 | memset(chip->oob_poi, 0xff, mtd->oobsize); |
1597 | memset(chip->oob_poi, 0xff, mtd->oobsize); | 1748 | nand_fill_oob(chip, ops->oobbuf, ops); |
1598 | nand_fill_oob(chip, ops->oobbuf, ops); | 1749 | status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask); |
1599 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, mtd->writesize, | 1750 | memset(chip->oob_poi, 0xff, mtd->oobsize); |
1600 | page & chip->pagemask); | ||
1601 | chip->write_buf(mtd, chip->oob_poi, mtd->oobsize); | ||
1602 | memset(chip->oob_poi, 0xff, mtd->oobsize); | ||
1603 | } else { | ||
1604 | chip->cmdfunc(mtd, NAND_CMD_SEQIN, | ||
1605 | mtd->writesize + ops->ooboffs, | ||
1606 | page & chip->pagemask); | ||
1607 | chip->write_buf(mtd, ops->oobbuf, ops->len); | ||
1608 | } | ||
1609 | |||
1610 | /* Send command to program the OOB data */ | ||
1611 | chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); | ||
1612 | 1751 | ||
1613 | status = chip->waitfunc(mtd, chip, FL_WRITING); | 1752 | if (status) |
1753 | return status; | ||
1614 | 1754 | ||
1615 | /* See if device thinks it succeeded */ | ||
1616 | if (status & NAND_STATUS_FAIL) { | ||
1617 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | ||
1618 | "Failed write, page 0x%08x\n", page); | ||
1619 | return -EIO; | ||
1620 | } | ||
1621 | ops->retlen = ops->len; | 1755 | ops->retlen = ops->len; |
1622 | 1756 | ||
1623 | #ifdef CONFIG_MTD_NAND_VERIFY_WRITE | 1757 | return 0; |
1624 | if (ops->mode != MTD_OOB_AUTO) { | ||
1625 | /* Send command to read back the data */ | ||
1626 | chip->cmdfunc(mtd, NAND_CMD_READOOB, ops->ooboffs, | ||
1627 | page & chip->pagemask); | ||
1628 | |||
1629 | if (chip->verify_buf(mtd, ops->oobbuf, ops->len)) { | ||
1630 | DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: " | ||
1631 | "Failed write verify, page 0x%08x\n", page); | ||
1632 | return -EIO; | ||
1633 | } | ||
1634 | } | ||
1635 | #endif | ||
1636 | return 0; | ||
1637 | } | 1758 | } |
1638 | 1759 | ||
1639 | /** | 1760 | /** |
@@ -1659,7 +1780,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to, | |||
1659 | return -EINVAL; | 1780 | return -EINVAL; |
1660 | } | 1781 | } |
1661 | 1782 | ||
1662 | nand_get_device(chip, mtd, FL_READING); | 1783 | nand_get_device(chip, mtd, FL_WRITING); |
1663 | 1784 | ||
1664 | switch(ops->mode) { | 1785 | switch(ops->mode) { |
1665 | case MTD_OOB_PLACE: | 1786 | case MTD_OOB_PLACE: |
@@ -1833,7 +1954,7 @@ int nand_erase_nand(struct mtd_info *mtd, struct erase_info *instr, | |||
1833 | 1954 | ||
1834 | chip->erase_cmd(mtd, page & chip->pagemask); | 1955 | chip->erase_cmd(mtd, page & chip->pagemask); |
1835 | 1956 | ||
1836 | status = chip->waitfunc(mtd, chip, FL_ERASING); | 1957 | status = chip->waitfunc(mtd, chip); |
1837 | 1958 | ||
1838 | /* | 1959 | /* |
1839 | * See if operation failed and additional status checks are | 1960 | * See if operation failed and additional status checks are |
@@ -2265,6 +2386,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2265 | chip->ecc.read_page = nand_read_page_hwecc; | 2386 | chip->ecc.read_page = nand_read_page_hwecc; |
2266 | if (!chip->ecc.write_page) | 2387 | if (!chip->ecc.write_page) |
2267 | chip->ecc.write_page = nand_write_page_hwecc; | 2388 | chip->ecc.write_page = nand_write_page_hwecc; |
2389 | if (!chip->ecc.read_oob) | ||
2390 | chip->ecc.read_oob = nand_read_oob_std; | ||
2391 | if (!chip->ecc.write_oob) | ||
2392 | chip->ecc.write_oob = nand_write_oob_std; | ||
2268 | 2393 | ||
2269 | case NAND_ECC_HW_SYNDROME: | 2394 | case NAND_ECC_HW_SYNDROME: |
2270 | if (!chip->ecc.calculate || !chip->ecc.correct || | 2395 | if (!chip->ecc.calculate || !chip->ecc.correct || |
@@ -2278,6 +2403,10 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2278 | chip->ecc.read_page = nand_read_page_syndrome; | 2403 | chip->ecc.read_page = nand_read_page_syndrome; |
2279 | if (!chip->ecc.write_page) | 2404 | if (!chip->ecc.write_page) |
2280 | chip->ecc.write_page = nand_write_page_syndrome; | 2405 | chip->ecc.write_page = nand_write_page_syndrome; |
2406 | if (!chip->ecc.read_oob) | ||
2407 | chip->ecc.read_oob = nand_read_oob_syndrome; | ||
2408 | if (!chip->ecc.write_oob) | ||
2409 | chip->ecc.write_oob = nand_write_oob_syndrome; | ||
2281 | 2410 | ||
2282 | if (mtd->writesize >= chip->ecc.size) | 2411 | if (mtd->writesize >= chip->ecc.size) |
2283 | break; | 2412 | break; |
@@ -2291,6 +2420,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2291 | chip->ecc.correct = nand_correct_data; | 2420 | chip->ecc.correct = nand_correct_data; |
2292 | chip->ecc.read_page = nand_read_page_swecc; | 2421 | chip->ecc.read_page = nand_read_page_swecc; |
2293 | chip->ecc.write_page = nand_write_page_swecc; | 2422 | chip->ecc.write_page = nand_write_page_swecc; |
2423 | chip->ecc.read_oob = nand_read_oob_std; | ||
2424 | chip->ecc.write_oob = nand_write_oob_std; | ||
2294 | chip->ecc.size = 256; | 2425 | chip->ecc.size = 256; |
2295 | chip->ecc.bytes = 3; | 2426 | chip->ecc.bytes = 3; |
2296 | break; | 2427 | break; |
@@ -2300,6 +2431,8 @@ int nand_scan(struct mtd_info *mtd, int maxchips) | |||
2300 | "This is not recommended !!\n"); | 2431 | "This is not recommended !!\n"); |
2301 | chip->ecc.read_page = nand_read_page_raw; | 2432 | chip->ecc.read_page = nand_read_page_raw; |
2302 | chip->ecc.write_page = nand_write_page_raw; | 2433 | chip->ecc.write_page = nand_write_page_raw; |
2434 | chip->ecc.read_oob = nand_read_oob_std; | ||
2435 | chip->ecc.write_oob = nand_write_oob_std; | ||
2303 | chip->ecc.size = mtd->writesize; | 2436 | chip->ecc.size = mtd->writesize; |
2304 | chip->ecc.bytes = 0; | 2437 | chip->ecc.bytes = 0; |
2305 | break; | 2438 | break; |
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index bf2ce68901f5..a30969eb9afe 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h | |||
@@ -63,18 +63,21 @@ extern void nand_release (struct mtd_info *mtd); | |||
63 | */ | 63 | */ |
64 | #define NAND_CMD_READ0 0 | 64 | #define NAND_CMD_READ0 0 |
65 | #define NAND_CMD_READ1 1 | 65 | #define NAND_CMD_READ1 1 |
66 | #define NAND_CMD_RNDOUT 5 | ||
66 | #define NAND_CMD_PAGEPROG 0x10 | 67 | #define NAND_CMD_PAGEPROG 0x10 |
67 | #define NAND_CMD_READOOB 0x50 | 68 | #define NAND_CMD_READOOB 0x50 |
68 | #define NAND_CMD_ERASE1 0x60 | 69 | #define NAND_CMD_ERASE1 0x60 |
69 | #define NAND_CMD_STATUS 0x70 | 70 | #define NAND_CMD_STATUS 0x70 |
70 | #define NAND_CMD_STATUS_MULTI 0x71 | 71 | #define NAND_CMD_STATUS_MULTI 0x71 |
71 | #define NAND_CMD_SEQIN 0x80 | 72 | #define NAND_CMD_SEQIN 0x80 |
73 | #define NAND_CMD_RNDIN 0x85 | ||
72 | #define NAND_CMD_READID 0x90 | 74 | #define NAND_CMD_READID 0x90 |
73 | #define NAND_CMD_ERASE2 0xd0 | 75 | #define NAND_CMD_ERASE2 0xd0 |
74 | #define NAND_CMD_RESET 0xff | 76 | #define NAND_CMD_RESET 0xff |
75 | 77 | ||
76 | /* Extended commands for large page devices */ | 78 | /* Extended commands for large page devices */ |
77 | #define NAND_CMD_READSTART 0x30 | 79 | #define NAND_CMD_READSTART 0x30 |
80 | #define NAND_CMD_RNDOUTSTART 0xE0 | ||
78 | #define NAND_CMD_CACHEDPROG 0x15 | 81 | #define NAND_CMD_CACHEDPROG 0x15 |
79 | 82 | ||
80 | /* Extended commands for AG-AND device */ | 83 | /* Extended commands for AG-AND device */ |
@@ -250,6 +253,13 @@ struct nand_ecc_ctrl { | |||
250 | void (*write_page)(struct mtd_info *mtd, | 253 | void (*write_page)(struct mtd_info *mtd, |
251 | struct nand_chip *chip, | 254 | struct nand_chip *chip, |
252 | const uint8_t *buf); | 255 | const uint8_t *buf); |
256 | int (*read_oob)(struct mtd_info *mtd, | ||
257 | struct nand_chip *chip, | ||
258 | int page, | ||
259 | int sndcmd); | ||
260 | int (*write_oob)(struct mtd_info *mtd, | ||
261 | struct nand_chip *chip, | ||
262 | int page); | ||
253 | }; | 263 | }; |
254 | 264 | ||
255 | /** | 265 | /** |
@@ -339,7 +349,7 @@ struct nand_chip { | |||
339 | unsigned int ctrl); | 349 | unsigned int ctrl); |
340 | int (*dev_ready)(struct mtd_info *mtd); | 350 | int (*dev_ready)(struct mtd_info *mtd); |
341 | void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); | 351 | void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); |
342 | int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); | 352 | int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this); |
343 | void (*erase_cmd)(struct mtd_info *mtd, int page); | 353 | void (*erase_cmd)(struct mtd_info *mtd, int page); |
344 | int (*scan_bbt)(struct mtd_info *mtd); | 354 | int (*scan_bbt)(struct mtd_info *mtd); |
345 | int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); | 355 | int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page); |