Skip to content

Commit

Permalink
fix(usb/host): Use new cache aligned DMA alloc functions
Browse files Browse the repository at this point in the history
  • Loading branch information
tore-espressif committed Aug 20, 2024
1 parent cdee290 commit 660319e
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 105 deletions.
97 changes: 9 additions & 88 deletions components/usb/hcd_dwc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 --------------------------------------------------------
Expand Down Expand Up @@ -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 ----------------------

/**
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}

Expand Down
10 changes: 2 additions & 8 deletions components/usb/test_apps/hcd/main/test_hcd_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
11 changes: 2 additions & 9 deletions components/usb/usb_private.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down

0 comments on commit 660319e

Please sign in to comment.