Skip to content

Commit fe687d6

Browse files
committed
audio: pipeline: enable position reporting for user-space pipelines
Place the pipeline position lookup table in the sysuser memory partition and replace k_spinlock with a dynamically allocated k_mutex when CONFIG_SOF_USERSPACE_LL is enabled. Spinlocks disable interrupts which is a privileged operation unavailable from user-mode threads. The mutex pointer is stored in a separate APP_SYSUSER_BSS variable outside the SHARED_DATA struct so Zephyr's kernel object tracking can recognize it for syscall verification. Move pipeline_posn_init() from task_main_start() to primary_core_init() before platform_init(), so the mutex is allocated before ipc_user_init() grants thread access to it. In pipeline_posn_get(), bypass the sof_get() kernel singleton and access the shared structure directly when running in user-space. Grant the ipc_user_init thread access to the pipeline position mutex via new pipeline_posn_grant_access() helper. Signed-off-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
1 parent b8d5999 commit fe687d6

5 files changed

Lines changed: 95 additions & 13 deletions

File tree

src/audio/pipeline/pipeline-graph.c

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <rtos/interrupt.h>
1616
#include <rtos/symbol.h>
1717
#include <rtos/alloc.h>
18+
#include <rtos/userspace_helper.h>
1819
#include <sof/lib/mm_heap.h>
1920
#include <sof/lib/uuid.h>
2021
#include <sof/compiler_attributes.h>
@@ -44,20 +45,69 @@ DECLARE_TR_CTX(pipe_tr, SOF_UUID(pipe_uuid), LOG_LEVEL_INFO);
4445
/* lookup table to determine busy/free pipeline metadata objects */
4546
struct pipeline_posn {
4647
bool posn_offset[PPL_POSN_OFFSETS]; /**< available offsets */
48+
#ifndef CONFIG_SOF_USERSPACE_LL
4749
struct k_spinlock lock; /**< lock mechanism */
50+
#endif
4851
};
4952
/* the pipeline position lookup table */
50-
static SHARED_DATA struct pipeline_posn pipeline_posn_shared;
53+
static APP_SYSUSER_BSS SHARED_DATA struct pipeline_posn pipeline_posn_shared;
54+
55+
#ifdef CONFIG_SOF_USERSPACE_LL
56+
/* Mutex pointer in user-accessible partition so user-space threads
57+
* can read the pointer for syscalls. Kept outside the SHARED_DATA
58+
* struct to avoid kernel object tracking issues.
59+
*/
60+
static APP_SYSUSER_BSS struct k_mutex *pipeline_posn_mutex;
61+
#endif
5162

5263
/**
5364
* \brief Retrieves pipeline position structure.
5465
* \return Pointer to pipeline position structure.
5566
*/
5667
static inline struct pipeline_posn *pipeline_posn_get(void)
5768
{
69+
#ifdef CONFIG_SOF_USERSPACE_LL
70+
return &pipeline_posn_shared;
71+
#else
5872
return sof_get()->pipeline_posn;
73+
#endif
74+
}
75+
76+
/*
77+
* Position table locking. User-space LL cannot use a spinlock (disabling
78+
* interrupts is privileged), so it uses a mutex; the config split is kept
79+
* here so the callers below stay identical for both configurations.
80+
*/
81+
#ifdef CONFIG_SOF_USERSPACE_LL
82+
typedef int pipeline_posn_key_t;
83+
84+
static inline pipeline_posn_key_t pipeline_posn_lock(struct pipeline_posn *posn)
85+
{
86+
(void)posn;
87+
k_mutex_lock(pipeline_posn_mutex, K_FOREVER);
88+
return 0;
5989
}
6090

