audio: dai-zephyr: enable user-space use of DAI, part 1#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>
|
For context, part of #10558 |
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. |
| 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.
| 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; |
| 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); |
There was a problem hiding this comment.
This is a valid problem, but problem exists in existing code, so I prefer to handle this case in a follow-up PR. If I need to revise this series, I will add a new commit to address this.
UPDATE: actually, this is not a real leak. Only error case where dd->z_config is allocated and non-zero, is the case where dai_set_dma_config() fails. But if that fails, nothing is allocated to dd->z_config->head_block either. So current code in main is safe.
lyakh
left a comment
There was a problem hiding this comment.
Yes, if possible, the kobject should be checked
| dev->ipc_config = *config; | ||
|
|
||
| dd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd)); | ||
| dd = sof_heap_alloc(heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd), 0); |
There was a problem hiding this comment.
I went back and forth between "heap" variable and just putting NULL, but in the end I think this is more readable and makes it explicit same value needs to be passed to alloc and free in this function. Compilation output should be the same in both cases.
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>
9fdefeb to
37702da
Compare
|
V2 pushed:
|
kv2019i
left a comment
There was a problem hiding this comment.
Replied to code review comments. V2 should be ready.
| dev->ipc_config = *config; | ||
|
|
||
| dd = rzalloc(SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd)); | ||
| dd = sof_heap_alloc(heap, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*dd), 0); |
There was a problem hiding this comment.
I went back and forth between "heap" variable and just putting NULL, but in the end I think this is more readable and makes it explicit same value needs to be passed to alloc and free in this function. Compilation output should be the same in both cases.
| 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); |
There was a problem hiding this comment.
This is a valid problem, but problem exists in existing code, so I prefer to handle this case in a follow-up PR. If I need to revise this series, I will add a new commit to address this.
UPDATE: actually, this is not a real leak. Only error case where dd->z_config is allocated and non-zero, is the case where dai_set_dma_config() fails. But if that fails, nothing is allocated to dd->z_config->head_block either. So current code in main is safe.
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