/* * Copyright (c) 2021 Carlo Caione, * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #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);