diff mbox series

[08/20] ASoC: soc-pcm.c: cleanup soc_get_playback_capture()

Message ID 87r0rep4we.wl-kuninori.morimoto.gx@renesas.com (mailing list archive)
State Superseded
Headers show
Series ASoC: replace dpcm_playback/capture to playback/capture_only | expand

Commit Message

Kuninori Morimoto May 18, 2023, 5:47 a.m. UTC
Current soc_get_playback_capture() (A) is checking playback/capture
availability for DPCM (X) / Normal (Y) / Codec2Codec (Z) connections.

(A)	static int soc_get_playback_capture(...)
	{
		...
 ^		if (dai_link->dynamic || dai_link->no_pcm) {
 |			...
 |(a)			if (dai_link->dpcm_playback) {
 |				...
 | ^				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 |(*)					...
 | v				}
 |				...
(X)			}
 |(b)			if (dai_link->dpcm_capture) {
 |				...
 | ^				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
 |(*)					...
 | v				}
 |				...
 v			}
		} else {
 ^ ^			/* Adapt stream for codec2codec links */
 |(Z)			int cpu_capture = ...
 | v			int cpu_playback = ...
(Y)
 | ^			for_each_rtd_codec_dais(rtd, i, codec_dai) {
 |(*)				...
 v v			}
		}
		...
	}

(*) part is checking each DAI's availability.

At first, (X) part is for DPCM, and it checks playback/capture
availability if dai_link has dpcm_playback/capture flag (a)(b).
But we are already using playback/capture_only flag.
for Normal (Y) and Codec2Codec (Z). We can use this flags for DPCM too.

Before				After
	dpcm_playback = 1;	=>	/* no flags */
	dpcm_capture  = 1;

	dpcm_playback = 1;	=>	playback_only = 1;

	dpcm_capture = 1;	=>	capture_only = 1;

This patch enables both flags case, but dpcm_playback/capture flags
will be removed if all driver were switched to new playback/capture_only
flags.

Here, CPU <-> Codec relationship is like this

	DPCM
		[CPU/dummy]-[dummy/Codec]
		^^^^^^^^^^^
	Normal
		[CPU/Codec]
		^^^^^^^^^^^

(X) part is checking only CPU       DAI, and
(Y) part is checking both CPU/Codec DAI

This means (X)/(Y) are checking same position.
Because dammy DAI is always available,
we can share same code for all cases (= X/Y/Z).

This patch merge these.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 sound/soc/soc-pcm.c | 75 +++++++++++++--------------------------------
 1 file changed, 22 insertions(+), 53 deletions(-)

Comments

Amadeusz Sławiński May 18, 2023, 10:38 a.m. UTC | #1
On 5/18/2023 7:47 AM, Kuninori Morimoto wrote:
> Current soc_get_playback_capture() (A) is checking playback/capture
> availability for DPCM (X) / Normal (Y) / Codec2Codec (Z) connections.
> 
> (A)	static int soc_get_playback_capture(...)
> 	{
> 		...
>   ^		if (dai_link->dynamic || dai_link->no_pcm) {
>   |			...
>   |(a)			if (dai_link->dpcm_playback) {
>   |				...
>   | ^				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
>   |(*)					...
>   | v				}
>   |				...
> (X)			}
>   |(b)			if (dai_link->dpcm_capture) {
>   |				...
>   | ^				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
>   |(*)					...
>   | v				}
>   |				...
>   v			}
> 		} else {
>   ^ ^			/* Adapt stream for codec2codec links */
>   |(Z)			int cpu_capture = ...
>   | v			int cpu_playback = ...
> (Y)
>   | ^			for_each_rtd_codec_dais(rtd, i, codec_dai) {
>   |(*)				...
>   v v			}
> 		}
> 		...
> 	}
> 
> (*) part is checking each DAI's availability.
> 
> At first, (X) part is for DPCM, and it checks playback/capture
> availability if dai_link has dpcm_playback/capture flag (a)(b).
> But we are already using playback/capture_only flag.
> for Normal (Y) and Codec2Codec (Z). We can use this flags for DPCM too.
> 
> Before				After
> 	dpcm_playback = 1;	=>	/* no flags */
> 	dpcm_capture  = 1;
> 
> 	dpcm_playback = 1;	=>	playback_only = 1;
> 
> 	dpcm_capture = 1;	=>	capture_only = 1;
> 
> This patch enables both flags case, but dpcm_playback/capture flags
> will be removed if all driver were switched to new playback/capture_only
> flags.
> 
> Here, CPU <-> Codec relationship is like this
> 
> 	DPCM
> 		[CPU/dummy]-[dummy/Codec]
> 		^^^^^^^^^^^
> 	Normal
> 		[CPU/Codec]
> 		^^^^^^^^^^^
> 
> (X) part is checking only CPU       DAI, and
> (Y) part is checking both CPU/Codec DAI
> 
> This means (X)/(Y) are checking same position.
> Because dammy DAI is always available,
> we can share same code for all cases (= X/Y/Z).
> 
> This patch merge these.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---

