Skip to content

Commit e9385d0

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 8cea89e commit e9385d0

File tree

6 files changed

+418
-20
lines changed

6 files changed

+418
-20
lines changed

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
@@ -17,6 +17,12 @@ config SOF_USERSPACE
1717
processing mode as userspace code and data. This feature is WIP
1818
and is not yet ready for production, for developers only.
1919

20+
config SOF_USERSPACE_INTERFACE_DMA
21+
bool "Enable SOF DMA interface to userspace threads"
22+
depends on USERSPACE
23+
help
24+
Allow user-space threads to use the SOF DMA interface.
25+
2026
config SOF_ZEPHYR_HEAP_CACHED
2127
bool "Cached Zephyr heap for SOF memory non-shared zones"
2228
default y if CAVS || ACE

zephyr/include/sof/lib/dma.h

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -266,22 +266,8 @@ 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.
283-
*/
284-
void sof_dma_put(struct sof_dma *dma);
269+
/* need to use sof-dma.h to avoid "syscalls/dma.h" name conflict */
270+
#include "sof-dma.h"
285271

286272
#ifndef CONFIG_ZEPHYR_NATIVE_DRIVERS
287273
#include "dma-legacy.h"

zephyr/include/sof/lib/sof-dma.h

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

0 commit comments

Comments
 (0)