@@ -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 = {
@@ -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 */