Reviewed-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Amadeusz Sławiński May 19, 2023, 9:57 a.m. UTC | #2
On 5/18/2023 7:47 AM, Kuninori Morimoto wrote:
> Current soc_get_playback_capture() (A) is checking playback/capture
> availability for DPCM (X) / Normal (Y) / Codec2Codec (Z) connections.
> 
> (A)	static int soc_get_playback_capture(...)
> 	{
> 		...
>   ^		if (dai_link->dynamic || dai_link->no_pcm) {
>   |			...
>   |(a)			if (dai_link->dpcm_playback) {
>   |				...
>   | ^				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
>   |(*)					...
>   | v				}
>   |				...
> (X)			}
>   |(b)			if (dai_link->dpcm_capture) {
>   |				...
>   | ^				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
>   |(*)					...
>   | v				}
>   |				...
>   v			}
> 		} else {
>   ^ ^			/* Adapt stream for codec2codec links */
>   |(Z)			int cpu_capture = ...
>   | v			int cpu_playback = ...
> (Y)
>   | ^			for_each_rtd_codec_dais(rtd, i, codec_dai) {
>   |(*)				...
>   v v			}
> 		}
> 		...
> 	}
> 
> (*) part is checking each DAI's availability.
> 
> At first, (X) part is for DPCM, and it checks playback/capture
> availability if dai_link has dpcm_playback/capture flag (a)(b).
> But we are already using playback/capture_only flag.
> for Normal (Y) and Codec2Codec (Z). We can use this flags for DPCM too.
> 
> Before				After
> 	dpcm_playback = 1;	=>	/* no flags */
> 	dpcm_capture  = 1;
> 
> 	dpcm_playback = 1;	=>	playback_only = 1;
> 
> 	dpcm_capture = 1;	=>	capture_only = 1;
> 
> This patch enables both flags case, but dpcm_playback/capture flags
> will be removed if all driver were switched to new playback/capture_only
> flags.
> 
> Here, CPU <-> Codec relationship is like this
> 
> 	DPCM
> 		[CPU/dummy]-[dummy/Codec]
> 		^^^^^^^^^^^
> 	Normal
> 		[CPU/Codec]
> 		^^^^^^^^^^^
> 
> (X) part is checking only CPU       DAI, and
> (Y) part is checking both CPU/Codec DAI
> 
> This means (X)/(Y) are checking same position.
> Because dammy DAI is always available,
> we can share same code for all cases (= X/Y/Z).
> 
> This patch merge these.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
> ---
>   sound/soc/soc-pcm.c | 75 +++++++++++++--------------------------------
>   1 file changed, 22 insertions(+), 53 deletions(-)
> 
> diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
> index af5d4e1effdf..f47ddf660c57 100644
> --- a/sound/soc/soc-pcm.c
> +++ b/sound/soc/soc-pcm.c
> @@ -2732,7 +2732,10 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
>   				    int *playback, int *capture)
>   {
>   	struct snd_soc_dai_link *dai_link = rtd->dai_link;
> +	struct snd_soc_dai *codec_dai;
>   	struct snd_soc_dai *cpu_dai;
> +	int cpu_capture  = SNDRV_PCM_STREAM_CAPTURE;
> +	int cpu_playback = SNDRV_PCM_STREAM_PLAYBACK;
>   	int tmp_playback = 0;
>   	int tmp_capture  = 0;
>   	int i;
> @@ -2748,61 +2751,27 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
>   		return -EINVAL;
>   	}
>   
> -	if (dai_link->dynamic || dai_link->no_pcm) {
> -		int stream;
> -
> -		if (dai_link->dpcm_playback) {
> -			stream = SNDRV_PCM_STREAM_PLAYBACK;
> +	/* Adapt stream for codec2codec links */
> +	if (dai_link->c2c_params) {
> +		cpu_capture  = SNDRV_PCM_STREAM_PLAYBACK;
> +		cpu_playback = SNDRV_PCM_STREAM_CAPTURE;
> +	}
>   
> -			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> -				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
> -					tmp_playback = 1;
> -					break;
> -				}
> -			}
> -			if (!tmp_playback) {
> -				dev_err(rtd->card->dev,
> -					"No CPU DAIs support playback for stream %s\n",
> -					dai_link->stream_name);
> -				return -EINVAL;
> -			}
> -		}
> -		if (dai_link->dpcm_capture) {
> -			stream = SNDRV_PCM_STREAM_CAPTURE;
> +	/* REMOVE ME */
> +	if (dai_link->dpcm_playback && !dai_link->dpcm_capture)
> +		dai_link->playback_only = 1;
> +	if (!dai_link->dpcm_playback && dai_link->dpcm_capture)
> +		dai_link->capture_only = 1;
>   
> -			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> -				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
> -					tmp_capture = 1;
> -					break;
> -				}
> -			}
> -
> -			if (!tmp_capture) {
> -				dev_err(rtd->card->dev,
> -					"No CPU DAIs support capture for stream %s\n",
> -					dai_link->stream_name);
> -				return -EINVAL;
> -			}
> -		}
> -	} else {
> -		struct snd_soc_dai *codec_dai;
> -
> -		/* Adapt stream for codec2codec links */
> -		int cpu_capture = dai_link->c2c_params ?
> -			SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
> -		int cpu_playback = dai_link->c2c_params ?
> -			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
> -
> -		for_each_rtd_codec_dais(rtd, i, codec_dai) {
> -			cpu_dai = asoc_rtd_to_cpu(rtd, i);
> -
> -			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
> -			    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
> -				tmp_playback = 1;
> -			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
> -			    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
> -				tmp_capture = 1;
> -		}
> +	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> +		codec_dai = asoc_rtd_to_codec(rtd, i); /* get paired codec */
> +
> +		if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
> +		    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
> +			tmp_playback = 1;
> +		if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
> +		    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
> +			tmp_capture = 1;
>   	}
>   
>   	if (dai_link->playback_only)

