aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@cruncher.tec.linutronix.de>2006-06-20 14:05:05 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-06-20 15:31:24 -0400
commit7bc3312bef4d6f220812500c0de7868fb7625a41 (patch)
tree9ad49e850cdfe9868a19a37681bbf4d403e47ed3
parent7e4178f90eec862affc97469118d5008bd1b5bda (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.c8
-rw-r--r--drivers/mtd/nand/diskonchip.c2
-rw-r--r--drivers/mtd/nand/nand_base.c297
-rw-r--r--include/linux/mtd/nand.h12
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
467static int doc200x_wait(struct mtd_info *mtd, struct nand_chip *this, int state) 467static 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*/
699static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip, int state) 706static 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 */
1109static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
1110 int page, int sndcmd)
1111{