fix(usb/host): Use new cache aligned DMA alloc functions

This commit is contained in:
Tomas Rezucha 2024-08-16 08:59:02 +02:00
parent 0bbd728196
commit 8f7dcc1eab
3 changed files with 17 additions and 106 deletions

View File

@ -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)
@ -1593,16 +1509,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));
size_t real_len = 0;
void *xfer_desc_list = transfer_descriptor_list_alloc(desc_list_len, &real_len);
if (buffer == NULL || xfer_desc_list == NULL) {
if (buffer == NULL) {
return NULL;
}
// 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;
}

View File

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

View File

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