Skip to content
Open
4 changes: 4 additions & 0 deletions src/audio/module_adapter/module_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,11 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
comp_cl_err(drv, "Failed to allocate DP module heap / vregion");
return NULL;
}
#ifdef CONFIG_SOF_USERSPACE_LL
mod_heap = sof_sys_user_heap_get();
#else
mod_heap = NULL;
#endif
} else {
#ifdef CONFIG_SOF_USERSPACE_LL
mod_heap = sof_sys_user_heap_get();
Expand Down
1 change: 1 addition & 0 deletions src/include/sof/audio/component.h
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ struct comp_driver {
* Currently used by module_adapter.
*/
struct k_heap *user_heap; /**< Userspace heap */
struct sof_uuid uid_cp; /**< UUID copy for LLEXT modules */
};

/** \brief Holds constant pointer to component driver */
Expand Down
21 changes: 21 additions & 0 deletions src/include/sof/lib_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ struct lib_manager_module {
struct llext *llext; /* Zephyr loadable extension context */
struct llext_buf_loader *ebl; /* Zephyr loadable extension buffer loader */
unsigned int n_dependent; /* For auxiliary modules: number of dependents */
unsigned int n_mod;
bool mapped;
bool domain_dp;
struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS];
};

Expand Down Expand Up @@ -217,6 +219,25 @@ void lib_manager_get_instance_bss_address(uint32_t instance_id,
*/
int lib_manager_load_library(uint32_t dma_id, uint32_t lib_id, uint32_t type);

struct userspace_context;
/*
* \brief Allocate the module and start the agent if needed
*/
int lib_manager_mod_create_priv(const struct comp_driver *drv,
const struct comp_ipc_config *config,
const void *spec, void **adapter_priv,
struct userspace_context **userspace,
const struct module_interface **ops);

#if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION)
__syscall int lib_manager_free_module(const uint32_t component_id);

#include <zephyr/syscalls/lib_manager.h>
#else
int z_impl_lib_manager_free_module(const uint32_t component_id);
#define lib_manager_free_module z_impl_lib_manager_free_module
#endif

/*
* \brief Initialize message
*
Expand Down
80 changes: 56 additions & 24 deletions src/ipc/ipc-common.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,6 @@ void ipc_schedule_process(struct ipc *ipc)
#define IPC_USER_EVENT_CMD BIT(0)
#define IPC_USER_EVENT_STOP BIT(1)

static struct k_thread ipc_user_thread;
static K_THREAD_STACK_DEFINE(ipc_user_stack, CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE);

/**
Expand Down Expand Up @@ -419,10 +418,59 @@ static void ipc_user_thread_fn(void *p1, void *p2, void *p3)
}
}

__cold static int ipc_user_init_thread(struct ipc_user *ipc_user)
{
char thread_name[] = "ll_user0";
int ret;

assert_can_be_cold();

/* Allocate kernel objects for the user-space thread */
ipc_user->event = k_object_alloc(K_OBJ_EVENT);
if (!ipc_user->event) {
LOG_ERR("user IPC event alloc failed");
return -ENOMEM;
}
k_event_init(ipc_user->event);

ipc_user->thread = k_object_alloc(K_OBJ_THREAD);
if (!ipc_user->thread) {
LOG_ERR("user IPC thread alloc failed");
ret = -ENOMEM;
goto e_event;
}

k_thread_create(ipc_user->thread, ipc_user_stack,
CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE,
ipc_user_thread_fn, ipc_user, NULL, NULL,
-1, K_USER, K_FOREVER);

k_thread_cpu_pin(ipc_user->thread, PLATFORM_PRIMARY_CORE_ID);
k_thread_name_set(ipc_user->thread, thread_name);

/*
* Each userspace IPC thread must be able to wait on its private event
* and signal completion on the primary core semaphore
*/
k_thread_access_grant(ipc_user->thread, ipc_user->sem, ipc_user->event);
user_grant_dai_access_all(ipc_user->thread);
user_grant_dma_access_all(ipc_user->thread);
k_mem_domain_add_thread(zephyr_ll_mem_domain(), ipc_user->thread);
user_ll_grant_access(ipc_user->thread, PLATFORM_PRIMARY_CORE_ID);

return 0;

e_event:
k_object_free(ipc_user->event);

return ret;
}