I put the patchset to test and it fails to enumerate devices on our 
platforms.

Bisect leads me to this patch, here is dmesg fragment:

[   34.609909] snd_soc_avs:avs_component_probe: avs_hdaudio 
avs_hdaudio.2: probing hdaudioB0D2-platform card hdaudioB0D2
[   34.612274] snd_soc_core:soc_tplg_load_header: avs_hdaudio 
avs_hdaudio.2: ASoC: Got 0x490 bytes of type 8 version 0 vendor 0 at pass 0
[   34.612456] snd_soc_core:soc_tplg_load_header: avs_hdaudio 
avs_hdaudio.2: ASoC: Got 0x7ec bytes of type 5 version 0 vendor 0 at pass 3
[   34.612477] snd_soc_core:soc_tplg_dapm_widget_elems_load: avs_hdaudio 
avs_hdaudio.2: ASoC: adding 6 DAPM widgets
[   34.612493] snd_soc_core:soc_tplg_dapm_widget_create: avs_hdaudio 
avs_hdaudio.2: ASoC: creating DAPM widget hdmi1_fe id 17
[   34.612774] snd_soc_core:soc_tplg_dapm_widget_create: avs_hdaudio 
avs_hdaudio.2: ASoC: creating DAPM widget hdmi1_be id 17
[   34.613025] snd_soc_core:soc_tplg_dapm_widget_create: avs_hdaudio 
avs_hdaudio.2: ASoC: creating DAPM widget hdmi2_fe id 17
[   34.613297] snd_soc_core:soc_tplg_dapm_widget_create: avs_hdaudio 
avs_hdaudio.2: ASoC: creating DAPM widget hdmi2_be id 17
[   34.613552] snd_soc_core:soc_tplg_dapm_widget_create: avs_hdaudio 
avs_hdaudio.2: ASoC: creating DAPM widget hdmi3_fe id 17
[   34.613823] snd_soc_core:soc_tplg_dapm_widget_create: avs_hdaudio 
avs_hdaudio.2: ASoC: creating DAPM widget hdmi3_be id 17
[   34.614077] snd_soc_core:soc_tplg_load_header: avs_hdaudio 
avs_hdaudio.2: ASoC: Got 0xab0 bytes of type 7 version 0 vendor 0 at pass 4
[   34.614272] snd_soc_core:snd_soc_register_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Registered DAI 'HDMI1-dai'
[   34.614290] snd_soc_core:snd_soc_dapm_new_dai_widgets: snd_soc_avs 
0000:00:0e.0: ASoC: adding HDMI1-playback widget
[   34.614453] snd_soc_core:snd_soc_add_pcm_runtime: avs_hdaudio 
avs_hdaudio.2: ASoC: binding HDMI1
[   34.615192] snd_soc_core:snd_soc_register_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Registered DAI 'HDMI2-dai'
[   34.615210] snd_soc_core:snd_soc_dapm_new_dai_widgets: snd_soc_avs 
0000:00:0e.0: ASoC: adding HDMI2-playback widget
[   34.615371] snd_soc_core:snd_soc_add_pcm_runtime: avs_hdaudio 
avs_hdaudio.2: ASoC: binding HDMI2
[   34.616060] snd_soc_core:snd_soc_register_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Registered DAI 'HDMI3-dai'
[   34.616077] snd_soc_core:snd_soc_dapm_new_dai_widgets: snd_soc_avs 
0000:00:0e.0: ASoC: adding HDMI3-playback widget
[   34.616235] snd_soc_core:snd_soc_add_pcm_runtime: avs_hdaudio 
avs_hdaudio.2: ASoC: binding HDMI3
[   34.616858] snd_soc_core:soc_tplg_pcm_elems_load: avs_hdaudio 
avs_hdaudio.2: ASoC: adding 3 PCM DAIs
[   34.616876] snd_soc_core:soc_tplg_load_header: avs_hdaudio 
avs_hdaudio.2: ASoC: Got 0x4a4 bytes of type 4 version 0 vendor 0 at pass 5
[   34.616895] snd_soc_core:soc_tplg_dapm_graph_elems_load: avs_hdaudio 
avs_hdaudio.2: ASoC: adding 9 DAPM routes for index 0
[   34.617601] avs_hdaudio avs_hdaudio.2: ASoC: Parent card not yet 
available, widget card binding deferred
[   34.618153] snd_soc_core:snd_soc_add_pcm_runtime: avs_hdaudio 
avs_hdaudio.2: ASoC: binding hdaudioB0D2 link0
[   34.618724] snd_soc_core:snd_soc_add_pcm_runtime: avs_hdaudio 
avs_hdaudio.2: ASoC: binding hdaudioB0D2 link1
[   34.619221] snd_soc_core:snd_soc_add_pcm_runtime: avs_hdaudio 
avs_hdaudio.2: ASoC: binding hdaudioB0D2 link2
[   34.619973]  probing-LINK: substream (null) has no playback, no capture
[   34.620016] avs_hdaudio avs_hdaudio.2: ASoC: can't create pcm (null) :-22
[   34.620196] snd_soc_core:snd_soc_unregister_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Unregistered DAI 'hdaudioB0D2-cpu0'
[   34.620309] snd_soc_core:snd_soc_unregister_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Unregistered DAI 'hdaudioB0D2-cpu1'
[   34.620419] snd_soc_core:snd_soc_unregister_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Unregistered DAI 'hdaudioB0D2-cpu2'
[   34.621254] snd_soc_core:snd_soc_unregister_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Unregistered DAI 'HDMI3-dai'
[   34.621837] snd_soc_core:snd_soc_unregister_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Unregistered DAI 'HDMI2-dai'
[   34.622704] snd_soc_core:snd_soc_unregister_dai: snd_soc_avs 
0000:00:0e.0: ASoC: Unregistered DAI 'HDMI1-dai'
[   34.623620] snd_soc_core:snd_soc_unregister_dai: snd_hda_codec_hdmi 
hdaudioB0D2: ASoC: Unregistered DAI 'HDMI 0'
[   34.623695] snd_soc_core:snd_soc_unregister_dai: snd_hda_codec_hdmi 
hdaudioB0D2: ASoC: Unregistered DAI 'HDMI 1'
[   34.623769] snd_soc_core:snd_soc_unregister_dai: snd_hda_codec_hdmi 
hdaudioB0D2: ASoC: Unregistered DAI 'HDMI 2'
[   34.624779] snd_hda_core:snd_hdac_display_power: snd_soc_avs 
0000:00:0e.0: display power disable
[   34.628057] avs_hdaudio: probe of avs_hdaudio.2 failed with error -22
Kuninori Morimoto May 22, 2023, 4:35 a.m. UTC | #3
Hi Amadeusz

