Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[nrf fromtree] tests: drivers: flash: common: Increase test coverage #1881

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions tests/drivers/flash/common/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,125 @@ ZTEST(flash_driver, test_read_unaligned_address)
}
}

ZTEST(flash_driver, test_flash_erase)
{
int rc;
uint8_t read_buf[EXPECTED_SIZE];
bool comparison_result;
const struct flash_parameters *fparams = flash_get_parameters(flash_dev);

erase_value = fparams->erase_value;

/* Write test data */
rc = flash_write(flash_dev, page_info.start_offset, expected, EXPECTED_SIZE);
zassert_equal(rc, 0, "Cannot write to flash");

/* Confirm write operation */
rc = flash_read(flash_dev, page_info.start_offset, read_buf, EXPECTED_SIZE);
zassert_equal(rc, 0, "Cannot read flash");

comparison_result = true;
for (int i = 0; i < EXPECTED_SIZE; i++) {
if (read_buf[i] != expected[i]) {
comparison_result = false;
TC_PRINT("i=%d:\tread_buf[i]=%d\texpected[i]=%d\n", i, read_buf[i],
expected[i]);
}
}
zassert_true(comparison_result, "Write operation failed");
/* Cross check - confirm that expected data is pseudo-random */
zassert_not_equal(read_buf[0], expected[1], "These values shall be different");

/* Erase a nb of pages aligned to the EXPECTED_SIZE */
rc = flash_erase(
flash_dev, page_info.start_offset,
(page_info.size * ((EXPECTED_SIZE + page_info.size - 1) / page_info.size)));
zassert_equal(rc, 0, "Flash memory not properly erased");

/* Confirm erase operation */
rc = flash_read(flash_dev, page_info.start_offset, read_buf, EXPECTED_SIZE);
zassert_equal(rc, 0, "Cannot read flash");

comparison_result = true;
for (int i = 0; i < EXPECTED_SIZE; i++) {
if (read_buf[i] != erase_value) {
comparison_result = false;
TC_PRINT("i=%d:\tread_buf[i]=%d\texpected=%d\n", i, read_buf[i],
erase_value);
}
}
zassert_true(comparison_result, "Write operation failed");
/* Cross check - confirm that expected data
* doesn't contain erase_value
*/
zassert_not_equal(expected[0], erase_value, "These values shall be different");
}

struct test_cb_data_type {
uint32_t page_counter; /* used to count how many pages was iterated */
uint32_t exit_page; /* terminate iteration when this page is reached */
};

static bool flash_callback(const struct flash_pages_info *info, void *data)
{
struct test_cb_data_type *cb_data = (struct test_cb_data_type *)data;

cb_data->page_counter++;

if (cb_data->page_counter >= cb_data->exit_page) {
return false;
}

return true;
}

ZTEST(flash_driver, test_flash_page_layout)
{
int rc;
struct flash_pages_info page_info_off = {0};
struct flash_pages_info page_info_idx = {0};
size_t page_count;
struct test_cb_data_type test_cb_data = {0};

#if !defined(CONFIG_FLASH_PAGE_LAYOUT)
ztest_test_skip();
#endif

/* Get page info with flash_get_page_info_by_offs() */
rc = flash_get_page_info_by_offs(flash_dev, TEST_AREA_OFFSET, &page_info_off);
zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc);
TC_PRINT("start_offset=0x%lx\tsize=%d\tindex=%d\n", page_info_off.start_offset,
(int)page_info_off.size, page_info_off.index);
zassert_true(page_info_off.start_offset >= 0, "start_offset is %d", rc);
zassert_true(page_info_off.size > 0, "size is %d", rc);
zassert_true(page_info_off.index >= 0, "index is %d", rc);

/* Get info for the same page with flash_get_page_info_by_idx() */
rc = flash_get_page_info_by_idx(flash_dev, page_info_off.index, &page_info_idx);
zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc);
zassert_equal(page_info_off.start_offset, page_info_idx.start_offset);
zassert_equal(page_info_off.size, page_info_idx.size);
zassert_equal(page_info_off.index, page_info_idx.index);

page_count = flash_get_page_count(flash_dev);
TC_PRINT("page_count=%d\n", (int)page_count);
zassert_true(page_count > 0, "flash_get_page_count returned %d", rc);
zassert_true(page_count >= page_info_off.index);

/* Test that callback is executed for every page */
test_cb_data.exit_page = page_count + 1;
flash_page_foreach(flash_dev, flash_callback, &test_cb_data);
zassert_true(page_count == test_cb_data.page_counter,
"page_count = %d not equal to pages counted with cb = %d", page_count,
test_cb_data.page_counter);

/* Test that callback can cancell iteration */
test_cb_data.page_counter = 0;
test_cb_data.exit_page = page_count >> 1;
flash_page_foreach(flash_dev, flash_callback, &test_cb_data);
zassert_true(test_cb_data.exit_page == test_cb_data.page_counter,
"%d pages were iterated while it shall stop on page %d",
test_cb_data.page_counter, test_cb_data.exit_page);
}

ZTEST_SUITE(flash_driver, NULL, flash_driver_setup, NULL, NULL, NULL);
3 changes: 2 additions & 1 deletion tests/drivers/flash/common/testcase.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ tests:
- nrf52840dk/nrf52840
drivers.flash.common.default:
filter: ((CONFIG_FLASH_HAS_DRIVER_ENABLED and not CONFIG_TRUSTED_EXECUTION_NONSECURE)
and dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions"))
and (dt_label_with_parent_compat_enabled("storage_partition", "fixed-partitions")
or dt_label_with_parent_compat_enabled("storage_partition", "nordic,owned-partitions")))
integration_platforms:
- qemu_x86
- mimxrt1060_evk
Expand Down
8 changes: 8 additions & 0 deletions tests/drivers/flash/negative_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SPDX-License-Identifier: Apache-2.0

cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(flash_negative_tests)

FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
5 changes: 5 additions & 0 deletions tests/drivers/flash/negative_tests/prj.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CONFIG_TEST=y
CONFIG_ZTEST=y
CONFIG_FLASH=y
CONFIG_FLASH_PAGE_LAYOUT=y
CONFIG_MAIN_STACK_SIZE=2048
242 changes: 242 additions & 0 deletions tests/drivers/flash/negative_tests/src/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
/*
* Copyright (c) 2020-2024 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <zephyr/kernel.h>
#include <zephyr/ztest.h>
#include <zephyr/drivers/flash.h>
#include <zephyr/devicetree.h>
#include <zephyr/storage/flash_map.h>

#if defined(CONFIG_NORDIC_QSPI_NOR)
#define TEST_AREA_DEV_NODE DT_INST(0, nordic_qspi_nor)
#elif defined(CONFIG_SPI_NOR)
#define TEST_AREA_DEV_NODE DT_INST(0, jedec_spi_nor)
#else
#define TEST_AREA storage_partition
#endif

/* TEST_AREA is only defined for configurations that rely on
* fixed-partition nodes.
*/
#if defined(TEST_AREA)
#define TEST_AREA_OFFSET FIXED_PARTITION_OFFSET(TEST_AREA)
#define TEST_AREA_SIZE FIXED_PARTITION_SIZE(TEST_AREA)
#define TEST_AREA_DEVICE FIXED_PARTITION_DEVICE(TEST_AREA)

#if defined(CONFIG_SOC_NRF54L15)
#define TEST_FLASH_START (DT_REG_ADDR(DT_MEM_FROM_FIXED_PARTITION(DT_NODELABEL(TEST_AREA))))
#define TEST_FLASH_SIZE (DT_REG_SIZE(DT_MEM_FROM_FIXED_PARTITION(DT_NODELABEL(TEST_AREA))))
#elif defined(CONFIG_SOC_NRF54H20)
#define TEST_FLASH_START (DT_REG_ADDR(DT_PARENT(DT_PARENT(DT_NODELABEL(TEST_AREA)))))
#define TEST_FLASH_SIZE (DT_REG_SIZE(DT_PARENT(DT_PARENT(DT_NODELABEL(TEST_AREA)))))
#else
#error "Missing definition of TEST_FLASH_START and TEST_FLASH_SIZE for this target"
#endif