__cold static void ipc_user_init(void)
{
struct ipc *ipc = ipc_get();
struct ipc_user *ipc_user = sof_heap_alloc(sof_sys_user_heap_get(), SOF_MEM_FLAG_USER,
struct ipc_user *ipc_user = sof_heap_alloc(sof_sys_user_heap_get(),
SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT,
sizeof(*ipc_user), 0);
int ret;

Expand All @@ -443,38 +491,22 @@ __cold static void ipc_user_init(void)

k_sem_init(ipc_user->sem, 0, 1);

/* Allocate kernel objects for the user-space thread */
ipc_user->event = k_object_alloc(K_OBJ_EVENT);
if (!ipc_user->event) {
LOG_ERR("user IPC event alloc failed");
ret = ipc_user_init_thread(ipc_user);
if (ret < 0) {
LOG_ERR("user IPC thread initialization failed");
sof_panic(SOF_IPC_PANIC_IPC);
}
k_event_init(ipc_user->event);

k_thread_create(&ipc_user_thread, ipc_user_stack,
CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE,
ipc_user_thread_fn, ipc_user, NULL, NULL,
-1, K_USER, K_FOREVER);

ipc_user->thread = &ipc_user_thread;
k_thread_access_grant(&ipc_user_thread, ipc_user->sem, ipc_user->event);
user_grant_dai_access_all(&ipc_user_thread);
user_grant_dma_access_all(&ipc_user_thread);
ret = user_access_to_mailbox(zephyr_ll_mem_domain(), &ipc_user_thread);
ret = user_access_to_mailbox(zephyr_ll_mem_domain(), ipc_user->thread);
if (ret < 0) {
LOG_ERR("ipc user: mailbox access grant failed: %d", ret);
sof_panic(SOF_IPC_PANIC_IPC);
}
user_ll_grant_access(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID);
k_mem_domain_add_thread(zephyr_ll_mem_domain(), &ipc_user_thread);

k_thread_cpu_pin(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID);
k_thread_name_set(&ipc_user_thread, "ipc_user");

/* Store references in ipc struct so kernel handler can forward commands */
ipc->ipc_user_pdata = ipc_user;

k_thread_start(&ipc_user_thread);
k_thread_start(ipc_user->thread);

struct task *task = zephyr_ll_task_alloc();

Expand All @@ -486,7 +518,7 @@ __cold static void ipc_user_init(void)
* Needed so user-space dai_common_new() can call
* k_thread_access_grant(audio_thread, dai_mutex) from user context.
*/
k_thread_access_grant(&ipc_user_thread, ipc_user->audio_thread);
k_thread_access_grant(ipc_user->thread, ipc_user->audio_thread);

/* Wait for user thread startup — consumes the initial k_sem_give from thread */
k_sem_take(ipc->ipc_user_pdata->sem, K_FOREVER);
Expand Down
2 changes: 2 additions & 0 deletions src/ipc/ipc-helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,9 @@ __cold int ipc_comp_free(struct ipc *ipc, uint32_t comp_id)
struct comp_buffer *buffer;
struct comp_buffer *safe;
struct list_item *clist;
#ifndef CONFIG_SOF_USERSPACE_LL
uint32_t flags;
#endif

assert_can_be_cold();

Expand Down
75 changes: 47 additions & 28 deletions src/ipc/ipc4/handler-user.c
Original file line number Diff line number Diff line change
Expand Up @@ -428,53 +428,72 @@ __cold const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data_wrapper
return ipc4_get_pipeline_data();
}

static int ipc4_pipeline_id_get(struct ipc4_message_request *ipc4,
struct ipc4_pipeline_set_state *state,
const uint32_t **ppl_id, unsigned int *ppl_count)
{
if (!state->extension.r.multi_ppl) {
if (ppl_count)
*ppl_count = 1;
if (ppl_id)
*ppl_id = NULL;
return state->primary.r.ppl_id;
}

const struct ipc4_pipeline_set_state_data *ppl_data = ipc4_get_pipeline_data();
unsigned int cnt = ppl_data->pipelines_count;

/*
* pipelines_count is read straight from the host-provided
* mailbox payload, so cap it at what the mailbox can
* physically hold. Anything larger means the host promised
* more ppl_id[] entries than fit in MAILBOX_HOSTBOX, and
* dereferencing the flex array would read out of bounds.
*/
if (cnt > (MAILBOX_HOSTBOX_SIZE - sizeof(struct ipc4_pipeline_set_state_data)) /
sizeof(uint32_t)) {
ipc_cmd_err(&ipc_tr, "ipc: pipelines_count %u exceeds mailbox bound",
cnt);
return -EINVAL;
}
dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_data->ppl_id,
sizeof(int) * cnt);
if (ppl_count)
*ppl_count = cnt;
if (ppl_id)
*ppl_id = ppl_data->ppl_id;

return ppl_data->ppl_id[0];
}

/**
* \brief Process SET_PIPELINE_STATE IPC4 message (prepare + trigger phases).
* @param[in] ipc4 IPC4 message request.
* @return 0 on success, IPC4 error code otherwise.
*/
int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4)
{
const struct ipc4_pipeline_set_state_data *ppl_data;
struct ipc4_pipeline_set_state state;
struct ipc_comp_dev *ppl_icd;
struct ipc *ipc = ipc_get();
uint32_t cmd, ppl_count;
uint32_t id = 0;
unsigned int id;
const uint32_t *ppl_id;
bool use_idc = false;
uint32_t idx;
int ret = 0;
int ret;
int i;

state.primary.dat = ipc4->primary.dat;
state.extension.dat = ipc4->extension.dat;
cmd = state.primary.r.ppl_state;
ppl_data = ipc4_get_pipeline_data();

if (state.extension.r.multi_ppl) {
ppl_count = ppl_data->pipelines_count;
/*
* pipelines_count is read straight from the host-provided
* mailbox payload, so cap it at what the mailbox can
* physically hold. Anything larger means the host promised
* more ppl_id[] entries than fit in MAILBOX_HOSTBOX, and
* dereferencing the flex array would read out of bounds.
*/
if (ppl_count > (MAILBOX_HOSTBOX_SIZE -
sizeof(struct ipc4_pipeline_set_state_data)) /
sizeof(uint32_t)) {
ipc_cmd_err(&ipc_tr,
"ipc: pipelines_count %u exceeds mailbox bound",
ppl_count);
return IPC4_ERROR_INVALID_PARAM;
}
ppl_id = ppl_data->ppl_id;
dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_id,
sizeof(int) * ppl_count);
} else {
ppl_count = 1;
id = state.primary.r.ppl_id;
ret = ipc4_pipeline_id_get(ipc4, &state, &ppl_id, &ppl_count);
if (ret < 0)
return IPC4_ERROR_INVALID_PARAM;

if (ppl_count == 1) {
id = ret;
ppl_id = &id;
}

Expand Down Expand Up @@ -573,7 +592,7 @@ int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4)
return ret;
}