Thank you for testing

> I put the patchset to test and it fails to enumerate devices on our 
> platforms.
> 
> Bisect leads me to this patch, here is dmesg fragment:
(snip)
> [   34.617601] avs_hdaudio avs_hdaudio.2: ASoC: Parent card not yet 
> available, widget card binding deferred
(snip)
> [   34.619973]  probing-LINK: substream (null) has no playback, no capture

Hmm..  I tested it on my many type of connections,
but couldn't reproduce the error...

It seems you got [01/20] patch error = no playback, no capture.
This means has_playback/capture both flags are 0.

It seems you are using soc-topology.
Is it topology specific something ?

But hmm.. ?

static int soc_get_playback_capture(...)
{
	...
(A)	if (dai_link->dynamic || dai_link->no_pcm) {
		...
		if (dai_link->dpcm_playback) {
			...
(B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
				...
			}
			...
		}
		if (dai_link->dpcm_capture) {
			...
(B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
				...
			}
		}
		...
	}
}

It checks CPU (B) when no_pcm (A) on original.
But I think "no_pcm - CPU" is dummy DAI -> above check is no meaning.
After the patch, it checks both CPU/Codec.

I wonder is your Codec which is connected to no_pcm DAI valid ?

Thank you for your help !!

Best regards
---
Kuninori Morimoto
Amadeusz Sławiński May 22, 2023, 9:14 a.m. UTC | #4
On 5/22/2023 6:35 AM, Kuninori Morimoto wrote:
> 
> Hi Amadeusz
> 
> Thank you for testing
> 
>> I put the patchset to test and it fails to enumerate devices on our
>> platforms.
>>
>> Bisect leads me to this patch, here is dmesg fragment:
> (snip)
>> [   34.617601] avs_hdaudio avs_hdaudio.2: ASoC: Parent card not yet
>> available, widget card binding deferred
> (snip)
>> [   34.619973]  probing-LINK: substream (null) has no playback, no capture
> 
> Hmm..  I tested it on my many type of connections,
> but couldn't reproduce the error...
> 
> It seems you got [01/20] patch error = no playback, no capture.
> This means has_playback/capture both flags are 0.
> 
> It seems you are using soc-topology.
> Is it topology specific something ?
> 
> But hmm.. ?
> 
> static int soc_get_playback_capture(...)
> {
> 	...
> (A)	if (dai_link->dynamic || dai_link->no_pcm) {
> 		...
> 		if (dai_link->dpcm_playback) {
> 			...
> (B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> 				...
> 			}
> 			...
> 		}
> 		if (dai_link->dpcm_capture) {
> 			...
> (B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> 				...
> 			}
> 		}
> 		...
> 	}
> }
> 
> It checks CPU (B) when no_pcm (A) on original.
> But I think "no_pcm - CPU" is dummy DAI -> above check is no meaning.
> After the patch, it checks both CPU/Codec.

