diff options
author | Tadashi Abe <tabe@mvista.com> | 2011-05-19 02:58:15 -0400 |
---|---|---|
committer | David Woodhouse <David.Woodhouse@intel.com> | 2011-05-24 21:11:11 -0400 |
commit | 100f2341e305f98de3aa12fb472771ab029cbda7 (patch) | |
tree | 40cc6edf73cf06b6392a18fd496cb9dc071c98d4 /drivers | |
parent | 52534f2dba5d033c0c33e515faa2767d7e8e986a (diff) |
mtd: fix hang-up in cfi erase and read contention
cfi erase command hangs up when erase and read contention occurs.
If read runs at the same address as erase operation, read issues
Erase-Suspend via get_chip() and the erase goes into sleep in wait queue.
But in this case, read operation exits by time-out without waking it up.
I think the other variants (0001, 0020 and lpddr) have the same problem too.
Tested and verified the patch only on CFI-0002 flash, though.
Signed-off-by: Tadashi Abe <tabe@mvista.com>
Acked-by: Joakim Tjernlund <joakim.tjernlund@transmode.se>
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0001.c | 9 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0002.c | 4 | ||||
-rw-r--r-- | drivers/mtd/chips/cfi_cmdset_0020.c | 1 | ||||
-rw-r--r-- | drivers/mtd/lpddr/lpddr_cmds.c | 7 |
4 files changed, 6 insertions, 15 deletions
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c index 09cb7c8d93b..121be022d1e 100644 --- a/drivers/mtd/chips/cfi_cmdset_0001.c +++ b/drivers/mtd/chips/cfi_cmdset_0001.c | |||
@@ -812,12 +812,9 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long | |||
812 | break; | 812 | break; |
813 | 813 | ||
814 | if (time_after(jiffies, timeo)) { | 814 | if (time_after(jiffies, timeo)) { |
815 | /* Urgh. Resume and pretend we weren't here. */ | 815 | /* Urgh. Resume and pretend we weren't here. |
816 | map_write(map, CMD(0xd0), adr); | 816 | * Make sure we're in 'read status' mode if it had finished */ |
817 | /* Make sure we're in 'read status' mode if it had finished */ | 817 | put_chip(map, chip, adr); |
818 | map_write(map, CMD(0x70), adr); | ||
819 | chip->state = FL_ERASING; | ||
820 | chip->oldstate = FL_READY; | ||
821 | printk(KERN_ERR "%s: Chip not ready after erase " | 818 | printk(KERN_ERR "%s: Chip not ready after erase " |
822 | "suspended: status = 0x%lx\n", map->name, status.x[0]); | 819 | "suspended: status = 0x%lx\n", map->name, status.x[0]); |
823 | return -EIO; | 820 | return -EIO; |
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c index b890f6c964d..9a99a5bd3ea 100644 --- a/drivers/mtd/chips/cfi_cmdset_0002.c +++ b/drivers/mtd/chips/cfi_cmdset_0002.c | |||
@@ -711,9 +711,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr | |||
711 | * there was an error (so leave the erase | 711 | * there was an error (so leave the erase |
712 | * routine to recover from it) or we trying to | 712 | * routine to recover from it) or we trying to |
713 | * use the erase-in-progress sector. */ | 713 | * use the erase-in-progress sector. */ |
714 | map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr); | 714 | put_chip(map, chip, adr); |
715 | chip->state = FL_ERASING; | ||
716 | chip->oldstate = FL_READY; | ||
717 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); | 715 | printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__); |
718 | return -EIO; | 716 | return -EIO; |
719 | } | 717 | } |
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index ed56ad3884f..179814a95f3 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c | |||
@@ -296,6 +296,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof | |||
296 | /* make sure we're in 'read status' mode */ | 296 | /* make sure we're in 'read status' mode */ |
297 | map_write(map, CMD(0x70), cmd_addr); | 297 | map_write(map, CMD(0x70), cmd_addr); |
298 | chip->state = FL_ERASING; | 298 | chip->state = FL_ERASING; |
299 | wake_up(&chip->wq); | ||
299 | mutex_unlock(&chip->mutex); | 300 | mutex_unlock(&chip->mutex); |
300 | printk(KERN_ERR "Chip not ready after erase " | 301 | printk(KERN_ERR "Chip not ready after erase " |
301 | "suspended: status = 0x%lx\n", status.x[0]); | 302 | "suspended: status = 0x%lx\n", status.x[0]); |
diff --git a/drivers/mtd/lpddr/lpddr_cmds.c b/drivers/mtd/lpddr/lpddr_cmds.c index 12679925b42..16dcd1c76ba 100644 --- a/drivers/mtd/lpddr/lpddr_cmds.c +++ b/drivers/mtd/lpddr/lpddr_cmds.c | |||
@@ -313,12 +313,7 @@ static int chip_ready(struct map_info *map, struct flchip *chip, int mode) | |||
313 | if (ret) { | 313 | if (ret) { |
314 | /* Oops. something got wrong. */ | 314 | /* Oops. something got wrong. */ |
315 | /* Resume and pretend we weren't here. */ | 315 | /* Resume and pretend we weren't here. */ |
316 | map_write(map, CMD(LPDDR_RESUME), | 316 | put_chip(map, chip); |
317 | map->pfow_base + PFOW_COMMAND_CODE); | ||
318 | map_write(map, CMD(LPDDR_START_EXECUTION), | ||
319 | map->pfow_base + PFOW_COMMAND_EXECUTE); | ||
320 | chip->state = FL_ERASING; | ||
321 | chip->oldstate = FL_READY; | ||
322 | printk(KERN_ERR "%s: suspend operation failed." | 317 | printk(KERN_ERR "%s: suspend operation failed." |
323 | "State may be wrong \n", map->name); | 318 | "State may be wrong \n", map->name); |
324 | return -EIO; | 319 | return -EIO; |