diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index 7400e27f7edd..bc27495958b5 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -1,9 +1,11 @@ # SPDX-License-Identifier: BSD-3-Clause if(CONFIG_IPC_MAJOR_3) - add_local_sources(sof module_adapter.c module_adapter_ipc3.c module/generic.c) + add_local_sources(sof module_adapter.c module_adapter_ipc3.c module/generic.c + module/memory-common.c module/memory-heap.c) elseif(CONFIG_IPC_MAJOR_4) - add_local_sources(sof module_adapter.c module_adapter_ipc4.c module/generic.c) + add_local_sources(sof module_adapter.c module_adapter_ipc4.c module/generic.c + module/memory-common.c module/memory-heap.c) endif() is_zephyr(zephyr) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 5b8eb8e43ee6..c491cb00a6a9 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -71,351 +71,6 @@ int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) return ret; } -static void mod_resource_init(struct processing_module *mod) -{ - struct module_data *md = &mod->priv; - /* Init memory list */ - list_init(&md->resources.res_list); - list_init(&md->resources.free_cont_list); - list_init(&md->resources.cont_chunk_list); - md->resources.heap_usage = 0; - md->resources.heap_high_water_mark = 0; -} - -int module_init(struct processing_module *mod) -{ - int ret; - struct comp_dev *dev = mod->dev; - const struct module_interface *const interface = dev->drv->adapter_ops; - - comp_dbg(dev, "entry"); - -#if CONFIG_IPC_MAJOR_3 - if (mod->priv.state == MODULE_INITIALIZED) - return 0; - if (mod->priv.state > MODULE_INITIALIZED) - return -EPERM; -#endif - if (!interface) { - comp_err(dev, "module interface not defined"); - return -EIO; - } - - /* check interface, there must be one and only one of processing procedure */ - if (!interface->init || - (!!interface->process + !!interface->process_audio_stream + - !!interface->process_raw_data < 1)) { - comp_err(dev, "comp is missing mandatory interfaces"); - return -EIO; - } - - mod_resource_init(mod); -#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) - mod->priv.resources.rsrc_mngr = k_current_get(); -#endif - /* Now we can proceed with module specific initialization */ - ret = interface->init(mod); - if (ret) { - comp_err(dev, "error %d: module specific init failed", ret); - mod_free_all(mod); - return ret; - } - - comp_dbg(dev, "done"); -#if CONFIG_IPC_MAJOR_3 - mod->priv.state = MODULE_INITIALIZED; -#endif - - return 0; -} - -struct container_chunk { - struct list_item chunk_list; - struct module_resource containers[CONFIG_MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE]; -}; - -static struct module_resource *container_get(struct processing_module *mod) -{ - struct module_resources *res = &mod->priv.resources; - struct k_heap *mod_heap = res->heap; - struct module_resource *container; - - if (list_is_empty(&res->free_cont_list)) { - struct container_chunk *chunk = sof_heap_alloc(mod_heap, 0, sizeof(*chunk), 0); - int i; - - if (!chunk) { - comp_err(mod->dev, "allocating more containers failed"); - return NULL; - } - - memset(chunk, 0, sizeof(*chunk)); - - list_item_append(&chunk->chunk_list, &res->cont_chunk_list); - for (i = 0; i < ARRAY_SIZE(chunk->containers); i++) - list_item_append(&chunk->containers[i].list, &res->free_cont_list); - } - - container = list_first_item(&res->free_cont_list, struct module_resource, list); - list_item_del(&container->list); - return container; -} - -static void container_put(struct processing_module *mod, struct module_resource *container) -{ - struct module_resources *res = &mod->priv.resources; - - list_item_append(&container->list, &res->free_cont_list); -} - -/** - * Allocates aligned buffer memory block for module. - * @param mod Pointer to the module this memory block is allocated for. - * @param bytes Size in bytes. - * @param alignment Alignment in bytes. - * @return Pointer to the allocated memory or NULL if failed. - * - * The allocated memory is automatically freed when the module is - * unloaded. The back-end, rballoc(), always aligns the memory to - * PLATFORM_DCACHE_ALIGN at the minimum. - */ -void *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment) -{ - struct module_resources *res = &mod->priv.resources; - struct module_resource *container; - - MEM_API_CHECK_THREAD(res); - - container = container_get(mod); - if (!container) - return NULL; - - if (!size) { - comp_err(mod->dev, "requested allocation of 0 bytes."); - container_put(mod, container); - return NULL; - } - - /* Allocate buffer memory for module */ - void *ptr = sof_heap_alloc(res->heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, - size, alignment); - - if (!ptr) { - comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", - size, alignment, dev_comp_id(mod->dev)); - container_put(mod, container); - return NULL; - } - /* Store reference to allocated memory */ - container->ptr = ptr; - container->size = size; - container->type = MOD_RES_HEAP; - list_item_prepend(&container->list, &res->res_list); - - res->heap_usage += size; - if (res->heap_usage > res->heap_high_water_mark) - res->heap_high_water_mark = res->heap_usage; - - return ptr; -} -EXPORT_SYMBOL(mod_balloc_align); - -/** - * Allocates aligned memory block with flags for module. - * @param mod Pointer to the module this memory block is allocated for. - * @param flags Allocator flags. - * @param bytes Size in bytes. - * @param alignment Alignment in bytes. - * @return Pointer to the allocated memory or NULL if failed. - * - * The allocated memory is automatically freed when the module is unloaded. - */ -void *mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, size_t alignment) -{ - struct module_resources *res = &mod->priv.resources; - struct module_resource *container; - - MEM_API_CHECK_THREAD(res); - - container = container_get(mod); - if (!container) - return NULL; - - if (!size) { - comp_err(mod->dev, "requested allocation of 0 bytes."); - container_put(mod, container); - return NULL; - } - - /* Allocate memory for module */ - void *ptr = sof_heap_alloc(res->heap, flags, size, alignment); - - if (!ptr) { - comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", - size, alignment, dev_comp_id(mod->dev)); - container_put(mod, container); - return NULL; - } - /* Store reference to allocated memory */ - container->ptr = ptr; - container->size = size; - container->type = MOD_RES_HEAP; - list_item_prepend(&container->list, &res->res_list); - - res->heap_usage += size; - if (res->heap_usage > res->heap_high_water_mark) - res->heap_high_water_mark = res->heap_usage; - - return ptr; -} -EXPORT_SYMBOL(mod_alloc_ext); - -/** - * Creates a blob handler and releases it when the module is unloaded - * @param mod Pointer to module this memory block is allocated for. - * @return Pointer to the created data blob handler - * - * Like comp_data_blob_handler_new() but the handler is automatically freed. - */ -#if CONFIG_COMP_BLOB -struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod) -{ - struct module_resources *res = &mod->priv.resources; - struct comp_data_blob_handler *bhp; - struct module_resource *container; - - MEM_API_CHECK_THREAD(res); - - container = container_get(mod); - if (!container) - return NULL; - - bhp = comp_data_blob_handler_new_ext(mod->dev, false, NULL, NULL); - if (!bhp) { - container_put(mod, container); - return NULL; - } - - container->bhp = bhp; - container->size = 0; - container->type = MOD_RES_BLOB_HANDLER; - list_item_prepend(&container->list, &res->res_list); - - return bhp; -} -EXPORT_SYMBOL(mod_data_blob_handler_new); -#endif - -/** - * Make a module associated shared SRAM copy of DRAM read-only data. - * @param mod Pointer to module this copy is allocated for. - * @return Pointer to the SRAM copy. - * - * Like fast_get() but the handler is automatically freed. - */ -#if CONFIG_FAST_GET -const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size) -{ - struct module_resources *res = &mod->priv.resources; - struct module_resource *container; - const void *ptr; - - MEM_API_CHECK_THREAD(res); - - container = container_get(mod); - if (!container) - return NULL; - - ptr = fast_get(res->heap, dram_ptr, size); - if (!ptr) { - container_put(mod, container); - return NULL; - } - - container->sram_ptr = ptr; - container->size = 0; - container->type = MOD_RES_FAST_GET; - list_item_prepend(&container->list, &res->res_list); - - return ptr; -} -EXPORT_SYMBOL(mod_fast_get); -#endif - -static int free_contents(struct processing_module *mod, struct module_resource *container) -{ - struct module_resources *res = &mod->priv.resources; - - switch (container->type) { - case MOD_RES_HEAP: - sof_heap_free(res->heap, container->ptr); - res->heap_usage -= container->size; - return 0; -#if CONFIG_COMP_BLOB - case MOD_RES_BLOB_HANDLER: - comp_data_blob_handler_free(container->bhp); - return 0; -#endif -#if CONFIG_FAST_GET - case MOD_RES_FAST_GET: - fast_put(res->heap, container->sram_ptr); - return 0; -#endif - default: - comp_err(mod->dev, "Unknown resource type: %d", container->type); - } - return -EINVAL; -} - -/** - * Frees the memory block removes it from module's book keeping. - * @param mod Pointer to module this memory block was allocated for. - * @param ptr Pointer to the memory block. - */ -int mod_free(struct processing_module *mod, const void *ptr) -{ - struct module_resources *res = &mod->priv.resources; - struct module_resource *container; - struct list_item *res_list; - - MEM_API_CHECK_THREAD(res); - if (!ptr) - return 0; - - /* Find which container keeps this memory */ - list_for_item(res_list, &res->res_list) { - container = container_of(res_list, struct module_resource, list); - if (container->ptr == ptr) { - int ret = free_contents(mod, container); - - list_item_del(&container->list); - container_put(mod, container); - return ret; - } - } - - comp_err(mod->dev, "error: could not find memory pointed by %p", ptr); - - return -EINVAL; -} -EXPORT_SYMBOL(mod_free); - -#if CONFIG_COMP_BLOB -void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh) -{ - mod_free(mod, (void *)dbh); -} -EXPORT_SYMBOL(mod_data_blob_handler_free); -#endif - -#if CONFIG_FAST_GET -void mod_fast_put(struct processing_module *mod, const void *sram_ptr) -{ - mod_free(mod, sram_ptr); -} -EXPORT_SYMBOL(mod_fast_put); -#endif - int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -580,74 +235,6 @@ int module_reset(struct processing_module *mod) return 0; } -/** - * Frees all the resources registered for this module - * @param mod Pointer to module that should have its resource freed. - * - * This function is called automatically when the module is unloaded. - */ -void mod_free_all(struct processing_module *mod) -{ - struct module_resources *res = &mod->priv.resources; - struct k_heap *mod_heap = res->heap; - struct list_item *list; - struct list_item *_list; - - MEM_API_CHECK_THREAD(res); - /* Free all contents found in used containers */ - list_for_item(list, &res->res_list) { - struct module_resource *container = - container_of(list, struct module_resource, list); - - free_contents(mod, container); - } - - /* - * We do not need to remove the containers from res_list in - * the loop above or go through free_cont_list as all the - * containers are anyway freed in the loop below, and the list - * heads are reinitialized when mod_resource_init() is called. - */ - list_for_item_safe(list, _list, &res->cont_chunk_list) { - struct container_chunk *chunk = - container_of(list, struct container_chunk, chunk_list); - - list_item_del(&chunk->chunk_list); - sof_heap_free(mod_heap, chunk); - } - - /* Make sure resource lists and accounting are reset */ - mod_resource_init(mod); -} -EXPORT_SYMBOL(mod_free_all); - -int module_free(struct processing_module *mod) -{ - const struct module_interface *const ops = mod->dev->drv->adapter_ops; - struct module_data *md = &mod->priv; - int ret = 0; - - if (ops->free) { - ret = ops->free(mod); - if (ret) - comp_warn(mod->dev, "error: %d", ret); - } - - /* Free all memory shared by module_adapter & module */ - md->cfg.avail = false; - md->cfg.size = 0; - rfree(md->cfg.data); - md->cfg.data = NULL; - if (md->runtime_params) { - rfree(md->runtime_params); - md->runtime_params = NULL; - } -#if CONFIG_IPC_MAJOR_3 - md->state = MODULE_DISABLED; -#endif - return ret; -} - /* * \brief Set module configuration - Common method to assemble large configuration message * \param[in] mod - struct processing_module pointer diff --git a/src/audio/module_adapter/module/memory-common.c b/src/audio/module_adapter/module/memory-common.c new file mode 100644 index 000000000000..01aa7756ab49 --- /dev/null +++ b/src/audio/module_adapter/module/memory-common.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Marcin Rajwa + +/* + * \file memory-common.c + * \brief Generic Codec Memory API common functions + * \author Marcin Rajwa + * + */ + +#include +#include +#include +#include + +LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); + +int module_init(struct processing_module *mod) +{ + int ret; + struct comp_dev *dev = mod->dev; + const struct module_interface *const interface = dev->drv->adapter_ops; + + comp_dbg(dev, "entry"); + +#if CONFIG_IPC_MAJOR_3 + if (mod->priv.state == MODULE_INITIALIZED) + return 0; + if (mod->priv.state > MODULE_INITIALIZED) + return -EPERM; +#endif + if (!interface) { + comp_err(dev, "module interface not defined"); + return -EIO; + } + + /* check interface, there must be one and only one of processing procedure */ + if (!interface->init || + (!!interface->process + !!interface->process_audio_stream + + !!interface->process_raw_data < 1)) { + comp_err(dev, "comp is missing mandatory interfaces"); + return -EIO; + } + + mod_resource_init(mod); +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) + mod->priv.resources.rsrc_mngr = k_current_get(); +#endif + /* Now we can proceed with module specific initialization */ + ret = interface->init(mod); + if (ret) { + comp_err(dev, "error %d: module specific init failed", ret); + mod_free_all(mod); + return ret; + } + + comp_dbg(dev, "done"); +#if CONFIG_IPC_MAJOR_3 + mod->priv.state = MODULE_INITIALIZED; +#endif + + return 0; +} + +#if CONFIG_COMP_BLOB +void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh) +{ + mod_free(mod, (void *)dbh); +} +EXPORT_SYMBOL(mod_data_blob_handler_free); +#endif + +#if CONFIG_FAST_GET +void mod_fast_put(struct processing_module *mod, const void *sram_ptr) +{ + mod_free(mod, sram_ptr); +} +EXPORT_SYMBOL(mod_fast_put); +#endif + diff --git a/src/audio/module_adapter/module/memory-heap.c b/src/audio/module_adapter/module/memory-heap.c new file mode 100644 index 000000000000..8eeb57442d2c --- /dev/null +++ b/src/audio/module_adapter/module/memory-heap.c @@ -0,0 +1,488 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2020 Intel Corporation. All rights reserved. +// +// Author: Marcin Rajwa + +/* + * \file memory-heap.c + * \brief Generic Codec Memory API heap functions + * \author Marcin Rajwa + * + */ + +#include + +#include +#include +#include + +/* The __ZEPHYR__ condition is to keep cmocka tests working */ +#if CONFIG_MODULE_MEMORY_API_DEBUG && defined(__ZEPHYR__) +#define MEM_API_CHECK_THREAD(res) __ASSERT((res)->rsrc_mngr == k_current_get(), \ + "Module memory API operation from wrong thread") +#else +#define MEM_API_CHECK_THREAD(res) +#endif + +LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); + +struct container_chunk { + struct list_item chunk_list; + struct module_resource containers[CONFIG_MODULE_MEMORY_API_CONTAINER_CHUNK_SIZE]; +}; + +void mod_resource_init(struct processing_module *mod) +{ + struct module_data *md = &mod->priv; + /* Init memory list */ + list_init(&md->resources.res_list); + list_init(&md->resources.free_cont_list); + list_init(&md->resources.cont_chunk_list); + md->resources.heap_usage = 0; + md->resources.heap_high_water_mark = 0; +} + +static struct module_resource *container_get(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct k_heap *mod_heap = res->heap; + struct module_resource *container; + + if (list_is_empty(&res->free_cont_list)) { + struct container_chunk *chunk = sof_heap_alloc(mod_heap, 0, sizeof(*chunk), 0); + int i; + + if (!chunk) { + comp_err(mod->dev, "allocating more containers failed"); + return NULL; + } + + memset(chunk, 0, sizeof(*chunk)); + + list_item_append(&chunk->chunk_list, &res->cont_chunk_list); + for (i = 0; i < ARRAY_SIZE(chunk->containers); i++) + list_item_append(&chunk->containers[i].list, &res->free_cont_list); + } + + container = list_first_item(&res->free_cont_list, struct module_resource, list); + list_item_del(&container->list); + return container; +} + +static void container_put(struct processing_module *mod, struct module_resource *container) +{ + struct module_resources *res = &mod->priv.resources; + + list_item_append(&container->list, &res->free_cont_list); +} + +/** + * Allocates aligned buffer memory block for module. + * @param mod Pointer to the module this memory block is allocated for. + * @param bytes Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * The allocated memory is automatically freed when the module is + * unloaded. The back-end, rballoc(), always aligns the memory to + * PLATFORM_DCACHE_ALIGN at the minimum. + */ +void *mod_balloc_align(struct processing_module *mod, size_t size, size_t alignment) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + + MEM_API_CHECK_THREAD(res); + + container = container_get(mod); + if (!container) + return NULL; + + if (!size) { + comp_err(mod->dev, "requested allocation of 0 bytes."); + container_put(mod, container); + return NULL; + } + + /* Allocate buffer memory for module */ + void *ptr = sof_heap_alloc(res->heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, + size, alignment); + + if (!ptr) { + comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", + size, alignment, dev_comp_id(mod->dev)); + container_put(mod, container); + return NULL; + } + /* Store reference to allocated memory */ + container->ptr = ptr; + container->size = size; + container->type = MOD_RES_HEAP; + list_item_prepend(&container->list, &res->res_list); + + res->heap_usage += size; + if (res->heap_usage > res->heap_high_water_mark) + res->heap_high_water_mark = res->heap_usage; + + return ptr; +} +EXPORT_SYMBOL(mod_balloc_align); + +/** + * Allocates aligned memory block with flags for module. + * @param mod Pointer to the module this memory block is allocated for. + * @param flags Allocator flags. + * @param bytes Size in bytes. + * @param alignment Alignment in bytes. + * @return Pointer to the allocated memory or NULL if failed. + * + * The allocated memory is automatically freed when the module is unloaded. + */ +void *mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, size_t alignment) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + + MEM_API_CHECK_THREAD(res); + + container = container_get(mod); + if (!container) + return NULL; + + if (!size) { + comp_err(mod->dev, "requested allocation of 0 bytes."); + container_put(mod, container); + return NULL; + } + + /* Allocate memory for module */ + void *ptr = sof_heap_alloc(res->heap, flags, size, alignment); + + if (!ptr) { + comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", + size, alignment, dev_comp_id(mod->dev)); + container_put(mod, container); + return NULL; + } + /* Store reference to allocated memory */ + container->ptr = ptr; + container->size = size; + container->type = MOD_RES_HEAP; + list_item_prepend(&container->list, &res->res_list); + + res->heap_usage += size; + if (res->heap_usage > res->heap_high_water_mark) + res->heap_high_water_mark = res->heap_usage; + + return ptr; +} +EXPORT_SYMBOL(mod_alloc_ext); + +/** + * Creates a blob handler and releases it when the module is unloaded + * @param mod Pointer to module this memory block is allocated for. + * @return Pointer to the created data blob handler + * + * Like comp_data_blob_handler_new() but the handler is automatically freed. + */ +#if CONFIG_COMP_BLOB +struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct comp_data_blob_handler *bhp; + struct module_resource *container; + + MEM_API_CHECK_THREAD(res); + + container = container_get(mod); + if (!container) + return NULL; + + bhp = comp_data_blob_handler_new_ext(mod->dev, false, NULL, NULL); + if (!bhp) { + container_put(mod, container); + return NULL; + } + + container->bhp = bhp; + container->size = 0; + container->type = MOD_RES_BLOB_HANDLER; + list_item_prepend(&container->list, &res->res_list); + + return bhp; +} +EXPORT_SYMBOL(mod_data_blob_handler_new); +#endif + +/** + * Make a module associated shared SRAM copy of DRAM read-only data. + * @param mod Pointer to module this copy is allocated for. + * @return Pointer to the SRAM copy. + * + * Like fast_get() but the handler is automatically freed. + */ +#if CONFIG_FAST_GET +const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + const void *ptr; + + MEM_API_CHECK_THREAD(res); + + container = container_get(mod); + if (!container) + return NULL; + + ptr = fast_get(res->heap, dram_ptr, size); + if (!ptr) { + container_put(mod, container); + return NULL; + } + + container->sram_ptr = ptr; + container->size = 0; + container->type = MOD_RES_FAST_GET; + list_item_prepend(&container->list, &res->res_list); + + return ptr; +} +EXPORT_SYMBOL(mod_fast_get); +#endif + +static int free_contents(struct processing_module *mod, struct module_resource *container) +{ + struct module_resources *res = &mod->priv.resources; + + switch (container->type) { + case MOD_RES_HEAP: + sof_heap_free(res->heap, container->ptr); + res->heap_usage -= container->size; + return 0; +#if CONFIG_COMP_BLOB + case MOD_RES_BLOB_HANDLER: + comp_data_blob_handler_free(container->bhp); + return 0; +#endif +#if CONFIG_FAST_GET + case MOD_RES_FAST_GET: + fast_put(res->heap, container->sram_ptr); + return 0; +#endif + default: + comp_err(mod->dev, "Unknown resource type: %d", container->type); + } + return -EINVAL; +} + +/** + * Frees the memory block removes it from module's book keeping. + * @param mod Pointer to module this memory block was allocated for. + * @param ptr Pointer to the memory block. + */ +int mod_free(struct processing_module *mod, const void *ptr) +{ + struct module_resources *res = &mod->priv.resources; + struct module_resource *container; + struct list_item *res_list; + + MEM_API_CHECK_THREAD(res); + if (!ptr) + return 0; + + /* Find which container keeps this memory */ + list_for_item(res_list, &res->res_list) { + container = container_of(res_list, struct module_resource, list); + if (container->ptr == ptr) { + int ret = free_contents(mod, container); + + list_item_del(&container->list); + container_put(mod, container); + return ret; + } + } + + comp_err(mod->dev, "error: could not find memory pointed by %p", ptr); + + return -EINVAL; +} +EXPORT_SYMBOL(mod_free); + +/** + * Frees all the resources registered for this module + * @param mod Pointer to module that should have its resource freed. + * + * This function is called automatically when the module is unloaded. + */ +void mod_free_all(struct processing_module *mod) +{ + struct module_resources *res = &mod->priv.resources; + struct k_heap *mod_heap = res->heap; + struct list_item *list; + struct list_item *_list; + + MEM_API_CHECK_THREAD(res); + /* Free all contents found in used containers */ + list_for_item(list, &res->res_list) { + struct module_resource *container = + container_of(list, struct module_resource, list); + + free_contents(mod, container); + } + + /* + * We do not need to remove the containers from res_list in + * the loop above or go through free_cont_list as all the + * containers are anyway freed in the loop below, and the list + * heads are reinitialized when mod_resource_init() is called. + */ + list_for_item_safe(list, _list, &res->cont_chunk_list) { + struct container_chunk *chunk = + container_of(list, struct container_chunk, chunk_list); + + list_item_del(&chunk->chunk_list); + sof_heap_free(mod_heap, chunk); + } + + /* Make sure resource lists and accounting are reset */ + mod_resource_init(mod); +} +EXPORT_SYMBOL(mod_free_all); + +int module_free(struct processing_module *mod) +{ + const struct module_interface *const ops = mod->dev->drv->adapter_ops; + struct module_data *md = &mod->priv; + int ret = 0; + + if (ops->free) { + ret = ops->free(mod); + if (ret) + comp_warn(mod->dev, "error: %d", ret); + } + + /* Free all memory shared by module_adapter & module */ + md->cfg.avail = false; + md->cfg.size = 0; + rfree(md->cfg.data); + md->cfg.data = NULL; + if (md->runtime_params) { + rfree(md->runtime_params); + md->runtime_params = NULL; + } +#if CONFIG_IPC_MAJOR_3 + md->state = MODULE_DISABLED; +#endif + return ret; +} + +#if CONFIG_MM_DRV +#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE +#else +#include +#define PAGE_SZ HOST_PAGE_SIZE +#endif + +static struct k_heap *module_adapter_dp_heap_new(const struct comp_ipc_config *config) +{ + /* src-lite with 8 channels has been seen allocating 14k in one go */ + /* FIXME: the size will be derived from configuration */ + const size_t heap_size = 20 * 1024; + + /* Keep uncached to match the default SOF heap! */ + uint8_t *mod_heap_mem = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + heap_size, PAGE_SZ); + + if (!mod_heap_mem) + return NULL; + + struct k_heap *mod_heap = (struct k_heap *)mod_heap_mem; + const size_t heap_prefix_size = ALIGN_UP(sizeof(*mod_heap), 8); + void *mod_heap_buf = mod_heap_mem + heap_prefix_size; + + k_heap_init(mod_heap, mod_heap_buf, heap_size - heap_prefix_size); + +#ifdef __ZEPHYR__ + mod_heap->heap.init_mem = mod_heap_buf; + mod_heap->heap.init_bytes = heap_size - heap_prefix_size; +#endif + return mod_heap; +} + +struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, + const struct comp_ipc_config *config) +{ + struct k_heap *mod_heap; + /* + * For DP shared modules the struct processing_module object must be + * accessible from all cores. Unfortunately at this point there's no + * information of components the module will be bound to. So we need to + * allocate shared memory for each DP module. + * To be removed when pipeline 2.0 is ready. + */ + uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER; + + if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_USERSPACE) && + !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) { + mod_heap = module_adapter_dp_heap_new(config); + if (!mod_heap) { + comp_cl_err(drv, "Failed to allocate DP module heap"); + return NULL; + } + } else { + mod_heap = drv->user_heap; + } + + struct processing_module *mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0); + + if (!mod) { + comp_cl_err(drv, "failed to allocate memory for module"); + goto emod; + } + + memset(mod, 0, sizeof(*mod)); + mod->priv.resources.heap = mod_heap; + + /* + * Would be difficult to optimize the allocation to use cache. Only if + * the whole currently active topology is running on the primary core, + * then it can be cached. Effectively it can be only cached in + * single-core configurations. + */ + struct comp_dev *dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0); + + if (!dev) { + comp_cl_err(drv, "failed to allocate memory for comp_dev"); + goto err; + } + + memset(dev, 0, sizeof(*dev)); + comp_init(drv, dev, sizeof(*dev)); + dev->ipc_config = *config; + mod->dev = dev; + dev->mod = mod; + + return mod; + +err: + sof_heap_free(mod_heap, mod); +emod: + if (mod_heap != drv->user_heap) + rfree(mod_heap); + + return NULL; +} + +void module_adapter_mem_free(struct processing_module *mod) +{ + struct k_heap *mod_heap = mod->priv.resources.heap; + +#if CONFIG_IPC_MAJOR_4 + sof_heap_free(mod_heap, mod->priv.cfg.input_pins); +#endif + sof_heap_free(mod_heap, mod->dev); + sof_heap_free(mod_heap, mod); +} + diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 7edc018dabb4..5dc37f6ec2e7 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -45,115 +45,6 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, return module_adapter_new_ext(drv, config, spec, NULL, NULL); } -#if CONFIG_MM_DRV -#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE -#else -#include -#define PAGE_SZ HOST_PAGE_SIZE -#endif - -static struct k_heap *module_adapter_dp_heap_new(const struct comp_ipc_config *config) -{ - /* src-lite with 8 channels has been seen allocating 14k in one go */ - /* FIXME: the size will be derived from configuration */ - const size_t heap_size = 20 * 1024; - - /* Keep uncached to match the default SOF heap! */ - uint8_t *mod_heap_mem = rballoc_align(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, - heap_size, PAGE_SZ); - - if (!mod_heap_mem) - return NULL; - - struct k_heap *mod_heap = (struct k_heap *)mod_heap_mem; - const size_t heap_prefix_size = ALIGN_UP(sizeof(*mod_heap), 8); - void *mod_heap_buf = mod_heap_mem + heap_prefix_size; - - k_heap_init(mod_heap, mod_heap_buf, heap_size - heap_prefix_size); -#ifdef __ZEPHYR__ - mod_heap->heap.init_mem = mod_heap_buf; - mod_heap->heap.init_bytes = heap_size - heap_prefix_size; -#endif - - return mod_heap; -} - -static struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, - const struct comp_ipc_config *config) -{ - struct k_heap *mod_heap; - /* - * For DP shared modules the struct processing_module object must be - * accessible from all cores. Unfortunately at this point there's no - * information of components the module will be bound to. So we need to - * allocate shared memory for each DP module. - * To be removed when pipeline 2.0 is ready. - */ - uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? - SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER; - - if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_USERSPACE) && - !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) { - mod_heap = module_adapter_dp_heap_new(config); - if (!mod_heap) { - comp_cl_err(drv, "Failed to allocate DP module heap"); - return NULL; - } - } else { - mod_heap = drv->user_heap; - } - - struct processing_module *mod = sof_heap_alloc(mod_heap, flags, sizeof(*mod), 0); - - if (!mod) { - comp_cl_err(drv, "failed to allocate memory for module"); - goto emod; - } - - memset(mod, 0, sizeof(*mod)); - mod->priv.resources.heap = mod_heap; - - /* - * Would be difficult to optimize the allocation to use cache. Only if - * the whole currently active topology is running on the primary core, - * then it can be cached. Effectively it can be only cached in - * single-core configurations. - */ - struct comp_dev *dev = sof_heap_alloc(mod_heap, SOF_MEM_FLAG_COHERENT, sizeof(*dev), 0); - - if (!dev) { - comp_cl_err(drv, "failed to allocate memory for comp_dev"); - goto err; - } - - memset(dev, 0, sizeof(*dev)); - comp_init(drv, dev, sizeof(*dev)); - dev->ipc_config = *config; - mod->dev = dev; - dev->mod = mod; - - return mod; - -err: - sof_heap_free(mod_heap, mod); -emod: - if (mod_heap != drv->user_heap) - rfree(mod_heap); - - return NULL; -} - -static void module_adapter_mem_free(struct processing_module *mod) -{ - struct k_heap *mod_heap = mod->priv.resources.heap; - -#if CONFIG_IPC_MAJOR_4 - sof_heap_free(mod_heap, mod->priv.cfg.input_pins); -#endif - sof_heap_free(mod_heap, mod->dev); - sof_heap_free(mod_heap, mod); -} - /* * \brief Create a module adapter component. * \param[in] drv - component driver pointer. diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index f339ac158ab0..fb4df938e346 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -227,6 +227,9 @@ static inline void *mod_zalloc(struct processing_module *mod, size_t size) } int mod_free(struct processing_module *mod, const void *ptr); +void module_adapter_mem_free(struct processing_module *mod); +struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, + const struct comp_ipc_config *config); #if CONFIG_COMP_BLOB struct comp_data_blob_handler *mod_data_blob_handler_new(struct processing_module *mod); void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_blob_handler *dbh); @@ -235,6 +238,7 @@ void mod_data_blob_handler_free(struct processing_module *mod, struct comp_data_ const void *mod_fast_get(struct processing_module *mod, const void * const dram_ptr, size_t size); void mod_fast_put(struct processing_module *mod, const void *sram_ptr); #endif +void mod_resource_init(struct processing_module *mod); void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, diff --git a/test/cmocka/src/audio/eq_fir/CMakeLists.txt b/test/cmocka/src/audio/eq_fir/CMakeLists.txt index 305a6846966c..90eeff6cb80e 100644 --- a/test/cmocka/src/audio/eq_fir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_fir/CMakeLists.txt @@ -24,6 +24,8 @@ add_library(audio_for_eq_fir STATIC ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-common.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-heap.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/comp_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/audio_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/audio/eq_iir/CMakeLists.txt b/test/cmocka/src/audio/eq_iir/CMakeLists.txt index aa704a1af92b..a0af9662694a 100644 --- a/test/cmocka/src/audio/eq_iir/CMakeLists.txt +++ b/test/cmocka/src/audio/eq_iir/CMakeLists.txt @@ -27,6 +27,8 @@ add_library(audio_for_eq_iir STATIC ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-common.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-heap.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/comp_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/audio_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/audio/mixer/CMakeLists.txt b/test/cmocka/src/audio/mixer/CMakeLists.txt index ea8cad0bd79e..ef80cf741a27 100644 --- a/test/cmocka/src/audio/mixer/CMakeLists.txt +++ b/test/cmocka/src/audio/mixer/CMakeLists.txt @@ -13,6 +13,8 @@ cmocka_test(mixer ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-common.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-heap.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/comp_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/audio_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c diff --git a/test/cmocka/src/audio/mux/CMakeLists.txt b/test/cmocka/src/audio/mux/CMakeLists.txt index 67b10f77270d..827a2aef740c 100644 --- a/test/cmocka/src/audio/mux/CMakeLists.txt +++ b/test/cmocka/src/audio/mux/CMakeLists.txt @@ -29,6 +29,8 @@ add_library( ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-common.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-heap.c ) sof_append_relative_path_definitions(audio_mux) diff --git a/test/cmocka/src/audio/volume/CMakeLists.txt b/test/cmocka/src/audio/volume/CMakeLists.txt index d89927578222..78cead46f5cf 100644 --- a/test/cmocka/src/audio/volume/CMakeLists.txt +++ b/test/cmocka/src/audio/volume/CMakeLists.txt @@ -23,6 +23,8 @@ add_library(audio_for_volume STATIC ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-common.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/memory-heap.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/comp_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/buffers/audio_buffer.c ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c