no_pcm means that we are describing Back End, if you check any file in 
sound/soc/intel/avs/boards, they set link->no_pcm to 1 - those files 
describe card and BE (codec) configuration.
Topology in case of our driver describe Front Ends (what is visible when 
you do "aplay -l"), as well as DSP path. Topology sets link->dynamic to 
1 in soc_tplg_fe_link_create().
Do note that card and topology are loaded separately hence the "card 
binding deferred" message in dmesg above.

> I wonder is your Codec which is connected to no_pcm DAI valid ?
> 

I'm not sure what do you mean, if it is valid? It works fine before this 
patch ;)
Kuninori Morimoto May 22, 2023, 11:49 p.m. UTC | #5
Hi Amadeusz

> > static int soc_get_playback_capture(...)
> > {
> > 	...
> > (A)	if (dai_link->dynamic || dai_link->no_pcm) {
> > 		...
> > 		if (dai_link->dpcm_playback) {
> > 			...
> > (B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> > 				...
> > 			}
> > 			...
> > 		}
> > 		if (dai_link->dpcm_capture) {
> > 			...
> > (B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> > 				...
> > 			}
> > 		}
> > 		...
> > 	}
> > }
> > 
> > It checks CPU (B) when no_pcm (A) on original.
> > But I think "no_pcm - CPU" is dummy DAI -> above check is no meaning.
> > After the patch, it checks both CPU/Codec.
(snip)
> > I wonder is your Codec which is connected to no_pcm DAI valid ?
> 
> I'm not sure what do you mean, if it is valid? It works fine before this 
> patch ;)

