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
60 changes: 53 additions & 7 deletions src/include/sof/ipc/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,26 +98,72 @@ struct ipc_user {
uint8_t init_drv_data[160] __aligned(4);
};

struct ipc {
struct k_spinlock lock; /* locking mechanism */
void *comp_data;
#ifdef CONFIG_SOF_USERSPACE_LL
/**
* Kernel-only IPC state.
*
* With CONFIG_SOF_USERSPACE_LL, struct ipc is in a partition that the LL and
* IPC user threads can write. The send queue, its lock, the completion
* state and the IPC processing task are used by kernel code only, so they
* are kept here instead. The field names match the struct ipc fields used
* without CONFIG_SOF_USERSPACE_LL, so code accesses both through ipc_ks().
*
* comp_data stays in struct ipc for the IPC user thread, but kernel code
* must use the copy here, ipc_ks(ipc)->comp_data, to find the buffer.
*/
struct ipc_kstate {
struct k_spinlock lock; /* locking mechanism */
void *comp_data; /* kernel copy of ipc->comp_data */
int pm_prepare_D3; /* do we need to prepare for D3 */
struct list_item msg_list; /* queue of messages to be sent */
uint32_t task_mask; /* tasks to be completed by this IPC */

/* processing task, run by the kernel scheduler */
#if CONFIG_TWB_IPC_TASK
struct task *ipc_task;
#else
struct task ipc_task;
#endif
};

/** Kernel context only. */
struct ipc_kstate *ipc_kstate_get(void);

struct ipc;

static inline struct ipc_kstate *ipc_ks(struct ipc *ipc)
{
(void)ipc;

/* PM */
int pm_prepare_D3; /* do we need to prepare for D3 */
return ipc_kstate_get();
}
#else
#define ipc_ks(ipc) (ipc)
#endif

struct ipc {
#ifndef CONFIG_SOF_USERSPACE_LL
/* in struct ipc_kstate with CONFIG_SOF_USERSPACE_LL, use ipc_ks() */
struct k_spinlock lock; /* locking mechanism */
int pm_prepare_D3; /* do we need to prepare for D3 */
struct list_item msg_list; /* queue of messages to be sent */
bool is_notification_pending; /* notification is being sent to host */
uint32_t task_mask; /* tasks to be completed by this IPC */
Comment thread
kv2019i marked this conversation as resolved.
Resolved
#endif
void *comp_data;

bool is_notification_pending; /* notification is being sent to host */
unsigned int core; /* core, processing the IPC */

struct list_item comp_list; /* list of component devices */

/* processing task */
#ifndef CONFIG_SOF_USERSPACE_LL
/* processing task, in struct ipc_kstate with CONFIG_SOF_USERSPACE_LL */
#if CONFIG_TWB_IPC_TASK
struct task *ipc_task;
#else
struct task ipc_task;
#endif
#endif

#ifdef CONFIG_SOF_USERSPACE_LL
struct ipc_user *ipc_user_pdata;
Expand Down
16 changes: 16 additions & 0 deletions src/include/sof/ipc/msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,22 @@ void z_impl_ipc_msg_send(struct ipc_msg *msg, void *data,
#define ipc_msg_send z_impl_ipc_msg_send
#endif

#ifdef CONFIG_USERSPACE
struct k_mem_domain;

/**
* \brief Drop queued messages sent by user threads of a memory domain.
*
* Messages sent by user threads are queued as kernel copies, found by the
* address of the user message and the memory domain of the sender. Call
* this before a memory domain is reused, so that a message still queued
* from its previous threads is not taken as theirs. Kernel context only.
*
* @param domain The memory domain.
*/
void ipc_user_msg_purge(struct k_mem_domain *domain);
#endif

/**
* \brief Send an IPC message directly for emergency.
* @param msg The IPC message to be freed.
Expand Down
10 changes: 10 additions & 0 deletions src/include/sof/userspace/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,16 @@ sending notifications: modules queue messages from `mod_ipc_msg_init()` with
processing errors with `send_resource_notif()`. DP modules have no access to the other IPC
syscalls or to heap, vregion, DMA, DAI or scheduler syscalls.

A message sent by a user thread is never linked into the kernel send queue. `ipc_msg_send()`
copies its header and payload (at most `CONFIG_SOF_IPC_USER_MSG_MAX_SIZE` bytes) once into
one of `CONFIG_SOF_IPC_USER_MSG_SLOTS` kernel-owned slots and queues the slot. The slot is
found again by the address of the user message and the memory domain of the sender, so
sending a queued message again updates the queued copy, and `ipc_msg_list_remove()` only
removes messages of the caller's own domain. `msg->list` and `msg->callback` of a user
message are not used. With `CONFIG_SOF_USERSPACE_LL`, the send queue, its lock and the IPC
processing task are kept in kernel-only `struct ipc_kstate`, not in the user-writable
`struct ipc`; kernel code accesses them with `ipc_ks()`.

The `zephyr/syscall/*.c` files hold the validators in one place per subsystem; the rows marked
**scattered** keep their `z_vrfy_` next to the kernel logic and are the migration targets.

Expand Down
Loading
Loading