lib_manager: modules: move native lib support to lib_manager

Moved module type identification to lib_manager. Since llext modules place
the buildinfo structure in a separate section, API version verification has
been moved to llext_manager. Thanks to these changes, the Processing Module
Adapter is used only by IADK modules as intended. This commit also fixes an
issue with the modules_free function not being called for native modules.

Signed-off-by: Adrian Warecki <adrian.warecki@intel.com>
Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
This commit is contained in:
Adrian Warecki 2024-03-11 19:12:23 +01:00 committed by Kai Vehmanen
parent 784da5468e
commit 902b1e5817
7 changed files with 191 additions and 138 deletions

View File

@ -10,12 +10,8 @@
#include <utilities/array.h>
#include <iadk_module_adapter.h>
#include <system_agent.h>
#include <native_system_agent.h>
#include <api_version.h>
#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
@ -51,63 +47,6 @@ DECLARE_SOF_RT_UUID("modules", intel_uuid, 0xee2585f2, 0xe7d8, 0x43dc,
0x90, 0xab, 0x42, 0x24, 0xe0, 0x0c, 0x3e, 0x84);
DECLARE_TR_CTX(intel_codec_tr, SOF_UUID(intel_uuid), LOG_LEVEL_INFO);
static int modules_new(struct processing_module *mod, const void *buildinfo,
uintptr_t module_entry_point)
{
struct module_data *md = &mod->priv;
struct comp_dev *dev = mod->dev;
struct comp_driver *drv = (struct comp_driver *)dev->drv;
uint32_t module_id = IPC4_MOD_ID(dev->ipc_config.id);
uint32_t instance_id = IPC4_INST_ID(dev->ipc_config.id);
uint32_t log_handle = (uint32_t) dev->drv->tctx;
/* Connect loadable module interfaces with module adapter entity. */
/* Check if native Zephyr lib is loaded */
void *system_agent;
const struct sof_module_api_build_info *mod_buildinfo;
if (buildinfo) {
mod_buildinfo = buildinfo;
} else {
const struct sof_man_module *const module_entry =
lib_manager_get_module_manifest(module_id);
if (!module_entry) {
comp_err(dev, "modules_new(): Failed to load manifest");
return -ENODATA;
}
mod_buildinfo =
(struct sof_module_api_build_info *)
(module_entry->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr);
}
byte_array_t mod_cfg = {
.data = (uint8_t *)md->cfg.init_data,
/* Intel modules expects DW size here */
.size = md->cfg.size >> 2,
};
/* Check if module is FDK */
if (mod_buildinfo->format == IADK_MODULE_API_BUILD_INFO_FORMAT &&
mod_buildinfo->api_version_number.full == IADK_MODULE_API_CURRENT_VERSION) {
system_agent = system_agent_start(module_entry_point, module_id, instance_id, 0,
log_handle, &mod_cfg);
module_set_private_data(mod, system_agent);
} else if (mod_buildinfo->format == SOF_MODULE_API_BUILD_INFO_FORMAT &&
mod_buildinfo->api_version_number.full == SOF_MODULE_API_CURRENT_VERSION) {
/* The module is native: start agent for sof loadable */
mod->is_native_sof = true;
drv->adapter_ops = native_system_agent_start(module_entry_point, module_id,
instance_id, 0, log_handle, &mod_cfg);
} else {
return -ENOEXEC;
}
return 0;
}
/**
* \brief modules_init.
* \param[in] mod - processing module pointer.
@ -121,51 +60,39 @@ static int modules_init(struct processing_module *mod)
struct comp_dev *dev = mod->dev;
const struct comp_driver *const drv = dev->drv;
const struct ipc4_base_module_cfg *src_cfg = &md->cfg.base_cfg;
struct comp_ipc_config *config = &(dev->ipc_config);
/* At this point module resources are allocated and it is moved to L2 memory. */
const void *buildinfo = NULL;
int ret;
uintptr_t module_entry_point = lib_manager_allocate_module(mod, config, src_cfg,
&buildinfo);
const struct comp_ipc_config *config = &dev->ipc_config;
void *system_agent;
uintptr_t module_entry_point = lib_manager_allocate_module(mod, config, src_cfg);
if (module_entry_point == 0) {
comp_err(dev, "modules_init(), lib_manager_allocate_module() failed!");
return -EINVAL;
}
/* At this point module resources are allocated and it is moved to L2 memory. */
comp_info(dev, "modules_init() start");
if (!module_get_private_data(mod) &&
drv->adapter_ops == &processing_module_adapter_interface) {
/* First load */
ret = modules_new(mod, buildinfo, module_entry_point);
if (ret < 0)
return ret;
}
const uint32_t module_id = IPC4_MOD_ID(config->id);
const uint32_t instance_id = IPC4_INST_ID(config->id);
const uint32_t log_handle = (uint32_t)drv->tctx;
byte_array_t mod_cfg = {
.data = (uint8_t *)md->cfg.init_data,
/* Intel modules expects DW size here */
.size = md->cfg.size >> 2,
};
system_agent = system_agent_start(module_entry_point, module_id, instance_id, 0, log_handle,
&mod_cfg);
module_set_private_data(mod, system_agent);
md->mpd.in_buff_size = src_cfg->ibs;
md->mpd.out_buff_size = src_cfg->obs;
/* Call module specific init function if exists. */
if (mod->is_native_sof) {
const struct module_interface *mod_in = drv->adapter_ops;
/* The order of preference */
if (mod_in->process)
mod->proc_type = MODULE_PROCESS_TYPE_SOURCE_SINK;
else if (mod_in->process_audio_stream)
mod->proc_type = MODULE_PROCESS_TYPE_STREAM;
else if (mod_in->process_raw_data)
mod->proc_type = MODULE_PROCESS_TYPE_RAW;
else
return -EINVAL;
ret = mod_in->init(mod);
} else {
mod->proc_type = MODULE_PROCESS_TYPE_SOURCE_SINK;
ret = iadk_wrapper_init(module_get_private_data(mod));
}
return ret;
mod->proc_type = MODULE_PROCESS_TYPE_SOURCE_SINK;
return iadk_wrapper_init(system_agent);
}
/**
@ -208,7 +135,6 @@ static int modules_process(struct processing_module *mod,
static int modules_free(struct processing_module *mod)
{
struct comp_dev *dev = mod->dev;
struct module_data *md = &mod->priv;
int ret;
comp_info(dev, "modules_free()");
@ -216,13 +142,10 @@ static int modules_free(struct processing_module *mod)
if (ret)
comp_err(dev, "modules_free(): iadk_wrapper_free failed with error: %d", ret);
if (!md->llext || !llext_unload(&md->llext)) {
/* Free module resources allocated in L2 memory. */
ret = lib_manager_free_module(dev->ipc_config.id);
if (ret < 0)
comp_err(dev, "modules_free(), lib_manager_free_module() failed!");
}
/* Free module resources allocated in L2 memory. */
ret = lib_manager_free_module(dev->ipc_config.id);
if (ret < 0)
comp_err(dev, "modules_free(), lib_manager_free_module() failed!");
return ret;
}

