diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index 5e0e47fdacb7..0ca21bacbb57 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -81,7 +81,9 @@ struct ipc_lib_msg { struct ext_library { struct k_spinlock lock; /* last locking CPU record */ struct sof_man_fw_desc *desc[LIB_MANAGER_MAX_LIBS]; +#ifdef CONFIG_LIBCODE_MODULE_SUPPORT uint32_t mods_exec_load_cnt; +#endif struct ipc_lib_msg *lib_notif_pool; uint32_t lib_notif_count; diff --git a/src/library_manager/Kconfig b/src/library_manager/Kconfig index f9a71ebf6cda..37fdd0d506a7 100644 --- a/src/library_manager/Kconfig +++ b/src/library_manager/Kconfig @@ -13,4 +13,17 @@ config LIBRARY_MANAGER Externally developed modules both for SOF and Zephyr could be used if enabled. If unsure say N. + + +config LIBCODE_MODULE_SUPPORT + bool "Add support for libcode modules" + default n + depends on LIBRARY_MANAGER + help + A loadable library can contain a several modules marked + as lib_code. This modules contains code shared by + a multiple modules. This option adds support for modules + of this type. + If unsure say N. + endmenu diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index fed652c2b026..f2c4ac041fd0 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -138,6 +138,71 @@ static int lib_manager_unload_module(const struct sof_man_module *const mod) return 0; } +#ifdef CONFIG_LIBCODE_MODULE_SUPPORT +/* There are modules marked as lib_code. This is code shared between several modules inside + * the library. Load all lib_code modules with first none lib_code module load. + */ +static int lib_manager_load_libcode_modules(const uint32_t module_id, + const struct sof_man_fw_desc *const desc) +{ + struct ext_library *const ext_lib = ext_lib_get(); + const struct sof_man_module *module_entry = (struct sof_man_module *) + ((char *)desc + SOF_MAN_MODULE_OFFSET(0)); + const uint32_t lib_id = LIB_MANAGER_GET_LIB_ID(module_id); + int ret, idx; + + if (++ext_lib->mods_exec_load_cnt > 1) + return 0; + + for (idx = 0; idx < desc->header.num_module_entries; ++idx, ++module_entry) { + if (module_entry->type.lib_code) { + ret = lib_manager_load_module(lib_id << LIB_MANAGER_LIB_ID_SHIFT | idx, + module_entry); + if (ret < 0) + goto err; + } + } + + return 0; + +err: + for (--idx, --module_entry; idx >= 0; --idx, --module_entry) { + if (module_entry->type.lib_code) { + ret = lib_manager_unload_module(module_entry); + if (ret < 0) + goto err; + } + } + + return ret; +} + +/* There are modules marked as lib_code. This is code shared between several modules inside + * the library. Unload all lib_code modules with last none lib_code module unload. + */ +static int lib_manager_unload_libcode_modules(const uint32_t module_id, + const struct sof_man_fw_desc *const desc) +{ + struct ext_library *const ext_lib = ext_lib_get(); + const struct sof_man_module *module_entry = (struct sof_man_module *) + ((char *)desc + SOF_MAN_MODULE_OFFSET(0)); + int ret, idx; + + if (--ext_lib->mods_exec_load_cnt > 0) + return 0; + + for (idx = 0; idx < desc->header.num_module_entries; ++idx, ++module_entry) { + if (module_entry->type.lib_code) { + ret = lib_manager_unload_module(module_entry); + if (ret < 0) + return ret; + } + } + + return 0; +} +#endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ + static void __sparse_cache *lib_manager_get_instance_bss_address(uint32_t module_id, uint32_t instance_id, struct sof_man_module *mod) @@ -225,11 +290,20 @@ uint32_t lib_manager_allocate_module(const struct comp_driver *drv, if (ret < 0) return 0; +#ifdef CONFIG_LIBCODE_MODULE_SUPPORT + ret = lib_manager_load_libcode_modules(module_id, desc); + if (ret < 0) + goto err; +#endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ + ret = lib_manager_allocate_module_instance(module_id, IPC4_INST_ID(ipc_config->id), base_cfg->is_pages, mod); if (ret < 0) { tr_err(&lib_manager_tr, "lib_manager_allocate_module(): module allocation failed: %d", ret); +#ifdef CONFIG_LIBCODE_MODULE_SUPPORT + lib_manager_unload_libcode_modules(module_id, desc); +#endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ goto err; } return mod->entry_point; @@ -257,6 +331,12 @@ int lib_manager_free_module(const struct comp_driver *drv, if (ret < 0) return ret; +#ifdef CONFIG_LIBCODE_MODULE_SUPPORT + ret = lib_manager_unload_libcode_modules(module_id, desc); + if (ret < 0) + return ret; +#endif /* CONFIG_LIBCODE_MODULE_SUPPORT */ + ret = lib_manager_free_module_instance(module_id, IPC4_INST_ID(ipc_config->id), mod); if (ret < 0) { tr_err(&lib_manager_tr,