118 lines
2.6 KiB
C
118 lines
2.6 KiB
C
/*
|
|
* Copyright (c) 2021 Carlo Caione, <ccaione@baylibre.com>
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <device.h>
|
|
#include <sys/sys_heap.h>
|
|
#include <sys/multi_heap.h>
|
|
#include <linker/linker-defs.h>
|
|
|
|
#include <multi_heap/shared_multi_heap.h>
|
|
|
|
#define DT_DRV_COMPAT shared_multi_heap
|
|
|
|
#define NUM_REGIONS DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT)
|
|
|
|
static struct sys_multi_heap shared_multi_heap;
|
|
static struct sys_heap heap_pool[SMH_REG_ATTR_NUM][NUM_REGIONS];
|
|
|
|
static smh_init_reg_fn_t smh_init_reg;
|
|
|
|
#define FOREACH_REG(n) \
|
|
{ .addr = (uintptr_t) LINKER_DT_RESERVED_MEM_GET_PTR(DT_DRV_INST(n)), \
|
|
.size = LINKER_DT_RESERVED_MEM_GET_SIZE(DT_DRV_INST(n)), \
|
|
.attr = DT_ENUM_IDX(DT_DRV_INST(n), capability), \
|
|
},
|
|
|
|
static struct shared_multi_heap_region dt_region[NUM_REGIONS] = {
|
|
DT_INST_FOREACH_STATUS_OKAY(FOREACH_REG)
|
|
};
|
|
|
|
static void *smh_choice(struct sys_multi_heap *mheap, void *cfg, size_t align, size_t size)
|
|
{
|
|
enum smh_reg_attr attr;
|
|
struct sys_heap *h;
|
|
void *block;
|
|
|
|
attr = (enum smh_reg_attr) cfg;
|
|
|
|
if (attr >= SMH_REG_ATTR_NUM || size == 0) {
|
|
return NULL;
|
|
}
|
|
|
|
for (size_t reg = 0; reg < NUM_REGIONS; reg++) {
|
|
h = &heap_pool[attr][reg];
|
|
|
|
if (h->heap == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
block = sys_heap_aligned_alloc(h, align, size);
|
|
if (block != NULL) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
static void smh_init_with_attr(enum smh_reg_attr attr)
|
|
{
|
|
unsigned int slot = 0;
|
|
uint8_t *mapped;
|
|
size_t size;
|
|
|
|
for (size_t reg = 0; reg < NUM_REGIONS; reg++) {
|
|
if (dt_region[reg].attr == attr) {
|
|
|
|
if (smh_init_reg != NULL) {
|
|
smh_init_reg(&dt_region[reg], &mapped, &size);
|
|
} else {
|
|
mapped = (uint8_t *) dt_region[reg].addr;
|
|
size = dt_region[reg].size;
|
|
}
|
|
|
|
sys_heap_init(&heap_pool[attr][slot], mapped, size);
|
|
sys_multi_heap_add_heap(&shared_multi_heap, &heap_pool[attr][slot]);
|
|
|
|
slot++;
|
|
}
|
|
}
|
|
}
|
|
|
|
void shared_multi_heap_free(void *block)
|
|
{
|
|
sys_multi_heap_free(&shared_multi_heap, block);
|
|
}
|
|
|
|
void *shared_multi_heap_alloc(enum smh_reg_attr attr, size_t bytes)
|
|
{
|
|
return sys_multi_heap_alloc(&shared_multi_heap, (void *) attr, bytes);
|
|
}
|
|
|
|
int shared_multi_heap_pool_init(smh_init_reg_fn_t smh_init_reg_fn)
|
|
{
|
|
smh_init_reg = smh_init_reg_fn;
|
|
|
|
sys_multi_heap_init(&shared_multi_heap, smh_choice);
|
|
|
|
for (size_t attr = 0; attr < SMH_REG_ATTR_NUM; attr++) {
|
|
smh_init_with_attr(attr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int shared_multi_heap_init(const struct device *dev)
|
|
{
|
|
__ASSERT_NO_MSG(NUM_REGIONS <= MAX_MULTI_HEAPS);
|
|
|
|
/* Nothing to do here. */
|
|
|
|
return 0;
|
|
}
|
|
SYS_INIT(shared_multi_heap_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
|