mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 18:50:34 +03:00
feat(mspi): split dma and mspi alignment
This commit is contained in:
committed by
Chen Ji Chang
parent
ef4387144e
commit
305d434bda
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/param.h>
|
||||
#include "esp_intr_alloc.h"
|
||||
#if CONFIG_UHCI_ENABLE_DEBUG_LOG
|
||||
// The local log level must be defined before including esp_log.h
|
||||
@@ -26,13 +27,10 @@
|
||||
#include "hal/uhci_hal.h"
|
||||
#include "hal/uhci_ll.h"
|
||||
#include "hal/dma_types.h"
|
||||
#include "hal/cache_hal.h"
|
||||
#include "hal/cache_ll.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "esp_private/gdma.h"
|
||||
#include "esp_private/esp_dma_utils.h"
|
||||
#include "esp_private/gdma_link.h"
|
||||
#include "esp_private/esp_cache_private.h"
|
||||
#include "esp_private/esp_psram_mspi.h"
|
||||
#include "uhci_private.h"
|
||||
#include "esp_memory_utils.h"
|
||||
@@ -213,8 +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);
|
||||
|
||||
// create DMA link list
|
||||
gdma_get_alignment_constraints(uhci_ctrl->tx_dir.dma_chan, &uhci_ctrl->tx_dir.int_mem_align, &uhci_ctrl->tx_dir.ext_mem_align);
|
||||
size_t buffer_alignment = UHCI_MAX(uhci_ctrl->tx_dir.int_mem_align, uhci_ctrl->tx_dir.ext_mem_align);
|
||||
size_t tx_dma_int_mem_alignment = 0, tx_dma_ext_mem_alignment = 0;
|
||||
gdma_get_channel_alignment_constraints(uhci_ctrl->tx_dir.dma_chan, &tx_dma_int_mem_alignment, &tx_dma_ext_mem_alignment, NULL);
|
||||
size_t buffer_alignment = MAX(tx_dma_int_mem_alignment, tx_dma_ext_mem_alignment);
|
||||
// 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
|
||||
// requires at most `esp_dma_calculate_node_count(max_transmit_size) + max_transmit_buffer_count - 1` DMA descriptors.
|
||||
@@ -237,8 +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));
|
||||
ESP_RETURN_ON_ERROR(gdma_config_transfer(uhci_ctrl->rx_dir.dma_chan, &transfer_cfg), TAG, "Config DMA rx channel transfer failed");
|
||||
|
||||
gdma_get_alignment_constraints(uhci_ctrl->rx_dir.dma_chan, &uhci_ctrl->rx_dir.int_mem_align, &uhci_ctrl->rx_dir.ext_mem_align);
|
||||
buffer_alignment = UHCI_MAX(uhci_ctrl->rx_dir.int_mem_align, uhci_ctrl->rx_dir.ext_mem_align);
|
||||
size_t rx_dma_int_mem_alignment = 0, rx_dma_ext_mem_alignment = 0;
|
||||
gdma_get_channel_alignment_constraints(uhci_ctrl->rx_dir.dma_chan, &rx_dma_int_mem_alignment, &rx_dma_ext_mem_alignment, NULL);
|
||||
buffer_alignment = MAX(rx_dma_int_mem_alignment, rx_dma_ext_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);
|
||||
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");
|
||||
@@ -284,10 +284,11 @@ static void uhci_do_transmit(uhci_controller_handle_t uhci_ctrl, uhci_transactio
|
||||
uhci_ctrl->tx_dir.cur_trans = trans;
|
||||
size_t buf_count = trans->buf_info_count;
|
||||
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++) {
|
||||
bool is_last = (i == buf_count - 1);
|
||||
size_t buffer_alignment = esp_ptr_internal(trans->buf_info[i].write_buffer) ? uhci_ctrl->tx_dir.int_mem_align : uhci_ctrl->tx_dir.ext_mem_align;
|
||||
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) {
|
||||
.buffer = (void *)trans->buf_info[i].write_buffer,
|
||||
.buffer_alignment = buffer_alignment,
|
||||
@@ -324,9 +325,11 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
|
||||
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
const uint32_t mem_cache_line_size = esp_ptr_external_ram(read_buffer) ? uhci_ctrl->ext_mem_cache_line_size : uhci_ctrl->int_mem_cache_line_size;
|
||||
// Must take cache line into consideration for C2M operation.
|
||||
const uint32_t max_alignment_needed = UHCI_MAX(UHCI_MAX(uhci_ctrl->rx_dir.int_mem_align, uhci_ctrl->rx_dir.ext_mem_align), mem_cache_line_size);
|
||||
const uint32_t mem_cache_line_size = esp_cache_get_line_size_by_addr(read_buffer);
|
||||
|
||||
size_t buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->rx_dir.dma_chan, read_buffer);
|
||||
const uint32_t max_alignment_needed = MAX(buffer_alignment, mem_cache_line_size);
|
||||
uhci_ctrl->rx_dir.cache_line = mem_cache_line_size;
|
||||
|
||||
// Align the read_buffer pointer to mem_cache_line_size
|
||||
@@ -364,13 +367,15 @@ 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_ERR_INVALID_ARG, err, TAG, "buffer_size is too small or too large");
|
||||
|
||||
size_t buffer_alignment = esp_ptr_internal(read_buffer) ? uhci_ctrl->rx_dir.int_mem_align : uhci_ctrl->rx_dir.ext_mem_align;
|
||||
size_t buffer_alignment = 0;
|
||||
buffer_alignment = gdma_get_buffer_alignment_constraint(uhci_ctrl->rx_dir.dma_chan, read_buffer);
|
||||
mount_configs[i] = (gdma_buffer_mount_config_t) {
|
||||
.buffer = read_buffer,
|
||||
.buffer_alignment = buffer_alignment,
|
||||
.length = uhci_ctrl->rx_dir.buffer_size_per_desc_node[i],
|
||||
.flags = {
|
||||
.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]);
|
||||
@@ -382,8 +387,7 @@ static esp_err_t uhci_receive_internal(uhci_controller_handle_t uhci_ctrl, uint8
|
||||
|
||||
// Invalidate cache before DMA starts to ensure no dirty cache lines.
|
||||
// All DMA nodes (mount_configs) share the same contiguous user buffer, so checking mount_configs[0].buffer is sufficient.
|
||||
bool need_cache_sync = esp_ptr_internal(mount_configs[0].buffer) ? (uhci_ctrl->int_mem_cache_line_size > 0) : (uhci_ctrl->ext_mem_cache_line_size > 0);
|
||||
if (need_cache_sync) {
|
||||
if (esp_cache_get_line_size_by_addr(mount_configs[0].buffer) > 0) {
|
||||
ESP_GOTO_ON_ERROR_ISR(esp_cache_msync(mount_configs[0].buffer, usable_size, ESP_CACHE_MSYNC_FLAG_DIR_M2C), err, TAG, "cache sync failed");
|
||||
}
|
||||
}
|
||||
@@ -465,20 +469,7 @@ esp_err_t uhci_multi_buffer_transmit(uhci_controller_handle_t uhci_ctrl, const u
|
||||
|
||||
total_size += write_size;
|
||||
|
||||
size_t alignment = 0;
|
||||
size_t cache_line_size = 0;
|
||||
if (esp_ptr_external_ram(write_buffer)) {
|
||||
alignment = uhci_ctrl->tx_dir.ext_mem_align;
|
||||
cache_line_size = uhci_ctrl->ext_mem_cache_line_size;
|
||||
} else {
|
||||
alignment = uhci_ctrl->tx_dir.int_mem_align;
|
||||
cache_line_size = uhci_ctrl->int_mem_cache_line_size;
|
||||
}
|
||||
|
||||
ESP_RETURN_ON_FALSE(((((uintptr_t)write_buffer) & (alignment - 1)) == 0) && (((write_size) & (alignment - 1)) == 0), ESP_ERR_INVALID_ARG,
|
||||
TAG, "buffer segment %zu address or size are not %zu bytes aligned", i, alignment);
|
||||
|
||||
if (cache_line_size > 0) {
|
||||
if (esp_cache_get_line_size_by_addr(write_buffer) > 0) {
|
||||
// Write back to cache to synchronize the cache before DMA start
|
||||
ESP_RETURN_ON_ERROR(esp_cache_msync((void *)write_buffer, write_size, ESP_CACHE_MSYNC_FLAG_DIR_C2M | ESP_CACHE_MSYNC_FLAG_UNALIGNED), TAG, "cache sync failed");
|
||||
}
|
||||
@@ -673,9 +664,6 @@ esp_err_t uhci_new_controller(const uhci_controller_config_t *config, uhci_contr
|
||||
uhci_ll_rx_set_eof_mode(uhci_ctrl->hal.dev, UHCI_RX_BREAK_CHR_EOF);
|
||||
}
|
||||
|
||||
esp_cache_get_alignment(MALLOC_CAP_SPIRAM, &uhci_ctrl->ext_mem_cache_line_size);
|
||||
esp_cache_get_alignment(MALLOC_CAP_INTERNAL, &uhci_ctrl->int_mem_cache_line_size);
|
||||
|
||||
ESP_GOTO_ON_ERROR(uhci_gdma_initialize(uhci_ctrl, config), err, TAG, "uhci gdma initialize failed");
|
||||
|
||||
// rx_num_dma_nodes is only known after uhci_gdma_initialize() queried the DMA alignment, so the
|
||||
|
||||
@@ -23,7 +23,6 @@ extern "C" {
|
||||
typedef struct uhci_controller_t uhci_controller_t;
|
||||
|
||||
#define UHCI_ALIGN_UP(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
#define UHCI_MAX(a, b) (((a)>(b))?(a):(b))
|
||||
|
||||
#define UHCI_PM_LOCK_NAME_LEN_MAX 16
|
||||
|
||||
@@ -70,8 +69,6 @@ typedef struct {
|
||||
uhci_transaction_desc_t *cur_trans; // pointer to current transaction
|
||||
QueueHandle_t trans_queues[UHCI_TRANS_QUEUE_MAX]; // transaction queue
|
||||
_Atomic uhci_tx_fsm_t tx_fsm; // channel life cycle specific FSM
|
||||
size_t int_mem_align; // Alignment for internal memory
|
||||
size_t ext_mem_align; // Alignment for external memory
|
||||
atomic_int num_trans_inflight; // Indicates the number of transactions that are undergoing but not recycled to ready_queue
|
||||
size_t max_transmit_size; // per-transaction max total size in bytes, from config->max_transmit_size; the DMA node pool is sized for this
|
||||
size_t max_buf_count; // per-transaction max buffer segment count, from config->max_transmit_buffer_count (at least 1)
|
||||
@@ -87,8 +84,6 @@ typedef struct {
|
||||
uint8_t **buffer_pointers; // Pointer for saving buffer pointer
|
||||
_Atomic uhci_rx_fsm_t rx_fsm; // channel life cycle specific FSM
|
||||
size_t cache_line; // cache line size need to be aligned up.
|
||||
size_t int_mem_align; // Alignment for internal memory
|
||||
size_t ext_mem_align; // Alignment for external memory
|
||||
size_t rx_num_dma_nodes; // rx dma number nodes
|
||||
gdma_buffer_mount_config_t *mount_configs; // scratch array (capacity rx_num_dma_nodes) reused by every receive to mount buffer segments; avoids a VLA in ISR context
|
||||
bool continuous; // continuous mode: keep DMA running across EOFs instead of stopping
|
||||
@@ -100,8 +95,6 @@ struct uhci_controller_t {
|
||||
uhci_tx_dir tx_dir; // tx direction structure
|
||||
uhci_rx_dir rx_dir; // rx direction structure
|
||||
void *user_data; // user data
|
||||
size_t int_mem_cache_line_size; // internal memory cache line size
|
||||
size_t ext_mem_cache_line_size; // external memory cache line size
|
||||
#if CONFIG_PM_ENABLE
|
||||
esp_pm_lock_handle_t pm_lock; // power management lock
|
||||
char pm_lock_name[UHCI_PM_LOCK_NAME_LEN_MAX]; // pm lock name
|
||||
|
||||
Reference in New Issue
Block a user