mtd: fix hang-up in cfi erase and read contention
authorTadashi Abe <tabe@mvista.com>
Thu, 19 May 2011 06:58:15 +0000 (15:58 +0900)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Wed, 25 May 2011 01:11:11 +0000 (02:11 +0100)
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>
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/lpddr/lpddr_cmds.c

index 09cb7c8d93b48d80dc874319d8672b680871b42e..121be022d1eae7d1c4d07aae5f11fc96bbd53354 100644 (file)
@@ -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;
index b890f6c964d9c32007136a704dbe42538ee39aec..9a99a5bd3ea51da27f49eecc31c034c1c38a4e37 100644 (file)
@@ -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;
                        }
index ed56ad3884fbc5d88ef97c46e046da4d7afab3a8..179814a95f3ac73bf0cfd6110a201f651a8c0647 100644 (file)
@@ -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]);
index 12679925b420abd2c06b50f86162149f053b3b24..16dcd1c76baf58971f37b6975b0a82a8d5f15d56 100644 (file)
@@ -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;