From e8813ddd1dbea6535a820994e1414c990d13cb74 Mon Sep 17 00:00:00 2001 From: Armando Date: Fri, 8 Sep 2023 15:20:22 +0800 Subject: [PATCH] feat(cache): added an helper API for cache-align-malloc --- components/esp_mm/esp_cache.c | 71 +++++++++++++++++++ .../include/esp_private/esp_cache_private.h | 64 +++++++++++++++++ 2 files changed, 135 insertions(+) create mode 100644 components/esp_mm/include/esp_private/esp_cache_private.h diff --git a/components/esp_mm/esp_cache.c b/components/esp_mm/esp_cache.c index 6eff6cbda4..2695589fa9 100644 --- a/components/esp_mm/esp_cache.c +++ b/components/esp_mm/esp_cache.c @@ -6,17 +6,24 @@ #include #include +#include #include "sdkconfig.h" #include "esp_check.h" #include "esp_log.h" +#include "esp_heap_caps.h" #include "esp_rom_caps.h" #include "soc/soc_caps.h" #include "hal/mmu_hal.h" #include "hal/cache_hal.h" +#include "hal/cache_ll.h" #include "esp_cache.h" +#include "esp_private/esp_cache_private.h" #include "esp_private/critical_section.h" static const char *TAG = "cache"; + +#define ALIGN_UP_BY(num, align) (((num) + ((align) - 1)) & ~((align) - 1)) + DEFINE_CRIT_SECTION_LOCK_STATIC(s_spinlock); @@ -74,3 +81,67 @@ esp_err_t esp_cache_msync(void *addr, size_t size, int flags) return ESP_OK; } + + +esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size) +{ + ESP_RETURN_ON_FALSE_ISR(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + + uint32_t cache_level = CACHE_LL_LEVEL_INT_MEM; + uint32_t heap_caps = 0; + uint32_t data_cache_line_size = 0; + void *ptr = NULL; + + if (flags & ESP_CACHE_MALLOC_FLAG_PSRAM) { + cache_level = CACHE_LL_LEVEL_EXT_MEM; + heap_caps |= MALLOC_CAP_SPIRAM; + } else { + heap_caps |= MALLOC_CAP_INTERNAL; + if (flags & ESP_CACHE_MALLOC_FLAG_DMA) { + heap_caps |= MALLOC_CAP_DMA; + } + } + +#if SOC_CACHE_INTERNAL_MEM_VIA_L1CACHE + data_cache_line_size = cache_hal_get_cache_line_size(CACHE_TYPE_DATA, cache_level); +#else + if (cache_level == CACHE_LL_LEVEL_EXT_MEM) { + data_cache_line_size = cache_hal_get_cache_line_size(CACHE_TYPE_DATA, cache_level); + } else { + data_cache_line_size = 4; + } +#endif + + size = ALIGN_UP_BY(size, data_cache_line_size); + ptr = heap_caps_aligned_alloc(data_cache_line_size, size, heap_caps); + ESP_RETURN_ON_FALSE_ISR(ptr, ESP_ERR_NO_MEM, TAG, "no enough heap memory for (%"PRId32")B alignment", data_cache_line_size); + + *out_ptr = ptr; + if (actual_size) { + *actual_size = size; + } + + return ESP_OK; +} + + +esp_err_t esp_cache_aligned_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, size_t *actual_size) +{ + ESP_RETURN_ON_FALSE_ISR(out_ptr, ESP_ERR_INVALID_ARG, TAG, "null pointer"); + + esp_err_t ret = ESP_FAIL; + size_t size_bytes = 0; + bool ovf = false; + + ovf = __builtin_mul_overflow(n, size, &size_bytes); + ESP_RETURN_ON_FALSE_ISR(!ovf, ESP_ERR_INVALID_ARG, TAG, "wrong size, total size overflow"); + + void *ptr = NULL; + ret = esp_cache_aligned_malloc(size_bytes, flags, &ptr, actual_size); + if (ret == ESP_OK) { + memset(ptr, 0, size_bytes); + *out_ptr = ptr; + } + + return ret; +} diff --git a/components/esp_mm/include/esp_private/esp_cache_private.h b/components/esp_mm/include/esp_private/esp_cache_private.h new file mode 100644 index 0000000000..7735d298b9 --- /dev/null +++ b/components/esp_mm/include/esp_private/esp_cache_private.h @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include +#include +#include "esp_err.h" +#include "esp_bit_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Cache malloc flags + */ +/** + * @brief Memory is in PSRAM + */ +#define ESP_CACHE_MALLOC_FLAG_PSRAM BIT(0) + +/** + * @brief Memory is capable to be accessed by DMA + */ +#define ESP_CACHE_MALLOC_FLAG_DMA BIT(1) + +/** + * @brief Helper function for malloc a cache aligned memory buffer + * + * @param[in] size Size in bytes, the amount of memory to allocate + * @param[in] flags Flags, see `ESP_CACHE_MALLOC_FLAG_x` + * @param[out] out_ptr A pointer to the memory allocated successfully + * @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the cache alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value. + * + * @return + * - ESP_OK: + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: No enough memory for allocation + */ +esp_err_t esp_cache_aligned_malloc(size_t size, uint32_t flags, void **out_ptr, size_t *actual_size); + +/** + * @brief Helper function for calloc a cache aligned memory buffer + * + * @param[in] n Number of continuing chunks of memory to allocate + * @param[in] size Size of one chunk, in bytes + * @param[in] flags Flags, see `ESP_CACHE_MALLOC_FLAG_x` + * @param[out] out_ptr A pointer to the memory allocated successfully + * @param[out] actual_size Actual size for allocation in bytes, when the size you specified doesn't meet the cache alignment requirements, this value might be bigger than the size you specified. Set null if you don't care this value. + * + * @return + * - ESP_OK: + * - ESP_ERR_INVALID_ARG: Invalid argument + * - ESP_ERR_NO_MEM: No enough memory for allocation + */ +esp_err_t esp_cache_aligned_calloc(size_t n, size_t size, uint32_t flags, void **out_ptr, size_t *actual_size); + + +#ifdef __cplusplus +} +#endif