1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

drivers/mtd_spi_nor: prevent data corruption on 'sector erase'

There is no difference between 4k erase and sector erase.
But sector erase would previously do `.block_erase` which would not
erase a sector (4k) but a whole block (64k).

Fortunately all boards declare `SPI_NOR_F_SECT_4K` and all file systems
don't try to erase anything smaller, so this was never triggered.

Add an `assert(0)` to crash instead of corrupting data.
This commit is contained in:
Benjamin Valentin 2020-10-25 23:23:48 +01:00
parent 783df5990b
commit fde3026312
9 changed files with 28 additions and 17 deletions

View File

@ -30,7 +30,6 @@ static const mtd_spi_nor_params_t _ikea_tradfri_nor_params = {
.wait_chip_erase = 2LU * US_PER_SEC,
.wait_32k_erase = 500LU *US_PER_MS,
.wait_sector_erase = 300LU * US_PER_MS,
.wait_4k_erase = 300LU * US_PER_MS,
.wait_chip_wake_up = 1LU * US_PER_MS,
.clk = IKEA_TRADFRI_NOR_SPI_CLK,
.flag = IKEA_TRADFRI_NOR_FLAGS,

View File

@ -51,9 +51,8 @@ static devfs_t mulle_nvram_devfs = {
static const mtd_spi_nor_params_t mulle_nor_params = {
.opcode = &mtd_spi_nor_opcode_default,
.wait_chip_erase = 16LU * US_PER_SEC,
.wait_sector_erase = 40LU * US_PER_MS,
.wait_sector_erase = 10LU * US_PER_MS,
.wait_32k_erase = 20LU * US_PER_MS,
.wait_4k_erase = 10LU * US_PER_MS,
.wait_chip_wake_up = 1LU * US_PER_MS,
.spi = MULLE_NOR_SPI_DEV,
.cs = MULLE_NOR_SPI_CS,

View File

@ -32,7 +32,6 @@ static const mtd_spi_nor_params_t _nrf52840dk_nor_params = {
.wait_chip_erase = 50LU * US_PER_SEC,
.wait_32k_erase = 240LU *US_PER_MS,
.wait_sector_erase = 40LU * US_PER_MS,
.wait_4k_erase = 40LU * US_PER_MS,
.wait_chip_wake_up = 35LU * US_PER_MS,
.clk = NRF52840DK_NOR_SPI_CLK,
.flag = NRF52840DK_NOR_FLAGS,

View File

@ -35,7 +35,6 @@ static const mtd_spi_nor_params_t _pinetime_nor_params = {
.wait_chip_erase = 9LU * US_PER_SEC,
.wait_32k_erase = 160LU *US_PER_MS,
.wait_sector_erase = 70LU * US_PER_MS,
.wait_4k_erase = 70LU * US_PER_MS,
.wait_chip_wake_up = 1LU * US_PER_MS,
.clk = PINETIME_NOR_SPI_CLK,
.flag = PINETIME_NOR_FLAGS,

View File

@ -33,7 +33,6 @@ static const mtd_spi_nor_params_t _serpente_nor_params = {
.wait_chip_erase = 15LU * US_PER_SEC,
.wait_32k_erase = 250LU * US_PER_MS,
.wait_sector_erase = 50LU * US_PER_MS,
.wait_4k_erase = 150LU * US_PER_MS,
.wait_chip_wake_up = 1LU * US_PER_MS,
.clk = SERPENTE_NOR_SPI_CLK,
.flag = SERPENTE_NOR_FLAGS,

View File

@ -32,7 +32,6 @@ static const mtd_spi_nor_params_t _weact_nor_params = {
.wait_chip_erase = 4800LU * US_PER_MS,
.wait_32k_erase = 300LU * US_PER_MS,
.wait_sector_erase = 70LU * US_PER_MS,
.wait_4k_erase = 70LU * US_PER_MS,
.wait_chip_wake_up = 1LU * US_PER_MS,
.clk = WEACT_411CE_NOR_SPI_CLK,
.flag = WEACT_411CE_NOR_FLAGS,

View File

@ -49,7 +49,7 @@ typedef struct {
uint8_t page_program; /**< Page program */
uint8_t sector_erase; /**< Block erase 4 KiB */
uint8_t block_erase_32k; /**< 32KiB block erase */
uint8_t block_erase; /**< Block erase (usually 64 KiB) */
uint8_t block_erase_64k; /**< Block erase (usually 64 KiB) */
uint8_t chip_erase; /**< Chip erase */
uint8_t sleep; /**< Deep power down */
uint8_t wake; /**< Release from deep power down */
@ -85,20 +85,26 @@ typedef struct __attribute__((packed)) {
* @brief Flag to set when the device support 4KiB sector erase (sector_erase opcode)
*/
#define SPI_NOR_F_SECT_4K (1)
/**
* @brief Flag to set when the device support 32KiB block erase (block_erase_32k opcode)
*/
#define SPI_NOR_F_SECT_32K (2)
/**
* @brief Flag to set when the device support 64KiB block erase (block_erase_32k opcode)
*/
#define SPI_NOR_F_SECT_64K (4)
/**
* @brief Compile-time parameters for a serial flash device
*/
typedef struct {
const mtd_spi_nor_opcode_t *opcode; /**< Opcode table for the device */
uint32_t wait_chip_erase; /**< Full chip erase wait time in µs */
uint32_t wait_sector_erase; /**< Sector erase wait time in µs */
uint32_t wait_64k_erase; /**< 64KB page erase wait time in µs */
uint32_t wait_32k_erase; /**< 32KB page erase wait time in µs */
uint32_t wait_4k_erase; /**< 4KB page erase wait time in µs */
uint32_t wait_sector_erase; /**< 4KB sector erase wait time in µs */
uint32_t wait_chip_wake_up; /**< Chip wake up time in µs */
spi_clk_t clk; /**< SPI clock */
uint16_t flag; /**< Config flags */

View File

@ -46,6 +46,8 @@
#define MTD_POWER_UP_WAIT_FOR_ID (0x0F)
#endif
#define MTD_64K (65536ul)
#define MTD_64K_ADDR_MASK (0xFFFF)
#define MTD_32K (32768ul)
#define MTD_32K_ADDR_MASK (0x7FFF)
#define MTD_4K (4096ul)
@ -605,6 +607,14 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size)
size -= total_size;
us = dev->params->wait_chip_erase;
}
else if ((dev->params->flag & SPI_NOR_F_SECT_64K) && (size >= MTD_64K) &&
((addr & MTD_64K_ADDR_MASK) == 0)) {
/* 64 KiB blocks can be erased with block erase command */
mtd_spi_cmd_addr_write(dev, dev->params->opcode->block_erase_64k, addr, NULL, 0);
addr += MTD_64K;
size -= MTD_64K;
us = dev->params->wait_64k_erase;
}
else if ((dev->params->flag & SPI_NOR_F_SECT_32K) && (size >= MTD_32K) &&
((addr & MTD_32K_ADDR_MASK) == 0)) {
/* 32 KiB blocks can be erased with block erase command */
@ -619,13 +629,14 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size)
mtd_spi_cmd_addr_write(dev, dev->params->opcode->sector_erase, addr, NULL, 0);
addr += MTD_4K;
size -= MTD_4K;
us = dev->params->wait_4k_erase;
us = dev->params->wait_sector_erase;
}
else {
mtd_spi_cmd_addr_write(dev, dev->params->opcode->block_erase, addr, NULL, 0);
addr += sector_size;
size -= sector_size;
us = dev->params->wait_sector_erase;
/* no suitable erase block found */
assert(0);
mtd_spi_release(dev);
return -EINVAL;
}
/* waiting for the command to complete before continuing */

View File

@ -36,7 +36,7 @@ const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default = {
.page_program = 0x02,
.sector_erase = 0x20,
.block_erase_32k = 0x52,
.block_erase = 0xd8,
.block_erase_64k = 0xd8,
.chip_erase = 0xc7,
.sleep = 0xb9,
.wake = 0xab,
@ -52,7 +52,7 @@ const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default_4bytes = {
.page_program = 0x12,
.sector_erase = 0x21,
.block_erase_32k = 0x5c,
.block_erase = 0xdc,
.block_erase_64k = 0xdc,
.chip_erase = 0xc7,
.sleep = 0xb9,
.wake = 0xab,