Skip to content

Commit 4b15ef7

Browse files
Merge branch 'fix/usb_comprehensive_heap' into 'master'
fix(usb/host): Do not call heap_caps_get_allocated_size() in USB host driver Closes IDFGH-15138 See merge request espressif/esp-idf!38715
2 parents 852466e + 6badd2c commit 4b15ef7

File tree

6 files changed

+47
-21
lines changed

6 files changed

+47
-21
lines changed

components/usb/hcd_dwc.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,24 @@
1616
#include "esp_err.h"
1717
#include "esp_log.h"
1818

19+
#include "soc/soc_caps.h"
1920
#include "soc/usb_dwc_periph.h"
2021
#include "hal/usb_dwc_hal.h"
2122
#include "hcd.h"
2223
#include "usb_private.h"
2324
#include "usb/usb_types_ch9.h"
2425

25-
#include "soc/soc_caps.h"
26-
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
2726
#include "esp_cache.h"
28-
#endif // SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
27+
#include "esp_private/esp_cache_private.h"
2928

3029
// ----------------------------------------------------- Macros --------------------------------------------------------
3130

31+
#define ALIGN_UP(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
32+
3233
// --------------------- Constants -------------------------
3334

35+
#define XFER_DESC_LIST_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED | MALLOC_CAP_INTERNAL)
36+
3437
#define INIT_DELAY_MS 30 // A delay of at least 25ms to enter Host mode. Make it 30ms to be safe
3538
#define DEBOUNCE_DELAY_MS CONFIG_USB_HOST_DEBOUNCE_DELAY_MS
3639
#define RESET_HOLD_MS CONFIG_USB_HOST_RESET_HOLD_MS
@@ -1518,16 +1521,18 @@ static dma_buffer_block_t *buffer_block_alloc(usb_transfer_type_t type)
15181521
}
15191522

15201523
// Transfer descriptor list: Must be 512 aligned and DMA capable (USB-DWC requirement) and its size must be cache aligned
1521-
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);
1524+
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, XFER_DESC_LIST_CAPS);
15221525
if (xfer_desc_list == NULL) {
15231526
free(buffer);
15241527
heap_caps_free(xfer_desc_list);
15251528
return NULL;
15261529
}
15271530
buffer->xfer_desc_list = xfer_desc_list;
1528-
// For targets with L1CACHE, the allocated size might be bigger than requested, this value is than used during memory sync
1529-
// We save this value here, so we don't have to call 'heap_caps_get_allocated_size()' during every memory sync
1530-
buffer->xfer_desc_list_len_bytes = heap_caps_get_allocated_size(xfer_desc_list);
1531+
1532+
// Note for developers: We do not use heap_caps_get_allocated_size() because it is broken with HEAP_POISONING=COMPREHENSIVE
1533+
size_t cache_align = 0;
1534+
esp_cache_get_alignment(XFER_DESC_LIST_CAPS, &cache_align);
1535+
buffer->xfer_desc_list_len_bytes = ALIGN_UP(desc_list_len * sizeof(usb_dwc_ll_dma_qtd_t), cache_align);
15311536
return buffer;
15321537
}
15331538

components/usb/include/usb/usb_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,7 @@ esp_err_t usb_host_endpoint_clear(usb_device_handle_t dev_hdl, uint8_t bEndpoint
569569
*
570570
* - This function allocates a transfer object
571571
* - Each transfer object has a fixed sized buffer specified on allocation
572+
* - The resulting data_buffer_size can be bigger that the requested size. This is to ensure that the data buffer is cache aligned
572573
* - A transfer object can be re-used indefinitely
573574
* - A transfer can be submitted using usb_host_transfer_submit() or usb_host_transfer_submit_control()
574575
*

components/usb/private_include/usb_private.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ typedef bool (*usb_proc_req_cb_t)(usb_proc_req_source_t source, bool in_isr, voi
7777
*
7878
* - Data buffer is allocated in DMA capable memory
7979
* - The constant fields of the URB are also set
80-
* - The data_buffer field of the URB is set to point to start of the allocated data buffer.
80+
* - The data_buffer field of the URB is set to point to start of the allocated data buffer
81+
* - The resulting data_buffer_size can be bigger that the requested size. This is to ensure that the data buffer is cache aligned
8182
*
8283
* @param[in] data_buffer_size Size of the URB's data buffer
8384
* @param[in] num_isoc_packets Number of isochronous packet descriptors

components/usb/test_apps/common/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,6 @@ idf_component_register(SRCS "dev_hid.c"
77
INCLUDE_DIRS
88
"../../private_include" # hcd and urb
99
"."
10-
REQUIRES usb unity)
10+
REQUIRES usb unity
11+
PRIV_REQUIRES esp_mm
12+
)

components/usb/test_apps/common/hcd_common.c

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,18 +260,27 @@ void test_hcd_pipe_free(hcd_pipe_handle_t pipe_hdl)
260260
vQueueDelete(pipe_evt_queue);
261261
}
262262

