diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 639dbc954dbb..48906bada70f 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -580,7 +580,7 @@ int module_prepare(struct processing_module *mod, #if CONFIG_SOF_USERSPACE_APPLICATION if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { - const union scheduler_dp_thread_ipc_param param = { + union scheduler_dp_thread_ipc_param param = { .pipeline_state = { .trigger_cmd = COMP_TRIGGER_PREPARE, .state = SOF_IPC4_PIPELINE_STATE_RUNNING, @@ -722,7 +722,7 @@ int module_reset(struct processing_module *mod) if (ops->reset) { #if CONFIG_SOF_USERSPACE_APPLICATION if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { - const union scheduler_dp_thread_ipc_param param = { + union scheduler_dp_thread_ipc_param param = { .pipeline_state.trigger_cmd = COMP_TRIGGER_STOP, }; ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_GLB_SET_PIPELINE_STATE, ¶m); @@ -781,11 +781,23 @@ int module_free(struct processing_module *mod) struct module_data *md = &mod->priv; int ret = 0; - if (ops->free && (mod->dev->ipc_config.proc_domain != COMP_PROCESSING_DOMAIN_DP || - !IS_ENABLED(CONFIG_SOF_USERSPACE_APPLICATION))) { - ret = ops->free(mod); - if (ret) - comp_warn(mod->dev, "error: %d", ret); + if (ops->free) { + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_LL || + !IS_ENABLED(CONFIG_SOF_USERSPACE_APPLICATION)) { + ret = ops->free(mod); + if (ret) + comp_warn(mod->dev, "error: %d", ret); +#if CONFIG_SOF_USERSPACE_APPLICATION + } else { + /* + * Run DP module's .free() method in its thread context. + * Unlike with other IPCs we first run module's .free() + * in thread context, then cancel the thread, and then + * execute final clean up + */ + scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_DELETE_INSTANCE, NULL); +#endif + } } /* Free all memory shared by module_adapter & module */ @@ -939,7 +951,7 @@ int module_bind(struct processing_module *mod, const struct bind_info *bind_data if (ops->bind) { #if CONFIG_SOF_USERSPACE_APPLICATION if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { - const union scheduler_dp_thread_ipc_param param = { + union scheduler_dp_thread_ipc_param param = { .bind_data = bind_data, }; ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_BIND, ¶m); @@ -972,7 +984,7 @@ int module_unbind(struct processing_module *mod, const struct bind_info *unbind_ if (ops->unbind) { #if CONFIG_SOF_USERSPACE_APPLICATION if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { - const union scheduler_dp_thread_ipc_param param = { + union scheduler_dp_thread_ipc_param param = { .bind_data = unbind_data, }; ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_UNBIND, ¶m); diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 98234daa082c..2da09b17f5a3 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -1413,7 +1413,7 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd) #if CONFIG_SOF_USERSPACE_APPLICATION if (dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { /* Process DP module's trigger */ - const union scheduler_dp_thread_ipc_param param = { + union scheduler_dp_thread_ipc_param param = { .pipeline_state.trigger_cmd = cmd, }; return scheduler_dp_thread_ipc(mod, SOF_IPC4_GLB_SET_PIPELINE_STATE, @@ -1483,17 +1483,6 @@ void module_adapter_free(struct comp_dev *dev) comp_dbg(dev, "start"); -#if CONFIG_SOF_USERSPACE_APPLICATION - if (dev->task) - /* - * Run DP module's .free() method in its thread context. - * Unlike with other IPCs we first run module's .free() in - * thread context, then cancel the thread, and then execute - * final clean up - */ - scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_DELETE_INSTANCE, NULL); -#endif - ret = module_free(mod); if (ret) comp_err(dev, "failed with error: %d", ret); diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index 7fa224a06d6c..a70eb77eff38 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include #include @@ -263,10 +265,27 @@ int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ return -EINVAL; } - if (interface->set_configuration) - return interface->set_configuration(mod, param_id, pos, data_offset_size, - (const uint8_t *)data, fragment_size, - NULL, 0); + if (interface->set_configuration) { +#if CONFIG_SOF_USERSPACE_APPLICATION + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + union scheduler_dp_thread_ipc_param param = { + .set_config = { + .param_id = param_id, + .position = pos, + .data_offset_size = data_offset_size, + .data = data, + .fragment_size = fragment_size, + }, + }; + + return scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_LARGE_CONFIG_SET, ¶m); + } else +#endif + return interface->set_configuration(mod, param_id, pos, data_offset_size, + (const uint8_t *)data, fragment_size, + NULL, 0); + } + return 0; } @@ -297,9 +316,28 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ } } - if (interface->get_configuration) - return interface->get_configuration(mod, param_id, data_offset_size, - (uint8_t *)data, fragment_size); + if (interface->get_configuration) { +#if CONFIG_SOF_USERSPACE_APPLICATION + if (mod->dev->ipc_config.proc_domain == COMP_PROCESSING_DOMAIN_DP) { + union scheduler_dp_thread_ipc_param param = { + .get_config = { + .param_id = param_id, + .data_offset_size = *data_offset_size, + .data = data, + .fragment_size = fragment_size, + }, + }; + + int ret = scheduler_dp_thread_ipc(mod, SOF_IPC4_MOD_LARGE_CONFIG_SET, + ¶m); + if (!ret) + *data_offset_size = param.get_config.data_offset_size; + } else +#endif + return interface->get_configuration(mod, param_id, data_offset_size, + (uint8_t *)data, fragment_size); + } + /* * Return error if getter is not implemented. Otherwise, the host will suppose * the GET_VALUE command is successful, but the received cdata is not filled. diff --git a/src/include/ipc4/handler.h b/src/include/ipc4/handler.h index cb54ecc08db0..8f624a3c5c70 100644 --- a/src/include/ipc4/handler.h +++ b/src/include/ipc4/handler.h @@ -34,19 +34,6 @@ int ipc4_user_module_load(const struct comp_driver *drv, int ipc4_process_module_config(struct ipc4_message_request *ipc4, bool set, uint32_t *reply_ext); -/** - * @brief Process MOD_LARGE_CONFIG_GET in any execution context. - * @param[in] ipc4 IPC4 message request. - * @param[out] reply_ext Receives extension value for reply. - * @param[out] reply_tx_size Receives TX data size for reply. - * @param[out] reply_tx_data Receives TX data pointer for reply. - * @return IPC4 status code (0 on success). - */ -int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, - uint32_t *reply_ext, - uint32_t *reply_tx_size, - void **reply_tx_data); - /** * @brief Process MOD_LARGE_CONFIG_SET in any execution context. * @param[in] ipc4 IPC4 message request. diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 2c72178cd766..a2260febb2fc 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -15,6 +15,7 @@ #include #include #include +#include struct processing_module; struct module_ext_init_data; @@ -129,15 +130,28 @@ union scheduler_dp_thread_ipc_param { int n_sinks; struct sof_sink **sinks; } pipeline_state; + struct { + uint32_t param_id; + enum module_cfg_fragment_position position; + uint32_t data_offset_size; + size_t fragment_size; + const char *data; + } set_config; + struct { + uint32_t param_id; + uint32_t data_offset_size; + size_t fragment_size; + char *data; + } get_config; }; #if CONFIG_ZEPHYR_DP_SCHEDULER int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, - const union scheduler_dp_thread_ipc_param *param); + union scheduler_dp_thread_ipc_param *param); #else static inline int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, - const union scheduler_dp_thread_ipc_param *param) + union scheduler_dp_thread_ipc_param *param) { return 0; } diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 5cea1bf7dbe4..94360942934b 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -1091,10 +1091,11 @@ __cold static int ipc4_get_vendor_config_module_instance(struct comp_dev *dev, return IPC4_SUCCESS; } -__cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, - uint32_t *reply_ext, - uint32_t *reply_tx_size, - void **reply_tx_data) +#ifdef CONFIG_SOF_USERSPACE_LL +__cold static int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, + uint32_t *reply_ext, + uint32_t *reply_tx_size, + void **reply_tx_data) { struct ipc4_module_large_config_reply reply; const struct ipc4_module_large_config *config = @@ -1189,6 +1190,7 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, *reply_tx_data = data; return ret; } +#endif __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ipc4) { @@ -1683,6 +1685,13 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, break; case SOF_IPC4_MOD_BIND: #ifdef CONFIG_SOF_USERSPACE_LL + /* + * bind and unbind can connect LL with DP. In that case it isn't + * immediately clear whether the handler should run in the DP + * thread context or in the LL IPC thread context. The LL IPC + * thread has access to DP modules, so we have to perform + * binding in the LL IPC thread context + */ ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat, ipc4_user_target_core_module(ipc4)); #else @@ -1691,6 +1700,7 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, break; case SOF_IPC4_MOD_UNBIND: #ifdef CONFIG_SOF_USERSPACE_LL + /* DP / LL: see comment above */ ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat, ipc4_user_target_core_module(ipc4)); #else diff --git a/src/schedule/zephyr_dp_schedule.h b/src/schedule/zephyr_dp_schedule.h index 2119e44c9dfc..d33e6895507c 100644 --- a/src/schedule/zephyr_dp_schedule.h +++ b/src/schedule/zephyr_dp_schedule.h @@ -42,6 +42,7 @@ struct task_dp_pdata { struct processing_module *mod; /* the module to be scheduled */ uint32_t ll_cycles_to_start; /* current number of LL cycles till delayed start */ #if CONFIG_SOF_USERSPACE_APPLICATION + uint8_t *ipc_config_data; struct ipc4_flat *flat; struct k_mem_partition mpart[SOF_DP_PART_TYPE_COUNT]; #endif diff --git a/src/schedule/zephyr_dp_schedule_application.c b/src/schedule/zephyr_dp_schedule_application.c index 0cf8c457b9b8..02bd00da5bbc 100644 --- a/src/schedule/zephyr_dp_schedule_application.c +++ b/src/schedule/zephyr_dp_schedule_application.c @@ -62,6 +62,19 @@ struct ipc4_flat { * valid and is covered by the DP thread's SOF_DP_PART_CFG partition. */ struct module_ext_init_data init_instance; + struct { + uint32_t param_id; + enum module_cfg_fragment_position position; + uint32_t data_offset_size; + size_t fragment_size; + const char *data; + } set_config; + struct { + uint32_t param_id; + uint32_t data_offset_size; + size_t fragment_size; + char *data; + } get_config; }; }; @@ -108,15 +121,39 @@ static int ipc_thread_flatten(unsigned int cmd, const union scheduler_dp_thread_ flat->pipeline_state.n_sinks * sizeof(flat->pipeline_state.sink[0])); } + break; + case SOF_IPC4_MOD_LARGE_CONFIG_SET: + flat->set_config.param_id = param->set_config.param_id; + flat->set_config.position = param->set_config.position; + flat->set_config.data_offset_size = param->set_config.data_offset_size; + flat->set_config.fragment_size = param->set_config.fragment_size; + flat->set_config.data = param->set_config.data; + break; + case SOF_IPC4_MOD_LARGE_CONFIG_GET: + flat->get_config.param_id = param->get_config.param_id; + flat->get_config.data_offset_size = param->get_config.data_offset_size; + flat->get_config.fragment_size = param->get_config.fragment_size; + flat->get_config.data = NULL/*param->get_config.data*/; } return 0; } +/* memory allocation helper structure */ +struct scheduler_dp_task_memory { + struct task task; + struct task_dp_pdata pdata; + struct comp_driver drv; + struct ipc4_flat flat; +}; + /* Unpack IPC data and execute a callback */ static void ipc_thread_unflatten_run(struct processing_module *pmod, struct ipc4_flat *flat) { const struct module_interface *const ops = pmod->dev->drv->adapter_ops; + struct scheduler_dp_task_memory *task_mem = container_of(flat, + struct scheduler_dp_task_memory, + flat); switch (flat->cmd) { case SOF_IPC4_MOD_BIND: @@ -167,6 +204,21 @@ static void ipc_thread_unflatten_run(struct processing_module *pmod, struct ipc4 flat->pipeline_state.sink, flat->pipeline_state.n_sinks); } + break; + case SOF_IPC4_MOD_LARGE_CONFIG_SET: + flat->ret = ops->set_configuration(pmod, flat->set_config.param_id, + flat->set_config.position, + flat->set_config.data_offset_size, + flat->set_config.data, + flat->set_config.fragment_size, NULL, 0); + break; + case SOF_IPC4_MOD_LARGE_CONFIG_GET: + flat->ret = ops->get_configuration(pmod, flat->get_config.param_id, + &flat->get_config.data_offset_size, + task_mem->pdata.ipc_config_data, + flat->get_config.fragment_size); + if (!flat->ret) + flat->get_config.data = task_mem->pdata.ipc_config_data; } } @@ -174,7 +226,7 @@ static void ipc_thread_unflatten_run(struct processing_module *pmod, struct ipc4 /* Signal an IPC and wait for processing completion */ int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, - const union scheduler_dp_thread_ipc_param *param) + union scheduler_dp_thread_ipc_param *param) { if (!pmod) { tr_err(&dp_tr, "no thread module"); @@ -205,16 +257,24 @@ int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, scheduler_dp_unlock(lock_key); - if (!ret) { - /* Wait for completion */ - ret = k_sem_take(&dp_sync[core], DP_THREAD_IPC_TIMEOUT); - if (ret < 0) - tr_err(&dp_tr, "Failed waiting for DP thread: %d", ret); - else - ret = pdata->flat->ret; + if (ret < 0) + return ret; + + /* Wait for completion */ + ret = k_sem_take(&dp_sync[core], DP_THREAD_IPC_TIMEOUT); + if (ret < 0) { + tr_err(&dp_tr, "Failed waiting for DP thread: %d", ret); + return ret; } - return ret; + if (!pdata->flat->ret && cmd == SOF_IPC4_MOD_LARGE_CONFIG_GET) { + /* A single case of returning data */ + param->get_config.data_offset_size = pdata->flat->get_config.data_offset_size; + return memcpy_s(param->get_config.data, SOF_IPC_MSG_MAX_SIZE, + pdata->flat->get_config.data, param->get_config.fragment_size); + } + + return pdata->flat->ret; } /* Go through all DP tasks and recalculate their readiness and deadlines @@ -415,14 +475,6 @@ static void scheduler_dp_domain_free(struct task_dp_pdata *pdata) objpool_free(&dp_mdom_head, mdom); } -/* memory allocation helper structure */ -struct scheduler_dp_task_memory { - struct task task; - struct task_dp_pdata pdata; - struct comp_driver drv; - struct ipc4_flat flat; -}; - void z_impl_scheduler_dp_internal_free(struct task *task) { struct task_dp_pdata *pdata = task->priv_data; @@ -500,20 +552,31 @@ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, struct task_dp_pdata *pdata = &task_memory->pdata; + if (mod->dev->drv->adapter_ops->get_configuration) { + pdata->ipc_config_data = mod_alloc_ext(mod, SOF_MEM_FLAG_USER, SOF_IPC_MSG_MAX_SIZE, + 0); + if (!pdata->ipc_config_data) { + tr_err(&dp_tr, "Failed to allocate memory for get-config"); + goto e_stack; + } + } else { + pdata->ipc_config_data = NULL; + } + pdata->flat = &task_memory->flat; pdata->event = k_object_alloc(K_OBJ_EVENT); if (!pdata->event) { tr_err(&dp_tr, "Event object allocation failed"); ret = -ENOMEM; - goto e_stack; + goto e_config; } pdata->thread = k_object_alloc(K_OBJ_THREAD); if (!pdata->thread) { tr_err(&dp_tr, "Thread object allocation failed"); ret = -ENOMEM; - goto e_kobj; + goto e_event; } memset(&pdata->thread->arch, 0, sizeof(pdata->thread->arch)); @@ -592,12 +655,12 @@ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, /* Host mailbox partition for additional IPC parameters: read-only */ pdata->mpart[SOF_DP_PART_CFG] = (struct k_mem_partition){ .start = (uintptr_t)sys_cache_uncached_ptr_get((void *)MAILBOX_HOSTBOX_BASE), - .size = 4096, + .size = MAILBOX_HOSTBOX_SIZE, .attr = K_MEM_PARTITION_P_RO_U_RO, }; pdata->mpart[SOF_DP_PART_CFG_CACHE] = (struct k_mem_partition){ .start = (uintptr_t)MAILBOX_HOSTBOX_BASE, - .size = 4096, + .size = MAILBOX_HOSTBOX_SIZE, .attr = K_MEM_PARTITION_P_RO_U_RO | XTENSA_MMU_CACHED_WB, }; @@ -636,10 +699,11 @@ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, if (on_pool) objpool_free(&dp_mdom_head, mdom); k_thread_abort(pdata->thread_id); -e_kobj: - /* k_object_free looks for a pointer in the list, any invalid value can be passed */ k_object_free(pdata->thread); +e_event: k_object_free(pdata->event); +e_config: + mod_free(mod, pdata->ipc_config_data); e_stack: user_stack_free(p_stack); e_tmem: