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 | { | ||
