Skip to content

Commit 1c67251

Browse files
committed
llext: add dependencies
Add support for auxiliary modules, exporting symbols to other modules. In such cases Zephyr LLEXT API generates a dependency list, available while the dependent module is loaded. SOF now preserves the minimum module context even while it isn't used, that includes dependency lists, so on a repeated load they're still available. Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski@linux.intel.com>
1 parent 294f155 commit 1c67251

File tree

3 files changed

+131
-9
lines changed

3 files changed

+131
-9
lines changed

src/include/sof/llext_manager.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config
2727

2828
int llext_manager_free_module(const uint32_t component_id);
2929

30+
int llext_manager_add_library(uint32_t module_id);
31+
3032
bool comp_is_llext(struct comp_dev *comp);
3133
#else
3234
#define module_is_llext(mod) false
3335
#define llext_manager_allocate_module(ipc_config, ipc_specific_config) 0
3436
#define llext_manager_free_module(component_id) 0
37+
#define llext_manager_add_library(module_id) 0
3538
#define comp_is_llext(comp) false
3639
#endif
3740

src/library_manager/lib_manager.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1032,14 +1032,22 @@ int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type)
10321032
rfree((__sparse_force void *)man_tmp_buffer);
10331033

10341034
cleanup:
1035-
#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL
1036-
core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000));
1037-
#endif
10381035
rfree((void *)dma_ext->dma_addr);
10391036
lib_manager_dma_deinit(dma_ext, dma_id);
10401037
rfree(dma_ext);
10411038
_ext_lib->runtime_data = NULL;
10421039

1040+
uint32_t module_id = lib_id << LIB_MANAGER_LIB_ID_SHIFT;
1041+
const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id);
1042+
1043+
if (module_is_llext(mod) && !ret)
1044+
/* Auxiliary LLEXT libraries need to be linked upon loading */
1045+
ret = llext_manager_add_library(module_id);
1046+
1047+
#if CONFIG_KCPS_DYNAMIC_CLOCK_CONTROL
1048+
core_kcps_adjust(cpu_get_id(), -(CLK_MAX_CPU_HZ / 1000));
1049+
#endif
1050+
10431051
if (!ret)
10441052
tr_info(&ipc_tr, "loaded library id: %u", lib_id);
10451053

src/library_manager/llext_manager.c

Lines changed: 117 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,9 +378,6 @@ static int llext_manager_link_single(uint32_t module_id, const struct sof_man_fw
378378

379379
tr_dbg(&lib_manager_tr, "mod_id: %u", module_id);
380380

381-
if (!ctx->mod)
382-
llext_manager_mod_init(ctx, desc);
383-
384381
if (entry_index >= desc->header.num_module_entries) {
385382
tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d",
386383
entry_index, desc->header.num_module_entries - 1);
@@ -462,12 +459,41 @@ static int llext_manager_link_single(uint32_t module_id, const struct sof_man_fw
462459
return mod_ctx_idx;
463460
}
464461

462+
static int llext_lib_find(const struct llext *llext, struct lib_manager_module **dep_ctx)
463+
{
464+
struct ext_library *_ext_lib = ext_lib_get();
465+
unsigned int i, j;
466+
467+
if (!llext)
468+
return -EINVAL;
469+
470+
for (i = 0; i < ARRAY_SIZE(_ext_lib->desc); i++) {
471+
if (!_ext_lib->desc[i])
472+
continue;
473+
474+
for (j = 0; j < _ext_lib->desc[i]->n_mod; j++)
475+
if (_ext_lib->desc[i]->mod[j].llext == llext) {
476+
*dep_ctx = _ext_lib->desc[i]->mod + j;
477+
return i;
478+
}
479+
}
480+
481+
return -ENOENT;
482+
}
483+
484+
static void llext_depend_unlink(struct lib_manager_module *dep_ctx[], int n)
485+
{
486+
for (; n >= 0; n--)
487+
if (dep_ctx[n] && dep_ctx[n]->llext->use_count == 1)
488+
llext_manager_unload_module(dep_ctx[n]);
489+
}
490+
465491
uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config,
466492
const void *ipc_specific_config)
467493
{
468494
uint32_t module_id = IPC4_MOD_ID(ipc_config->id);
469495
/* Library manifest */
470-
struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)
496+
const struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)
471497
lib_manager_get_library_manifest(module_id);
472498
/* Library context */
473499
struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id);
@@ -500,9 +526,50 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config
500526
}
501527

