From 00dd96320c69585c5ee82bc36f5d9a2c877af365 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:19:54 +0100 Subject: [PATCH 01/10] mtd: refactor mtd struct Add a min_erase_size field and sector_size and remove pages_per_sector field. This allow to use a different erase size than the sector size. --- drivers/include/mtd.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/include/mtd.h b/drivers/include/mtd.h index 900ecaba1b66..49e758c0a75e 100644 --- a/drivers/include/mtd.h +++ b/drivers/include/mtd.h @@ -58,7 +58,8 @@ typedef struct mtd_desc mtd_desc_t; typedef struct { const mtd_desc_t *driver; /**< MTD driver */ uint32_t sector_count; /**< Number of sector in the MTD */ - uint32_t pages_per_sector; /**< Number of pages by sector in the MTD */ + uint32_t sector_size; /**< Size of the sectors in the MTD */ + uint32_t min_erase_size; /**< Minimum size which can be erased */ uint32_t page_size; /**< Size of the pages in the MTD */ } mtd_dev_t; From bcb7bcea9d4c36013497d0104e1812531127a273 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:21:30 +0100 Subject: [PATCH 02/10] mtd_native: update implementation --- boards/native/board_init.c | 3 ++- cpu/native/mtd/mtd_native.c | 13 ++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/boards/native/board_init.c b/boards/native/board_init.c index 52cb9aef98e5..672cfb23b30b 100644 --- a/boards/native/board_init.c +++ b/boards/native/board_init.c @@ -39,7 +39,8 @@ static mtd_native_dev_t mtd0_dev = { .dev = { .driver = &native_flash_driver, .sector_count = MTD_SECTOR_NUM, - .pages_per_sector = MTD_SECTOR_SIZE / MTD_PAGE_SIZE, + .sector_size = MTD_SECTOR_SIZE, + .min_erase_size = MTD_SECTOR_SIZE, .page_size = MTD_PAGE_SIZE, }, .fname = MTD_NATIVE_FILENAME, diff --git a/cpu/native/mtd/mtd_native.c b/cpu/native/mtd/mtd_native.c index fd353a913c2f..19fff2fac6b0 100644 --- a/cpu/native/mtd/mtd_native.c +++ b/cpu/native/mtd/mtd_native.c @@ -42,8 +42,8 @@ static int _init(mtd_dev_t *dev) if (!f) { return -EIO; } - size_t size = dev->sector_count * dev->pages_per_sector * dev->page_size; - for (size_t i = 0; i < size; i++) { + size_t mtd_size = dev->sector_count * dev->sector_size; + for (size_t i = 0; i < mtd_size; i++) { real_fputc(0xff, f); } } @@ -56,7 +56,7 @@ static int _init(mtd_dev_t *dev) static int _read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) { mtd_native_dev_t *_dev = (mtd_native_dev_t*) dev; - size_t mtd_size = dev->sector_count * dev->pages_per_sector * dev->page_size; + size_t mtd_size = dev->sector_count * dev->sector_size; DEBUG("mtd_native: read from page %" PRIu32 " count %" PRIu32 "\n", addr, size); @@ -78,7 +78,7 @@ static int _read(mtd_dev_t *dev, void *buff, uint32_t addr, uint32_t size) static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) { mtd_native_dev_t *_dev = (mtd_native_dev_t*) dev; - size_t mtd_size = dev->sector_count * dev->pages_per_sector * dev->page_size; + size_t mtd_size = dev->sector_count * dev->sector_size; DEBUG("mtd_native: write from 0x%" PRIx32 " count %" PRIu32 "\n", addr, size); @@ -107,15 +107,14 @@ static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) { mtd_native_dev_t *_dev = (mtd_native_dev_t*) dev; - size_t mtd_size = dev->sector_count * dev->pages_per_sector * dev->page_size; - size_t sector_size = dev->pages_per_sector * dev->page_size; + size_t mtd_size = dev->sector_count * dev->sector_size; DEBUG("mtd_native: erase from sector %" PRIu32 " count %" PRIu32 "\n", addr, size); if (addr + size > mtd_size) { return -EOVERFLOW; } - if (((addr % sector_size) != 0) || ((size % sector_size) != 0)) { + if (((addr % dev->min_erase_size) != 0) || ((size % dev->min_erase_size) != 0)) { return -EOVERFLOW; } From dac43c1c434e7d538aef063a4d71af7af19921cc Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:21:58 +0100 Subject: [PATCH 03/10] mtd_spi_nor: update implementation --- drivers/include/mtd_spi_nor.h | 13 +++++ drivers/mtd_spi_nor/mtd_spi_nor.c | 67 ++++++++++++++++------- drivers/mtd_spi_nor/mtd_spi_nor_configs.c | 1 + 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/drivers/include/mtd_spi_nor.h b/drivers/include/mtd_spi_nor.h index c6347ec00c0f..64d8ee270f9f 100644 --- a/drivers/include/mtd_spi_nor.h +++ b/drivers/include/mtd_spi_nor.h @@ -42,6 +42,7 @@ extern "C" typedef struct { uint8_t rdid; /**< Read identification (JEDEC ID) */ uint8_t wren; /**< Write enable */ + uint8_t wrdi; /**< Write disable */ uint8_t rdsr; /**< Read status register */ uint8_t wrsr; /**< Write status register */ uint8_t read; /**< Read data bytes, 3 byte address */ @@ -109,6 +110,12 @@ typedef struct { * Computed by mtd_spi_nor_init, no need to touch outside the driver. */ uint32_t sec_addr_mask; + /** + * @brief bitmask corresponding to the minimum erasable sector address + * + * Computed by mtd_spi_nor_init, no need to touch outside the driver. + */ + uint32_t min_erase_addr_mask; uint8_t addr_width; /**< Number of bytes in addresses, usually 3 for small devices */ /** * @brief number of right shifts to get the address to the start of the page @@ -122,6 +129,12 @@ typedef struct { * Computed by mtd_spi_nor_init, no need to touch outside the driver. */ uint8_t sec_addr_shift; + /** + * @brief number of right shifts to get the address to the start of the erasable sector + * + * Computed by mtd_spi_nor_init, no need to touch outside the driver. + */ + uint8_t min_erase_addr_shift; } mtd_spi_nor_t; /** diff --git a/drivers/mtd_spi_nor/mtd_spi_nor.c b/drivers/mtd_spi_nor/mtd_spi_nor.c index f0ca7be4a886..be0d0e62e52b 100644 --- a/drivers/mtd_spi_nor/mtd_spi_nor.c +++ b/drivers/mtd_spi_nor/mtd_spi_nor.c @@ -284,12 +284,13 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd) DEBUG("mtd_spi_nor_init: %" PRIu32 " bytes " "(%" PRIu32 " sectors, %" PRIu32 " bytes/sector, " - "%" PRIu32 " pages, " - "%" PRIu32 " pages/sector, %" PRIu32 " bytes/page)\n", - mtd->pages_per_sector * mtd->sector_count * mtd->page_size, - mtd->sector_count, mtd->pages_per_sector * mtd->page_size, - mtd->pages_per_sector * mtd->sector_count, - mtd->pages_per_sector, mtd->page_size); + "%" PRIu32 " pages, %" PRIu32 " bytes/page," + "Min erase size %" PRIu32 ")\n", + mtd->sector_count * mtd->sector_size, + mtd->sector_count, mtd->sector_size, + (mtd->sector_count * mtd->sector_size) / mtd->page_size, + mtd->page_size, + mtd->min_erase_size); DEBUG("mtd_spi_nor_init: Using %u byte addresses\n", dev->addr_width); if (dev->addr_width == 0) { @@ -334,7 +335,7 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd) mask = 0; shift = 0; - uint32_t sector_size = mtd->page_size * mtd->pages_per_sector; + uint32_t sector_size = mtd->sector_size; if ((sector_size & (sector_size - 1)) == 0) { while ((sector_size >> shift) > 1) { ++shift; @@ -344,6 +345,19 @@ static int mtd_spi_nor_init(mtd_dev_t *mtd) dev->sec_addr_mask = mask; dev->sec_addr_shift = shift; + if (dev->flag & SPI_NOR_F_SECT_4K) { + dev->min_erase_addr_mask = UINT32_MAX << 12; + dev->min_erase_addr_shift = 12; + } + else if (dev->flag & SPI_NOR_F_SECT_32K) { + dev->min_erase_addr_mask = UINT32_MAX << 15; + dev->min_erase_addr_shift = 15; + } + else { + dev->min_erase_addr_mask = dev->sec_addr_mask; + dev->min_erase_addr_shift = dev->sec_addr_shift; + } + DEBUG("mtd_spi_nor_init: sec_addr_mask = 0x%08" PRIx32 ", sec_addr_shift = %u\n", mask, (unsigned int)shift); @@ -355,8 +369,9 @@ static int mtd_spi_nor_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t DEBUG("mtd_spi_nor_read: %p, %p, 0x%" PRIx32 ", 0x%" PRIx32 "\n", (void *)mtd, dest, addr, size); const mtd_spi_nor_t *dev = (mtd_spi_nor_t *)mtd; - size_t chipsize = mtd->page_size * mtd->pages_per_sector * mtd->sector_count; + size_t chipsize = mtd->sector_size * mtd->sector_count; if (addr > chipsize) { + DEBUG("mtd_spi_nor_read: ERR: reading outside memory!\n"); return -EOVERFLOW; } if (size > mtd->page_size) { @@ -384,7 +399,7 @@ static int mtd_spi_nor_read(mtd_dev_t *mtd, void *dest, uint32_t addr, uint32_t static int mtd_spi_nor_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uint32_t size) { - uint32_t total_size = mtd->page_size * mtd->pages_per_sector * mtd->sector_count; + uint32_t total_size = mtd->sector_size * mtd->sector_count; DEBUG("mtd_spi_nor_write: %p, %p, 0x%" PRIx32 ", 0x%" PRIx32 "\n", (void *)mtd, src, addr, size); @@ -402,6 +417,7 @@ static int mtd_spi_nor_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uin return -EOVERFLOW; } if (addr + size > total_size) { + DEBUG("mtd_spi_nor_write: ERR: writing outside memory!\n"); return -EOVERFLOW; } be_uint32_t addr_be = byteorder_htonl(addr); @@ -422,25 +438,29 @@ static int mtd_spi_nor_write(mtd_dev_t *mtd, const void *src, uint32_t addr, uin static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) { + int res = 0; DEBUG("mtd_spi_nor_erase: %p, 0x%" PRIx32 ", 0x%" PRIx32 "\n", (void *)mtd, addr, size); mtd_spi_nor_t *dev = (mtd_spi_nor_t *)mtd; - uint32_t sector_size = mtd->page_size * mtd->pages_per_sector; - uint32_t total_size = sector_size * mtd->sector_count; + uint32_t total_size = mtd->sector_size * mtd->sector_count; - if (dev->sec_addr_mask && - ((addr & ~dev->sec_addr_mask) != 0)) { + if (dev->min_erase_addr_mask && + ((addr & ~dev->min_erase_addr_mask) != 0)) { /* This is not a requirement in hardware, but it helps in catching * software bugs (the erase-all-your-files kind) */ - DEBUG("addr = %" PRIx32 " ~dev->erase_addr_mask = %" PRIx32 "", addr, ~dev->sec_addr_mask); + DEBUG("addr = %" PRIx32 " ~dev->min_erase_addr_mask = %" PRIx32 "", + addr, ~dev->min_erase_addr_mask); DEBUG("mtd_spi_nor_erase: ERR: erase addr not aligned on %" PRIu32 " byte boundary.\n", - sector_size); + mtd->min_erase_size); return -EOVERFLOW; } if (addr + size > total_size) { + DEBUG("mtd_spi_nor_erase: ERR: erasing outside memory!\n"); return -EOVERFLOW; } - if (size % sector_size != 0) { + if (size % mtd->min_erase_size != 0) { + DEBUG("mtd_spi_nor_erase: ERR: size is not aligned on %" PRIu32 " byte boundary\n", + mtd->min_erase_size); return -EOVERFLOW; } @@ -454,6 +474,11 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) mtd_spi_cmd(dev, dev->opcode->chip_erase); size -= total_size; } + else if ((size >= mtd->sector_size) && ((addr & ~dev->sec_addr_mask) == 0)){ + mtd_spi_cmd_addr_write(dev, dev->opcode->block_erase, addr_be, NULL, 0); + addr += mtd->sector_size; + size -= mtd->sector_size; + } else if ((dev->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 */ @@ -469,9 +494,11 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) size -= MTD_4K; } else { - mtd_spi_cmd_addr_write(dev, dev->opcode->block_erase, addr_be, NULL, 0); - addr += sector_size; - size -= sector_size; + DEBUG("mtd_spi_nor_erase: ERR: remaining size is not aligned on %" PRIu32 " byte boundary\n", + mtd->min_erase_size); + mtd_spi_cmd(dev, dev->opcode->wrdi); + res = -EOVERFLOW; + break; } /* waiting for the command to complete before continuing */ @@ -479,7 +506,7 @@ static int mtd_spi_nor_erase(mtd_dev_t *mtd, uint32_t addr, uint32_t size) } spi_release(dev->spi); - return 0; + return res; } static int mtd_spi_nor_power(mtd_dev_t *mtd, enum mtd_power_state power) diff --git a/drivers/mtd_spi_nor/mtd_spi_nor_configs.c b/drivers/mtd_spi_nor/mtd_spi_nor_configs.c index 9d31ff95105f..c32b6fa871df 100644 --- a/drivers/mtd_spi_nor/mtd_spi_nor_configs.c +++ b/drivers/mtd_spi_nor/mtd_spi_nor_configs.c @@ -29,6 +29,7 @@ const mtd_spi_nor_opcode_t mtd_spi_nor_opcode_default = { .rdid = 0x9f, .wren = 0x06, + .wrdi = 0x04, .rdsr = 0x05, .wrsr = 0x01, .read = 0x03, From 8afef56ad79a67fa3d0f10eb10df5f822b848b0e Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:22:16 +0100 Subject: [PATCH 04/10] mtd_vfs: update implementation --- drivers/mtd/mtd-vfs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mtd/mtd-vfs.c b/drivers/mtd/mtd-vfs.c index f2d384f2016a..3c924afd5d2a 100644 --- a/drivers/mtd/mtd-vfs.c +++ b/drivers/mtd/mtd-vfs.c @@ -54,7 +54,7 @@ static int mtd_vfs_fstat(vfs_file_t *filp, struct stat *buf) return -EFAULT; } buf->st_nlink = 1; - buf->st_size = mtd->page_size * mtd->sector_count * mtd->pages_per_sector; + buf->st_size = mtd->sector_count * mtd->sector_size; return 0; } @@ -71,7 +71,7 @@ static off_t mtd_vfs_lseek(vfs_file_t *filp, off_t off, int whence) off += filp->pos; break; case SEEK_END: - off += mtd->page_size * mtd->sector_count * mtd->pages_per_sector; + off += mtd->sector_count * mtd->sector_size; break; default: return -EINVAL; @@ -91,7 +91,7 @@ static ssize_t mtd_vfs_read(vfs_file_t *filp, void *dest, size_t nbytes) if (mtd == NULL) { return -EFAULT; } - uint32_t size = mtd->page_size * mtd->sector_count * mtd->pages_per_sector; + uint32_t size = mtd->sector_count * mtd->sector_size; uint32_t src = filp->pos; if (src >= size) { return 0; @@ -114,7 +114,7 @@ static ssize_t mtd_vfs_write(vfs_file_t *filp, const void *src, size_t nbytes) if (mtd == NULL) { return -EFAULT; } - uint32_t size = mtd->page_size * mtd->sector_count * mtd->pages_per_sector; + uint32_t size = mtd->sector_count * mtd->sector_size; uint32_t dest = filp->pos; if (dest >= size) { /* attempt to write outside the device memory */ From d7aaf5eb909ebeb5b5ccba0e9ec3e304cd5a629f Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:22:31 +0100 Subject: [PATCH 05/10] unittests/test-mtd: update tests --- tests/unittests/tests-mtd/tests-mtd.c | 90 ++++++++++++++++++++------- 1 file changed, 66 insertions(+), 24 deletions(-) diff --git a/tests/unittests/tests-mtd/tests-mtd.c b/tests/unittests/tests-mtd/tests-mtd.c index 277f251c7ab1..1f58adbd3866 100644 --- a/tests/unittests/tests-mtd/tests-mtd.c +++ b/tests/unittests/tests-mtd/tests-mtd.c @@ -31,16 +31,19 @@ #else /* Test mock object implementing a simple RAM-based mtd */ #ifndef SECTOR_COUNT -#define SECTOR_COUNT 4 +#define SECTOR_COUNT 4 #endif -#ifndef PAGE_PER_SECTOR -#define PAGE_PER_SECTOR 4 +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 512 +#endif +#ifndef MIN_ERASE_SIZE +#define MIN_ERASE_SIZE 256 #endif #ifndef PAGE_SIZE -#define PAGE_SIZE 128 +#define PAGE_SIZE 128 #endif -static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT]; +static uint8_t dummy_memory[SECTOR_SIZE * SECTOR_COUNT]; static int init(mtd_dev_t *dev) { @@ -72,7 +75,10 @@ static int write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size) if (((addr % PAGE_SIZE) + size) > PAGE_SIZE) { return -EOVERFLOW; } - memcpy(dummy_memory + addr, buff, size); + const uint8_t *p = buff; + for (size_t i = 0; i < size; i++) { + dummy_memory[addr + i] &= p[i]; + } return size; } @@ -81,10 +87,10 @@ static int erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) { (void)dev; - if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) { + if (size % (MIN_ERASE_SIZE) != 0) { return -EOVERFLOW; } - if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) { + if (addr % (MIN_ERASE_SIZE) != 0) { return -EOVERFLOW; } if (addr + size > sizeof(dummy_memory)) { @@ -113,7 +119,8 @@ static const mtd_desc_t driver = { static mtd_dev_t _dev = { .driver = &driver, .sector_count = SECTOR_COUNT, - .pages_per_sector = PAGE_PER_SECTOR, + .sector_size = SECTOR_SIZE, + .min_erase_size = MIN_ERASE_SIZE, .page_size = PAGE_SIZE, }; @@ -121,9 +128,9 @@ static mtd_dev_t *dev = (mtd_dev_t*) &_dev; #endif /* MTD_0 */ -static void setup_teardown(void) +static void teardown(void) { - mtd_erase(dev, 0, dev->pages_per_sector * dev->page_size); + mtd_erase(dev, 0, dev->sector_count * dev->sector_size); } static void test_mtd_init(void) @@ -135,7 +142,10 @@ static void test_mtd_init(void) static void test_mtd_erase(void) { /* Erase first sector */ - int ret = mtd_erase(dev, 0, dev->pages_per_sector * dev->page_size); + int ret = mtd_erase(dev, 0, dev->sector_size); + TEST_ASSERT_EQUAL_INT(0, ret); + + ret = mtd_erase(dev, 0, dev->min_erase_size); TEST_ASSERT_EQUAL_INT(0, ret); /* Erase with wrong size (les than sector size) */ @@ -147,16 +157,51 @@ static void test_mtd_erase(void) TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); /* Erase 2nd - 3rd sector */ - ret = mtd_erase(dev, dev->pages_per_sector * dev->page_size, - dev->pages_per_sector * dev->page_size * 2); + ret = mtd_erase(dev, dev->min_erase_size, + dev->min_erase_size * 2); TEST_ASSERT_EQUAL_INT(0, ret); /* Erase out of memory area */ - ret = mtd_erase(dev, dev->pages_per_sector * dev->page_size * dev->sector_count, - dev->pages_per_sector * dev->page_size); + ret = mtd_erase(dev, dev->sector_count * dev->sector_size, + dev->min_erase_size); TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); } +static void test_mtd_erase_read(void) +{ + int ret; + uint8_t buf[32]; + memset(buf, 0x55, sizeof(buf)); + + /* Fill in 4 sectors */ + size_t i = 0; + while (i < 4 * dev->sector_size) { + ret = mtd_write(dev, buf, i, sizeof(buf)); + i += sizeof(buf); + TEST_ASSERT_EQUAL_INT(sizeof(buf), ret); + } + + /* Erase 2 sectors, starting from second erasable unit */ + ret = mtd_erase(dev, dev->min_erase_size, 2 * dev->sector_size); + TEST_ASSERT_EQUAL_INT(0, ret); + + /* First erasable unit is not erased */ + memset(buf, 0, sizeof(buf)); + ret = mtd_read(dev, buf, dev->min_erase_size - sizeof(buf), sizeof(buf)); + TEST_ASSERT_EQUAL_INT(sizeof(buf), ret); + for (unsigned j = 0; j < sizeof(buf); j++) { + TEST_ASSERT_EQUAL_INT(0x55, buf[j]); + } + + /* Second erasable unit of third sector is not erased */ + memset(buf, 0, sizeof(buf)); + ret = mtd_read(dev, buf, 2 * dev->sector_size + dev->min_erase_size, sizeof(buf)); + TEST_ASSERT_EQUAL_INT(sizeof(buf), ret); + for (unsigned j = 0; j < sizeof(buf); j++) { + TEST_ASSERT_EQUAL_INT(0x55, buf[j]); + } +} + static void test_mtd_write_erase(void) { const char buf[] = "ABCDEFGHIJK"; @@ -167,7 +212,7 @@ static void test_mtd_write_erase(void) int ret = mtd_write(dev, buf, sizeof(buf_empty), sizeof(buf)); TEST_ASSERT_EQUAL_INT(sizeof(buf), ret); - ret = mtd_erase(dev, 0, dev->pages_per_sector * dev->page_size); + ret = mtd_erase(dev, 0, dev->min_erase_size); TEST_ASSERT_EQUAL_INT(0, ret); uint8_t expected[sizeof(buf_read)]; @@ -204,12 +249,12 @@ static void test_mtd_write_read(void) TEST_ASSERT_EQUAL_INT(0, memcmp(buf, buf_read + sizeof(buf_empty), sizeof(buf))); /* out of bounds write (addr) */ - ret = mtd_write(dev, buf, dev->pages_per_sector * dev->page_size * dev->sector_count, + ret = mtd_write(dev, buf, dev->sector_count * dev->sector_size, sizeof(buf)); TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); /* out of bounds write (addr + count) */ - ret = mtd_write(dev, buf, (dev->pages_per_sector * dev->page_size * dev->sector_count) + ret = mtd_write(dev, buf, (dev->sector_count * dev->sector_size) - (sizeof(buf) / 2), sizeof(buf)); TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); @@ -226,7 +271,6 @@ static void test_mtd_write_read(void) TEST_ASSERT_EQUAL_INT(-EOVERFLOW, ret); } -#ifdef MTD_0 static void test_mtd_write_read_flash(void) { const uint8_t buf1[] = {0xee, 0xdd, 0xcc}; @@ -249,7 +293,6 @@ static void test_mtd_write_read_flash(void) TEST_ASSERT_EQUAL_INT(0, memcmp(buf_expected, buf_read, sizeof(buf_expected))); TEST_ASSERT_EQUAL_INT(0, memcmp(buf_empty, buf_read + sizeof(buf_expected), sizeof(buf_empty))); } -#endif #if MODULE_VFS static void test_mtd_vfs(void) @@ -285,17 +328,16 @@ Test *tests_mtd_tests(void) EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(test_mtd_init), new_TestFixture(test_mtd_erase), + new_TestFixture(test_mtd_erase_read), new_TestFixture(test_mtd_write_erase), new_TestFixture(test_mtd_write_read), -#ifdef MTD_0 new_TestFixture(test_mtd_write_read_flash), -#endif #if MODULE_VFS new_TestFixture(test_mtd_vfs), #endif }; - EMB_UNIT_TESTCALLER(mtd_tests, setup_teardown, setup_teardown, fixtures); + EMB_UNIT_TESTCALLER(mtd_tests, NULL, teardown, fixtures); return (Test *)&mtd_tests; } From 855eb8e50bc40aebeaf2fd85aafc1db31a45b7e0 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Mon, 22 Jan 2018 18:49:52 +0100 Subject: [PATCH 06/10] pkg/littlefs: update mtd usage --- pkg/littlefs/fs/littlefs_fs.c | 5 ++- .../unittests/tests-littlefs/tests-littlefs.c | 38 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/pkg/littlefs/fs/littlefs_fs.c b/pkg/littlefs/fs/littlefs_fs.c index c0dfaf57b19f..3b84609c1947 100644 --- a/pkg/littlefs/fs/littlefs_fs.c +++ b/pkg/littlefs/fs/littlefs_fs.c @@ -135,10 +135,11 @@ static int prepare(littlefs_desc_t *fs) memset(&fs->fs, 0, sizeof(fs->fs)); if (!fs->config.block_count) { - fs->config.block_count = fs->dev->sector_count - fs->base_addr; + fs->config.block_count = ((fs->dev->sector_count * fs->dev->sector_size) / + fs->dev->min_erase_size) - fs->base_addr; } if (!fs->config.block_size) { - fs->config.block_size = fs->dev->page_size * fs->dev->pages_per_sector; + fs->config.block_size = fs->dev->min_erase_size; } if (!fs->config.prog_size) { fs->config.prog_size = fs->dev->page_size; diff --git a/tests/unittests/tests-littlefs/tests-littlefs.c b/tests/unittests/tests-littlefs/tests-littlefs.c index e98971b758e5..3d2565c3292a 100644 --- a/tests/unittests/tests-littlefs/tests-littlefs.c +++ b/tests/unittests/tests-littlefs/tests-littlefs.c @@ -31,16 +31,16 @@ #else /* Test mock object implementing a simple RAM-based mtd */ #ifndef SECTOR_COUNT -#define SECTOR_COUNT 16 +#define SECTOR_COUNT 16 #endif -#ifndef PAGE_PER_SECTOR -#define PAGE_PER_SECTOR 4 +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 128 #endif #ifndef PAGE_SIZE -#define PAGE_SIZE 64 +#define PAGE_SIZE 64 #endif -static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT]; +static uint8_t dummy_memory[SECTOR_SIZE * SECTOR_COUNT]; static int _init(mtd_dev_t *dev) { @@ -68,10 +68,13 @@ static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size if (addr + size > sizeof(dummy_memory)) { return -EOVERFLOW; } - if (size > PAGE_SIZE) { + if (((addr % PAGE_SIZE) + size) > PAGE_SIZE) { return -EOVERFLOW; } - memcpy(dummy_memory + addr, buff, size); + const uint8_t *p = buff; + for (size_t i = 0; i < size; i++) { + dummy_memory[addr + i] &= p[i]; + } return size; } @@ -80,10 +83,10 @@ static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) { (void)dev; - if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) { + if (size % SECTOR_SIZE != 0) { return -EOVERFLOW; } - if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) { + if (addr % SECTOR_SIZE != 0) { return -EOVERFLOW; } if (addr + size > sizeof(dummy_memory)) { @@ -112,7 +115,8 @@ static const mtd_desc_t driver = { static mtd_dev_t dev = { .driver = &driver, .sector_count = SECTOR_COUNT, - .pages_per_sector = PAGE_PER_SECTOR, + .sector_size = SECTOR_SIZE, + .min_erase_size = SECTOR_SIZE, .page_size = PAGE_SIZE, }; @@ -147,7 +151,7 @@ static void tests_littlefs_format(void) { int res; vfs_umount(&_test_littlefs_mount); - res = mtd_erase(_dev, 0, _dev->page_size * _dev->pages_per_sector * _dev->sector_count); + res = mtd_erase(_dev, 0, _dev->sector_size * _dev->sector_count); TEST_ASSERT_EQUAL_INT(0, res); res = vfs_mount(&_test_littlefs_mount); @@ -381,10 +385,9 @@ static void tests_littlefs_statvfs(void) int res = vfs_statvfs("/test-littlefs/", &stat1); TEST_ASSERT_EQUAL_INT(0, res); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat1.f_bsize); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat1.f_frsize); - TEST_ASSERT((_dev->pages_per_sector * _dev->page_size * _dev->sector_count) >= - stat1.f_blocks); + TEST_ASSERT_EQUAL_INT(_dev->min_erase_size, stat1.f_bsize); + TEST_ASSERT_EQUAL_INT(_dev->min_erase_size, stat1.f_frsize); + TEST_ASSERT((_dev->sector_size * _dev->sector_count) >= stat1.f_blocks); int fd = vfs_open("/test-littlefs/test.txt", O_CREAT | O_RDWR, 0); TEST_ASSERT(fd >= 0); @@ -398,8 +401,8 @@ static void tests_littlefs_statvfs(void) res = vfs_statvfs("/test-littlefs/", &stat2); TEST_ASSERT_EQUAL_INT(0, res); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat2.f_bsize); - TEST_ASSERT_EQUAL_INT(_dev->page_size * _dev->pages_per_sector, stat2.f_frsize); + TEST_ASSERT_EQUAL_INT(_dev->min_erase_size, stat2.f_bsize); + TEST_ASSERT_EQUAL_INT(_dev->min_erase_size, stat2.f_frsize); TEST_ASSERT(stat1.f_bfree > stat2.f_bfree); TEST_ASSERT(stat1.f_bavail > stat2.f_bavail); } @@ -409,7 +412,6 @@ Test *tests_littlefs_tests(void) #ifndef MTD_0 memset(dummy_memory, 0xff, sizeof(dummy_memory)); #endif - EMB_UNIT_TESTFIXTURES(fixtures) { new_TestFixture(tests_littlefs_format), new_TestFixture(tests_littlefs_mount_umount), From 5a2e0ec8ad652542eaeb76fbd27370c973be3a9d Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:17:34 +0100 Subject: [PATCH 07/10] boards/mulle: fix mtd configuration --- boards/mulle/board.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/boards/mulle/board.c b/boards/mulle/board.c index b4f548557d1f..a25f358a7396 100644 --- a/boards/mulle/board.c +++ b/boards/mulle/board.c @@ -52,8 +52,9 @@ static mtd_spi_nor_t mulle_nor_dev = { .base = { .driver = &mtd_spi_nor_driver, .page_size = 256, - .pages_per_sector = 256, + .sector_size = 65536, .sector_count = 32, + .min_erase_size = 65536, }, .opcode = &mtd_spi_nor_opcode_default, .spi = MULLE_NOR_SPI_DEV, From ec9aee918f1d83d06d07cc42d56d766fbd74e240 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 12:29:32 +0100 Subject: [PATCH 08/10] pkg/spiffs: update mtd usage --- pkg/spiffs/fs/spiffs_fs.c | 14 +++--- tests/unittests/tests-spiffs/tests-spiffs.c | 48 ++++++++++++--------- 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/pkg/spiffs/fs/spiffs_fs.c b/pkg/spiffs/fs/spiffs_fs.c index 73c017035142..c7efec7d1088 100644 --- a/pkg/spiffs/fs/spiffs_fs.c +++ b/pkg/spiffs/fs/spiffs_fs.c @@ -134,19 +134,19 @@ static int prepare(spiffs_desc_t *fs_desc) fs_desc->config.hal_erase_f = _dev_erase; #if SPIFFS_SINGLETON == 0 - DEBUG("spiffs: mount: mtd page_size=%" PRIu32 ", pages_per_sector=%" PRIu32 - ", sector_count=%" PRIu32 "\n", dev->page_size, dev->pages_per_sector, dev->sector_count); + DEBUG("spiffs: mount: mtd page_size=%" PRIu32 ", sector_size=%" PRIu32 + ", sector_count=%" PRIu32 "\n", dev->page_size, dev->sector_size, dev->sector_count); uint32_t sector_count = (fs_desc->block_count == 0) ? dev->sector_count : fs_desc->block_count; /* inside memory area */ - assert(((fs_desc->base_addr / (dev->page_size * dev->pages_per_sector)) + sector_count) + assert(((fs_desc->base_addr / dev->min_erase_size) + sector_count) <= dev->sector_count); /* base addr is aligned on a sector */ - assert(fs_desc->base_addr % (dev->pages_per_sector * dev->page_size) == 0); - fs_desc->config.phys_size = dev->page_size * dev->pages_per_sector * sector_count; - fs_desc->config.log_block_size = dev->page_size * dev->pages_per_sector; + assert(fs_desc->base_addr % dev->min_erase_size == 0); + fs_desc->config.phys_size = dev->min_erase_size * sector_count; + fs_desc->config.log_block_size = dev->min_erase_size; fs_desc->config.log_page_size = dev->page_size; fs_desc->config.phys_addr = fs_desc->base_addr; - fs_desc->config.phys_erase_block = dev->page_size * dev->pages_per_sector; + fs_desc->config.phys_erase_block = dev->min_erase_size; #endif return mtd_init(dev); diff --git a/tests/unittests/tests-spiffs/tests-spiffs.c b/tests/unittests/tests-spiffs/tests-spiffs.c index 92eb27449395..f7f40d3639d2 100644 --- a/tests/unittests/tests-spiffs/tests-spiffs.c +++ b/tests/unittests/tests-spiffs/tests-spiffs.c @@ -29,16 +29,16 @@ #else /* Test mock object implementing a simple RAM-based mtd */ #ifndef SECTOR_COUNT -#define SECTOR_COUNT 4 +#define SECTOR_COUNT 4 #endif -#ifndef PAGE_PER_SECTOR -#define PAGE_PER_SECTOR 8 +#ifndef SECTOR_SIZE +#define SECTOR_SIZE 1024 #endif #ifndef PAGE_SIZE -#define PAGE_SIZE 128 +#define PAGE_SIZE 128 #endif -static uint8_t dummy_memory[PAGE_PER_SECTOR * PAGE_SIZE * SECTOR_COUNT]; +static uint8_t dummy_memory[SECTOR_SIZE * SECTOR_COUNT]; static int _init(mtd_dev_t *dev) { @@ -68,7 +68,13 @@ static int _write(mtd_dev_t *dev, const void *buff, uint32_t addr, uint32_t size if (size > PAGE_SIZE) { return -EOVERFLOW; } - memcpy(dummy_memory + addr, buff, size); + if (((addr % PAGE_SIZE) + size) > PAGE_SIZE) { + return -EOVERFLOW; + } + const uint8_t *p = buff; + for (size_t i = 0; i < size; i++) { + dummy_memory[addr + i] &= p[i]; + } return size; } @@ -77,10 +83,10 @@ static int _erase(mtd_dev_t *dev, uint32_t addr, uint32_t size) { (void)dev; - if (size % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) { + if (size % SECTOR_SIZE != 0) { return -EOVERFLOW; } - if (addr % (PAGE_PER_SECTOR * PAGE_SIZE) != 0) { + if (addr % SECTOR_SIZE != 0) { return -EOVERFLOW; } if (addr + size > sizeof(dummy_memory)) { @@ -109,7 +115,8 @@ static const mtd_desc_t driver = { static mtd_dev_t dev = { .driver = &driver, .sector_count = SECTOR_COUNT, - .pages_per_sector = PAGE_PER_SECTOR, + .sector_size = SECTOR_SIZE, + .min_erase_size = SECTOR_SIZE, .page_size = PAGE_SIZE, }; @@ -150,7 +157,7 @@ static void tests_spiffs_format(void) { int res; vfs_umount(&_test_spiffs_mount); - res = mtd_erase(_dev, 0, _dev->page_size * _dev->pages_per_sector * _dev->sector_count); + res = mtd_erase(_dev, 0, _dev->sector_size * _dev->sector_count); TEST_ASSERT_EQUAL_INT(0, res); res = vfs_mount(&_test_spiffs_mount); @@ -362,8 +369,7 @@ static void tests_spiffs_statvfs(void) TEST_ASSERT_EQUAL_INT(0, res); TEST_ASSERT_EQUAL_INT(1, stat1.f_bsize); TEST_ASSERT_EQUAL_INT(1, stat1.f_frsize); - TEST_ASSERT((_dev->pages_per_sector * _dev->page_size * _dev->sector_count) >= - stat1.f_blocks); + TEST_ASSERT((_dev->sector_size * _dev->sector_count) >= stat1.f_blocks); int fd = vfs_open("/test-spiffs/test.txt", O_CREAT | O_RDWR, 0); TEST_ASSERT(fd >= 0); @@ -387,9 +393,9 @@ static void tests_spiffs_partition(void) { vfs_umount(&_test_spiffs_mount); - spiffs_desc.base_addr = _dev->page_size * _dev->pages_per_sector; + spiffs_desc.base_addr = _dev->min_erase_size; spiffs_desc.block_count = 2; - mtd_erase(_dev, 0, _dev->page_size * _dev->pages_per_sector * _dev->sector_count); + mtd_erase(_dev, 0, _dev->sector_size * _dev->sector_count); int res = vfs_format(&_test_spiffs_mount); TEST_ASSERT_EQUAL_INT(0, res); @@ -403,22 +409,22 @@ static void tests_spiffs_partition(void) const uint8_t buf_erased[4] = {0xff, 0xff, 0xff, 0xff}; int nread; res = 0; - for (size_t i = 0; i < _dev->page_size * _dev->pages_per_sector; i += sizeof(buf)) { - nread = mtd_read(_dev, buf, _dev->page_size * _dev->pages_per_sector + i, sizeof(buf)); + for (size_t i = 0; i < _dev->min_erase_size; i += sizeof(buf)) { + nread = mtd_read(_dev, buf, _dev->min_erase_size + i, sizeof(buf)); TEST_ASSERT_EQUAL_INT(sizeof(buf), nread); res |= memcmp(buf, buf_erased, sizeof(buf)); } TEST_ASSERT(res != 0); res = 0; - for (size_t i = 0; i < _dev->page_size * _dev->pages_per_sector; i += sizeof(buf)) { - nread = mtd_read(_dev, buf, (2 * _dev->page_size * _dev->pages_per_sector) + i, sizeof(buf)); + for (size_t i = 0; i < _dev->min_erase_size; i += sizeof(buf)) { + nread = mtd_read(_dev, buf, (2 * _dev->min_erase_size) + i, sizeof(buf)); TEST_ASSERT_EQUAL_INT(sizeof(buf), nread); res |= memcmp(buf, buf_erased, sizeof(buf)); } TEST_ASSERT(res != 0); /* Check previous sector (must be erased) */ res = 0; - for (size_t i = 0; i < _dev->page_size * _dev->pages_per_sector; i += sizeof(buf)) { + for (size_t i = 0; i < _dev->min_erase_size; i += sizeof(buf)) { nread = mtd_read(_dev, buf, i, sizeof(buf)); TEST_ASSERT_EQUAL_INT(sizeof(buf), nread); res |= memcmp(buf, buf_erased, sizeof(buf)); @@ -426,8 +432,8 @@ static void tests_spiffs_partition(void) TEST_ASSERT(res == 0); /* Check next sector (must be erased) */ res = 0; - for (size_t i = 0; i < _dev->page_size * _dev->pages_per_sector; i += sizeof(buf)) { - nread = mtd_read(_dev, buf, (3 * _dev->page_size * _dev->pages_per_sector) + i, sizeof(buf)); + for (size_t i = 0; i < _dev->min_erase_size; i += sizeof(buf)) { + nread = mtd_read(_dev, buf, (3 * _dev->min_erase_size) + i, sizeof(buf)); TEST_ASSERT_EQUAL_INT(sizeof(buf), nread); res |= memcmp(buf, buf_erased, sizeof(buf)); } From d9e092741f04630ffc240d7bc63f0da830ad2348 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 16:55:54 +0100 Subject: [PATCH 09/10] pkg/fatfs: update mtd usage --- pkg/fatfs/fatfs_diskio/mtd/mtd_diskio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fatfs/fatfs_diskio/mtd/mtd_diskio.c b/pkg/fatfs/fatfs_diskio/mtd/mtd_diskio.c index 5e072397545c..a066bfbe21ed 100644 --- a/pkg/fatfs/fatfs_diskio/mtd/mtd_diskio.c +++ b/pkg/fatfs/fatfs_diskio/mtd/mtd_diskio.c @@ -179,7 +179,7 @@ DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff) /*Erase block size in number of sectors (1 to 32768 in power of 2). Return 1 if the erase block size is unknown. */ case GET_BLOCK_SIZE: - *(DWORD *)buff = fatfs_mtd_devs[pdrv]->pages_per_sector; + *(DWORD *)buff = fatfs_mtd_devs[pdrv]->min_erase_size / fatfs_mtd_devs[pdrv]->page_size; return RES_OK; #endif From cdee757103a35c2a0ea4468456de28f502be3b77 Mon Sep 17 00:00:00 2001 From: Vincent Dupont Date: Tue, 23 Jan 2018 17:24:57 +0100 Subject: [PATCH 10/10] mtd_sdcard: update implementation --- drivers/mtd_sdcard/mtd_sdcard.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd_sdcard/mtd_sdcard.c b/drivers/mtd_sdcard/mtd_sdcard.c index 80423e9124a7..2f5e0ca74236 100644 --- a/drivers/mtd_sdcard/mtd_sdcard.c +++ b/drivers/mtd_sdcard/mtd_sdcard.c @@ -52,11 +52,12 @@ static int mtd_sdcard_init(mtd_dev_t *dev) (sdcard_spi_init(mtd_sd->sd_card, mtd_sd->params) == 0)) { /* erasing whole sectors is handled internally by the card so you can delete single blocks (i.e. pages) */ - dev->pages_per_sector = 1; dev->sector_count = sdcard_spi_get_sector_count(mtd_sd->sd_card); /* sdcard_spi always uses the fixed block size of SD-HC cards */ dev->page_size = SD_HC_BLOCK_SIZE; + dev->min_erase_size = SD_HC_BLOCK_SIZE; + dev->sector_size = SD_HC_BLOCK_SIZE; return 0; } return -EIO;