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 <[email protected]>
  • Loading branch information
lyakh committed Nov 3, 2023
1 parent b150c22 commit 333d97d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
35 changes: 24 additions & 11 deletions src/audio/module_adapter/module/modules.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <sof/lib_manager.h>
#include <sof/audio/module_adapter/module/module_interface.h>
#include <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 @@ -60,20 +61,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);
int ret;

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;
}
if (module_entry_point == 0) {
comp_err(dev, "modules_init(), lib_manager_allocate_module() failed!");
return -EINVAL;
}

if (!md->module_adapter) {
/* First load */
uint32_t module_id = IPC4_MOD_ID(config->id);
uint32_t instance_id = IPC4_INST_ID(config->id);
/* Connect loadable module interfaces with module adapter entity. */
Expand Down Expand Up @@ -277,6 +281,11 @@ static int modules_process_raw(struct processing_module *mod,
return ret;
}

static void lib_manager_module_free_cb(struct llext *, const void *ctx)
{
lib_manager_free_module(NULL, ctx);
}

/**
* \brief modules_free.
* \param[in] mod - processing module pointer.
Expand All @@ -302,6 +311,10 @@ 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 */
llext_unload(&md->llext, lib_manager_module_free_cb, &dev->ipc_config);

#if 0
/*
* Module unloading isn't implemented yet, it has to be done from a
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 @@ -151,7 +151,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
33 changes: 25 additions & 8 deletions src/library_manager/lib_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,16 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc,
SOF_MAN_ELF_TEXT_OFFSET + 0x8000,
mod_size);
ret = llext_load(&ebl.loader, mod->name, &proc->priv.llext, false);
if (ret < 0)
return ret;
if (ret > 0)
/* Already loaded */
return proc->priv.module_entry_point;
if (ret < 0) {
tr_err(&lib_manager_tr,
"lib_manager_allocate_module(): llext loading failed: %d", ret);
return 0;
}

assert(proc->priv.llext);

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 = ebl.loader.sects[LLEXT_SECT_TEXT].sh_size;
Expand All @@ -301,29 +309,38 @@ 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;
if (ret < 0) {
tr_err(&lib_manager_tr,
"lib_manager_allocate_module(): module loading failed: %d", ret);
goto e_llext;
}

/* Map .bss */
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;
}

ssize_t mod_o = llext_find_section(&ebl.loader, ".module");
const struct sof_man_module_manifest *mod_manifest = llext_peek(&ebl.loader,
mod_o);
const struct sof_man_module_manifest *mod_manifest = llext_peek(&ebl.loader, mod_o);

ssize_t binfo_o = llext_find_section(&ebl.loader, ".mod_buildinfo");
if (binfo_o)
*buildinfo = llext_peek(&ebl.loader, binfo_o);

return mod_manifest->module.entry_point;

e_bss:
lib_manager_unload_module(module_id, mod, desc);
e_llext:
llext_unload(&proc->priv.llext, NULL, NULL);
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 333d97d

Please sign in to comment.