Ah, sorry, let me explain detail.

	static int soc_get_playback_capture(...)
	{
		...
(A)		if (dai_link->dynamic || dai_link->no_pcm) {
			int stream;

			if (dai_link->dpcm_playback) {
				stream = SNDRV_PCM_STREAM_PLAYBACK;

(B)				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
(C)					if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
						has_playback = 1;
						break;
					}
				}
			...
	}

Before appling the patch, in DPCM case (A), it checks CPU valid only (B)/(C).
In many case, DPCM is like this

	dynamic			no_pcm
	[CPU/dummy-Codec] - [dummy-CPU/Codec]

I noticed that before the patch, it checks dummy DAI only for no_pcm case.
But after appling the patch, it will check both CPU and Codec
valid (X)/(Y)/(Z).

I think this was changed after patch.
So, my question was what happen for snd_soc_dai_stream_valid() on your Codec.

# I notcied that avs_create_dai_links() is not using dummy CPU on no_pcm case...


	static int soc_get_playback_capture(...)
	{
		...
(X)		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
(Y)			codec_dai = asoc_rtd_to_codec(rtd, i); /* get paired codec */

(Z)			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
(Z)			    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
				has_playback = 1;
(Z)			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
(Z)			    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
				has_capture = 1;
		}
		...
	}

Thank you for your help !!

Best regards
---
Kuninori Morimoto
Amadeusz Sławiński May 24, 2023, 11:21 a.m. UTC | #6
On 5/23/2023 1:49 AM, Kuninori Morimoto wrote:
> 
> Hi Amadeusz
> 
>>> static int soc_get_playback_capture(...)
>>> {
>>> 	...
>>> (A)	if (dai_link->dynamic || dai_link->no_pcm) {
>>> 		...
>>> 		if (dai_link->dpcm_playback) {
>>> 			...
>>> (B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
>>> 				...
>>> 			}
>>> 			...
>>> 		}
>>> 		if (dai_link->dpcm_capture) {
>>> 			...
>>> (B)			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
>>> 				...
>>> 			}
>>> 		}
>>> 		...
>>> 	}
>>> }
>>>
>>> It checks CPU (B) when no_pcm (A) on original.
>>> But I think "no_pcm - CPU" is dummy DAI -> above check is no meaning.
>>> After the patch, it checks both CPU/Codec.
> (snip)
>>> I wonder is your Codec which is connected to no_pcm DAI valid ?
>>
>> I'm not sure what do you mean, if it is valid? It works fine before this
>> patch ;)
> 
> Ah, sorry, let me explain detail.
> 
> 	static int soc_get_playback_capture(...)
> 	{
> 		...
> (A)		if (dai_link->dynamic || dai_link->no_pcm) {
> 			int stream;
> 
> 			if (dai_link->dpcm_playback) {
> 				stream = SNDRV_PCM_STREAM_PLAYBACK;
> 
> (B)				for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> (C)					if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
> 						has_playback = 1;
> 						break;
> 					}
> 				}
> 			...
> 	}
> 
> Before appling the patch, in DPCM case (A), it checks CPU valid only (B)/(C).
> In many case, DPCM is like this
> 
> 	dynamic			no_pcm
> 	[CPU/dummy-Codec] - [dummy-CPU/Codec]
> 
> I noticed that before the patch, it checks dummy DAI only for no_pcm case.
> But after appling the patch, it will check both CPU and Codec
> valid (X)/(Y)/(Z).
> 
> I think this was changed after patch.
> So, my question was what happen for snd_soc_dai_stream_valid() on your Codec.
> 
> # I notcied that avs_create_dai_links() is not using dummy CPU on no_pcm case...
> 
> 
> 	static int soc_get_playback_capture(...)
> 	{
> 		...
> (X)		for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
> (Y)			codec_dai = asoc_rtd_to_codec(rtd, i); /* get paired codec */
> 
> (Z)			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
> (Z)			    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
> 				has_playback = 1;
> (Z)			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
> (Z)			    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
> 				has_capture = 1;
> 		}
> 		...
> 	}
> 
> Thank you for your help !!
> 

