mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
sdio_slave: fix deinit pin and memory leak issues
This commit is contained in:
@@ -162,7 +162,7 @@ typedef enum {
|
|||||||
ringbuf_free_ptr = offset_of(sdio_ringbuf_t, free_ptr),
|
ringbuf_free_ptr = offset_of(sdio_ringbuf_t, free_ptr),
|
||||||
} sdio_ringbuf_pointer_t;
|
} sdio_ringbuf_pointer_t;
|
||||||
|
|
||||||
#define SDIO_RINGBUF_INITIALIZER() (sdio_ringbuf_t){.write_spinlock = portMUX_INITIALIZER_UNLOCKED,}
|
#define SDIO_RINGBUF_INITIALIZER {.write_spinlock = portMUX_INITIALIZER_UNLOCKED,}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sdio_slave_config_t config;
|
sdio_slave_config_t config;
|
||||||
@@ -191,24 +191,26 @@ typedef struct {
|
|||||||
portMUX_TYPE recv_spinlock;
|
portMUX_TYPE recv_spinlock;
|
||||||
} sdio_context_t;
|
} sdio_context_t;
|
||||||
|
|
||||||
static sdio_context_t context = {
|
#define CONTEXT_INIT_VAL { \
|
||||||
.intr_handle = NULL,
|
.intr_handle = NULL, \
|
||||||
/*------- events ---------------*/
|
/*------- events ---------------*/ \
|
||||||
.events = {},
|
.events = {}, \
|
||||||
.reg_spinlock = portMUX_INITIALIZER_UNLOCKED,
|
.reg_spinlock = portMUX_INITIALIZER_UNLOCKED, \
|
||||||
/*------- sending ---------------*/
|
/*------- sending ---------------*/ \
|
||||||
.send_state = STATE_IDLE,
|
.send_state = STATE_IDLE, \
|
||||||
.sendbuf = SDIO_RINGBUF_INITIALIZER(),
|
.sendbuf = SDIO_RINGBUF_INITIALIZER, \
|
||||||
.ret_queue = NULL,
|
.ret_queue = NULL, \
|
||||||
.in_flight = NULL,
|
.in_flight = NULL, \
|
||||||
.in_flight_end = NULL,
|
.in_flight_end = NULL, \
|
||||||
.in_flight_next = NULL,
|
.in_flight_next = NULL, \
|
||||||
/*------- receiving ---------------*/
|
/*------- receiving ---------------*/ \
|
||||||
.recv_link_list = STAILQ_HEAD_INITIALIZER(context.recv_link_list),
|
.recv_link_list = STAILQ_HEAD_INITIALIZER(context.recv_link_list), \
|
||||||
.recv_reg_list = TAILQ_HEAD_INITIALIZER(context.recv_reg_list),
|
.recv_reg_list = TAILQ_HEAD_INITIALIZER(context.recv_reg_list), \
|
||||||
.recv_cur_ret = NULL,
|
.recv_cur_ret = NULL, \
|
||||||
.recv_spinlock = portMUX_INITIALIZER_UNLOCKED,
|
.recv_spinlock = portMUX_INITIALIZER_UNLOCKED, \
|
||||||
};
|
}
|
||||||
|
|
||||||
|
static sdio_context_t context = CONTEXT_INIT_VAL;
|
||||||
|
|
||||||
static void sdio_intr(void*);
|
static void sdio_intr(void*);
|
||||||
static void sdio_intr_host(void*);
|
static void sdio_intr_host(void*);
|
||||||
@@ -238,7 +240,7 @@ static void sdio_ringbuf_deinit(sdio_ringbuf_t* buf)
|
|||||||
{
|
{
|
||||||
if (buf->remain_cnt != NULL) vSemaphoreDelete(buf->remain_cnt);
|
if (buf->remain_cnt != NULL) vSemaphoreDelete(buf->remain_cnt);
|
||||||
if (buf->data != NULL) free(buf->data);
|
if (buf->data != NULL) free(buf->data);
|
||||||
*buf = SDIO_RINGBUF_INITIALIZER();
|
*buf = (sdio_ringbuf_t) SDIO_RINGBUF_INITIALIZER;
|
||||||
}
|
}
|
||||||
|
|
||||||
static esp_err_t sdio_ringbuf_init(sdio_ringbuf_t* buf, int item_size, int item_cnt)
|
static esp_err_t sdio_ringbuf_init(sdio_ringbuf_t* buf, int item_size, int item_cnt)
|
||||||
@@ -251,7 +253,7 @@ static esp_err_t sdio_ringbuf_init(sdio_ringbuf_t* buf, int item_size, int item_
|
|||||||
//one item is not used.
|
//one item is not used.
|
||||||
buf->size = item_size * (item_cnt+1);
|
buf->size = item_size * (item_cnt+1);
|
||||||
//apply for resources
|
//apply for resources
|
||||||
buf->data = (uint8_t*)malloc(buf->size);
|
buf->data = (uint8_t*)heap_caps_malloc(buf->size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
if (buf->data == NULL) goto no_mem;
|
if (buf->data == NULL) goto no_mem;
|
||||||
buf->remain_cnt = xSemaphoreCreateCounting(item_cnt, item_cnt);
|
buf->remain_cnt = xSemaphoreCreateCounting(item_cnt, item_cnt);
|
||||||
if (buf->remain_cnt == NULL) goto no_mem;
|
if (buf->remain_cnt == NULL) goto no_mem;
|
||||||
@@ -451,6 +453,7 @@ static esp_err_t init_context(sdio_slave_config_t *config)
|
|||||||
{
|
{
|
||||||
SDIO_SLAVE_CHECK(*(uint32_t*)&context.config == 0, "sdio slave already initialized", ESP_ERR_INVALID_STATE);
|
SDIO_SLAVE_CHECK(*(uint32_t*)&context.config == 0, "sdio slave already initialized", ESP_ERR_INVALID_STATE);
|
||||||
|
|
||||||
|
context = (sdio_context_t)CONTEXT_INIT_VAL;
|
||||||
context.config = *config;
|
context.config = *config;
|
||||||
|
|
||||||
// in theory we can queue infinite buffers in the linked list, but for multi-core reason we have to use a queue to
|
// in theory we can queue infinite buffers in the linked list, but for multi-core reason we have to use a queue to
|
||||||
@@ -472,8 +475,6 @@ static esp_err_t init_context(sdio_slave_config_t *config)
|
|||||||
context.ret_queue = xQueueCreate(config->send_queue_size, sizeof(void*));
|
context.ret_queue = xQueueCreate(config->send_queue_size, sizeof(void*));
|
||||||
if (context.ret_queue == NULL) goto no_mem;
|
if (context.ret_queue == NULL) goto no_mem;
|
||||||
|
|
||||||
context.recv_link_list = (buf_stailq_t)STAILQ_HEAD_INITIALIZER(context.recv_link_list);
|
|
||||||
context.recv_reg_list = (buf_tailq_t)TAILQ_HEAD_INITIALIZER(context.recv_reg_list);
|
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
|
|
||||||
no_mem:
|
no_mem:
|
||||||
@@ -485,9 +486,9 @@ static void configure_pin(int pin, uint32_t func, bool pullup)
|
|||||||
{
|
{
|
||||||
const int sdmmc_func = func;
|
const int sdmmc_func = func;
|
||||||
const int drive_strength = 3;
|
const int drive_strength = 3;
|
||||||
assert(pin!=-1);
|
assert(pin != -1);
|
||||||
uint32_t reg = GPIO_PIN_MUX_REG[pin];
|
uint32_t reg = GPIO_PIN_MUX_REG[pin];
|
||||||
assert(reg!=UINT32_MAX);
|
assert(reg != UINT32_MAX);
|
||||||
|
|
||||||
PIN_INPUT_ENABLE(reg);
|
PIN_INPUT_ENABLE(reg);
|
||||||
PIN_FUNC_SELECT(reg, sdmmc_func);
|
PIN_FUNC_SELECT(reg, sdmmc_func);
|
||||||
@@ -574,6 +575,29 @@ static inline esp_err_t sdio_slave_hw_init(sdio_slave_config_t *config)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void recover_pin(int pin, int sdio_func)
|
||||||
|
{
|
||||||
|
uint32_t reg = GPIO_PIN_MUX_REG[pin];
|
||||||
|
assert(reg != UINT32_MAX);
|
||||||
|
|
||||||
|
int func = REG_GET_FIELD(reg, MCU_SEL);
|
||||||
|
if (func == sdio_func) {
|
||||||
|
gpio_set_direction(pin, GPIO_MODE_INPUT);
|
||||||
|
PIN_FUNC_SELECT(reg, PIN_FUNC_GPIO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sdio_slave_hw_deinit(void)
|
||||||
|
{
|
||||||
|
const sdio_slave_slot_info_t *slot = &sdio_slave_slot_info[1];
|
||||||
|
recover_pin(slot->clk_gpio, slot->func);
|
||||||
|
recover_pin(slot->cmd_gpio, slot->func);
|
||||||
|
recover_pin(slot->d0_gpio, slot->func);
|
||||||
|
recover_pin(slot->d1_gpio, slot->func);
|
||||||
|
recover_pin(slot->d2_gpio, slot->func);
|
||||||
|
recover_pin(slot->d3_gpio, slot->func);
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)
|
esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)
|
||||||
{
|
{
|
||||||
esp_err_t r;
|
esp_err_t r;
|
||||||
@@ -594,6 +618,20 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)
|
|||||||
|
|
||||||
void sdio_slave_deinit(void)
|
void sdio_slave_deinit(void)
|
||||||
{
|
{
|
||||||
|
sdio_slave_hw_deinit();
|
||||||
|
|
||||||
|
//unregister all buffers in the queue, and not in the queue
|
||||||
|
buf_desc_t *temp_desc;
|
||||||
|
buf_desc_t *desc;
|
||||||
|
TAILQ_FOREACH_SAFE(desc, &context.recv_reg_list, te, temp_desc) {
|
||||||
|
TAILQ_REMOVE(&context.recv_reg_list, desc, te);
|
||||||
|
free(desc);
|
||||||
|
}
|
||||||
|
STAILQ_FOREACH_SAFE(desc, &context.recv_link_list, qe, temp_desc) {
|
||||||
|
STAILQ_REMOVE(&context.recv_link_list, desc, buf_desc_s, qe);
|
||||||
|
free(desc);
|
||||||
|
}
|
||||||
|
|
||||||
esp_err_t ret = esp_intr_free(context.intr_handle);
|
esp_err_t ret = esp_intr_free(context.intr_handle);
|
||||||
assert(ret==ESP_OK);
|
assert(ret==ESP_OK);
|
||||||
context.intr_handle = NULL;
|
context.intr_handle = NULL;
|
||||||
@@ -1165,9 +1203,9 @@ static void sdio_intr_recv(void* arg)
|
|||||||
// This may cause the ``cur_ret`` pointer to be NULL, indicating the list is empty,
|
// This may cause the ``cur_ret`` pointer to be NULL, indicating the list is empty,
|
||||||
// in this case the ``tx_done`` should happen no longer until new desc is appended.
|
// in this case the ``tx_done`` should happen no longer until new desc is appended.
|
||||||
// The app is responsible to place the pointer to the right place again when appending new desc.
|
// The app is responsible to place the pointer to the right place again when appending new desc.
|
||||||
critical_enter_recv();
|
portENTER_CRITICAL_ISR(&context.recv_spinlock);
|
||||||
context.recv_cur_ret = STAILQ_NEXT(context.recv_cur_ret, qe);
|
context.recv_cur_ret = STAILQ_NEXT(context.recv_cur_ret, qe);
|
||||||
critical_exit_recv();
|
portEXIT_CRITICAL_ISR(&context.recv_spinlock);
|
||||||
ESP_EARLY_LOGV(TAG, "intr_recv: Give");
|
ESP_EARLY_LOGV(TAG, "intr_recv: Give");
|
||||||
xSemaphoreGiveFromISR(context.recv_event, &yield);
|
xSemaphoreGiveFromISR(context.recv_event, &yield);
|
||||||
SLC.slc0_int_clr.tx_done = 1;
|
SLC.slc0_int_clr.tx_done = 1;
|
||||||
@@ -1201,6 +1239,7 @@ esp_err_t sdio_slave_recv_load_buf(sdio_slave_buf_handle_t handle)
|
|||||||
SLC.slc0_tx_link.addr = (uint32_t)desc;
|
SLC.slc0_tx_link.addr = (uint32_t)desc;
|
||||||
SLC.slc0_tx_link.start = 1;
|
SLC.slc0_tx_link.start = 1;
|
||||||
ESP_LOGV(TAG, "recv_load_buf: start new");
|
ESP_LOGV(TAG, "recv_load_buf: start new");
|
||||||
|
SLC.slc0_int_ena.tx_done = 1;
|
||||||
} else {
|
} else {
|
||||||
//restart former ll operation
|
//restart former ll operation
|
||||||
SLC.slc0_tx_link.restart = 1;
|
SLC.slc0_tx_link.restart = 1;
|
||||||
@@ -1216,7 +1255,7 @@ sdio_slave_buf_handle_t sdio_slave_recv_register_buf(uint8_t *start)
|
|||||||
{
|
{
|
||||||
SDIO_SLAVE_CHECK(esp_ptr_dma_capable(start) && (uint32_t)start%4==0,
|
SDIO_SLAVE_CHECK(esp_ptr_dma_capable(start) && (uint32_t)start%4==0,
|
||||||
"buffer to register should be DMA capable and 32-bit aligned", NULL);
|
"buffer to register should be DMA capable and 32-bit aligned", NULL);
|
||||||
buf_desc_t *desc = (buf_desc_t*)malloc(sizeof(buf_desc_t));
|
buf_desc_t *desc = (buf_desc_t*)heap_caps_malloc(sizeof(buf_desc_t), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||||
if (desc == NULL) {
|
if (desc == NULL) {
|
||||||
SDIO_SLAVE_LOGE("cannot allocate lldesc for new buffer");
|
SDIO_SLAVE_LOGE("cannot allocate lldesc for new buffer");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
Reference in New Issue
Block a user