From 660319ecaf9e563d63366f1ab601e5245ddc73c7 Mon Sep 17 00:00:00 2001 From: Tomas Rezucha Date: Fri, 16 Aug 2024 08:59:02 +0200 Subject: [PATCH] fix(usb/host): Use new cache aligned DMA alloc functions --- components/usb/hcd_dwc.c | 97 ++----------------- .../usb/test_apps/hcd/main/test_hcd_common.c | 10 +- components/usb/usb_private.c | 11 +-- 3 files changed, 13 insertions(+), 105 deletions(-) diff --git a/components/usb/hcd_dwc.c b/components/usb/hcd_dwc.c index 1cd9f94ee0..93a2408f4c 100644 --- a/components/usb/hcd_dwc.c +++ b/components/usb/hcd_dwc.c @@ -11,7 +11,6 @@ #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_heap_caps.h" -#include "esp_dma_utils.h" #include "esp_intr_alloc.h" #include "soc/interrupts.h" // For interrupt index #include "esp_err.h" @@ -25,7 +24,6 @@ #include "soc/soc_caps.h" #if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE #include "esp_cache.h" -#include "esp_private/esp_cache_private.h" #endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE // ----------------------------------------------------- Macros -------------------------------------------------------- @@ -325,35 +323,6 @@ static inline void cache_sync_data_buffer(pipe_t *pipe, urb_t *urb, bool done) } #endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE -// --------------------- Allocation ------------------------ - -/** - * @brief Allocate Frame List - * - * - Frame list is allocated in DMA capable memory - * - Frame list is aligned to 512 and cache line size - * - * @note Free the memory with heap_caps_free() call - * - * @param[in] frame_list_len Length of the Frame List - * @return Pointer to allocated frame list - */ -static void *frame_list_alloc(size_t frame_list_len); - -/** - * @brief Allocate Transfer Descriptor List - * - * - Frame list is allocated in DMA capable memory - * - Frame list is aligned to 512 and cache line size - * - * @note Free the memory with heap_caps_free() call - * - * @param[in] list_len Required length - * @param[out] list_len_bytes_out Allocated length in bytes (can be greater than required) - * @return Pointer to allocated transfer descriptor list - */ -static void *transfer_descriptor_list_alloc(size_t list_len, size_t *list_len_bytes_out); - // ------------------- Buffer Control ---------------------- /** @@ -987,7 +956,7 @@ static port_t *port_obj_alloc(void) { port_t *port = calloc(1, sizeof(port_t)); usb_dwc_hal_context_t *hal = malloc(sizeof(usb_dwc_hal_context_t)); - void *frame_list = frame_list_alloc(FRAME_LIST_LEN); + void *frame_list = heap_caps_aligned_calloc(USB_DWC_FRAME_LIST_MEM_ALIGN, FRAME_LIST_LEN, sizeof(uint32_t), MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL); SemaphoreHandle_t port_mux = xSemaphoreCreateMutex(); if (port == NULL || hal == NULL || frame_list == NULL || port_mux == NULL) { free(port); @@ -1015,59 +984,6 @@ static void port_obj_free(port_t *port) free(port); } -void *frame_list_alloc(size_t frame_list_len) -{ - esp_err_t ret; - void *frame_list = NULL; - size_t actual_size = 0; - esp_dma_mem_info_t dma_mem_info = { - .dma_alignment_bytes = USB_DWC_FRAME_LIST_MEM_ALIGN, - }; - ret = esp_dma_capable_calloc(frame_list_len, sizeof(uint32_t), &dma_mem_info, &frame_list, &actual_size); - assert(ret == ESP_OK); - - // Both Frame List start address and size should be already cache aligned so this is only a sanity check - if (frame_list) { - if (!esp_dma_is_buffer_alignment_satisfied(frame_list, actual_size, dma_mem_info)) { - // This should never happen - heap_caps_free(frame_list); - frame_list = NULL; - } - } - return frame_list; -} - -void *transfer_descriptor_list_alloc(size_t list_len, size_t *list_len_bytes_out) -{ -#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - // Required Transfer Descriptor List size (in bytes) might not be aligned to cache line size, align the size up - size_t data_cache_line_size = 0; - esp_cache_get_alignment(MALLOC_CAP_DMA, &data_cache_line_size); - const size_t required_list_len_bytes = list_len * sizeof(usb_dwc_ll_dma_qtd_t); - *list_len_bytes_out = ALIGN_UP_BY(required_list_len_bytes, data_cache_line_size); -#else - *list_len_bytes_out = list_len * sizeof(usb_dwc_ll_dma_qtd_t); -#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE - - esp_err_t ret; - void *qtd_list = NULL; - size_t actual_size = 0; - esp_dma_mem_info_t dma_mem_info = { - .dma_alignment_bytes = USB_DWC_QTD_LIST_MEM_ALIGN, - }; - ret = esp_dma_capable_calloc(*list_len_bytes_out, 1, &dma_mem_info, &qtd_list, &actual_size); - assert(ret == ESP_OK); - - if (qtd_list) { - if (!esp_dma_is_buffer_alignment_satisfied(qtd_list, actual_size, dma_mem_info)) { - // This should never happen - heap_caps_free(qtd_list); - qtd_list = NULL; - } - } - return qtd_list; -} - // ----------------------- Public -------------------------- esp_err_t hcd_install(const hcd_config_t *config) @@ -1594,19 +1510,24 @@ static dma_buffer_block_t *buffer_block_alloc(usb_transfer_type_t type) desc_list_len = XFER_LIST_LEN_INTR; break; } + + // DMA buffer lock: Software structure for managing the transfer buffer dma_buffer_block_t *buffer = calloc(1, sizeof(dma_buffer_block_t)); if (buffer == NULL) { return NULL; } - size_t real_len = 0; - void *xfer_desc_list = transfer_descriptor_list_alloc(desc_list_len, &real_len); + + // Transfer descriptor list: Must be 512 aligned and DMA capable (USB-DWC requirement) and its size must be cache aligned + void *xfer_desc_list = heap_caps_aligned_calloc(USB_DWC_QTD_LIST_MEM_ALIGN, desc_list_len * sizeof(usb_dwc_ll_dma_qtd_t), 1, MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL); if (xfer_desc_list == NULL) { free(buffer); heap_caps_free(xfer_desc_list); return NULL; } buffer->xfer_desc_list = xfer_desc_list; - buffer->xfer_desc_list_len_bytes = real_len; + // For targets with L1CACHE, the allocated size might be bigger than requested, this value is than used during memory sync + // We save this value here, so we don't have to call 'heap_caps_get_allocated_size()' during every memory sync + buffer->xfer_desc_list_len_bytes = heap_caps_get_allocated_size(xfer_desc_list); return buffer; } diff --git a/components/usb/test_apps/hcd/main/test_hcd_common.c b/components/usb/test_apps/hcd/main/test_hcd_common.c index 293f6ca21f..0b4c3cd352 100644 --- a/components/usb/test_apps/hcd/main/test_hcd_common.c +++ b/components/usb/test_apps/hcd/main/test_hcd_common.c @@ -21,7 +21,6 @@ #include "test_usb_common.h" #include "mock_msc.h" #include "unity.h" -#include "esp_dma_utils.h" #define PORT_NUM 1 #define EVENT_QUEUE_LEN 5 @@ -264,19 +263,14 @@ urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size) { // Allocate a URB and data buffer urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT); - void *data_buffer; - size_t real_size; - esp_dma_mem_info_t dma_mem_info = { - .dma_alignment_bytes = 4, - }; - esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size); + void *data_buffer = heap_caps_malloc(data_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED); TEST_ASSERT_NOT_NULL_MESSAGE(urb, "Failed to allocate URB"); TEST_ASSERT_NOT_NULL_MESSAGE(data_buffer, "Failed to allocate transfer buffer"); // Initialize URB and underlying transfer structure. Need to cast to dummy due to const fields usb_transfer_dummy_t *transfer_dummy = (usb_transfer_dummy_t *)&urb->transfer; transfer_dummy->data_buffer = data_buffer; - transfer_dummy->data_buffer_size = real_size; + transfer_dummy->data_buffer_size = heap_caps_get_allocated_size(data_buffer); transfer_dummy->num_isoc_packets = num_isoc_packets; return urb; } diff --git a/components/usb/usb_private.c b/components/usb/usb_private.c index e5ab2d3da8..56d6b3d719 100644 --- a/components/usb/usb_private.c +++ b/components/usb/usb_private.c @@ -5,27 +5,20 @@ */ #include "esp_heap_caps.h" -#include "esp_dma_utils.h" #include "usb_private.h" #include "usb/usb_types_ch9.h" urb_t *urb_alloc(size_t data_buffer_size, int num_isoc_packets) { urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT); - void *data_buffer; - size_t real_size; - esp_dma_mem_info_t dma_mem_info = { - .dma_alignment_bytes = 4, - }; - //TODO: IDF-9639 - esp_dma_capable_malloc(data_buffer_size, &dma_mem_info, &data_buffer, &real_size); + void *data_buffer = heap_caps_malloc(data_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED); if (urb == NULL || data_buffer == NULL) { goto err; } // Cast as dummy transfer so that we can assign to const fields usb_transfer_dummy_t *dummy_transfer = (usb_transfer_dummy_t *)&urb->transfer; dummy_transfer->data_buffer = data_buffer; - dummy_transfer->data_buffer_size = real_size; + dummy_transfer->data_buffer_size = heap_caps_get_allocated_size(data_buffer); dummy_transfer->num_isoc_packets = num_isoc_packets; return urb; err: