diff --git a/components/driver/gdma.c b/components/driver/gdma.c index 8e2e9fd027..974bb0c48c 100644 --- a/components/driver/gdma.c +++ b/components/driver/gdma.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2022 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,19 +26,17 @@ static const char *TAG = "gdma"; -#if CONFIG_GDMA_ISR_IRAM_SAFE -#define GDMA_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED) +#if CONFIG_GDMA_ISR_IRAM_SAFE || CONFIG_GDMA_CTRL_FUNC_IN_IRAM #define GDMA_MEM_ALLOC_CAPS (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) #else -#define GDMA_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED #define GDMA_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT -#endif // CONFIG_GDMA_ISR_IRAM_SAFE +#endif -#if CONFIG_GDMA_CTRL_FUNC_IN_IRAM -#define GDMA_CTRL_FUNC_ATTR IRAM_ATTR +#if CONFIG_GDMA_ISR_IRAM_SAFE +#define GDMA_INTR_ALLOC_FLAGS (ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_INTRDISABLED) #else -#define GDMA_CTRL_FUNC_ATTR -#endif // CONFIG_GDMA_CTRL_FUNC_IN_IRAM +#define GDMA_INTR_ALLOC_FLAGS ESP_INTR_FLAG_INTRDISABLED +#endif #define GDMA_INVALID_PERIPH_TRIG (0x3F) #define SEARCH_REQUEST_RX_CHANNEL (1 << 0) @@ -109,11 +107,9 @@ struct gdma_rx_channel_t { }; static gdma_group_t *gdma_acquire_group_handle(int group_id); -static void gdma_release_group_handle(gdma_group_t *group); static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id); +static void gdma_release_group_handle(gdma_group_t *group); static void gdma_release_pair_handle(gdma_pair_t *pair); -static void gdma_uninstall_group(gdma_group_t *group); -static void gdma_uninstall_pair(gdma_pair_t *pair); static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel); static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel); static esp_err_t gdma_install_rx_interrupt(gdma_rx_channel_t *rx_chan); @@ -161,27 +157,28 @@ esp_err_t gdma_new_channel(const gdma_channel_alloc_config_t *config, gdma_chann for (int i = 0; i < SOC_GDMA_GROUPS && search_code; i++) { // loop to search group group = gdma_acquire_group_handle(i); - for (int j = 0; j < SOC_GDMA_PAIRS_PER_GROUP && search_code && group; j++) { // loop to search pair + ESP_GOTO_ON_FALSE(group, ESP_ERR_NO_MEM, err, TAG, "no mem for group(%d)", i); + for (int j = 0; j < SOC_GDMA_PAIRS_PER_GROUP && search_code; j++) { // loop to search pair pair = gdma_acquire_pair_handle(group, j); - if (pair) { - portENTER_CRITICAL(&pair->spinlock); - if (!(search_code & pair->occupy_code)) { // pair has suitable position for acquired channel(s) - pair->occupy_code |= search_code; - search_code = 0; // exit search loop - } - portEXIT_CRITICAL(&pair->spinlock); - if (!search_code) { - portENTER_CRITICAL(&group->spinlock); - group->pair_ref_counts[j]++; // channel obtains a reference to pair - portEXIT_CRITICAL(&group->spinlock); - } + ESP_GOTO_ON_FALSE(pair, ESP_ERR_NO_MEM, err, TAG, "no mem for pair(%d,%d)", i, j); + portENTER_CRITICAL(&pair->spinlock); + if (!(search_code & pair->occupy_code)) { // pair has suitable position for acquired channel(s) + pair->occupy_code |= search_code; + search_code = 0; // exit search loop + } + portEXIT_CRITICAL(&pair->spinlock); + if (search_code) { + gdma_release_pair_handle(pair); + pair = NULL; } - gdma_release_pair_handle(pair); } // loop used to search pair - gdma_release_group_handle(group); + if (search_code) { + gdma_release_group_handle(group); + group = 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); - + assert(pair && group); // pair and group handle shouldn't be NULL search_done: // register TX channel if (alloc_tx_channel) { @@ -214,6 +211,12 @@ err: if (alloc_rx_channel) { free(alloc_rx_channel); } + if (pair) { + gdma_release_pair_handle(pair); + } + if (group) { + gdma_release_group_handle(group); + } return ret; } @@ -386,9 +389,7 @@ esp_err_t gdma_register_tx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_trans_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_trans_eof not in IRAM"); } if (user_data) { - ESP_GOTO_ON_FALSE(esp_ptr_in_dram(user_data) || - esp_ptr_in_diram_dram(user_data) || - esp_ptr_in_rtc_dram_fast(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in DRAM"); + ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM"); } #endif // CONFIG_GDMA_ISR_IRAM_SAFE @@ -424,9 +425,7 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ ESP_GOTO_ON_FALSE(esp_ptr_in_iram(cbs->on_recv_eof), ESP_ERR_INVALID_ARG, err, TAG, "on_recv_eof not in IRAM"); } if (user_data) { - ESP_GOTO_ON_FALSE(esp_ptr_in_dram(user_data) || - esp_ptr_in_diram_dram(user_data) || - esp_ptr_in_rtc_dram_fast(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in DRAM"); + ESP_GOTO_ON_FALSE(esp_ptr_internal(user_data), ESP_ERR_INVALID_ARG, err, TAG, "user context not in internal RAM"); } #endif // CONFIG_GDMA_ISR_IRAM_SAFE @@ -447,7 +446,7 @@ err: return ret; } -GDMA_CTRL_FUNC_ATTR esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr) +esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr) { esp_err_t ret = ESP_OK; gdma_pair_t *pair = NULL; @@ -468,7 +467,7 @@ err: return ret; } -GDMA_CTRL_FUNC_ATTR esp_err_t gdma_stop(gdma_channel_handle_t dma_chan) +esp_err_t gdma_stop(gdma_channel_handle_t dma_chan) { esp_err_t ret = ESP_OK; gdma_pair_t *pair = NULL; @@ -487,7 +486,7 @@ err: return ret; } -GDMA_CTRL_FUNC_ATTR esp_err_t gdma_append(gdma_channel_handle_t dma_chan) +esp_err_t gdma_append(gdma_channel_handle_t dma_chan) { esp_err_t ret = ESP_OK; gdma_pair_t *pair = NULL; @@ -506,7 +505,7 @@ err: return ret; } -GDMA_CTRL_FUNC_ATTR esp_err_t gdma_reset(gdma_channel_handle_t dma_chan) +esp_err_t gdma_reset(gdma_channel_handle_t dma_chan) { esp_err_t ret = ESP_OK; gdma_pair_t *pair = NULL; @@ -525,7 +524,7 @@ err: return ret; } -static void gdma_uninstall_group(gdma_group_t *group) +static void gdma_release_group_handle(gdma_group_t *group) { int group_id = group->group_id; bool do_deinitialize = false; @@ -581,14 +580,7 @@ out: return group; } -static void gdma_release_group_handle(gdma_group_t *group) -{ - if (group) { - gdma_uninstall_group(group); - } -} - -static void gdma_uninstall_pair(gdma_pair_t *pair) +static void gdma_release_pair_handle(gdma_pair_t *pair) { gdma_group_t *group = pair->group; int pair_id = pair->pair_id; @@ -606,8 +598,7 @@ static void gdma_uninstall_pair(gdma_pair_t *pair) if (do_deinitialize) { free(pair); ESP_LOGD(TAG, "del pair (%d,%d)", group->group_id, pair_id); - - gdma_uninstall_group(group); + gdma_release_group_handle(group); } } @@ -646,17 +637,12 @@ out: return pair; } -static void gdma_release_pair_handle(gdma_pair_t *pair) -{ - if (pair) { - gdma_uninstall_pair(pair); - } -} - 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; + 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); portENTER_CRITICAL(&pair->spinlock); pair->tx_chan = NULL; @@ -666,15 +652,16 @@ static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel) if (dma_channel->intr) { esp_intr_free(dma_channel->intr); portENTER_CRITICAL(&pair->spinlock); - gdma_ll_tx_enable_interrupt(group->hal.dev, pair->pair_id, UINT32_MAX, false); // disable all interupt events - gdma_ll_tx_clear_interrupt_status(group->hal.dev, pair->pair_id, UINT32_MAX); // clear all pending events + gdma_ll_tx_enable_interrupt(group->hal.dev, pair_id, UINT32_MAX, false); // disable all interupt events + gdma_ll_tx_clear_interrupt_status(group->hal.dev, pair_id, UINT32_MAX); // clear all pending events portEXIT_CRITICAL(&pair->spinlock); - ESP_LOGD(TAG, "uninstall interrupt service for tx channel (%d,%d)", group->group_id, pair->pair_id); + ESP_LOGD(TAG, "uninstall interrupt service for tx channel (%d,%d)", group_id, pair_id); } - ESP_LOGD(TAG, "del tx channel (%d,%d)", group->group_id, pair->pair_id); free(tx_chan); - gdma_uninstall_pair(pair); + ESP_LOGD(TAG, "del tx channel (%d,%d)", group_id, pair_id); + // channel has a reference on pair, release it now + gdma_release_pair_handle(pair); return ESP_OK; } @@ -682,6 +669,8 @@ 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; + 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); portENTER_CRITICAL(&pair->spinlock); pair->rx_chan = NULL; @@ -691,15 +680,15 @@ static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel) if (dma_channel->intr) { esp_intr_free(dma_channel->intr); portENTER_CRITICAL(&pair->spinlock); - gdma_ll_rx_enable_interrupt(group->hal.dev, pair->pair_id, UINT32_MAX, false); // disable all interupt events - gdma_ll_rx_clear_interrupt_status(group->hal.dev, pair->pair_id, UINT32_MAX); // clear all pending events + gdma_ll_rx_enable_interrupt(group->hal.dev, pair_id, UINT32_MAX, false); // disable all interupt events + gdma_ll_rx_clear_interrupt_status(group->hal.dev, pair_id, UINT32_MAX); // clear all pending events portEXIT_CRITICAL(&pair->spinlock); - ESP_LOGD(TAG, "uninstall interrupt service for rx channel (%d,%d)", group->group_id, pair->pair_id); + ESP_LOGD(TAG, "uninstall interrupt service for rx channel (%d,%d)", group_id, pair_id); } - ESP_LOGD(TAG, "del rx channel (%d,%d)", group->group_id, pair->pair_id); free(rx_chan); - gdma_uninstall_pair(pair); + ESP_LOGD(TAG, "del rx channel (%d,%d)", group_id, pair_id); + gdma_release_pair_handle(pair); return ESP_OK; } diff --git a/components/driver/linker.lf b/components/driver/linker.lf index f260c79cf7..c01f1574b6 100644 --- a/components/driver/linker.lf +++ b/components/driver/linker.lf @@ -1,4 +1,3 @@ - [mapping:driver] archive: libdriver.a entries: @@ -7,3 +6,8 @@ entries: # placed in flash. if TWAI_ISR_IN_IRAM = y && (TWAI_ERRATA_FIX_RX_FRAME_INVALID = y || TWAI_ERRATA_FIX_RX_FIFO_CORRUPT = y): periph_ctrl: periph_module_reset (noflash) + if GDMA_CTRL_FUNC_IN_IRAM = y: + gdma: gdma_start (noflash) + gdma: gdma_stop (noflash) + gdma: gdma_append (noflash) + gdma: gdma_reset (noflash)