gpio: Allow per-parent interrupt data
authorMarc Zyngier <maz@kernel.org>
Tue, 26 Oct 2021 17:58:11 +0000 (18:58 +0100)
committerLinus Walleij <linus.walleij@linaro.org>
Tue, 26 Oct 2021 22:16:00 +0000 (00:16 +0200)
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>
Link: https://lore.kernel.org/r/20211026175815.52703-2-joey.gouly@arm.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/gpio/gpiolib.c
include/linux/gpio/driver.h

index d1b9b72..abfbf54 100644 (file)
@@ -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
index a0f9901..a673a35 100644 (file)
@@ -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:
@@ -204,6 +211,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
         * a particular driver wants to clear IRQ related registers