diff mbox series

gpio: don't WARN() on NULL descs if gpiolib is disabled

Message ID 20190708082343.30726-1-brgl@bgdev.pl
State New
Headers show
Series gpio: don't WARN() on NULL descs if gpiolib is disabled | expand

Commit Message

Bartosz Golaszewski July 8, 2019, 8:23 a.m. UTC
From: Bartosz Golaszewski <bgolaszewski@baylibre.com>

If gpiolib is disabled, we use the inline stubs from gpio/consumer.h
instead of regular definitions of GPIO API. The stubs for 'optional'
variants of gpiod_get routines return NULL in this case as if the
relevant GPIO wasn't found. This is correct so far.

Calling other (non-gpio_get) stubs from this header triggers a warning
because the GPIO descriptor couldn't have been requested. The warning
however is unconditional (WARN_ON(1)) and is emitted even if the passed
descriptor pointer is NULL.

We don't want to force the users of 'optional' gpio_get to check the
returned pointer before calling e.g. gpiod_set_value() so let's only
WARN on non-NULL descriptors.

Reported-by: Claus H. Stovgaard <cst@phaseone.com>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
---
 include/linux/gpio/consumer.h | 64 +++++++++++++++++------------------
 1 file changed, 32 insertions(+), 32 deletions(-)

Comments

Claus H. Stovgaard July 8, 2019, 10:18 a.m. UTC | #1
On Mon, 2019-07-08 at 10:23 +0200, Bartosz Golaszewski wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> 
> If gpiolib is disabled, we use the inline stubs from gpio/consumer.h
> instead of regular definitions of GPIO API. The stubs for 'optional'
> variants of gpiod_get routines return NULL in this case as if the
> relevant GPIO wasn't found. This is correct so far.
> 
> Calling other (non-gpio_get) stubs from this header triggers a
> warning
> because the GPIO descriptor couldn't have been requested. The warning
> however is unconditional (WARN_ON(1)) and is emitted even if the
> passed
> descriptor pointer is NULL.
> 
> We don't want to force the users of 'optional' gpio_get to check the
> returned pointer before calling e.g. gpiod_set_value() so let's only
> WARN on non-NULL descriptors.
> 
> Reported-by: Claus H. Stovgaard <cst@phaseone.com>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  include/linux/gpio/consumer.h | 64 +++++++++++++++++--------------
> ----
>  1 file changed, 32 insertions(+), 32 deletions(-)

Have tested it on my setup (ZynqMP with AT24 EEPROM), where it works
great. This have removed the warnings in the log regarding settting
wp_gpio for AT24.

Thanks
Claus
Linus Walleij July 9, 2019, 1:30 p.m. UTC | #2
Hi Bartosz,

On Mon, Jul 8, 2019 at 10:25 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:

> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> If gpiolib is disabled, we use the inline stubs from gpio/consumer.h
> instead of regular definitions of GPIO API. The stubs for 'optional'
> variants of gpiod_get routines return NULL in this case as if the
> relevant GPIO wasn't found. This is correct so far.
>
> Calling other (non-gpio_get) stubs from this header triggers a warning
> because the GPIO descriptor couldn't have been requested. The warning
> however is unconditional (WARN_ON(1)) and is emitted even if the passed
> descriptor pointer is NULL.
>
> We don't want to force the users of 'optional' gpio_get to check the
> returned pointer before calling e.g. gpiod_set_value() so let's only
> WARN on non-NULL descriptors.
>
> Reported-by: Claus H. Stovgaard <cst@phaseone.com>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

I remember I had this discussion in the past, and I made a large
refactoring to make it possible for drivers that need gpiod_*
calls to simply do:

select GPIOLIB

in Kconfig.

This should solve also this problem I think.

However I do realize that there may be situations where people
simply want to make GPIO support entirely optional without
having to e.g. create custom stubs and encapsulate things
inside if IS_ENABLED(CONFIG_GPIOLIB).

I was thinking something like this in the stubs:

gpiod_get[_index]() {
    return POISON;
}

gpiod_get[_index]_optional() {
   return NULL;
}