#else
#error "Unsupported configuraiton"
#endif

#define EXPECTED_SIZE 512

#if !defined(CONFIG_FLASH_HAS_EXPLICIT_ERASE) && !defined(CONFIG_FLASH_HAS_NO_EXPLICIT_ERASE)
#error There is no flash device enabled or it is missing Kconfig options
#endif

static const struct device *const flash_dev = TEST_AREA_DEVICE;
static struct flash_pages_info page_info;
static uint8_t __aligned(4) expected[EXPECTED_SIZE];

static void *flash_driver_setup(void)
{
int rc;

zassert_true(device_is_ready(flash_dev));

TC_PRINT("Test will run on device %s\n", flash_dev->name);
TC_PRINT("TEST_AREA_OFFSET = 0x%lx\n", (unsigned long)TEST_AREA_OFFSET);
TC_PRINT("TEST_AREA_SIZE = 0x%lx\n", (unsigned long)TEST_AREA_SIZE);
TC_PRINT("TEST_FLASH_START = 0x%lx\n", (unsigned long)TEST_FLASH_START);
TC_PRINT("TEST_FLASH_SIZE = 0x%lx\n", (unsigned long)TEST_FLASH_SIZE);

rc = flash_get_page_info_by_offs(flash_dev, TEST_AREA_OFFSET, &page_info);
zassert_true(rc == 0, "flash_get_page_info_by_offs returned %d", rc);
TC_PRINT("Test Page Info:\n");
TC_PRINT("start_offset = 0x%lx\n", (unsigned long)page_info.start_offset);
TC_PRINT("size = 0x%lx\n", (unsigned long)page_info.size);
TC_PRINT("index = %d\n", page_info.index);
TC_PRINT("===================================================================\n");

return NULL;
}

