diff --git a/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c b/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c index b49226f575..9e1f7b5a6c 100644 --- a/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c +++ b/components/esp_driver_i2s/test_apps/i2s/main/test_app_main.c @@ -8,8 +8,8 @@ #include "unity_test_runner.h" #include "esp_heap_caps.h" -// Some resources are lazy allocated in I2S driver, the threadhold is left for that case -#define TEST_MEMORY_LEAK_THRESHOLD (-300) +// Some resources are lazy allocated in I2S driver, the threshold is left for that case +#define TEST_MEMORY_LEAK_THRESHOLD (-350) static size_t before_free_8bit; static size_t before_free_32bit; diff --git a/components/esp_driver_sdm/src/sdm.c b/components/esp_driver_sdm/src/sdm.c index 0a233bf100..1a92e2a85d 100644 --- a/components/esp_driver_sdm/src/sdm.c +++ b/components/esp_driver_sdm/src/sdm.c @@ -162,11 +162,11 @@ static sdm_group_t *sdm_acquire_group_handle(int group_id, sdm_clock_source_t cl ESP_LOGD(TAG, "new group (%d) at %p", group_id, group); #if CONFIG_PM_ENABLE esp_pm_lock_type_t pm_type = ESP_PM_NO_LIGHT_SLEEP; -#if TIMER_LL_FUNC_CLOCK_SUPPORT_APB +#if SDM_LL_FUNC_CLOCK_SUPPORT_APB if (clk_src == SDM_CLK_SRC_APB) { pm_type = ESP_PM_APB_FREQ_MAX; } -#endif // TIMER_LL_FUNC_CLOCK_SUPPORT_APB +#endif // SDM_LL_FUNC_CLOCK_SUPPORT_APB if (esp_pm_lock_create(pm_type, 0, soc_sdm_signals[group_id].module_name, &group->pm_lock) != ESP_OK) { ESP_LOGE(TAG, "fail to create PM lock for group %d", group_id); } @@ -327,7 +327,7 @@ esp_err_t sdm_new_channel(const sdm_config_t *config, sdm_channel_handle_t *ret_ // preset the duty cycle to zero sdm_ll_set_pulse_density(group->hal.dev, chan_id, 0); - // initialize other members of timer + // initialize other members chan->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; atomic_init(&chan->fsm, SDM_FSM_INIT); // set the initial state to INIT diff --git a/components/esp_driver_spi/test_apps/slave/main/test_app_main.c b/components/esp_driver_spi/test_apps/slave/main/test_app_main.c index 85c249ef10..9011f78d4d 100644 --- a/components/esp_driver_spi/test_apps/slave/main/test_app_main.c +++ b/components/esp_driver_spi/test_apps/slave/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" #include "esp_newlib.h" -#define TEST_MEMORY_LEAK_THRESHOLD (200) +#define TEST_MEMORY_LEAK_THRESHOLD (300) void setUp(void) { diff --git a/components/esp_driver_spi/test_apps/slave_hd/main/test_app_main.c b/components/esp_driver_spi/test_apps/slave_hd/main/test_app_main.c index ed90c0c9b6..a1b70e2a24 100644 --- a/components/esp_driver_spi/test_apps/slave_hd/main/test_app_main.c +++ b/components/esp_driver_spi/test_apps/slave_hd/main/test_app_main.c @@ -9,7 +9,7 @@ #include "esp_heap_caps.h" #include "esp_newlib.h" -#define TEST_MEMORY_LEAK_THRESHOLD (200) +#define TEST_MEMORY_LEAK_THRESHOLD (300) void setUp(void) { diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index c8ac68e691..1c2a6a0dff 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -11,7 +11,7 @@ * +-----------------------------------+--+ +--+-----------------------------------+ * | GDMA-Group-X | | | | GDMA-Group-Y | * | +-------------+ +------------+ | | | | +-------------+ +------------+ | - * | | GDMA-Pair-0 |... |GDMA-Pair-N | | | | | | GDMA-Pair-0 |... |GDMA-Pair-N | | + * | | GDMA-Pair-0 |... |GDMA-Pair-N | | | | | | GDMA-Pair-0 |... |GDMA-Pair-M | | * | | | | | | | | | | | | | | * | | TX-Chan |... | TX-Chan | | | | | | TX-Chan |... | TX-Chan | | * | | RX-Chan | | RX-Chan | | | | | | RX-Chan | | RX-Chan | | @@ -29,25 +29,13 @@ #include "gdma_priv.h" #include "esp_memory_utils.h" #include "esp_flash_encrypt.h" -#include "esp_private/critical_section.h" - -#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP -#include "esp_private/gdma_sleep_retention.h" -#endif - -#if !SOC_RCC_IS_INDEPENDENT -// Reset and Clock Control registers are mixing with other peripherals, so we need to use a critical section -#define GDMA_RCC_ATOMIC() PERIPH_RCC_ATOMIC() -#else -#define GDMA_RCC_ATOMIC() -#endif #define GDMA_INVALID_PERIPH_TRIG (0x3F) #define SEARCH_REQUEST_RX_CHANNEL (1 << 0) #define SEARCH_REQUEST_TX_CHANNEL (1 << 1) typedef struct gdma_platform_t { - portMUX_TYPE spinlock; // platform level spinlock, protect the group handle slots and reference count of each group. + portMUX_TYPE spinlock; // platform level spinlock, protect the group handle slots and reference count of each group. gdma_group_t *groups[GDMA_LL_GET(INST_NUM)]; // array of GDMA group instances int group_ref_counts[GDMA_LL_GET(INST_NUM)]; // reference count used to protect group install/uninstall } gdma_platform_t; @@ -84,7 +72,23 @@ static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *sear int search_code = 0; gdma_pair_t *pair = NULL; gdma_group_t *group = NULL; - ESP_RETURN_ON_FALSE(config && ret_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + + // Validate input parameters + ESP_RETURN_ON_FALSE(search_info && config && ret_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(search_info->start_group_id < search_info->end_group_id, ESP_ERR_INVALID_ARG, TAG, "invalid group range"); + ESP_RETURN_ON_FALSE(search_info->pairs_per_group > 0, ESP_ERR_INVALID_ARG, TAG, "invalid pairs_per_group"); + if (config->sibling_chan) { + ESP_RETURN_ON_FALSE(config->sibling_chan->direction != config->direction, ESP_ERR_INVALID_ARG, TAG, + "sibling channel should have a different direction"); + ESP_RETURN_ON_FALSE(config->sibling_chan->pair, ESP_ERR_INVALID_ARG, TAG, "invalid sibling channel"); + } + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION + // retention module is per GDMA pair, before we allocate the pair object, some common registers are already configured in "hal_init" + // if a light sleep happens and powers off the gdma module, those registers will get lost + // to work around it, we can acquire a power lock first, before any register configuration + sleep_retention_power_lock_acquire(); +#endif if (config->flags.reserve_sibling) { search_code = SEARCH_REQUEST_RX_CHANNEL | SEARCH_REQUEST_TX_CHANNEL; // search for a pair of channels @@ -101,13 +105,13 @@ static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *sear if (config->sibling_chan) { pair = config->sibling_chan->pair; - ESP_GOTO_ON_FALSE(pair, ESP_ERR_INVALID_ARG, err, TAG, "invalid sibling channel"); - ESP_GOTO_ON_FALSE(config->sibling_chan->direction != config->direction, ESP_ERR_INVALID_ARG, err, TAG, "sibling channel should have a different direction"); group = pair->group; + // Acquire reference early, before any additional error checks esp_os_enter_critical(&group->spinlock); group->pair_ref_counts[pair->pair_id]++; // channel obtains a reference to pair esp_os_exit_critical(&group->spinlock); - goto search_done; // skip the search path below if user has specify a sibling channel + // skip the search path below if user has specify a sibling channel + goto search_done; } int start_group_id = search_info->start_group_id; @@ -129,17 +133,22 @@ static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *sear esp_os_exit_critical(&pair->spinlock); // found a pair that satisfies the search condition if (search_code == 0) { - esp_os_enter_critical(&group->spinlock); - group->pair_ref_counts[pair->pair_id]++; // channel obtains a reference to pair - esp_os_exit_critical(&group->spinlock); + // gdma_acquire_pair_handle already increased pair ref count, no need to do it again + // pair is ready to use, don't release it + // however, we need to release the group reference acquired by gdma_acquire_group_handle + // because gdma_acquire_pair_handle already added its own group reference + gdma_release_group_handle(group); + break; // exit inner loop, will also exit outer loop due to search_code == 0 + } else { + // not suitable pair, release it + gdma_release_pair_handle(pair); + pair = NULL; } - gdma_release_pair_handle(pair); } // loop used to search pair - gdma_release_group_handle(group); - // restore to initial state if no suitable channel slot is found - if (search_code) { + // Only release group if we didn't find a suitable pair in this group + if (search_code != 0) { + gdma_release_group_handle(group); group = NULL; - pair = NULL; } } // loop used to search group ESP_GOTO_ON_FALSE(search_code == 0, ESP_ERR_NOT_FOUND, err, TAG, "no free gdma channel, search code=%d", search_code); @@ -170,6 +179,13 @@ search_done: // set 1 as default weight, can be overwritten by user gdma_set_weight(*ret_chan, 1); #endif + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION + // set up the sleep retention link for the pair + gdma_acquire_sleep_retention(pair); + // release the helper power lock because we have finished setting up the sleep retention link + sleep_retention_power_lock_release(); +#endif (*ret_chan)->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; ESP_LOGD(TAG, "new %s channel (%d,%d) at %p", (config->direction == GDMA_CHANNEL_DIRECTION_TX) ? "tx" : "rx", group->group_id, pair->pair_id, *ret_chan); @@ -184,10 +200,15 @@ err: } if (pair) { gdma_release_pair_handle(pair); - } - if (group) { + // pair release will also release group if it's the last reference + // so we don't need to release group separately to avoid double-release + } else if (group) { + // only release group if pair wasn't allocated/released gdma_release_group_handle(group); } +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION + sleep_retention_power_lock_release(); +#endif return ret; } @@ -219,14 +240,6 @@ esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_c } #endif // SOC_HAS(AXI_GDMA) -#if SOC_HAS(AHB_GDMA) -esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan) -__attribute__((alias("gdma_new_ahb_channel"))); -#elif SOC_HAS(AXI_GDMA) -esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan) -__attribute__((alias("gdma_new_axi_channel"))); -#endif - esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan) { ESP_RETURN_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); @@ -613,14 +626,14 @@ static void gdma_release_group_handle(gdma_group_t *group) do_deinitialize = true; // deregister from the platform s_platform.groups[group_id] = NULL; + gdma_hal_deinit(&group->hal); + PERIPH_RCC_ATOMIC() { + gdma_ll_enable_bus_clock(group_id, false); + } } esp_os_exit_critical(&s_platform.spinlock); if (do_deinitialize) { - gdma_hal_deinit(&group->hal); - GDMA_RCC_ATOMIC() { - gdma_ll_enable_bus_clock(group_id, false); - } free(group); ESP_LOGD(TAG, "del group %d", group_id); } @@ -640,18 +653,11 @@ static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gd new_group = true; group = pre_alloc_group; s_platform.groups[group_id] = group; // register to platform - } else { - group = s_platform.groups[group_id]; - } - // someone acquired the group handle means we have a new object that refer to this group - s_platform.group_ref_counts[group_id]++; - esp_os_exit_critical(&s_platform.spinlock); - if (new_group) { group->group_id = group_id; group->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // enable APB to access GDMA registers - GDMA_RCC_ATOMIC() { + PERIPH_RCC_ATOMIC() { gdma_ll_enable_bus_clock(group_id, true); gdma_ll_reset_register(group_id); } @@ -662,6 +668,14 @@ static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gd #endif }; hal_init(&group->hal, &config); + } else { + group = s_platform.groups[group_id]; + } + // someone acquired the group handle means we have a new object that refer to this group + s_platform.group_ref_counts[group_id]++; + esp_os_exit_critical(&s_platform.spinlock); + + if (new_group) { ESP_LOGD(TAG, "new group (%d) at %p", group_id, group); } else { free(pre_alloc_group); @@ -687,9 +701,6 @@ static void gdma_release_pair_handle(gdma_pair_t *pair) if (do_deinitialize) { free(pair); -#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION - gdma_sleep_retention_deinit(group->group_id, pair_id); -#endif ESP_LOGD(TAG, "del pair (%d,%d)", group->group_id, pair_id); gdma_release_group_handle(group); } @@ -708,6 +719,10 @@ static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id) if (!group->pairs[pair_id]) { new_pair = true; pair = pre_alloc_pair; + // initialize pair before registering to avoid accessing uninitialized pair + pair->group = group; + pair->pair_id = pair_id; + pair->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; // register the pair to the group group->pairs[pair_id] = pair; } else { @@ -717,23 +732,18 @@ static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id) group->pair_ref_counts[pair_id]++; esp_os_exit_critical(&group->spinlock); + // Update group reference count outside of group->spinlock to avoid deadlock + // This must be done after pair registration to ensure group remains valid if (new_pair) { - pair->group = group; - pair->pair_id = pair_id; - pair->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; - esp_os_enter_critical(&s_platform.spinlock); - // pair obtains a reference to group, so increase it s_platform.group_ref_counts[group->group_id]++; esp_os_exit_critical(&s_platform.spinlock); -#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION - gdma_sleep_retention_init(group->group_id, pair_id); -#endif ESP_LOGD(TAG, "new pair (%d,%d) at %p", group->group_id, pair_id, pair); } else { free(pre_alloc_pair); } + out: return pair; } @@ -743,6 +753,7 @@ static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel) gdma_pair_t *pair = dma_channel->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; + // Store IDs early to avoid use-after-free int pair_id = pair->pair_id; int group_id = group->group_id; gdma_tx_channel_t *tx_chan = __containerof(dma_channel, gdma_tx_channel_t, base); @@ -762,6 +773,11 @@ static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel) free(tx_chan); ESP_LOGD(TAG, "del tx channel (%d,%d)", group_id, pair_id); + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION + // release sleep retention lock + gdma_release_sleep_retention(pair); +#endif // channel has a reference on pair, release it now gdma_release_pair_handle(pair); return ESP_OK; @@ -772,6 +788,7 @@ static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel) gdma_pair_t *pair = dma_channel->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; + // Store IDs early to avoid use-after-free int pair_id = pair->pair_id; int group_id = group->group_id; gdma_rx_channel_t *rx_chan = __containerof(dma_channel, gdma_rx_channel_t, base); @@ -791,6 +808,12 @@ static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel) free(rx_chan); ESP_LOGD(TAG, "del rx channel (%d,%d)", group_id, pair_id); + +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_GDMA_SUPPORT_SLEEP_RETENTION + // release sleep retention lock + gdma_release_sleep_retention(pair); +#endif + // channel has a reference on pair, release it now gdma_release_pair_handle(pair); return ESP_OK; } diff --git a/components/esp_hw_support/dma/gdma_priv.h b/components/esp_hw_support/dma/gdma_priv.h index ffa0e0bb89..a16305f58f 100644 --- a/components/esp_hw_support/dma/gdma_priv.h +++ b/components/esp_hw_support/dma/gdma_priv.h @@ -33,6 +33,8 @@ #include "soc/periph_defs.h" #include "esp_private/gdma.h" #include "esp_private/periph_ctrl.h" +#include "esp_private/critical_section.h" +#include "esp_private/sleep_retention.h" #if CONFIG_GDMA_OBJ_DRAM_SAFE #define GDMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) @@ -98,6 +100,9 @@ struct gdma_rx_channel_t { gdma_rx_event_callbacks_t cbs; // RX event callbacks }; +void gdma_acquire_sleep_retention(gdma_pair_t* pair); +void gdma_release_sleep_retention(gdma_pair_t* pair); + #ifdef __cplusplus } #endif diff --git a/components/esp_hw_support/dma/gdma_sleep_retention.c b/components/esp_hw_support/dma/gdma_sleep_retention.c index 6c8eeaf29c..a5f27b365d 100644 --- a/components/esp_hw_support/dma/gdma_sleep_retention.c +++ b/components/esp_hw_support/dma/gdma_sleep_retention.c @@ -4,61 +4,79 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include #include "gdma_priv.h" -#include "esp_private/sleep_retention.h" -#include "esp_private/esp_regdma.h" -typedef struct { - int group_id; - int pair_id; -} gdma_channel_retention_arg_t; +// Note!: the sleep retention APIs are using OS locks, so here we have to use a lock rather than a light-weight critical section +static _lock_t gdma_sleep_retention_lock; +static uint8_t pair_ref_counts[GDMA_LL_GET(INST_NUM)][GDMA_LL_GET(PAIRS_PER_INST)]; ESP_LOG_ATTR_TAG(TAG, "gdma"); static esp_err_t sleep_gdma_channel_retention_init(void *arg) { - gdma_channel_retention_arg_t *parg = (gdma_channel_retention_arg_t *)arg; - int group_id = parg->group_id; - int pair_id = parg->pair_id; + gdma_pair_t *pair = (gdma_pair_t *)arg; + int group_id = pair->group->group_id; + int pair_id = pair->pair_id; sleep_retention_module_t module = gdma_chx_regs_retention[group_id][pair_id].module_id; - esp_err_t err = sleep_retention_entries_create(gdma_chx_regs_retention[group_id][pair_id].link_list, gdma_chx_regs_retention[group_id][pair_id].link_num, REGDMA_LINK_PRI_GDMA, module); + esp_err_t err = sleep_retention_entries_create(gdma_chx_regs_retention[group_id][pair_id].link_list, + gdma_chx_regs_retention[group_id][pair_id].link_num, + REGDMA_LINK_PRI_GDMA, module); if (err == ESP_OK) { - ESP_LOGD(TAG, "GDMA pair (%d, %d) retention initialization", group_id, pair_id); + ESP_LOGD(TAG, "retention link created for pair (%d, %d)", group_id, pair_id); + } else { + ESP_LOGE(TAG, "failed to create retention link for pair (%d, %d)", group_id, pair_id); } - - ESP_RETURN_ON_ERROR(err, TAG, "Failed to create sleep retention linked list for GDMA pair (%d, %d) retention", group_id, pair_id); return err; } -esp_err_t gdma_sleep_retention_init(int group_id, int pair_id) +void gdma_acquire_sleep_retention(gdma_pair_t* pair) { - gdma_channel_retention_arg_t arg = { .group_id = group_id, .pair_id = pair_id }; + int group_id = pair->group->group_id; + int pair_id = pair->pair_id; sleep_retention_module_init_param_t init_param = { - .cbs = { .create = { .handle = sleep_gdma_channel_retention_init, .arg = &arg } }, + .cbs = { .create = { .handle = sleep_gdma_channel_retention_init, .arg = pair } }, .depends = RETENTION_MODULE_BITMAP_INIT(CLOCK_SYSTEM) }; sleep_retention_module_t module = gdma_chx_regs_retention[group_id][pair_id].module_id; - esp_err_t err = sleep_retention_module_init(module, &init_param); - if (err == ESP_OK) { - err = sleep_retention_module_allocate(module); + + _lock_acquire(&gdma_sleep_retention_lock); + // First time acquiring this pair, initialize the module + if (pair_ref_counts[group_id][pair_id] == 0) { + esp_err_t err = sleep_retention_module_init(module, &init_param); if (err != ESP_OK) { - ESP_LOGW(TAG, "Failed to allocate sleep retention linked list for GDMA retention"); + ESP_LOGW(TAG, "init retention module failed for pair (%d, %d), power domain may be turned off during sleep", group_id, pair_id); + } else { + err = sleep_retention_module_allocate(module); + if (err != ESP_OK) { + ESP_LOGW(TAG, "fail to allocate retention link list for pair (%d, %d)", group_id, pair_id); + // don't call sleep_retention_module_deinit here, otherwise GDMA peripheral may be powered off during sleep + } } } - return err; + pair_ref_counts[group_id][pair_id]++; + _lock_release(&gdma_sleep_retention_lock); } -esp_err_t gdma_sleep_retention_deinit(int group_id, int pair_id) +void gdma_release_sleep_retention(gdma_pair_t* pair) { + int group_id = pair->group->group_id; + int pair_id = pair->pair_id; sleep_retention_module_t module = gdma_chx_regs_retention[group_id][pair_id].module_id; - esp_err_t err = sleep_retention_module_free(module); - if (err != ESP_OK) { - ESP_LOGW(TAG, "GDMA pair (%d, %d) retention destroy failed", group_id, pair_id); + + _lock_acquire(&gdma_sleep_retention_lock); + pair_ref_counts[group_id][pair_id]--; + // Last reference, free the module + if (pair_ref_counts[group_id][pair_id] == 0) { + esp_err_t err = sleep_retention_module_free(module); + if (err != ESP_OK) { + ESP_LOGW(TAG, "fail to free the retention link list for pair (%d, %d)", group_id, pair_id); + } + err = sleep_retention_module_deinit(module); + if (err != ESP_OK) { + ESP_LOGW(TAG, "fail to deinit the retention module for pair (%d, %d)", group_id, pair_id); + } } - err = sleep_retention_module_deinit(module); - if (err != ESP_OK) { - ESP_LOGW(TAG, "GDMA pair (%d, %d) retention deinit failed", group_id, pair_id); - } - return err; + _lock_release(&gdma_sleep_retention_lock); } diff --git a/components/esp_hw_support/dma/include/esp_private/gdma.h b/components/esp_hw_support/dma/include/esp_private/gdma.h index 1683b88076..289b8e093d 100644 --- a/components/esp_hw_support/dma/include/esp_private/gdma.h +++ b/components/esp_hw_support/dma/include/esp_private/gdma.h @@ -52,7 +52,7 @@ typedef struct { /** * @brief Type of GDMA event callback - * @param dma_chan GDMA channel handle, created from `gdma_new_channel` + * @param dma_chan GDMA channel handle, created from `gdma_new_ahb_channel/gdma_new_axi_channel` * @param event_data GDMA event data. Different event share the same data structure, but the caller may only use a few or none of the data members. * @param user_data User registered data from `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks` * @@ -146,7 +146,7 @@ esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_c * @note Suggest to use helper macro `GDMA_MAKE_TRIGGER` to construct parameter `trig_periph`. e.g. GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA,0) * @note Connecting to a peripheral will also reset the DMA FIFO and FSM automatically * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] trig_periph GDMA trigger peripheral * @return * - ESP_OK: Connect GDMA channel successfully @@ -159,7 +159,7 @@ esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_perip /** * @brief Disconnect GMA channel from peripheral * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @return * - ESP_OK: Disconnect GDMA channel successfully * - ESP_ERR_INVALID_ARG: Disconnect GDMA channel failed because of invalid argument @@ -184,7 +184,7 @@ typedef struct { * @note It's highly recommended to enable the burst mode and set proper burst size for the DMA channel, * which can improve the performance in accessing external memory by a lot. * - * @param[in] chan DMA channel handle, allocated by `gdma_new_channel` + * @param[in] chan DMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] config Transfer configurations * @return * - ESP_OK: Configure DMA transfer parameters successfully @@ -202,7 +202,7 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf * @note The returned alignment doesn't take the cache line size into account, if you want to do aligned memory allocation, * you should align the buffer size to the cache line size by yourself if the DMA buffer is behind a cache. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[out] int_mem_alignment Internal memory alignment * @param[out] ext_mem_alignment External memory alignment * @return @@ -215,7 +215,7 @@ esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t /** * @brief Apply channel strategy for GDMA channel * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] config Configuration of GDMA channel strategy * - ESP_OK: Apply channel strategy successfully * - ESP_ERR_INVALID_ARG: Apply channel strategy failed because of invalid argument @@ -228,7 +228,7 @@ esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strateg * * @note By default, all GDMA channels are with the same priority: 0. Channels with the same priority are served in round-robin manner. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] priority Priority of GDMA channel, higher value means higher priority * @return * - ESP_OK: Set GDMA channel priority successfully @@ -239,9 +239,9 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority); /** * @brief Delete GDMA channel - * @note If you call `gdma_new_channel` several times for a same peripheral, make sure you call this API the same times. + * @note If you call `gdma_new_ahb_channel/gdma_new_axi_channel` several times for a same peripheral, make sure you call this API the same times. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @return * - ESP_OK: Delete GDMA channel successfully * - ESP_ERR_INVALID_ARG: Delete GDMA channel failed because of invalid argument @@ -255,7 +255,7 @@ esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan); * @note This API breaks the encapsulation of GDMA Channel Object. * With the returned group/channel ID, you can even bypass all other GDMA driver API and access Low Level API directly. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[out] group_id Returned group ID * @param[out] channel_id Returned channel ID * @return @@ -271,7 +271,7 @@ esp_err_t gdma_get_group_channel_id(gdma_channel_handle_t dma_chan, int *group_i * @brief Set GDMA event callbacks for TX channel * @note This API will install GDMA interrupt service for the channel internally * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly * @return @@ -285,7 +285,7 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ * @brief Set GDMA event callbacks for RX channel * @note This API will install GDMA interrupt service for the channel internally * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] cbs Group of callback functions * @param[in] user_data User data, which will be passed to callback functions directly * @return @@ -301,7 +301,7 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ * @note This function is allowed to run within ISR context * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] desc_base_addr Base address of descriptors (usually the descriptors are chained into a link or ring) * @return * - ESP_OK: Start DMA engine successfully @@ -317,7 +317,7 @@ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr); * @note This function is allowed to run within ISR context * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @return * - ESP_OK: Stop DMA engine successfully * - ESP_ERR_INVALID_ARG: Stop DMA engine failed because of invalid argument @@ -333,7 +333,7 @@ esp_err_t gdma_stop(gdma_channel_handle_t dma_chan); * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled * @note This API could also resume a paused DMA engine, make sure new descriptors have been appended to the descriptor chain before calling it. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @return * - ESP_OK: Send append command to DMA engine successfully * - ESP_ERR_INVALID_ARG: Send append command to DMA engine failed because of invalid argument @@ -348,7 +348,7 @@ esp_err_t gdma_append(gdma_channel_handle_t dma_chan); * @note This function is also allowed to run when Cache is disabled, if `CONFIG_GDMA_CTRL_FUNC_IN_IRAM` is enabled * @note Resetting a DMA channel won't break the connection with the target peripheral * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @return * - ESP_OK: DMA channel reset successfully * - ESP_ERR_INVALID_ARG: DMA channel reset failed due to invalid arguments @@ -369,7 +369,7 @@ typedef struct { * * @note The created ETM event object can be deleted later by calling `esp_etm_del_event` * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] config GDMA ETM event configuration * @param[out] out_event Returned ETM event handle * @return @@ -393,7 +393,7 @@ typedef struct { * @note The created ETM task object can be deleted later by calling `esp_etm_del_task` * @note If the GDMA task (e.g. start/stop) is controlled by ETM, then you can't use `gdma_start`/`gdma_stop` to control it. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] config GDMA ETM task configuration * @param[out] out_task Returned ETM task handle * @return @@ -412,7 +412,7 @@ esp_err_t gdma_new_etm_task(gdma_channel_handle_t dma_chan, const gdma_etm_task_ * which can bring conflict if the peripheral is also using the same trigger ID. This function can return the free IDs * for memory copy, at the runtime. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[out] mask Returned mask of free M2M trigger IDs * @return * - ESP_OK: Get free M2M trigger IDs successfully @@ -438,7 +438,7 @@ typedef struct { * @note This function must be called before `gdma_start`. * @note The CRC Calculator will reset itself automatically if the DMA stops and starts again. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] config CRC Calculator configuration * @return * - ESP_OK: Configure CRC Calculator successfully @@ -452,7 +452,7 @@ esp_err_t gdma_config_crc_calculator(gdma_channel_handle_t dma_chan, const gdma_ * * @note You need to call this function before a new DMA transaction starts, otherwise the CRC results may be overridden. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[out] result Returned CRC result * @return * - ESP_OK: Get CRC result successfully @@ -474,7 +474,7 @@ esp_err_t gdma_crc_get_result(gdma_channel_handle_t dma_chan, uint32_t *result); * @note Weighted arbitration is different from priority arbitration. "Weight" is used after comparing "priority" * After the priority comparison, then arbitrator checks whether there are still unused tokens in the channel. * - * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_channel` + * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] weight Weight of GDMA channel, higher value means higher priority in weighted arbitration. * @return * - ESP_OK: Set GDMA channel weight successfully diff --git a/components/esp_hw_support/include/esp_private/gdma_sleep_retention.h b/components/esp_hw_support/include/esp_private/gdma_sleep_retention.h deleted file mode 100644 index 19d649d79a..0000000000 --- a/components/esp_hw_support/include/esp_private/gdma_sleep_retention.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020-2023 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -// DO NOT USE THESE APIS IN ANY APPLICATIONS -// GDMA driver is not public for end users, but for ESP-IDF developers. - -#pragma once - -#include "esp_err.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Initialize GDMA channel retention link for powerdown the TOP powerdomain during lightsleep - * @param group_id Group id - * @param pair_id Pair id - * @return - * - ESP_OK: Create DMA retention link successfully - * - ESP_ERR_NO_MEM: Create DMA retention link failed because out of memory - */ -esp_err_t gdma_sleep_retention_init(int group_id, int pair_id); - -/** - * Destroy GDMA channel retention link - * @param group_id Group id - * @param pair_id Pair id - * @return - * - ESP_OK: GDMA channel retention link destrory successfully - * - ESP_ERR_INVALID_STATE: GDMA channel retention link not create yet - */ -esp_err_t gdma_sleep_retention_deinit(int group_id, int pair_id); - -#ifdef __cplusplus -} -#endif diff --git a/components/esp_hw_support/include/esp_private/periph_ctrl.h b/components/esp_hw_support/include/esp_private/periph_ctrl.h index cfbdc1fbe1..005001e035 100644 --- a/components/esp_hw_support/include/esp_private/periph_ctrl.h +++ b/components/esp_hw_support/include/esp_private/periph_ctrl.h @@ -25,9 +25,9 @@ extern "C" { * @note This macro will increase the reference lock of that peripheral. * You can get the value before the increment from the `rc_name` local variable */ -#define PERIPH_RCC_ACQUIRE_ATOMIC(rc_periph, rc_name) \ - for (uint8_t rc_name, _rc_cnt = 1, __DECLARE_RCC_RC_ATOMIC_ENV; \ - _rc_cnt ? (rc_name = periph_rcc_acquire_enter(rc_periph), 1) : 0; \ +#define PERIPH_RCC_ACQUIRE_ATOMIC(rc_periph, rc_name) \ + for (uint8_t rc_name, _rc_cnt = 1, __DECLARE_RCC_RC_ATOMIC_ENV __attribute__((unused)); \ + _rc_cnt ? (rc_name = periph_rcc_acquire_enter(rc_periph), 1) : 0; \ periph_rcc_acquire_exit(rc_periph, rc_name), _rc_cnt--) /** @@ -37,9 +37,9 @@ extern "C" { * @note This macro will decrease the reference lock of that peripheral. * You can get the value after the decrease from the `rc_name` local variable */ -#define PERIPH_RCC_RELEASE_ATOMIC(rc_periph, rc_name) \ - for (uint8_t rc_name, _rc_cnt = 1, __DECLARE_RCC_RC_ATOMIC_ENV; \ - _rc_cnt ? (rc_name = periph_rcc_release_enter(rc_periph), 1) : 0; \ +#define PERIPH_RCC_RELEASE_ATOMIC(rc_periph, rc_name) \ + for (uint8_t rc_name, _rc_cnt = 1, __DECLARE_RCC_RC_ATOMIC_ENV __attribute__((unused)); \ + _rc_cnt ? (rc_name = periph_rcc_release_enter(rc_periph), 1) : 0; \ periph_rcc_release_exit(rc_periph, rc_name), _rc_cnt--) /** @@ -47,9 +47,9 @@ extern "C" { * * @note User code protected by this macro should be as short as possible, because it's a critical section */ -#define PERIPH_RCC_ATOMIC() \ - for (int _rc_cnt = 1, __DECLARE_RCC_ATOMIC_ENV; \ - _rc_cnt ? (periph_rcc_enter(), 1) : 0; \ +#define PERIPH_RCC_ATOMIC() \ + for (int _rc_cnt = 1, __DECLARE_RCC_ATOMIC_ENV __attribute__((unused)); \ + _rc_cnt ? (periph_rcc_enter(), 1) : 0; \ periph_rcc_exit(), _rc_cnt--) /** @cond */