Linux Sound subsystem development
 help / color / mirror / Atom feed
From: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
To: vkoul@kernel.org, perex@perex.cz, tiwai@suse.com,
	lgirdwood@gmail.com, broonie@kernel.org,
	srinivas.kandagatla@oss.qualcomm.com
Cc: linux-sound@vger.kernel.org, kai.vehmanen@linux.intel.com,
	yung-chuan.liao@linux.intel.com, pierre-louis.bossart@linux.dev,
	daniel.baluta@nxp.com
Subject: [PATCH v3 04/26] ASoC: soc-compress: Provide a runtime for the compressed FE substream
Date: Fri, 11 Sep 2026 14:21:30 +0300	[thread overview]
Message-ID: <20260911112152.28528-5-peter.ujfalusi@linux.intel.com> (raw)
In-Reply-To: <20260911112152.28528-1-peter.ujfalusi@linux.intel.com>

When a compressed stream is used on the FE side of a DPCM link, the
BE is still running as 'normal' PCM.

DPCM lends the runtime of the FE to every BE it opens and
dpcm_be_reparent() re-points it at another FE when the lending one
disconnects. The internal PCM created for a compressed FE by
snd_soc_new_compress() is never opened via the PCM API, so its
substream has no runtime and the BEs of a compressed FE were left
with a NULL one.

BE DAI and codec drivers can look at substream->runtime, they add
their constraints to it in startup(), for example cs42l43, cs42l42,
hdac_hdmi.

The other users of compressed DPCM do not hit this as their BEs are
DSP internal ports, driven by code which takes everything from the
hw_params it is passed and never looks at substream->runtime. The
BEs here end at generic CODEC drivers which are shared with the non
DPCM case and cannot be expected to know about the FE type.

Allocate a runtime for the compressed FE substream while the stream
is open, initialize its constraints as snd_pcm_open() does and fill
it in from the BE parameters once the mandatory machine level
be_hw_params_fixup() has run, so that the compressed FE lends a valid
and populated runtime just like a PCM FE does.

This also allows a BE to be shared between a compressed and a PCM
FE, which is needed to play a notification over PCM to an endpoint
which a compressed stream is already using.

Signed-off-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Reviewed-by: Liam Girdwood <liam.r.girdwood@intel.com>
---
 sound/soc/soc-compress.c | 109 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 109 insertions(+)

diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index 093a70a93d2b..b803e8cb4ea4 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -16,6 +16,7 @@
 #include <sound/core.h>
 #include <sound/compress_params.h>
 #include <sound/compress_driver.h>
+#include <sound/pcm_params.h>
 #include <sound/soc.h>
 #include <sound/initval.h>
 #include <sound/soc-dpcm.h>
@@ -131,6 +132,104 @@ static int soc_compr_open(struct snd_compr_stream *cstream)
 	return ret;
 }
 
