diff options
author | Simon Kagstrom <simon.kagstrom@netinsight.net> | 2009-10-05 09:55:52 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2009-11-30 04:46:39 -0500 |
commit | 2af7c653993199fb32dc6d9504064a0c9c57e5d6 (patch) | |
tree | e5a493617a93cacaa77016567df7281d720121b4 | |
parent | c9f7ec30848637989b85a9f0ac5d4aa33c49916e (diff) |
mtd: Add panic_write for NAND flashes
This is a quick and dirty patch to add panic_write for NAND flashes. The
patch seems to work OK on my CRIS board running a 2.6.26 kernel with a
ID: 0x20, Chip ID: 0xf1 (ST Micro NAND 128MiB 3,3V 8-bit), and also on a
OpenRD base (Marvell Kirkwood) board with a Toshiba NAND 512MiB 3,3V
8-bit flash with 2.6.32-pre1.
Signed-off-by: Edgar E. Iglesias <edgar@axis.com>
Signed-off-by: Simon Kagstrom <simon.kagstrom@netinsight.net>
Signed-off-by: Artem Bityutskiy <Artem.Bityutskiy@nokia.com>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 128 |
1 files changed, 120 insertions, 8 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 2957cc70da3d..ba06473326d1 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c | |||
@@ -428,6 +428,28 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip, | |||
428 | return nand_isbad_bbt(mtd, ofs, allowbbt); | 428 | return nand_isbad_bbt(mtd, ofs, allowbbt); |
429 | } | 429 | } |
430 | 430 | ||
431 | /** | ||
432 | * panic_nand_wait_ready - [GENERIC] Wait for the ready pin after commands. | ||
433 | * @mtd: MTD device structure | ||
434 | * @timeo: Timeout | ||
435 | * | ||
436 | * Helper function for nand_wait_ready used when needing to wait in interrupt | ||
437 | * context. | ||
438 | */ | ||
439 | static void panic_nand_wait_ready(struct mtd_info *mtd, unsigned long timeo) | ||
440 | { | ||
441 | struct nand_chip *chip = mtd->priv; | ||
442 | int i; | ||
443 | |||
444 | /* Wait for the device to get ready */ | ||
445 | for (i = 0; i < timeo; i++) { | ||
446 | if (chip->dev_ready(mtd)) | ||
447 | break; | ||
448 | touch_softlockup_watchdog(); | ||
449 | mdelay(1); | ||
450 | } | ||
451 | } | ||
452 | |||
431 | /* | 453 | /* |
432 | * Wait for the ready pin, after a command | 454 | * Wait for the ready pin, after a command |
433 | * The timeout is catched later. | 455 | * The timeout is catched later. |
@@ -437,6 +459,10 @@ void nand_wait_ready(struct mtd_info *mtd) | |||
437 | struct nand_chip *chip = mtd->priv; | 459 | struct nand_chip *chip = mtd->priv; |
438 | unsigned long timeo = jiffies + 2; | 460 | unsigned long timeo = jiffies + 2; |
439 | 461 | ||
462 | /* 400ms timeout */ | ||
463 | if (in_interrupt() || oops_in_progress) | ||
464 | return panic_nand_wait_ready(mtd, 400); | ||
465 | |||
440 | led_trigger_event(nand_led_trigger, LED_FULL); | 466 | led_trigger_event(nand_led_trigger, LED_FULL); |
441 | /* wait until command is processed or timeout occures */ | 467 | /* wait until command is processed or timeout occures */ |
442 | do { | 468 | do { |
@@ -672,6 +698,22 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, | |||
672 | } | 698 | } |
673 | 699 | ||
674 | /** | 700 | /** |
701 | * panic_nand_get_device - [GENERIC] Get chip for selected access | ||
702 | * @chip: the nand chip descriptor | ||
703 | * @mtd: MTD device structure | ||
704 | * @new_state: the state which is requested | ||
705 | * | ||
706 | * Used when in panic, no locks are taken. | ||
707 | */ | ||
708 | static void panic_nand_get_device(struct nand_chip *chip, | ||
709 | struct mtd_info *mtd, int new_state) | ||
710 | { | ||
711 | /* Hardware controller shared among independend devices */ | ||
712 | chip->controller->active = chip; | ||
713 | chip->state = new_state; | ||
714 | } | ||
715 | |||
716 | /** | ||
675 | * nand_get_device - [GENERIC] Get chip for selected access | 717 | * nand_get_device - [GENERIC] Get chip for selected access |
676 | * @chip: the nand chip descriptor | 718 | * @chip: the nand chip descriptor |
677 | * @mtd: MTD device structure | 719 | * @mtd: MTD device structure |
@@ -710,6 +752,32 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | |||
710 | } | 752 | } |
711 | 753 | ||
712 | /** | 754 | /** |
755 | * panic_nand_wait - [GENERIC] wait until the command is done | ||
756 | * @mtd: MTD device structure | ||
757 | * @chip: NAND chip structure | ||
758 | * @timeo: Timeout | ||
759 | * | ||
760 | * Wait for command done. This is a helper function for nand_wait used when | ||
761 | * we are in interrupt context. May happen when in panic and trying to write | ||
762 | * an oops trough mtdoops. | ||
763 | */ | ||
764 | static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, | ||
765 | unsigned long timeo) | ||
766 | { | ||
767 | int i; | ||
768 | for (i = 0; i < timeo; i++) { | ||
769 | if (chip->dev_ready) { | ||
770 | if (chip->dev_ready(mtd)) | ||
771 | break; | ||
772 | } else { | ||
773 | if (chip->read_byte(mtd) & NAND_STATUS_READY) | ||
774 | break; | ||
775 | } | ||
776 | mdelay(1); | ||
777 | } | ||
778 | } | ||
779 | |||
780 | /** | ||
713 | * nand_wait - [DEFAULT] wait until the command is done | 781 | * nand_wait - [DEFAULT] wait until the command is done |
714 | * @mtd: MTD device structure | 782 | * @mtd: MTD device structure |
715 | * @chip: NAND chip structure | 783 | * @chip: NAND chip structure |
@@ -740,15 +808,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
740 | else | 808 | else |
741 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | 809 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); |
742 | 810 | ||
743 | while (time_before(jiffies, timeo)) { | 811 | if (in_interrupt() || oops_in_progress) |
744 | if (chip->dev_ready) { | 812 | panic_nand_wait(mtd, chip, timeo); |
745 | if (chip->dev_ready(mtd)) | 813 | else { |
746 | break; | 814 | while (time_before(jiffies, timeo)) { |
747 | } else { | 815 | if (chip->dev_ready) { |
748 | if (chip->read_byte(mtd) & NAND_STATUS_READY) | 816 | if (chip->dev_ready(mtd)) |
749 | break; | 817 | break; |
818 | } else { | ||
819 | if (chip->read_byte(mtd) & NAND_STATUS_READY) | ||
820 | break; | ||
821 | } | ||
822 | cond_resched(); | ||
750 | } | 823 | } |
751 | cond_resched(); | ||
752 | } | 824 | } |
753 | led_trigger_event(nand_led_trigger, LED_OFF); | 825 | led_trigger_event(nand_led_trigger, LED_OFF); |
754 | 826 | ||
@@ -1949,6 +2021,45 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
1949 | } | 2021 | } |
1950 | 2022 | ||
1951 | /** | 2023 | /** |
2024 | * panic_nand_write - [MTD Interface] NAND write with ECC | ||
2025 | * @mtd: MTD device structure | ||
2026 | * @to: offset to write to | ||
2027 | * @len: number of bytes to write | ||
2028 | * @retlen: pointer to variable to store the number of written bytes | ||
2029 | * @buf: the data to write | ||
2030 | * | ||
2031 | * NAND write with ECC. Used when performing writes in interrupt context, this | ||
2032 | * may for example be called by mtdoops when writing an oops while in panic. | ||
2033 | */ | ||
2034 | static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
2035 | size_t *retlen, const uint8_t *buf) | ||
2036 | { | ||
2037 | struct nand_chip *chip = mtd->priv; | ||
2038 | int ret; | ||
2039 | |||
2040 | /* Do not allow reads past end of device */ | ||
2041 | if ((to + len) > mtd->size) | ||
2042 | return -EINVAL; | ||
2043 | if (!len) | ||
2044 | return 0; | ||
2045 | |||
2046 | /* Wait for the device to get ready. */ | ||
2047 | panic_nand_wait(mtd, chip, 400); | ||
2048 | |||
2049 | /* Grab the device. */ | ||
2050 | panic_nand_get_device(chip, mtd, FL_WRITING); | ||
2051 | |||
2052 | chip->ops.len = len; | ||
2053 | chip->ops.datbuf = (uint8_t *)buf; | ||
2054 | chip->ops.oobbuf = NULL; | ||
2055 | |||
2056 | ret = nand_do_write_ops(mtd, to, &chip->ops); | ||
2057 | |||
2058 | *retlen = chip->ops.retlen; | ||
2059 | return ret; | ||
2060 | } | ||
2061 | |||
2062 | /** | ||
1952 | * nand_write - [MTD Interface] NAND write with ECC | 2063 | * nand_write - [MTD Interface] NAND write with ECC |
1953 | * @mtd: MTD device structure | 2064 | * @mtd: MTD device structure |
1954 | * @to: offset to write to | 2065 | * @to: offset to write to |
@@ -2877,6 +2988,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2877 | mtd->unpoint = NULL; | 2988 | mtd->unpoint = NULL; |
2878 | mtd->read = nand_read; | 2989 | mtd->read = nand_read; |
2879 | mtd->write = nand_write; | 2990 | mtd->write = nand_write; |
2991 | mtd->panic_write = panic_nand_write; | ||
2880 | mtd->read_oob = nand_read_oob; | 2992 | mtd->read_oob = nand_read_oob; |
2881 | mtd->write_oob = nand_write_oob; | 2993 | mtd->write_oob = nand_write_oob; |
2882 | mtd->sync = nand_sync; | 2994 | mtd->sync = nand_sync; |