From 0ee3d4a8306cb10579aaa3853ef78d7f03908c13 Mon Sep 17 00:00:00 2001 From: Ranjani Sridharan Date: Fri, 25 Aug 2023 15:02:11 -0700 Subject: [PATCH] ASoC: SOF: sof-audio: Modify the order of widget set up IPC4 expects the pipelines to be triggered in the order starting from the sink to the source. The order of triggering pipelines during start is determined by the order in which the widgets are set up. Today, we set up the widgets in the order from source->sink and save the pipelines that the widgets belong to in a list. This list is later traversed in the reverse order for triggering the pipelines. Instead of this, this patch proposes to change the order of widget set up from sink->source so that the pipelines will be added to the list in the same order as well. The FW can handle widgets getting set up in any order (source->sink or sink->source). So reversing the current order will not affect functionality. This change is particularly important in cases where there are 2 DAIs in the topology connected to the same host copier as in the case of AEC with reference capture. SSP DAI copier (Pipeline 0) -> AEC module -> host-copier (Pipeline 2) ^ | DMIC DAI copier (Pipeline 1) In this case, we want both the DAI pipelines (0 and 1) to be started after pipeline 2 has been started. With the order of widget setup from source to sink, the pipelines would be added to the trigger list in the order, pipeline 1, pipeline 2 and finally pipeline 0. This would trigger pipeline 0 first and result in an IPC timeout during start. Modifying the widget set up to start from the sink will guarantee that the pipelines will be added to the trigger list in the order 2 -> 1 -> 0 or 2 -> 0 -> 1 i.e pipeline 2 will always be first. The order of trigger between the 2 DAI pipelines does not matter and it will depend on which order they appear in the list of connected DAPM widgets. Signed-off-by: Ranjani Sridharan --- sound/soc/sof/ipc4-pcm.c | 4 +-- sound/soc/sof/sof-audio.c | 53 +++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 775c864313fa65..1813a48510353c 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -332,12 +332,12 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, * guaranteed for each fork independently. */ if (state == SOF_IPC4_PIPE_RUNNING || state == SOF_IPC4_PIPE_RESET) - for (i = pipeline_list->count - 1; i >= 0; i--) { + for (i = 0; i < pipeline_list->count; i++) { spipe = pipeline_list->pipelines[i]; sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list); } else - for (i = 0; i < pipeline_list->count; i++) { + for (i = pipeline_list->count - 1; i >= 0; i--) { spipe = pipeline_list->pipelines[i]; sof_ipc4_add_pipeline_to_trigger_list(sdev, state, spipe, trigger_list); } diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index e7ef77012c3586..364e0098c498c9 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -483,8 +483,8 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget } /* - * free all widgets in the sink path starting from the source widget - * (DAI type for capture, AIF type for playback) + * free all widgets in the source path starting from the sink widget + * (AIF type for capture, DAI type for playback) */ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, int dir, struct snd_sof_pcm *spcm) @@ -503,15 +503,15 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap ret = err; } - /* free all widgets in the sink paths even in case of error to keep use counts balanced */ - snd_soc_dapm_widget_for_each_sink_path(widget, p) { + /* free all widgets in the source paths even in case of error to keep use counts balanced */ + snd_soc_dapm_widget_for_each_source_path(widget, p) { if (!p->walking) { - if (!widget_in_list(list, p->sink)) + if (!widget_in_list(list, p->source)) continue; p->walking = true; - err = sof_free_widgets_in_path(sdev, p->sink, dir, spcm); + err = sof_free_widgets_in_path(sdev, p->source, dir, spcm); if (err < 0) ret = err; p->walking = false; @@ -522,8 +522,8 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap } /* - * set up all widgets in the sink path starting from the source widget - * (DAI type for capture, AIF type for playback). + * set up all widgets in the source path starting from the sink widget + * (AIF type for capture, DAI type for playback). * The error path in this function ensures that all successfully set up widgets getting freed. */ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget, @@ -548,7 +548,7 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d /* skip populating the pipe_widgets array if it is NULL */ if (!pipeline_list->pipelines) - goto sink_setup; + goto source_setup; /* * Add the widget's pipe_widget to the list of pipelines to be triggered if not @@ -567,15 +567,15 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d } } -sink_setup: - snd_soc_dapm_widget_for_each_sink_path(widget, p) { +source_setup: + snd_soc_dapm_widget_for_each_source_path(widget, p) { if (!p->walking) { - if (!widget_in_list(list, p->sink)) + if (!widget_in_list(list, p->source)) continue; p->walking = true; - ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, spcm); + ret = sof_set_up_widgets_in_path(sdev, p->source, dir, spcm); p->walking = false; if (ret < 0) { if (swidget) @@ -607,13 +607,28 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, if (is_virtual_widget(sdev, widget, __func__)) continue; - /* starting widget for playback is AIF type */ - if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in) - continue; + /* + * set up/free widgets in the order sink->source so that the pipelines will be + * added to the list in the same order as well. All other ops need to follow the + * source->sink order. + */ + if (op == SOF_WIDGET_SETUP || op == SOF_WIDGET_FREE) { + /* starting widget for playback is DAI type */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_dai_in) + continue; - /* starting widget for capture is DAI type */ - if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out) - continue; + /* starting widget for capture is AIF type */ + if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_aif_out) + continue; + } else { + /* starting widget for playback is AIF type */ + if (dir == SNDRV_PCM_STREAM_PLAYBACK && widget->id != snd_soc_dapm_aif_in) + continue; + + /* starting widget for capture is DAI type */ + if (dir == SNDRV_PCM_STREAM_CAPTURE && widget->id != snd_soc_dapm_dai_out) + continue; + } switch (op) { case SOF_WIDGET_SETUP: