From f6fba80b5fa8f3d34e2625cc74dbc6b88d3a41d1 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 11 Feb 2020 22:57:55 -0500 Subject: [PATCH] fixes for 4.9 Signed-off-by: Sasha Levin --- ...fe-be-trigger-order-based-on-the-com.patch | 185 ++++++++++++++++++ queue-4.9/series | 1 + 2 files changed, 186 insertions(+) create mode 100644 queue-4.9/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch diff --git a/queue-4.9/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch b/queue-4.9/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch new file mode 100644 index 00000000000..b6a801188bf --- /dev/null +++ b/queue-4.9/asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch @@ -0,0 +1,185 @@ +From 458fe42e530d513061d8ed2345452518a7b80ca7 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Mon, 4 Nov 2019 14:48:11 -0800 +Subject: ASoC: pcm: update FE/BE trigger order based on the command + +From: Ranjani Sridharan + +[ Upstream commit acbf27746ecfa96b290b54cc7f05273482ea128a ] + +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. + +Signed-off-by: Ranjani Sridharan +Signed-off-by: Pierre-Louis Bossart +Link: https://lore.kernel.org/r/20191104224812.3393-2-ranjani.sridharan@linux.intel.com +Signed-off-by: Mark Brown +Signed-off-by: Sasha Levin +--- + sound/soc/soc-pcm.c | 95 ++++++++++++++++++++++++++++++++------------- + 1 file changed, 68 insertions(+), 27 deletions(-) + +diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c +index 635b22fa1101a..280bb5cab87fd 100644 +--- a/sound/soc/soc-pcm.c ++++ b/sound/soc/soc-pcm.c +@@ -2137,42 +2137,81 @@ 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_be(struct snd_pcm_substream *substream, ++ int cmd, bool fe_first) ++{ ++ 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_be(substream, cmd, true); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ ret = dpcm_dai_trigger_fe_be(substream, cmd, false); ++ break; ++ 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_be(substream, cmd, false); ++ break; ++ case SNDRV_PCM_TRIGGER_STOP: ++ case SNDRV_PCM_TRIGGER_SUSPEND: ++ case SNDRV_PCM_TRIGGER_PAUSE_PUSH: ++ ret = dpcm_dai_trigger_fe_be(substream, cmd, true); ++ break; ++ default: ++ ret = -EINVAL; ++ break; + } +- +- dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", +- fe->dai_link->name, cmd); +- +- ret = soc_pcm_trigger(substream, cmd); + break; + case SND_SOC_DPCM_TRIGGER_BESPOKE: + /* bespoke trigger() - handles both FE and BEs */ +@@ -2181,10 +2220,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) + fe->dai_link->name, cmd); + + ret = soc_pcm_bespoke_trigger(substream, cmd); +- if (ret < 0) { +- dev_err(fe->dev,"ASoC: trigger FE failed %d\n", ret); +- goto out; +- } + break; + default: + dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, +@@ -2193,6 +2228,12 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) + goto out; + } + ++ if (ret < 0) { ++ dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", ++ cmd, ret); ++ goto out; ++ } ++ + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: +-- +2.20.1 + diff --git a/queue-4.9/series b/queue-4.9/series index 718da544317..3de70777ae4 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -94,3 +94,4 @@ cifs-fail-i-o-on-soft-mounts-if-sessionsetup-errors-out.patch clocksource-prevent-double-add_timer_on-for-watchdog_timer.patch perf-core-fix-mlock-accounting-in-perf_mmap.patch rxrpc-fix-service-call-disconnection.patch +asoc-pcm-update-fe-be-trigger-order-based-on-the-com.patch -- 2.47.3