Skip to content

Commit

Permalink
Merge branch 'bugfix/fix_spi_flash_api_concurrency_issue_v5.1' into '…
Browse files Browse the repository at this point in the history
…release/v5.1'

spi_flash: fix concurrency issue when concurrently calling esp_flash apis (v5.1)

See merge request espressif/esp-idf!24508
  • Loading branch information
suda-morris committed Jul 10, 2023
2 parents c558904 + a7f00f5 commit 0930b5c
Show file tree
Hide file tree
Showing 20 changed files with 434 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "esp_heap_caps.h"

// load partition table in tests will use memory
#define TEST_MEMORY_LEAK_THRESHOLD (450)
#define TEST_MEMORY_LEAK_THRESHOLD (600)

void setUp(void)
{
Expand Down
4 changes: 2 additions & 2 deletions components/esp_hw_support/test_apps/mspi/main/test_mspi.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,6 @@ TEST_CASE("MSPI: Test mspi timing turning time cost", "[mspi]")
printf("mspi psram speed up cost %ld\n", cost);
}

TEST_ASSERT_LESS_THAN_UINT32(TEST_TIME_LIMIT_US, slow_down_time[TEST_TIME_CNT / 2]);
TEST_ASSERT_LESS_THAN_UINT32(TEST_TIME_LIMIT_US, speed_up_time[TEST_TIME_CNT / 2]);
TEST_ASSERT_LESS_OR_EQUAL_UINT32(TEST_TIME_LIMIT_US, slow_down_time[TEST_TIME_CNT / 2]);
TEST_ASSERT_LESS_OR_EQUAL_UINT32(TEST_TIME_LIMIT_US, speed_up_time[TEST_TIME_CNT / 2]);
}
47 changes: 33 additions & 14 deletions components/spi_flash/spi_flash_os_func_app.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
Expand All @@ -22,9 +22,13 @@

#include "esp_private/spi_common_internal.h"

#define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA))
#define SPI_FLASH_CACHE_NO_DISABLE (CONFIG_SPI_FLASH_AUTO_SUSPEND || (CONFIG_SPIRAM_FETCH_INSTRUCTIONS && CONFIG_SPIRAM_RODATA) || CONFIG_APP_BUILD_TYPE_RAM)
static const char TAG[] = "spi_flash";

#if SPI_FLASH_CACHE_NO_DISABLE
static _lock_t s_spi1_flash_mutex;
#endif // #if SPI_FLASH_CACHE_NO_DISABLE

/*
* OS functions providing delay service and arbitration among chips, and with the cache.
*
Expand Down Expand Up @@ -55,21 +59,19 @@ static inline void on_spi_acquired(app_func_arg_t* ctx);
static inline void on_spi_yielded(app_func_arg_t* ctx);
static inline bool on_spi_check_yield(app_func_arg_t* ctx);

#if !SPI_FLASH_CACHE_NO_DISABLE
IRAM_ATTR static void cache_enable(void* arg)
{
#if !SPI_FLASH_CACHE_NO_DISABLE
spi_flash_enable_interrupts_caches_and_other_cpu();
#endif
}

IRAM_ATTR static void cache_disable(void* arg)
{
#if !SPI_FLASH_CACHE_NO_DISABLE
spi_flash_disable_interrupts_caches_and_other_cpu();
#endif
}
#endif //#if !SPI_FLASH_CACHE_NO_DISABLE

static IRAM_ATTR esp_err_t spi_start(void *arg)
static IRAM_ATTR esp_err_t acquire_spi_bus_lock(void *arg)
{
spi_bus_lock_dev_handle_t dev_lock = ((app_func_arg_t *)arg)->dev_lock;

Expand All @@ -82,41 +84,58 @@ static IRAM_ATTR esp_err_t spi_start(void *arg)
return ESP_OK;
}

static IRAM_ATTR esp_err_t spi_end(void *arg)
static IRAM_ATTR esp_err_t release_spi_bus_lock(void *arg)
{
return spi_bus_lock_acquire_end(((app_func_arg_t *)arg)->dev_lock);
}

static IRAM_ATTR esp_err_t spi23_start(void *arg){
esp_err_t ret = spi_start(arg);
esp_err_t ret = acquire_spi_bus_lock(arg);
on_spi_acquired((app_func_arg_t*)arg);
return ret;
}

static IRAM_ATTR esp_err_t spi23_end(void *arg){
esp_err_t ret = spi_end(arg);
esp_err_t ret = release_spi_bus_lock(arg);
on_spi_released((app_func_arg_t*)arg);
return ret;
}

static IRAM_ATTR esp_err_t spi1_start(void *arg)
{
esp_err_t ret = ESP_OK;
/**
* There are three ways for ESP Flash API lock:
* 1. spi bus lock, this is used when SPI1 is shared with GPSPI Master Driver
* 2. mutex, this is used when the Cache isn't need to be disabled.
* 3. cache lock (from cache_utils.h), this is used when we need to disable Cache to avoid access from SPI0
*
* From 1 to 3, the lock efficiency decreases.
*/
#if CONFIG_SPI_FLASH_SHARE_SPI1_BUS
//use the lock to disable the cache and interrupts before using the SPI bus
return spi_start(arg);
ret = acquire_spi_bus_lock(arg);
#elif SPI_FLASH_CACHE_NO_DISABLE
_lock_acquire(&s_spi1_flash_mutex);
#else
//directly disable the cache and interrupts when lock is not used
cache_disable(NULL);
on_spi_acquired((app_func_arg_t*)arg);
return ESP_OK;
#endif
on_spi_acquired((app_func_arg_t*)arg);
return ret;
}

