refactor(gdma): increase performance and optimize api

This commit is contained in:
Chen Jichang
2026-08-10 20:36:57 +08:00
committed by Chen Ji Chang
parent 305d434bda
commit bd2d64bffb
23 changed files with 119 additions and 142 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -221,10 +221,12 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s
gdma_reset(bsl->tx_channel); gdma_reset(bsl->tx_channel);
bitscrambler_reset(bs); bitscrambler_reset(bs);
size_t in_alignment = gdma_get_buffer_alignment_constraint(bsl->tx_channel, buffer_in);
size_t out_alignment = gdma_get_buffer_alignment_constraint(bsl->rx_channel, buffer_out);
// mount in and out buffer to the DMA link list // mount in and out buffer to the DMA link list
gdma_buffer_mount_config_t in_buf_mount_config = { gdma_buffer_mount_config_t in_buf_mount_config = {
.buffer = buffer_in, .buffer = buffer_in,
.buffer_alignment = 4, .buffer_alignment = in_alignment,
.length = length_bytes_in, .length = length_bytes_in,
.flags = { .flags = {
.mark_eof = true, .mark_eof = true,
@@ -234,12 +236,11 @@ esp_err_t bitscrambler_loopback_run(bitscrambler_handle_t bs, void *buffer_in, s
gdma_link_mount_buffers(bsl->tx_link_list, 0, &in_buf_mount_config, 1, NULL); gdma_link_mount_buffers(bsl->tx_link_list, 0, &in_buf_mount_config, 1, NULL);
gdma_buffer_mount_config_t out_buf_mount_config = { gdma_buffer_mount_config_t out_buf_mount_config = {
.buffer = buffer_out, .buffer = buffer_out,
.buffer_alignment = 4, .buffer_alignment = out_alignment,
.length = length_bytes_out, .length = length_bytes_out,
.flags = { .flags = {
.mark_eof = false, .mark_eof = false,
.mark_final = GDMA_FINAL_LINK_TO_NULL, .mark_final = GDMA_FINAL_LINK_TO_NULL,
.check_size_align = gdma_is_size_alignment_required(bsl->rx_channel),
} }
}; };
gdma_link_mount_buffers(bsl->rx_link_list, 0, &out_buf_mount_config, 1, NULL); gdma_link_mount_buffers(bsl->rx_link_list, 0, &out_buf_mount_config, 1, NULL);

View File

@@ -106,7 +106,10 @@ esp_err_t esp_cam_ctlr_dvp_dma_init(esp_cam_ctlr_dvp_dma_t *dma, uint32_t burst_
}; };
ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed"); ESP_GOTO_ON_ERROR(gdma_config_transfer(dma->dma_chan, &transfer_config), fail1, TAG, "set trans ability failed");
gdma_get_channel_alignment_constraints(dma->dma_chan, &dma->int_mem_align, &dma->ext_mem_align, NULL); gdma_channel_alignment_info_t align_info;
gdma_get_channel_alignment_constraints(dma->dma_chan, &align_info);
dma->int_mem_align = align_info.int_mem_alignment;
dma->ext_mem_align = align_info.ext_enc_mem_alignment;
size_t buffer_alignment = dma->ext_mem_align; size_t buffer_alignment = dma->ext_mem_align;
size_t desc_max_size = ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE; size_t desc_max_size = ESP_CAM_CTLR_DVP_DMA_DESC_BUFFER_MAX_SIZE;

View File

@@ -7,6 +7,7 @@
#pragma once #pragma once
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h>
#include "esp_etm.h" #include "esp_etm.h"
#include "hal/gdma_types.h" #include "hal/gdma_types.h"
#include "esp_err.h" #include "esp_err.h"
@@ -221,52 +222,44 @@ typedef struct {
esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config); esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transfer_config_t *config);
/** /**
* @brief Get the alignment constraints for a configured GDMA channel * @brief Alignment constraints of a configured GDMA channel
* *
* @note You should call this function after `gdma_config_transfer`, the later one can
* adjust the alignment constraints based on GDMA-specific conditions, e.g. burst size.
* @note Prefer this when allocating DMA buffers. Once a concrete buffer address is available, * @note Prefer this when allocating DMA buffers. Once a concrete buffer address is available,
* use `gdma_get_buffer_alignment_constraint` for the effective runtime constraint of that region. * use `gdma_get_buffer_alignment_constraint` for the effective runtime constraint of that region.
* @note For allocation from external memory: * @note For allocation from external memory:
* - Use `ext_enc_mem_alignment` as the safe default (worst-case MSPI encryption/ECC). * - Use `ext_enc_mem_alignment` as the safe default (worst-case MSPI encryption/ECC).
* - Use `ext_no_enc_mem_alignment` when intentionally targeting no-encryption external memory (e.g. no-enc PSRAM). * - Use `ext_no_enc_mem_alignment` when intentionally targeting no-encryption external memory (e.g. no-enc PSRAM).
* @note The returned alignment doesn't take the cache line size into account, if you want to do aligned memory allocation, * @note The returned alignment doesn't take the cache line size into account. If the DMA buffer is behind a cache,
* you should align the buffer size to the cache line size by yourself if the DMA buffer is behind a cache. * align the buffer size to the cache line size yourself when needed.
*/
typedef struct {
size_t int_mem_alignment; /*!< Alignment for internal memory */
size_t ext_enc_mem_alignment; /*!< Alignment for external memory including MSPI encryption/ECC constraints */
size_t ext_no_enc_mem_alignment; /*!< Alignment for external memory without MSPI region-specific constraints */
} gdma_channel_alignment_info_t;
/**
* @brief Get the alignment constraints for a configured GDMA channel
*
* @note Call this function after `gdma_config_transfer`.
* *
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_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] info Alignment constraints of the channel
* @param[out] ext_enc_mem_alignment External memory alignment including MSPI encryption/ECC constraints
* @param[out] ext_no_enc_mem_alignment External memory alignment without MSPI region-specific constraints.
* Useful when allocating from no-encryption external memory. Set to NULL if unused.
* @return * @return
* - ESP_OK: Get alignment constraints successfully * - ESP_OK: Get alignment constraints successfully
* - ESP_ERR_INVALID_ARG: Get alignment constraints failed because of invalid argument * - ESP_ERR_INVALID_ARG: Get alignment constraints failed because of invalid argument
* - ESP_FAIL: Get alignment constraints failed because of other error
*/ */
esp_err_t gdma_get_channel_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, esp_err_t gdma_get_channel_alignment_constraints(gdma_channel_handle_t dma_chan, gdma_channel_alignment_info_t *info);
size_t *ext_enc_mem_alignment, size_t *ext_no_enc_mem_alignment);
/**
* @brief Check whether buffer sizes must meet the configured channel alignment
*
* @note Call this function after `gdma_config_transfer`.
* @note This reports GDMA hardware constraints only. Region-specific MSPI constraints
* are enforced independently when buffers are mounted to a GDMA link list.
*
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel`
* @return True when buffer sizes must be aligned, otherwise false
*/
bool gdma_is_size_alignment_required(gdma_channel_handle_t dma_chan);
/** /**
* @brief Get the effective alignment constraint for a specific DMA buffer * @brief Get the effective alignment constraint for a specific DMA buffer
* *
* @note You should call this function after `gdma_config_transfer`. * @note Call this function after `gdma_config_transfer`.
* @note The returned alignment combines GDMA channel constraints with MSPI constraints * @note Combines GDMA channel constraints with MSPI constraints of the actual buffer region.
* of the actual buffer region. This lets external no-encryption PSRAM buffers use * External no-encryption PSRAM buffers can therefore use their real runtime constraint
* their real runtime constraint instead of a generic worst-case MSPI alignment. * instead of a generic worst-case MSPI alignment.
* @note The returned alignment doesn't take the cache line size into account. * @note The returned alignment doesn't take the cache line size into account.
* @note On invalid arguments, returns an impossible alignment (BIT(31)). * @note On invalid arguments, returns an impossible value (BIT(31)).
* *
* @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel` * @param[in] dma_chan GDMA channel handle, allocated by `gdma_new_ahb_channel/gdma_new_axi_channel`
* @param[in] buffer DMA buffer address * @param[in] buffer DMA buffer address

View File

@@ -82,12 +82,10 @@ typedef struct {
gdma_final_node_link_type_t mark_final: 2; /*!< Specify the next item of the final item of this mount. gdma_final_node_link_type_t mark_final: 2; /*!< Specify the next item of the final item of this mount.
For the other items that not the final one, it will be linked to the next item automatically and this field takes no effect. For the other items that not the final one, it will be linked to the next item automatically and this field takes no effect.
Note, the final item here does not mean the last item in the link list. It is `start_item_index + num_items - 1` */ Note, the final item here does not mean the last item in the link list. It is `start_item_index + num_items - 1` */
uint32_t bypass_buffer_align_check: 1; /*!< Whether to bypass the buffer alignment check. uint32_t bypass_buffer_addr_align_check: 1; /*!< Whether to bypass the buffer address alignment check.
Only enable it when you know what you are doing. */
uint32_t bypass_buffer_size_align_check: 1; /*!< Whether to bypass the buffer size alignment check.
Only enable it when you know what you are doing. */ Only enable it when you know what you are doing. */
uint32_t check_size_align: 1; /*!< Whether to check that `length` is aligned to the alignment.
RX callers can query `gdma_is_size_alignment_required` to determine whether
the configured channel requires this check. Under MSPI Flash Encryption /
PSRAM ECC, length alignment is always enforced regardless of this flag. */
} flags; //!< Flags for buffer mount configurations } flags; //!< Flags for buffer mount configurations
} gdma_buffer_mount_config_t; } gdma_buffer_mount_config_t;

