diff options
author | Alexander Belyakov <abelyako@mail.ru> | 2008-09-25 09:53:24 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-09-26 20:56:18 -0400 |
commit | 3afe7eb37f4d47f31d30a81c1b42ca02eab01e44 (patch) | |
tree | 7e860adfbe462b3570dfcb1f4b18dabffabf1908 /drivers/mtd | |
parent | ef89a8801321e0d0665c327c9d77d602ef764c87 (diff) |
[MTD] [NOR] fix cfi_cmdset_0001 FL_SYNCING race (take 2)
The patch fixes CFI issue with multipartitional devices leading to the
set of errors or even deadlock. The problem is CFI FL_SYNCING state race
with flash operations (e.g. erase suspend). It is reproduced by running
intensive writes on one JFFS2 partition and simultaneously performing
mount/unmount cycle on another partition of the same chip.
Signed-off-by: Alexander Belyakov <abelyako@googlemail.com>
Acked-by: Nicolas Pitre <nico@cam.org>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 5157e3cb4b9e..c93a8be5d5f1 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -725,6 +725,10 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long | |||
725 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; | 725 | struct cfi_pri_intelext *cfip = cfi->cmdset_priv; |
726 | unsigned long timeo = jiffies + HZ; | 726 | unsigned long timeo = jiffies + HZ; |
727 | 727 | ||
728 | /* Prevent setting state FL_SYNCING for chip in suspended state. */ | ||
729 | if (mode == FL_SYNCING && chip->oldstate != FL_READY) | ||
730 | goto sleep; | ||
731 | |||
728 | switch (chip->state) { | 732 | switch (chip->state) { |
729 | 733 | ||
730 | case FL_STATUS: | 734 | case FL_STATUS: |
@@ -830,8 +834,9 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
830 | DECLARE_WAITQUEUE(wait, current); | 834 | DECLARE_WAITQUEUE(wait, current); |
831 | 835 | ||
832 | retry: | 836 | retry: |
833 | if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING | 837 | if (chip->priv && |
834 | || mode == FL_OTP_WRITE || mode == FL_SHUTDOWN)) { | 838 | (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE |
839 | || mode == FL_SHUTDOWN) && chip->state != FL_SYNCING) { | ||
835 | /* | 840 | /* |
836 | * OK. We have possibility for contention on the write/erase | 841 | * OK. We have possibility for contention on the write/erase |
837 | * operations which are global to the real chip and not per | 842 | * operations which are global to the real chip and not per |
@@ -881,6 +886,14 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
881 | return ret; | 886 | return ret; |
882 | } | 887 | } |
883 | spin_lock(&shared->lock); | 888 | spin_lock(&shared->lock); |
889 | |||
890 | /* We should not own chip if it is already | ||
891 | * in FL_SYNCING state. Put contender and retry. */ | ||
892 | if (chip->state == FL_SYNCING) { | ||
893 | put_chip(map, contender, contender->start); | ||
894 | spin_unlock(contender->mutex); | ||
895 | goto retry; | ||
896 | } | ||
884 | spin_unlock(contender->mutex); | 897 | spin_unlock(contender->mutex); |
885 | } | 898 | } |
886 | 899 | ||