502528
if (!mctx->mapped) {
503-
/* Map executable code and data */
504-
int ret = llext_manager_load_module(mctx);
529+
int i, ret;
505530

531+
/*
532+
* Check if any dependencies need to be mapped - collect
533+
* pointers to library contexts
534+
*/
535+
struct lib_manager_module *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {};
536+
537+
for (i = 0; i < ARRAY_SIZE(mctx->llext->dependency); i++) {
538+
/* Dependencies are filled from the beginning of the array upwards */
539+
if (!mctx->llext->dependency[i])
540+
break;
541+
542+
/*
543+
* Protected by the IPC serialization, but maybe we should protect the
544+
* use-count explicitly too. Currently the use-count is first incremented
545+
* when an auxiliary library is loaded, it was then additionally incremented
546+
* when the current dependent module was mapped. If it's higher than two,
547+
* then some other modules also depend on it and have already mapped it.
548+
*/
549+
if (mctx->llext->dependency[i]->use_count > 2)
550+
continue;
551+
552+
/* First user of this dependency, load it into SRAM */
553+
ret = llext_lib_find(mctx->llext->dependency[i], &dep_ctx[i]);
554+
if (ret < 0) {
555+
tr_err(&lib_manager_tr,
556+
"Unmet dependency: cannot find dependency %u", i);
557+
continue;
558+
}
559+
560+
tr_dbg(&lib_manager_tr, "%s depending on %s index %u, %u users",
561+
mctx->llext->name, mctx->llext->dependency[i]->name,
562+
dep_ctx[i]->start_idx, mctx->llext->dependency[i]->use_count);
563+
564+
ret = llext_manager_load_module(dep_ctx[i]);
565+
if (ret < 0) {
566+
llext_depend_unlink(dep_ctx, i - 1);
567+
return 0;
568+
}
569+
}
570+
571+
/* Map executable code and data */
572+
ret = llext_manager_load_module(mctx);
506573
if (ret < 0)
507574
return 0;
508575
}
@@ -547,6 +614,17 @@ int llext_manager_free_module(const uint32_t component_id)
547614
return 0;
548615
}
549616

617+
struct lib_manager_module *dep_ctx[LLEXT_MAX_DEPENDENCIES] = {};
618+
int i; /* signed to match llext_depend_unlink() */
619+
620+
for (i = 0; i < ARRAY_SIZE(mctx->llext->dependency); i++)
621+
if (llext_lib_find(mctx->llext->dependency[i], &dep_ctx[i]) < 0)
622+
break;
623+
624+
/* Last user cleaning up, put dependencies */
625+
if (i)
626+
llext_depend_unlink(dep_ctx, i - 1);
627+
550628
/*
551629
* The last instance of the module has been destroyed and it can now be
552630
* unloaded from SRAM
@@ -559,6 +637,39 @@ int llext_manager_free_module(const uint32_t component_id)
559637
return llext_manager_unload_module(mctx);
560638
}
561639

640+
/* An auxiliary library has been loaded, need to read in its exported symbols */
641+
int llext_manager_add_library(uint32_t module_id)
642+
{
643+
struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(module_id);
644+
645+
if (ctx->mod) {
646+
tr_err(&lib_manager_tr, "module_id: %#x: repeated load!", module_id);
647+
return -EBUSY;
648+
}
649+
650+
const struct sof_man_fw_desc *desc = lib_manager_get_library_manifest(module_id);
651+
unsigned int i;
652+
653+
if (!ctx->mod)
654+
llext_manager_mod_init(ctx, desc);
655+
656+
for (i = 0; i < ctx->n_mod; i++) {
657+
const struct sof_man_module *mod = lib_manager_get_module_manifest(module_id + i);
658+
659+
if (mod->type.load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) {
660+
const struct sof_man_module_manifest *mod_manifest;
661+
const struct sof_module_api_build_info *buildinfo;
662+
int ret = llext_manager_link_single(module_id + i, desc, ctx,
663+
(const void **)&buildinfo, &mod_manifest);
664+
665+
if (ret < 0)
666+
return ret;
667+
}
668+
}
669+
670+
return 0;
671+
}
672+
562673
bool comp_is_llext(struct comp_dev *comp)
563674
{
564675
const uint32_t module_id = IPC4_MOD_ID(comp->ipc_config.id);

0 commit comments

Comments
 (0)