Skip to content

Commit d30da90

Browse files
committed
lib: dma: add support for user-space usage
Expose a subset of the Zephyr DMA interface to SOF user-space threads. The functionality is selected to cover current needs of SOF DMA client usage. SOF targets that do not use userspace, are not impacted. Use a simple object lookup for kernel objects passed from user-space and check the object is a valid kernel object before proceeding to syscall implementation. This is alternative to using Zephyr gen_kobjet_list.py infra, which would require adding the SOF DMA type to the list of Zephyr kobjects. Use a similar mechanism to look up and validate the kernel object, but use runtime methods to track objects. The permission is based on DMA devices. If a thread has access to DMA device, it will get access to all channels of the DMA controller. Memory accesses are checked for permission. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent 6ee638f commit d30da90

6 files changed

Lines changed: 427 additions & 19 deletions

File tree

src/lib/dma.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ DECLARE_TR_CTX(dma_tr, SOF_UUID(dma_uuid), LOG_LEVEL_INFO);
3636
#if CONFIG_ZEPHYR_NATIVE_DRIVERS
3737
static int dma_init(struct sof_dma *dma);
3838

39-
struct sof_dma *sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
39+
struct sof_dma *z_impl_sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
4040
{
4141
const struct dma_info *info = dma_info_get();
4242
int users, ret = 0;
@@ -129,7 +129,7 @@ struct sof_dma *sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t f
129129
return !ret ? dmin : NULL;
130130
}
131131

132-
void sof_dma_put(struct sof_dma *dma)
132+
void z_impl_sof_dma_put(struct sof_dma *dma)
133133
{
134134
k_spinlock_key_t key;
135135

@@ -168,8 +168,8 @@ static int dma_init(struct sof_dma *dma)
168168

169169
return 0;
170170
}
171-
EXPORT_SYMBOL(sof_dma_get);
172-
EXPORT_SYMBOL(sof_dma_put);
171+
EXPORT_SYMBOL(z_impl_sof_dma_get);
172+
EXPORT_SYMBOL(z_impl_sof_dma_put);
173173
#else
174174
struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
175175
{

zephyr/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,12 @@ if(NOT DEFINED PLATFORM)
490490
endif()
491491
zephyr_include_directories(${SOF_PLATFORM_PATH}/${PLATFORM}/include)
492492

493+
zephyr_library_sources_ifdef(CONFIG_USERSPACE
494+
syscall/sof_dma.c
495+
)
496+
497+
zephyr_syscall_header(include/sof/lib/sof_dma.h)
498+
493499
# Mandatory Files used on all platforms.
494500
# Commented files will be added/removed as integration dictates.
495501
zephyr_library_sources(

zephyr/Kconfig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@ config SOF_USERSPACE
2323
processing mode as userspace code and data. This feature is WIP
2424
and is not yet ready for production, for developers only.
2525

26+
config SOF_USERSPACE_INTERFACE_DMA
27+
bool "Enable SOF DMA interface to userspace threads"
28+
depends on USERSPACE
29+
help
30+
Allow user-space threads to use the SOF DMA interface.
31+
2632
config SOF_ZEPHYR_HEAP_CACHED
2733
bool "Cached Zephyr heap for SOF memory non-shared zones"
2834
default y if CAVS || ACE

zephyr/include/sof/lib/dma.h

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -266,22 +266,11 @@ typedef int (*dma_process_func)(const struct audio_stream *source,
266266
*/
267267
int dmac_init(struct sof *sof);
268268

269-
/**
270-
* \brief API to request a platform DMAC.
271-
*
272-
* Users can request DMAC based on dev type, copy direction, capabilities
273-
* and access privilege.
274-
* For exclusive access, ret DMAC with no channels draining.
275-
* For shared access, ret DMAC with the least number of channels draining.
276-
*/
277-
struct sof_dma *sof_dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags);
278-
279-
/**
280-
* \brief API to release a platform DMAC.
281-
*
282-
* @param[in] dma DMAC to relese.
269+
/*
270+
* Need to use sof_dma.h to avoid "syscalls/dma.h" name conflict
271+
* with Zephyr autogenerated headers for syscall support.
283272
*/
284-
void sof_dma_put(struct sof_dma *dma);
273+
#include "sof_dma.h"
285274

286275
#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS
287276
#include "dma-legacy.h"

zephyr/include/sof/lib/sof_dma.h

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/* SPDX-License-Identifier: BSD-3-Clause
2+
*
3+
* Copyright (c) 2025, Intel Corporation.
4+
*/
5+
6+
/*
7+
* Need to use sof_dma.h to avoid "syscalls/dma.h" name conflict
8+
* with Zephyr autogenerated headers for syscall support.
9+
*/
10+
11+
#ifndef SOF_DMA_H
12+
#define SOF_DMA_H
13+
14+
/**
15+
* \brief API to request a platform DMAC.
16+
*
17+
* Users can request DMAC based on dev type, copy direction, capabilities
18+
* and access privilege.
19+
* For exclusive access, ret DMAC with no channels draining.
20+
* For shared access, ret DMAC with the least number of channels draining.
21+
*/
22+
__syscall struct sof_dma *sof_dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags);
23+
24+
struct sof_dma *z_impl_sof_dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags);
25+
26+
27+
/**
28+
* \brief API to release a platform DMAC.
29+
*
30+
* @param[in] dma DMAC to release.
31+
*/
32+
__syscall void sof_dma_put(struct sof_dma *dma);
33+
34+
void z_impl_sof_dma_put(struct sof_dma *dma);
35+
36+
__syscall int sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value);
37+
38+
__syscall int sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag);
39+
40+
__syscall void sof_dma_release_channel(struct sof_dma *dma,
41+
uint32_t channel);
42+
43+
__syscall int sof_dma_config(struct sof_dma *dma, uint32_t channel,
44+
struct dma_config *config);
45+
46+
__syscall int sof_dma_start(struct sof_dma *dma, uint32_t channel);
47+
48+
__syscall int sof_dma_stop(struct sof_dma *dma, uint32_t channel);
49+
50+
__syscall int sof_dma_get_status(struct sof_dma *dma, uint32_t channel, struct dma_status *stat);
51+
52+
__syscall int sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size);
53+
54+
static inline int z_impl_sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value)
55+
{
56+
return dma_get_attribute(dma->z_dev, type, value);
57+
}
58+
59+
static inline int z_impl_sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag)
60+
{
61+
return dma_request_channel(dma->z_dev, &stream_tag);
62+
}
63+
64+
static inline void z_impl_sof_dma_release_channel(struct sof_dma *dma,
65+
uint32_t channel)
66+
{
67+
dma_release_channel(dma->z_dev, channel);
68+
}
69+
70+
static inline int z_impl_sof_dma_config(struct sof_dma *dma, uint32_t channel,
71+
struct dma_config *config)
72+
{
73+
return dma_config(dma->z_dev, channel, config);
74+
}
75+
76+
77+
static inline int z_impl_sof_dma_start(struct sof_dma *dma, uint32_t channel)
78+
{
79+
return dma_start(dma->z_dev, channel);
80+
}
81+
82+
static inline int z_impl_sof_dma_stop(struct sof_dma *dma, uint32_t channel)
83+
{
84+
return dma_stop(dma->z_dev, channel);
85+
}
86+
87+
static inline int z_impl_sof_dma_get_status(struct sof_dma *dma, uint32_t channel,
88+
struct dma_status *stat)
89+
{
90+
return dma_get_status(dma->z_dev, channel, stat);
91+
}
92+
93+
static inline int z_impl_sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size)
94+
{
95+
return dma_reload(dma->z_dev, channel, 0, 0, size);
96+
}
97+
98+
#ifdef CONFIG_SOF_USERSPACE_INTERFACE_DMA
99+
100+
/* include definitions from generated file */
101+
#include <zephyr/syscalls/sof_dma.h>
102+
103+
#else /* !CONFIG_SOF_USERSPACE_INTERFACE_DMA */
104+
105+
/*
106+
* SOF-specific mechanism to allow building SOF with user-space
107+
* support enabled in Zephyr, but not including all syscall
108+
* interfaces in the SOF binary. Thee downside is we cannot
109+
* use the zephyr/syscalls/sof_dma.h boilerplate that is autogenerated
110+
* but instead need a manual wrapper that is below here.
111+
*
112+
* This can be removed if DMA is used in all SOF user-space builds.
113+
*/
114+
115+
static inline struct sof_dma *sof_dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags)
116+
{
117+
return z_impl_sof_dma_get(dir, caps, dev, flags);
118+
}
119+
120+
static inline void sof_dma_put(struct sof_dma *dma)
121+
{
122+
return z_impl_sof_dma_put(dma);
123+
}
124+
125+
static inline int sof_dma_get_attribute(struct sof_dma *dma, uint32_t type, uint32_t *value)
126+
{
127+
return z_impl_sof_dma_get_attribute(dma, type, value);
128+
}
129+
130+
static inline int sof_dma_request_channel(struct sof_dma *dma, uint32_t stream_tag)
131+
{
132+
return z_impl_sof_dma_request_channel(dma, stream_tag);
133+
}
134+
135+
static inline void sof_dma_release_channel(struct sof_dma *dma,
136+
uint32_t channel)
137+
{
138+
return z_impl_sof_dma_release_channel(dma, channel);
139+
}
140+
141+
static inline int sof_dma_config(struct sof_dma *dma, uint32_t channel,
142+
struct dma_config *config)
143+
{
144+
return z_impl_sof_dma_config(dma, channel, config);
145+
}
146+
147+
static inline int sof_dma_start(struct sof_dma *dma, uint32_t channel)
148+
{
149+
return z_impl_sof_dma_start(dma, channel);
150+
}
151+
152+
static inline int sof_dma_stop(struct sof_dma *dma, uint32_t channel)
153+
{
154+
return z_impl_sof_dma_stop(dma, channel);
155+
}
156+
157+
static inline int sof_dma_get_status(struct sof_dma *dma, uint32_t channel, struct dma_status *stat)
158+
{
159+
return z_impl_sof_dma_get_status(dma, channel, stat);
160+
}
161+
162+
static inline int sof_dma_reload(struct sof_dma *dma, uint32_t channel, size_t size)
163+
{
164+
return z_impl_sof_dma_reload(dma, channel, size);
165+
}
166+
167+
#endif /* CONFIG_SOF_USERSPACE_INTERFACE_DMA */
168+
169+
#endif

0 commit comments

Comments
 (0)