ASoC: SOF: ipc4-pcm: reset all pipelines during FE DAI hw_free
authorRanjani Sridharan <ranjani.sridharan@linux.intel.com>
Mon, 15 May 2023 11:20:22 +0000 (14:20 +0300)
committerMark Brown <broonie@kernel.org>
Mon, 15 May 2023 11:25:37 +0000 (20:25 +0900)
Do not reset pipelines during the stop/suspend triggers in the BE DAI
ops as the BE DAI pipeline needs to be left in the PAUSED state. It should
only be reset during hw_free. This simplification is already done for
the FE pipelines and the DAI trigger only toggles the states between
PAUSED and RUNNING.

But because the FE DAI hw_free is invoked first and all the pipelines are
freed during this op, we need to make sure that the BE DAI pipeline also
gets reset before it is freed. So do not skip the pipelines that have the
skip_during_fe_trigger flag set when resetting pipelines.

Also, because the pipeline state changes are split between the FE and BE
DAI ops now, protect the BE DAI pipeline state changes with the
pipeline_state_mutex as well.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com
Reviewed-by: Bard Liao <yung-chuan.liao@linux.intel.com
Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com
Link: https://lore.kernel.org/r/20230515112022.30297-3-peter.ujfalusi@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org
sound/soc/sof/intel/hda-dai-ops.c
sound/soc/sof/ipc4-pcm.c

index 4c04adf..f121b9e 100644 (file)
@@ -178,6 +178,7 @@ static void hda_reset_hext_stream(struct snd_sof_dev *sdev, struct hdac_ext_stre
 static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                struct snd_pcm_substream *substream, int cmd)
 {
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
        struct snd_sof_widget *pipe_widget;
        struct sof_ipc4_pipeline *pipeline;
        struct snd_sof_widget *swidget;
@@ -189,6 +190,8 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
        pipe_widget = swidget->spipe->pipe_widget;
        pipeline = pipe_widget->private;
 
+       mutex_lock(&ipc4_data->pipeline_state_mutex);
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
@@ -199,7 +202,7 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
                ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_PAUSED);
                if (ret < 0)
-                       return ret;
+                       goto out;
 
                pipeline->state = SOF_IPC4_PIPE_PAUSED;
                break;
@@ -207,7 +210,8 @@ static int hda_ipc4_pre_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cp
                dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
                return -EINVAL;
        }
-
+out:
+       mutex_unlock(&ipc4_data->pipeline_state_mutex);
        return 0;
 }
 
@@ -237,53 +241,62 @@ static int hda_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
 static int hda_ipc4_post_trigger(struct snd_sof_dev *sdev, struct snd_soc_dai *cpu_dai,
                                 struct snd_pcm_substream *substream, int cmd)
 {
+       struct sof_ipc4_fw_data *ipc4_data = sdev->private;
        struct snd_sof_widget *pipe_widget;
        struct sof_ipc4_pipeline *pipeline;
        struct snd_sof_widget *swidget;
        struct snd_soc_dapm_widget *w;
-       int ret;
+       int ret = 0;
 
        w = snd_soc_dai_get_widget(cpu_dai, substream->stream);
        swidget = w->dobj.private;
        pipe_widget = swidget->spipe->pipe_widget;
        pipeline = pipe_widget->private;
 
+       mutex_lock(&ipc4_data->pipeline_state_mutex);
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
                        ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                          SOF_IPC4_PIPE_PAUSED);
                        if (ret < 0)
-                               return ret;
+                               goto out;
                        pipeline->state = SOF_IPC4_PIPE_PAUSED;
                }
 
                ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
                                                  SOF_IPC4_PIPE_RUNNING);
                if (ret < 0)
-                       return ret;
+                       goto out;
                pipeline->state = SOF_IPC4_PIPE_RUNNING;
+               swidget->spipe->started_count++;
                break;
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_STOP:
-       {
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                ret = sof_ipc4_set_pipeline_state(sdev, pipe_widget->instance_id,
-                                                 SOF_IPC4_PIPE_RESET);
+                                                 SOF_IPC4_PIPE_RUNNING);
                if (ret < 0)
-                       return ret;
-
-               pipeline->state = SOF_IPC4_PIPE_RESET;
+                       goto out;
+               pipeline->state = SOF_IPC4_PIPE_RUNNING;
+               break;
+       case SNDRV_PCM_TRIGGER_SUSPEND:
+       case SNDRV_PCM_TRIGGER_STOP:
+               /*
+                * STOP/SUSPEND trigger is invoked only once when all users of this pipeline have
+                * been stopped. So, clear the started_count so that the pipeline can be reset
+                */
+               swidget->spipe->started_count = 0;
                break;
-       }
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                break;
        default:
                dev_err(sdev->dev, "unknown trigger command %d\n", cmd);
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
-
-       return 0;
+out:
+       mutex_unlock(&ipc4_data->pipeline_state_mutex);
+       return ret;
 }
 
 static const struct hda_dai_widget_dma_ops hda_ipc4_dma_ops = {
index 9e2b6c4..0c905bd 100644 (file)
@@ -69,7 +69,7 @@ sof_ipc4_add_pipeline_to_trigger_list(struct snd_sof_dev *sdev, int state,
        struct snd_sof_widget *pipe_widget = spipe->pipe_widget;
        struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
 
-       if (pipeline->skip_during_fe_trigger)
+       if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET)
                return;
 
        switch (state) {
@@ -108,7 +108,7 @@ sof_ipc4_update_pipeline_state(struct snd_sof_dev *sdev, int state, int cmd,
        struct sof_ipc4_pipeline *pipeline = pipe_widget->private;
        int i;
 
-       if (pipeline->skip_during_fe_trigger)
+       if (pipeline->skip_during_fe_trigger && state != SOF_IPC4_PIPE_RESET)
                return;
 
        /* set state for pipeline if it was just triggered */