summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biedermann <ebiederman@lnxi.com>2005-05-20 04:28:26 +0100
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-05-23 13:22:11 +0200
commitfb4a90bfcd6d86e8531073c42fae7fde40974f5d (patch)
tree12122e4775bcaab4eec39b110a0450a82ef59964
parent6da70124a1cc05bdbd7c847901964edc6f634a91 (diff)
downloadop-kernel-dev-fb4a90bfcd6d86e8531073c42fae7fde40974f5d.zip
op-kernel-dev-fb4a90bfcd6d86e8531073c42fae7fde40974f5d.tar.gz
[MTD] CFI-0002 - Improve error checking
Check for errors besides infinite loops when writing and erasing. Signed-off-by: Eric W. Biederman <ebiederman@lnxi.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c99
1 files changed, 67 insertions, 32 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index fca8ff6..5984923 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -13,7 +13,7 @@
*
* This code is GPL
*
- * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.115 2005/05/20 03:28:23 eric Exp $
*
*/
@@ -43,6 +43,7 @@
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
+#define SST49LF008A 0x005a
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -191,6 +192,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
};
static struct cfi_fixup jedec_fixup_table[] = {
{ MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
+ { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
{ 0, 0, NULL, NULL }
};
@@ -401,6 +403,32 @@ static int chip_ready(struct map_info *map, unsigned long addr)
return map_word_equal(map, d, t);
}
+/*
+ * Return true if the chip is ready and has the correct value.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and it is indicated by no bits toggling.
+ *
+ * Error are indicated by toggling bits or bits held with the wrong value,
+ * or with bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ *
+ */
+static int chip_good(struct map_info *map, unsigned long addr, map_word expected)
+{
+ map_word oldd, curd;
+
+ oldd = map_read(map, addr);
+ curd = map_read(map, addr);
+
+ return map_word_equal(map, oldd, curd) &&
+ map_word_equal(map, curd, expected);
+}
+
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
DECLARE_WAITQUEUE(wait, current);
@@ -765,26 +793,29 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
cfi_udelay(1);
cfi_spin_lock(chip->mutex);
}
+ /* Did we succeed? */
+ if (!chip_good(map, adr, datum)) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
- printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
- if (++retry_cnt <= MAX_WORD_RETRIES)
- goto retry;
+ if (++retry_cnt <= MAX_WORD_RETRIES)
+ goto retry;
- ret = -EIO;
+ ret = -EIO;
+ }
op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
@@ -1187,10 +1218,13 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
@@ -1198,16 +1232,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
schedule_timeout(1);
cfi_spin_lock(chip->mutex);
}
+ /* Did we succeed? */
+ if (!chip_good(map, adr, map_word_ff(map))) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
+ ret = -EIO;
+ }
- ret = -EIO;
- op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
@@ -1272,10 +1305,13 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
cfi_spin_unlock(chip->mutex);
@@ -1283,16 +1319,15 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
schedule_timeout(1);
cfi_spin_lock(chip->mutex);
}
-
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
+ /* Did we succeed? */
+ if (chip_good(map, adr, map_word_ff(map))) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
+
+ ret = -EIO;
+ }
- ret = -EIO;
- op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
cfi_spin_unlock(chip->mutex);
OpenPOWER on IntegriCloud