return ret;
return IPC4_SUCCESS;
}

__cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4)
Expand Down
27 changes: 14 additions & 13 deletions src/ipc/ipc4/helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,24 +88,25 @@ void ipc_build_trace_posn(struct sof_ipc_dma_trace_posn *posn)
}

#if CONFIG_LIBRARY
static inline char *ipc4_get_comp_new_data(void)
static inline unsigned char *ipc4_get_comp_new_data(void)
{
struct ipc *ipc = ipc_get();
char *data = (char *)ipc->comp_data + sizeof(struct ipc4_module_init_instance);
unsigned char *data = (unsigned char *)ipc->comp_data +
sizeof(struct ipc4_module_init_instance);

return data;
}

static const struct comp_driver *ipc4_library_get_comp_drv(char *data)
static const struct comp_driver *ipc4_library_get_comp_drv(unsigned char *data)
{
return ipc4_get_drv(data);
}
#else
__cold static inline char *ipc4_get_comp_new_data(void)
__cold static inline unsigned char *ipc4_get_comp_new_data(void)
{
assert_can_be_cold();

return (char *)MAILBOX_HOSTBOX_BASE;
return (unsigned char *)MAILBOX_HOSTBOX_BASE;
}
#endif

Expand All @@ -116,7 +117,7 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i
const struct comp_driver *drv;
struct comp_dev *dev;
uint32_t comp_id;
char *data;
unsigned char *data;

assert_can_be_cold();

Expand Down Expand Up @@ -190,13 +191,13 @@ __cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_i

if (drv->type == SOF_COMP_MODULE_ADAPTER) {
const struct ipc_config_process spec = {
.data = (const unsigned char *)data,
.data = data,
.size = ipc_config.ipc_config_size,
};

dev = drv->ops.create(drv, &ipc_config, (const void *)&spec);
dev = drv->ops.create(drv, &ipc_config, &spec);
} else {
dev = drv->ops.create(drv, &ipc_config, (const void *)data);
dev = drv->ops.create(drv, &ipc_config, data);
}
if (!dev)
return NULL;
Expand Down Expand Up @@ -241,7 +242,7 @@ __cold struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4,
struct comp_ipc_config ipc_config;
struct comp_dev *dev;
uint32_t comp_id;
char *data;
unsigned char *data;
int ret;

assert_can_be_cold();
Expand Down Expand Up @@ -303,13 +304,13 @@ __cold struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4,

if (drv->type == SOF_COMP_MODULE_ADAPTER) {
const struct ipc_config_process spec = {
.data = (const unsigned char *)data,
.data = data,
.size = ipc_config.ipc_config_size,
};

dev = drv->ops.create(drv, &ipc_config, (const void *)&spec);
dev = drv->ops.create(drv, &ipc_config, &spec);
} else {
dev = drv->ops.create(drv, &ipc_config, (const void *)data);
dev = drv->ops.create(drv, &ipc_config, data);
}
if (!dev)
return NULL;
Expand Down
Loading
Loading