This way all gpiod_get() and optional calls are properly
handled and the semantic that only _optional calls
can return NULL is preserved. (Your patch would
violate this.)

Then other stubs can do:

gpiod_set_value() {
  WARN_ON(desc);
}

As in your patch, and all will be smooth provided the
_optional calls have been used to obtain the desc.

Yours,
Linus Walleij
Bartosz Golaszewski July 9, 2019, 2:20 p.m. UTC | #3
wt., 9 lip 2019 o 15:30 Linus Walleij <linus.walleij@linaro.org> napisał(a):
>
> Hi Bartosz,
>
> On Mon, Jul 8, 2019 at 10:25 AM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
>
> > From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> >
> > If gpiolib is disabled, we use the inline stubs from gpio/consumer.h
> > instead of regular definitions of GPIO API. The stubs for 'optional'
> > variants of gpiod_get routines return NULL in this case as if the
> > relevant GPIO wasn't found. This is correct so far.
> >
> > Calling other (non-gpio_get) stubs from this header triggers a warning
> > because the GPIO descriptor couldn't have been requested. The warning
> > however is unconditional (WARN_ON(1)) and is emitted even if the passed
> > descriptor pointer is NULL.
> >
> > We don't want to force the users of 'optional' gpio_get to check the
> > returned pointer before calling e.g. gpiod_set_value() so let's only
> > WARN on non-NULL descriptors.
> >
> > Reported-by: Claus H. Stovgaard <cst@phaseone.com>
> > Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> I remember I had this discussion in the past, and I made a large
> refactoring to make it possible for drivers that need gpiod_*
> calls to simply do:
>
> select GPIOLIB
>
> in Kconfig.
>
> This should solve also this problem I think.
>
> However I do realize that there may be situations where people
> simply want to make GPIO support entirely optional without
> having to e.g. create custom stubs and encapsulate things
> inside if IS_ENABLED(CONFIG_GPIOLIB).
>

In this case the board doesn't provide any GPIO controller at all so
there's simply no need to select GPIOLIB - it would only add bloat.

> I was thinking something like this in the stubs:
>
> gpiod_get[_index]() {
>     return POISON;
> }
>
> gpiod_get[_index]_optional() {
>    return NULL;
> }

This is already being done.

>
> This way all gpiod_get() and optional calls are properly
> handled and the semantic that only _optional calls
> can return NULL is preserved. (Your patch would
> violate this.)
>

