From 7909976e0ff464cf294abfce2f42bb32e4d7352c Mon Sep 17 00:00:00 2001 From: morris Date: Tue, 23 Dec 2025 10:34:07 +0800 Subject: [PATCH] refactor(gdma): channel allocation can return both direction within the same call --- .../driver/uart/hci_driver_uart_dma.c | 13 +- components/esp_adc/gdma/adc_dma.c | 3 +- .../src/bitscrambler_loopback.c | 18 +- .../dvp/src/esp_cam_ctlr_dvp_gdma.c | 3 +- components/esp_driver_i2s/i2s_common.c | 6 +- components/esp_driver_i3c/i3c_master.c | 6 +- components/esp_driver_parlio/src/parlio_rx.c | 3 +- components/esp_driver_parlio/src/parlio_tx.c | 3 +- components/esp_driver_rmt/src/rmt_rx.c | 3 +- components/esp_driver_rmt/src/rmt_tx.c | 3 +- .../esp_driver_spi/src/gpspi/spi_common.c | 17 +- components/esp_driver_uart/src/uhci.c | 6 +- .../esp_hal_dma/esp32c2/include/hal/gdma_ll.h | 2 + .../esp_hal_dma/esp32c3/include/hal/gdma_ll.h | 2 + .../esp32c5/include/hal/ahb_dma_ll.h | 2 + .../esp_hal_dma/esp32c6/include/hal/gdma_ll.h | 2 + .../esp32c61/include/hal/ahb_dma_ll.h | 2 + .../esp_hal_dma/esp32h2/include/hal/gdma_ll.h | 2 + .../esp32h21/include/hal/gdma_ll.h | 2 + .../esp32h4/include/hal/ahb_dma_ll.h | 2 + .../esp_hal_dma/esp32p4/include/hal/gdma_ll.h | 8 + .../esp_hal_dma/esp32s3/include/hal/gdma_ll.h | 2 + .../esp_hw_support/dma/async_memcpy_gdma.c | 18 +- components/esp_hw_support/dma/gdma.c | 328 +++++++++++------- components/esp_hw_support/dma/gdma_priv.h | 1 - .../dma/include/esp_private/gdma.h | 33 +- .../test_apps/dma/main/test_gdma.c | 120 ++----- .../test_apps/dma/main/test_gdma_crc.c | 5 +- components/esp_lcd/i80/esp_lcd_panel_io_i80.c | 6 +- components/esp_lcd/rgb/esp_lcd_panel_rgb.c | 3 +- .../esp_crypto_shared_gdma.c | 77 ++-- 31 files changed, 336 insertions(+), 365 deletions(-) diff --git a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c index 7bc3cc7c0b..675c7eed63 100644 --- a/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c +++ b/components/bt/porting/transport/driver/uart/hci_driver_uart_dma.c @@ -437,18 +437,9 @@ static void hci_driver_uart_dma_install(void) periph_module_enable(PERIPH_UHCI0_MODULE); periph_module_reset(PERIPH_UHCI0_MODULE); // install DMA driver - gdma_channel_alloc_config_t tx_channel_config = { - .flags.reserve_sibling = 1, - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; + gdma_channel_alloc_config_t channel_config = {0}; - ESP_ERROR_CHECK(gdma_new_ahb_channel(&tx_channel_config, &s_tx_channel)); - gdma_channel_alloc_config_t rx_channel_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = s_tx_channel, - }; - - ESP_ERROR_CHECK(gdma_new_ahb_channel(&rx_channel_config, &s_rx_channel)); + ESP_ERROR_CHECK(gdma_new_ahb_channel(&channel_config, &s_tx_channel, &s_rx_channel)); gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); gdma_strategy_config_t strategy_config = { diff --git a/components/esp_adc/gdma/adc_dma.c b/components/esp_adc/gdma/adc_dma.c index 21bc9431c4..20a1be79f3 100644 --- a/components/esp_adc/gdma/adc_dma.c +++ b/components/esp_adc/gdma/adc_dma.c @@ -29,12 +29,11 @@ esp_err_t adc_dma_init(adc_dma_t *adc_dma) esp_err_t ret = ESP_OK; //alloc rx gdma channel gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, #if CONFIG_ADC_CONTINUOUS_ISR_IRAM_SAFE .flags.isr_cache_safe = true, #endif }; - ret = gdma_new_ahb_channel(&rx_alloc_config, &(adc_dma->gdma_chan)); + ret = gdma_new_ahb_channel(&rx_alloc_config, NULL, &(adc_dma->gdma_chan)); if (ret != ESP_OK) { return ret; } diff --git a/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c b/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c index 843537ffef..8aedfde98a 100644 --- a/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c +++ b/components/esp_driver_bitscrambler/src/bitscrambler_loopback.c @@ -41,19 +41,19 @@ _Static_assert(offsetof(bitscrambler_loopback_t, bs) == 0, "bs needs to be 1st m static void bitscrambler_loopback_free(bitscrambler_loopback_t *bsl); static esp_err_t bitscrambler_loopback_cleanup(bitscrambler_handle_t bs, void* user_ctx); -static esp_err_t new_dma_channel(const gdma_channel_alloc_config_t *cfg, gdma_channel_handle_t *handle, int bus) +static esp_err_t new_dma_channel(const gdma_channel_alloc_config_t *cfg, gdma_channel_handle_t *tx_handle, gdma_channel_handle_t *rx_handle, int bus) { esp_err_t ret = ESP_OK; //Note that there are chips that do not have SOC_GDMA_BUS_* defined, but those chips also do //not have a BitScrambler. #ifdef SOC_GDMA_BUS_AHB if (bus == SOC_GDMA_BUS_AHB || bus == SOC_GDMA_BUS_ANY) { - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(cfg, handle), TAG, "alloc AHB DMA channel failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(cfg, tx_handle, rx_handle), TAG, "alloc AHB DMA channel failed"); } #endif #ifdef SOC_GDMA_BUS_AXI if (bus == SOC_GDMA_BUS_AXI) { - ESP_RETURN_ON_ERROR(gdma_new_axi_channel(cfg, handle), TAG, "alloc AXI DMA channel failed"); + ESP_RETURN_ON_ERROR(gdma_new_axi_channel(cfg, tx_handle, rx_handle), TAG, "alloc AXI DMA channel failed"); } #endif return ret; @@ -115,16 +115,8 @@ esp_err_t bitscrambler_loopback_create(bitscrambler_handle_t *handle, int attach ESP_GOTO_ON_ERROR(gdma_new_link_list(&dma_link_cfg, &bs->rx_link_list), err, TAG, "failed to create RX link list"); // create TX channel and RX channel, they should reside in the same DMA pair - gdma_channel_alloc_config_t tx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, - .flags.reserve_sibling = 1, - }; - ESP_GOTO_ON_ERROR(new_dma_channel(&tx_alloc_config, &bs->tx_channel, bus), err, TAG, "failed to create GDMA TX channel"); - gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = bs->tx_channel, - }; - ESP_GOTO_ON_ERROR(new_dma_channel(&rx_alloc_config, &bs->rx_channel, bus), err, TAG, "failed to create GDMA RX channel"); + gdma_channel_alloc_config_t alloc_config = {0}; + ESP_GOTO_ON_ERROR(new_dma_channel(&alloc_config, &bs->tx_channel, &bs->rx_channel, bus), err, TAG, "failed to create GDMA channels"); gdma_connect(bs->rx_channel, g_bitscrambler_periph_desc[attach_to].dma_trigger); gdma_connect(bs->tx_channel, g_bitscrambler_periph_desc[attach_to].dma_trigger); diff --git a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c index fc640319b9..4164d85fb8 100644 --- a/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c +++ b/components/esp_driver_cam/dvp/src/esp_cam_ctlr_dvp_gdma.c @@ -81,7 +81,6 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_ size_t alignment_size; gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, #if CONFIG_CAM_CTLR_DVP_CAM_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif @@ -89,7 +88,7 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_ ESP_RETURN_ON_ERROR(esp_cache_get_alignment(DVP_GDMA_DESC_ALLOC_CAPS, &alignment_size), TAG, "failed to get cache alignment"); - ESP_RETURN_ON_ERROR(DVP_GDMA_NEW_CHANNEL(&rx_alloc_config, &dma->dma_chan), TAG, "new channel failed"); + ESP_RETURN_ON_ERROR(DVP_GDMA_NEW_CHANNEL(&rx_alloc_config, NULL, &dma->dma_chan), TAG, "new channel failed"); ESP_GOTO_ON_ERROR(gdma_connect(dma->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_CAM, 0)), fail0, TAG, "connect failed"); diff --git a/components/esp_driver_i2s/i2s_common.c b/components/esp_driver_i2s/i2s_common.c index 287668a7f2..c277fed758 100644 --- a/components/esp_driver_i2s/i2s_common.c +++ b/components/esp_driver_i2s/i2s_common.c @@ -821,17 +821,15 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag) #endif }; if (handle->dir == I2S_DIR_TX) { - dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX; /* Register a new GDMA tx channel */ - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register tx dma channel error"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &handle->dma.dma_chan, NULL), TAG, "Register tx dma channel error"); ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect tx dma channel error"); gdma_tx_event_callbacks_t cb = {.on_trans_eof = i2s_dma_tx_callback}; /* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */ ESP_GOTO_ON_ERROR(gdma_register_tx_event_callbacks(handle->dma.dma_chan, &cb, handle), err2, TAG, "Register tx callback failed"); } else { - dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX; /* Register a new GDMA rx channel */ - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register rx dma channel error"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, NULL, &handle->dma.dma_chan), TAG, "Register rx dma channel error"); ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect rx dma channel error"); gdma_rx_event_callbacks_t cb = {.on_recv_eof = i2s_dma_rx_callback}; /* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */ diff --git a/components/esp_driver_i3c/i3c_master.c b/components/esp_driver_i3c/i3c_master.c index dd2c713037..71e1424218 100644 --- a/components/esp_driver_i3c/i3c_master.c +++ b/components/esp_driver_i3c/i3c_master.c @@ -293,8 +293,7 @@ static esp_err_t i3c_master_init_dma(i3c_master_bus_t *i3c_master_handle, const .flags.isr_cache_safe = true, #endif }; - dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX; - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &i3c_master_handle->dma_tx_chan), TAG, "DMA tx channel alloc failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &i3c_master_handle->dma_tx_chan, NULL), TAG, "DMA tx channel alloc failed"); gdma_connect(i3c_master_handle->dma_tx_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I3C, 0)); gdma_transfer_config_t transfer_cfg = { @@ -316,8 +315,7 @@ static esp_err_t i3c_master_init_dma(i3c_master_bus_t *i3c_master_handle, const ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &i3c_master_handle->tx_dma_link), TAG, "DMA tx link list alloc failed"); // Initialize DMA RX channel - dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX; - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, &i3c_master_handle->dma_rx_chan), TAG, "DMA rx channel alloc failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_cfg, NULL, &i3c_master_handle->dma_rx_chan), TAG, "DMA rx channel alloc failed"); gdma_connect(i3c_master_handle->dma_rx_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_I3C, 0)); ESP_RETURN_ON_ERROR(gdma_config_transfer(i3c_master_handle->dma_rx_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed"); diff --git a/components/esp_driver_parlio/src/parlio_rx.c b/components/esp_driver_parlio/src/parlio_rx.c index 8431768d7b..abe7c9f89d 100644 --- a/components/esp_driver_parlio/src/parlio_rx.c +++ b/components/esp_driver_parlio/src/parlio_rx.c @@ -444,12 +444,11 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t { /* Allocate and connect the GDMA channel */ gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, #if CONFIG_PARLIO_RX_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed"); + ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, NULL, &rx_unit->dma_chan), TAG, "allocate RX DMA channel failed"); gdma_connect(rx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0)); /* Set GDMA strategy */ diff --git a/components/esp_driver_parlio/src/parlio_tx.c b/components/esp_driver_parlio/src/parlio_tx.c index 342ab31daa..1cdd793415 100644 --- a/components/esp_driver_parlio/src/parlio_tx.c +++ b/components/esp_driver_parlio/src/parlio_tx.c @@ -138,12 +138,11 @@ static esp_err_t parlio_tx_unit_configure_gpio(parlio_tx_unit_t *tx_unit, const static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit, const parlio_tx_unit_config_t *config) { gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, #if CONFIG_PARLIO_TX_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &tx_unit->dma_chan), TAG, "allocate TX DMA channel failed"); + ESP_RETURN_ON_ERROR(PARLIO_GDMA_NEW_CHANNEL(&dma_chan_config, &tx_unit->dma_chan, NULL), TAG, "allocate TX DMA channel failed"); gdma_connect(tx_unit->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_PARLIO, 0)); gdma_strategy_config_t gdma_strategy_conf = { .auto_update_desc = false, // for loop transmission, we have no chance to change the owner diff --git a/components/esp_driver_rmt/src/rmt_rx.c b/components/esp_driver_rmt/src/rmt_rx.c index 808889087b..8bc8142f89 100644 --- a/components/esp_driver_rmt/src/rmt_rx.c +++ b/components/esp_driver_rmt/src/rmt_rx.c @@ -43,12 +43,11 @@ static inline void rmt_rx_mount_dma_buffer(rmt_rx_channel_t *rx_chan, const void static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx_channel_config_t *config) { gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, #if CONFIG_RMT_RX_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, NULL, &rx_channel->base.dma_chan), TAG, "allocate RX DMA channel failed"); gdma_transfer_config_t transfer_cfg = { .access_ext_mem = true, // support receive buffer to PSRAM .max_data_burst_size = 32, diff --git a/components/esp_driver_rmt/src/rmt_tx.c b/components/esp_driver_rmt/src/rmt_tx.c index cae0b2a07f..660bb12655 100644 --- a/components/esp_driver_rmt/src/rmt_tx.c +++ b/components/esp_driver_rmt/src/rmt_tx.c @@ -32,12 +32,11 @@ static bool rmt_dma_tx_eof_cb(gdma_channel_handle_t dma_chan, gdma_event_data_t static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx_channel_config_t *config) { gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, #if CONFIG_RMT_TX_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan), TAG, "allocate TX DMA channel failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&dma_chan_config, &tx_channel->base.dma_chan, NULL), TAG, "allocate TX DMA channel failed"); gdma_strategy_config_t gdma_strategy_conf = { .auto_update_desc = true, .owner_check = true, diff --git a/components/esp_driver_spi/src/gpspi/spi_common.c b/components/esp_driver_spi/src/gpspi/spi_common.c index 8f60793e30..bb9665967d 100644 --- a/components/esp_driver_spi/src/gpspi/spi_common.c +++ b/components/esp_driver_spi/src/gpspi/spi_common.c @@ -265,23 +265,14 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch esp_err_t ret = ESP_OK; if (dma_chan == SPI_DMA_CH_AUTO) { - gdma_channel_alloc_config_t tx_alloc_config = { - .flags.reserve_sibling = 1, -#if CONFIG_SPI_MASTER_ISR_IN_IRAM - .flags.isr_cache_safe = true, -#endif - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; - ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&tx_alloc_config, &dma_ctx->tx_dma_chan), SPI_TAG, "alloc gdma tx failed"); - - gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = dma_ctx->tx_dma_chan, + gdma_channel_alloc_config_t alloc_config = { #if CONFIG_SPI_MASTER_ISR_IN_IRAM .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&rx_alloc_config, &dma_ctx->rx_dma_chan), SPI_TAG, "alloc gdma rx failed"); + // Allocate TX and RX channels separately (they don't need to be in the same pair) + ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&alloc_config, &dma_ctx->tx_dma_chan, NULL), SPI_TAG, "alloc gdma tx channel failed"); + ESP_RETURN_ON_ERROR(SPI_GDMA_NEW_CHANNEL(&alloc_config, NULL, &dma_ctx->rx_dma_chan), SPI_TAG, "alloc gdma rx channel failed"); if (host_id == SPI2_HOST) { gdma_connect(dma_ctx->tx_dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SPI, 2)); diff --git a/components/esp_driver_uart/src/uhci.c b/components/esp_driver_uart/src/uhci.c index 0c551c2771..52e8179043 100644 --- a/components/esp_driver_uart/src/uhci.c +++ b/components/esp_driver_uart/src/uhci.c @@ -173,12 +173,11 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const { // Initialize DMA TX channel gdma_channel_alloc_config_t tx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, #if CONFIG_UHCI_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&tx_alloc_config, &uhci_ctrl->tx_dir.dma_chan), TAG, "DMA tx channel alloc failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&tx_alloc_config, &uhci_ctrl->tx_dir.dma_chan, NULL), TAG, "DMA tx channel alloc failed"); gdma_connect(uhci_ctrl->tx_dir.dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); gdma_transfer_config_t transfer_cfg = { @@ -207,12 +206,11 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const // Initialize DMA RX channel gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, #if CONFIG_UHCI_ISR_CACHE_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&rx_alloc_config, &uhci_ctrl->rx_dir.dma_chan), TAG, "DMA rx channel alloc failed"); + ESP_RETURN_ON_ERROR(gdma_new_ahb_channel(&rx_alloc_config, NULL, &uhci_ctrl->rx_dir.dma_chan), TAG, "DMA rx channel alloc failed"); gdma_connect(uhci_ctrl->rx_dir.dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); ESP_RETURN_ON_ERROR(gdma_config_transfer(uhci_ctrl->rx_dir.dma_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed"); diff --git a/components/esp_hal_dma/esp32c2/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32c2/include/hal/gdma_ll.h index 54618b4328..5545c4ac79 100644 --- a/components/esp_hal_dma/esp32c2/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32c2/include/hal/gdma_ll.h @@ -52,6 +52,8 @@ extern "C" { #define GDMA_LL_AHB_PAIRS_PER_GROUP 1 // Number of GDMA pairs in each AHB group #define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x01 // pair 0 is M2M capable + #define GDMA_LL_AHB_DESC_ALIGNMENT 4 #define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 diff --git a/components/esp_hal_dma/esp32c3/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32c3/include/hal/gdma_ll.h index 9b719b0e6f..b077aceb12 100644 --- a/components/esp_hal_dma/esp32c3/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32c3/include/hal/gdma_ll.h @@ -52,6 +52,8 @@ extern "C" { #define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group #define GDMA_LL_AHB_TX_RX_SHARE_INTERRUPT 1 // TX and RX channel in the same pair will share the same interrupt source number +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable + #define GDMA_LL_AHB_DESC_ALIGNMENT 4 #define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 diff --git a/components/esp_hal_dma/esp32c5/include/hal/ahb_dma_ll.h b/components/esp_hal_dma/esp32c5/include/hal/ahb_dma_ll.h index 54675abfd2..0923ce2afc 100644 --- a/components/esp_hal_dma/esp32c5/include/hal/ahb_dma_ll.h +++ b/components/esp_hal_dma/esp32c5/include/hal/ahb_dma_ll.h @@ -49,6 +49,8 @@ extern "C" { #define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups #define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable + #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ diff --git a/components/esp_hal_dma/esp32c6/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32c6/include/hal/gdma_ll.h index ff3eb8ce7b..15de42f60d 100644 --- a/components/esp_hal_dma/esp32c6/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32c6/include/hal/gdma_ll.h @@ -52,6 +52,8 @@ extern "C" { #define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups #define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable + #define GDMA_LL_AHB_DESC_ALIGNMENT 4 #define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 diff --git a/components/esp_hal_dma/esp32c61/include/hal/ahb_dma_ll.h b/components/esp_hal_dma/esp32c61/include/hal/ahb_dma_ll.h index 34344fa755..85566d0d19 100644 --- a/components/esp_hal_dma/esp32c61/include/hal/ahb_dma_ll.h +++ b/components/esp_hal_dma/esp32c61/include/hal/ahb_dma_ll.h @@ -49,6 +49,8 @@ extern "C" { #define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups #define GDMA_LL_AHB_PAIRS_PER_GROUP 2 // Number of GDMA pairs in each AHB group +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x03 // pair 0,1 are M2M capable + #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[1][2][GDMA_ETM_EVENT_MAX]){{{ \ [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ diff --git a/components/esp_hal_dma/esp32h2/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32h2/include/hal/gdma_ll.h index ff3eb8ce7b..15de42f60d 100644 --- a/components/esp_hal_dma/esp32h2/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32h2/include/hal/gdma_ll.h @@ -52,6 +52,8 @@ extern "C" { #define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups #define GDMA_LL_AHB_PAIRS_PER_GROUP 3 // Number of GDMA pairs in each AHB group +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable + #define GDMA_LL_AHB_DESC_ALIGNMENT 4 #define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 diff --git a/components/esp_hal_dma/esp32h21/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32h21/include/hal/gdma_ll.h index 01903c5ac5..620e0417fc 100644 --- a/components/esp_hal_dma/esp32h21/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32h21/include/hal/gdma_ll.h @@ -55,6 +55,8 @@ extern "C" { #define GDMA_LL_AHB_DESC_ALIGNMENT 4 #define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable + #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[1][3][GDMA_ETM_EVENT_MAX]){{{ \ [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ diff --git a/components/esp_hal_dma/esp32h4/include/hal/ahb_dma_ll.h b/components/esp_hal_dma/esp32h4/include/hal/ahb_dma_ll.h index facd2dab5a..addac62de0 100644 --- a/components/esp_hal_dma/esp32h4/include/hal/ahb_dma_ll.h +++ b/components/esp_hal_dma/esp32h4/include/hal/ahb_dma_ll.h @@ -48,6 +48,8 @@ extern "C" { #define GDMA_LL_AHB_NUM_GROUPS 1 // Number of AHB GDMA groups #define GDMA_LL_AHB_PAIRS_PER_GROUP 5 // Number of GDMA pairs in each AHB group +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x1F // pair 0,1,2,3,4 are M2M capable + #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[1][5][GDMA_ETM_EVENT_MAX]){{{ \ [GDMA_ETM_EVENT_EOF] = GDMA_EVT_OUT_EOF_CH0, \ diff --git a/components/esp_hal_dma/esp32p4/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32p4/include/hal/gdma_ll.h index ef67237bd8..db94709822 100644 --- a/components/esp_hal_dma/esp32p4/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32p4/include/hal/gdma_ll.h @@ -63,6 +63,14 @@ #define GDMA_LL_AHB_BURST_SIZE_ADJUSTABLE 1 // AHB GDMA supports adjustable burst size #endif +#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300 +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x06 // only pair 1,2 are M2M capable +#else +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable +#endif + +#define GDMA_LL_AXI_M2M_CAPABLE_PAIR_MASK 0x07 // pair 0,1,2 are M2M capable + #define GDMA_LL_TX_ETM_EVENT_TABLE(group, chan, event) \ (uint32_t[2][GDMA_ETM_EVENT_MAX]){ \ { \ diff --git a/components/esp_hal_dma/esp32s3/include/hal/gdma_ll.h b/components/esp_hal_dma/esp32s3/include/hal/gdma_ll.h index c7e7506f39..c8d0324a25 100644 --- a/components/esp_hal_dma/esp32s3/include/hal/gdma_ll.h +++ b/components/esp_hal_dma/esp32s3/include/hal/gdma_ll.h @@ -73,6 +73,8 @@ extern "C" { #define GDMA_LL_AHB_RX_BURST_NEEDS_ALIGNMENT 1 #define GDMA_LL_MAX_BURST_SIZE_PSRAM 64 // PSRAM controller doesn't support burst access with size > 64 bytes +#define GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK 0x1F // pair 0,1,2,3,4 are M2M capable + ///////////////////////////////////// Common ///////////////////////////////////////// /** diff --git a/components/esp_hw_support/dma/async_memcpy_gdma.c b/components/esp_hw_support/dma/async_memcpy_gdma.c index 00dc747ebe..eff9c832dc 100644 --- a/components/esp_hw_support/dma/async_memcpy_gdma.c +++ b/components/esp_hw_support/dma/async_memcpy_gdma.c @@ -103,7 +103,7 @@ static esp_err_t mcp_gdma_destroy(async_memcpy_gdma_context_t *mcp_gdma) } static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_config_t *config, async_memcpy_handle_t *mcp, - esp_err_t (*new_channel_func)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *), + esp_err_t (*new_channel_func)(const gdma_channel_alloc_config_t *, gdma_channel_handle_t *, gdma_channel_handle_t *), int gdma_bus_id) { esp_err_t ret = ESP_OK; @@ -118,17 +118,9 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi mcp_gdma->transaction_pool = heap_caps_calloc(trans_queue_len, sizeof(async_memcpy_transaction_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); ESP_GOTO_ON_FALSE(mcp_gdma->transaction_pool, ESP_ERR_NO_MEM, err, TAG, "no mem for transaction pool"); - // create TX channel and RX channel, they should reside in the same DMA pair - gdma_channel_alloc_config_t tx_alloc_config = { - .flags.reserve_sibling = 1, - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; - ESP_GOTO_ON_ERROR(new_channel_func(&tx_alloc_config, &mcp_gdma->tx_channel), err, TAG, "failed to alloc GDMA TX channel"); - gdma_channel_alloc_config_t rx_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = mcp_gdma->tx_channel, - }; - ESP_GOTO_ON_ERROR(new_channel_func(&rx_alloc_config, &mcp_gdma->rx_channel), err, TAG, "failed to alloc GDMA RX channel"); + // create TX and RX channels in the same pair with a single call + gdma_channel_alloc_config_t channel_config = {0}; + ESP_GOTO_ON_ERROR(new_channel_func(&channel_config, &mcp_gdma->tx_channel, &mcp_gdma->rx_channel), err, TAG, "failed to alloc GDMA channels"); // get a free DMA trigger ID for memory copy gdma_trigger_t m2m_trigger = GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_M2M, 0); @@ -147,7 +139,7 @@ static esp_err_t esp_async_memcpy_install_gdma_template(const async_memcpy_confi gdma_apply_strategy(mcp_gdma->rx_channel, &strategy_cfg); #if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION - if(config->weight){ + if (config->weight) { ESP_GOTO_ON_ERROR(gdma_set_weight(mcp_gdma->rx_channel, config->weight), err, TAG, "Set GDMA rx channel weight failed"); ESP_GOTO_ON_ERROR(gdma_set_weight(mcp_gdma->tx_channel, config->weight), err, TAG, "Set GDMA tx channel weight failed"); } diff --git a/components/esp_hw_support/dma/gdma.c b/components/esp_hw_support/dma/gdma.c index b2648aaefa..33f2335549 100644 --- a/components/esp_hw_support/dma/gdma.c +++ b/components/esp_hw_support/dma/gdma.c @@ -35,15 +35,14 @@ #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 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; -static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config)); -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 gdma_group_t *gdma_try_alloc_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config)); +static gdma_pair_t *gdma_try_alloc_pair_handle(gdma_group_t *group, int pair_id); +static void gdma_try_free_group_handle(gdma_group_t *group); +static void gdma_try_free_pair_handle(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); @@ -59,29 +58,28 @@ typedef struct { int start_group_id; int end_group_id; int pairs_per_group; + uint32_t m2m_capable_mask; void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config); } gdma_channel_search_info_t; ESP_LOG_ATTR_TAG(TAG, "gdma"); -static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *search_info, const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan) +static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *search_info, const gdma_channel_alloc_config_t *config, + gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan) { esp_err_t ret = ESP_OK; gdma_tx_channel_t *alloc_tx_channel = NULL; gdma_rx_channel_t *alloc_rx_channel = NULL; int search_code = 0; + bool found_pair = false; gdma_pair_t *pair = NULL; gdma_group_t *group = NULL; // 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 && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + ESP_RETURN_ON_FALSE(ret_tx_chan || ret_rx_chan, ESP_ERR_INVALID_ARG, TAG, "both channel pointers are NULL"); 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" @@ -90,71 +88,64 @@ static esp_err_t do_allocate_gdma_channel(const gdma_channel_search_info_t *sear 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 - } - if (config->direction == GDMA_CHANNEL_DIRECTION_TX) { - search_code |= SEARCH_REQUEST_TX_CHANNEL; // search TX only + // Determine search code based on which channels are requested + if (ret_tx_chan) { + search_code |= SEARCH_REQUEST_TX_CHANNEL; alloc_tx_channel = heap_caps_calloc(1, sizeof(gdma_tx_channel_t), GDMA_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(alloc_tx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for gdma tx channel"); - } else if (config->direction == GDMA_CHANNEL_DIRECTION_RX) { - search_code |= SEARCH_REQUEST_RX_CHANNEL; // search RX only + } + if (ret_rx_chan) { + search_code |= SEARCH_REQUEST_RX_CHANNEL; alloc_rx_channel = heap_caps_calloc(1, sizeof(gdma_rx_channel_t), GDMA_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(alloc_rx_channel, ESP_ERR_NO_MEM, err, TAG, "no mem for gdma rx channel"); } - if (config->sibling_chan) { - pair = config->sibling_chan->pair; - 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); - // skip the search path below if user has specify a sibling channel - goto search_done; - } + // If both channels are requested, they must be in the same pair + // The search_code will have both bits set, ensuring we find a pair with both channels available int start_group_id = search_info->start_group_id; int end_group_id = search_info->end_group_id; int pairs_per_group = search_info->pairs_per_group; - for (int i = start_group_id; i < end_group_id && search_code; i++) { // loop to search group - group = gdma_acquire_group_handle(i, search_info->hal_init); + // loop to search group + for (int i = start_group_id; i < end_group_id && !found_pair; i++) { + group = gdma_try_alloc_group_handle(i, search_info->hal_init); ESP_GOTO_ON_FALSE(group, ESP_ERR_NO_MEM, err, TAG, "no mem for group(%d)", i); group->bus_id = search_info->bus_id; - for (int j = 0; j < pairs_per_group && search_code; j++) { // loop to search pair - pair = gdma_acquire_pair_handle(group, j); + + // loop to search pair + for (int j = 0; j < pairs_per_group && !found_pair; j++) { + // Check M2M capability BEFORE acquiring pair to avoid unnecessary allocation + if (ret_tx_chan && ret_rx_chan) { // Both channels requested (implicit M2M usage) + if (!((1 << j) & search_info->m2m_capable_mask)) { + ESP_LOGV(TAG, "pair(%d,%d) not M2M capable, skip", i, j); + continue; // Skip pairs that don't support M2M + } + } + + pair = gdma_try_alloc_pair_handle(group, j); ESP_GOTO_ON_FALSE(pair, ESP_ERR_NO_MEM, err, TAG, "no mem for pair(%d,%d)", i, j); + + // Check if channels are available esp_os_enter_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 + found_pair = true; } esp_os_exit_critical(&pair->spinlock); - // found a pair that satisfies the search condition - if (search_code == 0) { - // 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; - } } // loop used to search pair - // Only release group if we didn't find a suitable pair in this group - if (search_code != 0) { - gdma_release_group_handle(group); + + // If no suitable pair found in this group, release the group before trying next group + if (!found_pair) { + gdma_try_free_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 + ESP_GOTO_ON_FALSE(found_pair, ESP_ERR_NOT_FOUND, err, TAG, "no free gdma channel, search code=%d", search_code); + + // Note: No lock protection is needed here because pair->occupy_code was already set atomically + // in the critical section above. Once the occupy_code bit is set, this is the only thread that + // can write to pair->tx_chan, so there's no race condition. if (alloc_tx_channel) { pair->tx_chan = alloc_tx_channel; alloc_tx_channel->base.pair = pair; @@ -162,10 +153,15 @@ search_done: alloc_tx_channel->base.periph_id = GDMA_INVALID_PERIPH_TRIG; alloc_tx_channel->base.flags.isr_cache_safe = config->flags.isr_cache_safe; alloc_tx_channel->base.del = gdma_del_tx_channel; // set channel deletion function - *ret_chan = &alloc_tx_channel->base; // return the installed channel + alloc_tx_channel->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + *ret_tx_chan = &alloc_tx_channel->base; // return the installed channel +#if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION + // set 1 as default weight, can be overwritten by user + gdma_set_weight(&alloc_tx_channel->base, 1); +#endif } - // register RX channel + // Note: Same as TX channel - no lock needed due to occupy_code protection if (alloc_rx_channel) { pair->rx_chan = alloc_rx_channel; alloc_rx_channel->base.pair = pair; @@ -173,40 +169,66 @@ search_done: alloc_rx_channel->base.periph_id = GDMA_INVALID_PERIPH_TRIG; alloc_rx_channel->base.flags.isr_cache_safe = config->flags.isr_cache_safe; alloc_rx_channel->base.del = gdma_del_rx_channel; // set channel deletion function - *ret_chan = &alloc_rx_channel->base; // return the installed channel - } + alloc_rx_channel->base.spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; + *ret_rx_chan = &alloc_rx_channel->base; // return the installed channel #if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION - // set 1 as default weight, can be overwritten by user - gdma_set_weight(*ret_chan, 1); + // set 1 as default weight, can be overwritten by user + gdma_set_weight(&alloc_rx_channel->base, 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); + // Each channel holds a reference to the sleep retention, so we need to acquire it for each channel + if (alloc_tx_channel) { + gdma_acquire_sleep_retention(pair); + } + if (alloc_rx_channel) { + 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); + ESP_LOGV(TAG, "new channel(s) in (%d,%d)%s%s", group->group_id, pair->pair_id, + alloc_tx_channel ? " tx" : "", alloc_rx_channel ? " rx" : ""); return ESP_OK; err: + if (pair) { + // If we successfully set occupy_code and/or channel pointers but failed later, + // we need to restore the pair state before releasing it + if (found_pair) { + esp_os_enter_critical(&pair->spinlock); + // Clear the occupy_code bits we set + pair->occupy_code &= ~search_code; + // NULL out any channel pointers we may have set to avoid dangling pointers + // The channel memory will be freed below + if (alloc_tx_channel && pair->tx_chan == alloc_tx_channel) { + pair->tx_chan = NULL; + } + if (alloc_rx_channel && pair->rx_chan == alloc_rx_channel) { + pair->rx_chan = NULL; + } + esp_os_exit_critical(&pair->spinlock); + } + // If we successfully acquired a pair but failed later, release it + // The pair release will also check and free the group if all pairs are gone + gdma_try_free_pair_handle(pair); + } else if (group) { + // If we acquired a group but failed to get a pair, try to release the group + // This handles the case where we created an empty group that never got any pairs + // Note: gdma_try_free_group_handle is state-based and idempotent, so calling it + // even when pair was released is safe (though the second call would be redundant) + gdma_try_free_group_handle(group); + } + // Free the channel structures after clearing the pair pointers if (alloc_tx_channel) { free(alloc_tx_channel); } if (alloc_rx_channel) { free(alloc_rx_channel); } - // coverity[dead_error_condition] - defensive check for code maintainability - if (pair) { - gdma_release_pair_handle(pair); - // 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 @@ -214,36 +236,40 @@ err: } #if SOC_HAS(AHB_GDMA) -esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan) +esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan) { gdma_channel_search_info_t search_info = { .bus_id = SOC_GDMA_BUS_AHB, .start_group_id = GDMA_LL_AHB_GROUP_START_ID, .end_group_id = GDMA_LL_AHB_GROUP_START_ID + GDMA_LL_AHB_NUM_GROUPS, .pairs_per_group = GDMA_LL_AHB_PAIRS_PER_GROUP, + .m2m_capable_mask = GDMA_LL_AHB_M2M_CAPABLE_PAIR_MASK, .hal_init = gdma_ahb_hal_init, }; - return do_allocate_gdma_channel(&search_info, config, ret_chan); + return do_allocate_gdma_channel(&search_info, config, ret_tx_chan, ret_rx_chan); } #endif // SOC_HAS(AHB_GDMA) #if SOC_HAS(AXI_GDMA) -esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan) +esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan) { gdma_channel_search_info_t search_info = { .bus_id = SOC_GDMA_BUS_AXI, .start_group_id = GDMA_LL_AXI_GROUP_START_ID, .end_group_id = GDMA_LL_AXI_GROUP_START_ID + GDMA_LL_AXI_NUM_GROUPS, .pairs_per_group = GDMA_LL_AXI_PAIRS_PER_GROUP, + .m2m_capable_mask = GDMA_LL_AXI_M2M_CAPABLE_PAIR_MASK, .hal_init = gdma_axi_hal_init, }; - return do_allocate_gdma_channel(&search_info, config, ret_chan); + return do_allocate_gdma_channel(&search_info, config, ret_tx_chan, ret_rx_chan); } #endif // SOC_HAS(AXI_GDMA) 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"); + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -257,18 +283,17 @@ esp_err_t gdma_del_channel(gdma_channel_handle_t dma_chan) esp_err_t gdma_get_group_channel_id(gdma_channel_handle_t dma_chan, int *group_id, int *channel_id) { - esp_err_t ret = ESP_OK; - gdma_pair_t *pair = NULL; - ESP_GOTO_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); - pair = dma_chan->pair; + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } + gdma_pair_t *pair = dma_chan->pair; if (group_id != NULL) { *group_id = pair->group->group_id; } if (channel_id != NULL) { *channel_id = pair->pair_id; } -err: - return ret; + return ESP_OK; } esp_err_t gdma_connect(gdma_channel_handle_t dma_chan, gdma_trigger_t trig_periph) @@ -345,7 +370,9 @@ esp_err_t gdma_disconnect(gdma_channel_handle_t dma_chan) esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_t *mask) { - ESP_RETURN_ON_FALSE(dma_chan && mask, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan || !mask) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; uint32_t free_mask = group->hal.priv_data->m2m_free_periph_mask; @@ -361,7 +388,9 @@ esp_err_t gdma_get_free_m2m_trig_id_mask(gdma_channel_handle_t dma_chan, uint32_ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config) { - ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan || !config) { + return ESP_ERR_INVALID_ARG; + } uint32_t max_data_burst_size = config->max_data_burst_size; if (max_data_burst_size) { // burst size must be power of 2 @@ -424,7 +453,9 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, size_t *ext_mem_alignment) { - ESP_RETURN_ON_FALSE(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } if (int_mem_alignment) { *int_mem_alignment = dma_chan->int_mem_alignment; } @@ -436,7 +467,9 @@ esp_err_t gdma_get_alignment_constraints(gdma_channel_handle_t dma_chan, size_t esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config) { - ESP_RETURN_ON_FALSE(dma_chan && config, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan || !config) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -448,7 +481,9 @@ esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strateg esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority) { - ESP_RETURN_ON_FALSE(dma_chan && priority <= GDMA_LL_CHANNEL_MAX_PRIORITY, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan || priority > GDMA_LL_CHANNEL_MAX_PRIORITY) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -461,7 +496,9 @@ esp_err_t gdma_set_priority(gdma_channel_handle_t dma_chan, uint32_t priority) #if SOC_GDMA_SUPPORT_WEIGHTED_ARBITRATION esp_err_t gdma_set_weight(gdma_channel_handle_t dma_chan, uint32_t weight) { - ESP_RETURN_ON_FALSE(dma_chan && weight <= GDMA_LL_CHANNEL_MAX_WEIGHT, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan || weight > GDMA_LL_CHANNEL_MAX_WEIGHT) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -559,8 +596,12 @@ esp_err_t gdma_register_rx_event_callbacks(gdma_channel_handle_t dma_chan, gdma_ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr) { - ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE_ISR(dma_chan->flags.start_stop_by_etm == false, ESP_ERR_INVALID_STATE, TAG, "channel is controlled by ETM"); + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } + if (dma_chan->flags.start_stop_by_etm) { + return ESP_ERR_INVALID_STATE; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -574,8 +615,12 @@ esp_err_t gdma_start(gdma_channel_handle_t dma_chan, intptr_t desc_base_addr) esp_err_t gdma_stop(gdma_channel_handle_t dma_chan) { - ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); - ESP_RETURN_ON_FALSE_ISR(dma_chan->flags.start_stop_by_etm == false, ESP_ERR_INVALID_STATE, TAG, "channel is controlled by ETM"); + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } + if (dma_chan->flags.start_stop_by_etm) { + return ESP_ERR_INVALID_STATE; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -589,7 +634,9 @@ esp_err_t gdma_stop(gdma_channel_handle_t dma_chan) esp_err_t gdma_append(gdma_channel_handle_t dma_chan) { - ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -603,7 +650,9 @@ esp_err_t gdma_append(gdma_channel_handle_t dma_chan) esp_err_t gdma_reset(gdma_channel_handle_t dma_chan) { - ESP_RETURN_ON_FALSE_ISR(dma_chan, ESP_ERR_INVALID_ARG, TAG, "invalid argument"); + if (!dma_chan) { + return ESP_ERR_INVALID_ARG; + } gdma_pair_t *pair = dma_chan->pair; gdma_group_t *group = pair->group; gdma_hal_context_t *hal = &group->hal; @@ -615,14 +664,21 @@ esp_err_t gdma_reset(gdma_channel_handle_t dma_chan) return ESP_OK; } -static void gdma_release_group_handle(gdma_group_t *group) +static void gdma_try_free_group_handle(gdma_group_t *group) { int group_id = group->group_id; bool do_deinitialize = false; esp_os_enter_critical(&s_platform.spinlock); - s_platform.group_ref_counts[group_id]--; - if (s_platform.group_ref_counts[group_id] == 0) { + // Check if all pairs are gone - if so, free the group + bool all_pairs_gone = true; + for (int i = 0; i < GDMA_LL_GET(PAIRS_PER_INST); i++) { + if (group->pairs[i] != NULL) { + all_pairs_gone = false; + break; + } + } + if (all_pairs_gone) { assert(s_platform.groups[group_id]); do_deinitialize = true; // deregister from the platform @@ -636,11 +692,11 @@ static void gdma_release_group_handle(gdma_group_t *group) if (do_deinitialize) { free(group); - ESP_LOGD(TAG, "del group %d", group_id); + ESP_LOGV(TAG, "del group %d", group_id); } } -static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config)) +static gdma_group_t *gdma_try_alloc_group_handle(int group_id, void (*hal_init)(gdma_hal_context_t *hal, const gdma_hal_config_t *config)) { bool new_group = false; gdma_group_t *group = NULL; @@ -672,12 +728,10 @@ static gdma_group_t *gdma_acquire_group_handle(int group_id, void (*hal_init)(gd } 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); + ESP_LOGV(TAG, "new group (%d) at %p", group_id, group); } else { free(pre_alloc_group); } @@ -685,29 +739,42 @@ out: return group; } -static void gdma_release_pair_handle(gdma_pair_t *pair) +static void gdma_try_free_pair_handle(gdma_pair_t *pair) { gdma_group_t *group = pair->group; int pair_id = pair->pair_id; bool do_deinitialize = false; - esp_os_enter_critical(&group->spinlock); - group->pair_ref_counts[pair_id]--; - if (group->pair_ref_counts[pair_id] == 0) { - assert(group->pairs[pair_id]); + // Use pair->spinlock to check channel pointers since that's the lock protecting them + esp_os_enter_critical(&pair->spinlock); + // Only free the pair if nothing is using or reserving it + if (pair->tx_chan == NULL && pair->rx_chan == NULL && pair->occupy_code == 0) { + // Mark for deinitialization, but need to update group->pairs under group lock do_deinitialize = true; - group->pairs[pair_id] = NULL; // deregister from pair } - esp_os_exit_critical(&group->spinlock); + esp_os_exit_critical(&pair->spinlock); + + if (do_deinitialize) { + // Now safely update the group's pair pointer under group lock + esp_os_enter_critical(&group->spinlock); + // Double-check in case another thread beat us to it + if (group->pairs[pair_id] != NULL) { + group->pairs[pair_id] = NULL; // deregister from group + } else { + // Another thread already freed this pair, abort + do_deinitialize = false; + } + esp_os_exit_critical(&group->spinlock); + } if (do_deinitialize) { free(pair); - ESP_LOGD(TAG, "del pair (%d,%d)", group->group_id, pair_id); - gdma_release_group_handle(group); + ESP_LOGV(TAG, "del pair (%d,%d)", group->group_id, pair_id); + gdma_try_free_group_handle(group); } } -static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id) +static gdma_pair_t *gdma_try_alloc_pair_handle(gdma_group_t *group, int pair_id) { bool new_pair = false; gdma_pair_t *pair = NULL; @@ -729,18 +796,11 @@ static gdma_pair_t *gdma_acquire_pair_handle(gdma_group_t *group, int pair_id) } else { pair = group->pairs[pair_id]; } - // someone acquired the pair handle means we have a new object that refer to this pair - 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 + // Log new pair creation if (new_pair) { - esp_os_enter_critical(&s_platform.spinlock); - s_platform.group_ref_counts[group->group_id]++; - esp_os_exit_critical(&s_platform.spinlock); - - ESP_LOGD(TAG, "new pair (%d,%d) at %p", group->group_id, pair_id, pair); + ESP_LOGV(TAG, "new pair (%d,%d) at %p", group->group_id, pair_id, pair); } else { free(pre_alloc_pair); } @@ -769,18 +829,18 @@ static esp_err_t gdma_del_tx_channel(gdma_channel_t *dma_channel) gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX, false); // disable all interrupt events gdma_hal_clear_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX); // clear all pending events esp_os_exit_critical(&pair->spinlock); - ESP_LOGD(TAG, "uninstall interrupt service for tx channel (%d,%d)", group_id, pair_id); + ESP_LOGV(TAG, "uninstall interrupt service for tx channel (%d,%d)", group_id, pair_id); } free(tx_chan); - ESP_LOGD(TAG, "del tx channel (%d,%d)", group_id, pair_id); + ESP_LOGV(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); + // release pair handle (will free pair if both channels are deleted) + gdma_try_free_pair_handle(pair); return ESP_OK; } @@ -804,18 +864,18 @@ static esp_err_t gdma_del_rx_channel(gdma_channel_t *dma_channel) gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX, false); // disable all interrupt events gdma_hal_clear_intr(hal, pair->pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX); // clear all pending events esp_os_exit_critical(&pair->spinlock); - ESP_LOGD(TAG, "uninstall interrupt service for rx channel (%d,%d)", group_id, pair_id); + ESP_LOGV(TAG, "uninstall interrupt service for rx channel (%d,%d)", group_id, pair_id); } free(rx_chan); - ESP_LOGD(TAG, "del rx channel (%d,%d)", group_id, pair_id); + ESP_LOGV(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); + // release pair handle (will free pair if both channels are deleted) + gdma_try_free_pair_handle(pair); return ESP_OK; } @@ -926,7 +986,7 @@ static esp_err_t gdma_install_rx_interrupt(gdma_rx_channel_t *rx_chan) gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX, false); // disable all interrupt events gdma_hal_clear_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_RX, UINT32_MAX); // clear all pending events esp_os_exit_critical(&pair->spinlock); - ESP_LOGD(TAG, "install interrupt service for rx channel (%d,%d)", group->group_id, pair_id); + ESP_LOGV(TAG, "install interrupt service for rx channel (%d,%d)", group->group_id, pair_id); err: return ret; @@ -958,7 +1018,7 @@ static esp_err_t gdma_install_tx_interrupt(gdma_tx_channel_t *tx_chan) gdma_hal_enable_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX, false); // disable all interrupt events gdma_hal_clear_intr(hal, pair_id, GDMA_CHANNEL_DIRECTION_TX, UINT32_MAX); // clear all pending events esp_os_exit_critical(&pair->spinlock); - ESP_LOGD(TAG, "install interrupt service for tx channel (%d,%d)", group->group_id, pair_id); + ESP_LOGV(TAG, "install interrupt service for tx channel (%d,%d)", group->group_id, pair_id); err: return ret; diff --git a/components/esp_hw_support/dma/gdma_priv.h b/components/esp_hw_support/dma/gdma_priv.h index a16305f58f..ecaf09a178 100644 --- a/components/esp_hw_support/dma/gdma_priv.h +++ b/components/esp_hw_support/dma/gdma_priv.h @@ -61,7 +61,6 @@ typedef struct gdma_group_t { uint32_t tx_periph_in_use_mask; // each bit indicates which peripheral (TX direction) has been occupied uint32_t rx_periph_in_use_mask; // each bit indicates which peripheral (RX direction) has been occupied gdma_pair_t *pairs[GDMA_LL_GET(PAIRS_PER_INST)]; // handles of GDMA pairs - int pair_ref_counts[GDMA_LL_GET(PAIRS_PER_INST)]; // reference count used to protect pair install/uninstall } gdma_group_t; struct gdma_pair_t { 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 a2bc904859..744e228054 100644 --- a/components/esp_hw_support/dma/include/esp_private/gdma.h +++ b/components/esp_hw_support/dma/include/esp_private/gdma.h @@ -26,10 +26,7 @@ typedef struct gdma_channel_t *gdma_channel_handle_t; * */ typedef struct { - gdma_channel_handle_t sibling_chan; /*!< DMA sibling channel handle (NULL means having sibling is not necessary) */ - gdma_channel_direction_t direction; /*!< DMA channel direction */ struct { - int reserve_sibling: 1; /*!< If set, DMA channel allocator would prefer to allocate new channel in a new pair, and reserve sibling channel for future use */ int isr_cache_safe: 1; /*!< If set, DMA channel allocator would allocate interrupt in cache-safe region, and ISR is serviceable when cache is disabled */ } flags; } gdma_channel_alloc_config_t; @@ -110,34 +107,44 @@ typedef struct { } gdma_strategy_config_t; /** - * @brief Create AHB-GDMA channel + * @brief Create AHB-GDMA channel(s) * @note This API won't install interrupt service for the allocated channel. * If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`. + * @note To allocate both TX and RX channels in a pair, pass non-NULL pointers for both ret_tx_chan and ret_rx_chan. + * To allocate only one direction, pass NULL for the unwanted direction. + * @note Allocation is atomic: if any channel fails to allocate, all partially allocated resources are cleaned up automatically. + * Either all requested channels are successfully allocated, or the function fails with no channels allocated. * * @param[in] config Pointer to a collection of configurations for allocating GDMA channel - * @param[out] ret_chan Returned channel handle + * @param[out] ret_tx_chan Returned TX channel handle. Pass NULL if TX channel is not needed. Must not be NULL if ret_rx_chan is also NULL. + * @param[out] ret_rx_chan Returned RX channel handle. Pass NULL if RX channel is not needed. Must not be NULL if ret_tx_chan is also NULL. * @return - * - ESP_OK: Create DMA channel successfully - * - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument + * - ESP_OK: Create DMA channel(s) successfully + * - ESP_ERR_INVALID_ARG: Create DMA channel failed because both ret_tx_chan and ret_rx_chan are NULL * - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory * - ESP_FAIL: Create DMA channel failed because of other error */ -esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan); +esp_err_t gdma_new_ahb_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan); /** - * @brief Create AXI-GDMA channel + * @brief Create AXI-GDMA channel(s) * @note This API won't install interrupt service for the allocated channel. * If interrupt service is needed, user has to register GDMA event callback by `gdma_register_tx_event_callbacks` or `gdma_register_rx_event_callbacks`. + * @note To allocate both TX and RX channels in a pair, pass non-NULL pointers for both ret_tx_chan and ret_rx_chan. + * To allocate only one direction, pass NULL for the unwanted direction. + * @note Allocation is atomic: if any channel fails to allocate, all partially allocated resources are cleaned up automatically. + * Either all requested channels are successfully allocated, or the function fails with no channels allocated. * * @param[in] config Pointer to a collection of configurations for allocating GDMA channel - * @param[out] ret_chan Returned channel handle + * @param[out] ret_tx_chan Returned TX channel handle. Pass NULL if TX channel is not needed. Must not be NULL if ret_rx_chan is also NULL. + * @param[out] ret_rx_chan Returned RX channel handle. Pass NULL if RX channel is not needed. Must not be NULL if ret_tx_chan is also NULL. * @return - * - ESP_OK: Create DMA channel successfully - * - ESP_ERR_INVALID_ARG: Create DMA channel failed because of invalid argument + * - ESP_OK: Create DMA channel(s) successfully + * - ESP_ERR_INVALID_ARG: Create DMA channel failed because both ret_tx_chan and ret_rx_chan are NULL * - ESP_ERR_NO_MEM: Create DMA channel failed because out of memory * - ESP_FAIL: Create DMA channel failed because of other error */ -esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_chan); +esp_err_t gdma_new_axi_channel(const gdma_channel_alloc_config_t *config, gdma_channel_handle_t *ret_tx_chan, gdma_channel_handle_t *ret_rx_chan); /** * @brief Connect GDMA channel to trigger peripheral diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma.c b/components/esp_hw_support/test_apps/dma/main/test_gdma.c index 256192ca51..65750eb45f 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma.c @@ -32,14 +32,13 @@ TEST_CASE("GDMA channel allocation", "[GDMA]") gdma_channel_alloc_config_t channel_config = {}; gdma_channel_handle_t tx_channels[GDMA_LL_GET(PAIRS_PER_INST)] = {}; gdma_channel_handle_t rx_channels[GDMA_LL_GET(PAIRS_PER_INST)] = {}; - channel_config.direction = GDMA_CHANNEL_DIRECTION_TX; #if SOC_HAS(AHB_GDMA) // install TX channels for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) { - TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[i])); + TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[i], NULL)); }; - TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, &tx_channels[0])); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, &tx_channels[0], NULL)); // Free interrupts before installing RX interrupts to ensure enough free interrupts for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) { @@ -47,11 +46,10 @@ TEST_CASE("GDMA channel allocation", "[GDMA]") } // install RX channels - channel_config.direction = GDMA_CHANNEL_DIRECTION_RX; for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) { - TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &rx_channels[i])); + TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, NULL, &rx_channels[i])); } - TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, &rx_channels[0])); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_ahb_channel(&channel_config, NULL, &rx_channels[0])); for (int i = 0; i < GDMA_LL_AHB_PAIRS_PER_GROUP; i++) { TEST_ESP_OK(gdma_del_channel(rx_channels[i])); @@ -61,20 +59,12 @@ TEST_CASE("GDMA channel allocation", "[GDMA]") // install single and paired TX/RX channels #if GDMA_LL_AHB_PAIRS_PER_GROUP >= 2 // single tx channel - channel_config.direction = GDMA_CHANNEL_DIRECTION_TX; - TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[0])); + TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[0], NULL)); - // create tx channel and reserve sibling - channel_config.direction = GDMA_CHANNEL_DIRECTION_TX; - channel_config.flags.reserve_sibling = 1; - TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[1])); - // create rx channel and specify sibling channel - channel_config.flags.reserve_sibling = 0; - channel_config.sibling_chan = tx_channels[1]; // specify sibling channel - channel_config.direction = GDMA_CHANNEL_DIRECTION_RX; - TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &rx_channels[1])); - channel_config.sibling_chan = NULL; - TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &rx_channels[0])); + // create tx and rx channel pair + TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, &tx_channels[1], &rx_channels[1])); + // create single rx channel + TEST_ESP_OK(gdma_new_ahb_channel(&channel_config, NULL, &rx_channels[0])); gdma_trigger_t fake_ahb_trigger1 = { .periph = 1, @@ -104,11 +94,10 @@ TEST_CASE("GDMA channel allocation", "[GDMA]") #if SOC_HAS(AXI_GDMA) // install TX channels - channel_config.direction = GDMA_CHANNEL_DIRECTION_TX; for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) { - TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[i])); + TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[i], NULL)); }; - TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, &tx_channels[0])); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, &tx_channels[0], NULL)); // Free interrupts before installing RX interrupts to ensure enough free interrupts for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) { @@ -116,11 +105,10 @@ TEST_CASE("GDMA channel allocation", "[GDMA]") } // install RX channels - channel_config.direction = GDMA_CHANNEL_DIRECTION_RX; for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) { - TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &rx_channels[i])); + TEST_ESP_OK(gdma_new_axi_channel(&channel_config, NULL, &rx_channels[i])); } - TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, &rx_channels[0])); + TEST_ASSERT_EQUAL(ESP_ERR_NOT_FOUND, gdma_new_axi_channel(&channel_config, NULL, &rx_channels[0])); for (int i = 0; i < GDMA_LL_AXI_PAIRS_PER_GROUP; i++) { TEST_ESP_OK(gdma_del_channel(rx_channels[i])); @@ -130,20 +118,12 @@ TEST_CASE("GDMA channel allocation", "[GDMA]") // install single and paired TX/RX channels #if GDMA_LL_AXI_PAIRS_PER_GROUP >= 2 // single tx channel - channel_config.direction = GDMA_CHANNEL_DIRECTION_TX; - TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[0])); + TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[0], NULL)); - // create tx channel and reserve sibling - channel_config.direction = GDMA_CHANNEL_DIRECTION_TX; - channel_config.flags.reserve_sibling = 1; - TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[1])); - // create rx channel and specify sibling channel - channel_config.flags.reserve_sibling = 0; - channel_config.sibling_chan = tx_channels[1]; // specify sibling channel - channel_config.direction = GDMA_CHANNEL_DIRECTION_RX; - TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &rx_channels[1])); - channel_config.sibling_chan = NULL; - TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &rx_channels[0])); + // create tx and rx channel pair + TEST_ESP_OK(gdma_new_axi_channel(&channel_config, &tx_channels[1], &rx_channels[1])); + // create single rx channel + TEST_ESP_OK(gdma_new_axi_channel(&channel_config, NULL, &rx_channels[0])); gdma_trigger_t fake_axi_trigger1 = { .periph = 1, @@ -344,20 +324,10 @@ static void test_gdma_m2m_mode(bool trig_retention_backup) { gdma_channel_handle_t tx_chan = NULL; gdma_channel_handle_t rx_chan = NULL; - gdma_channel_alloc_config_t tx_chan_alloc_config = {}; - gdma_channel_alloc_config_t rx_chan_alloc_config = {}; + gdma_channel_alloc_config_t chan_alloc_config = {}; #if SOC_HAS(AHB_GDMA) - tx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_TX, - .flags.reserve_sibling = true, - }; - TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); - rx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = tx_chan, - }; - TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan)); + TEST_ESP_OK(gdma_new_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan)); test_gdma_m2m_transaction(tx_chan, rx_chan, false, trig_retention_backup); @@ -366,16 +336,7 @@ static void test_gdma_m2m_mode(bool trig_retention_backup) #endif // SOC_HAS(AHB_GDMA) #if SOC_HAS(AXI_GDMA) - tx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_TX, - .flags.reserve_sibling = true, - }; - TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan)); - rx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = tx_chan, - }; - TEST_ESP_OK(gdma_new_axi_channel(&rx_chan_alloc_config, &rx_chan)); + TEST_ESP_OK(gdma_new_axi_channel(&chan_alloc_config, &tx_chan, &rx_chan)); // the AXI GDMA allows to put the DMA link list in the external memory test_gdma_m2m_transaction(tx_chan, rx_chan, true, trig_retention_backup); @@ -414,18 +375,8 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_ TEST_ASSERT_NOT_NULL(dst_data); gdma_channel_handle_t tx_chan = NULL; gdma_channel_handle_t rx_chan = NULL; - gdma_channel_alloc_config_t tx_chan_alloc_config = {}; - gdma_channel_alloc_config_t rx_chan_alloc_config = {}; - tx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_TX, - .flags.reserve_sibling = true, - }; - TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); - rx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = tx_chan, - }; - TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan)); + gdma_channel_alloc_config_t chan_alloc_config = {}; + TEST_ESP_OK(gdma_new_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan)); size_t sram_alignment = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); gdma_link_list_handle_t tx_link_list = NULL; @@ -673,22 +624,12 @@ TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]") { [[maybe_unused]] gdma_channel_handle_t tx_chan = NULL; [[maybe_unused]] gdma_channel_handle_t rx_chan = NULL; - [[maybe_unused]] gdma_channel_alloc_config_t tx_chan_alloc_config = {}; - [[maybe_unused]] gdma_channel_alloc_config_t rx_chan_alloc_config = {}; + [[maybe_unused]] gdma_channel_alloc_config_t chan_alloc_config = {}; #if SOC_HAS(AHB_GDMA) #if GDMA_LL_GET(AHB_PSRAM_CAPABLE) printf("Testing AHB-GDMA memory copy SRAM->PSRAM->SRAM\n"); - tx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_TX, - .flags.reserve_sibling = true, - }; - TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); - rx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = tx_chan, - }; - TEST_ESP_OK(gdma_new_ahb_channel(&rx_chan_alloc_config, &rx_chan)); + TEST_ESP_OK(gdma_new_ahb_channel(&chan_alloc_config, &tx_chan, &rx_chan)); test_gdma_memcpy_from_to_psram(tx_chan, rx_chan); @@ -700,16 +641,7 @@ TEST_CASE("GDMA memory copy SRAM->PSRAM->SRAM", "[GDMA][M2M]") #if SOC_HAS(AXI_GDMA) #if GDMA_LL_GET(AXI_PSRAM_CAPABLE) printf("Testing AXI-GDMA memory copy SRAM->PSRAM->SRAM\n"); - tx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_TX, - .flags.reserve_sibling = true, - }; - TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan)); - rx_chan_alloc_config = (gdma_channel_alloc_config_t) { - .direction = GDMA_CHANNEL_DIRECTION_RX, - .sibling_chan = tx_chan, - }; - TEST_ESP_OK(gdma_new_axi_channel(&rx_chan_alloc_config, &rx_chan)); + TEST_ESP_OK(gdma_new_axi_channel(&chan_alloc_config, &tx_chan, &rx_chan)); test_gdma_memcpy_from_to_psram(tx_chan, rx_chan); diff --git a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c index 9cef46927e..ce56c4e725 100644 --- a/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c +++ b/components/esp_hw_support/test_apps/dma/main/test_gdma_crc.c @@ -116,18 +116,17 @@ TEST_CASE("GDMA CRC Calculation", "[GDMA][CRC]") { gdma_channel_handle_t tx_chan = NULL; gdma_channel_alloc_config_t tx_chan_alloc_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, }; #if SOC_HAS(AHB_GDMA) printf("Test CRC calculation for AHB GDMA\r\n"); - TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan)); + TEST_ESP_OK(gdma_new_ahb_channel(&tx_chan_alloc_config, &tx_chan, NULL)); test_gdma_crc_calculation(tx_chan, 4); TEST_ESP_OK(gdma_del_channel(tx_chan)); #endif // SOC_HAS(AHB_GDMA) #if SOC_HAS(AXI_GDMA) printf("Test CRC calculation for AXI GDMA\r\n"); - TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan)); + TEST_ESP_OK(gdma_new_axi_channel(&tx_chan_alloc_config, &tx_chan, NULL)); test_gdma_crc_calculation(tx_chan, 3); TEST_ESP_OK(gdma_del_channel(tx_chan)); #endif // SOC_HAS(AXI_GDMA) diff --git a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c index 104e928719..d3253cb8be 100644 --- a/components/esp_lcd/i80/esp_lcd_panel_io_i80.c +++ b/components/esp_lcd/i80/esp_lcd_panel_io_i80.c @@ -579,10 +579,8 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l { esp_err_t ret = ESP_OK; // alloc DMA channel and connect to LCD peripheral - gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; - ret = LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &bus->dma_chan); + gdma_channel_alloc_config_t dma_chan_config = {0}; + ret = LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &bus->dma_chan, NULL); ESP_RETURN_ON_ERROR(ret, TAG, "alloc DMA channel failed"); gdma_connect(bus->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0)); gdma_strategy_config_t strategy_config = { diff --git a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c index e5def4c9ce..c6ee19d235 100644 --- a/components/esp_lcd/rgb/esp_lcd_panel_rgb.c +++ b/components/esp_lcd/rgb/esp_lcd_panel_rgb.c @@ -976,12 +976,11 @@ static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel) { // alloc DMA channel and connect to LCD peripheral gdma_channel_alloc_config_t dma_chan_config = { - .direction = GDMA_CHANNEL_DIRECTION_TX, #if CONFIG_LCD_RGB_ISR_IRAM_SAFE .flags.isr_cache_safe = true, #endif }; - ESP_RETURN_ON_ERROR(LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &rgb_panel->dma_chan), TAG, "alloc DMA channel failed"); + ESP_RETURN_ON_ERROR(LCD_GDMA_NEW_CHANNEL(&dma_chan_config, &rgb_panel->dma_chan, NULL), TAG, "alloc DMA channel failed"); gdma_connect(rgb_panel->dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_LCD, 0)); // configure DMA strategy diff --git a/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c b/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c index 05fb8fe050..72f33536f2 100644 --- a/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c +++ b/components/mbedtls/port/crypto_shared_gdma/esp_crypto_shared_gdma.c @@ -34,25 +34,27 @@ static const char *TAG = "crypto_shared_gdma"; -static gdma_channel_handle_t rx_channel; -static gdma_channel_handle_t tx_channel; +static gdma_channel_handle_t s_rx_channel; +static gdma_channel_handle_t s_tx_channel; /* Allocate a new GDMA channel, will keep trying until NEW_CHANNEL_TIMEOUT_MS */ -static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, gdma_channel_handle_t *channel) +static inline esp_err_t crypto_shared_gdma_new_channel(gdma_channel_alloc_config_t *channel_config, + gdma_channel_handle_t *tx_channel, gdma_channel_handle_t *rx_channel) { esp_err_t ret = ESP_FAIL; int time_waited_ms = 0; while (1) { #if SOC_AXI_GDMA_SUPPORTED - ret = gdma_new_axi_channel(channel_config, channel); + ret = gdma_new_axi_channel(channel_config, tx_channel, rx_channel); #else /* !SOC_AXI_GDMA_SUPPORTED */ - ret = gdma_new_ahb_channel(channel_config, channel); + ret = gdma_new_ahb_channel(channel_config, tx_channel, rx_channel); #endif /* SOC_AXI_GDMA_SUPPORTED */ if (ret == ESP_OK) { break; } else if (time_waited_ms >= NEW_CHANNEL_TIMEOUT_MS) { - *channel = NULL; + if (tx_channel && *tx_channel) *tx_channel = NULL; + if (rx_channel && *rx_channel) *rx_channel = NULL; break; } @@ -67,22 +69,17 @@ static esp_err_t crypto_shared_gdma_init(void) { esp_err_t ret; - gdma_channel_alloc_config_t channel_config_tx = { - .direction = GDMA_CHANNEL_DIRECTION_TX, - }; + gdma_channel_alloc_config_t channel_config = {0}; - gdma_channel_alloc_config_t channel_config_rx = { - .direction = GDMA_CHANNEL_DIRECTION_RX, - }; - - ret = crypto_shared_gdma_new_channel(&channel_config_tx, &tx_channel); + // Allocate TX and RX channels separately (they don't need to be in the same pair) + ret = crypto_shared_gdma_new_channel(&channel_config, &s_tx_channel, NULL); if (ret != ESP_OK) { goto err; } - ret = crypto_shared_gdma_new_channel(&channel_config_rx, &rx_channel); + ret = crypto_shared_gdma_new_channel(&channel_config, NULL, &s_rx_channel); if (ret != ESP_OK) { - gdma_del_channel(tx_channel); // Clean up already allocated TX channel + gdma_del_channel(s_tx_channel); // Clean up already allocated TX channel goto err; } @@ -90,7 +87,7 @@ static esp_err_t crypto_shared_gdma_init(void) .max_data_burst_size = 16, .access_ext_mem = true, // crypto peripheral may want to access PSRAM }; - gdma_config_transfer(tx_channel, &transfer_cfg); + gdma_config_transfer(s_tx_channel, &transfer_cfg); /* When using AHB-GDMA version 1, the max data burst size must be 0, otherwise buffers need to be aligned as well. * Whereas, in case of the other GDMA versions, the RX max burst size is default enabled, but with default burst size of 4, @@ -101,21 +98,21 @@ static esp_err_t crypto_shared_gdma_init(void) transfer_cfg.max_data_burst_size = 0; #endif - gdma_config_transfer(rx_channel, &transfer_cfg); + gdma_config_transfer(s_rx_channel, &transfer_cfg); #ifdef SOC_AES_SUPPORTED - gdma_connect(rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); - gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); + gdma_connect(s_rx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); + gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); #elif SOC_SHA_SUPPORTED - gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0)); + gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0)); #endif return ESP_OK; err: ESP_LOGE(TAG, "Failed to acquire DMA channel, Err=%d", ret); - tx_channel = NULL; - rx_channel = NULL; + s_tx_channel = NULL; + s_rx_channel = NULL; return ret; } @@ -141,7 +138,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c { int rx_ch_id = 0; - if (tx_channel == NULL) { + if (s_tx_channel == NULL) { /* Allocate a pair of RX and TX for crypto, should only happen the first time we use the GMDA or if user called esp_crypto_shared_gdma_release */ esp_err_t ret = crypto_shared_gdma_init(); @@ -151,16 +148,16 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c } /* Tx channel is shared between AES and SHA, need to connect to peripheral every time */ - gdma_disconnect(tx_channel); + gdma_disconnect(s_tx_channel); #ifdef SOC_SHA_SUPPORTED if (peripheral == GDMA_TRIG_PERIPH_SHA) { - gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0)); + gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_SHA, 0)); } else #endif // SOC_SHA_SUPPORTED #ifdef SOC_AES_SUPPORTED if (peripheral == GDMA_TRIG_PERIPH_AES) { - gdma_connect(tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); + gdma_connect(s_tx_channel, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_AES, 0)); } else #endif // SOC_AES_SUPPORTED { @@ -168,7 +165,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c } /* tx channel is reset by gdma_connect(), also reset rx to ensure a known state */ - gdma_get_channel_id(rx_channel, &rx_ch_id); + gdma_get_channel_id(s_rx_channel, &rx_ch_id); // IDF-14335: Use gdma_reset() instead #if SOC_AXI_GDMA_SUPPORTED @@ -184,7 +181,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c #if (SOC_GDMA_EXT_MEM_ENC_ALIGNMENT && SOC_AXI_GDMA_SUPPORTED) if (efuse_hal_flash_encryption_enabled()) { int tx_ch_id = 0; - gdma_get_channel_id(tx_channel, &tx_ch_id); + gdma_get_channel_id(s_tx_channel, &tx_ch_id); if (check_dma_descs_need_ext_mem_ecc_aes_access(input) || check_dma_descs_need_ext_mem_ecc_aes_access(output)) { axi_dma_ll_rx_enable_ext_mem_ecc_aes_access(&AXI_DMA, rx_ch_id, true); @@ -196,8 +193,8 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c } #endif /* SOC_GDMA_EXT_MEM_ENC_ALIGNMENT */ - gdma_start(tx_channel, (intptr_t)input); - gdma_start(rx_channel, (intptr_t)output); + gdma_start(s_tx_channel, (intptr_t)input); + gdma_start(s_rx_channel, (intptr_t)output); return ESP_OK; } @@ -206,7 +203,7 @@ esp_err_t esp_crypto_shared_gdma_start_axi_ahb(const crypto_dma_desc_t *input, c bool esp_crypto_shared_gdma_done(void) { int rx_ch_id = 0; - gdma_get_channel_id(rx_channel, &rx_ch_id); + gdma_get_channel_id(s_rx_channel, &rx_ch_id); while (1) { if ((axi_dma_ll_rx_get_interrupt_status(&AXI_DMA, rx_ch_id, true) & 1)) { break; @@ -220,16 +217,16 @@ void esp_crypto_shared_gdma_free() { esp_crypto_sha_aes_lock_acquire(); - if (rx_channel != NULL) { - gdma_disconnect(rx_channel); - gdma_del_channel(rx_channel); - rx_channel = NULL; + if (s_rx_channel != NULL) { + gdma_disconnect(s_rx_channel); + gdma_del_channel(s_rx_channel); + s_rx_channel = NULL; } - if (tx_channel != NULL) { - gdma_disconnect(tx_channel); - gdma_del_channel(tx_channel); - tx_channel = NULL; + if (s_tx_channel != NULL) { + gdma_disconnect(s_tx_channel); + gdma_del_channel(s_tx_channel); + s_tx_channel = NULL; } esp_crypto_sha_aes_lock_release();