+/*
+ * The internal PCM of a compressed FE is never opened via the PCM API, so its
+ * substream has no runtime attached to it.
+ *
+ * DPCM lends the runtime of the FE to every BE it opens and re-points it at
+ * another FE when the lending one goes away, so the compressed FE must provide
+ * one as well. Without it the BEs are left with a NULL runtime, which oopses
+ * in BE DAI and CODEC drivers looking at substream->runtime, and a BE can not
+ * be shared between a compressed and a PCM FE at all.
+ *
+ * The runtime is owned by the FE for as long as the compressed stream is open.
+ */
+static int soc_compr_alloc_fe_runtime(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_pcm_substream *fe_substream = snd_soc_dpcm_get_substream(fe, stream);
+	struct snd_pcm_hw_constraints *constrs;
+	int i;
+
+	if (!fe_substream || fe_substream->runtime)
+		return 0;
+
+	fe_substream->runtime = kzalloc_obj(*fe_substream->runtime);
+	if (!fe_substream->runtime)
+		return -ENOMEM;
+
+	/*
+	 * snd_pcm_open() initializes the constraints of a PCM runtime to
+	 * 'anything goes'. A zeroed one means an empty mask and a [0, 0]
+	 * interval instead, which the constraint helpers refine against and
+	 * reject, so initialize them the same way the PCM core does.
+	 *
+	 * The hw rules snd_pcm_hw_constraints_init() installs on top are only
+	 * evaluated by snd_pcm_hw_refine(), which never runs for this
+	 * substream, so they are not needed here.
+	 */
+	constrs = &fe_substream->runtime->hw_constraints;
+	for (i = SNDRV_PCM_HW_PARAM_FIRST_MASK; i <= SNDRV_PCM_HW_PARAM_LAST_MASK; i++)
+		snd_mask_any(constrs_mask(constrs, i));
+
+	for (i = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; i <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; i++)
+		snd_interval_any(constrs_interval(constrs, i));
+
+	return 0;
+}
+
+static void soc_compr_free_fe_runtime(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_pcm_substream *fe_substream = snd_soc_dpcm_get_substream(fe, stream);
+
+	if (!fe_substream || !fe_substream->runtime)
+		return;
+
+	/* BE startup callbacks may have added hw constraint rules */
+	kfree(fe_substream->runtime->hw_constraints.rules);
+	kfree(fe_substream->runtime);
+	fe_substream->runtime = NULL;
+}
+
+/*
+ * The BE parameters of a compressed FE are set up by the machine level
+ * be_hw_params_fixup(), which is mandatory for a compressed BE, see
+ * soc_compr_set_params_fe(). Once they are fixed up, use them to fill in the
+ * runtime the BEs have been lent, so that a BE DAI or CODEC driver sees the
+ * format it is being configured for.
+ */
+static void soc_compr_set_fe_runtime(struct snd_soc_pcm_runtime *fe, int stream)
+{
+	struct snd_pcm_substream *fe_substream = snd_soc_dpcm_get_substream(fe, stream);
+	struct snd_pcm_runtime *runtime;
+	struct snd_soc_dpcm *dpcm;
+
+	snd_soc_dpcm_mutex_assert_held(fe);
+
+	if (!fe_substream || !fe_substream->runtime)
+		return;
+
+	runtime = fe_substream->runtime;
+
+	for_each_dpcm_be(fe, stream, dpcm) {
+		struct snd_pcm_hw_params *params = &dpcm->be->dpcm[stream].hw_params;
+		int bits = snd_pcm_format_physical_width(params_format(params));
+
+		/* skip a BE which has not been fixed up */
+		if (bits <= 0)
+			continue;
+
+		runtime->access		= params_access(params);
+		runtime->format		= params_format(params);
+		runtime->subformat	= params_subformat(params);
+		runtime->channels	= params_channels(params);
+		runtime->rate		= params_rate(params);
+
+		runtime->sample_bits	= bits;
+		runtime->frame_bits	= bits * runtime->channels;
+		break;
+	}
+}
+
 static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 {
 	struct snd_soc_pcm_runtime *fe = cstream->private_data;
@@ -142,6 +241,10 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 
 	snd_soc_card_mutex_lock(fe->card);
 
+	ret = soc_compr_alloc_fe_runtime(fe, stream);
+	if (ret < 0)
+		goto be_err;
+
 	ret = dpcm_path_get(fe, stream, &list);
 	if (ret < 0)
 		goto be_err;
@@ -196,6 +299,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
 	dpcm_path_put(&list);
 	snd_soc_dpcm_mutex_unlock(fe);
 be_err:
+	soc_compr_free_fe_runtime(fe, stream);
 	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
 	snd_soc_card_mutex_unlock(fe->card);
 	return ret;
@@ -238,6 +342,9 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
 
 	snd_soc_dai_compr_shutdown(cpu_dai, cstream, 0);
 
+	/* all BEs are shut down and disconnected, the runtime is unused now */
+	soc_compr_free_fe_runtime(fe, stream);
+
 	snd_soc_card_mutex_unlock(fe->card);
 	return 0;
 }
@@ -388,6 +495,8 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
 
 	snd_soc_dpcm_mutex_lock(fe);
 	ret = dpcm_be_dai_hw_params(fe, stream);
+	if (!ret)
+		soc_compr_set_fe_runtime(fe, stream);
 	snd_soc_dpcm_mutex_unlock(fe);
 	if (ret < 0)
 		goto out;
-- 
2.55.0


  parent reply	other threads:[~2026-09-11 11:22 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-11 11:21 [PATCH v3 00/26] ALSA compress / ASoC compress / SOF: Compressed audio support with IPC4 Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 01/26] ALSA: compress: pin card module while stream is open Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 02/26] ALSA: compress: register the open file with the card Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 03/26] ALSA: compress: stop active streams on disconnect Peter Ujfalusi
2026-09-11 11:21 ` Peter Ujfalusi [this message]
2026-09-11 11:21 ` [PATCH v3 05/26] ASoC: soc-compress: Implement trigger FE-BE sequencing as with normal PCMs Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 06/26] ASoC: soc-compress: Stop running dpcm on free Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 07/26] ASoC: SOF: compress: Move the IPC agnostic helpers to sof-audio.c Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 08/26] ASoC: SOF: compress: Rename compress ops with ipc3 prefix Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 09/26] ASoC: SOF: sof-audio: Fix the pipeline_list population Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 10/26] ASoC: SOF: ipc4-pcm: Serialize the PCM free with the pipeline triggers Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 11/26] ASoC: SOF: sof-audio: do not dereference swidget->spipe unconditionally on free Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 12/26] ASoC: SOF: sof-audio: Expose a couple of functions Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 13/26] ASoC: SOF: pcm: Modify the signature of a couple of PCM IPC ops Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 14/26] ASoC: SOF: intel: hda-stream: Clear the current position when releasing stream Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 15/26] ASoC: SOF: ipc4: Add definition of module data in init_ext object type Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 16/26] ASoC: SOF: ipc4-topology: Support init_ext_module_data for process modules Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 17/26] ASoC: SOF: ipc4-pcm: Make the timestamp info usable outside of ipc4-pcm.c Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 18/26] ASoC: SOF: ipc4/ipc4-loader: Add SOF_INFO and CODEC_INFO to fw_config_params Peter Ujfalusi
2026-09-11 21:01   ` Mark Brown
2026-09-11 11:21 ` [PATCH v3 19/26] ASoC: SOF: ipc4-pcm: Handle COMPR DRAIN triggers as EOS pipeline state Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 20/26] ASoC: SOF: ipc4-topology: Set FAST_MODE for host copier in compr mode Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 21/26] ASoC: SOF: ops: Add new platform-specific ops for compress Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 22/26] ASoC: SOF: Add support for IPC4 compressed Peter Ujfalusi
2026-09-11 20:50   ` Mark Brown
2026-09-11 11:21 ` [PATCH v3 23/26] ASoC: SOF: ipc4: Handle compressed drain done notification from firmware Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 24/26] ASoC: SOF: Intel: Kconfig: Remove redundant IPC version selects Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 25/26] ASoC: SOF: Intel: Kconfig: Select compress support for TGL+ platforms Peter Ujfalusi
2026-09-11 11:21 ` [PATCH v3 26/26] ASoC: SOF: topology: Add support for decoder and encoder widgets Peter Ujfalusi

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=20260911112152.28528-5-peter.ujfalusi@linux.intel.com \
    --to=peter.ujfalusi@linux.intel.com \
    --cc=broonie@kernel.org \
    --cc=daniel.baluta@nxp.com \
    --cc=kai.vehmanen@linux.intel.com \
    --cc=lgirdwood@gmail.com \
    --cc=linux-sound@vger.kernel.org \
    --cc=perex@perex.cz \
    --cc=pierre-louis.bossart@linux.dev \
    --cc=srinivas.kandagatla@oss.qualcomm.com \
    --cc=tiwai@suse.com \
    --cc=vkoul@kernel.org \
    --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