Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 60 additions & 10 deletions src/include/ipc4/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,36 @@ struct ipc4_message_request;
*/
int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply);

/**
* @brief Process MOD_CONFIG_GET or MOD_CONFIG_SET in any execution context.
* @param[in] ipc4 IPC4 message request.
* @param[in] set true for CONFIG_SET, false for CONFIG_GET.
* @param[out] reply_ext Receives extension value for CONFIG_GET (may be NULL).
* @return IPC4 status code (0 on success).
*/
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.
* @return IPC4 status code (0 on success).
*/
int ipc4_process_large_config_set(struct ipc4_message_request *ipc4);

/**
* \brief Processes IPC4 userspace global message.
* @param[in] ipc4 IPC4 message request.
Expand All @@ -25,30 +55,50 @@ int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, struct i
int ipc4_user_process_glb_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply);

/**
* \brief Increment the IPC compound message pre-start counter.
* \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);

/**
* \brief Complete the IPC compound message.
* @param[in] msg_id IPC message ID.
* @param[in] error Error code of the IPC command.
*/
void ipc_compound_pre_start(int msg_id);
void ipc_compound_msg_done(uint32_t msg_id, int error);

#if defined(__ZEPHYR__) && defined(CONFIG_SOF_USERSPACE_LL)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

squashing: propose to squash with 378f458 (it won't apply directly, if you want to apply commits as is, you need 6edbb6c first)

/**
* \brief Decrement the IPC compound message pre-start counter on return value status.
* \brief Increment the IPC compound message pre-start counter.
* @param[in] msg_id IPC message ID.
* @param[in] ret Return value of the IPC command.
* @param[in] delayed True if the reply is delayed.
*/
void ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed);
__syscall void ipc_compound_pre_start(int msg_id);

/**
* \brief Complete the IPC compound message.
* \brief Decrement the IPC compound message pre-start counter on return value status.
* @param[in] msg_id IPC message ID.
* @param[in] error Error code of the IPC command.
* @param[in] ret Return value of the IPC command.
* @param[in] delayed True if the reply is delayed.
*/
void ipc_compound_msg_done(uint32_t msg_id, int error);
__syscall void ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed);

/**
* \brief Wait for the IPC compound message to complete.
* @return 0 on success, error code otherwise on timeout.
*/
int ipc_wait_for_compound_msg(void);
__syscall int ipc_wait_for_compound_msg(void);
#else
void z_impl_ipc_compound_pre_start(int msg_id);
#define ipc_compound_pre_start z_impl_ipc_compound_pre_start
void z_impl_ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed);
#define ipc_compound_post_start z_impl_ipc_compound_post_start
int z_impl_ipc_wait_for_compound_msg(void);
#define ipc_wait_for_compound_msg z_impl_ipc_wait_for_compound_msg
#endif

#if defined(__ZEPHYR__) && defined(CONFIG_SOF_USERSPACE_LL)
#include <zephyr/syscalls/handler.h>
#endif

#endif /* __SOF_IPC4_HANDLER_H__ */
124 changes: 123 additions & 1 deletion src/include/sof/ipc/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@
#include <stdbool.h>
#include <stdint.h>

struct comp_driver;
struct dma_sg_elem_array;
struct ipc_msg;
struct ipc4_message_request;

/* validates internal non tail structures within IPC command structure */
#define IPC_IS_SIZE_INVALID(object) \
Expand Down Expand Up @@ -53,6 +55,37 @@ extern struct tr_ctx ipc_tr;
#define IPC_TASK_SECONDARY_CORE BIT(2)
#define IPC_TASK_POWERDOWN BIT(3)

struct ipc_user {
struct k_thread *thread;
struct k_sem *sem;
struct k_event *event;
/** @brief Copy of IPC4 message primary word forwarded to user thread */
uint32_t ipc_msg_pri;
/** @brief Copy of IPC4 message extension word forwarded to user thread */
uint32_t ipc_msg_ext;
/** @brief Result code from user thread processing */
int result;
/** @brief Reply extension word from user thread (e.g. CONFIG_GET result) */
uint32_t reply_ext;
/** @brief Reply TX data size from user thread (e.g. LARGE_CONFIG_GET result) */
uint32_t reply_tx_size;
/** @brief Reply TX data pointer from user thread (e.g. LARGE_CONFIG_GET result) */
void *reply_tx_data;
struct ipc *ipc;
struct k_thread *audio_thread;
/** @brief Original kernel driver pointer for restoring dev->drv after create */
const struct comp_driver *init_drv;
/**
* @brief User-accessible copy of comp_driver + tr_ctx for create().
*
* The comp_driver and tr_ctx structs reside in kernel memory
* (.rodata/.data) which is not user-readable. The kernel handler
* copies them here before forwarding to the user thread.
* Size verified by BUILD_ASSERT in handler-user.c.
*/
uint8_t init_drv_data[160] __aligned(4);
};

