From 65d72abd1766a8b3ac94c569871db211e416dda9 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 21 Oct 2026 16:33:28 +0300 Subject: [PATCH] ASoC: SOF: ipc4-topology: Track topology-defined SRC sink rates The shared SRC/ASRC prepare callback gives a nonzero sink rate precedence over the rate requested by the capture stream. However, it also writes the selected output rate back to the same field. If topology does not specify a sink rate, subsequent prepares therefore treat the previous runtime rate as a fixed topology rate instead of following the current stream parameters. For example a capture stream opened at 16 kHz after one at 48 kHz on the same SRC keeps converting to 48 kHz. Record whether topology supplied a nonzero sink rate for SRC and ASRC, and only prioritize the stored rate in that case. Otherwise, select the rate at runtime on each prepare. Select the format, base configuration, rate and provenance flag through the appropriate SRC or ASRC type in the shared prepare callback. Their IPC payloads have different sizes, so accessing ASRC through an SRC pointer must not rely on matching member offsets. On 64-bit the two sizes happen to round up to the same offset for the following members, but on architectures with 4-byte pointer alignment available_fmt and msg are accessed at the wrong offset for ASRC. Reported-by: Kai Vehmanen Fixes: 3c3ce66b65c4 ("ASoC: SOF: ipc4-topology: Allow the use of multiple formats for src output") Cc: stable@vger.kernel.org Signed-off-by: Peter Ujfalusi Reviewed-by: Kai Vehmanen Tested-by: Kai Vehmanen --- sound/soc/sof/ipc4-topology.c | 40 ++++++++++++++++++++++++++++------- sound/soc/sof/ipc4-topology.h | 4 ++++ 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 8b13c97b348044..4e72a1a93d34aa 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -1182,6 +1182,9 @@ static int sof_ipc4_widget_setup_comp_src(struct snd_sof_widget *swidget) goto err; } + if (src->data.sink_rate) + src->sink_rate_from_tplg = true; + spipe->core_mask |= BIT(swidget->core); dev_dbg(scomp->dev, "SRC sink rate %d\n", src->data.sink_rate); @@ -1235,6 +1238,9 @@ static int sof_ipc4_widget_setup_comp_asrc(struct snd_sof_widget *swidget) goto err; } + if (asrc->data.out_freq) + asrc->sink_rate_from_tplg = true; + spipe->core_mask |= BIT(swidget->core); dev_dbg(scomp->dev, "ASRC sink rate %d, mode 0x%08x\n", @@ -2787,19 +2793,37 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, { struct snd_soc_component *scomp = swidget->scomp; struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); - struct sof_ipc4_src *src = swidget->private; - struct sof_ipc4_available_audio_format *available_fmt = &src->available_fmt; + struct sof_ipc4_available_audio_format *available_fmt; + struct sof_ipc4_base_module_cfg *base_config; struct sof_ipc4_audio_format *out_audio_fmt; struct sof_ipc4_audio_format *in_audio_fmt; u32 out_ref_rate, out_ref_channels, out_ref_valid_bits, out_ref_type; int output_fmt_index, input_fmt_index; + bool sink_rate_from_tplg; + u32 *sink_rate; /* This cannot happen */ if (unlikely(swidget->prepared)) return 0; + if (swidget->id == snd_soc_dapm_asrc) { + struct sof_ipc4_asrc *asrc = swidget->private; + + available_fmt = &asrc->available_fmt; + base_config = &asrc->data.base_config; + sink_rate = &asrc->data.out_freq; + sink_rate_from_tplg = asrc->sink_rate_from_tplg; + } else { + struct sof_ipc4_src *src = swidget->private; + + available_fmt = &src->available_fmt; + base_config = &src->data.base_config; + sink_rate = &src->data.sink_rate; + sink_rate_from_tplg = src->sink_rate_from_tplg; + } + input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, - &src->data.base_config, + base_config, pipeline_params, available_fmt); if (input_fmt_index < 0) @@ -2814,9 +2838,9 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, out_ref_valid_bits = SOF_IPC4_AUDIO_FORMAT_CFG_V_BIT_DEPTH(in_audio_fmt->fmt_cfg); out_ref_type = sof_ipc4_fmt_cfg_to_type(in_audio_fmt->fmt_cfg); - if (src->data.sink_rate) { + if (sink_rate_from_tplg) { /* Use the sink rate as reference */ - out_ref_rate = src->data.sink_rate; + out_ref_rate = *sink_rate; } else if (dir == SNDRV_PCM_STREAM_CAPTURE) { /* * Use the fe rate as reference for capture if the sink rate is @@ -2846,7 +2870,7 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, } output_fmt_index = sof_ipc4_init_output_audio_fmt(sdev, swidget, - &src->data.base_config, + base_config, available_fmt, out_ref_rate, out_ref_channels, @@ -2859,10 +2883,10 @@ static int sof_ipc4_prepare_src_module(struct snd_sof_widget *swidget, input_fmt_index, output_fmt_index); /* update pipeline memory usage */ - sof_ipc4_update_resource_usage(sdev, swidget, &src->data.base_config); + sof_ipc4_update_resource_usage(sdev, swidget, base_config); out_audio_fmt = &available_fmt->output_pin_fmts[output_fmt_index].audio_fmt; - src->data.sink_rate = out_audio_fmt->sampling_frequency; + *sink_rate = out_audio_fmt->sampling_frequency; /* update pipeline_params for sink widgets */ return sof_ipc4_update_hw_params(sdev, pipeline_params, out_audio_fmt, diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h index c2949ff979a5bf..b538b4183897a9 100644 --- a/sound/soc/sof/ipc4-topology.h +++ b/sound/soc/sof/ipc4-topology.h @@ -470,11 +470,13 @@ struct sof_ipc4_src_data { * @data: IPC base config data * @available_fmt: Available audio format * @msg: IPC4 message struct containing header and data info + * @sink_rate_from_tplg: Sink rate is specified by topology rather than runtime */ struct sof_ipc4_src { struct sof_ipc4_src_data data; struct sof_ipc4_available_audio_format available_fmt; struct sof_ipc4_msg msg; + bool sink_rate_from_tplg; }; /* @@ -494,11 +496,13 @@ struct sof_ipc4_asrc_data { * @data: IPC base config data * @available_fmt: Available audio format * @msg: IPC4 message struct containing header and data info + * @sink_rate_from_tplg: Sink rate is specified by topology rather than runtime */ struct sof_ipc4_asrc { struct sof_ipc4_asrc_data data; struct sof_ipc4_available_audio_format available_fmt; struct sof_ipc4_msg msg; + bool sink_rate_from_tplg; }; /**