diff options
| -rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 146 |
1 files changed, 77 insertions, 69 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 3aa3dca56ae6..a9eb1c516247 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
| @@ -85,6 +85,7 @@ static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, | |||
| 85 | static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, | 85 | static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, |
| 86 | size_t len); | 86 | size_t len); |
| 87 | 87 | ||
| 88 | static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode); | ||
| 88 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); | 89 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); |
| 89 | static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); | 90 | static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); |
| 90 | #include "fwh_lock.h" | 91 | #include "fwh_lock.h" |
| @@ -641,73 +642,13 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd, | |||
| 641 | /* | 642 | /* |
| 642 | * *********** CHIP ACCESS FUNCTIONS *********** | 643 | * *********** CHIP ACCESS FUNCTIONS *********** |
| 643 | */ | 644 | */ |
| 644 | 645 | static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode) | |
| 645 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) | ||
| 646 | { | 646 | { |
| 647 | DECLARE_WAITQUEUE(wait, current); | 647 | DECLARE_WAITQUEUE(wait, current); |
| 648 | struct cfi_private *cfi = map->fldrv_priv; | 648 | struct cfi_private *cfi = map->fldrv_priv; |
| 649 | map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01); | 649 | map_word status, status_OK = CMD(0x80), status_PWS = CMD(0x01); |
| 650 | unsigned long timeo; | ||
| 651 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; | 650 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; |
| 652 | 651 | unsigned long timeo = jiffies + HZ; | |
| 653 | resettime: | ||
| 654 | timeo = jiffies + HZ; | ||
| 655 | retry: | ||
| 656 | if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) { | ||
| 657 | /* | ||
| 658 | * OK. We have possibility for contension on the write/erase | ||
| 659 | * operations which are global to the real chip and not per | ||
| 660 | * partition. So let's fight it over in the partition which | ||
| 661 | * currently has authority on the operation. | ||
| 662 | * | ||
| 663 | * The rules are as follows: | ||
| 664 | * | ||
| 665 | * - any write operation must own shared->writing. | ||
| 666 | * | ||
| 667 | * - any erase operation must own _both_ shared->writing and | ||
| 668 | * shared->erasing. | ||
| 669 | * | ||
| 670 | * - contension arbitration is handled in the owner's context. | ||
| 671 | * | ||
| 672 | * The 'shared' struct can be read and/or written only when | ||
| 673 | * its lock is taken. | ||
| 674 | */ | ||
| 675 | struct flchip_shared *shared = chip->priv; | ||
| 676 | struct flchip *contender; | ||
| 677 | spin_lock(&shared->lock); | ||
| 678 | contender = shared->writing; | ||
| 679 | if (contender && contender != chip) { | ||
| 680 | /* | ||
| 681 | * The engine to perform desired operation on this | ||
| 682 | * partition is already in use by someone else. | ||
| 683 | * Let's fight over it in the context of the chip | ||
| 684 | * currently using it. If it is possible to suspend, | ||
| 685 | * that other partition will do just that, otherwise | ||
| 686 | * it'll happily send us to sleep. In any case, when | ||
| 687 | * get_chip returns success we're clear to go ahead. | ||
| 688 | */ | ||
| 689 | int ret = spin_trylock(contender->mutex); | ||
| 690 | spin_unlock(&shared->lock); | ||
| 691 | if (!ret) | ||
| 692 | goto retry; | ||
| 693 | spin_unlock(chip->mutex); | ||
| 694 | ret = get_chip(map, contender, contender->start, mode); | ||
| 695 | spin_lock(chip->mutex); | ||
| 696 | if (ret) { | ||
| 697 | spin_unlock(contender->mutex); | ||
| 698 | return ret; | ||
| 699 | } | ||
| 700 | timeo = jiffies + HZ; | ||
| 701 | spin_lock(&shared->lock); | ||
| 702 | spin_unlock(contender->mutex); | ||
| 703 | } | ||
| 704 | |||
| 705 | /* We now own it */ | ||
| 706 | shared->writing = chip; | ||
| 707 | if (mode == FL_ERASING) | ||
| 708 | shared->erasing = chip; | ||
| 709 | spin_unlock(&shared->lock); | ||
| 710 | } | ||
| 711 | 652 | ||
| 712 | switch (chip->state) { | 653 | switch (chip->state) { |
| 713 | 654 | ||
| @@ -722,16 +663,11 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
| 722 | if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS)) | 663 | if (chip->priv && map_word_andequal(map, status, status_PWS, status_PWS)) |
| 723 | break; | 664 | break; |
| 724 | 665 | ||
| 725 | if (time_after(jiffies, timeo)) { | ||
| 726 | printk(KERN_ERR "%s: Waiting for chip to be ready timed out. Status %lx\n", | ||
| 727 | map->name, status.x[0]); | ||
| 728 | return -EIO; | ||
| 729 | } | ||
| 730 | spin_unlock(chip->mutex); | 666 | spin_unlock(chip->mutex); |
| 731 | cfi_udelay(1); | 667 | cfi_udelay(1); |
| 732 | spin_lock(chip->mutex); | 668 | spin_lock(chip->mutex); |
| 733 | /* Someone else might have been playing with it. */ | 669 | /* Someone else might have been playing with it. */ |
| 734 | goto retry; | 670 | return -EAGAIN; |
| 735 | } | 671 | } |
| 736 | 672 | ||
| 737 | case FL_READY: | 673 | case FL_READY: |
| @@ -809,10 +745,82 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
| 809 | schedule(); | 745 | schedule(); |
| 810 | remove_wait_queue(&chip->wq, &wait); | 746 | remove_wait_queue(&chip->wq, &wait); |
| 811 | spin_lock(chip->mutex); | 747 | spin_lock(chip->mutex); |
| 812 | goto resettime; | 748 | return -EAGAIN; |
| 813 | } | 749 | } |
| 814 | } | 750 | } |
| 815 | 751 | ||
| 752 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) | ||
| 753 | { | ||
| 754 | int ret; | ||
| 755 | |||
| 756 | retry: | ||
| 757 | if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING | ||
| 758 | || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) { | ||
| 759 | /* | ||
| 760 | * OK. We have possibility for contention on the write/erase | ||
| 761 | * operations which are global to the real chip and not per | ||
| 762 | * partition. So let's fight it over in the partition which | ||
| 763 | * currently has authority on the operation. | ||
| 764 | * | ||
| 765 | * The rules are as follows: | ||
| 766 | * | ||
| 767 | * - any write operation must own shared->writing. | ||
| 768 | * | ||
| 769 | * - any erase operation must own _both_ shared->writing and | ||
| 770 | * shared->erasing. | ||
| 771 | * | ||
| 772 | * - contention arbitration is handled in the owner's context. | ||
| 773 | * | ||
| 774 | * The 'shared' struct can be read and/or written only when | ||
| 775 | * its lock is taken. | ||
| 776 | */ | ||
| 777 | struct flchip_shared *shared = chip->priv; | ||
| 778 | struct flchip *contender; | ||
| 779 | spin_lock(&shared->lock); | ||
| 780 | contender = shared->writing; | ||
| 781 | if (contender && contender != chip) { | ||
| 782 | /* | ||
| 783 | * The engine to perform desired operation on this | ||
| 784 | * partition is already in use by someone else. | ||
| 785 | * Let's fight over it in the context of the chip | ||
| 786 | * currently using it. If it is possible to suspend, | ||
| 787 | * that other partition will do just that, otherwise | ||
| 788 | * it'll happily send us to sleep. In any case, when | ||
| 789 | * get_chip returns success we're clear to go ahead. | ||
| 790 | */ | ||
| 791 | ret = spin_trylock(contender->mutex); | ||
| 792 | spin_unlock(&shared->lock); | ||
| 793 | if (!ret) | ||
| 794 | goto retry; | ||
| 795 | spin_unlock(chip->mutex); | ||
| 796 | ret = chip_ready(map, contender, contender->start, mode); | ||
| 797 | spin_lock(chip->mutex); | ||
| 798 | |||
| 799 | if (ret == -EAGAIN) { | ||
| 800 | spin_unlock(contender->mutex); | ||
| 801 | goto retry; | ||
| 802 | } | ||
| 803 | if (ret) { | ||
| 804 | spin_unlock(contender->mutex); | ||
| 805 | return ret; | ||
| 806 | } | ||
| 807 | spin_lock(&shared->lock); | ||
| 808 | spin_unlock(contender->mutex); | ||
| 809 | } | ||
| 810 | |||
| 811 | /* We now own it */ | ||
| 812 | shared->writing = chip; | ||
| 813 | if (mode == FL_ERASING) | ||
| 814 | shared->erasing = chip; | ||
| 815 | spin_unlock(&shared->lock); | ||
| 816 | } | ||
| 817 | ret = chip_ready(map, chip, adr, mode); | ||
| 818 | if (ret == -EAGAIN) | ||
| 819 | goto retry; | ||
| 820 | |||
| 821 | return ret; | ||
| 822 | } | ||
| 823 | |||
| 816 | static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) | 824 | static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) |
| 817 | { | 825 | { |
| 818 | struct cfi_private *cfi = map->fldrv_priv; | 826 | struct cfi_private *cfi = map->fldrv_priv; |