263+
#include "esp_private/esp_cache_private.h"
264+
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED)
265+
#define ALIGN_UP(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
266+
263267
urb_t *test_hcd_alloc_urb(int num_isoc_packets, size_t data_buffer_size)
264268
{
265269
// Allocate a URB and data buffer
266270
urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT);
267-
void *data_buffer = heap_caps_malloc(data_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED);
271+
272+
size_t cache_align = 0;
273+
esp_cache_get_alignment(DATA_BUFFER_CAPS, &cache_align);
274+
data_buffer_size = ALIGN_UP(data_buffer_size, cache_align);
275+
void *data_buffer = heap_caps_malloc(data_buffer_size, DATA_BUFFER_CAPS);
276+
268277
TEST_ASSERT_NOT_NULL_MESSAGE(urb, "Failed to allocate URB");
269278
TEST_ASSERT_NOT_NULL_MESSAGE(data_buffer, "Failed to allocate transfer buffer");
270279

271280
// Initialize URB and underlying transfer structure. Need to cast to dummy due to const fields
272281
usb_transfer_dummy_t *transfer_dummy = (usb_transfer_dummy_t *)&urb->transfer;
273282
transfer_dummy->data_buffer = data_buffer;
274-
transfer_dummy->data_buffer_size = heap_caps_get_allocated_size(data_buffer);
283+
transfer_dummy->data_buffer_size = data_buffer_size;
275284
transfer_dummy->num_isoc_packets = num_isoc_packets;
276285
return urb;
277286
}

components/usb/usb_private.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,40 @@
11
/*
2-
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
66

7+
#include "sdkconfig.h"
78
#include "esp_heap_caps.h"
89
#include "usb_private.h"
910
#include "usb/usb_types_ch9.h"
1011

12+
#if !CONFIG_IDF_TARGET_LINUX
13+
#include "esp_private/esp_cache_private.h"
14+
#define ALIGN_UP(num, align) ((align) == 0 ? (num) : (((num) + ((align) - 1)) & ~((align) - 1)))
15+
#endif
16+
#define DATA_BUFFER_CAPS (MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED)
17+
1118
urb_t *urb_alloc(size_t data_buffer_size, int num_isoc_packets)
1219
{
1320
urb_t *urb = heap_caps_calloc(1, sizeof(urb_t) + (sizeof(usb_isoc_packet_desc_t) * num_isoc_packets), MALLOC_CAP_DEFAULT);
14-
void *data_buffer = heap_caps_malloc(data_buffer_size, MALLOC_CAP_DMA | MALLOC_CAP_CACHE_ALIGNED);
21+
22+
#if !CONFIG_IDF_TARGET_LINUX
23+
// Note for developers: We do not use heap_caps_get_allocated_size() because it is broken with HEAP_POISONING=COMPREHENSIVE
24+
size_t cache_align = 0;
25+
esp_cache_get_alignment(DATA_BUFFER_CAPS, &cache_align);
26+
data_buffer_size = ALIGN_UP(data_buffer_size, cache_align);
27+
#endif
28+
29+
void *data_buffer = heap_caps_malloc(data_buffer_size, DATA_BUFFER_CAPS);
1530
if (urb == NULL || data_buffer == NULL) {
1631
goto err;
1732
}
1833

19-
#if CONFIG_IDF_TARGET_LINUX
20-
// heap_caps_get_allocated_size() return 0 on Linux target
21-
const size_t allocated_size = data_buffer_size;
22-
#else
23-
const size_t allocated_size = heap_caps_get_allocated_size(data_buffer);
24-
#endif
25-
2634
// Cast as dummy transfer so that we can assign to const fields
2735
usb_transfer_dummy_t *dummy_transfer = (usb_transfer_dummy_t *)&urb->transfer;
2836
dummy_transfer->data_buffer = data_buffer;
29-
dummy_transfer->data_buffer_size = allocated_size;
37+
dummy_transfer->data_buffer_size = data_buffer_size;
3038
dummy_transfer->num_isoc_packets = num_isoc_packets;
3139
return urb;
3240
err:

0 commit comments

Comments
 (0)