From 1469c18e498d285ddac273b1809f3a98ce6accdc Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 31 Jul 2026 15:35:46 +0200 Subject: [PATCH 001/109] userspace: proxy: suspend worker while reconfiguring it k_thread_cpu_pin() must not be called on a running thread, and the worker must not execute while its memory domain is being modified. Suspend the worker thread before pinning it to the module core and before the module memory domain is set up, and resume it once the domain has been configured. This fixes a crash in tests with a userspace DP module on a secondary core: the worker thread started by k_work_user_queue_start() was still running on another core and had not yet reached its queue wait condition by the time k_thread_cpu_pin() was called. Signed-off-by: Serhiy Katsyuba --- .../module_adapter/library/userspace_proxy.c | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/audio/module_adapter/library/userspace_proxy.c b/src/audio/module_adapter/library/userspace_proxy.c index 79e55bd4124e..e7159ce5b8b7 100644 --- a/src/audio/module_adapter/library/userspace_proxy.c +++ b/src/audio/module_adapter/library/userspace_proxy.c @@ -206,10 +206,30 @@ static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t c params->cmd = cmd; +#if !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + /* The worker must not run while its CPU affinity and memory domain are reconfigured. */ + k_thread_suspend(worker.thread_id); + +#ifdef CONFIG_SCHED_CPU_MASK + /* Pin worker thread to the same core as the module */ + ret = k_thread_cpu_pin(worker.thread_id, cpu_get_id()); + if (ret < 0) { + tr_err(&userspace_proxy_tr, "Failed to pin cpu, error: %d", ret); + k_thread_resume(worker.thread_id); + return ret; + } +#elif CONFIG_CORE_COUNT > 1 +#error "CONFIG_SCHED_CPU_MASK is required" +#endif +#endif + if (ipc_payload_access) { ret = k_mem_domain_add_partition(user_ctx->comp_dom, &ipc_part); if (ret < 0) { tr_err(&userspace_proxy_tr, "Add mailbox to domain error: %d", ret); +#if !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) + k_thread_resume(worker.thread_id); +#endif return ret; } } @@ -217,20 +237,12 @@ static int userspace_proxy_invoke(struct userspace_context *user_ctx, uint32_t c #if !IS_ENABLED(CONFIG_SOF_USERSPACE_MOD_IPC_BY_DP_THREAD) /* Switch worker thread to module memory domain */ ret = k_mem_domain_add_thread(user_ctx->comp_dom, worker.thread_id); + k_thread_resume(worker.thread_id); if (ret < 0) { tr_err(&userspace_proxy_tr, "Failed to switch memory domain, error: %d", ret); goto done; } -#ifdef CONFIG_SCHED_CPU_MASK - /* Pin worker thread to the same core as the module */ - ret = k_thread_cpu_pin(worker.thread_id, cpu_get_id()); - if (ret < 0) { - tr_err(&userspace_proxy_tr, "Failed to pin cpu, error: %d", ret); - goto done; - } -#endif - ret = k_work_user_submit_to_queue(&worker.work_queue, &user_ctx->work_item->work_item); if (ret < 0) { tr_err(&userspace_proxy_tr, "Submit to queue error: %d", ret); From 0dad33d68c7a73152c64bde01c879943737f34a1 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 3 Aug 2026 11:16:40 +0800 Subject: [PATCH 002/109] topology2: rename sof-ptl-rt713-l3-rt1320-l1-2ch.tplg The existing sof-ptl-rt713-l3-rt1320-l1.tplg includes 2ch PCH DMIC. And the '-2ch' suffix will be added in the Linux driver. Rename sof-ptl-rt713-l3-rt1320-l1 to sof-ptl-rt713-l3-rt1320-l1-2ch. It is fine because the sof-ptl-rt713-l3-rt1320-l1.tplg was not released to sof-bin yet. Signed-off-by: Bard Liao --- tools/topology/topology2/production/tplg-targets-ace3.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/topology/topology2/production/tplg-targets-ace3.cmake b/tools/topology/topology2/production/tplg-targets-ace3.cmake index 3b5dc858fd20..bb1c07a83356 100644 --- a/tools/topology/topology2/production/tplg-targets-ace3.cmake +++ b/tools/topology/topology2/production/tplg-targets-ace3.cmake @@ -168,11 +168,11 @@ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture- SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack" # LG Gram Pro 2026 (16Z90U-KU7BK) with RT713 on link 3 and single stereo RT1320 on link 1 -"cavs-sdw\;sof-ptl-rt713-l3-rt1320-l1\;PLATFORM=ptl,SDW_DMIC=0,NUM_SDW_AMP_LINKS=1,\ +"cavs-sdw\;sof-ptl-rt713-l3-rt1320-l1-2ch\;PLATFORM=ptl,SDW_DMIC=0,NUM_SDW_AMP_LINKS=1,\ NUM_DMICS=2,PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=3,DMIC1_ID=4,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=SDW1-Playback,\ SDW_JACK_OUT_STREAM=SDW3-Playback,SDW_JACK_IN_STREAM=SDW3-Capture,\ -PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt713-l3-rt1320-l1.bin" +PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt713-l3-rt1320-l1-2ch.bin" "cavs-sdw\;sof-ptl-cs42l43-l2-cs35l56x6-l13\;NUM_SDW_AMP_LINKS=3,SDW_DMIC=1,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ From b0981fe6f00125f19acc79ddb05dfe72cb4e0ff8 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 22 Jul 2026 17:55:42 +0300 Subject: [PATCH 003/109] app: debug_stream_overlay.conf: Remove XTENSA_BACKTRACE_EXCEPTION_DUMP Remove XTENSA_BACKTRACE_EXCEPTION_DUMP option from debug_stream_overlay.conf since its removed from Zephyr in commit: ba8bb9a20f97 arch: xtensa: change backtrace to use EXCEPTION_DUMP Signed-off-by: Jyri Sarha --- app/debug_stream_overlay.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/debug_stream_overlay.conf b/app/debug_stream_overlay.conf index 7edd6bf6709c..7b0b6cba60cc 100644 --- a/app/debug_stream_overlay.conf +++ b/app/debug_stream_overlay.conf @@ -37,5 +37,4 @@ CONFIG_SOF_TELEMETRY_IO_PERFORMANCE_MEASUREMENTS=n CONFIG_EXCEPTION_DUMP_HOOK=y # Do not try to send exception prints through logs; this causes problems on PTL with mtrace CONFIG_EXCEPTION_DUMP_HOOK_ONLY=y -# Print also backtrace through the exception hook -CONFIG_XTENSA_BACKTRACE_EXCEPTION_DUMP_HOOK=y + From f17ec2b271aef1f74ceec757f89857902ce0eb80 Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Tue, 26 May 2026 16:09:12 +0200 Subject: [PATCH 004/109] module: multiband_drc: rework module to use sink/source api Rework the multiband drc module to only use the sink/source api to prepare sof for the full transition to pipeline 2.0. Signed-off-by: Piotr Hoppe --- lmdk/include/rtos/panic.h | 2 +- src/audio/multiband_drc/multiband_drc.c | 50 +++---- src/audio/multiband_drc/multiband_drc.h | 16 +-- .../multiband_drc/multiband_drc_generic.c | 131 +++++++++++++----- 4 files changed, 125 insertions(+), 74 deletions(-) diff --git a/lmdk/include/rtos/panic.h b/lmdk/include/rtos/panic.h index 65fafab75826..baef9541ddb9 100644 --- a/lmdk/include/rtos/panic.h +++ b/lmdk/include/rtos/panic.h @@ -13,7 +13,7 @@ extern "C" { #endif /* runtime assertion */ -#define assert(x) do { if (!(x)) while (1); } while (0) +#define assert(x) do {if (!(x)) while (1);} while (0) #ifdef __cplusplus } diff --git a/src/audio/multiband_drc/multiband_drc.c b/src/audio/multiband_drc/multiband_drc.c index df69d48a9bab..091cad43b03d 100644 --- a/src/audio/multiband_drc/multiband_drc.c +++ b/src/audio/multiband_drc/multiband_drc.c @@ -5,10 +5,8 @@ // Author: Pin-chih Lin #include -#include #include #include -#include #include #include #include @@ -339,24 +337,29 @@ __cold static int multiband_drc_get_config(struct processing_module *mod, } static int multiband_drc_process(struct processing_module *mod, - struct input_stream_buffer *input_buffers, int num_input_buffers, - struct output_stream_buffer *output_buffers, - int num_output_buffers) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct audio_stream *source = input_buffers[0].data; - struct audio_stream *sink = output_buffers[0].data; - int frames = input_buffers[0].size; + int frames = source_get_data_frames_available(sources[0]); + int sink_frames = sink_get_free_frames(sinks[0]); int ret; comp_dbg(dev, "entry"); + /* Process only as many frames as both the source provides and the + * sink can accept, otherwise the copy would fail with -ENODATA. + */ + frames = MIN(frames, sink_frames); + if (!frames) + return 0; + /* Check for changed configuration */ if (comp_is_new_data_blob_available(cd->model_handler)) { cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); - ret = multiband_drc_setup(mod, (int16_t)audio_stream_get_channels(sink), - audio_stream_get_rate(sink)); + ret = multiband_drc_setup(mod, (int16_t)sink_get_channels(sinks[0]), + sink_get_rate(sinks[0])); if (ret < 0) { comp_err(dev, "failed DRC setup"); return ret; @@ -364,13 +367,14 @@ static int multiband_drc_process(struct processing_module *mod, } if (cd->process_enabled) - cd->multiband_drc_func(mod, source, sink, frames); + ret = cd->multiband_drc_func(mod, sources[0], sinks[0], frames); else - multiband_drc_default_pass(mod, source, sink, frames); + ret = multiband_drc_default_pass(mod, sources[0], sinks[0], frames); - /* calc new free and available */ - module_update_buffer_position(&input_buffers[0], &output_buffers[0], frames); - return 0; + if (ret < 0) + comp_err(dev, "processing failed: %d", ret); + + return ret; } static int multiband_drc_prepare(struct processing_module *mod, @@ -379,7 +383,6 @@ static int multiband_drc_prepare(struct processing_module *mod, { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct comp_buffer *sourceb; int channels; int rate; int ret = 0; @@ -390,17 +393,10 @@ static int multiband_drc_prepare(struct processing_module *mod, if (ret < 0) return ret; - /* DRC component will only ever have 1 source and 1 sink buffer */ - sourceb = comp_dev_get_first_data_producer(dev); - if (!sourceb) { - comp_err(dev, "no source buffer"); - return -ENOTCONN; - } - /* get source data format */ - cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); - channels = audio_stream_get_channels(&sourceb->stream); - rate = audio_stream_get_rate(&sourceb->stream); + cd->source_format = source_get_frm_fmt(sources[0]); + channels = (int16_t)source_get_channels(sources[0]); + rate = source_get_rate(sources[0]); /* Initialize DRC */ comp_dbg(dev, "source_format=%d, sink_format=%d", @@ -442,7 +438,7 @@ static int multiband_drc_reset(struct processing_module *mod) static const struct module_interface multiband_drc_interface = { .init = multiband_drc_init, .prepare = multiband_drc_prepare, - .process_audio_stream = multiband_drc_process, + .process = multiband_drc_process, .set_configuration = multiband_drc_set_config, .get_configuration = multiband_drc_get_config, .reset = multiband_drc_reset, diff --git a/src/audio/multiband_drc/multiband_drc.h b/src/audio/multiband_drc/multiband_drc.h index 6a99fda55cef..ba939663de5d 100644 --- a/src/audio/multiband_drc/multiband_drc.h +++ b/src/audio/multiband_drc/multiband_drc.h @@ -28,10 +28,10 @@ struct multiband_drc_state { struct iir_state_df1 deemphasis[PLATFORM_MAX_CHANNELS]; }; -typedef void (*multiband_drc_func)(const struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames); +typedef int (*multiband_drc_func)(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); /* Multiband DRC component private data */ struct multiband_drc_comp_data { @@ -54,10 +54,10 @@ extern const struct multiband_drc_proc_fnmap multiband_drc_proc_fnmap[]; extern const struct multiband_drc_proc_fnmap multiband_drc_proc_fnmap_pass[]; extern const size_t multiband_drc_proc_fncount; -void multiband_drc_default_pass(const struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames); +int multiband_drc_default_pass(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames); /** * \brief Returns Multiband DRC processing function. diff --git a/src/audio/multiband_drc/multiband_drc_generic.c b/src/audio/multiband_drc/multiband_drc_generic.c index bd64f5012fc8..b14387a1baaf 100644 --- a/src/audio/multiband_drc/multiband_drc_generic.c +++ b/src/audio/multiband_drc/multiband_drc_generic.c @@ -6,17 +6,18 @@ #include #include +#include #include #include "multiband_drc.h" #include "../drc/drc_algorithm.h" -void multiband_drc_default_pass(const struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames) +int multiband_drc_default_pass(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) { - audio_stream_copy(source, 0, sink, 0, audio_stream_get_channels(source) * frames); + return source_to_sink_copy(source, sink, true, frames * source_get_frame_bytes(source)); } static void multiband_drc_process_emp_crossover(struct multiband_drc_state *state, @@ -203,10 +204,10 @@ static void multiband_drc_process_deemp(struct multiband_drc_state *state, * :buf_drc_src[nch*nband] :buf_sink[nch] */ #if CONFIG_FORMAT_S16LE -static void multiband_drc_s16_default(const struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames) +static int multiband_drc_s16_default(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct multiband_drc_state *state = &cd->state; @@ -216,22 +217,35 @@ static void multiband_drc_s16_default(const struct processing_module *mod, int32_t buf_drc_sink[PLATFORM_MAX_CHANNELS * SOF_MULTIBAND_DRC_MAX_BANDS]; int32_t *band_buf_drc_src; int32_t *band_buf_drc_sink; - int16_t *x = audio_stream_get_rptr(source); - int16_t *y = audio_stream_get_wptr(sink); + const int16_t *x, *buf_x_start; + int16_t *y, *buf_y_start; + int buf_x_samples, buf_y_samples; + size_t n_bytes = frames * source_get_frame_bytes(source); int band; int nbuf; int npcm; + int ret; int ch; int i; - int nch = audio_stream_get_channels(source); + int nch = source_get_channels(source); int nband = cd->config->num_bands; int enable_emp_deemp = cd->config->enable_emp_deemp; int samples = frames * nch; + ret = source_get_data_s16(source, n_bytes, &x, &buf_x_start, &buf_x_samples); + if (ret) + return ret; + + ret = sink_get_buffer_s16(sink, n_bytes, &y, &buf_y_start, &buf_y_samples); + if (ret) { + source_release_data(source, 0); + return ret; + } + while (samples) { - nbuf = audio_stream_samples_without_wrap_s16(source, x); + nbuf = cir_buf_samples_to_wrap_s16(x, buf_x_start, buf_x_samples); npcm = MIN(samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s16(sink, y); + nbuf = cir_buf_samples_to_wrap_s16(y, buf_y_start, buf_y_samples); npcm = MIN(npcm, nbuf); for (i = 0; i < npcm; i += nch) { for (ch = 0; ch < nch; ch++) { @@ -263,17 +277,22 @@ static void multiband_drc_s16_default(const struct processing_module *mod, } } samples -= npcm; - x = audio_stream_wrap(source, x); - y = audio_stream_wrap(sink, y); + if (x >= buf_x_start + buf_x_samples) + x = buf_x_start; + if (y >= buf_y_start + buf_y_samples) + y = buf_y_start; } + source_release_data(source, n_bytes); + sink_commit_buffer(sink, n_bytes); + return 0; } #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -static void multiband_drc_s24_default(const struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames) +static int multiband_drc_s24_default(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct multiband_drc_state *state = &cd->state; @@ -283,22 +302,35 @@ static void multiband_drc_s24_default(const struct processing_module *mod, int32_t buf_drc_sink[PLATFORM_MAX_CHANNELS * SOF_MULTIBAND_DRC_MAX_BANDS]; int32_t *band_buf_drc_src; int32_t *band_buf_drc_sink; - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); + const int32_t *x, *buf_x_start; + int32_t *y, *buf_y_start; + int buf_x_samples, buf_y_samples; + size_t n_bytes = frames * source_get_frame_bytes(source); int band; int nbuf; int npcm; + int ret; int ch; int i; - int nch = audio_stream_get_channels(source); + int nch = source_get_channels(source); int nband = cd->config->num_bands; int enable_emp_deemp = cd->config->enable_emp_deemp; int samples = frames * nch; + ret = source_get_data_s32(source, n_bytes, &x, &buf_x_start, &buf_x_samples); + if (ret) + return ret; + + ret = sink_get_buffer_s32(sink, n_bytes, &y, &buf_y_start, &buf_y_samples); + if (ret) { + source_release_data(source, 0); + return ret; + } + while (samples) { - nbuf = audio_stream_samples_without_wrap_s24(source, x); + nbuf = cir_buf_samples_to_wrap_s32(x, buf_x_start, buf_x_samples); npcm = MIN(samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s24(sink, y); + nbuf = cir_buf_samples_to_wrap_s32(y, buf_y_start, buf_y_samples); npcm = MIN(npcm, nbuf); for (i = 0; i < npcm; i += nch) { for (ch = 0; ch < nch; ch++) { @@ -330,17 +362,22 @@ static void multiband_drc_s24_default(const struct processing_module *mod, } } samples -= npcm; - x = audio_stream_wrap(source, x); - y = audio_stream_wrap(sink, y); + if (x >= buf_x_start + buf_x_samples) + x = buf_x_start; + if (y >= buf_y_start + buf_y_samples) + y = buf_y_start; } + source_release_data(source, n_bytes); + sink_commit_buffer(sink, n_bytes); + return 0; } #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -static void multiband_drc_s32_default(const struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - uint32_t frames) +static int multiband_drc_s32_default(const struct processing_module *mod, + struct sof_source *source, + struct sof_sink *sink, + uint32_t frames) { struct multiband_drc_comp_data *cd = module_get_private_data(mod); struct multiband_drc_state *state = &cd->state; @@ -350,22 +387,35 @@ static void multiband_drc_s32_default(const struct processing_module *mod, int32_t buf_drc_sink[PLATFORM_MAX_CHANNELS * SOF_MULTIBAND_DRC_MAX_BANDS]; int32_t *band_buf_drc_src; int32_t *band_buf_drc_sink; - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); + const int32_t *x, *buf_x_start; + int32_t *y, *buf_y_start; + int buf_x_samples, buf_y_samples; + size_t n_bytes = frames * source_get_frame_bytes(source); int band; int nbuf; int npcm; + int ret; int ch; int i; - int nch = audio_stream_get_channels(source); + int nch = source_get_channels(source); int nband = cd->config->num_bands; int enable_emp_deemp = cd->config->enable_emp_deemp; int samples = frames * nch; + ret = source_get_data_s32(source, n_bytes, &x, &buf_x_start, &buf_x_samples); + if (ret) + return ret; + + ret = sink_get_buffer_s32(sink, n_bytes, &y, &buf_y_start, &buf_y_samples); + if (ret) { + source_release_data(source, 0); + return ret; + } + while (samples) { - nbuf = audio_stream_samples_without_wrap_s32(source, x); + nbuf = cir_buf_samples_to_wrap_s32(x, buf_x_start, buf_x_samples); npcm = MIN(samples, nbuf); - nbuf = audio_stream_samples_without_wrap_s32(sink, y); + nbuf = cir_buf_samples_to_wrap_s32(y, buf_y_start, buf_y_samples); npcm = MIN(npcm, nbuf); for (i = 0; i < npcm; i += nch) { for (ch = 0; ch < nch; ch++) { @@ -397,9 +447,14 @@ static void multiband_drc_s32_default(const struct processing_module *mod, } } samples -= npcm; - x = audio_stream_wrap(source, x); - y = audio_stream_wrap(sink, y); + if (x >= buf_x_start + buf_x_samples) + x = buf_x_start; + if (y >= buf_y_start + buf_y_samples) + y = buf_y_start; } + source_release_data(source, n_bytes); + sink_commit_buffer(sink, n_bytes); + return 0; } #endif /* CONFIG_FORMAT_S32LE */ From ab4d58538fa565db3aa0192f533c0684793409ef Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Jun 2026 14:48:50 +0200 Subject: [PATCH 005/109] ipc: eliminate multiple memcpy() calls Eliminate multiple instances of IPC4 data copying, use simple type- casts instead. This removes stack objects and replaces run-time copying with compile-time pointer substitution. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/audio/component_ext.h | 2 +- src/include/sof/ipc/topology.h | 4 +- src/ipc/ipc4/handler-user.c | 255 +++++++++++--------------- src/ipc/ipc4/helper.c | 6 +- 4 files changed, 117 insertions(+), 150 deletions(-) diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 313ff42ab588..229b43f0bddc 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -37,7 +37,7 @@ struct comp_driver_list { #if CONFIG_IPC_MAJOR_3 struct comp_dev *comp_new(struct sof_ipc_comp *comp); #elif CONFIG_IPC_MAJOR_4 -struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init); +struct comp_dev *comp_new_ipc4(const struct ipc4_module_init_instance *module_init); #endif /** See comp_ops::free */ diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index a76c299aa60e..ceabc7006203 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -56,8 +56,8 @@ struct comp_driver; struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4, const struct comp_driver *drv); #endif -int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma); -int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma); +int ipc4_chain_manager_create(const struct ipc4_chain_dma *cdma); +int ipc4_chain_dma_state(struct comp_dev *dev, const struct ipc4_chain_dma *cdma); int ipc4_create_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma); int ipc4_trigger_chain_dma(struct ipc *ipc, struct ipc4_chain_dma *cdma, bool *delay); int ipc4_process_on_core(uint32_t core, bool blocking); diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index bc1712b2762a..57f1e8193deb 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -583,15 +583,11 @@ __cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) #if CONFIG_COMP_CHAIN_DMA struct ipc_comp_dev *cdma_comp; struct ipc *ipc = ipc_get(); - struct ipc4_chain_dma cdma; + const struct ipc4_chain_dma *cdma = (const struct ipc4_chain_dma *)ipc4; int comp_id; int ret; - ret = memcpy_s(&cdma, sizeof(cdma), ipc4, sizeof(*ipc4)); - if (ret < 0) - return IPC4_FAILURE; - - comp_id = IPC4_COMP_ID(cdma.primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT, 0); + comp_id = IPC4_COMP_ID(cdma->primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT, 0); cdma_comp = ipc_get_comp_by_id(ipc, comp_id); if (!cdma_comp) { @@ -599,10 +595,10 @@ __cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) * Nothing to do when the chainDMA is not allocated and asked to * be freed */ - if (!cdma.primary.r.allocate && !cdma.primary.r.enable) + if (!cdma->primary.r.allocate && !cdma->primary.r.enable) return IPC4_SUCCESS; - ret = ipc4_chain_manager_create(&cdma); + ret = ipc4_chain_manager_create(cdma); if (ret < 0) return IPC4_FAILURE; @@ -611,7 +607,7 @@ __cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) return IPC4_FAILURE; } - ret = ipc4_chain_dma_state(cdma_comp->cd, &cdma); + ret = ipc4_chain_dma_state(cdma_comp->cd, cdma); if (ret < 0) { comp_free(cdma_comp->cd); list_item_del(&cdma_comp->list); @@ -622,7 +618,7 @@ __cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) return IPC4_SUCCESS; } - ret = ipc4_chain_dma_state(cdma_comp->cd, &cdma); + ret = ipc4_chain_dma_state(cdma_comp->cd, cdma); if (ret < 0) return IPC4_INVALID_CHAIN_STATE_TRANSITION; @@ -760,31 +756,25 @@ int ipc4_user_process_glb_message(struct ipc4_message_request *ipc4, __cold static int ipc4_init_module_instance(struct ipc4_message_request *ipc4) { - struct ipc4_module_init_instance module_init; + const struct ipc4_module_init_instance *module_init = + (const struct ipc4_module_init_instance *)ipc4; struct comp_dev *dev; assert_can_be_cold(); - /* we only need the common header here, all we have from the IPC */ - int ret = memcpy_s(&module_init, sizeof(module_init), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - - tr_dbg(&ipc_tr, - "%x : %x", - (uint32_t)module_init.primary.r.module_id, - (uint32_t)module_init.primary.r.instance_id); + tr_dbg(&ipc_tr, "%x : %x", + (uint32_t)module_init->primary.r.module_id, + (uint32_t)module_init->primary.r.instance_id); /* Pass IPC to target core */ - if (!cpu_is_me(module_init.extension.r.core_id)) - return ipc4_process_on_core(module_init.extension.r.core_id, false); + if (!cpu_is_me(module_init->extension.r.core_id)) + return ipc4_process_on_core(module_init->extension.r.core_id, false); - dev = comp_new_ipc4(&module_init); + dev = comp_new_ipc4(module_init); if (!dev) { ipc_cmd_err(&ipc_tr, "error: failed to init module %x : %x", - (uint32_t)module_init.primary.r.module_id, - (uint32_t)module_init.primary.r.instance_id); + (uint32_t)module_init->primary.r.module_id, + (uint32_t)module_init->primary.r.instance_id); return IPC4_MOD_NOT_INITIALIZED; } @@ -794,40 +784,30 @@ __cold static int ipc4_init_module_instance(struct ipc4_message_request *ipc4) #ifndef CONFIG_SOF_USERSPACE_LL __cold static int ipc4_bind_module_instance(struct ipc4_message_request *ipc4) { - struct ipc4_module_bind_unbind bu; + struct ipc4_module_bind_unbind *bu = (struct ipc4_module_bind_unbind *)ipc4; struct ipc *ipc = ipc_get(); assert_can_be_cold(); - int ret = memcpy_s(&bu, sizeof(bu), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - tr_dbg(&ipc_tr, "%x : %x with %x : %x", - (uint32_t)bu.primary.r.module_id, (uint32_t)bu.primary.r.instance_id, - (uint32_t)bu.extension.r.dst_module_id, (uint32_t)bu.extension.r.dst_instance_id); + (uint32_t)bu->primary.r.module_id, (uint32_t)bu->primary.r.instance_id, + (uint32_t)bu->extension.r.dst_module_id, (uint32_t)bu->extension.r.dst_instance_id); - return ipc_comp_connect(ipc, (ipc_pipe_comp_connect *)&bu); + return ipc_comp_connect(ipc, (ipc_pipe_comp_connect *)bu); } __cold static int ipc4_unbind_module_instance(struct ipc4_message_request *ipc4) { - struct ipc4_module_bind_unbind bu; + struct ipc4_module_bind_unbind *bu = (struct ipc4_module_bind_unbind *)ipc4; struct ipc *ipc = ipc_get(); assert_can_be_cold(); - int ret = memcpy_s(&bu, sizeof(bu), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - tr_dbg(&ipc_tr, "%x : %x with %x : %x", - (uint32_t)bu.primary.r.module_id, (uint32_t)bu.primary.r.instance_id, - (uint32_t)bu.extension.r.dst_module_id, (uint32_t)bu.extension.r.dst_instance_id); + (uint32_t)bu->primary.r.module_id, (uint32_t)bu->primary.r.instance_id, + (uint32_t)bu->extension.r.dst_module_id, (uint32_t)bu->extension.r.dst_instance_id); - return ipc_comp_disconnect(ipc, (ipc_pipe_comp_connect *)&bu); + return ipc_comp_disconnect(ipc, (ipc_pipe_comp_connect *)bu); } #endif /* !CONFIG_SOF_USERSPACE_LL */ @@ -1048,30 +1028,27 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, void **reply_tx_data) { struct ipc4_module_large_config_reply reply; - struct ipc4_module_large_config config; + const struct ipc4_module_large_config *config = + (const struct ipc4_module_large_config *)ipc4; char *data = ipc_get()->comp_data; const struct comp_driver *drv; struct comp_dev *dev = NULL; uint32_t data_offset; + int ret; assert_can_be_cold(); - int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - tr_dbg(&ipc_tr, "%x : %x", - (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); + (uint32_t)config->primary.r.module_id, (uint32_t)config->primary.r.instance_id); /* get component dev for non-basefw since there is no * component dev for basefw */ - if (config.primary.r.module_id) { + if (config->primary.r.module_id) { uint32_t comp_id; - comp_id = IPC4_COMP_ID(config.primary.r.module_id, - config.primary.r.instance_id); + comp_id = IPC4_COMP_ID(config->primary.r.module_id, + config->primary.r.instance_id); dev = ipc4_get_comp_dev(comp_id); if (!dev) return IPC4_MOD_INVALID_ID; @@ -1082,7 +1059,7 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, * non-userspace path retains ipc4_process_on_core() */ } else { - drv = ipc4_get_comp_drv(config.primary.r.module_id); + drv = ipc4_get_comp_drv(config->primary.r.module_id); } if (!drv) @@ -1091,16 +1068,16 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, if (!drv->ops.get_large_config) return IPC4_INVALID_REQUEST; - data_offset = config.extension.r.data_off_size; + data_offset = config->extension.r.data_off_size; /* check for vendor param first */ - if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + if (config->extension.r.large_param_id == VENDOR_CONFIG_PARAM) { /* For now only vendor_config case uses payload from hostbox */ dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); + config->extension.r.data_off_size); ret = ipc4_get_vendor_config_module_instance(dev, drv, - config.extension.r.init_block, - config.extension.r.final_block, + config->extension.r.init_block, + config->extension.r.final_block, &data_offset, data, (const char *)MAILBOX_HOSTBOX_BASE); @@ -1108,12 +1085,12 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, #if CONFIG_LIBRARY data += sizeof(reply); #endif - ipc4_prepare_for_kcontrol_get(dev, config.extension.r.large_param_id, + ipc4_prepare_for_kcontrol_get(dev, config->extension.r.large_param_id, data, data_offset); - ret = drv->ops.get_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, - config.extension.r.final_block, + ret = drv->ops.get_large_config(dev, config->extension.r.large_param_id, + config->extension.r.init_block, + config->extension.r.final_block, &data_offset, data); } @@ -1122,11 +1099,11 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, ret = IPC4_MOD_INVALID_ID; /* Copy host config and overwrite */ - reply.extension.dat = config.extension.dat; + reply.extension.dat = config->extension.dat; reply.extension.r.data_off_size = data_offset; /* The last block, no more data */ - if (!config.extension.r.final_block && data_offset < SOF_IPC_MSG_MAX_SIZE) + if (!config->extension.r.final_block && data_offset < SOF_IPC_MSG_MAX_SIZE) reply.extension.r.final_block = 1; /* Indicate last block if error occurs */ @@ -1147,30 +1124,27 @@ __cold int ipc4_process_large_config_get(struct ipc4_message_request *ipc4, __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_request *ipc4) { struct ipc4_module_large_config_reply reply; - struct ipc4_module_large_config config; + const struct ipc4_module_large_config *config = + (const struct ipc4_module_large_config *)ipc4; char *data = ipc_get()->comp_data; const struct comp_driver *drv; struct comp_dev *dev = NULL; uint32_t data_offset; + int ret; assert_can_be_cold(); - int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - tr_dbg(&ipc_tr, "%x : %x", - (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); + (uint32_t)config->primary.r.module_id, (uint32_t)config->primary.r.instance_id); /* get component dev for non-basefw since there is no * component dev for basefw */ - if (config.primary.r.module_id) { + if (config->primary.r.module_id) { uint32_t comp_id; - comp_id = IPC4_COMP_ID(config.primary.r.module_id, - config.primary.r.instance_id); + comp_id = IPC4_COMP_ID(config->primary.r.module_id, + config->primary.r.instance_id); dev = ipc4_get_comp_dev(comp_id); if (!dev) return IPC4_INVALID_RESOURCE_ID; @@ -1182,10 +1156,10 @@ __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_requ return ipc4_process_on_core(dev->ipc_config.core, false); } else { /* BaseFW module has only 0th instance */ - if (config.primary.r.instance_id) + if (config->primary.r.instance_id) return IPC4_INVALID_RESOURCE_ID; - drv = ipc4_get_comp_drv(config.primary.r.module_id); + drv = ipc4_get_comp_drv(config->primary.r.module_id); } if (!drv) @@ -1194,10 +1168,10 @@ __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_requ if (!drv->ops.get_large_config) return IPC4_INVALID_REQUEST; - data_offset = config.extension.r.data_off_size; + data_offset = config->extension.r.data_off_size; /* check for vendor param first */ - if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + if (config->extension.r.large_param_id == VENDOR_CONFIG_PARAM) { /* data_off_size is a 20-bit host-controlled field, so it can * claim far more than the hostbox can physically hold. */ @@ -1208,23 +1182,22 @@ __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_requ } /* For now only vendor_config case uses payload from hostbox */ dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); + config->extension.r.data_off_size); ret = ipc4_get_vendor_config_module_instance(dev, drv, - config.extension.r.init_block, - config.extension.r.final_block, - &data_offset, - data, + config->extension.r.init_block, + config->extension.r.final_block, + &data_offset, data, (const char *)MAILBOX_HOSTBOX_BASE); } else { #if CONFIG_LIBRARY data += sizeof(reply); #endif - ipc4_prepare_for_kcontrol_get(dev, config.extension.r.large_param_id, + ipc4_prepare_for_kcontrol_get(dev, config->extension.r.large_param_id, data, data_offset); - ret = drv->ops.get_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, - config.extension.r.final_block, + ret = drv->ops.get_large_config(dev, config->extension.r.large_param_id, + config->extension.r.init_block, + config->extension.r.final_block, &data_offset, data); } @@ -1233,11 +1206,11 @@ __cold static int ipc4_get_large_config_module_instance(struct ipc4_message_requ ret = IPC4_INVALID_RESOURCE_ID; /* Copy host config and overwrite */ - reply.extension.dat = config.extension.dat; + reply.extension.dat = config->extension.dat; reply.extension.r.data_off_size = data_offset; /* The last block, no more data */ - if (!config.extension.r.final_block && data_offset < SOF_IPC_MSG_MAX_SIZE) + if (!config->extension.r.final_block && data_offset < SOF_IPC_MSG_MAX_SIZE) reply.extension.r.final_block = 1; /* Indicate last block if error occurs */ @@ -1338,26 +1311,23 @@ __cold static int ipc4_set_vendor_config_module_instance(struct comp_dev *dev, __cold int ipc4_process_large_config_set(struct ipc4_message_request *ipc4) { - struct ipc4_module_large_config config; + const struct ipc4_module_large_config *config = + (const struct ipc4_module_large_config *)ipc4; struct comp_dev *dev = NULL; const struct comp_driver *drv; + int ret; assert_can_be_cold(); - int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); + config->extension.r.data_off_size); tr_dbg(&ipc_tr, "%x : %x", - (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); + (uint32_t)config->primary.r.module_id, (uint32_t)config->primary.r.instance_id); - if (config.primary.r.module_id) { + if (config->primary.r.module_id) { uint32_t comp_id; - comp_id = IPC4_COMP_ID(config.primary.r.module_id, config.primary.r.instance_id); + comp_id = IPC4_COMP_ID(config->primary.r.module_id, config->primary.r.instance_id); dev = ipc4_get_comp_dev(comp_id); if (!dev) return IPC4_MOD_INVALID_ID; @@ -1368,7 +1338,7 @@ __cold int ipc4_process_large_config_set(struct ipc4_message_request *ipc4) * non-userspace path retains ipc4_process_on_core() */ } else { - drv = ipc4_get_comp_drv(config.primary.r.module_id); + drv = ipc4_get_comp_drv(config->primary.r.module_id); } if (!drv) @@ -1378,28 +1348,28 @@ __cold int ipc4_process_large_config_set(struct ipc4_message_request *ipc4) return IPC4_INVALID_REQUEST; /* check for vendor param first */ - if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + if (config->extension.r.large_param_id == VENDOR_CONFIG_PARAM) { ret = ipc4_set_vendor_config_module_instance(dev, drv, - (uint32_t)config.primary.r.module_id, - (uint32_t)config.primary.r.instance_id, - config.extension.r.init_block, - config.extension.r.final_block, - config.extension.r.data_off_size, + (uint32_t)config->primary.r.module_id, + (uint32_t)config->primary.r.instance_id, + config->extension.r.init_block, + config->extension.r.final_block, + config->extension.r.data_off_size, (const char *)MAILBOX_HOSTBOX_BASE); } else { #if CONFIG_LIBRARY struct ipc *ipc = ipc_get(); - const char *data = (const char *)ipc->comp_data + sizeof(config); + const char *data = (const char *)ipc->comp_data + sizeof(*config); #else const char *data = (const char *)MAILBOX_HOSTBOX_BASE; #endif - ret = drv->ops.set_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, config.extension.r.final_block, - config.extension.r.data_off_size, data); + ret = drv->ops.set_large_config(dev, config->extension.r.large_param_id, + config->extension.r.init_block, config->extension.r.final_block, + config->extension.r.data_off_size, data); if (ret < 0) { ipc_cmd_err(&ipc_tr, "failed to set large_config_module_instance %x : %x", - (uint32_t)config.primary.r.module_id, - (uint32_t)config.primary.r.instance_id); + (uint32_t)config->primary.r.module_id, + (uint32_t)config->primary.r.instance_id); ret = IPC4_INVALID_RESOURCE_ID; } } @@ -1409,26 +1379,23 @@ __cold int ipc4_process_large_config_set(struct ipc4_message_request *ipc4) __cold static int ipc4_set_large_config_module_instance(struct ipc4_message_request *ipc4) { - struct ipc4_module_large_config config; + const struct ipc4_module_large_config *config = + (const struct ipc4_module_large_config *)ipc4; struct comp_dev *dev = NULL; const struct comp_driver *drv; + int ret; assert_can_be_cold(); - int ret = memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - - if (ret < 0) - return IPC4_FAILURE; - dcache_invalidate_region((__sparse_force void __sparse_cache *)MAILBOX_HOSTBOX_BASE, - config.extension.r.data_off_size); + config->extension.r.data_off_size); tr_dbg(&ipc_tr, "%x : %x", - (uint32_t)config.primary.r.module_id, (uint32_t)config.primary.r.instance_id); + (uint32_t)config->primary.r.module_id, (uint32_t)config->primary.r.instance_id); - if (config.primary.r.module_id) { + if (config->primary.r.module_id) { uint32_t comp_id; - comp_id = IPC4_COMP_ID(config.primary.r.module_id, config.primary.r.instance_id); + comp_id = IPC4_COMP_ID(config->primary.r.module_id, config->primary.r.instance_id); dev = ipc4_get_comp_dev(comp_id); if (!dev) return IPC4_INVALID_RESOURCE_ID; @@ -1440,10 +1407,10 @@ __cold static int ipc4_set_large_config_module_instance(struct ipc4_message_requ return ipc4_process_on_core(dev->ipc_config.core, false); } else { /* BaseFW module has only 0th instance */ - if (config.primary.r.instance_id) + if (config->primary.r.instance_id) return IPC4_INVALID_RESOURCE_ID; - drv = ipc4_get_comp_drv(config.primary.r.module_id); + drv = ipc4_get_comp_drv(config->primary.r.module_id); } if (!drv) @@ -1453,28 +1420,28 @@ __cold static int ipc4_set_large_config_module_instance(struct ipc4_message_requ return IPC4_INVALID_REQUEST; /* check for vendor param first */ - if (config.extension.r.large_param_id == VENDOR_CONFIG_PARAM) { + if (config->extension.r.large_param_id == VENDOR_CONFIG_PARAM) { ret = ipc4_set_vendor_config_module_instance(dev, drv, - (uint32_t)config.primary.r.module_id, - (uint32_t)config.primary.r.instance_id, - config.extension.r.init_block, - config.extension.r.final_block, - config.extension.r.data_off_size, + (uint32_t)config->primary.r.module_id, + (uint32_t)config->primary.r.instance_id, + config->extension.r.init_block, + config->extension.r.final_block, + config->extension.r.data_off_size, (const char *)MAILBOX_HOSTBOX_BASE); } else { #if CONFIG_LIBRARY struct ipc *ipc = ipc_get(); - const char *data = (const char *)ipc->comp_data + sizeof(config); + const char *data = (const char *)ipc->comp_data + sizeof(*config); #else const char *data = (const char *)MAILBOX_HOSTBOX_BASE; #endif - ret = drv->ops.set_large_config(dev, config.extension.r.large_param_id, - config.extension.r.init_block, config.extension.r.final_block, - config.extension.r.data_off_size, data); + ret = drv->ops.set_large_config(dev, config->extension.r.large_param_id, + config->extension.r.init_block, config->extension.r.final_block, + config->extension.r.data_off_size, data); if (ret < 0) { ipc_cmd_err(&ipc_tr, "failed to set large_config_module_instance %x : %x", - (uint32_t)config.primary.r.module_id, - (uint32_t)config.primary.r.instance_id); + (uint32_t)config->primary.r.module_id, + (uint32_t)config->primary.r.instance_id); ret = IPC4_INVALID_RESOURCE_ID; } } @@ -1609,10 +1576,10 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, case SOF_IPC4_MOD_LARGE_CONFIG_GET: #ifdef CONFIG_SOF_USERSPACE_LL { - struct ipc4_module_large_config config; + const struct ipc4_module_large_config *config = + (const struct ipc4_module_large_config *)ipc4; - memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - if (config.primary.r.module_id) { + if (config->primary.r.module_id) { /* Module case: forward to user thread */ ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat); @@ -1639,10 +1606,10 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, case SOF_IPC4_MOD_LARGE_CONFIG_SET: #ifdef CONFIG_SOF_USERSPACE_LL { - struct ipc4_module_large_config config; + const struct ipc4_module_large_config *config = + (const struct ipc4_module_large_config *)ipc4; - memcpy_s(&config, sizeof(config), ipc4, sizeof(*ipc4)); - if (config.primary.r.module_id) { + if (config->primary.r.module_id) { ret = ipc_user_forward_cmd(ipc4->primary.dat, ipc4->extension.dat); } else { diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index fd8bd8bf3dbc..0ff30b42c000 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -110,7 +110,7 @@ __cold static inline char *ipc4_get_comp_new_data(void) #endif /* Only called from ipc4_init_module_instance(), which is __cold */ -__cold struct comp_dev *comp_new_ipc4(struct ipc4_module_init_instance *module_init) +__cold struct comp_dev *comp_new_ipc4(const struct ipc4_module_init_instance *module_init) { struct comp_ipc_config ipc_config; const struct comp_driver *drv; @@ -1148,7 +1148,7 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) #if CONFIG_COMP_CHAIN_DMA /* Only called from ipc4_process_chain_dma(), which is __cold */ -__cold int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma) +__cold int ipc4_chain_manager_create(const struct ipc4_chain_dma *cdma) { const struct sof_uuid uuid = SOF_REG_UUID(chain_dma); const struct comp_driver *drv; @@ -1175,7 +1175,7 @@ __cold int ipc4_chain_manager_create(struct ipc4_chain_dma *cdma) } /* Only called from ipc4_process_chain_dma(), which is __cold */ -__cold int ipc4_chain_dma_state(struct comp_dev *dev, struct ipc4_chain_dma *cdma) +__cold int ipc4_chain_dma_state(struct comp_dev *dev, const struct ipc4_chain_dma *cdma) { const bool allocate = cdma->primary.r.allocate; const bool enable = cdma->primary.r.enable; From 11200e576b23655f79e29ffd7611399aed33d146 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Mon, 27 Jul 2026 23:02:23 +0200 Subject: [PATCH 006/109] audio: copier: bound ALH mapping count to the gateway config size copier_alh_assign_dai_index() reads alh_cfg.count from the host-supplied gateway config blob and walks alh_cfg.mapping[0..count). Count was only bounded by the mapping[] array size, not the actual blob size, so a malformed blob could make the mapping walk read past config_data and underflow dma_config_length in the HDA branch. Validate that the blob contains the fixed header before reading count, then ensure count is within the mapping[] bound and that its computed ALH configuration size fits in the blob. This rejects malformed configurations before any mapping[] access. HDA always reads mapping[0], including for a single gateway. Reject a zero count in this path so a header-only blob cannot cause that out-of-bounds read. Keep zero-count behavior unchanged for single ALH, which does not access mapping[]. Use %zu when logging blob_size to preserve size_t values on 64-bit builds. Signed-off-by: Tomasz Leman --- src/audio/copier/copier_dai.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/audio/copier/copier_dai.c b/src/audio/copier/copier_dai.c index 109bc2a4a6b2..0e54c0c7a9e5 100644 --- a/src/audio/copier/copier_dai.c +++ b/src/audio/copier/copier_dai.c @@ -77,7 +77,8 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, struct copier_data *cd = module_get_private_data(mod); const struct sof_alh_configuration_blob *alh_blob = gtw_cfg_data; uint8_t *dma_config; - size_t alh_cfg_size, dma_config_length; + size_t alh_cfg_size, dma_config_length, blob_size; + uint32_t alh_count; int i, dai_num, ret; if (!cd->config.gtw_cfg.config_length) { @@ -85,20 +86,29 @@ static int copier_alh_assign_dai_index(struct comp_dev *dev, return -EINVAL; } + blob_size = (size_t)cd->config.gtw_cfg.config_length << 2; + if (blob_size < sizeof(alh_blob->gtw_attributes) + sizeof(alh_blob->alh_cfg.count)) { + comp_err(mod->dev, "Invalid ALH gateway config: blob=%zu bytes", blob_size); + return -EINVAL; + } + + alh_count = alh_blob->alh_cfg.count; + if (alh_count > IPC4_ALH_MAX_NUMBER_OF_GTW || + get_alh_config_size(alh_blob) > blob_size) { + comp_err(mod->dev, "Invalid ALH gateway config: count=%u, blob=%zu bytes", + alh_count, blob_size); + return -EINVAL; + } + alh_cfg_size = get_alh_config_size(alh_blob); + switch (dai->type) { case SOF_DAI_INTEL_HDA: /* We use DAI_INTEL_HDA for ACE 2.0 platforms */ - /* - * alh_cfg.count is host-controlled and scales the config size - * and mapping[] walk below; bound it before any arithmetic so a - * crafted blob cannot read past the gateway config. - */ - if (alh_blob->alh_cfg.count > IPC4_ALH_MAX_NUMBER_OF_GTW) { + if (!alh_count) { comp_err(mod->dev, "Invalid ALH count: %u", - alh_blob->alh_cfg.count); + alh_count); return -EINVAL; } - alh_cfg_size = get_alh_config_size(alh_blob); dma_config = (uint8_t *)gtw_cfg_data + alh_cfg_size; dma_config_length = (cd->config.gtw_cfg.config_length << 2) - alh_cfg_size; From 34b281fa8c7df5fd3a3cab7548b2c0150311f383 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 4 Aug 2026 09:12:19 +0200 Subject: [PATCH 007/109] west.yml: update to include a p4wq fix Update Zephyr to include 24f16b4f886c ("lib: os: p4wq: skip k_thread_cpu_mask_clear() in PIN_ONLY mode"). Signed-off-by: Guennadi Liakhovetski --- west.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/west.yml b/west.yml index 3a0dfa9a89bb..a684deb8871a 100644 --- a/west.yml +++ b/west.yml @@ -43,7 +43,7 @@ manifest: - name: zephyr repo-path: zephyr - revision: 9885b002c1bdfd520355de44daa34edefc86f9e6 + revision: fbd71c30f7b9083de9826577edb57d360efc01ed remote: zephyrproject # Import some projects listed in zephyr/west.yml@revision From de6d625d8b92435042b01331327452588af82583 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Wed, 5 Aug 2026 14:35:27 +0300 Subject: [PATCH 008/109] audio: phase vocoder: derive input format from module base_cfg This patch fixes the issue with the Phase Vocoder module producing strong rattle with other than s16 format decoded output from compress decoders such as MP3 and AAC. The pipeline bind path only propagates the container frame_fmt into the shared buffer between two modules; it does not populate valid_sample_fmt. As a result source_get_valid_fmt() on the phase vocoder's input returned the zero-initialised value (S16_LE), so the wrong processing variant was selected whenever the topology declared a valid bit depth other than 16. Signed-off-by: Seppo Ingalsuo --- src/audio/phase_vocoder/phase_vocoder.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/audio/phase_vocoder/phase_vocoder.c b/src/audio/phase_vocoder/phase_vocoder.c index b82bf700eb9e..b756dce72072 100644 --- a/src/audio/phase_vocoder/phase_vocoder.c +++ b/src/audio/phase_vocoder/phase_vocoder.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "phase_vocoder.h" @@ -177,6 +178,12 @@ static int phase_vocoder_prepare(struct processing_module *mod, struct sof_sourc return -EINVAL; } +#if CONFIG_IPC_MAJOR_4 + /* Push base_cfg.audio_fmt onto endpoints so valid_sample_fmt is not left at 0 (S16_LE). */ + ipc4_update_source_format(sources[0], &base_cfg->audio_fmt); + ipc4_update_sink_format(sinks[0], &base_cfg->audio_fmt); +#endif + /* get source data format */ cd->frame_bytes = source_get_frame_bytes(sources[0]); cd->stream_channels = source_get_channels(sources[0]); From 95b648c19eec275e3cd2179e2ac90dd150180359 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 31 Jul 2026 14:35:38 +0200 Subject: [PATCH 009/109] llext: adjust for MMU flag application The .cold section contains executable code, while .coldrodata contains data. Therefore their MMU flags have to be different, particularly when mapping for userspace. Add a page-size alignment to account for such cases. Signed-off-by: Guennadi Liakhovetski --- scripts/llext_link_helper.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/llext_link_helper.py b/scripts/llext_link_helper.py index f10777c9918f..3b6c2d451e7c 100755 --- a/scripts/llext_link_helper.py +++ b/scripts/llext_link_helper.py @@ -144,8 +144,7 @@ def main(): # critical functions in a .cold ELF section, read-only data in a # .coldrodata ELF section, etc. When compiling and linking such # functions, an additional .cold.literal section is automatically - # created. Note, that for some reason the compiler also marks .cold as - # executable. + # created. # This script links those sections at address 0. We could hard-code # section names, but so far we choose to only link .text the "original" # way and all other executable sections we link at 0. For data sections @@ -168,6 +167,8 @@ def main(): dram_addr += section.header['sh_size'] + dram_addr = align_up(dram_addr, 0x1000) + for section in readonly_dram: s_alignment = section.header['sh_addralign'] s_name = section.name From f5176b94a4dc97e9c62ea76d9cdeb949d76b33fd Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 4 Aug 2026 17:40:13 +0300 Subject: [PATCH 010/109] audio: phase_vocoder: re-anchor synthesis phase on speed change When the user changes the speed control the component preserves the polar analysis state across the reset so that the interpolation can continue smoothly, but the synthesis phase accumulator output_phase was left drifting. Each output IFFT in stft_do_fft_ifft() advances output_phase by an interpolated one-analysis-hop delta of the form (1 - frac) * angle_delta_prev + frac * angle_delta, where frac is the current interpolation position between two consecutive analysis frames. That delta is added irrespective of the current speed, so at non-unity speed output_phase runs faster than the true polar angle. On top of that, the first post-reset IFFT does not consume a new input FFT yet still applies its phase interpolation step (with frac = 0, so the added term equals angle_delta_prev), which adds one extra angle_delta_prev per reset. After a repeated excursion (for example 1.0 -> 0.5 -> 1.0 with several intermediate steps) both effects accumulate as a random per-bin phase offset that persists after returning to unity speed. Perceptually this smears transients and dulls the sound even though the audio is being processed at speed 1.0 again. The steady-state invariant at speed 1.0 is that after each IFFT's phase interpolation step output_phase equals polar_prev.angle. To preserve this invariant across a speed change, re-anchor output_phase to polar_prev.angle minus angle_delta_prev in reset_for_new_speed(). The first post-reset IFFT then lands output_phase exactly on polar_prev.angle, and all subsequent IFFTs advance normally with no cumulative offset. Existing NULL and channel-count guards keep the init-time call from touching buffers before they are allocated. Signed-off-by: Seppo Ingalsuo --- .../phase_vocoder/phase_vocoder_common.c | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/audio/phase_vocoder/phase_vocoder_common.c b/src/audio/phase_vocoder/phase_vocoder_common.c index d21f4e9e90e5..e31bc0239819 100644 --- a/src/audio/phase_vocoder/phase_vocoder_common.c +++ b/src/audio/phase_vocoder/phase_vocoder_common.c @@ -215,6 +215,12 @@ static int32_t unwrap_angle_q27(int32_t angle) void phase_vocoder_reset_for_new_speed(struct phase_vocoder_comp_data *cd) { struct phase_vocoder_state *state = &cd->state; + struct phase_vocoder_polar *polar = &state->polar; + struct phase_vocoder_fft *fft = &state->fft; + struct ipolar32 *polar_prev_ch; + int32_t *angle_delta_prev_ch; + int32_t *output_phase_ch; + int ch, i; state->speed = cd->speed_ctrl; @@ -232,6 +238,27 @@ void phase_vocoder_reset_for_new_speed(struct phase_vocoder_comp_data *cd) */ state->num_input_fft = 1; state->num_output_ifft = 0; + + /* Re-anchor synthesis phase so the first post-reset IFFT lands + * output_phase back on polar_prev.angle (the steady-state invariant). + * Between speed changes output_phase advances by one analysis-hop + * delta per output IFFT regardless of speed, so at speed != 1 it + * drifts away from the true polar angle; and each reset also adds + * one extra angle_delta_prev on the first no-consume IFFT. If not done, + * both accumulate across interactive speed changes as a per-bin + * phase offset that smears transients and dulls the sound. + */ + for (ch = 0; ch < cd->process_channels; ch++) { + polar_prev_ch = polar->polar_prev[ch]; + angle_delta_prev_ch = polar->angle_delta_prev[ch]; + output_phase_ch = polar->output_phase[ch]; + if (!polar_prev_ch || !angle_delta_prev_ch || !output_phase_ch) + continue; + + for (i = 0; i < fft->half_fft_size; i++) + output_phase_ch[i] = + unwrap_angle_q27(polar_prev_ch[i].angle - angle_delta_prev_ch[i]); + } } static void copy_polar_angles(int32_t *angle_delta_ch, struct ipolar32 *polar_data_ch, From d53a76259bc031471be99a73e5afdff9ba005d75 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 5 Aug 2026 15:12:42 +0200 Subject: [PATCH 011/109] platform: posix: tear down IPC topology between fuzz testcases Without an explicit teardown a fuzz testcase that successfully creates components, buffers or pipelines leaves them registered in global_ipc->comp_list. The next LLVMFuzzerTestOneInput() then sees a non-empty topology it never asked for, which both hides bugs (crashes that depend on freshly-empty state are missed) and fabricates them (crashes that only occur because of carry-over from a previous case are unreproducible when the artifact is replayed on its own). Add a posix-only teardown helper, called from posix_fuzz_case_begin() once at the start of every testcase before the input is staged. The helper: * Runs a pre-pass that forces every COMP_TYPE_COMPONENT to COMP_STATE_READY and initialises any NULL bsource_list/bsink_list pointers, because ipc_comp_free() returns -EINVAL (and silently leaks the entry) for a component that is not READY or whose buffer lists were never list_init()'d - the latter happens when a component was registered but its init failed partway through. The pre-pass also cancels any active pipeline pipe_task so ipc_pipeline_free() does not stall waiting for it (up to 100 LL periods on native_sim). * Drains each type in batches: it snapshots up to POSIX_TEARDOWN_BATCH ids, frees them with the typed helper, and repeats until no entry of that type remains, so the number of objects a testcase creates is not bounded by the snapshot size (walking and freeing comp_list in one pass is unsafe because the SOF free helpers unlink each entry). A batch that frees nothing ends the loop so it cannot spin forever. * Frees in dependency order COMPONENT -> BUFFER -> PIPELINE so the topology layer never dereferences an already-freed parent. The BUFFER pass is compiled out for IPC4 because ipc4/helper.c never stores COMP_TYPE_BUFFER and ipc_buffer_free() does not exist there. * Ends with a force-drain pass that walks the whole residual list with list_for_item_safe() and removes each entry with list_item_del() + rfree(), so comp_list is guaranteed empty on return regardless of how many objects remained or of any future COMP_TYPE_* the typed passes do not cover. Signed-off-by: Tomasz Leman --- src/platform/posix/ipc.c | 150 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/src/platform/posix/ipc.c b/src/platform/posix/ipc.c index 8ef28ec654e4..64586755d18c 100644 --- a/src/platform/posix/ipc.c +++ b/src/platform/posix/ipc.c @@ -7,10 +7,12 @@ #include #include #include +#include #include #include #include #include +#include // 6c8f0d53-ff77-4ca1-b825-c0c4e1b0d322 SOF_DEFINE_REG_UUID(ipc_task_posix); @@ -37,6 +39,153 @@ extern size_t posix_fuzz_sz; static uint8_t fuzz_in[65536]; static size_t fuzz_in_sz; +/* + * posix_ipc_teardown - drop all IPC-tracked objects left over from the + * previous fuzz testcase so the next one starts from a clean topology. + * + * Walking and freeing comp_list in the same pass is unsafe because the + * SOF free helpers unlink the entry from the list, so we snapshot the + * IDs of one type into a local array first and then call the typed + * free function for each one. Passes run in dependency order + * (COMPONENT -> BUFFER -> PIPELINE) to keep the SOF topology layer + * from dereferencing already-freed parents. + * + * Each typed pass drains in batches: it snapshots up to + * POSIX_TEARDOWN_BATCH ids, frees them, and repeats until no entry of + * that type is left, so the number of objects a testcase may create is + * not bounded by the snapshot size. + * + * A final force-drain pass then walks anything still on the list with + * list_for_item_safe() and removes it with list_item_del() + rfree() + * directly. That keeps the harness future-proof against new COMP_TYPE_* + * values and against entries a typed free could not release: whatever + * the reason, comp_list is guaranteed empty on return. The inner union + * object (cd/cb/pipeline) is leaked in that edge case, which is + * acceptable for a fuzzing harness. + */ +#define POSIX_TEARDOWN_BATCH 256 + +static void posix_ipc_teardown(void) +{ + static const uint16_t free_order[] = { + COMP_TYPE_COMPONENT, +#if CONFIG_IPC_MAJOR_3 + /* + * IPC4 never stores COMP_TYPE_BUFFER in comp_list + * (see ipc4/helper.c) and ipc_buffer_free() is not + * compiled for IPC4, so skip the buffer pass there. + */ + COMP_TYPE_BUFFER, +#endif + COMP_TYPE_PIPELINE, + }; + uint32_t ids[POSIX_TEARDOWN_BATCH]; + struct ipc_comp_dev *icd; + struct list_item *pos, *tmp; + int n; + + if (!global_ipc) + return; + + /* + * Pre-pass: prepare components and pipelines for the ordered free + * passes below. + * + * ipc_comp_free() refuses to free a component unless its state is + * COMP_STATE_READY. A fuzz testcase that ran INIT_INSTANCE followed + * by SET_PIPELINE_STATE:RUNNING will leave components in PREPARE, + * PAUSED, or ACTIVE state. Force every component back to READY so + * the free pass can proceed without silently skipping entries. + * + * For pipelines with an active scheduler task, cancel the task before + * ipc_pipeline_free() calls schedule_task_free() on it. Without this, + * schedule_task_free() blocks waiting for the task to complete, which + * on native_sim can stall for up to 100 LL periods. + */ + list_for_item(pos, &global_ipc->comp_list) { + icd = container_of(pos, struct ipc_comp_dev, list); + if (icd->type == COMP_TYPE_COMPONENT && icd->cd) { + icd->cd->state = COMP_STATE_READY; + /* Ensure buffer lists are valid so ipc_comp_free() + * does not bail at the uninitialized-list check. + * A component whose init failed partway may have + * NULL list pointers. + */ + if (!icd->cd->bsource_list.next) + list_init(&icd->cd->bsource_list); + if (!icd->cd->bsink_list.next) + list_init(&icd->cd->bsink_list); + } + if (icd->type == COMP_TYPE_PIPELINE && + icd->pipeline && icd->pipeline->pipe_task) + schedule_task_cancel(icd->pipeline->pipe_task); + } + + for (int pass = 0; pass < (int)ARRAY_SIZE(free_order); pass++) { + uint16_t type = free_order[pass]; + + /* + * Drain this type in batches. The ipc_*_free() helpers + * unlink each entry internally, so snapshot up to + * POSIX_TEARDOWN_BATCH ids, free them, and repeat until no + * entry of this type is left. A batch that frees nothing + * (e.g. an entry ipc_comp_free() refuses to release) ends the + * loop so it cannot spin forever; the force-drain pass below + * removes any such straggler. + */ + do { + int freed = 0; + + n = 0; + list_for_item(pos, &global_ipc->comp_list) { + icd = container_of(pos, struct ipc_comp_dev, + list); + if (icd->type == type && + n < POSIX_TEARDOWN_BATCH) + ids[n++] = icd->id; + } + + for (int i = 0; i < n; i++) { + int ret = -EINVAL; + + switch (type) { + case COMP_TYPE_COMPONENT: + ret = ipc_comp_free(global_ipc, ids[i]); + break; +#if CONFIG_IPC_MAJOR_3 + case COMP_TYPE_BUFFER: + ret = ipc_buffer_free(global_ipc, ids[i]); + break; +#endif + case COMP_TYPE_PIPELINE: + ret = ipc_pipeline_free(global_ipc, + ids[i]); + break; + } + if (!ret) + freed++; + } + + if (!freed) + break; + } while (n == POSIX_TEARDOWN_BATCH); + } + + /* + * Force-drain anything still on the list: unknown/future + * COMP_TYPE_* values or entries a typed free could not release. + * Walk with the _safe variant because each entry is unlinked as it + * is visited. The inner union pointer leaks, but comp_list is empty + * on return regardless of how many objects remained, so the next + * testcase never observes a stale entry. + */ + list_for_item_safe(pos, tmp, &global_ipc->comp_list) { + icd = container_of(pos, struct ipc_comp_dev, list); + list_item_del(&icd->list); + rfree(icd); + } +} + /* * Testcase-isolation helpers used by the libFuzzer entry point in * fuzz.c. They keep ownership of the cross-call state in one module @@ -45,6 +194,7 @@ static size_t fuzz_in_sz; */ void posix_fuzz_case_begin(void) { + posix_ipc_teardown(); fuzz_in_sz = 0; } From ffa52dfc247ef1636c3ba16add4ee2b180d6c53c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 6 Aug 2026 17:12:31 +0200 Subject: [PATCH 012/109] schedule: ll: dynamically allocate the semaphore The LL scheduler semaphore is used by the userspace, so it has to be allocated dynamically. On the other hand dynamic object freeing from the userspace is unsupported by design. To securely free the semaphore object we add two syscalls that guarantee, that object freeing cannot be abused. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/schedule/ll_schedule_domain.h | 10 ++ src/schedule/zephyr_ll.c | 120 +++++++++++++++++- zephyr/CMakeLists.txt | 1 + 3 files changed, 126 insertions(+), 5 deletions(-) diff --git a/src/include/sof/schedule/ll_schedule_domain.h b/src/include/sof/schedule/ll_schedule_domain.h index f356566ca0aa..b4b58e6923e2 100644 --- a/src/include/sof/schedule/ll_schedule_domain.h +++ b/src/include/sof/schedule/ll_schedule_domain.h @@ -330,6 +330,16 @@ struct ll_schedule_domain *zephyr_domain_init(int clk); struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain); struct k_mem_domain *zephyr_ll_mem_domain(void); #endif /* CONFIG_SOF_USERSPACE_LL */ +#ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION +__syscall int zephyr_ll_task_sem_alloc(struct task *task); +__syscall int zephyr_ll_task_sem_free(struct task *task); +#include +#else +int z_impl_zephyr_ll_task_sem_alloc(struct task *task); +int z_impl_zephyr_ll_task_sem_free(struct task *task); +#define zephyr_ll_task_sem_alloc z_impl_zephyr_ll_task_sem_alloc +#define zephyr_ll_task_sem_free z_impl_zephyr_ll_task_sem_free +#endif /* CONFIG_SOF_FULL_ZEPHYR_APPLICATION */ #endif /* __ZEPHYR__ */ struct ll_schedule_domain *dma_multi_chan_domain_init(struct dma *dma_array, diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 85c7f80552c6..15a1846bcadf 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -41,7 +41,10 @@ struct zephyr_ll { struct zephyr_ll_pdata { bool run; bool freeing; + struct k_sem *sem_p; +#if !CONFIG_DYNAMIC_OBJECTS struct k_sem sem; +#endif }; #if CONFIG_SOF_USERSPACE_LL @@ -136,7 +139,7 @@ static void zephyr_ll_task_done(struct zephyr_ll *sch, * zephyr_ll_task_free() is trying to free this task. Complete * it and signal the semaphore to let the function proceed */ - k_sem_give(&pdata->sem); + k_sem_give(pdata->sem_p); tr_info(&ll_tr, "task complete %p %pU", task, task->uid); tr_info(&ll_tr, "num_tasks %d total_num_tasks %ld", @@ -448,6 +451,98 @@ static int zephyr_ll_task_schedule_after(void *data, struct task *task, uint64_t return zephyr_ll_task_schedule_common(sch, task, start, period, after, false); } +#if CONFIG_DYNAMIC_OBJECTS +static struct list_item zephyr_ll_task_sem_list = LIST_INIT(zephyr_ll_task_sem_list); + +struct zephyr_ll_task_sem { + struct task *task; + struct k_sem *sem; + struct list_item list; +}; + +int z_impl_zephyr_ll_task_sem_alloc(struct task *task) +{ + struct zephyr_ll_pdata *pdata = task->priv_data; + struct zephyr_ll_task_sem *ts = rmalloc(SOF_MEM_FLAG_COHERENT, sizeof(*ts)); + + if (!ts) + return -ENOMEM; + + ts->sem = k_object_alloc(K_OBJ_SEM); + if (!ts->sem) { + rfree(ts); + return -ENOMEM; + } + + k_sem_init(ts->sem, 0, 1); + + ts->task = task; + pdata->sem_p = ts->sem; + /* List is protected by IPC serialization */ + list_item_append(&ts->list, &zephyr_ll_task_sem_list); + + return 0; +} + +int z_impl_zephyr_ll_task_sem_free(struct task *task) +{ + struct zephyr_ll_pdata *pdata = task->priv_data; + struct list_item *list; + struct zephyr_ll_task_sem *ts; + bool found = false; + + /* List is protected by IPC serialization */ + list_for_item(list, &zephyr_ll_task_sem_list) { + ts = container_of(list, struct zephyr_ll_task_sem, list); + if (ts->task == task) { + found = true; + break; + } + } + + if (!found) + return -ENOENT; + + if (pdata->sem_p != ts->sem) + return -EINVAL; + + list_item_del(list); + k_object_free(ts->sem); + rfree(ts); + + return 0; +} + +#ifdef CONFIG_USERSPACE +#include +static inline int z_vrfy_zephyr_ll_task_sem_alloc(struct task *task) +{ + if (!task) + return -EINVAL; + K_OOPS(K_SYSCALL_MEMORY_WRITE(task, sizeof(*task))); + if (!task->priv_data) + return -EINVAL; + K_OOPS(K_SYSCALL_MEMORY_WRITE(task->priv_data, sizeof(struct zephyr_ll_pdata))); + + return z_impl_zephyr_ll_task_sem_alloc(task); +} +#include + +static inline int z_vrfy_zephyr_ll_task_sem_free(struct task *task) +{ + if (!task) + return -EINVAL; + K_OOPS(K_SYSCALL_MEMORY_WRITE(task, sizeof(*task))); + if (!task->priv_data) + return -EINVAL; + K_OOPS(K_SYSCALL_MEMORY_WRITE(task->priv_data, sizeof(struct zephyr_ll_pdata))); + + return z_impl_zephyr_ll_task_sem_free(task); +} +#include +#endif +#endif + /* * This is synchronous - after this returns the object can be destroyed! * Assertion: under Zephyr this is always called from a thread context! @@ -505,10 +600,13 @@ static int zephyr_ll_task_free(void *data, struct task *task) if (must_wait) /* Wait for up to 100 periods */ - k_sem_take(&pdata->sem, K_USEC(LL_TIMER_PERIOD_US * 100)); + k_sem_take(pdata->sem_p, K_USEC(LL_TIMER_PERIOD_US * 100)); /* Protect against racing with schedule_task() */ zephyr_ll_lock(sch, &flags); +#if CONFIG_DYNAMIC_OBJECTS + zephyr_ll_task_sem_free(task); +#endif task->priv_data = NULL; sof_heap_free(sch->heap, pdata); zephyr_ll_unlock(sch, &flags); @@ -573,6 +671,7 @@ static void zephyr_ll_scheduler_free(void *data, uint32_t flags) struct k_thread *zephyr_ll_init_context(void *data, struct task *task) { struct zephyr_ll *sch = data; + struct zephyr_ll_pdata *pdata = task->priv_data; int ret; /* @@ -587,7 +686,7 @@ struct k_thread *zephyr_ll_init_context(void *data, struct task *task) } assert(!k_is_user_context()); - k_thread_access_grant(zephyr_domain_thread_tid(sch->ll_domain), sch->lock); + k_thread_access_grant(zephyr_domain_thread_tid(sch->ll_domain), sch->lock, pdata->sem_p); tr_dbg(&ll_tr, "granting access to lock %p for thread %p", sch->lock, zephyr_domain_thread_tid(sch->ll_domain)); @@ -698,10 +797,21 @@ int zephyr_ll_task_init(struct task *task, memset(pdata, 0, sizeof(*pdata)); - k_sem_init(&pdata->sem, 0, 1); - task->priv_data = pdata; +#if CONFIG_DYNAMIC_OBJECTS + ret = zephyr_ll_task_sem_alloc(task); + if (ret < 0) { + sof_heap_free(heap, pdata); + task->priv_data = NULL; + return ret; + } +#else + pdata->sem_p = &pdata->sem; +#endif + + k_sem_init(pdata->sem_p, 0, 1); + return 0; } EXPORT_SYMBOL(zephyr_ll_task_init); diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 4b61a9517d46..0ed4a13ee742 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -623,6 +623,7 @@ zephyr_library_sources_ifdef(CONFIG_SHELL zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/audio/module_adapter/module/generic.h) zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/fast-get.h) zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/ipc/ipc_reply.h) +zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/schedule/ll_schedule_domain.h) zephyr_syscall_header(${SOF_SRC_PATH}/include/ipc4/handler.h) zephyr_syscall_header(include/rtos/alloc.h) zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_INTERFACE_ALLOC syscall/alloc.c) From 58a8d62eca0e3f01034b90bbac7d0e1dd45c1aed Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 5 Aug 2026 15:12:42 +0200 Subject: [PATCH 013/109] ipc4: helper: unlock module instance verbs on native_sim ipc4_get_comp_drv() returned NULL unconditionally on native_sim because the RIMAGE_MANIFEST guard (Intel ADSP ACE/CAVS only) was the sole path to a driver UUID lookup. Every INIT_INSTANCE call therefore failed with IPC4_MOD_NOT_INITIALIZED before creating any comp_dev, making the entire module instance verb surface (CONFIG_GET/SET, LARGE_CONFIG on real modules, BIND, UNBIND, DELETE_INSTANCE) unreachable from the fuzzer. Resolve module drivers on native_sim from a small fuzzer-only helper, ipc4_get_fuzzer_drv(), called from the CONFIG_ARCH_POSIX_LIBFUZZER branch of ipc4_get_comp_drv() so the heavily-used manifest lookup path is left untouched. It mirrors the IPC3 whitebox hack in posix/ipc.c: module_id is a 1-based index into the runtime component driver list, counting only instantiable module-adapter drivers so the fuzzer's module_id space matches what a real signed manifest exposes. Drivers with no ops.create, and internal gateway drivers (SOF_COMP_HOST/DAI) that are never IPC4 modules, are skipped (otherwise a module_id could land on an unconfigurable component or a NULL create op). module_id 0 (BaseFW) intentionally resolves to NULL: BaseFW is never created as a pipeline component, its messages are dispatched directly by base_fw.c. A tr_err() logs any module_id that maps to no driver to help developers and agents triage. The change is inactive in all non-fuzz builds. Measured impact (UBSan IPC4, seed=1, 20 s, small corpus): cov ~558 -> ~3974 (~7x lift from previously dead module instance paths) Signed-off-by: Tomasz Leman --- src/ipc/ipc4/helper.c | 64 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 0ff30b42c000..2fac5337f0f4 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1344,6 +1344,68 @@ __cold static const struct comp_driver *ipc4_get_drv(const void *uuid) return drv; } +#if defined(CONFIG_ARCH_POSIX_LIBFUZZER) && !defined(RIMAGE_MANIFEST) +/* + * ipc4_get_fuzzer_drv - resolve a module driver for native_sim fuzz builds. + * + * native_sim fuzz builds have no rimage manifest, so the manifest lookup in + * ipc4_get_comp_drv() can never resolve a driver and every module instance + * verb (INIT_INSTANCE, CONFIG_GET/SET, LARGE_CONFIG, BIND, UNBIND, + * DELETE_INSTANCE) would be unreachable from the fuzzer. + * + * Mirror the IPC3 whitebox hack in posix/ipc.c and treat module_id as a + * 1-based index into the runtime component driver list, counting only + * instantiable module-adapter drivers so the fuzzer's module_id space matches + * what a real signed manifest would expose. + * + * module_id 0 (BaseFW) is deliberately not mapped: BaseFW is never created as + * a pipeline component - its messages are dispatched directly by base_fw.c - + * so returning NULL for it here is correct. + */ +static const struct comp_driver *ipc4_get_fuzzer_drv(uint32_t module_id) +{ + struct comp_driver_list *dlist = comp_drivers_get(); + struct list_item *iter; + uint32_t idx = 0; + + if (!module_id) + return NULL; + + list_for_item(iter, &dlist->list) { + struct comp_driver_info *inf = + container_of(iter, struct comp_driver_info, list); + + /* + * Skip query-only entries (e.g. BaseFW) that cannot be + * instantiated because they have no create op. + */ + if (!inf->drv->ops.create) + continue; + + /* + * A real signed manifest only lists module-adapter modules. + * The internal gateway drivers (SOF_COMP_HOST, SOF_COMP_DAI) + * are registered for IPC3 but are never IPC4 modules: on the + * IPC4 path they receive no params() pass and cannot be + * configured (e.g. their DMA buffer is never allocated). Skip + * non-module-adapter drivers so the fuzzer's module_id space + * matches a real manifest and cannot map to an unconfigurable + * component. + */ + if (inf->drv->type != SOF_COMP_MODULE_ADAPTER) + continue; + + if (++idx == module_id) + return inf->drv; + } + + tr_err(&comp_tr, + "no instantiable driver at module_id %u (%u available)", + module_id, idx); + return NULL; +} +#endif + /* * Called from * - ipc4_get_large_config_module_instance() @@ -1361,6 +1423,8 @@ __cold const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id) #ifdef RIMAGE_MANIFEST desc = (const struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; +#elif defined(CONFIG_ARCH_POSIX_LIBFUZZER) + return ipc4_get_fuzzer_drv(module_id); #else /* Non-rimage platforms have no component facility yet. * This needs to move to the platform layer. From a1d5df0959ecf15ddb3c4526bc44d5e4eb654351 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Tue, 21 Jul 2026 20:00:50 +0200 Subject: [PATCH 014/109] audio: selector: guard against missing source component in trigger The IPC fuzzer hit a NULL pointer dereference in the IPC3 path while triggering a pipeline that contains a selector component. Both AddressSanitizer and UBSan report a READ SEGV at address 0x30 in dev_comp_type() (src/include/sof/audio/component.h). 0x30 is the offset of comp_dev::ipc_config.type, i.e. the accessor was called on a NULL comp_dev. Root cause: a comp_buffer links a producer on its ->source side to a consumer on its ->sink side, and buffers are zero-initialised, so an unconnected side stays NULL. selector_trigger() checks only that its source buffer exists and then passes that buffer's producer component straight to dev_comp_type() to look for an upstream KPB: type = dev_comp_type(comp_buffer_get_source_component(sourceb)); When the source buffer is attached to the selector but never attached to an upstream producer, comp_buffer::source is NULL and dev_comp_type() dereferences it. The mirror-image lookup in kpb.c already guards against a missing peer component; selector_trigger() was the only site doing this without the check. Look up the producer component first and treat a missing producer as "not a KPB" instead of dereferencing it. Also honour the comp_set_state() return value: the crashing trigger was a PAUSE issued from COMP_STATE_READY, which comp_set_state() already rejects with -EINVAL, but selector_trigger() ignored the error and fell through to the dereference. Bail out on error like every other component trigger handler. Signed-off-by: Tomasz Leman --- src/audio/selector/selector.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index faf21da0e228..df814b6c24f6 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -411,7 +411,7 @@ static int selector_cmd(struct comp_dev *dev, int cmd, void *data, static int selector_trigger(struct comp_dev *dev, int cmd) { struct comp_buffer *sourceb; - enum sof_comp_type type; + struct comp_dev *source_comp; int ret; comp_dbg(dev, "entry"); @@ -423,6 +423,8 @@ static int selector_trigger(struct comp_dev *dev, int cmd) } ret = comp_set_state(dev, cmd); + if (ret < 0) + return ret; if (ret == COMP_STATUS_STATE_ALREADY_SET) ret = 0; @@ -430,9 +432,14 @@ static int selector_trigger(struct comp_dev *dev, int cmd) * kpb_init_draining() and kpb_draining_task() are interrupted by * new pipeline_task() */ - type = dev_comp_type(comp_buffer_get_source_component(sourceb)); + /* The source buffer may be present without an attached producer + * component (e.g. a partially connected pipeline), so guard against a + * NULL source component before dereferencing it. + */ + source_comp = comp_buffer_get_source_component(sourceb); - return type == SOF_COMP_KPB ? PPL_STATUS_PATH_TERMINATE : ret; + return source_comp && dev_comp_type(source_comp) == SOF_COMP_KPB ? + PPL_STATUS_PATH_TERMINATE : ret; } /** From 22962296c1737560a5a1c3ced49a6562608cb80b Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Tue, 4 Aug 2026 19:39:47 +0200 Subject: [PATCH 015/109] audio: pipeline: guard NULL buffer peer in pipeline_get_dai_comp The IPC fuzzer built an IPC3 pipeline whose component owned a half-connected buffer - present on the component's buffer list but with no component attached to its opposite end - and then issued a SOF_IPC_STREAM_POSITION request. ipc_stream_position() calls pipeline_get_timestamp(), which walks the graph with pipeline_get_dai_comp() to locate the DAI endpoint. For each hop the walk takes the buffer's peer component via buffer_get_comp() and immediately dereferences comp->pipeline. For a dangling buffer buffer_get_comp() returns NULL, so the read faults at NULL + 8 (the ->pipeline field). A comp_buffer only carries a peer on a side once both ends are attached, but the IPC3 graph is assembled incrementally (each COMP_CONNECT attaches a single end) so a buffer can be left half-connected. The STREAM_POSITION path reaches this walk directly, independent of the trigger path, and does not go through the pipeline-run connectivity checks: a pipeline can be completed and then have a half-connected buffer attached by a later COMP_CONNECT, and a subsequent POSITION request walks the dangling edge. Guard the peer before dereferencing it, mirroring the existing checks in the tree: the IPC4 sibling pipeline_get_dai_comp_latency() already checks "if (!source || !source->pipeline)", and the XRUN rewind walk in pipeline_trigger_xrun() checks "if (!buffer_comp || !buffer_comp->pipeline)". A fully-connected buffer always has a non-NULL peer and a cross-pipeline peer keeps a non-NULL pointer, so only a genuinely dangling buffer is rejected and valid topologies are unaffected. pipeline_get_timestamp() already tolerates a NULL DAI result. Signed-off-by: Tomasz Leman --- src/audio/pipeline/pipeline-graph.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index adcb00a80719..6e154dfbfba6 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -506,8 +506,10 @@ struct comp_dev *pipeline_get_dai_comp(uint32_t pipeline_id, int dir) buffer = buffer_from_list(blist->next, dir); comp = buffer_get_comp(buffer, dir); - /* buffer_comp is in another pipeline and it is not complete */ - if (!comp->pipeline) + /* A half-connected buffer has no peer component on this side, or + * buffer_comp is in another pipeline and it is not complete. + */ + if (!comp || !comp->pipeline) return NULL; crt = ipc_get_ppl_comp(ipc, comp->pipeline->pipeline_id, dir); From 974dc492741e906a7bf6a139c06de246932bc495 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Tue, 28 Jul 2026 17:45:56 +0200 Subject: [PATCH 016/109] audio: component: Add const to source buffer parameter in cir_buf_copy() Qualify the source pointer of circular buffer as const in cir_buf_copy() and cir_buf_bytes_without_wrap() functions. Signed-off-by: Adrian Warecki --- src/audio/component.c | 12 ++++++------ src/include/sof/audio/audio_stream.h | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/audio/component.c b/src/audio/component.c index e2d32367f322..3c7021057259 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -269,7 +269,7 @@ int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, return samples; } -void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, +void cir_buf_copy(const void *src, const void *src_addr, const void *src_end, void *dst, void *dst_addr, void *dst_end, size_t byte_size) { size_t bytes = byte_size; @@ -281,7 +281,7 @@ void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, ae_int16x4 in_sample1, in_sample2; ae_valignx2 inu; ae_valignx2 outu = AE_ZALIGN128(); - ae_int16x8 *in = (ae_int16x8 *)src; + const ae_int16x8 *in = cir_buf_wrap(src, src_addr, src_end); ae_int16x8 *out = (ae_int16x8 *)dst; while (bytes) { @@ -360,7 +360,7 @@ int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, return samples; } -void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, +void cir_buf_copy(const void *src, const void *src_addr, const void *src_end, void *dst, void *dst_addr, void *dst_end, size_t byte_size) { size_t bytes = byte_size; @@ -373,7 +373,7 @@ void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, ae_int16x4 in_sample = AE_ZERO16(); ae_valign inu = AE_ZALIGN64(); ae_valign outu = AE_ZALIGN64(); - ae_int16x4 *in = (ae_int16x4 *)src; + ae_int16x4 *in = cir_buf_wrap(src, src_addr, src_end); ae_int16x4 *out = (ae_int16x4 *)dst; while (bytes) { @@ -433,14 +433,14 @@ int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, return samples; } -void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, +void cir_buf_copy(const void *src, const void *src_addr, const void *src_end, void *dst, void *dst_addr, void *dst_end, size_t byte_size) { size_t bytes = byte_size; size_t bytes_src; size_t bytes_dst; size_t bytes_copied; - uint8_t *in = (uint8_t *)src; + const uint8_t *in = src; uint8_t *out = (uint8_t *)dst; while (bytes) { diff --git a/src/include/sof/audio/audio_stream.h b/src/include/sof/audio/audio_stream.h index dc5d55103b4b..c614284b9358 100644 --- a/src/include/sof/audio/audio_stream.h +++ b/src/include/sof/audio/audio_stream.h @@ -902,7 +902,7 @@ audio_stream_samples_without_wrap_s32(const struct audio_stream *source, const v * @return Number of bytes to buffer wrap. For number of samples calculate * need to add size of sample to returned bytes count. */ -static inline int cir_buf_bytes_without_wrap(void *ptr, void *buf_end) +static inline int cir_buf_bytes_without_wrap(const void *ptr, const void *buf_end) { assert((intptr_t)buf_end >= (intptr_t)ptr); return (intptr_t)buf_end - (intptr_t)ptr; @@ -946,7 +946,7 @@ int audio_stream_copy(const struct audio_stream *source, uint32_t ioffset, * @param dst_end End address of sink circular buffer. * @param byte_size Number of bytes to copy. */ -void cir_buf_copy(void *src, void *src_addr, void *src_end, void *dst, +void cir_buf_copy(const void *src, const void *src_addr, const void *src_end, void *dst, void *dst_addr, void *dst_end, size_t byte_size); /** From edcdedbc1ae8d0db18d9d8d5d791345688d7c26c Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Thu, 23 Jul 2026 16:42:28 +0200 Subject: [PATCH 017/109] audio: pcm_converter: change pcm conversion function interface Rework the pcm conversion and dma copy paths to operate on circular buffer source and sink descriptors instead of the legacy audio stream buffers. Signed-off-by: Adrian Warecki --- posix/include/sof/lib/dma.h | 9 +- src/audio/copier/copier.c | 34 +- src/audio/pcm_converter/pcm_converter.c | 80 ++- .../pcm_converter/pcm_converter_generic.c | 616 ++++++++---------- src/audio/pcm_converter/pcm_converter_hifi3.c | 485 ++++++-------- src/audio/pcm_converter/pcm_remap.c | 336 +++++----- src/include/sof/audio/pcm_converter.h | 50 +- src/lib/dma.c | 45 +- .../src/audio/pcm_converter/pcm_float.c | 15 +- zephyr/include/sof/lib/dma.h | 9 +- 10 files changed, 850 insertions(+), 829 deletions(-) diff --git a/posix/include/sof/lib/dma.h b/posix/include/sof/lib/dma.h index cb829dcaa21a..0d81c4cb552e 100644 --- a/posix/include/sof/lib/dma.h +++ b/posix/include/sof/lib/dma.h @@ -265,10 +265,11 @@ struct dma_info { size_t num_dmas; }; -struct audio_stream; -typedef int (*dma_process_func)(const struct audio_stream __sparse_cache *source, - uint32_t ioffset, struct audio_stream __sparse_cache *sink, - uint32_t ooffset, uint32_t source_samples, uint32_t chmap); +struct cir_buf_source; +struct cir_buf_sink; +typedef int (*dma_process_func)(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t source_samples, uint32_t chmap); /** * \brief API to initialize a platform DMA controllers. diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 33c404a52404..018bcd81b870 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -531,6 +531,16 @@ static int do_conversion_copy(struct comp_dev *dev, struct comp_buffer *sink, struct comp_copy_limits *processed_data) { + struct cir_buf_source src_cir = { + .buf_start = audio_stream_get_addr(&src->stream), + .buf_end = audio_stream_get_end_addr(&src->stream), + .ptr = audio_stream_get_rptr(&src->stream), + }; + struct cir_buf_sink snk_cir = { + .buf_start = audio_stream_get_addr(&sink->stream), + .buf_end = audio_stream_get_end_addr(&sink->stream), + .ptr = audio_stream_get_wptr(&sink->stream), + }; int i; /* buffer params might be not yet configured by component on another pipeline */ @@ -550,7 +560,8 @@ static int do_conversion_copy(struct comp_dev *dev, return -EINVAL; buffer_stream_invalidate(src, processed_data->source_bytes); - cd->converter[i](&src->stream, 0, &sink->stream, 0, + cd->converter[i](&src_cir, audio_stream_get_channels(&src->stream), + &snk_cir, audio_stream_get_channels(&sink->stream), processed_data->frames * audio_stream_get_channels(&src->stream), DUMMY_CHMAP); @@ -619,8 +630,22 @@ static int copier_module_copy(struct processing_module *mod, sink_dev = comp_buffer_get_sink_component(sink_c); processed_data.sink_bytes = 0; if (sink_dev->state == COMP_STATE_ACTIVE) { + /* Bridge the legacy audio_stream buffers into cir_buf descriptors for + * the new pcm_converter interface (read/write pointers = offset 0). + */ + struct cir_buf_source src_cir = { + .buf_start = audio_stream_get_addr(input_buffers[0].data), + .buf_end = audio_stream_get_end_addr(input_buffers[0].data), + .ptr = audio_stream_get_rptr(input_buffers[0].data), + }; + struct cir_buf_sink snk_cir = { + .buf_start = audio_stream_get_addr(output_buffers[i].data), + .buf_end = audio_stream_get_end_addr(output_buffers[i].data), + .ptr = audio_stream_get_wptr(output_buffers[i].data), + }; uint32_t source_samples; int sink_queue_id; + pcm_converter_func converter; /* * Buffer ID is constructed as IPC4_COMP_ID(src_queue, dst_queue). @@ -630,14 +655,15 @@ static int copier_module_copy(struct processing_module *mod, sink_queue_id = IPC4_SRC_QUEUE_ID(buf_get_id(sink_c)); if (sink_queue_id >= IPC4_COPIER_MODULE_OUTPUT_PINS_COUNT) return -EINVAL; + converter = cd->converter[sink_queue_id]; comp_get_copy_limits(src_c, sink_c, &processed_data); source_samples = processed_data.frames * audio_stream_get_channels(input_buffers[0].data); - cd->converter[sink_queue_id](input_buffers[0].data, 0, - output_buffers[i].data, 0, - source_samples, DUMMY_CHMAP); + converter(&src_cir, audio_stream_get_channels(input_buffers[0].data), + &snk_cir, audio_stream_get_channels(output_buffers[i].data), + source_samples, DUMMY_CHMAP); output_buffers[i].size = processed_data.sink_bytes; cd->output_total_data_processed += processed_data.sink_bytes; diff --git a/src/audio/pcm_converter/pcm_converter.c b/src/audio/pcm_converter/pcm_converter.c index b489cc6e664b..4718d1814ede 100644 --- a/src/audio/pcm_converter/pcm_converter.c +++ b/src/audio/pcm_converter/pcm_converter.c @@ -15,35 +15,23 @@ #include #include -int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream *sink, uint32_t ooffset, - uint32_t samples, pcm_converter_lin_func converter) +int pcm_convert_as_linear(const struct cir_buf_source *source, size_t s_size_in, + struct cir_buf_sink *sink, size_t s_size_out, + size_t samples, pcm_converter_lin_func converter) { - const int s_size_in = audio_stream_sample_bytes(source); - const int s_size_out = audio_stream_sample_bytes(sink); const int log2_s_size_in = ffs(s_size_in) - 1; const int log2_s_size_out = ffs(s_size_out) - 1; - char *r_ptr = audio_stream_get_frag(source, audio_stream_get_rptr(source), ioffset, - s_size_in); - char *w_ptr = audio_stream_get_frag(sink, audio_stream_get_wptr(sink), ooffset, - s_size_out); - int i = 0; - int chunk; - int N1, N2; + const char *r_ptr = source->ptr; + char *w_ptr = sink->ptr; + size_t i = 0; + size_t chunk; + size_t N1, N2; - /* assert enough avail/free samples in source and sink buffer */ - if (audio_stream_get_avail_samples(source) < samples + ioffset) - return -EINVAL; - if (audio_stream_get_free_samples(sink) < samples + ooffset) - return -EINVAL; while (i < samples) { - /* calculate chunk size */ - /* "">> log2_s_size" is equal "/ s_size" here */ - N1 = audio_stream_bytes_without_wrap(source, r_ptr) >> - log2_s_size_in; - N2 = audio_stream_bytes_without_wrap(sink, w_ptr) >> - log2_s_size_out; + /* calculate chunk size; shifting by log2_s_size is dividing by s_size */ + N1 = ((const char *)source->buf_end - r_ptr) >> log2_s_size_in; + N2 = ((char *)sink->buf_end - w_ptr) >> log2_s_size_out; chunk = MIN(N1, N2); chunk = MIN(chunk, samples - i); @@ -51,16 +39,52 @@ int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, converter(r_ptr, w_ptr, chunk); /* move pointers */ - r_ptr = audio_stream_wrap(source, r_ptr + chunk * s_size_in); - w_ptr = audio_stream_wrap(sink, w_ptr + chunk * s_size_out); + r_ptr = cir_buf_wrap(r_ptr + chunk * s_size_in, + source->buf_start, source->buf_end); + w_ptr = cir_buf_wrap(w_ptr + chunk * s_size_out, + sink->buf_start, sink->buf_end); i += chunk; } return samples; } -int just_copy(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream *sink, uint32_t ooffset, uint32_t samples, uint32_t chmap) +/* Copy "bytes" of raw data from a source to a sink circular buffer. */ +static void just_copy_bytes(const struct cir_buf_source *source, struct cir_buf_sink *sink, + size_t bytes) { - return audio_stream_copy(source, ioffset, sink, ooffset, samples); + cir_buf_copy(source->ptr, source->buf_start, source->buf_end, + sink->ptr, sink->buf_start, sink->buf_end, bytes); +} + +int just_copy_1b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap) +{ + just_copy_bytes(source, sink, samples); + return samples; +} + +int just_copy_2b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap) +{ + just_copy_bytes(source, sink, samples * sizeof(int16_t)); + return samples; +} + +int just_copy_3b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap) +{ + just_copy_bytes(source, sink, samples * 3); + return samples; +} + +int just_copy_4b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap) +{ + just_copy_bytes(source, sink, samples * sizeof(int32_t)); + return samples; } diff --git a/src/audio/pcm_converter/pcm_converter_generic.c b/src/audio/pcm_converter/pcm_converter_generic.c index 56d2cf599288..fe346737750b 100644 --- a/src/audio/pcm_converter/pcm_converter_generic.c +++ b/src/audio/pcm_converter/pcm_converter_generic.c @@ -36,24 +36,22 @@ #define BYTES_TO_S32_SAMPLES 2 #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_u8_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_u8_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - uint8_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - uint32_t processed; - uint32_t nmax, i, n; + const uint8_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_U8_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = (INT8_MIN + *src) << 24; @@ -65,24 +63,22 @@ static int pcm_convert_u8_to_s32(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_to_u8(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_u8(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - uint8_t *dst = audio_stream_get_wptr(sink); - uint32_t processed; - uint32_t nmax, i, n; + const int32_t *src = source->ptr; + uint8_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_U8_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int8(Q_SHIFT_RND(*src, 24, 0)) - INT8_MIN; @@ -96,24 +92,22 @@ static int pcm_convert_s32_to_u8(const struct audio_stream *source, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_alaw_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_alaw_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - const uint8_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - uint32_t processed; - uint32_t nmax, i, n; + const uint8_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, (void *)src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_U8_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sofm_a_law_decode(*src) << 16; @@ -125,24 +119,22 @@ static int pcm_convert_alaw_to_s32(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_to_alaw(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_alaw(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - const int32_t *src = audio_stream_get_rptr(source); - uint8_t *dst = audio_stream_get_wptr(sink); - uint32_t processed; - uint32_t nmax, i, n; + const int32_t *src = source->ptr; + uint8_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, (void *)src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_U8_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sofm_a_law_encode(*src >> 16); @@ -156,24 +148,22 @@ static int pcm_convert_s32_to_alaw(const struct audio_stream *source, #endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_mulaw_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_mulaw_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - const uint8_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - uint32_t processed; - uint32_t nmax, i, n; + const uint8_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, (void *)src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_U8_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_U8_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sofm_mu_law_decode(*src) << 16; @@ -185,24 +175,22 @@ static int pcm_convert_mulaw_to_s32(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_to_mulaw(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_mulaw(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - const int32_t *src = audio_stream_get_rptr(source); - uint8_t *dst = audio_stream_get_wptr(sink); - uint32_t processed; - uint32_t nmax, i, n; + const int32_t *src = source->ptr; + uint8_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, (void *)src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_U8_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_U8_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sofm_mu_law_encode(*src >> 16); @@ -217,24 +205,22 @@ static int pcm_convert_s32_to_mulaw(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE -static int pcm_convert_s16_to_s24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_to_s24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int16_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int16_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S16_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S16_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src << 8; @@ -246,24 +232,22 @@ static int pcm_convert_s16_to_s24(const struct audio_stream *source, return samples; } -static int pcm_convert_s24_to_s16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_to_s16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int16_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int16_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S16_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S16_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int16(Q_SHIFT_RND(sign_extend_s24(*src), 23, 15)); @@ -279,24 +263,22 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S16LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_s16_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int16_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int16_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S16_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S16_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src << 16; @@ -308,24 +290,22 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_to_s16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_s16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int16_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int16_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S16_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S16_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int16(Q_SHIFT_RND(*src, 31, 15)); @@ -341,24 +321,22 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S32LE -static int pcm_convert_s24_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src << 8; @@ -370,24 +348,22 @@ static int pcm_convert_s24_to_s32(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_to_s24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_s24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int24(Q_SHIFT_RND(*src, 31, 23)); @@ -399,24 +375,22 @@ static int pcm_convert_s32_to_s24(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_s24_be(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_samples_without_wrap_s32(source, src); + nmax = cir_buf_samples_without_wrap_s32(src, source->buf_end); n = MIN(n, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, dst); + nmax = cir_buf_samples_without_wrap_s32(dst, sink->buf_end); n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int24(Q_SHIFT_RND(*src, 31, 23)) << 8; @@ -539,7 +513,7 @@ static int32_t _pcm_convert_i_to_f(int32_t src, int32_t pow) #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE static void pcm_convert_s16_to_f_lin(const void *psrc, void *pdst, - uint32_t samples) + size_t samples) { const int16_t *src = psrc; int32_t *dst = pdst; /* float */ @@ -552,7 +526,7 @@ static void pcm_convert_s16_to_f_lin(const void *psrc, void *pdst, } static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, - uint32_t samples) + size_t samples) { const int32_t *src = psrc; /* float */ int16_t *dst = pdst; @@ -564,26 +538,26 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, dst[i] = sat_int16(_pcm_convert_f_to_i(src[i], 15)); } -static int pcm_convert_s16_to_f(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_to_f(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int16_t), sink, sizeof(int32_t), samples, pcm_convert_s16_to_f_lin); } -static int pcm_convert_f_to_s16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_f_to_s16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int16_t), samples, pcm_convert_f_to_s16_lin); } #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S24LE static void pcm_convert_s24_to_f_lin(const void *psrc, void *pdst, - uint32_t samples) + size_t samples) { const int32_t *src = psrc; int32_t *dst = pdst; /* float */ @@ -596,7 +570,7 @@ static void pcm_convert_s24_to_f_lin(const void *psrc, void *pdst, } static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, - uint32_t samples) + size_t samples) { const int32_t *src = psrc; /* float */ int32_t *dst = pdst; @@ -608,26 +582,26 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, dst[i] = sat_int24(_pcm_convert_f_to_i(src[i], 23)); } -static int pcm_convert_s24_to_f(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_to_f(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_s24_to_f_lin); } -static int pcm_convert_f_to_s24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_f_to_s24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_f_to_s24_lin); } #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S32LE static void pcm_convert_s32_to_f_lin(const void *psrc, void *pdst, - uint32_t samples) + size_t samples) { const int32_t *src = psrc; int32_t *dst = pdst; /* float */ @@ -640,7 +614,7 @@ static void pcm_convert_s32_to_f_lin(const void *psrc, void *pdst, } static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, - uint32_t samples) + size_t samples) { const int32_t *src = psrc; /* float */ int32_t *dst = pdst; @@ -652,60 +626,60 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, dst[i] = _pcm_convert_f_to_i(src[i], 31); } -static int pcm_convert_s32_to_f(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_f(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_s32_to_f_lin); } -static int pcm_convert_f_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_f_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_f_to_s32_lin); } #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ const struct pcm_func_map pcm_func_map[] = { #if CONFIG_PCM_CONVERTER_FORMAT_U8 - { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_U8, just_copy }, + { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_U8, just_copy_1b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 */ #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE { SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S32_LE, pcm_convert_u8_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_U8, pcm_convert_s32_to_u8 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_A_LAW - { SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_A_LAW, just_copy }, + { SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_A_LAW, just_copy_1b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW */ #if CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE { SOF_IPC_FRAME_A_LAW, SOF_IPC_FRAME_S32_LE, pcm_convert_alaw_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_A_LAW, pcm_convert_s32_to_alaw }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW - { SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_MU_LAW, just_copy }, + { SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_MU_LAW, just_copy_1b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_MU_LAW */ #if CONFIG_PCM_CONVERTER_FORMAT_MU_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE { SOF_IPC_FRAME_MU_LAW, SOF_IPC_FRAME_S32_LE, pcm_convert_mulaw_to_s32 }, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_MU_LAW, pcm_convert_s32_to_mulaw }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_A_LAW && CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy_2b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE - { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy }, + { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy_3b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, @@ -717,10 +691,10 @@ const struct pcm_func_map pcm_func_map[] = { #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be }, - { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, just_copy }, + { SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT - { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f }, @@ -739,24 +713,22 @@ const struct pcm_func_map pcm_func_map[] = { const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); #if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 -static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c16_to_s16_c32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int16_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int16_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S16_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S16_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src; @@ -768,24 +740,22 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, return samples; } -static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c32_to_s16_c16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int16_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int16_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S16_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S16_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src & 0xffff; @@ -798,24 +768,22 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, } #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 -static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c32_to_s32_c32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src << 16; @@ -827,24 +795,22 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, return samples; } -static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_c32_to_s16_c32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int16(Q_SHIFT_RND(*src, 31, 15)); @@ -857,24 +823,22 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, } #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 -static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c32_to_s24_c32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = *src << 8; @@ -886,24 +850,22 @@ static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, return samples; } -static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_c32_to_s16_c32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i++) { *dst = sat_int16(Q_SHIFT_RND(sign_extend_s24(*src & 0xffffff), 23, 15)); @@ -917,24 +879,22 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 -static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_c24_to_s24_c32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - uint8_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const uint8_t *src = source->ptr; + int32_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset * 3; - dst += ooffset; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) / 3; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) / 3; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); for (i = 0; i < n; i += 1) { *dst = (*(src + 2) << 24) | (*(src + 1) << 16) | (*(src + 0) << 8); @@ -947,24 +907,22 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, return samples; } -static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_c32_to_s24_c24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - uint8_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i, n; + const int32_t *src = source->ptr; + uint8_t *dst = sink->ptr; + size_t processed; + size_t nmax, i, n; - src += ioffset; - dst += ooffset * 3; for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) / 3; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) / 3; n = MIN(n, nmax); for (i = 0; i < n; i += 1) { *dst = *src & 0xFF; @@ -981,25 +939,23 @@ static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, } /* 2x24bit samples are packed into 3x16bit samples for hda link dma */ -static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, +static int pcm_convert_s24_c32_to_s24_c24_link_gtw(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - uint16_t *dst = audio_stream_get_wptr(sink); - int processed; - int nmax, i = 0, n = 0; + const int32_t *src = source->ptr; + uint16_t *dst = sink->ptr; + size_t processed; + size_t nmax, i = 0, n = 0; - src += ioffset; - assert(ooffset == 0); for (processed = 0; processed < samples; processed += n) { - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); n = samples - processed; - nmax = audio_stream_bytes_without_wrap(source, src) >> BYTES_TO_S32_SAMPLES; + nmax = cir_buf_bytes_without_wrap(src, source->buf_end) >> BYTES_TO_S32_SAMPLES; n = MIN(n, nmax); - nmax = audio_stream_bytes_without_wrap(sink, dst) / 3; + nmax = cir_buf_bytes_without_wrap(dst, sink->buf_end) / 3; n = MIN(n, nmax); for (i = 0; i < n; i += 2) { *dst = (*src >> 8) & 0xFFFF; @@ -1045,11 +1001,11 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_U8, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_U8, - just_copy }, + just_copy_2b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_U8 && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - just_copy}, + just_copy_4b}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, @@ -1071,7 +1027,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, - just_copy }, + just_copy_4b }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S24LE @@ -1080,14 +1036,14 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE_MSB, just_copy}, + SOF_IPC_FRAME_S24_4LE_MSB, just_copy_4b}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, just_copy}, + SOF_IPC_FRAME_S32_LE, just_copy_4b}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S16LE diff --git a/src/audio/pcm_converter/pcm_converter_hifi3.c b/src/audio/pcm_converter/pcm_converter_hifi3.c index 2b6ca607415d..a25a0881f20c 100644 --- a/src/audio/pcm_converter/pcm_converter_hifi3.c +++ b/src/audio/pcm_converter/pcm_converter_hifi3.c @@ -36,24 +36,21 @@ * \param[in,out] sink Destination buffer. * \param[in] samples Number of samples to process. */ -static int pcm_convert_s16_to_s24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_to_s24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { ae_int16x4 sample = AE_ZERO16(); - uint32_t nmax, i, n, m, left, left_samples; + size_t nmax, i, n, m, left, left_samples; ae_valign inu = AE_ZALIGN64(); ae_valign outu = AE_ZALIGN64(); - int16_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); - - ae_int16x4 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int16x4 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s16(source, in); + nmax = cir_buf_samples_without_wrap_s16(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 2; left = n & 0x03; @@ -73,15 +70,15 @@ static int pcm_convert_s16_to_s24(const struct audio_stream *source, */ for (i = 0; i < left ; i++) { /* load one 16 bit samples */ - AE_L16_IP(sample, (ae_int16 *)in, sizeof(ae_int16)); + AE_L16_IP(sample, (const ae_int16 *)in, sizeof(ae_int16)); /* shift right and store one 32 bit sample */ AE_S32_L_IP(AE_SRAI32(AE_CVT32X2F16_32(sample), 8), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -110,26 +107,23 @@ static ae_int32x2 pcm_shift_s24_to_s16(ae_int32x2 sample) * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s24_to_s16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_to_s16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { ae_int16x4 sample = AE_ZERO16(); ae_int32x2 sample_1 = AE_ZERO32(); ae_int32x2 sample_2 = AE_ZERO32(); - uint32_t nmax, i, n, m, left, left_samples; + size_t nmax, i, n, m, left, left_samples; ae_valign inu = AE_ZALIGN64(); ae_valign outu = AE_ZALIGN64(); - ae_int32 *src = audio_stream_get_rptr(source); - ae_int16 *dst = audio_stream_get_wptr(sink); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int16x4 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int16x4 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, out); + nmax = cir_buf_samples_without_wrap_s16(out, sink->buf_end); n = MIN(n, nmax); m = n >> 2; left = n & 0x03; @@ -153,7 +147,7 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, */ for (i = 0; i < left ; i++) { /* load one 32 bit sample */ - AE_L32_IP(sample_1, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample_1, (const ae_int32 *)in, sizeof(ae_int32)); /* shift and round */ sample_1 = pcm_shift_s24_to_s16(sample_1); @@ -164,8 +158,8 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, sizeof(ae_int16)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; } @@ -181,24 +175,21 @@ static int pcm_convert_s24_to_s16(const struct audio_stream *source, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s16_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int16_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int16x4 sample = AE_ZERO16(); - uint32_t nmax, i, n, m, left, left_samples; + size_t nmax, i, n, m, left, left_samples; ae_valign inu = AE_ZALIGN64(); ae_valign outu = AE_ZALIGN64(); - - ae_int16x4 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int16x4 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s16(source, in); + nmax = cir_buf_samples_without_wrap_s16(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 2; left = n & 0x03; @@ -218,14 +209,14 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, */ for (i = 0; i < left ; i++) { /* load one 16 bit samples */ - AE_L16_IP(sample, (ae_int16 *)in, sizeof(ae_int16)); + AE_L16_IP(sample, (const ae_int16 *)in, sizeof(ae_int16)); /* store one 32 bit sample */ AE_S32_L_IP(AE_CVT32X2F16_32(sample), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; } @@ -237,26 +228,23 @@ static int pcm_convert_s16_to_s32(const struct audio_stream *source, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s32_to_s16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_s16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int16_t *dst = audio_stream_get_wptr(sink); ae_int16x4 sample = AE_ZERO16(); ae_int32x2 sample_1 = AE_ZERO32(); ae_int32x2 sample_2 = AE_ZERO32(); - uint32_t nmax, i, n, m, left, left_samples; + size_t nmax, i, n, m, left, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int16x4 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int16x4 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, out); + nmax = cir_buf_samples_without_wrap_s16(out, sink->buf_end); n = MIN(n, nmax); m = n >> 2; left = n & 0x3; @@ -277,7 +265,7 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, */ for (i = 0; i < left ; i++) { /* load one 32 bit samples */ - AE_L32_IP(sample_1, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample_1, (const ae_int32 *)in, sizeof(ae_int32)); /* shift and round */ sample = AE_ROUND16X4F32SSYM(sample_1, sample_1); /* store one 16 bit sample */ @@ -285,8 +273,8 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, sizeof(ae_int16)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -303,24 +291,21 @@ static int pcm_convert_s32_to_s16(const struct audio_stream *source, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s24_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -334,13 +319,13 @@ static int pcm_convert_s24_to_s32(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); AE_S32_L_IP(AE_SLAI32(sample, 8), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -368,24 +353,21 @@ static ae_int32x2 pcm_shift_s32_to_s24(ae_int32x2 sample) * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s32_to_s24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_s24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -400,37 +382,34 @@ static int pcm_convert_s32_to_s24(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { /* load one 32 bit sample */ - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); /* shift right and store one 32 bit sample */ sample = pcm_shift_s32_to_s24(sample); AE_S32_L_IP(sample, (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; } -static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_s24_be(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -447,15 +426,15 @@ static int pcm_convert_s32_to_s24_be(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { /* load one 32 bit sample */ - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); /* shift with saturation and rounding and store one 32 bit sample */ sample = AE_SRAA32RS(sample, 8); sample = AE_SLAI32S(sample, 8); AE_S32_L_IP(sample, (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -481,14 +460,13 @@ static inline int _round_s(xtfloat x) * \param[out] pdst destination linear buffer. * \param[in] samples Number of samples to process. */ -static void pcm_convert_s16_to_f_lin(const void *psrc, void *pdst, - uint32_t samples) +static void pcm_convert_s16_to_f_lin(const void *psrc, void *pdst, size_t samples) { const ae_int16 *in = psrc; xtfloat *out = pdst; ae_int16x4 sample = AE_ZERO16(); xtfloat fl; - int i = 0; + size_t i = 0; while (i < samples) { /* load one 16 bit sample */ @@ -511,14 +489,13 @@ static void pcm_convert_s16_to_f_lin(const void *psrc, void *pdst, * \param[out] pdst destination linear buffer. * \param[in] samples Number of samples to process. */ -static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, - uint32_t samples) +static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, size_t samples) { const xtfloat *in = psrc; ae_int16x4 *out = pdst; xtfloat x; int y; - int i = 0; + size_t i = 0; while (i < samples) { /* load one 32 bit sample */ @@ -541,11 +518,11 @@ static void pcm_convert_f_to_s16_lin(const void *psrc, void *pdst, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s16_to_f(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_to_f(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int16_t), sink, sizeof(int32_t), samples, pcm_convert_s16_to_f_lin); } @@ -556,11 +533,11 @@ static int pcm_convert_s16_to_f(const struct audio_stream *source, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_f_to_s16(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_f_to_s16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int16_t), samples, pcm_convert_f_to_s16_lin); } #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ @@ -573,15 +550,14 @@ static int pcm_convert_f_to_s16(const struct audio_stream *source, * \param[out] pdst destination linear buffer. * \param[in] samples Number of samples to process. */ -static void pcm_convert_s24_to_f_lin(const void *psrc, void *pdst, - uint32_t samples) +static void pcm_convert_s24_to_f_lin(const void *psrc, void *pdst, size_t samples) { const ae_int32 *in = psrc; xtfloat *out = pdst; ae_int32x2 sample = AE_ZERO32(); xtfloat fl; const xtfloat ratio = (xtfloat)(1.f / (1 << (23 - 15))); - int i = 0; + size_t i = 0; while (i < samples) { /* load one 24 bit sample */ @@ -607,14 +583,13 @@ static void pcm_convert_s24_to_f_lin(const void *psrc, void *pdst, * \param[out] pdst destination linear buffer. * \param[in] samples Number of samples to process. */ -static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, - uint32_t samples) +static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, size_t samples) { const xtfloat *in = psrc; ae_int32 *out = pdst; xtfloat x; ae_int32x2 y1; - int i = 0; + size_t i = 0; const xtfloat ratio = (xtfloat)(1 << (23 - 15)); while (i < samples) { @@ -642,11 +617,11 @@ static void pcm_convert_f_to_s24_lin(const void *psrc, void *pdst, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s24_to_f(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_to_f(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_s24_to_f_lin); } @@ -657,11 +632,11 @@ static int pcm_convert_s24_to_f(const struct audio_stream *source, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_f_to_s24(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_f_to_s24(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_f_to_s24_lin); } #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_24LE */ @@ -674,15 +649,14 @@ static int pcm_convert_f_to_s24(const struct audio_stream *source, * \param[out] pdst destination linear buffer. * \param[in] samples Number of samples to process. */ -static void pcm_convert_s32_to_f_lin(const void *psrc, void *pdst, - uint32_t samples) +static void pcm_convert_s32_to_f_lin(const void *psrc, void *pdst, size_t samples) { const ae_int32 *in = psrc; xtfloat *out = pdst; ae_int32x2 sample = AE_ZERO32(); xtfloat fl; const xtfloat ratio = (xtfloat)(1.f / (1ul << (31 - 15))); - int i = 0; + size_t i = 0; while (i < samples) { /* load one 32 bit sample */ @@ -706,14 +680,13 @@ static void pcm_convert_s32_to_f_lin(const void *psrc, void *pdst, * \param[out] pdst destination linear buffer. * \param[in] samples Number of samples to process. */ -static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, - uint32_t samples) +static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, size_t samples) { const xtfloat *in = psrc; ae_int32 *out = pdst; xtfloat x; ae_int32x2 y1; - int i = 0; + size_t i = 0; const xtfloat ratio = (xtfloat)(1ul << (31 - 15)); while (i < samples) { @@ -739,11 +712,11 @@ static void pcm_convert_f_to_s32_lin(const void *psrc, void *pdst, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_s32_to_f(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_to_f(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_s32_to_f_lin); } @@ -754,11 +727,11 @@ static int pcm_convert_s32_to_f(const struct audio_stream *source, * \param[in] samples Number of samples to process. * \return error code or number of processed samples. */ -static int pcm_convert_f_to_s32(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_f_to_s32(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - return pcm_convert_as_linear(source, ioffset, sink, ooffset, samples, + return pcm_convert_as_linear(source, sizeof(int32_t), sink, sizeof(int32_t), samples, pcm_convert_f_to_s32_lin); } #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_32LE */ @@ -766,20 +739,20 @@ static int pcm_convert_f_to_s32(const struct audio_stream *source, const struct pcm_func_map pcm_func_map[] = { #if CONFIG_PCM_CONVERTER_FORMAT_S16LE - { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy }, + { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE, just_copy_2b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE - { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy }, + { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24_3LE - { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy }, + { SOF_IPC_FRAME_S24_3LE, SOF_IPC_FRAME_S24_3LE, just_copy_3b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24_3LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s16_to_s24 }, { SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S16_LE, pcm_convert_s24_to_s16 }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S24LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE - { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy }, + { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE */ #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s16_to_s32 }, @@ -791,7 +764,7 @@ const struct pcm_func_map pcm_func_map[] = { #endif /* CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE */ #if XCHAL_HAVE_FP #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT - { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy }, + { SOF_IPC_FRAME_FLOAT, SOF_IPC_FRAME_FLOAT, just_copy_4b }, #endif /* CONFIG_PCM_CONVERTER_FORMAT_FLOAT */ #if CONFIG_PCM_CONVERTER_FORMAT_FLOAT && CONFIG_PCM_CONVERTER_FORMAT_S16LE { SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_FLOAT, pcm_convert_s16_to_f }, @@ -810,25 +783,22 @@ const struct pcm_func_map pcm_func_map[] = { const size_t pcm_func_count = ARRAY_SIZE(pcm_func_map); #if CONFIG_PCM_CONVERTER_FORMAT_S16_C16_AND_S16_C32 -static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c16_to_s16_c32(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int16_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int16x4 sample = AE_ZERO16(); - uint32_t nmax, i, n, m, left, left_samples; + size_t nmax, i, n, m, left, left_samples; ae_valign inu = AE_ZALIGN64(); ae_valign outu = AE_ZALIGN64(); - - ae_int16x4 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int16x4 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s16(source, in); + nmax = cir_buf_samples_without_wrap_s16(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 2; left = n & 0x03; @@ -848,39 +818,36 @@ static int pcm_convert_s16_c16_to_s16_c32(const struct audio_stream *source, */ for (i = 0; i < left ; i++) { /* load one 16 bit samples */ - AE_L16_IP(sample, (ae_int16 *)in, sizeof(ae_int16)); + AE_L16_IP(sample, (const ae_int16 *)in, sizeof(ae_int16)); /* store one 32 bit sample */ AE_S32_L_IP(AE_SEXT32X2D16_32(sample), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; } -static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c32_to_s16_c16(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int16_t *dst = audio_stream_get_wptr(sink); ae_int16x4 sample = AE_ZERO16(); ae_int32x2 sample_1 = AE_ZERO32(); ae_int32x2 sample_2 = AE_ZERO32(); - uint32_t nmax, i, n, m, left, left_samples; + size_t nmax, i, n, m, left, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int16x4 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int16x4 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, out); + nmax = cir_buf_samples_without_wrap_s16(out, sink->buf_end); n = MIN(n, nmax); m = n >> 2; left = n & 0x3; @@ -903,15 +870,15 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, */ for (i = 0; i < left ; i++) { /* load one 32 bit samples */ - AE_L32_IP(sample_1, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample_1, (const ae_int32 *)in, sizeof(ae_int32)); /* shift and round */ sample = AE_CVT16X4(sample_1, sample_1); /* store one 16 bit sample */ AE_S16_0_IP(AE_MOVAD16_0(sample), (ae_int16 *)out, sizeof(ae_int16)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -919,25 +886,22 @@ static int pcm_convert_s16_c32_to_s16_c16(const struct audio_stream *source, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S32_C32 -static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c32_to_s32_c32(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -951,36 +915,33 @@ static int pcm_convert_s16_c32_to_s32_c32(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); AE_S32_L_IP(AE_SLAI32(sample, 16), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; } -static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s32_c32_to_s16_c32(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -994,12 +955,12 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); AE_S32_L_IP(AE_SRAA32RS(sample, 16), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -1007,25 +968,22 @@ static int pcm_convert_s32_c32_to_s16_c32(const struct audio_stream *source, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S24_C32 -static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s16_c32_to_s24_c32(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -1039,12 +997,12 @@ static int pcm_convert_s16_c32_to_s24_c32(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); AE_S32_L_IP(AE_SLAI32(sample, 8), (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -1062,25 +1020,22 @@ static ae_int32x2 pcm_shift_s24_c32_to_s16(ae_int32x2 sample) return sample; } -static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_c32_to_s16_c32(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int32x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -1095,13 +1050,13 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); sample = pcm_shift_s24_c32_to_s16(sample); AE_S32_L_IP(sample, (ae_int32 *)out, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -1109,26 +1064,23 @@ static int pcm_convert_s24_c32_to_s16_c32(const struct audio_stream *source, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_C24_AND_S24_C32 -static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_c24_to_s24_c32(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - uint8_t *src = audio_stream_get_rptr(source); - int32_t *dst = audio_stream_get_wptr(sink); ae_int24x2 sample24 = AE_ZERO24(); ae_int32x2 sample = AE_ZERO32(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int24x2 *in = audio_stream_wrap(source, src + ioffset * 3); - ae_int32x2 *out = audio_stream_wrap(sink, dst + ooffset); + const ae_int24x2 *in = source->ptr; + ae_int32x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_bytes_without_wrap(source, in) / 3; + nmax = cir_buf_bytes_without_wrap(in, source->buf_end) / 3; n = MIN(left_samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, out); + nmax = cir_buf_samples_without_wrap_s32(out, sink->buf_end); n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -1149,33 +1101,30 @@ static int pcm_convert_s24_c24_to_s24_c32(const struct audio_stream *source, sizeof(ae_int32)); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; } -static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, - uint32_t ioffset, - struct audio_stream *sink, - uint32_t ooffset, uint32_t samples, uint32_t chmap) +static int pcm_convert_s24_c32_to_s24_c24(const struct cir_buf_source *source, + uint32_t src_channels, + struct cir_buf_sink *sink, + uint32_t sink_channels, size_t samples, uint32_t chmap) { - int32_t *src = audio_stream_get_rptr(source); - uint8_t *dst = audio_stream_get_wptr(sink); ae_int32x2 sample = AE_ZERO32(); ae_int24x2 sample24 = AE_ZERO24(); - uint32_t nmax, i, n, m, left_samples; + size_t nmax, i, n, m, left_samples; ae_valign outu = AE_ZALIGN64(); ae_valign inu = AE_ZALIGN64(); - - ae_int32x2 *in = audio_stream_wrap(source, src + ioffset); - ae_int24x2 *out = audio_stream_wrap(sink, dst + ooffset * 3); + const ae_int32x2 *in = source->ptr; + ae_int24x2 *out = sink->ptr; for (left_samples = samples; left_samples; left_samples -= n) { - nmax = audio_stream_samples_without_wrap_s32(source, in); + nmax = cir_buf_samples_without_wrap_s32(in, source->buf_end); n = MIN(left_samples, nmax); - nmax = audio_stream_bytes_without_wrap(sink, out) / 3; + nmax = cir_buf_bytes_without_wrap(out, sink->buf_end) / 3; n = MIN(n, nmax); m = n >> 1; inu = AE_LA64_PP(in); @@ -1189,13 +1138,13 @@ static int pcm_convert_s24_c32_to_s24_c24(const struct audio_stream *source, /* process the left 1 sample to avoid memory access overrun */ if (n & 0x01) { - AE_L32_IP(sample, (ae_int32 *)in, sizeof(ae_int32)); + AE_L32_IP(sample, (const ae_int32 *)in, sizeof(ae_int32)); sample24 = AE_MOVINT24X2_FROMF32X2(sample); AE_SA24_IP(sample24, outu, out); } - in = audio_stream_wrap(source, in); - out = audio_stream_wrap(sink, out); + in = cir_buf_wrap(in, source->buf_start, source->buf_end); + out = cir_buf_wrap(out, sink->buf_start, sink->buf_end); } return samples; @@ -1227,7 +1176,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24LE { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, - just_copy}, + just_copy_4b}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, pcm_convert_s24_to_s32}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, @@ -1249,7 +1198,7 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { #endif #if CONFIG_PCM_CONVERTER_FORMAT_S16_C32_AND_S16_C32 { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S16_LE, - just_copy }, + just_copy_4b }, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S24LE @@ -1258,14 +1207,14 @@ const struct pcm_func_vc_map pcm_func_vc_map[] = { { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE, pcm_convert_s32_to_s24}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S24_4LE_MSB, just_copy}, + SOF_IPC_FRAME_S24_4LE_MSB, just_copy_4b}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S32LE && CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, pcm_convert_s32_to_s24_be}, { SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S24_4LE_MSB, SOF_IPC_FRAME_S32_LE, - SOF_IPC_FRAME_S32_LE, just_copy}, + SOF_IPC_FRAME_S32_LE, just_copy_4b}, #endif #if CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB && CONFIG_PCM_CONVERTER_FORMAT_S16LE diff --git a/src/audio/pcm_converter/pcm_remap.c b/src/audio/pcm_converter/pcm_remap.c index f0ad6912a5f8..81d0fefd725d 100644 --- a/src/audio/pcm_converter/pcm_remap.c +++ b/src/audio/pcm_converter/pcm_remap.c @@ -6,17 +6,17 @@ #include #include -static void mute_channel_c16(struct audio_stream *stream, int channel, int frames) +static void mute_channel_c16(struct cir_buf_sink *sink, uint32_t num_channels, uint32_t channel, + size_t frames) { - int num_channels = audio_stream_get_channels(stream); - int16_t *ptr = (int16_t *)audio_stream_get_wptr(stream) + channel; + int16_t *ptr = (int16_t *)sink->ptr + channel; while (frames) { - int samples_wo_wrap, n, i; + size_t samples_wo_wrap, n, i; - ptr = audio_stream_wrap(stream, ptr); + ptr = cir_buf_wrap(ptr, sink->buf_start, sink->buf_end); - samples_wo_wrap = audio_stream_samples_without_wrap_s16(stream, ptr); + samples_wo_wrap = cir_buf_samples_without_wrap_s16(ptr, sink->buf_end); n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_channels); n = MIN(n, frames); @@ -29,17 +29,17 @@ static void mute_channel_c16(struct audio_stream *stream, int channel, int frame } } -static void mute_channel_c32(struct audio_stream *stream, int channel, int frames) +static void mute_channel_c32(struct cir_buf_sink *sink, uint32_t num_channels, uint32_t channel, + size_t frames) { - int num_channels = audio_stream_get_channels(stream); - int32_t *ptr = (int32_t *)audio_stream_get_wptr(stream) + channel; + int32_t *ptr = (int32_t *)sink->ptr + channel; while (frames) { - int samples_wo_wrap, n, i; + size_t samples_wo_wrap, n, i; - ptr = audio_stream_wrap(stream, ptr); + ptr = cir_buf_wrap(ptr, sink->buf_start, sink->buf_end); - samples_wo_wrap = audio_stream_samples_without_wrap_s32(stream, ptr); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(ptr, sink->buf_end); n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_channels); n = MIN(n, frames); @@ -52,18 +52,17 @@ static void mute_channel_c32(struct audio_stream *stream, int channel, int frame } } -static int remap_c16(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c16(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - int src_channel, sink_channel; - int num_src_channels = audio_stream_get_channels(source); - int num_sink_channels = audio_stream_get_channels(sink); - int frames = source_samples / num_src_channels; + uint32_t src_channel, sink_channel; + size_t frames = source_samples / src_channels; - for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { - int16_t *src, *dst; - int frames_left; + for (sink_channel = 0; sink_channel < sink_channels; sink_channel++) { + const int16_t *src; + int16_t *dst; + size_t frames_left; src_channel = chmap & 0xf; chmap >>= 4; @@ -71,36 +70,34 @@ static int remap_c16(const struct audio_stream *source, uint32_t dummy1, /* 0xf means "mute"; also mute any out-of-range source channel so * a crafted chmap nibble cannot index past the source frame. */ - if (src_channel == 0xf || src_channel >= num_src_channels) { - mute_channel_c16(sink, sink_channel, frames); + if (src_channel == 0xf || src_channel >= src_channels) { + mute_channel_c16(sink, sink_channels, sink_channel, frames); continue; } - src = (int16_t *)audio_stream_get_rptr(source) + src_channel; - dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; + src = (const int16_t *)source->ptr + src_channel; + dst = (int16_t *)sink->ptr + sink_channel; frames_left = frames; while (frames_left) { - int src_samples_wo_wrap, dst_samples_wo_wrap; - int src_loops, dst_loops, n, i; + size_t samples_wo_wrap, n, i; - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); - src_samples_wo_wrap = audio_stream_samples_without_wrap_s16(source, src); - src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s16(src, source->buf_end); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, src_channels); - dst_samples_wo_wrap = audio_stream_samples_without_wrap_s16(sink, dst); - dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s16(dst, sink->buf_end); + n = MIN(n, SOF_DIV_ROUND_UP(samples_wo_wrap, sink_channels)); - n = MIN(src_loops, dst_loops); n = MIN(n, frames_left); for (i = 0; i < n; i++) { *dst = *src; - src += num_src_channels; - dst += num_sink_channels; + src += src_channels; + dst += sink_channels; } frames_left -= n; @@ -110,19 +107,20 @@ static int remap_c16(const struct audio_stream *source, uint32_t dummy1, return source_samples; } -static inline int remap_c32_left_shift(const struct audio_stream *source, - struct audio_stream *sink, - uint32_t source_samples, uint32_t chmap, +static inline int remap_c32_left_shift(const struct cir_buf_source *source, + uint32_t num_src_channels, + struct cir_buf_sink *sink, + uint32_t num_sink_channels, + size_t source_samples, uint32_t chmap, int shift) { - int src_channel, sink_channel; - int num_src_channels = audio_stream_get_channels(source); - int num_sink_channels = audio_stream_get_channels(sink); - int frames = source_samples / num_src_channels; + uint32_t src_channel, sink_channel; + size_t frames = source_samples / num_src_channels; for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { - int32_t *src, *dst; - int frames_left; + const int32_t *src; + int32_t *dst; + size_t frames_left; src_channel = chmap & 0xf; chmap >>= 4; @@ -131,29 +129,27 @@ static inline int remap_c32_left_shift(const struct audio_stream *source, * a crafted chmap nibble cannot index past the source frame. */ if (src_channel == 0xf || src_channel >= num_src_channels) { - mute_channel_c32(sink, sink_channel, frames); + mute_channel_c32(sink, num_sink_channels, sink_channel, frames); continue; } - src = (int32_t *)audio_stream_get_rptr(source) + src_channel; - dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + src = (const int32_t *)source->ptr + src_channel; + dst = (int32_t *)sink->ptr + sink_channel; frames_left = frames; while (frames_left) { - int src_samples_wo_wrap, dst_samples_wo_wrap; - int src_loops, dst_loops, n, i; + size_t samples_wo_wrap, n, i; - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); - src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); - src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(src, source->buf_end); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_src_channels); - dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); - dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(dst, sink->buf_end); + n = MIN(n, SOF_DIV_ROUND_UP(samples_wo_wrap, num_sink_channels)); - n = MIN(src_loops, dst_loops); n = MIN(n, frames_left); for (i = 0; i < n; i++) { @@ -169,19 +165,20 @@ static inline int remap_c32_left_shift(const struct audio_stream *source, return source_samples; } -static inline int remap_c32_right_shift(const struct audio_stream *source, - struct audio_stream *sink, - uint32_t source_samples, uint32_t chmap, +static inline int remap_c32_right_shift(const struct cir_buf_source *source, + uint32_t num_src_channels, + struct cir_buf_sink *sink, + uint32_t num_sink_channels, + size_t source_samples, uint32_t chmap, int shift) { - int src_channel, sink_channel; - int num_src_channels = audio_stream_get_channels(source); - int num_sink_channels = audio_stream_get_channels(sink); - int frames = source_samples / num_src_channels; + uint32_t src_channel, sink_channel; + size_t frames = source_samples / num_src_channels; for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { - int32_t *src, *dst; - int frames_left; + const int32_t *src; + int32_t *dst; + size_t frames_left; src_channel = chmap & 0xf; chmap >>= 4; @@ -190,29 +187,27 @@ static inline int remap_c32_right_shift(const struct audio_stream *source, * a crafted chmap nibble cannot index past the source frame. */ if (src_channel == 0xf || src_channel >= num_src_channels) { - mute_channel_c32(sink, sink_channel, frames); + mute_channel_c32(sink, num_sink_channels, sink_channel, frames); continue; } - src = (int32_t *)audio_stream_get_rptr(source) + src_channel; - dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + src = (const int32_t *)source->ptr + src_channel; + dst = (int32_t *)sink->ptr + sink_channel; frames_left = frames; while (frames_left) { - int src_samples_wo_wrap, dst_samples_wo_wrap; - int src_loops, dst_loops, n, i; + size_t samples_wo_wrap, n, i; - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); - src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); - src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(src, source->buf_end); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_src_channels); - dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); - dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(dst, sink->buf_end); + n = MIN(n, SOF_DIV_ROUND_UP(samples_wo_wrap, num_sink_channels)); - n = MIN(src_loops, dst_loops); n = MIN(n, frames_left); for (i = 0; i < n; i++) { @@ -228,20 +223,20 @@ static inline int remap_c32_right_shift(const struct audio_stream *source, return source_samples; } -static inline int remap_c16_to_c32(const struct audio_stream *source, - struct audio_stream *sink, - uint32_t source_samples, uint32_t chmap, +static inline int remap_c16_to_c32(const struct cir_buf_source *source, + uint32_t num_src_channels, + struct cir_buf_sink *sink, + uint32_t num_sink_channels, + size_t source_samples, uint32_t chmap, int shift) { - int src_channel, sink_channel; - int num_src_channels = audio_stream_get_channels(source); - int num_sink_channels = audio_stream_get_channels(sink); - int frames = source_samples / num_src_channels; + uint32_t src_channel, sink_channel; + size_t frames = source_samples / num_src_channels; for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { - int16_t *src; + const int16_t *src; int32_t *dst; - int frames_left; + size_t frames_left; src_channel = chmap & 0xf; chmap >>= 4; @@ -250,29 +245,27 @@ static inline int remap_c16_to_c32(const struct audio_stream *source, * a crafted chmap nibble cannot index past the source frame. */ if (src_channel == 0xf || src_channel >= num_src_channels) { - mute_channel_c32(sink, sink_channel, frames); + mute_channel_c32(sink, num_sink_channels, sink_channel, frames); continue; } - src = (int16_t *)audio_stream_get_rptr(source) + src_channel; - dst = (int32_t *)audio_stream_get_wptr(sink) + sink_channel; + src = (const int16_t *)source->ptr + src_channel; + dst = (int32_t *)sink->ptr + sink_channel; frames_left = frames; while (frames_left) { - int src_samples_wo_wrap, dst_samples_wo_wrap; - int src_loops, dst_loops, n, i; + size_t samples_wo_wrap, n, i; - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); - src_samples_wo_wrap = audio_stream_samples_without_wrap_s16(source, src); - src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s16(src, source->buf_end); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_src_channels); - dst_samples_wo_wrap = audio_stream_samples_without_wrap_s32(sink, dst); - dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(dst, sink->buf_end); + n = MIN(n, SOF_DIV_ROUND_UP(samples_wo_wrap, num_sink_channels)); - n = MIN(src_loops, dst_loops); n = MIN(n, frames_left); for (i = 0; i < n; i++) { @@ -288,20 +281,20 @@ static inline int remap_c16_to_c32(const struct audio_stream *source, return source_samples; } -static inline int remap_c32_to_c16(const struct audio_stream *source, - struct audio_stream *sink, - uint32_t source_samples, uint32_t chmap, +static inline int remap_c32_to_c16(const struct cir_buf_source *source, + uint32_t num_src_channels, + struct cir_buf_sink *sink, + uint32_t num_sink_channels, + size_t source_samples, uint32_t chmap, int shift) { - int src_channel, sink_channel; - int num_src_channels = audio_stream_get_channels(source); - int num_sink_channels = audio_stream_get_channels(sink); - int frames = source_samples / num_src_channels; + uint32_t src_channel, sink_channel; + size_t frames = source_samples / num_src_channels; for (sink_channel = 0; sink_channel < num_sink_channels; sink_channel++) { - int32_t *src; + const int32_t *src; int16_t *dst; - int frames_left; + size_t frames_left; src_channel = chmap & 0xf; chmap >>= 4; @@ -310,29 +303,27 @@ static inline int remap_c32_to_c16(const struct audio_stream *source, * a crafted chmap nibble cannot index past the source frame. */ if (src_channel == 0xf || src_channel >= num_src_channels) { - mute_channel_c16(sink, sink_channel, frames); + mute_channel_c16(sink, num_sink_channels, sink_channel, frames); continue; } - src = (int32_t *)audio_stream_get_rptr(source) + src_channel; - dst = (int16_t *)audio_stream_get_wptr(sink) + sink_channel; + src = (const int32_t *)source->ptr + src_channel; + dst = (int16_t *)sink->ptr + sink_channel; frames_left = frames; while (frames_left) { - int src_samples_wo_wrap, dst_samples_wo_wrap; - int src_loops, dst_loops, n, i; + size_t samples_wo_wrap, n, i; - src = audio_stream_wrap(source, src); - dst = audio_stream_wrap(sink, dst); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); + dst = cir_buf_wrap(dst, sink->buf_start, sink->buf_end); - src_samples_wo_wrap = audio_stream_samples_without_wrap_s32(source, src); - src_loops = SOF_DIV_ROUND_UP(src_samples_wo_wrap, num_src_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s32(src, source->buf_end); + n = SOF_DIV_ROUND_UP(samples_wo_wrap, num_src_channels); - dst_samples_wo_wrap = audio_stream_samples_without_wrap_s16(sink, dst); - dst_loops = SOF_DIV_ROUND_UP(dst_samples_wo_wrap, num_sink_channels); + samples_wo_wrap = cir_buf_samples_without_wrap_s16(dst, sink->buf_end); + n = MIN(n, SOF_DIV_ROUND_UP(samples_wo_wrap, num_sink_channels)); - n = MIN(src_loops, dst_loops); n = MIN(n, frames_left); for (i = 0; i < n; i++) { @@ -348,81 +339,96 @@ static inline int remap_c32_to_c16(const struct audio_stream *source, return source_samples; } -static int remap_c32(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_left_shift(source, sink, source_samples, chmap, 0); + return remap_c32_left_shift(source, src_channels, sink, sink_channels, + source_samples, chmap, 0); } -static int remap_c32_to_c16_right_shift_16(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_to_c16_right_shift_16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_to_c16(source, sink, source_samples, chmap, 16); + return remap_c32_to_c16(source, src_channels, sink, sink_channels, + source_samples, chmap, 16); } -static int remap_c16_to_c32_left_shift_16(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c16_to_c32_left_shift_16(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c16_to_c32(source, sink, source_samples, chmap, 16); + return remap_c16_to_c32(source, src_channels, sink, sink_channels, + source_samples, chmap, 16); } -static int remap_c32_to_c16_right_shift_8(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_to_c16_right_shift_8(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_to_c16(source, sink, source_samples, chmap, 8); + return remap_c32_to_c16(source, src_channels, sink, sink_channels, + source_samples, chmap, 8); } -static int remap_c16_to_c32_left_shift_8(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c16_to_c32_left_shift_8(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c16_to_c32(source, sink, source_samples, chmap, 8); + return remap_c16_to_c32(source, src_channels, sink, sink_channels, + source_samples, chmap, 8); } -static int remap_c32_right_shift_8(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_right_shift_8(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_right_shift(source, sink, source_samples, chmap, 8); + return remap_c32_right_shift(source, src_channels, sink, sink_channels, + source_samples, chmap, 8); } -static int remap_c32_left_shift_8(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_left_shift_8(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_left_shift(source, sink, source_samples, chmap, 8); + return remap_c32_left_shift(source, src_channels, sink, sink_channels, + source_samples, chmap, 8); } -static int remap_c32_right_shift_16(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_right_shift_16(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_right_shift(source, sink, source_samples, chmap, 16); + return remap_c32_right_shift(source, src_channels, sink, sink_channels, + source_samples, chmap, 16); } -static int remap_c32_left_shift_16(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_left_shift_16(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_left_shift(source, sink, source_samples, chmap, 16); + return remap_c32_left_shift(source, src_channels, sink, sink_channels, + source_samples, chmap, 16); } -static int remap_c32_to_c16_no_shift(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c32_to_c16_no_shift(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c32_to_c16(source, sink, source_samples, chmap, 0); + return remap_c32_to_c16(source, src_channels, sink, sink_channels, + source_samples, chmap, 0); } -static int remap_c16_to_c32_no_shift(const struct audio_stream *source, uint32_t dummy1, - struct audio_stream *sink, uint32_t dummy2, - uint32_t source_samples, uint32_t chmap) +static int remap_c16_to_c32_no_shift(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t source_samples, uint32_t chmap) { - return remap_c16_to_c32(source, sink, source_samples, chmap, 0); + return remap_c16_to_c32(source, src_channels, sink, sink_channels, + source_samples, chmap, 0); } /* Unfortunately, all these nice "if"s were commented out to suppress diff --git a/src/include/sof/audio/pcm_converter.h b/src/include/sof/audio/pcm_converter.h index 3563a0d6557e..1b165c4b926d 100644 --- a/src/include/sof/audio/pcm_converter.h +++ b/src/include/sof/audio/pcm_converter.h @@ -23,6 +23,8 @@ #include struct audio_stream; +struct cir_buf_source; +struct cir_buf_sink; #if __XCC__ #include @@ -38,17 +40,17 @@ struct audio_stream; /** * \brief PCM conversion function interface for data in circular buffer - * \param source buffer with samples to process, read pointer is not modified - * \param ioffset offset to first sample in source stream - * \param sink output buffer, write pointer is not modified - * \param ooffset offset to first sample in sink stream + * \param source circular-buffer source descriptor, read pointer is not modified + * \param src_channels number of channels in the source stream + * \param sink circular-buffer sink descriptor, write pointer is not modified + * \param sink_channels number of channels in the sink stream * \param source_samples number of samples to convert, for remapping -- number of source samples * \param chmap channel map for remapping, ignored by non-remapping conversion func * \return error code or number of processed samples (source samples in case of remapping). */ -typedef int (*pcm_converter_func)(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t source_samples, uint32_t chmap); +typedef int (*pcm_converter_func)(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t source_samples, uint32_t chmap); /* A channel map that does not perform any remapping. */ #define DUMMY_CHMAP 0x76543210 @@ -60,7 +62,7 @@ typedef int (*pcm_converter_func)(const struct audio_stream *source, * \param samples number of samples to convert */ typedef void (*pcm_converter_lin_func)(const void *psrc, void *pdst, - uint32_t samples); + size_t samples); /** \brief PCM conversion functions map. */ struct pcm_func_map { @@ -184,20 +186,30 @@ pcm_get_conversion_vc_function(enum sof_ipc_frame in_bits, /** * \brief Convert data from circular buffer using converter working on linear * memory space - * \param source buffer with samples to process, read pointer is not modified - * \param ioffset offset to first sample in source stream - * \param sink output buffer, write pointer is not modified - * \param ooffset offset to first sample in sink stream + * \param source circular-buffer source descriptor, read pointer is not modified + * \param s_size_in source sample size in bytes + * \param sink circular-buffer sink descriptor, write pointer is not modified + * \param s_size_out sink sample size in bytes * \param samples number of samples to convert * \param converter core conversion function working on linear memory regions * \return error code or number of processed samples */ -int pcm_convert_as_linear(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream *sink, uint32_t ooffset, - uint32_t samples, pcm_converter_lin_func converter); - -/* Copy stream without conversion. chmap parameter is ignored. */ -int just_copy(const struct audio_stream *source, uint32_t ioffset, - struct audio_stream *sink, uint32_t ooffset, uint32_t samples, uint32_t chmap); +int pcm_convert_as_linear(const struct cir_buf_source *source, size_t s_size_in, + struct cir_buf_sink *sink, size_t s_size_out, + size_t samples, pcm_converter_lin_func converter); + +/* Copy stream without conversion, typed by sample size in bytes. chmap is ignored. */ +int just_copy_1b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap); +int just_copy_2b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap); +int just_copy_3b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap); +int just_copy_4b(const struct cir_buf_source *source, uint32_t src_channels, + struct cir_buf_sink *sink, uint32_t sink_channels, + size_t samples, uint32_t chmap); #endif /* __SOF_AUDIO_PCM_CONVERTER_H__ */ diff --git a/src/lib/dma.c b/src/lib/dma.c index 137dfb4e0fea..6500e7557483 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -380,8 +380,19 @@ int dma_buffer_copy_from(struct comp_buffer *source, /* source buffer contains data copied by DMA */ audio_stream_invalidate(istream, source_bytes); - /* process data */ - ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); + /* process data; the converter consumes cir_buf descriptors */ + struct cir_buf_source cir_src = { + .buf_start = audio_stream_get_addr(istream), + .buf_end = audio_stream_get_end_addr(istream), + .ptr = audio_stream_get_rptr(istream), + }; + struct cir_buf_sink cir_snk = { + .buf_start = audio_stream_get_addr(&sink->stream), + .buf_end = audio_stream_get_end_addr(&sink->stream), + .ptr = audio_stream_get_wptr(&sink->stream), + }; + + ret = process(&cir_src, source_channels, &cir_snk, sink_channels, source_samples, chmap); buffer_stream_writeback(sink, sink_bytes); @@ -443,8 +454,19 @@ int dma_buffer_copy_to(struct comp_buffer *source, buffer_stream_invalidate(source, source_bytes); - /* process data */ - ret = process(&source->stream, 0, ostream, 0, source_samples, chmap); + /* process data; the converter consumes cir_buf descriptors */ + struct cir_buf_source cir_src = { + .buf_start = audio_stream_get_addr(&source->stream), + .buf_end = audio_stream_get_end_addr(&source->stream), + .ptr = audio_stream_get_rptr(&source->stream), + }; + struct cir_buf_sink cir_snk = { + .buf_start = audio_stream_get_addr(ostream), + .buf_end = audio_stream_get_end_addr(ostream), + .ptr = audio_stream_get_wptr(ostream), + }; + + ret = process(&cir_src, source_channels, &cir_snk, sink_channels, source_samples, chmap); /* sink buffer contains data meant to copied to DMA */ audio_stream_writeback(ostream, sink_bytes); @@ -505,8 +527,19 @@ int stream_copy_from_no_consume(struct comp_dev *dev, struct comp_buffer *source source_samples = frames * source_channels; } - /* process data */ - ret = process(istream, 0, &sink->stream, 0, source_samples, chmap); + /* process data; the converter consumes cir_buf descriptors */ + struct cir_buf_source cir_src = { + .buf_start = audio_stream_get_addr(istream), + .buf_end = audio_stream_get_end_addr(istream), + .ptr = audio_stream_get_rptr(istream), + }; + struct cir_buf_sink cir_snk = { + .buf_start = audio_stream_get_addr(&sink->stream), + .buf_end = audio_stream_get_end_addr(&sink->stream), + .ptr = audio_stream_get_wptr(&sink->stream), + }; + + ret = process(&cir_src, source_channels, &cir_snk, sink_channels, source_samples, chmap); #if CONFIG_INTEL_ADSP_MIC_PRIVACY struct processing_module *mod = comp_mod(dev); diff --git a/test/cmocka/src/audio/pcm_converter/pcm_float.c b/test/cmocka/src/audio/pcm_converter/pcm_float.c index 70ccd3621758..0fed36a98774 100644 --- a/test/cmocka/src/audio/pcm_converter/pcm_float.c +++ b/test/cmocka/src/audio/pcm_converter/pcm_float.c @@ -99,7 +99,20 @@ static struct comp_buffer *_test_pcm_convert(enum sof_ipc_frame frm_in, enum sof /* run conversion */ fun = pcm_get_conversion_function(frm_in, frm_out); assert_non_null(fun); - fun(&source->stream, 0, &sink->stream, 0, samples, DUMMY_CHMAP); + + struct cir_buf_source cir_src = { + .buf_start = source->stream.addr, + .buf_end = source->stream.end_addr, + .ptr = source->stream.r_ptr, + }; + struct cir_buf_sink cir_snk = { + .buf_start = sink->stream.addr, + .buf_end = sink->stream.end_addr, + .ptr = sink->stream.w_ptr, + }; + + fun(&cir_src, audio_stream_get_channels(&source->stream), + &cir_snk, audio_stream_get_channels(&sink->stream), samples, DUMMY_CHMAP); /* assert last value in sink is untouched */ assert_int_equal(((uint8_t *)sink->stream.w_ptr)[outbytes - 1], fillval); diff --git a/zephyr/include/sof/lib/dma.h b/zephyr/include/sof/lib/dma.h index 4408d265804f..5dcc8455579b 100644 --- a/zephyr/include/sof/lib/dma.h +++ b/zephyr/include/sof/lib/dma.h @@ -259,10 +259,11 @@ struct dma_copy { #endif }; -struct audio_stream; -typedef int (*dma_process_func)(const struct audio_stream *source, - uint32_t ioffset, struct audio_stream *sink, - uint32_t ooffset, uint32_t source_samples, uint32_t chmap); +struct cir_buf_source; +struct cir_buf_sink; +typedef int (*dma_process_func)(const struct cir_buf_source *source, + uint32_t src_channels, struct cir_buf_sink *sink, + uint32_t sink_channels, size_t source_samples, uint32_t chmap); /** * \brief API to initialize a platform DMA controllers. From b8d599957229377938ade801536e9fa5a2e39798 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 7 Jul 2026 12:01:52 +0200 Subject: [PATCH 018/109] schedule: dp: call directly instead of a notifier scheduler_dp_ll_tick() is currently registered as a notifier callback, but it's always triggered deterministically, always with the same-core-only flag, which leads to it being called immediately. So the notifier only adds a layer of indirection and reduces clarity. Replace it with a direct function call. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/notifier.h | 1 - src/include/sof/schedule/dp_schedule.h | 1 + src/schedule/README.md | 4 +-- src/schedule/ll_schedule_xtos.c | 6 ++-- src/schedule/zephyr_dp_schedule.c | 31 +++++++------------ src/schedule/zephyr_dp_schedule.h | 2 +- src/schedule/zephyr_dp_schedule_application.c | 4 +-- src/schedule/zephyr_dp_schedule_thread.c | 9 ++++-- src/schedule/zephyr_ll.c | 8 ++--- 9 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/include/sof/lib/notifier.h b/src/include/sof/lib/notifier.h index 87ca2cd40265..f022b805144c 100644 --- a/src/include/sof/lib/notifier.h +++ b/src/include/sof/lib/notifier.h @@ -28,7 +28,6 @@ enum notify_id { NOTIFIER_ID_KPB_CLIENT_EVT, /* struct kpb_event_data * */ NOTIFIER_ID_DMA_DOMAIN_CHANGE, /* struct dma_chan_data * */ NOTIFIER_ID_DMA_COPY, /* struct dma_cb_data* */ - NOTIFIER_ID_LL_POST_RUN, /* NULL */ NOTIFIER_ID_DMA_IRQ, /* struct dma_chan_data * */ NOTIFIER_ID_DAI_TRIGGER, /* struct dai_group * */ NOTIFIER_ID_MIC_PRIVACY_STATE_CHANGE, /* struct mic_privacy_settings * */ diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index 2267d676fb8a..d4225d741930 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -78,6 +78,7 @@ int scheduler_dp_task_init(struct task **task, uint16_t core, size_t stack_size, uint32_t options); +void scheduler_dp_ll_tick(void); /** * \brief Extract information about scheduler's tasks diff --git a/src/schedule/README.md b/src/schedule/README.md index 493ab092decc..6c919ae96a19 100644 --- a/src/schedule/README.md +++ b/src/schedule/README.md @@ -50,7 +50,7 @@ graph TD DMADomain --> |Wakeup| LL LL -->|Runs tasks| Threads - LL -->|NOTIFIER_ID_LL_POST_RUN| DP + LL -->|LL Tick Source| DP DP -->|Recalculate Deadlines| DPThread DPThread -->|Update Thread Deadlines| Threads @@ -69,7 +69,7 @@ The LL scheduler (`zephyr_ll.c`) is designed for extreme low-latency processing. - **Domain Threads**: The LL scheduler runs within a dedicated high-priority Zephyr thread (`ll_thread0`, etc.) pinned to each core (`zephyr_domain.c`). - **Triggers**: It is woken up by a hardware timer (e.g., a 1ms tick) or directly by hardware DMA interrupts (`zephyr_dma_domain.c`). - **Execution**: Once woken up, it locks the domain, iterates through all scheduled tasks in priority order, moves them to a temporary list, and calls their `.run()` functions. -- **Post-Run**: After all tasks execute, it triggers a `NOTIFIER_ID_LL_POST_RUN` event. This event cascades to wake up other dependent schedulers like DP and TWB. Event not run on LL userspace configuration. +- **Post-Run**: After all tasks execute, it triggers the DP scheduler for task deadline recalculation. ### Task State Diagram diff --git a/src/schedule/ll_schedule_xtos.c b/src/schedule/ll_schedule_xtos.c index be24f3b34fd4..0df3cc9a271d 100644 --- a/src/schedule/ll_schedule_xtos.c +++ b/src/schedule/ll_schedule_xtos.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -317,8 +318,9 @@ static void schedule_ll_tasks_run(void *data) if (schedule_ll_is_pending(sch)) schedule_ll_tasks_execute(sch); - notifier_event(sch, NOTIFIER_ID_LL_POST_RUN, - NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); +#ifdef CONFIG_ZEPHYR_DP_SCHEDULER + scheduler_dp_ll_tick(); +#endif perf_cnt_stamp(&sch->pcd, perf_ll_sched_trace, 0 /* ignored */); perf_cnt_average(&sch->pcd, perf_avg_ll_sched_trace, 0 /* ignored */); diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 25fa8b319457..7beb739d1b09 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include "zephyr_dp_schedule.h" @@ -223,19 +222,19 @@ static enum task_state scheduler_dp_ll_tick_dummy(void *data) * needed 1.2ms for processing - but the example would be too complicated) */ -void scheduler_dp_ll_tick(void *receiver_data, enum notify_id event_type, void *caller_data) +void scheduler_dp_ll_tick(void) { - (void)receiver_data; - (void)event_type; - (void)caller_data; unsigned int lock_key; struct scheduler_dp_data *dp_sch = scheduler_get_data(SOF_SCHEDULE_DP); + if (!dp_sch) + return; + /* remember current timestamp as "NOW" */ dp_sch->last_ll_tick_timestamp = k_cycle_get_32(); lock_key = scheduler_dp_lock(cpu_get_id()); - scheduler_dp_recalculate(dp_sch, event_type == NOTIFIER_ID_LL_POST_RUN); + scheduler_dp_recalculate(dp_sch); scheduler_dp_unlock(lock_key); } @@ -347,10 +346,9 @@ static struct scheduler_ops schedule_dp_ops = { .schedule_task_free = scheduler_dp_task_free, }; +/* Runs on each core */ __cold int scheduler_dp_init(void) { - int ret; - assert_can_be_cold(); struct scheduler_dp_data *dp_sch = rzalloc(SOF_MEM_FLAG_KERNEL, @@ -364,18 +362,11 @@ __cold int scheduler_dp_init(void) scheduler_init(SOF_SCHEDULE_DP, &schedule_dp_ops, dp_sch); /* init src of DP tick */ - ret = schedule_task_init_ll(&dp_sch->ll_tick_src, - SOF_UUID(dp_sched_uuid), - SOF_SCHEDULE_LL_TIMER, - 0, scheduler_dp_ll_tick_dummy, dp_sch, - cpu_get_id(), 0); - - if (ret) - return ret; - - notifier_register(NULL, NULL, NOTIFIER_ID_LL_POST_RUN, scheduler_dp_ll_tick, 0); - - return 0; + return schedule_task_init_ll(&dp_sch->ll_tick_src, + SOF_UUID(dp_sched_uuid), + SOF_SCHEDULE_LL_TIMER, + 0, scheduler_dp_ll_tick_dummy, dp_sch, + cpu_get_id(), 0); } void scheduler_get_task_info_dp(struct scheduler_props *scheduler_props, uint32_t *data_off_size) diff --git a/src/schedule/zephyr_dp_schedule.h b/src/schedule/zephyr_dp_schedule.h index c4f37fc812f2..694bb541f87e 100644 --- a/src/schedule/zephyr_dp_schedule.h +++ b/src/schedule/zephyr_dp_schedule.h @@ -52,7 +52,7 @@ struct task_dp_pdata { #endif }; -void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_run); +void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch); void dp_thread_fn(void *p1, void *p2, void *p3); unsigned int scheduler_dp_lock(uint16_t core); void scheduler_dp_unlock(unsigned int key); diff --git a/src/schedule/zephyr_dp_schedule_application.c b/src/schedule/zephyr_dp_schedule_application.c index 791e16ab190d..daf9070ae4dc 100644 --- a/src/schedule/zephyr_dp_schedule_application.c +++ b/src/schedule/zephyr_dp_schedule_application.c @@ -197,7 +197,7 @@ int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, /* Go through all DP tasks and recalculate their readiness and deadlines * NOT REENTRANT, called with scheduler_dp_lock() held */ -void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_run) +void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch) { struct list_item *tlist; struct task *curr_task; @@ -210,7 +210,7 @@ void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_ bool trigger_task = false; /* decrease number of LL ticks/cycles left till the module reaches its deadline */ - if (mod->dp_startup_delay && is_ll_post_run && pdata->ll_cycles_to_start) { + if (mod->dp_startup_delay && pdata->ll_cycles_to_start) { pdata->ll_cycles_to_start--; if (!pdata->ll_cycles_to_start) /* delayed start complete, clear startup delay flag. diff --git a/src/schedule/zephyr_dp_schedule_thread.c b/src/schedule/zephyr_dp_schedule_thread.c index 7fbb3b6a5c21..f2c2434bc2b5 100644 --- a/src/schedule/zephyr_dp_schedule_thread.c +++ b/src/schedule/zephyr_dp_schedule_thread.c @@ -30,7 +30,7 @@ extern struct tr_ctx dp_tr; /* Go through all DP tasks and recalculate their readiness and deadlines * NOT REENTRANT, should be called with scheduler_dp_lock() */ -void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_run) +static void scheduler_dp_recalculate_thread(struct scheduler_dp_data *dp_sch, bool is_ll_post_run) { struct list_item *tlist; struct task *curr_task; @@ -106,6 +106,11 @@ void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch, bool is_ll_post_ } } +void scheduler_dp_recalculate(struct scheduler_dp_data *dp_sch) +{ + scheduler_dp_recalculate_thread(dp_sch, true); +} + /* Thread function called in component context, on target core */ void dp_thread_fn(void *p1, void *p2, void *p3) { @@ -177,7 +182,7 @@ void dp_thread_fn(void *p1, void *p2, void *p3) * currently its limited to current core only */ if (dp_sch) - scheduler_dp_recalculate(dp_sch, false); + scheduler_dp_recalculate_thread(dp_sch, false); scheduler_dp_unlock(lock_key); } diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 15a1846bcadf..fd70a4fe31df 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -325,10 +325,8 @@ static void zephyr_ll_run(void *data) zephyr_ll_unlock(sch, &flags); -#ifndef CONFIG_SOF_USERSPACE_LL - /* TODO: to be replaced with direct function calls */ - notifier_event(sch, NOTIFIER_ID_LL_POST_RUN, - NOTIFIER_TARGET_CORE_LOCAL, NULL, 0); +#ifdef CONFIG_ZEPHYR_DP_SCHEDULER + scheduler_dp_ll_tick(); #endif } From f3732b2f61fa5020aa64fd2a0d296455a0538225 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Mon, 27 Jul 2026 19:12:09 +0200 Subject: [PATCH 019/109] tools: rimage: return a negative error code from elf_error() elf_error() negates its argument, so an already negative code was turned into a positive value that callers testing "ret < 0" take for success. Signed-off-by: Adrian Bonislawski --- tools/rimage/src/elf_file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/rimage/src/elf_file.c b/tools/rimage/src/elf_file.c index c40d3a69abfb..c68a7d3af4e6 100644 --- a/tools/rimage/src/elf_file.c +++ b/tools/rimage/src/elf_file.c @@ -95,13 +95,13 @@ static struct name_val p_flags[] = { * * @param elf elf file structure * @param msg error message - * @param error error code to return - * @return error code + * @param error positive errno value, or an already negative error code + * @return negative error code */ static int elf_error(const struct elf_file *elf, const char *msg, int error) { fprintf(stderr, "Error: %s: %s\n", elf->filename, msg); - return -error; + return error < 0 ? error : -error; } /** From 1a9554a848a6368ff595c8789e096088bbf4cde3 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 6 Aug 2026 19:24:49 +0300 Subject: [PATCH 020/109] zephyr: cpu: turn cpu_get_id() into a system call cpu_get_id() ultimately reads a privileged special register via arch_proc_id() (e.g. the Xtensa PRID register). When low-atency pipelines run in user-space threads (CONFIG_SOF_USERSPACE_LL), this read is issued from user mode and faults. While many direct usages of cpu_get_id() have been removed from SOF codebase, multiple usages remain. As the remaining usages are mostly on less frequently used code paths (most via cpu_is_me() call, which is used in IPC handling), opt to keep the remaining cpu_get_id() calls and make the function available as a system call. The system call machinery is gated on CONFIG_SOF_FULL_ZEPHYR_APPLICATION so unit-test builds keep the plain inline definition. Signed-off-by: Kai Vehmanen --- zephyr/CMakeLists.txt | 2 ++ zephyr/include/sof/lib/cpu.h | 27 +++++++++++++++++++++++++++ zephyr/syscall/cpu.c | 22 ++++++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 zephyr/syscall/cpu.c diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index 0ed4a13ee742..e0e7e8bfb302 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -620,6 +620,8 @@ zephyr_library_sources_ifdef(CONFIG_SHELL sof_shell.c ) +zephyr_syscall_header(include/sof/lib/cpu.h) +zephyr_library_sources_ifdef(CONFIG_USERSPACE syscall/cpu.c) zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/audio/module_adapter/module/generic.h) zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/fast-get.h) zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/ipc/ipc_reply.h) diff --git a/zephyr/include/sof/lib/cpu.h b/zephyr/include/sof/lib/cpu.h index c23405e85121..a47b93898973 100644 --- a/zephyr/include/sof/lib/cpu.h +++ b/zephyr/include/sof/lib/cpu.h @@ -40,13 +40,32 @@ void cpu_notify_state_exit(enum pm_state state); #endif /* CONFIG_PM */ +/* + * cpu_get_id() is exposed as a Zephyr system call so that user-mode + * threads (e.g. user-space LL pipelines) can query the current core + * id. The underlying arch_proc_id() reads a privileged special + * register (e.g. Xtensa PRID) which would fault if executed directly + * from user mode. In supervisor context the generated wrapper inlines + * the z_impl_cpu_get_id() body, so there is no overhead there. + */ +#if defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +__syscall int cpu_get_id(void); +#endif + /* let the compiler optimise when in single core mode */ #if CONFIG_MULTICORE && CONFIG_SMP +#if defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +static inline int z_impl_cpu_get_id(void) +{ + return arch_proc_id(); +} +#else static inline int cpu_get_id(void) { return arch_proc_id(); } +#endif static inline bool cpu_is_primary(int id) { @@ -73,7 +92,11 @@ int cpu_restore_secondary_cores(void); int cpu_secondary_cores_prepare_d0ix(void); #else +#if defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +static inline int z_impl_cpu_get_id(void) { return 0; }; +#else static inline int cpu_get_id(void) { return 0; }; +#endif static inline bool cpu_is_primary(int id) { return 1; }; @@ -93,6 +116,10 @@ static inline int cpu_secondary_cores_prepare_d0ix(void) { return 0; }; #endif /* CONFIG_MULTICORE && CONFIG_SMP */ +#if defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) +#include +#endif + #endif #endif /* __SOF_LIB_CPU_H__ */ diff --git a/zephyr/syscall/cpu.c b/zephyr/syscall/cpu.c new file mode 100644 index 000000000000..ee1990db8fd4 --- /dev/null +++ b/zephyr/syscall/cpu.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include +#include +#include + +/** + * \brief Userspace verification wrapper for cpu_get_id(). + * + * The system call takes no arguments and passes no pointers, so no + * access validation is required; the call is simply forwarded to the + * implementation running in supervisor context. + * + * @return Id of the DSP core executing the call. + */ +static inline int z_vrfy_cpu_get_id(void) +{ + return z_impl_cpu_get_id(); +} +#include From 76507b5edd039644180ca27c222deea9d18651e6 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 May 2026 15:03:28 +0200 Subject: [PATCH 021/109] lib-manager: use user heap for the driver object When CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP isn't selected, dynamically allocated driver objects should still be accessible to the userspace. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/lib_manager.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index 19c317ed1089..8d41eafa7e8e 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -819,6 +819,8 @@ int lib_manager_register_module(const uint32_t component_id) goto cleanup; } } +#else + drv_heap = sof_sys_user_heap_get(); #endif /* CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP */ drv = sof_heap_alloc(drv_heap, SOF_MEM_FLAG_KERNEL | SOF_MEM_FLAG_COHERENT, From 3072cce56e64e06be962bc7c8e3a110199b6ad60 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 22 May 2026 15:37:31 +0200 Subject: [PATCH 022/109] llext: map modules for userspace LL When loading and linking LLEXT modules map them automatically for the LL memory domain, unless they belong to the DP domain. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib_manager.h | 1 + src/library_manager/llext_manager.c | 66 +++++++++++++++++++++++++---- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index 29c226eb61a7..2e641476fcb4 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -115,6 +115,7 @@ struct lib_manager_module { struct llext_buf_loader *ebl; /* Zephyr loadable extension buffer loader */ unsigned int n_dependent; /* For auxiliary modules: number of dependents */ bool mapped; + bool domain_dp; struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS]; }; diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 4c1e4f02d5b5..b9e8f7ec4b29 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -23,6 +24,7 @@ #include #include #include +#include #include #include @@ -199,6 +201,13 @@ static void llext_manager_unmap_detached_sections(const struct llext_loader *ldr #endif } +#ifdef CONFIG_USERSPACE +static int llext_manager_add_mod_domain(struct lib_manager_module *mctx, + struct k_mem_domain *domain); +static int llext_manager_rm_mod_domain(struct lib_manager_module *mctx, + struct k_mem_domain *domain); +#endif + static int llext_manager_load_module(struct lib_manager_module *mctx) { /* Executable code (.text) */ @@ -292,8 +301,22 @@ static int llext_manager_load_module(struct lib_manager_module *mctx) memset((__sparse_force void *)bss_addr, 0, bss_size); mctx->mapped = true; - return 0; +#ifdef CONFIG_SOF_USERSPACE_LL + if (!mctx->domain_dp) { + ret = llext_manager_add_mod_domain(mctx, zephyr_ll_mem_domain()); + if (ret < 0) { + tr_err(&lib_manager_tr, "failed to add domain: %d", ret); + goto e_data; + } + } +#endif + return 0; +#ifdef CONFIG_SOF_USERSPACE_LL +e_data: + if (data_size) + llext_manager_align_unmap(va_base_data, data_size); +#endif e_rodata: if (rodata_size) llext_manager_align_unmap(va_base_rodata, rodata_size); @@ -353,6 +376,11 @@ static int llext_manager_unload_module(struct lib_manager_module *mctx) mctx->mapped = false; +#ifdef CONFIG_SOF_USERSPACE_LL + if (!mctx->domain_dp) + llext_manager_rm_mod_domain(mctx, zephyr_ll_mem_domain()); +#endif + return err; } @@ -496,6 +524,7 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, if (mod_array[i].segment[LIB_MANAGER_TEXT].file_offset != offs) { offs = mod_array[i].segment[LIB_MANAGER_TEXT].file_offset; ctx->mod[n_mod].mapped = false; + ctx->mod[n_mod].domain_dp = false; ctx->mod[n_mod].llext = NULL; ctx->mod[n_mod].ebl = NULL; ctx->mod[n_mod].n_dependent = 0; @@ -738,6 +767,8 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config dep_ctx[i] = dep; } + /* Avoid mapping DP modules to the LL domain */ + mctx->domain_dp = ipc_config->proc_domain == COMP_PROCESSING_DOMAIN_DP; /* Map executable code and data */ ret = llext_manager_load_module(mctx); if (ret < 0) @@ -778,13 +809,8 @@ static int llext_manager_rm_partition(struct k_mem_domain *domain, return k_mem_domain_remove_partition(domain, &part); } -int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *domain) +static int llext_manager_add_mod_domain(struct lib_manager_module *mctx, struct k_mem_domain *domain) { - const uint32_t module_id = IPC4_MOD_ID(component_id); - struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); - const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); - const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); - struct lib_manager_module *mctx = ctx->mod + mod_idx; const struct llext *ext = mctx->llext; const struct llext_loader *ldr = &mctx->ebl->loader; @@ -800,6 +826,13 @@ int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *d uintptr_t va_base_data = mctx->segment[LIB_MANAGER_DATA].addr; size_t data_size = mctx->segment[LIB_MANAGER_DATA].size; + /* + * Add to domain on first load: for "normal" modules use_count == 1, + * for dependencies use_count == 2 and n_dependent == 1 + */ + if (ext->use_count > 1 && mctx->n_dependent != 1) + return 0; + int ret = llext_manager_add_partition(domain, va_base_text, text_size, K_MEM_PARTITION_P_RX_U_RX | XTENSA_MMU_CACHED_WB); @@ -914,7 +947,7 @@ int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *d return ret; } -int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *domain) +int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *domain) { const uint32_t module_id = IPC4_MOD_ID(component_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); @@ -922,6 +955,12 @@ int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *do const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); struct lib_manager_module *mctx = ctx->mod + mod_idx; + /* FIXME: handle dependencies */ + return llext_manager_add_mod_domain(mctx, domain); +} + +static int llext_manager_rm_mod_domain(struct lib_manager_module *mctx, struct k_mem_domain *domain) +{ /* Executable code (.text) */ uintptr_t va_base_text = mctx->segment[LIB_MANAGER_TEXT].addr; size_t text_size = mctx->segment[LIB_MANAGER_TEXT].size; @@ -988,6 +1027,17 @@ int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *do return ret; } + +int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *domain) +{ + const uint32_t module_id = IPC4_MOD_ID(component_id); + struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); + const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); + const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + struct lib_manager_module *mctx = ctx->mod + mod_idx; + + return llext_manager_rm_mod_domain(mctx, domain); +} #endif int llext_manager_free_module(const uint32_t component_id) From 00f1d48f956acfe51eae59804947350e3cda61e3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Jun 2026 15:57:14 +0200 Subject: [PATCH 023/109] ipc: allocate userspace IPC thread dynamically Prepare for multi-core support: allocate the IPC thread dynamically and extract thread initialisation into a separate function. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc-common.c | 77 +++++++++++++++++++++++++++++++------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/ipc/ipc-common.c b/src/ipc/ipc-common.c index afc8fe45de05..eb961a95bdfe 100644 --- a/src/ipc/ipc-common.c +++ b/src/ipc/ipc-common.c @@ -318,7 +318,6 @@ void ipc_schedule_process(struct ipc *ipc) #define IPC_USER_EVENT_CMD BIT(0) #define IPC_USER_EVENT_STOP BIT(1) -static struct k_thread ipc_user_thread; static K_THREAD_STACK_DEFINE(ipc_user_stack, CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE); /** @@ -419,6 +418,54 @@ static void ipc_user_thread_fn(void *p1, void *p2, void *p3) } } +__cold static int ipc_user_init_thread(struct ipc_user *ipc_user) +{ + char thread_name[] = "ll_user0"; + int ret; + + assert_can_be_cold(); + + /* Allocate kernel objects for the user-space thread */ + ipc_user->event = k_object_alloc(K_OBJ_EVENT); + if (!ipc_user->event) { + LOG_ERR("user IPC event alloc failed"); + return -ENOMEM; + } + k_event_init(ipc_user->event); + + ipc_user->thread = k_object_alloc(K_OBJ_THREAD); + if (!ipc_user->thread) { + LOG_ERR("user IPC thread alloc failed"); + ret = -ENOMEM; + goto e_event; + } + + k_thread_create(ipc_user->thread, ipc_user_stack, + CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE, + ipc_user_thread_fn, ipc_user, NULL, NULL, + -1, K_USER, K_FOREVER); + + k_thread_cpu_pin(ipc_user->thread, PLATFORM_PRIMARY_CORE_ID); + k_thread_name_set(ipc_user->thread, thread_name); + + /* + * Each userspace IPC thread must be able to wait on its private event + * and signal completion on the primary core semaphore + */ + k_thread_access_grant(ipc_user->thread, ipc_user->sem, ipc_user->event); + user_grant_dai_access_all(ipc_user->thread); + user_grant_dma_access_all(ipc_user->thread); + k_mem_domain_add_thread(zephyr_ll_mem_domain(), ipc_user->thread); + user_ll_grant_access(ipc_user->thread, PLATFORM_PRIMARY_CORE_ID); + + return 0; + +e_event: + k_object_free(ipc_user->event); + + return ret; +} + __cold static void ipc_user_init(void) { struct ipc *ipc = ipc_get(); @@ -443,38 +490,22 @@ __cold static void ipc_user_init(void) k_sem_init(ipc_user->sem, 0, 1); - /* Allocate kernel objects for the user-space thread */ - ipc_user->event = k_object_alloc(K_OBJ_EVENT); - if (!ipc_user->event) { - LOG_ERR("user IPC event alloc failed"); + ret = ipc_user_init_thread(ipc_user); + if (ret < 0) { + LOG_ERR("user IPC thread initialization failed"); sof_panic(SOF_IPC_PANIC_IPC); } - k_event_init(ipc_user->event); - k_thread_create(&ipc_user_thread, ipc_user_stack, - CONFIG_SOF_IPC_USER_THREAD_STACK_SIZE, - ipc_user_thread_fn, ipc_user, NULL, NULL, - -1, K_USER, K_FOREVER); - - ipc_user->thread = &ipc_user_thread; - k_thread_access_grant(&ipc_user_thread, ipc_user->sem, ipc_user->event); - user_grant_dai_access_all(&ipc_user_thread); - user_grant_dma_access_all(&ipc_user_thread); - ret = user_access_to_mailbox(zephyr_ll_mem_domain(), &ipc_user_thread); + ret = user_access_to_mailbox(zephyr_ll_mem_domain(), ipc_user->thread); if (ret < 0) { LOG_ERR("ipc user: mailbox access grant failed: %d", ret); sof_panic(SOF_IPC_PANIC_IPC); } - user_ll_grant_access(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID); - k_mem_domain_add_thread(zephyr_ll_mem_domain(), &ipc_user_thread); - - k_thread_cpu_pin(&ipc_user_thread, PLATFORM_PRIMARY_CORE_ID); - k_thread_name_set(&ipc_user_thread, "ipc_user"); /* Store references in ipc struct so kernel handler can forward commands */ ipc->ipc_user_pdata = ipc_user; - k_thread_start(&ipc_user_thread); + k_thread_start(ipc_user->thread); struct task *task = zephyr_ll_task_alloc(); @@ -486,7 +517,7 @@ __cold static void ipc_user_init(void) * Needed so user-space dai_common_new() can call * k_thread_access_grant(audio_thread, dai_mutex) from user context. */ - k_thread_access_grant(&ipc_user_thread, ipc_user->audio_thread); + k_thread_access_grant(ipc_user->thread, ipc_user->audio_thread); /* Wait for user thread startup — consumes the initial k_sem_give from thread */ k_sem_take(ipc->ipc_user_pdata->sem, K_FOREVER); From 9543056b4f7453ebacaba2a5940bda5f27400200 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 10 Jun 2026 16:03:36 +0200 Subject: [PATCH 024/109] ipc: allocate userspace context uncached Userspace IPC context is global, allocate it uncached. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc-common.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ipc/ipc-common.c b/src/ipc/ipc-common.c index eb961a95bdfe..96b957f9fabb 100644 --- a/src/ipc/ipc-common.c +++ b/src/ipc/ipc-common.c @@ -469,7 +469,8 @@ __cold static int ipc_user_init_thread(struct ipc_user *ipc_user) __cold static void ipc_user_init(void) { struct ipc *ipc = ipc_get(); - struct ipc_user *ipc_user = sof_heap_alloc(sof_sys_user_heap_get(), SOF_MEM_FLAG_USER, + struct ipc_user *ipc_user = sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, sizeof(*ipc_user), 0); int ret; From cf4bcd61ff9057ff1f16502cbaf4bbe61699b16c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 22 Jun 2026 12:04:57 +0200 Subject: [PATCH 025/109] ipc: ipc4: extract pipeline ID detection into a function The SOF_IPC4_GLB_SET_PIPELINE_STATE IPC can apply to one or to multiple pipelines. Extract pipeline ID detection into a function to be re-used with userspace IPC processing. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc4/handler-user.c | 75 +++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 57f1e8193deb..7a70e8c6ded5 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -428,6 +428,44 @@ __cold const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data_wrapper return ipc4_get_pipeline_data(); } +static int ipc4_pipeline_id_get(struct ipc4_message_request *ipc4, + struct ipc4_pipeline_set_state *state, + const uint32_t **ppl_id, unsigned int *ppl_count) +{ + if (!state->extension.r.multi_ppl) { + if (ppl_count) + *ppl_count = 1; + if (ppl_id) + *ppl_id = NULL; + return state->primary.r.ppl_id; + } + + const struct ipc4_pipeline_set_state_data *ppl_data = ipc4_get_pipeline_data(); + unsigned int cnt = ppl_data->pipelines_count; + + /* + * pipelines_count is read straight from the host-provided + * mailbox payload, so cap it at what the mailbox can + * physically hold. Anything larger means the host promised + * more ppl_id[] entries than fit in MAILBOX_HOSTBOX, and + * dereferencing the flex array would read out of bounds. + */ + if (cnt > (MAILBOX_HOSTBOX_SIZE - sizeof(struct ipc4_pipeline_set_state_data)) / + sizeof(uint32_t)) { + ipc_cmd_err(&ipc_tr, "ipc: pipelines_count %u exceeds mailbox bound", + cnt); + return -EINVAL; + } + dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_data->ppl_id, + sizeof(int) * cnt); + if (ppl_count) + *ppl_count = cnt; + if (ppl_id) + *ppl_id = ppl_data->ppl_id; + + return ppl_data->ppl_id[0]; +} + /** * \brief Process SET_PIPELINE_STATE IPC4 message (prepare + trigger phases). * @param[in] ipc4 IPC4 message request. @@ -435,46 +473,27 @@ __cold const struct ipc4_pipeline_set_state_data *ipc4_get_pipeline_data_wrapper */ int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) { - const struct ipc4_pipeline_set_state_data *ppl_data; struct ipc4_pipeline_set_state state; struct ipc_comp_dev *ppl_icd; struct ipc *ipc = ipc_get(); uint32_t cmd, ppl_count; - uint32_t id = 0; + unsigned int id; const uint32_t *ppl_id; bool use_idc = false; uint32_t idx; - int ret = 0; + int ret; int i; state.primary.dat = ipc4->primary.dat; state.extension.dat = ipc4->extension.dat; cmd = state.primary.r.ppl_state; - ppl_data = ipc4_get_pipeline_data(); - if (state.extension.r.multi_ppl) { - ppl_count = ppl_data->pipelines_count; - /* - * pipelines_count is read straight from the host-provided - * mailbox payload, so cap it at what the mailbox can - * physically hold. Anything larger means the host promised - * more ppl_id[] entries than fit in MAILBOX_HOSTBOX, and - * dereferencing the flex array would read out of bounds. - */ - if (ppl_count > (MAILBOX_HOSTBOX_SIZE - - sizeof(struct ipc4_pipeline_set_state_data)) / - sizeof(uint32_t)) { - ipc_cmd_err(&ipc_tr, - "ipc: pipelines_count %u exceeds mailbox bound", - ppl_count); - return IPC4_ERROR_INVALID_PARAM; - } - ppl_id = ppl_data->ppl_id; - dcache_invalidate_region((__sparse_force void __sparse_cache *)ppl_id, - sizeof(int) * ppl_count); - } else { - ppl_count = 1; - id = state.primary.r.ppl_id; + ret = ipc4_pipeline_id_get(ipc4, &state, &ppl_id, &ppl_count); + if (ret < 0) + return IPC4_ERROR_INVALID_PARAM; + + if (ppl_count == 1) { + id = ret; ppl_id = &id; } @@ -573,7 +592,7 @@ int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) return ret; } - return ret; + return IPC4_SUCCESS; } __cold static int ipc4_process_chain_dma(struct ipc4_message_request *ipc4) From f6892225a286ae0166402877d2091cfd6023312c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 9 Jul 2026 12:04:43 +0200 Subject: [PATCH 026/109] schedule: dp: make compatible with userspace LL DP scheduler operations, instance data and DP module memory have to be accessible to the userspace LL scheduler. Allocate dynamic data on the userspace heap and place static data in the userspace accessible ELF section. Signed-off-by: Guennadi Liakhovetski --- src/audio/module_adapter/module_adapter.c | 4 ++++ src/schedule/zephyr_dp_schedule.c | 12 +++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 53e8c75c42e2..a2b293e4ad0d 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -93,7 +93,11 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv comp_cl_err(drv, "Failed to allocate DP module heap / vregion"); return NULL; } +#ifdef CONFIG_SOF_USERSPACE_LL + mod_heap = sof_sys_user_heap_get(); +#else mod_heap = NULL; +#endif } else { #ifdef CONFIG_SOF_USERSPACE_LL mod_heap = sof_sys_user_heap_get(); diff --git a/src/schedule/zephyr_dp_schedule.c b/src/schedule/zephyr_dp_schedule.c index 7beb739d1b09..fa8bbd285791 100644 --- a/src/schedule/zephyr_dp_schedule.c +++ b/src/schedule/zephyr_dp_schedule.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -28,6 +27,9 @@ #include +#include +#include + LOG_MODULE_REGISTER(dp_schedule, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(dp_sched); @@ -336,7 +338,7 @@ static int scheduler_dp_task_shedule(void *data, struct task *task, uint64_t sta return 0; } -static struct scheduler_ops schedule_dp_ops = { +APP_SYSUSER_DATA static struct scheduler_ops schedule_dp_ops = { .schedule_task = scheduler_dp_task_shedule, #if CONFIG_SOF_USERSPACE_APPLICATION .schedule_task_cancel = scheduler_dp_task_cancel, @@ -351,12 +353,12 @@ __cold int scheduler_dp_init(void) { assert_can_be_cold(); - struct scheduler_dp_data *dp_sch = rzalloc(SOF_MEM_FLAG_KERNEL, - sizeof(struct scheduler_dp_data)); + struct scheduler_dp_data *dp_sch = sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_KERNEL, sizeof(*dp_sch), 0); if (!dp_sch) return -ENOMEM; - dp_sch->ll_tick_src.priv_data = NULL; + memset(dp_sch, 0, sizeof(*dp_sch)); list_init(&dp_sch->tasks); scheduler_init(SOF_SCHEDULE_DP, &schedule_dp_ops, dp_sch); From 302485865682cf33301fc222fa9c22b773f6cc68 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Wed, 5 Aug 2026 15:11:49 +0200 Subject: [PATCH 027/109] ipc: fix a compiler warning Fix an "unused variable" compiler warning for when buildins with CONFIG_SOF_USERSPACE_LL=y. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc-helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ipc/ipc-helper.c b/src/ipc/ipc-helper.c index cbd17d00da4c..567255a9e22a 100644 --- a/src/ipc/ipc-helper.c +++ b/src/ipc/ipc-helper.c @@ -297,7 +297,9 @@ __cold int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) struct comp_buffer *buffer; struct comp_buffer *safe; struct list_item *clist; +#ifndef CONFIG_SOF_USERSPACE_LL uint32_t flags; +#endif assert_can_be_cold(); From 02709e23ce5c919b39203e317213b6b0c47dc6b9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 10:08:15 +0200 Subject: [PATCH 028/109] ipc: (cosmetic) reduce the number of type-casts Change several pointers from "char *" to "unsigned char *" to reduce the number of type-casts. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc4/helper.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 2fac5337f0f4..fb7353c1e1a8 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -88,24 +88,25 @@ void ipc_build_trace_posn(struct sof_ipc_dma_trace_posn *posn) } #if CONFIG_LIBRARY -static inline char *ipc4_get_comp_new_data(void) +static inline unsigned char *ipc4_get_comp_new_data(void) { struct ipc *ipc = ipc_get(); - char *data = (char *)ipc->comp_data + sizeof(struct ipc4_module_init_instance); + unsigned char *data = (unsigned char *)ipc->comp_data + + sizeof(struct ipc4_module_init_instance); return data; } -static const struct comp_driver *ipc4_library_get_comp_drv(char *data) +static const struct comp_driver *ipc4_library_get_comp_drv(unsigned char *data) { return ipc4_get_drv(data); } #else -__cold static inline char *ipc4_get_comp_new_data(void) +__cold static inline unsigned char *ipc4_get_comp_new_data(void) { assert_can_be_cold(); - return (char *)MAILBOX_HOSTBOX_BASE; + return (unsigned char *)MAILBOX_HOSTBOX_BASE; } #endif @@ -116,7 +117,7 @@ __cold struct comp_dev *comp_new_ipc4(const struct ipc4_module_init_instance *mo const struct comp_driver *drv; struct comp_dev *dev; uint32_t comp_id; - char *data; + unsigned char *data; assert_can_be_cold(); @@ -190,13 +191,13 @@ __cold struct comp_dev *comp_new_ipc4(const struct ipc4_module_init_instance *mo if (drv->type == SOF_COMP_MODULE_ADAPTER) { const struct ipc_config_process spec = { - .data = (const unsigned char *)data, + .data = data, .size = ipc_config.ipc_config_size, }; - dev = drv->ops.create(drv, &ipc_config, (const void *)&spec); + dev = drv->ops.create(drv, &ipc_config, &spec); } else { - dev = drv->ops.create(drv, &ipc_config, (const void *)data); + dev = drv->ops.create(drv, &ipc_config, data); } if (!dev) return NULL; @@ -241,7 +242,7 @@ __cold struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4, struct comp_ipc_config ipc_config; struct comp_dev *dev; uint32_t comp_id; - char *data; + unsigned char *data; int ret; assert_can_be_cold(); @@ -303,13 +304,13 @@ __cold struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4, if (drv->type == SOF_COMP_MODULE_ADAPTER) { const struct ipc_config_process spec = { - .data = (const unsigned char *)data, + .data = data, .size = ipc_config.ipc_config_size, }; - dev = drv->ops.create(drv, &ipc_config, (const void *)&spec); + dev = drv->ops.create(drv, &ipc_config, &spec); } else { - dev = drv->ops.create(drv, &ipc_config, (const void *)data); + dev = drv->ops.create(drv, &ipc_config, data); } if (!dev) return NULL; From e1c266df1dc6df54f562c0b56ad55474f8ed13c3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 10:18:58 +0200 Subject: [PATCH 029/109] component: use a local UUID copy for LLEXT instances The .uid field in struct comp_driver is used for driver identification using its unique UUID. However with LLEXT that UUID is located in DRAM, which makes access to it difficult from userspace threads. Make a local copy of it instead for reliable driver searching from different contexts. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/audio/component.h | 2 ++ src/library_manager/lib_manager.c | 3 ++- test/ztest/unit/fast-get/CMakeLists.txt | 5 +++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index db8a69e63646..bf5fce875038 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -593,6 +594,7 @@ struct comp_driver { * Currently used by module_adapter. */ struct k_heap *user_heap; /**< Userspace heap */ + struct sof_uuid uid_cp; /**< UUID copy for LLEXT modules */ }; /** \brief Holds constant pointer to component driver */ diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index 8d41eafa7e8e..1b1dd5f2cc9e 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -760,7 +760,8 @@ static void lib_manager_module_free(struct comp_dev *dev) static void lib_manager_prepare_module_adapter(struct comp_driver *drv, const struct sof_uuid *uuid) { drv->type = SOF_COMP_MODULE_ADAPTER; - drv->uid = uuid; + drv->uid_cp = *uuid; + drv->uid = &drv->uid_cp; drv->tctx = &lib_manager_tr; drv->ops.create = lib_manager_module_create; drv->ops.prepare = module_adapter_prepare; diff --git a/test/ztest/unit/fast-get/CMakeLists.txt b/test/ztest/unit/fast-get/CMakeLists.txt index 39b79142d8bd..3fe6a87680f4 100644 --- a/test/ztest/unit/fast-get/CMakeLists.txt +++ b/test/ztest/unit/fast-get/CMakeLists.txt @@ -5,13 +5,18 @@ project(test_fast_get) set(SOF_ROOT "${PROJECT_SOURCE_DIR}/../../../..") +# Set SOF top directory for UUID registry generation +set(sof_top_dir ${SOF_ROOT}) + # Include SOF CMake functions include(${SOF_ROOT}/scripts/cmake/misc.cmake) +include(${SOF_ROOT}/scripts/cmake/uuid-registry.cmake) target_include_directories(app PRIVATE ${SOF_ROOT}/zephyr/include ${SOF_ROOT}/src/include ${SOF_ROOT}/src/platform/posix/include + ${PROJECT_BINARY_DIR}/include/generated # For uuid-registry.h ) # Define SOF-specific configurations for unit testing From 982533e6bb99c389f9696409591fbca2d6b57316 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 13:47:41 +0200 Subject: [PATCH 030/109] llext: add a check to llext_manager_mod_find() Add a check to llext_manager_mod_find() in case scanning the array reached the last element, that the index indeed is within that element's range. Return an error otherwise. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib_manager.h | 1 + src/library_manager/llext_manager.c | 39 ++++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index 2e641476fcb4..fb277ac75f64 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -114,6 +114,7 @@ struct lib_manager_module { struct llext *llext; /* Zephyr loadable extension context */ struct llext_buf_loader *ebl; /* Zephyr loadable extension buffer loader */ unsigned int n_dependent; /* For auxiliary modules: number of dependents */ + unsigned int n_mod; bool mapped; bool domain_dp; struct lib_manager_segment_desc segment[LIB_MANAGER_N_SEGMENTS]; diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index b9e8f7ec4b29..4ad3c55d55bc 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -528,14 +528,19 @@ static int llext_manager_mod_init(struct lib_manager_mod_ctx *ctx, ctx->mod[n_mod].llext = NULL; ctx->mod[n_mod].ebl = NULL; ctx->mod[n_mod].n_dependent = 0; - ctx->mod[n_mod++].start_idx = i; + ctx->mod[n_mod].start_idx = i; + if (n_mod) + ctx->mod[n_mod - 1].n_mod = i - ctx->mod[n_mod - 1].start_idx; + n_mod++; } + ctx->mod[n_mod - 1].n_mod = desc->header.num_module_entries - ctx->mod[n_mod - 1].start_idx; + return 0; } /* Find a module context, containing the driver with the supplied index */ -static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigned int idx) +static int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx, unsigned int idx) { unsigned int i; @@ -543,6 +548,12 @@ static unsigned int llext_manager_mod_find(const struct lib_manager_mod_ctx *ctx if (ctx->mod[i].start_idx > idx) break; + if (i == ctx->n_mod && ctx->mod[i - 1].start_idx + ctx->mod[i - 1].n_mod <= idx) { + tr_err(&lib_manager_tr, "%u beyond %u + %u after %u", idx, + ctx->mod[i - 1].start_idx, ctx->mod[i - 1].n_mod, i); + return -ENOENT; + } + return i - 1; } @@ -564,7 +575,11 @@ static int llext_manager_link_single(uint32_t module_id, const struct sof_man_fw return -EINVAL; } - unsigned int mod_ctx_idx = llext_manager_mod_find(ctx, entry_index); + int mod_ctx_idx = llext_manager_mod_find(ctx, entry_index); + + if (mod_ctx_idx < 0) + return mod_ctx_idx; + struct lib_manager_module *mctx = ctx->mod + mod_ctx_idx; size_t mod_size; int i, inst_idx; @@ -952,7 +967,11 @@ int llext_manager_add_domain(const uint32_t component_id, struct k_mem_domain *d const uint32_t module_id = IPC4_MOD_ID(component_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); - const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + const int mod_idx = llext_manager_mod_find(ctx, entry_index); + + if (mod_idx < 0) + return mod_idx; + struct lib_manager_module *mctx = ctx->mod + mod_idx; /* FIXME: handle dependencies */ @@ -1033,7 +1052,11 @@ int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *do const uint32_t module_id = IPC4_MOD_ID(component_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); const uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); - const unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + const int mod_idx = llext_manager_mod_find(ctx, entry_index); + + if (mod_idx < 0) + return mod_idx; + struct lib_manager_module *mctx = ctx->mod + mod_idx; return llext_manager_rm_mod_domain(mctx, domain); @@ -1058,7 +1081,11 @@ int llext_manager_free_module(const uint32_t component_id) return -ENOENT; } - unsigned int mod_idx = llext_manager_mod_find(ctx, entry_index); + int mod_idx = llext_manager_mod_find(ctx, entry_index); + + if (mod_idx < 0) + return mod_idx; + struct lib_manager_module *mctx = ctx->mod + mod_idx; /* Protected by IPC serialization */ From e4436e28479944cf78ac46030ce83b4f0ec6cd11 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 12 Aug 2026 12:42:25 +0300 Subject: [PATCH 031/109] module: generic: convert mod_free_all() to a syscall module_adapter_free() runs in a user-mode thread in userspace-LL mode and calls mod_free_all(). Unlike mod_free(), mod_free_all() was a plain function, so its internal sof_heap_free() calls on the module heap went through the user-mode syscall verifier, which only permits the LL user heap and K_OOPSes on the module heap. Convert mod_free_all() to a syscall so the objpool/heap cleanup runs in supervisor context, matching mod_free(). Signed-off-by: Kai Vehmanen --- src/audio/module_adapter/module/generic.c | 17 ++++++++++++++++- .../sof/audio/module_adapter/module/generic.h | 4 +++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index ee1b2df92829..e14fe2b2cecc 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -501,6 +501,20 @@ int z_vrfy_mod_free(struct processing_module *mod, const void *ptr) } #include +void z_vrfy_mod_free_all(struct processing_module *mod) +{ + size_t h_size = 0; + uintptr_t h_start; + + K_OOPS(K_SYSCALL_MEMORY_WRITE(mod, sizeof(*mod))); + mod_heap_info(mod, &h_size, &h_start); + if (h_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE(h_start, h_size)); + + z_impl_mod_free_all(mod); +} +#include + #if CONFIG_COMP_BLOB struct comp_data_blob_handler *z_vrfy_mod_data_blob_handler_new(struct processing_module *mod) { @@ -734,7 +748,7 @@ int module_reset(struct processing_module *mod) * * This function is called automatically when the module is unloaded. */ -void mod_free_all(struct processing_module *mod) +void z_impl_mod_free_all(struct processing_module *mod) { struct module_resources *res = &mod->priv.resources; @@ -749,6 +763,7 @@ void mod_free_all(struct processing_module *mod) /* Make sure resource lists and accounting are reset */ mod_resource_init(mod); } +EXPORT_SYMBOL(z_impl_mod_free_all); int module_free(struct processing_module *mod) { diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 6740593a7cf1..6976b9d485ee 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -197,12 +197,15 @@ void mod_heap_info(struct processing_module *mod, size_t *size, uintptr_t *start __syscall void *mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, size_t alignment); __syscall int mod_free(struct processing_module *mod, const void *ptr); +__syscall void mod_free_all(struct processing_module *mod); #else void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t size, size_t alignment); int z_impl_mod_free(struct processing_module *mod, const void *ptr); +void z_impl_mod_free_all(struct processing_module *mod); #define mod_alloc_ext z_impl_mod_alloc_ext #define mod_free z_impl_mod_free +#define mod_free_all z_impl_mod_free_all #endif /** @@ -259,7 +262,6 @@ const void *z_impl_mod_fast_get(struct processing_module *mod, const void * cons #endif void mod_fast_put(struct processing_module *mod, const void *sram_ptr); #endif -void mod_free_all(struct processing_module *mod); int module_prepare(struct processing_module *mod, struct sof_source **sources, int num_of_sources, struct sof_sink **sinks, int num_of_sinks); From a8571c5b976ecd3267ab35441f0025bd83f56db6 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 12 Aug 2026 19:02:42 +0300 Subject: [PATCH 032/109] posix: rtos: implement K_MUTEX_DEFINE() macro Implement a wrapper for this Zephyr interface so it can be used in generic SOF code. Signed-off-by: Kai Vehmanen --- posix/include/rtos/mutex.h | 1 + 1 file changed, 1 insertion(+) diff --git a/posix/include/rtos/mutex.h b/posix/include/rtos/mutex.h index 19b360bdaea5..f82b4169d73c 100644 --- a/posix/include/rtos/mutex.h +++ b/posix/include/rtos/mutex.h @@ -16,6 +16,7 @@ #include #define K_FOREVER ((k_timeout_t) { .ticks = 0xffffffff }) +#define K_MUTEX_DEFINE(name) struct k_mutex name struct k_mutex { struct k_spinlock lock; From a0939f4bc2e664e8b6701ba2d5e498933546ef8b Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 12 Aug 2026 15:29:13 +0300 Subject: [PATCH 033/109] module: generic: use a single static lock for module resources Replace the per-pool k_mutex embedded in struct module_resources with a single static K_MUTEX_DEFINE() shared by all module resource pools. This approach to implement locking works both in kernel and userspace SOF builds. When userspace is enabled, the resource API is only ever entered from supervisor context (the z_impl_* syscall bodies), so is it ok to have the lock only accessible from kernel. Lock contention is negligible: resource bookkeeping happens at module setup and teardown, not on the processing path, and the mutex carries priority inheritance for the rare overlap. Signed-off-by: Kai Vehmanen --- src/audio/module_adapter/module/generic.c | 55 +++++++++++-------- .../sof/audio/module_adapter/module/generic.h | 1 - 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index e14fe2b2cecc..37071a2448e3 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -28,6 +28,15 @@ LOG_MODULE_DECLARE(module_adapter, CONFIG_SOF_LOG_LEVEL); +/* + * A single lock shared by all module resource pools. The resource API is only + * ever entered from supervisor context (the z_impl_* syscall bodies), so the + * lock does not need to live in the per-module, user-writable struct - a static + * kernel object serialises all pools. Contention is negligible because resource + * bookkeeping only happens at module setup/teardown, not on the processing path. + */ +static K_MUTEX_DEFINE(mod_res_lock); + int module_load_config(struct comp_dev *dev, const void *cfg, size_t size) { int ret; @@ -79,7 +88,6 @@ void mod_resource_init(struct processing_module *mod) struct module_resources *res = &mod->priv.resources; /* Init memory list */ - k_mutex_init(&res->lock); list_init(&res->objpool.list); res->objpool.heap = res->alloc->heap; res->objpool.vreg = res->alloc->vreg; @@ -179,18 +187,18 @@ void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t struct module_resources *res = &mod->priv.resources; struct module_resource *container; - k_mutex_lock(&res->lock, K_FOREVER); + k_mutex_lock(&mod_res_lock, K_FOREVER); container = container_get(mod); if (!container) { - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } if (!size) { comp_err(mod->dev, "requested allocation of 0 bytes."); container_put(mod, container); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } @@ -202,7 +210,7 @@ void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", size, alignment, dev_comp_id(mod->dev)); container_put(mod, container); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } /* Store reference to allocated memory */ @@ -214,7 +222,7 @@ void *z_impl_mod_balloc_align(struct processing_module *mod, size_t size, size_t if (res->heap_usage > res->heap_high_water_mark) res->heap_high_water_mark = res->heap_usage; - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return ptr; } EXPORT_SYMBOL(z_impl_mod_balloc_align); @@ -235,18 +243,18 @@ void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t struct module_resources *res = &mod->priv.resources; struct module_resource *container; - k_mutex_lock(&res->lock, K_FOREVER); + k_mutex_lock(&mod_res_lock, K_FOREVER); container = container_get(mod); if (!container) { - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } if (!size) { comp_err(mod->dev, "requested allocation of 0 bytes."); container_put(mod, container); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } @@ -257,7 +265,7 @@ void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t comp_err(mod->dev, "Failed to alloc %zu bytes %zu alignment for comp %#x.", size, alignment, dev_comp_id(mod->dev)); container_put(mod, container); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } /* Store reference to allocated memory */ @@ -269,7 +277,7 @@ void *z_impl_mod_alloc_ext(struct processing_module *mod, uint32_t flags, size_t if (res->heap_usage > res->heap_high_water_mark) res->heap_high_water_mark = res->heap_usage; - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return ptr; } EXPORT_SYMBOL(z_impl_mod_alloc_ext); @@ -284,22 +292,21 @@ EXPORT_SYMBOL(z_impl_mod_alloc_ext); #if CONFIG_COMP_BLOB struct comp_data_blob_handler *z_impl_mod_data_blob_handler_new(struct processing_module *mod) { - struct module_resources *res = &mod->priv.resources; struct comp_data_blob_handler *bhp; struct module_resource *container; - k_mutex_lock(&res->lock, K_FOREVER); + k_mutex_lock(&mod_res_lock, K_FOREVER); container = container_get(mod); if (!container) { - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } bhp = comp_data_blob_handler_new_ext(mod->dev, false, NULL, NULL); if (!bhp) { container_put(mod, container); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } @@ -307,7 +314,7 @@ struct comp_data_blob_handler *z_impl_mod_data_blob_handler_new(struct processin container->size = 0; container->type = MOD_RES_BLOB_HANDLER; - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return bhp; } EXPORT_SYMBOL(z_impl_mod_data_blob_handler_new); @@ -328,18 +335,18 @@ const void *z_impl_mod_fast_get(struct processing_module *mod, const void * cons struct module_resource *container; const void *ptr; - k_mutex_lock(&res->lock, K_FOREVER); + k_mutex_lock(&mod_res_lock, K_FOREVER); container = container_get(mod); if (!container) { - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } ptr = fast_get(res->alloc, dram_ptr, size); if (!ptr) { container_put(mod, container); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return NULL; } @@ -347,7 +354,7 @@ const void *z_impl_mod_fast_get(struct processing_module *mod, const void * cons container->size = 0; container->type = MOD_RES_FAST_GET; - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); return ptr; } EXPORT_SYMBOL(z_impl_mod_fast_get); @@ -425,10 +432,10 @@ int z_impl_mod_free(struct processing_module *mod, const void *ptr) /* Find which container holds this memory */ struct mod_res_cb_arg cb_arg = {mod, ptr}; - k_mutex_lock(&res->lock, K_FOREVER); + k_mutex_lock(&mod_res_lock, K_FOREVER); int ret = objpool_iterate(&res->objpool, mod_res_free, &cb_arg); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); if (ret < 0) comp_err(mod->dev, "error: could not find memory pointed by %p", ptr); @@ -755,10 +762,10 @@ void z_impl_mod_free_all(struct processing_module *mod) /* Free all contents found in used containers */ struct mod_res_cb_arg cb_arg = {mod, NULL}; - k_mutex_lock(&res->lock, K_FOREVER); + k_mutex_lock(&mod_res_lock, K_FOREVER); objpool_iterate(&res->objpool, mod_res_free, &cb_arg); objpool_prune(&res->objpool); - k_mutex_unlock(&res->lock); + k_mutex_unlock(&mod_res_lock); /* Make sure resource lists and accounting are reset */ mod_resource_init(mod); diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 6976b9d485ee..70fb602d1aca 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -125,7 +125,6 @@ struct module_param { * when the module unloads. */ struct module_resources { - struct k_mutex lock; struct objpool_head objpool; size_t heap_usage; size_t heap_high_water_mark; From eb3c9bbd5a35fc2f2a778b9e298ae5c18c10c86a Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Wed, 12 Aug 2026 09:33:08 +0300 Subject: [PATCH 034/109] app: overlays: ptl: ll_userspace: disable DP scheduler Support to run DP scheduler when LL is running in user-space is not yet complete, so disable this feature in the overlay for now. Signed-off-by: Kai Vehmanen --- app/overlays/ptl/ll_userspace_overlay.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/app/overlays/ptl/ll_userspace_overlay.conf b/app/overlays/ptl/ll_userspace_overlay.conf index 8888a66f4c24..53b881320e6f 100644 --- a/app/overlays/ptl/ll_userspace_overlay.conf +++ b/app/overlays/ptl/ll_userspace_overlay.conf @@ -36,3 +36,4 @@ CONFIG_SOF_BOOT_TEST_ALLOWED=n CONFIG_CROSS_CORE_STREAM=n CONFIG_INTEL_ADSP_MIC_PRIVACY=n CONFIG_XRUN_NOTIFICATIONS_ENABLE=n +CONFIG_ZEPHYR_DP_SCHEDULER=n From 4b3fad352ccea9975b74b5b52c519caf1a3935be Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 13 Jul 2026 19:40:10 +0300 Subject: [PATCH 035/109] audio: chain_dma: port to sof_dma_* syscall wrappers Port chain DMA to SOF's sof_dma_* syscall wrappers (as host and dai already do) so its DMA operations can run unprivileged. Channel handles are stored as integer indices instead of kernel-only struct dma_chan_data pointers, matching the sof_dma_* API which takes indices. Both channel indices are initialised to -EINVAL so an incomplete initialisation is detected consistently for host and link. No functional change for existing (privileged) builds. Signed-off-by: Kai Vehmanen --- src/audio/chain_dma.c | 114 ++++++++++++++++++++++++++---------------- 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index e7207e636ee8..4a99690675e9 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -61,13 +61,13 @@ struct chain_dma_data { /* local host DMA config */ struct sof_dma *dma_host; - struct dma_chan_data *chan_host; + int chan_host_index; struct dma_config z_config_host; struct dma_block_config dma_block_cfg_host; /* local link DMA config */ struct sof_dma *dma_link; - struct dma_chan_data *chan_link; + int chan_link_index; struct dma_config z_config_link; struct dma_block_config dma_block_cfg_link; @@ -79,18 +79,18 @@ static int chain_host_start(struct comp_dev *dev) struct chain_dma_data *cd = comp_get_drvdata(dev); int err; - if (!cd->chan_host || !cd->chan_host->dma) { + if (cd->chan_host_index < 0 || !cd->dma_host) { comp_err(dev, "incomplete initialization detected, aborting host %p", - cd->chan_host); + cd->dma_host); return -ENODEV; } - err = dma_start(cd->chan_host->dma->z_dev, cd->chan_host->index); + err = sof_dma_start(cd->dma_host, cd->chan_host_index); if (err < 0) return err; - comp_info(dev, "dma_start() host chan_index = %u", - cd->chan_host->index); + comp_info(dev, "dma_start() host chan_index = %d", + cd->chan_host_index); return 0; } @@ -99,12 +99,18 @@ static int chain_link_start(struct comp_dev *dev) struct chain_dma_data *cd = comp_get_drvdata(dev); int err; - err = dma_start(cd->chan_link->dma->z_dev, cd->chan_link->index); + if (cd->chan_link_index < 0 || !cd->dma_link) { + comp_err(dev, "incomplete initialization detected, aborting link %p", + cd->dma_link); + return -ENODEV; + } + + err = sof_dma_start(cd->dma_link, cd->chan_link_index); if (err < 0) return err; - comp_info(dev, "dma_start() link chan_index = %u", - cd->chan_link->index); + comp_info(dev, "dma_start() link chan_index = %d", + cd->chan_link_index); return 0; } @@ -113,12 +119,18 @@ static int chain_link_stop(struct comp_dev *dev) struct chain_dma_data *cd = comp_get_drvdata(dev); int err; - err = dma_stop(cd->chan_link->dma->z_dev, cd->chan_link->index); + if (cd->chan_link_index < 0 || !cd->dma_link) { + comp_err(dev, "incomplete initialization detected, aborting link %p", + cd->dma_link); + return -ENODEV; + } + + err = sof_dma_stop(cd->dma_link, cd->chan_link_index); if (err < 0) return err; - comp_info(dev, "dma_stop() link chan_index = %u", - cd->chan_link->index); + comp_info(dev, "dma_stop() link chan_index = %d", + cd->chan_link_index); return 0; } @@ -128,12 +140,18 @@ static int chain_host_stop(struct comp_dev *dev) struct chain_dma_data *cd = comp_get_drvdata(dev); int err; - err = dma_stop(cd->chan_host->dma->z_dev, cd->chan_host->index); + if (cd->chan_host_index < 0 || !cd->dma_host) { + comp_err(dev, "incomplete initialization detected, aborting host %p", + cd->dma_host); + return -ENODEV; + } + + err = sof_dma_stop(cd->dma_host, cd->chan_host_index); if (err < 0) return err; - comp_info(dev, "dma_stop() host chan_index = %u", - cd->chan_host->index); + comp_info(dev, "dma_stop() host chan_index = %d", + cd->chan_host_index); return 0; } @@ -171,7 +189,7 @@ static enum task_state chain_task_run(void *data) /* Link DMA can return -EPIPE and current status if xrun occurs, then it is not critical * and flow shall continue. Other error values will be treated as critical. */ - ret = dma_get_status(cd->chan_link->dma->z_dev, cd->chan_link->index, &stat); + ret = sof_dma_get_status(cd->dma_link, cd->chan_link_index, &stat); switch (ret) { case 0: #if CONFIG_XRUN_NOTIFICATIONS_ENABLE @@ -195,7 +213,7 @@ static enum task_state chain_task_run(void *data) link_read_pos = stat.read_position; /* Host DMA does not report xruns. All error values will be treated as critical. */ - ret = dma_get_status(cd->chan_host->dma->z_dev, cd->chan_host->index, &stat); + ret = sof_dma_get_status(cd->dma_host, cd->chan_host_index, &stat); if (ret < 0) { tr_err(&chain_dma_tr, "dma_get_status() error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; @@ -213,14 +231,14 @@ static enum task_state chain_task_run(void *data) */ const size_t increment = MIN(host_free_bytes, link_avail_bytes); - ret = dma_reload(cd->chan_host->dma->z_dev, cd->chan_host->index, 0, 0, increment); + ret = sof_dma_reload(cd->dma_host, cd->chan_host_index, increment); if (ret < 0) { tr_err(&chain_dma_tr, "dma_reload() host error, ret = %d", ret); return SOF_TASK_STATE_COMPLETED; } - ret = dma_reload(cd->chan_link->dma->z_dev, cd->chan_link->index, 0, 0, increment); + ret = sof_dma_reload(cd->dma_link, cd->chan_link_index, increment); if (ret < 0) { tr_err(&chain_dma_tr, "dma_reload() link error, ret = %d", ret); @@ -236,9 +254,8 @@ static enum task_state chain_task_run(void *data) const size_t half_buff_size = buff_size / 2; if (!cd->first_data_received && host_avail_bytes > half_buff_size) { - ret = dma_reload(cd->chan_link->dma->z_dev, - cd->chan_link->index, 0, 0, - MIN(host_avail_bytes, link_free_bytes)); + ret = sof_dma_reload(cd->dma_link, cd->chan_link_index, + MIN(host_avail_bytes, link_free_bytes)); if (ret < 0) { tr_err(&chain_dma_tr, "dma_reload() link error, ret = %d", ret); @@ -252,8 +269,8 @@ static enum task_state chain_task_run(void *data) host_read_pos, buff_size); - ret = dma_reload(cd->chan_host->dma->z_dev, cd->chan_host->index, - 0, 0, transferred); + ret = sof_dma_reload(cd->dma_host, cd->chan_host_index, + transferred); if (ret < 0) { tr_err(&chain_dma_tr, "dma_reload() host error, ret = %d", ret); @@ -262,8 +279,8 @@ static enum task_state chain_task_run(void *data) if (host_avail_bytes >= half_buff_size && link_free_bytes >= half_buff_size) { - ret = dma_reload(cd->chan_link->dma->z_dev, cd->chan_link->index, - 0, 0, half_buff_size); + ret = sof_dma_reload(cd->dma_link, cd->chan_link_index, + half_buff_size); if (ret < 0) { tr_err(&chain_dma_tr, "dma_reload() link error, ret = %d", ret); @@ -373,10 +390,21 @@ __cold static void chain_release(struct comp_dev *dev) assert_can_be_cold(); - dma_release_channel(cd->chan_host->dma->z_dev, cd->chan_host->index); - sof_dma_put(cd->dma_host); - dma_release_channel(cd->chan_link->dma->z_dev, cd->chan_link->index); - sof_dma_put(cd->dma_link); + if (cd->dma_host) { + if (cd->chan_host_index >= 0) + sof_dma_release_channel(cd->dma_host, cd->chan_host_index); + sof_dma_put(cd->dma_host); + cd->dma_host = NULL; + cd->chan_host_index = -EINVAL; + } + + if (cd->dma_link) { + if (cd->chan_link_index >= 0) + sof_dma_release_channel(cd->dma_link, cd->chan_link_index); + sof_dma_put(cd->dma_link); + cd->dma_link = NULL; + cd->chan_link_index = -EINVAL; + } if (cd->dma_buffer) { buffer_free(cd->dma_buffer); @@ -463,16 +491,16 @@ __cold static int chain_init(struct comp_dev *dev, void *addr, size_t length) /* get host DMA channel */ channel = cd->host_connector_node_id.f.v_index; - channel = dma_request_channel(cd->dma_host->z_dev, &channel); + channel = sof_dma_request_channel(cd->dma_host, channel); if (channel < 0) { comp_err(dev, "host dma_request_channel() failed for %u", cd->host_connector_node_id.f.v_index); return channel; } - cd->chan_host = &cd->dma_host->chan[channel]; + cd->chan_host_index = channel; - err = dma_config(cd->dma_host->z_dev, cd->chan_host->index, dma_cfg_host); + err = sof_dma_config(cd->dma_host, cd->chan_host_index, dma_cfg_host); if (err < 0) { comp_err(dev, "host dma_config() failed for %d", channel); goto error_host; @@ -480,7 +508,7 @@ __cold static int chain_init(struct comp_dev *dev, void *addr, size_t length) /* get link DMA channel */ channel = cd->link_connector_node_id.f.v_index; - channel = dma_request_channel(cd->dma_link->z_dev, &channel); + channel = sof_dma_request_channel(cd->dma_link, channel); if (channel < 0) { comp_err(dev, "link dma_request_channel() failed for %u", cd->link_connector_node_id.f.v_index); @@ -488,9 +516,9 @@ __cold static int chain_init(struct comp_dev *dev, void *addr, size_t length) goto error_host; } - cd->chan_link = &cd->dma_link->chan[channel]; + cd->chan_link_index = channel; - err = dma_config(cd->dma_link->z_dev, cd->chan_link->index, dma_cfg_link); + err = sof_dma_config(cd->dma_link, cd->chan_link_index, dma_cfg_link); if (err < 0) { comp_err(dev, "link dma_config() failed for %d", channel); goto error_link; @@ -498,11 +526,9 @@ __cold static int chain_init(struct comp_dev *dev, void *addr, size_t length) return 0; error_link: - dma_release_channel(cd->dma_link->z_dev, cd->chan_link->index); - cd->chan_link = NULL; + sof_dma_release_channel(cd->dma_link, cd->chan_link_index); error_host: - dma_release_channel(cd->dma_host->z_dev, cd->chan_host->index); - cd->chan_host = NULL; + sof_dma_release_channel(cd->dma_host, cd->chan_host_index); return err; } @@ -559,8 +585,8 @@ __cold static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uin } /* retrieve DMA buffer address alignment */ - ret = dma_get_attribute(cd->dma_host->z_dev, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, - &addr_align); + ret = sof_dma_get_attribute(cd->dma_host, DMA_ATTR_BUFFER_ADDRESS_ALIGNMENT, + &addr_align); if (ret < 0) { comp_err(dev, "could not get dma buffer address alignment, err = %d", ret); @@ -660,6 +686,8 @@ __cold static struct comp_dev *chain_task_create(const struct comp_driver *drv, cd->first_data_received = false; cd->cs = scs ? 2 : 4; cd->chain_task.state = SOF_TASK_STATE_INIT; + cd->chan_host_index = -EINVAL; + cd->chan_link_index = -EINVAL; comp_set_drvdata(dev, cd); From 0c13329c6e7455ec48f6a7248bde19d19843f5b0 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 13 Jul 2026 19:44:09 +0300 Subject: [PATCH 036/109] audio: chain_dma: allocate comp_dev and private data from user heap When the LL pipeline runs in user-space (CONFIG_SOF_USERSPACE_LL) the component and its private data must reside on the user heap so the unprivileged user LL thread can access them. Introduce chain_dev_alloc()/ chain_cd_alloc() and their free counterparts to keep the config-specific allocation out of chain_task_create()/chain_task_free() instead of sprinkling #ifdefs through the control flow. The non-user-space path is unchanged (comp_alloc()/rzalloc()). Signed-off-by: Kai Vehmanen --- src/audio/chain_dma.c | 77 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index 4a99690675e9..ba2ffe7ee72e 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -657,6 +658,70 @@ static int chain_task_trigger(struct comp_dev *dev, int cmd) } } +/* + * comp_dev and private data allocation helpers. For user-space LL both + * objects must live on the user heap so the (unprivileged) user LL thread + * can access them; otherwise the normal component/rmalloc paths are used. + */ +#ifdef CONFIG_SOF_USERSPACE_LL +__cold static struct comp_dev *chain_dev_alloc(const struct comp_driver *drv) +{ + struct comp_dev *dev; + + dev = sof_heap_alloc(sof_sys_user_heap_get(), + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT, + sizeof(*dev), 0); + if (!dev) + return NULL; + + memset(dev, 0, sizeof(*dev)); + comp_init(drv, dev, sizeof(*dev)); + + return dev; +} + +__cold static struct chain_dma_data *chain_cd_alloc(void) +{ + struct chain_dma_data *cd; + + cd = sof_heap_alloc(sof_sys_user_heap_get(), SOF_MEM_FLAG_USER, sizeof(*cd), 0); + if (cd) + memset(cd, 0, sizeof(*cd)); + + return cd; +} + +__cold static void chain_dev_free(struct comp_dev *dev) +{ + sof_heap_free(sof_sys_user_heap_get(), dev); +} + +__cold static void chain_cd_free(struct chain_dma_data *cd) +{ + sof_heap_free(sof_sys_user_heap_get(), cd); +} +#else +__cold static struct comp_dev *chain_dev_alloc(const struct comp_driver *drv) +{ + return comp_alloc(drv, sizeof(struct comp_dev)); +} + +__cold static struct chain_dma_data *chain_cd_alloc(void) +{ + return rzalloc(SOF_MEM_FLAG_USER, sizeof(struct chain_dma_data)); +} + +__cold static void chain_dev_free(struct comp_dev *dev) +{ + comp_free_device(dev); +} + +__cold static void chain_cd_free(struct chain_dma_data *cd) +{ + rfree(cd); +} +#endif + __cold static struct comp_dev *chain_task_create(const struct comp_driver *drv, const struct comp_ipc_config *ipc_config, const void *ipc_specific_config) @@ -675,11 +740,11 @@ __cold static struct comp_dev *chain_task_create(const struct comp_driver *drv, if (host_dma_id >= max_chain_number) return NULL; - dev = comp_alloc(drv, sizeof(*dev)); + dev = chain_dev_alloc(drv); if (!dev) return NULL; - cd = rzalloc(SOF_MEM_FLAG_USER, sizeof(*cd)); + cd = chain_cd_alloc(); if (!cd) goto error; @@ -695,9 +760,9 @@ __cold static struct comp_dev *chain_task_create(const struct comp_driver *drv, if (!ret) return dev; - rfree(cd); + chain_cd_free(cd); error: - comp_free_device(dev); + chain_dev_free(dev); return NULL; } @@ -708,8 +773,8 @@ __cold static void chain_task_free(struct comp_dev *dev) assert_can_be_cold(); chain_release(dev); - rfree(cd); - comp_free_device(dev); + chain_cd_free(cd); + chain_dev_free(dev); } static const struct comp_driver comp_chain_dma = { From 9c64730b409ccf4c4bcb180334b1d406c1cf6b52 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 13 Jul 2026 19:45:58 +0300 Subject: [PATCH 037/109] audio: chain_dma: allocate DMA buffer from user LL heap context For CONFIG_SOF_USERSPACE_LL the DMA buffer must be allocated from the user LL heap so it is reachable by the unprivileged user LL thread that runs chain_task_run(). Pass the LL alloc context to buffer_alloc() instead of NULL; for non-user-space builds alloc_ctx stays NULL and the default heap is used as before. Signed-off-by: Kai Vehmanen --- src/audio/chain_dma.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index ba2ffe7ee72e..34106c57cc83 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -537,6 +538,7 @@ __cold static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uin uint32_t fifo_size) { struct chain_dma_data *cd = comp_get_drvdata(dev); + struct mod_alloc_ctx *alloc_ctx = NULL; uint32_t addr_align; size_t buff_size; void *buff_addr; @@ -615,8 +617,14 @@ __cold static int chain_task_init(struct comp_dev *dev, uint8_t host_dma_id, uin } fifo_size = ALIGN_UP_INTERNAL(fifo_size, addr_align); + +#ifdef CONFIG_SOF_USERSPACE_LL + alloc_ctx = ipc_get()->ll_alloc; +#endif + /* allocate not shared buffer */ - cd->dma_buffer = buffer_alloc(NULL, fifo_size, SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, + cd->dma_buffer = buffer_alloc(alloc_ctx, fifo_size, + SOF_MEM_FLAG_USER | SOF_MEM_FLAG_DMA, addr_align, BUFFER_USAGE_NOT_SHARED); if (!cd->dma_buffer) { From bceb0ecb5473b324b7c3095d1f9c3d435cd97724 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 26 Feb 2026 17:14:39 +0200 Subject: [PATCH 038/109] ipc: ipc4: use the SOF sof_dma_get_status() in dai_common_position() Use the sof_dma_get_status() wrapper to get DMA status in dai_common_position(). This allows the code to be used from user-space context. Signed-off-by: Kai Vehmanen --- src/ipc/ipc4/dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index 1540d95cf0f0..ee5821ad31c0 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -425,7 +425,7 @@ int dai_common_position(struct dai_data *dd, struct comp_dev *dev, platform_dai_wallclock(dev, &dd->wallclock); posn->wallclock = dd->wallclock; - ret = dma_get_status(dd->dma->z_dev, dd->chan_index, &status); + ret = sof_dma_get_status(dd->dma, dd->chan_index, &status); if (ret < 0) return ret; From cfd606d3062a0cf82bff91231dcbdeb3f28baf79 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 13 Aug 2026 11:22:44 +0300 Subject: [PATCH 039/109] ipc: ipc4: dai: do not set the direction bit for UAOL The link_config computed here is handed to the UAOL driver as the stream channel map and written to UAOLxPCMSyCM. On ACE 2.x and later that register only defines the lchan, hchan and strm fields, its two upper bits are reserved, and union hdalink_cfg keeps the direction in the topmost of them. Setting the direction therefore wrote a reserved bit for every capture stream, after which the link transferred no data at all and reported no error. Playback was unaffected because its direction is zero. The link does not need to be told the direction: transmit and receive streams have separate indices, so the stream already implies it. Fixes: ddd5c6442915 ("dai: uaol: add support for Intel UAOL") Signed-off-by: Peter Ujfalusi --- src/ipc/ipc4/dai.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/ipc4/dai.c b/src/ipc/ipc4/dai.c index ee5821ad31c0..c0ed1f52c3a1 100644 --- a/src/ipc/ipc4/dai.c +++ b/src/ipc/ipc4/dai.c @@ -66,7 +66,7 @@ void dai_set_link_hda_config(uint16_t *link_config, case SOF_DAI_INTEL_UAOL: link_cfg.full = 0; link_cfg.part.hchan = gtw_fmt->channels_count - 1; - link_cfg.part.dir = common_config->direction; + /* UAOLxPCMSyCM has no direction bit, the stream selects it */ link_cfg.part.stream = common_config->host_dma_config[0]->stream_id; break; default: From ec2305eaa9672c0bb605877d47daa8974bace554 Mon Sep 17 00:00:00 2001 From: Jun Lai Date: Thu, 4 Jun 2026 15:15:25 +0800 Subject: [PATCH 040/109] dax: update p_dax pointer state on mock version It is necessary cause p_dax is used in dax.c now. Signed-off-by: Jun Lai --- src/audio/module_adapter/module/dolby/dax_mock.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/audio/module_adapter/module/dolby/dax_mock.c b/src/audio/module_adapter/module/dolby/dax_mock.c index c8889699a7e8..92803cad0820 100644 --- a/src/audio/module_adapter/module/dolby/dax_mock.c +++ b/src/audio/module_adapter/module/dolby/dax_mock.c @@ -29,11 +29,13 @@ uint32_t dax_query_period_frames(struct sof_dax *dax_ctx) int dax_free(struct sof_dax *dax_ctx) { + dax_ctx->p_dax = NULL; return 0; } int dax_init(struct sof_dax *dax_ctx) { + dax_ctx->p_dax = dax_ctx->persist_buffer.addr; return 0; } @@ -81,7 +83,7 @@ int dax_set_ctc_enable(int32_t enable, struct sof_dax *dax_ctx) const char *dax_get_version(void) { - return ""; + return "mock_version"; } void *dax_find_params(uint32_t query_id, From b819d85066e4d481e087fda1e85f9c6ef6e78654 Mon Sep 17 00:00:00 2001 From: Jun Lai Date: Thu, 4 Jun 2026 15:18:33 +0800 Subject: [PATCH 041/109] dax: fix race condition on the tuning buffer While the tuning buffer is being updated, it may also be being used simultaneously in the process thread. Signed-off-by: Jun Lai --- src/audio/module_adapter/module/dolby/dax.c | 58 ++++++++++++++++----- src/audio/module_adapter/module/dolby/dax.h | 3 ++ 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/src/audio/module_adapter/module/dolby/dax.c b/src/audio/module_adapter/module/dolby/dax.c index 984bd2c11680..09f3cf1711c2 100644 --- a/src/audio/module_adapter/module/dolby/dax.c +++ b/src/audio/module_adapter/module/dolby/dax.c @@ -25,6 +25,7 @@ SOF_DEFINE_REG_UUID(dolby_dax_audio_processing); #define DAX_CP_MASK 0x8 #define DAX_VOLUME_MASK 0x10 #define DAX_CTC_MASK 0x20 +#define DAX_TUNING_FILE_MASK 0x40 #define DAX_PROCESSING_MASK 0x10000 #define DAX_RESET_MASK 0x20000 #define DAX_FREE_MASK 0x40000 @@ -241,24 +242,27 @@ static bool is_enabled(struct processing_module *mod) return dax_ctx->enable && dax_ctx->p_dax; } -static int set_tuning_file(struct processing_module *mod, void *value, uint32_t size) +static int set_tuning_file(struct processing_module *mod) { - int ret = 0; + int ret = -EINVAL; struct comp_dev *dev = mod->dev; struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct dax_buffer old_tuning_buf = {0}; + k_spinlock_key_t key; - if (dax_buffer_alloc(mod, &dax_ctx->tuning_file_buffer, size) != 0) { - comp_err(dev, "allocate %u bytes failed for tuning file", size); - ret = -ENOMEM; - } else { - memcpy_s(dax_ctx->tuning_file_buffer.addr, - dax_ctx->tuning_file_buffer.free, - value, - size); + key = k_spin_lock(&adapter_data->lock); + if (adapter_data->cache_tuning_buf.addr && adapter_data->cache_tuning_buf.size > 0) { + old_tuning_buf = dax_ctx->tuning_file_buffer; + dax_ctx->tuning_file_buffer = adapter_data->cache_tuning_buf; + adapter_data->cache_tuning_buf = (struct dax_buffer){0}; + ret = 0; } + k_spin_unlock(&adapter_data->lock, key); + + dax_buffer_release(mod, &old_tuning_buf); - comp_info(dev, "allocated: tuning %u, ret %d", dax_ctx->tuning_file_buffer.size, ret); + comp_info(dev, "apply tuning %p, ret %d", dax_ctx->tuning_file_buffer.addr, ret); return ret; } @@ -363,11 +367,33 @@ static int dax_set_param_wrapper(struct processing_module *mod, struct comp_dev *dev = mod->dev; struct dax_adapter_data *adapter_data = module_get_private_data(mod); struct sof_dax *dax_ctx = &adapter_data->dax_ctx; + struct dax_buffer new_tuning_buf = { 0 }; + struct dax_buffer old_tuning_buf = { 0 }; + k_spinlock_key_t key; int32_t tmp_val; switch (id) { case DAX_PARAM_ID_TUNING_FILE: - set_tuning_file(mod, value, size); + ret = dax_buffer_alloc(mod, &new_tuning_buf, size); + if (ret != 0) { + comp_err(dev, "allocate %u bytes failed for tuning file, ret %d", size, + ret); + break; + } + ret = memcpy_s(new_tuning_buf.addr, new_tuning_buf.free, value, size); + if (ret != 0) { + comp_err(dev, "copy tuning file failed, ret %d", ret); + dax_buffer_release(mod, &new_tuning_buf); + break; + } + key = k_spin_lock(&adapter_data->lock); + old_tuning_buf = adapter_data->cache_tuning_buf; + adapter_data->cache_tuning_buf = new_tuning_buf; + k_spin_unlock(&adapter_data->lock, key); + dax_buffer_release(mod, &old_tuning_buf); + flag_process(adapter_data, DAX_TUNING_FILE_MASK, DAX_FLAG_SET); + comp_info(dev, "allocated: tuning %p, size %u", new_tuning_buf.addr, + new_tuning_buf.size); break; case DAX_PARAM_ID_ENABLE: tmp_val = *((int32_t *)value); @@ -488,6 +514,12 @@ static void check_and_update_settings(struct processing_module *mod) if (!is_enabled(mod)) return; + if (flag_process(adapter_data, DAX_TUNING_FILE_MASK, DAX_FLAG_READ_AND_CLEAR)) { + set_tuning_file(mod); + flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_SET); + flag_process(adapter_data, DAX_VOLUME_MASK, DAX_FLAG_SET); + } + if (flag_process(adapter_data, DAX_DEVICE_MASK, DAX_FLAG_READ_AND_CLEAR)) { set_device(mod, dax_ctx->out_device); set_tuning_device(mod, dax_ctx->tuning_device); @@ -547,6 +579,7 @@ static int sof_dax_free(struct processing_module *mod) dax_buffer_release(mod, &dax_ctx->tuning_file_buffer); mod_data_blob_handler_free(mod, dax_ctx->blob_handler); dax_ctx->blob_handler = NULL; + dax_buffer_release(mod, &adapter_data->cache_tuning_buf); mod_free(mod, adapter_data); module_set_private_data(mod, NULL); } @@ -584,6 +617,7 @@ static int sof_dax_init(struct processing_module *mod) adapter_data = module_get_private_data(mod); adapter_data->comp_id = dev->ipc_config.id; adapter_data->priority = DAX_USER_PRIORITY_DEFAULT; + k_spinlock_init(&adapter_data->lock); dax_ctx = &adapter_data->dax_ctx; dax_ctx->enable = 0; dax_ctx->profile = 0; diff --git a/src/audio/module_adapter/module/dolby/dax.h b/src/audio/module_adapter/module/dolby/dax.h index da0419fa3766..43c900253dc6 100644 --- a/src/audio/module_adapter/module/dolby/dax.h +++ b/src/audio/module_adapter/module/dolby/dax.h @@ -7,6 +7,7 @@ * Author: Jun Lai */ +#include #include #include @@ -24,6 +25,8 @@ struct dax_adapter_data { atomic_t proc_flags; uint32_t comp_id; int32_t priority; + struct dax_buffer cache_tuning_buf; + struct k_spinlock lock; }; /** From 87dc5819a7ed825fb3383c6a1e474417d1ba802d Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Tue, 7 Jul 2026 10:51:08 +0800 Subject: [PATCH 042/109] topology2: sdw-dmic-generic: add multiple DMIC number support Add NUM_DMICS to set SDW DMIC number. The value is 2 by default. Signed-off-by: Bard Liao --- .../cavs/host-gateway-tdfb-drc-capture.conf | 43 ++++ .../platform/intel/sdw-dmic-generic.conf | 214 +++++++++++++++++- 2 files changed, 254 insertions(+), 3 deletions(-) diff --git a/tools/topology/topology2/include/pipelines/cavs/host-gateway-tdfb-drc-capture.conf b/tools/topology/topology2/include/pipelines/cavs/host-gateway-tdfb-drc-capture.conf index 752c421535c5..352ffb2389a3 100644 --- a/tools/topology/topology2/include/pipelines/cavs/host-gateway-tdfb-drc-capture.conf +++ b/tools/topology/topology2/include/pipelines/cavs/host-gateway-tdfb-drc-capture.conf @@ -19,6 +19,37 @@ +Define { + TDFB_DMIC_PCM_CHANNELS 2 +} + +IncludeByKey.TDFB_DMIC_PCM_CHANNELS { + "1" { + Define { + TDFB_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_MONO + TDFB_DMIC_CHANNEL_MAP $CHANNEL_MAP_MONO + } + } + "2" { + Define { + TDFB_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_STEREO + TDFB_DMIC_CHANNEL_MAP $CHANNEL_MAP_STEREO + } + } + "4" { + Define { + TDFB_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_3_POINT_1 + TDFB_DMIC_CHANNEL_MAP $CHANNEL_MAP_3_POINT_1 + } + } + "8" { + Define { + TDFB_SDW_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_7_POINT_1 + TDFB_SDW_DMIC_CHANNEL_MAP $CHANNEL_MAP_7_POINT_1 + } + } +} + Class.Pipeline."host-gateway-tdfb-drc-capture" { SubTreeCopy.baseclass { @@ -56,12 +87,18 @@ Class.Pipeline."host-gateway-tdfb-drc-capture" { { in_bit_depth 32 in_valid_bit_depth 32 + in_channels $TDFB_DMIC_PCM_CHANNELS + in_ch_cfg $TDFB_DMIC_CHANNEL_CFG + in_ch_map $TDFB_DMIC_CHANNEL_MAP } ] Object.Base.output_audio_format [ { out_bit_depth 32 out_valid_bit_depth 32 + out_channels $TDFB_DMIC_PCM_CHANNELS + out_ch_cfg $TDFB_DMIC_CHANNEL_CFG + out_ch_map $TDFB_DMIC_CHANNEL_MAP } ] } @@ -81,12 +118,18 @@ Class.Pipeline."host-gateway-tdfb-drc-capture" { { in_bit_depth 32 in_valid_bit_depth 32 + in_channels $TDFB_DMIC_PCM_CHANNELS + in_ch_cfg $TDFB_DMIC_CHANNEL_CFG + in_ch_map $TDFB_DMIC_CHANNEL_MAP } ] Object.Base.output_audio_format [ { out_bit_depth 32 out_valid_bit_depth 32 + out_channels $TDFB_DMIC_PCM_CHANNELS + out_ch_cfg $TDFB_DMIC_CHANNEL_CFG + out_ch_map $TDFB_DMIC_CHANNEL_MAP } ] } diff --git a/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf b/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf index 98c1cf7068d9..7a42ade4704f 100644 --- a/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf +++ b/tools/topology/topology2/platform/intel/sdw-dmic-generic.conf @@ -5,7 +5,37 @@ Define { SDW_DMIC_STREAM 'SDW3-Capture' SDW_DMIC_BE_ID 4 SDW_DMIC_PASSTHROUGH "false" - SDW_DMIC_HOST_PIPELINE_ID 40 + SDW_DMIC_HOST_PIPELINE_ID 40 + SDW_DMIC_PCM_CHANNELS 2 + SDW_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_STEREO + SDW_DMIC_CHANNEL_MAP $CHANNEL_MAP_STEREO +} + +IncludeByKey.SDW_DMIC_PCM_CHANNELS { + "1" { + Define { + SDW_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_MONO + SDW_DMIC_CHANNEL_MAP $CHANNEL_MAP_MONO + } + } + "2" { + Define { + SDW_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_STEREO + SDW_DMIC_CHANNEL_MAP $CHANNEL_MAP_STEREO + } + } + "4" { + Define { + SDW_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_3_POINT_1 + SDW_DMIC_CHANNEL_MAP $CHANNEL_MAP_3_POINT_1 + } + } + "8" { + Define { + SDW_DMIC_CHANNEL_CFG $CHANNEL_CONFIG_7_POINT_1 + SDW_DMIC_CHANNEL_MAP $CHANNEL_MAP_7_POINT_1 + } + } } Object.Dai.ALH [ @@ -16,7 +46,7 @@ Object.Dai.ALH [ name $SDW_DMIC_STREAM default_hw_conf_id 0 rate 48000 - channels 2 + channels $SDW_DMIC_PCM_CHANNELS Object.Base.hw_config.1 { id 0 @@ -38,46 +68,134 @@ IncludeByKey.SDW_DMIC_ENHANCED_CAPTURE { pcm_id 4 IncludeByKey.PCM_FORMAT_ALL { "true" { + num_input_audio_formats 5 num_output_audio_formats 5 + Object.Base.input_audio_format [ + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 24 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + in_sample_type $SAMPLE_TYPE_FLOAT + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 8 + in_valid_bit_depth 8 + in_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + ] Object.Base.output_audio_format [ { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 16 out_valid_bit_depth 16 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 24 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 32 out_sample_type $SAMPLE_TYPE_FLOAT + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 8 out_valid_bit_depth 8 out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } ] } "false" { + num_input_audio_formats 3 num_output_audio_formats 3 + Object.Base.input_audio_format [ + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 16 + in_valid_bit_depth 16 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 24 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + in_channels $SDW_DMIC_PCM_CHANNELS + in_bit_depth 32 + in_valid_bit_depth 32 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP + } + ] Object.Base.output_audio_format [ { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 16 out_valid_bit_depth 16 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 24 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } ] } @@ -122,6 +240,76 @@ IncludeByKey.SDW_DMIC_ENHANCED_CAPTURE { Object.Widget.host-copier.1 { stream_name "sdw dmic" pcm_id 4 + IncludeByKey.PCM_FORMAT_ALL { + "true" { + num_output_audio_formats 5 + Object.Base.output_audio_format [ + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + out_sample_type $SAMPLE_TYPE_FLOAT + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 8 + out_valid_bit_depth 8 + out_sample_type $SAMPLE_TYPE_UNSIGNED_INTEGER + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + ] + } + "false" { + num_output_audio_formats 3 + Object.Base.output_audio_format [ + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 16 + out_valid_bit_depth 16 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 24 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + { + out_channels $SDW_DMIC_PCM_CHANNELS + out_bit_depth 32 + out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP + } + ] + } + } } } ] @@ -142,19 +330,25 @@ Object.Widget { num_output_audio_formats 1 num_output_pins 1 - # 32-bit 48KHz 2ch + # 32-bit 48KHz capture, channel count derived from NUM_DMICS. Object.Base.input_audio_format [ { + in_channels $SDW_DMIC_PCM_CHANNELS in_bit_depth 32 in_valid_bit_depth $SDW_LINK_VALID_BITS in_sample_type $SAMPLE_TYPE_MSB_INTEGER + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP in_fmt_cfg "$[($in_channels | ($in_valid_bit_depth * 256))]" } ] Object.Base.output_audio_format [ { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } ] } @@ -175,14 +369,20 @@ Object.Widget { # index 41 is in herited from the pipeline definition Object.Base.input_audio_format [ { + in_channels $SDW_DMIC_PCM_CHANNELS in_bit_depth 32 in_valid_bit_depth 32 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP } ] Object.Base.output_audio_format [ { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } ] @@ -198,14 +398,20 @@ Object.Widget { num_output_audio_formats 1 Object.Base.input_audio_format [ { + in_channels $SDW_DMIC_PCM_CHANNELS in_bit_depth 32 in_valid_bit_depth 32 + in_ch_cfg $SDW_DMIC_CHANNEL_CFG + in_ch_map $SDW_DMIC_CHANNEL_MAP } ] Object.Base.output_audio_format [ { + out_channels $SDW_DMIC_PCM_CHANNELS out_bit_depth 32 out_valid_bit_depth 32 + out_ch_cfg $SDW_DMIC_CHANNEL_CFG + out_ch_map $SDW_DMIC_CHANNEL_MAP } ] } @@ -227,6 +433,8 @@ Object.PCM.pcm [ Object.PCM.pcm_caps.1 { name "sdw dmic" + channels_min $SDW_DMIC_PCM_CHANNELS + channels_max $SDW_DMIC_PCM_CHANNELS IncludeByKey.PCM_FORMAT_ALL { "true" { formats 'S16_LE,S24_LE,S32_LE,U8,FLOAT_LE' From 81ad08dd7784a0f12431c409d3ce8906459b8e34 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 20 Jul 2026 11:31:34 +0800 Subject: [PATCH 043/109] topology2: add sof-sdca-mic-4ch-id4 tplgs support Add 4 channel sdca mic function topologies support. Signed-off-by: Bard Liao --- .../topology2/production/tplg-targets-sdca-generic.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake index c7d5b5d8af1b..9331b165b03a 100644 --- a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake +++ b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake @@ -27,9 +27,14 @@ DEEP_BUF_SPK=true" SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,NUM_HDMIS=0,\ DEEP_BUF_SPK=true" +#default NUM_DMICS=2 "cavs-sdw\;sof-sdca-mic-id4\;SDW_JACK=false,SDW_DMIC=1,NUM_HDMIS=0,\ SDW_DMIC_STREAM=Capture-SmartMic" +"cavs-sdw\;sof-sdca-mic-4ch-id4\;SDW_JACK=false,SDW_DMIC=1,NUM_HDMIS=0,\ +SDW_DMIC_STREAM=Capture-SmartMic,SDW_DMIC_PCM_CHANNELS=4,TDFB_DMIC_PCM_CHANNELS=4,\ +EFX_MIC_TDFB_PARAMS=line4_pass" + "cavs-sdw\;sof-hdmi-pcm5-id2\;SDW_JACK=false,HDMI1_ID=2,HDMI2_ID=3,HDMI3_ID=4" "cavs-sdw\;sof-hdmi-pcm5-id3\;SDW_JACK=false,HDMI1_ID=3,HDMI2_ID=4,HDMI3_ID=5" "cavs-sdw\;sof-hdmi-pcm5-id4\;SDW_JACK=false,HDMI1_ID=4,HDMI2_ID=5,HDMI3_ID=6" From 58a8058d8f4b13e9f6aed55ca98b18deb979af84 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 10 Aug 2026 15:00:42 +0300 Subject: [PATCH 044/109] schedule: zephyr_ll: grant LL thread access to per-task semaphores In CONFIG_SOF_USERSPACE_LL builds the LL scheduler thread runs unprivileged, so every Zephyr kernel object it accesses must be explicitly granted to it. In commit ffa52dfc247e ("schedule: ll: dynamically allocate the semaphore"), task semaphores were converted to dynamically allocated objects. Only the bootstrap task's semaphore was granted to the LL thread (in zephyr_ll_init_context()); tasks created later (e.g. chain_dma) were not, so pausing/stopping such a task while it was running crashed the DSP. Fix the issue by grant the LL scheduling thread access to the task's semaphore at allocation time, from the syscall implementation which runs in privileged context. Add zephyr_domain_thread_tid_for_core() to look up the LL thread for an explicit core without relying on cpu_get_id(), and without dereferencing user-accessible task struct. Fixes: ffa52dfc247e ("schedule: ll: dynamically allocate the semaphore") Signed-off-by: Kai Vehmanen --- src/include/sof/schedule/ll_schedule_domain.h | 1 + src/schedule/zephyr_domain.c | 27 +++++++++++++++++++ src/schedule/zephyr_ll.c | 19 +++++++++++++ 3 files changed, 47 insertions(+) diff --git a/src/include/sof/schedule/ll_schedule_domain.h b/src/include/sof/schedule/ll_schedule_domain.h index b4b58e6923e2..03991debb0cb 100644 --- a/src/include/sof/schedule/ll_schedule_domain.h +++ b/src/include/sof/schedule/ll_schedule_domain.h @@ -328,6 +328,7 @@ struct ll_schedule_domain *zephyr_domain_init(int clk); #define timer_domain_init(timer, clk) zephyr_domain_init(clk) #ifdef CONFIG_SOF_USERSPACE_LL struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain); +struct k_thread *zephyr_domain_thread_tid_for_core(int core); struct k_mem_domain *zephyr_ll_mem_domain(void); #endif /* CONFIG_SOF_USERSPACE_LL */ #ifdef CONFIG_SOF_FULL_ZEPHYR_APPLICATION diff --git a/src/schedule/zephyr_domain.c b/src/schedule/zephyr_domain.c index 681b0c872f58..b37f91285854 100644 --- a/src/schedule/zephyr_domain.c +++ b/src/schedule/zephyr_domain.c @@ -289,6 +289,14 @@ static int zephyr_domain_unregister(struct ll_schedule_domain *domain, #else /* CONFIG_SOF_USERSPACE_LL */ +/* + * Kernel-owned per-core LL thread table. Populated from the privileged + * domain-thread init path and consulted by z_impl_zephyr_ll_task_sem_alloc() + * so that privileged code never has to traverse the user-accessible + * scheduler/domain objects to find the LL thread of a given core. + */ +static struct k_thread *ll_thread_tid[CONFIG_CORE_COUNT]; + /* * Privileged thread initialization for userspace LL scheduling. * Creates the scheduling thread, sets up timer, grants access to kernel @@ -343,6 +351,9 @@ static int zephyr_domain_thread_init(struct ll_schedule_domain *domain, INT_TO_POINTER(core), NULL, CONFIG_LL_THREAD_PRIORITY, K_USER, K_FOREVER); + /* record in the kernel-only table for syscall-context lookups */ + ll_thread_tid[core] = dt->ll_thread; + #ifdef CONFIG_SCHED_CPU_MASK k_thread_cpu_pin(thread, core); #endif @@ -477,6 +488,7 @@ static void zephyr_domain_thread_free(struct ll_schedule_domain *domain, k_thread_abort(dt->ll_thread); k_object_free(dt->ll_thread); dt->ll_thread = NULL; + ll_thread_tid[core] = NULL; } if (dt->sem) { @@ -498,6 +510,21 @@ struct k_thread *zephyr_domain_thread_tid(struct ll_schedule_domain *domain) return dt->ll_thread; } +/* + * Return the LL scheduling thread for an explicitly given core. + * + * Reads a kernel-only table keyed by core, so it is safe to call from a + * privileged syscall context without dereferencing any user-accessible + * scheduler or domain object, and without relying on cpu_get_id(). + */ +struct k_thread *zephyr_domain_thread_tid_for_core(int core) +{ + if (core < 0 || core >= CONFIG_CORE_COUNT) + return NULL; + + return ll_thread_tid[core]; +} + #endif /* CONFIG_SOF_USERSPACE_LL */ #if CONFIG_CROSS_CORE_STREAM diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index fd70a4fe31df..145416afad3e 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -474,6 +474,25 @@ int z_impl_zephyr_ll_task_sem_alloc(struct task *task) k_sem_init(ts->sem, 0, 1); +#if CONFIG_SOF_USERSPACE_LL + /* + * The per-task semaphore is signalled from zephyr_ll_task_done(), + * which runs in the (unprivileged) LL scheduler thread when a task is + * freed while it is still running. k_object_alloc() only grants access + * to the calling thread (the IPC handler that creates the task), so the + * LL thread must be granted access explicitly, otherwise its + * k_sem_give() traps with a userspace permission fault. + * + * Resolve the LL thread from kernel-only per-core state keyed by the + * task's target core; never traverse the user-accessible scheduler or + * domain objects from privileged context. + */ + struct k_thread *ll_tid = zephyr_domain_thread_tid_for_core(task->core); + + if (ll_tid) + k_thread_access_grant(ll_tid, ts->sem); +#endif + ts->task = task; pdata->sem_p = ts->sem; /* List is protected by IPC serialization */ From 29a321eff903207d63abb05afd5035147602d26c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 18 Aug 2026 12:45:21 +0200 Subject: [PATCH 045/109] idc: make struct idc_msg::payload a pointer to const The IDC layer only ever reads from msg->payload (it is memcpy'd into a per-core scratch buffer before the target core runs, and any actual output data is returned through a separately referenced coherent buffer, e.g. get_attribute_remote_payload::value). Nothing writes through this pointer, so mark it const void * to let senders pass read-only data without casting away const. Signed-off-by: Guennadi Liakhovetski --- posix/include/rtos/idc.h | 2 +- zephyr/include/rtos/idc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/posix/include/rtos/idc.h b/posix/include/rtos/idc.h index a9a03258712f..3f4c48bf0f51 100644 --- a/posix/include/rtos/idc.h +++ b/posix/include/rtos/idc.h @@ -160,7 +160,7 @@ struct idc_msg { uint32_t extension; /**< extension value */ uint32_t core; /**< core id */ uint32_t size; /**< payload size in bytes */ - void *payload; /**< pointer to payload data */ + const void *payload; /**< pointer to payload data */ }; /** \brief IDC data. */ diff --git a/zephyr/include/rtos/idc.h b/zephyr/include/rtos/idc.h index a8616d9e2a11..3e30250344e2 100644 --- a/zephyr/include/rtos/idc.h +++ b/zephyr/include/rtos/idc.h @@ -160,7 +160,7 @@ struct idc_msg { uint32_t extension; /**< extension value */ uint32_t core; /**< core id */ uint32_t size; /**< payload size in bytes */ - void *payload; /**< pointer to payload data */ + const void *payload; /**< pointer to payload data */ }; /** \brief IDC data. */ From d4af2888966e91958e5f3cadc07cb2c4699768b3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 18 Aug 2026 12:45:33 +0200 Subject: [PATCH 046/109] audio: constify bind/unbind data pointers Make struct bind_info::ipc4_data a pointer to const struct ipc4_module_bind_unbind, since bind/unbind handlers only ever read this IPC4 payload. This required propagating const through the second argument of struct module_interface::bind()/unbind(), struct comp_ops::bind()/unbind(), comp_bind()/comp_unbind() and all their implementations (copier, kpb, mixin/mixout, tone, tester, userspace_proxy, dai_zephyr_unbind, DP scheduler IPC plumbing). Signed-off-by: Guennadi Liakhovetski --- src/audio/copier/copier.c | 4 ++-- src/audio/copier/dai_copier.h | 5 +++-- src/audio/dai-zephyr.c | 6 +++--- src/audio/kpb.c | 8 ++++---- src/audio/mixin_mixout/mixin_mixout.c | 8 ++++---- src/audio/module_adapter/library/userspace_proxy.c | 4 ++-- src/audio/module_adapter/module/generic.c | 4 ++-- src/audio/module_adapter/module_adapter_ipc4.c | 6 +++--- src/audio/tone/tone-ipc4.c | 4 ++-- src/debug/tester/tester.c | 4 ++-- src/debug/tester/tester.h | 4 ++-- src/include/module/module/interface.h | 4 ++-- src/include/sof/audio/component.h | 6 +++--- src/include/sof/audio/component_ext.h | 8 ++++---- .../module_adapter/library/userspace_proxy_user.h | 2 +- .../sof/audio/module_adapter/module/generic.h | 12 ++++++------ src/include/sof/schedule/dp_schedule.h | 2 +- 17 files changed, 46 insertions(+), 45 deletions(-) diff --git a/src/audio/copier/copier.c b/src/audio/copier/copier.c index 018bcd81b870..2375b540b493 100644 --- a/src/audio/copier/copier.c +++ b/src/audio/copier/copier.c @@ -1229,7 +1229,7 @@ __cold static int copier_get_hw_params(struct comp_dev *dev, struct sof_ipc_stre return dai_common_get_hw_params(dd, dev, params, dir); } -__cold static int copier_bind(struct processing_module *mod, struct bind_info *bind_data) +__cold static int copier_bind(struct processing_module *mod, const struct bind_info *bind_data) { const struct ipc4_module_bind_unbind *const bu = bind_data->ipc4_data; const uint32_t src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); @@ -1258,7 +1258,7 @@ __cold static int copier_bind(struct processing_module *mod, struct bind_info *b return -ENODEV; } -__cold static int copier_unbind(struct processing_module *mod, struct bind_info *unbind_data) +__cold static int copier_unbind(struct processing_module *mod, const struct bind_info *unbind_data) { struct copier_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; diff --git a/src/audio/copier/dai_copier.h b/src/audio/copier/dai_copier.h index 481b06b4bc58..eb540efb86c4 100644 --- a/src/audio/copier/dai_copier.h +++ b/src/audio/copier/dai_copier.h @@ -61,7 +61,7 @@ static inline int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct co return 0; } -static inline int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, void *data) +static inline int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, const void *data) { return 0; } @@ -69,7 +69,8 @@ static inline int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, v int dai_zephyr_multi_endpoint_copy(struct dai_data **dd, struct comp_dev *dev, struct comp_buffer *multi_endpoint_buffer, int num_endpoints); -int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, struct bind_info *unbind_data); +int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, + const struct bind_info *unbind_data); #endif diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 3b9a73510658..1dbd4f5e133d 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -2045,10 +2045,10 @@ static uint64_t dai_get_processed_data(struct comp_dev *dev, uint32_t stream_no, } #ifdef CONFIG_IPC_MAJOR_4 -__cold -int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, struct bind_info *unbind_data) +__cold int dai_zephyr_unbind(struct dai_data *dd, struct comp_dev *dev, + const struct bind_info *unbind_data) { - struct ipc4_module_bind_unbind *bu; + const struct ipc4_module_bind_unbind *bu; int buf_id; assert_can_be_cold(); diff --git a/src/audio/kpb.c b/src/audio/kpb.c index 2cec91393517..d5434f5e6a87 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -338,10 +338,10 @@ static int kpb_get_attribute(struct comp_dev *dev, * \param[in] bind_data - bind/unbind data. * \return: none. */ -static int kpb_bind(struct comp_dev *dev, struct bind_info *bind_data) +static int kpb_bind(struct comp_dev *dev, const struct bind_info *bind_data) { struct comp_data *kpb = comp_get_drvdata(dev); - struct ipc4_module_bind_unbind *bu; + const struct ipc4_module_bind_unbind *bu; int buf_id; int ret = 0; @@ -385,10 +385,10 @@ static int kpb_bind(struct comp_dev *dev, struct bind_info *bind_data) * \param[in] data - ipc4 bind/unbind data. * \return: none. */ -static int kpb_unbind(struct comp_dev *dev, struct bind_info *unbind_data) +static int kpb_unbind(struct comp_dev *dev, const struct bind_info *unbind_data) { struct comp_data *kpb = comp_get_drvdata(dev); - struct ipc4_module_bind_unbind *bu; + const struct ipc4_module_bind_unbind *bu; int buf_id; comp_dbg(dev, "entry"); diff --git a/src/audio/mixin_mixout/mixin_mixout.c b/src/audio/mixin_mixout/mixin_mixout.c index 839f0eea8e17..78cea04daf19 100644 --- a/src/audio/mixin_mixout/mixin_mixout.c +++ b/src/audio/mixin_mixout/mixin_mixout.c @@ -806,9 +806,9 @@ static int mixout_prepare(struct processing_module *mod, return 0; } -static int mixout_bind(struct processing_module *mod, struct bind_info *bind_data) +static int mixout_bind(struct processing_module *mod, const struct bind_info *bind_data) { - struct ipc4_module_bind_unbind *bu; + const struct ipc4_module_bind_unbind *bu; struct comp_dev *mixin; struct pending_frames *pending_frames; int src_id; @@ -853,9 +853,9 @@ static int mixout_bind(struct processing_module *mod, struct bind_info *bind_dat return 0; } -static int mixout_unbind(struct processing_module *mod, struct bind_info *unbind_data) +static int mixout_unbind(struct processing_module *mod, const struct bind_info *unbind_data) { - struct ipc4_module_bind_unbind *bu; + const struct ipc4_module_bind_unbind *bu; struct comp_dev *mixin; struct pending_frames *pending_frames; int src_id; diff --git a/src/audio/module_adapter/library/userspace_proxy.c b/src/audio/module_adapter/library/userspace_proxy.c index e7159ce5b8b7..485bd7f157c3 100644 --- a/src/audio/module_adapter/library/userspace_proxy.c +++ b/src/audio/module_adapter/library/userspace_proxy.c @@ -849,7 +849,7 @@ static bool userspace_proxy_is_ready_to_process(struct processing_module *mod, * @param bind_data - pointer to bind_info structure. * @return 0 for success, error otherwise. */ -static int userspace_proxy_bind(struct processing_module *mod, struct bind_info *bind_data) +static int userspace_proxy_bind(struct processing_module *mod, const struct bind_info *bind_data) { struct module_params *params = user_work_get_params(mod->user_ctx); int ret; @@ -877,7 +877,7 @@ static int userspace_proxy_bind(struct processing_module *mod, struct bind_info * @param unbind_data - pointer to bind_info structure. * @return 0 for success, error otherwise. */ -static int userspace_proxy_unbind(struct processing_module *mod, struct bind_info *unbind_data) +static int userspace_proxy_unbind(struct processing_module *mod, const struct bind_info *unbind_data) { struct module_params *params = user_work_get_params(mod->user_ctx); int ret; diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 37071a2448e3..398717dc26fb 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -908,7 +908,7 @@ int module_set_configuration(struct processing_module *mod, } EXPORT_SYMBOL(module_set_configuration); -int module_bind(struct processing_module *mod, struct bind_info *bind_data) +int module_bind(struct processing_module *mod, const struct bind_info *bind_data) { int ret; const struct module_interface *const ops = mod->dev->drv->adapter_ops; @@ -941,7 +941,7 @@ int module_bind(struct processing_module *mod, struct bind_info *bind_data) return ret; } -int module_unbind(struct processing_module *mod, struct bind_info *unbind_data) +int module_unbind(struct processing_module *mod, const struct bind_info *unbind_data) { int ret; const struct module_interface *const ops = mod->dev->drv->adapter_ops; diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index 96e3bac4e9e2..da372fc477dc 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -376,7 +376,7 @@ static bool module_adapter_multi_sink_source_prepare(struct comp_dev *dev) } static int module_update_source_buffer_params(struct processing_module *mod, - struct bind_info *bind_data) + const struct bind_info *bind_data) { struct module_config *dst = &mod->priv.cfg; struct sof_ipc_stream_params params; @@ -407,7 +407,7 @@ static int module_update_source_buffer_params(struct processing_module *mod, return 0; } -int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) +int module_adapter_bind(struct comp_dev *dev, const struct bind_info *bind_data) { struct processing_module *mod = comp_mod(dev); int ret; @@ -425,7 +425,7 @@ int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) return 0; } -int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data) +int module_adapter_unbind(struct comp_dev *dev, const struct bind_info *unbind_data) { struct processing_module *mod = comp_mod(dev); int ret; diff --git a/src/audio/tone/tone-ipc4.c b/src/audio/tone/tone-ipc4.c index 30d99058a3d6..eaa2bffcdb48 100644 --- a/src/audio/tone/tone-ipc4.c +++ b/src/audio/tone/tone-ipc4.c @@ -169,7 +169,7 @@ static int tone_reset(struct processing_module *mod) return 0; } -static int tone_bind(struct processing_module *mod, struct bind_info *bind_data) +static int tone_bind(struct processing_module *mod, const struct bind_info *bind_data) { struct comp_data *cd = module_get_private_data(mod); @@ -183,7 +183,7 @@ static int tone_bind(struct processing_module *mod, struct bind_info *bind_data) return 0; } -static int tone_unbind(struct processing_module *mod, struct bind_info *unbind_data) +static int tone_unbind(struct processing_module *mod, const struct bind_info *unbind_data) { struct comp_data *cd = module_get_private_data(mod); diff --git a/src/debug/tester/tester.c b/src/debug/tester/tester.c index 161b90a7d3f3..5464b93bb281 100644 --- a/src/debug/tester/tester.c +++ b/src/debug/tester/tester.c @@ -186,7 +186,7 @@ static int tester_free(struct processing_module *mod) return ret; } -static int tester_bind(struct processing_module *mod, struct bind_info *bind_data) +static int tester_bind(struct processing_module *mod, const struct bind_info *bind_data) { struct tester_module_data *cd = module_get_private_data(mod); int ret = 0; @@ -197,7 +197,7 @@ static int tester_bind(struct processing_module *mod, struct bind_info *bind_dat return ret; } -static int tester_unbind(struct processing_module *mod, struct bind_info *unbind_data) +static int tester_unbind(struct processing_module *mod, const struct bind_info *unbind_data) { struct tester_module_data *cd = module_get_private_data(mod); int ret = 0; diff --git a/src/debug/tester/tester.h b/src/debug/tester/tester.h index 79a65b65a7b2..3fc4e9c49038 100644 --- a/src/debug/tester/tester.h +++ b/src/debug/tester/tester.h @@ -75,12 +75,12 @@ struct tester_test_case_interface { /** * copy of module bind method, with additional ctx param */ - int (*bind)(void *ctx, struct processing_module *mod, struct bind_info *bind_data); + int (*bind)(void *ctx, struct processing_module *mod, const struct bind_info *bind_data); /** * copy of module unbind method, with additional ctx param */ - int (*unbind)(void *ctx, struct processing_module *mod, struct bind_info *unbind_data); + int (*unbind)(void *ctx, struct processing_module *mod, const struct bind_info *unbind_data); /** * copy of module trigger method, with additional ctx param diff --git a/src/include/module/module/interface.h b/src/include/module/module/interface.h index a968ab862028..8e31117f9469 100644 --- a/src/include/module/module/interface.h +++ b/src/include/module/module/interface.h @@ -268,13 +268,13 @@ struct module_interface { * (optional) Module specific bind procedure, called when modules are bound with each other. * Usually can be __cold */ - int (*bind)(struct processing_module *mod, struct bind_info *bind_data); + int (*bind)(struct processing_module *mod, const struct bind_info *bind_data); /** * (optional) Module specific unbind procedure, called when modules are disconnected from * one another. Usually can be __cold */ - int (*unbind)(struct processing_module *mod, struct bind_info *unbind_data); + int (*unbind)(struct processing_module *mod, const struct bind_info *unbind_data); /** * (optional) Module specific trigger procedure, called when modules are triggered. Usually diff --git a/src/include/sof/audio/component.h b/src/include/sof/audio/component.h index bf5fce875038..672603e430c7 100644 --- a/src/include/sof/audio/component.h +++ b/src/include/sof/audio/component.h @@ -283,7 +283,7 @@ enum bind_type { struct bind_info { /* pointer to IPC4 bind/unbind data */ - struct ipc4_module_bind_unbind *ipc4_data; + const struct ipc4_module_bind_unbind *ipc4_data; /* type of binding * bind call will be called twice for every component, first when binding a data source, @@ -516,7 +516,7 @@ struct comp_ops { * * Usually can be __cold. */ - int (*bind)(struct comp_dev *dev, struct bind_info *bind_data); + int (*bind)(struct comp_dev *dev, const struct bind_info *bind_data); /** * Unbind, atomic - used to notify component of unbind event. @@ -525,7 +525,7 @@ struct comp_ops { * * Usually can be __cold. */ - int (*unbind)(struct comp_dev *dev, struct bind_info *unbind_data); + int (*unbind)(struct comp_dev *dev, const struct bind_info *unbind_data); /** * Gets config in component. diff --git a/src/include/sof/audio/component_ext.h b/src/include/sof/audio/component_ext.h index 229b43f0bddc..63cff9759425 100644 --- a/src/include/sof/audio/component_ext.h +++ b/src/include/sof/audio/component_ext.h @@ -438,7 +438,7 @@ static inline struct comp_driver_list *comp_drivers_get(void) #endif #if CONFIG_IPC_MAJOR_4 -static inline int comp_ipc4_bind_remote(struct comp_dev *dev, struct bind_info *bind_data) +static inline int comp_ipc4_bind_remote(struct comp_dev *dev, const struct bind_info *bind_data) { struct idc_msg msg = { IDC_MSG_BIND, IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, @@ -448,7 +448,7 @@ static inline int comp_ipc4_bind_remote(struct comp_dev *dev, struct bind_info * } #endif -static inline int comp_bind(struct comp_dev *dev, struct bind_info *bind_data) +static inline int comp_bind(struct comp_dev *dev, const struct bind_info *bind_data) { #if CONFIG_IPC_MAJOR_4 if (dev->drv->ops.bind) @@ -467,7 +467,7 @@ static inline int comp_bind(struct comp_dev *dev, struct bind_info *bind_data) } #if CONFIG_IPC_MAJOR_4 -static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, struct bind_info *unbind_data) +static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, const struct bind_info *unbind_data) { struct idc_msg msg = { IDC_MSG_UNBIND, IDC_EXTENSION(dev->ipc_config.id), dev->ipc_config.core, @@ -477,7 +477,7 @@ static inline int comp_ipc4_unbind_remote(struct comp_dev *dev, struct bind_info } #endif -static inline int comp_unbind(struct comp_dev *dev, struct bind_info *unbind_data) +static inline int comp_unbind(struct comp_dev *dev, const struct bind_info *unbind_data) { #if CONFIG_IPC_MAJOR_4 if (dev->drv->ops.unbind) diff --git a/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h index e571705cec17..6585db5eb533 100644 --- a/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h +++ b/src/include/sof/audio/module_adapter/library/userspace_proxy_user.h @@ -72,7 +72,7 @@ struct module_params { struct module_large_cfg_get_params get_conf; struct module_processing_mode_params proc_mode; struct module_process_params proc; - struct bind_info *bind_data; + const struct bind_info *bind_data; int trigger_data; } ext; }; diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index 70fb602d1aca..e7ba1eabefab 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -321,8 +321,8 @@ int module_set_configuration(struct processing_module *mod, enum module_cfg_fragment_position pos, size_t data_offset_size, const uint8_t *fragment, size_t fragment_size, uint8_t *response, size_t response_size); -int module_bind(struct processing_module *mod, struct bind_info *bind_data); -int module_unbind(struct processing_module *mod, struct bind_info *unbind_data); +int module_bind(struct processing_module *mod, const struct bind_info *bind_data); +int module_unbind(struct processing_module *mod, const struct bind_info *unbind_data); struct comp_dev *module_adapter_new(const struct comp_driver *drv, const struct comp_ipc_config *config, const void *spec); @@ -369,13 +369,13 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ } static inline -int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data) +int module_adapter_bind(struct comp_dev *dev, const struct bind_info *bind_data) { return 0; } static inline -int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data) +int module_adapter_unbind(struct comp_dev *dev, const struct bind_info *unbind_data) { return 0; } @@ -404,8 +404,8 @@ int module_get_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ bool last_block, uint32_t *data_offset, char *data); int module_adapter_get_attribute(struct comp_dev *dev, uint32_t type, void *value); int module_adapter_set_attribute(struct comp_dev *dev, uint32_t type, void *value); -int module_adapter_bind(struct comp_dev *dev, struct bind_info *bind_data); -int module_adapter_unbind(struct comp_dev *dev, struct bind_info *unbind_data); +int module_adapter_bind(struct comp_dev *dev, const struct bind_info *bind_data); +int module_adapter_unbind(struct comp_dev *dev, const struct bind_info *unbind_data); uint64_t module_adapter_get_total_data_processed(struct comp_dev *dev, uint32_t stream_no, bool input); diff --git a/src/include/sof/schedule/dp_schedule.h b/src/include/sof/schedule/dp_schedule.h index d4225d741930..1b55405d0fb1 100644 --- a/src/include/sof/schedule/dp_schedule.h +++ b/src/include/sof/schedule/dp_schedule.h @@ -109,7 +109,7 @@ struct sof_sink; * that would add multiple functions to the API. */ union scheduler_dp_thread_ipc_param { - struct bind_info *bind_data; + const struct bind_info *bind_data; struct { unsigned int trigger_cmd; enum ipc4_pipeline_state state; From 2be08cc10926e8a738fd7da3497d3444ce6cf40c Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 18 Aug 2026 11:54:52 +0200 Subject: [PATCH 047/109] ipc: ipc4: rename ipc_comp_(dis)connect() Currently both IPC3 and IPC4 use ipc_comp_connect() and ipc_comp_disconnect() even though their second parameter has different types. This makes no sense since both implementations and calling sites are different. Rename IPC4 versions to drop type-casts. Signed-off-by: Guennadi Liakhovetski --- src/include/ipc4/handler.h | 16 ++++++++++++++++ src/include/sof/ipc/topology.h | 2 +- src/ipc/ipc4/handler-user.c | 10 ++++------ src/ipc/ipc4/helper.c | 9 +++------ 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/include/ipc4/handler.h b/src/include/ipc4/handler.h index 0ed298dd9ad1..d6f839458d54 100644 --- a/src/include/ipc4/handler.h +++ b/src/include/ipc4/handler.h @@ -68,6 +68,22 @@ int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4); */ void ipc_compound_msg_done(uint32_t msg_id, int error); +/** + * \brief Connect components together on a pipeline. + * @param ipc The global IPC context. + * @param bu IPC4 bind-unbind data. + * @return IPC4_SUCCESS on success, error code otherwise. + */ +int ipc4_comp_connect(struct ipc *ipc, const struct ipc4_module_bind_unbind *bu); + +/** + * \brief Disconnect components in a pipeline. + * @param ipc The global IPC context. + * @param bu IPC4 bind-unbind data. + * @return IPC4_SUCCESS on success, error code otherwise. + */ +int ipc4_comp_disconnect(struct ipc *ipc, const struct ipc4_module_bind_unbind *bu); + #if defined(__ZEPHYR__) && defined(CONFIG_SOF_FULL_ZEPHYR_APPLICATION) /** * \brief Increment the IPC compound message pre-start counter. diff --git a/src/include/sof/ipc/topology.h b/src/include/sof/ipc/topology.h index ceabc7006203..422563185a90 100644 --- a/src/include/sof/ipc/topology.h +++ b/src/include/sof/ipc/topology.h @@ -165,7 +165,7 @@ int ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id); /** * \brief Connect components together on a pipeline. * @param ipc The global IPC context. - * @param connect Components to connect together.. + * @param connect Components to connect together. * @return 0 on success or negative error. */ int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *connect); diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 7a70e8c6ded5..5888b007ed42 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -812,7 +812,7 @@ __cold static int ipc4_bind_module_instance(struct ipc4_message_request *ipc4) (uint32_t)bu->primary.r.module_id, (uint32_t)bu->primary.r.instance_id, (uint32_t)bu->extension.r.dst_module_id, (uint32_t)bu->extension.r.dst_instance_id); - return ipc_comp_connect(ipc, (ipc_pipe_comp_connect *)bu); + return ipc4_comp_connect(ipc, bu); } __cold static int ipc4_unbind_module_instance(struct ipc4_message_request *ipc4) @@ -826,7 +826,7 @@ __cold static int ipc4_unbind_module_instance(struct ipc4_message_request *ipc4) (uint32_t)bu->primary.r.module_id, (uint32_t)bu->primary.r.instance_id, (uint32_t)bu->extension.r.dst_module_id, (uint32_t)bu->extension.r.dst_instance_id); - return ipc_comp_disconnect(ipc, (ipc_pipe_comp_connect *)bu); + return ipc4_comp_disconnect(ipc, bu); } #endif /* !CONFIG_SOF_USERSPACE_LL */ @@ -1707,8 +1707,7 @@ int ipc_user_thread_dispatch(struct ipc_user *ipc_user) if (result < 0) break; - result = ipc_comp_connect(ipc_user->ipc, - (ipc_pipe_comp_connect *)&bu); + result = ipc4_comp_connect(ipc_user->ipc, &bu); break; } case SOF_IPC4_MOD_UNBIND: { @@ -1718,8 +1717,7 @@ int ipc_user_thread_dispatch(struct ipc_user *ipc_user) if (result < 0) break; - result = ipc_comp_disconnect(ipc_user->ipc, - (ipc_pipe_comp_connect *)&bu); + result = ipc4_comp_disconnect(ipc_user->ipc, &bu); break; } case SOF_IPC4_MOD_INIT_INSTANCE: { diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index fb7353c1e1a8..f1e112fb37ea 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -772,9 +773,8 @@ static int ll_wait_finished_on_core(struct comp_dev *dev) #endif /* Only called from ipc4_bind_module_instance(), which is __cold */ -__cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) +__cold int ipc4_comp_connect(struct ipc *ipc, const struct ipc4_module_bind_unbind *bu) { - struct ipc4_module_bind_unbind *bu; struct bind_info bind_data; struct comp_buffer *buffer; struct comp_dev *source; @@ -790,7 +790,6 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) assert_can_be_cold(); - bu = (struct ipc4_module_bind_unbind *)_connect; src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); sink_id = IPC4_COMP_ID(bu->extension.r.dst_module_id, bu->extension.r.dst_instance_id); source = ipc4_get_comp_dev(src_id); @@ -1041,9 +1040,8 @@ __cold int ipc_comp_connect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) * pipeline and create it in modified form. */ /* Only called from ipc4_unbind_module_instance(), which is __cold */ -__cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) +__cold int ipc4_comp_disconnect(struct ipc *ipc, const struct ipc4_module_bind_unbind *bu) { - struct ipc4_module_bind_unbind *bu; struct comp_buffer *buffer = NULL; struct comp_buffer *buf; struct comp_dev *src, *sink; @@ -1055,7 +1053,6 @@ __cold int ipc_comp_disconnect(struct ipc *ipc, ipc_pipe_comp_connect *_connect) assert_can_be_cold(); - bu = (struct ipc4_module_bind_unbind *)_connect; src_id = IPC4_COMP_ID(bu->primary.r.module_id, bu->primary.r.instance_id); sink_id = IPC4_COMP_ID(bu->extension.r.dst_module_id, bu->extension.r.dst_instance_id); src = ipc4_get_comp_dev(src_id); From 67707f5815a916164474e4db3c7a0b398315cbfe Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 17 Aug 2026 15:10:50 +0300 Subject: [PATCH 048/109] module: generic: remove unnecessary EXPORT_SYMBOL Remove export for mod_free_all(). It is not needed and unnecessary exports have a cost when modules are loaded. Fixes: a0939f4bc2e6 ("module: generic: use a single static lock for module resources") Signed-off-by: Kai Vehmanen --- src/audio/module_adapter/module/generic.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 398717dc26fb..3e46bdac73fd 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -770,7 +770,6 @@ void z_impl_mod_free_all(struct processing_module *mod) /* Make sure resource lists and accounting are reset */ mod_resource_init(mod); } -EXPORT_SYMBOL(z_impl_mod_free_all); int module_free(struct processing_module *mod) { From 5aeec5a2ec2c90aa62185b80c1db9af477e2d373 Mon Sep 17 00:00:00 2001 From: eholzbach Date: Sat, 8 Aug 2026 18:07:30 -0400 Subject: [PATCH 049/109] tools: include sys/types.h to build probes tool on musl sys/types.h is automatically included with glibc, not musl Signed-off-by: eholzbach --- tools/probes/probes_demux.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/probes/probes_demux.c b/tools/probes/probes_demux.c index b92aaf88a19b..7b875cf9bb8a 100644 --- a/tools/probes/probes_demux.c +++ b/tools/probes/probes_demux.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include From f06c0892c073139ee9047752b4d4042c9afe51ae Mon Sep 17 00:00:00 2001 From: eholzbach Date: Sat, 8 Aug 2026 18:10:35 -0400 Subject: [PATCH 050/109] tools: fix int/long mismatch on 32bit builds of ctl.c Signed-off-by: eholzbach --- tools/ctl/ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ctl/ctl.c b/tools/ctl/ctl.c index f21c9b0b3ed3..a1966473025a 100644 --- a/tools/ctl/ctl.c +++ b/tools/ctl/ctl.c @@ -507,7 +507,7 @@ static int ctl_set_get(struct ctl_data *ctl_data) ref_size = ctl_data->buffer[BUFFER_SIZE_OFFSET] + BUFFER_TLV_HEADER_BYTES; if (read_size != ref_size) { fprintf(stderr, - "Error: Blob TLV header size %u (plus %lu) does not match with read bytes count %zu.\n", + "Error: Blob TLV header size %u (plus %zu) does not match with read bytes count %zu.\n", ctl_data->buffer[BUFFER_SIZE_OFFSET], BUFFER_TLV_HEADER_BYTES, read_size); return -EINVAL; From b717e072875e36b7ba0962d3e94fefb0d07674cf Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Tue, 7 Jul 2026 11:11:57 +0200 Subject: [PATCH 051/109] test(cmocka, dcblock): add unit tests for DC blocking filter Signed-off-by: Piotr Hoppe --- src/arch/xtensa/configs/unit_test_defconfig | 1 + test/cmocka/src/audio/CMakeLists.txt | 3 + test/cmocka/src/audio/dcblock/CMakeLists.txt | 57 ++ .../src/audio/dcblock/dcblock_math_test.c | 327 ++++++++++ .../src/audio/dcblock/dcblock_process.c | 565 ++++++++++++++++++ 5 files changed, 953 insertions(+) create mode 100644 test/cmocka/src/audio/dcblock/CMakeLists.txt create mode 100644 test/cmocka/src/audio/dcblock/dcblock_math_test.c create mode 100644 test/cmocka/src/audio/dcblock/dcblock_process.c diff --git a/src/arch/xtensa/configs/unit_test_defconfig b/src/arch/xtensa/configs/unit_test_defconfig index afe031acedba..f7703eb7f26c 100644 --- a/src/arch/xtensa/configs/unit_test_defconfig +++ b/src/arch/xtensa/configs/unit_test_defconfig @@ -1,2 +1,3 @@ CONFIG_METEORLAKE=y CONFIG_COMP_DRC=y +CONFIG_COMP_DCBLOCK=y diff --git a/test/cmocka/src/audio/CMakeLists.txt b/test/cmocka/src/audio/CMakeLists.txt index d199fd18a0ea..a5b300b6f232 100644 --- a/test/cmocka/src/audio/CMakeLists.txt +++ b/test/cmocka/src/audio/CMakeLists.txt @@ -25,3 +25,6 @@ endif() if(CONFIG_COMP_DRC) add_subdirectory(drc) endif() +if(CONFIG_COMP_DCBLOCK) + add_subdirectory(dcblock) +endif() diff --git a/test/cmocka/src/audio/dcblock/CMakeLists.txt b/test/cmocka/src/audio/dcblock/CMakeLists.txt new file mode 100644 index 000000000000..494d59217f7d --- /dev/null +++ b/test/cmocka/src/audio/dcblock/CMakeLists.txt @@ -0,0 +1,57 @@ +# SPDX-License-Identifier: BSD-3-Clause + +cmocka_test(dcblock_math_test + dcblock_math_test.c + ${PROJECT_SOURCE_DIR}/src/audio/dcblock/dcblock_generic.c + ${PROJECT_SOURCE_DIR}/src/math/numbers.c +) + +target_include_directories(dcblock_math_test PRIVATE ${PROJECT_SOURCE_DIR}/src/audio) +target_include_directories(dcblock_math_test PRIVATE ${PROJECT_SOURCE_DIR}/src/audio/dcblock) + +cmocka_test(dcblock_process + dcblock_process.c +) + +target_include_directories(dcblock_process PRIVATE ${PROJECT_SOURCE_DIR}/src/audio) +target_include_directories(dcblock_process PRIVATE ${PROJECT_SOURCE_DIR}/src/audio/dcblock) + +# make small version of libaudio so we don't have to care +# about unused missing references + +add_compile_options(-DUNIT_TEST) + +add_library(audio_for_dcblock STATIC + ${PROJECT_SOURCE_DIR}/src/audio/dcblock/dcblock.c + ${PROJECT_SOURCE_DIR}/src/audio/dcblock/dcblock_generic.c + ${PROJECT_SOURCE_DIR}/src/audio/dcblock/dcblock_ipc3.c + ${PROJECT_SOURCE_DIR}/src/math/numbers.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module_adapter_ipc3.c + ${PROJECT_SOURCE_DIR}/src/audio/module_adapter/module/generic.c + ${PROJECT_SOURCE_DIR}/src/audio/buffers/comp_buffer.c + ${PROJECT_SOURCE_DIR}/src/audio/buffers/audio_buffer.c + ${PROJECT_SOURCE_DIR}/src/audio/source_api_helper.c + ${PROJECT_SOURCE_DIR}/src/audio/sink_api_helper.c + ${PROJECT_SOURCE_DIR}/src/audio/sink_source_utils.c + ${PROJECT_SOURCE_DIR}/src/audio/audio_stream.c + ${PROJECT_SOURCE_DIR}/src/audio/component.c + ${PROJECT_SOURCE_DIR}/src/audio/data_blob.c + ${PROJECT_SOURCE_DIR}/src/module/audio/source_api.c + ${PROJECT_SOURCE_DIR}/src/module/audio/sink_api.c + ${PROJECT_SOURCE_DIR}/src/ipc/ipc3/helper.c + ${PROJECT_SOURCE_DIR}/src/ipc/ipc-common.c + ${PROJECT_SOURCE_DIR}/src/ipc/ipc-helper.c + ${PROJECT_SOURCE_DIR}/src/lib/objpool.c + ${PROJECT_SOURCE_DIR}/test/cmocka/src/notifier_mocks.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-graph.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-params.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-schedule.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-stream.c + ${PROJECT_SOURCE_DIR}/src/audio/pipeline/pipeline-xrun.c +) +sof_append_relative_path_definitions(audio_for_dcblock) + +target_link_libraries(audio_for_dcblock PRIVATE sof_options) + +target_link_libraries(dcblock_process PRIVATE audio_for_dcblock) diff --git a/test/cmocka/src/audio/dcblock/dcblock_math_test.c b/test/cmocka/src/audio/dcblock/dcblock_math_test.c new file mode 100644 index 000000000000..a94912192f81 --- /dev/null +++ b/test/cmocka/src/audio/dcblock/dcblock_math_test.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "dcblock.h" + +#define TEST_CHANNELS 2 +#define TEST_FRAMES 256 + +/* Q2.30 coefficient close to 1.0 used for the DC removal test cases. */ +#define R_COEF_NEAR_ONE 1063004406 /* ~0.99 in Q2.30 */ + +/* + * Reference DC blocking filter implemented in floating point. Mirrors the + * fixed point recurrence y[n] = x[n] - x[n-1] + R * y[n-1] where R is the + * Q2.30 coefficient converted to a real number. + */ +struct ref_state { + double x_prev; + double y_prev; +}; + +static double dcblock_ref(struct ref_state *s, double r, double x) +{ + double y = x - s->x_prev + r * s->y_prev; + + s->x_prev = x; + s->y_prev = y; + return y; +} + +/* Build an audio_stream over a linear (non wrapping) sample buffer. */ +static void setup_stream(struct audio_stream *stream, void *data, + size_t bytes, enum sof_ipc_frame fmt, int channels) +{ + memset(stream, 0, sizeof(*stream)); + stream->addr = data; + stream->end_addr = (char *)data + bytes; + stream->r_ptr = data; + stream->w_ptr = data; + stream->size = bytes; + stream->runtime_stream_params.frame_fmt = fmt; + stream->runtime_stream_params.channels = channels; +} + +/* Fill the source buffer with a per-channel sinusoid plus a DC offset. */ +static void gen_input(double *ref_in, int channels, int frames, double dc) +{ + int ch, i; + + for (i = 0; i < frames; i++) { + for (ch = 0; ch < channels; ch++) { + double phase = 2.0 * M_PI * (i + 1) * (ch + 1) / 64.0; + + ref_in[i * channels + ch] = dc + 0.3 * sin(phase); + } + } +} + +/* + * Runs the S32 processing function and compares it to the floating point + * reference. Returns the mean absolute value of the last quarter of the + * output which is used to check DC convergence. + */ +static double run_s32_case(int32_t r_coeff, double dc, double tol_rel) +{ + struct comp_data cd; + struct audio_stream source, sink; + int32_t src[TEST_FRAMES * TEST_CHANNELS]; + int32_t dst[TEST_FRAMES * TEST_CHANNELS]; + double ref_in[TEST_FRAMES * TEST_CHANNELS]; + struct ref_state rstate[TEST_CHANNELS]; + double r = (double)r_coeff / (double)ONE_Q2_30; + double tail_abs_sum = 0.0; + int tail_count = 0; + dcblock_func func; + int ch, i; + + memset(&cd, 0, sizeof(cd)); + for (ch = 0; ch < TEST_CHANNELS; ch++) + cd.R_coeffs[ch] = r_coeff; + + memset(rstate, 0, sizeof(rstate)); + gen_input(ref_in, TEST_CHANNELS, TEST_FRAMES, dc); + + for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) + src[i] = (int32_t)round(ref_in[i] * 2147483647.0); + + setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); + setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); + + func = dcblock_find_func(SOF_IPC_FRAME_S32_LE); + assert_non_null(func); + assert_int_equal(func(&cd, &csrc, &csnk, TEST_FRAMES), 0); + + for (i = 0; i < TEST_FRAMES; i++) { + for (ch = 0; ch < TEST_CHANNELS; ch++) { + int idx = i * TEST_CHANNELS + ch; + double refy = dcblock_ref(&rstate[ch], r, + (double)src[idx] / 2147483648.0); + double outy = (double)dst[idx] / 2147483648.0; + double delta = fabs(refy - outy); + + if (delta > tol_rel) { + printf("s32 mismatch idx %d ref %g out %g delta %g\n", + idx, refy, outy, delta); + assert_true(delta <= tol_rel); + } + + if (i >= TEST_FRAMES * 3 / 4) { + tail_abs_sum += fabs(outy); + tail_count++; + } + } + } + + return tail_count ? tail_abs_sum / tail_count : 0.0; +} + +/* Passthrough: R = 1.0 gives y[n] = x[n] - x[n-1], a pure differentiator. */ +static void test_dcblock_passthrough(void **state) +{ + (void)state; + + /* With no DC and R=1.0 the reference matches bit-close. */ + run_s32_case(ONE_Q2_30, 0.0, 1.0e-6); +} + +/* A strong DC offset must be attenuated towards zero in steady state. */ +static void test_dcblock_dc_removal(void **state) +{ + (void)state; + + double tail = run_s32_case(R_COEF_NEAR_ONE, 0.5, 1.0e-6); + + /* The residual DC plus small sinusoid must be well below the input DC. */ + printf("dc_removal tail mean abs = %g\n", tail); + assert_true(tail < 0.25); +} + +/* Full scale input must not overflow (saturation path in dcblock_generic). */ +static void test_dcblock_saturation(void **state) +{ + (void)state; + + struct comp_data cd; + struct audio_stream source, sink; + int32_t src[TEST_FRAMES * TEST_CHANNELS]; + int32_t dst[TEST_FRAMES * TEST_CHANNELS]; + dcblock_func func; + int i; + + memset(&cd, 0, sizeof(cd)); + for (i = 0; i < TEST_CHANNELS; i++) + cd.R_coeffs[i] = ONE_Q2_30; + + /* Alternating +full/-full scale is the worst case for the difference. */ + for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) + src[i] = (i & 1) ? INT32_MAX : INT32_MIN; + + setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); + setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); + + func = dcblock_find_func(SOF_IPC_FRAME_S32_LE); + assert_non_null(func); + assert_int_equal(func(&cd, &csrc, &csnk, TEST_FRAMES), 0); + + for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) { + assert_true(dst[i] <= INT32_MAX); + assert_true(dst[i] >= INT32_MIN); + } +} + +/* Bit-exactness check against the floating point reference for S32. */ +static void test_dcblock_bitexact_s32(void **state) +{ + (void)state; + + run_s32_case(R_COEF_NEAR_ONE, 0.1, 1.0e-6); +} + +/* + * Runs the S16 processing function and compares it to the floating point + * reference. The component internally works in Q1.31, so the tolerance must + * account for the 16-bit output quantization step (2 LSB of S16). + */ +static void run_s16_case(int32_t r_coeff, double dc) +{ + struct comp_data cd; + struct audio_stream source, sink; + int16_t src[TEST_FRAMES * TEST_CHANNELS]; + int16_t dst[TEST_FRAMES * TEST_CHANNELS]; + double ref_in[TEST_FRAMES * TEST_CHANNELS]; + struct ref_state rstate[TEST_CHANNELS]; + double r = (double)r_coeff / (double)ONE_Q2_30; + double tol = 2.0 / 32768.0; + dcblock_func func; + int ch, i; + + memset(&cd, 0, sizeof(cd)); + for (ch = 0; ch < TEST_CHANNELS; ch++) + cd.R_coeffs[ch] = r_coeff; + + memset(rstate, 0, sizeof(rstate)); + gen_input(ref_in, TEST_CHANNELS, TEST_FRAMES, dc); + + for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) + src[i] = (int16_t)round(ref_in[i] * 32767.0); + + setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S16_LE, TEST_CHANNELS); + setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S16_LE, TEST_CHANNELS); + + func = dcblock_find_func(SOF_IPC_FRAME_S16_LE); + assert_non_null(func); + assert_int_equal(func(&cd, &csrc, &csnk, TEST_FRAMES), 0); + + for (i = 0; i < TEST_FRAMES; i++) { + for (ch = 0; ch < TEST_CHANNELS; ch++) { + int idx = i * TEST_CHANNELS + ch; + double refy = dcblock_ref(&rstate[ch], r, + (double)src[idx] / 32768.0); + double outy = (double)dst[idx] / 32768.0; + double delta = fabs(refy - outy); + + if (delta > tol) { + printf("s16 mismatch idx %d ref %g out %g delta %g\n", + idx, refy, outy, delta); + assert_true(delta <= tol); + } + } + } +} + +/* Bit-exactness check against the floating point reference for S16. */ +static void test_dcblock_bitexact_s16(void **state) +{ + (void)state; + + run_s16_case(R_COEF_NEAR_ONE, 0.1); +} + +/* + * Runs the S24 (in 32-bit container) processing function and compares it to + * the floating point reference with a tolerance of 2 LSB of S24. + */ +static void run_s24_case(int32_t r_coeff, double dc) +{ + struct comp_data cd; + struct audio_stream source, sink; + int32_t src[TEST_FRAMES * TEST_CHANNELS]; + int32_t dst[TEST_FRAMES * TEST_CHANNELS]; + double ref_in[TEST_FRAMES * TEST_CHANNELS]; + struct ref_state rstate[TEST_CHANNELS]; + double r = (double)r_coeff / (double)ONE_Q2_30; + double tol = 2.0 / 8388608.0; + dcblock_func func; + int ch, i; + + memset(&cd, 0, sizeof(cd)); + for (ch = 0; ch < TEST_CHANNELS; ch++) + cd.R_coeffs[ch] = r_coeff; + + memset(rstate, 0, sizeof(rstate)); + gen_input(ref_in, TEST_CHANNELS, TEST_FRAMES, dc); + + for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) + src[i] = (int32_t)round(ref_in[i] * 8388607.0); + + setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S24_4LE, TEST_CHANNELS); + setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S24_4LE, TEST_CHANNELS); + + func = dcblock_find_func(SOF_IPC_FRAME_S24_4LE); + assert_non_null(func); + func(&cd, &source, &sink, TEST_FRAMES); + + for (i = 0; i < TEST_FRAMES; i++) { + for (ch = 0; ch < TEST_CHANNELS; ch++) { + int idx = i * TEST_CHANNELS + ch; + double refy = dcblock_ref(&rstate[ch], r, + (double)src[idx] / 8388608.0); + double outy = (double)dst[idx] / 8388608.0; + double delta = fabs(refy - outy); + + if (delta > tol) { + printf("s24 mismatch idx %d ref %g out %g delta %g\n", + idx, refy, outy, delta); + assert_true(delta <= tol); + } + } + } +} + +/* Bit-exactness check against the floating point reference for S24. */ +static void test_dcblock_bitexact_s24(void **state) +{ + (void)state; + + run_s24_case(R_COEF_NEAR_ONE, 0.1); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_dcblock_passthrough), + cmocka_unit_test(test_dcblock_dc_removal), + cmocka_unit_test(test_dcblock_saturation), + cmocka_unit_test(test_dcblock_bitexact_s32), + cmocka_unit_test(test_dcblock_bitexact_s16), + cmocka_unit_test(test_dcblock_bitexact_s24), + }; + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, NULL, NULL); +} diff --git a/test/cmocka/src/audio/dcblock/dcblock_process.c b/test/cmocka/src/audio/dcblock/dcblock_process.c new file mode 100644 index 000000000000..9b39f7a9e9c6 --- /dev/null +++ b/test/cmocka/src/audio/dcblock/dcblock_process.c @@ -0,0 +1,565 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dcblock.h" + +#include "../../util.h" +#include "../../../include/cmocka_chirp_2ch.h" + +/* Allow a few LSB of error due to the internal Q-format rounding. */ +#define ERROR_TOLERANCE_S16 2 +#define ERROR_TOLERANCE_S24 4 +#define ERROR_TOLERANCE_S32 2048 + +/* Q2.30 DC blocking coefficient (~0.98) used for all channels. */ +#define R_COEF 1052266987 + +/* Thresholds for frames count jitter for rand() function */ +#define THR_RAND_PLUS_ONE ((RAND_MAX >> 1) + (RAND_MAX >> 2)) +#define THR_RAND_MINUS_ONE ((RAND_MAX >> 1) - (RAND_MAX >> 2)) + +struct buffer_state { + int idx; +}; + +static struct buffer_state buffer_fill_data; +static struct buffer_state buffer_verify_data; + +/* Floating point reference filter state, one per channel. */ +struct ref_state { + double x_prev; + double y_prev; +}; + +static struct ref_state ref_states[PLATFORM_MAX_CHANNELS]; + +static double dcblock_ref(int ch, double x) +{ + struct ref_state *s = &ref_states[ch]; + double r = (double)R_COEF / (double)ONE_Q2_30; + double y = x - s->x_prev + r * s->y_prev; + + /* The fixed point filter saturates the Q1.31 state after every + * sample (sat_int32). The DC blocker has a passband gain slightly + * above one, so without this clamp the reference state would drift + * away from the implementation for near full-scale input. + */ + if (y > 2147483647.0 / 2147483648.0) + y = 2147483647.0 / 2147483648.0; + else if (y < -1.0) + y = -1.0; + + s->x_prev = x; + s->y_prev = y; + return y; +} + +struct test_parameters { + uint32_t channels; + uint32_t frames; + uint32_t buffer_size_mult; + uint32_t source_format; + uint32_t sink_format; +}; + +struct test_data { + struct comp_dev *dev; + struct comp_buffer *sink; + struct comp_buffer *source; + struct test_parameters *params; + struct processing_module *mod; + bool continue_loop; +}; + +static int setup_group(void **state) +{ + sys_comp_init(sof_get()); + sys_comp_module_dcblock_interface_init(); + return 0; +} + +static struct sof_ipc_comp_process *create_dcblock_comp_ipc(struct test_data *td) +{ + struct sof_ipc_comp_process *ipc; + size_t ipc_size = sizeof(struct sof_ipc_comp_process); + const struct sof_uuid uuid = SOF_REG_UUID(dcblock); + + ipc = calloc(1, ipc_size + SOF_UUID_SIZE); + memcpy_s(ipc + 1, SOF_UUID_SIZE, &uuid, SOF_UUID_SIZE); + ipc->comp.hdr.size = ipc_size + SOF_UUID_SIZE; + ipc->comp.type = SOF_COMP_MODULE_ADAPTER; + ipc->config.hdr.size = sizeof(struct sof_ipc_comp_config); + ipc->size = 0; + ipc->comp.ext_data_length = SOF_UUID_SIZE; + return ipc; +} + +/* Send a configuration blob holding the per-channel R coefficients. */ +static int dcblock_send_config(struct processing_module *mod) +{ + const struct module_interface *const ops = mod->dev->drv->adapter_ops; + const size_t coeff_size = PLATFORM_MAX_CHANNELS * sizeof(int32_t); + size_t cdata_size = sizeof(struct sof_ipc_ctrl_data) + + sizeof(struct sof_abi_hdr) + coeff_size; + struct sof_ipc_ctrl_data *cdata; + int32_t coeffs[PLATFORM_MAX_CHANNELS]; + int ret; + int i; + + cdata = calloc(1, cdata_size); + if (!cdata) + return -ENOMEM; + + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) + coeffs[i] = R_COEF; + + cdata->cmd = SOF_CTRL_CMD_BINARY; + cdata->num_elems = coeff_size; + cdata->data[0].magic = SOF_ABI_MAGIC; + cdata->data[0].type = 0; + cdata->data[0].size = coeff_size; + cdata->data[0].abi = SOF_ABI_VERSION; + memcpy_s(cdata->data[0].data, coeff_size, coeffs, coeff_size); + + ret = ops->set_configuration(mod, 0, MODULE_CFG_FRAGMENT_SINGLE, + coeff_size, (const uint8_t *)cdata, + coeff_size, NULL, 0); + + free(cdata); + return ret; +} + +static void prepare_sink(struct test_data *td, struct processing_module *mod) +{ + struct test_parameters *parameters = td->params; + struct module_data *md = &mod->priv; + size_t size; + size_t free; + + size = parameters->frames * get_frame_bytes(parameters->sink_format, parameters->channels) * + parameters->buffer_size_mult; + + md->mpd.out_buff_size = parameters->frames * get_frame_bytes(parameters->sink_format, + parameters->channels); + + td->sink = create_test_sink(td->dev, 0, parameters->sink_format, + parameters->channels, size); + free = audio_stream_get_free_bytes(&td->sink->stream); + assert_int_equal(free, size); +} + +static void prepare_source(struct test_data *td, struct processing_module *mod) +{ + struct test_parameters *parameters = td->params; + struct module_data *md = &mod->priv; + size_t size; + size_t free; + + md->mpd.in_buff_size = parameters->frames * get_frame_bytes(parameters->source_format, + parameters->channels); + + size = parameters->frames * get_frame_bytes(parameters->source_format, + parameters->channels) * parameters->buffer_size_mult; + + td->source = create_test_source(td->dev, 0, parameters->source_format, + parameters->channels, size); + free = audio_stream_get_free_bytes(&td->source->stream); + assert_int_equal(free, size); +} + +static int setup(void **state) +{ + struct test_parameters *params = *state; + struct processing_module *mod; + struct test_data *td; + struct sof_ipc_comp_process *ipc; + struct comp_dev *dev; + int ret; + int i; + + td = test_malloc(sizeof(*td)); + if (!td) + return -EINVAL; + + td->params = test_malloc(sizeof(*params)); + if (!td->params) { + test_free(td); + return -EINVAL; + } + + memcpy_s(td->params, sizeof(*td->params), params, sizeof(*params)); + ipc = create_dcblock_comp_ipc(td); + buffer_fill_data.idx = 0; + buffer_verify_data.idx = 0; + for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) { + ref_states[i].x_prev = 0.0; + ref_states[i].y_prev = 0.0; + } + + dev = comp_new((struct sof_ipc_comp *)ipc); + free(ipc); + if (!dev) + return -EINVAL; + + td->dev = dev; + dev->frames = params->frames; + mod = comp_mod(dev); + + ret = dcblock_send_config(mod); + if (ret) + return ret; + + prepare_sink(td, mod); + prepare_source(td, mod); + + mod->input_buffers = test_malloc(sizeof(struct input_stream_buffer)); + mod->input_buffers[0].data = &td->source->stream; + mod->output_buffers = test_malloc(sizeof(struct output_stream_buffer)); + mod->output_buffers[0].data = &td->sink->stream; + mod->stream_params = test_malloc(sizeof(struct sof_ipc_stream_params)); + mod->stream_params->channels = params->channels; + mod->period_bytes = get_frame_bytes(params->source_format, params->channels) * 48000 / 1000; + + ret = module_prepare(mod, NULL, 0, NULL, 0); + if (ret) + return ret; + + td->continue_loop = true; + + *state = td; + return 0; +} + +static int teardown(void **state) +{ + struct test_data *td = *state; + struct processing_module *mod = comp_mod(td->dev); + + test_free(mod->input_buffers); + test_free(mod->output_buffers); + test_free(mod->stream_params); + mod->stream_params = NULL; + test_free(td->params); + free_test_source(td->source); + free_test_sink(td->sink); + comp_free(td->dev); + test_free(td); + return 0; +} + +#if CONFIG_FORMAT_S16LE +static void fill_source_s16(struct test_data *td, int frames_max) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int16_t *x; + int bytes_total; + int samples; + int frames; + int i; + int samples_processed = 0; + + sb = comp_dev_get_first_data_producer(dev); + ss = &sb->stream; + frames = MIN(audio_stream_get_free_frames(ss), frames_max); + samples = frames * audio_stream_get_channels(ss); + for (i = 0; i < samples; i++) { + x = audio_stream_write_frag_s16(ss, i); + *x = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 15)); + samples_processed++; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + break; + } + } + + if (samples_processed > 0) { + bytes_total = samples_processed * audio_stream_sample_bytes(ss); + comp_update_buffer_produce(sb, bytes_total); + } + + mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); +} + +static void verify_sink_s16(struct test_data *td) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int nch = td->params->channels; + int32_t delta; + int32_t ref; + int32_t out; + int16_t *x; + int16_t in; + int samples; + int i; + + sb = comp_dev_get_first_data_consumer(dev); + ss = &sb->stream; + samples = mod->output_buffers[0].size >> 1; + for (i = 0; i < samples; i++) { + x = audio_stream_read_frag_s16(ss, i); + out = *x; + in = sat_int16(Q_SHIFT_RND(chirp_2ch[buffer_verify_data.idx], 31, 15)); + ref = (int32_t)round(dcblock_ref(buffer_verify_data.idx % nch, + (double)in / 32768.0) * 32768.0); + ref = sat_int16(ref); + buffer_verify_data.idx++; + delta = ref - out; + if (delta > ERROR_TOLERANCE_S16 || delta < -ERROR_TOLERANCE_S16) + assert_int_equal(out, ref); + } +} +#endif /* CONFIG_FORMAT_S16LE */ + +#if CONFIG_FORMAT_S24LE +static void fill_source_s24(struct test_data *td, int frames_max) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t *x; + int bytes_total; + int samples; + int frames; + int i; + int samples_processed = 0; + + sb = comp_dev_get_first_data_producer(dev); + ss = &sb->stream; + frames = MIN(audio_stream_get_free_frames(ss), frames_max); + samples = frames * audio_stream_get_channels(ss); + for (i = 0; i < samples; i++) { + x = audio_stream_write_frag_s32(ss, i); + *x = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_fill_data.idx++], 31, 23)); + samples_processed++; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + break; + } + } + + if (samples_processed > 0) { + bytes_total = samples_processed * audio_stream_sample_bytes(ss); + comp_update_buffer_produce(sb, bytes_total); + } + + mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); +} + +static void verify_sink_s24(struct test_data *td) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int nch = td->params->channels; + int32_t delta; + int32_t ref; + int32_t out; + int32_t *x; + int32_t in; + int samples; + int i; + + sb = comp_dev_get_first_data_consumer(dev); + ss = &sb->stream; + samples = mod->output_buffers[0].size >> 2; + for (i = 0; i < samples; i++) { + x = audio_stream_read_frag_s32(ss, i); + out = (*x << 8) >> 8; /* Make sure there's no 24 bit overflow */ + in = sat_int24(Q_SHIFT_RND(chirp_2ch[buffer_verify_data.idx], 31, 23)); + ref = (int32_t)round(dcblock_ref(buffer_verify_data.idx % nch, + (double)in / 8388608.0) * 8388608.0); + ref = sat_int24(ref); + buffer_verify_data.idx++; + delta = ref - out; + if (delta > ERROR_TOLERANCE_S24 || delta < -ERROR_TOLERANCE_S24) + assert_int_equal(out, ref); + } +} +#endif /* CONFIG_FORMAT_S24LE */ + +#if CONFIG_FORMAT_S32LE +static void fill_source_s32(struct test_data *td, int frames_max) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int32_t *x; + int bytes_total; + int samples; + int frames; + int i; + int samples_processed = 0; + + sb = comp_dev_get_first_data_producer(dev); + ss = &sb->stream; + frames = MIN(audio_stream_get_free_frames(ss), frames_max); + samples = frames * audio_stream_get_channels(ss); + for (i = 0; i < samples; i++) { + x = audio_stream_write_frag_s32(ss, i); + *x = chirp_2ch[buffer_fill_data.idx++]; + samples_processed++; + if (buffer_fill_data.idx == CHIRP_2CH_LENGTH) { + td->continue_loop = false; + break; + } + } + + if (samples_processed > 0) { + bytes_total = samples_processed * audio_stream_sample_bytes(ss); + comp_update_buffer_produce(sb, bytes_total); + } + + mod->input_buffers[0].size = samples_processed / audio_stream_get_channels(ss); +} + +static void verify_sink_s32(struct test_data *td) +{ + struct processing_module *mod = comp_mod(td->dev); + struct comp_dev *dev = td->dev; + struct comp_buffer *sb; + struct audio_stream *ss; + int nch = td->params->channels; + int64_t delta; + int32_t ref; + int32_t out; + int32_t *x; + int32_t in; + int samples; + int i; + + sb = comp_dev_get_first_data_consumer(dev); + ss = &sb->stream; + samples = mod->output_buffers[0].size >> 2; + for (i = 0; i < samples; i++) { + x = audio_stream_read_frag_s32(ss, i); + out = *x; + in = chirp_2ch[buffer_verify_data.idx]; + ref = (int32_t)round(dcblock_ref(buffer_verify_data.idx % nch, + (double)in / 2147483648.0) * 2147483648.0); + buffer_verify_data.idx++; + delta = (int64_t)ref - (int64_t)out; + if (delta > ERROR_TOLERANCE_S32 || delta < -ERROR_TOLERANCE_S32) + assert_int_equal(out, ref); + } +} +#endif /* CONFIG_FORMAT_S32LE */ + +static int frames_jitter(int frames) +{ + int r = rand(); + + if (r > THR_RAND_PLUS_ONE) + return frames + 1; + else if (r < THR_RAND_MINUS_ONE) + return frames - 1; + else + return frames; +} + +static void test_audio_dcblock(void **state) +{ + struct test_data *td = *state; + struct processing_module *mod = comp_mod(td->dev); + struct comp_buffer *source = td->source; + struct comp_buffer *sink = td->sink; + int ret; + int frames; + + while (td->continue_loop) { + frames = frames_jitter(td->params->frames); + switch (audio_stream_get_frm_fmt(&source->stream)) { + case SOF_IPC_FRAME_S16_LE: + fill_source_s16(td, frames); + break; + case SOF_IPC_FRAME_S24_4LE: + fill_source_s24(td, frames); + break; + case SOF_IPC_FRAME_S32_LE: + fill_source_s32(td, frames); + break; + default: + assert(0); + break; + } + + mod->input_buffers[0].consumed = 0; + mod->output_buffers[0].size = 0; + ret = module_process_legacy(mod, mod->input_buffers, 1, + mod->output_buffers, 1); + assert_int_equal(ret, 0); + + comp_update_buffer_consume(source, mod->input_buffers[0].consumed); + comp_update_buffer_produce(sink, mod->output_buffers[0].size); + + switch (audio_stream_get_frm_fmt(&sink->stream)) { + case SOF_IPC_FRAME_S16_LE: + verify_sink_s16(td); + break; + case SOF_IPC_FRAME_S24_4LE: + verify_sink_s24(td); + break; + case SOF_IPC_FRAME_S32_LE: + verify_sink_s32(td); + break; + default: + assert(0); + break; + } + + comp_update_buffer_consume(sink, mod->output_buffers[0].size); + } +} + +static struct test_parameters parameters[] = { +#if CONFIG_FORMAT_S16LE + { 2, 48, 2, SOF_IPC_FRAME_S16_LE, SOF_IPC_FRAME_S16_LE }, +#endif /* CONFIG_FORMAT_S16LE */ +#if CONFIG_FORMAT_S24LE + { 2, 48, 2, SOF_IPC_FRAME_S24_4LE, SOF_IPC_FRAME_S24_4LE }, +#endif /* CONFIG_FORMAT_S24LE */ +#if CONFIG_FORMAT_S32LE + { 2, 48, 2, SOF_IPC_FRAME_S32_LE, SOF_IPC_FRAME_S32_LE }, +#endif /* CONFIG_FORMAT_S32LE */ +}; + +int main(void) +{ + int i; + + struct CMUnitTest tests[ARRAY_SIZE(parameters)]; + + for (i = 0; i < ARRAY_SIZE(parameters); i++) { + tests[i].name = "test_audio_dcblock"; + tests[i].test_func = test_audio_dcblock; + tests[i].setup_func = setup; + tests[i].teardown_func = teardown; + tests[i].initial_state = ¶meters[i]; + } + + cmocka_set_message_output(CM_OUTPUT_TAP); + + return cmocka_run_group_tests(tests, setup_group, NULL); +} From f44656145b5b238a326490c80bdbdc2fee09e557 Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Wed, 8 Jul 2026 10:36:47 +0200 Subject: [PATCH 052/109] test(cmocka, dcblock): adopt test to use SOF API Signed-off-by: Piotr Hoppe --- .../src/audio/dcblock/dcblock_math_test.c | 84 ++++++----- .../src/audio/dcblock/dcblock_process.c | 134 ++++++++++++++---- 2 files changed, 155 insertions(+), 63 deletions(-) diff --git a/test/cmocka/src/audio/dcblock/dcblock_math_test.c b/test/cmocka/src/audio/dcblock/dcblock_math_test.c index a94912192f81..d41288c231ad 100644 --- a/test/cmocka/src/audio/dcblock/dcblock_math_test.c +++ b/test/cmocka/src/audio/dcblock/dcblock_math_test.c @@ -11,14 +11,34 @@ #include #include -#include +#include #include +#include #include "dcblock.h" #define TEST_CHANNELS 2 #define TEST_FRAMES 256 +/* + * The dcblock processing functions operate on struct cir_buf_source / + * struct cir_buf_sink circular buffer views. The tests use static, non + * wrapping sample buffers, so the views simply span the whole array. + */ +static void cir_buf_src_setup(struct cir_buf_source *s, const void *data, size_t bytes) +{ + s->buf_start = data; + s->buf_end = (const char *)data + bytes; + s->ptr = data; +} + +static void cir_buf_snk_setup(struct cir_buf_sink *s, void *data, size_t bytes) +{ + s->buf_start = data; + s->buf_end = (char *)data + bytes; + s->ptr = data; +} + /* Q2.30 coefficient close to 1.0 used for the DC removal test cases. */ #define R_COEF_NEAR_ONE 1063004406 /* ~0.99 in Q2.30 */ @@ -41,20 +61,6 @@ static double dcblock_ref(struct ref_state *s, double r, double x) return y; } -/* Build an audio_stream over a linear (non wrapping) sample buffer. */ -static void setup_stream(struct audio_stream *stream, void *data, - size_t bytes, enum sof_ipc_frame fmt, int channels) -{ - memset(stream, 0, sizeof(*stream)); - stream->addr = data; - stream->end_addr = (char *)data + bytes; - stream->r_ptr = data; - stream->w_ptr = data; - stream->size = bytes; - stream->runtime_stream_params.frame_fmt = fmt; - stream->runtime_stream_params.channels = channels; -} - /* Fill the source buffer with a per-channel sinusoid plus a DC offset. */ static void gen_input(double *ref_in, int channels, int frames, double dc) { @@ -77,7 +83,8 @@ static void gen_input(double *ref_in, int channels, int frames, double dc) static double run_s32_case(int32_t r_coeff, double dc, double tol_rel) { struct comp_data cd; - struct audio_stream source, sink; + struct cir_buf_source csrc; + struct cir_buf_sink csnk; int32_t src[TEST_FRAMES * TEST_CHANNELS]; int32_t dst[TEST_FRAMES * TEST_CHANNELS]; double ref_in[TEST_FRAMES * TEST_CHANNELS]; @@ -89,6 +96,7 @@ static double run_s32_case(int32_t r_coeff, double dc, double tol_rel) int ch, i; memset(&cd, 0, sizeof(cd)); + cd.channels = TEST_CHANNELS; for (ch = 0; ch < TEST_CHANNELS; ch++) cd.R_coeffs[ch] = r_coeff; @@ -98,8 +106,8 @@ static double run_s32_case(int32_t r_coeff, double dc, double tol_rel) for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) src[i] = (int32_t)round(ref_in[i] * 2147483647.0); - setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); - setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); + cir_buf_src_setup(&csrc, src, sizeof(src)); + cir_buf_snk_setup(&csnk, dst, sizeof(dst)); func = dcblock_find_func(SOF_IPC_FRAME_S32_LE); assert_non_null(func); @@ -156,30 +164,36 @@ static void test_dcblock_saturation(void **state) (void)state; struct comp_data cd; - struct audio_stream source, sink; + struct cir_buf_source csrc; + struct cir_buf_sink csnk; int32_t src[TEST_FRAMES * TEST_CHANNELS]; int32_t dst[TEST_FRAMES * TEST_CHANNELS]; dcblock_func func; int i; memset(&cd, 0, sizeof(cd)); + cd.channels = TEST_CHANNELS; for (i = 0; i < TEST_CHANNELS; i++) - cd.R_coeffs[i] = ONE_Q2_30; + cd.R_coeffs[i] = R_COEF_NEAR_ONE; - /* Alternating +full/-full scale is the worst case for the difference. */ + /* + * Alternate per frame so that every channel sees the full-scale + * transitions and exercises the saturation path. + */ for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) - src[i] = (i & 1) ? INT32_MAX : INT32_MIN; + src[i] = ((i / TEST_CHANNELS) & 1) ? INT32_MAX : INT32_MIN; - setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); - setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S32_LE, TEST_CHANNELS); + cir_buf_src_setup(&csrc, src, sizeof(src)); + cir_buf_snk_setup(&csnk, dst, sizeof(dst)); func = dcblock_find_func(SOF_IPC_FRAME_S32_LE); assert_non_null(func); assert_int_equal(func(&cd, &csrc, &csnk, TEST_FRAMES), 0); for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) { - assert_true(dst[i] <= INT32_MAX); - assert_true(dst[i] >= INT32_MIN); + int32_t expected = ((i / TEST_CHANNELS) & 1) ? INT32_MAX : INT32_MIN; + + assert_int_equal(dst[i], expected); } } @@ -199,7 +213,8 @@ static void test_dcblock_bitexact_s32(void **state) static void run_s16_case(int32_t r_coeff, double dc) { struct comp_data cd; - struct audio_stream source, sink; + struct cir_buf_source csrc; + struct cir_buf_sink csnk; int16_t src[TEST_FRAMES * TEST_CHANNELS]; int16_t dst[TEST_FRAMES * TEST_CHANNELS]; double ref_in[TEST_FRAMES * TEST_CHANNELS]; @@ -210,6 +225,7 @@ static void run_s16_case(int32_t r_coeff, double dc) int ch, i; memset(&cd, 0, sizeof(cd)); + cd.channels = TEST_CHANNELS; for (ch = 0; ch < TEST_CHANNELS; ch++) cd.R_coeffs[ch] = r_coeff; @@ -219,8 +235,8 @@ static void run_s16_case(int32_t r_coeff, double dc) for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) src[i] = (int16_t)round(ref_in[i] * 32767.0); - setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S16_LE, TEST_CHANNELS); - setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S16_LE, TEST_CHANNELS); + cir_buf_src_setup(&csrc, src, sizeof(src)); + cir_buf_snk_setup(&csnk, dst, sizeof(dst)); func = dcblock_find_func(SOF_IPC_FRAME_S16_LE); assert_non_null(func); @@ -258,7 +274,8 @@ static void test_dcblock_bitexact_s16(void **state) static void run_s24_case(int32_t r_coeff, double dc) { struct comp_data cd; - struct audio_stream source, sink; + struct cir_buf_source csrc; + struct cir_buf_sink csnk; int32_t src[TEST_FRAMES * TEST_CHANNELS]; int32_t dst[TEST_FRAMES * TEST_CHANNELS]; double ref_in[TEST_FRAMES * TEST_CHANNELS]; @@ -269,6 +286,7 @@ static void run_s24_case(int32_t r_coeff, double dc) int ch, i; memset(&cd, 0, sizeof(cd)); + cd.channels = TEST_CHANNELS; for (ch = 0; ch < TEST_CHANNELS; ch++) cd.R_coeffs[ch] = r_coeff; @@ -278,12 +296,12 @@ static void run_s24_case(int32_t r_coeff, double dc) for (i = 0; i < TEST_FRAMES * TEST_CHANNELS; i++) src[i] = (int32_t)round(ref_in[i] * 8388607.0); - setup_stream(&source, src, sizeof(src), SOF_IPC_FRAME_S24_4LE, TEST_CHANNELS); - setup_stream(&sink, dst, sizeof(dst), SOF_IPC_FRAME_S24_4LE, TEST_CHANNELS); + cir_buf_src_setup(&csrc, src, sizeof(src)); + cir_buf_snk_setup(&csnk, dst, sizeof(dst)); func = dcblock_find_func(SOF_IPC_FRAME_S24_4LE); assert_non_null(func); - func(&cd, &source, &sink, TEST_FRAMES); + assert_int_equal(func(&cd, &csrc, &csnk, TEST_FRAMES), 0); for (i = 0; i < TEST_FRAMES; i++) { for (ch = 0; ch < TEST_CHANNELS; ch++) { diff --git a/test/cmocka/src/audio/dcblock/dcblock_process.c b/test/cmocka/src/audio/dcblock/dcblock_process.c index 9b39f7a9e9c6..9ebe197de213 100644 --- a/test/cmocka/src/audio/dcblock/dcblock_process.c +++ b/test/cmocka/src/audio/dcblock/dcblock_process.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include #include @@ -99,6 +102,9 @@ static struct sof_ipc_comp_process *create_dcblock_comp_ipc(struct test_data *td const struct sof_uuid uuid = SOF_REG_UUID(dcblock); ipc = calloc(1, ipc_size + SOF_UUID_SIZE); + if (!ipc) + return NULL; + memcpy_s(ipc + 1, SOF_UUID_SIZE, &uuid, SOF_UUID_SIZE); ipc->comp.hdr.size = ipc_size + SOF_UUID_SIZE; ipc->comp.type = SOF_COMP_MODULE_ADAPTER; @@ -111,7 +117,6 @@ static struct sof_ipc_comp_process *create_dcblock_comp_ipc(struct test_data *td /* Send a configuration blob holding the per-channel R coefficients. */ static int dcblock_send_config(struct processing_module *mod) { - const struct module_interface *const ops = mod->dev->drv->adapter_ops; const size_t coeff_size = PLATFORM_MAX_CHANNELS * sizeof(int32_t); size_t cdata_size = sizeof(struct sof_ipc_ctrl_data) + sizeof(struct sof_abi_hdr) + coeff_size; @@ -135,9 +140,7 @@ static int dcblock_send_config(struct processing_module *mod) cdata->data[0].abi = SOF_ABI_VERSION; memcpy_s(cdata->data[0].data, coeff_size, coeffs, coeff_size); - ret = ops->set_configuration(mod, 0, MODULE_CFG_FRAGMENT_SINGLE, - coeff_size, (const uint8_t *)cdata, - coeff_size, NULL, 0); + ret = module_adapter_cmd(mod->dev, COMP_CMD_SET_DATA, cdata, cdata_size); free(cdata); return ret; @@ -181,28 +184,77 @@ static void prepare_source(struct test_data *td, struct processing_module *mod) assert_int_equal(free, size); } +static void cleanup_test_data(struct test_data *td) +{ + struct processing_module *mod; + + if (!td) + return; + + if (td->dev) { + mod = comp_mod(td->dev); + if (mod) { + test_free(mod->input_buffers); + mod->input_buffers = NULL; + test_free(mod->output_buffers); + mod->output_buffers = NULL; + test_free(mod->stream_params); + mod->stream_params = NULL; + } + } + + if (td->source) { + free_test_source(td->source); + td->source = NULL; + } + + if (td->sink) { + free_test_sink(td->sink); + td->sink = NULL; + } + + if (td->dev) { + comp_free(td->dev); + td->dev = NULL; + } + + test_free(td->params); + test_free(td); +} + static int setup(void **state) { struct test_parameters *params = *state; struct processing_module *mod; struct test_data *td; - struct sof_ipc_comp_process *ipc; + struct sof_ipc_comp_process *ipc = NULL; struct comp_dev *dev; + struct sof_source *sources[1]; + struct sof_sink *sinks[1]; int ret; int i; td = test_malloc(sizeof(*td)); - if (!td) + if (!td) { + *state = NULL; return -EINVAL; + } + *td = (struct test_data){ 0 }; + *state = td; td->params = test_malloc(sizeof(*params)); if (!td->params) { - test_free(td); - return -EINVAL; + ret = -ENOMEM; + goto error; } memcpy_s(td->params, sizeof(*td->params), params, sizeof(*params)); ipc = create_dcblock_comp_ipc(td); + if (!ipc) { + ret = -ENOMEM; + goto error; + } + buffer_fill_data.idx = 0; buffer_verify_data.idx = 0; for (i = 0; i < PLATFORM_MAX_CHANNELS; i++) { @@ -212,8 +264,11 @@ static int setup(void **state) dev = comp_new((struct sof_ipc_comp *)ipc); free(ipc); - if (!dev) - return -EINVAL; + ipc = NULL; + if (!dev) { + ret = -EINVAL; + goto error; + } td->dev = dev; dev->frames = params->frames; @@ -221,43 +276,54 @@ static int setup(void **state) ret = dcblock_send_config(mod); if (ret) - return ret; + goto error; prepare_sink(td, mod); prepare_source(td, mod); mod->input_buffers = test_malloc(sizeof(struct input_stream_buffer)); + if (!mod->input_buffers) { + ret = -ENOMEM; + goto error; + } mod->input_buffers[0].data = &td->source->stream; mod->output_buffers = test_malloc(sizeof(struct output_stream_buffer)); + if (!mod->output_buffers) { + ret = -ENOMEM; + goto error; + } mod->output_buffers[0].data = &td->sink->stream; mod->stream_params = test_malloc(sizeof(struct sof_ipc_stream_params)); + if (!mod->stream_params) { + ret = -ENOMEM; + goto error; + } mod->stream_params->channels = params->channels; mod->period_bytes = get_frame_bytes(params->source_format, params->channels) * 48000 / 1000; - ret = module_prepare(mod, NULL, 0, NULL, 0); + sources[0] = audio_buffer_get_source(&td->source->audio_buffer); + sinks[0] = audio_buffer_get_sink(&td->sink->audio_buffer); + ret = module_prepare(mod, sources, 1, sinks, 1); if (ret) - return ret; + goto error; td->continue_loop = true; *state = td; return 0; + +error: + free(ipc); + cleanup_test_data(td); + *state = NULL; + return ret; } static int teardown(void **state) { struct test_data *td = *state; - struct processing_module *mod = comp_mod(td->dev); - test_free(mod->input_buffers); - test_free(mod->output_buffers); - test_free(mod->stream_params); - mod->stream_params = NULL; - test_free(td->params); - free_test_source(td->source); - free_test_sink(td->sink); - comp_free(td->dev); - test_free(td); + cleanup_test_data(td); return 0; } @@ -485,9 +551,15 @@ static void test_audio_dcblock(void **state) struct processing_module *mod = comp_mod(td->dev); struct comp_buffer *source = td->source; struct comp_buffer *sink = td->sink; + struct sof_source *sources[1]; + struct sof_sink *sinks[1]; + uint32_t avail_before; int ret; int frames; + sources[0] = audio_buffer_get_source(&source->audio_buffer); + sinks[0] = audio_buffer_get_sink(&sink->audio_buffer); + while (td->continue_loop) { frames = frames_jitter(td->params->frames); switch (audio_stream_get_frm_fmt(&source->stream)) { @@ -505,14 +577,16 @@ static void test_audio_dcblock(void **state) break; } - mod->input_buffers[0].consumed = 0; - mod->output_buffers[0].size = 0; - ret = module_process_legacy(mod, mod->input_buffers, 1, - mod->output_buffers, 1); + /* Process exactly the frames just filled. The source/sink API + * updates the buffer read/write positions internally, so record + * the sink fill level to know how many bytes were produced. + */ + td->dev->frames = mod->input_buffers[0].size; + avail_before = audio_stream_get_avail_bytes(&sink->stream); + ret = module_process_sink_src(mod, sources, 1, sinks, 1); assert_int_equal(ret, 0); - - comp_update_buffer_consume(source, mod->input_buffers[0].consumed); - comp_update_buffer_produce(sink, mod->output_buffers[0].size); + mod->output_buffers[0].size = + audio_stream_get_avail_bytes(&sink->stream) - avail_before; switch (audio_stream_get_frm_fmt(&sink->stream)) { case SOF_IPC_FRAME_S16_LE: From a4690383254f6402fee7321a374c045f5cb827f9 Mon Sep 17 00:00:00 2001 From: Piotr Hoppe Date: Wed, 8 Jul 2026 13:04:51 +0200 Subject: [PATCH 053/109] audio: dcblock: switch to source/sink API Convert the DC blocking filter from the deprecated audio_stream / process_audio_stream interface to the modern sof_source / sof_sink processing API. The module .process callback now acquires the source and sink circular buffers once via source_get_data() / sink_get_buffer() and passes them to the processing functions as struct cir_buf_source / struct cir_buf_sink views, mirroring the volume component. The generic path uses the shared cir_buf_samples_without_wrap_*() and cir_buf_wrap() helpers, while the HiFi3/HiFi4 variants derive the circular buffer bounds from the same views. Channel count is cached in comp_data during prepare(). Signed-off-by: Piotr Hoppe --- src/audio/dcblock/dcblock.c | 98 +++++++++---- src/audio/dcblock/dcblock.h | 15 +- src/audio/dcblock/dcblock_generic.c | 207 +++++++++++++++------------- src/audio/dcblock/dcblock_hifi3.c | 158 +++++++++++++-------- src/audio/dcblock/dcblock_hifi4.c | 110 +++++++++------ 5 files changed, 365 insertions(+), 223 deletions(-) diff --git a/src/audio/dcblock/dcblock.c b/src/audio/dcblock/dcblock.c index 15e6139b7a89..6e620b2983d7 100644 --- a/src/audio/dcblock/dcblock.c +++ b/src/audio/dcblock/dcblock.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -140,25 +142,62 @@ static int dcblock_set_config(struct processing_module *mod, uint32_t config_id, /** * \brief Copies and processes stream data. - * \param[in,out] dev DC Blocking Filter module. + * \param[in,out] mod DC Blocking Filter module. * \return Error code. */ static int dcblock_process(struct processing_module *mod, - struct input_stream_buffer *input_buffers, - int num_input_buffers, - struct output_stream_buffer *output_buffers, - int num_output_buffers) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); - struct audio_stream *source = input_buffers[0].data; - struct audio_stream *sink = output_buffers[0].data; - uint32_t frames = input_buffers[0].size; - - comp_dbg(mod->dev, "entry"); - - cd->dcblock_func(cd, source, sink, frames); + struct comp_dev *dev = mod->dev; + struct sof_source *source = sources[0]; + struct sof_sink *sink = sinks[0]; + struct cir_buf_source source_buf; + struct cir_buf_sink sink_buf; + size_t source_frame_bytes = source_get_frame_bytes(source); + size_t sink_frame_bytes = sink_get_frame_bytes(sink); + size_t source_bytes, sink_bytes, bytes; + uint32_t frames = source_get_data_frames_available(source); + uint32_t sink_frames = sink_get_free_frames(sink); + int ret; + + comp_dbg(dev, "entry"); + + frames = MIN(frames, sink_frames); + if (!frames) + return 0; + + source_bytes = frames * source_frame_bytes; + sink_bytes = frames * sink_frame_bytes; + + /* acquire the source and sink circular buffer views once */ + ret = source_get_data(source, source_bytes, &source_buf.ptr, + &source_buf.buf_start, &bytes); + if (ret) + return ret; + source_buf.buf_end = (const char *)source_buf.buf_start + bytes; + + ret = sink_get_buffer(sink, sink_bytes, &sink_buf.ptr, + &sink_buf.buf_start, &bytes); + if (ret) { + source_release_data(source, 0); + return ret; + } + sink_buf.buf_end = (char *)sink_buf.buf_start + bytes; + + ret = cd->dcblock_func(cd, &source_buf, &sink_buf, frames); + if (ret) { + /* Undo the acquire without consuming source data or + * publishing partially-written output. + */ + source_release_data(source, 0); + sink_commit_buffer(sink, 0); + return ret; + } - module_update_buffer_position(&input_buffers[0], &output_buffers[0], frames); + source_release_data(source, source_bytes); + sink_commit_buffer(sink, sink_bytes); return 0; } @@ -172,27 +211,40 @@ static int dcblock_prepare(struct processing_module *mod, struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); - struct comp_buffer *sourceb, *sinkb; struct comp_dev *dev = mod->dev; size_t data_size; comp_info(dev, "entry"); /* DC Filter component will only ever have one source and sink buffer */ - sourceb = comp_dev_get_first_data_producer(dev); - sinkb = comp_dev_get_first_data_consumer(dev); - if (!sourceb || !sinkb) { - comp_err(dev, "no source or sink buffer"); - return -ENOTCONN; + if (num_of_sources != 1 || num_of_sinks != 1) { + comp_err(dev, "Invalid number of sources/sinks"); + return -EINVAL; } dcblock_params(mod); /* get source data format */ - cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); + cd->source_format = source_get_frm_fmt(sources[0]); + + /* get sink data format */ + cd->sink_format = sink_get_frm_fmt(sinks[0]); + + if (cd->source_format != cd->sink_format) { + comp_err(dev, "source and sink frame formats do not match"); + return -EINVAL; + } + + /* The processing uses a single channel count as the frame stride for + * both source and sink, so they must match to avoid corrupt output. + */ + if (source_get_channels(sources[0]) != sink_get_channels(sinks[0])) { + comp_err(dev, "mismatch source/sink stream channels"); + return -EINVAL; + } - /* get sink data format and period bytes */ - cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); + /* get channel count for processing */ + cd->channels = source_get_channels(sources[0]); dcblock_init_state(cd); cd->dcblock_func = dcblock_find_func(cd->source_format); @@ -238,7 +290,7 @@ static int dcblock_reset(struct processing_module *mod) static const struct module_interface dcblock_interface = { .init = dcblock_init, .prepare = dcblock_prepare, - .process_audio_stream = dcblock_process, + .process = dcblock_process, .set_configuration = dcblock_set_config, .get_configuration = dcblock_get_config, .reset = dcblock_reset, diff --git a/src/audio/dcblock/dcblock.h b/src/audio/dcblock/dcblock.h index eaf09da22bf2..dca1308b80ba 100644 --- a/src/audio/dcblock/dcblock.h +++ b/src/audio/dcblock/dcblock.h @@ -12,11 +12,17 @@ #include #include #include +#include +#include #include #include struct audio_stream; struct comp_dev; +struct sof_source; +struct sof_sink; +struct cir_buf_source; +struct cir_buf_sink; struct dcblock_state { int32_t x_prev; /**< state variable referring to x[n-1] */ @@ -30,10 +36,10 @@ struct dcblock_state { struct comp_data; -typedef void (*dcblock_func)(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames); +typedef int (*dcblock_func)(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames); /* DC Blocking Filter component private data */ struct comp_data { @@ -48,6 +54,7 @@ struct comp_data { enum sof_ipc_frame source_format; enum sof_ipc_frame sink_format; + int channels; /**< number of channels */ dcblock_func dcblock_func; /**< processing function */ }; diff --git a/src/audio/dcblock/dcblock_generic.c b/src/audio/dcblock/dcblock_generic.c index 4ff5fa11315b..0c8468868949 100644 --- a/src/audio/dcblock/dcblock_generic.c +++ b/src/audio/dcblock/dcblock_generic.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "dcblock.h" @@ -36,119 +37,141 @@ static int32_t dcblock_generic(struct dcblock_state *state, } #if CONFIG_FORMAT_S16LE -static void dcblock_s16_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +/** + * dcblock_s16_default() - Process S16_LE format. + * @cd: DC blocking filter component private data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * Return: Value zero for success, otherwise an error code. + */ +static int dcblock_s16_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - struct dcblock_state *state; - int16_t *x = audio_stream_get_rptr(source); - int16_t *y = audio_stream_get_wptr(sink); - int32_t R; + const int16_t *x = source->ptr; + int16_t *y = sink->ptr; + int samples_without_wrap; + int nch = cd->channels; + int remaining_samples = frames * nch; int32_t tmp; - int idx; - int ch; - int i, n, nmax; - int nch = audio_stream_get_channels(source); - int samples = nch * frames; - - while (samples) { - nmax = audio_stream_samples_without_wrap_s16(source, x); - n = MIN(samples, nmax); - nmax = audio_stream_samples_without_wrap_s16(sink, y); - n = MIN(n, nmax); - for (ch = 0; ch < nch; ch++) { - state = &cd->state[ch]; - R = cd->R_coeffs[ch]; - idx = ch; - for (i = 0; i < n; i += nch) { - tmp = dcblock_generic(state, R, x[idx] << 16); - y[idx] = sat_int16(Q_SHIFT_RND(tmp, 31, 15)); - idx += nch; - } + int ch = 0; + int i; + + while (remaining_samples) { + samples_without_wrap = cir_buf_samples_without_wrap_s16(x, source->buf_end); + samples_without_wrap = MIN(samples_without_wrap, + cir_buf_samples_without_wrap_s16(y, sink->buf_end)); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + for (i = 0; i < samples_without_wrap; i++) { + tmp = dcblock_generic(&cd->state[ch], cd->R_coeffs[ch], + *x << 16); + *y = sat_int16(Q_SHIFT_RND(tmp, 31, 15)); + x++; + y++; + if (++ch == nch) + ch = 0; } - samples -= n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); + x = cir_buf_wrap((void *)x, source->buf_start, source->buf_end); + y = cir_buf_wrap(y, sink->buf_start, sink->buf_end); + remaining_samples -= samples_without_wrap; } + return 0; } #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -static void dcblock_s24_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +/** + * dcblock_s24_default() - Process S24_4LE format. + * @cd: DC blocking filter component private data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * Return: Value zero for success, otherwise an error code. + */ +static int dcblock_s24_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - struct dcblock_state *state; - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int32_t R; + const int32_t *x = source->ptr; + int32_t *y = sink->ptr; + int samples_without_wrap; + int nch = cd->channels; + int remaining_samples = frames * nch; int32_t tmp; - int idx; - int ch; - int i, n, nmax; - int nch = audio_stream_get_channels(source); - int samples = nch * frames; - - while (samples) { - nmax = audio_stream_samples_without_wrap_s24(source, x); - n = MIN(samples, nmax); - nmax = audio_stream_samples_without_wrap_s24(sink, y); - n = MIN(n, nmax); - for (ch = 0; ch < nch; ch++) { - state = &cd->state[ch]; - R = cd->R_coeffs[ch]; - idx = ch; - for (i = 0; i < n; i += nch) { - tmp = dcblock_generic(state, R, x[idx] << 8); - y[idx] = sat_int24(Q_SHIFT_RND(tmp, 31, 23)); - idx += nch; - } + int ch = 0; + int i; + + while (remaining_samples) { + samples_without_wrap = cir_buf_samples_without_wrap_s32(x, source->buf_end); + samples_without_wrap = MIN(samples_without_wrap, + cir_buf_samples_without_wrap_s32(y, sink->buf_end)); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + for (i = 0; i < samples_without_wrap; i++) { + tmp = dcblock_generic(&cd->state[ch], cd->R_coeffs[ch], + *x << 8); + *y = sat_int24(Q_SHIFT_RND(tmp, 31, 23)); + x++; + y++; + if (++ch == nch) + ch = 0; } - samples -= n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); + x = cir_buf_wrap((void *)x, source->buf_start, source->buf_end); + y = cir_buf_wrap(y, sink->buf_start, sink->buf_end); + remaining_samples -= samples_without_wrap; } + return 0; } #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -static void dcblock_s32_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +/** + * dcblock_s32_default() - Process S32_LE format. + * @cd: DC blocking filter component private data. + * @source: Source for PCM samples data. + * @sink: Sink for PCM samples data. + * @frames: Number of audio data frames to process. + * + * Return: Value zero for success, otherwise an error code. + */ +static int dcblock_s32_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - struct dcblock_state *state; - int32_t *x = audio_stream_get_rptr(source); - int32_t *y = audio_stream_get_wptr(sink); - int32_t R; - int idx; - int ch; - int i, n, nmax; - int nch = audio_stream_get_channels(source); - int samples = nch * frames; - - while (samples) { - nmax = audio_stream_samples_without_wrap_s32(source, x); - n = MIN(samples, nmax); - nmax = audio_stream_samples_without_wrap_s32(sink, y); - n = MIN(n, nmax); - for (ch = 0; ch < nch; ch++) { - state = &cd->state[ch]; - R = cd->R_coeffs[ch]; - idx = ch; - for (i = 0; i < n; i += nch) { - y[idx] = dcblock_generic(state, R, x[idx]); - idx += nch; - } + const int32_t *x = source->ptr; + int32_t *y = sink->ptr; + int samples_without_wrap; + int nch = cd->channels; + int remaining_samples = frames * nch; + int ch = 0; + int i; + + while (remaining_samples) { + samples_without_wrap = cir_buf_samples_without_wrap_s32(x, source->buf_end); + samples_without_wrap = MIN(samples_without_wrap, + cir_buf_samples_without_wrap_s32(y, sink->buf_end)); + samples_without_wrap = MIN(samples_without_wrap, remaining_samples); + for (i = 0; i < samples_without_wrap; i++) { + *y = dcblock_generic(&cd->state[ch], cd->R_coeffs[ch], + *x); + x++; + y++; + if (++ch == nch) + ch = 0; } - samples -= n; - x = audio_stream_wrap(source, x + n); - y = audio_stream_wrap(sink, y + n); + x = cir_buf_wrap((void *)x, source->buf_start, source->buf_end); + y = cir_buf_wrap(y, sink->buf_start, sink->buf_end); + remaining_samples -= samples_without_wrap; } + + return 0; } #endif /* CONFIG_FORMAT_S32LE */ diff --git a/src/audio/dcblock/dcblock_hifi3.c b/src/audio/dcblock/dcblock_hifi3.c index d49a1ccca986..cd03fb101b16 100644 --- a/src/audio/dcblock/dcblock_hifi3.c +++ b/src/audio/dcblock/dcblock_hifi3.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "dcblock.h" @@ -29,35 +30,44 @@ static inline ae_int32x2 dcblock_cal(ae_int32x2 R, ae_int32x2 state_x, ae_int32 return AE_ROUND32F64SSYM(AE_SLAI64S(out, 1)); } -/* Setup circular for component source */ -static inline void dcblock_set_circular(const struct audio_stream *source) +/* Set source as circular buffer 0 for the strided per-channel reads */ +static inline void dcblock_set_circular(void *src_begin, void *src_end) { - /* Set source as circular buffer 0 */ - AE_SETCBEGIN0(audio_stream_get_addr(source)); - AE_SETCEND0(audio_stream_get_end_addr(source)); + AE_SETCBEGIN0(src_begin); + AE_SETCEND0(src_end); } #if CONFIG_FORMAT_S16LE -static void dcblock_s16_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +static int dcblock_s16_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - ae_int16 *src = audio_stream_get_rptr(source); - ae_int16 *dst = audio_stream_get_wptr(sink); - ae_int16 *in; - ae_int16 *out; + ae_int16 *src = (ae_int16 *)source->ptr; + ae_int16 *dst = (ae_int16 *)sink->ptr; + ae_int16 *x_start = (ae_int16 *)source->buf_start; + ae_int16 *y_start = (ae_int16 *)sink->buf_start; + ae_int16 *x_end = (ae_int16 *)source->buf_end; + ae_int16 *y_end = (ae_int16 *)sink->buf_end; + ae_int16 *in, *out; ae_int32x2 R, state_x, state_y, sample; ae_int16x4 in_sample, out_sample; - int ch, i, n; - int nch = audio_stream_get_channels(source); + int x_size = x_end - x_start; + int y_size = y_end - y_start; + int nch = cd->channels; + int remaining = frames * nch; const int inc = nch * sizeof(ae_int16); - int samples = nch * frames; + int ch, i, n; + + /* Set source as circular buffer 0 for the strided per-channel reads */ + dcblock_set_circular(x_start, x_end); - dcblock_set_circular(source); - while (samples) { - n = audio_stream_samples_without_wrap_s16(sink, dst); - n = MIN(n, samples); + while (remaining) { + /* The sink uses linear stores, so limit the chunk to the sink + * contiguous space. The source wraps via circular addressing. + */ + n = y_end - dst; + n = MIN(n, remaining); for (ch = 0; ch < nch; ch++) { in = src + ch; out = dst + ch; @@ -77,34 +87,46 @@ static void dcblock_s16_default(struct comp_data *cd, cd->state[ch].x_prev = state_x; cd->state[ch].y_prev = state_y; } - samples -= n; - dst = audio_stream_wrap(sink, dst + n); - src = audio_stream_wrap(source, src + n); + remaining -= n; + dst += n; + if (dst >= y_end) + dst -= y_size; + src += n; + while (src >= x_end) + src -= x_size; } + + return 0; } #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -static void dcblock_s24_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +static int dcblock_s24_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - ae_int32 *src = audio_stream_get_rptr(source); - ae_int32 *dst = audio_stream_get_wptr(sink); - ae_int32 *in; - ae_int32 *out; + ae_int32 *src = (ae_int32 *)source->ptr; + ae_int32 *dst = (ae_int32 *)sink->ptr; + ae_int32 *x_start = (ae_int32 *)source->buf_start; + ae_int32 *y_start = (ae_int32 *)sink->buf_start; + ae_int32 *x_end = (ae_int32 *)source->buf_end; + ae_int32 *y_end = (ae_int32 *)sink->buf_end; + ae_int32 *in, *out; ae_int32x2 R, state_x, state_y; ae_int32x2 in_sample, out_sample; - int ch, i, n; - int nch = audio_stream_get_channels(source); + int x_size = x_end - x_start; + int y_size = y_end - y_start; + int nch = cd->channels; + int remaining = frames * nch; const int inc = nch * sizeof(ae_int32); - int samples = nch * frames; + int ch, i, n; - dcblock_set_circular(source); - while (samples) { - n = audio_stream_samples_without_wrap_s24(sink, dst); - n = MIN(n, samples); + dcblock_set_circular(x_start, x_end); + + while (remaining) { + n = y_end - dst; + n = MIN(n, remaining); for (ch = 0; ch < nch; ch++) { in = src + ch; out = dst + ch; @@ -124,34 +146,46 @@ static void dcblock_s24_default(struct comp_data *cd, cd->state[ch].x_prev = state_x; cd->state[ch].y_prev = state_y; } - samples -= n; - dst = audio_stream_wrap(sink, dst + n); - src = audio_stream_wrap(source, src + n); + remaining -= n; + dst += n; + if (dst >= y_end) + dst -= y_size; + src += n; + while (src >= x_end) + src -= x_size; } + + return 0; } #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -static void dcblock_s32_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +static int dcblock_s32_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - ae_int32 *src = audio_stream_get_rptr(source); - ae_int32 *dst = audio_stream_get_wptr(sink); - ae_int32 *in; - ae_int32 *out; + ae_int32 *src = (ae_int32 *)source->ptr; + ae_int32 *dst = (ae_int32 *)sink->ptr; + ae_int32 *x_start = (ae_int32 *)source->buf_start; + ae_int32 *y_start = (ae_int32 *)sink->buf_start; + ae_int32 *x_end = (ae_int32 *)source->buf_end; + ae_int32 *y_end = (ae_int32 *)sink->buf_end; + ae_int32 *in, *out; ae_int32x2 R, state_x, state_y; ae_int32x2 in_sample; - int ch, i, n; - int nch = audio_stream_get_channels(source); + int x_size = x_end - x_start; + int y_size = y_end - y_start; + int nch = cd->channels; + int remaining = frames * nch; const int inc = nch * sizeof(ae_int32); - int samples = nch * frames; + int ch, i, n; + + dcblock_set_circular(x_start, x_end); - dcblock_set_circular(source); - while (samples) { - n = audio_stream_samples_without_wrap_s32(sink, dst); - n = MIN(n, samples); + while (remaining) { + n = y_end - dst; + n = MIN(n, remaining); for (ch = 0; ch < nch; ch++) { in = src + ch; out = dst + ch; @@ -167,10 +201,16 @@ static void dcblock_s32_default(struct comp_data *cd, cd->state[ch].x_prev = state_x; cd->state[ch].y_prev = state_y; } - samples -= n; - dst = audio_stream_wrap(sink, dst + n); - src = audio_stream_wrap(source, src + n); + remaining -= n; + dst += n; + if (dst >= y_end) + dst -= y_size; + src += n; + while (src >= x_end) + src -= x_size; } + + return 0; } #endif /* CONFIG_FORMAT_S32LE */ diff --git a/src/audio/dcblock/dcblock_hifi4.c b/src/audio/dcblock/dcblock_hifi4.c index f6ff06a55a63..50a61acda505 100644 --- a/src/audio/dcblock/dcblock_hifi4.c +++ b/src/audio/dcblock/dcblock_hifi4.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "dcblock.h" @@ -29,37 +30,40 @@ static inline ae_int32x2 dcblock_cal(ae_int32x2 R, ae_int32x2 state_x, ae_int32 return AE_ROUND32F64SSYM(AE_SLAI64S(out, 1)); } -/* Setup circular for component sink and source */ -static inline void dcblock_set_circular(const struct audio_stream *source, - const struct audio_stream *sink) +/* Set source as circular buffer 0 and sink as circular buffer 1 */ +static inline void dcblock_set_circular(void *src_begin, void *src_end, + void *sink_begin, void *sink_end) { - /* Set source as circular buffer 0 */ - AE_SETCBEGIN0(audio_stream_get_addr(source)); - AE_SETCEND0(audio_stream_get_end_addr(source)); - - /* Set sink as circular buffer 1 */ - AE_SETCBEGIN1(audio_stream_get_addr(sink)); - AE_SETCEND1(audio_stream_get_end_addr(sink)); + AE_SETCBEGIN0(src_begin); + AE_SETCEND0(src_end); + AE_SETCBEGIN1(sink_begin); + AE_SETCEND1(sink_end); } #if CONFIG_FORMAT_S16LE -static void dcblock_s16_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +static int dcblock_s16_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - ae_int16 *in; - ae_int16 *out; + ae_int16 *src = (ae_int16 *)source->ptr; + ae_int16 *dst = (ae_int16 *)sink->ptr; + ae_int16 *x_start = (ae_int16 *)source->buf_start; + ae_int16 *y_start = (ae_int16 *)sink->buf_start; + ae_int16 *x_end = (ae_int16 *)source->buf_end; + ae_int16 *y_end = (ae_int16 *)sink->buf_end; + ae_int16 *in, *out; ae_int32x2 R, state_x, state_y, sample; ae_int16x4 in_sample, out_sample; - int ch, i; - int nch = audio_stream_get_channels(source); + int nch = cd->channels; const int inc = nch * sizeof(ae_int16); + int ch, i; + + dcblock_set_circular(x_start, x_end, y_start, y_end); - dcblock_set_circular(source, sink); for (ch = 0; ch < nch; ch++) { - in = (ae_int16 *)audio_stream_get_rptr(source) + ch; - out = (ae_int16 *)audio_stream_get_wptr(sink) + ch; + in = src + ch; + out = dst + ch; state_x = cd->state[ch].x_prev; state_y = cd->state[ch].y_prev; R = cd->R_coeffs[ch]; @@ -76,28 +80,35 @@ static void dcblock_s16_default(struct comp_data *cd, cd->state[ch].x_prev = state_x; cd->state[ch].y_prev = state_y; } + + return 0; } #endif /* CONFIG_FORMAT_S16LE */ #if CONFIG_FORMAT_S24LE -static void dcblock_s24_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +static int dcblock_s24_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - ae_int32 *in; - ae_int32 *out; + ae_int32 *src = (ae_int32 *)source->ptr; + ae_int32 *dst = (ae_int32 *)sink->ptr; + ae_int32 *x_start = (ae_int32 *)source->buf_start; + ae_int32 *y_start = (ae_int32 *)sink->buf_start; + ae_int32 *x_end = (ae_int32 *)source->buf_end; + ae_int32 *y_end = (ae_int32 *)sink->buf_end; + ae_int32 *in, *out; ae_int32x2 R, state_x, state_y; ae_int32x2 in_sample, out_sample; - int ch, i; - int nch = audio_stream_get_channels(source); + int nch = cd->channels; const int inc = nch * sizeof(ae_int32); + int ch, i; - dcblock_set_circular(source, sink); - for (ch = 0; ch < nch; ch++) { - in = (ae_int32 *)audio_stream_get_rptr(source) + ch; - out = (ae_int32 *)audio_stream_get_wptr(sink) + ch; + dcblock_set_circular(x_start, x_end, y_start, y_end); + for (ch = 0; ch < nch; ch++) { + in = src + ch; + out = dst + ch; state_x = cd->state[ch].x_prev; state_y = cd->state[ch].y_prev; R = cd->R_coeffs[ch]; @@ -114,28 +125,35 @@ static void dcblock_s24_default(struct comp_data *cd, cd->state[ch].x_prev = state_x; cd->state[ch].y_prev = state_y; } + + return 0; } #endif /* CONFIG_FORMAT_S24LE */ #if CONFIG_FORMAT_S32LE -static void dcblock_s32_default(struct comp_data *cd, - const struct audio_stream *source, - const struct audio_stream *sink, - uint32_t frames) +static int dcblock_s32_default(struct comp_data *cd, + struct cir_buf_source *source, + struct cir_buf_sink *sink, + uint32_t frames) { - ae_int32 *in; - ae_int32 *out; + ae_int32 *src = (ae_int32 *)source->ptr; + ae_int32 *dst = (ae_int32 *)sink->ptr; + ae_int32 *x_start = (ae_int32 *)source->buf_start; + ae_int32 *y_start = (ae_int32 *)sink->buf_start; + ae_int32 *x_end = (ae_int32 *)source->buf_end; + ae_int32 *y_end = (ae_int32 *)sink->buf_end; + ae_int32 *in, *out; ae_int32x2 R, state_x, state_y; ae_int32x2 in_sample; - int ch, i; - int nch = audio_stream_get_channels(source); + int nch = cd->channels; const int inc = nch * sizeof(ae_int32); + int ch, i; - dcblock_set_circular(source, sink); - for (ch = 0; ch < nch; ch++) { - in = (ae_int32 *)audio_stream_get_rptr(source) + ch; - out = (ae_int32 *)audio_stream_get_wptr(sink) + ch; + dcblock_set_circular(x_start, x_end, y_start, y_end); + for (ch = 0; ch < nch; ch++) { + in = src + ch; + out = dst + ch; state_x = cd->state[ch].x_prev; state_y = cd->state[ch].y_prev; R = cd->R_coeffs[ch]; @@ -148,6 +166,8 @@ static void dcblock_s32_default(struct comp_data *cd, cd->state[ch].x_prev = state_x; cd->state[ch].y_prev = state_y; } + + return 0; } #endif /* CONFIG_FORMAT_S32LE */ From 0421e2c9e4268d22cca594013db107eebfcc51a3 Mon Sep 17 00:00:00 2001 From: DineshKumar Kalva Date: Tue, 11 Aug 2026 16:27:06 +0530 Subject: [PATCH 054/109] acp_7_x: board: enable ACP panic dump coredump backend Enable CONFIG_DEBUG_COREDUMP with the AMD ACP panic dump backend and minimal memory dump on the ACP 7.X ADSP board, so a DSP firmware crash is captured into the ACP scratch exception buffer and reported to the host SOF driver. Signed-off-by: DineshKumar Kalva --- app/boards/acp_7_x_adsp.conf | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/boards/acp_7_x_adsp.conf b/app/boards/acp_7_x_adsp.conf index 04c63271c9ac..2515f5d763d6 100644 --- a/app/boards/acp_7_x_adsp.conf +++ b/app/boards/acp_7_x_adsp.conf @@ -55,3 +55,6 @@ CONFIG_CORE_COUNT=1 CONFIG_FORMAT_CONVERT_HIFI3=n CONFIG_PCM_CONVERTER_FORMAT_S24_4LE_MSB=y CONFIG_XTENSA_INTERRUPT_NONPREEMPTABLE=y +CONFIG_DEBUG_COREDUMP=y +CONFIG_DEBUG_COREDUMP_BACKEND_AMD_ACP_PANIC_DUMP=y +CONFIG_DEBUG_COREDUMP_MEMORY_DUMP_MIN=y From 8d52fbdd84c5adc510ae133e963b3691b4d33d99 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Fri, 7 Aug 2026 16:07:40 +0200 Subject: [PATCH 055/109] schedule: ll: support negative task priorities Change LL task priorities and scheduler initialization interfaces from uint16_t to int16_t. Lower numeric values continue to represent higher priorities, so existing task ordering remains unchanged. Pipelines can use priority 0. The signed range allows the IPC4 trigger tasks introduced by the following commit to use priority -1 and run before all pipeline copy tasks. Signed-off-by: Serhiy Katsyuba --- posix/include/rtos/task.h | 2 +- src/include/sof/schedule/ll_schedule.h | 4 ++-- src/include/sof/schedule/schedule.h | 2 +- src/platform/library/include/platform/lib/ll_schedule.h | 2 +- src/platform/library/schedule/ll_schedule.c | 2 +- src/platform/library/schedule/schedule.c | 2 +- src/schedule/ll_schedule_xtos.c | 2 +- src/schedule/schedule.c | 2 +- src/schedule/zephyr_ll.c | 6 +++--- test/cmocka/src/common_mocks.c | 4 ++-- zephyr/include/rtos/task.h | 2 +- zephyr/test/userspace/test_ll_task.c | 3 ++- 12 files changed, 17 insertions(+), 16 deletions(-) diff --git a/posix/include/rtos/task.h b/posix/include/rtos/task.h index bb09ac63bac4..f73384b3cd58 100644 --- a/posix/include/rtos/task.h +++ b/posix/include/rtos/task.h @@ -58,7 +58,7 @@ struct task { uint64_t start; /**< start time in [ms] since now (LL only) */ const struct sof_uuid_entry *uid; /**< Uuid */ uint16_t type; /**< type of the task (LL or EDF) */ - uint16_t priority; /**< priority of the task (used by LL) */ + int16_t priority; /**< priority of the task (used by LL); lower runs first */ uint16_t core; /**< execution core */ uint16_t flags; /**< custom flags */ struct schedule_data *sch; /**< scheduler bound to task */ diff --git a/src/include/sof/schedule/ll_schedule.h b/src/include/sof/schedule/ll_schedule.h index 241a20daff40..b5baccfe3ab7 100644 --- a/src/include/sof/schedule/ll_schedule.h +++ b/src/include/sof/schedule/ll_schedule.h @@ -40,14 +40,14 @@ int scheduler_init_ll(struct ll_schedule_domain *domain); int schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags); #else int zephyr_ll_scheduler_init(struct ll_schedule_domain *domain); int zephyr_ll_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags); #define scheduler_init_ll zephyr_ll_scheduler_init diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index a68169736ef2..32b09f24f473 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -359,7 +359,7 @@ static inline struct k_thread *scheduler_init_context(struct task *task) */ int schedule_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags); /** diff --git a/src/platform/library/include/platform/lib/ll_schedule.h b/src/platform/library/include/platform/lib/ll_schedule.h index 06c918b84fdc..b5ba7f94da6a 100644 --- a/src/platform/library/include/platform/lib/ll_schedule.h +++ b/src/platform/library/include/platform/lib/ll_schedule.h @@ -19,7 +19,7 @@ int scheduler_init_ll(struct ll_schedule_domain *domain); int schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags); #endif /* __LIBRARY_INCLUDE_LIB_SCHEDULE_H__ */ diff --git a/src/platform/library/schedule/ll_schedule.c b/src/platform/library/schedule/ll_schedule.c index 1bfc378ffad2..b81d576f0de3 100644 --- a/src/platform/library/schedule/ll_schedule.c +++ b/src/platform/library/schedule/ll_schedule.c @@ -105,7 +105,7 @@ static struct scheduler_ops schedule_ll_ops = { int schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { return schedule_task_init(task, uid, SOF_SCHEDULE_LL_TIMER, 0, run, diff --git a/src/platform/library/schedule/schedule.c b/src/platform/library/schedule/schedule.c index f110711afe35..ea4cc33608ac 100644 --- a/src/platform/library/schedule/schedule.c +++ b/src/platform/library/schedule/schedule.c @@ -22,7 +22,7 @@ struct schedulers **arch_schedulers_get(void) int schedule_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { struct schedulers *schedulers = *arch_schedulers_get(); diff --git a/src/schedule/ll_schedule_xtos.c b/src/schedule/ll_schedule_xtos.c index 0df3cc9a271d..704a680e144d 100644 --- a/src/schedule/ll_schedule_xtos.c +++ b/src/schedule/ll_schedule_xtos.c @@ -609,7 +609,7 @@ static int schedule_ll_task_after(void *data, struct task *task, uint64_t start, int schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { struct ll_task_pdata *ll_pdata; diff --git a/src/schedule/schedule.c b/src/schedule/schedule.c index 519b8f144ba6..00ba29d1f9f0 100644 --- a/src/schedule/schedule.c +++ b/src/schedule/schedule.c @@ -35,7 +35,7 @@ static inline bool scheduler_is_user(int type) int schedule_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { struct schedulers *schedulers; diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 145416afad3e..e7a72e6db028 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -163,8 +163,8 @@ static void zephyr_ll_task_insert_unlocked(struct zephyr_ll *sch, struct task *t /* * Tasks are added into the list in priority order. List order - * defines schedule order. Priority 0 indicates highest - * priority and is run first. Tasks with the same priority are + * defines schedule order. Lower values indicate higher priority + * and run first. Tasks with the same priority are * served on a first-come-first-served basis. */ list_for_item(list, &sch->tasks) { @@ -778,7 +778,7 @@ void user_ll_unlock_sched(int core) int zephyr_ll_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { struct zephyr_ll_pdata *pdata; diff --git a/test/cmocka/src/common_mocks.c b/test/cmocka/src/common_mocks.c index 2c2867346293..633108a0730e 100644 --- a/test/cmocka/src/common_mocks.c +++ b/test/cmocka/src/common_mocks.c @@ -312,7 +312,7 @@ struct schedulers ** WEAK arch_schedulers_get(void) int WEAK schedule_task_init(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { (void)task; @@ -329,7 +329,7 @@ int WEAK schedule_task_init(struct task *task, int WEAK schedule_task_init_ll(struct task *task, const struct sof_uuid_entry *uid, uint16_t type, - uint16_t priority, enum task_state (*run)(void *data), + int16_t priority, enum task_state (*run)(void *data), void *data, uint16_t core, uint32_t flags) { return 0; diff --git a/zephyr/include/rtos/task.h b/zephyr/include/rtos/task.h index cfcba9130cef..82fedcfff9fa 100644 --- a/zephyr/include/rtos/task.h +++ b/zephyr/include/rtos/task.h @@ -57,7 +57,7 @@ struct task { uint64_t start; /**< start time in [ms] since now (LL only) */ const struct sof_uuid_entry *uid; /**< Uuid */ uint16_t type; /**< type of the task (LL or EDF) */ - uint16_t priority; /**< priority of the task (used by LL) */ + int16_t priority; /**< priority of the task (used by LL); lower runs first */ uint16_t core; /**< execution core */ uint16_t flags; /**< custom flags */ struct schedule_data *sch; /**< scheduler bound to task */ diff --git a/zephyr/test/userspace/test_ll_task.c b/zephyr/test/userspace/test_ll_task.c index 234423defc60..1e31e01538b7 100644 --- a/zephyr/test/userspace/test_ll_task.c +++ b/zephyr/test/userspace/test_ll_task.c @@ -49,7 +49,7 @@ static enum task_state task_callback(void *arg) static void ll_task_test(void) { struct task *task; - int priority = 0; + int16_t priority = -1; int core = 0; int ret; @@ -67,6 +67,7 @@ static void ll_task_test(void) priority, task_callback, (void *)&test_runs, core, 0); zassert_equal(ret, 0); + zassert_equal(task->priority, priority, "negative priority was not preserved"); LOG_INF("task init done"); From 002e4991baa05049e8b44331ca25c2b9203d4831 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Wed, 12 Aug 2026 13:09:21 +0200 Subject: [PATCH 056/109] ipc4: pipeline: split trigger and copy processing Split IPC4 LL pipeline processing into two tasks: * A one-shot trigger task that normally returns TASK_COMPLETED, causing the LL scheduler to remove it from its task list. It is not strictly one-shot, as it can be rescheduled to support delayed triggers. * A copy task, with almost no changes to the existing implementation. When a pipeline starts, both tasks are added to the LL scheduler. Trigger tasks are appended with the highest priority, -1, regardless of their pipeline priority. They are therefore added in IPC order and run before any LL copy tasks. Copy tasks are added as before, respecting their pipeline priorities. Once a trigger task has completed, it returns TASK_COMPLETED and is removed from the LL scheduler's task list. The copy task is prevented from copying while its trigger task remains on the LL scheduler's list to support delayed triggering. When stopping a pipeline, only the trigger task needs to be added because the copy task is already scheduled. Once the trigger task changes the pipeline state to paused, both tasks return TASK_COMPLETED and are removed from the scheduler's task list. Separating trigger and copy processing preserves the pipeline trigger order specified by a multi-pipeline-set-state IPC, regardless of pipeline priorities, while allowing copy tasks to run according to pipeline priorities. This makes the blocking wait introduced by commit c5d638a74f9d ("ipc4: handler: maintain IPC set_pipeline_state order") unnecessary. Signed-off-by: Serhiy Katsyuba --- src/audio/pipeline/pipeline-graph.c | 7 +- src/audio/pipeline/pipeline-schedule.c | 197 ++++++++++++++++++++++++- src/include/sof/audio/pipeline.h | 11 +- uuid-registry.txt | 1 + 4 files changed, 201 insertions(+), 15 deletions(-) diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 6e154dfbfba6..c6665cb4d08c 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -260,12 +260,7 @@ int pipeline_free(struct pipeline *p) */ /* remove from any scheduling */ - if (p->pipe_task) { -#if !CONFIG_LIBRARY || UNIT_TEST - schedule_task_free(p->pipe_task); -#endif - sof_heap_free(p->heap, p->pipe_task); - } + pipeline_comp_ll_task_free(p); ipc_msg_free(p->msg); diff --git a/src/audio/pipeline/pipeline-schedule.c b/src/audio/pipeline/pipeline-schedule.c index eee3b2c406d7..b62b4eda6c0f 100644 --- a/src/audio/pipeline/pipeline-schedule.c +++ b/src/audio/pipeline/pipeline-schedule.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -34,6 +35,16 @@ LOG_MODULE_DECLARE(pipe, CONFIG_SOF_LOG_LEVEL); SOF_DEFINE_REG_UUID(pipe_task); +#ifdef CONFIG_IPC_MAJOR_4 +SOF_DEFINE_REG_UUID(pipe_trigger_task); + +/* + * Track a delayed trigger so later trigger tasks cannot overtake + * it and change the pipeline order requested by the host. + */ +static APP_SYSUSER_BSS struct pipeline *delayed_trigger_owner[CONFIG_CORE_COUNT]; +#endif + #if CONFIG_ZEPHYR_DP_SCHEDULER SOF_DEFINE_REG_UUID(dp_task); @@ -160,7 +171,9 @@ static enum task_state pipeline_task_cmd(struct pipeline *p, return err; } -static enum task_state pipeline_task(void *arg) +#ifndef CONFIG_IPC_MAJOR_4 +/** Run IPC3 pipeline trigger and copy processing. */ +static enum task_state ipc3_pipeline_task(void *arg) { struct sof_ipc_reply reply = { .hdr.cmd = SOF_IPC_GLB_REPLY, @@ -239,6 +252,120 @@ static enum task_state pipeline_task(void *arg) return SOF_TASK_STATE_RESCHEDULE; } +#else /* CONFIG_IPC_MAJOR_4 */ + +/** Run an IPC4 pipeline trigger task. */ +static enum task_state ipc4_pipeline_trigger_task(void *arg) +{ + struct sof_ipc_reply reply = { + .hdr.cmd = SOF_IPC_GLB_REPLY, + .hdr.size = sizeof(reply), + }; + struct pipeline *p = arg; + enum task_state state; + struct pipeline *owner = delayed_trigger_owner[p->core]; + + /* some other trigger task is still waiting for its delayed trigger */ + if (owner && owner != p) + return SOF_TASK_STATE_RESCHEDULE; + + if (p->xrun_bytes) { + delayed_trigger_owner[p->core] = NULL; + + if (p->trigger.cmd != COMP_TRIGGER_NO_ACTION) { + p->trigger.cmd = COMP_TRIGGER_NO_ACTION; + reply.error = -EPIPE; + ipc_msg_reply(&reply); + } + + return SOF_TASK_STATE_COMPLETED; + } + + if (p->trigger.delay) { + delayed_trigger_owner[p->core] = p; + p->trigger.delay--; + return SOF_TASK_STATE_RESCHEDULE; + } + + if (p->trigger.cmd == COMP_TRIGGER_NO_ACTION) { + delayed_trigger_owner[p->core] = NULL; + return SOF_TASK_STATE_COMPLETED; + } + + state = pipeline_task_cmd(p, &reply); + if (state == SOF_TASK_STATE_RESCHEDULE && p->trigger.delay) { + delayed_trigger_owner[p->core] = p; + return state; + } + + delayed_trigger_owner[p->core] = NULL; + + /* RUNNING means that the independent copy task should keep running. */ + return state == SOF_TASK_STATE_RUNNING ? SOF_TASK_STATE_COMPLETED : state; +} + +/** Run IPC4 pipeline copy processing. */ +static enum task_state ipc4_pipeline_copy_task(void *arg) +{ + struct pipeline *p = arg; + int err; + + pipe_dbg(p, "entry"); + + /* are we in xrun ? */ + if (p->xrun_bytes) { + /* try to recover */ + err = pipeline_xrun_recover(p); + if (err < 0) + /* skip copy if still in xrun */ + return SOF_TASK_STATE_COMPLETED; + } + + /* Do not copy until the pipeline trigger sequence has completed. */ + if (task_is_active(p->trigger_task)) + return SOF_TASK_STATE_RESCHEDULE; + + if (p->status == COMP_STATE_PAUSED) + return SOF_TASK_STATE_COMPLETED; + + err = pipeline_copy(p); + if (err < 0) { + /* try to recover */ + err = pipeline_xrun_recover(p); + if (err < 0) { + pipe_err(p, "xrun recovery failed! pipeline is stopped."); + /* failed - host will stop this pipeline */ + return SOF_TASK_STATE_COMPLETED; + } + } + + pipe_dbg(p, "sched"); + + return SOF_TASK_STATE_RESCHEDULE; +} + +/** Allocate and initialize an IPC4 pipeline trigger task. */ +static struct task *ipc4_pipeline_trigger_task_init(struct pipeline *p, uint32_t type) +{ + struct task *task; + + task = sof_heap_alloc(p->heap, SOF_MEM_FLAG_USER, sizeof(*task), 0); + if (!task) + return NULL; + + memset(task, 0, sizeof(*task)); + + /* All trigger tasks use the highest priority, regardless of pipeline priority. */ + if (schedule_task_init_ll(task, SOF_UUID(pipe_trigger_task_uuid), type, -1, + ipc4_pipeline_trigger_task, p, p->core, 0) < 0) { + sof_heap_free(p->heap, task); + return NULL; + } + + return task; +} +#endif /* CONFIG_IPC_MAJOR_4 */ + static struct task *pipeline_task_init(struct pipeline *p, uint32_t type) { struct pipeline_task *task = NULL; @@ -251,7 +378,12 @@ static struct task *pipeline_task_init(struct pipeline *p, uint32_t type) memset(task, 0, sizeof(*task)); if (schedule_task_init_ll(&task->task, SOF_UUID(pipe_task_uuid), type, - p->priority, pipeline_task, + p->priority, +#ifdef CONFIG_IPC_MAJOR_4 + ipc4_pipeline_copy_task, +#else + ipc3_pipeline_task, +#endif p, p->core, 0) < 0) { sof_heap_free(p->heap, task); return NULL; @@ -325,6 +457,10 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, p->trigger.pending = true; p->trigger.host = ppl_data->start; ppl_data->start = NULL; +#ifdef CONFIG_IPC_MAJOR_4 + if (schedule_task(p->trigger_task, 0, 0) < 0) + pipe_err(p, "failed to schedule trigger task"); +#endif } else { pipeline_schedule_cancel(p); p->status = COMP_STATE_PAUSED; @@ -346,6 +482,10 @@ void pipeline_schedule_triggered(struct pipeline_walk_context *ctx, p->trigger.pending = true; p->trigger.host = ppl_data->start; ppl_data->start = NULL; +#ifdef CONFIG_IPC_MAJOR_4 + if (schedule_task(p->trigger_task, 0, 0) < 0) + pipe_err(p, "failed to schedule trigger task"); +#endif } else { p->status = COMP_STATE_ACTIVE; } @@ -374,14 +514,24 @@ int pipeline_comp_ll_task_init(struct pipeline *p) { uint32_t type; + /* right now we always consider pipeline as a low latency + * component, but it may change in the future + */ + type = pipeline_is_timer_driven(p) ? SOF_SCHEDULE_LL_TIMER : + SOF_SCHEDULE_LL_DMA; + +#ifdef CONFIG_IPC_MAJOR_4 + if (!p->trigger_task) { + p->trigger_task = ipc4_pipeline_trigger_task_init(p, type); + if (!p->trigger_task) { + pipe_err(p, "trigger task init failed"); + return -ENOMEM; + } + } +#endif + /* initialize task if necessary */ if (!p->pipe_task) { - /* right now we always consider pipeline as a low latency - * component, but it may change in the future - */ - type = pipeline_is_timer_driven(p) ? SOF_SCHEDULE_LL_TIMER : - SOF_SCHEDULE_LL_DMA; - p->pipe_task = pipeline_task_init(p, type); if (!p->pipe_task) { pipe_err(p, "task init failed"); @@ -392,6 +542,37 @@ int pipeline_comp_ll_task_init(struct pipeline *p) return 0; } +/** Free pipeline LL tasks and release delayed-trigger ownership. */ +void pipeline_comp_ll_task_free(struct pipeline *p) +{ +#ifdef CONFIG_IPC_MAJOR_4 + if (p->trigger_task) { +#if !CONFIG_LIBRARY || UNIT_TEST + schedule_task_free(p->trigger_task); +#endif + } + + /* + * Since the task has now been removed from the scheduler, a possible race + * with LL between the check and store below cannot cause any harm: other + * tasks do nothing when they see another owner. Therefore, LL locking can + * be skipped here. + */ + if (delayed_trigger_owner[p->core] == p) + delayed_trigger_owner[p->core] = NULL; + + if (p->trigger_task) + sof_heap_free(p->heap, p->trigger_task); +#endif + + if (p->pipe_task) { +#if !CONFIG_LIBRARY || UNIT_TEST + schedule_task_free(p->pipe_task); +#endif + sof_heap_free(p->heap, p->pipe_task); + } +} + #if CONFIG_ZEPHYR_DP_SCHEDULER static enum task_state dp_task_run(void *data) { diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 913a569c208c..6d6202ae9fae 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -73,7 +73,10 @@ struct pipeline { bool expect_eos; /* pipeline is expecting end of stream */ /* scheduling */ - struct task *pipe_task; /* pipeline processing task */ +#ifdef CONFIG_IPC_MAJOR_4 + struct task *trigger_task; /* IPC4 pipeline trigger task */ +#endif + struct task *pipe_task; /* IPC3 pipeline processing task or IPC4 pipeline copy task */ struct pipeline *sched_next; /* pipeline scheduled after this */ struct pipeline *sched_prev; /* pipeline scheduled before this */ @@ -361,6 +364,12 @@ static inline bool pipeline_is_this_cpu(struct pipeline *p) */ int pipeline_comp_ll_task_init(struct pipeline *p); +/** + * \brief Free the LL tasks owned by a pipeline. + * \param[in] p pipeline. + */ +void pipeline_comp_ll_task_free(struct pipeline *p); + /** * \brief Init a DP task for a component * \param[in] comp a component the task is created for diff --git a/uuid-registry.txt b/uuid-registry.txt index e9e8f8e77876..04c4a3881b21 100644 --- a/uuid-registry.txt +++ b/uuid-registry.txt @@ -136,6 +136,7 @@ f36BF24B-9AAF-83f4-8677E072E8AEADB7 notification_pool 09fbcb7a-a9c5-4a57-84344440e598ab24 phase_vocoder 4e934adb-b0ec-4d33-a086c1022f921321 pipe f11818eb-e92e-4082-82a3dc54c604ebb3 pipe_task +069b6fab-ae56-432f-8f4285ce63ea98bf pipe_trigger_task d7f6712d-131c-45a7-82ed6aa9dc2291ea pm_runtime 76cc9773-440c-4df9-95a872defe7796fc power 9d1fb66e-4ffb-497f-994b17719686596e probe From 6a61c48ef09e433ecf9ba76f9794c941bc281de6 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 13 Aug 2026 11:39:52 +0200 Subject: [PATCH 057/109] Revert "ipc4: handler: maintain IPC set_pipeline_state order" This reverts commit 05bffd7e306e5febba1866724e2f7f28c56cd471. Signed-off-by: Serhiy Katsyuba --- src/ipc/ipc4/handler-user.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 5888b007ed42..592ac053e570 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -575,17 +575,6 @@ int ipc4_set_pipeline_state(struct ipc4_message_request *ipc4) ipc_compound_pre_start(state.primary.r.type); ret = ipc4_pipeline_trigger(ppl_icd, cmd, &delayed); ipc_compound_post_start(state.primary.r.type, ret, delayed); - if (delayed) { - /* To maintain pipeline order for triggers, we must - * do a blocking wait until trigger is processed. - * This will add a max delay of 'ppl_count' LL ticks - * to process the full trigger list. - */ - if (ipc_wait_for_compound_msg() != 0) { - ipc_cmd_err(&ipc_tr, "ipc4: fail with delayed trigger"); - return IPC4_FAILURE; - } - } } if (ret != 0) From 12dd7265291cc23e6130377f09f0e713ded9d465 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Thu, 13 Aug 2026 21:08:47 +0200 Subject: [PATCH 058/109] ipc4: helper: reject invalid pipeline core ID Validate the requested core ID before dispatching pipeline creation. This prevents an out-of-bounds access found by IPC4 fuzzing. Signed-off-by: Serhiy Katsyuba --- src/ipc/ipc4/helper.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index f1e112fb37ea..988da04c5f15 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -531,6 +531,12 @@ __cold int ipc_pipeline_new(struct ipc *ipc, ipc_pipe_new *_pipe_desc) tr_dbg(&ipc_tr, "ipc: pipeline id = %u", (uint32_t)pipe_desc->primary.r.instance_id); + if (pipe_desc->extension.r.core_id >= CONFIG_CORE_COUNT) { + tr_err(&ipc_tr, "invalid pipeline core ID: %u", + (uint32_t)pipe_desc->extension.r.core_id); + return IPC4_INVALID_CORE_ID; + } + /* pass IPC to target core */ if (!cpu_is_me(pipe_desc->extension.r.core_id)) return ipc4_process_on_core(pipe_desc->extension.r.core_id, false); From ae07410b20944dd35380c9cd315b263ff57ed866 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 18 Aug 2026 11:35:08 +0200 Subject: [PATCH 059/109] ipc: ipc4: remove a memcpy() in MOD_INIT_INSTANCE Use a type-cast instead of a memcpy() to obtain struct ipc4_module_init_instance data. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc4/handler-user.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ipc/ipc4/handler-user.c b/src/ipc/ipc4/handler-user.c index 592ac053e570..12f1234aef7a 100644 --- a/src/ipc/ipc4/handler-user.c +++ b/src/ipc/ipc4/handler-user.c @@ -1502,28 +1502,25 @@ __cold int ipc4_user_process_module_message(struct ipc4_message_request *ipc4, case SOF_IPC4_MOD_INIT_INSTANCE: #ifdef CONFIG_SOF_USERSPACE_LL { + BUILD_ASSERT(sizeof(struct comp_driver) + sizeof(struct tr_ctx) <= + sizeof(((struct ipc_user *)0)->init_drv_data), + "ipc_user.init_drv_data too small for driver copy"); + /* User-space init: kernel does driver lookup only (requires * access to IMR manifest and driver list in kernel memory). * Component creation (drv->ops.create) runs in user thread * so untrusted module code does not execute in kernel context. * Cross-core creation stays fully in kernel. */ - struct ipc4_module_init_instance mi; - - BUILD_ASSERT(sizeof(struct comp_driver) + sizeof(struct tr_ctx) <= - sizeof(((struct ipc_user *)0)->init_drv_data), - "ipc_user.init_drv_data too small for driver copy"); - - ret = memcpy_s(&mi, sizeof(mi), ipc4, sizeof(*ipc4)); - if (ret < 0) - break; + const struct ipc4_module_init_instance *mi = + (const struct ipc4_module_init_instance *)ipc4; - if (!cpu_is_me(mi.extension.r.core_id)) { + if (!cpu_is_me(mi->extension.r.core_id)) { ret = ipc4_init_module_instance(ipc4); } else { struct ipc *ipc = ipc_get(); - uint32_t comp_id = IPC4_COMP_ID(mi.primary.r.module_id, - mi.primary.r.instance_id); + uint32_t comp_id = IPC4_COMP_ID(mi->primary.r.module_id, + mi->primary.r.instance_id); const struct comp_driver *drv = ipc4_get_comp_drv( IPC4_MOD_ID(comp_id)); struct ipc_user *pdata = ipc->ipc_user_pdata; From e99bda34ff7668fd2b7fa1ca1d0b25e503a27f44 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 09:26:48 +0200 Subject: [PATCH 060/109] ipc: (cosmetic) compact several lines Join several needlessly broken lines. Signed-off-by: Guennadi Liakhovetski --- src/ipc/ipc-helper.c | 21 +++++++-------------- src/ipc/ipc4/helper.c | 43 ++++++++++++++----------------------------- 2 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/ipc/ipc-helper.c b/src/ipc/ipc-helper.c index 567255a9e22a..4c46d104856f 100644 --- a/src/ipc/ipc-helper.c +++ b/src/ipc/ipc-helper.c @@ -82,8 +82,7 @@ __cold struct comp_buffer *buffer_new(struct mod_alloc_ctx *alloc, #endif /* allocate buffer */ - buffer = buffer_alloc(alloc, desc->size, flags, PLATFORM_DCACHE_ALIGN, - is_shared); + buffer = buffer_alloc(alloc, desc->size, flags, PLATFORM_DCACHE_ALIGN, is_shared); if (buffer) { buffer->stream.runtime_stream_params.id = desc->comp.id; buffer->stream.runtime_stream_params.pipeline_id = desc->comp.pipeline_id; @@ -188,14 +187,12 @@ int comp_verify_params(struct comp_dev *dev, uint32_t flag, if (dir == PPL_DIR_DOWNSTREAM) { comp_dev_for_each_consumer(dev, buf) { comp_update_params(flag, params, buf); - buffer_set_params(buf, params, - BUFFER_UPDATE_FORCE); + buffer_set_params(buf, params, BUFFER_UPDATE_FORCE); } } else { comp_dev_for_each_producer(dev, buf) { comp_update_params(flag, params, buf); - buffer_set_params(buf, params, - BUFFER_UPDATE_FORCE); + buffer_set_params(buf, params, BUFFER_UPDATE_FORCE); } } @@ -284,11 +281,9 @@ int ipc_pipeline_complete(struct ipc *ipc, uint32_t comp_id) pipeline_id = ipc_pipe->pipeline->pipeline_id; - tr_dbg(&ipc_tr, "ipc: pipe %d -> complete on comp 0x%x", pipeline_id, - comp_id); + tr_dbg(&ipc_tr, "ipc: pipe %d -> complete on comp 0x%x", pipeline_id, comp_id); - return pipeline_complete(ipc_pipe->pipeline, ipc_ppl_source->cd, - ipc_ppl_sink->cd); + return pipeline_complete(ipc_pipe->pipeline, ipc_ppl_source->cd, ipc_ppl_sink->cd); } __cold int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) @@ -306,8 +301,7 @@ __cold int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) /* check whether component exists */ icd = ipc_get_comp_by_id(ipc, comp_id); if (!icd) { - tr_err(&ipc_tr, "comp id: 0x%x is not found", - comp_id); + tr_err(&ipc_tr, "comp id: 0x%x is not found", comp_id); return -ENODEV; } @@ -336,8 +330,7 @@ __cold int ipc_comp_free(struct ipc *ipc, uint32_t comp_id) * leak on error. Bug-free host drivers won't do * this, this was found via fuzzing. */ - tr_err(&ipc_tr, "uninitialized buffer lists on comp 0x%x\n", - icd->id); + tr_err(&ipc_tr, "uninitialized buffer lists on comp 0x%x\n", icd->id); return -EINVAL; } diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 988da04c5f15..93fc69ef89db 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -295,9 +295,7 @@ __cold struct comp_dev *comp_new_ipc4_user(struct ipc4_message_request *ipc4, ipc_config.proc_domain = COMP_PROCESSING_DOMAIN_LL; #else if (module_init.extension.r.proc_domain) { - tr_err(&ipc_tr, - "ipc: DP scheduling is disabled, cannot create comp 0x%x", - comp_id); + tr_err(&ipc_tr, "ipc: DP scheduling is disabled, cannot create comp 0x%x", comp_id); return NULL; } ipc_config.proc_domain = COMP_PROCESSING_DOMAIN_LL; @@ -1172,8 +1170,7 @@ __cold int ipc4_chain_manager_create(const struct ipc4_chain_dma *cdma) const uint32_t comp_id = IPC4_COMP_ID(cdma->primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT, 0); dev->ipc_config.id = comp_id; - dev->ipc_config.pipeline_id = cdma->primary.r.host_dma_id - + IPC4_MAX_MODULE_COUNT; + dev->ipc_config.pipeline_id = cdma->primary.r.host_dma_id + IPC4_MAX_MODULE_COUNT; return ipc4_add_comp_dev(dev); } @@ -1315,13 +1312,10 @@ __cold static const struct comp_driver *ipc4_search_for_drv(const void *uuid) /* search driver list with UUID */ list_for_item(clist, &drivers->list) { - info = container_of(clist, struct comp_driver_info, - list); + info = container_of(clist, struct comp_driver_info, list); if (!memcmp(info->drv->uid, uuid, UUID_SIZE)) { - tr_dbg(&comp_tr, - "found type %d, uuid %pU", - info->drv->type, - info->drv->tctx->uuid_p); + tr_dbg(&comp_tr, "found type %d, uuid %pU", + info->drv->type, info->drv->tctx->uuid_p); drv = info->drv; break; } @@ -1403,8 +1397,7 @@ static const struct comp_driver *ipc4_get_fuzzer_drv(uint32_t module_id) return inf->drv; } - tr_err(&comp_tr, - "no instantiable driver at module_id %u (%u available)", + tr_err(&comp_tr, "no instantiable driver at module_id %u (%u available)", module_id, idx); return NULL; } @@ -1648,10 +1641,8 @@ void ipc4_audio_format_to_stream_params(const struct ipc4_audio_format *audio_fm params->sample_valid_bytes = audio_fmt->valid_bit_depth / 8; params->buffer_fmt = audio_fmt->interleaving_style; - audio_stream_fmt_conversion(audio_fmt->depth, - audio_fmt->valid_bit_depth, - &frame_fmt, &valid_fmt, - audio_fmt->s_type); + audio_stream_fmt_conversion(audio_fmt->depth, audio_fmt->valid_bit_depth, + &frame_fmt, &valid_fmt, audio_fmt->s_type); params->frame_fmt = frame_fmt; for (i = 0; i < SOF_IPC_MAX_CHANNELS; i++) @@ -1676,10 +1667,8 @@ void ipc4_update_buffer_format(struct comp_buffer *buf_c, audio_stream_set_channels(&buf_c->stream, fmt->channels_count); audio_stream_set_rate(&buf_c->stream, fmt->sampling_frequency); - audio_stream_fmt_conversion(fmt->depth, - fmt->valid_bit_depth, - &frame_fmt, &valid_fmt, - fmt->s_type); + audio_stream_fmt_conversion(fmt->depth, fmt->valid_bit_depth, + &frame_fmt, &valid_fmt, fmt->s_type); audio_stream_set_frm_fmt(&buf_c->stream, frame_fmt); audio_stream_set_valid_fmt(&buf_c->stream, valid_fmt); @@ -1698,10 +1687,8 @@ void ipc4_update_source_format(struct sof_source *source, source_set_channels(source, fmt->channels_count); source_set_rate(source, fmt->sampling_frequency); - audio_stream_fmt_conversion(fmt->depth, - fmt->valid_bit_depth, - &frame_fmt, &valid_fmt, - fmt->s_type); + audio_stream_fmt_conversion(fmt->depth, fmt->valid_bit_depth, + &frame_fmt, &valid_fmt, fmt->s_type); source_set_frm_fmt(source, frame_fmt); source_set_valid_fmt(source, valid_fmt); @@ -1716,10 +1703,8 @@ void ipc4_update_sink_format(struct sof_sink *sink, sink_set_channels(sink, fmt->channels_count); sink_set_rate(sink, fmt->sampling_frequency); - audio_stream_fmt_conversion(fmt->depth, - fmt->valid_bit_depth, - &frame_fmt, &valid_fmt, - fmt->s_type); + audio_stream_fmt_conversion(fmt->depth, fmt->valid_bit_depth, + &frame_fmt, &valid_fmt, fmt->s_type); sink_set_frm_fmt(sink, frame_fmt); sink_set_valid_fmt(sink, valid_fmt); From 6fb963f06ecf22da3974d7401eb9f5d2ef69ef2f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 21 Aug 2026 10:25:50 +0200 Subject: [PATCH 061/109] audio: module-adapter: (cosmetic) remove unused macros PAGE_SZ isn't used any more in module_adapter.c, remove the definisions. Signed-off-by: Guennadi Liakhovetski --- src/audio/module_adapter/module_adapter.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index a2b293e4ad0d..995501bfbe0a 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -51,13 +51,6 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, return module_adapter_new_ext(drv, config, spec, NULL, NULL, NULL); } -#if CONFIG_MM_DRV -#define PAGE_SZ CONFIG_MM_DRV_PAGE_SIZE -#else -#include -#define PAGE_SZ HOST_PAGE_SIZE -#endif - static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config, size_t *heap_size) { From 71c6dfd3b9a7d11a4bf96f7de50503e3482503ff Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 13 Aug 2026 15:26:31 +0300 Subject: [PATCH 062/109] topology2: Add the UAOL DAI type The USB Audio Offload Link is an ACE2+ alt link. The firmware enumerates its gateways in the ALH class family, but the ALH DAI class carries SoundWire specific attributes, so UAOL is described by a DAI class of its own. Allow "UAOL" as a dai type and as a copier type, and let the dai-copier take the two UAOL node types which common_definitions.conf already defines. Signed-off-by: Peter Ujfalusi --- .../include/components/dai-copier.conf | 4 + .../topology2/include/components/dai.conf | 1 + .../topology/topology2/include/dais/uaol.conf | 95 +++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 tools/topology/topology2/include/dais/uaol.conf diff --git a/tools/topology/topology2/include/components/dai-copier.conf b/tools/topology/topology2/include/components/dai-copier.conf index e5508ada3df5..3b97ff0b4adf 100644 --- a/tools/topology/topology2/include/components/dai-copier.conf +++ b/tools/topology/topology2/include/components/dai-copier.conf @@ -44,6 +44,7 @@ Class.Widget."dai-copier" { "HDA" "SSP" "DMIC" + "UAOL" "SAI" ] } @@ -57,6 +58,7 @@ Class.Widget."dai-copier" { "SSP" "DMIC" "HDA" + "UAOL" "SAI" ] } @@ -103,6 +105,8 @@ Class.Widget."dai-copier" { $DMIC_LINK_INPUT_CLASS # DMIC link input (DSP <-) $I2S_LINK_OUTPUT_CLASS # I2S link output (DSP ->) $I2S_LINK_INPUT_CLASS # I2S link input (DSP <-) + $ALH_UAOL_STREAM_LINK_OUTPUT_CLASS # UAOL link output (DSP ->) + $ALH_UAOL_STREAM_LINK_INPUT_CLASS # UAOL link input (DSP <-) $IPC_OUTPUT_CLASS # IPC output (DSP ->) $IPC_INPUT_CLASS # IPC input (DSP <-) $I2S_MULTILINK_OUTPUT_CLASS # I2S Multi gtw output (DSP ->) diff --git a/tools/topology/topology2/include/components/dai.conf b/tools/topology/topology2/include/components/dai.conf index 4a34594b5eb0..41f884b4e9f9 100644 --- a/tools/topology/topology2/include/components/dai.conf +++ b/tools/topology/topology2/include/components/dai.conf @@ -28,6 +28,7 @@ Class.Widget."dai" { "DMIC" "HDA" "ALH" + "UAOL" "SAI" "ESAI" ] diff --git a/tools/topology/topology2/include/dais/uaol.conf b/tools/topology/topology2/include/dais/uaol.conf new file mode 100644 index 000000000000..56d8dd726481 --- /dev/null +++ b/tools/topology/topology2/include/dais/uaol.conf @@ -0,0 +1,95 @@ +# +# UAOL DAI +# +# All attributes defined herein are namespaced by alsatplg to +# "Object.Dai.UAOL.attribute_name" +# +# UAOL (USB Audio Offload Link) is an ACE2+ alt link. It belongs to the ALH +# class family in the firmware gateway enumeration, but it is described by its +# own DAI class because the ALH class carries SoundWire specific attributes. +# +# Usage: this component can be used by declaring as follows: +# +# For Playback +#Object.Dai.UAOL."N" { +# direction "playback" +# name "UAOL0" +# id 0 +# Object.Base.hw_config."0" {} +# } +# For Capture +#Object.Dai.UAOL."N" { +# direction "capture" +# name "UAOL0" +# id 0 +# Object.Base.hw_config."1" {} +# } +# +# Where N is the dai index of the UAOL DAI in the firmware + +Class.Dai."UAOL" { + # + # instance ID of UAOL DAI object + # + DefineAttribute."instance" {} + + # + # UAOL link index in the firmware + # + DefineAttribute."dai_index" { + token_ref "dai.word" + } + + DefineAttribute."direction" { + type "string" + constraints { + !valid_values [ + "playback" + "capture" + "duplex" + ] + } + } + + # type of DAI + DefineAttribute.dai_type { + type "string" + token_ref "dai.string" + } + + # Backend DAI Link ID matching with the machine driver + DefineAttribute.id {} + + DefineAttribute."default_hw_config_id" {} + + DefineAttribute.name { + type "string" + } + + DefineAttribute.rate {} + + DefineAttribute.ch {} + + attributes { + !constructor [ + "name" + ] + !mandatory [ + "id" + "dai_index" + ] + !immutable [ + "type" + ] + # + # UAOL DAI objects instantiated within the same alsaconf node must + # have unique instance attribute + # + unique "instance" + } + + dai_type "UAOL" + default_hw_config_id 0 + rate 48000 + ch 2 +} From 73c674a74a10919777e089d5f78c00ccb2f32c50 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Thu, 13 Aug 2026 15:26:43 +0300 Subject: [PATCH 063/109] topology2: Add the cavs-uaol function topology The sof_sdw machine driver creates a backend DAI link for the USB Audio Offload Link when the platform reports one. Add the function topology which is loaded next to the other function topologies of that card. The playback path is a mixer based one, so a deep buffer PCM can share the link with the normal playback PCM. The capture path is a straight one with a high pass EQ IIR, matching what the SoundWire jack does, because the number of captured channels follows the USB device while a mixer only handles a fixed channel count. What the link is run at is decided by the USB device that happens to be plugged in, which is not known when the topology is built, so every widget of both paths carries the whole set of formats a USB device may ask for: S16_LE, S24_LE and S32_LE, 1 to 8 channels and the standard rates from 8 to 192 kHz, which is as far as UAOL goes. The kernel narrows the PCM down to what the connected device actually supports. The matrix is spelled out with CombineArrays in include/formats/uaol_*.conf, one file for the wire formats and one for the 32 bit only modules in between. 7 channels is left out, it is the one count in the range with no channel config and no channel map defined. The deep buffer PCM stays at 48 kHz stereo, it comes from the shared platform/intel/deep-buffer.conf, so it can only join the mixer while the normal playback PCM runs at that format, or is not running at all. The two directions are separate DAI links so that the format fixup of a link is decided by the DAI copier of that direction alone. Their names are kept short because alsatplg drops the widget tuples once the generated widget name exceeds 36 characters. The UAOL backend is the last one the machine driver creates, so its DAI link ID depends on the composition of the board. Build the ID variants which the SoundWire boards can produce. Signed-off-by: Peter Ujfalusi --- tools/topology/topology2/README.md | 5 + tools/topology/topology2/cavs-uaol.conf | 86 +++++ .../formats/uaol_input_audio_formats.conf | 344 ++++++++++++++++++ .../formats/uaol_input_audio_formats_s32.conf | 176 +++++++++ .../formats/uaol_output_audio_formats.conf | 344 ++++++++++++++++++ .../uaol_output_audio_formats_s32.conf | 176 +++++++++ .../platform/intel/uaol-generic.conf | 204 +++++++++++ .../tplg-targets-sdca-generic.cmake | 13 + 8 files changed, 1348 insertions(+) create mode 100644 tools/topology/topology2/cavs-uaol.conf create mode 100644 tools/topology/topology2/include/formats/uaol_input_audio_formats.conf create mode 100644 tools/topology/topology2/include/formats/uaol_input_audio_formats_s32.conf create mode 100644 tools/topology/topology2/include/formats/uaol_output_audio_formats.conf create mode 100644 tools/topology/topology2/include/formats/uaol_output_audio_formats_s32.conf create mode 100644 tools/topology/topology2/platform/intel/uaol-generic.conf diff --git a/tools/topology/topology2/README.md b/tools/topology/topology2/README.md index bea7ffcfdcde..759867a47d1c 100644 --- a/tools/topology/topology2/README.md +++ b/tools/topology/topology2/README.md @@ -242,6 +242,8 @@ default ID ranges for the same endpoint types. | Jack Echo Ref | 11 | `SDW_JACK_ECHO_REF_PCM_ID` | | Speaker Echo Ref | 12 | `SDW_SPK_ECHO_REF_PCM_ID` | | Bluetooth | 2 or 20 | `BT_PCM_ID` | +| USB Audio Offload (UAOL) | 21 | `UAOL_PCM_ID` | +| Deepbuffer UAOL | 22 | `DEEP_BUFFER_PCM_ID` | | Deep Buffer (Jack) | 31 | `DEEP_BUFFER_PCM_ID` | | Deep Buffer (Speaker) | 35 | `DEEP_BUFFER_PCM_ID_2` | | DMIC Deep Buffer | 46 | `DMIC0_DEEP_BUFFER_PCM_ID` | @@ -301,6 +303,9 @@ is at N1 (50/51, 60/61, 70/71, 80/81). | HDMI 4 Host / DAI | 80 / 81 | `HDMI4_HOST_PIPELINE_ID` / `HDMI4_DAI_PIPELINE_ID` | | Compress Jack / Speaker | 90 / 92 | `COMPR_PIPELINE_ID` / `COMPR_2_PIPELINE_ID` | | PCH DMIC0 Host / DAI | 100 / 101 | `DMIC0_HOST_PIPELINE_ID` / `DMIC0_DAI_PIPELINE_ID` | +| UAOL Playback Host / DAI | 210 / 211 | `UAOL_PB_HOST_PIPELINE_ID` / `UAOL_PB_DAI_PIPELINE_ID` | +| UAOL Capture Host / DAI | 212 / 213 | `UAOL_CP_HOST_PIPELINE_ID` / `UAOL_CP_DAI_PIPELINE_ID` | +| UAOL Deepbuffer | 214 | `DEEP_BUFFER_PIPELINE_ID` | **Intel HDA Pipeline IDs:** diff --git a/tools/topology/topology2/cavs-uaol.conf b/tools/topology/topology2/cavs-uaol.conf new file mode 100644 index 000000000000..0baa4cb28f74 --- /dev/null +++ b/tools/topology/topology2/cavs-uaol.conf @@ -0,0 +1,86 @@ +# Basic USB Audio Offload Link (UAOL) topology. +# +# This is a function topology, loaded next to the other function topologies of +# the sof_sdw card, so its PCM and pipeline IDs must not collide with theirs. +# +# The UAOL function itself lives in platform/intel/uaol-generic.conf. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Define { + UAOL_PLAYBACK_PCM 'UAOL Playback' + UAOL_CAPTURE_PCM 'UAOL Capture' + # The two directions are separate DAI links so that the format fixup of + # a link is decided by the DAI copier of that direction alone. The names + # are abbreviated because alsatplg drops widget tuples above 36 characters + # and the dai-copier name is 'dai-copier.UAOL..' + UAOL_PB_DAI_NAME 'UAOL0-Play' + UAOL_CP_DAI_NAME 'UAOL0-Cap' + # The BE IDs are the dai link IDs that are matched with the machine + # driver, which creates the playback link first + UAOL_PB_BE_ID 9 + UAOL_CP_BE_ID 10 + # UAOL_DAI_INDEX is the UAOL link the DSP uses, only link 0 is addressable + UAOL_DAI_INDEX 0 + UAOL_PCM_NAME 'UAOL' + UAOL_PCM_ID 21 + UAOL_PB_HOST_PIPELINE_ID 210 + UAOL_PB_DAI_PIPELINE_ID 211 + UAOL_CP_HOST_PIPELINE_ID 212 + UAOL_CP_DAI_PIPELINE_ID 213 + # Both paths pass through whatever the offloaded USB device asks for, so + # the PCM advertises everything a USB device may support. 7 channels is + # left out of the widget formats, it has no channel config and no channel + # map, so it is the one count in the range which cannot be run. + UAOL_CHANNELS_MIN 1 + UAOL_CHANNELS_MAX 8 + # UAOL supports up to 192 kHz + UAOL_RATE_MIN 8000 + UAOL_RATE_MAX 192000 + UAOL_RATES '8000,11025,12000,16000,22050,24000,32000,44100,48000,64000,88200,96000,128000,176400,192000' + + # The deep buffer PCM feeds the same mixer as the normal playback PCM. It + # takes the source and the sink as plain widget names, so it repeats the + # pipeline IDs defined above. + DEEP_BUFFER_PCM_NAME 'Deepbuffer UAOL' + DEEP_BUFFER_PCM_ID 22 + DEEP_BUFFER_PIPELINE_ID 214 + DEEP_BUFFER_PIPELINE_SRC 'mixin.214.1' + DEEP_BUFFER_PIPELINE_SINK 'mixout.211.1' +} + + diff --git a/tools/topology/topology2/include/formats/uaol_input_audio_formats.conf b/tools/topology/topology2/include/formats/uaol_input_audio_formats.conf new file mode 100644 index 000000000000..4a8ca0c0c9f0 --- /dev/null +++ b/tools/topology/topology2/include/formats/uaol_input_audio_formats.conf @@ -0,0 +1,344 @@ + # Every format the offloaded USB endpoint can carry: S16_LE, S24_LE and + # S32_LE, 1 to 8 channels and every standard rate from 8 to 192 kHz. + # + # 7 channels is left out, it has no channel config and no channel map in + # common_definitions.conf. + num_input_audio_formats 315 + CombineArrays.Object.Base.input_audio_format [ + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 1 ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + in_ch_map [ $CHANNEL_MAP_MONO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 1 ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + in_ch_map [ $CHANNEL_MAP_MONO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 2 ] + in_ch_cfg [ $CHANNEL_CONFIG_STEREO ] + in_ch_map [ $CHANNEL_MAP_STEREO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 2 ] + in_ch_cfg [ $CHANNEL_CONFIG_STEREO ] + in_ch_map [ $CHANNEL_MAP_STEREO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 3 ] + in_ch_cfg [ $CHANNEL_CONFIG_2_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_2_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 3 ] + in_ch_cfg [ $CHANNEL_CONFIG_2_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_2_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 4 ] + in_ch_cfg [ $CHANNEL_CONFIG_3_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_3_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 4 ] + in_ch_cfg [ $CHANNEL_CONFIG_3_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_3_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 5 ] + in_ch_cfg [ $CHANNEL_CONFIG_5_POINT_0 ] + in_ch_map [ $CHANNEL_MAP_5_POINT_0 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 5 ] + in_ch_cfg [ $CHANNEL_CONFIG_5_POINT_0 ] + in_ch_map [ $CHANNEL_MAP_5_POINT_0 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 6 ] + in_ch_cfg [ $CHANNEL_CONFIG_5_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_5_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 6 ] + in_ch_cfg [ $CHANNEL_CONFIG_5_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_5_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 16 ] + in_valid_bit_depth [ 16 ] + in_channels [ 8 ] + in_ch_cfg [ $CHANNEL_CONFIG_7_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_7_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 24 32 ] + in_channels [ 8 ] + in_ch_cfg [ $CHANNEL_CONFIG_7_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_7_POINT_1 ] + } + ] diff --git a/tools/topology/topology2/include/formats/uaol_input_audio_formats_s32.conf b/tools/topology/topology2/include/formats/uaol_input_audio_formats_s32.conf new file mode 100644 index 000000000000..a98428ba1533 --- /dev/null +++ b/tools/topology/topology2/include/formats/uaol_input_audio_formats_s32.conf @@ -0,0 +1,176 @@ + # The formats of a module which only processes 32 bit samples, for every + # channel count and rate the offloaded USB endpoint can carry. + # + # 7 channels is left out, it has no channel config and no channel map in + # common_definitions.conf. + num_input_audio_formats 105 + CombineArrays.Object.Base.input_audio_format [ + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 1 ] + in_ch_cfg [ $CHANNEL_CONFIG_MONO ] + in_ch_map [ $CHANNEL_MAP_MONO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 2 ] + in_ch_cfg [ $CHANNEL_CONFIG_STEREO ] + in_ch_map [ $CHANNEL_MAP_STEREO ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 3 ] + in_ch_cfg [ $CHANNEL_CONFIG_2_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_2_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 4 ] + in_ch_cfg [ $CHANNEL_CONFIG_3_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_3_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 5 ] + in_ch_cfg [ $CHANNEL_CONFIG_5_POINT_0 ] + in_ch_map [ $CHANNEL_MAP_5_POINT_0 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 6 ] + in_ch_cfg [ $CHANNEL_CONFIG_5_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_5_POINT_1 ] + } + { + in_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + in_bit_depth [ 32 ] + in_valid_bit_depth [ 32 ] + in_channels [ 8 ] + in_ch_cfg [ $CHANNEL_CONFIG_7_POINT_1 ] + in_ch_map [ $CHANNEL_MAP_7_POINT_1 ] + } + ] diff --git a/tools/topology/topology2/include/formats/uaol_output_audio_formats.conf b/tools/topology/topology2/include/formats/uaol_output_audio_formats.conf new file mode 100644 index 000000000000..0ff39effcd62 --- /dev/null +++ b/tools/topology/topology2/include/formats/uaol_output_audio_formats.conf @@ -0,0 +1,344 @@ + # Every format the offloaded USB endpoint can carry: S16_LE, S24_LE and + # S32_LE, 1 to 8 channels and every standard rate from 8 to 192 kHz. + # + # 7 channels is left out, it has no channel config and no channel map in + # common_definitions.conf. + num_output_audio_formats 315 + CombineArrays.Object.Base.output_audio_format [ + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 1 ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + out_ch_map [ $CHANNEL_MAP_MONO ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 1 ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + out_ch_map [ $CHANNEL_MAP_MONO ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 2 ] + out_ch_cfg [ $CHANNEL_CONFIG_STEREO ] + out_ch_map [ $CHANNEL_MAP_STEREO ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 2 ] + out_ch_cfg [ $CHANNEL_CONFIG_STEREO ] + out_ch_map [ $CHANNEL_MAP_STEREO ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 3 ] + out_ch_cfg [ $CHANNEL_CONFIG_2_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_2_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 3 ] + out_ch_cfg [ $CHANNEL_CONFIG_2_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_2_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 4 ] + out_ch_cfg [ $CHANNEL_CONFIG_3_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_3_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 4 ] + out_ch_cfg [ $CHANNEL_CONFIG_3_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_3_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 5 ] + out_ch_cfg [ $CHANNEL_CONFIG_5_POINT_0 ] + out_ch_map [ $CHANNEL_MAP_5_POINT_0 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 5 ] + out_ch_cfg [ $CHANNEL_CONFIG_5_POINT_0 ] + out_ch_map [ $CHANNEL_MAP_5_POINT_0 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 6 ] + out_ch_cfg [ $CHANNEL_CONFIG_5_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_5_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 6 ] + out_ch_cfg [ $CHANNEL_CONFIG_5_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_5_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 16 ] + out_valid_bit_depth [ 16 ] + out_channels [ 8 ] + out_ch_cfg [ $CHANNEL_CONFIG_7_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_7_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 24 32 ] + out_channels [ 8 ] + out_ch_cfg [ $CHANNEL_CONFIG_7_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_7_POINT_1 ] + } + ] diff --git a/tools/topology/topology2/include/formats/uaol_output_audio_formats_s32.conf b/tools/topology/topology2/include/formats/uaol_output_audio_formats_s32.conf new file mode 100644 index 000000000000..8dea01de8020 --- /dev/null +++ b/tools/topology/topology2/include/formats/uaol_output_audio_formats_s32.conf @@ -0,0 +1,176 @@ + # The formats of a module which only processes 32 bit samples, for every + # channel count and rate the offloaded USB endpoint can carry. + # + # 7 channels is left out, it has no channel config and no channel map in + # common_definitions.conf. + num_output_audio_formats 105 + CombineArrays.Object.Base.output_audio_format [ + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 1 ] + out_ch_cfg [ $CHANNEL_CONFIG_MONO ] + out_ch_map [ $CHANNEL_MAP_MONO ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 2 ] + out_ch_cfg [ $CHANNEL_CONFIG_STEREO ] + out_ch_map [ $CHANNEL_MAP_STEREO ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 3 ] + out_ch_cfg [ $CHANNEL_CONFIG_2_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_2_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 4 ] + out_ch_cfg [ $CHANNEL_CONFIG_3_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_3_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 5 ] + out_ch_cfg [ $CHANNEL_CONFIG_5_POINT_0 ] + out_ch_map [ $CHANNEL_MAP_5_POINT_0 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 6 ] + out_ch_cfg [ $CHANNEL_CONFIG_5_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_5_POINT_1 ] + } + { + out_rate [ + 8000 + 11025 + 12000 + 16000 + 22050 + 24000 + 32000 + 44100 + 48000 + 64000 + 88200 + 96000 + 128000 + 176400 + 192000 + ] + out_bit_depth [ 32 ] + out_valid_bit_depth [ 32 ] + out_channels [ 8 ] + out_ch_cfg [ $CHANNEL_CONFIG_7_POINT_1 ] + out_ch_map [ $CHANNEL_MAP_7_POINT_1 ] + } + ] diff --git a/tools/topology/topology2/platform/intel/uaol-generic.conf b/tools/topology/topology2/platform/intel/uaol-generic.conf new file mode 100644 index 000000000000..b1e56ad90b21 --- /dev/null +++ b/tools/topology/topology2/platform/intel/uaol-generic.conf @@ -0,0 +1,204 @@ +# USB Audio Offload Link (UAOL) function. +# +# The offloaded USB endpoint is driven by the UAOL gateway in the firmware: +# +# PCM ---------------> gain ---> mixin ---+ +# | +# Deepbuffer PCM ----> gain ---> mixin ---+--> mixout --> gain --> UAOL0-Play +# +# PCM <------------ module-copier <--- eqiir <---------------- UAOL0-Cap +# +# The capture path carries no mixer, as the number of channels follows the USB +# device and a mixer only handles a fixed channel count. +# +# What the endpoint can be run at is decided by the USB device, which is only +# known once one is plugged in, so every widget of both paths carries the whole +# set of formats a USB device may ask for: S16_LE, S24_LE and S32_LE, 1 to 8 +# channels and the standard rates from 8 to 192 kHz, which is as far as UAOL +# goes. The kernel narrows the PCM down to what the connected device actually +# supports. +# +# The deep buffer PCM is left at 48 kHz stereo, as it comes from the shared +# platform/intel/deep-buffer.conf. It can only join the mixer while the normal +# playback PCM runs at that format, or is not running at all. + +# Deep buffer playback, included when the DMA buffer is 1 - 1000 ms +IncludeByKey.DEEPBUFFER_FW_DMA_MS { + "([1-9]|[1-9][0-9]|[1-9][0-9][0-9]|1000)" "platform/intel/deep-buffer.conf" +} + +Object.Dai.UAOL [ + { + name $UAOL_PB_DAI_NAME + dai_index $UAOL_DAI_INDEX + id $UAOL_PB_BE_ID + default_hw_conf_id 0 + Object.Base.hw_config.1 { + name "UAOL0-Play" + } + direction playback + } + { + name $UAOL_CP_DAI_NAME + dai_index $UAOL_DAI_INDEX + id $UAOL_CP_BE_ID + default_hw_conf_id 0 + Object.Base.hw_config.1 { + name "UAOL0-Cap" + } + direction capture + } +] + +Object.Pipeline { + host-copier-gain-mixin-playback [ + { + index $UAOL_PB_HOST_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name $UAOL_PLAYBACK_PCM + pcm_id $UAOL_PCM_ID + + + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Pre Mixer $UAOL_PCM_NAME Playback Volume' + } + + + } + Object.Widget.mixin.1 { + + + } + } + ] + + mixout-gain-dai-copier-playback [ + { + index $UAOL_PB_DAI_PIPELINE_ID + + Object.Widget.mixout.1 { + + + } + Object.Widget.dai-copier.1 { + node_type $ALH_UAOL_STREAM_LINK_OUTPUT_CLASS + stream_name $UAOL_PB_DAI_NAME + dai_type "UAOL" + copier_type "UAOL" + + + } + Object.Widget.gain.1 { + Object.Control.mixer.1 { + name 'Post Mixer $UAOL_PCM_NAME Playback Volume' + } + + + } + } + ] + + host-gateway-capture [ + { + index $UAOL_CP_HOST_PIPELINE_ID + + Object.Widget.host-copier.1 { + stream_name $UAOL_CAPTURE_PCM + pcm_id $UAOL_PCM_ID + + + } + } + ] + + dai-copier-eqiir-module-copier-capture [ + { + index $UAOL_CP_DAI_PIPELINE_ID + + Object.Widget.dai-copier.1 { + node_type $ALH_UAOL_STREAM_LINK_INPUT_CLASS + stream_name $UAOL_CP_DAI_NAME + dai_type "UAOL" + type dai_out + copier_type "UAOL" + num_output_pins 1 + + + } + + # The coefficients are designed for 48 kHz, so the corner + # frequency scales with the rate the device is run at + Object.Widget.eqiir.1 { + Object.Control.bytes.1 { + name '$UAOL_PCM_NAME Capture IIR Eq' + + } + + + } + + Object.Widget.module-copier.2 { + + + } + } + ] +} + +Object.PCM.pcm [ + { + name $UAOL_PCM_NAME + id $UAOL_PCM_ID + direction "duplex" + Object.Base.fe_dai.1 { + name $UAOL_PCM_NAME + } + Object.PCM.pcm_caps.1 { + direction "playback" + name $UAOL_PLAYBACK_PCM + formats 'S16_LE,S24_LE,S32_LE' + channels_min $UAOL_CHANNELS_MIN + channels_max $UAOL_CHANNELS_MAX + rates $UAOL_RATES + rate_min $UAOL_RATE_MIN + rate_max $UAOL_RATE_MAX + } + Object.PCM.pcm_caps.2 { + direction "capture" + name $UAOL_CAPTURE_PCM + formats 'S16_LE,S24_LE,S32_LE' + channels_min $UAOL_CHANNELS_MIN + channels_max $UAOL_CHANNELS_MAX + rates $UAOL_RATES + rate_min $UAOL_RATE_MIN + rate_max $UAOL_RATE_MAX + } + } +] + +# top-level pipeline connections +Object.Base.route [ + { + source "host-copier.$UAOL_PCM_ID.playback" + sink "gain.$UAOL_PB_HOST_PIPELINE_ID.1" + } + { + source "mixin.$UAOL_PB_HOST_PIPELINE_ID.1" + sink "mixout.$UAOL_PB_DAI_PIPELINE_ID.1" + } + { + source "gain.$UAOL_PB_DAI_PIPELINE_ID.1" + sink "dai-copier.UAOL.$UAOL_PB_DAI_NAME.playback" + } + { + source "dai-copier.UAOL.$UAOL_CP_DAI_NAME.capture" + sink "eqiir.$UAOL_CP_DAI_PIPELINE_ID.1" + } + { + source "module-copier.$UAOL_CP_DAI_PIPELINE_ID.2" + sink "host-copier.$UAOL_PCM_ID.capture" + } +] diff --git a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake index 9331b165b03a..216a637d8b50 100644 --- a/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake +++ b/tools/topology/topology2/production/tplg-targets-sdca-generic.cmake @@ -42,6 +42,19 @@ EFX_MIC_TDFB_PARAMS=line4_pass" "cavs-sdw\;sof-hdmi-pcm5-id6\;SDW_JACK=false,HDMI1_ID=6,HDMI2_ID=7,HDMI3_ID=8" "cavs-sdw\;sof-hdmi-pcm5-id7\;SDW_JACK=false,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9" +# USB Audio Offload Link function topology. The UAOL backend is the last one +# sof_sdw creates, so its dai link ID depends on the composition of the board: +# it follows the SoundWire links, the PCH DMIC pair, the three HDMI links and +# the BT link. Each direction is a separate link, so two consecutive IDs are +# taken. The range below covers a jack and amplifier board without DMIC and BT +# (6) up to a jack, amplifier with feedback, PCH DMIC and BT board (10). +# Add a variant here for every further ID that is needed. +"cavs-uaol\;sof-uaol-id6\;UAOL_PB_BE_ID=6,UAOL_CP_BE_ID=7" +"cavs-uaol\;sof-uaol-id7\;UAOL_PB_BE_ID=7,UAOL_CP_BE_ID=8" +"cavs-uaol\;sof-uaol-id8\;UAOL_PB_BE_ID=8,UAOL_CP_BE_ID=9" +"cavs-uaol\;sof-uaol-id9\;UAOL_PB_BE_ID=9,UAOL_CP_BE_ID=10" +"cavs-uaol\;sof-uaol-id10\;UAOL_PB_BE_ID=10,UAOL_CP_BE_ID=11" + # Feature topologies which should work with the function topologies above "cavs-sdw\;sof-sdca-amp-ref\;SDW_JACK=false,NUM_HDMIS=0,JACK_RATE=48000,\ SDW_AMP_FEEDBACK=false,SDW_SPK_ECHO_REF=true,SDW_SPK_ECHO_REF_PCM_ID=12" From a72ff1f336d7dce523f5c3cd8c48a2498fd0d6ba Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Thu, 20 Aug 2026 19:33:30 +0300 Subject: [PATCH 064/109] topology2: add d0i3_compatible properties to host-copier widget Add playback_compatible_d0i3 and capture_compatible_d0i3 attributes to the host-copier widget class so they can be set on host-copier widgets to enable Wake on Voice and similar functionalities for the associated PCMs. Signed-off-by: Jyri Sarha --- .../topology2/include/components/host-copier.conf | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/topology/topology2/include/components/host-copier.conf b/tools/topology/topology2/include/components/host-copier.conf index 73911ef6e128..896ab30bb1a2 100644 --- a/tools/topology/topology2/include/components/host-copier.conf +++ b/tools/topology/topology2/include/components/host-copier.conf @@ -83,6 +83,18 @@ Class.Widget."host-copier" { token_ref "copier.word" } + # + # D0I3 compatibility flags for streams. When set, the DSP can + # remain in D0i3 during S0ix while this stream is active. + # + DefineAttribute."playback_compatible_d0i3" { + token_ref "stream.bool" + } + + DefineAttribute."capture_compatible_d0i3" { + token_ref "stream.bool" + } + attributes { # # The host copier widget name would be constructed using the copier pcm_id and From ce13360334c27c47ea6fed4ef958f97bd23db719 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Mon, 17 Aug 2026 21:03:06 +0300 Subject: [PATCH 065/109] 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 --- src/audio/pipeline/pipeline-graph.c | 90 +++++++++++++++++++++++--- src/include/sof/audio/pipeline-trace.h | 4 ++ src/include/sof/audio/pipeline.h | 8 +++ src/init/init.c | 6 ++ src/ipc/ipc-common.c | 1 + zephyr/wrapper.c | 3 - 6 files changed, 99 insertions(+), 13 deletions(-) diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index c6665cb4d08c..6b566f207afa 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -44,10 +45,20 @@ DECLARE_TR_CTX(pipe_tr, SOF_UUID(pipe_uuid), LOG_LEVEL_INFO); /* lookup table to determine busy/free pipeline metadata objects */ struct pipeline_posn { bool posn_offset[PPL_POSN_OFFSETS]; /**< available offsets */ +#ifndef CONFIG_SOF_USERSPACE_LL struct k_spinlock lock; /**< lock mechanism */ +#endif }; /* the pipeline position lookup table */ -static SHARED_DATA struct pipeline_posn pipeline_posn_shared; +static APP_SYSUSER_BSS SHARED_DATA struct pipeline_posn pipeline_posn_shared; + +#ifdef CONFIG_SOF_USERSPACE_LL +/* Mutex pointer in user-accessible partition so user-space threads + * can read the pointer for syscalls. Kept outside the SHARED_DATA + * struct to avoid kernel object tracking issues. + */ +static APP_SYSUSER_BSS struct k_mutex *pipeline_posn_mutex; +#endif /** * \brief Retrieves pipeline position structure. @@ -55,9 +66,48 @@ static SHARED_DATA struct pipeline_posn pipeline_posn_shared; */ static inline struct pipeline_posn *pipeline_posn_get(void) { +#ifdef CONFIG_SOF_USERSPACE_LL + return &pipeline_posn_shared; +#else return sof_get()->pipeline_posn; +#endif +} + +/* + * Position table locking. User-space LL cannot use a spinlock (disabling + * interrupts is privileged), so it uses a mutex; the config split is kept + * here so the callers below stay identical for both configurations. + */ +#ifdef CONFIG_SOF_USERSPACE_LL +typedef int pipeline_posn_key_t; + +static inline pipeline_posn_key_t pipeline_posn_lock(struct pipeline_posn *posn) +{ + (void)posn; + k_mutex_lock(pipeline_posn_mutex, K_FOREVER); + return 0; } +static inline void pipeline_posn_unlock(struct pipeline_posn *posn, pipeline_posn_key_t key) +{ + (void)posn; + (void)key; + k_mutex_unlock(pipeline_posn_mutex); +} +#else +typedef k_spinlock_key_t pipeline_posn_key_t; + +static inline pipeline_posn_key_t pipeline_posn_lock(struct pipeline_posn *posn) +{ + return k_spin_lock(&posn->lock); +} + +static inline void pipeline_posn_unlock(struct pipeline_posn *posn, pipeline_posn_key_t key) +{ + k_spin_unlock(&posn->lock, key); +} +#endif + /** * \brief Retrieves first free pipeline position offset. * \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) struct pipeline_posn *pipeline_posn = pipeline_posn_get(); int ret = -EINVAL; uint32_t i; - k_spinlock_key_t key; - - key = k_spin_lock(&pipeline_posn->lock); + pipeline_posn_key_t key = pipeline_posn_lock(pipeline_posn); for (i = 0; i < PPL_POSN_OFFSETS; ++i) { if (!pipeline_posn->posn_offset[i]) { @@ -81,8 +129,7 @@ static inline int pipeline_posn_offset_get(uint32_t *posn_offset) } } - - k_spin_unlock(&pipeline_posn->lock, key); + pipeline_posn_unlock(pipeline_posn, key); return ret; } @@ -95,20 +142,34 @@ static inline void pipeline_posn_offset_put(uint32_t posn_offset) { struct pipeline_posn *pipeline_posn = pipeline_posn_get(); int i = posn_offset / sizeof(struct sof_ipc_stream_posn); - k_spinlock_key_t key; - - key = k_spin_lock(&pipeline_posn->lock); + pipeline_posn_key_t key = pipeline_posn_lock(pipeline_posn); pipeline_posn->posn_offset[i] = false; - k_spin_unlock(&pipeline_posn->lock, key); + pipeline_posn_unlock(pipeline_posn, key); } void pipeline_posn_init(struct sof *sof) { sof->pipeline_posn = &pipeline_posn_shared; +#ifdef CONFIG_SOF_USERSPACE_LL + pipeline_posn_mutex = k_object_alloc(K_OBJ_MUTEX); + if (!pipeline_posn_mutex) { + pipe_cl_err("pipeline posn mutex alloc failed"); + k_panic(); + } + k_mutex_init(pipeline_posn_mutex); +#else k_spinlock_init(&sof->pipeline_posn->lock); +#endif +} + +#ifdef CONFIG_SOF_USERSPACE_LL +void pipeline_posn_grant_access(struct k_thread *thread) +{ + k_thread_access_grant(thread, pipeline_posn_mutex); } +#endif /* create new pipeline - returns pipeline id or negative error */ 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_ p->pipeline_id = pipeline_id; p->status = COMP_STATE_INIT; p->trigger.cmd = COMP_TRIGGER_NO_ACTION; + +#ifndef CONFIG_SOF_USERSPACE_LL + /* + * pipe_tr lives in the .trace_ctx section, which is not mapped into + * the sysuser partition, so it cannot be read from a user-mode thread. + * The copy is also unnecessary in that configuration: with Zephyr + * logging the pipe_*() macros use the global pipe_tr, not p->tctx. + */ ret = memcpy_s(&p->tctx, sizeof(struct tr_ctx), &pipe_tr, sizeof(struct tr_ctx)); if (ret < 0) { pipe_err(p, "failed to copy trace settings"); goto free; } +#endif ret = pipeline_posn_offset_get(&p->posn_offset); if (ret < 0) { diff --git a/src/include/sof/audio/pipeline-trace.h b/src/include/sof/audio/pipeline-trace.h index d1f89583ad45..dbd5ae7f7c84 100644 --- a/src/include/sof/audio/pipeline-trace.h +++ b/src/include/sof/audio/pipeline-trace.h @@ -59,6 +59,10 @@ extern struct tr_ctx pipe_tr; #else +#if defined(__ZEPHYR__) && defined(CONFIG_SOF_USERSPACE_LL) +#error "Invalid build config: User-space cannot access trace context." +#endif + #define pipe_err(pipe_p, __e, ...) \ trace_dev_err(trace_pipe_get_tr_ctx, trace_pipe_get_id, \ trace_pipe_get_subid, pipe_p, __e, ##__VA_ARGS__) diff --git a/src/include/sof/audio/pipeline.h b/src/include/sof/audio/pipeline.h index 6d6202ae9fae..858c81d98a2f 100644 --- a/src/include/sof/audio/pipeline.h +++ b/src/include/sof/audio/pipeline.h @@ -209,6 +209,14 @@ int pipeline_complete(struct pipeline *p, struct comp_dev *source, */ void pipeline_posn_init(struct sof *sof); +#ifdef CONFIG_SOF_USERSPACE_LL +/** + * \brief Grants user-space thread access to pipeline position mutex. + * \param[in] thread Thread to grant access to. + */ +void pipeline_posn_grant_access(struct k_thread *thread); +#endif + /** * \brief Resets the pipeline and free runtime resources. * \param[in] p pipeline. diff --git a/src/init/init.c b/src/init/init.c index 7976e2eb673e..5990cfebc2dc 100644 --- a/src/init/init.c +++ b/src/init/init.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #if CONFIG_IPC_MAJOR_4 #include @@ -232,6 +233,11 @@ __cold static int primary_core_init(int argc, char *argv[], struct sof *sof) zephyr_ll_user_resources_init(); #endif + /* init pipeline position offsets - must be before platform_init() + * which calls ipc_init() -> ipc_user_init() that needs the posn mutex. + */ + pipeline_posn_init(sof); + /* init the platform */ if (platform_init(sof) < 0) sof_panic(SOF_IPC_PANIC_PLATFORM); diff --git a/src/ipc/ipc-common.c b/src/ipc/ipc-common.c index 96b957f9fabb..c5e2727ab3cb 100644 --- a/src/ipc/ipc-common.c +++ b/src/ipc/ipc-common.c @@ -457,6 +457,7 @@ __cold static int ipc_user_init_thread(struct ipc_user *ipc_user) user_grant_dma_access_all(ipc_user->thread); k_mem_domain_add_thread(zephyr_ll_mem_domain(), ipc_user->thread); user_ll_grant_access(ipc_user->thread, PLATFORM_PRIMARY_CORE_ID); + pipeline_posn_grant_access(ipc_user->thread); return 0; diff --git a/zephyr/wrapper.c b/zephyr/wrapper.c index 9bbb43f8a798..afdc5b54a2e9 100644 --- a/zephyr/wrapper.c +++ b/zephyr/wrapper.c @@ -177,9 +177,6 @@ int task_main_start(struct sof *sof) /* init default audio components */ sys_comp_init(sof); - /* init pipeline position offsets */ - pipeline_posn_init(sof); - return 0; } From 1a0edd5006ebf5c3f100c0d776be8949c2567c14 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 25 Aug 2026 18:19:32 +0300 Subject: [PATCH 066/109] schedule: ll: handle completed task state in library scheduler Update the library LL scheduler in schedule_ll_run_tasks() to check the task_run() return state and remove tasks returning SOF_TASK_STATE_COMPLETED from the scheduler list. Following commit 002e4991baa0 ("ipc4: pipeline: split trigger and copy processing"), IPC4 uses a one-shot trigger task that returns SOF_TASK_STATE_COMPLETED upon trigger completion, while the copy task waits for task_is_active(p->trigger_task) to clear before copying. Previously, the library LL scheduler ignored the return value of task_run() and reset the task state back to SOF_TASK_STATE_QUEUED, leaving trigger_task permanently active and causing testbench pipeline copy tasks to stall indefinitely. Signed-off-by: Seppo Ingalsuo --- src/platform/library/schedule/ll_schedule.c | 25 ++++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/platform/library/schedule/ll_schedule.c b/src/platform/library/schedule/ll_schedule.c index b81d576f0de3..f865f4db18e9 100644 --- a/src/platform/library/schedule/ll_schedule.c +++ b/src/platform/library/schedule/ll_schedule.c @@ -31,6 +31,7 @@ void schedule_ll_run_tasks(void) { struct list_item *tlist, *tlist_; struct task *task; + enum task_state state; /* list empty then return */ if (list_is_empty(&sched_list)) @@ -44,12 +45,14 @@ void schedule_ll_run_tasks(void) if (task->state == SOF_TASK_STATE_QUEUED) { task->state = SOF_TASK_STATE_RUNNING; - task->ops.run(task->data); + state = task_run(task); - /* only re-queue if not cancelled */ - if (task->state == SOF_TASK_STATE_RUNNING) + if (state == SOF_TASK_STATE_COMPLETED) { + task->state = SOF_TASK_STATE_COMPLETED; + list_item_del(&task->list); + } else if (task->state == SOF_TASK_STATE_RUNNING) { task->state = SOF_TASK_STATE_QUEUED; - + } } } } @@ -58,6 +61,10 @@ void schedule_ll_run_tasks(void) static int schedule_ll_task(void *data, struct task *task, uint64_t start, uint64_t period) { + if (task->state == SOF_TASK_STATE_QUEUED || + task->state == SOF_TASK_STATE_RUNNING) + return 0; + /* add task to list */ list_item_prepend(&task->list, &sched_list); task->state = SOF_TASK_STATE_QUEUED; @@ -76,9 +83,12 @@ static void ll_scheduler_free(void *data, uint32_t flags) /* TODO: scheduler free and cancel APIs can merge as part of Zephyr */ static int schedule_ll_task_cancel(void *data, struct task *task) { + if (task->state == SOF_TASK_STATE_QUEUED || + task->state == SOF_TASK_STATE_RUNNING) + list_item_del(&task->list); + /* delete task */ task->state = SOF_TASK_STATE_CANCEL; - list_item_del(&task->list); return 0; } @@ -86,8 +96,11 @@ static int schedule_ll_task_cancel(void *data, struct task *task) /* TODO: scheduler free and cancel APIs can merge as part of Zephyr */ static int schedule_ll_task_free(void *data, struct task *task) { + if (task->state == SOF_TASK_STATE_QUEUED || + task->state == SOF_TASK_STATE_RUNNING) + list_item_del(&task->list); + task->state = SOF_TASK_STATE_FREE; - list_item_del(&task->list); return 0; } From 9fc0bd33832c1c85ea7ff548873be55e0c990c54 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 14:01:11 +0200 Subject: [PATCH 067/109] llext: move 2 functions higher Move llext_manager_add_partition() and llext_manager_rm_partition() higher in the file for future use. No functional change. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 61 +++++++++++++++-------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 4ad3c55d55bc..1be78041b074 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -168,6 +168,38 @@ static int llext_manager_load_data_from_storage(const struct sys_mm_drv_region * return ret; } +#ifdef CONFIG_USERSPACE +static int llext_manager_add_partition(struct k_mem_domain *domain, + uintptr_t addr, size_t size, + k_mem_partition_attr_t attr) +{ + size_t pre_pad_size = addr & (PAGE_SZ - 1); + struct k_mem_partition part = { + .start = addr - pre_pad_size, + .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), + .attr = attr, + }; + + tr_dbg(&lib_manager_tr, "add %#zx @ %lx partition", part.size, part.start); + return k_mem_domain_add_partition(domain, &part); +} + +static int llext_manager_rm_partition(struct k_mem_domain *domain, + uintptr_t addr, size_t size, + k_mem_partition_attr_t attr) +{ + size_t pre_pad_size = addr & (PAGE_SZ - 1); + struct k_mem_partition part = { + .start = addr - pre_pad_size, + .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), + .attr = attr, + }; + + tr_dbg(&lib_manager_tr, "remove %#zx @ %lx partition", part.size, part.start); + return k_mem_domain_remove_partition(domain, &part); +} +#endif + static void llext_manager_unmap_detached_sections(const struct llext_loader *ldr, const struct llext *ext, enum llext_mem region, @@ -794,35 +826,6 @@ uintptr_t llext_manager_allocate_module(const struct comp_ipc_config *ipc_config } #ifdef CONFIG_USERSPACE -static int llext_manager_add_partition(struct k_mem_domain *domain, - uintptr_t addr, size_t size, - k_mem_partition_attr_t attr) -{ - size_t pre_pad_size = addr & (PAGE_SZ - 1); - struct k_mem_partition part = { - .start = addr - pre_pad_size, - .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), - .attr = attr, - }; - - tr_dbg(&lib_manager_tr, "add %#zx @ %lx partition", part.size, part.start); - return k_mem_domain_add_partition(domain, &part); -} - -static int llext_manager_rm_partition(struct k_mem_domain *domain, - uintptr_t addr, size_t size, - k_mem_partition_attr_t attr) -{ - size_t pre_pad_size = addr & (PAGE_SZ - 1); - struct k_mem_partition part = { - .start = addr - pre_pad_size, - .size = ALIGN_UP(pre_pad_size + size, PAGE_SZ), - .attr = attr, - }; - - tr_dbg(&lib_manager_tr, "remove %#zx @ %lx partition", part.size, part.start); - return k_mem_domain_remove_partition(domain, &part); -} static int llext_manager_add_mod_domain(struct lib_manager_module *mctx, struct k_mem_domain *domain) { From 979effd20e8103f0623c6877f1d409a0f610a4c9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 14:48:45 +0200 Subject: [PATCH 068/109] llext: don't access DRAM when freeing With userspace LL enabled module freeing runs in syscall contex on behalf of the userspace IPC thread. That thread doesn't have access to DRAM. Therefore we cannot call lib_manager_get_module_manifest() in that case. Use SRAM module data by calling llext_manager_mod_find() instead. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib_manager.h | 1 + src/library_manager/lib_manager.c | 10 +++++++--- src/library_manager/llext_manager.c | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/include/sof/lib_manager.h b/src/include/sof/lib_manager.h index fb277ac75f64..019695be69ef 100644 --- a/src/include/sof/lib_manager.h +++ b/src/include/sof/lib_manager.h @@ -123,6 +123,7 @@ struct lib_manager_module { struct lib_manager_mod_ctx { void *base_addr; /* library cold storage address (e.g. DRAM) */ unsigned int n_mod; + unsigned int load_type; struct lib_manager_module *mod; }; diff --git a/src/library_manager/lib_manager.c b/src/library_manager/lib_manager.c index 1b1dd5f2cc9e..a672f51133d2 100644 --- a/src/library_manager/lib_manager.c +++ b/src/library_manager/lib_manager.c @@ -423,15 +423,18 @@ static int lib_manager_free_module(const uint32_t component_id) tr_dbg(&lib_manager_tr, "mod_id: %#x", component_id); + const struct lib_manager_mod_ctx *const ctx = lib_manager_get_mod_ctx(module_id); + + if (ctx->load_type == SOF_MAN_MOD_TYPE_LLEXT || + ctx->load_type == SOF_MAN_MOD_TYPE_LLEXT_AUX) + return llext_manager_free_module(component_id); + mod = lib_manager_get_module_manifest(module_id); if (!mod) { tr_err(&lib_manager_tr, "failed to get module descriptor"); return -EINVAL; } - if (module_is_llext(mod)) - return llext_manager_free_module(component_id); - ret = lib_manager_unload_module(mod); if (ret < 0) return ret; @@ -500,6 +503,7 @@ static void lib_manager_update_sof_ctx(void *base_addr, uint32_t lib_id) } ctx->base_addr = base_addr; + ctx->load_type = SOF_MAN_MOD_TYPE_MODULE; _ext_lib->desc[lib_id] = ctx; /* TODO: maybe need to call dcache_writeback here? */ diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index 1be78041b074..f3797f67a8d9 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -1170,6 +1170,7 @@ int llext_manager_add_library(uint32_t module_id) return ret; } } + ctx->load_type = SOF_MAN_MOD_TYPE_LLEXT; return 0; } From 5b3739b1737621fc67f4ebf94d6aacf41e0a1de8 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 15:09:09 +0200 Subject: [PATCH 069/109] llext: temporarily map ELF headers for userspace when freeing llext_manager_unload_module() is called in a syscall context on behalf of the userspace IPC thread, so it doesn't have direct access to LLEXT module DRAM data. Map section headers temporarily for the duration of the function. Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index f3797f67a8d9..a163fdd062f2 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -382,6 +382,19 @@ static int llext_manager_unload_module(struct lib_manager_module *mctx) mctx->segment[LIB_MANAGER_BSS].size; int err = 0, ret; +#ifdef CONFIG_SOF_USERSPACE_LL + unsigned int sect_cnt = llext_section_count(ext); + size_t total = sect_cnt * sizeof(elf_shdr_t); + const elf_shdr_t *shdr; + + ret = llext_get_section_info(ldr, ext, 0, &shdr, NULL, NULL); + if (ret < 0) + return ret; + + /* Temporarily map ELF section headers */ + llext_manager_add_partition(zephyr_ll_mem_domain(), (uintptr_t)shdr, total, + K_MEM_PARTITION_P_RW_U_NA | XTENSA_MMU_CACHED_WB); +#endif llext_manager_unmap_detached_sections(ldr, ext, LLEXT_MEM_TEXT, va_base_text, text_size); ret = llext_manager_align_unmap(va_base_text, text_size); @@ -406,6 +419,10 @@ static int llext_manager_unload_module(struct lib_manager_module *mctx) if (ret < 0 && !err) err = ret; +#ifdef CONFIG_SOF_USERSPACE_LL + llext_manager_rm_partition(zephyr_ll_mem_domain(), (uintptr_t)shdr, total, + K_MEM_PARTITION_P_RW_U_NA | XTENSA_MMU_CACHED_WB); +#endif mctx->mapped = false; #ifdef CONFIG_SOF_USERSPACE_LL From 4c90b5519c1feb9f7c9b6da9a69458a989fe46c9 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 3 Aug 2026 15:14:59 +0200 Subject: [PATCH 070/109] llext: avoid DRAM access in userspace when freeing llext_manager_free_module() cannot access DRAM when running with userspace LL enabled. Don't call lib_manager_get_library_manifest() to obtain the DRAM descriptor, needed to verify the entry index. The index is now verified by llext_manager_mod_find(). Signed-off-by: Guennadi Liakhovetski --- src/library_manager/llext_manager.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/library_manager/llext_manager.c b/src/library_manager/llext_manager.c index a163fdd062f2..bcbfd290ceb0 100644 --- a/src/library_manager/llext_manager.c +++ b/src/library_manager/llext_manager.c @@ -1086,16 +1086,9 @@ int llext_manager_rm_domain(const uint32_t component_id, struct k_mem_domain *do int llext_manager_free_module(const uint32_t component_id) { const uint32_t module_id = IPC4_MOD_ID(component_id); - struct sof_man_fw_desc *desc = (struct sof_man_fw_desc *)lib_manager_get_library_manifest(module_id); struct lib_manager_mod_ctx *ctx = lib_manager_get_mod_ctx(module_id); uint32_t entry_index = LIB_MANAGER_GET_MODULE_INDEX(module_id); - if (entry_index >= desc->header.num_module_entries) { - tr_err(&lib_manager_tr, "Invalid driver index %u exceeds %d", - entry_index, desc->header.num_module_entries - 1); - return -ENOENT; - } - if (!ctx->mod) { tr_err(&lib_manager_tr, "NULL module array: ID %#x ctx %p", component_id, ctx); return -ENOENT; From 988cf5d663a7deb23849b3ff570106b27061cdc3 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2026 09:53:07 +0200 Subject: [PATCH 071/109] global: remove unused SHARED_DATA SHARED_DATA is only non-empty on non-Zephyr and non-unit-test builds of cAVS. At most that includes pure build tests or testbench, of which none need it either. Remove it globally. Signed-off-by: Guennadi Liakhovetski --- src/audio/base_fw.c | 4 +- src/audio/chain_dma.c | 2 +- src/audio/component.c | 4 +- src/audio/dai-legacy.c | 4 +- src/audio/dai-zephyr.c | 4 +- src/audio/google/google_hotword_detect.c | 4 +- src/audio/host-legacy.c | 4 +- src/audio/host-zephyr.c | 4 +- src/audio/kpb.c | 4 +- src/audio/pipeline/pipeline-graph.c | 5 +- src/audio/selector/selector.c | 4 +- src/audio/tone/tone-ipc3.c | 4 +- src/audio/tone/tone-ipc4.c | 2 +- src/audio/tone/tone.c | 2 +- src/audio/tone/tone.h | 2 +- src/drivers/interrupt.c | 2 +- src/idc/idc.c | 2 +- .../sof/audio/module_adapter/module/generic.h | 2 +- src/lib/clk.c | 2 +- src/lib/notifier.c | 2 +- .../amd/acp_6_3/include/platform/lib/memory.h | 1 - src/platform/amd/acp_6_3/lib/clk.c | 2 +- src/platform/amd/acp_6_3/lib/dma.c | 2 +- src/platform/amd/acp_6_3/lib/memory.c | 32 ++++++------ src/platform/amd/acp_6_3/platform.c | 2 +- .../amd/acp_7_0/include/platform/lib/memory.h | 1 - src/platform/amd/acp_7_0/lib/clk.c | 2 +- src/platform/amd/acp_7_0/lib/dma.c | 2 +- src/platform/amd/acp_7_0/lib/memory.c | 32 ++++++------ .../amd/acp_7_x/include/platform/lib/memory.h | 1 - src/platform/amd/acp_7_x/lib/clk.c | 2 +- .../rembrandt/include/platform/lib/memory.h | 2 - src/platform/amd/rembrandt/lib/clk.c | 2 +- src/platform/amd/rembrandt/lib/dma.c | 2 +- .../amd/renoir/include/platform/lib/memory.h | 2 - src/platform/amd/renoir/lib/clk.c | 2 +- src/platform/amd/renoir/lib/dma.c | 2 +- src/platform/amd/renoir/lib/memory.c | 32 ++++++------ src/platform/amd/renoir/platform.c | 2 +- .../amd/vangogh/include/platform/lib/memory.h | 2 - src/platform/amd/vangogh/lib/clk.c | 2 +- src/platform/amd/vangogh/lib/dma.c | 2 +- src/platform/amd/vangogh/lib/memory.c | 32 ++++++------ src/platform/amd/vangogh/platform.c | 2 +- .../imx8/include/platform/lib/memory.h | 11 +--- src/platform/imx8/lib/clk.c | 2 +- src/platform/imx8/lib/dai.c | 4 +- src/platform/imx8/lib/dma.c | 2 +- src/platform/imx8/lib/memory.c | 32 ++++++------ .../imx8m/include/platform/lib/memory.h | 11 +--- src/platform/imx8m/lib/clk.c | 2 +- src/platform/imx8m/lib/dai.c | 4 +- src/platform/imx8m/lib/dma.c | 2 +- src/platform/imx8m/lib/memory.c | 34 ++++++------ .../imx8m_cm7/include/platform/lib/memory.h | 2 - .../imx8ulp/include/platform/lib/memory.h | 11 +--- src/platform/imx8ulp/lib/clk.c | 2 +- src/platform/imx8ulp/lib/dai.c | 2 +- src/platform/imx8ulp/lib/dma.c | 2 +- src/platform/imx8ulp/lib/memory.c | 32 ++++++------ .../imx93_a55/include/platform/lib/memory.h | 2 - .../imx95/include/platform/lib/memory.h | 2 - .../intel/ace/include/ace/lib/memory.h | 8 --- .../intel/cavs/include/cavs/lib/memory.h | 12 ----- .../library/include/platform/lib/memory.h | 2 - src/platform/library/lib/memory.c | 52 +++++++++---------- src/platform/library/platform.c | 2 +- .../mt8186/include/platform/lib/memory.h | 11 +--- src/platform/mt8186/lib/clk.c | 2 +- src/platform/mt8186/lib/dai.c | 2 +- src/platform/mt8186/lib/dma.c | 2 +- src/platform/mt8186/lib/memory.c | 34 ++++++------ src/platform/mt8186/platform.c | 2 +- .../mt8188/include/platform/lib/memory.h | 13 ++--- src/platform/mt8188/lib/clk.c | 2 +- src/platform/mt8188/lib/dai.c | 2 +- src/platform/mt8188/lib/dma.c | 2 +- src/platform/mt8188/lib/memory.c | 34 ++++++------ src/platform/mt8188/platform.c | 2 +- .../mt8195/include/platform/lib/memory.h | 11 +--- src/platform/mt8195/lib/clk.c | 2 +- src/platform/mt8195/lib/dai.c | 2 +- src/platform/mt8195/lib/dma.c | 2 +- src/platform/mt8195/lib/memory.c | 34 ++++++------ src/platform/mt8195/platform.c | 2 +- .../mt8196/include/platform/lib/memory.h | 13 ++--- src/platform/mt8196/lib/clk.c | 2 +- src/platform/mt8196/lib/dai.c | 2 +- src/platform/mt8196/lib/dma.c | 2 +- src/platform/mt8196/lib/memory.c | 34 ++++++------ src/platform/mt8196/platform.c | 2 +- .../mt8365/include/platform/lib/memory.h | 11 +--- src/platform/mt8365/lib/clk.c | 2 +- src/platform/mt8365/lib/dai.c | 2 +- src/platform/mt8365/lib/dma.c | 2 +- src/platform/mt8365/lib/memory.c | 34 ++++++------ src/platform/mt8365/platform.c | 2 +- .../mtk/include/platform/lib/memory.h | 2 - .../posix/include/platform/lib/memory.h | 2 - .../qemu_xtensa/include/platform/lib/memory.h | 1 - src/samples/audio/detect_test.c | 2 +- src/samples/audio/smart_amp_test_ipc3.c | 2 +- zephyr/lib/clk.c | 2 +- zephyr/lib/dma.c | 2 +- 104 files changed, 323 insertions(+), 422 deletions(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 2602add04cdc..88d3a54adcee 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -4,7 +4,7 @@ // #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -857,7 +857,7 @@ static const struct comp_driver comp_basefw = { }, }; -static SHARED_DATA struct comp_driver_info comp_basefw_info = { +static struct comp_driver_info comp_basefw_info = { .drv = &comp_basefw, }; diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index 34106c57cc83..1260cf44a21c 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -795,7 +795,7 @@ static const struct comp_driver comp_chain_dma = { }, }; -static SHARED_DATA struct comp_driver_info comp_chain_dma_info = { +static struct comp_driver_info comp_chain_dma_info = { .drv = &comp_chain_dma, }; diff --git a/src/audio/component.c b/src/audio/component.c index 3c7021057259..e2c38a9c62da 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -13,7 +13,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -36,7 +36,7 @@ LOG_MODULE_REGISTER(component, CONFIG_SOF_LOG_LEVEL); -static APP_SYSUSER_BSS SHARED_DATA struct comp_driver_list cd; +static APP_SYSUSER_BSS struct comp_driver_list cd; #ifdef CONFIG_SOF_USERSPACE_LL struct comp_driver_list *comp_drivers_get(void) diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index 8a9496c49121..d16aec40efd8 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -19,7 +19,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -1128,7 +1128,7 @@ static const struct comp_driver comp_dai = { }, }; -static SHARED_DATA struct comp_driver_info comp_dai_info = { +static struct comp_driver_info comp_dai_info = { .drv = &comp_dai, }; diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 1dbd4f5e133d..7bb53c88e178 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -19,7 +19,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -2092,7 +2092,7 @@ static const struct comp_driver comp_dai = { }, }; -static SHARED_DATA struct comp_driver_info comp_dai_info = { +static struct comp_driver_info comp_dai_info = { .drv = &comp_dai, }; diff --git a/src/audio/google/google_hotword_detect.c b/src/audio/google/google_hotword_detect.c index 1055f7914e1e..f8f7c22467be 100644 --- a/src/audio/google/google_hotword_detect.c +++ b/src/audio/google/google_hotword_detect.c @@ -15,7 +15,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -466,7 +466,7 @@ static const struct comp_driver ghd_driver = { }, }; -static SHARED_DATA struct comp_driver_info ghd_driver_info = { +static struct comp_driver_info ghd_driver_info = { .drv = &ghd_driver, }; diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index 4560959bb044..d56319c0184d 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -17,7 +17,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -1068,7 +1068,7 @@ static const struct comp_driver comp_host = { }, }; -static SHARED_DATA struct comp_driver_info comp_host_info = { +static struct comp_driver_info comp_host_info = { .drv = &comp_host, }; diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index 95f8f35a3736..f2bfae946d8d 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -17,7 +17,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -1332,7 +1332,7 @@ static const struct comp_driver comp_host = { }, }; -static SHARED_DATA struct comp_driver_info comp_host_info = { +static struct comp_driver_info comp_host_info = { .drv = &comp_host, }; diff --git a/src/audio/kpb.c b/src/audio/kpb.c index d5434f5e6a87..40353ff71e20 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -26,7 +26,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -2742,7 +2742,7 @@ static const struct comp_driver comp_kpb = { }, }; -static SHARED_DATA struct comp_driver_info comp_kpb_info = { +static struct comp_driver_info comp_kpb_info = { .drv = &comp_kpb, }; diff --git a/src/audio/pipeline/pipeline-graph.c b/src/audio/pipeline/pipeline-graph.c index 6b566f207afa..670df08e9383 100644 --- a/src/audio/pipeline/pipeline-graph.c +++ b/src/audio/pipeline/pipeline-graph.c @@ -50,12 +50,11 @@ struct pipeline_posn { #endif }; /* the pipeline position lookup table */ -static APP_SYSUSER_BSS SHARED_DATA struct pipeline_posn pipeline_posn_shared; +static APP_SYSUSER_BSS struct pipeline_posn pipeline_posn_shared; #ifdef CONFIG_SOF_USERSPACE_LL /* Mutex pointer in user-accessible partition so user-space threads - * can read the pointer for syscalls. Kept outside the SHARED_DATA - * struct to avoid kernel object tracking issues. + * can read the pointer for syscalls. */ static APP_SYSUSER_BSS struct k_mutex *pipeline_posn_mutex; #endif diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index df814b6c24f6..422e08f69603 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -22,7 +22,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -609,7 +609,7 @@ static const struct comp_driver comp_selector = { }, }; -static SHARED_DATA struct comp_driver_info comp_selector_info = { +static struct comp_driver_info comp_selector_info = { .drv = &comp_selector, }; diff --git a/src/audio/tone/tone-ipc3.c b/src/audio/tone/tone-ipc3.c index db36b9a88cbe..b2ebb3209571 100644 --- a/src/audio/tone/tone-ipc3.c +++ b/src/audio/tone/tone-ipc3.c @@ -16,7 +16,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include @@ -395,7 +395,7 @@ static const struct comp_driver comp_tone = { }, }; -static SHARED_DATA struct comp_driver_info comp_tone_info = { +static struct comp_driver_info comp_tone_info = { .drv = &comp_tone, }; diff --git a/src/audio/tone/tone-ipc4.c b/src/audio/tone/tone-ipc4.c index eaa2bffcdb48..db2497e8aa40 100644 --- a/src/audio/tone/tone-ipc4.c +++ b/src/audio/tone/tone-ipc4.c @@ -17,7 +17,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include diff --git a/src/audio/tone/tone.c b/src/audio/tone/tone.c index 975e4ee06bc8..0941d7edcb69 100644 --- a/src/audio/tone/tone.c +++ b/src/audio/tone/tone.c @@ -17,7 +17,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include diff --git a/src/audio/tone/tone.h b/src/audio/tone/tone.h index 4183543e0beb..33c0862ef19c 100644 --- a/src/audio/tone/tone.h +++ b/src/audio/tone/tone.h @@ -14,7 +14,7 @@ #include #include #include -#include /* for SHARED_DATA */ +#include /* likely unneeded */ #include #include #include diff --git a/src/drivers/interrupt.c b/src/drivers/interrupt.c index afa07c4d1d46..a1215314cb9d 100644 --- a/src/drivers/interrupt.c +++ b/src/drivers/interrupt.c @@ -43,7 +43,7 @@ DECLARE_TR_CTX(irq_tr, SOF_UUID(irq_uuid), LOG_LEVEL_INFO); #define interrupt_disable mux_interrupt_disable #endif -static SHARED_DATA struct cascade_root cascade_root; +static struct cascade_root cascade_root; static int interrupt_register_internal(uint32_t irq, void (*handler)(void *arg), void *arg, struct irq_desc *desc); diff --git a/src/idc/idc.c b/src/idc/idc.c index 145a22abfa1c..195de0a18d2a 100644 --- a/src/idc/idc.c +++ b/src/idc/idc.c @@ -39,7 +39,7 @@ LOG_MODULE_REGISTER(idc, CONFIG_SOF_LOG_LEVEL); /** \brief IDC message payload per core. */ -static SHARED_DATA struct idc_payload static_payload[CONFIG_CORE_COUNT]; +static struct idc_payload static_payload[CONFIG_CORE_COUNT]; SOF_DEFINE_REG_UUID(idc); diff --git a/src/include/sof/audio/module_adapter/module/generic.h b/src/include/sof/audio/module_adapter/module/generic.h index e7ba1eabefab..625b3a180a60 100644 --- a/src/include/sof/audio/module_adapter/module/generic.h +++ b/src/include/sof/audio/module_adapter/module/generic.h @@ -78,7 +78,7 @@ static const struct comp_driver comp_##adapter##_module = { \ .adapter_ops = &(adapter), \ }; \ \ -static SHARED_DATA struct comp_driver_info comp_module_##adapter##_info = { \ +static struct comp_driver_info comp_module_##adapter##_info = { \ .drv = &comp_##adapter##_module, \ }; \ \ diff --git a/src/lib/clk.c b/src/lib/clk.c index 1b5025b616cb..89c159f20d31 100644 --- a/src/lib/clk.c +++ b/src/lib/clk.c @@ -24,7 +24,7 @@ SOF_DEFINE_REG_UUID(clock); DECLARE_TR_CTX(clock_tr, SOF_UUID(clock_uuid), LOG_LEVEL_INFO); -SHARED_DATA struct k_spinlock clk_lock; +struct k_spinlock clk_lock; static inline uint32_t clock_get_nearest_freq_idx(const struct freq_table *tab, uint32_t size, uint32_t hz) diff --git a/src/lib/notifier.c b/src/lib/notifier.c index 102dc55fc7b3..20770bd828a2 100644 --- a/src/lib/notifier.c +++ b/src/lib/notifier.c @@ -26,7 +26,7 @@ SOF_DEFINE_REG_UUID(notifier); DECLARE_TR_CTX(nt_tr, SOF_UUID(notifier_uuid), LOG_LEVEL_INFO); -static SHARED_DATA struct notify_data notify_data_shared[CONFIG_CORE_COUNT]; +static struct notify_data notify_data_shared[CONFIG_CORE_COUNT]; struct callback_handle { void *receiver; diff --git a/src/platform/amd/acp_6_3/include/platform/lib/memory.h b/src/platform/amd/acp_6_3/include/platform/lib/memory.h index 2b4fc43e6322..6c9e7c7f5b36 100644 --- a/src/platform/amd/acp_6_3/include/platform/lib/memory.h +++ b/src/platform/amd/acp_6_3/include/platform/lib/memory.h @@ -162,7 +162,6 @@ #if !defined(__ASSEMBLER__) && !defined(LINKER) struct sof; -#define SHARED_DATA void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/amd/acp_6_3/lib/clk.c b/src/platform/amd/acp_6_3/lib/clk.c index f060aafc22c6..9b39b46be987 100644 --- a/src/platform/amd/acp_6_3/lib/clk.c +++ b/src/platform/amd/acp_6_3/lib/clk.c @@ -51,7 +51,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; void audio_pll_power_off(void); void audio_pll_power_on(void); diff --git a/src/platform/amd/acp_6_3/lib/dma.c b/src/platform/amd/acp_6_3/lib/dma.c index 01da5ce0b528..e41c081af9e9 100644 --- a/src/platform/amd/acp_6_3/lib/dma.c +++ b/src/platform/amd/acp_6_3/lib/dma.c @@ -25,7 +25,7 @@ extern struct dma_ops acp_dai_sp_dma_ops; extern struct dma_ops acp_dai_hs_dma_ops; extern struct dma_ops acp_dai_sw_audio_dma_ops; -SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_DMA0, diff --git a/src/platform/amd/acp_6_3/lib/memory.c b/src/platform/amd/acp_6_3/lib/memory.c index 94047b7c488a..363f110516b5 100644 --- a/src/platform/amd/acp_6_3/lib/memory.c +++ b/src/platform/amd/acp_6_3/lib/memory.c @@ -12,29 +12,29 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -46,14 +46,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/amd/acp_6_3/platform.c b/src/platform/amd/acp_6_3/platform.c index e0b1f2b8fe9f..e06cf8db0e2c 100644 --- a/src/platform/amd/acp_6_3/platform.c +++ b/src/platform/amd/acp_6_3/platform.c @@ -127,7 +127,7 @@ const struct ext_man_windows xsram_window }, }; -static SHARED_DATA struct timer timer = { +static struct timer timer = { .id = TIMER0, .irq = IRQ_NUM_TIMER0, }; diff --git a/src/platform/amd/acp_7_0/include/platform/lib/memory.h b/src/platform/amd/acp_7_0/include/platform/lib/memory.h index 60a72e9f38c1..214b638da4df 100644 --- a/src/platform/amd/acp_7_0/include/platform/lib/memory.h +++ b/src/platform/amd/acp_7_0/include/platform/lib/memory.h @@ -173,7 +173,6 @@ #if !defined(__ASSEMBLER__) && !defined(LINKER) struct sof; -#define SHARED_DATA void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/amd/acp_7_0/lib/clk.c b/src/platform/amd/acp_7_0/lib/clk.c index da2b069682d0..e0ab1baf8033 100644 --- a/src/platform/amd/acp_7_0/lib/clk.c +++ b/src/platform/amd/acp_7_0/lib/clk.c @@ -50,7 +50,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; void audio_pll_power_off(void); void audio_pll_power_on(void); diff --git a/src/platform/amd/acp_7_0/lib/dma.c b/src/platform/amd/acp_7_0/lib/dma.c index bbc6b4a6cd8a..60fb1e631b5e 100644 --- a/src/platform/amd/acp_7_0/lib/dma.c +++ b/src/platform/amd/acp_7_0/lib/dma.c @@ -24,7 +24,7 @@ extern struct dma_ops acp_dai_sp_dma_ops; extern struct dma_ops acp_dai_hs_dma_ops; extern struct dma_ops acp_dai_sw_audio_dma_ops; -SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_DMA0, diff --git a/src/platform/amd/acp_7_0/lib/memory.c b/src/platform/amd/acp_7_0/lib/memory.c index ce3925e95860..fa1caa2ae726 100644 --- a/src/platform/amd/acp_7_0/lib/memory.c +++ b/src/platform/amd/acp_7_0/lib/memory.c @@ -13,29 +13,29 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -47,14 +47,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/amd/acp_7_x/include/platform/lib/memory.h b/src/platform/amd/acp_7_x/include/platform/lib/memory.h index df1007e50674..0a7039e4036b 100644 --- a/src/platform/amd/acp_7_x/include/platform/lib/memory.h +++ b/src/platform/amd/acp_7_x/include/platform/lib/memory.h @@ -228,7 +228,6 @@ #if !defined(__ASSEMBLER__) && !defined(LINKER) struct sof; -#define SHARED_DATA void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/amd/acp_7_x/lib/clk.c b/src/platform/amd/acp_7_x/lib/clk.c index 00aa89be48b2..1f0f3acd176e 100644 --- a/src/platform/amd/acp_7_x/lib/clk.c +++ b/src/platform/amd/acp_7_x/lib/clk.c @@ -68,7 +68,7 @@ typedef enum _acp_clock_type_ { } acp_clock_type_t; /* Static variables */ -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; /* Function prototypes */ void audio_pll_power_off(void); diff --git a/src/platform/amd/rembrandt/include/platform/lib/memory.h b/src/platform/amd/rembrandt/include/platform/lib/memory.h index bd618b6d9bdb..fb3f1fe30fe8 100644 --- a/src/platform/amd/rembrandt/include/platform/lib/memory.h +++ b/src/platform/amd/rembrandt/include/platform/lib/memory.h @@ -152,8 +152,6 @@ #if !defined(__ASSEMBLER__) && !defined(LINKER) struct sof; - -#define SHARED_DATA void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/amd/rembrandt/lib/clk.c b/src/platform/amd/rembrandt/lib/clk.c index 071e8c74168f..8f2529f21d57 100644 --- a/src/platform/amd/rembrandt/lib/clk.c +++ b/src/platform/amd/rembrandt/lib/clk.c @@ -19,7 +19,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(NUM_CPU_FREQ == ARRAY_SIZE(platform_cpu_freq), invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static int acp_reg_read_via_smn(uint32_t reg_offset, uint32_t size) diff --git a/src/platform/amd/rembrandt/lib/dma.c b/src/platform/amd/rembrandt/lib/dma.c index 66ddea8effe8..838e954dbc4e 100644 --- a/src/platform/amd/rembrandt/lib/dma.c +++ b/src/platform/amd/rembrandt/lib/dma.c @@ -25,7 +25,7 @@ extern struct dma_ops acp_dai_sp_dma_ops; #endif extern struct dma_ops acp_dai_hs_dma_ops; -SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_DMA0, diff --git a/src/platform/amd/renoir/include/platform/lib/memory.h b/src/platform/amd/renoir/include/platform/lib/memory.h index 0d1df900e6fd..d9a3825fbc86 100644 --- a/src/platform/amd/renoir/include/platform/lib/memory.h +++ b/src/platform/amd/renoir/include/platform/lib/memory.h @@ -147,8 +147,6 @@ #if !defined(__ASSEMBLER__) && !defined(LINKER) struct sof; - -#define SHARED_DATA void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/amd/renoir/lib/clk.c b/src/platform/amd/renoir/lib/clk.c index 4880daafac71..ea81e756e9a1 100644 --- a/src/platform/amd/renoir/lib/clk.c +++ b/src/platform/amd/renoir/lib/clk.c @@ -19,7 +19,7 @@ static struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(NUM_CPU_FREQ == ARRAY_SIZE(platform_cpu_freq), invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static int acp_reg_read_via_smn(uint32_t reg_offset, uint32_t size) diff --git a/src/platform/amd/renoir/lib/dma.c b/src/platform/amd/renoir/lib/dma.c index e6c75bee3905..2183a3464951 100644 --- a/src/platform/amd/renoir/lib/dma.c +++ b/src/platform/amd/renoir/lib/dma.c @@ -24,7 +24,7 @@ extern struct dma_ops acp_dai_bt_dma_ops; #endif extern struct dma_ops acp_dai_sp_dma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_DMA0, diff --git a/src/platform/amd/renoir/lib/memory.c b/src/platform/amd/renoir/lib/memory.c index a5b33cbb24d6..bfee7c08174d 100644 --- a/src/platform/amd/renoir/lib/memory.c +++ b/src/platform/amd/renoir/lib/memory.c @@ -12,29 +12,29 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -46,14 +46,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/amd/renoir/platform.c b/src/platform/amd/renoir/platform.c index 419f1251bd84..bccbd7c5c399 100644 --- a/src/platform/amd/renoir/platform.c +++ b/src/platform/amd/renoir/platform.c @@ -124,7 +124,7 @@ const struct ext_man_windows xsram_window }, }; -static SHARED_DATA struct timer timer_shared = { +static struct timer timer_shared = { .id = TIMER0, .irq = IRQ_NUM_TIMER0, }; diff --git a/src/platform/amd/vangogh/include/platform/lib/memory.h b/src/platform/amd/vangogh/include/platform/lib/memory.h index 49a12236833c..a9f42b597dd9 100644 --- a/src/platform/amd/vangogh/include/platform/lib/memory.h +++ b/src/platform/amd/vangogh/include/platform/lib/memory.h @@ -146,8 +146,6 @@ #if !defined(__ASSEMBLER__) && !defined(LINKER) struct sof; - -#define SHARED_DATA void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/amd/vangogh/lib/clk.c b/src/platform/amd/vangogh/lib/clk.c index 25f7befed373..b91472a739ce 100644 --- a/src/platform/amd/vangogh/lib/clk.c +++ b/src/platform/amd/vangogh/lib/clk.c @@ -21,7 +21,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(NUM_CPU_FREQ == ARRAY_SIZE(platform_cpu_freq), invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static int acp_reg_read_via_smn(uint32_t reg_offset, uint32_t size) diff --git a/src/platform/amd/vangogh/lib/dma.c b/src/platform/amd/vangogh/lib/dma.c index cd764542dcfa..3a16b1d1ba65 100644 --- a/src/platform/amd/vangogh/lib/dma.c +++ b/src/platform/amd/vangogh/lib/dma.c @@ -23,7 +23,7 @@ extern struct dma_ops acp_dai_bt_dma_ops; extern struct dma_ops acp_dai_sp_dma_ops; extern struct dma_ops acp_dai_hs_dma_ops; -SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_DMA0, diff --git a/src/platform/amd/vangogh/lib/memory.c b/src/platform/amd/vangogh/lib/memory.c index d4a0ab144706..566175154721 100644 --- a/src/platform/amd/vangogh/lib/memory.c +++ b/src/platform/amd/vangogh/lib/memory.c @@ -13,29 +13,29 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -47,14 +47,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/amd/vangogh/platform.c b/src/platform/amd/vangogh/platform.c index 300239a023be..da2c24bfb067 100644 --- a/src/platform/amd/vangogh/platform.c +++ b/src/platform/amd/vangogh/platform.c @@ -123,7 +123,7 @@ const struct ext_man_windows xsram_window }, }; -static SHARED_DATA struct timer timer = { +static struct timer timer = { .id = TIMER0, .irq = IRQ_NUM_TIMER0, }; diff --git a/src/platform/imx8/include/platform/lib/memory.h b/src/platform/imx8/include/platform/lib/memory.h index 674d1af2611f..862abcd49d25 100644 --- a/src/platform/imx8/include/platform/lib/memory.h +++ b/src/platform/imx8/include/platform/lib/memory.h @@ -179,12 +179,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since IMX doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -195,9 +189,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since IMX doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since IMX doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/imx8/lib/clk.c b/src/platform/imx8/lib/clk.c index 152cac1752d7..4eeb2dac3357 100644 --- a/src/platform/imx8/lib/clk.c +++ b/src/platform/imx8/lib/clk.c @@ -24,7 +24,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(NUM_CPU_FREQ == ARRAY_SIZE(platform_cpu_freq), invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; void platform_clock_init(struct sof *sof) { diff --git a/src/platform/imx8/lib/dai.c b/src/platform/imx8/lib/dai.c index 69366cf18d3f..a0f8fcc39135 100644 --- a/src/platform/imx8/lib/dai.c +++ b/src/platform/imx8/lib/dai.c @@ -15,7 +15,7 @@ #include #include -static SHARED_DATA struct dai esai[] = { +static struct dai esai[] = { { .index = 0, .plat_data = { @@ -39,7 +39,7 @@ static SHARED_DATA struct dai esai[] = { }, }; -static SHARED_DATA struct dai sai[] = { +static struct dai sai[] = { { .index = 1, .plat_data = { diff --git a/src/platform/imx8/lib/dma.c b/src/platform/imx8/lib/dma.c index e5a40d251557..dc3efa653d0a 100644 --- a/src/platform/imx8/lib/dma.c +++ b/src/platform/imx8/lib/dma.c @@ -22,7 +22,7 @@ static const int edma0_ints[EDMA0_CHAN_MAX] = { [EDMA0_SAI_CHAN_TX] = EDMA0_SAI_CHAN_TX_IRQ, }; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_EDMA0, diff --git a/src/platform/imx8/lib/memory.c b/src/platform/imx8/lib/memory.c index d4527d756ac1..81794bafd6d6 100644 --- a/src/platform/imx8/lib/memory.c +++ b/src/platform/imx8/lib/memory.c @@ -12,29 +12,29 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -46,14 +46,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/imx8m/include/platform/lib/memory.h b/src/platform/imx8m/include/platform/lib/memory.h index 490e65a0052d..671a9ca77095 100644 --- a/src/platform/imx8m/include/platform/lib/memory.h +++ b/src/platform/imx8m/include/platform/lib/memory.h @@ -198,12 +198,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since IMX doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -214,9 +208,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since IMX doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since IMX doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/imx8m/lib/clk.c b/src/platform/imx8m/lib/clk.c index 78aacfd05e28..573858873ef8 100644 --- a/src/platform/imx8m/lib/clk.c +++ b/src/platform/imx8m/lib/clk.c @@ -19,7 +19,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(NUM_CPU_FREQ == ARRAY_SIZE(platform_cpu_freq), invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; void platform_clock_init(struct sof *sof) { diff --git a/src/platform/imx8m/lib/dai.c b/src/platform/imx8m/lib/dai.c index 1293cdc6fd7f..433c27ef141a 100644 --- a/src/platform/imx8m/lib/dai.c +++ b/src/platform/imx8m/lib/dai.c @@ -15,7 +15,7 @@ #include #include -static SHARED_DATA struct dai sai[] = { +static struct dai sai[] = { { .index = 1, .plat_data = { @@ -144,7 +144,7 @@ static SHARED_DATA struct dai sai[] = { }; -static SHARED_DATA struct dai micfil[] = { +static struct dai micfil[] = { { .index = 2, .plat_data = { diff --git a/src/platform/imx8m/lib/dma.c b/src/platform/imx8m/lib/dma.c index f9cb5a74682a..c9fe4a98e030 100644 --- a/src/platform/imx8m/lib/dma.c +++ b/src/platform/imx8m/lib/dma.c @@ -14,7 +14,7 @@ extern struct dma_ops dummy_dma_ops; extern struct dma_ops sdma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_HOST, diff --git a/src/platform/imx8m/lib/memory.c b/src/platform/imx8m/lib/memory.c index 9f26cd3ebe80..3f2eceee1afb 100644 --- a/src/platform/imx8m/lib/memory.c +++ b/src/platform/imx8m/lib/memory.c @@ -12,30 +12,30 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -48,14 +48,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/imx8m_cm7/include/platform/lib/memory.h b/src/platform/imx8m_cm7/include/platform/lib/memory.h index af0b0b823e24..14886bf371fc 100644 --- a/src/platform/imx8m_cm7/include/platform/lib/memory.h +++ b/src/platform/imx8m_cm7/include/platform/lib/memory.h @@ -12,8 +12,6 @@ #define PLATFORM_DCACHE_ALIGN DCACHE_LINE_SIZE -#define SHARED_DATA - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/imx8ulp/include/platform/lib/memory.h b/src/platform/imx8ulp/include/platform/lib/memory.h index ee74e6989e86..a84c6f56da48 100644 --- a/src/platform/imx8ulp/include/platform/lib/memory.h +++ b/src/platform/imx8ulp/include/platform/lib/memory.h @@ -182,12 +182,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since IMX doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -198,9 +192,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since IMX doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since IMX doesn't support SMP. */ static inline void platform_shared_commit(void *ptr, int bytes) { } diff --git a/src/platform/imx8ulp/lib/clk.c b/src/platform/imx8ulp/lib/clk.c index 93a0a83ed54d..3bdc873eacf9 100644 --- a/src/platform/imx8ulp/lib/clk.c +++ b/src/platform/imx8ulp/lib/clk.c @@ -19,7 +19,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(NUM_CPU_FREQ == ARRAY_SIZE(platform_cpu_freq), invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; void platform_clock_init(struct sof *sof) { diff --git a/src/platform/imx8ulp/lib/dai.c b/src/platform/imx8ulp/lib/dai.c index 879da871ffcb..797bbc3260be 100644 --- a/src/platform/imx8ulp/lib/dai.c +++ b/src/platform/imx8ulp/lib/dai.c @@ -14,7 +14,7 @@ #include #include -static SHARED_DATA struct dai sai[] = { +static struct dai sai[] = { { .index = 5, .plat_data = { diff --git a/src/platform/imx8ulp/lib/dma.c b/src/platform/imx8ulp/lib/dma.c index 0cfc47f68039..81b3e0f09de2 100644 --- a/src/platform/imx8ulp/lib/dma.c +++ b/src/platform/imx8ulp/lib/dma.c @@ -20,7 +20,7 @@ static const int edma2_ints[IMX8ULP_EDMA2_CHAN_MAX] = { [IMX8ULP_EDMA2_CHAN1] = IMX8ULP_EDMA2_CHAN1_IRQ, }; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_EDMA2, diff --git a/src/platform/imx8ulp/lib/memory.c b/src/platform/imx8ulp/lib/memory.c index cafd4b5d3d0c..9224dae6e05f 100644 --- a/src/platform/imx8ulp/lib/memory.c +++ b/src/platform/imx8ulp/lib/memory.c @@ -13,29 +13,29 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -47,14 +47,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/imx93_a55/include/platform/lib/memory.h b/src/platform/imx93_a55/include/platform/lib/memory.h index b9c84ff42a7f..6b74eb7e5d53 100644 --- a/src/platform/imx93_a55/include/platform/lib/memory.h +++ b/src/platform/imx93_a55/include/platform/lib/memory.h @@ -20,8 +20,6 @@ * thing so all the below cache/shared data "management" * functions aren't necessary. */ -#define SHARED_DATA - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/imx95/include/platform/lib/memory.h b/src/platform/imx95/include/platform/lib/memory.h index 552c20e32530..0679e74242de 100644 --- a/src/platform/imx95/include/platform/lib/memory.h +++ b/src/platform/imx95/include/platform/lib/memory.h @@ -12,8 +12,6 @@ #define PLATFORM_DCACHE_ALIGN DCACHE_LINE_SIZE -#define SHARED_DATA - #define uncache_to_cache(address) address #define cache_to_uncache(address) address #define cache_to_uncache_init(address) address diff --git a/src/platform/intel/ace/include/ace/lib/memory.h b/src/platform/intel/ace/include/ace/lib/memory.h index f5740a7d659d..803acec71ce9 100644 --- a/src/platform/intel/ace/include/ace/lib/memory.h +++ b/src/platform/intel/ace/include/ace/lib/memory.h @@ -19,14 +19,6 @@ /* data cache line alignment */ #define PLATFORM_DCACHE_ALIGN DCACHE_LINE_SIZE -/** - * \brief Data shared between different cores. - * Placed into dedicated section, which should be accessed through - * uncached memory region. SMP platforms without uncache can simply - * align to cache line size instead. - */ -#define SHARED_DATA - #include #define uncache_to_cache(address) sys_cache_cached_ptr_get(address) diff --git a/src/platform/intel/cavs/include/cavs/lib/memory.h b/src/platform/intel/cavs/include/cavs/lib/memory.h index 0473131da6c8..ee8cd030df3c 100644 --- a/src/platform/intel/cavs/include/cavs/lib/memory.h +++ b/src/platform/intel/cavs/include/cavs/lib/memory.h @@ -33,18 +33,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Placed into dedicated section, which should be accessed through - * uncached memory region. SMP platforms without uncache can simply - * align to cache line size instead. - */ -#if !defined(UNIT_TEST) && !defined __ZEPHYR__ -#define SHARED_DATA __section(".shared_data") __attribute__((aligned(PLATFORM_DCACHE_ALIGN))) -#else -#define SHARED_DATA -#endif - #define SRAM_ALIAS_BASE 0x9E000000 #define SRAM_ALIAS_MASK 0xFF000000 #define SRAM_ALIAS_OFFSET SRAM_UNCACHED_ALIAS diff --git a/src/platform/library/include/platform/lib/memory.h b/src/platform/library/include/platform/lib/memory.h index 11f0114c1dde..4fe40783573c 100644 --- a/src/platform/library/include/platform/lib/memory.h +++ b/src/platform/library/include/platform/lib/memory.h @@ -35,8 +35,6 @@ uint8_t *get_library_mailbox(void); #define PLATFORM_HEAP_SYSTEM_SHARED 1 #define PLATFORM_HEAP_RUNTIME_SHARED 1 -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/library/lib/memory.c b/src/platform/library/lib/memory.c index 1a03d1ecf503..3f92c62889d7 100644 --- a/src/platform/library/lib/memory.c +++ b/src/platform/library/lib/memory.c @@ -27,22 +27,22 @@ #define HEAP_BUFFER_BASE 0xBE1C0000 /* Heap blocks for system runtime for primary core */ -static SHARED_DATA struct block_hdr sys_rt_0_block64[HEAP_SYS_RT_0_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_0_block512[HEAP_SYS_RT_0_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_0_block1024[HEAP_SYS_RT_0_COUNT1024]; +static struct block_hdr sys_rt_0_block64[HEAP_SYS_RT_0_COUNT64]; +static struct block_hdr sys_rt_0_block512[HEAP_SYS_RT_0_COUNT512]; +static struct block_hdr sys_rt_0_block1024[HEAP_SYS_RT_0_COUNT1024]; /* Heap blocks for system runtime for secondary core */ #if CONFIG_CORE_COUNT > 1 -static SHARED_DATA struct block_hdr +static struct block_hdr sys_rt_x_block64[CONFIG_CORE_COUNT - 1][HEAP_SYS_RT_X_COUNT64]; -static SHARED_DATA struct block_hdr +static struct block_hdr sys_rt_x_block512[CONFIG_CORE_COUNT - 1][HEAP_SYS_RT_X_COUNT512]; -static SHARED_DATA struct block_hdr +static struct block_hdr sys_rt_x_block1024[CONFIG_CORE_COUNT - 1][HEAP_SYS_RT_X_COUNT1024]; #endif /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[CONFIG_CORE_COUNT][3] = { +static struct block_map sys_rt_heap_map[CONFIG_CORE_COUNT][3] = { { BLOCK_DEF(64, HEAP_SYS_RT_0_COUNT64, uncached_block_hdr(sys_rt_0_block64)), BLOCK_DEF(512, HEAP_SYS_RT_0_COUNT512, @@ -76,16 +76,16 @@ static SHARED_DATA struct block_map sys_rt_heap_map[CONFIG_CORE_COUNT][3] = { }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block64[HEAP_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_COUNT4096]; +static struct block_hdr mod_block64[HEAP_COUNT64]; +static struct block_hdr mod_block128[HEAP_COUNT128]; +static struct block_hdr mod_block256[HEAP_COUNT256]; +static struct block_hdr mod_block512[HEAP_COUNT512]; +static struct block_hdr mod_block1024[HEAP_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(64, HEAP_COUNT64, uncached_block_hdr(mod_block64)), BLOCK_DEF(128, HEAP_COUNT128, uncached_block_hdr(mod_block128)), BLOCK_DEF(256, HEAP_COUNT256, uncached_block_hdr(mod_block256)), @@ -97,14 +97,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { #if CONFIG_CORE_COUNT > 1 /* Heap blocks for runtime shared */ -static SHARED_DATA struct block_hdr rt_shared_block64[HEAP_RUNTIME_SHARED_COUNT64]; -static SHARED_DATA struct block_hdr rt_shared_block128[HEAP_RUNTIME_SHARED_COUNT128]; -static SHARED_DATA struct block_hdr rt_shared_block256[HEAP_RUNTIME_SHARED_COUNT256]; -static SHARED_DATA struct block_hdr rt_shared_block512[HEAP_RUNTIME_SHARED_COUNT512]; -static SHARED_DATA struct block_hdr rt_shared_block1024[HEAP_RUNTIME_SHARED_COUNT1024]; +static struct block_hdr rt_shared_block64[HEAP_RUNTIME_SHARED_COUNT64]; +static struct block_hdr rt_shared_block128[HEAP_RUNTIME_SHARED_COUNT128]; +static struct block_hdr rt_shared_block256[HEAP_RUNTIME_SHARED_COUNT256]; +static struct block_hdr rt_shared_block512[HEAP_RUNTIME_SHARED_COUNT512]; +static struct block_hdr rt_shared_block1024[HEAP_RUNTIME_SHARED_COUNT1024]; /* Heap memory map for runtime shared */ -static SHARED_DATA struct block_map rt_shared_heap_map[] = { +static struct block_map rt_shared_heap_map[] = { BLOCK_DEF(64, HEAP_RUNTIME_SHARED_COUNT64, uncached_block_hdr(rt_shared_block64)), BLOCK_DEF(128, HEAP_RUNTIME_SHARED_COUNT128, uncached_block_hdr(rt_shared_block128)), BLOCK_DEF(256, HEAP_RUNTIME_SHARED_COUNT256, uncached_block_hdr(rt_shared_block256)), @@ -114,21 +114,21 @@ static SHARED_DATA struct block_map rt_shared_heap_map[] = { #endif /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT_MAX]; -static SHARED_DATA struct block_hdr lp_buf_block[HEAP_LP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT_MAX]; +static struct block_hdr lp_buf_block[HEAP_LP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT_MAX, uncached_block_hdr(buf_block)), }; -static SHARED_DATA struct block_map lp_buf_heap_map[] = { +static struct block_map lp_buf_heap_map[] = { BLOCK_DEF(HEAP_LP_BUFFER_BLOCK_SIZE, HEAP_LP_BUFFER_COUNT, uncached_block_hdr(lp_buf_block)), }; -static SHARED_DATA struct mm memmap; +static struct mm memmap; void platform_init_memmap(struct sof *sof) { diff --git a/src/platform/library/platform.c b/src/platform/library/platform.c index 756c34c996f4..ced1dcbca32d 100644 --- a/src/platform/library/platform.c +++ b/src/platform/library/platform.c @@ -13,7 +13,7 @@ #include #include -static SHARED_DATA struct timer timer = {}; +static struct timer timer = {}; static uint8_t mailbox[MAILBOX_DSPBOX_SIZE + MAILBOX_HOSTBOX_SIZE + diff --git a/src/platform/mt8186/include/platform/lib/memory.h b/src/platform/mt8186/include/platform/lib/memory.h index 305e4c917846..68c95bb53db0 100644 --- a/src/platform/mt8186/include/platform/lib/memory.h +++ b/src/platform/mt8186/include/platform/lib/memory.h @@ -184,12 +184,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since mt8186 doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -200,9 +194,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since mt8186 doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since mt8186 doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/mt8186/lib/clk.c b/src/platform/mt8186/lib/clk.c index 6a5b2910c506..b1b88ff9fe7b 100644 --- a/src/platform/mt8186/lib/clk.c +++ b/src/platform/mt8186/lib/clk.c @@ -32,7 +32,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static void clk_dsppll_enable(uint32_t value) { diff --git a/src/platform/mt8186/lib/dai.c b/src/platform/mt8186/lib/dai.c index 4d302d48fbdc..a45056846a2e 100644 --- a/src/platform/mt8186/lib/dai.c +++ b/src/platform/mt8186/lib/dai.c @@ -23,7 +23,7 @@ static int afe_dai_handshake[MT8186_DAI_NUM] = { AFE_HANDSHAKE(MT8186_AFE_IO_I2S0, MT8186_IRQ_12, MT8186_MEMIF_UL2), }; -static SHARED_DATA struct dai afe_dai[MT8186_DAI_NUM]; +static struct dai afe_dai[MT8186_DAI_NUM]; const struct dai_type_info dti[] = { { diff --git a/src/platform/mt8186/lib/dma.c b/src/platform/mt8186/lib/dma.c index db00628ae547..a8e3308367fc 100644 --- a/src/platform/mt8186/lib/dma.c +++ b/src/platform/mt8186/lib/dma.c @@ -19,7 +19,7 @@ extern const struct dma_ops dummy_dma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_HOST, diff --git a/src/platform/mt8186/lib/memory.c b/src/platform/mt8186/lib/memory.c index 1ffc41859713..beae268b7f6f 100644 --- a/src/platform/mt8186/lib/memory.c +++ b/src/platform/mt8186/lib/memory.c @@ -13,30 +13,30 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -49,14 +49,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/mt8186/platform.c b/src/platform/mt8186/platform.c index e08766eba70d..7d708750f8f0 100644 --- a/src/platform/mt8186/platform.c +++ b/src/platform/mt8186/platform.c @@ -121,7 +121,7 @@ const struct ext_man_windows xsram_window } }; -static SHARED_DATA struct timer timer_shared = { +static struct timer timer_shared = { .id = OSTIMER0, .irq = MTK_DSP_IRQ_OSTIMER32, }; diff --git a/src/platform/mt8188/include/platform/lib/memory.h b/src/platform/mt8188/include/platform/lib/memory.h index 305e4c917846..17343e78ef76 100644 --- a/src/platform/mt8188/include/platform/lib/memory.h +++ b/src/platform/mt8188/include/platform/lib/memory.h @@ -39,7 +39,7 @@ #define EXT_MANIFEST_ELF_SIZE (SRAM_BASE + SRAM_SIZE - EXT_MANIFEST_ELF_BASE) /* - * The Memory Layout on MT8186 are organised like this :- + * The Memory Layout on MT8188 are organised like this :- * * +--------------------------------------------------------------------------+ * | Offset | Region | Size | @@ -184,12 +184,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since mt8186 doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -200,9 +194,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since mt8186 doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since mt8188 doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/mt8188/lib/clk.c b/src/platform/mt8188/lib/clk.c index bd97dad069a4..7a179128c1fc 100644 --- a/src/platform/mt8188/lib/clk.c +++ b/src/platform/mt8188/lib/clk.c @@ -32,7 +32,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static void clk_dsppll_enable(uint32_t value) { diff --git a/src/platform/mt8188/lib/dai.c b/src/platform/mt8188/lib/dai.c index d721bd4c1d39..53b30146a2fd 100644 --- a/src/platform/mt8188/lib/dai.c +++ b/src/platform/mt8188/lib/dai.c @@ -23,7 +23,7 @@ static int afe_dai_handshake[MT8188_DAI_NUM] = { AFE_HANDSHAKE(MT8188_AFE_IO_ETDM2_IN, MT8188_IRQ_22, MT8188_MEMIF_UL5), }; -static SHARED_DATA struct dai afe_dai[MT8188_DAI_NUM]; +static struct dai afe_dai[MT8188_DAI_NUM]; const struct dai_type_info dti[] = { { diff --git a/src/platform/mt8188/lib/dma.c b/src/platform/mt8188/lib/dma.c index aa377133b730..51bcb18a16ef 100644 --- a/src/platform/mt8188/lib/dma.c +++ b/src/platform/mt8188/lib/dma.c @@ -19,7 +19,7 @@ extern const struct dma_ops dummy_dma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_HOST, diff --git a/src/platform/mt8188/lib/memory.c b/src/platform/mt8188/lib/memory.c index 5ef0828ffc6c..6475b01e48ad 100644 --- a/src/platform/mt8188/lib/memory.c +++ b/src/platform/mt8188/lib/memory.c @@ -13,30 +13,30 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -49,14 +49,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/mt8188/platform.c b/src/platform/mt8188/platform.c index d3433a3b46c8..babedcba3ac6 100644 --- a/src/platform/mt8188/platform.c +++ b/src/platform/mt8188/platform.c @@ -121,7 +121,7 @@ const struct ext_man_windows xsram_window } }; -static SHARED_DATA struct timer timer_shared = { +static struct timer timer_shared = { .id = OSTIMER0, .irq = MTK_DSP_IRQ_OSTIMER32, }; diff --git a/src/platform/mt8195/include/platform/lib/memory.h b/src/platform/mt8195/include/platform/lib/memory.h index 7a93d36d1b2a..75b8b3348e04 100644 --- a/src/platform/mt8195/include/platform/lib/memory.h +++ b/src/platform/mt8195/include/platform/lib/memory.h @@ -175,12 +175,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since mt8195 doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -191,9 +185,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since mt8195 doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since mt8195 doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/mt8195/lib/clk.c b/src/platform/mt8195/lib/clk.c index 894396ab4855..6fc89418650e 100644 --- a/src/platform/mt8195/lib/clk.c +++ b/src/platform/mt8195/lib/clk.c @@ -41,7 +41,7 @@ const uint32_t cpu_freq_enc[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static inline void clk_setl(uint32_t addr, uint32_t val) { diff --git a/src/platform/mt8195/lib/dai.c b/src/platform/mt8195/lib/dai.c index c385331489a6..e2e291e19f6e 100644 --- a/src/platform/mt8195/lib/dai.c +++ b/src/platform/mt8195/lib/dai.c @@ -23,7 +23,7 @@ static int afe_dai_handshake[MT8195_DAI_NUM] = { AFE_HANDSHAKE(MT8195_AFE_IO_ETDM2_IN, MT8195_IRQ_22, MT8195_MEMIF_UL5), }; -static SHARED_DATA struct dai afe_dai[MT8195_DAI_NUM]; +static struct dai afe_dai[MT8195_DAI_NUM]; const struct dai_type_info dti[] = { { diff --git a/src/platform/mt8195/lib/dma.c b/src/platform/mt8195/lib/dma.c index 7a9719e8a30c..89ee43af7eac 100644 --- a/src/platform/mt8195/lib/dma.c +++ b/src/platform/mt8195/lib/dma.c @@ -18,7 +18,7 @@ extern struct dma_ops dummy_dma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_HOST, diff --git a/src/platform/mt8195/lib/memory.c b/src/platform/mt8195/lib/memory.c index c452a0520cc7..0fbfb0f5b3d1 100644 --- a/src/platform/mt8195/lib/memory.c +++ b/src/platform/mt8195/lib/memory.c @@ -12,30 +12,30 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -48,14 +48,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/mt8195/platform.c b/src/platform/mt8195/platform.c index 6a08580ad043..c1e59049b57a 100644 --- a/src/platform/mt8195/platform.c +++ b/src/platform/mt8195/platform.c @@ -121,7 +121,7 @@ const struct ext_man_windows xsram_window } }; -static SHARED_DATA struct timer timer_shared = { +static struct timer timer_shared = { .id = OSTIMER0, .irq = LX_ADSP_TIMTER_IRQ0_B, }; diff --git a/src/platform/mt8196/include/platform/lib/memory.h b/src/platform/mt8196/include/platform/lib/memory.h index b849fe09cb4f..41536d2ace4b 100644 --- a/src/platform/mt8196/include/platform/lib/memory.h +++ b/src/platform/mt8196/include/platform/lib/memory.h @@ -38,7 +38,7 @@ #define EXT_MANIFEST_ELF_SIZE (SRAM_BASE + SRAM_SIZE - EXT_MANIFEST_ELF_BASE) /* - * The Memory Layout on MT8189 are organised like this :- + * The Memory Layout on MT8196 are organised like this :- * * +--------------------------------------------------------------------------+ * | Offset | Region | Size | @@ -183,12 +183,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since mt8186 doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -199,9 +193,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since mt8186 doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since mt8196 doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/mt8196/lib/clk.c b/src/platform/mt8196/lib/clk.c index ebf109a0c9fc..a860a04b0133 100644 --- a/src/platform/mt8196/lib/clk.c +++ b/src/platform/mt8196/lib/clk.c @@ -30,7 +30,7 @@ const struct freq_table platform_cpu_freq[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; void platform_clock_init(struct sof *sof) { diff --git a/src/platform/mt8196/lib/dai.c b/src/platform/mt8196/lib/dai.c index 6f5300e6aa48..63a08e5eb095 100755 --- a/src/platform/mt8196/lib/dai.c +++ b/src/platform/mt8196/lib/dai.c @@ -24,7 +24,7 @@ static int afe_dai_handshake[MT8196_DAI_NUM] = { AFE_HANDSHAKE(MT8196_DAI_AP_DMIC_CH34, MT8196_IRQ_15, MT8196_MEMIF_UL2), }; -static SHARED_DATA struct dai afe_dai[MT8196_DAI_NUM]; +static struct dai afe_dai[MT8196_DAI_NUM]; const struct dai_type_info dti[] = { { diff --git a/src/platform/mt8196/lib/dma.c b/src/platform/mt8196/lib/dma.c index 0cc4e1043a26..fef728fc87ea 100644 --- a/src/platform/mt8196/lib/dma.c +++ b/src/platform/mt8196/lib/dma.c @@ -18,7 +18,7 @@ extern const struct dma_ops dummy_dma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_HOST, diff --git a/src/platform/mt8196/lib/memory.c b/src/platform/mt8196/lib/memory.c index 7445f1713830..c46956ed4946 100644 --- a/src/platform/mt8196/lib/memory.c +++ b/src/platform/mt8196/lib/memory.c @@ -12,30 +12,30 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -48,14 +48,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/mt8196/platform.c b/src/platform/mt8196/platform.c index c093e7b003ef..8cb188ce2210 100644 --- a/src/platform/mt8196/platform.c +++ b/src/platform/mt8196/platform.c @@ -120,7 +120,7 @@ const struct ext_man_windows xsram_window } }; -static SHARED_DATA struct timer timer_shared = { +static struct timer timer_shared = { .id = OSTIMER0, .irq = MTK_DSP_IRQ_OSTIMER32_C0, }; diff --git a/src/platform/mt8365/include/platform/lib/memory.h b/src/platform/mt8365/include/platform/lib/memory.h index 75965466ae95..93bf268c93a2 100644 --- a/src/platform/mt8365/include/platform/lib/memory.h +++ b/src/platform/mt8365/include/platform/lib/memory.h @@ -198,12 +198,6 @@ struct sof; -/** - * \brief Data shared between different cores. - * Does nothing, since mt8195 doesn't support SMP. - */ -#define SHARED_DATA - void platform_init_memmap(struct sof *sof); #define uncache_to_cache(address) address @@ -214,9 +208,8 @@ void platform_init_memmap(struct sof *sof); /** * \brief Function for keeping shared data synchronized. * It's used after usage of data shared by different cores. - * Such data is either statically marked with SHARED_DATA - * or dynamically allocated with SOF_MEM_FLAG_SHARED flag. - * Does nothing, since mt8195 doesn't support SMP. + * Such data is dynamically allocated with SOF_MEM_FLAG_SHARED + * flag. Does nothing, since mt8195 doesn't support SMP. */ static inline void *platform_rfree_prepare(void *ptr) diff --git a/src/platform/mt8365/lib/clk.c b/src/platform/mt8365/lib/clk.c index 57bc821049fb..e685e1e2d4fc 100644 --- a/src/platform/mt8365/lib/clk.c +++ b/src/platform/mt8365/lib/clk.c @@ -41,7 +41,7 @@ const uint32_t cpu_freq_enc[] = { STATIC_ASSERT(ARRAY_SIZE(platform_cpu_freq) == NUM_CPU_FREQ, invalid_number_of_cpu_frequencies); -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static inline void clk_setl(uint32_t addr, uint32_t val) { diff --git a/src/platform/mt8365/lib/dai.c b/src/platform/mt8365/lib/dai.c index 6700e3257ac2..522952996d75 100644 --- a/src/platform/mt8365/lib/dai.c +++ b/src/platform/mt8365/lib/dai.c @@ -37,7 +37,7 @@ static int afe_dai_handshake[MT8365_DAI_NUM] = { AFE_HANDSHAKE(MT8365_AFE_IO_DMIC, MT8365_AFE_IRQ_4, MT8365_MEMIF_VUL), }; -static SHARED_DATA struct dai afe_dai[MT8365_DAI_NUM]; +static struct dai afe_dai[MT8365_DAI_NUM]; const struct dai_type_info dti[] = { { diff --git a/src/platform/mt8365/lib/dma.c b/src/platform/mt8365/lib/dma.c index 9e6209790731..d80c81723676 100644 --- a/src/platform/mt8365/lib/dma.c +++ b/src/platform/mt8365/lib/dma.c @@ -18,7 +18,7 @@ extern const struct dma_ops dummy_dma_ops; -static SHARED_DATA struct dma dma[PLATFORM_NUM_DMACS] = { +static struct dma dma[PLATFORM_NUM_DMACS] = { { .plat_data = { .id = DMA_ID_HOST, diff --git a/src/platform/mt8365/lib/memory.c b/src/platform/mt8365/lib/memory.c index 7ed1417dc1f2..e64eef957742 100644 --- a/src/platform/mt8365/lib/memory.c +++ b/src/platform/mt8365/lib/memory.c @@ -12,30 +12,30 @@ #include /* Heap blocks for system runtime */ -static SHARED_DATA struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; -static SHARED_DATA struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; -static SHARED_DATA struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; +static struct block_hdr sys_rt_block64[HEAP_SYS_RT_COUNT64]; +static struct block_hdr sys_rt_block512[HEAP_SYS_RT_COUNT512]; +static struct block_hdr sys_rt_block1024[HEAP_SYS_RT_COUNT1024]; /* Heap memory for system runtime */ -static SHARED_DATA struct block_map sys_rt_heap_map[] = { +static struct block_map sys_rt_heap_map[] = { BLOCK_DEF(64, HEAP_SYS_RT_COUNT64, sys_rt_block64), BLOCK_DEF(512, HEAP_SYS_RT_COUNT512, sys_rt_block512), BLOCK_DEF(1024, HEAP_SYS_RT_COUNT1024, sys_rt_block1024), }; /* Heap blocks for modules */ -static SHARED_DATA struct block_hdr mod_block16[HEAP_RT_COUNT16]; -static SHARED_DATA struct block_hdr mod_block32[HEAP_RT_COUNT32]; -static SHARED_DATA struct block_hdr mod_block64[HEAP_RT_COUNT64]; -static SHARED_DATA struct block_hdr mod_block128[HEAP_RT_COUNT128]; -static SHARED_DATA struct block_hdr mod_block256[HEAP_RT_COUNT256]; -static SHARED_DATA struct block_hdr mod_block512[HEAP_RT_COUNT512]; -static SHARED_DATA struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; -static SHARED_DATA struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; -static SHARED_DATA struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; +static struct block_hdr mod_block16[HEAP_RT_COUNT16]; +static struct block_hdr mod_block32[HEAP_RT_COUNT32]; +static struct block_hdr mod_block64[HEAP_RT_COUNT64]; +static struct block_hdr mod_block128[HEAP_RT_COUNT128]; +static struct block_hdr mod_block256[HEAP_RT_COUNT256]; +static struct block_hdr mod_block512[HEAP_RT_COUNT512]; +static struct block_hdr mod_block1024[HEAP_RT_COUNT1024]; +static struct block_hdr mod_block2048[HEAP_RT_COUNT2048]; +static struct block_hdr mod_block4096[HEAP_RT_COUNT4096]; /* Heap memory map for modules */ -static SHARED_DATA struct block_map rt_heap_map[] = { +static struct block_map rt_heap_map[] = { BLOCK_DEF(16, HEAP_RT_COUNT16, mod_block16), BLOCK_DEF(32, HEAP_RT_COUNT32, mod_block32), BLOCK_DEF(64, HEAP_RT_COUNT64, mod_block64), @@ -48,14 +48,14 @@ static SHARED_DATA struct block_map rt_heap_map[] = { }; /* Heap blocks for buffers */ -static SHARED_DATA struct block_hdr buf_block[HEAP_BUFFER_COUNT]; +static struct block_hdr buf_block[HEAP_BUFFER_COUNT]; /* Heap memory map for buffers */ -static SHARED_DATA struct block_map buf_heap_map[] = { +static struct block_map buf_heap_map[] = { BLOCK_DEF(HEAP_BUFFER_BLOCK_SIZE, HEAP_BUFFER_COUNT, buf_block), }; -static SHARED_DATA struct mm memmap = { +static struct mm memmap = { .system[0] = { .heap = HEAP_SYSTEM_BASE, .size = HEAP_SYSTEM_SIZE, diff --git a/src/platform/mt8365/platform.c b/src/platform/mt8365/platform.c index 5ae6378c5eb5..93e617cdebbf 100644 --- a/src/platform/mt8365/platform.c +++ b/src/platform/mt8365/platform.c @@ -120,7 +120,7 @@ const struct ext_man_windows xsram_window } }; -static SHARED_DATA struct timer timer_shared = { +static struct timer timer_shared = { .id = OSTIMER0, .irq = SYSTICK_TIMER_IRQ, }; diff --git a/src/platform/mtk/include/platform/lib/memory.h b/src/platform/mtk/include/platform/lib/memory.h index 1e3acbee6912..b5ce4de855ab 100644 --- a/src/platform/mtk/include/platform/lib/memory.h +++ b/src/platform/mtk/include/platform/lib/memory.h @@ -23,8 +23,6 @@ BUILD_ASSERT(PLATFORM_DCACHE_ALIGN == XCHAL_DCACHE_LINESIZE); #define PLATFORM_HEAP_RUNTIME 1 #define PLATFORM_HEAP_BUFFER 1 -#define SHARED_DATA /* no special section attribute needed */ - /* Mailbox window addresses for the rimage extended manifest. The * struct is optimized out in generated code, it's just here to be a * little clearer than the pages of #defines used traditionally. diff --git a/src/platform/posix/include/platform/lib/memory.h b/src/platform/posix/include/platform/lib/memory.h index f2f6e567223b..e24c48aa40b3 100644 --- a/src/platform/posix/include/platform/lib/memory.h +++ b/src/platform/posix/include/platform/lib/memory.h @@ -47,6 +47,4 @@ extern uint32_t posix_trace[]; #define host_to_local(addr) (addr) -#define SHARED_DATA /**/ - #endif /* PLATFORM_HOST_PLATFORM_MEMORY_H */ diff --git a/src/platform/qemu_xtensa/include/platform/lib/memory.h b/src/platform/qemu_xtensa/include/platform/lib/memory.h index 7c8f9da9c1c1..57f001de169b 100644 --- a/src/platform/qemu_xtensa/include/platform/lib/memory.h +++ b/src/platform/qemu_xtensa/include/platform/lib/memory.h @@ -10,6 +10,5 @@ #define PLATFORM_DCACHE_ALIGN sizeof(void *) #define HOST_PAGE_SIZE 4096 -#define SHARED_DATA #endif /* __PLATFORM_LIB_MEMORY_H__ */ diff --git a/src/samples/audio/detect_test.c b/src/samples/audio/detect_test.c index 7979d7db3d6c..2ce5f01f3999 100644 --- a/src/samples/audio/detect_test.c +++ b/src/samples/audio/detect_test.c @@ -1107,7 +1107,7 @@ static const struct comp_driver comp_keyword = { }, }; -static SHARED_DATA struct comp_driver_info comp_keyword_info = { +static struct comp_driver_info comp_keyword_info = { .drv = &comp_keyword, }; diff --git a/src/samples/audio/smart_amp_test_ipc3.c b/src/samples/audio/smart_amp_test_ipc3.c index 1172fb3c0716..da1f293eb55a 100644 --- a/src/samples/audio/smart_amp_test_ipc3.c +++ b/src/samples/audio/smart_amp_test_ipc3.c @@ -559,7 +559,7 @@ static const struct comp_driver comp_smart_amp = { }, }; -static SHARED_DATA struct comp_driver_info comp_smart_amp_info = { +static struct comp_driver_info comp_smart_amp_info = { .drv = &comp_smart_amp, }; diff --git a/zephyr/lib/clk.c b/zephyr/lib/clk.c index 0cc9006e3a11..06cc5979753e 100644 --- a/zephyr/lib/clk.c +++ b/zephyr/lib/clk.c @@ -13,7 +13,7 @@ #include #include -static SHARED_DATA struct clock_info platform_clocks_info[NUM_CLOCKS]; +static struct clock_info platform_clocks_info[NUM_CLOCKS]; static int select_cpu_freq(int clock, int hz) { diff --git a/zephyr/lib/dma.c b/zephyr/lib/dma.c index 1e28d7215026..a478d5069a09 100644 --- a/zephyr/lib/dma.c +++ b/zephyr/lib/dma.c @@ -21,7 +21,7 @@ #define DW_DMA_BUFFER_PERIOD_COUNT 0x4 #define HDA_DMA_BUFFER_PERIOD_COUNT 4 -APP_SYSUSER_DATA SHARED_DATA struct sof_dma dma[] = { +APP_SYSUSER_DATA struct sof_dma dma[] = { #if DT_NODE_HAS_STATUS(DT_NODELABEL(lpgpdma0), okay) { /* Low Power GP DMAC 0 */ .plat_data = { From a3a1ee32d19d23a2809600d2ec6f2584847127f5 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2026 14:59:02 +0200 Subject: [PATCH 072/109] global: remove unused memory.h headers Compilation verified, that memory.h are no longer needed after removal of SHARED_DATA. Signed-off-by: Guennadi Liakhovetski --- src/audio/base_fw.c | 1 - src/audio/component.c | 1 - src/audio/dai-legacy.c | 1 - src/audio/dai-zephyr.c | 1 - src/audio/google/google_hotword_detect.c | 1 - src/audio/host-legacy.c | 1 - src/audio/host-zephyr.c | 1 - src/audio/kpb.c | 1 - src/audio/selector/selector.c | 1 - src/audio/tone/tone-ipc3.c | 1 - src/audio/tone/tone-ipc4.c | 1 - src/audio/tone/tone.c | 1 - src/audio/tone/tone.h | 1 - 13 files changed, 13 deletions(-) diff --git a/src/audio/base_fw.c b/src/audio/base_fw.c index 88d3a54adcee..1ad9580d74b5 100644 --- a/src/audio/base_fw.c +++ b/src/audio/base_fw.c @@ -4,7 +4,6 @@ // #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/component.c b/src/audio/component.c index e2c38a9c62da..af0b9c278368 100644 --- a/src/audio/component.c +++ b/src/audio/component.c @@ -13,7 +13,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/dai-legacy.c b/src/audio/dai-legacy.c index d16aec40efd8..49fb8e011ffd 100644 --- a/src/audio/dai-legacy.c +++ b/src/audio/dai-legacy.c @@ -19,7 +19,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/dai-zephyr.c b/src/audio/dai-zephyr.c index 7bb53c88e178..9f4e5dc57295 100644 --- a/src/audio/dai-zephyr.c +++ b/src/audio/dai-zephyr.c @@ -19,7 +19,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/google/google_hotword_detect.c b/src/audio/google/google_hotword_detect.c index f8f7c22467be..d67a97a5823f 100644 --- a/src/audio/google/google_hotword_detect.c +++ b/src/audio/google/google_hotword_detect.c @@ -15,7 +15,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/host-legacy.c b/src/audio/host-legacy.c index d56319c0184d..d17da437ffb4 100644 --- a/src/audio/host-legacy.c +++ b/src/audio/host-legacy.c @@ -17,7 +17,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/host-zephyr.c b/src/audio/host-zephyr.c index f2bfae946d8d..5f23ff405857 100644 --- a/src/audio/host-zephyr.c +++ b/src/audio/host-zephyr.c @@ -17,7 +17,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/kpb.c b/src/audio/kpb.c index 40353ff71e20..4e5049919baf 100644 --- a/src/audio/kpb.c +++ b/src/audio/kpb.c @@ -26,7 +26,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 422e08f69603..bc48f99b5126 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -22,7 +22,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/tone/tone-ipc3.c b/src/audio/tone/tone-ipc3.c index b2ebb3209571..75017fe3910f 100644 --- a/src/audio/tone/tone-ipc3.c +++ b/src/audio/tone/tone-ipc3.c @@ -16,7 +16,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/tone/tone-ipc4.c b/src/audio/tone/tone-ipc4.c index db2497e8aa40..a54ed0b2b862 100644 --- a/src/audio/tone/tone-ipc4.c +++ b/src/audio/tone/tone-ipc4.c @@ -17,7 +17,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/tone/tone.c b/src/audio/tone/tone.c index 0941d7edcb69..dac32a3c187e 100644 --- a/src/audio/tone/tone.c +++ b/src/audio/tone/tone.c @@ -17,7 +17,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include diff --git a/src/audio/tone/tone.h b/src/audio/tone/tone.h index 33c0862ef19c..1a3978b710b5 100644 --- a/src/audio/tone/tone.h +++ b/src/audio/tone/tone.h @@ -14,7 +14,6 @@ #include #include #include -#include /* likely unneeded */ #include #include #include From 1cc8b9264d95388d9533cc617129e216f63190c4 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 25 Aug 2026 09:29:54 +0200 Subject: [PATCH 073/109] rimage: reject unsupported MEU signing modes Leave unsupported SUE and ACE MEU callbacks unset and report a runtime error before writer dispatch. Signed-off-by: Adrian Bonislawski --- tools/rimage/src/adsp_config.c | 4 ++-- tools/rimage/src/rimage.c | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/rimage/src/adsp_config.c b/tools/rimage/src/adsp_config.c index 6cc7434e74bc..931c77e10403 100644 --- a/tools/rimage/src/adsp_config.c +++ b/tools/rimage/src/adsp_config.c @@ -2052,7 +2052,7 @@ static int parse_adsp_config_v1_5(const toml_table_t *toml, struct image *image) /* assign correct write functions */ out->write_firmware = man_write_fw_v1_5_sue; - out->write_firmware_meu = man_write_fw_meu_v1_5; + out->write_firmware_meu = NULL; out->verify_firmware = ri_manifest_verify_v1_5; /* parse others sibtables */ @@ -2235,7 +2235,7 @@ static int parse_adsp_config_ace_v1_5(const toml_table_t *toml, struct image *im /* assign correct write functions */ out->write_firmware = man_write_fw_ace_v1_5; - out->write_firmware_meu = man_write_fw_meu_v2_5; + out->write_firmware_meu = NULL; out->verify_firmware = ri_manifest_verify_v2_5; /* version array has already been parsed, so increment ctx.array_cnt */ diff --git a/tools/rimage/src/rimage.c b/tools/rimage/src/rimage.c index 2245288dfece..0b41905944c2 100644 --- a/tools/rimage/src/rimage.c +++ b/tools/rimage/src/rimage.c @@ -202,6 +202,12 @@ int main(int argc, char *argv[]) goto out; } + if (image.meu_offset && !image.adsp->write_firmware_meu) { + fprintf(stderr, "error: MEU signing is not supported for this target\n"); + ret = -EINVAL; + goto out; + } + /* set IMR Type and the PV bit in found machine definition */ if (image.adsp->man_v1_8) { if (imr_type_override) @@ -274,7 +280,6 @@ int main(int argc, char *argv[]) /* process and write output */ if (image.meu_offset) { - assert(image.adsp->write_firmware_meu); ret = image.adsp->write_firmware_meu(&image); } else { assert(image.adsp->write_firmware); From c086688cc777d97682d8361e1da5b2f352ae26b3 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 25 Aug 2026 09:36:15 +0200 Subject: [PATCH 074/109] rimage: require module configuration for relocatable images Reject relocatable manifest creation when the TOML configuration does not provide module metadata. Signed-off-by: Adrian Bonislawski --- tools/rimage/src/manifest.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index 22eddfa00c74..92e7cc11842c 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -542,6 +542,11 @@ static int man_module_create_reloc(struct image *image, struct manifest_module * struct elf_section section; int err; + if (!modules) { + fprintf(stderr, "error: relocatable image requires module configuration\n"); + return -EINVAL; + } + /* load in module manifest data */ err = elf_section_read_by_name(&module->file.elf, ".module", §ion); if (err) { From f7789c99fa3ea4425e63a98e946ee78dd76d85f7 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Tue, 25 Aug 2026 10:34:43 +0200 Subject: [PATCH 075/109] rimage: fix CSE header detection check when re-signing Test the outcome of the scan instead of the loop index, so the check no longer depends on the loop bound, and align the message with the one used by verify_image(). Signed-off-by: Adrian Bonislawski --- tools/rimage/src/manifest.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/rimage/src/manifest.c b/tools/rimage/src/manifest.c index 92e7cc11842c..db89d5f699b0 100644 --- a/tools/rimage/src/manifest.c +++ b/tools/rimage/src/manifest.c @@ -1791,8 +1791,12 @@ int resign_image(struct image *image) } } - if (i >= size) { - fprintf(stderr, "error: didn't found header marker %d\n", i); + /* the scan stops a full marker before the end, so a trailing partial word + * leaves the loop index below the size; test the result of the scan itself + */ + if (!image->fw_image) { + fprintf(stderr, "error: could not find valid CSE header $CPD in %s\n", + image->in_file); ret = -EINVAL; goto out; } From ab633d7338eb1ab916b46047d5ec5988875a694f Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Wed, 5 Aug 2026 15:56:29 +0200 Subject: [PATCH 076/109] llext: export ipc4_update_sink_format symbol required for asrc When built as an llext module, asrc requires the base-firmware provided symbol ipc4_update_sink_format(), export it. Signed-off-by: Adrian Warecki --- src/ipc/ipc4/helper.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index 93fc69ef89db..467a40a8d66d 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1679,6 +1679,7 @@ void ipc4_update_buffer_format(struct comp_buffer *buf_c, audio_buffer_set_hw_params_configured(&buf_c->audio_buffer); } +EXPORT_SYMBOL(ipc4_update_buffer_format); void ipc4_update_source_format(struct sof_source *source, const struct ipc4_audio_format *fmt) @@ -1710,4 +1711,4 @@ void ipc4_update_sink_format(struct sof_sink *sink, sink_set_valid_fmt(sink, valid_fmt); sink_set_buffer_fmt(sink, fmt->interleaving_style); } -EXPORT_SYMBOL(ipc4_update_buffer_format); +EXPORT_SYMBOL(ipc4_update_sink_format); From 6e724c505a74fa1bc8769410806ee85954c851b7 Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Wed, 8 Jul 2026 17:39:40 +0200 Subject: [PATCH 077/109] module: asrc: rework module to use only sink/source api Rework the asrc module to only use the sink/source API to prepare the sof for the full transition to pipeline 2.0. Signed-off-by: Adrian Warecki --- src/audio/asrc/asrc.c | 205 +++++++++++++++++-------------------- src/audio/asrc/asrc.h | 14 ++- src/audio/asrc/asrc_ipc3.c | 13 ++- src/audio/asrc/asrc_ipc4.c | 9 +- 4 files changed, 122 insertions(+), 119 deletions(-) diff --git a/src/audio/asrc/asrc.c b/src/audio/asrc/asrc.c index b070d3b1c251..b4911f6c28fd 100644 --- a/src/audio/asrc/asrc.c +++ b/src/audio/asrc/asrc.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include #include @@ -32,35 +34,22 @@ LOG_MODULE_REGISTER(asrc, CONFIG_SOF_LOG_LEVEL); -/* In-line functions */ - -static inline void src_inc_wrap(int32_t **ptr, int32_t *end, size_t size) -{ - if (*ptr >= end) - *ptr = (int32_t *)((uint8_t *)*ptr - size); -} - -static inline void src_inc_wrap_s16(int16_t **ptr, int16_t *end, size_t size) -{ - if (*ptr >= end) - *ptr = (int16_t *)((uint8_t *)*ptr - size); -} - /* A fast copy function for same in and out rate */ static void src_copy_s32(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - int *n_read, int *n_written) + struct cir_buf_source *source, + struct cir_buf_sink *sink, + unsigned int channels, + size_t *n_read, size_t *n_written) { struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; int32_t *buf; - int32_t *src = audio_stream_get_rptr(source); - int32_t *snk = audio_stream_get_wptr(sink); + const int32_t *src = source->ptr; + int32_t *snk = sink->ptr; int n_wrap_src; int n_wrap_snk; int n_copy; - int n; + unsigned int n; int ret; int i; int in_frames = 0; @@ -72,17 +61,16 @@ static void src_copy_s32(struct processing_module *mod, /* Copy input data from source */ buf = (int32_t *)cd->ibuf[0]; - n = cd->source_frames * audio_stream_get_channels(source); + n = cd->source_frames * channels; while (n > 0) { - n_wrap_src = (int32_t *)audio_stream_get_end_addr(source) - src; + n_wrap_src = cir_buf_samples_without_wrap_s32(src, source->buf_end); n_copy = (n < n_wrap_src) ? n : n_wrap_src; for (i = 0; i < n_copy; i++) *buf++ = (*src++) << cd->data_shift; /* Update and check both source and destination for wrap */ n -= n_copy; - src_inc_wrap(&src, audio_stream_get_end_addr(source), - audio_stream_get_size(source)); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); } /* Run ASRC */ @@ -103,17 +91,16 @@ static void src_copy_s32(struct processing_module *mod, comp_err(dev, "error %d", ret); buf = (int32_t *)cd->obuf[0]; - n = out_frames * audio_stream_get_channels(sink); + n = out_frames * channels; while (n > 0) { - n_wrap_snk = (int32_t *)audio_stream_get_end_addr(sink) - snk; + n_wrap_snk = cir_buf_samples_without_wrap_s32(snk, sink->buf_end); n_copy = (n < n_wrap_snk) ? n : n_wrap_snk; for (i = 0; i < n_copy; i++) *snk++ = (*buf++) >> cd->data_shift; /* Update and check both source and destination for wrap */ n -= n_copy; - src_inc_wrap(&snk, audio_stream_get_end_addr(sink), - audio_stream_get_size(sink)); + snk = cir_buf_wrap(snk, sink->buf_start, sink->buf_end); } *n_read = in_frames; @@ -121,21 +108,22 @@ static void src_copy_s32(struct processing_module *mod, } static void src_copy_s16(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - int *n_read, int *n_written) + struct cir_buf_source *source, + struct cir_buf_sink *sink, + unsigned int channels, + size_t *n_read, size_t *n_written) { struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - int16_t *src = audio_stream_get_rptr(source); - int16_t *snk = audio_stream_get_wptr(sink); + const int16_t *src = source->ptr; + int16_t *snk = sink->ptr; int16_t *buf; int n_wrap_src; int n_wrap_snk; int n_copy; int s_copy; int ret; - int n; + unsigned int n; int in_frames = 0; int out_frames = 0; int idx = 0; @@ -144,9 +132,9 @@ static void src_copy_s16(struct processing_module *mod, /* Copy input data from source */ buf = (int16_t *)cd->ibuf[0]; - n = cd->source_frames * audio_stream_get_channels(source); + n = cd->source_frames * channels; while (n > 0) { - n_wrap_src = (int16_t *)audio_stream_get_end_addr(source) - src; + n_wrap_src = cir_buf_samples_without_wrap_s16(src, source->buf_end); n_copy = (n < n_wrap_src) ? n : n_wrap_src; s_copy = n_copy * sizeof(int16_t); ret = memcpy_s(buf, s_copy, src, s_copy); @@ -156,8 +144,7 @@ static void src_copy_s16(struct processing_module *mod, n -= n_copy; src += n_copy; buf += n_copy; - src_inc_wrap_s16(&src, audio_stream_get_end_addr(source), - audio_stream_get_size(source)); + src = cir_buf_wrap(src, source->buf_start, source->buf_end); } /* Run ASRC */ @@ -179,9 +166,9 @@ static void src_copy_s16(struct processing_module *mod, comp_err(dev, "error %d", ret); buf = (int16_t *)cd->obuf[0]; - n = out_frames * audio_stream_get_channels(sink); + n = out_frames * channels; while (n > 0) { - n_wrap_snk = (int16_t *)audio_stream_get_end_addr(sink) - snk; + n_wrap_snk = cir_buf_samples_without_wrap_s16(snk, sink->buf_end); n_copy = (n < n_wrap_snk) ? n : n_wrap_snk; s_copy = n_copy * sizeof(int16_t); ret = memcpy_s(snk, s_copy, buf, s_copy); @@ -191,8 +178,7 @@ static void src_copy_s16(struct processing_module *mod, n -= n_copy; snk += n_copy; buf += n_copy; - src_inc_wrap_s16(&snk, audio_stream_get_end_addr(sink), - audio_stream_get_size(sink)); + snk = cir_buf_wrap(snk, sink->buf_start, sink->buf_end); } *n_read = in_frames; @@ -337,12 +323,12 @@ static int asrc_set_config(struct processing_module *mod, uint32_t config_id, } /* set component audio stream parameters */ -static int asrc_params(struct processing_module *mod) +static int asrc_params(struct processing_module *mod, + struct sof_source *source, struct sof_sink *sink) { struct sof_ipc_stream_params *pcm_params = mod->stream_params; struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct comp_buffer *sourceb, *sinkb; int err; comp_info(dev, "entry"); @@ -359,24 +345,17 @@ static int asrc_params(struct processing_module *mod) return -EINVAL; } - sourceb = comp_dev_get_first_data_producer(dev); - sinkb = comp_dev_get_first_data_consumer(dev); - if (!sourceb || !sinkb) { - comp_err(dev, "no source or sink buffer"); - return -ENOTCONN; - } - /* update the source/sink buffer formats. Sink rate will be modified below */ - asrc_update_buffer_format(sourceb, cd); - asrc_update_buffer_format(sinkb, cd); + asrc_update_source_format(source, cd); + asrc_update_sink_format(sink, cd); /* Don't change sink rate if value from IPC is 0 (auto detect) */ if (asrc_get_sink_rate(&cd->ipc_config)) - audio_stream_set_rate(&sinkb->stream, asrc_get_sink_rate(&cd->ipc_config)); + sink_set_rate(sink, asrc_get_sink_rate(&cd->ipc_config)); /* set source/sink_frames/rate */ - cd->source_rate = audio_stream_get_rate(&sourceb->stream); - cd->sink_rate = audio_stream_get_rate(&sinkb->stream); + cd->source_rate = source_get_rate(source); + cd->sink_rate = sink_get_rate(sink); if (!cd->sink_rate) { comp_err(dev, "zero sink rate"); @@ -498,7 +477,8 @@ static int asrc_prepare(struct processing_module *mod, { struct comp_data *cd = module_get_private_data(mod); struct comp_dev *dev = mod->dev; - struct comp_buffer *sourceb, *sinkb; + struct sof_source *source; + struct sof_sink *sink; uint32_t source_period_bytes; uint32_t sink_period_bytes; int sample_bytes; @@ -511,35 +491,27 @@ static int asrc_prepare(struct processing_module *mod, comp_info(dev, "entry"); - ret = asrc_params(mod); + /* SRC component will only ever have 1 source and 1 sink buffer */ + if (num_of_sources != 1 || num_of_sinks != 1) { + comp_err(dev, "expected exactly 1 source and 1 sink (got %d/%d)", num_of_sources, + num_of_sinks); + return -ENOTCONN; + } + + source = sources[0]; + sink = sinks[0]; + + ret = asrc_params(mod, source, sink); if (ret < 0) return ret; - /* - * SRC component will only ever have 1 source and 1 sink buffer, - * asrc_params() has checked their validity already - */ - sourceb = comp_dev_get_first_data_producer(dev); - sinkb = comp_dev_get_first_data_consumer(dev); - /* get source data format and period bytes */ - cd->source_format = audio_stream_get_frm_fmt(&sourceb->stream); - source_period_bytes = audio_stream_period_bytes(&sourceb->stream, - cd->source_frames); + cd->source_format = source_get_frm_fmt(source); + source_period_bytes = source_get_frame_bytes(source) * cd->source_frames; /* get sink data format and period bytes */ - cd->sink_format = audio_stream_get_frm_fmt(&sinkb->stream); - sink_period_bytes = audio_stream_period_bytes(&sinkb->stream, - cd->sink_frames); - - if (audio_stream_get_size(&sinkb->stream) < - dev->ipc_config.periods_sink * sink_period_bytes) { - comp_err(dev, "sink buffer size %d is insufficient < %d * %d", - audio_stream_get_size(&sinkb->stream), dev->ipc_config.periods_sink, - sink_period_bytes); - ret = -ENOMEM; - goto err; - } + cd->sink_format = sink_get_frm_fmt(sink); + sink_period_bytes = sink_get_frame_bytes(sink) * cd->sink_frames; /* validate */ if (!sink_period_bytes) { @@ -554,7 +526,7 @@ static int asrc_prepare(struct processing_module *mod, } /* ASRC supports S16_LE, S24_4LE and S32_LE formats */ - switch (audio_stream_get_frm_fmt(&sourceb->stream)) { + switch (source_get_frm_fmt(source)) { case SOF_IPC_FRAME_S16_LE: cd->asrc_func = src_copy_s16; break; @@ -572,7 +544,7 @@ static int asrc_prepare(struct processing_module *mod, } /* Allocate input and output data buffer for ASRC processing */ - frame_bytes = audio_stream_frame_bytes(&sourceb->stream); + frame_bytes = source_get_frame_bytes(source); cd->buf_size = (cd->source_frames_max + cd->sink_frames_max) * frame_bytes; @@ -585,8 +557,8 @@ static int asrc_prepare(struct processing_module *mod, goto err; } - sample_bytes = frame_bytes / audio_stream_get_channels(&sourceb->stream); - for (i = 0; i < audio_stream_get_channels(&sourceb->stream); i++) { + sample_bytes = frame_bytes / source_get_channels(source); + for (i = 0; i < source_get_channels(source); i++) { cd->ibuf[i] = cd->buf + i * sample_bytes; cd->obuf[i] = cd->ibuf[i] + cd->source_frames_max * frame_bytes; } @@ -594,7 +566,7 @@ static int asrc_prepare(struct processing_module *mod, /* Get required size and allocate memory for ASRC */ sample_bits = sample_bytes * 8; ret = asrc_get_required_size(mod, &cd->asrc_size, - audio_stream_get_channels(&sourceb->stream), + source_get_channels(source), sample_bits); if (ret) { comp_err(dev, "get_required_size_bytes failed"); @@ -619,7 +591,7 @@ static int asrc_prepare(struct processing_module *mod, fs_sec = cd->source_rate; } - ret = asrc_initialise(mod, cd->asrc_obj, audio_stream_get_channels(&sourceb->stream), + ret = asrc_initialise(mod, cd->asrc_obj, source_get_channels(source), fs_prim, fs_sec, ASRC_IOF_INTERLEAVED, ASRC_IOF_INTERLEAVED, ASRC_BM_LINEAR, cd->frames, sample_bits, @@ -747,16 +719,22 @@ static int asrc_control_loop(struct comp_dev *dev, struct comp_data *cd) /* copy and process stream data from source to sink buffers */ static int asrc_process(struct processing_module *mod, - struct input_stream_buffer *input_buffers, int num_input_buffers, - struct output_stream_buffer *output_buffers, int num_output_buffers) + struct sof_source **sources, int num_of_sources, + struct sof_sink **sinks, int num_of_sinks) { struct comp_data *cd = module_get_private_data(mod); + struct sof_source *source = sources[0]; + struct sof_sink *sink = sinks[0]; + size_t src_frame_bytes = source_get_frame_bytes(source); + size_t snk_frame_bytes = sink_get_frame_bytes(sink); + unsigned int channels = source_get_channels(source); + struct cir_buf_source source_buf; struct comp_dev *dev = mod->dev; - struct comp_buffer *source, *sink; - struct audio_stream *source_s = input_buffers[0].data; - struct audio_stream *sink_s = output_buffers[0].data; - int frames_src; - int frames_snk; + size_t frames_src, frames_snk; + struct cir_buf_sink sink_buf; + size_t consumed = 0; + size_t produced = 0; + size_t bytes; int ret; comp_dbg(dev, "entry"); @@ -765,12 +743,8 @@ static int asrc_process(struct processing_module *mod, if (ret) return ret; - /* asrc component needs 1 source and 1 sink buffer */ - source = comp_dev_get_first_data_producer(dev); - sink = comp_dev_get_first_data_consumer(dev); - - frames_src = audio_stream_get_avail_frames(source_s); - frames_snk = audio_stream_get_free_frames(sink_s); + frames_src = source_get_data_frames_available(source); + frames_snk = sink_get_free_frames(sink); if (cd->mode == ASRC_OM_PULL) { /* Let ASRC access max number of source frames in pull mode. @@ -795,20 +769,29 @@ static int asrc_process(struct processing_module *mod, cd->source_frames = MIN(cd->source_frames, frames_src); } - if (cd->source_frames && cd->sink_frames) { - int consumed = 0; - int produced = 0; - - /* consumed bytes are not known at this point */ - buffer_stream_invalidate(source, audio_stream_get_size(source_s)); - cd->asrc_func(mod, source_s, sink_s, &consumed, &produced); - buffer_stream_writeback(sink, produced * audio_stream_frame_bytes(sink_s)); + if (!cd->source_frames || !cd->sink_frames) + return 0; - comp_dbg(dev, "consumed = %u, produced = %u", consumed, produced); + ret = source_get_data(source, cd->source_frames * src_frame_bytes, + &source_buf.ptr, &source_buf.buf_start, &bytes); + if (ret) + return ret; + source_buf.buf_end = (const char *)source_buf.buf_start + bytes; - output_buffers[0].size = produced * audio_stream_frame_bytes(sink_s); - input_buffers[0].consumed = consumed * audio_stream_frame_bytes(source_s); + ret = sink_get_buffer(sink, cd->sink_frames * snk_frame_bytes, + &sink_buf.ptr, &sink_buf.buf_start, &bytes); + if (ret) { + source_release_data(source, 0); + return ret; } + sink_buf.buf_end = (char *)sink_buf.buf_start + bytes; + + cd->asrc_func(mod, &source_buf, &sink_buf, channels, &consumed, &produced); + + comp_dbg(dev, "consumed = %zu, produced = %zu", consumed, produced); + + source_release_data(source, consumed * src_frame_bytes); + sink_commit_buffer(sink, produced * snk_frame_bytes); return 0; } @@ -838,7 +821,7 @@ static int asrc_reset(struct processing_module *mod) static const struct module_interface asrc_interface = { .init = asrc_init, .prepare = asrc_prepare, - .process_audio_stream = asrc_process, + .process = asrc_process, .trigger = asrc_trigger, .set_configuration = asrc_set_config, .reset = asrc_reset, diff --git a/src/audio/asrc/asrc.h b/src/audio/asrc/asrc.h index 4d7a902a0c9d..021bf4e6d0d0 100644 --- a/src/audio/asrc/asrc.h +++ b/src/audio/asrc/asrc.h @@ -12,6 +12,8 @@ #include "asrc_farrow.h" struct comp_data; +struct sof_source; +struct sof_sink; #ifdef CONFIG_IPC_MAJOR_4 #include @@ -82,10 +84,11 @@ int asrc_dai_get_timestamp(struct comp_data *cd, struct timestamp_data *tsd); #define COEF_C2 Q_CONVERT_FLOAT(0.99, 30) typedef void (*asrc_proc_func)(struct processing_module *mod, - const struct audio_stream *source, - struct audio_stream *sink, - int *consumed, - int *produced); + struct cir_buf_source *source, + struct cir_buf_sink *sink, + unsigned int channels, + size_t *consumed, + size_t *produced); /* asrc component private data */ struct comp_data { ipc_asrc_cfg ipc_config; @@ -122,7 +125,8 @@ struct comp_data { int asrc_dai_configure_timestamp(struct comp_data *cd); int asrc_dai_start_timestamp(struct comp_data *cd); int asrc_dai_stop_timestamp(struct comp_data *cd); -void asrc_update_buffer_format(struct comp_buffer *buf_c, struct comp_data *cd); +void asrc_update_source_format(struct sof_source *source, struct comp_data *cd); +void asrc_update_sink_format(struct sof_sink *sink, struct comp_data *cd); void asrc_set_stream_params(struct comp_data *cd, struct sof_ipc_stream_params *params); int asrc_verify_stream_params(struct processing_module *mod, struct sof_ipc_stream_params *params); extern struct tr_ctx asrc_tr; diff --git a/src/audio/asrc/asrc_ipc3.c b/src/audio/asrc/asrc_ipc3.c index 07cdb33f14f2..3dbfbd0f6328 100644 --- a/src/audio/asrc/asrc_ipc3.c +++ b/src/audio/asrc/asrc_ipc3.c @@ -55,13 +55,24 @@ int asrc_dai_get_timestamp(struct comp_data *cd, struct timestamp_data *tsd) return cd->dai_dev->drv->ops.dai_ts_get(cd->dai_dev, tsd); } -void asrc_update_buffer_format(struct comp_buffer *buf_c, struct comp_data *cd) +void asrc_update_source_format(struct sof_source *source, struct comp_data *cd) { + (void)source; + (void)cd; + /* IPC3 don't need to update audio stream format here. */ +} + +void asrc_update_sink_format(struct sof_sink *sink, struct comp_data *cd) +{ + (void)sink; + (void)cd; /* IPC3 don't need to update audio stream format here. */ } void asrc_set_stream_params(struct comp_data *cd, struct sof_ipc_stream_params *params) { + (void)cd; + (void)params; /* IPC3 don't need to update audio stream format here. */ } diff --git a/src/audio/asrc/asrc_ipc4.c b/src/audio/asrc/asrc_ipc4.c index cba17aeee410..91537edc46f5 100644 --- a/src/audio/asrc/asrc_ipc4.c +++ b/src/audio/asrc/asrc_ipc4.c @@ -66,9 +66,14 @@ int asrc_dai_get_timestamp(struct comp_data *cd, struct timestamp_data *tsd) return ops->endpoint_ops->dai_ts_get(cd->dai_dev, tsd); } -void asrc_update_buffer_format(struct comp_buffer *buf_c, struct comp_data *cd) +void asrc_update_source_format(struct sof_source *source, struct comp_data *cd) { - ipc4_update_buffer_format(buf_c, &cd->ipc_config.base.audio_fmt); + ipc4_update_source_format(source, &cd->ipc_config.base.audio_fmt); +} + +void asrc_update_sink_format(struct sof_sink *sink, struct comp_data *cd) +{ + ipc4_update_sink_format(sink, &cd->ipc_config.base.audio_fmt); } void asrc_set_stream_params(struct comp_data *cd, struct sof_ipc_stream_params *params) From 4d139117191549c220a27f53c401a2ba9f294c2e Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 21 Aug 2026 13:00:55 +0200 Subject: [PATCH 078/109] audio: mux: fix a blob size check Before dereferencing the data blob make sure that it matches the expected size, not just isn't exceeding the maximum size. Signed-off-by: Guennadi Liakhovetski --- src/audio/mux/mux_ipc4.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/mux/mux_ipc4.c b/src/audio/mux/mux_ipc4.c index f5ead3a93368..8f33e44ea1ae 100644 --- a/src/audio/mux/mux_ipc4.c +++ b/src/audio/mux/mux_ipc4.c @@ -148,7 +148,7 @@ int mux_params(struct processing_module *mod) int ret; cfg = comp_get_data_blob(cd->model_handler, &blob_size, NULL); - if (!cfg || blob_size > MUX_BLOB_MAX_SIZE) { + if (!cfg || blob_size != sizeof(*cfg)) { comp_err(mod->dev, "illegal blob size %zu", blob_size); return -EINVAL; } From d55b1a96529c95bcc05b47e1651cdaf2e9714dde Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 25 Aug 2026 16:08:41 +0200 Subject: [PATCH 079/109] topology2: add an HDA topology with DP SRC on core 2 Add a topology, similar to the existing HDA SRC one, but with SRC in DP scheduling domain and with it and connected pipelines running on core 2. Signed-off-by: Guennadi Liakhovetski --- .../topology/topology2/cavs-src-mixin-mixout-hda.conf | 11 +++++++++++ .../topology/topology2/development/tplg-targets.cmake | 4 ++++ .../topology2/platform/intel/deep-buffer.conf | 7 +++++++ 3 files changed, 22 insertions(+) diff --git a/tools/topology/topology2/cavs-src-mixin-mixout-hda.conf b/tools/topology/topology2/cavs-src-mixin-mixout-hda.conf index b567e5f810bb..77cc8329ec6e 100644 --- a/tools/topology/topology2/cavs-src-mixin-mixout-hda.conf +++ b/tools/topology/topology2/cavs-src-mixin-mixout-hda.conf @@ -7,6 +7,8 @@ Define { DEEP_BUFFER_PIPELINE_SRC 'mixin.15.1' DEEP_BUFFER_PIPELINE_SINK 'mixout.2.1' DEEP_BUFFER_PCM_NAME 'Deepbuffer HDA Analog' + SRC_CORE 0 + SRC_DOMAIN "default" } # include deep buffer config if buffer size is in 1 - 1000 ms. @@ -31,6 +33,7 @@ Object.Pipeline { mixout-gain-dai-copier-playback [ { index 2 + core_id $SRC_CORE Object.Widget.dai-copier.1 { node_type $HDA_LINK_OUTPUT_CLASS @@ -43,12 +46,16 @@ Object.Pipeline { name '2 Main Playback Volume' } } + Object.Widget.pipeline.1 { + core $SRC_CORE + } } ] host-copier-gain-src-mixin-playback [ { index 1 + core_id $SRC_CORE Object.Widget.host-copier.1 { stream_name $ANALOG_PLAYBACK_PCM @@ -56,6 +63,7 @@ Object.Pipeline { } Object.Widget.src.1 { + scheduler_domain "$SRC_DOMAIN" } Object.Widget.gain.1 { @@ -63,6 +71,9 @@ Object.Pipeline { name '1 2nd Playback Volume' } } + Object.Widget.pipeline.1 { + core $SRC_CORE + } } ] diff --git a/tools/topology/topology2/development/tplg-targets.cmake b/tools/topology/topology2/development/tplg-targets.cmake index ab6a8b2976b5..8835fad0635d 100644 --- a/tools/topology/topology2/development/tplg-targets.cmake +++ b/tools/topology/topology2/development/tplg-targets.cmake @@ -270,6 +270,10 @@ GOOGLE_RTC_AEC_SUPPORT=1,DEEP_BUF_SPK=true,GOOGLE_AEC_DP_CORE_ID=2" # CAVS HDA topology with gain and SRC before mixin for HDA and passthrough pipelines for HDMI "sof-hda-generic\;sof-hda-src-generic\;HDA_CONFIG=src" +# Like above but with SRC in DP mode on core 2 +"sof-hda-generic\;sof-hda-src-generic-dp\;HDA_CONFIG=src,DEEP_BUFFER_CORE=2,SRC_CORE=2,\ +SRC_DOMAIN=DP" + # BT offload for tgl "cavs-nocodec-bt\;sof-nocodec-bt-tgl\;PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-nocodec-bt-tgl.bin,\ PLATFORM=tgl" diff --git a/tools/topology/topology2/platform/intel/deep-buffer.conf b/tools/topology/topology2/platform/intel/deep-buffer.conf index 5b86088feddf..a6cc498f5b14 100644 --- a/tools/topology/topology2/platform/intel/deep-buffer.conf +++ b/tools/topology/topology2/platform/intel/deep-buffer.conf @@ -1,7 +1,11 @@ +Define { + DEEP_BUFFER_CORE 0 +} Object.Pipeline.deepbuffer-playback [ { index $DEEP_BUFFER_PIPELINE_ID + core_id $DEEP_BUFFER_CORE Object.Widget.host-copier.1 { stream_name $DEEP_BUFFER_PCM_NAME @@ -104,6 +108,9 @@ Object.Pipeline.deepbuffer-playback [ } ] } + Object.Widget.pipeline.1 { + core $DEEP_BUFFER_CORE + } } ] From 28b104f546d0cb147c7b22f4049aabe158a25859 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 18 Aug 2026 14:28:04 +0200 Subject: [PATCH 080/109] schedule: add a function for finding userspace scherulers scheduler_get_data() only finds scheduler data for kernel mode schedulers. Add a similar function for userspace schedulers. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/schedule/schedule.h | 28 +++++++++++++++++++++------- src/schedule/zephyr_ll.c | 10 +++++++++- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/include/sof/schedule/schedule.h b/src/include/sof/schedule/schedule.h index 32b09f24f473..f28f472b121f 100644 --- a/src/include/sof/schedule/schedule.h +++ b/src/include/sof/schedule/schedule.h @@ -186,14 +186,8 @@ struct schedulers **arch_user_schedulers_get(void); struct schedulers **arch_user_schedulers_get_for_core(int core); -/** - * Retrieves scheduler's data. - * @param type SOF_SCHEDULE_ type. - * @return Pointer to scheduler's data. - */ -static inline void *scheduler_get_data(uint16_t type) +static inline void *scheduler_list_get_data(struct schedulers *schedulers, uint16_t type) { - struct schedulers *schedulers = *arch_schedulers_get(); struct schedule_data *sch; struct list_item *slist; @@ -209,6 +203,26 @@ static inline void *scheduler_get_data(uint16_t type) return NULL; } +/** + * Retrieves scheduler's data. + * @param type SOF_SCHEDULE_ type. + * @return Pointer to scheduler's data. + */ +static inline void *scheduler_get_data(uint16_t type) +{ + return scheduler_list_get_data(*arch_schedulers_get(), type); +} + +/** + * Retrieves userspace scheduler's data. + * @param type SOF_SCHEDULE_ type. + * @return Pointer to scheduler's data. + */ +static inline void *scheduler_get_user_data(uint16_t type) +{ + return scheduler_list_get_data(*arch_user_schedulers_get(), type); +} + /** See scheduler_ops::schedule_task_running */ static inline int schedule_task_running(struct task *task) { diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index e7a72e6db028..8e55695538ec 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -889,9 +889,13 @@ void scheduler_get_task_info_ll(struct scheduler_props *scheduler_props, uint32_t *data_off_size) { uint32_t flags; +#if CONFIG_SOF_USERSPACE_LL + struct zephyr_ll *ll_sch = scheduler_get_user_data(SOF_SCHEDULE_LL_TIMER); +#else + struct zephyr_ll *ll_sch = scheduler_get_data(SOF_SCHEDULE_LL_TIMER); +#endif scheduler_props->processing_domain = COMP_PROCESSING_DOMAIN_LL; - struct zephyr_ll *ll_sch = scheduler_get_data(SOF_SCHEDULE_LL_TIMER); zephyr_ll_lock(ll_sch, &flags); scheduler_get_task_info(scheduler_props, data_off_size, &ll_sch->tasks); @@ -901,7 +905,11 @@ void scheduler_get_task_info_ll(struct scheduler_props *scheduler_props, /* Return a pointer to the LL scheduler timer domain */ struct ll_schedule_domain *zephyr_ll_domain(void) { +#if CONFIG_SOF_USERSPACE_LL + struct zephyr_ll *ll_sch = scheduler_get_user_data(SOF_SCHEDULE_LL_TIMER); +#else struct zephyr_ll *ll_sch = scheduler_get_data(SOF_SCHEDULE_LL_TIMER); +#endif return ll_sch ? ll_sch->ll_domain : NULL; } From 09774b2b0d3ff99dc5b28f984b7f75bd6f3ac2ee Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 24 Aug 2026 12:50:53 +0200 Subject: [PATCH 081/109] schedule: dp: application: clarify privilege level scheduler_dp_task_init() currently only runs in privileged mode, add a comment and a check for that. Signed-off-by: Guennadi Liakhovetski --- src/schedule/zephyr_dp_schedule_application.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/schedule/zephyr_dp_schedule_application.c b/src/schedule/zephyr_dp_schedule_application.c index daf9070ae4dc..547823ca6e6f 100644 --- a/src/schedule/zephyr_dp_schedule_application.c +++ b/src/schedule/zephyr_dp_schedule_application.c @@ -425,7 +425,7 @@ static void scheduler_dp_thread_name_set(k_tid_t thread_id, struct processing_mo #define scheduler_dp_thread_name_set(x, y) #endif -/* Called only in IPC context */ +/* Called only in IPC context in kernel mode (this can change) */ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, const struct task_ops *ops, struct processing_module *mod, uint16_t core, size_t stack_size, uint32_t options) @@ -437,6 +437,7 @@ int scheduler_dp_task_init(struct task **task, const struct sof_uuid_entry *uid, /* must be called on the same core the task will be bound to */ assert(cpu_get_id() == core); + assert(!k_is_user_context()); /* * allocate memory From 99eb7e1b979dd644504ad1373684af7cb589a524 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 24 Aug 2026 12:52:46 +0200 Subject: [PATCH 082/109] userspace: simplify preprocessor conditionals The entire user_access_to_mailbox() function is already under an #ifdef CONFIG_SOF_USERSPACE_LL condition. Remove an additional identical check inside the function. Signed-off-by: Guennadi Liakhovetski --- zephyr/lib/userspace_helper.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/zephyr/lib/userspace_helper.c b/zephyr/lib/userspace_helper.c index ea9db4181b9d..e205fc256308 100644 --- a/zephyr/lib/userspace_helper.c +++ b/zephyr/lib/userspace_helper.c @@ -110,7 +110,7 @@ int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) if (ret < 0) return ret; -#if defined(CONFIG_SOF_USERSPACE_LL) && defined(CONFIG_IPC_MAJOR_4) +#ifdef CONFIG_IPC_MAJOR_4 /* HOSTBOX partitions for IPC4 module init parameter block reads. * comp_new_ipc4() accesses MAILBOX_HOSTBOX_BASE directly to get * the module configuration data sent by the host. @@ -141,9 +141,7 @@ int user_access_to_mailbox(struct k_mem_domain *domain, k_tid_t thread_id) ret = k_mem_domain_add_partition(domain, &hostbox_partition); if (ret < 0) return ret; -#endif /* CONFIG_IPC_MAJOR_4 */ - -#ifndef CONFIG_IPC_MAJOR_4 +#else /* CONFIG_IPC_MAJOR_4 */ /* * Next mailbox_stream (not available in IPC4). Stream access is cached, * so different mapping this time. From 2f9967b9cd5376d79493753a587b961ff3e6baa7 Mon Sep 17 00:00:00 2001 From: Kai Vehmanen Date: Thu, 25 Jun 2026 14:12:12 +0300 Subject: [PATCH 083/109] zephyr: lib: make vregion_alloc/free system calls Make vregion_alloc(), vregion_alloc_coherent(), vregion_alloc_align(), vregion_alloc_coherent_align(), and vregion_free() available as Zephyr system calls for user-space threads. Add K_SYSCALL_MEMORY_WRITE verification to all syscall handlers to validate the calling thread has access to the vregion's managed memory area. Add CONFIG_SOF_USERSPACE_INTERFACE_VREGION Kconfig option to control the feature. It is auto-selected by SOF_USERSPACE_LL when SOF_VREGIONS is enabled. Signed-off-by: Kai Vehmanen Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/vregion.h | 26 ++++++++++--- zephyr/CMakeLists.txt | 2 + zephyr/Kconfig | 9 +++++ zephyr/lib/vregion.c | 25 ++++++------ zephyr/syscall/vregion.c | 73 +++++++++++++++++++++++++++++++++++ 5 files changed, 119 insertions(+), 16 deletions(-) create mode 100644 zephyr/syscall/vregion.c diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index 5c066c90dbc8..c7d43845b89a 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -6,6 +6,8 @@ #define __SOF_LIB_VREGION_H__ #include +#include +#include #ifdef __cplusplus extern "C" { @@ -80,12 +82,16 @@ struct vregion *vregion_put(struct vregion *vr); * @param[in] size Size of memory to allocate in bytes. * @return void* Pointer to the allocated memory, or NULL on failure. */ -void *vregion_alloc(struct vregion *vr, size_t size); +__syscall void *vregion_alloc(struct vregion *vr, size_t size); + +void *z_impl_vregion_alloc(struct vregion *vr, size_t size); /** * @brief like vregion_alloc() but allocates coherent memory */ -void *vregion_alloc_coherent(struct vregion *vr, size_t size); +__syscall void *vregion_alloc_coherent(struct vregion *vr, size_t size); + +void *z_impl_vregion_alloc_coherent(struct vregion *vr, size_t size); /** * @brief Allocate aligned memory from the specified virtual region. @@ -98,12 +104,16 @@ void *vregion_alloc_coherent(struct vregion *vr, size_t size); * @param[in] alignment Alignment of memory to allocate in bytes. * @return void* Pointer to the allocated memory, or NULL on failure. */ -void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); +__syscall void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); + +void *z_impl_vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); /** * @brief like vregion_alloc_align() but allocates coherent memory */ -void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); +__syscall void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); + +void *z_impl_vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); /** * @brief Free memory allocated from the specified virtual region. @@ -113,7 +123,9 @@ void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t align * @param[in] vr Pointer to the virtual region instance. * @param[in] ptr Pointer to the memory to free. */ -void vregion_free(struct vregion *vr, void *ptr); +__syscall void vregion_free(struct vregion *vr, void *ptr); + +void z_impl_vregion_free(struct vregion *vr, void *ptr); /** * @brief Log virtual region memory usage. @@ -181,4 +193,8 @@ static inline void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t } #endif +#if CONFIG_SOF_VREGIONS +#include +#endif + #endif /* __SOF_LIB_VREGION_H__ */ diff --git a/zephyr/CMakeLists.txt b/zephyr/CMakeLists.txt index e0e7e8bfb302..c8f49c1f07cb 100644 --- a/zephyr/CMakeLists.txt +++ b/zephyr/CMakeLists.txt @@ -629,6 +629,8 @@ zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/schedule/ll_schedule_domain.h) zephyr_syscall_header(${SOF_SRC_PATH}/include/ipc4/handler.h) zephyr_syscall_header(include/rtos/alloc.h) zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_INTERFACE_ALLOC syscall/alloc.c) +zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/vregion.h) +zephyr_library_sources_ifdef(CONFIG_SOF_USERSPACE_INTERFACE_VREGION syscall/vregion.c) zephyr_syscall_header(${SOF_SRC_PATH}/include/sof/lib/dai-zephyr.h) zephyr_library_sources_ifdef(CONFIG_USERSPACE syscall/dai.c) diff --git a/zephyr/Kconfig b/zephyr/Kconfig index ab88efcb9a6a..2d03a6d6f7ae 100644 --- a/zephyr/Kconfig +++ b/zephyr/Kconfig @@ -36,11 +36,20 @@ config SOF_USERSPACE_INTERFACE_ALLOC Allow user-space threads to use sof_heap_alloc/sof_heap_free as Zephyr system calls. +config SOF_USERSPACE_INTERFACE_VREGION + bool "Enable SOF vregion interface to userspace threads" + depends on USERSPACE + depends on SOF_VREGIONS + help + Allow user-space threads to use vregion_alloc/vregion_free + and their variants as Zephyr system calls. + config SOF_USERSPACE_LL bool "Run Low-Latency pipelines in userspace threads" depends on USERSPACE select SOF_USERSPACE_INTERFACE_ALLOC select SOF_USERSPACE_INTERFACE_DMA + select SOF_USERSPACE_INTERFACE_VREGION if SOF_VREGIONS help Run Low-Latency (LL) pipelines in userspace threads. This adds memory protection between operating system resources and diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c index 9c8c94c23f97..ff7d3ef0f98d 100644 --- a/zephyr/lib/vregion.c +++ b/zephyr/lib/vregion.c @@ -365,7 +365,7 @@ static void lifetime_free(struct vlinear_heap *heap, void *ptr) * @param vr Pointer to the virtual region instance. * @param ptr Pointer to the memory to free. */ -void vregion_free(struct vregion *vr, void *ptr) +void z_impl_vregion_free(struct vregion *vr, void *ptr) { if (!vr || !ptr) return; @@ -390,7 +390,7 @@ void vregion_free(struct vregion *vr, void *ptr) k_mutex_unlock(&vr->lock); } -EXPORT_SYMBOL(vregion_free); +EXPORT_SYMBOL(z_impl_vregion_free); /** * @brief Allocate memory from the virtual region. @@ -401,7 +401,8 @@ EXPORT_SYMBOL(vregion_free); * * @return void* Pointer to the allocated memory, or NULL on failure. */ -void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) +void *z_impl_vregion_alloc_align(struct vregion *vr, + size_t size, size_t alignment) { void *p; @@ -429,7 +430,7 @@ void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) return p; } -EXPORT_SYMBOL(vregion_alloc_align); +EXPORT_SYMBOL(z_impl_vregion_alloc_align); /** * @brief Allocate memory from the virtual region. @@ -437,17 +438,17 @@ EXPORT_SYMBOL(vregion_alloc_align); * @param[in] size Size of the allocation. * @return void* Pointer to the allocated memory, or NULL on failure. */ -void *vregion_alloc(struct vregion *vr, size_t size) +void *z_impl_vregion_alloc(struct vregion *vr, size_t size) { - return vregion_alloc_align(vr, size, 0); + return z_impl_vregion_alloc_align(vr, size, 0); } -EXPORT_SYMBOL(vregion_alloc); +EXPORT_SYMBOL(z_impl_vregion_alloc); -void *vregion_alloc_coherent(struct vregion *vr, size_t size) +void *z_impl_vregion_alloc_coherent(struct vregion *vr, size_t size) { size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); - void *p = vregion_alloc_align(vr, size, CONFIG_DCACHE_LINE_SIZE); + void *p = z_impl_vregion_alloc_align(vr, size, CONFIG_DCACHE_LINE_SIZE); if (!p) return NULL; @@ -456,14 +457,15 @@ void *vregion_alloc_coherent(struct vregion *vr, size_t size) return sys_cache_uncached_ptr_get(p); } +EXPORT_SYMBOL(z_impl_vregion_alloc_coherent); -void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment) +void *z_impl_vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment) { if (alignment < CONFIG_DCACHE_LINE_SIZE) alignment = CONFIG_DCACHE_LINE_SIZE; size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); - void *p = vregion_alloc_align(vr, size, alignment); + void *p = z_impl_vregion_alloc_align(vr, size, alignment); if (!p) return NULL; @@ -472,6 +474,7 @@ void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t align return sys_cache_uncached_ptr_get(p); } +EXPORT_SYMBOL(z_impl_vregion_alloc_coherent_align); /** * @brief Log virtual region memory usage. diff --git a/zephyr/syscall/vregion.c b/zephyr/syscall/vregion.c new file mode 100644 index 000000000000..70fb038eba05 --- /dev/null +++ b/zephyr/syscall/vregion.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: BSD-3-Clause +// +// Copyright(c) 2026 Intel Corporation. + +#include +#include +#include + +static inline void *z_vrfy_vregion_alloc(struct vregion *vr, size_t size) +{ + size_t vr_size = 0; + uintptr_t vr_start; + + vregion_mem_info(vr, &vr_size, &vr_start); + if (vr_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + + return z_impl_vregion_alloc(vr, size); +} +#include + +static inline void *z_vrfy_vregion_alloc_coherent(struct vregion *vr, size_t size) +{ + size_t vr_size = 0; + uintptr_t vr_start; + + vregion_mem_info(vr, &vr_size, &vr_start); + if (vr_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + + return z_impl_vregion_alloc_coherent(vr, size); +} +#include + +static inline void *z_vrfy_vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) +{ + size_t vr_size = 0; + uintptr_t vr_start; + + vregion_mem_info(vr, &vr_size, &vr_start); + if (vr_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + + return z_impl_vregion_alloc_align(vr, size, alignment); +} +#include + +static inline void *z_vrfy_vregion_alloc_coherent_align(struct vregion *vr, + size_t size, size_t alignment) +{ + size_t vr_size = 0; + uintptr_t vr_start; + + vregion_mem_info(vr, &vr_size, &vr_start); + if (vr_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + + return z_impl_vregion_alloc_coherent_align(vr, size, alignment); +} +#include + +static inline void z_vrfy_vregion_free(struct vregion *vr, void *ptr) +{ + size_t vr_size = 0; + uintptr_t vr_start; + + vregion_mem_info(vr, &vr_size, &vr_start); + if (vr_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + + z_impl_vregion_free(vr, ptr); +} +#include From c4f3c1f68e0c02cb9c8c026f89b87e4b4fdf3233 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 20 Aug 2026 16:23:37 +0200 Subject: [PATCH 084/109] vregion: extract a common function Extract common syscall verification code into a function. Also add a a check that the underlying metadata object is inaccessible to the userspace context. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/vregion.h | 3 +++ zephyr/lib/vregion.c | 22 +++++++++++++++ zephyr/syscall/vregion.c | 50 ++++++++++------------------------- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index c7d43845b89a..a8aac6a2222f 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -143,6 +143,8 @@ void vregion_info(struct vregion *vr); */ void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start); +bool vregion_verify(struct vregion *vr); + #else /* CONFIG_SOF_VREGIONS */ struct vregion { @@ -186,6 +188,7 @@ static inline void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t if (size) *size = 0; } +static inline bool vregion_verify(struct vregion *vr) {return false;} #endif /* CONFIG_SOF_VREGIONS */ diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c index ff7d3ef0f98d..58f566680c9e 100644 --- a/zephyr/lib/vregion.c +++ b/zephyr/lib/vregion.c @@ -501,3 +501,25 @@ void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start) if (start) *start = (uintptr_t)vr->base; } + +#if CONFIG_SOF_VREGIONS && CONFIG_USERSPACE +#include + +bool vregion_verify(struct vregion *vr) +{ + if (!vr) + return false; + + /* vregion instances must not be accessible to the userspace. */ + K_OOPS(!K_SYSCALL_MEMORY_READ(vr, sizeof(*vr))); + + size_t vr_size = 0; + uintptr_t vr_start; + + vregion_mem_info(vr, &vr_size, &vr_start); + if (vr_size) + K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + + return true; +} +#endif diff --git a/zephyr/syscall/vregion.c b/zephyr/syscall/vregion.c index 70fb038eba05..55ec58ffe3ce 100644 --- a/zephyr/syscall/vregion.c +++ b/zephyr/syscall/vregion.c @@ -8,66 +8,44 @@ static inline void *z_vrfy_vregion_alloc(struct vregion *vr, size_t size) { - size_t vr_size = 0; - uintptr_t vr_start; + if (vregion_verify(vr)) + return z_impl_vregion_alloc(vr, size); - vregion_mem_info(vr, &vr_size, &vr_start); - if (vr_size) - K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); - - return z_impl_vregion_alloc(vr, size); + return NULL; } #include static inline void *z_vrfy_vregion_alloc_coherent(struct vregion *vr, size_t size) { - size_t vr_size = 0; - uintptr_t vr_start; - - vregion_mem_info(vr, &vr_size, &vr_start); - if (vr_size) - K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + if (vregion_verify(vr)) + return z_impl_vregion_alloc_coherent(vr, size); - return z_impl_vregion_alloc_coherent(vr, size); + return NULL; } #include static inline void *z_vrfy_vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) { - size_t vr_size = 0; - uintptr_t vr_start; - - vregion_mem_info(vr, &vr_size, &vr_start); - if (vr_size) - K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); + if (vregion_verify(vr)) + return z_impl_vregion_alloc_align(vr, size, alignment); - return z_impl_vregion_alloc_align(vr, size, alignment); + return NULL; } #include static inline void *z_vrfy_vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment) { - size_t vr_size = 0; - uintptr_t vr_start; + if (vregion_verify(vr)) + return z_impl_vregion_alloc_coherent_align(vr, size, alignment); - vregion_mem_info(vr, &vr_size, &vr_start); - if (vr_size) - K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); - - return z_impl_vregion_alloc_coherent_align(vr, size, alignment); + return NULL; } #include static inline void z_vrfy_vregion_free(struct vregion *vr, void *ptr) { - size_t vr_size = 0; - uintptr_t vr_start; - - vregion_mem_info(vr, &vr_size, &vr_start); - if (vr_size) - K_OOPS(K_SYSCALL_MEMORY_WRITE((void *)vr_start, vr_size)); - - z_impl_vregion_free(vr, ptr); + if (vregion_verify(vr)) + z_impl_vregion_free(vr, ptr); } #include From dcebcb6a7bb9582052c9845c2255b703df7a742f Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Tue, 7 Jul 2026 10:50:58 +0200 Subject: [PATCH 085/109] vregion: make 3 vregion API functions syscalls vregion_get(), vregion_put() and vregion_set_interim() should also be callable from the userspace. Make them syscalls. Also remove redundant symbol exporting since the vregion API shouldn't be used directly by LLEXT modules. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/vregion.h | 12 +++++------- zephyr/lib/vregion.c | 9 ++++----- zephyr/syscall/vregion.c | 23 +++++++++++++++++++++++ 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index a8aac6a2222f..baa176654263 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -51,7 +51,7 @@ struct vregion *vregion_create(size_t memsize); * * @param[in] vr Pointer to the virtual region instance. */ -void vregion_set_interim(struct vregion *vr); +__syscall void vregion_set_interim(struct vregion *vr); /** * @brief Increment virtual region's user count. @@ -62,7 +62,7 @@ void vregion_set_interim(struct vregion *vr); * @param[in] vr Pointer to the virtual region instance to release. * @return struct vregion* Pointer to the virtual region instance. */ -struct vregion *vregion_get(struct vregion *vr); +__syscall struct vregion *vregion_get(struct vregion *vr); /** * @brief Decrement virtual region's user count or destroy it. @@ -73,7 +73,7 @@ struct vregion *vregion_get(struct vregion *vr); * @param[in] vr Pointer to the virtual region instance to release. * @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed. */ -struct vregion *vregion_put(struct vregion *vr); +__syscall struct vregion *vregion_put(struct vregion *vr); /** * @brief Allocate memory from the specified virtual region. @@ -145,6 +145,8 @@ void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start); bool vregion_verify(struct vregion *vr); +#include + #else /* CONFIG_SOF_VREGIONS */ struct vregion { @@ -196,8 +198,4 @@ static inline bool vregion_verify(struct vregion *vr) {return false;} } #endif -#if CONFIG_SOF_VREGIONS -#include -#endif - #endif /* __SOF_LIB_VREGION_H__ */ diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c index 58f566680c9e..cede860b94f1 100644 --- a/zephyr/lib/vregion.c +++ b/zephyr/lib/vregion.c @@ -161,12 +161,12 @@ struct vregion *vregion_create(size_t memsize) /* log the new vregion */ LOG_INF("new at base %p size %#zx pages %u metadata at %p", - (void *)vr->base, total_size, pages, (void *)vr); + (void *)vregion_base, total_size, pages, (void *)vr); return vr; } -struct vregion *vregion_get(struct vregion *vr) +struct vregion *z_impl_vregion_get(struct vregion *vr) { if (!vr) return NULL; @@ -184,7 +184,7 @@ struct vregion *vregion_get(struct vregion *vr) * @param[in] vr Pointer to the virtual region instance to release. * @return struct vregion* Pointer to the virtual region instance or NULL if it has been destroyed. */ -struct vregion *vregion_put(struct vregion *vr) +struct vregion *z_impl_vregion_put(struct vregion *vr) { unsigned int use_count; @@ -259,7 +259,7 @@ static void interim_heap_init(struct vregion *vr) vr->lifetime.used = (uint8_t *)vr->lifetime.ptr - (uint8_t *)vr->lifetime.base; } -void vregion_set_interim(struct vregion *vr) +void z_impl_vregion_set_interim(struct vregion *vr) { if (!vr) return; @@ -491,7 +491,6 @@ void vregion_info(struct vregion *vr) LOG_INF("lifetime used %#zx free count %d", vr->lifetime.used, vr->lifetime.free_count); } -EXPORT_SYMBOL(vregion_info); void vregion_mem_info(struct vregion *vr, size_t *size, uintptr_t *start) { diff --git a/zephyr/syscall/vregion.c b/zephyr/syscall/vregion.c index 55ec58ffe3ce..abc912e88c29 100644 --- a/zephyr/syscall/vregion.c +++ b/zephyr/syscall/vregion.c @@ -49,3 +49,26 @@ static inline void z_vrfy_vregion_free(struct vregion *vr, void *ptr) z_impl_vregion_free(vr, ptr); } #include + +struct vregion *z_vrfy_vregion_get(struct vregion *vr) +{ + if (vregion_verify(vr)) + return z_impl_vregion_get(vr); + return NULL; +} +#include + +struct vregion *z_vrfy_vregion_put(struct vregion *vr) +{ + if (vregion_verify(vr)) + return z_impl_vregion_put(vr); + return NULL; +} +#include + +void z_vrfy_vregion_set_interim(struct vregion *vr) +{ + if (vregion_verify(vr)) + z_impl_vregion_set_interim(vr); +} +#include From 4034a060909f6931976d7f1a0488abff5a6e48da Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Mon, 6 Jul 2026 16:58:35 +0200 Subject: [PATCH 086/109] vregion: add mapping to vregion creation and freeing When userspace LL scheduling is enabled, some vregions have to be accessible to the LL userspace domain. Add a new system call to create vregions with such a mapping and add unmapping to freeing for such mapped vregions. Signed-off-by: Guennadi Liakhovetski --- src/audio/buffers/comp_buffer.c | 2 +- src/audio/module_adapter/module_adapter.c | 22 +++---- src/include/sof/lib/vregion.h | 11 ++++ zephyr/lib/vregion.c | 72 +++++++++++++++++++++++ zephyr/syscall/vregion.c | 8 +++ 5 files changed, 101 insertions(+), 14 deletions(-) diff --git a/src/audio/buffers/comp_buffer.c b/src/audio/buffers/comp_buffer.c index 8a3d44133d4b..37d2cc07e16c 100644 --- a/src/audio/buffers/comp_buffer.c +++ b/src/audio/buffers/comp_buffer.c @@ -166,7 +166,7 @@ static void comp_buffer_free(struct sof_audio_buffer *audio_buffer) if (alloc && alloc->vreg) { vregion_free(alloc->vreg, buffer); if (!vregion_put(alloc->vreg)) - rfree(alloc); + sof_heap_free(alloc->heap, alloc); } else { sof_heap_free(alloc ? alloc->heap : NULL, buffer); } diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 995501bfbe0a..0ac5de8edf1e 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -51,16 +51,6 @@ struct comp_dev *module_adapter_new(const struct comp_driver *drv, return module_adapter_new_ext(drv, config, spec, NULL, NULL, NULL); } -static struct vregion *module_adapter_dp_heap_new(const struct comp_ipc_config *config, - size_t *heap_size) -{ - /* src-lite with 8 channels has been seen allocating 14k in one go */ - /* FIXME: the size will be derived from configuration */ - const size_t buf_size = 28 * 1024; - - return vregion_create(buf_size); -} - static struct processing_module *module_adapter_mem_alloc(const struct comp_driver *drv, const struct comp_ipc_config *config) { @@ -77,11 +67,15 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv */ uint32_t flags = config->proc_domain == COMP_PROCESSING_DOMAIN_DP ? SOF_MEM_FLAG_USER | SOF_MEM_FLAG_COHERENT : SOF_MEM_FLAG_USER; - size_t heap_size; + size_t vreg_size; + uintptr_t vreg_start; if (config->proc_domain == COMP_PROCESSING_DOMAIN_DP && IS_ENABLED(CONFIG_SOF_VREGIONS) && IS_ENABLED(CONFIG_USERSPACE) && !IS_ENABLED(CONFIG_SOF_USERSPACE_USE_DRIVER_HEAP)) { - mod_vreg = module_adapter_dp_heap_new(config, &heap_size); + /* src-lite with 8 channels has been seen allocating 14k in one go */ + /* FIXME: the size will be derived from configuration */ + vreg_size = 28 * 1024; + mod_vreg = vregion_create_map(&vreg_start, &vreg_size); if (!mod_vreg) { comp_cl_err(drv, "Failed to allocate DP module heap / vregion"); return NULL; @@ -98,7 +92,8 @@ static struct processing_module *module_adapter_mem_alloc(const struct comp_driv #else mod_heap = drv->user_heap; #endif - heap_size = 0; + vreg_size = 0; + vreg_start = 0; mod_vreg = NULL; } @@ -199,6 +194,7 @@ static void module_adapter_mem_free(struct processing_module *mod) * * Note: Use the ext version if you need to set the module's private data before calling * the create method. + * Note 2: ATM runs in privileged / kernel mode for DP modules */ struct comp_dev *module_adapter_new_ext(const struct comp_driver *drv, const struct comp_ipc_config *config, diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index baa176654263..521f5ced26ca 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -42,6 +42,13 @@ enum vregion_mem_type { */ struct vregion *vregion_create(size_t memsize); +/** + * @brief Create and map a new virtual region instance. + * + * Like above, but usable by userspace and can add domain access. + */ +__syscall struct vregion *vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size); + /** * @brief Switch virtual region allocations to interim mode. * @@ -157,6 +164,10 @@ static inline struct vregion *vregion_create(size_t memsize) { return NULL; } +static inline struct vregion *vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size) +{ + return NULL; +} static inline void vregion_set_interim(struct vregion *vr) {} static inline struct vregion *vregion_get(struct vregion *vr) { diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c index cede860b94f1..87e72b4ae0fa 100644 --- a/zephyr/lib/vregion.c +++ b/zephyr/lib/vregion.c @@ -8,11 +8,13 @@ #include #include #include +#include #include #include #include #include #include +#include LOG_MODULE_REGISTER(vregion, CONFIG_SOF_LOG_LEVEL); @@ -87,6 +89,7 @@ struct vregion { unsigned int pages; /* size of whole region in pages */ struct k_mutex lock; /* protect vregion heaps and use-count */ unsigned int use_count; + struct k_mem_domain *domain; /* current allocation mode */ enum vregion_mem_type type; /* LIFETIME at creation, switch to INTERIM */ @@ -144,6 +147,7 @@ struct vregion *vregion_create(size_t memsize) vr->base = vregion_base; vr->size = total_size; vr->pages = pages; + vr->domain = NULL; /* lifetime linear allocator starts at the beginning of the vregion memory */ vr->lifetime.base = vregion_base; @@ -178,6 +182,72 @@ struct vregion *z_impl_vregion_get(struct vregion *vr) return vr; } +struct vregion *z_impl_vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size) +{ + if (!vreg_start || !vreg_size || !*vreg_size) + return NULL; + + struct vregion *vr = vregion_create(*vreg_size); + + if (!vr) + return NULL; + +#if CONFIG_USERSPACE && CONFIG_SOF_USERSPACE_LL + vregion_mem_info(vr, vreg_size, vreg_start); + + /* + * In the userspace LL case allocations are also performed by the + * userspace IPC thread, which is also the one, executing this syscall + */ + struct k_mem_domain *domain = zephyr_ll_mem_domain(); + struct k_mem_partition part = { + .start = *vreg_start, + .size = *vreg_size, + .attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB, + }; + int ret = k_mem_domain_add_partition(domain, &part); + + if (ret < 0) { + vregion_put(vr); + return NULL; + } + + part.start = (uintptr_t)sys_cache_uncached_ptr_get((void *)part.start); + part.attr = K_MEM_PARTITION_P_RW_U_RW; + + ret = k_mem_domain_add_partition(domain, &part); + if (ret < 0) { + vregion_put(vr); + return NULL; + } + + vr->domain = domain; +#endif + + return vr; +} + +static void vregion_unmap(struct vregion *vr) +{ +#if CONFIG_USERSPACE && CONFIG_SOF_USERSPACE_LL + if (!vr->domain) + return; + + struct k_mem_partition part = { + .attr = K_MEM_PARTITION_P_RW_U_RW | XTENSA_MMU_CACHED_WB, + .start = (uintptr_t)vr->base, + .size = vr->size, + }; + + k_mem_domain_remove_partition(vr->domain, &part); + + part.start = (uintptr_t)sys_cache_uncached_ptr_get((void *)part.start); + part.attr = K_MEM_PARTITION_P_RW_U_RW; + + k_mem_domain_remove_partition(vr->domain, &part); +#endif +} + /** * @brief Decrement virtual region's user count or destroy it. * @@ -204,6 +274,8 @@ struct vregion *z_impl_vregion_put(struct vregion *vr) LOG_DBG("destroy %p size %#zx pages %u", (void *)vr->base, vr->size, vr->pages); LOG_DBG(" lifetime used %zu free count %d", vr->lifetime.used, vr->lifetime.free_count); vpage_free(vr->base); + + vregion_unmap(vr); rfree(vr); return NULL; diff --git a/zephyr/syscall/vregion.c b/zephyr/syscall/vregion.c index abc912e88c29..d45678377e71 100644 --- a/zephyr/syscall/vregion.c +++ b/zephyr/syscall/vregion.c @@ -66,6 +66,14 @@ struct vregion *z_vrfy_vregion_put(struct vregion *vr) } #include +struct vregion *z_vrfy_vregion_create_map(uintptr_t *vreg_start, size_t *vreg_size) +{ + K_OOPS(K_SYSCALL_MEMORY_WRITE(vreg_start, sizeof(*vreg_start))); + K_OOPS(K_SYSCALL_MEMORY_WRITE(vreg_size, sizeof(*vreg_size))); + return z_impl_vregion_create_map(vreg_start, vreg_size); +} +#include + void z_vrfy_vregion_set_interim(struct vregion *vr) { if (vregion_verify(vr)) From c6080f441957748aa42e2817aabfc3f1821c0d80 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 27 Aug 2026 12:56:59 +0200 Subject: [PATCH 087/109] vregion: remove unneeded declarations z_impl_* functions are declared in automatically generated Zephyr headers, no need to declare them again. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/vregion.h | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index 521f5ced26ca..18fe579a31e2 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -91,15 +91,11 @@ __syscall struct vregion *vregion_put(struct vregion *vr); */ __syscall void *vregion_alloc(struct vregion *vr, size_t size); -void *z_impl_vregion_alloc(struct vregion *vr, size_t size); - /** * @brief like vregion_alloc() but allocates coherent memory */ __syscall void *vregion_alloc_coherent(struct vregion *vr, size_t size); -void *z_impl_vregion_alloc_coherent(struct vregion *vr, size_t size); - /** * @brief Allocate aligned memory from the specified virtual region. * @@ -113,15 +109,11 @@ void *z_impl_vregion_alloc_coherent(struct vregion *vr, size_t size); */ __syscall void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); -void *z_impl_vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); - /** * @brief like vregion_alloc_align() but allocates coherent memory */ __syscall void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); -void *z_impl_vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); - /** * @brief Free memory allocated from the specified virtual region. * @@ -132,8 +124,6 @@ void *z_impl_vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_ */ __syscall void vregion_free(struct vregion *vr, void *ptr); -void z_impl_vregion_free(struct vregion *vr, void *ptr); - /** * @brief Log virtual region memory usage. * From ba65768477188155aef34bbc33138d5f61064c28 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Thu, 27 Aug 2026 13:02:04 +0200 Subject: [PATCH 088/109] vregion: make two functions inline Make vregion_alloc() and vregion_alloc_coherent() static inlines, calling their respective aligned versions with zero alignment. Signed-off-by: Guennadi Liakhovetski --- src/include/sof/lib/vregion.h | 30 ++++++++++++++++++------------ zephyr/lib/vregion.c | 27 --------------------------- zephyr/syscall/vregion.c | 18 ------------------ 3 files changed, 18 insertions(+), 57 deletions(-) diff --git a/src/include/sof/lib/vregion.h b/src/include/sof/lib/vregion.h index 18fe579a31e2..559c47ed3431 100644 --- a/src/include/sof/lib/vregion.h +++ b/src/include/sof/lib/vregion.h @@ -83,36 +83,42 @@ __syscall struct vregion *vregion_get(struct vregion *vr); __syscall struct vregion *vregion_put(struct vregion *vr); /** - * @brief Allocate memory from the specified virtual region. + * @brief Allocate aligned memory from the specified virtual region. + * + * Allocate aligned memory from the specified virtual region using the + * current allocation mode (lifetime or interim). * * @param[in] vr Pointer to the virtual region instance. * @param[in] size Size of memory to allocate in bytes. + * @param[in] alignment Alignment of memory to allocate in bytes. * @return void* Pointer to the allocated memory, or NULL on failure. */ -__syscall void *vregion_alloc(struct vregion *vr, size_t size); +__syscall void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); /** - * @brief like vregion_alloc() but allocates coherent memory + * @brief like vregion_alloc_align() but allocates coherent memory */ -__syscall void *vregion_alloc_coherent(struct vregion *vr, size_t size); +__syscall void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); /** - * @brief Allocate aligned memory from the specified virtual region. - * - * Allocate aligned memory from the specified virtual region using the - * current allocation mode (lifetime or interim). + * @brief Allocate memory from the specified virtual region. * * @param[in] vr Pointer to the virtual region instance. * @param[in] size Size of memory to allocate in bytes. - * @param[in] alignment Alignment of memory to allocate in bytes. * @return void* Pointer to the allocated memory, or NULL on failure. */ -__syscall void *vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment); +static inline void *vregion_alloc(struct vregion *vr, size_t size) +{ + return vregion_alloc_align(vr, size, 0); +} /** - * @brief like vregion_alloc_align() but allocates coherent memory + * @brief like vregion_alloc() but allocates coherent memory */ -__syscall void *vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment); +static inline void *vregion_alloc_coherent(struct vregion *vr, size_t size) +{ + return vregion_alloc_coherent_align(vr, size, 0); +} /** * @brief Free memory allocated from the specified virtual region. diff --git a/zephyr/lib/vregion.c b/zephyr/lib/vregion.c index 87e72b4ae0fa..e8cfb2347246 100644 --- a/zephyr/lib/vregion.c +++ b/zephyr/lib/vregion.c @@ -504,33 +504,6 @@ void *z_impl_vregion_alloc_align(struct vregion *vr, } EXPORT_SYMBOL(z_impl_vregion_alloc_align); -/** - * @brief Allocate memory from the virtual region. - * @param[in] vr Pointer to the virtual region instance. - * @param[in] size Size of the allocation. - * @return void* Pointer to the allocated memory, or NULL on failure. - */ -void *z_impl_vregion_alloc(struct vregion *vr, size_t size) -{ - return z_impl_vregion_alloc_align(vr, size, 0); -} -EXPORT_SYMBOL(z_impl_vregion_alloc); - -void *z_impl_vregion_alloc_coherent(struct vregion *vr, size_t size) -{ - size = ALIGN_UP(size, CONFIG_DCACHE_LINE_SIZE); - - void *p = z_impl_vregion_alloc_align(vr, size, CONFIG_DCACHE_LINE_SIZE); - - if (!p) - return NULL; - - sys_cache_data_invd_range(p, size); - - return sys_cache_uncached_ptr_get(p); -} -EXPORT_SYMBOL(z_impl_vregion_alloc_coherent); - void *z_impl_vregion_alloc_coherent_align(struct vregion *vr, size_t size, size_t alignment) { if (alignment < CONFIG_DCACHE_LINE_SIZE) diff --git a/zephyr/syscall/vregion.c b/zephyr/syscall/vregion.c index d45678377e71..dd02f854cf82 100644 --- a/zephyr/syscall/vregion.c +++ b/zephyr/syscall/vregion.c @@ -6,24 +6,6 @@ #include #include -static inline void *z_vrfy_vregion_alloc(struct vregion *vr, size_t size) -{ - if (vregion_verify(vr)) - return z_impl_vregion_alloc(vr, size); - - return NULL; -} -#include - -static inline void *z_vrfy_vregion_alloc_coherent(struct vregion *vr, size_t size) -{ - if (vregion_verify(vr)) - return z_impl_vregion_alloc_coherent(vr, size); - - return NULL; -} -#include - static inline void *z_vrfy_vregion_alloc_align(struct vregion *vr, size_t size, size_t alignment) { if (vregion_verify(vr)) From c401b411e64e3171376562b4db3c24b5e7093325 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 25 Aug 2026 09:55:57 +0300 Subject: [PATCH 089/109] topology: cmake: build topologies in parallel, add -s to force sequential alsatplg custom commands were marked USES_TERMINAL. With the Ninja generator this places them in the single-job "console" pool, which serializes every topology build regardless of the -j value passed to ninja. Building all 579 topologies therefore never used more than one core, even on a many-core machine. Drop USES_TERMINAL by default so Ninja can run alsatplg invocations in parallel, controlled by a new TPLG_SEQUENTIAL_BUILD CMake option (default OFF). Add a -s flag to build-tools.sh that sets TPLG_SEQUENTIAL_BUILD=ON, to restore the old, easier to debug one-at-a-time behavior when needed. It updates the CMake cache in place, so it also works on an existing incremental build tree without deleting it. Results Sequential (before this patch or with -T -s with this patch): ./scripts/build-tools.sh -T -s 19.30s user 2.34s system 99% cpu 21.817 total Parallel: rm -rf tools/build_tools; time ./scripts/build-tools.sh -T ./scripts/build-tools.sh -T 33.79s user 3.52s system 986% cpu 3.783 total The build time changes from ~22s to ~4s Signed-off-by: Peter Ujfalusi --- scripts/README.md | 1 + scripts/build-tools.sh | 25 +++++++++++++++++++++---- tools/topology/CMakeLists.txt | 14 ++++++++++++-- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/scripts/README.md b/scripts/README.md index 30441422899b..8833eb33e21e 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -50,6 +50,7 @@ Tooling and topology can be built together using one script. To build all topolo * `-T` : Rebuild ALL `topology/` targets * `-X` : Rebuild topology1 only * `-Y` : Rebuild topology2 only +* `-s` : Force sequential (one at a time) topology builds, for debugging. Topologies build in parallel by default. * `-t` : Rebuild test topologies * `-A` : Clone and rebuild the local ALSA git version for `alsa-lib` and `alsa-utils` with latest non-distro features. * `-C` : No build, only CMake re-configuration. Shows CMake targets. diff --git a/scripts/build-tools.sh b/scripts/build-tools.sh index 6304265820cd..e2f1de4ad797 100755 --- a/scripts/build-tools.sh +++ b/scripts/build-tools.sh @@ -16,7 +16,7 @@ Attention: the list of selected shortcuts below is _not_ exhaustive. To build _everything_ don't select any particular target; this will build CMake's default target "ALL". -usage: $0 [-c|-f|-h|-l|-p|-t|-T|-X|-Y|-A] +usage: $0 [-c|-f|-h|-l|-p|-s|-t|-T|-X|-Y|-A] -h Display help -c Rebuild ctl/ @@ -25,6 +25,8 @@ usage: $0 [-c|-f|-h|-l|-p|-t|-T|-X|-Y|-A] -T Rebuild topology/ (not topology/development/! Use ALL) -X Rebuild topology1 only -Y Rebuild topology2 only + -s Force sequential (one at a time) topology builds, for debugging. + Normally topologies build in parallel with -j "$NO_PROCESSORS". -t Rebuild test/topology/ (or tools/test/topology/tplg-build.sh directly) -A Clone and rebuild local ALSA lib and utils. @@ -41,10 +43,19 @@ reconfigure_build() mkdir -p "$BUILD_TOOLS_DIR" ( cd "$BUILD_TOOLS_DIR" - cmake -GNinja -DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" "${SOF_REPO}/tools" + cmake -GNinja -DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" \ + -DTPLG_SEQUENTIAL_BUILD="$TPLG_SEQUENTIAL_BUILD" "${SOF_REPO}/tools" ) } +# Update the TPLG_SEQUENTIAL_BUILD CMake cache entry without wiping an +# existing, already configured build tree. +update_sequential_build_option() +{ + cmake -S "${SOF_REPO}/tools" -B "$BUILD_TOOLS_DIR" \ + -DTPLG_SEQUENTIAL_BUILD="$TPLG_SEQUENTIAL_BUILD" +} + make_tool() { # if no argument provided, all the tools will be built. Empty tool is @@ -95,12 +106,13 @@ main() { local DO_BUILD_ctl DO_BUILD_logger DO_BUILD_probes \ DO_BUILD_tests DO_BUILD_topologies1 DO_BUILD_topologies2 SCRIPT_DIR SOF_REPO \ - CMAKE_ONLY BUILD_ALL + CMAKE_ONLY BUILD_ALL TPLG_SEQUENTIAL_BUILD SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd) SOF_REPO=$(dirname "$SCRIPT_DIR") : "${BUILD_TOOLS_DIR:=$SOF_REPO/tools/build_tools}" : "${NO_PROCESSORS:=$(nproc)}" BUILD_ALL=false + TPLG_SEQUENTIAL_BUILD=OFF if [ $# -eq 0 ]; then BUILD_ALL=true @@ -120,11 +132,12 @@ main() # eval is a sometimes necessary evil # shellcheck disable=SC2034 - while getopts "cfhlptTCXYA" OPTION; do + while getopts "cfhlpstTCXYA" OPTION; do case "$OPTION" in c) DO_BUILD_ctl=true ;; l) DO_BUILD_logger=true ;; p) DO_BUILD_probes=true ;; + s) TPLG_SEQUENTIAL_BUILD=ON ;; t) DO_BUILD_tests=true ;; T) DO_BUILD_topologies1=true ; DO_BUILD_topologies2=true ;; X) DO_BUILD_topologies1=true ;; @@ -153,6 +166,10 @@ main() reconfigure_build } + # Switching -s on or off must apply even to an already configured, + # incremental build tree, so update the cache unconditionally. + update_sequential_build_option + if "$BUILD_ALL"; then # default CMake targets make_tool # trust set -e diff --git a/tools/topology/CMakeLists.txt b/tools/topology/CMakeLists.txt index 92a7acf6e5a6..263bc8a4f75f 100644 --- a/tools/topology/CMakeLists.txt +++ b/tools/topology/CMakeLists.txt @@ -2,6 +2,16 @@ set(SOF_TOPOLOGY_BINARY_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}") set(SOF_ALSA_TOOLS_DIR "${SOF_ROOT_SOURCE_DIRECTORY}/../tools/bin") set(ALSATPLG_CMD "${SOF_ALSA_TOOLS_DIR}/alsatplg") +# With the Ninja generator, USES_TERMINAL forces the single-job "console" +# pool, serializing every topology build regardless of -j. Enable this +# option to force that serialized, easier to debug behavior back on. +option(TPLG_SEQUENTIAL_BUILD "Build topologies one at a time (for debugging)" OFF) +if(TPLG_SEQUENTIAL_BUILD) + set(TPLG_USES_TERMINAL USES_TERMINAL) +else() + set(TPLG_USES_TERMINAL "") +endif() + function(alsatplg_version OUT_STATUS OUT_VERSION) execute_process(COMMAND ${ALSATPLG_CMD} --version RESULT_VARIABLE status @@ -69,7 +79,7 @@ macro(add_alsatplg_command) # the -o(utput) file. # See bug https://github.com/alsa-project/alsa-utils/issues/126 COMMAND ${ALSATPLG_CMD} \$\${VERBOSE:+-v 1} -c ${ARGV0} -o ${ARGV1} - USES_TERMINAL + ${TPLG_USES_TERMINAL} ) endmacro() @@ -97,7 +107,7 @@ macro(add_alsatplg2_command conf_header conf_target input_name output_name inclu # -p to pre-process Topology2.0 conf file COMMAND ALSA_CONFIG_DIR=${CMAKE_SOURCE_DIR}/topology/topology2 ${ALSATPLG_CMD} \$\${VERBOSE:+-v 1} -I ${include_path} -D "'${defines}'" -p -c ${output_name}.conf -o ${output_name}.tplg - USES_TERMINAL + ${TPLG_USES_TERMINAL} ) endmacro() From fabfc964878ee17828030332a5fb9287ab76ddf3 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Sat, 22 Aug 2026 20:20:45 +0200 Subject: [PATCH 090/109] iadk: system_agent: reject unparsable module settings Reject malformed initialization data before deriving the extended module configuration. Signed-off-by: Adrian Bonislawski --- src/audio/module_adapter/iadk/system_agent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index caed8cf65860..ebf3567876cb 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -91,6 +91,8 @@ int SystemAgent::CheckIn(ProcessingModuleFactoryInterface& module_factory, const dsp_fw::DwordArray& cfg_ipc_msg = *reinterpret_cast(obfuscated_mod_cfg); ModuleInitialSettingsConcrete settings(cfg_ipc_msg); + if (!settings.IsParsable()) + return -EINVAL; ProcessingModulePrerequisites prerequisites; module_factory.GetPrerequisites(prerequisites); From 07ee36cf89f4b8515c4336f2419d8a18f78616a3 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Sat, 22 Aug 2026 20:21:25 +0200 Subject: [PATCH 091/109] iadk: system_agent: handle module factory creation errors Stop module initialization when the external factory reports a creation error. Signed-off-by: Adrian Bonislawski --- src/audio/module_adapter/iadk/system_agent.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index ebf3567876cb..a805ddd24f8d 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -87,6 +87,7 @@ int SystemAgent::CheckIn(ProcessingModuleFactoryInterface& module_factory, void *obfuscated_parent_ppl, void **obfuscated_modinst_p) { + ErrorCode::Type error; IoPinsInfo pins_info; const dsp_fw::DwordArray& cfg_ipc_msg = *reinterpret_cast(obfuscated_mod_cfg); @@ -112,7 +113,11 @@ int SystemAgent::CheckIn(ProcessingModuleFactoryInterface& module_factory, settings.DeduceBaseModuleCfgExt(prerequisites.input_pins_count, prerequisites.output_pins_count); - module_factory.Create(*this, module_placeholder, ModuleInitialSettings(settings), pins_info); + error = module_factory.Create(*this, module_placeholder, ModuleInitialSettings(settings), + pins_info); + if (error != ErrorCode::NO_ERROR) + return -EINVAL; + IadkModuleAdapter& module_adapter = *reinterpret_cast(module_handle_); *obfuscated_modinst_p = &module_adapter; reinterpret_cast(module_placeholder)->Init(); From f036c8b2aefd75e9004618b60fbcfcbab3a06afd Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Sat, 22 Aug 2026 20:22:03 +0200 Subject: [PATCH 092/109] iadk: ModuleInitialSettingsConcrete: use output pin size Use the matching output pin type when validating compound configuration sizes. Signed-off-by: Adrian Bonislawski --- .../module_adapter/iadk/module_initial_settings_concrete.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp b/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp index 82e1e02f5e96..83ac99a07835 100644 --- a/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp +++ b/src/audio/module_adapter/iadk/module_initial_settings_concrete.cpp @@ -54,11 +54,11 @@ ModuleInitialSettingsConcrete::ModuleInitialSettingsConcrete(DwordArray const &c const size_t computed_msg_size = sizeof(CompoundCfg) - /* CompoundCfg already contains one InputPinFormat and - * one InputPinFormat + * one OutputPinFormat */ (sizeof(InputPinFormat) + sizeof(OutputPinFormat)) + unvalidated_compound_cfg->cfg_ext.nb_input_pins*sizeof(InputPinFormat) + - unvalidated_compound_cfg->cfg_ext.nb_output_pins*sizeof(InputPinFormat); + unvalidated_compound_cfg->cfg_ext.nb_output_pins*sizeof(OutputPinFormat); /* check size consistency */ if (ipc_msg_size != computed_msg_size) { From 89abbfb7376ca633148e2947ff423bcb633dae29 Mon Sep 17 00:00:00 2001 From: Adrian Bonislawski Date: Wed, 26 Aug 2026 10:31:44 +0200 Subject: [PATCH 093/109] iadk: system_agent: return -EINVAL for invalid pin counts Return -EINVAL instead when module prerequisites specify an unsupported number of input or output pins. Signed-off-by: Adrian Bonislawski --- src/audio/module_adapter/iadk/system_agent.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/module_adapter/iadk/system_agent.cpp b/src/audio/module_adapter/iadk/system_agent.cpp index a805ddd24f8d..7f5bc63a9559 100644 --- a/src/audio/module_adapter/iadk/system_agent.cpp +++ b/src/audio/module_adapter/iadk/system_agent.cpp @@ -107,7 +107,7 @@ int SystemAgent::CheckIn(ProcessingModuleFactoryInterface& module_factory, (prerequisites.input_pins_count > INPUT_PIN_COUNT) || (prerequisites.output_pins_count < 1) || (prerequisites.output_pins_count > OUTPUT_PIN_COUNT)) - return -1; + return -EINVAL; /* Deduce BaseModuleCfgExt if it was not part of the INIT_INSTANCE IPC message */ settings.DeduceBaseModuleCfgExt(prerequisites.input_pins_count, From 3d03219735d6dd712c7ff610dffce7b7f803fe2c Mon Sep 17 00:00:00 2001 From: Mateusz Redzynia Date: Wed, 26 Aug 2026 12:42:59 +0200 Subject: [PATCH 094/109] ci: add concurrency groups to all pr triggered workflows Add concurrency groups to all pr triggered workflows. ```${{ github.workflow }}-${{ github.event_name }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}``` In case of PR trigger the above translates to: - ```'Zephyr-pull_request-refs/pull/{pr_number}/merge'``` In any other case it translates to: - ```'Zephyr-workflow_dispatch-62137'``` - ```'Zephyr-push-62138'``` This allows to group and cancel only PR runs that can clog the CI and skips the dispatched or pushed workflows. Signed-off-by: Mateusz Redzynia --- .github/workflows/build_all.yml | 6 ++++++ .github/workflows/codeql.yml | 4 ++-- .github/workflows/codestyle.yml | 6 ++++++ .github/workflows/ipc_fuzzer.yml | 6 ++++++ .github/workflows/llext.yml | 6 ++++++ .github/workflows/pull-request.yml | 6 ++++++ .github/workflows/repro-build.yml | 6 ++++++ .github/workflows/rimage.yml | 6 ++++++ .github/workflows/sof-docs.yml | 6 ++++++ .github/workflows/sparse-zephyr.yml | 6 ++++++ .github/workflows/testbench.yml | 6 ++++++ .github/workflows/tools.yml | 6 ++++++ .github/workflows/unit-tests.yml | 6 ++++++ .github/workflows/zephyr-shell.yml | 6 ++++++ .github/workflows/zephyr-unit-tests.yml | 6 +++--- .github/workflows/zephyr.yml | 9 +++++---- .github/workflows/zizmor.yml | 5 +++-- 17 files changed, 91 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build_all.yml b/.github/workflows/build_all.yml index 19fee4a98ca4..9115fa26d071 100644 --- a/.github/workflows/build_all.yml +++ b/.github/workflows/build_all.yml @@ -11,6 +11,12 @@ on: [pull_request, workflow_dispatch, workflow_call] permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: stub-build: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 4f7c29d6c831..cc99ee2c209b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -9,9 +9,9 @@ on: permissions: contents: read -# Specifies group name that stops previous workflows if the name matches +# Group workflows together to cancel outdated runs concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: true jobs: diff --git a/.github/workflows/codestyle.yml b/.github/workflows/codestyle.yml index ea9e0a20d150..fab95196af88 100644 --- a/.github/workflows/codestyle.yml +++ b/.github/workflows/codestyle.yml @@ -17,6 +17,12 @@ on: [pull_request, workflow_call, workflow_dispatch] permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: yamllint: runs-on: ubuntu-latest diff --git a/.github/workflows/ipc_fuzzer.yml b/.github/workflows/ipc_fuzzer.yml index f52291839111..6b89339e7445 100644 --- a/.github/workflows/ipc_fuzzer.yml +++ b/.github/workflows/ipc_fuzzer.yml @@ -25,6 +25,12 @@ on: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: simple-IPC-fuzz_sh: diff --git a/.github/workflows/llext.yml b/.github/workflows/llext.yml index 149c9e2e3571..5b3defbe5cc0 100644 --- a/.github/workflows/llext.yml +++ b/.github/workflows/llext.yml @@ -14,6 +14,12 @@ defaults: permissions: contents: read +# Group workflows together to cancel outdated runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: build: runs-on: ubuntu-24.04 diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 0bd3865dec97..86680903cfb9 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -34,6 +34,12 @@ on: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: doxygen: diff --git a/.github/workflows/repro-build.yml b/.github/workflows/repro-build.yml index abe48a8cecb2..3c68f9c35235 100644 --- a/.github/workflows/repro-build.yml +++ b/.github/workflows/repro-build.yml @@ -17,6 +17,12 @@ on: [pull_request, workflow_dispatch, workflow_call] permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: main: runs-on: ubuntu-24.04 diff --git a/.github/workflows/rimage.yml b/.github/workflows/rimage.yml index 53059681ae9d..de2372fead42 100644 --- a/.github/workflows/rimage.yml +++ b/.github/workflows/rimage.yml @@ -25,6 +25,12 @@ on: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: # Basic build test diff --git a/.github/workflows/sof-docs.yml b/.github/workflows/sof-docs.yml index 63af4acfc714..46c9b5361054 100644 --- a/.github/workflows/sof-docs.yml +++ b/.github/workflows/sof-docs.yml @@ -20,6 +20,12 @@ on: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: # This is unfortunately a mix of sof-docs/.github/ + pull-request.yml#doxygen diff --git a/.github/workflows/sparse-zephyr.yml b/.github/workflows/sparse-zephyr.yml index 5afa6361f51a..a10002d44924 100644 --- a/.github/workflows/sparse-zephyr.yml +++ b/.github/workflows/sparse-zephyr.yml @@ -14,6 +14,12 @@ defaults: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: # As of sparse commit ce1a6720f69e / Sept 2022, the exit status of # sparse.c is an unusable mess and always zero in practice. Moreover diff --git a/.github/workflows/testbench.yml b/.github/workflows/testbench.yml index d54b1db331db..f7d3b866982e 100644 --- a/.github/workflows/testbench.yml +++ b/.github/workflows/testbench.yml @@ -31,6 +31,12 @@ on: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: build-and-test: runs-on: ubuntu-24.04 diff --git a/.github/workflows/tools.yml b/.github/workflows/tools.yml index 825b571321d8..5fdc1c443d41 100644 --- a/.github/workflows/tools.yml +++ b/.github/workflows/tools.yml @@ -10,6 +10,12 @@ on: [pull_request, workflow_dispatch, workflow_call] permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: # This is not the same as building every ./build-tools.sh option. top-level_default_CMake_target_ALL: diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index de8577e87171..76e8c5c9e0b7 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -13,6 +13,12 @@ on: [pull_request, workflow_dispatch, workflow_call] permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: cmocka_utests: runs-on: ubuntu-latest diff --git a/.github/workflows/zephyr-shell.yml b/.github/workflows/zephyr-shell.yml index 23f8e6947b22..9d09f05da3bf 100644 --- a/.github/workflows/zephyr-shell.yml +++ b/.github/workflows/zephyr-shell.yml @@ -23,6 +23,12 @@ defaults: permissions: contents: read +# Group workflows together to cancel outdated runs, do not cancel manual runs +concurrency: + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" + cancel-in-progress: true + jobs: build: runs-on: ubuntu-24.04 diff --git a/.github/workflows/zephyr-unit-tests.yml b/.github/workflows/zephyr-unit-tests.yml index ed089a148597..6d6e9bdf0d88 100644 --- a/.github/workflows/zephyr-unit-tests.yml +++ b/.github/workflows/zephyr-unit-tests.yml @@ -1,5 +1,5 @@ --- -name: "Unit tests" +name: "Zephyr Unit tests" # yamllint disable-line rule:truthy on: pull_request: @@ -9,9 +9,9 @@ on: permissions: contents: read -# Specifies group name that stops previous workflows if the name matches +# Group workflows together to cancel outdated runs concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} cancel-in-progress: true jobs: diff --git a/.github/workflows/zephyr.yml b/.github/workflows/zephyr.yml index ecfc6f4089ee..863526ced731 100644 --- a/.github/workflows/zephyr.yml +++ b/.github/workflows/zephyr.yml @@ -17,11 +17,12 @@ on: required: false default: 'mnfst' -# Specifies group name that stops previous wokrflows if the name matches +# Group workflows together to cancel outdated runs, do not cancel manual runs concurrency: - # eg. "Zephyr-pull_request-my_fork_branch_to_merge" - # eg. "Zephyr-push-refs/heads/my_branch_merging" - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + # eg. 'Zephyr-workflow_dispatch-62137' + # eg. 'Zephyr-pull_request-refs/pull/{pr_number}/merge' + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" cancel-in-progress: true permissions: diff --git a/.github/workflows/zizmor.yml b/.github/workflows/zizmor.yml index 45303525aa81..8f66645c692f 100644 --- a/.github/workflows/zizmor.yml +++ b/.github/workflows/zizmor.yml @@ -11,9 +11,10 @@ on: permissions: {} -# Specifies group name that stops previous workflows if the name matches +# Group workflows together to cancel outdated runs, do not cancel manual runs concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref }} + group: "${{ github.workflow }}-${{ github.event_name }}-\ + ${{ github.event_name == 'pull_request' && github.ref || github.run_id }}" cancel-in-progress: true jobs: From 947611a157e553833b584335b74ac619b1840d18 Mon Sep 17 00:00:00 2001 From: Serhiy Katsyuba Date: Wed, 26 Aug 2026 17:15:04 +0200 Subject: [PATCH 095/109] ipc4: honor pipeline pause requests The no_pause flag should not be used with IPC4. An IPC4 module must not silently ignore a pipeline pause request without sending an error response. This fixes a crash during pipeline deletion when a pipeline containing a MUX ignored a prior PAUSE request and remained active during teardown. Signed-off-by: Serhiy Katsyuba --- src/audio/module_adapter/module_adapter.c | 2 ++ src/audio/mux/mux.c | 2 ++ src/include/module/module/base.h | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/audio/module_adapter/module_adapter.c b/src/audio/module_adapter/module_adapter.c index 0ac5de8edf1e..f94d5fe4f572 100644 --- a/src/audio/module_adapter/module_adapter.c +++ b/src/audio/module_adapter/module_adapter.c @@ -1357,6 +1357,7 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd) if (dev->ipc_config.type == SOF_COMP_HOST || dev->ipc_config.type == SOF_COMP_DAI) return interface->endpoint_ops->trigger(dev, cmd); +#if CONFIG_IPC_MAJOR_3 /* * If the module doesn't support pause, keep it active along with the rest of the * downstream modules @@ -1365,6 +1366,7 @@ int module_adapter_trigger(struct comp_dev *dev, int cmd) dev->state = COMP_STATE_ACTIVE; return PPL_STATUS_PATH_STOP; } +#endif if (interface->trigger) { #if CONFIG_SOF_USERSPACE_APPLICATION diff --git a/src/audio/mux/mux.c b/src/audio/mux/mux.c index 1476779e7324..c651f772a598 100644 --- a/src/audio/mux/mux.c +++ b/src/audio/mux/mux.c @@ -112,7 +112,9 @@ static int mux_demux_common_init(struct processing_module *mod, enum sof_comp_ty } mod->verify_params_flags = BUFF_PARAMS_CHANNELS; +#if CONFIG_IPC_MAJOR_3 mod->no_pause = true; +#endif cd->comp_type = type; return 0; diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index 8818ffb9f212..5d41d2d8a6b4 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -168,8 +168,10 @@ struct processing_module { */ bool dp_startup_delay; +#if CONFIG_IPC_MAJOR_3 /* flag to indicate module does not pause */ bool no_pause; +#endif /* * flag to indicate that the sink buffer writeback should be skipped. It will be handled From 682b5fd7ee9610cc98445187b3a6c0bda5bfe92f Mon Sep 17 00:00:00 2001 From: Daniel Baluta Date: Tue, 18 Aug 2026 11:47:03 +0300 Subject: [PATCH 096/109] ipc4: use fixed-width types in ipc4_audio_format struct ipc4_audio_format used bare enum members. On ARM EABI targets (e.g i.MX95 Cortex-M7) the toolchain defaults to -fshort-enums, which shrinks the enum-typed members. This makes host-supplied channels_count/valid_bit_depth be on the wrong offset. Fix this by using fixed uint32_t type instead of enums. Note that the same struct on the Linux kernel side uses uint32_t so this patch also aligns ipc4_audio_format structs on FW side / Host side. Signed-off-by; Daniel Baluta --- src/include/module/ipc4/base-config.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/module/ipc4/base-config.h b/src/include/module/ipc4/base-config.h index e5a5b49effd5..82a6d552306b 100644 --- a/src/include/module/ipc4/base-config.h +++ b/src/include/module/ipc4/base-config.h @@ -115,14 +115,14 @@ enum ipc4_stream_type { }; struct ipc4_audio_format { - enum ipc4_sampling_frequency sampling_frequency; - enum ipc4_bit_depth depth; + uint32_t sampling_frequency; /* enum ipc4_sampling_frequency */ + uint32_t depth; /* enum ipc4_bit_depth */ uint32_t ch_map; - enum ipc4_channel_config ch_cfg; + uint32_t ch_cfg; /* enum ipc4_channel_config */ uint32_t interleaving_style; uint32_t channels_count : 8; uint32_t valid_bit_depth : 8; - enum ipc4_sample_type s_type : 8; + uint32_t s_type : 8; /* enum ipc4_sample_type */ uint32_t reserved : 8; } __attribute__((packed, aligned(4))); From 49de2702eebd96a993094e1ec1b0dead83816e54 Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Sat, 22 Aug 2026 12:07:06 +0530 Subject: [PATCH 097/109] topology2: add WoV feature topology targets and graph Add a standalone feature manifest (dmic-wov-feature.conf) for WoV/KPB pipeline loaded on top of the function topology via feature_topologies. Add a single platform-agnostic feature topology target sof-dmic-4ch-wov in tplg-targets-ace3.cmake, shared across PTL (rt721/rt722) and WCL. Signed-off-by: Naveen Manohar --- .../topology/topology2/dmic-wov-feature.conf | 31 +++++++++++++++++++ .../include/pipelines/cavs/wov-detect.conf | 2 ++ .../production/tplg-targets-ace3.cmake | 4 +++ 3 files changed, 37 insertions(+) create mode 100644 tools/topology/topology2/dmic-wov-feature.conf diff --git a/tools/topology/topology2/dmic-wov-feature.conf b/tools/topology/topology2/dmic-wov-feature.conf new file mode 100644 index 000000000000..a260404cf33b --- /dev/null +++ b/tools/topology/topology2/dmic-wov-feature.conf @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf b/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf index 0f4490525c83..ff192d4679ac 100644 --- a/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf +++ b/tools/topology/topology2/include/pipelines/cavs/wov-detect.conf @@ -58,6 +58,8 @@ Class.Pipeline."wov-detect" { } micsel."1" { + num_input_audio_formats 1 + num_output_audio_formats 1 Object.Base.input_audio_format [ { in_rate 16000 diff --git a/tools/topology/topology2/production/tplg-targets-ace3.cmake b/tools/topology/topology2/production/tplg-targets-ace3.cmake index bb1c07a83356..06ffc7eb11a7 100644 --- a/tools/topology/topology2/production/tplg-targets-ace3.cmake +++ b/tools/topology/topology2/production/tplg-targets-ace3.cmake @@ -108,6 +108,10 @@ SDW_JACK_OUT_STREAM=Playback-SimpleJack,SDW_JACK_IN_STREAM=Capture-SimpleJack,\ PREPROCESS_PLUGINS=nhlt,NHLT_BIN=nhlt-sof-ptl-rt722-4ch.bin,DMIC0_ENHANCED_CAPTURE=true,\ EFX_DMIC0_TDFB_PARAMS=line4_pass,EFX_DMIC0_DRC_PARAMS=dmic_default" +# DMIC WoV feature topology; platform-agnostic, shared across PTL/WCL +"dmic-wov-feature\;sof-dmic-4ch-wov\;PLATFORM=none,NUM_DMICS=4,\ +DMIC0_ID=5,DMIC1_ID=6,DMIC1_ENABLE=false,DMIC1_RATE=16000,INCLUDE_WOV=true" + "cavs-sdw\;sof-ptl-rt722-2ch\;PLATFORM=ptl,SDW_DMIC=1,NUM_SDW_AMP_LINKS=1,NUM_DMICS=2,\ PDM1_MIC_A_ENABLE=0,PDM1_MIC_B_ENABLE=0,DMIC0_ID=5,DMIC1_ID=6,HDMI1_ID=7,HDMI2_ID=8,HDMI3_ID=9,\ SDW_AMP_FEEDBACK=false,SDW_SPK_STREAM=Playback-SmartAmp,SDW_DMIC_STREAM=Capture-SmartMic,\ From 5e1f9760de21590edabe90a5ae6004d7d5c4837c Mon Sep 17 00:00:00 2001 From: Naveen Manohar Date: Sat, 22 Aug 2026 12:07:06 +0530 Subject: [PATCH 098/109] rimage: wcl: wire google hotword module manifest Add Google hotword module manifest for WCL and include it when CONFIG_COMP_GOOGLE_HOTWORD_DETECT is enabled or all modular components are forced. Signed-off-by: Naveen Manohar --- src/audio/google/google_hotword_detect.toml | 23 +++++++++++++++++++++ tools/rimage/config/wcl.toml.h | 4 ++++ 2 files changed, 27 insertions(+) create mode 100644 src/audio/google/google_hotword_detect.toml diff --git a/src/audio/google/google_hotword_detect.toml b/src/audio/google/google_hotword_detect.toml new file mode 100644 index 000000000000..1c51b2f07eb3 --- /dev/null +++ b/src/audio/google/google_hotword_detect.toml @@ -0,0 +1,23 @@ +#ifndef LOAD_TYPE +#define LOAD_TYPE "0" +#endif + +[[module.entry]] +name = "HOTWORD" +uuid = UUIDREG_STR_GOOGLE_HOTWORD +affinity_mask = "0x1" +instance_count = "1" +domain_types = "0" +load_type = LOAD_TYPE +module_type = "10" +auto_start = "0" +sched_caps = [1, 0x00008000] + +REM # pin = [dir, type, sample rate, size, container, channel-cfg] +pin = [0, 0, 0x8, 0x2, 0x2, 0x3, + 1, 0, 0xfeef, 0xf, 0xf, 0x1] + +REM # mod_cfg [PAR_0 PAR_1 PAR_2 PAR_3 IS_BYTES CPS IBS OBS MOD_FLAGS CPC OBLS] +mod_cfg = [0, 0, 0, 0, 0, 4000000, 0, 0, 0, 0, 0] + +index = __COUNTER__ diff --git a/tools/rimage/config/wcl.toml.h b/tools/rimage/config/wcl.toml.h index 27d00f1444be..f239e063a459 100644 --- a/tools/rimage/config/wcl.toml.h +++ b/tools/rimage/config/wcl.toml.h @@ -126,6 +126,10 @@ index = __COUNTER__ #include