diff options
author | Eric W. Biedermann <ebiederman@lnxi.com> | 2005-05-19 23:28:26 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-05-23 07:22:11 -0400 |
commit | fb4a90bfcd6d86e8531073c42fae7fde40974f5d (patch) | |
tree | 12122e4775bcaab4eec39b110a0450a82ef59964 /drivers | |
parent | 6da70124a1cc05bdbd7c847901964edc6f634a91 (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')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 99 |
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 | ||
47 | static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); | 48 | static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); |
48 | static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); | 49 | 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[] = { | |||
191 | }; | 192 | }; |
192 | static struct cfi_fixup jedec_fixup_table[] = { | 193 | static 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 | */ | ||
421 | static 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 | |||
404 | static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) | 432 | static 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); |