Skip to content

[DRAFT] userspace LL/audio test PR#10558

Draft
kv2019i wants to merge 35 commits intothesofproject:mainfrom
kv2019i:feat/userspace-ll-wip
Draft

[DRAFT] userspace LL/audio test PR#10558
kv2019i wants to merge 35 commits intothesofproject:mainfrom
kv2019i:feat/userspace-ll-wip

Conversation

@kv2019i
Copy link
Collaborator

@kv2019i kv2019i commented Feb 19, 2026

SOF has recently gained ability to run DP (=preemptable audio tasks) in Zephyr user-space.

This PR is an early stage pull-request for changes to extend this capability to all of the audio pipeline code, and specifically the LL (low-latency) tasks.

This early stage as the design is not set in stone and the PR uses a number of short cuts in order to move (and tests) incrementally larger sets of audio functionality.

If CONFIG_SOF_BOOT_TEST_STANDALONE is set, ipc_init() is terminated
early. This ensures SOF will not start to generate or respond
to IPC messages that could potentially interfere with standalone
test cases (some of which send and receive IPCs).

The current implementation leaves the component list uninitialized
and this can cause trouble to standalone tests that want to utilzie
common IPC code to build messages.

Fix this problem by executing more of ipc_init() also in the standalone
mode.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add a method to add access to a component object to a particular
thread. This is required as component object state includes kernel
objects and to use these from user-space, access needs to be granted.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
In userspace LL builds, use a mutex to protect component
connections. This code shoudl work for kernel builds, but at least
now add new code under a ifdef to avoid the cost of additional
mutex object.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add a built option to make sof_heap_allo/free available as
system calls to user-space.

Add a test case for the functions that runs in a user-space thread.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Separate the state for LL scheduler memory into kernel and user
accessible resources. The pointer to the LL heap must be accessible
from user-space, so that user space can allocate memory and pass
the heap pointer as argument.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Turn the pdata->sem into a dynamic object in userspace LL builds.
Keep statically allocated semaphore for kernel LL builds.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Move the user-accessible heap pointer to common partition defined
in userspace_helper.h.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add a heap parameter to DMA scatter-gather allocation interface. This
makes it possible to control how allocations are done for the DMA
buffers.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Continue the work in commit 9567234 ("buffer: allocate on specific
heap") and add ability to specify the heap to all buffer interface
functions.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Allow a non-null pointer at the end of the DMA transfer block list,
if and only if it points to the first entry in the block list.

The SOF DAI module sets the DMA transfers blocks like this and
this change is required to use DAI module from user-space.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The platform data descriptions need to be accessible to all threads.
These are e.g. used when setting up host/DAI copiers and they need
platform DMA properties.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Use separate heaps depending whether host copier is run in user
or kernel space.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
For historical reasons, host-zephyr has somewhat complicated code to
manage the DMA channel instance information. When a DMA channel is allocated,
a pointer to the system DMA channel table is acquired and some additional
information is stored per channel. This is however redundant as the only
piece of information actually needed is the channel index.

Simplify the code by not storing the channel pointer anymore, but
rather just store the channel index and use that in all calls to the
DMA driver.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Make sure we use the same heap to allocate DMA SG buffers as
we use for other component resources.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
These interfaces are no longer used anywhere, so they can be
safely removed.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Force to use user-space LL heap in host_common_new() if
CONFIG_SOF_USERSPACE_LL is set.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Ensure component heap is correctly passed whenever memory
is allocated in the component. This allows to run the component
both in kernel and user space.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The pcm_converter depends on a set of global function tables to set up
correct conversion functions. These objects need to be made available to
user-space threads, so that pcm_converter can be also run in user-space.
No impact to kernel-space use of pcm_converter.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The notifier feature is not available when running in user-space,
so disable the notify calls in comp_buffer_free() in these builds.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Convert all memory allocations to use the sof_heap_alloc() interface
and pass the dai_data specific heap object. This makes dai-zephyr
code compatible with use from user-space, but does not effect
kernel space use.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The dai_get()/dai_put() provide a helper to access DAI devices.
When used in user-space, the wrapper struct should be created in
user-space memory.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
For historical reasons, dai-zephyr has somewhat complicated code to
manage the DMA channel instance information. When a DMA channel is
allocated, a pointer to the system DMA channel table is acquired and
some additional information is stored per channel. This is however
redundant as the only piece of information actually needed is the
channel index.

Simplify the code by not storing the channel pointer anymore, but rather
just store the channel index and use that in all calls to the DMA
driver.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The spinlock used to protect access to DAI properties can be
converted to a mutex as this is only accessed from IPC and LL threads
and both are normal Zephyr threads. As an additional benefit, use
of mutex allows to run the dai-zephyr module in user-space.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Modify code to allocate DAI properties object on stack and
use dai_get_properties_copy(). This is required when DAI code
is run in user-space and a syscall is needed to talk to the DAI
driver. It's not possible to return a pointer to kernel memory,
so instead data needs to be copied to caller stack.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Add a new test to userspace_ll set that takes a step towards
running full audio pipelines in user-space. The test creates a pipeline
with two components (IPC4 host and DAI copiers), does pipeline
prepare, one copy cycle in prepared state and tears down the pipeline.

One user-space thread is created to manage the pipelines. This would
be equivalent to user IPC handler thread. Another user-space thread
is created for the LL scheduler.

This test has some limitation, but is a useful test point to
test resource allocations in pipeline, component and module adapter
code. The code adds a reference test case where the same flow is fully
run in kernel space.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The logic in comp_buffer_free() to check the module heap reference
count, and if it goes to zero, free the heap itself - this does
not belong in the buffer free method.

TODO: needs cleanup before submission.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
When SOF is built with LL pipes in user-space, module adapter should
allocate all resources from the LL user heap.

Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
This is temporary and not needed anymore when DAI is also
created in user-space.
@kv2019i
Copy link
Collaborator Author

kv2019i commented Feb 19, 2026

Running the pipeline_two_components_user test added in this PR, on a Intel PTL, looks like this:

START - pipeline_two_components_user
[    0.000163] <inf> sof_boot_test: pipeline_two_components: copier module_id = 3
[    0.000163] <inf> sof_boot_test: pipeline_two_components: running test with user memory domain
[    0.000163] <inf> pipe: pipeline_new: pipeline new pipe_id 2 priority 0
[    0.000163] <dbg> ipc: ipc4_get_drv: found type 22, uuid 0xa00bc350U
[    0.000163] <dbg> module_adapter: module_adapter_new_ext: start
[    0.000163] <dbg> module_adapter: module_adapter_mem_alloc: using ll user heap for module
[    0.000165] <dbg> module_adapter: module_init: comp:2 0x3 entry
[    0.000165] <dbg> dma: z_impl_sof_dma_get: dma_get(), dma-probe id = 0
[    0.000165] <inf> dma: z_impl_sof_dma_get: dma_get() ID 0 sref = 1 busy channels 0
[    0.000165] <dbg> module_adapter: module_init: comp:2 0x3 done
[    0.000165] <dbg> module_adapter: module_adapter_new_ext: comp:2 0x3 done
[    0.000165] <dbg> ipc: ipc4_add_comp_dev: add comp 0x3
[    0.000165] <dbg> ll_schedule: zephyr_domain_thread_tid: entry
[    0.000165] <dbg> component: comp_grant_access_to_thread: grant access to mutex 0x400bf798 for thread 0x400bf6c0
[    0.000165] <dbg> component: comp_grant_access_to_thread: grant access to mutex 0x400bf798 for thread 0x401894e0
[    0.000165] <inf> sof_boot_test: pipeline_two_components: host copier created, comp_id = 0x3
[    0.000165] <dbg> ipc: ipc4_get_drv: found type 22, uuid 0xa00bc350U
[    0.000165] <dbg> module_adapter: module_adapter_new_ext: start
[    0.000165] <dbg> module_adapter: module_adapter_mem_alloc: using ll user heap for module
[    0.000165] <dbg> module_adapter: module_init: comp:2 0x10003 entry
[    0.000165] <inf> copier: copier_dai_init: comp:2 0x10003 dd 0x4019d280 initialized, index -1
[    0.000165] <dbg> dma: z_impl_sof_dma_get: dma_get(), dma-probe id = 0
[    0.000165] <inf> dma: z_impl_sof_dma_get: dma_get() ID 0 sref = 1 busy channels 0
[    0.000165] <inf> ipc: dai_config: comp:2 0x10003 dai type = 3 index = 0 dd 0x4019d280
[    0.000165] <dbg> ipc: dai_config: comp:2 0x10003 Alloc dai_spec_config 0xa019d480 size size 84
[    0.000165] <dbg> module_adapter: module_init: comp:2 0x10003 done
[    0.000165] <dbg> module_adapter: module_adapter_new_ext: comp:2 0x10003 done
[    0.000165] <dbg> ipc: ipc4_add_comp_dev: add comp 0x10003
[    0.000165] <dbg> ll_schedule: zephyr_domain_thread_tid: entry
[    0.000165] <dbg> component: comp_grant_access_to_thread: grant access to mutex 0x400bf7e0 for thread 0x400bf6c0
[    0.000165] <dbg> component: comp_grant_access_to_thread: grant access to mutex 0x400bf7e0 for thread 0x401894e0
[    0.000165] <inf> sof_boot_test: pipeline_two_components: DAI copier created, comp_id = 0x10003
[    0.000166] <dbg> buffer: buffer_alloc: buffer_alloc()
[    0.000166] <dbg> buffer: buffer_alloc_struct: buffer_alloc_struct()
[    0.000166] <dbg> userspace_helper: user_grant_dai_access_all: Granted DAI access to thread 0x401894e0 for 45 devices
[    0.000166] <dbg> userspace_helper: user_grant_dma_access_all: Granted DMA device access: dma@72c00 to thread 0x401894e0
[    0.000166] <dbg> userspace_helper: user_grant_dma_access_all: Granted DMA device access: dma@72800 to thread 0x401894e0
[    0.000166] <dbg> userspace_helper: user_grant_dma_access_all: Granted DMA device access: dma@79800 to thread 0x401894e0
[    0.000166] <dbg> userspace_helper: user_grant_dma_access_all: Granted DMA device access: dma@79400 to thread 0x401894e0
[    0.000166] <inf> sof_boot_test: pipeline_two_components: user thread started, waiting for completion
[    0.000170] <dbg> pipe: pipeline_reset: pipe:2 0x3 pipe reset
[    0.000170] <dbg> pipe: pipeline_comp_reset: pipe:2 0x3 current->comp.id = 0x3, dir = 0
[    0.000170] <dbg> module_adapter: module_adapter_reset: comp:2 0x3 resetting
[    0.000170] <dbg> copier: copier_reset: comp:2 0x3 entry
[    0.000170] <dbg> buffer: comp_buffer_free: buf:0 0x0 buffer_free()
[    0.000170] <dbg> module_adapter: module_adapter_reset: comp:2 0x3 done
[    0.000170] <dbg> pipe: pipeline_comp_reset: pipe:2 0x3 current->comp.id = 0x10003, dir = 0
[    0.000170] <dbg> module_adapter: module_adapter_reset: comp:2 0x10003 resetting
[    0.000170] <dbg> copier: copier_reset: comp:2 0x10003 entry
[    0.000170] <dbg> buffer: comp_buffer_free: buf:0 0x0 buffer_free()
[    0.000170] <dbg> module_adapter: module_adapter_reset: comp:2 0x10003 done
[    0.000170] <dbg> pipe: pipeline_disconnect: comp:2 0x3 disconnect buffer 0 as sink
[    0.000170] <dbg> pipe: pipeline_disconnect: comp:2 0x10003 disconnect buffer 0 as source
[    0.000170] <dbg> buffer: comp_buffer_free: buf:0 0x0 buffer_free()
[    0.000170] <dbg> buffer: comp_buffer_free: buf:0 0x0 buffer_free()
[    0.000170] <dbg> module_adapter: module_adapter_reset: comp:2 0x10003 done
[    0.000170] <dbg> pipe: pipeline_disconnect: comp:2 0x3 disconnect buffer 0 as sink
[    0.000170] <dbg> pipe: pipeline_disconnect: comp:2 0x10003 disconnect buffer 0 as source
[    0.000170] <dbg> buffer: comp_buffer_free: buf:0 0x0 buffer_free()
[    0.000170] <dbg> module_adapter: module_adapter_free: comp:2 0x3 start
[    0.000170] <inf> dma: z_impl_sof_dma_put: dma_put(), dma = 0x400c8488, sref = 0
[    0.000170] <dbg> module_adapter: module_adapter_free: comp:2 0x10003 start
[    0.000170] <inf> dma: z_impl_sof_dma_put: dma_put(), dma = 0x400c8518, sref = 0
[    0.000170] <dbg> pipe: pipeline_free: pipe:2 0x3 entry
[    0.000170] <inf> sof_boot_test: pipeline_two_components: two component pipeline test complete
 PASS - pipeline_two_components_user in 0.023 seconds

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments