From 8a60add0bbe3f434491d05ca6ac05c0628aa2410 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 12 Feb 2026 21:16:34 +0200 Subject: [PATCH] pipeline: protect component connections with a mutex In userspace LL builds, use a mutex to protect component connections. This code should work in kernel builds as well, but start with an incremental change that only affects LL builds, in which mutex use is mandatory. Signed-off-by: Kai Vehmanen --- src/audio/buffers/comp_buffer.c | 6 ++++-- src/audio/pipeline/pipeline-graph.c | 22 ++++++++++++++++------ src/include/sof/audio/component.h | 8 ++++++++ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/audio/buffers/comp_buffer.c b/src/audio/buffers/comp_buffer.c index 0c28d9204cd1..4a4c69b469e8 100644 --- a/src/audio/buffers/comp_buffer.c +++ b/src/audio/buffers/comp_buffer.c @@ -559,7 +559,8 @@ static inline struct list_item *buffer_comp_list(struct comp_buffer *buffer, } /* - * Locking: must be called with interrupts disabled! Serialized IPCs protect us + * Locking: must be called with interrupts disabled (or sys_mutex held for + * userspace LL builds)! Serialized IPCs protect us * from racing attach / detach calls, but the scheduler can interrupt the IPC * thread and begin using the buffer for streaming. FIXME: this is still a * problem with different cores. @@ -572,7 +573,8 @@ void buffer_attach(struct comp_buffer *buffer, struct list_item *head, int dir) } /* - * Locking: must be called with interrupts disabled! See buffer_attach() above + * Locking: must be called with interrupts disabled (or sys_mutex held for + * userspace LL builds)! See buffer_attach() above * for details */ void buffer_detach(struct comp_buffer *buffer, struct list_item *head, int dir) diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 89bb3574289b..38053f016bbb 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -178,24 +178,34 @@ static void buffer_set_comp(struct comp_buffer *buffer, struct comp_dev *comp, comp_buffer_set_sink_component(buffer, comp); } +#ifdef CONFIG_SOF_USERSPACE_LL +#define PPL_LOCK_DECLARE +#define PPL_LOCK() { int ret = sys_mutex_lock(&comp->list_mutex, K_FOREVER); assert(ret == 0); } +#define PPL_UNLOCK() { int ret = sys_mutex_unlock(&comp->list_mutex); assert(ret == 0); } +#else +#define PPL_LOCK_DECLARE uint32_t flags +#define PPL_LOCK() irq_local_disable(flags) +#define PPL_UNLOCK() irq_local_enable(flags) +#endif + int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer, int dir) { struct list_item *comp_list; - uint32_t flags; + PPL_LOCK_DECLARE; if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) comp_info(comp, "connect buffer %d as sink", buf_get_id(buffer)); else comp_info(comp, "connect buffer %d as source", buf_get_id(buffer)); - irq_local_disable(flags); + PPL_LOCK(); comp_list = comp_buffer_list(comp, dir); buffer_attach(buffer, comp_list, dir); buffer_set_comp(buffer, comp, dir); - irq_local_enable(flags); + PPL_UNLOCK(); return 0; } @@ -203,20 +213,20 @@ int pipeline_connect(struct comp_dev *comp, struct comp_buffer *buffer, void pipeline_disconnect(struct comp_dev *comp, struct comp_buffer *buffer, int dir) { struct list_item *comp_list; - uint32_t flags; + PPL_LOCK_DECLARE; if (dir == PPL_CONN_DIR_COMP_TO_BUFFER) comp_dbg(comp, "disconnect buffer %d as sink", buf_get_id(buffer)); else comp_dbg(comp, "disconnect buffer %d as source", buf_get_id(buffer)); - irq_local_disable(flags); + PPL_LOCK(); comp_list = comp_buffer_list(comp, dir); buffer_detach(buffer, comp_list, dir); buffer_set_comp(buffer, NULL, dir); - irq_local_enable(flags); + PPL_UNLOCK(); } /* pipelines must be inactive */ diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index b6695b9cd312..82b9599df8c8 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -679,6 +680,10 @@ struct comp_dev { struct list_item bsource_list; /**< list of source buffers */ struct list_item bsink_list; /**< list of sink buffers */ +#ifdef CONFIG_SOF_USERSPACE_LL + struct sys_mutex list_mutex; /**< protect lists of source/sinks */ +#endif + /* performance data*/ struct comp_perf_data perf_data; /* Input Buffer Size for pin 0, add array for other pins if needed */ @@ -863,6 +868,9 @@ static inline void comp_init(const struct comp_driver *drv, dev->state = COMP_STATE_INIT; list_init(&dev->bsink_list); list_init(&dev->bsource_list); +#ifdef CONFIG_SOF_USERSPACE_LL + sys_mutex_init(&dev->list_mutex); +#endif memcpy_s(&dev->tctx, sizeof(dev->tctx), trace_comp_drv_get_tr_ctx(dev->drv), sizeof(struct tr_ctx)); }