Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions src/include/sof/lib/dai-zephyr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__ */
8 changes: 8 additions & 0 deletions src/lib/dai.c
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,14 @@ const struct device *zephyr_dev[] = {
#endif
};

const struct device **dai_get_device_list(size_t *count)
{
if (count)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems count is mandatory ? assert ?

*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)
{
Expand Down
2 changes: 2 additions & 0 deletions src/schedule/zephyr_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Comment on lines 338 to +340
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These calls are unconditional, but the implementations in userspace_helper.c are built only under CONFIG_USERSPACE && CONFIG_SOF_USERSPACE_LL (and currently the header declarations are not similarly guarded). This can lead to unresolved symbols in configurations where this file is compiled but CONFIG_SOF_USERSPACE_LL (or even CONFIG_USERSPACE) is off. Guard these calls with the same Kconfig option(s), and/or provide static inline no-op stubs in the header for non-enabled configurations.

Suggested change
k_thread_access_grant(thread, dt->sem, domain->lock, zephyr_domain->timer);
user_grant_dai_access_all(thread);
user_grant_dma_access_all(thread);
k_thread_access_grant(thread, dt->sem, domain->lock, zephyr_domain->timer);
#if CONFIG_USERSPACE && CONFIG_SOF_USERSPACE_LL
user_grant_dai_access_all(thread);
user_grant_dma_access_all(thread);
#endif

Copilot uses AI. Check for mistakes.
tr_dbg(&ll_tr, "granted LL access to thread %p (core %d)", thread, core);

k_thread_start(thread);
Expand Down
14 changes: 14 additions & 0 deletions zephyr/include/rtos/userspace_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,20 @@ 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);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These APIs are declared for all CONFIG_USERSPACE builds, but the implementations are under CONFIG_SOF_USERSPACE_LL in the .c file. To keep the public API consistent and avoid configuration-dependent link issues, either (1) wrap these declarations with #ifdef CONFIG_SOF_USERSPACE_LL to match the implementation, or (2) provide static inline no-op stubs when CONFIG_SOF_USERSPACE_LL is disabled.

Copilot uses AI. Check for mistakes.

/**
* 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);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These APIs are declared for all CONFIG_USERSPACE builds, but the implementations are under CONFIG_SOF_USERSPACE_LL in the .c file. To keep the public API consistent and avoid configuration-dependent link issues, either (1) wrap these declarations with #ifdef CONFIG_SOF_USERSPACE_LL to match the implementation, or (2) provide static inline no-op stubs when CONFIG_SOF_USERSPACE_LL is disabled.

Copilot uses AI. Check for mistakes.

#else

static inline int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id)
Expand Down
7 changes: 7 additions & 0 deletions zephyr/include/sof/lib/dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning const struct device ** allows callers to modify the returned array contents (even if the devices themselves are const). Since this API is exposing a shared internal list, it should return an immutable list type: const struct device * const *. Same applies to dai_get_device_list() for consistency/safety.

Suggested change
const struct device **dma_get_device_list(size_t *count);
const struct device * const *dma_get_device_list(size_t *count);

Copilot uses AI. Check for mistakes.

/** @}*/

#endif /* __SOF_LIB_DMA_H__ */
14 changes: 14 additions & 0 deletions zephyr/lib/dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Comment on lines +222 to +225
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dma_get_device_list() writes to a function-static array on every call. If multiple threads can call this concurrently, this introduces a data race on device_list[]. To avoid racy writes, populate the list once during a single-threaded init phase (e.g., in dmac_init()), or implement a one-time initialization guard that does not perform concurrent writes.

Copilot uses AI. Check for mistakes.

if (count)
*count = ARRAY_SIZE(dma);

for (i = 0; i < ARRAY_SIZE(dma); i++)
device_list[i] = dma[i].z_dev;

Comment on lines +225 to +232
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dma_get_device_list() writes to a function-static array on every call. If multiple threads can call this concurrently, this introduces a data race on device_list[]. To avoid racy writes, populate the list once during a single-threaded init phase (e.g., in dmac_init()), or implement a one-time initialization guard that does not perform concurrent writes.

Suggested change
int i;
if (count)
*count = ARRAY_SIZE(dma);
for (i = 0; i < ARRAY_SIZE(dma); i++)
device_list[i] = dma[i].z_dev;
static struct k_spinlock device_list_lock;
static int device_list_initialized;
int i;
k_spinlock_key_t key;
if (count)
*count = ARRAY_SIZE(dma);
key = k_spin_lock(&device_list_lock);
if (!device_list_initialized) {
for (i = 0; i < ARRAY_SIZE(dma); i++)
device_list[i] = dma[i].z_dev;
device_list_initialized = 1;
}
k_spin_unlock(&device_list_lock, key);

Copilot uses AI. Check for mistakes.
return device_list;
}

/* Initialize all platform DMAC's */
int dmac_init(struct sof *sof)
{
Expand Down
38 changes: 38 additions & 0 deletions zephyr/lib/userspace_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@
#include <sof/audio/module_adapter/module/generic.h>
#include <sof/audio/module_adapter/library/userspace_proxy.h>
#include <sof/lib/mailbox.h>
#include <sof/lib/dai.h>
#include <sof/lib/dma.h>

#define MODULE_DRIVER_HEAP_CACHED CONFIG_SOF_ZEPHYR_HEAP_CACHED

/* Zephyr includes */
#include <zephyr/kernel.h>
#include <zephyr/app_memory/app_memdomain.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(userspace_helper, CONFIG_SOF_LOG_LEVEL);

#if CONFIG_USERSPACE

Expand Down Expand Up @@ -88,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)
Comment on lines +96 to 98
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user_access_to_mailbox() is now compiled only when CONFIG_SOF_USERSPACE_LL is enabled, but it appears to be a general userspace helper (and is still declared under #if CONFIG_USERSPACE in the header). This creates a concrete risk of link failures or missing functionality in CONFIG_USERSPACE=y builds that don’t enable CONFIG_SOF_USERSPACE_LL. Consider moving the #ifdef CONFIG_SOF_USERSPACE_LL guard so it only wraps the new DAI/DMA grant helpers (not user_access_to_mailbox()), or alternatively provide stubs / adjust header declarations so the build remains consistent across configurations.

Copilot uses AI. Check for mistakes.
{
struct k_mem_partition mem_partition;
Expand Down Expand Up @@ -128,6 +135,37 @@ 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);
}

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);
}
}

Comment on lines +160 to +166
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logging once per DMA device can become noisy and adds overhead (even at LOG_DBG, it still does formatting work depending on Zephyr logging configuration). Consider logging a single summary line (as done for DAI) or gating per-device debug logs behind a more verbose config.

Suggested change
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);
}
}
for (i = 0; i < count; i++)
k_thread_access_grant(thread, devices[i]);
LOG_DBG("Granted DMA access to thread %p for %zu devices", thread, count);
}

Copilot uses AI. Check for mistakes.
#endif /* CONFIG_SOF_USERSPACE_LL */

#else /* CONFIG_USERSPACE */

void *user_stack_allocate(size_t stack_size, uint32_t options)
Expand Down