forked from espressif/esp-idf
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
change(system): heap_caps_alloc returns aligned memory if caps indica…
…te a need for it 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.
- Loading branch information
Showing
15 changed files
with
323 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* 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; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
* SPDX-FileCopyrightText: 2019-2024 Espressif Systems (Shanghai) CO LTD | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <stdint.h> | ||
#include <stdlib.h> | ||
#include "multi_heap.h" | ||
#include "sdkconfig.h" | ||
#include "esp_err.h" | ||
#include "esp_attr.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
/** | ||
* @brief Adjust size, alignment and caps of a memory allocation request to the specific | ||
* hardware requirements, dependent on where the memory gets allocated. | ||
* | ||
* @note Note that heap_caps_base.c has its own definition for this function in order not to depend | ||
* on this component. | ||
* | ||
* @param[in,out] p_alignment Pointer to alignment requirements. This may be modified upwards if the | ||
* hardware has stricter alignment requirements. | ||
* @param[in,out] p_size Pointer to size of memory to be allocated. This may be modified upwards | ||
* if e.g. the memory needs to be aligned to a cache line. | ||
* @param[in,out] p_caps Pointer to memory requirements. This may be adjusted if the memory | ||
* requirements need modification for the heap caps allocator to work | ||
* properly. | ||
*/ | ||
void esp_heap_adjust_alignment_to_hw(size_t *p_alignment, size_t *p_size, uint32_t *p_caps); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.