diff mbox series

[v3,1/5] gpio: Allow per-parent interrupt data

Message ID 20211016141839.45460-2-joey.gouly@arm.com
State New
Headers show
Series pinctrl/GPIO driver for Apple SoCs | expand

Commit Message

Joey Gouly Oct. 16, 2021, 2:18 p.m. UTC
From: Marc Zyngier <maz@kernel.org>

The core gpiolib code is able to deal with multiple interrupt parents
for a single gpio irqchip. It however only allows a single piece
of data to be conveyed to all flow handlers (either the gpio_chip
or some other, driver-specific data).

This means that drivers have to go through some interesting dance
to find the correct context, something that isn't great in interrupt
context (see aebdc8abc9db86e2bd33070fc2f961012fff74b4 for a prime
example).

Instead, offer an optional way for a pinctrl/gpio driver to provide
an array of pointers which gets used to provide the correct context
to the flow handler.

Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Joey Gouly <joey.gouly@arm.com>
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/gpio/gpiolib.c      |  9 +++++++--
 include/linux/gpio/driver.h | 19 +++++++++++++++++--
 2 files changed, 24 insertions(+), 4 deletions(-)

Comments

Linus Walleij Oct. 16, 2021, 10:37 p.m. UTC | #1
Top-posting because I need a nod from Bartosz that I can
merge this patch with the rest in the pinctrl tree.

Bartosz: I can also offer this one patch in an immutable branch
as well so you can pull it in as well.

Yours,
Linus Walleij

On Sat, Oct 16, 2021 at 4:19 PM Joey Gouly <joey.gouly@arm.com> wrote:

> From: Marc Zyngier <maz@kernel.org>
>
> The core gpiolib code is able to deal with multiple interrupt parents
> for a single gpio irqchip. It however only allows a single piece
> of data to be conveyed to all flow handlers (either the gpio_chip
> or some other, driver-specific data).
>
> This means that drivers have to go through some interesting dance
> to find the correct context, something that isn't great in interrupt
> context (see aebdc8abc9db86e2bd33070fc2f961012fff74b4 for a prime
> example).
>
> Instead, offer an optional way for a pinctrl/gpio driver to provide
> an array of pointers which gets used to provide the correct context
> to the flow handler.
>
> Signed-off-by: Marc Zyngier <maz@kernel.org>
> Signed-off-by: Joey Gouly <joey.gouly@arm.com>
> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
> ---
>  drivers/gpio/gpiolib.c      |  9 +++++++--
>  include/linux/gpio/driver.h | 19 +++++++++++++++++--
>  2 files changed, 24 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> index d1b9b721218f..abfbf546d159 100644
> --- a/drivers/gpio/gpiolib.c
> +++ b/drivers/gpio/gpiolib.c
> @@ -1534,9 +1534,14 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
>         }
>
>         if (gc->irq.parent_handler) {
> -               void *data = gc->irq.parent_handler_data ?: gc;
> -
>                 for (i = 0; i < gc->irq.num_parents; i++) {
> +                       void *data;
> +
> +                       if (gc->irq.per_parent_data)
> +                               data = gc->irq.parent_handler_data_array[i];
> +                       else
> +                               data = gc->irq.parent_handler_data ?: gc;
> +
>                         /*
>                          * The parent IRQ chip is already using the chip_data
>                          * for this IRQ chip, so our callbacks simply use the
> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> index a0f9901dcae6..a673a359e20b 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -168,11 +168,18 @@ struct gpio_irq_chip {
>
>         /**
>          * @parent_handler_data:
> +        * @parent_handler_data_array:
>          *
>          * Data associated, and passed to, the handler for the parent
> -        * interrupt.
> +        * interrupt. Can either be a single pointer if @per_parent_data
> +        * is false, or an array of @num_parents pointers otherwise.  If
> +        * @per_parent_data is true, @parent_handler_data_array cannot be
> +        * NULL.
>          */
> -       void *parent_handler_data;
> +       union {
> +               void *parent_handler_data;
> +               void **parent_handler_data_array;
> +       };
>
>         /**
>          * @num_parents:
> @@ -203,6 +210,14 @@ struct gpio_irq_chip {
>          */
>         bool threaded;
>
> +       /**
> +        * @per_parent_data:
> +        *
> +        * True if parent_handler_data_array describes a @num_parents
> +        * sized array to be used as parent data.
> +        */
> +       bool per_parent_data;
> +
>         /**
>          * @init_hw: optional routine to initialize hardware before
>          * an IRQ chip will be added. This is quite useful when
> --
> 2.17.1
>
Bartosz Golaszewski Nov. 4, 2021, 3:30 p.m. UTC | #2
On Sun, Oct 17, 2021 at 12:37 AM Linus Walleij <linus.walleij@linaro.org> wrote:
>
> Top-posting because I need a nod from Bartosz that I can
> merge this patch with the rest in the pinctrl tree.
>
> Bartosz: I can also offer this one patch in an immutable branch
> as well so you can pull it in as well.
>
> Yours,
> Linus Walleij

Hey! Sorry, didn't see it. Yes please take it.

Acked-by: Bartosz Golaszewski <brgl@bgdev.pl>
diff mbox series

Patch

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d1b9b721218f..abfbf546d159 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1534,9 +1534,14 @@  static int gpiochip_add_irqchip(struct gpio_chip *gc,
 	}
 
 	if (gc->irq.parent_handler) {
-		void *data = gc->irq.parent_handler_data ?: gc;
-
 		for (i = 0; i < gc->irq.num_parents; i++) {
+			void *data;
+
+			if (gc->irq.per_parent_data)
+				data = gc->irq.parent_handler_data_array[i];
+			else
+				data = gc->irq.parent_handler_data ?: gc;
+
 			/*
 			 * The parent IRQ chip is already using the chip_data
 			 * for this IRQ chip, so our callbacks simply use the
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index a0f9901dcae6..a673a359e20b 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -168,11 +168,18 @@  struct gpio_irq_chip {
 
 	/**
 	 * @parent_handler_data:
+	 * @parent_handler_data_array:
 	 *
 	 * Data associated, and passed to, the handler for the parent
-	 * interrupt.
+	 * interrupt. Can either be a single pointer if @per_parent_data
+	 * is false, or an array of @num_parents pointers otherwise.  If
+	 * @per_parent_data is true, @parent_handler_data_array cannot be
+	 * NULL.
 	 */
-	void *parent_handler_data;
+	union {
+		void *parent_handler_data;
+		void **parent_handler_data_array;
+	};
 
 	/**
 	 * @num_parents:
@@ -203,6 +210,14 @@  struct gpio_irq_chip {
 	 */
 	bool threaded;
 
+	/**
+	 * @per_parent_data:
+	 *
+	 * True if parent_handler_data_array describes a @num_parents
+	 * sized array to be used as parent data.
+	 */
+	bool per_parent_data;
+
 	/**
 	 * @init_hw: optional routine to initialize hardware before
 	 * an IRQ chip will be added. This is quite useful when