View File

@@ -12,7 +12,6 @@ entries:
gdma: gdma_append (noflash) gdma: gdma_append (noflash)
gdma: gdma_reset (noflash) gdma: gdma_reset (noflash)
gdma: gdma_get_buffer_alignment_constraint (noflash) gdma: gdma_get_buffer_alignment_constraint (noflash)
gdma: gdma_is_size_alignment_required (noflash)
[mapping:gdma_hal] [mapping:gdma_hal]
archive: libesp_hal_dma.a archive: libesp_hal_dma.a

View File

@@ -163,8 +163,9 @@ esp_err_t esp_async_crc_install_gdma_template(const async_crc_config_t *config,
ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->rx_channel, &transfer_cfg), err, TAG, "config RX DMA transfer failed"); ESP_GOTO_ON_ERROR(gdma_config_transfer(crc_gdma->rx_channel, &transfer_cfg), err, TAG, "config RX DMA transfer failed");
// Get buffer alignment required by GDMA channel // Get buffer alignment required by GDMA channel
size_t rx_int_mem_alignment = 0; gdma_channel_alignment_info_t rx_align_info;
gdma_get_channel_alignment_constraints(crc_gdma->rx_channel, &rx_int_mem_alignment, NULL, NULL); gdma_get_channel_alignment_constraints(crc_gdma->rx_channel, &rx_align_info);
size_t rx_int_mem_alignment = rx_align_info.int_mem_alignment;
size_t rx_buffer_size = (rx_int_mem_alignment > CRC_DMA_RX_SINK_BUFFER_SIZE) ? size_t rx_buffer_size = (rx_int_mem_alignment > CRC_DMA_RX_SINK_BUFFER_SIZE) ?
rx_int_mem_alignment : CRC_DMA_RX_SINK_BUFFER_SIZE; rx_int_mem_alignment : CRC_DMA_RX_SINK_BUFFER_SIZE;
crc_gdma->rx_sink_buffer = heap_caps_aligned_calloc(rx_int_mem_alignment, 1, rx_buffer_size, crc_gdma->rx_sink_buffer = heap_caps_aligned_calloc(rx_int_mem_alignment, 1, rx_buffer_size,
@@ -189,7 +190,6 @@ esp_err_t esp_async_crc_install_gdma_template(const async_crc_config_t *config,
.length = rx_buffer_size, .length = rx_buffer_size,
.flags = { .flags = {
.mark_final = GDMA_FINAL_LINK_TO_HEAD, .mark_final = GDMA_FINAL_LINK_TO_HEAD,
.check_size_align = gdma_is_size_alignment_required(crc_gdma->rx_channel),
}, },
}; };
ESP_GOTO_ON_ERROR(gdma_link_mount_buffers(crc_gdma->rx_link_list, 0, &rx_buf_mount_config, 1, NULL), ESP_GOTO_ON_ERROR(gdma_link_mount_buffers(crc_gdma->rx_link_list, 0, &rx_buf_mount_config, 1, NULL),

View File

@@ -324,12 +324,11 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
trans->stash_buffer = NULL; trans->stash_buffer = NULL;
} }
size_t buffer_alignment = 0;
size_t num_dma_nodes = 0; size_t num_dma_nodes = 0;
// allocate gdma TX link // allocate gdma TX link
buffer_alignment = gdma_get_buffer_alignment_constraint(mcp_gdma->tx_channel, src); size_t tx_buffer_alignment = gdma_get_buffer_alignment_constraint(mcp_gdma->tx_channel, src);
num_dma_nodes = esp_dma_calculate_node_count(n, buffer_alignment, MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE); num_dma_nodes = esp_dma_calculate_node_count(n, tx_buffer_alignment, MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
gdma_link_list_config_t tx_link_cfg = { gdma_link_list_config_t tx_link_cfg = {
.item_alignment = dma_link_item_alignment, .item_alignment = dma_link_item_alignment,
.num_items = num_dma_nodes, .num_items = num_dma_nodes,
@@ -343,7 +342,7 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
gdma_buffer_mount_config_t tx_buf_mount_config[1] = { gdma_buffer_mount_config_t tx_buf_mount_config[1] = {
[0] = { [0] = {
.buffer = src, .buffer = src,
.buffer_alignment = buffer_alignment, .buffer_alignment = tx_buffer_alignment,
.length = n, .length = n,
.flags = { .flags = {
.mark_eof = true, // mark the last item as EOF, so the RX channel can also received an EOF list item .mark_eof = true, // mark the last item as EOF, so the RX channel can also received an EOF list item
@@ -361,8 +360,8 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
} }
// allocate gdma RX link // allocate gdma RX link
buffer_alignment = gdma_get_buffer_alignment_constraint(mcp_gdma->rx_channel, dst); size_t rx_buffer_alignment = gdma_get_buffer_alignment_constraint(mcp_gdma->rx_channel, dst);
num_dma_nodes = esp_dma_calculate_node_count(n, buffer_alignment, MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE); num_dma_nodes = esp_dma_calculate_node_count(n, rx_buffer_alignment, MCP_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
gdma_link_list_config_t rx_link_cfg = { gdma_link_list_config_t rx_link_cfg = {
.item_alignment = dma_link_item_alignment, .item_alignment = dma_link_item_alignment,
.num_items = num_dma_nodes + 3, // add 3 extra items for the cache aligned buffers .num_items = num_dma_nodes + 3, // add 3 extra items for the cache aligned buffers
@@ -379,9 +378,8 @@ static esp_err_t mcp_gdma_memcpy(async_memcpy_context_t *ctx, void *dst, void *s
gdma_buffer_mount_config_t rx_buf_mount_config[3] = {0}; gdma_buffer_mount_config_t rx_buf_mount_config[3] = {0};
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
rx_buf_mount_config[i].buffer = trans->rx_buf_array.aligned_buffer[i].aligned_buffer; rx_buf_mount_config[i].buffer = trans->rx_buf_array.aligned_buffer[i].aligned_buffer;
rx_buf_mount_config[i].buffer_alignment = buffer_alignment; rx_buf_mount_config[i].buffer_alignment = rx_buffer_alignment;
rx_buf_mount_config[i].length = trans->rx_buf_array.aligned_buffer[i].length; rx_buf_mount_config[i].length = trans->rx_buf_array.aligned_buffer[i].length;
rx_buf_mount_config[i].flags.check_size_align = gdma_is_size_alignment_required(mcp_gdma->rx_channel);
} }
gdma_link_mount_buffers(trans->rx_link_list, 0, rx_buf_mount_config, 3, NULL); gdma_link_mount_buffers(trans->rx_link_list, 0, rx_buf_mount_config, 3, NULL);

View File

@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -45,7 +45,7 @@ esp_err_t esp_dma_split_rx_buffer_to_cache_aligned(void *rx_buffer, size_t buffe
split_line_size = int_mem_cache_line_size; split_line_size = int_mem_cache_line_size;
} }
bool align_required = split_line_size > 0; bool align_required = split_line_size > 0;
ESP_EARLY_LOGV(TAG, "split_line_size:%d", split_line_size); ESP_EARLY_LOGV(TAG, "split_line_size:%" PRIu32, (uint32_t)split_line_size);
if (*ret_stash_buffer == NULL) { if (*ret_stash_buffer == NULL) {
// If the stash buffer is not offered by the caller, allocate the stash buffer from internal RAM // If the stash buffer is not offered by the caller, allocate the stash buffer from internal RAM
@@ -69,10 +69,10 @@ esp_err_t esp_dma_split_rx_buffer_to_cache_aligned(void *rx_buffer, size_t buffe
// calculate head_overflow_len // calculate head_overflow_len
size_t head_overflow_len = (uintptr_t)rx_buffer % split_line_size; size_t head_overflow_len = (uintptr_t)rx_buffer % split_line_size;
head_overflow_len = head_overflow_len ? split_line_size - head_overflow_len : 0; head_overflow_len = head_overflow_len ? split_line_size - head_overflow_len : 0;
ESP_EARLY_LOGV(TAG, "head_addr:%p head_overflow_len:%zu", rx_buffer, head_overflow_len); ESP_EARLY_LOGV(TAG, "head_addr:%p head_overflow_len:%" PRIu32, rx_buffer, (uint32_t)head_overflow_len);
// calculate tail_overflow_len // calculate tail_overflow_len
size_t tail_overflow_len = ((uintptr_t)rx_buffer + buffer_len) % split_line_size; size_t tail_overflow_len = ((uintptr_t)rx_buffer + buffer_len) % split_line_size;
ESP_EARLY_LOGV(TAG, "tail_addr:%p tail_overflow_len:%zu", rx_buffer + buffer_len - tail_overflow_len, tail_overflow_len); ESP_EARLY_LOGV(TAG, "tail_addr:%p tail_overflow_len:%" PRIu32, rx_buffer + buffer_len - tail_overflow_len, (uint32_t)tail_overflow_len);
// special handling when input_buffer length is no more than buffer alignment // special handling when input_buffer length is no more than buffer alignment
bool is_small_buf = head_overflow_len >= buffer_len || tail_overflow_len >= buffer_len; bool is_small_buf = head_overflow_len >= buffer_len || tail_overflow_len >= buffer_len;

View File

@@ -428,7 +428,7 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
if (config->access_ext_mem) { if (config->access_ext_mem) {
#if (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH) && SOC_AHB_GDMA_VERSION != 1 #if (SOC_PSRAM_DMA_CAPABLE || SOC_DMA_CAN_ACCESS_FLASH) && SOC_AHB_GDMA_VERSION != 1
// Under Flash Encryption/PSRAM ECC, external DMA must use MSPI-aligned bursts. // Under Flash Encryption/PSRAM ECC, DMA must use MSPI-aligned bursts.
size_t mspi_alignment = esp_mspi_get_alignment(NULL); size_t mspi_alignment = esp_mspi_get_alignment(NULL);
if (mspi_alignment > 1) { if (mspi_alignment > 1) {
if (max_data_burst_size < mspi_alignment) { if (max_data_burst_size < mspi_alignment) {
@@ -449,7 +449,6 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
} }
bool en_data_burst = max_data_burst_size > 0; bool en_data_burst = max_data_burst_size > 0;
dma_chan->flags.size_alignment_required = false;
if (en_data_burst) { if (en_data_burst) {
#if CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION #if CONFIG_GDMA_ENABLE_WEIGHTED_ARBITRATION
// due to hardware limitation, if weighted arbitration is enabled, the data must be aligned to burst size // due to hardware limitation, if weighted arbitration is enabled, the data must be aligned to burst size
@@ -464,7 +463,6 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
int_mem_alignment = MAX(int_mem_alignment, 4); int_mem_alignment = MAX(int_mem_alignment, 4);
ext_enc_mem_alignment = MAX(ext_enc_mem_alignment, max_data_burst_size); ext_enc_mem_alignment = MAX(ext_enc_mem_alignment, max_data_burst_size);
ext_no_enc_mem_alignment = MAX(ext_no_enc_mem_alignment, max_data_burst_size); ext_no_enc_mem_alignment = MAX(ext_no_enc_mem_alignment, max_data_burst_size);
dma_chan->flags.size_alignment_required = true;
} }
#endif #endif
@@ -513,42 +511,30 @@ esp_err_t gdma_config_transfer(gdma_channel_handle_t dma_chan, const gdma_transf
return ESP_OK; return ESP_OK;
} }
esp_err_t gdma_get_channel_alignment_constraints(gdma_channel_handle_t dma_chan, size_t *int_mem_alignment, esp_err_t gdma_get_channel_alignment_constraints(gdma_channel_handle_t dma_chan, gdma_channel_alignment_info_t *info)
size_t *ext_enc_mem_alignment, size_t *ext_no_enc_mem_alignment)
{ {
if (!dma_chan) { if (!dma_chan || !info) {
return ESP_ERR_INVALID_ARG; return ESP_ERR_INVALID_ARG;
} }
if (int_mem_alignment) { info->int_mem_alignment = dma_chan->int_mem_alignment;
*int_mem_alignment = dma_chan->int_mem_alignment; info->ext_enc_mem_alignment = dma_chan->ext_enc_mem_alignment;
} info->ext_no_enc_mem_alignment = dma_chan->ext_no_enc_mem_alignment;
if (ext_enc_mem_alignment) {
*ext_enc_mem_alignment = dma_chan->ext_enc_mem_alignment;
}
if (ext_no_enc_mem_alignment) {
*ext_no_enc_mem_alignment = dma_chan->ext_no_enc_mem_alignment;
}
return ESP_OK; return ESP_OK;
} }
bool gdma_is_size_alignment_required(gdma_channel_handle_t dma_chan)
{
return dma_chan && dma_chan->flags.size_alignment_required;
}
size_t gdma_get_buffer_alignment_constraint(gdma_channel_handle_t dma_chan, const void *buffer) size_t gdma_get_buffer_alignment_constraint(gdma_channel_handle_t dma_chan, const void *buffer)
{ {
if (!dma_chan || !buffer) { if (!dma_chan || !buffer) {
return BIT(31); return BIT(31);
} }
size_t base_alignment = dma_chan->int_mem_alignment; // Internal SRAM only needs the DMA-side constraint; MSPI rules apply to PSRAM/Flash.
if (esp_ptr_external_ram(buffer) || esp_ptr_in_drom(buffer)) { if (!(esp_ptr_external_ram(buffer) || esp_ptr_in_drom(buffer))) {
base_alignment = dma_chan->ext_no_enc_mem_alignment; return dma_chan->int_mem_alignment;
} }
size_t mspi_alignment = esp_mspi_get_alignment(buffer); size_t mspi_alignment = esp_mspi_get_alignment(buffer);
return MAX(base_alignment, mspi_alignment); return MAX(dma_chan->ext_no_enc_mem_alignment, mspi_alignment);
} }
esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config) esp_err_t gdma_apply_strategy(gdma_channel_handle_t dma_chan, const gdma_strategy_config_t *config)

View File

@@ -186,17 +186,13 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i
} }
// alignment must be a power of 2 // alignment must be a power of 2
ESP_RETURN_ON_FALSE_ISR((buffer_alignment & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "align err idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment); ESP_RETURN_ON_FALSE_ISR((buffer_alignment & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "align err idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment);
size_t mspi_alignment = esp_mspi_get_alignment(buf); size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment);
size_t effective_alignment = MAX(buffer_alignment, mspi_alignment); // Address and size alignment checks are independent; both use the caller-provided buffer_alignment.
size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, effective_alignment); if (!config->flags.bypass_buffer_addr_align_check) {
if (!config->flags.bypass_buffer_align_check) { ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buf & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf misalign idx=%"PRIu32" align=%"PRIu32, bi, buffer_alignment);
ESP_RETURN_ON_FALSE_ISR(((uintptr_t)buf & (effective_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf misalign idx=%"PRIu32" align=%"PRIu32, bi, effective_alignment); }
// Length alignment: if (!config->flags.bypass_buffer_size_align_check) {
// - Always required under MSPI strict mode (Flash Encryption / PSRAM ECC): size must align. ESP_RETURN_ON_FALSE_ISR((len & (buffer_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf len misalign idx=%"PRIu32" len=%"PRIu32" align=%"PRIu32"", bi, len, buffer_alignment);
// - Also when check_size_align is set by a caller whose configured channel requires size alignment.
if (mspi_alignment > 1 || config->flags.check_size_align) {
ESP_RETURN_ON_FALSE_ISR((len & (effective_alignment - 1)) == 0, ESP_ERR_INVALID_ARG, TAG, "buf len misalign idx=%"PRIu32" len=%"PRIu32" align=%"PRIu32"", bi, len, effective_alignment);
}
} }
size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length; size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length;
ESP_RETURN_ON_FALSE_ISR(num_items_need <= remaining, ESP_ERR_INVALID_ARG, TAG, ESP_RETURN_ON_FALSE_ISR(num_items_need <= remaining, ESP_ERR_INVALID_ARG, TAG,
@@ -224,9 +220,7 @@ esp_err_t gdma_link_mount_buffers(gdma_link_list_handle_t list, int start_item_i
memset(lli_nc, 0, item_size); memset(lli_nc, 0, item_size);
continue; continue;
} }
size_t mspi_alignment = esp_mspi_get_alignment(buf); size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, buffer_alignment);
size_t effective_alignment = MAX(buffer_alignment, mspi_alignment);
size_t max_buffer_mount_length = ALIGN_DOWN(GDMA_MAX_BUFFER_SIZE_PER_LINK_ITEM, effective_alignment);
size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length; size_t num_items_need = (len + max_buffer_mount_length - 1) / max_buffer_mount_length;
// mount the buffer to the link list // mount the buffer to the link list
for (size_t i = 0; i < num_items_need; i++) { for (size_t i = 0; i < num_items_need; i++) {

View File

@@ -96,7 +96,6 @@ struct gdma_channel_t {
struct { struct {
uint32_t start_stop_by_etm: 1; // whether the channel is started/stopped by ETM uint32_t start_stop_by_etm: 1; // whether the channel is started/stopped by ETM
uint32_t isr_cache_safe: 1; // whether the interrupt of this channel need to be cache safe uint32_t isr_cache_safe: 1; // whether the interrupt of this channel need to be cache safe
uint32_t size_alignment_required: 1; // whether buffer size must meet the channel alignment
} flags; } flags;
}; };

View File

@@ -283,9 +283,10 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe
gdma_link_list_handle_t rx_link_list = NULL; gdma_link_list_handle_t rx_link_list = NULL;
test_gdma_config_link_list(tx_chan, rx_chan, &tx_link_list, &rx_link_list, 16, dma_link_in_ext_mem); test_gdma_config_link_list(tx_chan, rx_chan, &tx_link_list, &rx_link_list, 16, dma_link_in_ext_mem);
size_t int_mem_alignment = 0; gdma_channel_alignment_info_t tx_align_info;
size_t ext_mem_alignment = 0; TEST_ESP_OK(gdma_get_channel_alignment_constraints(tx_chan, &tx_align_info));
TEST_ESP_OK(gdma_get_channel_alignment_constraints(tx_chan, &int_mem_alignment, &ext_mem_alignment, NULL)); size_t int_mem_alignment = tx_align_info.int_mem_alignment;
size_t __attribute__((unused)) ext_mem_alignment = tx_align_info.ext_enc_mem_alignment;
// allocate the source buffer from SRAM // allocate the source buffer from SRAM
uint8_t *src_data = heap_caps_aligned_calloc(int_mem_alignment, 1, 128, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); uint8_t *src_data = heap_caps_aligned_calloc(int_mem_alignment, 1, 128, MALLOC_CAP_DMA | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
@@ -352,9 +353,6 @@ static void test_gdma_m2m_transaction(gdma_channel_handle_t tx_chan, gdma_channe
.buffer = dst_data, .buffer = dst_data,
.buffer_alignment = sram_alignment, // RX buffer should be aligned to the cache line size, because we will do cache invalidate later .buffer_alignment = sram_alignment, // RX buffer should be aligned to the cache line size, because we will do cache invalidate later
.length = 256, .length = 256,
.flags = {
.check_size_align = gdma_is_size_alignment_required(rx_chan),
},
}; };
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL)); TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
@@ -503,7 +501,6 @@ static void test_gdma_m2m_desc_empty_event(gdma_channel_handle_t tx_chan, gdma_c
.length = 64, .length = 64,
.flags = { .flags = {
.mark_final = GDMA_FINAL_LINK_TO_NULL, .mark_final = GDMA_FINAL_LINK_TO_NULL,
.check_size_align = gdma_is_size_alignment_required(rx_chan),
}, },
}; };
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL)); TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));
@@ -584,7 +581,9 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_
TEST_ESP_OK(gdma_config_transfer(rx_chan, &transfer_config)); TEST_ESP_OK(gdma_config_transfer(rx_chan, &transfer_config));
size_t rx_mem_alignment = 0; size_t rx_mem_alignment = 0;
TEST_ESP_OK(gdma_get_channel_alignment_constraints(rx_chan, &rx_mem_alignment, NULL, NULL)); gdma_channel_alignment_info_t rx_align_info;
TEST_ESP_OK(gdma_get_channel_alignment_constraints(rx_chan, &rx_align_info));
rx_mem_alignment = rx_align_info.int_mem_alignment;
// prepare the source data // prepare the source data
for (int i = 0; i < data_length; i++) { for (int i = 0; i < data_length; i++) {
@@ -616,7 +615,7 @@ static void test_gdma_m2m_unaligned_buffer_test(uint8_t *dst_data, uint8_t *src_
rx_aligned_buf_mount_config[i].buffer = align_array.aligned_buffer[i].aligned_buffer; rx_aligned_buf_mount_config[i].buffer = align_array.aligned_buffer[i].aligned_buffer;
rx_aligned_buf_mount_config[i].buffer_alignment = MAX(sram_alignment, rx_mem_alignment); rx_aligned_buf_mount_config[i].buffer_alignment = MAX(sram_alignment, rx_mem_alignment);
rx_aligned_buf_mount_config[i].length = align_array.aligned_buffer[i].length; rx_aligned_buf_mount_config[i].length = align_array.aligned_buffer[i].length;
rx_aligned_buf_mount_config[i].flags.check_size_align = gdma_is_size_alignment_required(rx_chan); rx_aligned_buf_mount_config[i].flags.bypass_buffer_size_align_check = true; // head and tail buffer size is not aligned to the cache line size
} }
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, rx_aligned_buf_mount_config, 3, NULL)); TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, rx_aligned_buf_mount_config, 3, NULL));
@@ -779,7 +778,6 @@ TEST_CASE("GDMA M2M Unaligned RX Buffer Test", "[GDMA][M2M]")
.length = COPY_SIZE, .length = COPY_SIZE,
.flags = { .flags = {
.mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here .mark_final = GDMA_FINAL_LINK_TO_NULL, // using singly list, so terminate the link here
.check_size_align = gdma_is_size_alignment_required(rx_chan),
} }
}; };
TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL)); TEST_ESP_OK(gdma_link_mount_buffers(rx_link_list, 0, &rx_buf_mount_config, 1, NULL));

View File

@@ -369,9 +369,9 @@ static esp_err_t i3c_master_init_dma(i3c_master_bus_t *i3c_master_handle, const
ESP_GOTO_ON_ERROR(gdma_config_transfer(i3c_master_handle->dma_tx_chan, &transfer_cfg), err2, TAG, "Config DMA tx channel transfer failed"); ESP_GOTO_ON_ERROR(gdma_config_transfer(i3c_master_handle->dma_tx_chan, &transfer_cfg), err2, TAG, "Config DMA tx channel transfer failed");
// create DMA link list // create DMA link list
size_t int_mem_align = 0; gdma_channel_alignment_info_t align_info;
gdma_get_channel_alignment_constraints(i3c_master_handle->dma_tx_chan, &int_mem_align, NULL, NULL); gdma_get_channel_alignment_constraints(i3c_master_handle->dma_tx_chan, &align_info);
i3c_master_handle->dma_buffer_alignment = I3C_ALIGN_UP(int_mem_align, I3C_MASTER_DMA_INTERFACE_ALIGNMENT); i3c_master_handle->dma_buffer_alignment = I3C_ALIGN_UP(align_info.int_mem_alignment, I3C_MASTER_DMA_INTERFACE_ALIGNMENT);
size_t num_dma_nodes = esp_dma_calculate_node_count(dma_config->max_transfer_size, i3c_master_handle->dma_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE); size_t num_dma_nodes = esp_dma_calculate_node_count(dma_config->max_transfer_size, i3c_master_handle->dma_buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
gdma_link_list_config_t dma_link_config = { gdma_link_list_config_t dma_link_config = {
.item_alignment = 4, // 4 bytes alignment for AHB-DMA .item_alignment = 4, // 4 bytes alignment for AHB-DMA
@@ -581,7 +581,6 @@ static esp_err_t do_dma_transaction_handler(i3c_master_bus_handle_t bus_handle,
.flags = { .flags = {
.mark_eof = true, .mark_eof = true,
.mark_final = GDMA_FINAL_LINK_TO_NULL, .mark_final = GDMA_FINAL_LINK_TO_NULL,
.check_size_align = gdma_is_size_alignment_required(bus_handle->dma_rx_chan),
} }
}; };

View File

@@ -147,16 +147,13 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
rx_unit->node_num = required_node_num; rx_unit->node_num = required_node_num;
gdma_buffer_mount_config_t mount_config[required_node_num] = {}; gdma_buffer_mount_config_t mount_config[required_node_num] = {};
bool size_alignment_required = gdma_is_size_alignment_required(rx_unit->dma_chan);
/* Mount head buffer */ /* Mount head buffer */
if (head_node_num) { if (head_node_num) {
mount_config[0].buffer = trans->aligned_payload.buf.head.aligned_buffer; mount_config[0].buffer = trans->aligned_payload.buf.head.aligned_buffer;
mount_config[0].buffer_alignment = trans->alignment; mount_config[0].buffer_alignment = trans->alignment;
mount_config[0].length = trans->aligned_payload.buf.head.length; mount_config[0].length = trans->aligned_payload.buf.head.length;
mount_config[0].flags.bypass_buffer_align_check = false;
mount_config[0].flags.mark_eof = false; mount_config[0].flags.mark_eof = false;
mount_config[0].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT; mount_config[0].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT;
mount_config[0].flags.check_size_align = size_alignment_required;
} }
/* Mount body buffer */ /* Mount body buffer */
size_t mount_size = 0; size_t mount_size = 0;
@@ -173,10 +170,8 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
mount_config[i].buffer = (void *)((uint8_t *)trans->aligned_payload.buf.body.aligned_buffer + offset); mount_config[i].buffer = (void *)((uint8_t *)trans->aligned_payload.buf.body.aligned_buffer + offset);
mount_config[i].buffer_alignment = trans->alignment; mount_config[i].buffer_alignment = trans->alignment;
mount_config[i].length = mount_size; mount_config[i].length = mount_size;
mount_config[i].flags.bypass_buffer_align_check = false;
mount_config[i].flags.mark_eof = false; mount_config[i].flags.mark_eof = false;
mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT; mount_config[i].flags.mark_final = GDMA_FINAL_LINK_TO_DEFAULT;
mount_config[i].flags.check_size_align = size_alignment_required;
offset += mount_size; offset += mount_size;
rest_size -= mount_size; rest_size -= mount_size;
} }
@@ -185,8 +180,6 @@ size_t parlio_rx_mount_transaction_buffer(parlio_rx_unit_handle_t rx_unit, parli
mount_config[required_node_num - 1].buffer = trans->aligned_payload.buf.tail.aligned_buffer; mount_config[required_node_num - 1].buffer = trans->aligned_payload.buf.tail.aligned_buffer;
mount_config[required_node_num - 1].buffer_alignment = trans->alignment; mount_config[required_node_num - 1].buffer_alignment = trans->alignment;
mount_config[required_node_num - 1].length = trans->aligned_payload.buf.tail.length; mount_config[required_node_num - 1].length = trans->aligned_payload.buf.tail.length;
mount_config[required_node_num - 1].flags.bypass_buffer_align_check = false;
mount_config[required_node_num - 1].flags.check_size_align = size_alignment_required;
} }
/* For infinite transaction, link the node as a ring */ /* For infinite transaction, link the node as a ring */
mount_config[required_node_num - 1].flags.mark_final = !trans->flags.infinite ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_HEAD; mount_config[required_node_num - 1].flags.mark_final = !trans->flags.infinite ? GDMA_FINAL_LINK_TO_NULL : GDMA_FINAL_LINK_TO_HEAD;
@@ -476,7 +469,10 @@ static esp_err_t parlio_rx_unit_init_dma(parlio_rx_unit_handle_t rx_unit, size_t
.access_ext_mem = true, .access_ext_mem = true,
}; };
ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); ESP_RETURN_ON_ERROR(gdma_config_transfer(rx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
ESP_RETURN_ON_ERROR(gdma_get_channel_alignment_constraints(rx_unit->dma_chan, &rx_unit->int_mem_align, &rx_unit->ext_mem_align, NULL), TAG, "get alignment constraints failed"); gdma_channel_alignment_info_t align_info;
ESP_RETURN_ON_ERROR(gdma_get_channel_alignment_constraints(rx_unit->dma_chan, &align_info), TAG, "get alignment constraints failed");
rx_unit->int_mem_align = align_info.int_mem_alignment;
rx_unit->ext_mem_align = align_info.ext_enc_mem_alignment;
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA); uint32_t cache_line_size = cache_hal_get_cache_line_size(CACHE_LL_LEVEL_INT_MEM, CACHE_TYPE_DATA);
rx_unit->int_mem_align = rx_unit->int_mem_align > cache_line_size ? rx_unit->int_mem_align : cache_line_size; rx_unit->int_mem_align = rx_unit->int_mem_align > cache_line_size ? rx_unit->int_mem_align : cache_line_size;

View File

@@ -163,7 +163,10 @@ static esp_err_t parlio_tx_unit_init_dma(parlio_tx_unit_t *tx_unit, const parlio
.access_ext_mem = true, // support transmit PSRAM buffer .access_ext_mem = true, // support transmit PSRAM buffer
}; };
ESP_RETURN_ON_ERROR(gdma_config_transfer(tx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); ESP_RETURN_ON_ERROR(gdma_config_transfer(tx_unit->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
gdma_get_channel_alignment_constraints(tx_unit->dma_chan, &tx_unit->int_mem_align, &tx_unit->ext_mem_align, NULL); gdma_channel_alignment_info_t align_info;
gdma_get_channel_alignment_constraints(tx_unit->dma_chan, &align_info);
tx_unit->int_mem_align = align_info.int_mem_alignment;
tx_unit->ext_mem_align = align_info.ext_enc_mem_alignment;
// create DMA link list // create DMA link list
size_t buffer_alignment = MAX(tx_unit->int_mem_align, tx_unit->ext_mem_align); size_t buffer_alignment = MAX(tx_unit->int_mem_align, tx_unit->ext_mem_align);
@@ -463,8 +466,7 @@ esp_err_t parlio_tx_unit_register_event_callbacks(parlio_tx_unit_handle_t tx_uni
static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_t *t) static void parlio_mount_buffer(parlio_tx_unit_t *tx_unit, parlio_tx_trans_desc_t *t)
{ {
size_t buffer_alignment = 0; size_t buffer_alignment = gdma_get_buffer_alignment_constraint(tx_unit->dma_chan, t->payload);
buffer_alignment = gdma_get_buffer_alignment_constraint(tx_unit->dma_chan, t->payload);
// DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up // DMA transfer data based on bytes not bits, so convert the bit length to bytes, round up
size_t payload_bytes = (t->payload_bits + 7) / 8; size_t payload_bytes = (t->payload_bits + 7) / 8;
gdma_buffer_mount_config_t mount_config = { gdma_buffer_mount_config_t mount_config = {

View File

@@ -33,7 +33,6 @@ static inline void rmt_rx_mount_dma_buffer(rmt_rx_channel_t *rx_chan, const void
.buffer_alignment = mem_alignment, .buffer_alignment = mem_alignment,
.flags = { .flags = {
.mark_final = GDMA_FINAL_LINK_TO_DEFAULT, .mark_final = GDMA_FINAL_LINK_TO_DEFAULT,
.check_size_align = gdma_is_size_alignment_required(rx_chan->base.dma_chan),
} }
}; };
} }
@@ -63,9 +62,9 @@ static esp_err_t rmt_rx_init_dma_link(rmt_rx_channel_t *rx_channel, const rmt_rx
ESP_RETURN_ON_ERROR(gdma_register_rx_event_callbacks(rx_channel->base.dma_chan, &cbs, rx_channel), TAG, "register DMA callbacks failed"); ESP_RETURN_ON_ERROR(gdma_register_rx_event_callbacks(rx_channel->base.dma_chan, &cbs, rx_channel), TAG, "register DMA callbacks failed");
// get the alignment requirement from DMA // get the alignment requirement from DMA
size_t dma_int_mem_alignment = 0, dma_ext_mem_alignment = 0; gdma_channel_alignment_info_t align_info;
gdma_get_channel_alignment_constraints(rx_channel->base.dma_chan, &dma_int_mem_alignment, &dma_ext_mem_alignment, NULL); gdma_get_channel_alignment_constraints(rx_channel->base.dma_chan, &align_info);
size_t buffer_alignment = MAX(dma_int_mem_alignment, dma_ext_mem_alignment); size_t buffer_alignment = MAX(align_info.int_mem_alignment, align_info.ext_enc_mem_alignment);
rx_channel->num_dma_nodes = esp_dma_calculate_node_count(config->mem_block_symbols * sizeof(rmt_symbol_word_t), rx_channel->num_dma_nodes = esp_dma_calculate_node_count(config->mem_block_symbols * sizeof(rmt_symbol_word_t),
buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE); buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
rx_channel->num_dma_nodes = MAX(2, rx_channel->num_dma_nodes); // at least 2 DMA nodes for ping-pong rx_channel->num_dma_nodes = MAX(2, rx_channel->num_dma_nodes); // at least 2 DMA nodes for ping-pong

View File

@@ -53,9 +53,10 @@ static esp_err_t rmt_tx_init_dma_link(rmt_tx_channel_t *tx_channel, const rmt_tx
// register the DMA callbacks may fail if the interrupt service can not be installed successfully // register the DMA callbacks may fail if the interrupt service can not be installed successfully
ESP_RETURN_ON_ERROR(gdma_register_tx_event_callbacks(tx_channel->base.dma_chan, &cbs, tx_channel), TAG, "register DMA callbacks failed"); ESP_RETURN_ON_ERROR(gdma_register_tx_event_callbacks(tx_channel->base.dma_chan, &cbs, tx_channel), TAG, "register DMA callbacks failed");
size_t int_alignment = 0; gdma_channel_alignment_info_t align_info;
// get the alignment requirement from DMA // get the alignment requirement from DMA
gdma_get_channel_alignment_constraints(tx_channel->base.dma_chan, &int_alignment, NULL, NULL); gdma_get_channel_alignment_constraints(tx_channel->base.dma_chan, &align_info);
size_t int_alignment = align_info.int_mem_alignment;
// apply RMT hardware alignment requirement // apply RMT hardware alignment requirement
int_alignment = MAX(int_alignment, sizeof(rmt_symbol_word_t)); int_alignment = MAX(int_alignment, sizeof(rmt_symbol_word_t));
// the memory returned by `heap_caps_aligned_calloc` also meets the cache alignment requirement (both address and size) // the memory returned by `heap_caps_aligned_calloc` also meets the cache alignment requirement (both address and size)

View File

@@ -320,8 +320,14 @@ static esp_err_t alloc_dma_chan(spi_host_device_t host_id, spi_dma_chan_t dma_ch
ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->rx_dma_chan, &trans_cfg), SPI_TAG, "config gdma rx transfer failed"); ESP_RETURN_ON_ERROR(gdma_config_transfer(dma_ctx->rx_dma_chan, &trans_cfg), SPI_TAG, "config gdma rx transfer failed");
// Get DMA alignment constraints // Get DMA alignment constraints
gdma_get_channel_alignment_constraints(dma_ctx->tx_dma_chan, &dma_ctx->dma_align_tx_int, &dma_ctx->dma_align_tx_ext, NULL); gdma_channel_alignment_info_t tx_align_info;
gdma_get_channel_alignment_constraints(dma_ctx->rx_dma_chan, &dma_ctx->dma_align_rx_int, &dma_ctx->dma_align_rx_ext, NULL); gdma_get_channel_alignment_constraints(dma_ctx->tx_dma_chan, &tx_align_info);
dma_ctx->dma_align_tx_int = tx_align_info.int_mem_alignment;
dma_ctx->dma_align_tx_ext = tx_align_info.ext_enc_mem_alignment;
gdma_channel_alignment_info_t rx_align_info;
gdma_get_channel_alignment_constraints(dma_ctx->rx_dma_chan, &rx_align_info);
dma_ctx->dma_align_rx_int = rx_align_info.int_mem_alignment;
dma_ctx->dma_align_rx_ext = rx_align_info.ext_enc_mem_alignment;
} }
return ret; return ret;
} }

View File

@@ -211,9 +211,9 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const
gdma_apply_strategy(uhci_ctrl->tx_dir.dma_chan, &strategy_config); gdma_apply_strategy(uhci_ctrl->tx_dir.dma_chan, &strategy_config);
// create DMA link list // create DMA link list
size_t tx_dma_int_mem_alignment = 0, tx_dma_ext_mem_alignment = 0; gdma_channel_alignment_info_t tx_align_info;
gdma_get_channel_alignment_constraints(uhci_ctrl->tx_dir.dma_chan, &tx_dma_int_mem_alignment, &tx_dma_ext_mem_alignment, NULL); gdma_get_channel_alignment_constraints(uhci_ctrl->tx_dir.dma_chan, &tx_align_info);
size_t buffer_alignment = MAX(tx_dma_int_mem_alignment, tx_dma_ext_mem_alignment); size_t buffer_alignment = MAX(tx_align_info.int_mem_alignment, tx_align_info.ext_enc_mem_alignment);
// Given that the combined size of all buffers does not exceed `max_transmit_size` and // Given that the combined size of all buffers does not exceed `max_transmit_size` and
// the number of buffers does not exceed `max_transmit_buffer_count`, a single transfer // the number of buffers does not exceed `max_transmit_buffer_count`, a single transfer
// requires at most `esp_dma_calculate_node_count(max_transmit_size) + max_transmit_buffer_count - 1` DMA descriptors. // requires at most `esp_dma_calculate_node_count(max_transmit_size) + max_transmit_buffer_count - 1` DMA descriptors.
@@ -236,9 +236,9 @@ static esp_err_t uhci_gdma_initialize(uhci_controller_handle_t uhci_ctrl, const
gdma_connect(uhci_ctrl->rx_dir.dma_chan, GDMA_MAKE_TRIGGER(GDMA_TRIG_PERIPH_UHCI, 0)); 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"); ESP_RETURN_ON_ERROR(gdma_config_transfer(uhci_ctrl->rx_dir.dma_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed");
size_t rx_dma_int_mem_alignment = 0, rx_dma_ext_mem_alignment = 0; gdma_channel_alignment_info_t rx_align_info;
gdma_get_channel_alignment_constraints(uhci_ctrl->rx_dir.dma_chan, &rx_dma_int_mem_alignment, &rx_dma_ext_mem_alignment, NULL); gdma_get_channel_alignment_constraints(uhci_ctrl->rx_dir.dma_chan, &rx_align_info);
buffer_alignment = MAX(rx_dma_int_mem_alignment, rx_dma_ext_mem_alignment); buffer_alignment = MAX(rx_align_info.int_mem_alignment, rx_align_info.ext_enc_mem_alignment);
uhci_ctrl->rx_dir.rx_num_dma_nodes = esp_dma_calculate_node_count(config->max_receive_internal_mem, buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE); uhci_ctrl->rx_dir.rx_num_dma_nodes = esp_dma_calculate_node_count(config->max_receive_internal_mem, buffer_alignment, DMA_DESCRIPTOR_BUFFER_MAX_SIZE);
dma_link_config.num_items = uhci_ctrl->rx_dir.rx_num_dma_nodes; dma_link_config.num_items = uhci_ctrl->rx_dir.rx_num_dma_nodes;
ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &uhci_ctrl->rx_dir.dma_link), TAG, "DMA rx link list alloc failed"); ESP_RETURN_ON_ERROR(gdma_new_link_list(&dma_link_config, &uhci_ctrl->rx_dir.dma_link), TAG, "DMA rx link list alloc failed");
@@ -284,11 +284,10 @@ static void uhci_do_transmit(uhci_controller_handle_t uhci_ctrl, uhci_transactio
uhci_ctrl->tx_dir.cur_trans = trans; uhci_ctrl->tx_dir.cur_trans = trans;
size_t buf_count = trans->buf_info_count; size_t buf_count = trans->buf_info_count;
gdma_buffer_mount_config_t *mount_configs = uhci_ctrl->tx_dir.mount_configs; gdma_buffer_mount_config_t *mount_configs = uhci_ctrl->tx_dir.mount_configs;
size_t buffer_alignment = 0;
for (size_t i = 0; i < buf_count; i++) { for (size_t i = 0; i < buf_count; i++) {
bool is_last = (i == buf_count - 1); bool is_last = (i == buf_count - 1);
buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->tx_dir.dma_chan, trans->buf_info[i].write_buffer); size_t buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->tx_dir.dma_chan, trans->buf_info[i].write_buffer);
mount_configs[i] = (gdma_buffer_mount_config_t) { mount_configs[i] = (gdma_buffer_mount_config_t) {
.buffer = (void *)trans->buf_info[i].write_buffer, .buffer = (void *)trans->buf_info[i].write_buffer,
.buffer_alignment = buffer_alignment, .buffer_alignment = buffer_alignment,
@@ -367,7 +366,6 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
ESP_GOTO_ON_FALSE_ISR(uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] != 0 && uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] <= DMA_DESCRIPTOR_BUFFER_MAX_SIZE, ESP_GOTO_ON_FALSE_ISR(uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] != 0 && uhci_ctrl->rx_dir.buffer_size_per_desc_node[i] <= DMA_DESCRIPTOR_BUFFER_MAX_SIZE,
ESP_ERR_INVALID_ARG, err, TAG, "buffer_size is too small or too large"); ESP_ERR_INVALID_ARG, err, TAG, "buffer_size is too small or too large");
size_t buffer_alignment = 0;
buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->rx_dir.dma_chan, read_buffer); buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->rx_dir.dma_chan, read_buffer);
mount_configs[i] = (gdma_buffer_mount_config_t) { mount_configs[i] = (gdma_buffer_mount_config_t) {
.buffer = read_buffer, .buffer = read_buffer,
@@ -375,7 +373,6 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
.length = uhci_ctrl->rx_dir.buffer_size_per_desc_node[i], .length = uhci_ctrl->rx_dir.buffer_size_per_desc_node[i],
.flags = { .flags = {
.mark_final = GDMA_FINAL_LINK_TO_DEFAULT, .mark_final = GDMA_FINAL_LINK_TO_DEFAULT,
.check_size_align = gdma_is_size_alignment_required(uhci_ctrl->rx_dir.dma_chan),
} }
}; };
ESP_DRAM_LOGD(TAG, "The DMA node %d has %d byte", i, uhci_ctrl->rx_dir.buffer_size_per_desc_node[i]); ESP_DRAM_LOGD(TAG, "The DMA node %d has %d byte", i, uhci_ctrl->rx_dir.buffer_size_per_desc_node[i]);

