aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Korolev <akorolev@infradead.org>2007-10-22 12:55:20 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2007-10-23 07:07:52 -0400
commit5a37cf19efcceae14c2078449e35b9f4eb3e63e4 (patch)
tree4d4bb74499d093aa9a921e72875d223f15506657
parent2a754b51aacb122cec25c849e3cf7f5503cc3ec6 (diff)
[MTD] [NOR] Fix deadlock in Intel chip driver caused by get_chip recursion
This patch solves kernel deadlock issue seen on JFFF2 simultaneous operations. Detailed investigation of the issue showed that the kernel deadlock is caused by tons of recursive get_chip calls. Signed-off-by: Alexey Korolev <akorolev@infradead.org> Acked-by: Nicolas Pitre <nico@cam.org> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c146
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,
85static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, 85static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
86 size_t len); 86 size_t len);
87 87
88static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
88static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode); 89static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode);
89static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr); 90static 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 645static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
645static 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
752static 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
816static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) 824static 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;