mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
sdio_slave: fix deinit pin and memory leak issues
This commit is contained in:
parent
087c8f6065
commit
e2b20f2e4b
@ -162,7 +162,7 @@ typedef enum {
|
||||
ringbuf_free_ptr = offset_of(sdio_ringbuf_t, free_ptr),
|
||||
} 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 {
|
||||
sdio_slave_config_t config;
|
||||
@ -191,24 +191,26 @@ typedef struct {
|
||||
portMUX_TYPE recv_spinlock;
|
||||
} sdio_context_t;
|
||||
|
||||
static sdio_context_t context = {
|
||||
.intr_handle = NULL,
|
||||
/*------- events ---------------*/
|
||||
.events = {},
|
||||
.reg_spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
/*------- sending ---------------*/
|
||||
.send_state = STATE_IDLE,
|
||||
.sendbuf = SDIO_RINGBUF_INITIALIZER(),
|
||||
.ret_queue = NULL,
|
||||
.in_flight = NULL,
|
||||
.in_flight_end = NULL,
|
||||
.in_flight_next = NULL,
|
||||
/*------- receiving ---------------*/
|
||||
.recv_link_list = STAILQ_HEAD_INITIALIZER(context.recv_link_list),
|
||||
.recv_reg_list = TAILQ_HEAD_INITIALIZER(context.recv_reg_list),
|
||||
.recv_cur_ret = NULL,
|
||||
.recv_spinlock = portMUX_INITIALIZER_UNLOCKED,
|
||||
};
|
||||
#define CONTEXT_INIT_VAL { \
|
||||
.intr_handle = NULL, \
|
||||
/*------- events ---------------*/ \
|
||||
.events = {}, \
|
||||
.reg_spinlock = portMUX_INITIALIZER_UNLOCKED, \
|
||||
/*------- sending ---------------*/ \
|
||||
.send_state = STATE_IDLE, \
|
||||
.sendbuf = SDIO_RINGBUF_INITIALIZER, \
|
||||
.ret_queue = NULL, \
|
||||
.in_flight = NULL, \
|
||||
.in_flight_end = NULL, \
|
||||
.in_flight_next = NULL, \
|
||||
/*------- receiving ---------------*/ \
|
||||
.recv_link_list = STAILQ_HEAD_INITIALIZER(context.recv_link_list), \
|
||||
.recv_reg_list = TAILQ_HEAD_INITIALIZER(context.recv_reg_list), \
|
||||
.recv_cur_ret = NULL, \
|
||||
.recv_spinlock = portMUX_INITIALIZER_UNLOCKED, \
|
||||
}
|
||||
|
||||
static sdio_context_t context = CONTEXT_INIT_VAL;
|
||||
|
||||
static void sdio_intr(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->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)
|
||||
@ -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.
|
||||
buf->size = item_size * (item_cnt+1);
|
||||
//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;
|
||||
buf->remain_cnt = xSemaphoreCreateCounting(item_cnt, item_cnt);
|
||||
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);
|
||||
|
||||
context = (sdio_context_t)CONTEXT_INIT_VAL;
|
||||
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
|
||||
@ -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*));
|
||||
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;
|
||||
|
||||
no_mem:
|
||||
@ -485,9 +486,9 @@ static void configure_pin(int pin, uint32_t func, bool pullup)
|
||||
{
|
||||
const int sdmmc_func = func;
|
||||
const int drive_strength = 3;
|
||||
assert(pin!=-1);
|
||||
assert(pin != -1);
|
||||
uint32_t reg = GPIO_PIN_MUX_REG[pin];
|
||||
assert(reg!=UINT32_MAX);
|
||||
assert(reg != UINT32_MAX);
|
||||
|
||||
PIN_INPUT_ENABLE(reg);
|
||||
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;
|
||||
}
|
||||
|
||||
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 r;
|
||||
@ -594,6 +618,20 @@ esp_err_t sdio_slave_initialize(sdio_slave_config_t *config)
|
||||
|
||||
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);
|
||||
assert(ret==ESP_OK);
|
||||
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,
|
||||
// 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.
|
||||
critical_enter_recv();
|
||||
portENTER_CRITICAL_ISR(&context.recv_spinlock);
|
||||
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");
|
||||
xSemaphoreGiveFromISR(context.recv_event, &yield);
|
||||
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.start = 1;
|
||||
ESP_LOGV(TAG, "recv_load_buf: start new");
|
||||
SLC.slc0_int_ena.tx_done = 1;
|
||||
} else {
|
||||
//restart former ll operation
|
||||
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,
|
||||
"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) {
|
||||
SDIO_SLAVE_LOGE("cannot allocate lldesc for new buffer");
|
||||
return NULL;
|
||||
|
Loading…
x
Reference in New Issue
Block a user