Hi,
sorry for small delay, I've debugged the issue. Seems like one less 
critical problem is in ASoC HDA codec, which blocks HDA and HDMI probing 
altogether in our driver, something like this should fix this:

commit ed93e4fbc045b8da7906484a9c88e6b53864949b (HEAD)
Author: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Date:   Wed May 24 20:54:44 2023 +0200

     ASoC: codecs: hda: Fix probe codec definition

     In order to properly bind snd_soc_dai_driver its snd_soc_pcm_stream 
need
     to provide channels_min value, otherwise ASoC framework may think that
     stream is improper.

     Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>

diff --git a/sound/soc/codecs/hda.c b/sound/soc/codecs/hda.c
index d57b043d6bfe..62fd99f530bf 100644
--- a/sound/soc/codecs/hda.c
+++ b/sound/soc/codecs/hda.c
@@ -341,6 +341,8 @@ static const struct snd_soc_dapm_widget 
hda_dapm_widgets[] = {
  static struct snd_soc_dai_driver card_binder_dai = {
         .id = -1,
         .name = "codec-probing-DAI",
+       .capture.channels_min = 1,
+       .playback.channels_min = 1,
  };

  static int hda_hdev_attach(struct hdac_device *hdev)


With the above fixed, there is issue with how HDMI is being initialized 
and I consider it a blocker. So it needs to be fixed first before this 
patchset can be merged. I did simple patch like:

diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 64a944016c78..e84c3e46557e 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -2317,6 +2317,7 @@ static int generic_hdmi_build_pcms(struct 
hda_codec *codec)
                 if (spec->pcm_used >= ARRAY_SIZE(spec->pcm_rec))
                         break;
                 /* other pstr fields are set in open */
+               pstr->channels_min = 1;
         }

         return 0;

and it works for testing purposes, but as commented in code, those 
fields are initialized later (in hdmi_pcm_open()), which apparently in 
case of ASoC binding is too late. Likely those assignments need to be 
moved earlier.

Another thing that should probably be done is some kind of look through 
ASoC codec files to make sure that they all define channels_min 
properly, otherwise there may be more unexpected failures.

Thanks,
Amadeusz
Kuninori Morimoto May 24, 2023, 11:48 p.m. UTC | #7
Hi Amadeusz
Cc Mark

Thank you for debuging/checking.

