OSDN Git Service

ASoC: SOF: sof-audio: Only process widgets in the connected widget list
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Fri, 27 Jan 2023 12:00:17 +0000 (14:00 +0200)
committerMark Brown <broonie@kernel.org>
Fri, 27 Jan 2023 12:14:01 +0000 (12:14 +0000)
When walking the list of the widgets from the source to the sink, we
accidentally also end up preparing/setting up the widgets that are not
in the list of connected DAPM widgets associated with the PCM. Avoid
this by checking if a widget is part of the connected DAPM widget list
during widget prepare, unprepare, setup or free.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Péter Ujfalusi <peter.ujfalusi@linux.intel.com>
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://lore.kernel.org/r/20230127120031.10709-5-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sof/sof-audio.c

index d242a30..a72e689 100644 (file)
@@ -241,24 +241,32 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
                        if (!widget->dobj.private)
                                continue;
 
-                       snd_soc_dapm_widget_for_each_sink_path(widget, p)
+                       snd_soc_dapm_widget_for_each_sink_path(widget, p) {
+                               if (!widget_in_list(list, p->sink))
+                                       continue;
+
                                if (p->sink->dobj.private) {
                                        ret = sof_route_setup(sdev, widget, p->sink);
                                        if (ret < 0)
                                                return ret;
                                }
+                       }
                }
        } else {
                for_each_dapm_widgets(list, i, widget) {
                        if (!widget->dobj.private)
                                continue;
 
-                       snd_soc_dapm_widget_for_each_source_path(widget, p)
+                       snd_soc_dapm_widget_for_each_source_path(widget, p) {
+                               if (!widget_in_list(list, p->source))
+                                       continue;
+
                                if (p->source->dobj.private) {
                                        ret = sof_route_setup(sdev, p->source, widget);
                                        if (ret < 0)
                                                return ret;
                                }
+                       }
                }
        }
 
@@ -266,7 +274,8 @@ static int sof_setup_pipeline_connections(struct snd_sof_dev *sdev,
 }
 
 static void
-sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget)
+sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
+                             struct snd_soc_dapm_widget_list *list)
 {
        const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
        struct snd_sof_widget *swidget = widget->dobj.private;
@@ -287,9 +296,11 @@ sof_unprepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widg
 sink_unprepare:
        /* unprepare all widgets in the sink paths */
        snd_soc_dapm_widget_for_each_sink_path(widget, p) {
+               if (!widget_in_list(list, p->sink))
+                       continue;
                if (!p->walking && p->sink->dobj.private) {
                        p->walking = true;
-                       sof_unprepare_widgets_in_path(sdev, p->sink);
+                       sof_unprepare_widgets_in_path(sdev, p->sink, list);
                        p->walking = false;
                }
        }
@@ -299,7 +310,8 @@ static int
 sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
                            struct snd_pcm_hw_params *fe_params,
                            struct snd_sof_platform_stream_params *platform_params,
-                           struct snd_pcm_hw_params *pipeline_params, int dir)
+                           struct snd_pcm_hw_params *pipeline_params, int dir,
+                           struct snd_soc_dapm_widget_list *list)
 {
        const struct sof_ipc_tplg_ops *tplg_ops = sof_ipc_get_ops(sdev, tplg);
        struct snd_sof_widget *swidget = widget->dobj.private;
@@ -327,10 +339,13 @@ sof_prepare_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget
 sink_prepare:
        /* prepare all widgets in the sink paths */
        snd_soc_dapm_widget_for_each_sink_path(widget, p) {
+               if (!widget_in_list(list, p->sink))
+                       continue;
                if (!p->walking && p->sink->dobj.private) {
                        p->walking = true;
                        ret = sof_prepare_widgets_in_path(sdev, p->sink,  fe_params,
-                                                         platform_params, pipeline_params, dir);
+                                                         platform_params, pipeline_params, dir,
+                                                         list);
                        p->walking = false;
                        if (ret < 0) {
                                /* unprepare the source widget */
@@ -351,7 +366,7 @@ sink_prepare:
  * (DAI type for capture, AIF type for playback)
  */
 static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget *widget,
-                                   int dir)
+                                   int dir, struct snd_soc_dapm_widget_list *list)
 {
        struct snd_soc_dapm_path *p;
        int err;
@@ -366,9 +381,12 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap
        /* 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) {
                if (!p->walking) {
+                       if (!widget_in_list(list, p->sink))
+                               continue;
+
                        p->walking = true;
 
-                       err = sof_free_widgets_in_path(sdev, p->sink, dir);
+                       err = sof_free_widgets_in_path(sdev, p->sink, dir, list);
                        if (err < 0)
                                ret = err;
                        p->walking = false;
@@ -384,7 +402,7 @@ static int sof_free_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_dap
  * 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,
-                                     int dir)
+                                     int dir, struct snd_soc_dapm_widget_list *list)
 {
        struct snd_soc_dapm_path *p;
        int ret;
@@ -397,9 +415,12 @@ static int sof_set_up_widgets_in_path(struct snd_sof_dev *sdev, struct snd_soc_d
 
        snd_soc_dapm_widget_for_each_sink_path(widget, p) {
                if (!p->walking) {
+                       if (!widget_in_list(list, p->sink))
+                               continue;
+
                        p->walking = true;
 
-                       ret = sof_set_up_widgets_in_path(sdev, p->sink, dir);
+                       ret = sof_set_up_widgets_in_path(sdev, p->sink, dir, list);
                        p->walking = false;
                        if (ret < 0) {
                                if (widget->dobj.private)
@@ -434,11 +455,11 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_l
 
                switch (op) {
                case SOF_WIDGET_SETUP:
-                       ret = sof_set_up_widgets_in_path(sdev, widget, dir);
+                       ret = sof_set_up_widgets_in_path(sdev, widget, dir, list);
                        str = "set up";
                        break;
                case SOF_WIDGET_FREE:
-                       ret = sof_free_widgets_in_path(sdev, widget, dir);
+                       ret = sof_free_widgets_in_path(sdev, widget, dir, list);
                        str = "free";
                        break;
                case SOF_WIDGET_PREPARE:
@@ -454,12 +475,12 @@ sof_walk_widgets_in_order(struct snd_sof_dev *sdev, struct snd_soc_dapm_widget_l
                         */
                        memcpy(&pipeline_params, fe_params, sizeof(*fe_params));
 
-                       ret = sof_prepare_widgets_in_path(sdev, widget, fe_params,
-                                                         platform_params, &pipeline_params, dir);
+                       ret = sof_prepare_widgets_in_path(sdev, widget, fe_params, platform_params,
+                                                         &pipeline_params, dir, list);
                        break;
                }
                case SOF_WIDGET_UNPREPARE:
-                       sof_unprepare_widgets_in_path(sdev, widget);
+                       sof_unprepare_widgets_in_path(sdev, widget, list);
                        break;
                default:
                        dev_err(sdev->dev, "Invalid widget op %d\n", op);