ZTEST(flash_driver_negative, test_negative_flash_erase)
{
int rc;

#if !defined(TEST_AREA)
/* Flash memory boundaries are correctly calculated
* only for storage_partition.
*/
ztest_test_skip();
#endif

/* Acceptable values of erase size and offset are subject to
* hardware-specific multiples of page size and offset.
*/

/* Check error returned when erasing memory at wrong address (too low) */
rc = flash_erase(flash_dev, (TEST_FLASH_START - page_info.size), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_erase returned %d", rc);

/* Check error returned when erasing memory at wrong address (too high) */
rc = flash_erase(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_erase returned %d", rc);

/* Check error returned when erasing unaligned memory or too large chunk of memory */
rc = flash_erase(flash_dev, (TEST_AREA_OFFSET + 1), (TEST_FLASH_SIZE + 1));
zassert_true(rc < 0, "Invalid use of flash_erase returned %d", rc);

/* Erasing 0 bytes shall succeed */
rc = flash_erase(flash_dev, TEST_AREA_OFFSET, 0);
zassert_true(rc == 0, "flash_erase 0 bytes returned %d", rc);
}

ZTEST(flash_driver_negative, test_negative_flash_fill)
{
int rc;
uint8_t fill_val = 0xA; /* Dummy value */

#if !defined(TEST_AREA)
/* Flash memory boundaries are correctly calculated
* only for storage_partition.
*/
ztest_test_skip();
#endif

/* Erase page offset and size are constrains of paged, explicit erase devices,
* but can be relaxed with devices without such requirement.
*/

/* Check error returned when filling memory at wrong address (too low) */
rc = flash_fill(flash_dev, fill_val, (TEST_FLASH_START - page_info.size), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc);

/* Check error returned when filling memory at wrong address (too high) */
rc = flash_fill(flash_dev, fill_val, (TEST_FLASH_START + TEST_FLASH_SIZE), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc);

/* Check error returned when filling unaligned memory */
rc = flash_fill(flash_dev, fill_val, (TEST_AREA_OFFSET + 1), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc);
rc = flash_fill(flash_dev, fill_val, TEST_AREA_OFFSET, (page_info.size + 1));
zassert_true(rc < 0, "Invalid use of flash_fill returned %d", rc);

/* Filling 0 bytes shall succeed */
rc = flash_fill(flash_dev, fill_val, TEST_AREA_OFFSET, 0);
zassert_true(rc == 0, "flash_fill 0 bytes returned %d", rc);
}

ZTEST(flash_driver_negative, test_negative_flash_flatten)
{
int rc;

#if !defined(TEST_AREA)
/* Flash memory boundaries are correctly calculated
* only for storage_partition.
*/
ztest_test_skip();
#endif

/* Erase page offset and size are constrains of paged, explicit erase devices,
* but can be relaxed with devices without such requirement.
*/

/* Check error returned when flatten memory at wrong address (too low) */
rc = flash_flatten(flash_dev, (TEST_FLASH_START - page_info.size), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc);

/* Check error returned when flatten memory at wrong address (too high) */
rc = flash_flatten(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc);

/* Check error returned when flatten unaligned memory */
rc = flash_flatten(flash_dev, (TEST_AREA_OFFSET + 1), page_info.size);
zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc);
rc = flash_flatten(flash_dev, TEST_AREA_OFFSET, (page_info.size + 1));
zassert_true(rc < 0, "Invalid use of flash_flatten returned %d", rc);

/* Flatten 0 bytes shall succeed */
rc = flash_flatten(flash_dev, TEST_AREA_OFFSET, 0);
zassert_true(rc == 0, "flash_flatten 0 bytes returned %d", rc);
}

ZTEST(flash_driver_negative, test_negative_flash_read)
{
int rc;
uint8_t read_buf[EXPECTED_SIZE];

#if !defined(TEST_AREA)
/* Flash memory boundaries are correctly calculated
* only for storage_partition.
*/
ztest_test_skip();
#endif

/* All flash drivers support reads without alignment restrictions on
* the read offset, the read size, or the destination address.
*/

/* Check error returned when reading from a wrong address (too low) */
rc = flash_read(flash_dev, (TEST_FLASH_START - page_info.size), read_buf, EXPECTED_SIZE);
zassert_true(rc < 0, "Invalid use of flash_read returned %d", rc);

/* Check error returned when reading from a wrong address (too high) */
rc = flash_read(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), read_buf, EXPECTED_SIZE);
zassert_true(rc < 0, "Invalid use of flash_read returned %d", rc);

/* Check error returned when reading too many data */
rc = flash_read(flash_dev, TEST_AREA_OFFSET, read_buf, (TEST_FLASH_SIZE + page_info.size));
zassert_true(rc < 0, "Invalid use of flash_read returned %d", rc);

/* Reading 0 bytes shall succeed */
rc = flash_read(flash_dev, TEST_AREA_OFFSET, read_buf, 0);
zassert_true(rc == 0, "flash_read 0 bytes returned %d", rc);
}

ZTEST(flash_driver_negative, test_negative_flash_write)
{
int rc;

#if !defined(TEST_AREA)
/* Flash memory boundaries are correctly calculated
* only for storage_partition.
*/
ztest_test_skip();
#endif

/* Write size and offset must be multiples of the minimum write block size
* supported by the driver.
*/

/* Check error returned when writing to a wrong address (too low) */
rc = flash_write(flash_dev, (TEST_FLASH_START - page_info.size), expected, page_info.size);
zassert_true(rc < 0, "Invalid use of flash_write returned %d", rc);

/* Check error returned when writing to a wrong address (too high) */
rc = flash_write(flash_dev, (TEST_FLASH_START + TEST_FLASH_SIZE), expected, page_info.size);
zassert_true(rc < 0, "Invalid use of flash_write returned %d", rc);

/* Check error returned when writing at unaligned memory or too large chunk of memory */
rc = flash_write(flash_dev, (TEST_AREA_OFFSET + 1), expected, (TEST_FLASH_SIZE + 1));
zassert_true(rc < 0, "Invalid use of flash_write returned %d", rc);

/* Writing 0 bytes shall succeed */
rc = flash_write(flash_dev, TEST_AREA_OFFSET, expected, 0);
zassert_true(rc == 0, "flash_write 0 bytes returned %d", rc);
}

ZTEST_SUITE(flash_driver_negative, NULL, flash_driver_setup, NULL, NULL, NULL);
Loading
Loading