diff options
Diffstat (limited to 'drivers/mtd/nand/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 141 |
1 files changed, 130 insertions, 11 deletions
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 2957cc70da3d..8f2958fe2148 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 |
@@ -698,8 +740,14 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | |||
698 | return 0; | 740 | return 0; |
699 | } | 741 | } |
700 | if (new_state == FL_PM_SUSPENDED) { | 742 | if (new_state == FL_PM_SUSPENDED) { |
701 | spin_unlock(lock); | 743 | if (chip->controller->active->state == FL_PM_SUSPENDED) { |
702 | return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN; | 744 | chip->state = FL_PM_SUSPENDED; |
745 | spin_unlock(lock); | ||
746 | return 0; | ||
747 | } else { | ||
748 | spin_unlock(lock); | ||
749 | return -EAGAIN; | ||
750 | } | ||
703 | } | 751 | } |
704 | set_current_state(TASK_UNINTERRUPTIBLE); | 752 | set_current_state(TASK_UNINTERRUPTIBLE); |
705 | add_wait_queue(wq, &wait); | 753 | add_wait_queue(wq, &wait); |
@@ -710,6 +758,32 @@ nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state) | |||
710 | } | 758 | } |
711 | 759 | ||
712 | /** | 760 | /** |
761 | * panic_nand_wait - [GENERIC] wait until the command is done | ||
762 | * @mtd: MTD device structure | ||
763 | * @chip: NAND chip structure | ||
764 | * @timeo: Timeout | ||
765 | * | ||
766 | * Wait for command done. This is a helper function for nand_wait used when | ||
767 | * we are in interrupt context. May happen when in panic and trying to write | ||
768 | * an oops trough mtdoops. | ||
769 | */ | ||
770 | static void panic_nand_wait(struct mtd_info *mtd, struct nand_chip *chip, | ||
771 | unsigned long timeo) | ||
772 | { | ||
773 | int i; | ||
774 | for (i = 0; i < timeo; i++) { | ||
775 | if (chip->dev_ready) { | ||
776 | if (chip->dev_ready(mtd)) | ||
777 | break; | ||
778 | } else { | ||
779 | if (chip->read_byte(mtd) & NAND_STATUS_READY) | ||
780 | break; | ||
781 | } | ||
782 | mdelay(1); | ||
783 | } | ||
784 | } | ||
785 | |||
786 | /** | ||
713 | * nand_wait - [DEFAULT] wait until the command is done | 787 | * nand_wait - [DEFAULT] wait until the command is done |
714 | * @mtd: MTD device structure | 788 | * @mtd: MTD device structure |
715 | * @chip: NAND chip structure | 789 | * @chip: NAND chip structure |
@@ -740,15 +814,19 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *chip) | |||
740 | else | 814 | else |
741 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); | 815 | chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1); |
742 | 816 | ||
743 | while (time_before(jiffies, timeo)) { | 817 | if (in_interrupt() || oops_in_progress) |
744 | if (chip->dev_ready) { | 818 | panic_nand_wait(mtd, chip, timeo); |
745 | if (chip->dev_ready(mtd)) | 819 | else { |
746 | break; | 820 | while (time_before(jiffies, timeo)) { |
747 | } else { | 821 | if (chip->dev_ready) { |
748 | if (chip->read_byte(mtd) & NAND_STATUS_READY) | 822 | if (chip->dev_ready(mtd)) |
749 | break; | 823 | break; |
824 | } else { | ||
825 | if (chip->read_byte(mtd) & NAND_STATUS_READY) | ||
826 | break; | ||
827 | } | ||
828 | cond_resched(); | ||
750 | } | 829 | } |
751 | cond_resched(); | ||
752 | } | 830 | } |
753 | led_trigger_event(nand_led_trigger, LED_OFF); | 831 | led_trigger_event(nand_led_trigger, LED_OFF); |
754 | 832 | ||
@@ -1949,6 +2027,45 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to, | |||
1949 | } | 2027 | } |
1950 | 2028 | ||
1951 | /** | 2029 | /** |
2030 | * panic_nand_write - [MTD Interface] NAND write with ECC | ||
2031 | * @mtd: MTD device structure | ||
2032 | * @to: offset to write to | ||
2033 | * @len: number of bytes to write | ||
2034 | * @retlen: pointer to variable to store the number of written bytes | ||
2035 | * @buf: the data to write | ||
2036 | * | ||
2037 | * NAND write with ECC. Used when performing writes in interrupt context, this | ||
2038 | * may for example be called by mtdoops when writing an oops while in panic. | ||
2039 | */ | ||
2040 | static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
2041 | size_t *retlen, const uint8_t *buf) | ||
2042 | { | ||
2043 | struct nand_chip *chip = mtd->priv; | ||
2044 | int ret; | ||
2045 | |||
2046 | /* Do not allow reads past end of device */ | ||
2047 | if ((to + len) > mtd->size) | ||
2048 | return -EINVAL; | ||
2049 | if (!len) | ||
2050 | return 0; | ||
2051 | |||
2052 | /* Wait for the device to get ready. */ | ||
2053 | panic_nand_wait(mtd, chip, 400); | ||
2054 | |||
2055 | /* Grab the device. */ | ||
2056 | panic_nand_get_device(chip, mtd, FL_WRITING); | ||
2057 | |||
2058 | chip->ops.len = len; | ||
2059 | chip->ops.datbuf = (uint8_t *)buf; | ||
2060 | chip->ops.oobbuf = NULL; | ||
2061 | |||
2062 | ret = nand_do_write_ops(mtd, to, &chip->ops); | ||
2063 | |||
2064 | *retlen = chip->ops.retlen; | ||
2065 | return ret; | ||
2066 | } | ||
2067 | |||
2068 | /** | ||
1952 | * nand_write - [MTD Interface] NAND write with ECC | 2069 | * nand_write - [MTD Interface] NAND write with ECC |
1953 | * @mtd: MTD device structure | 2070 | * @mtd: MTD device structure |
1954 | * @to: offset to write to | 2071 | * @to: offset to write to |
@@ -2645,7 +2762,8 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips) | |||
2645 | type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); | 2762 | type = nand_get_flash_type(mtd, chip, busw, &nand_maf_id); |
2646 | 2763 | ||
2647 | if (IS_ERR(type)) { | 2764 | if (IS_ERR(type)) { |
2648 | printk(KERN_WARNING "No NAND device found!!!\n"); | 2765 | if (!(chip->options & NAND_SCAN_SILENT_NODEV)) |
2766 | printk(KERN_WARNING "No NAND device found.\n"); | ||
2649 | chip->select_chip(mtd, -1); | 2767 | chip->select_chip(mtd, -1); |
2650 | return PTR_ERR(type); | 2768 | return PTR_ERR(type); |
2651 | } | 2769 | } |
@@ -2877,6 +2995,7 @@ int nand_scan_tail(struct mtd_info *mtd) | |||
2877 | mtd->unpoint = NULL; | 2995 | mtd->unpoint = NULL; |
2878 | mtd->read = nand_read; | 2996 | mtd->read = nand_read; |
2879 | mtd->write = nand_write; | 2997 | mtd->write = nand_write; |
2998 | mtd->panic_write = panic_nand_write; | ||
2880 | mtd->read_oob = nand_read_oob; | 2999 | mtd->read_oob = nand_read_oob; |
2881 | mtd->write_oob = nand_write_oob; | 3000 | mtd->write_oob = nand_write_oob; |
2882 | mtd->sync = nand_sync; | 3001 | mtd->sync = nand_sync; |