91+
static inline void pipeline_posn_unlock(struct pipeline_posn *posn, pipeline_posn_key_t key)
92+
{
93+
(void)posn;
94+
(void)key;
95+
k_mutex_unlock(pipeline_posn_mutex);
96+
}
97+
#else
98+
typedef k_spinlock_key_t pipeline_posn_key_t;
99+
100+
static inline pipeline_posn_key_t pipeline_posn_lock(struct pipeline_posn *posn)
101+
{
102+
return k_spin_lock(&posn->lock);
103+
}
104+
105+
static inline void pipeline_posn_unlock(struct pipeline_posn *posn, pipeline_posn_key_t key)
106+
{
107+
k_spin_unlock(&posn->lock, key);
108+
}
109+
#endif
110+
61111
/**
62112
* \brief Retrieves first free pipeline position offset.
63113
* \param[in,out] posn_offset Pipeline position offset to be set.
@@ -68,9 +118,7 @@ static inline int pipeline_posn_offset_get(uint32_t *posn_offset)
68118
struct pipeline_posn *pipeline_posn = pipeline_posn_get();
69119
int ret = -EINVAL;
70120
uint32_t i;
71-
k_spinlock_key_t key;
72-
73-
key = k_spin_lock(&pipeline_posn->lock);
121+
pipeline_posn_key_t key = pipeline_posn_lock(pipeline_posn);
74122

75123
for (i = 0; i < PPL_POSN_OFFSETS; ++i) {
76124
if (!pipeline_posn->posn_offset[i]) {
@@ -81,8 +129,7 @@ static inline int pipeline_posn_offset_get(uint32_t *posn_offset)
81129
}
82130
}
83131

84-
85-
k_spin_unlock(&pipeline_posn->lock, key);
132+
pipeline_posn_unlock(pipeline_posn, key);
86133

87134
return ret;
88135
}
@@ -95,20 +142,34 @@ static inline void pipeline_posn_offset_put(uint32_t posn_offset)
95142
{
96143
struct pipeline_posn *pipeline_posn = pipeline_posn_get();
97144
int i = posn_offset / sizeof(struct sof_ipc_stream_posn);
98-
k_spinlock_key_t key;
99-
100-
key = k_spin_lock(&pipeline_posn->lock);
145+
pipeline_posn_key_t key = pipeline_posn_lock(pipeline_posn);
101146

102147
pipeline_posn->posn_offset[i] = false;
103148

104-
k_spin_unlock(&pipeline_posn->lock, key);
149+
pipeline_posn_unlock(pipeline_posn, key);
105150
}
106151

107152
void pipeline_posn_init(struct sof *sof)
108153
{
109154
sof->pipeline_posn = &pipeline_posn_shared;
155+
#ifdef CONFIG_SOF_USERSPACE_LL
156+
pipeline_posn_mutex = k_object_alloc(K_OBJ_MUTEX);
157+
if (!pipeline_posn_mutex) {
158+
pipe_cl_err("pipeline posn mutex alloc failed");
159+
k_panic();
160+
}
161+
k_mutex_init(pipeline_posn_mutex);
162+
#else
110163
k_spinlock_init(&sof->pipeline_posn->lock);
164+
#endif
165+
}
166+
167+
#ifdef CONFIG_SOF_USERSPACE_LL
168+
void pipeline_posn_grant_access(struct k_thread *thread)
169+
{
170+
k_thread_access_grant(thread, pipeline_posn_mutex);
111171
}
172+
#endif
112173

113174
/* create new pipeline - returns pipeline id or negative error */
114175
struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_t priority,
@@ -140,12 +201,21 @@ struct pipeline *pipeline_new(struct k_heap *heap, uint32_t pipeline_id, uint32_
140201
p->pipeline_id = pipeline_id;
141202
p->status = COMP_STATE_INIT;
142203
p->trigger.cmd = COMP_TRIGGER_NO_ACTION;
204+
205+
#ifndef CONFIG_SOF_USERSPACE_LL
206+
/*
207+
* pipe_tr lives in the .trace_ctx section, which is not mapped into
208+
* the sysuser partition, so it cannot be read from a user-mode thread.
209+
* The copy is also unnecessary in that configuration: with Zephyr
210+
* logging the pipe_*() macros use the global pipe_tr, not p->tctx.
211+
*/
143212
ret = memcpy_s(&p->tctx, sizeof(struct tr_ctx), &pipe_tr,
144213
sizeof(struct tr_ctx));
145214
if (ret < 0) {
146215
pipe_err(p, "failed to copy trace settings");
147216
goto free;
148217
}
218+
#endif
149219

150220
ret = pipeline_posn_offset_get(&p->posn_offset);
151221
if (ret < 0) {

src/include/sof/audio/pipeline.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source,
206206
*/
207207
void pipeline_posn_init(struct sof *sof);
208208

209+
#ifdef CONFIG_SOF_USERSPACE_LL
210+
/**
211+
* \brief Grants user-space thread access to pipeline position mutex.
212+
* \param[in] thread Thread to grant access to.
213+
*/
214+
void pipeline_posn_grant_access(struct k_thread *thread);
215+
#endif
216+
209217
/**
210218
* \brief Resets the pipeline and free runtime resources.
211219
* \param[in] p pipeline.

src/init/init.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <sof/schedule/dp_schedule.h>
3333
#include <sof/schedule/ll_schedule.h>
3434
#include <sof/schedule/ll_schedule_domain.h>
35+
#include <sof/audio/pipeline.h>
3536
#include <ipc/trace.h>
3637
#if CONFIG_IPC_MAJOR_4
3738
#include <ipc4/fw_reg.h>
@@ -232,6 +233,11 @@ __cold static int primary_core_init(int argc, char *argv[], struct sof *sof)
232233
zephyr_ll_user_resources_init();
233234
#endif
234235

236+
/* init pipeline position offsets - must be before platform_init()
237+
* which calls ipc_init() -> ipc_user_init() that needs the posn mutex.
238+
*/
239+
pipeline_posn_init(sof);
240+
235241
/* init the platform */
236242
if (platform_init(sof) < 0)
237243
sof_panic(SOF_IPC_PANIC_PLATFORM);

src/ipc/ipc-common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,7 @@ __cold static void ipc_user_init(void)
466466
sof_panic(SOF_IPC_PANIC_IPC);
467467
}
468468
user_ll_grant_access(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID);
469+
pipeline_posn_grant_access(&ipc_user_thread);
469470
k_mem_domain_add_thread(zephyr_ll_mem_domain(), &ipc_user_thread);
470471

471472
k_thread_cpu_pin(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID);

zephyr/wrapper.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,6 @@ int task_main_start(struct sof *sof)
177177
/* init default audio components */
178178
sys_comp_init(sof);
179179

180-
/* init pipeline position offsets */
181-
pipeline_posn_init(sof);
182-
183180
return 0;
184181
}
185182

0 commit comments

Comments
 (0)