diff mbox series

[v3,5/8] ASoC: soc-pcm: call snd_soc_dai_startup()/shutdown() once

Message ID 875zgfcey5.wl-kuninori.morimoto.gx@renesas.com (mailing list archive)
State Accepted
Commit b56be800f1292c9b79c4f66571c701551bdf9e12
Headers show
Series ASoC: soc-pcm cleanup step2 | expand

Commit Message

Kuninori Morimoto Feb. 10, 2020, 3:14 a.m. UTC
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

Current soc_pcm_open() calls snd_soc_dai_startup() under loop.
Thus, it needs to care about started/not-yet-started codec DAI.

But, if soc-dai.c is handling it, soc-pcm.c don't need to care
about it.
This patch adds started flag to soc-dai.h, and simplify soc-pcm.c.
This is one of prepare for cleanup soc-pcm-open()

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
v2 -> v3

	- use flag
	- Startuped DAI only can call Shutdown,
	  and it can't Start again without Shutdown.

 include/sound/soc-dai.h |  5 ++++-
 sound/soc/soc-dai.c     | 11 +++++++++--
 sound/soc/soc-pcm.c     |  7 ++-----
 3 files changed, 15 insertions(+), 8 deletions(-)

Comments

Amadeusz Sławiński March 27, 2020, 6:16 p.m. UTC | #1
On 2/10/2020 4:14 AM, Kuninori Morimoto wrote:
> 
> From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> 
> Current soc_pcm_open() calls snd_soc_dai_startup() under loop.
> Thus, it needs to care about started/not-yet-started codec DAI.
> 
> But, if soc-dai.c is handling it, soc-pcm.c don't need to care
> about it.
> This patch adds started flag to soc-dai.h, and simplify soc-pcm.c.
> This is one of prepare for cleanup soc-pcm-open()
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>

> ---
(...)

>   static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
> diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
> index 51031e33..73a8293 100644
> --- a/sound/soc/soc-dai.c
> +++ b/sound/soc/soc-dai.c
> @@ -295,17 +295,24 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
>   {
>   	int ret = 0;
>   
> -	if (dai->driver->ops->startup)
> +	if (!dai->started &&
> +	    dai->driver->ops->startup)
>   		ret = dai->driver->ops->startup(substream, dai);
>   
> +	if (ret == 0)
> +		dai->started = 1;
> +
>   	return ret;
>   }

Hi,

the above change breaks simultaneous playback and capture on single DAI 
in more complicated use cases. With above change when one runs playback 
first, startup callback is skipped when running capture while playback 
is still running.

With snd_soc_skl it leads to null pointer dereference, because we didn't 
initialize streams properly:

[   78.901574] dpcm_be_dai_hw_params:2219:  Analog Playback and Capture: 
ASoC: hw_params BE Analog Playback and Capture
[   78.901582] dapm_update_dai_unlocked:2638: snd_hda_codec_realtek 
ehdaudio0D0: Update DAI routes for Analog Codec DAI capture
[   78.901585] dapm_update_dai_chan:2612: snd_hda_codec_realtek 
ehdaudio0D0: Connecting DAI route AIF3TX -> Analog Codec Capture
[   78.901590] dapm_update_dai_chan:2612: snd_hda_codec_realtek 
ehdaudio0D0: Connecting DAI route AIF1TX -> Analog Codec Capture
[   78.901608] dapm_update_dai_unlocked:2638: snd_soc_skl 0000:00:1f.3: 
Update DAI routes for Analog CPU DAI capture
[   78.901612] dapm_update_dai_chan:2612: snd_soc_skl 0000:00:1f.3: 
Connecting DAI route Analog CPU Capture -> codec0_in
[   78.901615] dpcm_fe_dai_hw_params:2277:  Analog HDA DSP: ASoC: 
hw_params FE Analog HDA DSP rate 48000 chan 2 fmt 2
[   78.901622] skl_pcm_hw_params:307: snd_soc_skl 0000:00:1f.3: 
skl_pcm_hw_params: hda-dsp-analog-dai
[   78.901624] 
==================================================================
[   78.907515] BUG: KASAN: null-ptr-deref in 
skl_pcm_hw_params+0x102/0x3d0 [snd_soc_skl]
[   78.914003] Write of size 4 at addr 0000000000000044 by task arecord/2119

