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 */
4546struct 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 */
5667static 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
107152void 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 */
114175struct 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 ) {
0 commit comments