Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
c6af12b
schedule: add a function for finding userspace scherulers
lyakh Aug 18, 2026
6fec37c
schedule: dp: application: clarify privilege level
lyakh Aug 24, 2026
4e9d74b
userspace: simplify preprocessor conditionals
lyakh Aug 24, 2026
fc40ed5
zephyr: lib: make vregion_alloc/free system calls
kv2019i Jun 25, 2026
0893bbf
vregion: extract a common function
lyakh Aug 20, 2026
4ce12b1
vregion: make 3 vregion API functions syscalls
lyakh Jul 7, 2026
6301ff2
vregion: add mapping to vregion creation and freeing
lyakh Jul 6, 2026
713ad12
vregion: remove unneeded declarations
lyakh Aug 27, 2026
0528bd3
vregion: make two functions inline
lyakh Aug 27, 2026
3c4763a
audio: mux: fix a blob size check
lyakh Aug 21, 2026
882b19d
boards: intel: default to user-space LL for ptl and wcl
kv2019i Aug 13, 2026
add5e88
ipc: only add cold partitions if they're non-empty
lyakh May 21, 2026
ff90c9d
audio: pipeline: add a missing header
lyakh May 21, 2026
561eb36
lib-manager: add a syscall to handle LLEXT-related work
lyakh May 22, 2026
2ce1167
ipc: add the DP case to module initialization
lyakh Jul 2, 2026
c9dc2bf
llext: with userspace let LL thread access DP modules too
lyakh Jul 2, 2026
5fdb4de
schedule: dp: use scheduler_get_user_data()
lyakh Aug 20, 2026
cf486ed
schedule: userspace: DP: make scheduler_dp_ll_tick() a syscall
lyakh Jul 7, 2026
8f3e75c
schedule: dp: userspace: make scheduler_dp_internal_free() a syscall
lyakh Jul 7, 2026
54a575f
schedule: ll: enable multicore userspace
lyakh Jun 10, 2026
7645d46
schedule: dp: userspace grant IPC thread rights on DP assets
lyakh Jul 8, 2026
a031e6b
schedule: ll: userspace: grant the LL thread rights on DP
lyakh Jul 8, 2026
aec3b09
ipc: add a comment to explain DP flow
lyakh Jul 9, 2026
888b0e6
ipc: ipc4: extract common code into a function
lyakh Aug 3, 2026
8213252
userspace: perform library loading in kernel context
lyakh Aug 3, 2026
6c5d8f1
schedule: ll: userspace: enable LLEXT
lyakh May 22, 2026
9add191
Revert "boards: intel: default to user-space LL for ptl and wcl"
lyakh Aug 19, 2026
44c6e81
userspace-ll: re-enable DRAM execution and data
lyakh Aug 3, 2026
94ce07a
userspace-ll: re-enable the DP scheduler
lyakh Aug 20, 2026
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
8 changes: 1 addition & 7 deletions app/overlays/ptl/ll_userspace_overlay.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,23 @@ CONFIG_SOF_USERSPACE_LL=y
# make the drivers work in user-space
CONFIG_SOF_USERSPACE_INTERFACE_DMA=y
CONFIG_DAI_USERSPACE=y
CONFIG_MAX_THREAD_BYTES=4

# Temporary settings that are needed currently to enable user-space LL
# --------------------------------------------------------------------

# problem with DSP panics due to illegal instruction hit in user-space if cold
# store execution is enabled. Disable it for now until rootcause is found.
CONFIG_COLD_STORE_EXECUTE_DRAM=n
CONFIG_COLD_STORE_EXECUTE_DEBUG=n

# telemetry not yet user-space compatible
CONFIG_SOF_TELEMETRY_PERFORMANCE_MEASUREMENTS=n
CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=n

# disable loadable modules (hits privilege issues in user-space now)
CONFIG_LLEXT_STORAGE_WRITABLE=n
CONFIG_LLEXT_EXPERIMENTAL=n
CONFIG_MODULES=n

# some of current boot tests interfere with user-space setup
CONFIG_SOF_BOOT_TEST_ALLOWED=n

# misc features not yet compatible with user-space
CONFIG_CROSS_CORE_STREAM=n
CONFIG_INTEL_ADSP_MIC_PRIVACY=n
CONFIG_XRUN_NOTIFICATIONS_ENABLE=n
CONFIG_ZEPHYR_DP_SCHEDULER=n
2 changes: 1 addition & 1 deletion src/audio/buffers/comp_buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ static void comp_buffer_free(struct sof_audio_buffer *audio_buffer)
if (alloc && alloc->vreg) {
vregion_free(alloc->vreg, buffer);
if (!vregion_put(alloc->vreg))
rfree(alloc);
sof_heap_free(alloc->heap, alloc);
} else {
sof_heap_free(alloc ? alloc->heap : NULL, buffer);
}
Expand Down
22 changes: 9 additions & 13 deletions src/audio/module_adapter/module_adapter.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,6 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv,
return module_adapter_new_ext(drv, config, spec, NULL, NULL, NULL);
}

static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config,
size_t *heap_size)
{
/* src-lite with 8 channels has been seen allocating 14k in one go */
/* FIXME: the size will be derived from configuration */
const size_t buf_size = 28 * 1024;

return vregion_create(buf_size);
}

static struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv,
const struct comp_ipc_config *config)
{
Expand All @@ -77,11 +67,15 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
*/
uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ?
SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER;
size_t heap_size;
size_t vreg_size;
uintptr_t vreg_start;

if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) &&
IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) {
mod_vreg = module_adapter_dp_heap_new(config, &heap_size);
/* src-lite with 8 channels has been seen allocating 14k in one go */
/* FIXME: the size will be derived from configuration */
vreg_size = 28 * 1024;
mod_vreg = vregion_create_map(&vreg_start, &vreg_size);
if (!mod_vreg) {
comp_cl_err(drv, "Failed to allocate DP module heap / vregion");
return NULL;
Expand All @@ -98,7 +92,8 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv
#else
mod_heap = drv->user_heap;
#endif
heap_size = 0;
vreg_size = 0;
vreg_start = 0;
mod_vreg = NULL;
}

Expand Down Expand Up @@ -199,6 +194,7 @@ static void module_adapter_mem_free(struct processing_module *mod)
*
* Note: Use the ext version if you need to set the module's private data before calling
* the create method.
* Note 2: ATM runs in privileged / kernel mode for DP modules
*/
struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv,
const struct comp_ipc_config *config,
Expand Down
2 changes: 1 addition & 1 deletion src/audio/mux/mux_ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ int mux_params(struct processing_module *mod)
int ret;

cfg = comp_get_data_blob(cd->model_handler, &blob_size, NULL);
if (!cfg || blob_size > MUX_BLOB_MAX_SIZE) {
if (!cfg || blob_size != sizeof(*cfg)) {
comp_err(mod->dev, "illegal blob size %zu", blob_size);
return -EINVAL;
}
Expand Down
1 change: 1 addition & 0 deletions src/audio/pipeline/pipeline-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <sof/lib/uuid.h>
#include <sof/compiler_attributes.h>
#include <sof/list.h>
#include <sof/schedule/ll_schedule_domain.h>
#include <rtos/spinlock.h>
#include <rtos/string.h>
#include <rtos/clk.h>
Expand Down
8 changes: 8 additions & 0 deletions src/include/ipc4/handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ struct ipc4_message_request;
*/
int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, struct ipc_msg *reply);

/**
* \brief Load a dynamically loadable module.
* @param[in] drv Component driver.
* @param[in] mi SOF_IPC4_MOD_INIT_INSTANCE data
*/
int ipc4_user_module_load(const struct comp_driver *drv,
const struct ipc4_module_init_instance *mi);

/**
* @brief Process MOD_CONFIG_GET or MOD_CONFIG_SET in any execution context.
* @param[in] ipc4 IPC4 message request.
Expand Down
22 changes: 18 additions & 4 deletions src/include/sof/ipc/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,9 @@ extern struct tr_ctx ipc_tr;
#define IPC_TASK_POWERDOWN BIT(3)

struct ipc_user {
struct k_thread *thread;
struct k_thread *thread[CONFIG_CORE_COUNT];
struct k_sem *sem;
struct k_event *event;
struct k_event *event[CONFIG_CORE_COUNT];
/** @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 */
Expand All @@ -73,9 +73,10 @@ struct ipc_user {
/** @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;
struct k_thread *audio_thread[CONFIG_CORE_COUNT];
/** @brief Original kernel driver pointer for restoring dev->drv after create */
const struct comp_driver *init_drv;
bool init_needed[CONFIG_CORE_COUNT];
/**
* @brief User-accessible copy of comp_driver + tr_ctx for create().
*
Expand Down Expand Up @@ -326,7 +327,7 @@ extern bool ipc_enter_gdb;
* @param extension Extension message word
* @return Result code from user thread processing
*/
int ipc_user_forward_cmd(uint32_t primary, uint32_t extension);
int ipc_user_forward_cmd(uint32_t primary, uint32_t extension, unsigned int core);

/**
* @brief Protocol-specific dispatch of a forwarded IPC command.
Expand All @@ -338,6 +339,19 @@ int ipc_user_forward_cmd(uint32_t primary, uint32_t extension);
* @return Result code to report back to the host
*/
int ipc_user_thread_dispatch(struct ipc_user *ipc_user);

/**
* @brief Initialize IPC and LL scheduler threads on a booting secondary core.
*
* @param core Secondary core ID
* @return 0 or a negative error code
*/
int ipc_user_init_secondary(unsigned int core);
#endif

/**
* \brief get pointer to the userspace IPC thread for core
*/
struct k_thread *ipc_thread_user(unsigned int core);

#endif /* __SOF_DRIVERS_IPC_H__ */
56 changes: 40 additions & 16 deletions src/include/sof/lib/vregion.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#define __SOF_LIB_VREGION_H__

#include <stddef.h>
#include <stdint.h>
#include <sof/compiler_attributes.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -40,6 +42,13 @@ enum vregion_mem_type {
*/
struct vregion *vregion_create(size_t memsize);

/**
* @brief Create and map a new virtual region instance.
*
* Like above, but usable by userspace and can add domain access.
*/
__syscall struct vregion *vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size);

/**
* @brief Switch virtual region allocations to interim mode.
*
Expand All @@ -49,7 +58,7 @@ struct vregion *vregion_create(size_t memsize);
*
* @param[in] vr Pointer to the virtual region instance.
*/
void vregion_set_interim(struct vregion *vr);
__syscall void vregion_set_interim(struct vregion *vr);

/**
* @brief Increment virtual region's user count.
Expand All @@ -60,7 +69,7 @@ void vregion_set_interim(struct vregion *vr);
* @param[in] vr Pointer to the virtual region instance to release.
* @return struct vregion* Pointer to the virtual region instance.
*/
struct vregion *vregion_get(struct vregion *vr);
__syscall struct vregion *vregion_get(struct vregion *vr);

/**
* @brief Decrement virtual region's user count or destroy it.
Expand All @@ -71,39 +80,45 @@ struct vregion *vregion_get(struct vregion *vr);
* @param[in] vr Pointer to the virtual region instance to release.
* @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed.
*/
struct vregion *vregion_put(struct vregion *vr);
__syscall struct vregion *vregion_put(struct vregion *vr);

/**
* @brief Allocate memory from the specified virtual region.
* @brief Allocate aligned memory from the specified virtual region.
*
* Allocate aligned memory from the specified virtual region using the
* current allocation mode (lifetime or interim).
*
* @param[in] vr Pointer to the virtual region instance.
* @param[in] size Size of memory to allocate in bytes.
* @param[in] alignment Alignment of memory to allocate in bytes.
* @return void* Pointer to the allocated memory, or NULL on failure.
*/
void *vregion_alloc(struct vregion *vr, size_t size);
__syscall void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment);

/**
* @brief like vregion_alloc() but allocates coherent memory
* @brief like vregion_alloc_align() but allocates coherent memory
*/
void *vregion_alloc_coherent(struct vregion *vr, size_t size);
__syscall void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment);

/**
* @brief Allocate aligned memory from the specified virtual region.
*
* Allocate aligned memory from the specified virtual region using the
* current allocation mode (lifetime or interim).
* @brief Allocate memory from the specified virtual region.
*
* @param[in] vr Pointer to the virtual region instance.
* @param[in] size Size of memory to allocate in bytes.
* @param[in] alignment Alignment of memory to allocate in bytes.
* @return void* Pointer to the allocated memory, or NULL on failure.
*/
void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment);
static inline void *vregion_alloc(struct vregion *vr, size_t size)
{
return vregion_alloc_align(vr, size, 0);
}

/**
* @brief like vregion_alloc_align() but allocates coherent memory
* @brief like vregion_alloc() but allocates coherent memory
*/
void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment);
static inline void *vregion_alloc_coherent(struct vregion *vr, size_t size)
{
return vregion_alloc_coherent_align(vr, size, 0);
}

/**
* @brief Free memory allocated from the specified virtual region.
Expand All @@ -113,7 +128,7 @@ void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t align
* @param[in] vr Pointer to the virtual region instance.
* @param[in] ptr Pointer to the memory to free.
*/
void vregion_free(struct vregion *vr, void *ptr);
__syscall void vregion_free(struct vregion *vr, void *ptr);

/**
* @brief Log virtual region memory usage.
Expand All @@ -131,6 +146,10 @@ void vregion_info(struct vregion *vr);
*/
void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start);

bool vregion_verify(struct vregion *vr);

#include <zephyr/syscalls/vregion.h>

#else /* CONFIG_SOF_VREGIONS */

struct vregion {
Expand All @@ -141,6 +160,10 @@ static inline struct vregion *vregion_create(size_t memsize)
{
return NULL;
}
static inline struct vregion *vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size)
{
return NULL;
}
static inline void vregion_set_interim(struct vregion *vr) {}
static inline struct vregion *vregion_get(struct vregion *vr)
{
Expand Down Expand Up @@ -174,6 +197,7 @@ static inline void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t
if (size)
*size = 0;
}
static inline bool vregion_verify(struct vregion *vr) {return false;}

#endif /* CONFIG_SOF_VREGIONS */

Expand Down
19 changes: 19 additions & 0 deletions src/include/sof/lib_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,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
7 changes: 6 additions & 1 deletion src/include/sof/schedule/dp_schedule.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,12 @@ int scheduler_dp_task_init(struct task **task,
uint16_t core,
size_t stack_size,
uint32_t options);
void scheduler_dp_ll_tick(void);

#if defined(__ZEPHYR__) && CONFIG_SOF_FULL_ZEPHYR_APPLICATION
__syscall void scheduler_dp_internal_free(struct task *task);
__syscall void scheduler_dp_ll_tick(unsigned int core);
#include <zephyr/syscalls/dp_schedule.h>
#endif

/**
* \brief Extract information about scheduler's tasks
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 @@ -330,6 +330,7 @@ struct ll_schedule_domain *zephyr_domain_init(int clk);
struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain);
struct k_thread *zephyr_domain_thread_tid_for_core(int core);
struct k_mem_domain *zephyr_ll_mem_domain(void);
struct k_thread *zephyr_ll_domain_thread(void);
#endif /* CONFIG_SOF_USERSPACE_LL */
#ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION
__syscall int zephyr_ll_task_sem_alloc(struct task *task);
Expand Down
Loading
Loading