Skip to content

Commit

Permalink
module: add support for module unloading
Browse files Browse the repository at this point in the history
Zephyr added support for extension ref-counting, so now repeated
calls to llext_load() simply increment the extension use-count and
then an equal number of calls to llext_unload() is needed to unload
the extension. Add support for this to SOF. We use the llext unload
callback facility to call lib_manager_free_module() although in our
case races are impossible because of IPC serialisation.

Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
  • Loading branch information
lyakh committed Dec 8, 2023
1 parent a859bc1 commit 7e4a212
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 23 deletions.
40 changes: 28 additions & 12 deletions src/audio/module_adapter/module/modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <sof/lib_manager.h>
#include <sof/audio/module_adapter/module/module_interface.h>
#include <module/module/api_ver.h>
#include <zephyr/llext/llext.h>

/* Intel module adapter is an extension to SOF module adapter component that allows to integrate
* modules developed under IADK (Intel Audio Development Kit) Framework. IADK modules uses uniform
Expand Down Expand Up @@ -61,20 +62,23 @@ static int modules_init(struct processing_module *mod)
struct module_data *md = &mod->priv;
struct comp_dev *dev = mod->dev;
const struct ipc4_base_module_cfg *src_cfg = &md->cfg.base_cfg;
struct comp_ipc_config *config = &mod->dev->ipc_config;
const void *buildinfo = NULL;
/*
* Allocate module resources and move it to L2 memory, or just increment
* the use-count.
*/
uintptr_t module_entry_point = lib_manager_allocate_module(mod, config,
src_cfg, &buildinfo);

if (module_entry_point == 0) {
comp_err(dev, "modules_init(), lib_manager_allocate_module() failed!");
return -EINVAL;
}
comp_info(mod->dev, "modules_init() start");

if (!md->module_adapter) {
struct comp_ipc_config *config = &(mod->dev->ipc_config);
/* At this point module resources are allocated and it is moved to L2 memory. */
const void *buildinfo = NULL;
uintptr_t module_entry_point = lib_manager_allocate_module(mod, config,
src_cfg, &buildinfo);

if (module_entry_point == 0) {
comp_err(dev, "modules_init(), lib_manager_allocate_module() failed!");
return -EINVAL;
}
comp_info(mod->dev, "modules_init() start");

/* First load */
uint32_t module_id = IPC4_MOD_ID(config->id);
uint32_t instance_id = IPC4_INST_ID(config->id);
uint32_t log_handle = (uint32_t)mod->dev->drv->tctx;
Expand Down Expand Up @@ -309,6 +313,18 @@ static int modules_free(struct processing_module *mod)
rfree(md->mpd.in_buff);
rfree(md->mpd.out_buff);

if (md->llext) {
/* This uses a reference counter to decide, when to unload */
int cnt = llext_unload(&md->llext);

if (!cnt) {
/* Free module resources allocated in L2 memory. */
ret = lib_manager_free_module(mod, &dev->ipc_config);
if (ret < 0)
comp_err(dev, "modules_free(), lib_manager_free_module() failed!");
}
}

return ret;
}

Expand Down
2 changes: 1 addition & 1 deletion src/include/sof/lib_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc,
* Function is responsible to free module resources in HP memory.
*/
int lib_manager_free_module(struct processing_module *proc,
struct comp_ipc_config *ipc_config);
const struct comp_ipc_config *ipc_config);
/*
* \brief Load library
*
Expand Down
29 changes: 19 additions & 10 deletions src/library_manager/lib_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,7 @@ static int lib_manager_allocate_module_instance(uint32_t module_id, uint32_t ins
void __sparse_cache *va_base = lib_manager_get_instance_bss_address(module_id,
instance_id, mod);

/*
* Map bss memory and clear it.
*/
/* Map bss memory and clear it. */
if (sys_mm_drv_map_region((__sparse_force void *)va_base, POINTER_TO_UINT(NULL),
bss_size, SYS_MM_MEM_PERM_RW) < 0)
return -ENOMEM;
Expand All @@ -168,9 +166,7 @@ static int lib_manager_free_module_instance(uint32_t module_id, uint32_t instanc
uint32_t bss_size = mod->segment[SOF_MAN_SEGMENT_BSS].flags.r.length * PAGE_SZ;
void __sparse_cache *va_base = lib_manager_get_instance_bss_address(module_id,
instance_id, mod);
/*
* Unmap bss memory.
*/
/* Unmap bss memory. */
return sys_mm_drv_unmap_region((__sparse_force void *)va_base, bss_size);
}

Expand All @@ -195,8 +191,14 @@ static int lib_manager_link_llext(struct sof_man_fw_desc *desc, struct sof_man_m
struct llext_load_param ldr_parm = {false};
int ret = llext_load(&ebl.loader, mod->name, &md->llext, &ldr_parm);

if (ret < 0)
if (ret > 0)
/* Already loaded */
return md->module_entry_point;
if (ret < 0) {
tr_err(&lib_manager_tr,
"llext loading failed: %d", ret);
return ret;
}

mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = ebl.loader.sects[LLEXT_SECT_TEXT].sh_addr;
mod->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length =
Expand Down Expand Up @@ -276,20 +278,27 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc,
/* Map .text and the rest as .data */
ret = lib_manager_load_module(module_id, mod, desc);
if (ret < 0)
return 0;
goto e_ldmod;

ret = lib_manager_allocate_module_instance(module_id, IPC4_INST_ID(ipc_config->id), mod);
if (ret < 0) {
tr_err(&lib_manager_tr,
"lib_manager_allocate_module(): module allocation failed: %d", ret);
return 0;
goto e_bss;
}

return mod_manifest->module.entry_point;

e_bss:
lib_manager_unload_module(module_id, mod, desc);
e_ldmod:
if (module_is_llext(mod))
llext_unload(&proc->priv.llext);
return 0;
}

int lib_manager_free_module(struct processing_module *proc,
struct comp_ipc_config *ipc_config)
const struct comp_ipc_config *ipc_config)
{
struct sof_man_fw_desc *desc;
struct sof_man_module *mod;
Expand Down

0 comments on commit 7e4a212

Please sign in to comment.