diff --git a/src/audio/module_adapter/CMakeLists.txt b/src/audio/module_adapter/CMakeLists.txt index 7400e27f7edd..2c79f2fbfefd 100644 --- a/src/audio/module_adapter/CMakeLists.txt +++ b/src/audio/module_adapter/CMakeLists.txt @@ -66,6 +66,7 @@ if(zephyr) ### Zephyr ### zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_PROXY library/userspace_proxy.c + library/userspace_proxy_user.c ) zephyr_library_sources_ifdef(CONFIG_PASSTHROUGH_CODEC diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index 14f8e70f49a1..caed8cf65860 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -38,7 +39,7 @@ namespace system { /* Structure storing handles to system service operations */ -const AdspSystemService SystemAgent::system_service_ = { +const APP_TASK_DATA AdspSystemService SystemAgent::system_service_ = { native_system_service_log_message, native_system_service_safe_memcpy, native_system_service_safe_memmove, diff --git a/src/audio/module_adapter/library/native_system_service.c b/src/audio/module_adapter/library/native_system_service.c index 5126fa5ff12b..1c4688e885d0 100644 --- a/src/audio/module_adapter/library/native_system_service.c +++ b/src/audio/module_adapter/library/native_system_service.c @@ -19,6 +19,7 @@ #include #include #include +#include #define RSIZE_MAX 0x7FFFFFFF @@ -162,7 +163,7 @@ AdspErrorCode native_system_service_get_interface(enum interface_id id, return ADSP_NO_ERROR; } -const struct native_system_service native_system_service = { +const APP_TASK_DATA struct native_system_service native_system_service = { .basic = { .log_message = native_system_service_log_message, .safe_memcpy = native_system_service_safe_memcpy, diff --git a/src/audio/module_adapter/library/userspace_proxy.c b/src/audio/module_adapter/library/userspace_proxy.c index d6b1516dfb3c..0020d0745330 100644 --- a/src/audio/module_adapter/library/userspace_proxy.c +++ b/src/audio/module_adapter/library/userspace_proxy.c @@ -27,14 +27,19 @@ #include #include +#include #include #include #include #include #include +#include #include + /* Assume that all the code runs in supervisor mode and don't made a system calls. */ +#define __ZEPHYR_SUPERVISOR__ + LOG_MODULE_REGISTER(userspace_proxy, CONFIG_SOF_LOG_LEVEL); /* 6f6b6f4b-6f73-7466-20e1e62b9779f003 */ @@ -44,7 +49,140 @@ DECLARE_TR_CTX(userspace_proxy_tr, SOF_UUID(userspace_proxy_uuid), LOG_LEVEL_INF static const struct module_interface userspace_proxy_interface; -static int userspace_proxy_memory_init(struct userspace_context *user, +struct user_worker { + k_tid_t thread_id; /* ipc worker thread ID */ + uint32_t reference_count; /* module reference count */ + void *stack_ptr; /* pointer to worker stack */ + struct k_work_user_q work_queue; + struct k_event event; +}; + +static struct user_worker worker; + +static int user_worker_create(void) +{ + if (worker.reference_count) { + worker.reference_count++; + return 0; + } + + worker.stack_ptr = user_stack_allocate(CONFIG_SOF_STACK_SIZE, K_USER); + if (!worker.stack_ptr) { + tr_err(&userspace_proxy_tr, "Userspace worker stack allocation failed."); + return -ENOMEM; + } + + k_event_init(&worker.event); + k_work_user_queue_start(&worker.work_queue, worker.stack_ptr, CONFIG_SOF_STACK_SIZE, 0, + NULL); + + worker.thread_id = k_work_user_queue_thread_get(&worker.work_queue); + + k_thread_access_grant(worker.thread_id, &worker.event); + + worker.reference_count++; + return 0; +} + +static void user_worker_free(void) +{ + /* Module removed so decrement counter */ + worker.reference_count--; + + /* Free worker resources if no more active user space modules */ + if (worker.reference_count == 0) { + k_thread_abort(worker.thread_id); + user_stack_free(worker.stack_ptr); + } +} + +static int user_work_item_init(struct userspace_context *user_ctx, struct k_heap *user_heap) +{ + struct user_work_item *work_item = NULL; + int ret; + + ret = user_worker_create(); + if (ret) + return ret; + + work_item = sof_heap_alloc(user_heap, SOF_MEM_FLAG_COHERENT, sizeof(*work_item), 0); + if (!work_item) + return -ENOMEM; + + k_work_user_init(&work_item->work_item, userspace_proxy_worker_handler); + + work_item->event = &worker.event; + work_item->params.context = user_ctx; + user_ctx->work_item = work_item; + + return 0; +} + +static void user_work_item_free(struct userspace_context *user_ctx, struct k_heap *user_heap) +{ + sof_heap_free(user_heap, user_ctx->work_item); + user_worker_free(); +} + +static inline struct module_params *user_work_get_params(struct userspace_context *user_ctx) +{ + return &user_ctx->work_item->params; +} + +static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t cmd, + bool ipc_payload_access) +{ + struct module_params *params = user_work_get_params(user_ctx); + struct k_mem_partition ipc_part = { + .start = (uintptr_t)MAILBOX_HOSTBOX_BASE, + .size = MAILBOX_HOSTBOX_SIZE, + .attr = K_MEM_PARTITION_P_RO_U_RO, + }; + int ret; + + params->cmd = cmd; + + if (ipc_payload_access) { + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &ipc_part); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "add mailbox to domain error: %d", ret); + return ret; + } + } + + /* Switch worker thread to module memory domain */ + ret = k_mem_domain_add_thread(user_ctx->comp_dom, worker.thread_id); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "failed to switch memory domain: error: %d", ret); + goto done; + } + + ret = k_work_user_submit_to_queue(&worker.work_queue, &user_ctx->work_item->work_item); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "k_work_user_submit_to_queue(): error: %d", ret); + goto done; + } + + /* Timeout value is aligned with the ipc_wait_for_compound_msg function */ + if (!k_event_wait_safe(&worker.event, DP_TASK_EVENT_IPC_DONE, false, + Z_TIMEOUT_US(250 * 20))) { + tr_err(&userspace_proxy_tr, "ipc processing timedout."); + ret = -ETIMEDOUT; + } + +done: + if (ipc_payload_access) { + ret = k_mem_domain_remove_partition(user_ctx->comp_dom, &ipc_part); + if (ret < 0) + tr_err(&userspace_proxy_tr, "Mailbox remove from domain error: %d", ret); + } + + return ret; +} + +extern struct k_mem_partition common_partition; + +static int userspace_proxy_memory_init(struct userspace_context *user_ctx, const struct comp_driver *drv) { /* Add module private heap to memory partitions */ @@ -73,16 +211,21 @@ static int userspace_proxy_memory_init(struct userspace_context *user, #endif struct k_mem_partition *parts_ptr[] = { + &common_partition, #ifdef HEAP_PART_CACHED &heap_part_cached, #endif &heap_part }; - return k_mem_domain_init(user->comp_dom, ARRAY_SIZE(parts_ptr), parts_ptr); + tr_dbg(&userspace_proxy_tr, "Common partition %p + %zx, attr = %u", + UINT_TO_POINTER(common_partition.start), common_partition.size, + common_partition.attr); + + return k_mem_domain_init(user_ctx->comp_dom, ARRAY_SIZE(parts_ptr), parts_ptr); } -static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t instance_id, +static int userspace_proxy_add_sections(struct userspace_context *user_ctx, uint32_t instance_id, const struct sof_man_module *const mod) { struct k_mem_partition mem_partition; @@ -103,7 +246,7 @@ static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t mem_partition.start = mod->segment[idx].v_base_addr; mem_partition.size = mod->segment[idx].flags.r.length * CONFIG_MM_DRV_PAGE_SIZE; - ret = k_mem_domain_add_partition(user->comp_dom, &mem_partition); + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &mem_partition); tr_dbg(&userspace_proxy_tr, "Add mod partition %p + %zx, attr = %u, ret = %d", UINT_TO_POINTER(mem_partition.start), mem_partition.size, @@ -116,7 +259,7 @@ static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t lib_manager_get_instance_bss_address(instance_id, mod, &va_base, &mem_partition.size); mem_partition.start = POINTER_TO_UINT(va_base); mem_partition.attr = K_MEM_PARTITION_P_RW_U_RW; - ret = k_mem_domain_add_partition(user->comp_dom, &mem_partition); + ret = k_mem_domain_add_partition(user_ctx->comp_dom, &mem_partition); tr_dbg(&userspace_proxy_tr, "Add bss partition %p + %zx, attr = %u, ret = %d", UINT_TO_POINTER(mem_partition.start), mem_partition.size, @@ -125,19 +268,40 @@ static int userspace_proxy_add_sections(struct userspace_context *user, uint32_t return ret; } +static int userspace_proxy_start_agent(struct userspace_context *user_ctx, + system_agent_start_fn start_fn, + const struct system_agent_params *agent_params, + const void **agent_interface) +{ + const byte_array_t * const mod_cfg = (byte_array_t *)agent_params->mod_cfg; + struct module_params *params = user_work_get_params(user_ctx); + int ret; + + params->ext.agent.start_fn = start_fn; + params->ext.agent.params = *agent_params; + params->ext.agent.mod_cfg = *mod_cfg; + + ret = userspace_proxy_invoke(user_ctx, MODULE_CMD_AGENT_START, true); + if (ret) + return ret; + + *agent_interface = params->ext.agent.out_interface; + return 0; +} + int userspace_proxy_create(struct userspace_context **user_ctx, const struct comp_driver *drv, const struct sof_man_module *manifest, system_agent_start_fn start_fn, const struct system_agent_params *agent_params, const void **agent_interface, const struct module_interface **ops) { - struct userspace_context *user; + struct userspace_context *context; struct k_mem_domain *domain; int ret; tr_dbg(&userspace_proxy_tr, "userspace create"); - user = k_heap_alloc(drv->user_heap, sizeof(struct userspace_context), K_FOREVER); - if (!user) + context = k_heap_alloc(drv->user_heap, sizeof(struct userspace_context), K_FOREVER); + if (!context) return -ENOMEM; /* Allocate memory domain struct */ @@ -146,27 +310,31 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com ret = -ENOMEM; goto error; } - user->comp_dom = domain; + context->comp_dom = domain; + + ret = userspace_proxy_memory_init(context, drv); + if (ret) + goto error_dom; - ret = userspace_proxy_memory_init(user, drv); + ret = userspace_proxy_add_sections(context, agent_params->instance_id, manifest); if (ret) goto error_dom; - ret = userspace_proxy_add_sections(user, agent_params->instance_id, manifest); + ret = user_work_item_init(context, drv->user_heap); if (ret) goto error_dom; /* Start the system agent, if provided. */ - if (start_fn) { - ret = start_fn(agent_params, agent_interface); + if (start_fn) { + ret = userspace_proxy_start_agent(context, start_fn, agent_params, agent_interface); if (ret) { tr_err(&userspace_proxy_tr, "System agent failed with error %d.", ret); - goto error_dom; + goto error_work_item; } } - *user_ctx = user; + *user_ctx = context; /* Store a pointer to the module's interface. For the LMDK modules, the agent places a * pointer to the module interface at the address specified by agent_interface. Since this @@ -174,7 +342,7 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com * after the agent has been started. For other module types, the ops parameter points to a * valid module interface. */ - user->interface = *ops; + context->interface = *ops; /* All calls to the module interface must pass through the proxy. Set up our own interface. */ @@ -182,16 +350,19 @@ int userspace_proxy_create(struct userspace_context **user_ctx, const struct com return 0; +error_work_item: + user_work_item_free(context, drv->user_heap); error_dom: rfree(domain); error: - k_heap_free(drv->user_heap, user); + k_heap_free(drv->user_heap, context); return ret; } void userspace_proxy_destroy(const struct comp_driver *drv, struct userspace_context *user_ctx) { tr_dbg(&userspace_proxy_tr, "userspace proxy destroy"); + user_work_item_free(user_ctx, drv->user_heap); rfree(user_ctx->comp_dom); k_heap_free(drv->user_heap, user_ctx); } @@ -206,10 +377,18 @@ void userspace_proxy_destroy(const struct comp_driver *drv, struct userspace_con */ static int userspace_proxy_init(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); + params->mod = mod; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_INIT, true); + if (ret) + return ret; + /* Return status from module code operation. */ - return mod->user_ctx->interface->init(mod); + return params->status; } /** @@ -223,21 +402,40 @@ static int userspace_proxy_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->prepare) return 0; - return mod->user_ctx->interface->prepare(mod, sources, num_of_sources, sinks, num_of_sinks); + params->ext.proc.sources = sources; + params->ext.proc.num_of_sources = num_of_sources; + params->ext.proc.sinks = sinks; + params->ext.proc.num_of_sinks = num_of_sinks; + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_PREPARE, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** - * Copy parameters to user worker accessible space. - * Queue module init() operation and return its result. - * Module init() code is performed in user workqueue. + * Forward processing request to the module's process() implementation. * - * @param mod - pointer to processing module structure. - * @return 0 for success, error otherwise. + * It is invoked by the DP thread running in userspace, so no + * additional queuing or context switching is performed here. + * + * @param mod Pointer to the processing module instance. + * @param sources Array of input sources for the module. + * @param num_of_sources Number of input sources. + * @param sinks Array of output sinks for the module. + * @param num_of_sinks Number of output sinks. + * + * @return 0 on success, negative error code on failure. */ static int userspace_proxy_process(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks) @@ -255,10 +453,18 @@ static int userspace_proxy_process(struct processing_module *mod, struct sof_sou */ static int userspace_proxy_reset(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + if (!mod->user_ctx->interface->reset) return 0; - return mod->user_ctx->interface->reset(mod); + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_RESET, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -271,13 +477,19 @@ static int userspace_proxy_reset(struct processing_module *mod) */ static int userspace_proxy_free(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); int ret = 0; comp_dbg(mod->dev, "start"); - if (mod->user_ctx->interface->free) - ret = mod->user_ctx->interface->free(mod); + if (mod->user_ctx->interface->free) { + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_FREE, false); + if (ret) + return ret; + ret = params->status; + } + /* Destroy workqueue if this was last active userspace module */ userspace_proxy_destroy(mod->dev->drv, mod->user_ctx); mod->user_ctx = NULL; @@ -309,14 +521,28 @@ static int userspace_proxy_set_configuration(struct processing_module *mod, uint size_t fragment_size, uint8_t *response, size_t response_size) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->set_configuration) return 0; - return mod->user_ctx->interface->set_configuration(mod, config_id, pos, data_offset_size, - fragment, fragment_size, - response, response_size); + params->ext.set_conf.config_id = config_id; + params->ext.set_conf.pos = pos; + params->ext.set_conf.data_off_size = data_offset_size; + params->ext.set_conf.fragment = fragment; + params->ext.set_conf.fragment_size = fragment_size; + params->ext.set_conf.response = response; + params->ext.set_conf.response_size = response_size; + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_SET_CONF, true); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -338,13 +564,37 @@ static int userspace_proxy_get_configuration(struct processing_module *mod, uint uint32_t *data_offset_size, uint8_t *fragment, size_t fragment_size) { + struct module_params *params = user_work_get_params(mod->user_ctx); + struct k_mem_domain *domain = mod->user_ctx->comp_dom; + struct k_mem_partition ipc_resp_part = { + .start = (uintptr_t)ipc_get()->comp_data, + .size = SOF_IPC_MSG_MAX_SIZE, + .attr = K_MEM_PARTITION_P_RW_U_RW, + }; + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->get_configuration) return -EIO; - return mod->user_ctx->interface->get_configuration(mod, config_id, data_offset_size, - fragment, fragment_size); + params->ext.get_conf.config_id = config_id; + params->ext.get_conf.data_off_size = data_offset_size; + params->ext.get_conf.fragment = fragment; + params->ext.get_conf.fragment_size = fragment_size; + + ret = k_mem_domain_add_partition(domain, &ipc_resp_part); + if (ret < 0) { + comp_err(mod->dev, "add response buffer to domain error: %d", ret); + return ret; + } + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_GET_CONF, true); + + k_mem_domain_remove_partition(domain, &ipc_resp_part); + + /* Return status from module code operation. */ + return ret ? ret : params->status; } /** @@ -359,12 +609,21 @@ static int userspace_proxy_get_configuration(struct processing_module *mod, uint static int userspace_proxy_set_processing_mode(struct processing_module *mod, enum module_processing_mode mode) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->set_processing_mode) return 0; - return mod->user_ctx->interface->set_processing_mode(mod, mode); + params->ext.proc_mode.mode = mode; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_SET_PROCMOD, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -378,12 +637,20 @@ static int userspace_proxy_set_processing_mode(struct processing_module *mod, static enum module_processing_mode userspace_proxy_get_processing_mode(struct processing_module *mod) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->get_processing_mode) return -EIO; - return mod->user_ctx->interface->get_processing_mode(mod); + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_GET_PROCMOD, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->ext.proc_mode.mode; } /** @@ -400,14 +667,27 @@ static bool userspace_proxy_is_ready_to_process(struct processing_module *mod, struct sof_sink **sinks, int num_of_sinks) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->is_ready_to_process) return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, num_of_sinks); - return mod->user_ctx->interface->is_ready_to_process(mod, sources, num_of_sources, - sinks, num_of_sinks); + params->ext.proc.sources = sources; + params->ext.proc.num_of_sources = num_of_sources; + params->ext.proc.sinks = sinks; + params->ext.proc.num_of_sinks = num_of_sinks; + + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_PROC_READY, false); + if (ret) + return generic_module_is_ready_to_process(mod, sources, num_of_sources, sinks, + num_of_sinks); + + /* Return status from module code operation. */ + return params->status; } /** @@ -421,12 +701,21 @@ static bool userspace_proxy_is_ready_to_process(struct processing_module *mod, */ static int userspace_proxy_bind(struct processing_module *mod, struct bind_info *bind_data) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->bind) return 0; - return mod->user_ctx->interface->bind(mod, bind_data); + params->ext.bind_data = bind_data; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_BIND, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -440,12 +729,21 @@ static int userspace_proxy_bind(struct processing_module *mod, struct bind_info */ static int userspace_proxy_unbind(struct processing_module *mod, struct bind_info *unbind_data) { + struct module_params *params = user_work_get_params(mod->user_ctx); + int ret; + comp_dbg(mod->dev, "start"); if (!mod->user_ctx->interface->unbind) return 0; - return mod->user_ctx->interface->unbind(mod, unbind_data); + params->ext.bind_data = unbind_data; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_UNBIND, false); + if (ret) + return ret; + + /* Return status from module code operation. */ + return params->status; } /** @@ -458,12 +756,18 @@ static int userspace_proxy_unbind(struct processing_module *mod, struct bind_inf */ static int userspace_proxy_trigger(struct processing_module *mod, int cmd) { + struct module_params *params = user_work_get_params(mod->user_ctx); int ret = 0; comp_dbg(mod->dev, "start"); - if (mod->user_ctx->interface->trigger) - ret = mod->user_ctx->interface->trigger(mod, cmd); + if (mod->user_ctx->interface->trigger) { + params->ext.trigger_data = cmd; + ret = userspace_proxy_invoke(mod->user_ctx, MODULE_CMD_TRIGGER, false); + if (ret) + return ret; + ret = params->status; + } if (!ret) ret = module_adapter_set_state(mod, mod->dev, cmd); @@ -472,7 +776,7 @@ static int userspace_proxy_trigger(struct processing_module *mod, int cmd) return ret; } -/* Userspace Module Adapter API */ +/* Userspace Proxy Module API */ APP_TASK_DATA static const struct module_interface userspace_proxy_interface = { .init = userspace_proxy_init, .is_ready_to_process = userspace_proxy_is_ready_to_process, diff --git a/src/audio/module_adapter/library/userspace_proxy_user.c b/src/audio/module_adapter/library/userspace_proxy_user.c new file mode 100644 index 000000000000..bf5f2a26e0eb --- /dev/null +++ b/src/audio/module_adapter/library/userspace_proxy_user.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2025 Intel Corporation. All rights reserved. +// +// Author: Adrian Warecki + +/** + * \file audio/module_adapter/library/userspace_proxy_user.c + * \brief Userspace proxy functions executed only in userspace context. + * \authors Adrian Warecki + */ + +/* Assume that all the code runs in user mode and unconditionally made a system calls. */ +#define __ZEPHYR_USER__ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +void userspace_proxy_handle_request(struct processing_module *mod, struct module_params *params) +{ + const struct module_interface *ops = params->context->interface; + + switch (params->cmd) { + case MODULE_CMD_AGENT_START: + /* Set pointer to user accessible mod_cfg structure. */ + params->ext.agent.params.mod_cfg = ¶ms->ext.agent.mod_cfg; + + params->status = params->ext.agent.start_fn(¶ms->ext.agent.params, + ¶ms->ext.agent.out_interface); + break; + + case MODULE_CMD_INIT: + params->status = ops->init(params->mod); + break; + + case MODULE_CMD_PREPARE: + params->status = ops->prepare(params->mod, params->ext.proc.sources, + params->ext.proc.num_of_sources, + params->ext.proc.sinks, + params->ext.proc.num_of_sinks); + break; + + case MODULE_CMD_PROC_READY: + params->status = ops->is_ready_to_process(params->mod, + params->ext.proc.sources, + params->ext.proc.num_of_sources, + params->ext.proc.sinks, + params->ext.proc.num_of_sinks); + break; + + case MODULE_CMD_BIND: + params->status = ops->bind(params->mod, params->ext.bind_data); + break; + + case MODULE_CMD_UNBIND: + params->status = ops->unbind(params->mod, params->ext.bind_data); + break; + + case MODULE_CMD_RESET: + params->status = ops->reset(params->mod); + break; + + case MODULE_CMD_FREE: + params->status = ops->free(params->mod); + break; + + case MODULE_CMD_SET_CONF: + params->status = ops->set_configuration(params->mod, + params->ext.set_conf.config_id, + params->ext.set_conf.pos, + params->ext.set_conf.data_off_size, + params->ext.set_conf.fragment, + params->ext.set_conf.fragment_size, + params->ext.set_conf.response, + params->ext.set_conf.response_size); + break; + + case MODULE_CMD_GET_CONF: + params->status = ops->get_configuration(params->mod, + params->ext.get_conf.config_id, + params->ext.get_conf.data_off_size, + params->ext.get_conf.fragment, + params->ext.get_conf.fragment_size); + break; + + case MODULE_CMD_SET_PROCMOD: + params->status = ops->set_processing_mode(params->mod, + params->ext.proc_mode.mode); + break; + + case MODULE_CMD_GET_PROCMOD: + params->ext.proc_mode.mode = ops->get_processing_mode(params->mod); + break; + + case MODULE_CMD_TRIGGER: + params->status = ops->trigger(params->mod, params->ext.trigger_data); + break; + + default: + params->status = -EINVAL; + break; + } +} + +void userspace_proxy_worker_handler(struct k_work_user *work_item) +{ + struct user_work_item *user_work_item = CONTAINER_OF(work_item, struct user_work_item, + work_item); + struct module_params *params = &user_work_item->params; + + userspace_proxy_handle_request(params->mod, params); + k_event_post(user_work_item->event, DP_TASK_EVENT_IPC_DONE); +} diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy.h b/src/include/sof/audio/module_adapter/library/userspace_proxy.h index 150812183a90..872646d1eec9 100644 --- a/src/include/sof/audio/module_adapter/library/userspace_proxy.h +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy.h @@ -14,10 +14,12 @@ #include #include +#include #include #include #include +#include struct module_interface; struct comp_driver; @@ -28,6 +30,7 @@ struct system_agent_params; struct userspace_context { struct k_mem_domain *comp_dom; /* Module specific memory domain */ const struct module_interface *interface; /* Userspace module interface */ + struct user_work_item *work_item; /* work item for user worker thread */ }; #endif /* CONFIG_USERSPACE */ diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h new file mode 100644 index 000000000000..6124d868925c --- /dev/null +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2025 Intel Corporation. All rights reserved. + * + * Author: Adrian Warecki + */ + +#ifndef __SOF_AUDIO_USERSPACE_PROXY_USER_H__ +#define __SOF_AUDIO_USERSPACE_PROXY_USER_H__ + +#if CONFIG_SOF_USERSPACE_PROXY +struct module_agent_params { + system_agent_start_fn start_fn; + struct system_agent_params params; + byte_array_t mod_cfg; + const void *out_interface; +}; + +struct module_large_cfg_set_params { + uint32_t config_id; + enum module_cfg_fragment_position pos; + uint32_t data_off_size; + const uint8_t *fragment; + size_t fragment_size; + uint8_t *response; + size_t response_size; +}; + +struct module_large_cfg_get_params { + uint32_t config_id; + uint32_t *data_off_size; + uint8_t *fragment; + size_t fragment_size; +}; + +struct module_processing_mode_params { + enum module_processing_mode mode; +}; + +struct module_process_params { + struct sof_source **sources; + int num_of_sources; + struct sof_sink **sinks; + int num_of_sinks; +}; + +enum userspace_proxy_cmd { + MODULE_CMD_AGENT_START, + MODULE_CMD_INIT, + MODULE_CMD_PREPARE, + MODULE_CMD_PROC_READY, + MODULE_CMD_SET_PROCMOD, + MODULE_CMD_GET_PROCMOD, + MODULE_CMD_SET_CONF, + MODULE_CMD_GET_CONF, + MODULE_CMD_BIND, + MODULE_CMD_UNBIND, + MODULE_CMD_RESET, + MODULE_CMD_FREE, + MODULE_CMD_TRIGGER +}; + +struct module_params { + enum userspace_proxy_cmd cmd; + int status; + struct processing_module *mod; + struct userspace_context *context; + union { + struct module_agent_params agent; + struct module_large_cfg_set_params set_conf; + struct module_large_cfg_get_params get_conf; + struct module_processing_mode_params proc_mode; + struct module_process_params proc; + struct bind_info *bind_data; + int trigger_data; + } ext; +}; + +struct user_work_item { + struct k_work_user work_item; /* ipc worker workitem */ + struct k_event *event; /* ipc worker done event */ + struct module_params params; +}; + +void userspace_proxy_handle_request(struct processing_module *mod, struct module_params *params); + +void userspace_proxy_worker_handler(struct k_work_user *work_item); + +#endif /* CONFIG_SOF_USERSPACE_PROXY */ + +#endif /* __SOF_AUDIO_USERSPACE_PROXY_USER_H__ */ diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 99f1dcd2b16f..78a5ed892972 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -89,6 +89,7 @@ void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, enum { DP_TASK_EVENT_PROCESS = BIT(0), /* Need to process data */ DP_TASK_EVENT_CANCEL = BIT(1), /* Thread cancellation */ + DP_TASK_EVENT_IPC_DONE = BIT(3), /* IPC processing has completed. */ }; #endif /* __SOF_SCHEDULE_DP_SCHEDULE_H__ */ diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index cde00a4c15a3..aeb3bc22ae1d 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -490,7 +490,7 @@ const struct sof_man_module *lib_manager_get_module_manifest(const uint32_t modu * \brief Starts system agent and returns module interface into agent_interface variable. * * \param[in] drv - Pointer to the component driver structure. - * \param[in] component_id - Identifier of the component. + * \param[in] config - Pointer to component ipc config structure * \param[in] args - Pointer to components' ipc configuration arguments. * \param[in] module_entry_point - Entry point address of the module. * \param[in] agent - Function pointer to the system agent start function. @@ -500,7 +500,8 @@ const struct sof_man_module *lib_manager_get_module_manifest(const uint32_t modu * * \return Error code returned by the system agent, 0 on success. */ -static int lib_manager_start_agent(const struct comp_driver *drv, const uint32_t component_id, +static int lib_manager_start_agent(const struct comp_driver *drv, + const struct comp_ipc_config *config, const struct sof_man_module *mod_manifest, const struct ipc_config_process *args, const uintptr_t module_entry_point, @@ -518,9 +519,9 @@ static int lib_manager_start_agent(const struct comp_driver *drv, const uint32_t mod_cfg.size = args->size >> 2; agent_params.entry_point = module_entry_point; - agent_params.module_id = IPC4_MOD_ID(component_id); - agent_params.instance_id = IPC4_INST_ID(component_id); - agent_params.core_id = 0; + agent_params.module_id = IPC4_MOD_ID(config->id); + agent_params.instance_id = IPC4_INST_ID(config->id); + agent_params.core_id = config->core; agent_params.log_handle = (uint32_t)drv->tctx; agent_params.mod_cfg = &mod_cfg; @@ -663,7 +664,7 @@ static struct comp_dev *lib_manager_module_create(const struct comp_driver *drv, /* At this point module resources are allocated and it is moved to L2 memory. */ if (agent) { - ret = lib_manager_start_agent(drv, config->id, mod, args, module_entry_point, agent, + ret = lib_manager_start_agent(drv, config, mod, args, module_entry_point, agent, agent_iface, &userspace, &ops); if (ret) goto err;