> > I noticed that before the patch, it checks dummy DAI only for no_pcm case.
> > But after appling the patch, it will check both CPU and Codec
> > valid (X)/(Y)/(Z).
(snip)
> sorry for small delay, I've debugged the issue. Seems like one less 
> critical problem is in ASoC HDA codec, which blocks HDA and HDMI probing 
> altogether in our driver, something like this should fix this:
(snip)
> @@ -341,6 +341,8 @@ static const struct snd_soc_dapm_widget 
> hda_dapm_widgets[] = {
>   static struct snd_soc_dai_driver card_binder_dai = {
>          .id = -1,
>          .name = "codec-probing-DAI",
> +       .capture.channels_min = 1,
> +       .playback.channels_min = 1,
>   };
(snip)
> and it works for testing purposes, but as commented in code, those 
> fields are initialized later (in hdmi_pcm_open()), which apparently in 
> case of ASoC binding is too late. Likely those assignments need to be 
> moved earlier.
> 
> Another thing that should probably be done is some kind of look through 
> ASoC codec files to make sure that they all define channels_min 
> properly, otherwise there may be more unexpected failures.

Hmm...

>From logic point of view, I think we need to check all validation.
But from compatible point of view, we want to skip validation check
for BE Codec...
Especially, quick hack solution (= adding channels_min in many place)
might case other bug I guess.

OK, let's skip BE Codec in v2 for now.

Thank you for your help !!

Best regards
---
Kuninori Morimoto
diff mbox series

Patch

diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index af5d4e1effdf..f47ddf660c57 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -2732,7 +2732,10 @@  static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
 				    int *playback, int *capture)
 {
 	struct snd_soc_dai_link *dai_link = rtd->dai_link;
+	struct snd_soc_dai *codec_dai;
 	struct snd_soc_dai *cpu_dai;
+	int cpu_capture  = SNDRV_PCM_STREAM_CAPTURE;
+	int cpu_playback = SNDRV_PCM_STREAM_PLAYBACK;
 	int tmp_playback = 0;
 	int tmp_capture  = 0;
 	int i;
@@ -2748,61 +2751,27 @@  static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd,
 		return -EINVAL;
 	}
 
-	if (dai_link->dynamic || dai_link->no_pcm) {
-		int stream;
-
-		if (dai_link->dpcm_playback) {
-			stream = SNDRV_PCM_STREAM_PLAYBACK;
+	/* Adapt stream for codec2codec links */
+	if (dai_link->c2c_params) {
+		cpu_capture  = SNDRV_PCM_STREAM_PLAYBACK;
+		cpu_playback = SNDRV_PCM_STREAM_CAPTURE;
+	}
 
-			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
-					tmp_playback = 1;
-					break;
-				}
-			}
-			if (!tmp_playback) {
-				dev_err(rtd->card->dev,
-					"No CPU DAIs support playback for stream %s\n",
-					dai_link->stream_name);
-				return -EINVAL;
-			}
-		}
-		if (dai_link->dpcm_capture) {
-			stream = SNDRV_PCM_STREAM_CAPTURE;
+	/* REMOVE ME */
+	if (dai_link->dpcm_playback && !dai_link->dpcm_capture)
+		dai_link->playback_only = 1;
+	if (!dai_link->dpcm_playback && dai_link->dpcm_capture)
+		dai_link->capture_only = 1;
 
-			for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
-				if (snd_soc_dai_stream_valid(cpu_dai, stream)) {
-					tmp_capture = 1;
-					break;
-				}
-			}
-
-			if (!tmp_capture) {
-				dev_err(rtd->card->dev,
-					"No CPU DAIs support capture for stream %s\n",
-					dai_link->stream_name);
-				return -EINVAL;
-			}
-		}
-	} else {
-		struct snd_soc_dai *codec_dai;
-
-		/* Adapt stream for codec2codec links */
-		int cpu_capture = dai_link->c2c_params ?
-			SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE;
-		int cpu_playback = dai_link->c2c_params ?
-			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-
-		for_each_rtd_codec_dais(rtd, i, codec_dai) {
-			cpu_dai = asoc_rtd_to_cpu(rtd, i);
-
-			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
-			    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
-				tmp_playback = 1;
-			if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
-			    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
-				tmp_capture = 1;
-		}
+	for_each_rtd_cpu_dais(rtd, i, cpu_dai) {
+		codec_dai = asoc_rtd_to_codec(rtd, i); /* get paired codec */
+
+		if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_PLAYBACK) &&
+		    snd_soc_dai_stream_valid(cpu_dai,   cpu_playback))
+			tmp_playback = 1;
+		if (snd_soc_dai_stream_valid(codec_dai, SNDRV_PCM_STREAM_CAPTURE) &&
+		    snd_soc_dai_stream_valid(cpu_dai,   cpu_capture))
+			tmp_capture = 1;
 	}
 
 	if (dai_link->playback_only)