View File

@ -33,6 +33,7 @@ LOG_MODULE_REGISTER(module_adapter, CONFIG_SOF_LOG_LEVEL);
* \brief Create a module adapter component.
* \param[in] drv - component driver pointer.
* \param[in] config - component ipc descriptor pointer.
* \param[in] spec - passdowned data from driver.
*
* \return: a pointer to newly created module adapter component on success. NULL on error.
*/

View File

@ -179,9 +179,6 @@ struct processing_module {
*/
bool stream_copy_single_to_single;
/* flag to insure that module is loadable */
bool is_native_sof;
/* total processed data after stream started */
uint64_t total_data_consumed;
uint64_t total_data_produced;

View File

@ -81,8 +81,11 @@ struct ipc_lib_msg {
struct list_item list;
};
struct sof_man_module_manifest;
struct lib_manager_mod_ctx {
void *base_addr;
const struct sof_man_module_manifest *mod_manifest;
size_t segment_size[3];
};
@ -166,7 +169,7 @@ struct processing_module;
*/
uintptr_t lib_manager_allocate_module(struct processing_module *proc,
const struct comp_ipc_config *ipc_config,
const void *ipc_specific_config, const void **buildinfo);
const void *ipc_specific_config);
/*
* \brief Free module

View File

@ -13,7 +13,7 @@ struct comp_ipc_config;
uintptr_t llext_manager_allocate_module(struct processing_module *proc,
const struct comp_ipc_config *ipc_config,
const void *ipc_specific_config, const void **buildinfo);
const void *ipc_specific_config);
int llext_manager_free_module(const uint32_t component_id);

View File

@ -22,9 +22,14 @@
#include <sof/llext_manager.h>
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/audio/module_adapter/module/modules.h>
#include <utilities/array.h>
#include <native_system_agent.h>
#include <api_version.h>
#include <module/module/api_ver.h>
#include <zephyr/cache.h>
#include <zephyr/drivers/mm/system_mm.h>
#include <zephyr/llext/llext.h>
#if CONFIG_LIBRARY_AUTH_SUPPORT
#include <auth/intel_auth_api.h>
@ -340,7 +345,7 @@ static inline bool module_is_llext(const struct sof_man_module *mod)
uintptr_t lib_manager_allocate_module(struct processing_module *proc,
const struct comp_ipc_config *ipc_config,
const void *ipc_specific_config, const void **buildinfo)
const void *ipc_specific_config)
{
const struct sof_man_module *mod;
const struct ipc4_base_module_cfg *base_cfg = ipc_specific_config;
@ -358,8 +363,7 @@ uintptr_t lib_manager_allocate_module(struct processing_module *proc,
}
if (module_is_llext(mod))
return llext_manager_allocate_module(proc, ipc_config, ipc_specific_config,
buildinfo);
return llext_manager_allocate_module(proc, ipc_config, ipc_specific_config);
ret = lib_manager_load_module(module_id, mod);
if (ret < 0)
@ -495,12 +499,93 @@ const struct sof_man_module *lib_manager_get_module_manifest(const uint32_t modu
}
#if CONFIG_INTEL_MODULES
/*
* \brief Load module code, allocate its instance and create a module adapter component.
* \param[in] drv - component driver pointer.
* \param[in] config - component ipc descriptor pointer.
* \param[in] spec - passdowned data from driver.
*
* \return: a pointer to newly created module adapter component on success. NULL on error.
*/
static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv,
const struct comp_ipc_config *config,
const void *spec)
{
const struct ipc_config_process *args = (struct ipc_config_process *)spec;
const uint32_t module_id = IPC4_MOD_ID(config->id);
const uint32_t instance_id = IPC4_INST_ID(config->id);
const uint32_t log_handle = (uint32_t)drv->tctx;
byte_array_t mod_cfg;
/*
* Variable used by llext_manager to temporary store llext handle before creation
* a instance of processing_module.
*/
struct processing_module tmp_proc;
struct comp_dev *dev;
/* At this point module resources are allocated and it is moved to L2 memory. */
tmp_proc.priv.llext = NULL;
const uint32_t module_entry_point = lib_manager_allocate_module(&tmp_proc, config,
args->data);
if (!module_entry_point) {
tr_err(&lib_manager_tr,
"lib_manager_module_create(), lib_manager_allocate_module() failed!");
return NULL;
}
tr_info(&lib_manager_tr, "lib_manager_module_create() start");
mod_cfg.data = (uint8_t *)args->data;
/* Intel modules expects DW size here */
mod_cfg.size = args->size >> 2;
((struct comp_driver *)drv)->adapter_ops = native_system_agent_start(module_entry_point,
module_id, instance_id,
0, log_handle,
&mod_cfg);
if (!drv->adapter_ops) {
lib_manager_free_module(module_id);
tr_err(&lib_manager_tr,
"lib_manager_module_create(), native_system_agent_start failed!");
return NULL;
}
dev = module_adapter_new(drv, config, spec);
if (dev) {
struct processing_module *mod = comp_get_drvdata(dev);
mod->priv.llext = tmp_proc.priv.llext;
}
return dev;
}
static void lib_manager_module_free(struct comp_dev *dev)
{
struct processing_module *mod = comp_get_drvdata(dev);
struct llext *llext = mod->priv.llext;
const struct comp_ipc_config *const config = &mod->dev->ipc_config;
const uint32_t module_id = config->id;
int ret;
/* This call invalidates dev, mod and config pointers! */
module_adapter_free(dev);
if (!llext || !llext_unload(&llext)) {
/* Free module resources allocated in L2 memory. */
ret = lib_manager_free_module(module_id);
if (ret < 0)
comp_err(dev, "modules_free(), lib_manager_free_module() failed!");
}
}
static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const struct sof_uuid *uuid)
{
drv->type = SOF_COMP_MODULE_ADAPTER;
drv->uid = uuid;
drv->tctx = &lib_manager_tr;
drv->ops.create = module_adapter_new;
drv->ops.create = lib_manager_module_create;
drv->ops.prepare = module_adapter_prepare;
drv->ops.params = module_adapter_params;
drv->ops.copy = module_adapter_copy;
@ -509,7 +594,7 @@ static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const st
#endif
drv->ops.trigger = module_adapter_trigger;
drv->ops.reset = module_adapter_reset;
drv->ops.free = module_adapter_free;
drv->ops.free = lib_manager_module_free;
drv->ops.set_large_config = module_set_large_config;
drv->ops.get_large_config = module_get_large_config;
drv->ops.get_attribute = module_adapter_get_attribute;
@ -527,22 +612,22 @@ static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const st
int lib_manager_register_module(const uint32_t component_id)
{
const struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(component_id);
const struct sof_man_fw_desc *const desc = lib_manager_get_library_manifest(component_id);
const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(component_id);
const struct sof_man_fw_desc *desc;
const struct sof_module_api_build_info *build_info;
struct comp_driver_info *new_drv_info;
struct comp_driver *drv = NULL;
struct sof_man_module *mod;
const struct sof_man_module *mod;
int ret;
/* Get library manifest based on component_id */
if (!ctx || !ctx->base_addr)
if (!desc) {
tr_err(&lib_manager_tr, "Error: Couldn't find loadable module with id %u.",
component_id);
return -ENOENT;
}
desc = (const struct sof_man_fw_desc *)((const char *)ctx->base_addr +
SOF_MAN_ELF_TEXT_OFFSET);
if (entry_index >= desc->header.num_module_entries) {
tr_err(&lib_manager_tr, "Entry index %d out of bounds.", entry_index);
tr_err(&lib_manager_tr, "Entry index %u out of bounds.", entry_index);
return -ENOENT;
}
@ -568,13 +653,44 @@ int lib_manager_register_module(const uint32_t component_id)
goto cleanup;
}
/* Fill the new_drv_info structure with already known parameters */
/* Check already registered components */
mod = (struct sof_man_module *)((uint8_t *)desc + SOF_MAN_MODULE_OFFSET(entry_index));
mod = (struct sof_man_module *)((const uint8_t *)desc + SOF_MAN_MODULE_OFFSET(entry_index));
const struct sof_uuid *uid = (struct sof_uuid *)&mod->uuid[0];
lib_manager_prepare_module_adapter(drv, uid);
/*
* llext modules store build info structure in separate section which is not accessible now.
*/
if (!module_is_llext(mod)) {
build_info = (const struct sof_module_api_build_info *)((const char *)desc -
SOF_MAN_ELF_TEXT_OFFSET +
mod->segment[SOF_MAN_SEGMENT_TEXT].file_offset);
tr_info(&lib_manager_tr,
"lib_manager_register_module(): Module API version: %u.%u.%u, format: 0x%x",
build_info->api_version_number.fields.major,
build_info->api_version_number.fields.middle,
build_info->api_version_number.fields.minor,
build_info->format);
/* Check if module is IADK */
if (build_info->format == IADK_MODULE_API_BUILD_INFO_FORMAT &&
build_info->api_version_number.full == IADK_MODULE_API_CURRENT_VERSION) {
/* Use module_adapter functions */
drv->ops.create = module_adapter_new;
drv->ops.prepare = module_adapter_prepare;
} else {
/* Check if module is NOT native */
if (build_info->format != SOF_MODULE_API_BUILD_INFO_FORMAT ||
build_info->api_version_number.full != SOF_MODULE_API_CURRENT_VERSION) {
tr_err(&lib_manager_tr,
"lib_manager_register_module(): Unsupported module API version");
return -ENOEXEC;
}
}
}
/* Fill the new_drv_info structure with already known parameters */
new_drv_info->drv = drv;
/* Register new driver in the list */

View File

@ -30,6 +30,7 @@
#include <zephyr/llext/llext.h>
#include <rimage/sof/user/manifest.h>
#include <module/module/api_ver.h>
#include <errno.h>
#include <stdbool.h>
@ -181,7 +182,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul
struct llext_load_param ldr_parm = {!ctx->segment_size[SOF_MAN_SEGMENT_TEXT]};
int ret = llext_load(&ebl.loader, mod->name, &md->llext, &ldr_parm);
if (ret < 0)
if (ret)
return ret;
mod->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = ebl.loader.sects[LLEXT_MEM_TEXT].sh_addr;
@ -230,7 +231,7 @@ static int llext_manager_link(struct sof_man_fw_desc *desc, struct sof_man_modul
uintptr_t llext_manager_allocate_module(struct processing_module *proc,
const struct comp_ipc_config *ipc_config,
const void *ipc_specific_config, const void **buildinfo)
const void *ipc_specific_config)
{
struct sof_man_fw_desc *desc;
struct sof_man_module *mod;
@ -238,7 +239,7 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc,
uint32_t module_id = IPC4_MOD_ID(ipc_config->id);
uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id);
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
const struct sof_man_module_manifest *mod_manifest;
const struct sof_module_api_build_info *buildinfo;
tr_dbg(&lib_manager_tr, "llext_manager_allocate_module(): mod_id: %#x",
ipc_config->id);
@ -252,23 +253,35 @@ uintptr_t llext_manager_allocate_module(struct processing_module *proc,
mod = (struct sof_man_module *)((char *)desc + SOF_MAN_MODULE_OFFSET(entry_index));
ret = llext_manager_link(desc, mod, module_id, &proc->priv, buildinfo, &mod_manifest);
ret = llext_manager_link(desc, mod, module_id, &proc->priv, (const void **)&buildinfo,
&ctx->mod_manifest);
if (ret < 0)
return 0;
/* Map .text and the rest as .data */
ret = llext_manager_load_module(module_id, mod);
if (ret < 0)
return 0;
if (!ret) {
/* First instance: check that the module is native */
if (buildinfo->format != SOF_MODULE_API_BUILD_INFO_FORMAT ||
buildinfo->api_version_number.full != SOF_MODULE_API_CURRENT_VERSION) {
tr_err(&lib_manager_tr,
"llext_manager_allocate_module(): Unsupported module API version");
return -ENOEXEC;
}
ret = llext_manager_allocate_module_bss(module_id, mod);
if (ret < 0) {
tr_err(&lib_manager_tr,
"llext_manager_allocate_module(): module allocation failed: %d", ret);
return 0;
/* Map .text and the rest as .data */
ret = llext_manager_load_module(module_id, mod);
if (ret < 0)
return 0;
ret = llext_manager_allocate_module_bss(module_id, mod);
if (ret < 0) {
tr_err(&lib_manager_tr,
"llext_manager_allocate_module(): module allocation failed: %d",
ret);
return 0;
}
}
return mod_manifest->module.entry_point;
return ctx->mod_manifest->module.entry_point;
}
int llext_manager_free_module(const uint32_t component_id)