Browse Source

sdio_slave: fix deinit pin and memory leak issues

Michael (XIAO Xufeng) 6 năm trước cách đây
mục cha
commit
e2b20f2e4b
1 tập tin đã thay đổi với 67 bổ sung28 xóa
  1. 67 28
      components/driver/sdio_slave.c

+ 67 - 28
components/driver/sdio_slave.c

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