[PATCH 2/3] ASoC: add function parameters to enable forced path pruning

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Mon Mar 9 22:48:49 CET 2020



On 3/9/20 12:07 PM, Guennadi Liakhovetski wrote:
> This is a preparation for the host part of a virtualised VirtIO audio
> host-guest driver pair. It adds a "mode" parameter to
> soc_dpcm_runtime_update() to allow it to be used when stopping
> streaming in a virtual machine, which requires forced DPCM audio path
> pruning.
> 
> For audio virtualisation the host side driver will be using the vhost
> API, i.e. it will run completely in the kernel. When a guest begins to
> stream audio, the vhost calls snd_soc_runtime_activate() and
> soc_dpcm_runtime_update() to activate an audio path and update audio
> routing. When streaming is stopped, the vhost driver calls
> soc_dpcm_runtime_update() and snd_soc_runtime_deactivate(). The latter
> doesn't work at the moment, because the DPCM doesn't recognise the
> path as inactive. We address this by adding a "mode" parameter to
> soc_dpcm_runtime_update(). If virtualisation isn't used, the current
> behaviour isn't affected.
> 
> Signed-off-by: Guennadi Liakhovetski <guennadi.liakhovetski at linux.intel.com>

Late feedback I know, but would it make sense to split this patch in two 
where
a) first dpcm_process_paths() take a new force_prune parameter, set to 
false always
b) the prune parameter is modified depending on the update_mode

Besides making it simpler to review it would also allow to check for 
non-regressions/bisect.