Amadeusz
Pierre-Louis Bossart March 27, 2020, 6:38 p.m. UTC | #2
>>   static inline void *snd_soc_dai_get_dma_data(const struct 
>> snd_soc_dai *dai,
>> diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
>> index 51031e33..73a8293 100644
>> --- a/sound/soc/soc-dai.c
>> +++ b/sound/soc/soc-dai.c
>> @@ -295,17 +295,24 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
>>   {
>>       int ret = 0;
>> -    if (dai->driver->ops->startup)
>> +    if (!dai->started &&
>> +        dai->driver->ops->startup)
>>           ret = dai->driver->ops->startup(substream, dai);
>> +    if (ret == 0)
>> +        dai->started = 1;
>> +
>>       return ret;
>>   }
> 
> Hi,
> 
> the above change breaks simultaneous playback and capture on single DAI 
> in more complicated use cases. With above change when one runs playback 
> first, startup callback is skipped when running capture while playback 
> is still running.

Should the 'started' bitfield should be an array for capture and 
playback cases respectively? e.g.

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 78bac995db15..d4825b82c7a3 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -351,7 +351,7 @@ struct snd_soc_dai {

         /* bit field */
         unsigned int probed:1;
-       unsigned int started:1;
+       unsigned int started[SNDRV_PCM_STREAM_LAST + 1];
  };

  static inline struct snd_soc_pcm_stream *
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 19142f6e533c..8f3cad8db89a 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -295,12 +295,12 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
  {
         int ret = 0;

-       if (!dai->started &&
+       if (!dai->started[substream->stream] &&
             dai->driver->ops->startup)
                 ret = dai->driver->ops->startup(substream, dai);

         if (ret == 0)
-               dai->started = 1;
+               dai->started[substream->stream] = 1;

         return ret;
  }
@@ -308,11 +308,11 @@ int snd_soc_dai_startup(struct snd_soc_dai *dai,
  void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
                          struct snd_pcm_substream *substream)
  {
-       if (dai->started &&
+       if (dai->started[substream->stream] &&
             dai->driver->ops->shutdown)
                 dai->driver->ops->shutdown(substream, dai);

-       dai->started = 0;
+       dai->started[substream->stream] = 0;
  }

  int snd_soc_dai_prepare(struct snd_soc_dai *dai,
Kuninori Morimoto March 30, 2020, 1:10 a.m. UTC | #3
Hi Amadeusz, Pierre-Louis

Thank you for your feedback, and sorry to bother you.

> > the above change breaks simultaneous playback and capture on single
> > DAI in more complicated use cases. With above change when one runs
> > playback first, startup callback is skipped when running capture
> > while playback is still running.

Similar issue had been happened on component open before.
https://lore.kernel.org/alsa-devel/20200219182650.1416-1-kai.vehmanen@linux.intel.com/

I'm so sorry but this is bug.
In my quick check, this patch is not related to other patches.
So, just reverting it is nice idea, I think.

> Should the 'started' bitfield should be an array for capture and
> playback cases respectively? e.g.

Yeah.
But, I will re-try this issue (for DAI, for Component) again.
Let's just revert it so far.
Is it OK for you ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto




Thank you for your help !!

Best regards
---
Kuninori Morimoto
Amadeusz Sławiński March 30, 2020, 7:25 a.m. UTC | #4
On 3/30/2020 3:10 AM, Kuninori Morimoto wrote:
> 
> Hi Amadeusz, Pierre-Louis
> 
> Thank you for your feedback, and sorry to bother you.
> 
>>> the above change breaks simultaneous playback and capture on single
>>> DAI in more complicated use cases. With above change when one runs
>>> playback first, startup callback is skipped when running capture
>>> while playback is still running.
> 
> Similar issue had been happened on component open before.
> https://lore.kernel.org/alsa-devel/20200219182650.1416-1-kai.vehmanen@linux.intel.com/
> 
> I'm so sorry but this is bug.
> In my quick check, this patch is not related to other patches.
> So, just reverting it is nice idea, I think.
> 
>> Should the 'started' bitfield should be an array for capture and
>> playback cases respectively? e.g.
> 
> Yeah.
> But, I will re-try this issue (for DAI, for Component) again.
> Let's just revert it so far.
> Is it OK for you ?
> 
> Thank you for your help !!
> 

Hi,

I tested patch from Pierre and it works for me, I'm also ok with revert.

Thanks,
Amadeusz
Mark Brown March 30, 2020, 11:08 a.m. UTC | #5
On Mon, Mar 30, 2020 at 09:25:31AM +0200, Amadeusz Sławiński wrote:
> On 3/30/2020 3:10 AM, Kuninori Morimoto wrote:

> > But, I will re-try this issue (for DAI, for Component) again.
> > Let's just revert it so far.
> > Is it OK for you ?

> I tested patch from Pierre and it works for me, I'm also ok with revert.

Pierre's patch makes sense to me and this is the only reported issue so
I'd be happy with that.  Whichever way can one (or both!) of you please
send a patch?
Kuninori Morimoto March 30, 2020, 11:28 p.m. UTC | #6
Hi Mark

> > I tested patch from Pierre and it works for me, I'm also ok with revert.
> 
> Pierre's patch makes sense to me and this is the only reported issue so
> I'd be happy with that.  Whichever way can one (or both!) of you please
> send a patch?

I have no objection about Pierre's patch.
But I want to re-make it in future.

Thank you for your help !!

Best regards
---
Kuninori Morimoto
diff mbox series

Patch

diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index eaaeb00..04c23ac 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -324,7 +324,6 @@  struct snd_soc_dai {
 	/* DAI runtime info */
 	unsigned int capture_active;		/* stream usage count */
 	unsigned int playback_active;		/* stream usage count */
-	unsigned int probed:1;
 
 	unsigned int active;
 
@@ -348,6 +347,10 @@  struct snd_soc_dai {
 	unsigned int rx_mask;
 
 	struct list_head list;
+
+	/* bit field */
+	unsigned int probed:1;
+	unsigned int started:1;
 };
 
 static inline void *snd_soc_dai_get_dma_data(const struct snd_soc_dai *dai,
diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c
index 51031e33..73a8293 100644
--- a/sound/soc/soc-dai.c
+++ b/sound/soc/soc-dai.c
@@ -295,17 +295,24 @@  int snd_soc_dai_startup(struct snd_soc_dai *dai,
 {
 	int ret = 0;
 
-	if (dai->driver->ops->startup)
+	if (!dai->started &&
+	    dai->driver->ops->startup)
 		ret = dai->driver->ops->startup(substream, dai);
 
+	if (ret == 0)
+		dai->started = 1;
+
 	return ret;
 }
 
 void snd_soc_dai_shutdown(struct snd_soc_dai *dai,
 			 struct snd_pcm_substream *substream)
 {
-	if (dai->driver->ops->shutdown)
+	if (dai->started &&
+	    dai->driver->ops->shutdown)
 		dai->driver->ops->shutdown(substream, dai);
+
+	dai->started = 0;
 }
 
 int snd_soc_dai_prepare(struct snd_soc_dai *dai,
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 8d8ed47..d53afb9 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -568,7 +568,7 @@  static int soc_pcm_open(struct snd_pcm_substream *substream)
 	if (ret < 0) {
 		pr_err("ASoC: %s startup failed: %d\n",
 		       rtd->dai_link->name, ret);
-		goto machine_err;
+		goto codec_dai_err;
 	}
 
 	/* Dynamic PCM DAI links compat checks use dynamic capabilities */
@@ -637,11 +637,8 @@  static int soc_pcm_open(struct snd_pcm_substream *substream)
 config_err:
 	soc_rtd_shutdown(rtd, substream);
 
-machine_err:
-	i = rtd->num_codecs;
-
 codec_dai_err:
-	for_each_rtd_codec_dai_rollback(rtd, i, codec_dai)
+	for_each_rtd_codec_dai(rtd, i, codec_dai)
 		snd_soc_dai_shutdown(codec_dai, substream);
 
 component_err: