From cffaeae2c651bd0d96b9d5b6ab924900b51d841b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 5 Feb 2026 19:39:54 +0200 Subject: [PATCH 1/4] dai: add functionality to grant access to DAI devices Add helper functions to provide a list of all Zephyr devices and to grant a user thread access to them. Signed-off-by: Kai Vehmanen --- src/include/sof/lib/dai-zephyr.h | 7 +++++++ src/lib/dai.c | 8 ++++++++ zephyr/include/rtos/userspace_helper.h | 7 +++++++ zephyr/lib/userspace_helper.c | 18 ++++++++++++++++++ 4 files changed, 40 insertions(+) diff --git a/src/include/sof/lib/dai-zephyr.h b/src/include/sof/lib/dai-zephyr.h index 5a15399190ee..049adba4a656 100644 --- a/src/include/sof/lib/dai-zephyr.h +++ b/src/include/sof/lib/dai-zephyr.h @@ -306,6 +306,13 @@ void dai_release_llp_slot(struct dai_data *dd); * \brief Retrieve a pointer to the Zephyr device structure for a DAI of a given type and index. */ const struct device *dai_get_device(uint32_t type, uint32_t index); + +/** + * \brief Retrieve the list of all DAI devices. + * \param count Pointer to store the number of devices in the list. + * \return Pointer to the array of device pointers. + */ +const struct device **dai_get_device_list(size_t *count); /** @}*/ #endif /* __SOF_LIB_DAI_ZEPHYR_H__ */ diff --git a/src/lib/dai.c b/src/lib/dai.c index 0c11d25f9732..2b2d5707a84a 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -187,6 +187,14 @@ const struct device *zephyr_dev[] = { #endif }; +const struct device **dai_get_device_list(size_t *count) +{ + if (count) + *count = ARRAY_SIZE(zephyr_dev); + + return zephyr_dev; +} + /* convert sof_ipc_dai_type to Zephyr dai_type */ static int sof_dai_type_to_zephyr(uint32_t type) { diff --git a/zephyr/include/rtos/userspace_helper.h b/zephyr/include/rtos/userspace_helper.h index 30326946eda5..c19479a3a48e 100644 --- a/zephyr/include/rtos/userspace_helper.h +++ b/zephyr/include/rtos/userspace_helper.h @@ -113,6 +113,13 @@ void module_driver_heap_remove(struct k_heap *mod_drv_heap); */ int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id); +/** + * Grant DAI device access to a user-space thread. + * + * @param thread user-space thread for which DAI access is granted + */ +void user_grant_dai_access_all(struct k_thread *thread); + #else static inline int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) diff --git a/zephyr/lib/userspace_helper.c b/zephyr/lib/userspace_helper.c index 22b4aa0e139a..e6703e089d7c 100644 --- a/zephyr/lib/userspace_helper.c +++ b/zephyr/lib/userspace_helper.c @@ -19,12 +19,16 @@ #include #include #include +#include #define MODULE_DRIVER_HEAP_CACHED CONFIG_SOF_ZEPHYR_HEAP_CACHED /* Zephyr includes */ #include #include +#include + +LOG_MODULE_REGISTER(userspace_helper, CONFIG_SOF_LOG_LEVEL); #if CONFIG_USERSPACE @@ -128,6 +132,20 @@ int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) return 0; } +void user_grant_dai_access_all(struct k_thread *thread) +{ + const struct device **devices; + size_t count; + size_t i; + + devices = dai_get_device_list(&count); + + for (i = 0; i < count; i++) + k_thread_access_grant(thread, devices[i]); + + LOG_DBG("Granted DAI access to thread %p for %zu devices", thread, count); +} + #else /* CONFIG_USERSPACE */ void *user_stack_allocate(size_t stack_size, uint32_t options) From b36268a48ee088cca5d5c4a3c1392bfdd2fa0029 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 9 Feb 2026 15:14:55 +0200 Subject: [PATCH 2/4] dma: add functionality to grant access to DMA devices Add helper functions to provide a list of all Zephyr DMA devices and to grant a user thread access to them. Signed-off-by: Kai Vehmanen --- zephyr/include/rtos/userspace_helper.h | 7 +++++++ zephyr/include/sof/lib/dma.h | 7 +++++++ zephyr/lib/dma.c | 14 ++++++++++++++ zephyr/lib/userspace_helper.c | 16 ++++++++++++++++ 4 files changed, 44 insertions(+) diff --git a/zephyr/include/rtos/userspace_helper.h b/zephyr/include/rtos/userspace_helper.h index c19479a3a48e..64460b791aa6 100644 --- a/zephyr/include/rtos/userspace_helper.h +++ b/zephyr/include/rtos/userspace_helper.h @@ -120,6 +120,13 @@ int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id); */ void user_grant_dai_access_all(struct k_thread *thread); +/** + * Grant DMA device access to a user-space thread. + * + * @param thread user-space thread for which DMA access is granted + */ +void user_grant_dma_access_all(struct k_thread *thread); + #else static inline int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) diff --git a/zephyr/include/sof/lib/dma.h b/zephyr/include/sof/lib/dma.h index b13f3c25221b..dbec5f88b1f9 100644 --- a/zephyr/include/sof/lib/dma.h +++ b/zephyr/include/sof/lib/dma.h @@ -343,6 +343,13 @@ static inline const struct dma_info *dma_info_get(void) return sof_get()->dma_info; } +/** + * \brief Retrieve the list of all DMA devices. + * \param count Pointer to store the number of devices in the list. + * \return Pointer to the array of device pointers. + */ +const struct device **dma_get_device_list(size_t *count); + /** @}*/ #endif /* __SOF_LIB_DMA_H__ */ diff --git a/zephyr/lib/dma.c b/zephyr/lib/dma.c index 7452459f8b0a..bb7edacfa674 100644 --- a/zephyr/lib/dma.c +++ b/zephyr/lib/dma.c @@ -219,6 +219,20 @@ const struct dma_info lib_dma = { .num_dmas = ARRAY_SIZE(dma) }; +const struct device **dma_get_device_list(size_t *count) +{ + static const struct device *device_list[ARRAY_SIZE(dma)]; + int i; + + if (count) + *count = ARRAY_SIZE(dma); + + for (i = 0; i < ARRAY_SIZE(dma); i++) + device_list[i] = dma[i].z_dev; + + return device_list; +} + /* Initialize all platform DMAC's */ int dmac_init(struct sof *sof) { diff --git a/zephyr/lib/userspace_helper.c b/zephyr/lib/userspace_helper.c index e6703e089d7c..51e3733bffed 100644 --- a/zephyr/lib/userspace_helper.c +++ b/zephyr/lib/userspace_helper.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MODULE_DRIVER_HEAP_CACHED CONFIG_SOF_ZEPHYR_HEAP_CACHED @@ -146,6 +147,21 @@ void user_grant_dai_access_all(struct k_thread *thread) LOG_DBG("Granted DAI access to thread %p for %zu devices", thread, count); } +void user_grant_dma_access_all(struct k_thread *thread) +{ + const struct device **devices; + size_t count; + size_t i; + + devices = dma_get_device_list(&count); + + for (i = 0; i < count; i++) { + k_thread_access_grant(thread, devices[i]); + LOG_DBG("Granted DMA device access: %d %s to thread %p", + i, devices[i]->name, thread); + } +} + #else /* CONFIG_USERSPACE */ void *user_stack_allocate(size_t stack_size, uint32_t options) From 947349e5e8975695d3c91ddc056311591634f0e5 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 9 Feb 2026 15:15:17 +0200 Subject: [PATCH 3/4] schedule: user-space ll: grant access to DAIs and DMAs If the low-latency domain tasks are run in user-space, grant the LL threads access to all DAI and DMA devices. In future, there may be need to filter access permissions more, and/or have variation between different build targets, but for now the user LL thread will have access to the same devices as it does in kernel space. Note that access to memory is separately controlled and in addition to having access to a DMA device, user-space thread also needs access to the memory before it can do DMA transactions. Signed-off-by: Kai Vehmanen --- src/schedule/zephyr_domain.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/schedule/zephyr_domain.c b/src/schedule/zephyr_domain.c index 9a3ef284fd30..6a5812353d9e 100644 --- a/src/schedule/zephyr_domain.c +++ b/src/schedule/zephyr_domain.c @@ -336,6 +336,8 @@ static int zephyr_domain_register_user(struct ll_schedule_domain *domain, k_mem_domain_add_thread(zephyr_ll_mem_domain(), thread); k_thread_access_grant(thread, dt->sem, domain->lock, zephyr_domain->timer); + user_grant_dai_access_all(thread); + user_grant_dma_access_all(thread); tr_dbg(&ll_tr, "granted LL access to thread %p (core %d)", thread, core); k_thread_start(thread); From b18e8ca5798affd8c04bc793200952e88720a0b7 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 5 Feb 2026 21:25:14 +0200 Subject: [PATCH 4/4] zephyr: userspace_helper: do not always build access helpers Now that we have CONFIG_SOF_USERSPACE_LL, use it to conditionally drop some of the thread access helpers. Access to mailbox, DAIs and DMAs is currently only needed if LL thread is run in user-space. Leave these out if SOF is built for LL thread scheduling in kernel space. Signed-off-by: Kai Vehmanen --- zephyr/lib/userspace_helper.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/zephyr/lib/userspace_helper.c b/zephyr/lib/userspace_helper.c index 51e3733bffed..7657f3abbc6d 100644 --- a/zephyr/lib/userspace_helper.c +++ b/zephyr/lib/userspace_helper.c @@ -93,6 +93,8 @@ int user_memory_attach_common_partition(struct k_mem_domain *dom) return k_mem_domain_add_partition(dom, &common_partition); } +#ifdef CONFIG_SOF_USERSPACE_LL + int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) { struct k_mem_partition mem_partition; @@ -162,6 +164,8 @@ void user_grant_dma_access_all(struct k_thread *thread) } } +#endif /* CONFIG_SOF_USERSPACE_LL */ + #else /* CONFIG_USERSPACE */ void *user_stack_allocate(size_t stack_size, uint32_t options)