Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
To: lgirdwood@gmail.com, broonie@kernel.org
Cc: alsa-devel@alsa-project.org, kai.vehmanen@linux.intel.com,
	pierre-louis.bossart@linux.intel.com, rander.wang@intel.com,
	ranjani.sridharan@linux.intel.com,
	yung-chuan.liao@linux.intel.com
Subject: [PATCH 11/18] ASoC: SOF: ipc4-pcm: Use the PCM stream's pipeline_info during trigger
Date: Fri, 27 Jan 2023 14:00:24 +0200	[thread overview]
Message-ID: <20230127120031.10709-12-peter.ujfalusi@linux.intel.com> (raw)
In-Reply-To: <20230127120031.10709-1-peter.ujfalusi@linux.intel.com>

From: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>

Use the list of pipelines in the PCM stream's pipeline info to trigger
the pipelines in the right order. Add a helper for triggering pipelines
in batch mode that will be used to trigger multiple pipelines at the
same time.

Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Libin Yang <libin.yang@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>
---
 include/sound/sof/ipc4/header.h |   3 +
 sound/soc/sof/ipc4-pcm.c        | 137 ++++++++++++++++++++++++--------
 sound/soc/sof/ipc4-topology.h   |  10 +++
 3 files changed, 115 insertions(+), 35 deletions(-)

