3030#include <sof/audio/component.h>
3131#include <sof/schedule/dp_schedule.h>
3232#include <rtos/userspace_helper.h>
33+ #include <rtos/user_work.h>
3334#include <utilities/array.h>
3435#include <zephyr/sys/sem.h>
3536#include <sof/audio/module_adapter/module/generic.h>
@@ -54,12 +55,16 @@ static const struct module_interface userspace_proxy_interface;
5455#include <sof/audio/module_adapter/iadk/system_agent.h>
5556#include <sof/schedule/dp_schedule.h>
5657
57- static inline int user_worker_get (void )
58+ static inline int user_worker_get (int core )
5859{
60+ ARG_UNUSED (core );
5961 return 0 ;
6062}
6163
62- static inline void user_worker_put (void ) { }
64+ static inline void user_worker_put (int core )
65+ {
66+ ARG_UNUSED (core );
67+ }
6368
6469struct k_work_user * userspace_proxy_register_ipc_handler (struct processing_module * mod ,
6570 struct k_event * event )
@@ -86,9 +91,9 @@ struct k_work_user *userspace_proxy_register_ipc_handler(struct processing_modul
8691 * It invokes the appropriate module function in userspace context and writes the operation
8792 * result back into the work item.
8893 *
89- * There is only a single work queue, which is shared by all userspace modules. It is created
90- * dynamically when needed. Because SOF uses a single dedicated thread for handling IPC, there
91- * is no need to perform any additional serialization when accessing the worker .
94+ * Each core owns one work queue, shared by the userspace modules assigned to that core.
95+ * Each work queue has its own worker thread, which is pinned to its core before it is first
96+ * started and never migrates .
9297 */
9398struct user_worker {
9499 k_tid_t thread_id ; /* ipc worker thread ID */
@@ -98,70 +103,94 @@ struct user_worker {
98103 struct k_event event ;
99104};
100105
101- static struct user_worker worker ;
106+ static struct user_worker workers [ CONFIG_CORE_COUNT ] ;
102107
103- static int user_worker_get (void )
108+ static int user_worker_get (int core )
104109{
105- if (worker .reference_count ) {
106- worker .reference_count ++ ;
110+ struct user_worker * worker ;
111+ int ret ;
112+
113+ if (core < 0 || core >= CONFIG_CORE_COUNT )
114+ return - EINVAL ;
115+
116+ worker = & workers [core ];
117+ if (worker -> reference_count ) {
118+ worker -> reference_count ++ ;
107119 return 0 ;
108120 }
109121
110- worker . stack_ptr = user_stack_allocate (CONFIG_SOF_USERSPACE_PROXY_WORKER_STACK_SIZE ,
111- K_USER );
112- if (!worker . stack_ptr ) {
122+ worker -> stack_ptr = user_stack_allocate (CONFIG_SOF_USERSPACE_PROXY_WORKER_STACK_SIZE ,
123+ K_USER );
124+ if (!worker -> stack_ptr ) {
113125 tr_err (& userspace_proxy_tr , "Userspace worker stack allocation failed." );
114126 return - ENOMEM ;
115127 }
116128
117- k_event_init (& worker .event );
118- k_work_user_queue_start (& worker .work_queue , worker .stack_ptr ,
119- CONFIG_SOF_USERSPACE_PROXY_WORKER_STACK_SIZE , 0 , NULL );
129+ k_event_init (& worker -> event );
130+ sof_work_user_queue_create (& worker -> work_queue , worker -> stack_ptr ,
131+ CONFIG_SOF_USERSPACE_PROXY_WORKER_STACK_SIZE , 0 , NULL );
132+ worker -> thread_id = k_work_user_queue_thread_get (& worker -> work_queue );
133+ k_thread_access_grant (worker -> thread_id , & worker -> event );
120134
121- worker .thread_id = k_work_user_queue_thread_get (& worker .work_queue );
135+ #ifdef CONFIG_SCHED_CPU_MASK
136+ ret = k_thread_cpu_pin (worker -> thread_id , core );
137+ if (ret < 0 ) {
138+ tr_err (& userspace_proxy_tr , "Failed to pin userspace worker to core %u: %d" ,
139+ core , ret );
140+ k_thread_abort (worker -> thread_id );
141+ user_stack_free (worker -> stack_ptr );
142+ worker -> stack_ptr = NULL ;
143+ worker -> thread_id = NULL ;
144+ return ret ;
145+ }
146+ #elif CONFIG_CORE_COUNT > 1
147+ #error "CONFIG_SCHED_CPU_MASK is not enabled"
148+ #endif
122149
123- k_thread_access_grant (worker . thread_id , & worker . event );
150+ k_thread_start (worker -> thread_id );
124151
125- worker . reference_count ++ ;
152+ worker -> reference_count ++ ;
126153 return 0 ;
127154}
128155
129- static void user_worker_put (void )
156+ static void user_worker_put (int core )
130157{
158+ struct user_worker * worker = & workers [core ];
159+
131160 /* Module removed so decrement counter */
132- worker . reference_count -- ;
161+ worker -> reference_count -- ;
133162
134163 /* Free worker resources if no more active user space modules */
135- if (worker .reference_count == 0 ) {
136- k_thread_abort (worker .thread_id );
137- user_stack_free (worker .stack_ptr );
164+ if (worker -> reference_count == 0 ) {
165+ k_thread_abort (worker -> thread_id );
166+ user_stack_free (worker -> stack_ptr );
167+ worker -> stack_ptr = NULL ;
168+ worker -> thread_id = NULL ;
138169 }
139170}
140171#endif
141172
142173static int user_work_item_init (struct userspace_context * user_ctx , struct k_heap * user_heap )
143174{
144175 struct user_work_item * work_item = NULL ;
176+ const int core = cpu_get_id ();
145177 int ret ;
146178
147- ret = user_worker_get ();
179+ ret = user_worker_get (core );
148180 if (ret )
149181 return ret ;
150182
151- /* We have only a single userspace IPC worker. It handles requests for all userspace
152- * modules, which may run on different cores. Because the worker processes work items
153- * coming from any core, the work item must be allocated in coherent memory.
154- */
183+ /* TODO: this can probably be cached now? */
155184 work_item = sof_heap_alloc (user_heap , SOF_MEM_FLAG_COHERENT , sizeof (* work_item ), 0 );
156185 if (!work_item ) {
157- user_worker_put ();
186+ user_worker_put (core );
158187 return - ENOMEM ;
159188 }
160189
161190 k_work_user_init (& work_item -> work_item , userspace_proxy_worker_handler );
162191
163192#if !IS_ENABLED (CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD )
164- work_item -> event = & worker .event ;
193+ work_item -> event = & workers [ core ] .event ;
165194#endif
166195 work_item -> params .context = user_ctx ;
167196 work_item -> params .mod = NULL ;
@@ -173,7 +202,7 @@ static int user_work_item_init(struct userspace_context *user_ctx, struct k_heap
173202static void user_work_item_free (struct userspace_context * user_ctx , struct k_heap * user_heap )
174203{
175204 sof_heap_free (user_heap , user_ctx -> work_item );
176- user_worker_put ();
205+ user_worker_put (cpu_get_id () );
177206}
178207
179208static inline struct module_params * user_work_get_params (struct userspace_context * user_ctx )
@@ -193,7 +222,8 @@ static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t c
193222#if IS_ENABLED (CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD )
194223 struct k_event * const event = user_ctx -> dp_event ;
195224#else
196- struct k_event * const event = & worker .event ;
225+ struct user_worker * worker = & workers [cpu_get_id ()];
226+ struct k_event * const event = & worker -> event ;
197227#endif
198228 struct module_params * params = user_work_get_params (user_ctx );
199229 const uintptr_t ipc_req_buf = (uintptr_t )MAILBOX_HOSTBOX_BASE ;
@@ -216,22 +246,13 @@ static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t c
216246
217247#if !IS_ENABLED (CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD )
218248 /* Switch worker thread to module memory domain */
219- ret = k_mem_domain_add_thread (user_ctx -> comp_dom , worker . thread_id );
249+ ret = k_mem_domain_add_thread (user_ctx -> comp_dom , worker -> thread_id );
220250 if (ret < 0 ) {
221251 tr_err (& userspace_proxy_tr , "Failed to switch memory domain, error: %d" , ret );
222252 goto done ;
223253 }
224254
225- #ifdef CONFIG_SCHED_CPU_MASK
226- /* Pin worker thread to the same core as the module */
227- ret = k_thread_cpu_pin (worker .thread_id , cpu_get_id ());
228- if (ret < 0 ) {
229- tr_err (& userspace_proxy_tr , "Failed to pin cpu, error: %d" , ret );
230- goto done ;
231- }
232- #endif
233-
234- ret = k_work_user_submit_to_queue (& worker .work_queue , & user_ctx -> work_item -> work_item );
255+ ret = k_work_user_submit_to_queue (& worker -> work_queue , & user_ctx -> work_item -> work_item );
235256 if (ret < 0 ) {
236257 tr_err (& userspace_proxy_tr , "Submit to queue error: %d" , ret );
237258 goto done ;
0 commit comments