From: Marc Zyngier maz@kernel.org
[ Upstream commit cfe6807d82e97e81c3209dca9448f091e1448a57 ]
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 Stable-dep-of: 8c00914e5438 ("gpiolib: Fix GPIO chip IRQ initialization restriction") Signed-off-by: Sasha Levin sashal@kernel.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 8c041a8dd9d8f..099fe2e39bd63 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1578,9 +1578,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 11c26ae7b4fa4..65df2ce96f0b1 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