mem_mgmt: Add a memory attributes memory allocator
Using this new library it is now possible to leverage the memory attribute property 'zephyr,memory-attr' to define and create a set of memory heaps from which the user can allocate memory from with certain attributes / capabilities. When the CONFIG_MEM_ATTR_HEAP option is set, every region marked with one of the memory attributes listed in include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h is added to a pool of memory heaps used for dynamic allocation of memory buffers with certain attributes. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
a8d56c4f1f
commit
09fd6b6ea5
27
include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h
Normal file
27
include/zephyr/dt-bindings/memory-attr/memory-attr-sw.h
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Carlo Caione <ccaione@baylibre.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#ifndef ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_
|
||||||
|
#define ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_
|
||||||
|
|
||||||
|
#include <zephyr/sys/util_macro.h>
|
||||||
|
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Software specific memory attributes.
|
||||||
|
*/
|
||||||
|
#define DT_MEM_SW_MASK DT_MEM_SW_ATTR_MASK
|
||||||
|
#define DT_MEM_SW_GET(x) ((x) & DT_MEM_SW_ATTR_MASK)
|
||||||
|
#define DT_MEM_SW(x) ((x) << DT_MEM_SW_ATTR_SHIFT)
|
||||||
|
|
||||||
|
#define ATTR_SW_ALLOC_CACHE BIT(0)
|
||||||
|
#define ATTR_SW_ALLOC_NON_CACHE BIT(1)
|
||||||
|
#define ATTR_SW_ALLOC_DMA BIT(2)
|
||||||
|
|
||||||
|
#define DT_MEM_SW_ALLOC_CACHE DT_MEM_SW(ATTR_SW_ALLOC_CACHE)
|
||||||
|
#define DT_MEM_SW_ALLOC_NON_CACHE DT_MEM_SW(ATTR_SW_ALLOC_NON_CACHE)
|
||||||
|
#define DT_MEM_SW_ALLOC_DMA DT_MEM_SW(ATTR_SW_ALLOC_DMA)
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_MEM_ATTR_SW_H_ */
|
98
include/zephyr/mem_mgmt/mem_attr_heap.h
Normal file
98
include/zephyr/mem_mgmt/mem_attr_heap.h
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Carlo Caione, <ccaione@baylibre.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_
|
||||||
|
#define ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Memory heaps based on memory attributes
|
||||||
|
* @defgroup memory_attr_heap Memory heaps based on memory attributes
|
||||||
|
* @ingroup mem_mgmt
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/mem_mgmt/mem_attr.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Init the memory pool
|
||||||
|
*
|
||||||
|
* This must be the first function to be called to initialize the memory pools
|
||||||
|
* from all the memory regions with the a software attribute.
|
||||||
|
*
|
||||||
|
* @retval 0 on success.
|
||||||
|
* @retval -EALREADY if the pool was already initialized.
|
||||||
|
* @retval -ENOMEM too many regions already allocated.
|
||||||
|
*/
|
||||||
|
int mem_attr_heap_pool_init(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate memory with a specified attribute and size.
|
||||||
|
*
|
||||||
|
* Allocates a block of memory of the specified size in bytes and with a
|
||||||
|
* specified capability / attribute. The attribute is used to select the
|
||||||
|
* correct memory heap to allocate memory from.
|
||||||
|
*
|
||||||
|
* @param attr capability / attribute requested for the memory block.
|
||||||
|
* @param bytes requested size of the allocation in bytes.
|
||||||
|
*
|
||||||
|
* @retval ptr a valid pointer to the allocated memory.
|
||||||
|
* @retval NULL if no memory is available with that attribute and size.
|
||||||
|
*/
|
||||||
|
void *mem_attr_heap_alloc(uint32_t attr, size_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocate aligned memory with a specified attribute, size and alignment.
|
||||||
|
*
|
||||||
|
* Allocates a block of memory of the specified size in bytes and with a
|
||||||
|
* specified capability / attribute. Takes an additional parameter specifying a
|
||||||
|
* power of two alignment in bytes.
|
||||||
|
*
|
||||||
|
* @param attr capability / attribute requested for the memory block.
|
||||||
|
* @param align power of two alignment for the returned pointer in bytes.
|
||||||
|
* @param bytes requested size of the allocation in bytes.
|
||||||
|
*
|
||||||
|
* @retval ptr a valid pointer to the allocated memory.
|
||||||
|
* @retval NULL if no memory is available with that attribute and size.
|
||||||
|
*/
|
||||||
|
void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free the allocated memory
|
||||||
|
*
|
||||||
|
* Used to free the passed block of memory that must be the return value of a
|
||||||
|
* previously call to @ref mem_attr_heap_alloc or @ref
|
||||||
|
* mem_attr_heap_aligned_alloc.
|
||||||
|
*
|
||||||
|
* @param block block to free, must be a pointer to a block allocated by
|
||||||
|
* @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc.
|
||||||
|
*/
|
||||||
|
void mem_attr_heap_free(void *block);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get a specific memory region descriptor for a provided address
|
||||||
|
*
|
||||||
|
* Finds the memory region descriptor struct controlling the provided pointer.
|
||||||
|
*
|
||||||
|
* @param addr address to be found, must be a pointer to a block allocated by
|
||||||
|
* @ref mem_attr_heap_alloc or @ref mem_attr_heap_aligned_alloc.
|
||||||
|
*
|
||||||
|
* @retval str pointer to a memory region structure the address belongs to.
|
||||||
|
*/
|
||||||
|
const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* ZEPHYR_INCLUDE_MEM_ATTR_HEAP_H_ */
|
|
@ -1,3 +1,4 @@
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
zephyr_sources_ifdef(CONFIG_MEM_ATTR mem_attr.c)
|
zephyr_sources_ifdef(CONFIG_MEM_ATTR mem_attr.c)
|
||||||
|
zephyr_sources_ifdef(CONFIG_MEM_ATTR_HEAP mem_attr_heap.c)
|
||||||
|
|
|
@ -10,3 +10,10 @@ config MEM_ATTR
|
||||||
time an array of the memory regions defined in the DT that can be
|
time an array of the memory regions defined in the DT that can be
|
||||||
probed at run-time using several helper functions. Set to `N` if
|
probed at run-time using several helper functions. Set to `N` if
|
||||||
unsure to save RODATA space.
|
unsure to save RODATA space.
|
||||||
|
|
||||||
|
config MEM_ATTR_HEAP
|
||||||
|
bool "Memory Attributes heap allocator"
|
||||||
|
depends on MEM_ATTR
|
||||||
|
help
|
||||||
|
Enable an heap allocator based on memory attributes to dynamically
|
||||||
|
allocate memory from DeviceTree defined memory regions.
|
||||||
|
|
136
subsys/mem_mgmt/mem_attr_heap.c
Normal file
136
subsys/mem_mgmt/mem_attr_heap.c
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Carlo Caione, <ccaione@baylibre.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/sys/sys_heap.h>
|
||||||
|
#include <zephyr/mem_mgmt/mem_attr.h>
|
||||||
|
#include <zephyr/sys/multi_heap.h>
|
||||||
|
#include <zephyr/dt-bindings/memory-attr/memory-attr.h>
|
||||||
|
#include <zephyr/dt-bindings/memory-attr/memory-attr-sw.h>
|
||||||
|
|
||||||
|
struct ma_heap {
|
||||||
|
struct sys_heap heap;
|
||||||
|
uint32_t attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct ma_heap ma_heaps[MAX_MULTI_HEAPS];
|
||||||
|
struct sys_multi_heap multi_heap;
|
||||||
|
int nheaps;
|
||||||
|
} mah_data;
|
||||||
|
|
||||||
|
static void *mah_choice(struct sys_multi_heap *m_heap, void *cfg, size_t align, size_t size)
|
||||||
|
{
|
||||||
|
uint32_t attr;
|
||||||
|
void *block;
|
||||||
|
|
||||||
|
if (size == 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr = (uint32_t)(long) cfg;
|
||||||
|
|
||||||
|
/* Set in case the user requested a non-existing attr */
|
||||||
|
block = NULL;
|
||||||
|
|
||||||
|
for (size_t hdx = 0; hdx < mah_data.nheaps; hdx++) {
|
||||||
|
struct ma_heap *h;
|
||||||
|
|
||||||
|
h = &mah_data.ma_heaps[hdx];
|
||||||
|
|
||||||
|
if (h->attr != attr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = sys_heap_aligned_alloc(&h->heap, align, size);
|
||||||
|
if (block != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mem_attr_heap_free(void *block)
|
||||||
|
{
|
||||||
|
sys_multi_heap_free(&mah_data.multi_heap, block);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *mem_attr_heap_alloc(uint32_t attr, size_t bytes)
|
||||||
|
{
|
||||||
|
return sys_multi_heap_alloc(&mah_data.multi_heap,
|
||||||
|
(void *)(long) attr, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *mem_attr_heap_aligned_alloc(uint32_t attr, size_t align, size_t bytes)
|
||||||
|
{
|
||||||
|
return sys_multi_heap_aligned_alloc(&mah_data.multi_heap,
|
||||||
|
(void *)(long) attr, align, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct mem_attr_region_t *mem_attr_heap_get_region(void *addr)
|
||||||
|
{
|
||||||
|
const struct sys_multi_heap_rec *heap_rec;
|
||||||
|
|
||||||
|
heap_rec = sys_multi_heap_get_heap(&mah_data.multi_heap, addr);
|
||||||
|
|
||||||
|
return (const struct mem_attr_region_t *) heap_rec->user_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ma_heap_add(const struct mem_attr_region_t *region, uint32_t attr)
|
||||||
|
{
|
||||||
|
struct ma_heap *mh;
|
||||||
|
struct sys_heap *h;
|
||||||
|
|
||||||
|
/* No more heaps available */
|
||||||
|
if (mah_data.nheaps >= MAX_MULTI_HEAPS) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
mh = &mah_data.ma_heaps[mah_data.nheaps++];
|
||||||
|
h = &mh->heap;
|
||||||
|
|
||||||
|
mh->attr = attr;
|
||||||
|
|
||||||
|
sys_heap_init(h, (void *) region->dt_addr, region->dt_size);
|
||||||
|
sys_multi_heap_add_heap(&mah_data.multi_heap, h, (void *) region);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int mem_attr_heap_pool_init(void)
|
||||||
|
{
|
||||||
|
const struct mem_attr_region_t *regions;
|
||||||
|
static atomic_t state;
|
||||||
|
size_t num_regions;
|
||||||
|
|
||||||
|
if (!atomic_cas(&state, 0, 1)) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_multi_heap_init(&mah_data.multi_heap, mah_choice);
|
||||||
|
|
||||||
|
num_regions = mem_attr_get_regions(®ions);
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < num_regions; idx++) {
|
||||||
|
uint32_t sw_attr;
|
||||||
|
|
||||||
|
sw_attr = DT_MEM_SW_ATTR_GET(regions[idx].dt_attr);
|
||||||
|
|
||||||
|
/* No SW attribute is present */
|
||||||
|
if (!sw_attr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ma_heap_add(®ions[idx], sw_attr)) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue