[alsa-devel] [RFC PATCH 1/2] ASoC: pcm: update FE/BE trigger order based on the command

Pierre-Louis Bossart pierre-louis.bossart at linux.intel.com
Fri Oct 4 23:32:34 CEST 2019


On 10/4/19 8:41 AM, Ranjani Sridharan wrote:
> Currently, the trigger orders SND_SOC_DPCM_TRIGGER_PRE/POST
> determine the order in which FE DAI and BE DAI are triggered.
> In the case of SND_SOC_DPCM_TRIGGER_PRE, the FE DAI is
> triggered before the BE DAI and in the case of
> SND_SOC_DPCM_TRIGGER_POST, the BE DAI is triggered before
> the FE DAI. And this order remains the same irrespective of the
> trigger command.
> 
> In the case of the SOF driver, during playback, the FW
> expects the BE DAI to be triggered before the FE DAI during
> the START trigger. The BE DAI trigger handles the starting of
> Link DMA and so it must be started before the FE DAI is started
> to prevent xruns during pause/release. This can be addressed
> by setting the trigger order for the FE dai link to
> SND_SOC_DPCM_TRIGGER_POST. But during the STOP trigger,
> the FW expects the FE DAI to be triggered before the BE DAI.
> Retaining the same order during the START and STOP commands,
> results in FW error as the DAI component in the FW is still
> active.
> 
> The issue can be fixed by mirroring the trigger order of
> FE and BE DAI's during the START and STOP trigger. So, with the
> trigger order set to SND_SOC_DPCM_TRIGGER_PRE, the FE DAI will be
> trigger first during SNDRV_PCM_TRIGGER_START/STOP/RESUME
> and the BE DAI will be triggered first during the
> STOP/SUSPEND/PAUSE commands. Conversely, with the trigger order
> set to SND_SOC_DPCM_TRIGGER_POST, the BE DAI will be triggered
> first during the SNDRV_PCM_TRIGGER_START/STOP/RESUME commands
> and the FE DAI will be triggered first during the
> SNDRV_PCM_TRIGGER_STOP/SUSPEND/PAUSE commands.
> 
> Github Issue: https://github.com/thesofproject/linux/issues/1160
> Signed-off-by: Ranjani Sridharan <ranjani.sridharan at linux.intel.com>
> ---
>   sound/soc/soc-pcm.c | 99 ++++++++++++++++++++++++++++++++-------------
>   1 file changed, 72 insertions(+), 27 deletions(-)
> 
> diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
> index 66910500e3b6..8e5097eead27 100644
> --- a/sound/soc/soc-pcm.c
> +++ b/sound/soc/soc-pcm.c
> @@ -2340,42 +2340,85 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream,
>   }
>   EXPORT_SYMBOL_GPL(dpcm_be_dai_trigger);
>   
> +static int dpcm_dai_trigger_fe_first(struct snd_pcm_substream *substream,
> +				     int cmd, bool fe_first)

the function name is odd with the fe_first repeat

maybe 'dpcm_dai_trigger_fe_be' ?

> +{
> +	struct snd_soc_pcm_runtime *fe = substream->private_data;
> +	int ret;
> +
> +	/* call trigger on the frontend before the backend. */
> +	if (fe_first) {
> +		dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
> +			fe->dai_link->name, cmd);
> +
> +		ret = soc_pcm_trigger(substream, cmd);
> +		if (ret < 0)
> +			return ret;
> +
> +		ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
> +		return ret;
> +	}
> +
> +	/* call trigger on the frontend after the backend. */
> +	ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
> +	if (ret < 0)
> +		return ret;
> +
> +	dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n",
> +		fe->dai_link->name, cmd);
> +
> +	ret = soc_pcm_trigger(substream, cmd);
> +
> +	return ret;
> +}
> +
>   static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd)
>   {
>   	struct snd_soc_pcm_runtime *fe = substream->private_data;
> -	int stream = substream->stream, ret;
> +	int stream = substream->stream;
> +	int ret = 0;
>   	enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream];
>   
>   	fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE;
>   
>   	switch (trigger) {
>   	case SND_SOC_DPCM_TRIGGER_PRE:
> -		/* call trigger on the frontend before the backend. */
> -
> -		dev_dbg(fe->dev, "ASoC: pre trigger FE %s cmd %d\n",
> -				fe->dai_link->name, cmd);
> -
> -		ret = soc_pcm_trigger(substream, cmd);
> -		if (ret < 0) {
> -			dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
> -			goto out;
> +		switch (cmd) {
> +		case SNDRV_PCM_TRIGGER_START:
> +		case SNDRV_PCM_TRIGGER_RESUME:
> +		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +			ret = dpcm_dai_trigger_fe_first(substream, cmd, true);
> +			break;
> +		case SNDRV_PCM_TRIGGER_STOP:
> +		case SNDRV_PCM_TRIGGER_SUSPEND:
> +			ret = dpcm_dai_trigger_fe_first(substream, cmd, false);
> +			break;
> +		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +			ret = dpcm_dai_trigger_fe_first(substream, cmd, false);
> +			break;

can we group these 3 cases together? The last two are identical.

> +		default:
> +			ret = -EINVAL;
> +			break;
>   		}
> -
> -		ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
>   		break;
>   	case SND_SOC_DPCM_TRIGGER_POST:
> -		/* call trigger on the frontend after the backend. */
> -
> -		ret = dpcm_be_dai_trigger(fe, substream->stream, cmd);
> -		if (ret < 0) {
> -			dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret);
> -			goto out;
> +		switch (cmd) {
> +		case SNDRV_PCM_TRIGGER_START:
> +		case SNDRV_PCM_TRIGGER_RESUME:
> +		case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +			ret = dpcm_dai_trigger_fe_first(substream, cmd, false);
> +			break;
> +		case SNDRV_PCM_TRIGGER_STOP:
> +		case SNDRV_PCM_TRIGGER_SUSPEND:
> +			ret = dpcm_dai_trigger_fe_first(substream, cmd, true);
> +			break;
> +		case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +			ret = dpcm_dai_trigger_fe_first(substream, cmd, true);
> +			break;

can we group these 3 cases together? The last two are identical.

> +		default:
> +			ret = -EINVAL;
> +			break;
>   		}


More information about the Alsa-devel mailing list