diff --git a/include/sound/sof/ipc4/header.h b/include/sound/sof/ipc4/header.h
index 622193be7ac4..d31349bf011d 100644
--- a/include/sound/sof/ipc4/header.h
+++ b/include/sound/sof/ipc4/header.h
@@ -185,6 +185,9 @@ enum sof_ipc4_pipeline_state {
 #define SOF_IPC4_GLB_PIPE_STATE_MASK		GENMASK(15, 0)
 #define SOF_IPC4_GLB_PIPE_STATE(x)		((x) << SOF_IPC4_GLB_PIPE_STATE_SHIFT)
 
+/* pipeline set state IPC msg extension */
+#define SOF_IPC4_GLB_PIPE_STATE_EXT_MULTI	BIT(0)
+
 /* load library ipc msg */
 #define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT	16
 #define SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID(x)	((x) << SOF_IPC4_GLB_LOAD_LIBRARY_LIB_ID_SHIFT)
diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c
index db9d0adb2717..a5482185cd6c 100644
--- a/sound/soc/sof/ipc4-pcm.c
+++ b/sound/soc/sof/ipc4-pcm.c
@@ -13,6 +13,33 @@
 #include "ipc4-priv.h"
 #include "ipc4-topology.h"
 
+static int sof_ipc4_set_multi_pipeline_state(struct snd_sof_dev *sdev, u32 state,
+					     struct ipc4_pipeline_set_state_data *data)
+{
+	struct sof_ipc4_msg msg = {{ 0 }};
+	u32 primary, ipc_size;
+
+	/* trigger a single pipeline */
+	if (data->count == 1)
+		return sof_ipc4_set_pipeline_state(sdev, data->pipeline_ids[0], state);
+
+	primary = state;
+	primary |= SOF_IPC4_MSG_TYPE_SET(SOF_IPC4_GLB_SET_PIPELINE_STATE);
+	primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST);
+	primary |= SOF_IPC4_MSG_TARGET(SOF_IPC4_FW_GEN_MSG);
+	msg.primary = primary;
+
+	/* trigger multiple pipelines with a single IPC */
+	msg.extension = SOF_IPC4_GLB_PIPE_STATE_EXT_MULTI;
+
+	/* ipc_size includes the count and the pipeline IDs for the number of pipelines */
+	ipc_size = sizeof(u32) * (data->count + 1);
+	msg.data_size = ipc_size;
+	msg.data_ptr = data;
+
+	return sof_ipc_tx_message(sdev->ipc, &msg, ipc_size, NULL, 0);
+}
+
 int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 id, u32 state)
 {
 	struct sof_ipc4_msg msg = {{ 0 }};
@@ -37,60 +64,100 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component,
 {
 	struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(component);
 	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
-	struct snd_sof_widget *pipeline_widget;
-	struct snd_soc_dapm_widget_list *list;
-	struct snd_soc_dapm_widget *widget;
+	struct snd_sof_pcm_stream_pipeline_list *pipeline_list;
+	struct ipc4_pipeline_set_state_data *data;
+	struct snd_sof_widget *pipe_widget;
 	struct sof_ipc4_pipeline *pipeline;
-	struct snd_sof_widget *swidget;
 	struct snd_sof_pcm *spcm;
-	int ret = 0;
-	int num_widgets;
+	int ret;
+	int i, j;
 
 	spcm = snd_sof_find_spcm_dai(component, rtd);
 	if (!spcm)
 		return -EINVAL;
 
-	list = spcm->stream[substream->stream].list;
-
-	for_each_dapm_widgets(list, num_widgets, widget) {
-		swidget = widget->dobj.private;
+	pipeline_list = &spcm->stream[substream->stream].pipeline_list;
+
+	/* nothing to trigger if the list is empty */
+	if (!pipeline_list->pipe_widgets)
+		return 0;
+
+	/* allocate memory for the pipeline data */
+	data = kzalloc(struct_size(data, pipeline_ids, pipeline_list->count), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/*
+	 * IPC4 requires pipelines to be triggered in order starting at the sink and
+	 * walking all the way to the source. So traverse the pipeline_list in the reverse order.
+	 * Skip the pipelines that have their skip_during_fe_trigger flag set or if they're already
+	 * in the requested state. If there is a fork in the pipeline, the order of triggering
+	 * between the left/right paths will be indeterministic. But the sink->source trigger order
+	 * sink->source would still be guaranteed for each fork independently.
+	 */
+	for (i = pipeline_list->count - 1; i >= 0; i--) {
+		pipe_widget = pipeline_list->pipe_widgets[i];
+		pipeline = pipe_widget->private;
+		if (pipeline->state != state && !pipeline->skip_during_fe_trigger)
+			data->pipeline_ids[data->count++] = pipe_widget->instance_id;
+	}
 
-		if (!swidget)
-			continue;
+	/* return if all pipelines are in the requested state already */
+	if (!data->count) {
+		kfree(data);
+		return 0;
+	}
 
-		pipeline_widget = swidget->pipe_widget;
-		pipeline = (struct sof_ipc4_pipeline *)pipeline_widget->private;
+	/*
+	 * Pause all pipelines. This could result in an extra IPC to pause all pipelines even if
+	 * they are already paused. But it helps keep the logic simpler and the firmware handles
+	 * the repeated pause gracefully. This can be optimized in the future if needed.
+	 */
+	ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, data);
+	if (ret < 0) {
+		dev_err(sdev->dev, "failed to pause all pipelines\n");
+		goto free;
+	}
 
-		if (pipeline->state == state || pipeline->skip_during_fe_trigger)
-			continue;
+	/* update PAUSED state for all pipelines that were just triggered */
+	for (i = 0; i < data->count; i++) {
+		for (j = 0; j < pipeline_list->count; j++) {
+			pipe_widget = pipeline_list->pipe_widgets[j];
+			pipeline = pipe_widget->private;
 
-		/* first set the pipeline to PAUSED state */
-		if (pipeline->state != SOF_IPC4_PIPE_PAUSED) {
-			ret = sof_ipc4_set_pipeline_state(sdev, pipeline_widget->instance_id,
-							  SOF_IPC4_PIPE_PAUSED);
-			if (ret < 0) {
-				dev_err(sdev->dev, "failed to pause pipeline %d\n",
-					swidget->pipeline_id);
-				return ret;
+			if (data->pipeline_ids[i] == pipe_widget->instance_id) {
+				pipeline->state = SOF_IPC4_PIPE_PAUSED;
+				break;
 			}
 		}
+	}
 
-		pipeline->state = SOF_IPC4_PIPE_PAUSED;
+	/* return if this is the final state */
+	if (state == SOF_IPC4_PIPE_PAUSED)
+		goto free;
 
-		if (pipeline->state == state)
-			continue;
+	/* else set the final state in the DSP */
+	ret = sof_ipc4_set_multi_pipeline_state(sdev, state, data);
+	if (ret < 0) {
+		dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state);
+		goto free;
+	}
 
-		/* then set the final state */
-		ret = sof_ipc4_set_pipeline_state(sdev, pipeline_widget->instance_id, state);
-		if (ret < 0) {
-			dev_err(sdev->dev, "failed to set state %d for pipeline %d\n",
-				state, swidget->pipeline_id);
-			break;
-		}
+	/* update final state for all pipelines that were just triggered */
+	for (i = 0; i < data->count; i++) {
+		for (j = 0; j < pipeline_list->count; j++) {
+			pipe_widget = pipeline_list->pipe_widgets[j];
+			pipeline = pipe_widget->private;
 
-		pipeline->state = state;
+			if (data->pipeline_ids[i] == pipe_widget->instance_id) {
+				pipeline->state = state;
+				break;
+			}
+		}
 	}
 
+free:
+	kfree(data);
 	return ret;
 }
 
diff --git a/sound/soc/sof/ipc4-topology.h b/sound/soc/sof/ipc4-topology.h
index 028b5d91b9db..ee5d31e68a77 100644
--- a/sound/soc/sof/ipc4-topology.h
+++ b/sound/soc/sof/ipc4-topology.h
@@ -84,6 +84,16 @@ struct sof_ipc4_pipeline {
 	bool skip_during_fe_trigger;
 };
 
+/**
+ * struct sof_ipc4_multi_pipeline_data - multi pipeline trigger IPC data
+ * @count: Number of pipelines to be triggered
+ * @pipeline_ids: Flexible array of IDs of the pipelines to be triggered
+ */
+struct ipc4_pipeline_set_state_data {
+	u32 count;
+	DECLARE_FLEX_ARRAY(u32, pipeline_ids);
+} __packed;
+
 /**
  * struct sof_ipc4_available_audio_format - Available audio formats
  * @base_config: Available base config
-- 
2.39.1


  parent reply	other threads:[~2023-01-27 12:04 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-01-27 12:00 From 644473b181f0f310e428301a2ed459f912eec7ea Mon Sep 17 00:00:00 2001 Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 01/18] ASoC: SOF: ipc4-topology: No need to unbind routes within a pipeline Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 02/18] ASoC: soc-pcm: Export widget_in_list() Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 03/18] ASoC: SOF: sof-audio: Set up/free DAI/AIF widgets only once Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 04/18] ASoC: SOF: sof-audio: Only process widgets in the connected widget list Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 05/18] ASoC: SOF: pcm: do not free widgets during suspend trigger Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 06/18] ASoC: SOF: topology: Set IPC-specific trigger order for DAI links Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 07/18] ASoC: SOF: Introduce PCM setup/free PCM IPC ops Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 08/18] ASoC: SOF: ipc4-pcm: Define pcm_setup/free ops Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 09/18] ASoC: SOF: ipc4: Add flag to skip triggering pipelines during FE DAI trigger Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 10/18] ASoC: SOF: sof-audio: Populate the PCM stream pipeline_info Peter Ujfalusi
2023-01-27 12:00 ` Peter Ujfalusi [this message]
2023-01-27 12:00 ` [PATCH 12/18] ASoC: SOF: Introduce struct snd_sof_pipeline Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 13/18] ASoC: SOF: ipc4-pcm: Rename 'data' variable to trigger_list Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 14/18] ASoC: SOF: ipc4-pcm: Implement pipeline trigger reference counting Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 15/18] ASoC: SOF: ipc4-topology: Protect pipeline free with mutex Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 16/18] ASoC: SOF: Avoid double decrementing use_count in sof_widget_setup on error Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 17/18] ASoC: SOF: Protect swidget->use_count with mutex for kcontrol access race Peter Ujfalusi
2023-01-27 12:00 ` [PATCH 18/18] ASoC: SOF: ipc4-pcm: Do not run the trigger pipelines if no spipe is stored Peter Ujfalusi
2023-01-27 12:07 ` [PATCH 00/18] ASoC: SOF: ipc4: Multi-stream playback and capture support Péter Ujfalusi
2023-01-28 10:48 ` From 644473b181f0f310e428301a2ed459f912eec7ea Mon Sep 17 00:00:00 2001 Mark Brown

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230127120031.10709-12-peter.ujfalusi@linux.intel.com \
    --to=peter.ujfalusi@linux.intel.com \
    --cc=alsa-devel@alsa-project.org \
    --cc=broonie@kernel.org \
    --cc=kai.vehmanen@linux.intel.com \
    --cc=lgirdwood@gmail.com \
    --cc=pierre-louis.bossart@linux.intel.com \
    --cc=rander.wang@intel.com \
    --cc=ranjani.sridharan@linux.intel.com \
    --cc=yung-chuan.liao@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox