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

Commit 6510bbc8 authored by Joakim Tjernlund's avatar Joakim Tjernlund Committed by Boris Brezillon
Browse files

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



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>
parent 47016b34
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -831,21 +831,25 @@ static int chip_ready (struct map_info *map, struct flchip *chip, unsigned long
		     (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1))))
			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 */
		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'
		 * appears to make some (28F320) flash devices switch to
		 * 'read' mode.  Make sure that we switch to 'read status'
		 * 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->state = FL_ERASE_SUSPENDING;
		chip->erase_suspended = 1;
		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))
			        break;

@@ -1041,8 +1045,8 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
		   sending the 0x70 (Read Status) command to an erasing
		   chip and expecting it to be ignored, that's what we
		   do. */
		map_write(map, CMD(0xd0), adr);
		map_write(map, CMD(0x70), adr);
		map_write(map, CMD(0xd0), chip->in_progress_block_addr);
		map_write(map, CMD(0x70), chip->in_progress_block_addr);
		chip->oldstate = FL_READY;
		chip->state = FL_ERASING;
		break;
@@ -1933,6 +1937,8 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
	map_write(map, CMD(0xD0), adr);
	chip->state = FL_ERASING;
	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,
				   adr, len,
+1 −0
Original line number Diff line number Diff line
@@ -85,6 +85,7 @@ struct flchip {
	unsigned int write_suspended:1;
	unsigned int erase_suspended:1;
	unsigned long in_progress_block_addr;
	unsigned long in_progress_block_mask;

	struct mutex mutex;
	wait_queue_head_t wq; /* Wait on here when we're waiting for the chip