[PATCH] soundwire: intel: trap TRIGGER_SUSPEND in .trigger callback

Takashi Iwai tiwai at suse.de
Tue Jul 27 08:30:11 CEST 2021


On Tue, 27 Jul 2021 07:32:56 +0200,
Bard Liao wrote:
> 
> From: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> 
> This patch provides both a simplification of the suspend flows and a
> better balanced operation during suspend/resume transition.
> 
> The exiting code relies on a convoluted way of dealing with suspend
> signals. Since there is no .suspend DAI callback, we used the
> component .suspend and marked all the component DAI dmas as
> 'suspended'. The information was used in the .prepare stage to
> differentiate resume operations from xrun handling, and only
> reinitialize SHIM registers and DMA in the former case.
> 
> While this solution has been working reliably for about 2 years, there
> is a much better solution consisting in trapping the TRIGGER_SUSPEND
> in the .trigger DAI ops. The DMA is still marked in the same way for
> the .prepare op to run, but in addition the callbacks sent to DSP
> firmware are now balanced.
> 
> Normal operation:
> hw_params -> intel_params_stream
> hw_free   -> intel_free_stream
> 
> suspend    -> intel_free_stream
> prepare    -> intel_params_stream
> 
> This balanced operation was not required with existing SOF firmware
> relying on static pipelines instantiated at every boot. With the
> on-going transition to dynamic pipelines, it's however a requirement
> to keep the use count for the DAI widget balanced across all
> transitions.

The trigger callback is handled in the stream lock atomically, and are
you sure that you want to operate a possibly heavy task there?

If it's just for releasing before re-acquiring a stream, you can do it
in sync_stop PCM ops instead, too.  This is called in prior to prepare
and hw_params ops when a stream has been stopped or suspended
beforehand.


thanks,

Takashi

> 
> Co-developed-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart at linux.intel.com>
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> Reviewed-by: Péter Ujfalusi <peter.ujfalusi at linux.intel.com>
> Reviewed-by: Rander Wang <rander.wang at intel.com>
> Signed-off-by: Bard Liao <yung-chuan.liao at linux.intel.com>
> ---
>  drivers/soundwire/intel.c | 53 +++++++++++++++++++++------------------
>  1 file changed, 29 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/soundwire/intel.c b/drivers/soundwire/intel.c
> index fb9c23e13206..a0178779a5ba 100644
> --- a/drivers/soundwire/intel.c
> +++ b/drivers/soundwire/intel.c
> @@ -1005,29 +1005,6 @@ static void intel_shutdown(struct snd_pcm_substream *substream,
>  	pm_runtime_put_autosuspend(cdns->dev);
>  }
>  
> -static int intel_component_dais_suspend(struct snd_soc_component *component)
> -{
> -	struct sdw_cdns_dma_data *dma;
> -	struct snd_soc_dai *dai;
> -
> -	for_each_component_dais(component, dai) {
> -		/*
> -		 * we don't have a .suspend dai_ops, and we don't have access
> -		 * to the substream, so let's mark both capture and playback
> -		 * DMA contexts as suspended
> -		 */
> -		dma = dai->playback_dma_data;
> -		if (dma)
> -			dma->suspended = true;
> -
> -		dma = dai->capture_dma_data;
> -		if (dma)
> -			dma->suspended = true;
> -	}
> -
> -	return 0;
> -}
> -
>  static int intel_pcm_set_sdw_stream(struct snd_soc_dai *dai,
>  				    void *stream, int direction)
>  {
> @@ -1056,11 +1033,39 @@ static void *intel_get_sdw_stream(struct snd_soc_dai *dai,
>  	return dma->stream;
>  }
>  
> +static int intel_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai)
> +{
> +	struct sdw_cdns *cdns = snd_soc_dai_get_drvdata(dai);
> +	struct sdw_intel *sdw = cdns_to_intel(cdns);
> +	struct sdw_cdns_dma_data *dma;
> +
> +	/*
> +	 * The .prepare callback is used to deal with xruns and resume operations. In the case
> +	 * of xruns, the DMAs and SHIM registers cannot be touched, but for resume operations the
> +	 * DMAs and SHIM registers need to be initialized.
> +	 * the .trigger callback is used to track the suspend case only.
> +	 */
> +	if (cmd != SNDRV_PCM_TRIGGER_SUSPEND)
> +		return 0;
> +
> +	dma = snd_soc_dai_get_dma_data(dai, substream);
> +	if (!dma) {
> +		dev_err(dai->dev, "failed to get dma data in %s\n",
> +			__func__);
> +		return -EIO;
> +	}
> +
> +	dma->suspended = true;
> +
> +	return intel_free_stream(sdw, substream, dai, sdw->instance);
> +}
> +
>  static const struct snd_soc_dai_ops intel_pcm_dai_ops = {
>  	.startup = intel_startup,
>  	.hw_params = intel_hw_params,
>  	.prepare = intel_prepare,
>  	.hw_free = intel_hw_free,
> +	.trigger = intel_trigger,
>  	.shutdown = intel_shutdown,
>  	.set_sdw_stream = intel_pcm_set_sdw_stream,
>  	.get_sdw_stream = intel_get_sdw_stream,
> @@ -1071,6 +1076,7 @@ static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
>  	.hw_params = intel_hw_params,
>  	.prepare = intel_prepare,
>  	.hw_free = intel_hw_free,
> +	.trigger = intel_trigger,
>  	.shutdown = intel_shutdown,
>  	.set_sdw_stream = intel_pdm_set_sdw_stream,
>  	.get_sdw_stream = intel_get_sdw_stream,
> @@ -1078,7 +1084,6 @@ static const struct snd_soc_dai_ops intel_pdm_dai_ops = {
>  
>  static const struct snd_soc_component_driver dai_component = {
>  	.name           = "soundwire",
> -	.suspend	= intel_component_dais_suspend
>  };
>  
>  static int intel_create_dai(struct sdw_cdns *cdns,
> -- 
> 2.17.1
> 


More information about the Alsa-devel mailing list