Commit 83112a70 authored by David Woodhouse's avatar David Woodhouse

MTD: Intel flash chip driver locking fixes.

Cleanups and fixes in preparation for XIP support -- fix unbalanced use
of get_chip() and put_chip(), and clean up the code a little in 
preparation for what's to come.
Signed-off-by: default avatarNicolas Pitre <nico@cam.org>
Signed-off-by: default avatarDavid Woodhouse <dwmw2@infradead.org>
parent 9307638e
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* *
* (C) 2000 Red Hat. GPL'd * (C) 2000 Red Hat. GPL'd
* *
* $Id: cfi_cmdset_0001.c,v 1.157 2004/10/15 20:00:26 nico Exp $ * $Id: cfi_cmdset_0001.c,v 1.160 2004/11/01 06:02:24 nico Exp $
* *
* *
* 10/10/2000 Nicolas Pitre <nico@cam.org> * 10/10/2000 Nicolas Pitre <nico@cam.org>
...@@ -861,6 +861,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz ...@@ -861,6 +861,7 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
} }
return ret; return ret;
} }
#if 0 #if 0
static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz) static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz)
{ {
...@@ -1028,6 +1029,7 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned ...@@ -1028,6 +1029,7 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
/* Done and happy. */ /* Done and happy. */
chip->state = FL_STATUS; chip->state = FL_STATUS;
/* check for lock bit */ /* check for lock bit */
if (map_word_bitsset(map, status, CMD(0x02))) { if (map_word_bitsset(map, status, CMD(0x02))) {
/* clear status */ /* clear status */
...@@ -1179,13 +1181,15 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip, ...@@ -1179,13 +1181,15 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
if (++z > 20) { if (++z > 20) {
/* Argh. Not ready for write to buffer */ /* Argh. Not ready for write to buffer */
map_word Xstatus;
map_write(map, CMD(0x70), cmd_adr); map_write(map, CMD(0x70), cmd_adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %lx, status = %lx\n", Xstatus = map_read(map, cmd_adr);
status.x[0], map_read(map, cmd_adr).x[0]);
/* Odd. Clear status bits */ /* Odd. Clear status bits */
map_write(map, CMD(0x50), cmd_adr); map_write(map, CMD(0x50), cmd_adr);
map_write(map, CMD(0x70), cmd_adr); map_write(map, CMD(0x70), cmd_adr);
printk(KERN_ERR "Chip not ready for buffer write. status = %lx, Xstatus = %lx\n",
status.x[0], Xstatus.x[0]);
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
...@@ -1413,16 +1417,17 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1413,16 +1417,17 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
/* OK Still waiting */ /* OK Still waiting */
if (time_after(jiffies, timeo)) { if (time_after(jiffies, timeo)) {
map_word Xstatus;
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %lx, status = %lx.\n", Xstatus = map_read(map, adr);
adr, status.x[0], map_read(map, adr).x[0]);
/* Clear status bits */ /* Clear status bits */
map_write(map, CMD(0x50), adr); map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), adr);
DISABLE_VPP(map); printk(KERN_ERR "waiting for erase at %08lx to complete timed out. status = %lx, Xstatus = %lx.\n",
spin_unlock(chip->mutex); adr, status.x[0], Xstatus.x[0]);
return -EIO; ret = -EIO;
goto out;
} }
/* Latency issues. Drop the lock, wait a while and retry */ /* Latency issues. Drop the lock, wait a while and retry */
...@@ -1431,9 +1436,6 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1431,9 +1436,6 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
schedule_timeout(1); schedule_timeout(1);
spin_lock(chip->mutex); spin_lock(chip->mutex);
} }
DISABLE_VPP(map);
ret = 0;
/* We've broken this before. It doesn't hurt to be safe */ /* We've broken this before. It doesn't hurt to be safe */
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), adr);
...@@ -1442,7 +1444,13 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1442,7 +1444,13 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
/* check for lock bit */ /* check for lock bit */
if (map_word_bitsset(map, status, CMD(0x3a))) { if (map_word_bitsset(map, status, CMD(0x3a))) {
unsigned char chipstatus = status.x[0]; unsigned char chipstatus;
/* Reset the error bits */
map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr);
chipstatus = status.x[0];
if (!map_word_equal(map, status, CMD(chipstatus))) { if (!map_word_equal(map, status, CMD(chipstatus))) {
int i, w; int i, w;
for (w=0; w<map_words(map); w++) { for (w=0; w<map_words(map); w++) {
...@@ -1453,10 +1461,7 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1453,10 +1461,7 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n", printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
status.x[0], chipstatus); status.x[0], chipstatus);
} }
/* Reset the error bits */
map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr);
if ((chipstatus & 0x30) == 0x30) { if ((chipstatus & 0x30) == 0x30) {
printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus); printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
ret = -EIO; ret = -EIO;
...@@ -1471,16 +1476,18 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1471,16 +1476,18 @@ static int do_erase_oneblock(struct map_info *map, struct flchip *chip,
if (retries--) { if (retries--) {
printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus); printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
timeo = jiffies + HZ; timeo = jiffies + HZ;
chip->state = FL_STATUS; put_chip(map, chip, adr);
spin_unlock(chip->mutex); spin_unlock(chip->mutex);
goto retry; goto retry;
} }
printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus); printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
ret = -EIO; ret = -EIO;
} }
} else {
ret = 0;
} }
wake_up(&chip->wq); out: put_chip(map, chip, adr);
spin_unlock(chip->mutex); spin_unlock(chip->mutex);
return ret; return ret;
} }
...@@ -1548,12 +1555,13 @@ static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip ...@@ -1548,12 +1555,13 @@ static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip
unsigned long adr, int len, void *thunk) unsigned long adr, int len, void *thunk)
{ {
struct cfi_private *cfi = map->fldrv_priv; struct cfi_private *cfi = map->fldrv_priv;
int ofs_factor = cfi->interleave * cfi->device_type; int status, ofs_factor = cfi->interleave * cfi->device_type;
cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
adr, cfi_read_query(map, adr+(2*ofs_factor)));
chip->state = FL_JEDEC_QUERY; chip->state = FL_JEDEC_QUERY;
status = cfi_read_query(map, adr+(2*ofs_factor));
printk(KERN_DEBUG "block status register for 0x%08lx is %x\n",
adr, status);
return 0; return 0;
} }
#endif #endif
...@@ -1609,11 +1617,13 @@ static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1609,11 +1617,13 @@ static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip,
/* OK Still waiting */ /* OK Still waiting */
if (time_after(jiffies, timeo)) { if (time_after(jiffies, timeo)) {
map_word Xstatus;
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), adr);
chip->state = FL_STATUS; chip->state = FL_STATUS;
printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %lx, status = %lx.\n", Xstatus = map_read(map, adr);
status.x[0], map_read(map, adr).x[0]); printk(KERN_ERR "waiting for unlock to complete timed out. status = %lx, Xstatus = %lx.\n",
DISABLE_VPP(map); status.x[0], Xstatus.x[0]);
put_chip(map, chip, adr);
spin_unlock(chip->mutex); spin_unlock(chip->mutex);
return -EIO; return -EIO;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment