audio: dai-zephyr: enable user-space use of DAI #10801
Conversation
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 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>
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>
The Zephyr locking interfaces do not have a variant that allows the lock object to be put in dynamically allocated user-space memory. Implement a variant on top of Zephyr k_mutex that provides this support for SOF. Provide a no-op wrapper for POSIX library builds (just like we do for other locking interfaces). Kconfig option SOF_USERSPACE_INTERFACE_MUTEX is added to control whether umutex.h is exposed to user-space or not. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
The spinlock used to protect access to DAI properties can be converted to a sof_umutex as this is only accessed from IPC and LL threads and both are normal Zephyr threads. As an additional benefit, use of sof_umutex allows to run the dai-zephyr module in user-space. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Reorder redefinitions to ensure "struct mod_alloc_ctx" is defined before lib/dai.h is included. 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 affect kernel space use. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
|
For context, part of #10558 |
| depends on USERSPACE | ||
| help | ||
| Allow user-space threads to use sof_heap_alloc/sof_heap_free | ||
| as Zephyr system calls. |
There was a problem hiding this comment.
Oops, this ALLOC is a stray commit, will remove in V2.
| ) | ||
| if(CONFIG_USERSPACE AND CONFIG_SOF_USERSPACE_INTERFACE_ALLOC) | ||
| zephyr_library_sources(userspace/test_heap_alloc.c) | ||
| endif() |
There was a problem hiding this comment.
And another stray bit for test_heap_alloc.c. Will remove in V2.
There was a problem hiding this comment.
Pull request overview
This PR enables the dai-zephyr component (and related infrastructure) to be usable from Zephyr user-space threads by introducing a user-space mutex abstraction, updating syscall verification, and adjusting allocations to work with user-space heaps/memory domains.
Changes:
- Add
sof_umutexAPI (Zephyr + POSIX) with syscall plumbing and a user-space test. - Update dai-zephyr to use
sof_umutexfor property protection and to use heap-aware allocation/free paths. - Update the SOF DMA syscall deep-copy logic to support cyclic (looping) SG block lists.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| zephyr/test/userspace/test_umutex.c | Adds a user-space thread test for sof_umutex init/lock/unlock/free. |
| zephyr/test/CMakeLists.txt | Wires new user-space tests into the Zephyr test build. |
| zephyr/syscall/umutex.c | Adds syscall verification handlers for sof_umutex_*. |
| zephyr/syscall/sof_dma.c | Extends DMA block list deep-copy to allow looping SG lists. |
| zephyr/lib/umutex.c | Implements kernel-side sof_umutex using dynamically allocated k_mutex. |
| zephyr/Kconfig | Introduces Kconfig switches for userspace alloc + mutex interfaces and selects mutex for userspace LL. |
| zephyr/include/rtos/umutex.h | Declares the sof_umutex API and syscall wrappers. |
| zephyr/include/rtos/mutex.h | Exposes sof_umutex via the RTOS mutex umbrella header. |
| zephyr/CMakeLists.txt | Adds umutex implementation and syscall sources/headers to the Zephyr build. |
| src/lib/dai.c | Updates dai_get()/dai_put() allocation/free to use sof_heap_alloc/free (userspace LL aware). |
| src/ipc/ipc4/dai.c | Uses heap-aware allocation/free for dd->dai_spec_config. |
| src/include/sof/lib/dai-zephyr.h | Switches DAI property lock to sof_umutex and adds mod_alloc_ctx to dai_data. |
| src/include/sof/audio/component.h | Moves mod_alloc_ctx definition earlier to satisfy DAI header needs. |
| src/audio/dai-zephyr.c | Replaces spinlock-based property protection with sof_umutex and updates multiple allocations to use alloc_ctx.heap. |
| posix/include/rtos/umutex.h | Adds POSIX header wrapper for sof_umutex. |
| posix/include/rtos/mutex.h | Adds a POSIX stub implementation of sof_umutex. |
| if(CONFIG_USERSPACE AND CONFIG_SOF_USERSPACE_INTERFACE_ALLOC) | ||
| zephyr_library_sources(userspace/test_heap_alloc.c) | ||
| endif() |
| static inline int z_vrfy_sof_umutex_lock(struct sof_umutex *umutex, | ||
| k_timeout_t timeout) | ||
| { | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE(umutex, sizeof(struct sof_umutex))); | ||
| return z_impl_sof_umutex_lock(umutex, timeout); | ||
| } | ||
| #include <zephyr/syscalls/sof_umutex_lock_mrsh.c> | ||
|
|
||
| static inline int z_vrfy_sof_umutex_unlock(struct sof_umutex *umutex) | ||
| { | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE(umutex, sizeof(struct sof_umutex))); | ||
| return z_impl_sof_umutex_unlock(umutex); | ||
| } | ||
| #include <zephyr/syscalls/sof_umutex_unlock_mrsh.c> | ||
|
|
||
| static inline void z_vrfy_sof_umutex_free(struct sof_umutex *umutex) | ||
| { | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE(umutex, sizeof(struct sof_umutex))); | ||
| z_impl_sof_umutex_free(umutex); |
There was a problem hiding this comment.
This is a valid concern. The verification is similar to zephyr sys_mutex() but it has additional step to look up the k_object() that is not here. Let me mark as draft to ensure this is addressed before merge.
| K_OOPS(K_SYSCALL_MEMORY_WRITE(umutex, sizeof(struct sof_umutex))); | ||
| return z_impl_sof_umutex_lock(umutex, timeout); | ||
| } | ||
| #include <zephyr/syscalls/sof_umutex_lock_mrsh.c> | ||
|
|
||
| static inline int z_vrfy_sof_umutex_unlock(struct sof_umutex *umutex) | ||
| { | ||
| K_OOPS(K_SYSCALL_MEMORY_WRITE(umutex, sizeof(struct sof_umutex))); |
| int z_impl_sof_umutex_init(struct sof_umutex *umutex) | ||
| { | ||
| struct k_mutex *m; | ||
| int ret; | ||
|
|
||
| m = k_object_alloc(K_OBJ_MUTEX); | ||
| if (m == NULL) { | ||
| return -ENOMEM; | ||
| } | ||
|
|
||
| ret = k_mutex_init(m); | ||
| if (ret) { | ||
| k_object_free(m); | ||
| return ret; | ||
| } | ||
|
|
||
| umutex->mutex = m; | ||
| return 0; |
| /* called from ipc/ipc3/dai.c */ | ||
| int dai_get_handshake(struct dai *dai, int direction, int stream_id) | ||
| { | ||
| k_spinlock_key_t key = k_spin_lock(&dai->lock); | ||
| const struct dai_properties *props = dai_get_properties(dai->dev, direction, | ||
| stream_id); | ||
| int hs_id = props->dma_hs_id; | ||
| struct dai_properties props; | ||
| int ret; | ||
|
|
||
| k_spin_unlock(&dai->lock, key); | ||
| sof_umutex_lock(&dai->lock, K_FOREVER); | ||
| ret = dai_get_properties_copy(dai->dev, direction, stream_id, &props); | ||
| sof_umutex_unlock(&dai->lock); | ||
| if (ret < 0) |
| dd->dma_buffer = NULL; | ||
| dma_sg_free(NULL, &config->elem_array); | ||
| rfree(dd->z_config); | ||
| dma_sg_free(dd->alloc_ctx.heap, &config->elem_array); |
A series of of patches to enable dai-zephyr component to be used in user-space. This includes:
Similar changes to host-zephyr are in #10799