sdio_slave: fix deinit pin and memory leak issues

pull/4494/head
Michael (XIAO Xufeng) 2019-09-28 16:37:35 +08:00
rodzic 087c8f6065
commit e2b20f2e4b
1 zmienionych plików z 67 dodań i 28 usunięć

Wyświetl plik

@ -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;