diff mbox series

[v1,06/10] ASoC: loongson: Fix codec detection failure on FDT systems

Message ID f9111564acc6c9ac011318a7eb3c6843ea0529ce.1725518229.git.zhoubinbin@loongson.cn (mailing list archive)
State Superseded
Headers show
Series ASoC: Some issues about loongson i2s | expand

Commit Message

Binbin Zhou Sept. 5, 2024, 7:02 a.m. UTC
When the Codec is compiled into a module, we can't use
snd_soc_of_get_dlc() to get the codec dai_name, use
snd_soc_get_dai_name() instead.

Also, for the cpu dailink, its dai_name is already defined as
"loongson-i2s", so just get the corresponding of_node attribute here.

Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 sound/soc/loongson/loongson_card.c | 89 +++++++++++++++++++++---------
 1 file changed, 63 insertions(+), 26 deletions(-)

Comments

Krzysztof Kozlowski Sept. 6, 2024, 10:28 a.m. UTC | #1
On Thu, Sep 05, 2024 at 03:02:55PM +0800, Binbin Zhou wrote:
> When the Codec is compiled into a module, we can't use
> snd_soc_of_get_dlc() to get the codec dai_name, use
> snd_soc_get_dai_name() instead.
> 
> Also, for the cpu dailink, its dai_name is already defined as
> "loongson-i2s", so just get the corresponding of_node attribute here.
> 
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  sound/soc/loongson/loongson_card.c | 89 +++++++++++++++++++++---------
>  1 file changed, 63 insertions(+), 26 deletions(-)
> 
> diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
> index a25287efdd5c..d45a3e77cb90 100644
> --- a/sound/soc/loongson/loongson_card.c
> +++ b/sound/soc/loongson/loongson_card.c
> @@ -119,44 +119,81 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
>  	return 0;
>  }
>  
> -static int loongson_card_parse_of(struct loongson_card_data *data)
> +static int loongson_parse_cpu(struct device *dev, struct device_node **dai_node)
>  {
> -	struct snd_soc_card *card = &data->snd_card;
> -	struct device_node *cpu, *codec;
> -	struct device *dev = card->dev;
> -	int ret, i;
> +	struct device_node *cpu;
> +	int ret = 0;
>  
>  	cpu = of_get_child_by_name(dev->of_node, "cpu");
> -	if (!cpu) {
> -		dev_err(dev, "platform property missing or invalid\n");
> +	if (!cpu)
>  		return -EINVAL;
> -	}
> +
> +	*dai_node = of_parse_phandle(cpu, "sound-dai", 0);
> +	if (!*dai_node)
> +		ret = -EINVAL;
> +
> +	of_node_put(cpu);

This goes just after of_parse_phandle, which simplifies your code.

> +	return ret;
> +}
> +
> +static int loongson_parse_codec(struct device *dev, struct device_node **dai_node,
> +				const char **dai_name)
> +{
> +	struct of_phandle_args args;
> +	struct device_node *codec;
> +	int ret = 0;
>  
>  	codec = of_get_child_by_name(dev->of_node, "codec");
> -	if (!codec) {
> -		dev_err(dev, "audio-codec property missing or invalid\n");
> +	if (!codec)

Hm? So you exit here and then caller does of_node_put on stack value.
This is buggy.

> +		return -EINVAL;
> +
> +	ret = of_parse_phandle_with_args(codec, "sound-dai", "#sound-dai-cells", 0, &args);
> +	if (ret)
> +		goto free_codec;
> +
> +	ret = snd_soc_get_dai_name(&args, dai_name);
> +	if (ret)

Your error paths should clean here. Each function is responsible to
clean up after itself in case of errors, not rely on caller.

> +		goto free_codec;
> +
> +	*dai_node = of_parse_phandle(codec, "sound-dai", 0);
> +	if (!*dai_node)
>  		ret = -EINVAL;
> -		goto free_cpu;
> +
> +free_codec:

You are not freeing any resources here (at least not directly). You are
dropping reference. Use matching label name. free is associated with
kalloc()..


> +	of_node_put(codec);
> +	return ret;
> +}
> +
> +static int loongson_card_parse_of(struct loongson_card_data *data)
> +{
> +	struct device_node *codec_dai_node, *cpu_dai_node;
> +	struct snd_soc_card *card = &data->snd_card;
> +	struct device *dev = card->dev;
> +	const char *codec_dai_name;
> +	int ret = 0, i;
> +
> +	ret = loongson_parse_cpu(dev, &cpu_dai_node);
> +	if (ret) {
> +		dev_err(dev, "cpu property missing or invalid.\n");
> +		goto out;
> +	}
> +
> +	ret = loongson_parse_codec(dev, &codec_dai_node, &codec_dai_name);
> +	if (ret) {
> +		dev_err(dev, "audio-codec property missing or invalid.\n");
> +		goto out;
>  	}
>  
>  	for (i = 0; i < card->num_links; i++) {
> -		ret = snd_soc_of_get_dlc(cpu, NULL, loongson_dai_links[i].cpus, 0);
> -		if (ret) {
> -			dev_err(dev, "getting cpu dlc error (%d)\n", ret);
> -			goto free_codec;
> -		}
> -
> -		ret = snd_soc_of_get_dlc(codec, NULL, loongson_dai_links[i].codecs, 0);
> -		if (ret) {
> -			dev_err(dev, "getting codec dlc error (%d)\n", ret);
> -			goto free_codec;
> -		}
> +		loongson_dai_links[i].platforms->of_node = cpu_dai_node;
> +		loongson_dai_links[i].cpus->of_node = cpu_dai_node;
> +		loongson_dai_links[i].codecs->of_node = codec_dai_node;
> +		loongson_dai_links[i].codecs->dai_name = codec_dai_name;
>  	}
>  
> -free_codec:
> -	of_node_put(codec);
> -free_cpu:
> -	of_node_put(cpu);
> +out:
> +	of_node_put(codec_dai_node);

Yeah, so here we see drop of reference from stack-based pointer...

Best regards,
Krzysztof
Binbin Zhou Sept. 9, 2024, 7:51 a.m. UTC | #2
Hi Krzysztof:

Thanks for your detailed review.

On Fri, Sep 6, 2024 at 4:29 PM Krzysztof Kozlowski <krzk@kernel.org> wrote:
>
> On Thu, Sep 05, 2024 at 03:02:55PM +0800, Binbin Zhou wrote:
> > When the Codec is compiled into a module, we can't use
> > snd_soc_of_get_dlc() to get the codec dai_name, use
> > snd_soc_get_dai_name() instead.
> >
> > Also, for the cpu dailink, its dai_name is already defined as
> > "loongson-i2s", so just get the corresponding of_node attribute here.
> >
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> >  sound/soc/loongson/loongson_card.c | 89 +++++++++++++++++++++---------
> >  1 file changed, 63 insertions(+), 26 deletions(-)
> >
> > diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
> > index a25287efdd5c..d45a3e77cb90 100644
> > --- a/sound/soc/loongson/loongson_card.c
> > +++ b/sound/soc/loongson/loongson_card.c
> > @@ -119,44 +119,81 @@ static int loongson_card_parse_acpi(struct loongson_card_data *data)
> >       return 0;
> >  }
> >
> > -static int loongson_card_parse_of(struct loongson_card_data *data)
> > +static int loongson_parse_cpu(struct device *dev, struct device_node **dai_node)
> >  {
> > -     struct snd_soc_card *card = &data->snd_card;
> > -     struct device_node *cpu, *codec;
> > -     struct device *dev = card->dev;
> > -     int ret, i;
> > +     struct device_node *cpu;
> > +     int ret = 0;
> >
> >       cpu = of_get_child_by_name(dev->of_node, "cpu");
> > -     if (!cpu) {
> > -             dev_err(dev, "platform property missing or invalid\n");
> > +     if (!cpu)
> >               return -EINVAL;
> > -     }
> > +
> > +     *dai_node = of_parse_phandle(cpu, "sound-dai", 0);
> > +     if (!*dai_node)
> > +             ret = -EINVAL;
> > +
> > +     of_node_put(cpu);
>
> This goes just after of_parse_phandle, which simplifies your code.

OK.. the ret param is unnecessary also.
>
> > +     return ret;
> > +}
> > +
> > +static int loongson_parse_codec(struct device *dev, struct device_node **dai_node,
> > +                             const char **dai_name)
> > +{
> > +     struct of_phandle_args args;
> > +     struct device_node *codec;
> > +     int ret = 0;
> >
> >       codec = of_get_child_by_name(dev->of_node, "codec");
> > -     if (!codec) {
> > -             dev_err(dev, "audio-codec property missing or invalid\n");
> > +     if (!codec)
>
> Hm? So you exit here and then caller does of_node_put on stack value.
> This is buggy.

Sorry, I can not get your point, I think there is nothing that should be put.
>
> > +             return -EINVAL;
> > +
> > +     ret = of_parse_phandle_with_args(codec, "sound-dai", "#sound-dai-cells", 0, &args);
> > +     if (ret)
> > +             goto free_codec;
> > +
> > +     ret = snd_soc_get_dai_name(&args, dai_name);
> > +     if (ret)
>
> Your error paths should clean here. Each function is responsible to
> clean up after itself in case of errors, not rely on caller.

Yes, I should of_node_put(args.np); here
>
> > +             goto free_codec;
> > +
> > +     *dai_node = of_parse_phandle(codec, "sound-dai", 0);
> > +     if (!*dai_node)
> >               ret = -EINVAL;
> > -             goto free_cpu;
> > +
> > +free_codec:
>
> You are not freeing any resources here (at least not directly). You are
> dropping reference. Use matching label name. free is associated with
> kalloc()..
>

OK, I will rename the label name as codec_put.

Thanks.
Binbin
>
> > +     of_node_put(codec);
> > +     return ret;
> > +}
> > +
> > +static int loongson_card_parse_of(struct loongson_card_data *data)
> > +{
> > +     struct device_node *codec_dai_node, *cpu_dai_node;
> > +     struct snd_soc_card *card = &data->snd_card;
> > +     struct device *dev = card->dev;
> > +     const char *codec_dai_name;
> > +     int ret = 0, i;
> > +
> > +     ret = loongson_parse_cpu(dev, &cpu_dai_node);
> > +     if (ret) {
> > +             dev_err(dev, "cpu property missing or invalid.\n");
> > +             goto out;
> > +     }
> > +
> > +     ret = loongson_parse_codec(dev, &codec_dai_node, &codec_dai_name);
> > +     if (ret) {
> > +             dev_err(dev, "audio-codec property missing or invalid.\n");
> > +             goto out;
> >       }
> >
> >       for (i = 0; i < card->num_links; i++) {
> > -             ret = snd_soc_of_get_dlc(cpu, NULL, loongson_dai_links[i].cpus, 0);
> > -             if (ret) {
> > -                     dev_err(dev, "getting cpu dlc error (%d)\n", ret);
> > -                     goto free_codec;
> > -             }
> > -
> > -             ret = snd_soc_of_get_dlc(codec, NULL, loongson_dai_links[i].codecs, 0);
> > -             if (ret) {
> > -                     dev_err(dev, "getting codec dlc error (%d)\n", ret);
> > -                     goto free_codec;
> > -             }
> > +             loongson_dai_links[i].platforms->of_node = cpu_dai_node;
> > +             loongson_dai_links[i].cpus->of_node = cpu_dai_node;
> > +             loongson_dai_links[i].codecs->of_node = codec_dai_node;
> > +             loongson_dai_links[i].codecs->dai_name = codec_dai_name;
> >       }
> >
> > -free_codec:
> > -     of_node_put(codec);
> > -free_cpu:
> > -     of_node_put(cpu);
> > +out:
> > +     of_node_put(codec_dai_node);
>
> Yeah, so here we see drop of reference from stack-based pointer...
>
> Best regards,
> Krzysztof
>
Krzysztof Kozlowski Sept. 9, 2024, 7:53 a.m. UTC | #3
On 09/09/2024 09:51, Binbin Zhou wrote:
>>
>>> +     return ret;
>>> +}
>>> +
>>> +static int loongson_parse_codec(struct device *dev, struct device_node **dai_node,
>>> +                             const char **dai_name)
>>> +{
>>> +     struct of_phandle_args args;
>>> +     struct device_node *codec;
>>> +     int ret = 0;
>>>
>>>       codec = of_get_child_by_name(dev->of_node, "codec");
>>> -     if (!codec) {
>>> -             dev_err(dev, "audio-codec property missing or invalid\n");
>>> +     if (!codec)
>>
>> Hm? So you exit here and then caller does of_node_put on stack value.
>> This is buggy.
> 
> Sorry, I can not get your point, I think there is nothing that should be put.

You drop reference from a pointer which is a random stack value.

Best regards,
Krzysztof
diff mbox series

Patch

diff --git a/sound/soc/loongson/loongson_card.c b/sound/soc/loongson/loongson_card.c
index a25287efdd5c..d45a3e77cb90 100644
--- a/sound/soc/loongson/loongson_card.c
+++ b/sound/soc/loongson/loongson_card.c
@@ -119,44 +119,81 @@  static int loongson_card_parse_acpi(struct loongson_card_data *data)
 	return 0;
 }
 
-static int loongson_card_parse_of(struct loongson_card_data *data)
+static int loongson_parse_cpu(struct device *dev, struct device_node **dai_node)
 {
-	struct snd_soc_card *card = &data->snd_card;
-	struct device_node *cpu, *codec;
-	struct device *dev = card->dev;
-	int ret, i;
+	struct device_node *cpu;
+	int ret = 0;
 
 	cpu = of_get_child_by_name(dev->of_node, "cpu");
-	if (!cpu) {
-		dev_err(dev, "platform property missing or invalid\n");
+	if (!cpu)
 		return -EINVAL;
-	}
+
+	*dai_node = of_parse_phandle(cpu, "sound-dai", 0);
+	if (!*dai_node)
+		ret = -EINVAL;
+
+	of_node_put(cpu);
+	return ret;
+}
+
+static int loongson_parse_codec(struct device *dev, struct device_node **dai_node,
+				const char **dai_name)
+{
+	struct of_phandle_args args;
+	struct device_node *codec;
+	int ret = 0;
 
 	codec = of_get_child_by_name(dev->of_node, "codec");
-	if (!codec) {
-		dev_err(dev, "audio-codec property missing or invalid\n");
+	if (!codec)
+		return -EINVAL;
+
+	ret = of_parse_phandle_with_args(codec, "sound-dai", "#sound-dai-cells", 0, &args);
+	if (ret)
+		goto free_codec;
+
+	ret = snd_soc_get_dai_name(&args, dai_name);
+	if (ret)
+		goto free_codec;
+
+	*dai_node = of_parse_phandle(codec, "sound-dai", 0);
+	if (!*dai_node)
 		ret = -EINVAL;
-		goto free_cpu;
+
+free_codec:
+	of_node_put(codec);
+	return ret;
+}
+
+static int loongson_card_parse_of(struct loongson_card_data *data)
+{
+	struct device_node *codec_dai_node, *cpu_dai_node;
+	struct snd_soc_card *card = &data->snd_card;
+	struct device *dev = card->dev;
+	const char *codec_dai_name;
+	int ret = 0, i;
+
+	ret = loongson_parse_cpu(dev, &cpu_dai_node);
+	if (ret) {
+		dev_err(dev, "cpu property missing or invalid.\n");
+		goto out;
+	}
+
+	ret = loongson_parse_codec(dev, &codec_dai_node, &codec_dai_name);
+	if (ret) {
+		dev_err(dev, "audio-codec property missing or invalid.\n");
+		goto out;
 	}
 
 	for (i = 0; i < card->num_links; i++) {
-		ret = snd_soc_of_get_dlc(cpu, NULL, loongson_dai_links[i].cpus, 0);
-		if (ret) {
-			dev_err(dev, "getting cpu dlc error (%d)\n", ret);
-			goto free_codec;
-		}
-
-		ret = snd_soc_of_get_dlc(codec, NULL, loongson_dai_links[i].codecs, 0);
-		if (ret) {
-			dev_err(dev, "getting codec dlc error (%d)\n", ret);
-			goto free_codec;
-		}
+		loongson_dai_links[i].platforms->of_node = cpu_dai_node;
+		loongson_dai_links[i].cpus->of_node = cpu_dai_node;
+		loongson_dai_links[i].codecs->of_node = codec_dai_node;
+		loongson_dai_links[i].codecs->dai_name = codec_dai_name;
 	}
 
-free_codec:
-	of_node_put(codec);
-free_cpu:
-	of_node_put(cpu);
+out:
+	of_node_put(codec_dai_node);
+	of_node_put(cpu_dai_node);
 	return ret;
 }