mtd: cfi: cmdset_0002: Do not allow read/write to suspend erase block.
authorJoakim Tjernlund <joakim.tjernlund@infinera.com>
Thu, 1 Mar 2018 13:39:41 +0000 (14:39 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 1 May 2018 19:58:18 +0000 (12:58 -0700)
commit 7b70eb14392a7cf505f9b358d06c33b5af73d1e7 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.

Taken from cfi_cmdset_0001 driver.

Signed-off-by: Joakim Tjernlund <joakim.tjernlund@infinera.com>
Cc: <stable@vger.kernel.org>
Reviewed-by: Richard Weinberger <richard@nod.at>
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/mtd/chips/cfi_cmdset_0002.c

index 56aa6b7..d524a64 100644 (file)
@@ -816,9 +816,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
                    (mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
                        goto sleep;
 
-               /* We could check to see if we're trying to access the sector
-                * that is currently being erased. However, no user will try
-                * anything like that so we just wait for the timeout. */
+               /* 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 */
                /* It's harmless to issue the Erase-Suspend and Erase-Resume
@@ -2267,6 +2268,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
        chip->in_progress_block_addr = adr;
+       chip->in_progress_block_mask = ~(map->size - 1);
 
        INVALIDATE_CACHE_UDELAY(map, chip,
                                adr, map->size,
@@ -2356,6 +2358,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
        chip->state = FL_ERASING;
        chip->erase_suspended = 0;
        chip->in_progress_block_addr = adr;
+       chip->in_progress_block_mask = ~(len - 1);
 
        INVALIDATE_CACHE_UDELAY(map, chip,
                                adr, len,