mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
a1ba660b4a
The implicit promise of heap_alloc_caps() and friends is that the memory it returns is fit for the purpose as requested in the caps field. Before this commit, that did not happen; e.g. DMA-capable memory wass returned from a correct region, but not aligned/sized to something the DMA subsystem can handle. This commit adds an API to the esp_mm component that is then used by the heap component to adjust allocation alignment, caps and size dependent on the hardware requirement of the requested allocation caps.
101 lines
3.4 KiB
C
101 lines
3.4 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
#include "sdkconfig.h"
|
|
#include "esp_heap_caps.h"
|
|
#include "esp_private/esp_cache_private.h"
|
|
#include "soc/soc_caps.h"
|
|
#if SOC_GDMA_SUPPORTED
|
|
#include "hal/gdma_ll.h"
|
|
#endif
|
|
|
|
#if CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH
|
|
#define HEAP_IRAM_ATTR
|
|
#else
|
|
#define HEAP_IRAM_ATTR IRAM_ATTR
|
|
#endif
|
|
|
|
#define CAPS_NEEDING_ALIGNMENT (MALLOC_CAP_DMA|MALLOC_CAP_DMA_DESC_AHB|MALLOC_CAP_DMA_DESC_AXI|MALLOC_CAP_CACHE_ALIGNED)
|
|
|
|
HEAP_IRAM_ATTR void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t *p_size, uint32_t *p_caps)
|
|
{
|
|
size_t size = *p_size;
|
|
size_t alignment = *p_alignment;
|
|
uint32_t caps = *p_caps;
|
|
|
|
//Bail out early if we don't need alignment
|
|
if (!(caps & CAPS_NEEDING_ALIGNMENT)) {
|
|
return;
|
|
}
|
|
|
|
#if CONFIG_APP_BUILD_TYPE_PURE_RAM_APP
|
|
//Cache functions aren't linked in so we cannot allocate anything needing alignment.
|
|
#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE
|
|
//Cannot do this for either internal or external memory.
|
|
*p_caps |= MALLOC_CAP_INVALID;
|
|
#else
|
|
//Internal memory DMA alloc is allowed.
|
|
if (caps & MALLOC_CAP_SPIRAM) {
|
|
*p_caps |= MALLOC_CAP_INVALID;
|
|
}
|
|
#endif
|
|
return;
|
|
#endif
|
|
|
|
//Ask cache driver what alignment is applicable here.
|
|
size_t cache_alignment_bytes = 0;
|
|
esp_err_t ret = esp_cache_get_alignment(caps, &cache_alignment_bytes);
|
|
if (ret != ESP_OK) {
|
|
//This is not supposed to happen.
|
|
*p_caps |= MALLOC_CAP_INVALID;
|
|
return;
|
|
}
|
|
|
|
#if SOC_GDMA_SUPPORTED && SOC_AXI_GDMA_SUPPORTED
|
|
//Special case: AXI DMA descriptors need to be aligned to 8-byte boundaries.
|
|
if ((caps & MALLOC_CAP_DMA_DESC_AXI) && (cache_alignment_bytes < GDMA_LL_AXI_DESC_ALIGNMENT)) {
|
|
cache_alignment_bytes = GDMA_LL_AXI_DESC_ALIGNMENT;
|
|
}
|
|
#endif
|
|
|
|
// We assume both DMA alignment and requested alignment are powers of two. We can safely
|
|
// do this because:
|
|
// - DMA alignment in current chips always is a power of two, and is unlikely to ever
|
|
// be something else,
|
|
// - Requested alignment is checked by heap_caps_aligned_check_args to be a power
|
|
// of two.
|
|
if (cache_alignment_bytes > alignment) {
|
|
alignment = cache_alignment_bytes;
|
|
}
|
|
// Align up `size` to resulting alignment as well.
|
|
size = (size + alignment - 1) & (~(alignment - 1));
|
|
|
|
// For the heap allocator itself, there's no difference between data and descriptor DMA; the regions
|
|
// are only marked as DMA-capable.
|
|
if (caps & (MALLOC_CAP_DMA_DESC_AHB | MALLOC_CAP_DMA_DESC_AXI)) {
|
|
caps &= ~(MALLOC_CAP_DMA_DESC_AHB | MALLOC_CAP_DMA_DESC_AXI);
|
|
caps |= MALLOC_CAP_DMA;
|
|
}
|
|
|
|
// Workaround: the heap allocator doesn't have regions marked `MALLOC_CAP_DMA | MALLOC_CAP_SPIRAM`
|
|
// so we need to request those without the DMA flag.
|
|
if (caps & MALLOC_CAP_SPIRAM) {
|
|
caps &= ~MALLOC_CAP_DMA;
|
|
//Note: we do not erase any DMA descriptor caps. DMA descriptors cannot be in external
|
|
//memory, so the MALLOC_CAP_SPIRAM|MALLOC_CAP_DMA_DESC_* simply will not return any
|
|
//usable memory.
|
|
}
|
|
// MALLOC_CAP_CACHE_ALIGNED is not a real flag the heap_base component will understand; it
|
|
// only sets alignment (which we handled here)
|
|
caps &= ~ MALLOC_CAP_CACHE_ALIGNED;
|
|
|
|
*p_size = size;
|
|
*p_alignment = alignment;
|
|
*p_caps = caps;
|
|
}
|