> ---
>   include/sound/soc-dpcm.h | 28 ++++++++++++++++----
>   sound/soc/soc-compress.c |  2 +-
>   sound/soc/soc-dapm.c     |  8 +++---
>   sound/soc/soc-pcm.c      | 68 +++++++++++++++++++++++++++++++++---------------
>   4 files changed, 75 insertions(+), 31 deletions(-)
> 
> diff --git a/include/sound/soc-dpcm.h b/include/sound/soc-dpcm.h
> index 4022357..aa56118 100644
> --- a/include/sound/soc-dpcm.h
> +++ b/include/sound/soc-dpcm.h
> @@ -61,6 +61,23 @@ enum snd_soc_dpcm_trigger {
>   	SND_SOC_DPCM_TRIGGER_BESPOKE,
>   };
>   
> +/**
> + * enum snd_soc_dpcm_update_mode - mode for calling soc_dpcm_runtime_update()
> + *
> + * @SND_SOC_DPCM_UPDATE_FULL:		default mode, used for mux, mixer, and
> + *					volume widgets
> + * @SND_SOC_DPCM_UPDATE_NEW_ONLY:	a pipeline is starting. Skip checking
> + *					for old paths.
> + * @SND_SOC_DPCM_UPDATE_OLD_ONLY:	a pipeline is shutting down. Skip
> + *					checking for new paths, force old path
> + *					pruning.
> + */
> +enum snd_soc_dpcm_update_mode {
> +	SND_SOC_DPCM_UPDATE_FULL,
> +	SND_SOC_DPCM_UPDATE_NEW_ONLY,
> +	SND_SOC_DPCM_UPDATE_OLD_ONLY,
> +};
> +
>   /*
>    * Dynamic PCM link
>    * This links together a FE and BE DAI at runtime and stores the link
> @@ -133,7 +150,8 @@ struct snd_pcm_substream *
>   	snd_soc_dpcm_get_substream(struct snd_soc_pcm_runtime *be, int stream);
>   
>   /* internal use only */
> -int soc_dpcm_runtime_update(struct snd_soc_card *);
> +int soc_dpcm_runtime_update(struct snd_soc_card *card,
> +			    enum snd_soc_dpcm_update_mode mode);
>   
>   #ifdef CONFIG_DEBUG_FS
>   void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd);
> @@ -143,11 +161,11 @@ static inline void soc_dpcm_debugfs_add(struct snd_soc_pcm_runtime *rtd)
>   }
>   #endif
>   
> -int dpcm_path_get(struct snd_soc_pcm_runtime *fe,
> -	int stream, struct snd_soc_dapm_widget_list **list_);
> +int dpcm_path_get(struct snd_soc_pcm_runtime *fe, int stream,
> +	struct snd_soc_dapm_widget_list **list_);
>   void dpcm_path_put(struct snd_soc_dapm_widget_list **list);
> -int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
> -	int stream, struct snd_soc_dapm_widget_list **list, int new);
> +int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, int stream,
> +	struct snd_soc_dapm_widget_list **list, bool new, bool force_prune);
>   int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream);
>   int dpcm_be_dai_shutdown(struct snd_soc_pcm_runtime *fe, int stream);
>   void dpcm_be_disconnect(struct snd_soc_pcm_runtime *fe, int stream);
> diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
> index 50062eb..66d7e78 100644
> --- a/sound/soc/soc-compress.c
> +++ b/sound/soc/soc-compress.c
> @@ -162,7 +162,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream)
>   		dev_dbg(fe->dev, "Compress ASoC: %s no valid %s route\n",
>   			fe->dai_link->name, stream ? "capture" : "playback");
>   	/* calculate valid and active FE <-> BE dpcms */
> -	dpcm_process_paths(fe, stream, &list, 1);
> +	dpcm_process_paths(fe, stream, &list, true, false);
>   	fe->dpcm[stream].runtime = fe_substream->runtime;
>   
>   	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
> diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
> index 09fa437..f496c53 100644
> --- a/sound/soc/soc-dapm.c
> +++ b/sound/soc/soc-dapm.c
> @@ -2292,7 +2292,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm,
>   	card->update = NULL;
>   	mutex_unlock(&card->dapm_mutex);
>   	if (ret > 0)
> -		soc_dpcm_runtime_update(card);
> +		soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);
>   	return ret;
>   }
>   EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power);
> @@ -2357,7 +2357,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm,
>   	card->update = NULL;
>   	mutex_unlock(&card->dapm_mutex);
>   	if (ret > 0)
> -		soc_dpcm_runtime_update(card);
> +		soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);
>   	return ret;
>   }
>   EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power);
> @@ -3397,7 +3397,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol,
>   	mutex_unlock(&card->dapm_mutex);
>   
>   	if (ret > 0)
> -		soc_dpcm_runtime_update(card);
> +		soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);
>   
>   	return change;
>   }
> @@ -3502,7 +3502,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol,
>   	mutex_unlock(&card->dapm_mutex);
>   
>   	if (ret > 0)
> -		soc_dpcm_runtime_update(card);
> +		soc_dpcm_runtime_update(card, SND_SOC_DPCM_UPDATE_FULL);
>   
>   	return change;
>   }
> diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
> index 8732cf1..5b3bc3f 100644
> --- a/sound/soc/soc-pcm.c
> +++ b/sound/soc/soc-pcm.c
> @@ -1658,14 +1658,14 @@ static bool dpcm_be_is_active(struct snd_soc_dpcm *dpcm, int stream,
>   }
>   
>   static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream,
> -	struct snd_soc_dapm_widget_list **list_)
> +			    struct snd_soc_dapm_widget_list **list_, bool force)
>   {
>   	struct snd_soc_dpcm *dpcm;
>   	int prune = 0;
>   
>   	/* Destroy any old FE <--> BE connections */
>   	for_each_dpcm_be(fe, stream, dpcm) {
> -		if (dpcm_be_is_active(dpcm, stream, *list_))
> +		if (!force && dpcm_be_is_active(dpcm, stream, *list_))
>   			continue;
>   
>   		dev_dbg(fe->dev, "ASoC: pruning %s BE %s for %s\n",
> @@ -1740,12 +1740,13 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream,
>    * FE substream.
>    */
>   int dpcm_process_paths(struct snd_soc_pcm_runtime *fe,
> -	int stream, struct snd_soc_dapm_widget_list **list, int new)
> +		       int stream, struct snd_soc_dapm_widget_list **list,
> +		       bool new, bool force_prune)
>   {
>   	if (new)
>   		return dpcm_add_paths(fe, stream, list);
>   	else
> -		return dpcm_prune_paths(fe, stream, list);
> +		return dpcm_prune_paths(fe, stream, list, force_prune);
>   }
>   
>   void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream)
> @@ -2770,11 +2771,13 @@ static int dpcm_fe_dai_prepare(struct snd_pcm_substream *substream)
>   	return ret;
>   }
>   
> -static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
> +static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream,
> +				    bool force)
>   {
>   	struct snd_pcm_substream *substream =
>   		snd_soc_dpcm_get_substream(fe, stream);
>   	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
> +	int event = force ? SND_SOC_DAPM_STREAM_STOP : SND_SOC_DAPM_STREAM_NOP;
>   	int err;
>   
>   	dev_dbg(fe->dev, "ASoC: runtime %s close on FE %s\n",
> @@ -2806,7 +2809,7 @@ static int dpcm_run_update_shutdown(struct snd_soc_pcm_runtime *fe, int stream)
>   		dev_err(fe->dev,"ASoC: shutdown FE failed %d\n", err);
>   
>   	/* run the stream event for each BE */
> -	dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_NOP);
> +	dpcm_dapm_stream_event(fe, stream, event);
>   
>   	return 0;
>   }
> @@ -2899,7 +2902,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream)
>   	return ret;
>   }
>   
> -static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
> +static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, bool new,
> +				      bool force_prune)
>   {
>   	struct snd_soc_dapm_widget_list *list;
>   	int stream;
> @@ -2945,13 +2949,14 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
>   		}
>   
>   		/* update any playback/capture paths */
> -		count = dpcm_process_paths(fe, stream, &list, new);
> +		count = dpcm_process_paths(fe, stream, &list, new, force_prune);
>   		if (count) {
>   			dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE);
>   			if (new)
>   				ret = dpcm_run_update_startup(fe, stream);
>   			else
> -				ret = dpcm_run_update_shutdown(fe, stream);
> +				ret = dpcm_run_update_shutdown(fe, stream,
> +							       force_prune);
>   			if (ret < 0)
>   				dev_err(fe->dev, "ASoC: failed to shutdown some BEs\n");
>   			dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_NO);
> @@ -2969,25 +2974,46 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new)
>   /* Called by DAPM mixer/mux changes to update audio routing between PCMs and
>    * any DAI links.
>    */
> -int soc_dpcm_runtime_update(struct snd_soc_card *card)
> +int soc_dpcm_runtime_update(struct snd_soc_card *card,
> +			    enum snd_soc_dpcm_update_mode mode)
>   {
>   	struct snd_soc_pcm_runtime *fe;
>   	int ret = 0;
>   
>   	mutex_lock_nested(&card->mutex, SND_SOC_CARD_CLASS_RUNTIME);
> +
>   	/* shutdown all old paths first */
> -	for_each_card_rtds(card, fe) {
> -		ret = soc_dpcm_fe_runtime_update(fe, 0);
> -		if (ret)
> -			goto out;
> -	}
> +	if (mode != SND_SOC_DPCM_UPDATE_NEW_ONLY)
> +		/*
> +		 * This is entered if mode == FULL or OLD_ONLY. In both cases we
> +		 * have to call soc_dpcm_fe_runtime_update() but only in the
> +		 * OLD_ONLY case we have to set the "force" (last) parameter to
> +		 * "true."
> +		 */
> +		for_each_card_rtds(card, fe) {
> +			/*
> +			 * check "old" paths (new = false), only force for
> +			 * shutting down.
> +			 */
> +			ret = soc_dpcm_fe_runtime_update(fe, false,
> +					mode == SND_SOC_DPCM_UPDATE_OLD_ONLY);
> +			if (ret)
> +				goto out;
> +		}
>   
>   	/* bring new paths up */
> -	for_each_card_rtds(card, fe) {
> -		ret = soc_dpcm_fe_runtime_update(fe, 1);
> -		if (ret)
> -			goto out;
> -	}
> +	if (mode != SND_SOC_DPCM_UPDATE_OLD_ONLY)
> +		/*
> +		 * This is entered if mode == FULL or NEW_ONLY. In both cases we
> +		 * have to call soc_dpcm_fe_runtime_update() with the "force"
> +		 * (last) parameter set to "false"
> +		 */
> +		for_each_card_rtds(card, fe) {
> +			/* check "new" paths (new = true), no forcing */
> +			ret = soc_dpcm_fe_runtime_update(fe, true, false);
> +			if (ret)
> +				goto out;
> +		}
>   
>   out:
>   	mutex_unlock(&card->mutex);
> @@ -3042,7 +3068,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream)
>   	}
>   
>   	/* calculate valid and active FE <-> BE dpcms */
> -	dpcm_process_paths(fe, stream, &list, 1);
> +	dpcm_process_paths(fe, stream, &list, true, false);
>   
>   	ret = dpcm_fe_dai_startup(fe_substream);
>   	if (ret < 0)
> 


More information about the Alsa-devel mailing list