Skip to content

Commit 3fcc3fb

Browse files
init worker from 0 core
Signed-off-by: Serhiy Katsyuba <serhiy.katsyuba@intel.com>
1 parent 5d3ee22 commit 3fcc3fb

4 files changed

Lines changed: 81 additions & 32 deletions

File tree

src/audio/module_adapter/library/userspace_proxy.c

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,15 @@ struct user_worker {
103103
struct k_event event;
104104
};
105105

106-
static struct user_worker worker[CONFIG_CORE_COUNT];
106+
static struct user_worker worker[CONFIG_CORE_COUNT] = { { 0 } };
107107

108-
static int user_worker_get(int cpu)
108+
int user_worker_create(int cpu)
109109
{
110-
int ret = 0;
111-
110+
assert(cpu_is_me(0));
112111
assert(cpu >= 0 && cpu < (int)ARRAY_SIZE(worker));
113112

114-
if (worker[cpu].reference_count) {
115-
worker[cpu].reference_count++;
113+
if (worker[cpu].stack_ptr) {
114+
tr_err(&userspace_proxy_tr, "Userspace worker already created for core %d.", cpu);
116115
return 0;
117116
}
118117

@@ -130,45 +129,42 @@ static int user_worker_get(int cpu)
130129
worker[cpu].thread_id = k_work_user_queue_thread_get(&worker[cpu].work_queue);
131130

132131
#ifdef CONFIG_SCHED_CPU_MASK
133-
/*
134-
* k_work_user_queue_start() starts the worker thread immediately.
135-
* We need to make sure it is not running when pinning it to a specific core.
136-
*/
137-
k_thread_suspend(worker[cpu].thread_id);
138-
139-
/* Pin worker thread to the same core as the module */
140-
ret = k_thread_cpu_pin(worker[cpu].thread_id, cpu);
132+
int ret = k_thread_cpu_pin(worker[cpu].thread_id, cpu);
141133
if (ret) {
142134
tr_err(&userspace_proxy_tr, "Failed to pin worker to core %d, error: %d",
143135
cpu, ret);
144136
k_panic();
145137
}
146-
147-
k_thread_resume(worker[cpu].thread_id);
148-
149138
#elif CONFIG_CORE_COUNT > 1
150139
#error "CONFIG_SCHED_CPU_MASK is not enabled"
151140
#endif
152141

153142
k_thread_access_grant(worker[cpu].thread_id, &worker[cpu].event);
154143

155-
worker[cpu].reference_count++;
156-
157144
return 0;
158145
}
159146

160-
static void user_worker_put(int cpu)
147+
void user_worker_free(int cpu)
161148
{
162149
assert(cpu >= 0 && cpu < (int)ARRAY_SIZE(worker));
150+
assert(worker[cpu].stack_ptr);
163151

164-
/* Module removed so decrement counter */
165-
worker[cpu].reference_count--;
152+
k_thread_abort(worker[cpu].thread_id);
153+
user_stack_free(worker[cpu].stack_ptr);
154+
worker[cpu].stack_ptr = NULL;
155+
}
166156

167-
/* Free worker resources if no more active user space modules */
168-
if (worker[cpu].reference_count == 0) {
169-
k_thread_abort(worker[cpu].thread_id);
170-
user_stack_free(worker[cpu].stack_ptr);
171-
}
157+
static int user_worker_get(int cpu)
158+
{
159+
assert(cpu >= 0 && cpu < (int)ARRAY_SIZE(worker));
160+
assert(worker[cpu].stack_ptr);
161+
162+
return 0;
163+
}
164+
165+
static void user_worker_put(int cpu)
166+
{
167+
ARG_UNUSED(cpu);
172168
}
173169
#endif
174170

src/include/sof/audio/module_adapter/library/userspace_proxy.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,38 @@ struct k_work_user *userspace_proxy_register_ipc_handler(struct processing_modul
8181

8282
#endif /* CONFIG_SOF_USERSPACE_PROXY */
8383

84+
/*
85+
* Per-core userspace IPC worker lifecycle.
86+
*
87+
* A userspace IPC worker is a user-mode work queue (and its worker thread) that
88+
* services IPC requests targeting userspace modules running on a given core. The
89+
* worker is created on, and managed from, the primary core. Configurations that do
90+
* not use a dedicated per-core worker resolve these calls to no-ops.
91+
*/
92+
#if CONFIG_SOF_USERSPACE_PROXY && !CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD
93+
/**
94+
* Create the userspace IPC worker for the given core.
95+
*
96+
* Must be called while running on the primary core. The worker thread is pinned to
97+
* the target core. Calling it again for a core that already has a worker is a no-op.
98+
*
99+
* @param cpu - target core id the worker is created for
100+
* @return 0 on success, negative error code otherwise.
101+
*/
102+
int user_worker_create(int cpu);
103+
104+
/**
105+
* Free the userspace IPC worker for the given core.
106+
*
107+
* Must be called from the primary core while the target core is still running, as it
108+
* aborts the worker thread.
109+
*
110+
* @param cpu - target core id whose worker is freed
111+
*/
112+
void user_worker_free(int cpu);
113+
#else
114+
static inline int user_worker_create(int cpu) { return 0; }
115+
static inline void user_worker_free(int cpu) { }
116+
#endif
117+
84118
#endif /* __SOF_AUDIO_USERSPACE_PROXY_H__ */

src/init/init.c

Lines changed: 7 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/module_adapter/library/userspace_proxy.h>
3536
#include <ipc/trace.h>
3637
#if CONFIG_IPC_MAJOR_4
3738
#include <ipc4/fw_reg.h>
@@ -230,6 +231,12 @@ __cold static int primary_core_init(int argc, char *argv[], struct sof *sof)
230231
zephyr_ll_user_resources_init();
231232
#endif
232233

234+
/* Create the userspace IPC worker for the primary core. Secondary cores get
235+
* theirs from cpu_enable_core(). Resolves to a no-op when unused.
236+
*/
237+
if (user_worker_create(cpu_get_id()) < 0)
238+
sof_panic(SOF_IPC_PANIC_MEM);
239+
233240
/* init the platform */
234241
if (platform_init(sof) < 0)
235242
sof_panic(SOF_IPC_PANIC_PLATFORM);

zephyr/lib/cpu.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ static uint32_t mic_disable_status;
2222
#include <sof/lib/pm_runtime.h>
2323
#include <ipc/topology.h>
2424
#include <module/module/base.h>
25+
#include <sof/audio/module_adapter/library/userspace_proxy.h>
2526
#include <rtos/alloc.h>
2627

2728
#include "../audio/copier/copier.h"
@@ -230,6 +231,8 @@ void cpu_notify_state_exit(enum pm_state state)
230231

231232
int cpu_enable_core(int id)
232233
{
234+
int ret = 0;
235+
233236
/* only called from single core, no RMW lock */
234237
__ASSERT_NO_MSG(cpu_is_primary(arch_proc_id()));
235238
/*
@@ -247,15 +250,18 @@ int cpu_enable_core(int id)
247250
* initialization. By reinitializing the idle thread, we would overwrite the kernel structs
248251
* and the idle thread stack.
249252
*/
250-
if (pm_state_next_get(id)->state == PM_STATE_ACTIVE) {
253+
if (pm_state_next_get(id)->state == PM_STATE_ACTIVE)
251254
k_smp_cpu_start(id, secondary_init, NULL);
252-
return 0;
253-
}
255+
else
256+
k_smp_cpu_resume(id, secondary_init, NULL, true, false);
254257

255-
k_smp_cpu_resume(id, secondary_init, NULL, true, false);
258+
/* The core is up now; create its userspace IPC worker on the primary core.
259+
* Resolves to a no-op when no per-core userspace worker is used.
260+
*/
261+
ret = user_worker_create(id);
256262
#endif /* CONFIG_PM */
257263

258-
return 0;
264+
return ret;
259265
}
260266

261267
void cpu_disable_core(int id)
@@ -267,6 +273,12 @@ void cpu_disable_core(int id)
267273
tr_warn(&zephyr_tr, "core %d is already disabled", id);
268274
return;
269275
}
276+
277+
/* Free the core's userspace IPC worker while the core is still running; the
278+
* worker thread is aborted cross-core. Resolves to a no-op when unused.
279+
*/
280+
user_worker_free(id);
281+
270282
#if defined(CONFIG_PM)
271283
/* TODO: before requesting core shut down check if it's not actively used */
272284
if (!pm_state_force(id, &(struct pm_state_info){PM_STATE_SOFT_OFF, 0, 0})) {

0 commit comments

Comments
 (0)