struct ipc {
struct k_spinlock lock; /* locking mechanism */
void *comp_data;
Expand All @@ -74,6 +107,11 @@ struct ipc {
struct task ipc_task;
#endif

#ifdef CONFIG_SOF_USERSPACE_LL
struct ipc_user *ipc_user_pdata;
struct mod_alloc_ctx *ll_alloc;
#endif

#ifdef CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS
/* io performance measurement */
struct io_perf_data_item *io_perf_in_msg_count;
Expand All @@ -95,6 +133,12 @@ struct ipc {

extern struct task_ops ipc_task_ops;

#ifdef CONFIG_SOF_USERSPACE_LL

struct ipc *ipc_get(void);

#else

/**
* \brief Get the IPC global context.
* @return The global IPC context.
Expand All @@ -104,6 +148,8 @@ static inline struct ipc *ipc_get(void)
return sof_get()->ipc;
}

#endif /* CONFIG_SOF_USERSPACE_LL */

/**
* \brief Initialise global IPC context.
* @param[in,out] sof Global SOF context.
Expand Down Expand Up @@ -166,6 +212,56 @@ struct dai_data;
*/
int ipc_dai_data_config(struct dai_data *dd, struct comp_dev *dev);

/**
* \brief Processes IPC4 userspace module message.
* @param[in] ipc4 IPC4 message request.
* @param[in] reply IPC message reply structure.
* @return IPC4_SUCCESS on success, error code otherwise.
*/
int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply);

/**
* \brief Processes IPC4 userspace global message.
* @param[in] ipc4 IPC4 message request.
* @param[in] reply IPC message reply structure.
* @return IPC4_SUCCESS on success, error code otherwise.
*/
int ipc4_user_process_glb_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply);

/*
* When CONFIG_SOF_USERSPACE_LL is enabled, compound message functions are
* declared as syscalls in ipc4/handler.h — do not re-declare here with
* external linkage as that conflicts with the static inline syscall wrappers.
*/
#if !(defined(__ZEPHYR__) && defined(CONFIG_SOF_USERSPACE_LL))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these 3 under the #if seem unneeded - would be removed by squashing

/**
* \brief Increment the IPC compound message pre-start counter.
* @param[in] msg_id IPC message ID.
*/
void ipc_compound_pre_start(int msg_id);

/**
* \brief Decrement the IPC compound message pre-start counter on return value status.
* @param[in] msg_id IPC message ID.
* @param[in] ret Return value of the IPC command.
* @param[in] delayed True if the reply is delayed.
*/
void ipc_compound_post_start(uint32_t msg_id, int ret, bool delayed);

/**
* \brief Wait for the IPC compound message to complete.
* @return 0 on success, error code otherwise on timeout.
*/
int ipc_wait_for_compound_msg(void);
#endif /* !CONFIG_SOF_USERSPACE_LL */

/**
* \brief Complete the IPC compound message.
* @param[in] msg_id IPC message ID.
* @param[in] error Error code of the IPC command.
*/
void ipc_compound_msg_done(uint32_t msg_id, int error);

/**
* \brief create a IPC boot complete message.
* @param[in] header header.
Expand Down Expand Up @@ -240,7 +336,7 @@ int ipc_process_on_core(uint32_t core, bool blocking);
* \brief reply to an IPC message.
* @param[in] reply pointer to the reply structure.
*/
void ipc_msg_reply(struct sof_ipc_reply *reply);
#include <sof/ipc/ipc_reply.h>

/**
* \brief Call platform-specific IPC completion function.
Expand All @@ -250,4 +346,30 @@ void ipc_complete_cmd(struct ipc *ipc);
/* GDB stub: should enter GDB after completing the IPC processing */
extern bool ipc_enter_gdb;

#ifdef CONFIG_SOF_USERSPACE_LL
/**
* @brief Forward an IPC command to the user-space thread and wait for it.
*
* Protocol-agnostic: only the two raw message words are handed across the
* kernel/user boundary. The active IPC major's ipc_user_thread_dispatch()
* interprets them in the user thread.
*
* @param primary Primary message word
* @param extension Extension message word
* @return Result code from user thread processing
*/
int ipc_user_forward_cmd(uint32_t primary, uint32_t extension);

/**
* @brief Protocol-specific dispatch of a forwarded IPC command.
*
* Runs in the user-space IPC thread. A __weak default returns -ENOSYS;
* the active IPC major (e.g. IPC4) provides the real implementation.
*
* @param ipc_user User IPC context holding the forwarded message words
* @return Result code to report back to the host
*/
int ipc_user_thread_dispatch(struct ipc_user *ipc_user);
#endif

#endif /* __SOF_DRIVERS_IPC_H__ */
28 changes: 28 additions & 0 deletions src/include/sof/ipc/ipc_reply.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright(c) 2026 Intel Corporation. All rights reserved.
*/

#ifndef __SOF_IPC_IPC_REPLY_H__
#define __SOF_IPC_IPC_REPLY_H__

#include <ipc/header.h>

struct sof_ipc_reply;

/**
* \brief reply to an IPC message.
* @param[in] reply pointer to the reply structure.
*/
#if defined(__ZEPHYR__) && defined(CONFIG_SOF_USERSPACE_LL)
__syscall void ipc_msg_reply(struct sof_ipc_reply *reply);
#else
void z_impl_ipc_msg_reply(struct sof_ipc_reply *reply);
#define ipc_msg_reply z_impl_ipc_msg_reply
#endif

#if defined(__ZEPHYR__) && defined(CONFIG_SOF_USERSPACE_LL)
#include <zephyr/syscalls/ipc_reply.h>
#endif

#endif /* __SOF_IPC_IPC_REPLY_H__ */
7 changes: 7 additions & 0 deletions src/include/sof/ipc/topology.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ typedef uint32_t ipc_comp;
struct ipc_comp_dev;
const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id);
struct comp_dev *ipc4_get_comp_dev(uint32_t comp_id);
int ipc4_add_comp_dev(struct comp_dev *dev);
#ifdef CONFIG_SOF_USERSPACE_LL
struct ipc4_message_request;
struct comp_driver;
struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4,
const struct comp_driver *drv);
#endif
int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma);
int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma);
int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma);
Expand Down
1 change: 1 addition & 0 deletions src/include/sof/schedule/ll_schedule_domain.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ struct task *zephyr_ll_task_alloc(void);
struct k_heap *zephyr_ll_user_heap(void);
bool zephyr_ll_user_heap_verify(struct k_heap *heap);
void zephyr_ll_user_resources_init(void);
void user_ll_grant_access(struct k_thread *thread, int core);
void user_ll_lock_sched(int core);
void user_ll_unlock_sched(int core);
#ifdef CONFIG_ASSERT
Expand Down
Loading
Loading