From 9ab723146eb8abc278197052957b664cd3d68c4b Mon Sep 17 00:00:00 2001 From: "Mike J. Chen" Date: Tue, 5 Nov 2024 17:20:49 -0800 Subject: [PATCH] nvs: support sector_size of 64KB Allows NVS to work with flash device configured to use only 64KB block erase. Due to how addresses are encoded internally in NVS, 64KB is the maximum sector size. Add a test for this during mount. Add a native_sim unit test case for 64kb erase block size Signed-off-by: Mike J. Chen --- include/zephyr/fs/nvs.h | 2 +- subsys/fs/nvs/nvs.c | 7 ++++ subsys/fs/nvs/nvs_priv.h | 2 + .../native_sim_64kb_erase_block.overlay | 41 +++++++++++++++++++ tests/subsys/fs/nvs/src/main.c | 37 +++++++++++++---- tests/subsys/fs/nvs/testcase.yaml | 3 ++ 6 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 tests/subsys/fs/nvs/boards/native_sim_64kb_erase_block.overlay diff --git a/include/zephyr/fs/nvs.h b/include/zephyr/fs/nvs.h index df70b64f58bc..f654933166f9 100644 --- a/include/zephyr/fs/nvs.h +++ b/include/zephyr/fs/nvs.h @@ -48,7 +48,7 @@ struct nvs_fs { /** Data write address */ uint32_t data_wra; /** File system is split into sectors, each sector must be multiple of erase-block-size */ - uint16_t sector_size; + uint32_t sector_size; /** Number of sectors in the file system */ uint16_t sector_count; /** Flag indicating if the file system is initialized */ diff --git a/subsys/fs/nvs/nvs.c b/subsys/fs/nvs/nvs.c index 2e553fdbf554..8a710d570fb1 100644 --- a/subsys/fs/nvs/nvs.c +++ b/subsys/fs/nvs/nvs.c @@ -1025,6 +1025,13 @@ int nvs_mount(struct nvs_fs *fs) return -EINVAL; } + /* check that sector size is not greater than max */ + if (fs->sector_size > NVS_MAX_SECTOR_SIZE) { + LOG_ERR("Sector size %u too large, maximum is %zu", + fs->sector_size, NVS_MAX_SECTOR_SIZE); + return -EINVAL; + } + /* check that sector size is a multiple of pagesize */ rc = flash_get_page_info_by_offs(fs->flash_device, fs->offset, &info); if (rc) { diff --git a/subsys/fs/nvs/nvs_priv.h b/subsys/fs/nvs/nvs_priv.h index 53f109ee1320..0c302d132f6c 100644 --- a/subsys/fs/nvs/nvs_priv.h +++ b/subsys/fs/nvs/nvs_priv.h @@ -21,6 +21,8 @@ extern "C" { #define ADDR_SECT_SHIFT 16 #define ADDR_OFFS_MASK 0x0000FFFF +#define NVS_MAX_SECTOR_SIZE KB(64) + /* * Status return values */ diff --git a/tests/subsys/fs/nvs/boards/native_sim_64kb_erase_block.overlay b/tests/subsys/fs/nvs/boards/native_sim_64kb_erase_block.overlay new file mode 100644 index 000000000000..2079b50ceab2 --- /dev/null +++ b/tests/subsys/fs/nvs/boards/native_sim_64kb_erase_block.overlay @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025 Google LLC + * + * SPDX-License-Identifier: Apache-2.0 + */ + +&flash0 { + erase-block-size = <0x10000>; + + /* + * Delete old partitions that were not aligned on 64kb addresses and + * create new ones that are aligned. + */ + /delete-node/ partitions; + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x00010000>; + }; + slot0_partition: partition@10000 { + label = "image-0"; + reg = <0x00010000 0x00070000>; + }; + slot1_partition: partition@80000 { + label = "image-1"; + reg = <0x00080000 0x00070000>; + }; + scratch_partition: partition@f0000 { + label = "image-scratch"; + reg = <0x000f0000 0x00020000>; + }; + storage_partition: partition@110000 { + label = "storage"; + reg = <0x00110000 0x00050000>; + }; + }; +}; diff --git a/tests/subsys/fs/nvs/src/main.c b/tests/subsys/fs/nvs/src/main.c index 1747a7ba4aaf..d900c5aa99bf 100644 --- a/tests/subsys/fs/nvs/src/main.c +++ b/tests/subsys/fs/nvs/src/main.c @@ -96,7 +96,14 @@ ZTEST_SUITE(nvs, NULL, setup, before, after, NULL); ZTEST_F(nvs, test_nvs_mount) { int err; + size_t orig_sector_size = fixture->fs.sector_size; + fixture->fs.sector_size = KB(128); + err = nvs_mount(&fixture->fs); + zassert_true(err == -EINVAL, + "nvs_mount did not return expected err for invalid sector_size"); + + fixture->fs.sector_size = orig_sector_size; err = nvs_mount(&fixture->fs); zassert_true(err == 0, "nvs_mount call failure: %d", err); } @@ -307,7 +314,7 @@ static void write_content(uint16_t max_id, uint16_t begin, uint16_t end, for (uint16_t i = begin; i < end; i++) { uint8_t id = (i % max_id); - uint8_t id_data = id + max_id * (i / max_id); + uint8_t id_data = id + max_id * ((i % 256) / max_id); memset(buf, id_data, sizeof(buf)); @@ -346,13 +353,25 @@ ZTEST_F(nvs, test_nvs_gc_3sectors) const uint16_t max_id = 10; /* 50th write will trigger 1st GC. */ - const uint16_t max_writes = 51; + uint16_t max_writes = 51; /* 75th write will trigger 2st GC. */ - const uint16_t max_writes_2 = 51 + 25; + uint16_t max_writes_2 = 51 + 25; /* 100th write will trigger 3st GC. */ - const uint16_t max_writes_3 = 51 + 25 + 25; + uint16_t max_writes_3 = 51 + 25 + 25; /* 125th write will trigger 4st GC. */ - const uint16_t max_writes_4 = 51 + 25 + 25 + 25; + uint16_t max_writes_4 = 51 + 25 + 25 + 25; + + if (fixture->fs.sector_size == KB(64)) { + /* write 1637 will trigger 1st GC. */ + /* write 3274 will trigger 2nd GC. */ + max_writes = 3275; + /* write 4911 will trigger 3rd GC. */ + max_writes_2 = 3275 + 1637; + /* write 6548 will trigger 4th GC. */ + max_writes_3 = 3275 + 1637 + 1637; + /* write 8185 will trigger 5th GC. */ + max_writes_4 = 3275 + 1637 + 1637 + 1637; + } fixture->fs.sector_count = 3; @@ -361,7 +380,7 @@ ZTEST_F(nvs, test_nvs_gc_3sectors) zassert_equal(fixture->fs.ate_wra >> ADDR_SECT_SHIFT, 0, "unexpected write sector"); - /* Trigger 1st GC */ + /* Trigger 1st and 2nd GC */ write_content(max_id, 0, max_writes, &fixture->fs); /* sector sequence: empty,closed, write */ @@ -376,7 +395,7 @@ ZTEST_F(nvs, test_nvs_gc_3sectors) "unexpected write sector"); check_content(max_id, &fixture->fs); - /* Trigger 2nd GC */ + /* Trigger 3rd GC */ write_content(max_id, max_writes, max_writes_2, &fixture->fs); /* sector sequence: write, empty, closed */ @@ -391,7 +410,7 @@ ZTEST_F(nvs, test_nvs_gc_3sectors) "unexpected write sector"); check_content(max_id, &fixture->fs); - /* Trigger 3rd GC */ + /* Trigger 4th GC */ write_content(max_id, max_writes_2, max_writes_3, &fixture->fs); /* sector sequence: closed, write, empty */ @@ -406,7 +425,7 @@ ZTEST_F(nvs, test_nvs_gc_3sectors) "unexpected write sector"); check_content(max_id, &fixture->fs); - /* Trigger 4th GC */ + /* Trigger 5th GC */ write_content(max_id, max_writes_3, max_writes_4, &fixture->fs); /* sector sequence: empty,closed, write */ diff --git a/tests/subsys/fs/nvs/testcase.yaml b/tests/subsys/fs/nvs/testcase.yaml index c796cda1307b..34b28ab30e62 100644 --- a/tests/subsys/fs/nvs/testcase.yaml +++ b/tests/subsys/fs/nvs/testcase.yaml @@ -28,3 +28,6 @@ tests: - CONFIG_NVS_LOOKUP_CACHE=y - CONFIG_NVS_LOOKUP_CACHE_SIZE=64 platform_allow: native_sim + filesystem.nvs.64kb_erase_block: + extra_args: DTC_OVERLAY_FILE=boards/native_sim_64kb_erase_block.overlay + platform_allow: native_sim