Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 100f2341 authored by Tadashi Abe's avatar Tadashi Abe Committed by David Woodhouse
Browse files

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: default avatarTadashi Abe <tabe@mvista.com>
Acked-by: default avatarJoakim Tjernlund <joakim.tjernlund@transmode.se>
Signed-off-by: default avatarDavid Woodhouse <David.Woodhouse@intel.com>
parent 52534f2d
Loading
Loading
Loading
Loading
+3 −6
Original line number Diff line number Diff line
@@ -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;
+1 −3
Original line number Diff line number Diff line
@@ -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;
			}
+1 −0
Original line number Diff line number Diff line
@@ -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]);
+1 −6
Original line number Diff line number Diff line
@@ -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;