From a5f7ceff812e73a17b2720586abf367c0ee97f5c Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Thu, 7 Mar 2024 22:43:44 +0000 Subject: [PATCH] storage/flash_map: Add flash_area_flatten Add equivalent of flash_erase, from Flash API, to Flash Map API; idea is the same: function tries to erase area if driver provides erase function, otherwise writes erase_value across the defined area. Signed-off-by: Dominik Ermel --- include/zephyr/storage/flash_map.h | 23 +++++++++ subsys/storage/flash_map/flash_map.c | 9 ++++ tests/subsys/storage/flash_map/src/main.c | 61 +++++++++++++++++++++++ 3 files changed, 93 insertions(+) diff --git a/include/zephyr/storage/flash_map.h b/include/zephyr/storage/flash_map.h index b03628afc93..937e242830a 100644 --- a/include/zephyr/storage/flash_map.h +++ b/include/zephyr/storage/flash_map.h @@ -187,6 +187,29 @@ int flash_area_write(const struct flash_area *fa, off_t off, const void *src, */ int flash_area_erase(const struct flash_area *fa, off_t off, size_t len); +/** + * @brief Erase flash area or fill with erase-value + * + * On program-erase devices this function behaves exactly like flash_area_erase. + * On RAM non-volatile device it will call erase, if driver provides such + * callback, or will fill given range with erase-value defined by driver. + * This function should be only used by code that has not been written + * to directly support devices that do not require erase and rely on + * device being erased prior to some operations. + * Note that emulated erase, on devices that do not require, is done + * via write, which affects endurance of device. + * + * @see flash_area_erase() + * @see flash_flatten() + * + * @param[in] fa Flash area + * @param[in] off Offset relative from beginning of flash area. + * @param[in] len Number of bytes to be erase + * + * @return 0 on success, negative errno code on fail. + */ +int flash_area_flatten(const struct flash_area *fa, off_t off, size_t len); + /** * @brief Get write block size of the flash area * diff --git a/subsys/storage/flash_map/flash_map.c b/subsys/storage/flash_map/flash_map.c index 79be7cae6d6..471b33358c9 100644 --- a/subsys/storage/flash_map/flash_map.c +++ b/subsys/storage/flash_map/flash_map.c @@ -82,6 +82,15 @@ int flash_area_erase(const struct flash_area *fa, off_t off, size_t len) return flash_erase(fa->fa_dev, fa->fa_off + off, len); } +int flash_area_flatten(const struct flash_area *fa, off_t off, size_t len) +{ + if (!is_in_flash_area_bounds(fa, off, len)) { + return -EINVAL; + } + + return flash_flatten(fa->fa_dev, fa->fa_off + off, len); +} + uint32_t flash_area_align(const struct flash_area *fa) { return flash_get_write_block_size(fa->fa_dev); diff --git a/tests/subsys/storage/flash_map/src/main.c b/tests/subsys/storage/flash_map/src/main.c index e66f6ac7e0f..18fea4b2421 100644 --- a/tests/subsys/storage/flash_map/src/main.c +++ b/tests/subsys/storage/flash_map/src/main.c @@ -202,4 +202,65 @@ ZTEST(flash_map, test_fixed_partition_node_macros) DEVICE_DT_GET(DT_MTD_FROM_FIXED_PARTITION(SLOT1_PARTITION_NODE))); } +ZTEST(flash_map, test_flash_area_erase_and_flatten) +{ + int i; + bool erased = true; + int rc; + const struct flash_area *fa; + const struct device *flash_dev; + + rc = flash_area_open(SLOT1_PARTITION_ID, &fa); + zassert_true(rc == 0, "flash_area_open() fail"); + + /* First erase the area so it's ready for use. */ + flash_dev = flash_area_get_device(fa); + + rc = flash_erase(flash_dev, fa->fa_off, fa->fa_size); + zassert_true(rc == 0, "flash area erase fail"); + + rc = flash_fill(flash_dev, 0xaa, fa->fa_off, fa->fa_size); + zassert_true(rc == 0, "flash device fill fail"); + + rc = flash_area_erase(fa, 0, fa->fa_size); + zassert_true(rc == 0, "flash area erase fail"); + + /* we work under assumption that flash_fill is working and tested */ + for (i = 0; erased && i < fa->fa_size; ++i) { + uint8_t buf[32]; + int chunk = MIN(sizeof(buf), fa->fa_size - i); + + rc = flash_read(flash_dev, i, buf, chunk); + zassert_equal(rc, 0, "Unexpected read fail"); + for (int ii = 0; ii < chunk; ++ii, ++i) { + if (buf[ii] != flash_area_erased_val(fa)) { + erased = false; + break; + } + } + } + zassert_true(erased, "Erase failed at index %d", i); + + rc = flash_fill(flash_dev, 0xaa, fa->fa_off, fa->fa_size); + zassert_true(rc == 0, "flash device fill fail"); + + rc = flash_area_flatten(fa, 0, fa->fa_size); + + erased = true; + for (i = 0; erased && i < fa->fa_size; ++i) { + uint8_t buf[32]; + int chunk = MIN(sizeof(buf), fa->fa_size - i); + + rc = flash_read(flash_dev, i, buf, chunk); + zassert_equal(rc, 0, "Unexpected read fail"); + for (int ii = 0; ii < chunk; ++ii, ++i) { + if (buf[ii] != flash_area_erased_val(fa)) { + erased = false; + break; + } + } + } + zassert_true(erased, "Flatten/Erase failed at index %d", i); +} + ZTEST_SUITE(flash_map, NULL, NULL, NULL, NULL, NULL);