aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorEric W. Biedermann <ebiederman@lnxi.com>2005-05-19 23:28:26 -0400
committerThomas Gleixner <tglx@mtd.linutronix.de>2005-05-23 07:22:11 -0400
commitfb4a90bfcd6d86e8531073c42fae7fde40974f5d (patch)
tree12122e4775bcaab4eec39b110a0450a82ef59964 /drivers/mtd
parent6da70124a1cc05bdbd7c847901964edc6f634a91 (diff)
[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>
Diffstat (limited to 'drivers/mtd')
-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 fca8ff6f7e14..59849236f526 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -13,7 +13,7 @@
13 * 13 *
14 * This code is GPL 14 * This code is GPL
15 * 15 *
16 * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $ 16 * $Id: cfi_cmdset_0002.c,v 1.115 2005/05/20 03:28:23 eric Exp $
17 * 17 *
18 */ 18 */
19 19
@@ -43,6 +43,7 @@
43#define MANUFACTURER_AMD 0x0001 43#define MANUFACTURER_AMD 0x0001
44#define MANUFACTURER_SST 0x00BF 44#define MANUFACTURER_SST 0x00BF
45#define SST49LF004B 0x0060 45#define SST49LF004B 0x0060
46#define SST49LF008A 0x005a
46 47
47static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); 48static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
48static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); 49static 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[] = {
191}; 192};
192static struct cfi_fixup jedec_fixup_table[] = { 193static struct cfi_fixup jedec_fixup_table[] = {
193 { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, }, 194 { MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
195 { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
194 { 0, 0, NULL, NULL } 196 { 0, 0, NULL, NULL }
195}; 197};
196 198
@@ -401,6 +403,32 @@ static int chip_ready(struct map_info *map, unsigned long addr)
401 return map_word_equal(map, d, t); 403 return map_word_equal(map, d, t);
402} 404}
403 405
406/*
407 * Return true if the chip is ready and has the correct value.
408 *
409 * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
410 * non-suspended sector) and it is indicated by no bits toggling.
411 *
412 * Error are indicated by toggling bits or bits held with the wrong value,
413 * or with bits toggling.
414 *
415 * Note that anything more complicated than checking if no bits are toggling
416 * (including checking DQ5 for an error status) is tricky to get working
417 * correctly and is therefore not done (particulary with interleaved chips
418 * as each chip must be checked independantly of the others).
419 *
420 */
421static int chip_good(struct map_info *map, unsigned long addr, map_word expected)
422{
423 map_word oldd, curd;
424
425 oldd = map_read(map, addr);
426 curd = map_read(map, addr);
427
428 return map_word_equal(map, oldd, curd) &&
429 map_word_equal(map, curd, expected);
430}
431
404static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) 432static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
405{ 433{
406 DECLARE_WAITQUEUE(wait, current); 434 DECLARE_WAITQUEUE(wait, current);
@@ -765,26 +793,29 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
765 } 793 }
766 794
767 if (chip_ready(map, adr)) 795 if (chip_ready(map, adr))
768 goto op_done; 796 break;
769 797
770 if (time_after(jiffies, timeo)) 798 if (time_after(jiffies, timeo)) {
799 printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
771 break; 800 break;
801 }
772 802
773 /* Latency issues. Drop the lock, wait a while and retry */ 803 /* Latency issues. Drop the lock, wait a while and retry */
774 cfi_spin_unlock(chip->mutex); 804 cfi_spin_unlock(chip->mutex);
775 cfi_udelay(1); 805 cfi_udelay(1);
776 cfi_spin_lock(chip->mutex); 806 cfi_spin_lock(chip->mutex);
777 } 807 }
808 /* Did we succeed? */
809 if (!chip_good(map, adr, datum)) {
810 /* reset on all failures. */
811 map_write( map, CMD(0xF0), chip->start );
812 /* FIXME - should have reset delay before continuing */
778 813
779 printk(KERN_WARNING "MTD %s(): software timeout\n", __func__); 814 if (++retry_cnt <= MAX_WORD_RETRIES)
780 815 goto retry;
781 /* reset on all failures. */
782 map_write( map, CMD(0xF0), chip->start );
783 /* FIXME - should have reset delay before continuing */
784 if (++retry_cnt <= MAX_WORD_RETRIES)
785 goto retry;
786 816
787 ret = -EIO; 817 ret = -EIO;
818 }
788 op_done: 819 op_done:
789 chip->state = FL_READY; 820 chip->state = FL_READY;
790 put_chip(map, chip, adr); 821 put_chip(map, chip, adr);
@@ -1187,10 +1218,13 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
1187 } 1218 }
1188 1219
1189 if (chip_ready(map, adr)) 1220 if (chip_ready(map, adr))
1190 goto op_done; 1221 break;
1191 1222
1192 if (time_after(jiffies, timeo)) 1223 if (time_after(jiffies, timeo)) {
1224 printk(KERN_WARNING "MTD %s(): software timeout\n",
1225 __func__ );
1193 break; 1226 break;
1227 }
1194 1228
1195 /* Latency issues. Drop the lock, wait a while and retry */ 1229 /* Latency issues. Drop the lock, wait a while and retry */
1196 cfi_spin_unlock(chip->mutex); 1230 cfi_spin_unlock(chip->mutex);
@@ -1198,16 +1232,15 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
1198 schedule_timeout(1); 1232 schedule_timeout(1);
1199 cfi_spin_lock(chip->mutex); 1233 cfi_spin_lock(chip->mutex);
1200 } 1234 }
1235 /* Did we succeed? */
1236 if (!chip_good(map, adr, map_word_ff(map))) {
1237 /* reset on all failures. */
1238 map_write( map, CMD(0xF0), chip->start );
1239 /* FIXME - should have reset delay before continuing */
1201 1240
1202 printk(KERN_WARNING "MTD %s(): software timeout\n", 1241 ret = -EIO;
1203 __func__ ); 1242 }
1204
1205 /* reset on all failures. */
1206 map_write( map, CMD(0xF0), chip->start );
1207 /* FIXME - should have reset delay before continuing */
1208 1243
1209 ret = -EIO;
1210 op_done:
1211 chip->state = FL_READY; 1244 chip->state = FL_READY;
1212 put_chip(map, chip, adr); 1245 put_chip(map, chip, adr);
1213 cfi_spin_unlock(chip->mutex); 1246 cfi_spin_unlock(chip->mutex);
@@ -1272,10 +1305,13 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
1272 } 1305 }
1273 1306
1274 if (chip_ready(map, adr)) 1307 if (chip_ready(map, adr))
1275 goto op_done; 1308 break;
1276 1309
1277 if (time_after(jiffies, timeo)) 1310 if (time_after(jiffies, timeo)) {
1311 printk(KERN_WARNING "MTD %s(): software timeout\n",
1312 __func__ );
1278 break; 1313 break;
1314 }
1279 1315
1280 /* Latency issues. Drop the lock, wait a while and retry */ 1316 /* Latency issues. Drop the lock, wait a while and retry */
1281 cfi_spin_unlock(chip->mutex); 1317 cfi_spin_unlock(chip->mutex);
@@ -1283,16 +1319,15 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
1283 schedule_timeout(1); 1319 schedule_timeout(1);
1284 cfi_spin_lock(chip->mutex); 1320 cfi_spin_lock(chip->mutex);
1285 } 1321 }
1286 1322 /* Did we succeed? */
1287 printk(KERN_WARNING "MTD %s(): software timeout\n", 1323 if (chip_good(map, adr, map_word_ff(map))) {
1288 __func__ ); 1324 /* reset on all failures. */
1289 1325 map_write( map, CMD(0xF0), chip->start );
1290 /* reset on all failures. */ 1326 /* FIXME - should have reset delay before continuing */
1291 map_write( map, CMD(0xF0), chip->start ); 1327
1292 /* FIXME - should have reset delay before continuing */ 1328 ret = -EIO;
1329 }
1293 1330
1294 ret = -EIO;
1295 op_done:
1296 chip->state = FL_READY; 1331 chip->state = FL_READY;
1297 put_chip(map, chip, adr); 1332 put_chip(map, chip, adr);
1298 cfi_spin_unlock(chip->mutex); 1333 cfi_spin_unlock(chip->mutex);