mtd: fix hang-up in cfi erase and read contention

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Tue May 24 21:59:07 EDT 2011


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=100f2341e305f98de3aa12fb472771ab029cbda7
Commit:     100f2341e305f98de3aa12fb472771ab029cbda7
Parent:     52534f2dba5d033c0c33e515faa2767d7e8e986a
Author:     Tadashi Abe <tabe at mvista.com>
AuthorDate: Thu May 19 15:58:15 2011 +0900
Committer:  David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Wed May 25 02:11:11 2011 +0100

    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 at mvista.com>
    Acked-by: Joakim Tjernlund <joakim.tjernlund at transmode.se>
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
---
 drivers/mtd/chips/cfi_cmdset_0001.c |    9 +++------
 drivers/mtd/chips/cfi_cmdset_0002.c |    4 +---
 drivers/mtd/chips/cfi_cmdset_0020.c |    1 +
 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 09cb7c8..121be02 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
 			        break;
 
 			if (time_after(jiffies, timeo)) {
-				/* Urgh. Resume and pretend we weren't here.  */
-				map_write(map, CMD(0xd0), adr);
-				/* Make sure we're in 'read status' mode if it had finished */
-				map_write(map, CMD(0x70), adr);
-				chip->state = FL_ERASING;
-				chip->oldstate = FL_READY;
+				/* Urgh. Resume and pretend we weren't here.
+				 * Make sure we're in 'read status' mode if it had finished */
+				put_chip(map, chip, adr);
 				printk(KERN_ERR "%s: Chip not ready after erase "
 				       "suspended: status = 0x%lx\n", map->name, status.x[0]);
 				return -EIO;
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index b890f6c..9a99a5b 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
 				 * there was an error (so leave the erase
 				 * routine to recover from it) or we trying to
 				 * use the erase-in-progress sector. */
-				map_write(map, cfi->sector_erase_cmd, chip->in_progress_block_addr);
-				chip->state = FL_ERASING;
-				chip->oldstate = FL_READY;
+				put_chip(map, chip, adr);
 				printk(KERN_ERR "MTD %s(): chip not ready after erase suspend\n", __func__);
 				return -EIO;
 			}
diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c
index ed56ad3..179814a 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
 				/* make sure we're in 'read status' mode */
 				map_write(map, CMD(0x70), cmd_addr);
 				chip->state = FL_ERASING;
+				wake_up(&chip->wq);
 				mutex_unlock(&chip->mutex);
 				printk(KERN_ERR "Chip not ready after erase "
 				       "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 1267992..16dcd1c 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)
 		if (ret) {
 			/* Oops. something got wrong. */
 			/* Resume and pretend we weren't here.  */
-			map_write(map, CMD(LPDDR_RESUME),
-				map->pfow_base + PFOW_COMMAND_CODE);
-			map_write(map, CMD(LPDDR_START_EXECUTION),
-				map->pfow_base + PFOW_COMMAND_EXECUTE);
-			chip->state = FL_ERASING;
-			chip->oldstate = FL_READY;
+			put_chip(map, chip);
 			printk(KERN_ERR "%s: suspend operation failed."
 					"State may be wrong \n", map->name);
 			return -EIO;



More information about the linux-mtd-cvs mailing list