diff mbox

clk: fix clk-gpio.c with optional clock= DT property

Message ID E1aFJ0A-00086Z-0I@rmk-PC.arm.linux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Russell King Jan. 2, 2016, 10:01 a.m. UTC
When the clock DT property is not given, of_clk_get_parent_count()
returns -ENOENT, which then tries to allocate -2 x 4 bytes of memory,
which of course fails, causing the whole driver to fail to create
the clock.

This causes the SolidRun platforms to fail probing the SDHCI1 interface
which is connected to the WiFi.

Fix this by detecting errno codes, skipping the allocation, and fixing
of_clk_gpio_gate_delayed_register_get() to handle a NULL parent_names
array.

Fixes: 80eeb1f0f757 ("clk: add gpio controlled clock multiplexer")
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
This goes all the way back to 80eeb1f0f757 ("clk: add gpio controlled
clock multiplexer") introduced in June in v4.3-rc2 - which raises the
question why _development_ work in clk is being merged outside of the
merge window.

A rewrite of this patch will be necessary to apply to v4.3 kernels.

This applies on top of v4.4-rc6.

 drivers/clk/clk-gpio.c | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

Comments

Russell King - ARM Linux Feb. 17, 2016, 11:05 p.m. UTC | #1
On Sat, Jan 02, 2016 at 10:01:34AM +0000, Russell King wrote:
> When the clock DT property is not given, of_clk_get_parent_count()
> returns -ENOENT, which then tries to allocate -2 x 4 bytes of memory,
> which of course fails, causing the whole driver to fail to create
> the clock.
> 
> This causes the SolidRun platforms to fail probing the SDHCI1 interface
> which is connected to the WiFi.
> 
> Fix this by detecting errno codes, skipping the allocation, and fixing
> of_clk_gpio_gate_delayed_register_get() to handle a NULL parent_names
> array.
> 
> Fixes: 80eeb1f0f757 ("clk: add gpio controlled clock multiplexer")
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> ---
> This goes all the way back to 80eeb1f0f757 ("clk: add gpio controlled
> clock multiplexer") introduced in June in v4.3-rc2 - which raises the
> question why _development_ work in clk is being merged outside of the
> merge window.
> 
> A rewrite of this patch will be necessary to apply to v4.3 kernels.
> 
> This applies on top of v4.4-rc6.
> 
>  drivers/clk/clk-gpio.c | 23 ++++++++++++++---------
>  1 file changed, 14 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
> index 335322dc403f..05cca9298f44 100644
> --- a/drivers/clk/clk-gpio.c
> +++ b/drivers/clk/clk-gpio.c
> @@ -264,8 +264,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
>  		const char * const *parent_names, u8 num_parents,
>  		unsigned gpio, bool active_low)
>  {
> -	return clk_register_gpio_gate(NULL, name, parent_names[0],
> -			gpio, active_low, 0);
> +	return clk_register_gpio_gate(NULL, name, parent_names ?
> +			parent_names[0] : NULL, gpio, active_low, 0);
>  }
>  
>  static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
> @@ -292,13 +292,18 @@ static void __init of_gpio_clk_setup(struct device_node *node,
>  		return;
>  
>  	num_parents = of_clk_get_parent_count(node);
> -
> -	parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
> -	if (!parent_names)
> -		return;
> -
> -	for (i = 0; i < num_parents; i++)
> -		parent_names[i] = of_clk_get_parent_name(node, i);
> +	if (num_parents > 0) {
> +		parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
> +		if (!parent_names) {
> +			kfree(data);
> +			return;
> +		}
> +
> +		for (i = 0; i < num_parents; i++)
> +			parent_names[i] = of_clk_get_parent_name(node, i);
> +	} else {
> +		parent_names = NULL;
> +	}
>  
>  	data->num_parents = num_parents;
>  	data->parent_names = parent_names;
> -- 
> 2.1.0

Yes, indeed, my patch above which fixed clk-gpio.c as can be seen above
does not have the problem that I'm currently seeing...
Michael Turquette Feb. 18, 2016, 12:07 a.m. UTC | #2
Quoting Russell King - ARM Linux (2016-02-17 15:05:29)
> On Sat, Jan 02, 2016 at 10:01:34AM +0000, Russell King wrote:
> > When the clock DT property is not given, of_clk_get_parent_count()
> > returns -ENOENT, which then tries to allocate -2 x 4 bytes of memory,
> > which of course fails, causing the whole driver to fail to create
> > the clock.
> > 
> > This causes the SolidRun platforms to fail probing the SDHCI1 interface
> > which is connected to the WiFi.
> > 
> > Fix this by detecting errno codes, skipping the allocation, and fixing
> > of_clk_gpio_gate_delayed_register_get() to handle a NULL parent_names
> > array.
> > 
> > Fixes: 80eeb1f0f757 ("clk: add gpio controlled clock multiplexer")
> > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > ---
> > This goes all the way back to 80eeb1f0f757 ("clk: add gpio controlled
> > clock multiplexer") introduced in June in v4.3-rc2 - which raises the
> > question why _development_ work in clk is being merged outside of the
> > merge window.
> > 
> > A rewrite of this patch will be necessary to apply to v4.3 kernels.
> > 
> > This applies on top of v4.4-rc6.
> > 
> >  drivers/clk/clk-gpio.c | 23 ++++++++++++++---------
> >  1 file changed, 14 insertions(+), 9 deletions(-)
> > 
> > diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
> > index 335322dc403f..05cca9298f44 100644
> > --- a/drivers/clk/clk-gpio.c
> > +++ b/drivers/clk/clk-gpio.c
> > @@ -264,8 +264,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
> >               const char * const *parent_names, u8 num_parents,
> >               unsigned gpio, bool active_low)
> >  {
> > -     return clk_register_gpio_gate(NULL, name, parent_names[0],
> > -                     gpio, active_low, 0);
> > +     return clk_register_gpio_gate(NULL, name, parent_names ?
> > +                     parent_names[0] : NULL, gpio, active_low, 0);
> >  }
> >  
> >  static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
> > @@ -292,13 +292,18 @@ static void __init of_gpio_clk_setup(struct device_node *node,
> >               return;
> >  
> >       num_parents = of_clk_get_parent_count(node);
> > -
> > -     parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
> > -     if (!parent_names)
> > -             return;
> > -
> > -     for (i = 0; i < num_parents; i++)
> > -             parent_names[i] = of_clk_get_parent_name(node, i);
> > +     if (num_parents > 0) {
> > +             parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
> > +             if (!parent_names) {
> > +                     kfree(data);
> > +                     return;
> > +             }
> > +
> > +             for (i = 0; i < num_parents; i++)
> > +                     parent_names[i] = of_clk_get_parent_name(node, i);
> > +     } else {
> > +             parent_names = NULL;
> > +     }
> >  
> >       data->num_parents = num_parents;
> >       data->parent_names = parent_names;
> > -- 
> > 2.1.0
> 
> Yes, indeed, my patch above which fixed clk-gpio.c as can be seen above
> does not have the problem that I'm currently seeing...

Hi Russell,

I must be missing something. After merging your patch on top of Brian's,
the code looks like:

        ...
        int i, num_parents;

        num_parents = of_clk_get_parent_count(node);
        if (num_parents < 0)
                return;

        data = kzalloc(sizeof(*data), GFP_KERNEL);
        if (!data)
                return;

        if (num_parents) {
                parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
                if (!parent_names) {
                        kfree(data);
                        return;
                }

                for (i = 0; i < num_parents; i++)
                        parent_names[i] = of_clk_get_parent_name(node, i);
        } else {
                parent_names = NULL;
        }

Brian's if (num_parents < 0) check, followed by the if (num_parent)
check appear equivalent to your original patch. Not sure why I merged it
as if (num_parents) instead of if (num_parents > 0) as your original
patch uses, but thanks to the extra check that predates your patch it
should be equivalent.

Let me know if I've lost the plot.

Regards,
Mike

> 
> -- 
> RMK's Patch system: http://www.arm.linux.org.uk/developer/patches/
> FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
> according to speedtest.net.
Russell King - ARM Linux Feb. 18, 2016, 12:55 a.m. UTC | #3
On Wed, Feb 17, 2016 at 04:07:47PM -0800, Michael Turquette wrote:
> Quoting Russell King - ARM Linux (2016-02-17 15:05:29)
> > On Sat, Jan 02, 2016 at 10:01:34AM +0000, Russell King wrote:
> > > When the clock DT property is not given, of_clk_get_parent_count()
> > > returns -ENOENT, which then tries to allocate -2 x 4 bytes of memory,
> > > which of course fails, causing the whole driver to fail to create
> > > the clock.
> > > 
> > > This causes the SolidRun platforms to fail probing the SDHCI1 interface
> > > which is connected to the WiFi.
> > > 
> > > Fix this by detecting errno codes, skipping the allocation, and fixing
> > > of_clk_gpio_gate_delayed_register_get() to handle a NULL parent_names
> > > array.
> > > 
> > > Fixes: 80eeb1f0f757 ("clk: add gpio controlled clock multiplexer")
> > > Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
> > > ---
> > > This goes all the way back to 80eeb1f0f757 ("clk: add gpio controlled
> > > clock multiplexer") introduced in June in v4.3-rc2 - which raises the
> > > question why _development_ work in clk is being merged outside of the
> > > merge window.
> > > 
> > > A rewrite of this patch will be necessary to apply to v4.3 kernels.
> > > 
> > > This applies on top of v4.4-rc6.
> > > 
> > >  drivers/clk/clk-gpio.c | 23 ++++++++++++++---------
> > >  1 file changed, 14 insertions(+), 9 deletions(-)
> > > 
> > > diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
> > > index 335322dc403f..05cca9298f44 100644
> > > --- a/drivers/clk/clk-gpio.c
> > > +++ b/drivers/clk/clk-gpio.c
> > > @@ -264,8 +264,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
> > >               const char * const *parent_names, u8 num_parents,
> > >               unsigned gpio, bool active_low)
> > >  {
> > > -     return clk_register_gpio_gate(NULL, name, parent_names[0],
> > > -                     gpio, active_low, 0);
> > > +     return clk_register_gpio_gate(NULL, name, parent_names ?
> > > +                     parent_names[0] : NULL, gpio, active_low, 0);
> > >  }
> > >  
> > >  static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
> > > @@ -292,13 +292,18 @@ static void __init of_gpio_clk_setup(struct device_node *node,
> > >               return;
> > >  
> > >       num_parents = of_clk_get_parent_count(node);
> > > -
> > > -     parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
> > > -     if (!parent_names)
> > > -             return;
> > > -
> > > -     for (i = 0; i < num_parents; i++)
> > > -             parent_names[i] = of_clk_get_parent_name(node, i);
> > > +     if (num_parents > 0) {
> > > +             parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
> > > +             if (!parent_names) {
> > > +                     kfree(data);
> > > +                     return;
> > > +             }
> > > +
> > > +             for (i = 0; i < num_parents; i++)
> > > +                     parent_names[i] = of_clk_get_parent_name(node, i);
> > > +     } else {
> > > +             parent_names = NULL;
> > > +     }
> > >  
> > >       data->num_parents = num_parents;
> > >       data->parent_names = parent_names;
> > > -- 
> > > 2.1.0
> > 
> > Yes, indeed, my patch above which fixed clk-gpio.c as can be seen above
> > does not have the problem that I'm currently seeing...
> 
> Hi Russell,
> 
> I must be missing something. After merging your patch on top of Brian's,
> the code looks like:
> 
>         ...
>         int i, num_parents;
> 
>         num_parents = of_clk_get_parent_count(node);
>         if (num_parents < 0)
>                 return;
> 
>         data = kzalloc(sizeof(*data), GFP_KERNEL);
>         if (!data)
>                 return;
> 
>         if (num_parents) {
>                 parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
>                 if (!parent_names) {
>                         kfree(data);
>                         return;
>                 }
> 
>                 for (i = 0; i < num_parents; i++)
>                         parent_names[i] = of_clk_get_parent_name(node, i);
>         } else {
>                 parent_names = NULL;
>         }
> 
> Brian's if (num_parents < 0) check, followed by the if (num_parent)
> check appear equivalent to your original patch. Not sure why I merged it
> as if (num_parents) instead of if (num_parents > 0) as your original
> patch uses, but thanks to the extra check that predates your patch it
> should be equivalent.
> 
> Let me know if I've lost the plot.

You have.  Read the commit log on my patch.  Then look at this code:

         num_parents = of_clk_get_parent_count(node);
         if (num_parents < 0)
                 return;

compared to mine:

         num_parents = of_clk_get_parent_count(node);
         if (num_parents > 0) {
                 parent_names = kcalloc(num_parents, sizeof(char *), ...

It is very much _NOT_ equivalent.

The big pointer here is this:
* My patch works.
* The code you have in mainline does not work.

Therefore, they _can't_ be equivalent - because they have _visibly_
different behaviours.  So, they are different.

The former omits the _entire_ registration of the clock if
of_clk_get_parent_count() returns a negative number.  Thus, no
parent clocks, no clock gets registered.

The whole point behind my patch was to restore the regression
that occurred: the regression being that having no parent clocks
used to be explicitly allowed, and the patch I mentioned in my
commit message broke it.

This is even explained in the very first sentence of my commit
log:

| When the clock DT property is not given, of_clk_get_parent_count()
                                           ^^^^^^^^^^^^^^^^^^^^^^^^^
| returns -ENOENT, which then tries to allocate -2 x 4 bytes of memory,
  ^^^^^^^^^^^^^^^

-ENOENT is a negative number.  Now look at the patch which totally
rejects the clock if of_clk_get_parent_count() returns any negative
number...

I assume, therefore, that you did not *even* read my commit log...
diff mbox

Patch

diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c
index 335322dc403f..05cca9298f44 100644
--- a/drivers/clk/clk-gpio.c
+++ b/drivers/clk/clk-gpio.c
@@ -264,8 +264,8 @@  static struct clk *of_clk_gpio_gate_delayed_register_get(const char *name,
 		const char * const *parent_names, u8 num_parents,
 		unsigned gpio, bool active_low)
 {
-	return clk_register_gpio_gate(NULL, name, parent_names[0],
-			gpio, active_low, 0);
+	return clk_register_gpio_gate(NULL, name, parent_names ?
+			parent_names[0] : NULL, gpio, active_low, 0);
 }
 
 static struct clk *of_clk_gpio_mux_delayed_register_get(const char *name,
@@ -292,13 +292,18 @@  static void __init of_gpio_clk_setup(struct device_node *node,
 		return;
 
 	num_parents = of_clk_get_parent_count(node);
-
-	parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
-	if (!parent_names)
-		return;
-
-	for (i = 0; i < num_parents; i++)
-		parent_names[i] = of_clk_get_parent_name(node, i);
+	if (num_parents > 0) {
+		parent_names = kcalloc(num_parents, sizeof(char *), GFP_KERNEL);
+		if (!parent_names) {
+			kfree(data);
+			return;
+		}
+
+		for (i = 0; i < num_parents; i++)
+			parent_names[i] = of_clk_get_parent_name(node, i);
+	} else {
+		parent_names = NULL;
+	}
 
 	data->num_parents = num_parents;
 	data->parent_names = parent_names;