Maybe I'm missing something, but I don't quite see how my patch
violates this behavior. :(

> Then other stubs can do:
>
> gpiod_set_value() {
>   WARN_ON(desc);
> }
>
> As in your patch, and all will be smooth provided the
> _optional calls have been used to obtain the desc.
>
> Yours,
> Linus Walleij

Bart
Enrico Weigelt, metux IT consult July 10, 2019, 1:09 p.m. UTC | #4
On 09.07.19 15:30, Linus Walleij wrote:

Hi,

> I remember I had this discussion in the past, and I made a large> refactoring to make it possible for drivers that need gpiod_*> calls
to simply do:> > select GPIOLIB> > in Kconfig.
Would that allow enabling gpio consumers or drivers selectable w/o
having the gpio subsystem enabled first ?

--mtx
Claus H. Stovgaard July 10, 2019, 8:02 p.m. UTC | #5
Hi Linus

On tir, 2019-07-09 at 15:30 +0200, Linus Walleij wrote:
> 
> I remember I had this discussion in the past, and I made a large
> refactoring to make it possible for drivers that need gpiod_*
> calls to simply do:
> 
> select GPIOLIB
> 
> in Kconfig.
> 
> This should solve also this problem I think.
> 
> However I do realize that there may be situations where people
> simply want to make GPIO support entirely optional without
> having to e.g. create custom stubs and encapsulate things
> inside if IS_ENABLED(CONFIG_GPIOLIB).

You properly saw the email in linux-i2c, but will just it for
completeness.
https://marc.info/?l=linux-i2c&m=156257442124566&w=2

The background for getting the warning, was upgrading a system on
Xilinx ZynqMP SoC from 4.14 to 4.19. As part of this upgrade wp (write
protect) has been introduced in the at24 driver, resulting in the
warning from comsumer.h as I don't have enabled GPIOLIB.

Regards
Claus
Linus Walleij July 16, 2019, 9:46 p.m. UTC | #6
On Tue, Jul 9, 2019 at 4:20 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> wt., 9 lip 2019 o 15:30 Linus Walleij <linus.walleij@linaro.org> napisał(a):

> > I was thinking something like this in the stubs:
> >
> > gpiod_get[_index]() {
> >     return POISON;
> > }
> >
> > gpiod_get[_index]_optional() {
> >    return NULL;
> > }
>
> This is already being done.

Ah it is.

> > This way all gpiod_get() and optional calls are properly
> > handled and the semantic that only _optional calls
> > can return NULL is preserved. (Your patch would
> > violate this.)
> >
>
> Maybe I'm missing something, but I don't quite see how my patch
> violates this behavior. :(

I missed that we actually do pass a poison from the strict
*get functions, mea culpa.

Let's apply this, will you send me a pull request or shall I
just try to apply it?

Yours,
Linus Walleij
Bartosz Golaszewski July 20, 2019, 6:03 p.m. UTC | #7
wt., 16 lip 2019 o 23:46 Linus Walleij <linus.walleij@linaro.org> napisał(a):
>
> On Tue, Jul 9, 2019 at 4:20 PM Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> > wt., 9 lip 2019 o 15:30 Linus Walleij <linus.walleij@linaro.org> napisał(a):
>
> > > I was thinking something like this in the stubs:
> > >
> > > gpiod_get[_index]() {
> > >     return POISON;
> > > }
> > >
> > > gpiod_get[_index]_optional() {
> > >    return NULL;
> > > }
> >
> > This is already being done.
>
> Ah it is.
>
> > > This way all gpiod_get() and optional calls are properly
> > > handled and the semantic that only _optional calls
> > > can return NULL is preserved. (Your patch would
> > > violate this.)
> > >
> >
> > Maybe I'm missing something, but I don't quite see how my patch
> > violates this behavior. :(
>
> I missed that we actually do pass a poison from the strict
> *get functions, mea culpa.
>
> Let's apply this, will you send me a pull request or shall I
> just try to apply it?
>
> Yours,
> Linus Walleij

I'll apply it to my local tree and send it for v5.3-rc2.

Bart
Linus Walleij July 20, 2019, 7:44 p.m. UTC | #8
On Sat, Jul 20, 2019 at 8:03 PM Bartosz Golaszewski
<bgolaszewski@baylibre.com> wrote:

> I'll apply it to my local tree and send it for v5.3-rc2.

OK! Do you see it as bug fix so it should go in the rcs?

It pretty much needs to be a regression to go in there,
because this stub stuff blew up in my face before :/

Thanks,
Linus
Bartosz Golaszewski July 22, 2019, 6:14 a.m. UTC | #9
sob., 20 lip 2019 o 21:45 Linus Walleij <linus.walleij@linaro.org> napisał(a):
>
> On Sat, Jul 20, 2019 at 8:03 PM Bartosz Golaszewski
> <bgolaszewski@baylibre.com> wrote:
>
> > I'll apply it to my local tree and send it for v5.3-rc2.
>
> OK! Do you see it as bug fix so it should go in the rcs?
>
> It pretty much needs to be a regression to go in there,
> because this stub stuff blew up in my face before :/
>
> Thanks,
> Linus

It causes a warning every time someone writes to an at24 EEPROM
without GPIOLIB selected. To me it sounds like a bug that should go
into stable. Let me know if I'm wrong in thinking that, then I'll send
it for v5.4.

Bart
diff mbox series

Patch

diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 9ddcf50a3c59..a7f08fb0f865 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -247,7 +247,7 @@  static inline void gpiod_put(struct gpio_desc *desc)
 	might_sleep();
 
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 
 static inline void devm_gpiod_unhinge(struct device *dev,
@@ -256,7 +256,7 @@  static inline void devm_gpiod_unhinge(struct device *dev,
 	might_sleep();
 
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 
 static inline void gpiod_put_array(struct gpio_descs *descs)
@@ -264,7 +264,7 @@  static inline void gpiod_put_array(struct gpio_descs *descs)
 	might_sleep();
 
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(descs);
 }
 
 static inline struct gpio_desc *__must_check
@@ -317,7 +317,7 @@  static inline void devm_gpiod_put(struct device *dev, struct gpio_desc *desc)
 	might_sleep();
 
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 
 static inline void devm_gpiod_put_array(struct device *dev,
@@ -326,32 +326,32 @@  static inline void devm_gpiod_put_array(struct device *dev,
 	might_sleep();
 
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(descs);
 }
 
 
 static inline int gpiod_get_direction(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -ENOSYS;
 }
 static inline int gpiod_direction_input(struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -ENOSYS;
 }
 static inline int gpiod_direction_output(struct gpio_desc *desc, int value)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -ENOSYS;
 }
 static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -ENOSYS;
 }
 
@@ -359,7 +359,7 @@  static inline int gpiod_direction_output_raw(struct gpio_desc *desc, int value)
 static inline int gpiod_get_value(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return 0;
 }
 static inline int gpiod_get_array_value(unsigned int array_size,
@@ -368,13 +368,13 @@  static inline int gpiod_get_array_value(unsigned int array_size,
 					unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 static inline void gpiod_set_value(struct gpio_desc *desc, int value)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 static inline int gpiod_set_array_value(unsigned int array_size,
 					struct gpio_desc **desc_array,
@@ -382,13 +382,13 @@  static inline int gpiod_set_array_value(unsigned int array_size,
 					unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 static inline int gpiod_get_raw_value(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return 0;
 }
 static inline int gpiod_get_raw_array_value(unsigned int array_size,
@@ -397,13 +397,13 @@  static inline int gpiod_get_raw_array_value(unsigned int array_size,
 					    unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 static inline void gpiod_set_raw_value(struct gpio_desc *desc, int value)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 static inline int gpiod_set_raw_array_value(unsigned int array_size,
 					    struct gpio_desc **desc_array,
@@ -411,14 +411,14 @@  static inline int gpiod_set_raw_array_value(unsigned int array_size,
 					    unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 
 static inline int gpiod_get_value_cansleep(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return 0;
 }
 static inline int gpiod_get_array_value_cansleep(unsigned int array_size,
@@ -427,13 +427,13 @@  static inline int gpiod_get_array_value_cansleep(unsigned int array_size,
 				     unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 static inline void gpiod_set_value_cansleep(struct gpio_desc *desc, int value)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 static inline int gpiod_set_array_value_cansleep(unsigned int array_size,
 					    struct gpio_desc **desc_array,
@@ -441,13 +441,13 @@  static inline int gpiod_set_array_value_cansleep(unsigned int array_size,
 					    unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 static inline int gpiod_get_raw_value_cansleep(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return 0;
 }
 static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
@@ -456,14 +456,14 @@  static inline int gpiod_get_raw_array_value_cansleep(unsigned int array_size,
 					       unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 static inline void gpiod_set_raw_value_cansleep(struct gpio_desc *desc,
 						int value)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 }
 static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
 						struct gpio_desc **desc_array,
@@ -471,41 +471,41 @@  static inline int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
 						unsigned long *value_bitmap)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc_array);
 	return 0;
 }
 
 static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -ENOSYS;
 }
 
 static inline int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -ENOSYS;
 }
 
 static inline int gpiod_is_active_low(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return 0;
 }
 static inline int gpiod_cansleep(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return 0;
 }
 
 static inline int gpiod_to_irq(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -EINVAL;
 }
 
@@ -513,7 +513,7 @@  static inline int gpiod_set_consumer_name(struct gpio_desc *desc,
 					  const char *name)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -EINVAL;
 }
 
@@ -525,7 +525,7 @@  static inline struct gpio_desc *gpio_to_desc(unsigned gpio)
 static inline int desc_to_gpio(const struct gpio_desc *desc)
 {
 	/* GPIO can never have been requested */
-	WARN_ON(1);
+	WARN_ON(desc);
 	return -EINVAL;
 }