Commit e29fe597 authored by Joakim Tjernlund's avatar Joakim Tjernlund Committed by Stefan Bader

mtd: cfi: cmdset_0001: Do not allow read/write to suspend erase block.

BugLink: http://bugs.launchpad.net/bugs/1768825

commit 6510bbc8 upstream.

Currently it is possible to read and/or write to suspend EB's.
Writing /dev/mtdX or /dev/mtdblockX from several processes may
break the flash state machine.
Signed-off-by: default avatarJoakim Tjernlund <joakim.tjernlund@infinera.com>
Cc: <stable@vger.kernel.org>
Reviewed-by: default avatarRichard Weinberger <richard@nod.at>
Signed-off-by: default avatarBoris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 32a47e2b
...@@ -825,21 +825,25 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long ...@@ -825,21 +825,25 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
(mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
goto sleep; goto sleep;
/* Do not allow suspend iff read/write to EB address */
if ((adr & chip->in_progress_block_mask) ==
chip->in_progress_block_addr)
goto sleep;
/* Erase suspend */ /* Erase suspend */
map_write(map, CMD(0xB0), adr); map_write(map, CMD(0xB0), chip->in_progress_block_addr);
/* If the flash has finished erasing, then 'erase suspend' /* If the flash has finished erasing, then 'erase suspend'
* appears to make some (28F320) flash devices switch to * appears to make some (28F320) flash devices switch to
* 'read' mode. Make sure that we switch to 'read status' * 'read' mode. Make sure that we switch to 'read status'
* mode so we get the right data. --rmk * mode so we get the right data. --rmk
*/ */
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), chip->in_progress_block_addr);
chip->oldstate = FL_ERASING; chip->oldstate = FL_ERASING;
chip->state = FL_ERASE_SUSPENDING; chip->state = FL_ERASE_SUSPENDING;
chip->erase_suspended = 1; chip->erase_suspended = 1;
for (;;) { for (;;) {
status = map_read(map, adr); status = map_read(map, chip->in_progress_block_addr);
if (map_word_andequal(map, status, status_OK, status_OK)) if (map_word_andequal(map, status, status_OK, status_OK))
break; break;
...@@ -1035,8 +1039,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad ...@@ -1035,8 +1039,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
sending the 0x70 (Read Status) command to an erasing sending the 0x70 (Read Status) command to an erasing
chip and expecting it to be ignored, that's what we chip and expecting it to be ignored, that's what we
do. */ do. */
map_write(map, CMD(0xd0), adr); map_write(map, CMD(0xd0), chip->in_progress_block_addr);
map_write(map, CMD(0x70), adr); map_write(map, CMD(0x70), chip->in_progress_block_addr);
chip->oldstate = FL_READY; chip->oldstate = FL_READY;
chip->state = FL_ERASING; chip->state = FL_ERASING;
break; break;
...@@ -1927,6 +1931,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, ...@@ -1927,6 +1931,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xD0), adr); map_write(map, CMD(0xD0), adr);
chip->state = FL_ERASING; chip->state = FL_ERASING;
chip->erase_suspended = 0; chip->erase_suspended = 0;
chip->in_progress_block_addr = adr;
chip->in_progress_block_mask = ~(len - 1);
ret = INVAL_CACHE_AND_WAIT(map, chip, adr, ret = INVAL_CACHE_AND_WAIT(map, chip, adr,
adr, len, adr, len,
......
...@@ -85,6 +85,7 @@ struct flchip { ...@@ -85,6 +85,7 @@ struct flchip {
unsigned int write_suspended:1; unsigned int write_suspended:1;
unsigned int erase_suspended:1; unsigned int erase_suspended:1;
unsigned long in_progress_block_addr; unsigned long in_progress_block_addr;
unsigned long in_progress_block_mask;
struct mutex mutex; struct mutex mutex;
wait_queue_head_t wq; /* Wait on here when we're waiting for the chip wait_queue_head_t wq; /* Wait on here when we're waiting for the chip
......
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