@@ -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+
465491uintptr_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+
562673bool comp_is_llext (struct comp_dev * comp )
563674{
564675 const uint32_t module_id = IPC4_MOD_ID (comp -> ipc_config .id );
0 commit comments