static IRAM_ATTR esp_err_t spi1_end(void *arg)
{
esp_err_t ret = ESP_OK;

/**
* There are three ways for ESP Flash API lock, see `spi1_start`
*/
#if CONFIG_SPI_FLASH_SHARE_SPI1_BUS
ret = spi_end(arg);
ret = release_spi_bus_lock(arg);
#elif SPI_FLASH_CACHE_NO_DISABLE
_lock_release(&s_spi1_flash_mutex);
#else
cache_enable(NULL);
#endif
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
set(srcs "test_flash_utils.c")

idf_component_register(SRCS ${srcs}
INCLUDE_DIRS include
REQUIRES esp_partition)
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#pragma once

#include <esp_types.h>
#include "esp_partition.h"

#ifdef __cplusplus
extern "C" {
#endif


/**
* Return the 'flash_test' custom data partition
* defined in the custom partition table.
*
* @return partition handle
*/
const esp_partition_t *get_test_flash_partition(void);

#ifdef __cplusplus
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <string.h>
#include "test_flash_utils.h"

const esp_partition_t *get_test_flash_partition(void)
{
/* This finds "flash_test" partition defined in custom partitions.csv */
const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_ANY, "flash_test");
assert(result != NULL); /* means partition table set wrong */
return result;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include "esp_heap_caps.h"

// Some resources are lazy allocated in flash encryption, the threadhold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD (400)
#define TEST_MEMORY_LEAK_THRESHOLD (600)

void setUp(void)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# This is the project CMakeLists.txt file for the test subproject
cmake_minimum_required(VERSION 3.16)

set(EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/components/spi_flash/test_apps/components")

include($ENV{IDF_PATH}/tools/cmake/project.cmake)

project(test_esp_flash_stress)
2 changes: 2 additions & 0 deletions components/spi_flash/test_apps/esp_flash_stress/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
set(srcs "test_app_main.c"
"test_esp_flash_stress.c")

# In order for the cases defined by `TEST_CASE` to be linked into the final elf,
# the component can be registered as WHOLE_ARCHIVE
idf_component_register(SRCS ${srcs}
PRIV_REQUIRES test_flash_utils spi_flash unity
WHOLE_ARCHIVE)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

#include "unity.h"
#include "unity_test_utils.h"
#include "esp_heap_caps.h"

// load partition table in tests will use memory
#define TEST_MEMORY_LEAK_THRESHOLD (600)

void setUp(void)
{
unity_utils_record_free_mem();
}

void tearDown(void)
{
esp_reent_cleanup(); //clean up some of the newlib's lazy allocations
unity_utils_evaluate_leaks_direct(TEST_MEMORY_LEAK_THRESHOLD);
}

void app_main(void)
{
printf(" ______ _____ _____ ______ _ _ _____ _ \n");
printf("| ____|/ ____| __ \\ | ____| | | | / ____| | \n");
printf("| |__ | (___ | |__) | | |__ | | __ _ ___| |__ | (___ | |_ _ __ ___ ___ ___ \n");
printf("| __| \\___ \\| ___/ | __| | |/ _` / __| '_ \\ \\___ \\| __| '__/ _ \\/ __/ __|\n");
printf("| |____ ____) | | | | | | (_| \\__ \\ | | | ____) | |_| | | __/\\__ \\__ \\\n");
printf("|______|_____/|_| |_| |_|\\__,_|___/_| |_| |_____/ \\__|_| \\___||___/___/\n");

unity_run_menu();
}
Loading

0 comments on commit 0930b5c

Please sign in to comment.