View File

@@ -30,7 +30,7 @@ size_t esp_mspi_get_alignment(const void *ptr)
is_psram_enc = is_psram && !esp_psram_ptr_is_no_enc(ptr); is_psram_enc = is_psram && !esp_psram_ptr_is_no_enc(ptr);
#endif /* CONFIG_SPIRAM */ #endif /* CONFIG_SPIRAM */
if (esp_efuse_is_flash_encryption_enabled() && (generic_query || is_drom || is_psram_enc)) { if ((generic_query || is_drom || is_psram_enc) && esp_efuse_is_flash_encryption_enabled()) {
alignment = MAX(alignment, MSPI_FLASH_ENC_ALIGNMENT); alignment = MAX(alignment, MSPI_FLASH_ENC_ALIGNMENT);
} }

View File

@@ -678,7 +678,10 @@ static esp_err_t lcd_i80_init_dma_link(esp_lcd_i80_bus_handle_t bus, const esp_l
.access_ext_mem = true, // the LCD can carry pixel buffer from the external memory .access_ext_mem = true, // the LCD can carry pixel buffer from the external memory
}; };
ESP_RETURN_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); ESP_RETURN_ON_ERROR(gdma_config_transfer(bus->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
gdma_get_channel_alignment_constraints(bus->dma_chan, &bus->int_mem_align, &bus->ext_mem_align, NULL); gdma_channel_alignment_info_t align_info;
gdma_get_channel_alignment_constraints(bus->dma_chan, &align_info);
bus->int_mem_align = align_info.int_mem_alignment;
bus->ext_mem_align = align_info.ext_enc_mem_alignment;
size_t buffer_alignment = MAX(bus->int_mem_align, bus->ext_mem_align); size_t buffer_alignment = MAX(bus->int_mem_align, bus->ext_mem_align);
size_t num_dma_nodes = esp_dma_calculate_node_count(bus->max_transfer_bytes, buffer_alignment, LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE); size_t num_dma_nodes = esp_dma_calculate_node_count(bus->max_transfer_bytes, buffer_alignment, LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE);

View File

@@ -1244,7 +1244,10 @@ static esp_err_t lcd_rgb_create_dma_channel(esp_rgb_panel_t *rgb_panel)
}; };
ESP_RETURN_ON_ERROR(gdma_config_transfer(rgb_panel->dma_chan, &trans_cfg), TAG, "config DMA transfer failed"); ESP_RETURN_ON_ERROR(gdma_config_transfer(rgb_panel->dma_chan, &trans_cfg), TAG, "config DMA transfer failed");
// get the memory alignment required by the DMA // get the memory alignment required by the DMA
gdma_get_channel_alignment_constraints(rgb_panel->dma_chan, &rgb_panel->int_mem_align, &rgb_panel->ext_mem_align, NULL); gdma_channel_alignment_info_t align_info;
gdma_get_channel_alignment_constraints(rgb_panel->dma_chan, &align_info);
rgb_panel->int_mem_align = align_info.int_mem_alignment;
rgb_panel->ext_mem_align = align_info.ext_enc_mem_alignment;
// register DMA event callbacks // register DMA event callbacks
gdma_tx_event_callbacks_t cbs = { gdma_tx_event_callbacks_t cbs = {
@@ -1358,7 +1361,9 @@ static esp_err_t lcd_rgb_panel_init_trans_link(esp_rgb_panel_t *rgb_panel)
.buffer = rgb_panel->fbs[0] + restart_skip_bytes, .buffer = rgb_panel->fbs[0] + restart_skip_bytes,
.buffer_alignment = buffer_alignment, .buffer_alignment = buffer_alignment,
.length = MIN(LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE, rgb_panel->fb_size) - restart_skip_bytes, .length = MIN(LCD_DMA_DESCRIPTOR_BUFFER_MAX_SIZE, rgb_panel->fb_size) - restart_skip_bytes,
.flags.bypass_buffer_align_check = true, // the restart buffer may doesn't match the buffer alignment but it doesn't really matter in this case // the restart buffer may doesn't match the buffer alignment but it doesn't really matter in this case
.flags.bypass_buffer_addr_align_check = true,
.flags.bypass_buffer_size_align_check = true,
}; };
ESP_RETURN_ON_ERROR(gdma_link_mount_buffers(rgb_panel->dma_restart_link, 0, &restart_buffer_mount_cfg, 1, NULL), ESP_RETURN_ON_ERROR(gdma_link_mount_buffers(rgb_panel->dma_restart_link, 0, &restart_buffer_mount_cfg, 1, NULL),
TAG, "mount DMA restart buffer failed"); TAG, "mount DMA restart buffer failed");

View File

@@ -35,7 +35,7 @@
#define IDF_PERFORMANCE_MIN_AES_GCM_UPDATE_THROUGHPUT_MBSEC 2.1 #define IDF_PERFORMANCE_MIN_AES_GCM_UPDATE_THROUGHPUT_MBSEC 2.1
// SHA256 hardware throughput at 240MHz, threshold set lower than worst case // SHA256 hardware throughput at 240MHz, threshold set lower than worst case
#define IDF_PERFORMANCE_MIN_SHA256_THROUGHPUT_MBSEC 90.0 #define IDF_PERFORMANCE_MIN_SHA256_THROUGHPUT_MBSEC 88.0
// esp_sha() time to process 32KB of input data from RAM // esp_sha() time to process 32KB of input data from RAM
#define IDF_PERFORMANCE_MAX_TIME_SHA1_32KB 900 #define IDF_PERFORMANCE_MAX_TIME_SHA1_32KB 900
#define IDF_PERFORMANCE_MAX_TIME_SHA512_32KB 900 #define IDF_PERFORMANCE_MAX_TIME_SHA512_32KB 900