refactor(driver_spi): slave hd move dma context to driver layer

This commit is contained in:
wanckl
2026-07-29 16:26:54 +08:00
parent 96e4fc85a0
commit 9ce985dca0
3 changed files with 76 additions and 83 deletions

View File

@@ -5,6 +5,7 @@
*/
#include <stdatomic.h>
#include <sys/param.h>
#include "esp_compiler.h"
#include "esp_log.h"
#include "esp_check.h"
@@ -41,6 +42,26 @@ typedef struct {
bool dma_hw_error; //true if DMA hardware over/underflow occurred
} spi_slave_hd_trans_priv_t;
typedef struct {
spi_dma_desc_t *desc; // DMA descriptor
void *arg; // Original transaction descriptor
} slave_hd_append_desc_t;
/** append dma pool layout
*
* |**********............-------*******|
* ^ ^ ^ ^
* | | | |
* root done hw_eof free
*/
typedef struct {
slave_hd_append_desc_t *desc_root; ///< Root of the DMA descriptors.
slave_hd_append_desc_t *free_desc; ///< Current DMA descriptor that could be linked (set up).
slave_hd_append_desc_t *done_desc; ///< Head of the finished descriptors which are not dealed by software
uint32_t eof_desc; ///< DMA desc of current end
uint32_t used_desc_cnt; ///< Number of the descriptors that have been setup
} slave_hd_append_context_t;
typedef struct {
spi_host_device_t host_id;
int cs_io_num;
@@ -53,6 +74,8 @@ typedef struct {
spi_slave_hd_callback_config_t callback;
spi_slave_hd_hal_context_t hal;
bool append_mode;
slave_hd_append_context_t append_tx_ctx;
slave_hd_append_context_t append_rx_ctx;
QueueHandle_t tx_trans_queue;
QueueHandle_t tx_ret_queue;
@@ -113,6 +136,7 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
SPIHD_CHECK((bus_config->intr_flags & ESP_INTR_FLAG_IRAM) == 0, "ESP_INTR_FLAG_IRAM should be disabled when CONFIG_SPI_SLAVE_ISR_IN_IRAM is not set.", ESP_ERR_INVALID_ARG);
#endif
SPIHD_CHECK(!three_wire_mode || GPIO_IS_VALID_OUTPUT_GPIO(bus_config->mosi_io_num), "mosi pin must be output capable in 3-wire mode", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(!append_mode || bus_config->max_transfer_sz > SPI_MAX_DMA_LEN, "max_transfer_sz must greater than 4092 to using append mode", ESP_ERR_INVALID_ARG);
SPIHD_CHECK(ESP_OK == spicommon_bus_alloc(host_id, "slave_hd"), "host already in use", ESP_ERR_INVALID_STATE);
// spi_slave_hd_slot_t contains atomic variable, memory must be allocated from internal memory
@@ -149,18 +173,24 @@ esp_err_t spi_slave_hd_init(spi_host_device_t host_id, const spi_bus_config_t *b
goto cleanup;
}
host->hal.dma_desc_num = host->dma_ctx->dma_desc_num;
host->hal.dmadesc_tx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
host->hal.dmadesc_rx = heap_caps_malloc(sizeof(spi_slave_hd_hal_desc_append_t) * host->hal.dma_desc_num, MALLOC_CAP_DEFAULT);
if (!(host->hal.dmadesc_tx && host->hal.dmadesc_rx)) {
slave_hd_append_context_t *append_tx = &host->append_tx_ctx;
slave_hd_append_context_t *append_rx = &host->append_rx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
append_tx->desc_root = heap_caps_malloc(sizeof(slave_hd_append_desc_t) * dma_desc_num, MALLOC_CAP_DEFAULT);
append_rx->desc_root = heap_caps_malloc(sizeof(slave_hd_append_desc_t) * dma_desc_num, MALLOC_CAP_DEFAULT);
if (!(append_tx->desc_root && append_rx->desc_root)) {
ret = ESP_ERR_NO_MEM;
goto cleanup;
}
//Pair each desc to each possible trans
for (int i = 0; i < host->hal.dma_desc_num; i ++) {
host->hal.dmadesc_tx[i].desc = &host->dma_ctx->dmadesc_tx[i];
host->hal.dmadesc_rx[i].desc = &host->dma_ctx->dmadesc_rx[i];
for (int i = 0; i < dma_desc_num; i ++) {
append_tx->desc_root[i].desc = &host->dma_ctx->dmadesc_tx[i];
append_rx->desc_root[i].desc = &host->dma_ctx->dmadesc_rx[i];
}
append_tx->free_desc = append_tx->desc_root;
append_rx->free_desc = append_rx->desc_root;
append_tx->done_desc = append_tx->desc_root + dma_desc_num - 1;
append_rx->done_desc = append_rx->desc_root + dma_desc_num - 1;
ret = spicommon_bus_initialize_io(host_id, bus_config, SPICOMMON_BUSFLAG_SLAVE | bus_config->flags, NULL);
if (ret != ESP_OK) {
@@ -350,8 +380,8 @@ esp_err_t spi_slave_hd_deinit(spi_host_device_t host_id)
spicommon_bus_free_io_cfg(host_id);
spicommon_cs_free_io(host->cs_io_num, &host->bus_attr->gpio_reserve);
free(host->hal.dmadesc_tx);
free(host->hal.dmadesc_rx);
free(host->append_tx_ctx.desc_root);
free(host->append_rx_ctx.desc_root);
spicommon_dma_chan_free(host_id);
spicommon_bus_free(host_id);
@@ -561,7 +591,7 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_segment_isr(void *arg)
}
}
static inline SPI_SLAVE_ISR_ATTR void slave_hd_append_desc_walk(spi_slave_hd_hal_desc_append_t *desc_head, uint32_t desc_num, spi_slave_hd_hal_desc_append_t **p_desc, uint32_t steps)
static inline SPI_SLAVE_ISR_ATTR void slave_hd_append_desc_walk(slave_hd_append_desc_t *desc_head, uint32_t desc_num, slave_hd_append_desc_t **p_desc, uint32_t steps)
{
steps %= desc_num;
*p_desc += steps;
@@ -574,20 +604,21 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_tx_isr(void *arg)
{
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg;
spi_slave_hd_callback_config_t *callback = &host->callback;
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_tx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
while ((uint32_t)hal->tx_dma_head->desc != hal->current_eof_addr) {
slave_hd_append_desc_walk(hal->dmadesc_tx, hal->dma_desc_num, &hal->tx_dma_head, 1);
int offset = hal->tx_dma_head - hal->dmadesc_tx;
while ((uint32_t)append->done_desc->desc != append->eof_desc) {
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->done_desc, 1);
int offset = append->done_desc - append->desc_root;
spi_slave_hd_trans_priv_t ret_priv_trans = {
.trans = hal->tx_dma_head->arg,
.trans = append->done_desc->arg,
.aligned_buffer = gdma_link_get_buffer(host->dma_ctx->tx_link_handle, offset),
};
portENTER_CRITICAL_ISR(&host->int_spinlock);
hal->tx_used_desc_cnt--;
append->used_desc_cnt--;
portEXIT_CRITICAL_ISR(&host->int_spinlock);
bool ret_queue = true;
@@ -619,21 +650,22 @@ static SPI_SLAVE_ISR_ATTR void spi_slave_hd_append_rx_isr(void *arg)
{
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)arg;
spi_slave_hd_callback_config_t *callback = &host->callback;
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_rx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
BaseType_t awoken = pdFALSE;
BaseType_t ret __attribute__((unused));
while ((uint32_t)hal->rx_dma_head->desc != hal->current_eof_addr) {
slave_hd_append_desc_walk(hal->dmadesc_rx, hal->dma_desc_num, &hal->rx_dma_head, 1);
int offset = hal->rx_dma_head - hal->dmadesc_rx;
while ((uint32_t)append->done_desc->desc != append->eof_desc) {
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->done_desc, 1);
int offset = append->done_desc - append->desc_root;
spi_slave_hd_trans_priv_t ret_priv_trans = {
.trans = hal->rx_dma_head->arg,
.trans = append->done_desc->arg,
.aligned_buffer = gdma_link_get_buffer(host->dma_ctx->rx_link_handle, offset),
};
ret_priv_trans.trans->trans_len = gdma_link_get_length(host->dma_ctx->rx_link_handle, offset);
portENTER_CRITICAL_ISR(&host->int_spinlock);
hal->rx_used_desc_cnt--;
append->used_desc_cnt--;
portEXIT_CRITICAL_ISR(&host->int_spinlock);
bool ret_queue = true;
@@ -668,10 +700,11 @@ static SPI_SLAVE_ISR_ATTR bool s_spi_slave_hd_append_gdma_isr(gdma_channel_handl
assert(event_data);
spi_slave_hd_slot_t *host = (spi_slave_hd_slot_t*)user_data;
host->hal.current_eof_addr = event_data->tx_eof_desc_addr;
if (host->dma_ctx->tx_dma_chan == dma_chan) {
host->append_tx_ctx.eof_desc = event_data->tx_eof_desc_addr;
spi_slave_hd_append_tx_isr(user_data);
} else {
host->append_rx_ctx.eof_desc = event_data->rx_eof_desc_addr;
spi_slave_hd_append_rx_isr(user_data);
}
return true;
@@ -687,11 +720,11 @@ static SPI_SLAVE_ISR_ATTR void s_spi_slave_hd_append_legacy_isr(void *arg)
portENTER_CRITICAL_ISR(&host->int_spinlock);
if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_RECV)) {
hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->rx_dma_chan);
host->append_rx_ctx.eof_desc = spi_dma_get_eof_desc(host->dma_ctx->rx_dma_chan);
rx_done = true;
}
if (spi_slave_hd_hal_check_clear_event(hal, SPI_EV_SEND)) {
hal->current_eof_addr = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan);
host->append_tx_ctx.eof_desc = spi_dma_get_eof_desc(host->dma_ctx->tx_dma_chan);
tx_done = true;
}
portEXIT_CRITICAL_ISR(&host->int_spinlock);
@@ -753,39 +786,39 @@ static esp_err_t get_ret_queue_result(spi_host_device_t host_id, spi_slave_chan_
esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data, size_t len, void *arg)
{
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_tx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
//Check if there are enough available DMA descriptors for software to use
int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_tx_int : host->dma_ctx->dma_align_tx_ext;
// unsupported buffer which lead invalid buf_align should already checked by 'setup_priv_trans'
int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align));
int available_desc_num = hal->dma_desc_num - hal->tx_used_desc_cnt;
int available_desc_num = dma_desc_num - append->used_desc_cnt;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
int offset = hal->tx_cur_desc - hal->dmadesc_tx;
int offset = append->free_desc - append->desc_root;
spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, false);
hal->tx_cur_desc->arg = arg;
append->free_desc->arg = arg;
if (!hal->tx_used_desc_cnt) {
if (!append->used_desc_cnt) {
//start a link
hal->tx_dma_tail = hal->tx_cur_desc;
spi_dma_reset(host->dma_ctx->tx_dma_chan);
spi_slave_hd_hal_hw_prepare_tx(hal);
spi_dma_start(host->dma_ctx->tx_dma_chan, hal->tx_cur_desc->desc);
spi_dma_start(host->dma_ctx->tx_dma_chan, append->free_desc->desc);
} else {
//there is already a consecutive link
gdma_link_list_handle_t link_handle = host->dma_ctx->tx_link_handle;
gdma_link_concat(link_handle, offset - 1, link_handle, offset);
hal->tx_dma_tail = hal->tx_cur_desc;
spi_dma_append(host->dma_ctx->tx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
portENTER_CRITICAL(&host->int_spinlock);
hal->tx_used_desc_cnt += num_required;
append->used_desc_cnt += num_required;
portEXIT_CRITICAL(&host->int_spinlock);
slave_hd_append_desc_walk(hal->dmadesc_tx, hal->dma_desc_num, &hal->tx_cur_desc, num_required);
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->free_desc, num_required);
return ESP_OK;
}
@@ -793,38 +826,38 @@ esp_err_t s_spi_slave_hd_append_txdma(spi_slave_hd_slot_t *host, uint8_t *data,
esp_err_t s_spi_slave_hd_append_rxdma(spi_slave_hd_slot_t *host, uint8_t *data, size_t len, void *arg)
{
spi_slave_hd_hal_context_t *hal = &host->hal;
slave_hd_append_context_t *append = &host->append_rx_ctx;
uint32_t dma_desc_num = host->dma_ctx->dma_desc_num;
//Check if there are enough available dma descriptors for software to use
int buf_align = esp_ptr_internal(data) ? host->dma_ctx->dma_align_rx_int : host->dma_ctx->dma_align_rx_ext;
int num_required = howmany(len, ESP_ALIGN_DOWN(DMA_DESCRIPTOR_BUFFER_MAX_SIZE, buf_align));
int available_desc_num = hal->dma_desc_num - hal->rx_used_desc_cnt;
int available_desc_num = dma_desc_num - append->used_desc_cnt;
if (num_required > available_desc_num) {
return ESP_ERR_INVALID_STATE;
}
int offset = hal->rx_cur_desc - hal->dmadesc_rx;
int offset = append->free_desc - append->desc_root;
spicommon_dma_desc_setup_link(host->dma_ctx, offset, data, len, true);
hal->rx_cur_desc->arg = arg;
append->free_desc->arg = arg;
if (!hal->rx_used_desc_cnt) {
if (!append->used_desc_cnt) {
//start a link
hal->rx_dma_tail = hal->rx_cur_desc;
spi_dma_reset(host->dma_ctx->rx_dma_chan);
spi_slave_hd_hal_hw_prepare_rx(hal);
spi_dma_start(host->dma_ctx->rx_dma_chan, hal->rx_cur_desc->desc);
spi_dma_start(host->dma_ctx->rx_dma_chan, append->free_desc->desc);
} else {
//there is already a consecutive link
gdma_link_list_handle_t link_handle = host->dma_ctx->rx_link_handle;
gdma_link_concat(link_handle, offset - 1, link_handle, offset);
hal->rx_dma_tail = hal->rx_cur_desc;
spi_dma_append(host->dma_ctx->rx_dma_chan);
}
//Move the current descriptor pointer according to the number of the linked descriptors
portENTER_CRITICAL(&host->int_spinlock);
hal->rx_used_desc_cnt += num_required;
append->used_desc_cnt += num_required;
portEXIT_CRITICAL(&host->int_spinlock);
slave_hd_append_desc_walk(hal->dmadesc_rx, hal->dma_desc_num, &hal->rx_cur_desc, num_required);
slave_hd_append_desc_walk(append->desc_root, dma_desc_num, &append->free_desc, num_required);
return ESP_OK;
}

View File

@@ -47,8 +47,6 @@
#include "esp_err.h"
#include "soc/soc_caps.h"
#include "hal/spi_types.h"
#include "hal/dma_types.h"
#include "hal/gdma_types.h"
#if SOC_GPSPI_SUPPORTED
#include "hal/spi_ll.h"
#endif
@@ -59,26 +57,6 @@ extern "C" {
#if SOC_GPSPI_SUPPORTED
//NOTE!! If both A and B are not defined, '#if (A==B)' is true, because GCC use 0 stand for undefined symbol
#if !defined(SOC_GDMA_TRIG_PERIPH_SPI2_BUS)
typedef dma_descriptor_align4_t spi_dma_desc_t;
#else
#if defined(SOC_GDMA_BUS_AXI) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AXI)
typedef dma_descriptor_align8_t spi_dma_desc_t;
#elif defined(SOC_GDMA_BUS_AHB) && (SOC_GDMA_TRIG_PERIPH_SPI2_BUS == SOC_GDMA_BUS_AHB)
typedef dma_descriptor_align4_t spi_dma_desc_t;
#endif
#endif
/**
* @brief Type of dma descriptor with appended members
* this structure inherits DMA descriptor, with a pointer to the transaction descriptor passed from users.
*/
typedef struct {
spi_dma_desc_t *desc; ///< DMA descriptor
void *arg; ///< This points to the transaction descriptor user passed in
} spi_slave_hd_hal_desc_append_t;
/// Configuration of the HAL
typedef struct {
uint32_t host_id; ///< Host ID of the spi peripheral
@@ -99,22 +77,8 @@ typedef struct {
/// Context of the HAL, initialized by :cpp:func:`spi_slave_hd_hal_init`.
typedef struct {
/* These two need to be malloced by the driver first */
spi_slave_hd_hal_desc_append_t *dmadesc_tx; ///< Head of the TX DMA descriptors.
spi_slave_hd_hal_desc_append_t *dmadesc_rx; ///< Head of the RX DMA descriptors.
/* address of the hardware */
spi_dev_t *dev; ///< Beginning address of the peripheral registers.
uint32_t dma_desc_num; ///< Number of the available DMA descriptors. Calculated from ``bus_max_transfer_size``.
uint32_t current_eof_addr;
spi_slave_hd_hal_desc_append_t *tx_cur_desc; ///< Current TX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *tx_dma_head; ///< Head of the linked TX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *tx_dma_tail; ///< Tail of the linked TX DMA descriptors which are not used by hardware
uint32_t tx_used_desc_cnt; ///< Number of the TX descriptors that have been setup
spi_slave_hd_hal_desc_append_t *rx_cur_desc; ///< Current RX DMA descriptor that could be linked (set up).
spi_slave_hd_hal_desc_append_t *rx_dma_head; ///< Head of the linked RX DMA descriptors which are not used by hardware
spi_slave_hd_hal_desc_append_t *rx_dma_tail; ///< Tail of the linked RX DMA descriptors which are not used by hardware
uint32_t rx_used_desc_cnt; ///< Number of the RX descriptors that have been setup
/* Internal status used by the HAL implementation, initialized as 0. */
uint32_t intr_not_triggered;

View File

@@ -19,10 +19,6 @@ void spi_slave_hd_hal_init(spi_slave_hd_hal_context_t *hal, const spi_slave_hd_h
{
spi_dev_t *hw = spi_periph_signal[hal_config->host_id].hw;
hal->dev = hw;
hal->tx_cur_desc = hal->dmadesc_tx;
hal->rx_cur_desc = hal->dmadesc_rx;
hal->tx_dma_head = hal->dmadesc_tx + hal->dma_desc_num - 1;
hal->rx_dma_head = hal->dmadesc_rx + hal->dma_desc_num - 1;
spi_ll_slave_hd_init(hw);
spi_ll_set_addr_bitlen(hw, hal_config->address_bits);