linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/12] gpio: Tight IRQ chip integration
@ 2017-11-02 17:49 Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 01/12] gpio: Introduce struct gpio_irq_chip Thierry Reding
                   ` (13 more replies)
  0 siblings, 14 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

Hi Linus,

here's the latest series of patches that implement the tighter IRQ chip
integration. I've dropped the banked infrastructure for now as per the
discussion with Grygorii.

The first couple of patches are mostly preparatory work in order to
consolidate all IRQ chip related fields in a new structure and create
the base functionality for adding IRQ chips.

After that, I've added the Tegra186 GPIO support patch that makes use of
the new tight integration.

Changes in v6:
- rebased on latest linux-gpio devel branch
- one patch dropped due to rebase

Changes in v5:
- dropped the banked infrastructure patches for now (Grygorii)
- allocate interrupts on demand, rather than upfront (Grygorii)
- split up the first patch further as requested by Grygorii

Not sure what happened in between here. Notes in commit logs indicate
that this is actually version 5, but I can't find the cover letter for
v3 and v4.

Changes in v2:
- rename pins to lines for consistent terminology
- rename gpio_irq_chip_banked_handler() to
  gpio_irq_chip_banked_chained_handler()

Thierry


*** BLURB HERE ***

Thierry Reding (12):
  gpio: Introduce struct gpio_irq_chip
  gpio: Move irqchip into struct gpio_irq_chip
  gpio: Move irqdomain into struct gpio_irq_chip
  gpio: Move irq_handler to struct gpio_irq_chip
  gpio: Move irq_default_type to struct gpio_irq_chip
  gpio: Move irq_chained_parent to struct gpio_irq_chip
  gpio: Move irq_nested into struct gpio_irq_chip
  gpio: Move irq_valid_mask into struct gpio_irq_chip
  gpio: Move lock_key into struct gpio_irq_chip
  gpio: Implement tighter IRQ chip integration
  gpio: Export gpiochip_irq_{map,unmap}()
  gpio: Add Tegra186 support

 Documentation/gpio/driver.txt               |   6 +-
 drivers/bcma/driver_gpio.c                  |   2 +-
 drivers/gpio/Kconfig                        |   9 +
 drivers/gpio/Makefile                       |   1 +
 drivers/gpio/gpio-104-dio-48e.c             |   2 +-
 drivers/gpio/gpio-104-idi-48.c              |   2 +-
 drivers/gpio/gpio-104-idio-16.c             |   2 +-
 drivers/gpio/gpio-adnp.c                    |   2 +-
 drivers/gpio/gpio-altera.c                  |   4 +-
 drivers/gpio/gpio-aspeed.c                  |   6 +-
 drivers/gpio/gpio-ath79.c                   |   2 +-
 drivers/gpio/gpio-crystalcove.c             |   2 +-
 drivers/gpio/gpio-dln2.c                    |   2 +-
 drivers/gpio/gpio-ftgpio010.c               |   2 +-
 drivers/gpio/gpio-ingenic.c                 |   2 +-
 drivers/gpio/gpio-intel-mid.c               |   2 +-
 drivers/gpio/gpio-lynxpoint.c               |   2 +-
 drivers/gpio/gpio-max732x.c                 |   2 +-
 drivers/gpio/gpio-merrifield.c              |   2 +-
 drivers/gpio/gpio-omap.c                    |   2 +-
 drivers/gpio/gpio-pca953x.c                 |   2 +-
 drivers/gpio/gpio-pcf857x.c                 |   2 +-
 drivers/gpio/gpio-pci-idio-16.c             |   2 +-
 drivers/gpio/gpio-pl061.c                   |   2 +-
 drivers/gpio/gpio-rcar.c                    |   2 +-
 drivers/gpio/gpio-reg.c                     |   4 +-
 drivers/gpio/gpio-stmpe.c                   |   6 +-
 drivers/gpio/gpio-tc3589x.c                 |   2 +-
 drivers/gpio/gpio-tegra186.c                | 623 ++++++++++++++++++++++++++++
 drivers/gpio/gpio-vf610.c                   |   2 +-
 drivers/gpio/gpio-wcove.c                   |   2 +-
 drivers/gpio/gpio-ws16c48.c                 |   2 +-
 drivers/gpio/gpio-xgene-sb.c                |   2 +-
 drivers/gpio/gpio-xlp.c                     |   2 +-
 drivers/gpio/gpio-zx.c                      |   2 +-
 drivers/gpio/gpio-zynq.c                    |   2 +-
 drivers/gpio/gpiolib.c                      | 213 ++++++++--
 drivers/pinctrl/bcm/pinctrl-bcm2835.c       |   4 +-
 drivers/pinctrl/bcm/pinctrl-iproc-gpio.c    |   2 +-
 drivers/pinctrl/intel/pinctrl-baytrail.c    |   6 +-
 drivers/pinctrl/intel/pinctrl-cherryview.c  |   6 +-
 drivers/pinctrl/intel/pinctrl-intel.c       |   2 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c |   2 +-
 drivers/pinctrl/nomadik/pinctrl-nomadik.c   |   4 +-
 drivers/pinctrl/pinctrl-amd.c               |   2 +-
 drivers/pinctrl/pinctrl-at91.c              |   2 +-
 drivers/pinctrl/pinctrl-coh901.c            |   2 +-
 drivers/pinctrl/pinctrl-mcp23s08.c          |   2 +-
 drivers/pinctrl/pinctrl-oxnas.c             |   2 +-
 drivers/pinctrl/pinctrl-pic32.c             |   2 +-
 drivers/pinctrl/pinctrl-pistachio.c         |   2 +-
 drivers/pinctrl/pinctrl-st.c                |   2 +-
 drivers/pinctrl/pinctrl-sx150x.c            |   2 +-
 drivers/pinctrl/qcom/pinctrl-msm.c          |   2 +-
 drivers/pinctrl/sirf/pinctrl-atlas7.c       |   2 +-
 drivers/pinctrl/sirf/pinctrl-sirf.c         |   2 +-
 drivers/pinctrl/spear/pinctrl-plgpio.c      |   2 +-
 drivers/platform/x86/intel_int0002_vgpio.c  |   6 +-
 include/linux/gpio/driver.h                 | 154 +++++--
 59 files changed, 1004 insertions(+), 136 deletions(-)
 create mode 100644 drivers/gpio/gpio-tegra186.c

-- 
2.14.1

^ permalink raw reply	[flat|nested] 25+ messages in thread

* [PATCH v6 01/12] gpio: Introduce struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 02/12] gpio: Move irqchip into " Thierry Reding
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

This new structure will be used to group all fields related to interrupt
handling in a GPIO chip. Doing so will properly namespace these fields
and make it easier to distinguish which fields are used for IRQ support.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 include/linux/gpio/driver.h | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index ed04fa2a00a8..36a065521fa0 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -19,6 +19,36 @@ struct module;
 
 #ifdef CONFIG_GPIOLIB
 
+#ifdef CONFIG_GPIOLIB_IRQCHIP
+/**
+ * struct gpio_irq_chip - GPIO interrupt controller
+ */
+struct gpio_irq_chip {
+	/**
+	 * @domain_ops:
+	 *
+	 * Table of interrupt domain operations for this IRQ chip.
+	 */
+	const struct irq_domain_ops *domain_ops;
+
+	/**
+	 * @parent_handler:
+	 *
+	 * The interrupt handler for the GPIO chip's parent interrupts, may be
+	 * NULL if the parent interrupts are nested rather than cascaded.
+	 */
+	irq_flow_handler_t parent_handler;
+
+	/**
+	 * @parent_handler_data:
+	 *
+	 * Data associated, and passed to, the handler for the parent
+	 * interrupt.
+	 */
+	void *parent_handler_data;
+};
+#endif
+
 /**
  * struct gpio_chip - abstract a GPIO controller
  * @label: a functional name for the GPIO device, such as a part
@@ -176,6 +206,14 @@ struct gpio_chip {
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
+
+	/**
+	 * @irq:
+	 *
+	 * Integrates interrupt chip functionality with the GPIO chip. Can be
+	 * used to handle IRQs for most practical cases.
+	 */
+	struct gpio_irq_chip irq;
 #endif
 
 #if defined(CONFIG_OF_GPIO)
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 02/12] gpio: Move irqchip into struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 01/12] gpio: Introduce struct gpio_irq_chip Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 03/12] gpio: Move irqdomain " Thierry Reding
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 14 +++++++-------
 include/linux/gpio/driver.h | 14 ++++++++++++--
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 3827f0767101..d3d0b3134ba3 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1646,7 +1646,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * category than their parents, so it won't report false recursion.
 	 */
 	irq_set_lockdep_class(irq, chip->lock_key);
-	irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
+	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq_handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq_nested)
 		irq_set_nested_thread(irq, 1);
@@ -1739,10 +1739,10 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 		irq_domain_remove(gpiochip->irqdomain);
 	}
 
-	if (gpiochip->irqchip) {
-		gpiochip->irqchip->irq_request_resources = NULL;
-		gpiochip->irqchip->irq_release_resources = NULL;
-		gpiochip->irqchip = NULL;
+	if (gpiochip->irq.chip) {
+		gpiochip->irq.chip->irq_request_resources = NULL;
+		gpiochip->irq.chip->irq_release_resources = NULL;
+		gpiochip->irq.chip = NULL;
 	}
 
 	gpiochip_irqchip_free_valid_mask(gpiochip);
@@ -1817,7 +1817,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 		type = IRQ_TYPE_NONE;
 	}
 
-	gpiochip->irqchip = irqchip;
+	gpiochip->irq.chip = irqchip;
 	gpiochip->irq_handler = handler;
 	gpiochip->irq_default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
@@ -1826,7 +1826,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
 	if (!gpiochip->irqdomain) {
-		gpiochip->irqchip = NULL;
+		gpiochip->irq.chip = NULL;
 		return -EINVAL;
 	}
 
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 36a065521fa0..a79b3b18fadd 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -24,6 +24,13 @@ struct module;
  * struct gpio_irq_chip - GPIO interrupt controller
  */
 struct gpio_irq_chip {
+	/**
+	 * @chip:
+	 *
+	 * GPIO IRQ chip implementation, provided by GPIO driver.
+	 */
+	struct irq_chip *chip;
+
 	/**
 	 * @domain_ops:
 	 *
@@ -47,6 +54,11 @@ struct gpio_irq_chip {
 	 */
 	void *parent_handler_data;
 };
+
+static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
+{
+	return container_of(chip, struct gpio_irq_chip, chip);
+}
 #endif
 
 /**
@@ -112,7 +124,6 @@ struct gpio_irq_chip {
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irqchip: GPIO IRQ chip impl, provided by GPIO driver
  * @irqdomain: Interrupt translation domain; responsible for mapping
  *	between GPIO hwirq number and linux irq number
  * @irq_handler: the irq handler to use (often a predefined irq core function)
@@ -197,7 +208,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	struct irq_chip		*irqchip;
 	struct irq_domain	*irqdomain;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 03/12] gpio: Move irqdomain into struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 01/12] gpio: Introduce struct gpio_irq_chip Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 02/12] gpio: Move irqchip into " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 04/12] gpio: Move irq_handler to " Thierry Reding
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 Documentation/gpio/driver.txt               |  2 +-
 drivers/bcma/driver_gpio.c                  |  2 +-
 drivers/gpio/gpio-104-dio-48e.c             |  2 +-
 drivers/gpio/gpio-104-idi-48.c              |  2 +-
 drivers/gpio/gpio-104-idio-16.c             |  2 +-
 drivers/gpio/gpio-adnp.c                    |  2 +-
 drivers/gpio/gpio-altera.c                  |  4 ++--
 drivers/gpio/gpio-aspeed.c                  |  2 +-
 drivers/gpio/gpio-ath79.c                   |  2 +-
 drivers/gpio/gpio-crystalcove.c             |  2 +-
 drivers/gpio/gpio-dln2.c                    |  2 +-
 drivers/gpio/gpio-ftgpio010.c               |  2 +-
 drivers/gpio/gpio-ingenic.c                 |  2 +-
 drivers/gpio/gpio-intel-mid.c               |  2 +-
 drivers/gpio/gpio-lynxpoint.c               |  2 +-
 drivers/gpio/gpio-max732x.c                 |  2 +-
 drivers/gpio/gpio-merrifield.c              |  2 +-
 drivers/gpio/gpio-omap.c                    |  2 +-
 drivers/gpio/gpio-pca953x.c                 |  2 +-
 drivers/gpio/gpio-pcf857x.c                 |  2 +-
 drivers/gpio/gpio-pci-idio-16.c             |  2 +-
 drivers/gpio/gpio-pl061.c                   |  2 +-
 drivers/gpio/gpio-rcar.c                    |  2 +-
 drivers/gpio/gpio-reg.c                     |  4 ++--
 drivers/gpio/gpio-stmpe.c                   |  2 +-
 drivers/gpio/gpio-tc3589x.c                 |  2 +-
 drivers/gpio/gpio-vf610.c                   |  2 +-
 drivers/gpio/gpio-wcove.c                   |  2 +-
 drivers/gpio/gpio-ws16c48.c                 |  2 +-
 drivers/gpio/gpio-xgene-sb.c                |  2 +-
 drivers/gpio/gpio-xlp.c                     |  2 +-
 drivers/gpio/gpio-zx.c                      |  2 +-
 drivers/gpio/gpio-zynq.c                    |  2 +-
 drivers/gpio/gpiolib.c                      | 22 ++++++++++++----------
 drivers/pinctrl/bcm/pinctrl-bcm2835.c       |  4 ++--
 drivers/pinctrl/bcm/pinctrl-iproc-gpio.c    |  2 +-
 drivers/pinctrl/intel/pinctrl-baytrail.c    |  2 +-
 drivers/pinctrl/intel/pinctrl-cherryview.c  |  2 +-
 drivers/pinctrl/intel/pinctrl-intel.c       |  2 +-
 drivers/pinctrl/mvebu/pinctrl-armada-37xx.c |  2 +-
 drivers/pinctrl/nomadik/pinctrl-nomadik.c   |  4 ++--
 drivers/pinctrl/pinctrl-amd.c               |  2 +-
 drivers/pinctrl/pinctrl-at91.c              |  2 +-
 drivers/pinctrl/pinctrl-coh901.c            |  2 +-
 drivers/pinctrl/pinctrl-mcp23s08.c          |  2 +-
 drivers/pinctrl/pinctrl-oxnas.c             |  2 +-
 drivers/pinctrl/pinctrl-pic32.c             |  2 +-
 drivers/pinctrl/pinctrl-pistachio.c         |  2 +-
 drivers/pinctrl/pinctrl-st.c                |  2 +-
 drivers/pinctrl/pinctrl-sx150x.c            |  2 +-
 drivers/pinctrl/qcom/pinctrl-msm.c          |  2 +-
 drivers/pinctrl/sirf/pinctrl-atlas7.c       |  2 +-
 drivers/pinctrl/sirf/pinctrl-sirf.c         |  2 +-
 drivers/pinctrl/spear/pinctrl-plgpio.c      |  2 +-
 drivers/platform/x86/intel_int0002_vgpio.c  |  2 +-
 include/linux/gpio/driver.h                 | 11 ++++++++---
 56 files changed, 78 insertions(+), 71 deletions(-)

diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index fc1d2f83564d..dcf6af1d9e56 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -254,7 +254,7 @@ GPIO irqchips usually fall in one of two categories:
 	static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 		unsigned long wa_lock_flags;
 		raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
-		generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit));
+		generic_handle_irq(irq_find_mapping(bank->chip.irq.domain, bit));
 		raw_spin_unlock_irqrestore(&bank->wa_lock, wa_lock_flags);
 
 * GENERIC CHAINED GPIO irqchips: these are the same as "CHAINED GPIO irqchips",
diff --git a/drivers/bcma/driver_gpio.c b/drivers/bcma/driver_gpio.c
index 982d5781d3ce..2c0ffb77d738 100644
--- a/drivers/bcma/driver_gpio.c
+++ b/drivers/bcma/driver_gpio.c
@@ -113,7 +113,7 @@ static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	for_each_set_bit(gpio, &irqs, gc->ngpio)
-		generic_handle_irq(irq_find_mapping(gc->irqdomain, gpio));
+		generic_handle_irq(irq_find_mapping(gc->irq.domain, gpio));
 	bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
 
 	return IRQ_HANDLED;
diff --git a/drivers/gpio/gpio-104-dio-48e.c b/drivers/gpio/gpio-104-dio-48e.c
index 598e209efa2d..bab3b94c5cbc 100644
--- a/drivers/gpio/gpio-104-dio-48e.c
+++ b/drivers/gpio/gpio-104-dio-48e.c
@@ -326,7 +326,7 @@ static irqreturn_t dio48e_irq_handler(int irq, void *dev_id)
 	unsigned long gpio;
 
 	for_each_set_bit(gpio, &irq_mask, 2)
-		generic_handle_irq(irq_find_mapping(chip->irqdomain,
+		generic_handle_irq(irq_find_mapping(chip->irq.domain,
 			19 + gpio*24));
 
 	raw_spin_lock(&dio48egpio->lock);
diff --git a/drivers/gpio/gpio-104-idi-48.c b/drivers/gpio/gpio-104-idi-48.c
index 51f046e29ff7..add859d59766 100644
--- a/drivers/gpio/gpio-104-idi-48.c
+++ b/drivers/gpio/gpio-104-idi-48.c
@@ -209,7 +209,7 @@ static irqreturn_t idi_48_irq_handler(int irq, void *dev_id)
 		for_each_set_bit(bit_num, &irq_mask, 8) {
 			gpio = bit_num + boundary * 8;
 
-			generic_handle_irq(irq_find_mapping(chip->irqdomain,
+			generic_handle_irq(irq_find_mapping(chip->irq.domain,
 				gpio));
 		}
 	}
diff --git a/drivers/gpio/gpio-104-idio-16.c b/drivers/gpio/gpio-104-idio-16.c
index ec2ce34ff473..2f16638a0589 100644
--- a/drivers/gpio/gpio-104-idio-16.c
+++ b/drivers/gpio/gpio-104-idio-16.c
@@ -199,7 +199,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
 	int gpio;
 
 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
-		generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
 
 	raw_spin_lock(&idio16gpio->lock);
 
diff --git a/drivers/gpio/gpio-adnp.c b/drivers/gpio/gpio-adnp.c
index 7f475eef3faa..44c09904daa6 100644
--- a/drivers/gpio/gpio-adnp.c
+++ b/drivers/gpio/gpio-adnp.c
@@ -320,7 +320,7 @@ static irqreturn_t adnp_irq(int irq, void *data)
 
 		for_each_set_bit(bit, &pending, 8) {
 			unsigned int child_irq;
-			child_irq = irq_find_mapping(adnp->gpio.irqdomain,
+			child_irq = irq_find_mapping(adnp->gpio.irq.domain,
 						     base + bit);
 			handle_nested_irq(child_irq);
 		}
diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c
index ccc02ed65b3c..8e76d390e653 100644
--- a/drivers/gpio/gpio-altera.c
+++ b/drivers/gpio/gpio-altera.c
@@ -211,7 +211,7 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
 	altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	chip = irq_desc_get_chip(desc);
 	mm_gc = &altera_gc->mmchip;
-	irqdomain = altera_gc->mmchip.gc.irqdomain;
+	irqdomain = altera_gc->mmchip.gc.irq.domain;
 
 	chained_irq_enter(chip, desc);
 
@@ -239,7 +239,7 @@ static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
 	altera_gc = gpiochip_get_data(irq_desc_get_handler_data(desc));
 	chip = irq_desc_get_chip(desc);
 	mm_gc = &altera_gc->mmchip;
-	irqdomain = altera_gc->mmchip.gc.irqdomain;
+	irqdomain = altera_gc->mmchip.gc.irq.domain;
 
 	chained_irq_enter(chip, desc);
 
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 00dc1c020198..2bfce0ab7326 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -469,7 +469,7 @@ static void aspeed_gpio_irq_handler(struct irq_desc *desc)
 		reg = ioread32(bank_irq_reg(data, bank, GPIO_IRQ_STATUS));
 
 		for_each_set_bit(p, &reg, 32) {
-			girq = irq_find_mapping(gc->irqdomain, i * 32 + p);
+			girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
 			generic_handle_irq(girq);
 		}
 
diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c
index 02e56e0c793a..5fad89dfab7e 100644
--- a/drivers/gpio/gpio-ath79.c
+++ b/drivers/gpio/gpio-ath79.c
@@ -209,7 +209,7 @@ static void ath79_gpio_irq_handler(struct irq_desc *desc)
 	if (pending) {
 		for_each_set_bit(irq, &pending, gc->ngpio)
 			generic_handle_irq(
-				irq_linear_revmap(gc->irqdomain, irq));
+				irq_linear_revmap(gc->irq.domain, irq));
 	}
 
 	chained_irq_exit(irqchip, desc);
diff --git a/drivers/gpio/gpio-crystalcove.c b/drivers/gpio/gpio-crystalcove.c
index e60156ec0c18..b6f0f729656c 100644
--- a/drivers/gpio/gpio-crystalcove.c
+++ b/drivers/gpio/gpio-crystalcove.c
@@ -295,7 +295,7 @@ static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data)
 
 	for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) {
 		if (pending & BIT(gpio)) {
-			virq = irq_find_mapping(cg->chip.irqdomain, gpio);
+			virq = irq_find_mapping(cg->chip.irq.domain, gpio);
 			handle_nested_irq(virq);
 		}
 	}
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index aecb847166f5..1dada68b9a27 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -420,7 +420,7 @@ static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
 		return;
 	}
 
-	irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
+	irq = irq_find_mapping(dln2->gpio.irq.domain, pin);
 	if (!irq) {
 		dev_err(dln2->gpio.parent, "pin %d not mapped to IRQ\n", pin);
 		return;
diff --git a/drivers/gpio/gpio-ftgpio010.c b/drivers/gpio/gpio-ftgpio010.c
index e9386f8b67f5..b7896bae83ca 100644
--- a/drivers/gpio/gpio-ftgpio010.c
+++ b/drivers/gpio/gpio-ftgpio010.c
@@ -149,7 +149,7 @@ static void ftgpio_gpio_irq_handler(struct irq_desc *desc)
 	stat = readl(g->base + GPIO_INT_STAT);
 	if (stat)
 		for_each_set_bit(offset, &stat, gc->ngpio)
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    offset));
 
 	chained_irq_exit(irqchip, desc);
diff --git a/drivers/gpio/gpio-ingenic.c b/drivers/gpio/gpio-ingenic.c
index 254780730b95..15fb2bc796a8 100644
--- a/drivers/gpio/gpio-ingenic.c
+++ b/drivers/gpio/gpio-ingenic.c
@@ -242,7 +242,7 @@ static void ingenic_gpio_irq_handler(struct irq_desc *desc)
 		flag = gpio_ingenic_read_reg(jzgc, JZ4740_GPIO_FLAG);
 
 	for_each_set_bit(i, &flag, 32)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, i));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, i));
 	chained_irq_exit(irq_chip, desc);
 }
 
diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c
index b76ecee82c3f..629575ea46a0 100644
--- a/drivers/gpio/gpio-intel-mid.c
+++ b/drivers/gpio/gpio-intel-mid.c
@@ -295,7 +295,7 @@ static void intel_mid_irq_handler(struct irq_desc *desc)
 			mask = BIT(gpio);
 			/* Clear before handling so we can't lose an edge */
 			writel(mask, gedr);
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    base + gpio));
 		}
 	}
diff --git a/drivers/gpio/gpio-lynxpoint.c b/drivers/gpio/gpio-lynxpoint.c
index fbd393b46ce0..1e557b10d73e 100644
--- a/drivers/gpio/gpio-lynxpoint.c
+++ b/drivers/gpio/gpio-lynxpoint.c
@@ -255,7 +255,7 @@ static void lp_gpio_irq_handler(struct irq_desc *desc)
 			mask = BIT(pin);
 			/* Clear before handling so we don't lose an edge */
 			outl(mask, reg);
-			irq = irq_find_mapping(lg->chip.irqdomain, base + pin);
+			irq = irq_find_mapping(lg->chip.irq.domain, base + pin);
 			generic_handle_irq(irq);
 		}
 	}
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 7f4d26ce5f23..c04fae1ba32a 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -486,7 +486,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
 
 	do {
 		level = __ffs(pending);
-		handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
+		handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
 						   level));
 
 		pending &= ~(1 << level);
diff --git a/drivers/gpio/gpio-merrifield.c b/drivers/gpio/gpio-merrifield.c
index ec8560298805..dd67a31ac337 100644
--- a/drivers/gpio/gpio-merrifield.c
+++ b/drivers/gpio/gpio-merrifield.c
@@ -357,7 +357,7 @@ static void mrfld_irq_handler(struct irq_desc *desc)
 		for_each_set_bit(gpio, &pending, 32) {
 			unsigned int irq;
 
-			irq = irq_find_mapping(gc->irqdomain, base + gpio);
+			irq = irq_find_mapping(gc->irq.domain, base + gpio);
 			generic_handle_irq(irq);
 		}
 	}
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index dbf869fb63ce..ce27d6a586bf 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -733,7 +733,7 @@ static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
 
 			raw_spin_lock_irqsave(&bank->wa_lock, wa_lock_flags);
 
-			generic_handle_irq(irq_find_mapping(bank->chip.irqdomain,
+			generic_handle_irq(irq_find_mapping(bank->chip.irq.domain,
 							    bit));
 
 			raw_spin_unlock_irqrestore(&bank->wa_lock,
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c
index 1b9dbf691ae7..babb7bd2ba59 100644
--- a/drivers/gpio/gpio-pca953x.c
+++ b/drivers/gpio/gpio-pca953x.c
@@ -608,7 +608,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
 	for (i = 0; i < NBANK(chip); i++) {
 		while (pending[i]) {
 			level = __ffs(pending[i]);
-			handle_nested_irq(irq_find_mapping(chip->gpio_chip.irqdomain,
+			handle_nested_irq(irq_find_mapping(chip->gpio_chip.irq.domain,
 							level + (BANK_SZ * i)));
 			pending[i] &= ~(1 << level);
 			nhandled++;
diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c
index a4fd78b9c0e4..38fbb420c6cd 100644
--- a/drivers/gpio/gpio-pcf857x.c
+++ b/drivers/gpio/gpio-pcf857x.c
@@ -196,7 +196,7 @@ static irqreturn_t pcf857x_irq(int irq, void *data)
 	mutex_unlock(&gpio->lock);
 
 	for_each_set_bit(i, &change, gpio->chip.ngpio)
-		handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i));
+		handle_nested_irq(irq_find_mapping(gpio->chip.irq.domain, i));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/gpio/gpio-pci-idio-16.c b/drivers/gpio/gpio-pci-idio-16.c
index 7de4f6a2cb49..57d1b7fbf07b 100644
--- a/drivers/gpio/gpio-pci-idio-16.c
+++ b/drivers/gpio/gpio-pci-idio-16.c
@@ -240,7 +240,7 @@ static irqreturn_t idio_16_irq_handler(int irq, void *dev_id)
 		return IRQ_NONE;
 
 	for_each_set_bit(gpio, &idio16gpio->irq_mask, chip->ngpio)
-		generic_handle_irq(irq_find_mapping(chip->irqdomain, gpio));
+		generic_handle_irq(irq_find_mapping(chip->irq.domain, gpio));
 
 	raw_spin_lock(&idio16gpio->lock);
 
diff --git a/drivers/gpio/gpio-pl061.c b/drivers/gpio/gpio-pl061.c
index 6aaaab79c205..b70974cb9ef1 100644
--- a/drivers/gpio/gpio-pl061.c
+++ b/drivers/gpio/gpio-pl061.c
@@ -221,7 +221,7 @@ static void pl061_irq_handler(struct irq_desc *desc)
 	pending = readb(pl061->base + GPIOMIS);
 	if (pending) {
 		for_each_set_bit(offset, &pending, PL061_GPIO_NR)
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    offset));
 	}
 
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index ddcff4f543bc..0ea998a3e357 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -207,7 +207,7 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
 			  gpio_rcar_read(p, INTMSK))) {
 		offset = __ffs(pending);
 		gpio_rcar_write(p, INTCLR, BIT(offset));
-		generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain,
+		generic_handle_irq(irq_find_mapping(p->gpio_chip.irq.domain,
 						    offset));
 		irqs_handled++;
 	}
diff --git a/drivers/gpio/gpio-reg.c b/drivers/gpio/gpio-reg.c
index e85903eddc68..23e771dba4c1 100644
--- a/drivers/gpio/gpio-reg.c
+++ b/drivers/gpio/gpio-reg.c
@@ -103,8 +103,8 @@ static int gpio_reg_to_irq(struct gpio_chip *gc, unsigned offset)
 	struct gpio_reg *r = to_gpio_reg(gc);
 	int irq = r->irqs[offset];
 
-	if (irq >= 0 && r->irqdomain)
-		irq = irq_find_mapping(r->irqdomain, irq);
+	if (irq >= 0 && r->irq.domain)
+		irq = irq_find_mapping(r->irq.domain, irq);
 
 	return irq;
 }
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 001a89db5161..18d8bef76d85 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -397,7 +397,7 @@ static irqreturn_t stmpe_gpio_irq(int irq, void *dev)
 		while (stat) {
 			int bit = __ffs(stat);
 			int line = bank * 8 + bit;
-			int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain,
+			int child_irq = irq_find_mapping(stmpe_gpio->chip.irq.domain,
 							 line);
 
 			handle_nested_irq(child_irq);
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index 433b45ef332e..91a8ef8e7f3f 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -268,7 +268,7 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
 		while (stat) {
 			int bit = __ffs(stat);
 			int line = i * 8 + bit;
-			int irq = irq_find_mapping(tc3589x_gpio->chip.irqdomain,
+			int irq = irq_find_mapping(tc3589x_gpio->chip.irq.domain,
 						   line);
 
 			handle_nested_irq(irq);
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index cbe9e06861de..4610cc2938ad 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -160,7 +160,7 @@ static void vf610_gpio_irq_handler(struct irq_desc *desc)
 	for_each_set_bit(pin, &irq_isfr, VF610_GPIO_PER_PORT) {
 		vf610_gpio_writel(BIT(pin), port->base + PORT_ISFR);
 
-		generic_handle_irq(irq_find_mapping(port->gc.irqdomain, pin));
+		generic_handle_irq(irq_find_mapping(port->gc.irq.domain, pin));
 	}
 
 	chained_irq_exit(chip, desc);
diff --git a/drivers/gpio/gpio-wcove.c b/drivers/gpio/gpio-wcove.c
index 85341eab795d..dde7c6aecbb5 100644
--- a/drivers/gpio/gpio-wcove.c
+++ b/drivers/gpio/gpio-wcove.c
@@ -350,7 +350,7 @@ static irqreturn_t wcove_gpio_irq_handler(int irq, void *data)
 			offset = (gpio > GROUP0_NR_IRQS) ? 1 : 0;
 			mask = (offset == 1) ? BIT(gpio - GROUP0_NR_IRQS) :
 								BIT(gpio);
-			virq = irq_find_mapping(wg->chip.irqdomain, gpio);
+			virq = irq_find_mapping(wg->chip.irq.domain, gpio);
 			handle_nested_irq(virq);
 			regmap_update_bits(wg->regmap, IRQ_STATUS_BASE + offset,
 								mask, mask);
diff --git a/drivers/gpio/gpio-ws16c48.c b/drivers/gpio/gpio-ws16c48.c
index 5037974ac063..746648244bf3 100644
--- a/drivers/gpio/gpio-ws16c48.c
+++ b/drivers/gpio/gpio-ws16c48.c
@@ -332,7 +332,7 @@ static irqreturn_t ws16c48_irq_handler(int irq, void *dev_id)
 			int_id = inb(ws16c48gpio->base + 8 + port);
 			for_each_set_bit(gpio, &int_id, 8)
 				generic_handle_irq(irq_find_mapping(
-					chip->irqdomain, gpio + 8*port));
+					chip->irq.domain, gpio + 8*port));
 		}
 
 		int_pending = inb(ws16c48gpio->base + 6) & 0x7;
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
index 82c3ee6da66a..4f2623c2393e 100644
--- a/drivers/gpio/gpio-xgene-sb.c
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -287,7 +287,7 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
 	if (!priv->irq_domain)
 		return -ENODEV;
 
-	priv->gc.irqdomain = priv->irq_domain;
+	priv->gc.irq.domain = priv->irq_domain;
 
 	ret = devm_gpiochip_add_data(&pdev->dev, &priv->gc, priv);
 	if (ret) {
diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c
index d857e1d8e731..e74bd43a6974 100644
--- a/drivers/gpio/gpio-xlp.c
+++ b/drivers/gpio/gpio-xlp.c
@@ -225,7 +225,7 @@ static void xlp_gpio_generic_handler(struct irq_desc *desc)
 
 		if (gpio_stat & BIT(gpio % XLP_GPIO_REGSZ))
 			generic_handle_irq(irq_find_mapping(
-						priv->chip.irqdomain, gpio));
+						priv->chip.irq.domain, gpio));
 	}
 	chained_irq_exit(irqchip, desc);
 }
diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c
index be3a87da8438..5eacad9b2692 100644
--- a/drivers/gpio/gpio-zx.c
+++ b/drivers/gpio/gpio-zx.c
@@ -170,7 +170,7 @@ static void zx_irq_handler(struct irq_desc *desc)
 	writew_relaxed(pending, chip->base + ZX_GPIO_IC);
 	if (pending) {
 		for_each_set_bit(offset, &pending, ZX_GPIO_NR)
-			generic_handle_irq(irq_find_mapping(gc->irqdomain,
+			generic_handle_irq(irq_find_mapping(gc->irq.domain,
 							    offset));
 	}
 
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index b3cc948a2d8b..75ee877e5cd5 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -562,7 +562,7 @@ static void zynq_gpio_handle_bank_irq(struct zynq_gpio *gpio,
 				      unsigned long pending)
 {
 	unsigned int bank_offset = gpio->p_data->bank_min[bank_num];
-	struct irq_domain *irqdomain = gpio->chip.irqdomain;
+	struct irq_domain *irqdomain = gpio->chip.irq.domain;
 	int offset;
 
 	if (!pending)
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d3d0b3134ba3..9ee75a45ba37 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1550,7 +1550,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 {
 	unsigned int offset;
 
-	if (!gpiochip->irqdomain) {
+	if (!gpiochip->irq.domain) {
 		chip_err(gpiochip, "called %s before setting up irqchip\n",
 			 __func__);
 		return;
@@ -1577,7 +1577,7 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 	for (offset = 0; offset < gpiochip->ngpio; offset++) {
 		if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
 			continue;
-		irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
+		irq_set_parent(irq_find_mapping(gpiochip->irq.domain, offset),
 			       parent_irq);
 	}
 }
@@ -1708,7 +1708,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
 	if (!gpiochip_irqchip_irq_valid(chip, offset))
 		return -ENXIO;
-	return irq_create_mapping(chip->irqdomain, offset);
+	return irq_create_mapping(chip->irq.domain, offset);
 }
 
 /**
@@ -1719,7 +1719,7 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
  */
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 {
-	unsigned int offset;
+	unsigned int offset, irq;
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
@@ -1729,14 +1729,16 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 	}
 
 	/* Remove all IRQ mappings and delete the domain */
-	if (gpiochip->irqdomain) {
+	if (gpiochip->irq.domain) {
 		for (offset = 0; offset < gpiochip->ngpio; offset++) {
 			if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
 				continue;
-			irq_dispose_mapping(
-				irq_find_mapping(gpiochip->irqdomain, offset));
+
+			irq = irq_find_mapping(gpiochip->irq.domain, offset);
+			irq_dispose_mapping(irq);
 		}
-		irq_domain_remove(gpiochip->irqdomain);
+
+		irq_domain_remove(gpiochip->irq.domain);
 	}
 
 	if (gpiochip->irq.chip) {
@@ -1822,10 +1824,10 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	gpiochip->irq_default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->lock_key = lock_key;
-	gpiochip->irqdomain = irq_domain_add_simple(of_node,
+	gpiochip->irq.domain = irq_domain_add_simple(of_node,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
-	if (!gpiochip->irqdomain) {
+	if (!gpiochip->irq.domain) {
 		gpiochip->irq.chip = NULL;
 		return -EINVAL;
 	}
diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
index 0944310225db..72d122748293 100644
--- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c
+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c
@@ -383,7 +383,7 @@ static void bcm2835_gpio_irq_handle_bank(struct bcm2835_pinctrl *pc,
 		/* FIXME: no clue why the code looks up the type here */
 		type = pc->irq_type[gpio];
 
-		generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irqdomain,
+		generic_handle_irq(irq_linear_revmap(pc->gpio_chip.irq.domain,
 						     gpio));
 	}
 }
@@ -665,7 +665,7 @@ static void bcm2835_pctl_pin_dbg_show(struct pinctrl_dev *pctldev,
 	enum bcm2835_fsel fsel = bcm2835_pinctrl_fsel_get(pc, offset);
 	const char *fname = bcm2835_functions[fsel];
 	int value = bcm2835_gpio_get_bit(pc, GPLEV0, offset);
-	int irq = irq_find_mapping(chip->irqdomain, offset);
+	int irq = irq_find_mapping(chip->irq.domain, offset);
 
 	seq_printf(s, "function %s in %s; irq %d (%s)",
 		fname, value ? "hi" : "lo",
diff --git a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
index 85a8c97d9dfe..b93f62dc8733 100644
--- a/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
+++ b/drivers/pinctrl/bcm/pinctrl-iproc-gpio.c
@@ -172,7 +172,7 @@ static void iproc_gpio_irq_handler(struct irq_desc *desc)
 
 		for_each_set_bit(bit, &val, NGPIOS_PER_BANK) {
 			unsigned pin = NGPIOS_PER_BANK * i + bit;
-			int child_irq = irq_find_mapping(gc->irqdomain, pin);
+			int child_irq = irq_find_mapping(gc->irq.domain, pin);
 
 			/*
 			 * Clear the interrupt before invoking the
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 0f3a02495aeb..5897981e5ed3 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1627,7 +1627,7 @@ static void byt_gpio_irq_handler(struct irq_desc *desc)
 		pending = readl(reg);
 		raw_spin_unlock(&vg->lock);
 		for_each_set_bit(pin, &pending, 32) {
-			virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
+			virq = irq_find_mapping(vg->chip.irq.domain, base + pin);
 			generic_handle_irq(virq);
 		}
 	}
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 04e929fd0ffe..1cd7043edbc1 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1523,7 +1523,7 @@ static void chv_gpio_irq_handler(struct irq_desc *desc)
 		unsigned irq, offset;
 
 		offset = pctrl->intr_lines[intr_line];
-		irq = irq_find_mapping(gc->irqdomain, offset);
+		irq = irq_find_mapping(gc->irq.domain, offset);
 		generic_handle_irq(irq);
 	}
 
diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c
index 71df0f70b61f..ffda27bfd133 100644
--- a/drivers/pinctrl/intel/pinctrl-intel.c
+++ b/drivers/pinctrl/intel/pinctrl-intel.c
@@ -1005,7 +1005,7 @@ static irqreturn_t intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
 			if (padno >= community->npins)
 				break;
 
-			irq = irq_find_mapping(gc->irqdomain,
+			irq = irq_find_mapping(gc->irq.domain,
 					       community->pin_base + padno);
 			generic_handle_irq(irq);
 
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
index ac299a6cdfd6..93bc2754744c 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-37xx.c
@@ -592,7 +592,7 @@ static void armada_37xx_irq_handler(struct irq_desc *desc)
 	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
 	struct irq_chip *chip = irq_desc_get_chip(desc);
 	struct armada_37xx_pinctrl *info = gpiochip_get_data(gc);
-	struct irq_domain *d = gc->irqdomain;
+	struct irq_domain *d = gc->irq.domain;
 	int i;
 
 	chained_irq_enter(chip, desc);
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index a53f1a9b1ed2..f0e7a8c114b2 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -413,7 +413,7 @@ nmk_gpio_disable_lazy_irq(struct nmk_gpio_chip *nmk_chip, unsigned offset)
 	u32 falling = nmk_chip->fimsc & BIT(offset);
 	u32 rising = nmk_chip->rimsc & BIT(offset);
 	int gpio = nmk_chip->chip.base + offset;
-	int irq = irq_find_mapping(nmk_chip->chip.irqdomain, offset);
+	int irq = irq_find_mapping(nmk_chip->chip.irq.domain, offset);
 	struct irq_data *d = irq_get_irq_data(irq);
 
 	if (!rising && !falling)
@@ -815,7 +815,7 @@ static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status)
 	while (status) {
 		int bit = __ffs(status);
 
-		generic_handle_irq(irq_find_mapping(chip->irqdomain, bit));
+		generic_handle_irq(irq_find_mapping(chip->irq.domain, bit));
 		status &= ~BIT(bit);
 	}
 
diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c
index 3f6b34febbf1..06362bf84a5b 100644
--- a/drivers/pinctrl/pinctrl-amd.c
+++ b/drivers/pinctrl/pinctrl-amd.c
@@ -532,7 +532,7 @@ static irqreturn_t amd_gpio_irq_handler(int irq, void *dev_id)
 			regval = readl(regs + i);
 			if (!(regval & PIN_IRQ_PENDING))
 				continue;
-			irq = irq_find_mapping(gc->irqdomain, irqnr + i);
+			irq = irq_find_mapping(gc->irq.domain, irqnr + i);
 			generic_handle_irq(irq);
 			/* Clear interrupt */
 			writel(regval, regs + i);
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 569bc28cb909..03492e3c09fa 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -1603,7 +1603,7 @@ static void gpio_irq_handler(struct irq_desc *desc)
 
 		for_each_set_bit(n, &isr, BITS_PER_LONG) {
 			generic_handle_irq(irq_find_mapping(
-					   gpio_chip->irqdomain, n));
+					   gpio_chip->irq.domain, n));
 		}
 	}
 	chained_irq_exit(chip, desc);
diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c
index ac155e7d3412..7939b178c6ae 100644
--- a/drivers/pinctrl/pinctrl-coh901.c
+++ b/drivers/pinctrl/pinctrl-coh901.c
@@ -517,7 +517,7 @@ static void u300_gpio_irq_handler(struct irq_desc *desc)
 
 		for_each_set_bit(irqoffset, &val, U300_GPIO_PINS_PER_PORT) {
 			int offset = pinoffset + irqoffset;
-			int pin_irq = irq_find_mapping(chip->irqdomain, offset);
+			int pin_irq = irq_find_mapping(chip->irq.domain, offset);
 
 			dev_dbg(gpio->dev, "GPIO IRQ %d on pin %d\n",
 				pin_irq, offset);
diff --git a/drivers/pinctrl/pinctrl-mcp23s08.c b/drivers/pinctrl/pinctrl-mcp23s08.c
index 3e40d4245512..db19a2f2f575 100644
--- a/drivers/pinctrl/pinctrl-mcp23s08.c
+++ b/drivers/pinctrl/pinctrl-mcp23s08.c
@@ -537,7 +537,7 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
 		    ((gpio_bit_changed || intcap_changed) &&
 			(BIT(i) & mcp->irq_fall) && !gpio_set) ||
 		    defval_changed) {
-			child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
+			child_irq = irq_find_mapping(mcp->chip.irq.domain, i);
 			handle_nested_irq(child_irq);
 		}
 	}
diff --git a/drivers/pinctrl/pinctrl-oxnas.c b/drivers/pinctrl/pinctrl-oxnas.c
index 494ec9a7573a..53ec22a51f5c 100644
--- a/drivers/pinctrl/pinctrl-oxnas.c
+++ b/drivers/pinctrl/pinctrl-oxnas.c
@@ -1064,7 +1064,7 @@ static void oxnas_gpio_irq_handler(struct irq_desc *desc)
 	stat = readl(bank->reg_base + IRQ_PENDING);
 
 	for_each_set_bit(pin, &stat, BITS_PER_LONG)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
 
 	chained_irq_exit(chip, desc);
 }
diff --git a/drivers/pinctrl/pinctrl-pic32.c b/drivers/pinctrl/pinctrl-pic32.c
index 31ceb958b3fe..96390228d388 100644
--- a/drivers/pinctrl/pinctrl-pic32.c
+++ b/drivers/pinctrl/pinctrl-pic32.c
@@ -2106,7 +2106,7 @@ static void pic32_gpio_irq_handler(struct irq_desc *desc)
 	pending = pic32_gpio_get_pending(gc, stat);
 
 	for_each_set_bit(pin, &pending, BITS_PER_LONG)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
 
 	chained_irq_exit(chip, desc);
 }
diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c
index 55375b1b3cc8..302190d1558d 100644
--- a/drivers/pinctrl/pinctrl-pistachio.c
+++ b/drivers/pinctrl/pinctrl-pistachio.c
@@ -1307,7 +1307,7 @@ static void pistachio_gpio_irq_handler(struct irq_desc *desc)
 	pending = gpio_readl(bank, GPIO_INTERRUPT_STATUS) &
 		gpio_readl(bank, GPIO_INTERRUPT_EN);
 	for_each_set_bit(pin, &pending, 16)
-		generic_handle_irq(irq_linear_revmap(gc->irqdomain, pin));
+		generic_handle_irq(irq_linear_revmap(gc->irq.domain, pin));
 	chained_irq_exit(chip, desc);
 }
 
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index a5205b94b2e6..2081c67667a8 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1408,7 +1408,7 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank)
 					continue;
 			}
 
-			generic_handle_irq(irq_find_mapping(bank->gpio_chip.irqdomain, n));
+			generic_handle_irq(irq_find_mapping(bank->gpio_chip.irq.domain, n));
 		}
 	}
 }
diff --git a/drivers/pinctrl/pinctrl-sx150x.c b/drivers/pinctrl/pinctrl-sx150x.c
index 7450f5118445..7db4f6a6eb17 100644
--- a/drivers/pinctrl/pinctrl-sx150x.c
+++ b/drivers/pinctrl/pinctrl-sx150x.c
@@ -561,7 +561,7 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
 
 	status = val;
 	for_each_set_bit(n, &status, pctl->data->ngpios)
-		handle_nested_irq(irq_find_mapping(pctl->gpio.irqdomain, n));
+		handle_nested_irq(irq_find_mapping(pctl->gpio.irq.domain, n));
 
 	return IRQ_HANDLED;
 }
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index ff491da64dab..7a960590ecaa 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -795,7 +795,7 @@ static void msm_gpio_irq_handler(struct irq_desc *desc)
 		g = &pctrl->soc->groups[i];
 		val = readl(pctrl->regs + g->intr_status_reg);
 		if (val & BIT(g->intr_status_bit)) {
-			irq_pin = irq_find_mapping(gc->irqdomain, i);
+			irq_pin = irq_find_mapping(gc->irq.domain, i);
 			generic_handle_irq(irq_pin);
 			handled++;
 		}
diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c
index 4db9323251e3..f5cef6e5fa3e 100644
--- a/drivers/pinctrl/sirf/pinctrl-atlas7.c
+++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c
@@ -5820,7 +5820,7 @@ static void atlas7_gpio_handle_irq(struct irq_desc *desc)
 				__func__, gc->label,
 				bank->gpio_offset + pin_in_bank);
 			generic_handle_irq(
-				irq_find_mapping(gc->irqdomain,
+				irq_find_mapping(gc->irq.domain,
 					bank->gpio_offset + pin_in_bank));
 		}
 
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index d3ef05973901..8b14a1f1e671 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -587,7 +587,7 @@ static void sirfsoc_gpio_handle_irq(struct irq_desc *desc)
 		if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
 			pr_debug("%s: gpio id %d idx %d happens\n",
 				__func__, bank->id, idx);
-			generic_handle_irq(irq_find_mapping(gc->irqdomain, idx +
+			generic_handle_irq(irq_find_mapping(gc->irq.domain, idx +
 					bank->id * SIRFSOC_GPIO_BANK_SIZE));
 		}
 
diff --git a/drivers/pinctrl/spear/pinctrl-plgpio.c b/drivers/pinctrl/spear/pinctrl-plgpio.c
index cf6d68c7345b..72ae6bccee55 100644
--- a/drivers/pinctrl/spear/pinctrl-plgpio.c
+++ b/drivers/pinctrl/spear/pinctrl-plgpio.c
@@ -401,7 +401,7 @@ static void plgpio_irq_handler(struct irq_desc *desc)
 			/* get correct irq line number */
 			pin = i * MAX_GPIO_PER_REG + pin;
 			generic_handle_irq(
-				irq_find_mapping(gc->irqdomain, pin));
+				irq_find_mapping(gc->irq.domain, pin));
 		}
 	}
 	chained_irq_exit(irqchip, desc);
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index 92dc230ef5b2..f6b3af73dea5 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -119,7 +119,7 @@ static irqreturn_t int0002_irq(int irq, void *data)
 	if (!(gpe_sts_reg & GPE0A_PME_B0_STS_BIT))
 		return IRQ_NONE;
 
-	generic_handle_irq(irq_find_mapping(chip->irqdomain,
+	generic_handle_irq(irq_find_mapping(chip->irq.domain,
 					    GPE0A_PME_B0_VIRT_GPIO_PIN));
 
 	pm_system_wakeup();
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index a79b3b18fadd..c5dfa8c0b829 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -31,6 +31,14 @@ struct gpio_irq_chip {
 	 */
 	struct irq_chip *chip;
 
+	/**
+	 * @domain:
+	 *
+	 * Interrupt translation domain; responsible for mapping between GPIO
+	 * hwirq number and Linux IRQ number.
+	 */
+	struct irq_domain *domain;
+
 	/**
 	 * @domain_ops:
 	 *
@@ -124,8 +132,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irqdomain: Interrupt translation domain; responsible for mapping
- *	between GPIO hwirq number and linux irq number
  * @irq_handler: the irq handler to use (often a predefined irq core function)
  *	for GPIO IRQs, provided by GPIO driver
  * @irq_default_type: default IRQ triggering type applied during GPIO driver
@@ -208,7 +214,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	struct irq_domain	*irqdomain;
 	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 04/12] gpio: Move irq_handler to struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (2 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 03/12] gpio: Move irqdomain " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 05/12] gpio: Move irq_default_type " Thierry Reding
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      |  4 ++--
 include/linux/gpio/driver.h | 11 ++++++++---
 2 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 9ee75a45ba37..dafbca12c4ca 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1646,7 +1646,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * category than their parents, so it won't report false recursion.
 	 */
 	irq_set_lockdep_class(irq, chip->lock_key);
-	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq_handler);
+	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq_nested)
 		irq_set_nested_thread(irq, 1);
@@ -1820,7 +1820,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	}
 
 	gpiochip->irq.chip = irqchip;
-	gpiochip->irq_handler = handler;
+	gpiochip->irq.handler = handler;
 	gpiochip->irq_default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->lock_key = lock_key;
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index c5dfa8c0b829..864f507e859b 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -46,6 +46,14 @@ struct gpio_irq_chip {
 	 */
 	const struct irq_domain_ops *domain_ops;
 
+	/**
+	 * @handler:
+	 *
+	 * The IRQ handler to use (often a predefined IRQ core function) for
+	 * GPIO IRQs, provided by GPIO driver.
+	 */
+	irq_flow_handler_t handler;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -132,8 +140,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irq_handler: the irq handler to use (often a predefined irq core function)
- *	for GPIO IRQs, provided by GPIO driver
  * @irq_default_type: default IRQ triggering type applied during GPIO driver
  *	initialization, provided by GPIO driver
  * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
@@ -214,7 +220,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	irq_flow_handler_t	irq_handler;
 	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
 	bool			irq_nested;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 05/12] gpio: Move irq_default_type to struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (3 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 04/12] gpio: Move irq_handler to " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 06/12] gpio: Move irq_chained_parent " Thierry Reding
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      |  6 +++---
 include/linux/gpio/driver.h | 11 ++++++++---
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index dafbca12c4ca..d3608cf511de 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1656,8 +1656,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
 	 * is passed as default type.
 	 */
-	if (chip->irq_default_type != IRQ_TYPE_NONE)
-		irq_set_irq_type(irq, chip->irq_default_type);
+	if (chip->irq.default_type != IRQ_TYPE_NONE)
+		irq_set_irq_type(irq, chip->irq.default_type);
 
 	return 0;
 }
@@ -1821,7 +1821,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 
 	gpiochip->irq.chip = irqchip;
 	gpiochip->irq.handler = handler;
-	gpiochip->irq_default_type = type;
+	gpiochip->irq.default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
 	gpiochip->lock_key = lock_key;
 	gpiochip->irq.domain = irq_domain_add_simple(of_node,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 864f507e859b..1367fa94105f 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -54,6 +54,14 @@ struct gpio_irq_chip {
 	 */
 	irq_flow_handler_t handler;
 
+	/**
+	 * @default_type:
+	 *
+	 * Default IRQ triggering type applied during GPIO driver
+	 * initialization, provided by GPIO driver.
+	 */
+	unsigned int default_type;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -140,8 +148,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irq_default_type: default IRQ triggering type applied during GPIO driver
- *	initialization, provided by GPIO driver
  * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
  *	provided by GPIO driver for chained interrupt (not for nested
  *	interrupts).
@@ -220,7 +226,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	unsigned int		irq_default_type;
 	unsigned int		irq_chained_parent;
 	bool			irq_nested;
 	bool			irq_need_valid_mask;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 06/12] gpio: Move irq_chained_parent to struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (4 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 05/12] gpio: Move irq_default_type " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 07/12] gpio: Move irq_nested into " Thierry Reding
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 17 ++++++++++++-----
 include/linux/gpio/driver.h | 19 +++++++++++++++----
 2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index d3608cf511de..8eadae73ff20 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1570,7 +1570,8 @@ static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
 		irq_set_chained_handler_and_data(parent_irq, parent_handler,
 						 gpiochip);
 
-		gpiochip->irq_chained_parent = parent_irq;
+		gpiochip->irq.parents = &parent_irq;
+		gpiochip->irq.num_parents = 1;
 	}
 
 	/* Set the parent IRQ for all affected IRQs */
@@ -1719,17 +1720,23 @@ static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
  */
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 {
-	unsigned int offset, irq;
+	unsigned int offset;
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
-	if (gpiochip->irq_chained_parent) {
-		irq_set_chained_handler_and_data(
-			gpiochip->irq_chained_parent, NULL, NULL);
+	if (gpiochip->irq.num_parents > 0) {
+		struct gpio_irq_chip *irq = &gpiochip->irq;
+		unsigned int i;
+
+		for (i = 0; i < irq->num_parents; i++)
+			irq_set_chained_handler_and_data(irq->parents[i],
+							 NULL, NULL);
 	}
 
 	/* Remove all IRQ mappings and delete the domain */
 	if (gpiochip->irq.domain) {
+		unsigned int irq;
+
 		for (offset = 0; offset < gpiochip->ngpio; offset++) {
 			if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
 				continue;
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 1367fa94105f..86f00d908e90 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -77,6 +77,21 @@ struct gpio_irq_chip {
 	 * interrupt.
 	 */
 	void *parent_handler_data;
+
+	/**
+	 * @num_parents:
+	 *
+	 * The number of interrupt parents of a GPIO chip.
+	 */
+	unsigned int num_parents;
+
+	/**
+	 * @parents:
+	 *
+	 * A list of interrupt parents of a GPIO chip. This is owned by the
+	 * driver, so the core will only reference this list, not modify it.
+	 */
+	unsigned int *parents;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -148,9 +163,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
- *	provided by GPIO driver for chained interrupt (not for nested
- *	interrupts).
  * @irq_nested: True if set the interrupt handling is nested.
  * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
  *	bits set to one
@@ -226,7 +238,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	unsigned int		irq_chained_parent;
 	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 07/12] gpio: Move irq_nested into struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (5 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 06/12] gpio: Move irq_chained_parent " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 08/12] gpio: Move irq_valid_mask " Thierry Reding
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 8 ++++----
 include/linux/gpio/driver.h | 9 +++++++--
 2 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 8eadae73ff20..236a9f55a265 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1614,7 +1614,7 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
 				 struct irq_chip *irqchip,
 				 unsigned int parent_irq)
 {
-	if (!gpiochip->irq_nested) {
+	if (!gpiochip->irq.nested) {
 		chip_err(gpiochip, "tried to nest a chained gpiochip\n");
 		return;
 	}
@@ -1649,7 +1649,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	irq_set_lockdep_class(irq, chip->lock_key);
 	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler);
 	/* Chips that use nested thread handlers have them marked */
-	if (chip->irq_nested)
+	if (chip->irq.nested)
 		irq_set_nested_thread(irq, 1);
 	irq_set_noprobe(irq);
 
@@ -1667,7 +1667,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 {
 	struct gpio_chip *chip = d->host_data;
 
-	if (chip->irq_nested)
+	if (chip->irq.nested)
 		irq_set_nested_thread(irq, 0);
 	irq_set_chip_and_handler(irq, NULL, NULL);
 	irq_set_chip_data(irq, NULL);
@@ -1801,7 +1801,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 		pr_err("missing gpiochip .dev parent pointer\n");
 		return -EINVAL;
 	}
-	gpiochip->irq_nested = nested;
+	gpiochip->irq.nested = nested;
 	of_node = gpiochip->parent->of_node;
 #ifdef CONFIG_OF_GPIO
 	/*
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 86f00d908e90..1c3d06fe54b1 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -92,6 +92,13 @@ struct gpio_irq_chip {
 	 * driver, so the core will only reference this list, not modify it.
 	 */
 	unsigned int *parents;
+
+	/**
+	 * @nested:
+	 *
+	 * True if set the interrupt handling is nested.
+	 */
+	bool nested;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -163,7 +170,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irq_nested: True if set the interrupt handling is nested.
  * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
  *	bits set to one
  * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
@@ -238,7 +244,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	bool			irq_nested;
 	bool			irq_need_valid_mask;
 	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 08/12] gpio: Move irq_valid_mask into struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (6 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 07/12] gpio: Move irq_nested into " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 09/12] gpio: Move lock_key " Thierry Reding
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 Documentation/gpio/driver.txt              |  4 ++--
 drivers/gpio/gpio-aspeed.c                 |  4 ++--
 drivers/gpio/gpio-stmpe.c                  |  4 ++--
 drivers/gpio/gpiolib.c                     | 16 ++++++++--------
 drivers/pinctrl/intel/pinctrl-baytrail.c   |  4 ++--
 drivers/pinctrl/intel/pinctrl-cherryview.c |  4 ++--
 drivers/platform/x86/intel_int0002_vgpio.c |  4 ++--
 include/linux/gpio/driver.h                | 21 +++++++++++++++------
 8 files changed, 35 insertions(+), 26 deletions(-)

diff --git a/Documentation/gpio/driver.txt b/Documentation/gpio/driver.txt
index dcf6af1d9e56..d8de1c7de85a 100644
--- a/Documentation/gpio/driver.txt
+++ b/Documentation/gpio/driver.txt
@@ -313,8 +313,8 @@ symbol:
   mark all the child IRQs as having the other IRQ as parent.
 
 If there is a need to exclude certain GPIOs from the IRQ domain, you can
-set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
-called. This allocates an .irq_valid_mask with as many bits set as there
+set .irq.need_valid_mask of the gpiochip before gpiochip_add_data() is
+called. This allocates an .irq.valid_mask with as many bits set as there
 are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
 mask. The mask must be filled in before gpiochip_irqchip_add() or
 gpiochip_irqchip_add_nested() is called.
diff --git a/drivers/gpio/gpio-aspeed.c b/drivers/gpio/gpio-aspeed.c
index 2bfce0ab7326..8781817d9003 100644
--- a/drivers/gpio/gpio-aspeed.c
+++ b/drivers/gpio/gpio-aspeed.c
@@ -501,7 +501,7 @@ static void set_irq_valid_mask(struct aspeed_gpio *gpio)
 			if (i >= gpio->config->nr_gpios)
 				break;
 
-			clear_bit(i, gpio->chip.irq_valid_mask);
+			clear_bit(i, gpio->chip.irq.valid_mask);
 		}
 
 		props++;
@@ -856,7 +856,7 @@ static int __init aspeed_gpio_probe(struct platform_device *pdev)
 	gpio->chip.set_config = aspeed_gpio_set_config;
 	gpio->chip.label = dev_name(&pdev->dev);
 	gpio->chip.base = -1;
-	gpio->chip.irq_need_valid_mask = true;
+	gpio->chip.irq.need_valid_mask = true;
 
 	rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
 	if (rc < 0)
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 18d8bef76d85..e6e5cca624a7 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -451,7 +451,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 	of_property_read_u32(np, "st,norequest-mask",
 			&stmpe_gpio->norequest_mask);
 	if (stmpe_gpio->norequest_mask)
-		stmpe_gpio->chip.irq_need_valid_mask = true;
+		stmpe_gpio->chip.irq.need_valid_mask = true;
 
 	if (irq < 0)
 		dev_info(&pdev->dev,
@@ -482,7 +482,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
 			/* Forbid unused lines to be mapped as IRQs */
 			for (i = 0; i < sizeof(u32); i++)
 				if (stmpe_gpio->norequest_mask & BIT(i))
-					clear_bit(i, stmpe_gpio->chip.irq_valid_mask);
+					clear_bit(i, stmpe_gpio->chip.irq.valid_mask);
 		}
 		ret =  gpiochip_irqchip_add_nested(&stmpe_gpio->chip,
 						   &stmpe_gpio_irq_chip,
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 236a9f55a265..0bf844470693 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1504,33 +1504,33 @@ static struct gpio_chip *find_chip_by_name(const char *name)
 
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
-	if (!gpiochip->irq_need_valid_mask)
+	if (!gpiochip->irq.need_valid_mask)
 		return 0;
 
-	gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
+	gpiochip->irq.valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
 					   sizeof(long), GFP_KERNEL);
-	if (!gpiochip->irq_valid_mask)
+	if (!gpiochip->irq.valid_mask)
 		return -ENOMEM;
 
 	/* Assume by default all GPIOs are valid */
-	bitmap_fill(gpiochip->irq_valid_mask, gpiochip->ngpio);
+	bitmap_fill(gpiochip->irq.valid_mask, gpiochip->ngpio);
 
 	return 0;
 }
 
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
 {
-	kfree(gpiochip->irq_valid_mask);
-	gpiochip->irq_valid_mask = NULL;
+	kfree(gpiochip->irq.valid_mask);
+	gpiochip->irq.valid_mask = NULL;
 }
 
 static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
 				       unsigned int offset)
 {
 	/* No mask means all valid */
-	if (likely(!gpiochip->irq_valid_mask))
+	if (likely(!gpiochip->irq.valid_mask))
 		return true;
-	return test_bit(offset, gpiochip->irq_valid_mask);
+	return test_bit(offset, gpiochip->irq.valid_mask);
 }
 
 /**
diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 5897981e5ed3..9c1ca29c60b7 100644
--- a/drivers/pinctrl/intel/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -1660,7 +1660,7 @@ static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
 
 		value = readl(reg);
 		if (value & BYT_DIRECT_IRQ_EN) {
-			clear_bit(i, gc->irq_valid_mask);
+			clear_bit(i, gc->irq.valid_mask);
 			dev_dbg(dev, "excluding GPIO %d from IRQ domain\n", i);
 		} else if ((value & BYT_PIN_MUX) == byt_get_gpio_mux(vg, i)) {
 			byt_gpio_clear_triggering(vg, i);
@@ -1703,7 +1703,7 @@ static int byt_gpio_probe(struct byt_gpio *vg)
 	gc->can_sleep	= false;
 	gc->parent	= &vg->pdev->dev;
 	gc->ngpio	= vg->soc_data->npins;
-	gc->irq_need_valid_mask	= true;
+	gc->irq.need_valid_mask	= true;
 
 #ifdef CONFIG_PM_SLEEP
 	vg->saved_context = devm_kcalloc(&vg->pdev->dev, gc->ngpio,
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index 1cd7043edbc1..e23def322de2 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -1584,7 +1584,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 	chip->label = dev_name(pctrl->dev);
 	chip->parent = pctrl->dev;
 	chip->base = -1;
-	chip->irq_need_valid_mask = need_valid_mask;
+	chip->irq.need_valid_mask = need_valid_mask;
 
 	ret = devm_gpiochip_add_data(pctrl->dev, chip, pctrl);
 	if (ret) {
@@ -1616,7 +1616,7 @@ static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
 		intsel >>= CHV_PADCTRL0_INTSEL_SHIFT;
 
 		if (need_valid_mask && intsel >= pctrl->community->nirqs)
-			clear_bit(i, chip->irq_valid_mask);
+			clear_bit(i, chip->irq.valid_mask);
 	}
 
 	/* Clear all interrupts */
diff --git a/drivers/platform/x86/intel_int0002_vgpio.c b/drivers/platform/x86/intel_int0002_vgpio.c
index f6b3af73dea5..f7b67e898abc 100644
--- a/drivers/platform/x86/intel_int0002_vgpio.c
+++ b/drivers/platform/x86/intel_int0002_vgpio.c
@@ -165,7 +165,7 @@ static int int0002_probe(struct platform_device *pdev)
 	chip->direction_output = int0002_gpio_direction_output;
 	chip->base = -1;
 	chip->ngpio = GPE0A_PME_B0_VIRT_GPIO_PIN + 1;
-	chip->irq_need_valid_mask = true;
+	chip->irq.need_valid_mask = true;
 
 	ret = devm_gpiochip_add_data(&pdev->dev, chip, NULL);
 	if (ret) {
@@ -173,7 +173,7 @@ static int int0002_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	bitmap_clear(chip->irq_valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
+	bitmap_clear(chip->irq.valid_mask, 0, GPE0A_PME_B0_VIRT_GPIO_PIN);
 
 	/*
 	 * We manually request the irq here instead of passing a flow-handler
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 1c3d06fe54b1..067efcd4f46d 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -99,6 +99,21 @@ struct gpio_irq_chip {
 	 * True if set the interrupt handling is nested.
 	 */
 	bool nested;
+
+	/**
+	 * @need_valid_mask:
+	 *
+	 * If set core allocates @valid_mask with all bits set to one.
+	 */
+	bool need_valid_mask;
+
+	/**
+	 * @valid_mask:
+	 *
+	 * If not %NULL holds bitmask of GPIOs which are valid to be included
+	 * in IRQ domain of the chip.
+	 */
+	unsigned long *valid_mask;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -170,10 +185,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
- *	bits set to one
- * @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
- *	be included in IRQ domain of the chip
  * @lock_key: per GPIO IRQ chip lockdep class
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
@@ -244,8 +255,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	bool			irq_need_valid_mask;
-	unsigned long		*irq_valid_mask;
 	struct lock_class_key	*lock_key;
 
 	/**
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 09/12] gpio: Move lock_key into struct gpio_irq_chip
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (7 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 08/12] gpio: Move irq_valid_mask " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 10/12] gpio: Implement tighter IRQ chip integration Thierry Reding
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

In order to consolidate the multiple ways to associate an IRQ chip with
a GPIO chip, move more fields into the new struct gpio_irq_chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 4 ++--
 include/linux/gpio/driver.h | 9 +++++++--
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 0bf844470693..685a05caf1ba 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1646,7 +1646,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 	 * This lock class tells lockdep that GPIO irqs are in a different
 	 * category than their parents, so it won't report false recursion.
 	 */
-	irq_set_lockdep_class(irq, chip->lock_key);
+	irq_set_lockdep_class(irq, chip->irq.lock_key);
 	irq_set_chip_and_handler(irq, chip->irq.chip, chip->irq.handler);
 	/* Chips that use nested thread handlers have them marked */
 	if (chip->irq.nested)
@@ -1830,7 +1830,7 @@ int gpiochip_irqchip_add_key(struct gpio_chip *gpiochip,
 	gpiochip->irq.handler = handler;
 	gpiochip->irq.default_type = type;
 	gpiochip->to_irq = gpiochip_to_irq;
-	gpiochip->lock_key = lock_key;
+	gpiochip->irq.lock_key = lock_key;
 	gpiochip->irq.domain = irq_domain_add_simple(of_node,
 					gpiochip->ngpio, first_irq,
 					&gpiochip_domain_ops, gpiochip);
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 067efcd4f46d..c363ee198ff9 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -62,6 +62,13 @@ struct gpio_irq_chip {
 	 */
 	unsigned int default_type;
 
+	/**
+	 * @lock_key:
+	 *
+	 * Per GPIO IRQ chip lockdep class.
+	 */
+	struct lock_class_key *lock_key;
+
 	/**
 	 * @parent_handler:
 	 *
@@ -185,7 +192,6 @@ static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
  *	safely.
  * @bgpio_dir: shadowed direction register for generic GPIO to clear/set
  *	direction safely.
- * @lock_key: per GPIO IRQ chip lockdep class
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
@@ -255,7 +261,6 @@ struct gpio_chip {
 	 * With CONFIG_GPIOLIB_IRQCHIP we get an irqchip inside the gpiolib
 	 * to handle IRQs for most practical cases.
 	 */
-	struct lock_class_key	*lock_key;
 
 	/**
 	 * @irq:
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 10/12] gpio: Implement tighter IRQ chip integration
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (8 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 09/12] gpio: Move lock_key " Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 11/12] gpio: Export gpiochip_irq_{map,unmap}() Thierry Reding
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

Currently GPIO drivers are required to add the GPIO chip and its
corresponding IRQ chip separately, which can result in a lot of
boilerplate. Use the newly introduced struct gpio_irq_chip, embedded in
struct gpio_chip, that drivers can fill in if they want the GPIO core
to automatically register the IRQ chip associated with a GPIO chip.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 124 +++++++++++++++++++++++++++++++++++++++++++-
 include/linux/gpio/driver.h |   7 +++
 2 files changed, 129 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 685a05caf1ba..5bc99d08d538 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -72,6 +72,7 @@ static LIST_HEAD(gpio_lookup_list);
 LIST_HEAD(gpio_devices);
 
 static void gpiochip_free_hogs(struct gpio_chip *chip);
+static int gpiochip_add_irqchip(struct gpio_chip *gpiochip);
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
@@ -1266,6 +1267,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
 	if (status)
 		goto err_remove_from_list;
 
+	status = gpiochip_add_irqchip(chip);
+	if (status)
+		goto err_remove_chip;
+
 	status = of_gpiochip_add(chip);
 	if (status)
 		goto err_remove_chip;
@@ -1707,9 +1712,119 @@ static void gpiochip_irq_relres(struct irq_data *d)
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
+	unsigned int irq;
+	int err;
+
 	if (!gpiochip_irqchip_irq_valid(chip, offset))
 		return -ENXIO;
-	return irq_create_mapping(chip->irq.domain, offset);
+
+	irq = irq_create_mapping(chip->irq.domain, offset);
+	if (!irq)
+		return 0;
+
+	if (chip->irq.map) {
+		err = irq_set_parent(irq, chip->irq.map[offset]);
+		if (err < 0)
+			return err;
+	}
+
+	return irq;
+}
+
+/**
+ * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
+ * @gpiochip: the GPIO chip to add the IRQ chip to
+ */
+static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
+{
+	struct irq_chip *irqchip = gpiochip->irq.chip;
+	const struct irq_domain_ops *ops;
+	struct device_node *np;
+	unsigned int type;
+	unsigned int i;
+
+	if (!irqchip)
+		return 0;
+
+	if (gpiochip->irq.parent_handler && gpiochip->can_sleep) {
+		chip_err(gpiochip, "you cannot have chained interrupts on a "
+			 "chip that may sleep\n");
+		return -EINVAL;
+	}
+
+	type = gpiochip->irq.default_type;
+	np = gpiochip->parent->of_node;
+
+#ifdef CONFIG_OF_GPIO
+	/*
+	 * If the gpiochip has an assigned OF node this takes precedence
+	 * FIXME: get rid of this and use gpiochip->parent->of_node
+	 * everywhere
+	 */
+	if (gpiochip->of_node)
+		np = gpiochip->of_node;
+#endif
+
+	/*
+	 * Specifying a default trigger is a terrible idea if DT or ACPI is
+	 * used to configure the interrupts, as you may end up with
+	 * conflicting triggers. Tell the user, and reset to NONE.
+	 */
+	if (WARN(np && type != IRQ_TYPE_NONE,
+		 "%s: Ignoring %u default trigger\n", np->full_name, type))
+		type = IRQ_TYPE_NONE;
+
+	if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {
+		acpi_handle_warn(ACPI_HANDLE(gpiochip->parent),
+				 "Ignoring %u default trigger\n", type);
+		type = IRQ_TYPE_NONE;
+	}
+
+	gpiochip->to_irq = gpiochip_to_irq;
+	gpiochip->irq.default_type = type;
+
+	if (gpiochip->irq.domain_ops)
+		ops = gpiochip->irq.domain_ops;
+	else
+		ops = &gpiochip_domain_ops;
+
+	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
+						     0, ops, gpiochip);
+	if (!gpiochip->irq.domain)
+		return -EINVAL;
+
+	/*
+	 * It is possible for a driver to override this, but only if the
+	 * alternative functions are both implemented.
+	 */
+	if (!irqchip->irq_request_resources &&
+	    !irqchip->irq_release_resources) {
+		irqchip->irq_request_resources = gpiochip_irq_reqres;
+		irqchip->irq_release_resources = gpiochip_irq_relres;
+	}
+
+	if (gpiochip->irq.parent_handler) {
+		void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
+
+		for (i = 0; i < gpiochip->irq.num_parents; i++) {
+			/*
+			 * The parent IRQ chip is already using the chip_data
+			 * for this IRQ chip, so our callbacks simply use the
+			 * handler_data.
+			 */
+			irq_set_chained_handler_and_data(gpiochip->irq.parents[i],
+							 gpiochip->irq.parent_handler,
+							 data);
+		}
+
+		gpiochip->irq.nested = false;
+	} else {
+		gpiochip->irq.nested = true;
+	}
+
+	acpi_gpiochip_request_interrupts(gpiochip);
+
+	return 0;
 }
 
 /**
@@ -1724,7 +1839,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
-	if (gpiochip->irq.num_parents > 0) {
+	if (gpiochip->irq.chip) {
 		struct gpio_irq_chip *irq = &gpiochip->irq;
 		unsigned int i;
 
@@ -1857,6 +1972,11 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
+static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
+{
+	return 0;
+}
+
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
 static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
 {
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index c363ee198ff9..51fc7b023364 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -100,6 +100,13 @@ struct gpio_irq_chip {
 	 */
 	unsigned int *parents;
 
+	/**
+	 * @map:
+	 *
+	 * A list of interrupt parents for each line of a GPIO chip.
+	 */
+	unsigned int *map;
+
 	/**
 	 * @nested:
 	 *
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 11/12] gpio: Export gpiochip_irq_{map,unmap}()
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (9 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 10/12] gpio: Implement tighter IRQ chip integration Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-02 17:49 ` [PATCH v6 12/12] gpio: Add Tegra186 support Thierry Reding
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

Export these functions so that drivers can explicitly use these when
setting up their IRQ domain.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
 drivers/gpio/gpiolib.c      | 8 +++++---
 include/linux/gpio/driver.h | 4 ++++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5bc99d08d538..c65322532906 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1638,8 +1638,8 @@ EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
  * gpiochip by assigning the gpiochip as chip data, and using the irqchip
  * stored inside the gpiochip.
  */
-static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
-			    irq_hw_number_t hwirq)
+int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
+		     irq_hw_number_t hwirq)
 {
 	struct gpio_chip *chip = d->host_data;
 
@@ -1667,8 +1667,9 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(gpiochip_irq_map);
 
-static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
+void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 {
 	struct gpio_chip *chip = d->host_data;
 
@@ -1677,6 +1678,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 	irq_set_chip_and_handler(irq, NULL, NULL);
 	irq_set_chip_data(irq, NULL);
 }
+EXPORT_SYMBOL_GPL(gpiochip_irq_unmap);
 
 static const struct irq_domain_ops gpiochip_domain_ops = {
 	.map	= gpiochip_irq_map,
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 51fc7b023364..bbe5c647f29d 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -367,6 +367,10 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
 
 #ifdef CONFIG_GPIOLIB_IRQCHIP
 
+int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
+		     irq_hw_number_t hwirq);
+void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq);
+
 void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
 		struct irq_chip *irqchip,
 		unsigned int parent_irq,
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* [PATCH v6 12/12] gpio: Add Tegra186 support
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (10 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 11/12] gpio: Export gpiochip_irq_{map,unmap}() Thierry Reding
@ 2017-11-02 17:49 ` Thierry Reding
  2017-11-03 22:30 ` [PATCH v6 00/12] gpio: Tight IRQ chip integration Grygorii Strashko
  2017-11-03 22:50 ` Linus Walleij
  13 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-02 17:49 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

From: Thierry Reding <treding@nvidia.com>

Tegra186 has two GPIO controllers that are largely register compatible
between one another but are completely different from the controller
found on earlier generations.

Signed-off-by: Thierry Reding <treding@nvidia.com>
---
Changes in v4:
- use platform_irq_count() instead of of_irq_count()

Changes in v3:
- make use of GPIOLIB_IRQCHIP for IRQ chip handling

Changes in v2:
- add pin names to allow easy lookup using the chardev interface
- distinguish AON and main GPIO controllers by label
- use gpiochip_get_data() instead of container_of()
- use C99 initializers
---
 drivers/gpio/Kconfig         |   9 +
 drivers/gpio/Makefile        |   1 +
 drivers/gpio/gpio-tegra186.c | 623 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 633 insertions(+)
 create mode 100644 drivers/gpio/gpio-tegra186.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 9feb8e1ff2ff..4ed6a7967784 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -441,6 +441,15 @@ config GPIO_TEGRA
 	help
 	  Say yes here to support GPIO pins on NVIDIA Tegra SoCs.
 
+config GPIO_TEGRA186
+	tristate "NVIDIA Tegra186 GPIO support"
+	default ARCH_TEGRA_186_SOC
+	depends on ARCH_TEGRA_186_SOC || COMPILE_TEST
+	depends on OF_GPIO
+	select GPIOLIB_IRQCHIP
+	help
+	  Say yes here to support GPIO pins on NVIDIA Tegra186 SoCs.
+
 config GPIO_TS4800
 	tristate "TS-4800 DIO blocks and compatibles"
 	depends on OF_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index ac4b7c34a668..120e79c0ebb2 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -114,6 +114,7 @@ obj-$(CONFIG_GPIO_SYSCON)	+= gpio-syscon.o
 obj-$(CONFIG_GPIO_TB10X)	+= gpio-tb10x.o
 obj-$(CONFIG_GPIO_TC3589X)	+= gpio-tc3589x.o
 obj-$(CONFIG_GPIO_TEGRA)	+= gpio-tegra.o
+obj-$(CONFIG_GPIO_TEGRA186)	+= gpio-tegra186.o
 obj-$(CONFIG_GPIO_THUNDERX)	+= gpio-thunderx.o
 obj-$(CONFIG_GPIO_TIMBERDALE)	+= gpio-timberdale.o
 obj-$(CONFIG_GPIO_PALMAS)	+= gpio-palmas.o
diff --git a/drivers/gpio/gpio-tegra186.c b/drivers/gpio/gpio-tegra186.c
new file mode 100644
index 000000000000..b55b5ca882c7
--- /dev/null
+++ b/drivers/gpio/gpio-tegra186.c
@@ -0,0 +1,623 @@
+/*
+ * Copyright (c) 2016-2017 NVIDIA Corporation
+ *
+ * Author: Thierry Reding <treding@nvidia.com>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ */
+
+#include <linux/gpio/driver.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+
+#include <dt-bindings/gpio/tegra186-gpio.h>
+
+#define TEGRA186_GPIO_ENABLE_CONFIG 0x00
+#define  TEGRA186_GPIO_ENABLE_CONFIG_ENABLE BIT(0)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_OUT BIT(1)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_NONE (0x0 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL (0x1 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE (0x2 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE (0x3 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK (0x3 << 2)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL BIT(4)
+#define  TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT BIT(6)
+
+#define TEGRA186_GPIO_DEBOUNCE_CONTROL 0x04
+#define  TEGRA186_GPIO_DEBOUNCE_CONTROL_THRESHOLD(x) ((x) & 0xff)
+
+#define TEGRA186_GPIO_INPUT 0x08
+#define  TEGRA186_GPIO_INPUT_HIGH BIT(0)
+
+#define TEGRA186_GPIO_OUTPUT_CONTROL 0x0c
+#define  TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED BIT(0)
+
+#define TEGRA186_GPIO_OUTPUT_VALUE 0x10
+#define  TEGRA186_GPIO_OUTPUT_VALUE_HIGH BIT(0)
+
+#define TEGRA186_GPIO_INTERRUPT_CLEAR 0x14
+
+#define TEGRA186_GPIO_INTERRUPT_STATUS(x) (0x100 + (x) * 4)
+
+struct tegra_gpio_port {
+	const char *name;
+	unsigned int offset;
+	unsigned int pins;
+	unsigned int irq;
+};
+
+struct tegra_gpio_soc {
+	const struct tegra_gpio_port *ports;
+	unsigned int num_ports;
+	const char *name;
+};
+
+struct tegra_gpio {
+	struct gpio_chip gpio;
+	struct irq_chip intc;
+	unsigned int num_irq;
+	unsigned int *irq;
+
+	const struct tegra_gpio_soc *soc;
+
+	void __iomem *base;
+};
+
+static const struct tegra_gpio_port *
+tegra186_gpio_get_port(struct tegra_gpio *gpio, unsigned int *pin)
+{
+	unsigned int start = 0, i;
+
+	for (i = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+
+		if (*pin >= start && *pin < start + port->pins) {
+			*pin -= start;
+			return port;
+		}
+
+		start += port->pins;
+	}
+
+	return NULL;
+}
+
+static void __iomem *tegra186_gpio_get_base(struct tegra_gpio *gpio,
+					    unsigned int pin)
+{
+	const struct tegra_gpio_port *port;
+
+	port = tegra186_gpio_get_port(gpio, &pin);
+	if (!port)
+		return NULL;
+
+	return gpio->base + port->offset + pin * 0x20;
+}
+
+static int tegra186_gpio_get_direction(struct gpio_chip *chip,
+				       unsigned int offset)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
+		return 0;
+
+	return 1;
+}
+
+static int tegra186_gpio_direction_input(struct gpio_chip *chip,
+					 unsigned int offset)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL);
+	value |= TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
+	writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL);
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_OUT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+	return 0;
+}
+
+static int tegra186_gpio_direction_output(struct gpio_chip *chip,
+					  unsigned int offset, int level)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	/* configure output level first */
+	chip->set(chip, offset, level);
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -EINVAL;
+
+	/* set the direction */
+	value = readl(base + TEGRA186_GPIO_OUTPUT_CONTROL);
+	value &= ~TEGRA186_GPIO_OUTPUT_CONTROL_FLOATED;
+	writel(value, base + TEGRA186_GPIO_OUTPUT_CONTROL);
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_ENABLE;
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_OUT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+	return 0;
+}
+
+static int tegra186_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	if (value & TEGRA186_GPIO_ENABLE_CONFIG_OUT)
+		value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE);
+	else
+		value = readl(base + TEGRA186_GPIO_INPUT);
+
+	return value & BIT(0);
+}
+
+static void tegra186_gpio_set(struct gpio_chip *chip, unsigned int offset,
+			      int level)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, offset);
+	if (WARN_ON(base == NULL))
+		return;
+
+	value = readl(base + TEGRA186_GPIO_OUTPUT_VALUE);
+	if (level == 0)
+		value &= ~TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
+	else
+		value |= TEGRA186_GPIO_OUTPUT_VALUE_HIGH;
+
+	writel(value, base + TEGRA186_GPIO_OUTPUT_VALUE);
+}
+
+static int tegra186_gpio_of_xlate(struct gpio_chip *chip,
+				  const struct of_phandle_args *spec,
+				  u32 *flags)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(chip);
+	unsigned int port, pin, i, offset = 0;
+
+	if (WARN_ON(chip->of_gpio_n_cells < 2))
+		return -EINVAL;
+
+	if (WARN_ON(spec->args_count < chip->of_gpio_n_cells))
+		return -EINVAL;
+
+	port = spec->args[0] / 8;
+	pin = spec->args[0] % 8;
+
+	if (port >= gpio->soc->num_ports) {
+		dev_err(chip->parent, "invalid port number: %u\n", port);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < port; i++)
+		offset += gpio->soc->ports[i].pins;
+
+	if (flags)
+		*flags = spec->args[1];
+
+	return offset + pin;
+}
+
+static void tegra186_irq_ack(struct irq_data *data)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return;
+
+	writel(1, base + TEGRA186_GPIO_INTERRUPT_CLEAR);
+}
+
+static void tegra186_irq_mask(struct irq_data *data)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+}
+
+static void tegra186_irq_unmask(struct irq_data *data)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value |= TEGRA186_GPIO_ENABLE_CONFIG_INTERRUPT;
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+}
+
+static int tegra186_irq_set_type(struct irq_data *data, unsigned int flow)
+{
+	struct tegra_gpio *gpio = irq_data_get_irq_chip_data(data);
+	void __iomem *base;
+	u32 value;
+
+	base = tegra186_gpio_get_base(gpio, data->hwirq);
+	if (WARN_ON(base == NULL))
+		return -ENODEV;
+
+	value = readl(base + TEGRA186_GPIO_ENABLE_CONFIG);
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_MASK;
+	value &= ~TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+
+	switch (flow & IRQ_TYPE_SENSE_MASK) {
+	case IRQ_TYPE_NONE:
+		break;
+
+	case IRQ_TYPE_EDGE_RISING:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_SINGLE_EDGE;
+		break;
+
+	case IRQ_TYPE_EDGE_BOTH:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_DOUBLE_EDGE;
+		break;
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL;
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_LEVEL;
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		value |= TEGRA186_GPIO_ENABLE_CONFIG_TRIGGER_TYPE_LEVEL;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	writel(value, base + TEGRA186_GPIO_ENABLE_CONFIG);
+
+	if ((flow & IRQ_TYPE_EDGE_BOTH) == 0)
+		irq_set_handler_locked(data, handle_level_irq);
+	else
+		irq_set_handler_locked(data, handle_edge_irq);
+
+	return 0;
+}
+
+static void tegra186_gpio_irq(struct irq_desc *desc)
+{
+	struct tegra_gpio *gpio = irq_desc_get_handler_data(desc);
+	struct irq_domain *domain = gpio->gpio.irq.domain;
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	unsigned int parent = irq_desc_get_irq(desc);
+	unsigned int i, offset = 0;
+
+	chained_irq_enter(chip, desc);
+
+	for (i = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+		void __iomem *base = gpio->base + port->offset;
+		unsigned int pin, irq;
+		unsigned long value;
+
+		/* skip ports that are not associated with this controller */
+		if (parent != gpio->irq[port->irq])
+			goto skip;
+
+		value = readl(base + TEGRA186_GPIO_INTERRUPT_STATUS(1));
+
+		for_each_set_bit(pin, &value, port->pins) {
+			irq = irq_find_mapping(domain, offset + pin);
+			if (WARN_ON(irq == 0))
+				continue;
+
+			generic_handle_irq(irq);
+		}
+
+skip:
+		offset += port->pins;
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static int tegra186_gpio_irq_domain_xlate(struct irq_domain *domain,
+					  struct device_node *np,
+					  const u32 *spec, unsigned int size,
+					  unsigned long *hwirq,
+					  unsigned int *type)
+{
+	struct tegra_gpio *gpio = gpiochip_get_data(domain->host_data);
+	unsigned int port, pin, i, offset = 0;
+
+	if (size < 2)
+		return -EINVAL;
+
+	port = spec[0] / 8;
+	pin = spec[0] % 8;
+
+	if (port >= gpio->soc->num_ports) {
+		dev_err(gpio->gpio.parent, "invalid port number: %u\n", port);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < port; i++)
+		offset += gpio->soc->ports[i].pins;
+
+	*type = spec[1] & IRQ_TYPE_SENSE_MASK;
+	*hwirq = offset + pin;
+
+	return 0;
+}
+
+static const struct irq_domain_ops tegra186_gpio_irq_domain_ops = {
+	.map = gpiochip_irq_map,
+	.unmap = gpiochip_irq_unmap,
+	.xlate = tegra186_gpio_irq_domain_xlate,
+};
+
+static struct lock_class_key tegra186_gpio_lock_class;
+
+static int tegra186_gpio_probe(struct platform_device *pdev)
+{
+	unsigned int i, j, offset;
+	struct gpio_irq_chip *irq;
+	struct tegra_gpio *gpio;
+	struct resource *res;
+	char **names;
+	int err;
+
+	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
+	if (!gpio)
+		return -ENOMEM;
+
+	gpio->soc = of_device_get_match_data(&pdev->dev);
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gpio");
+	gpio->base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(gpio->base))
+		return PTR_ERR(gpio->base);
+
+	err = platform_irq_count(pdev);
+	if (err < 0)
+		return err;
+
+	gpio->num_irq = err;
+
+	gpio->irq = devm_kcalloc(&pdev->dev, gpio->num_irq, sizeof(*gpio->irq),
+				 GFP_KERNEL);
+	if (!gpio->irq)
+		return -ENOMEM;
+
+	for (i = 0; i < gpio->num_irq; i++) {
+		err = platform_get_irq(pdev, i);
+		if (err < 0)
+			return err;
+
+		gpio->irq[i] = err;
+	}
+
+	gpio->gpio.label = gpio->soc->name;
+	gpio->gpio.parent = &pdev->dev;
+
+	gpio->gpio.get_direction = tegra186_gpio_get_direction;
+	gpio->gpio.direction_input = tegra186_gpio_direction_input;
+	gpio->gpio.direction_output = tegra186_gpio_direction_output;
+	gpio->gpio.get = tegra186_gpio_get,
+	gpio->gpio.set = tegra186_gpio_set;
+
+	gpio->gpio.base = -1;
+
+	for (i = 0; i < gpio->soc->num_ports; i++)
+		gpio->gpio.ngpio += gpio->soc->ports[i].pins;
+
+	names = devm_kcalloc(gpio->gpio.parent, gpio->gpio.ngpio,
+			     sizeof(*names), GFP_KERNEL);
+	if (!names)
+		return -ENOMEM;
+
+	for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+		char *name;
+
+		for (j = 0; j < port->pins; j++) {
+			name = devm_kasprintf(gpio->gpio.parent, GFP_KERNEL,
+					      "P%s.%02x", port->name, j);
+			if (!name)
+				return -ENOMEM;
+
+			names[offset + j] = name;
+		}
+
+		offset += port->pins;
+	}
+
+	gpio->gpio.names = (const char * const *)names;
+
+	gpio->gpio.of_node = pdev->dev.of_node;
+	gpio->gpio.of_gpio_n_cells = 2;
+	gpio->gpio.of_xlate = tegra186_gpio_of_xlate;
+
+	gpio->intc.name = pdev->dev.of_node->name;
+	gpio->intc.irq_ack = tegra186_irq_ack;
+	gpio->intc.irq_mask = tegra186_irq_mask;
+	gpio->intc.irq_unmask = tegra186_irq_unmask;
+	gpio->intc.irq_set_type = tegra186_irq_set_type;
+
+	irq = &gpio->gpio.irq;
+	irq->chip = &gpio->intc;
+	irq->domain_ops = &tegra186_gpio_irq_domain_ops;
+	irq->handler = handle_simple_irq;
+	irq->lock_key = &tegra186_gpio_lock_class;
+	irq->default_type = IRQ_TYPE_NONE;
+	irq->parent_handler = tegra186_gpio_irq;
+	irq->parent_handler_data = gpio;
+	irq->num_parents = gpio->num_irq;
+	irq->parents = gpio->irq;
+
+	irq->map = devm_kcalloc(&pdev->dev, gpio->gpio.ngpio,
+				sizeof(*irq->map), GFP_KERNEL);
+	if (!irq->map)
+		return -ENOMEM;
+
+	for (i = 0, offset = 0; i < gpio->soc->num_ports; i++) {
+		const struct tegra_gpio_port *port = &gpio->soc->ports[i];
+
+		for (j = 0; j < port->pins; j++)
+			irq->map[offset + j] = irq->parents[port->irq];
+
+		offset += port->pins;
+	}
+
+	platform_set_drvdata(pdev, gpio);
+
+	err = devm_gpiochip_add_data(&pdev->dev, &gpio->gpio, gpio);
+	if (err < 0)
+		return err;
+
+	return 0;
+}
+
+static int tegra186_gpio_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+#define TEGRA_MAIN_GPIO_PORT(port, base, count, controller)	\
+	[TEGRA_MAIN_GPIO_PORT_##port] = {			\
+		.name = #port,					\
+		.offset = base,					\
+		.pins = count,					\
+		.irq = controller,				\
+	}
+
+static const struct tegra_gpio_port tegra186_main_ports[] = {
+	TEGRA_MAIN_GPIO_PORT( A, 0x2000, 7, 2),
+	TEGRA_MAIN_GPIO_PORT( B, 0x3000, 7, 3),
+	TEGRA_MAIN_GPIO_PORT( C, 0x3200, 7, 3),
+	TEGRA_MAIN_GPIO_PORT( D, 0x3400, 6, 3),
+	TEGRA_MAIN_GPIO_PORT( E, 0x2200, 8, 2),
+	TEGRA_MAIN_GPIO_PORT( F, 0x2400, 6, 2),
+	TEGRA_MAIN_GPIO_PORT( G, 0x4200, 6, 4),
+	TEGRA_MAIN_GPIO_PORT( H, 0x1000, 7, 1),
+	TEGRA_MAIN_GPIO_PORT( I, 0x0800, 8, 0),
+	TEGRA_MAIN_GPIO_PORT( J, 0x5000, 8, 5),
+	TEGRA_MAIN_GPIO_PORT( K, 0x5200, 1, 5),
+	TEGRA_MAIN_GPIO_PORT( L, 0x1200, 8, 1),
+	TEGRA_MAIN_GPIO_PORT( M, 0x5600, 6, 5),
+	TEGRA_MAIN_GPIO_PORT( N, 0x0000, 7, 0),
+	TEGRA_MAIN_GPIO_PORT( O, 0x0200, 4, 0),
+	TEGRA_MAIN_GPIO_PORT( P, 0x4000, 7, 4),
+	TEGRA_MAIN_GPIO_PORT( Q, 0x0400, 6, 0),
+	TEGRA_MAIN_GPIO_PORT( R, 0x0a00, 6, 0),
+	TEGRA_MAIN_GPIO_PORT( T, 0x0600, 4, 0),
+	TEGRA_MAIN_GPIO_PORT( X, 0x1400, 8, 1),
+	TEGRA_MAIN_GPIO_PORT( Y, 0x1600, 7, 1),
+	TEGRA_MAIN_GPIO_PORT(BB, 0x2600, 2, 2),
+	TEGRA_MAIN_GPIO_PORT(CC, 0x5400, 4, 5),
+};
+
+static const struct tegra_gpio_soc tegra186_main_soc = {
+	.num_ports = ARRAY_SIZE(tegra186_main_ports),
+	.ports = tegra186_main_ports,
+	.name = "tegra186-gpio",
+};
+
+#define TEGRA_AON_GPIO_PORT(port, base, count, controller)	\
+	[TEGRA_AON_GPIO_PORT_##port] = {			\
+		.name = #port,					\
+		.offset = base,					\
+		.pins = count,					\
+		.irq = controller,				\
+	}
+
+static const struct tegra_gpio_port tegra186_aon_ports[] = {
+	TEGRA_AON_GPIO_PORT( S, 0x0200, 5, 0),
+	TEGRA_AON_GPIO_PORT( U, 0x0400, 6, 0),
+	TEGRA_AON_GPIO_PORT( V, 0x0800, 8, 0),
+	TEGRA_AON_GPIO_PORT( W, 0x0a00, 8, 0),
+	TEGRA_AON_GPIO_PORT( Z, 0x0e00, 4, 0),
+	TEGRA_AON_GPIO_PORT(AA, 0x0c00, 8, 0),
+	TEGRA_AON_GPIO_PORT(EE, 0x0600, 3, 0),
+	TEGRA_AON_GPIO_PORT(FF, 0x0000, 5, 0),
+};
+
+static const struct tegra_gpio_soc tegra186_aon_soc = {
+	.num_ports = ARRAY_SIZE(tegra186_aon_ports),
+	.ports = tegra186_aon_ports,
+	.name = "tegra186-gpio-aon",
+};
+
+static const struct of_device_id tegra186_gpio_of_match[] = {
+	{
+		.compatible = "nvidia,tegra186-gpio",
+		.data = &tegra186_main_soc
+	}, {
+		.compatible = "nvidia,tegra186-gpio-aon",
+		.data = &tegra186_aon_soc
+	}, {
+		/* sentinel */
+	}
+};
+
+static struct platform_driver tegra186_gpio_driver = {
+	.driver = {
+		.name = "tegra186-gpio",
+		.of_match_table = tegra186_gpio_of_match,
+	},
+	.probe = tegra186_gpio_probe,
+	.remove = tegra186_gpio_remove,
+};
+module_platform_driver(tegra186_gpio_driver);
+
+MODULE_DESCRIPTION("NVIDIA Tegra186 GPIO controller driver");
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_LICENSE("GPL v2");
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (11 preceding siblings ...)
  2017-11-02 17:49 ` [PATCH v6 12/12] gpio: Add Tegra186 support Thierry Reding
@ 2017-11-03 22:30 ` Grygorii Strashko
  2017-11-06 11:18   ` Thierry Reding
  2017-11-03 22:50 ` Linus Walleij
  13 siblings, 1 reply; 25+ messages in thread
From: Grygorii Strashko @ 2017-11-03 22:30 UTC (permalink / raw)
  To: Thierry Reding, Linus Walleij
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

Hi 

On 11/02/2017 12:49 PM, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
> 
> Hi Linus,
> 
> here's the latest series of patches that implement the tighter IRQ chip
> integration. I've dropped the banked infrastructure for now as per the
> discussion with Grygorii.
> 
> The first couple of patches are mostly preparatory work in order to
> consolidate all IRQ chip related fields in a new structure and create
> the base functionality for adding IRQ chips.
> 
> After that, I've added the Tegra186 GPIO support patch that makes use of
> the new tight integration.
> 
> Changes in v6:
> - rebased on latest linux-gpio devel branch
> - one patch dropped due to rebase
> 
> Changes in v5:
> - dropped the banked infrastructure patches for now (Grygorii)
> - allocate interrupts on demand, rather than upfront (Grygorii)
> - split up the first patch further as requested by Grygorii
> 
> Not sure what happened in between here. Notes in commit logs indicate
> that this is actually version 5, but I can't find the cover letter for
> v3 and v4.
> 
> Changes in v2:
> - rename pins to lines for consistent terminology
> - rename gpio_irq_chip_banked_handler() to
>    gpio_irq_chip_banked_chained_handler()
> 

Sry, for delayed reply, very sorry.

Patches 1 - 9, 11 : looks good, so
Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>

Patch 10 - unfortunately not all my comment were incorporated [1], 
so below diff on top of patch 10
which illustrates what i want and also converts gpio-omap to use new infra as
test for this new infra.

Pls, take a look

[1] https://www.spinics.net/lists/linux-tegra/msg31145.html

-- regards,
-grygorii

-----------><-------------
>From 210fe3ad7a642691a1b7603e441f6980b10ff2b4 Mon Sep 17 00:00:00 2001
From: Grygorii Strashko <grygorii.strashko@ti.com>
Date: Fri, 3 Nov 2017 17:24:51 -0500
Subject: [PATCH] [not for merge] gpiolib: update and test new gpioirq chip
 infra

changes in gpiolib:
 - move set_parent to gpiochip_irq_map() and use parents instead of map for only
   one parent
 - add gpio_irq_chip->first_irq for static IRQ allocation
 - fix nested = true if parent_handler not set
 - fix gpiochip_irqchip_remove() if parent_handler not set
 - get of_node from gpiodev
 - fix lock_key: drivers do not need to set it, but looks a bit overcomplicated
   as lock_class_key will be created for each gpiochip_add_data() call.
   Honestly, do not seem better way :(

GPIO OMAP driver updated to use new gpioirq chip infra and tested on am335x-evm.
seems it's working - can see irqs from keys.

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
 drivers/gpio/gpio-omap.c    | 36 ++++++++++++++--------------
 drivers/gpio/gpiolib.c      | 58 +++++++++++++++++++--------------------------
 include/linux/gpio/driver.h | 32 ++++++++++++++++++++++++-
 3 files changed, 73 insertions(+), 53 deletions(-)

diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index ce27d6a..4048f18 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1054,6 +1054,7 @@ static void omap_gpio_mod_init(struct gpio_bank *bank)
 
 static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
 {
+	struct gpio_irq_chip *irq;
 	static int gpio;
 	int irq_base = 0;
 	int ret;
@@ -1081,16 +1082,6 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
 	}
 	bank->chip.ngpio = bank->width;
 
-	ret = gpiochip_add_data(&bank->chip, bank);
-	if (ret) {
-		dev_err(bank->chip.parent,
-			"Could not register gpio chip %d\n", ret);
-		return ret;
-	}
-
-	if (!bank->is_mpuio)
-		gpio += bank->width;
-
 #ifdef CONFIG_ARCH_OMAP1
 	/*
 	 * REVISIT: Once we have OMAP1 supporting SPARSE_IRQ, we can drop
@@ -1111,25 +1102,34 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc)
 			irqc->irq_set_wake = NULL;
 	}
 
-	ret = gpiochip_irqchip_add(&bank->chip, irqc,
-				   irq_base, handle_bad_irq,
-				   IRQ_TYPE_NONE);
+	irq = &bank->chip.irq;
+	irq->chip = irqc;
+//	irq->domain_ops = not required;
+	irq->handler = handle_bad_irq;
+//	irq->lock_key = not required;
+	irq->default_type = IRQ_TYPE_NONE;
+//	irq->parent_handler = not used by this driver;
+//	irq->parent_handler_data = not used by this driver;
+	irq->num_parents = 1;
+	irq->parents = &bank->irq;
+	irq->first_irq = irq_base;
 
+	ret = gpiochip_add_data(&bank->chip, bank);
 	if (ret) {
 		dev_err(bank->chip.parent,
-			"Couldn't add irqchip to gpiochip %d\n", ret);
-		gpiochip_remove(&bank->chip);
-		return -ENODEV;
+			"Could not register gpio chip %d\n", ret);
+		return ret;
 	}
 
-	gpiochip_set_chained_irqchip(&bank->chip, irqc, bank->irq, NULL);
-
 	ret = devm_request_irq(bank->chip.parent, bank->irq,
 			       omap_gpio_irq_handler,
 			       0, dev_name(bank->chip.parent), bank);
 	if (ret)
 		gpiochip_remove(&bank->chip);
 
+	if (!bank->is_mpuio)
+		gpio += bank->width;
+
 	return ret;
 }
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 5bc99d0..d11b4df 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -72,7 +72,8 @@ static LIST_HEAD(gpio_lookup_list);
 LIST_HEAD(gpio_devices);
 
 static void gpiochip_free_hogs(struct gpio_chip *chip);
-static int gpiochip_add_irqchip(struct gpio_chip *gpiochip);
+static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
+				    struct lock_class_key *lock_key);
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
 static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
 static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
@@ -1121,7 +1122,8 @@ static void gpiochip_setup_devs(void)
  * chip->base is invalid or already associated with a different chip.
  * Otherwise it returns zero as a success code.
  */
-int gpiochip_add_data(struct gpio_chip *chip, void *data)
+int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
+			  struct lock_class_key *irq_lock_key)
 {
 	unsigned long	flags;
 	int		status = 0;
@@ -1267,7 +1269,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
 	if (status)
 		goto err_remove_from_list;
 
-	status = gpiochip_add_irqchip(chip);
+	status = gpiochip_add_irqchip_key(chip, irq_lock_key);
 	if (status)
 		goto err_remove_chip;
 
@@ -1642,6 +1644,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 			    irq_hw_number_t hwirq)
 {
 	struct gpio_chip *chip = d->host_data;
+	int err = 0;
 
 	if (!gpiochip_irqchip_irq_valid(chip, hwirq))
 		return -ENXIO;
@@ -1658,6 +1661,12 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
 		irq_set_nested_thread(irq, 1);
 	irq_set_noprobe(irq);
 
+	if (chip->irq.num_parents == 1)
+		err = irq_set_parent(irq, chip->irq.parents[0]);
+	else if (chip->irq.map)
+		err = irq_set_parent(irq, chip->irq.map[hwirq]);
+	if (err < 0)
+		return err;
 	/*
 	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
 	 * is passed as default type.
@@ -1712,30 +1721,18 @@ static void gpiochip_irq_relres(struct irq_data *d)
 
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
-	unsigned int irq;
-	int err;
-
 	if (!gpiochip_irqchip_irq_valid(chip, offset))
 		return -ENXIO;
 
-	irq = irq_create_mapping(chip->irq.domain, offset);
-	if (!irq)
-		return 0;
-
-	if (chip->irq.map) {
-		err = irq_set_parent(irq, chip->irq.map[offset]);
-		if (err < 0)
-			return err;
-	}
-
-	return irq;
+	return irq_create_mapping(chip->irq.domain, offset);
 }
 
 /**
  * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
  * @gpiochip: the GPIO chip to add the IRQ chip to
  */
-static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
+static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
+				    struct lock_class_key *lock_key)
 {
 	struct irq_chip *irqchip = gpiochip->irq.chip;
 	const struct irq_domain_ops *ops;
@@ -1753,17 +1750,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 	}
 
 	type = gpiochip->irq.default_type;
-	np = gpiochip->parent->of_node;
-
-#ifdef CONFIG_OF_GPIO
-	/*
-	 * If the gpiochip has an assigned OF node this takes precedence
-	 * FIXME: get rid of this and use gpiochip->parent->of_node
-	 * everywhere
-	 */
-	if (gpiochip->of_node)
-		np = gpiochip->of_node;
-#endif
+	/* called from gpiochip_add_data() and is set properly */
+	np = gpiochip->gpiodev->dev.of_node;
 
 	/*
 	 * Specifying a default trigger is a terrible idea if DT or ACPI is
@@ -1789,7 +1777,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		ops = &gpiochip_domain_ops;
 
 	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
-						     0, ops, gpiochip);
+						     gpiochip->irq.first_irq,
+						     ops, gpiochip);
 	if (!gpiochip->irq.domain)
 		return -EINVAL;
 
@@ -1818,9 +1807,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
 		}
 
 		gpiochip->irq.nested = false;
-	} else {
-		gpiochip->irq.nested = true;
 	}
+	/* GPIO driver might not specify parent_handler, but it doesn't mean
+	 * it's irq_nested, as driver may use request_irq() */
 
 	acpi_gpiochip_request_interrupts(gpiochip);
 
@@ -1839,7 +1828,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 
 	acpi_gpiochip_free_interrupts(gpiochip);
 
-	if (gpiochip->irq.chip) {
+	if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
 		struct gpio_irq_chip *irq = &gpiochip->irq;
 		unsigned int i;
 
@@ -1972,7 +1961,8 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
 
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
-static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
+static inline int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
+					   struct lock_class_key *lock_key)
 {
 	return 0;
 }
diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
index 51fc7b0..3254996 100644
--- a/include/linux/gpio/driver.h
+++ b/include/linux/gpio/driver.h
@@ -128,6 +128,15 @@ struct gpio_irq_chip {
 	 * in IRQ domain of the chip.
 	 */
 	unsigned long *valid_mask;
+
+	/**
+	 * @first_irq:
+	 *
+	 * Required for static irq allocation.
+	 * if set irq_domain_add_simple() will allocate and map all IRQs
+	 * during initialization.
+	 */
+	unsigned int first_irq;
 };
 
 static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
@@ -312,8 +321,29 @@ struct gpio_chip {
 extern const char *gpiochip_is_requested(struct gpio_chip *chip,
 			unsigned offset);
 
+extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
+				 struct lock_class_key *irq_lock_key);
+#ifdef CONFIG_LOCKDEP
+/*
+ * Lockdep requires that each irqchip instance be created with a
+ * unique key so as to avoid unnecessary warnings. This upfront
+ * boilerplate static inlines provides such a key for each
+ * unique instance which is created now from inside gpiochip_add_data_key().
+ */
+static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
+{
+	static struct lock_class_key key;
+
+	return gpiochip_add_data_key(chip, data, key);
+}
+
+#else
+static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
+{
+	return gpiochip_add_data_key(chip, data, NULL);
+}
+#endif /* CONFIG_LOCKDEP */
 /* add/remove chips */
-extern int gpiochip_add_data(struct gpio_chip *chip, void *data);
 static inline int gpiochip_add(struct gpio_chip *chip)
 {
 	return gpiochip_add_data(chip, NULL);
-- 
2.10.5

^ permalink raw reply related	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
                   ` (12 preceding siblings ...)
  2017-11-03 22:30 ` [PATCH v6 00/12] gpio: Tight IRQ chip integration Grygorii Strashko
@ 2017-11-03 22:50 ` Linus Walleij
  2017-11-03 23:50   ` Grygorii Strashko
  13 siblings, 1 reply; 25+ messages in thread
From: Linus Walleij @ 2017-11-03 22:50 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

On Thu, Nov 2, 2017 at 6:49 PM, Thierry Reding <thierry.reding@gmail.com> wrote:

> here's the latest series of patches that implement the tighter IRQ chip
> integration. I've dropped the banked infrastructure for now as per the
> discussion with Grygorii.

And I really liked that part.

> The first couple of patches are mostly preparatory work in order to
> consolidate all IRQ chip related fields in a new structure and create
> the base functionality for adding IRQ chips.
>
> After that, I've added the Tegra186 GPIO support patch that makes use of
> the new tight integration.
>
> Changes in v6:
> - rebased on latest linux-gpio devel branch
> - one patch dropped due to rebase

I guess I will consider queueing them already for v4.15 if
Torvalds churns out another -rc on sunday, I do not
doubt that you will finish it as we have discussed with banks and
all. If v4.14 is released on sunday let's queue this early for v4.16.

Yours,
Linus Walleij

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-03 22:50 ` Linus Walleij
@ 2017-11-03 23:50   ` Grygorii Strashko
  2017-11-06 13:22     ` Linus Walleij
  0 siblings, 1 reply; 25+ messages in thread
From: Grygorii Strashko @ 2017-11-03 23:50 UTC (permalink / raw)
  To: Linus Walleij, Thierry Reding
  Cc: Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

hi Linus,

On 11/03/2017 05:50 PM, Linus Walleij wrote:
> On Thu, Nov 2, 2017 at 6:49 PM, Thierry Reding <thierry.reding@gmail.com> wrote:
> 
>> here's the latest series of patches that implement the tighter IRQ chip
>> integration. I've dropped the banked infrastructure for now as per the
>> discussion with Grygorii.
> 
> And I really liked that part.
> 
>> The first couple of patches are mostly preparatory work in order to
>> consolidate all IRQ chip related fields in a new structure and create
>> the base functionality for adding IRQ chips.
>>
>> After that, I've added the Tegra186 GPIO support patch that makes use of
>> the new tight integration.
>>
>> Changes in v6:
>> - rebased on latest linux-gpio devel branch
>> - one patch dropped due to rebase
> 
> I guess I will consider queueing them already for v4.15 if
> Torvalds churns out another -rc on sunday, I do not
> doubt that you will finish it as we have discussed with banks and
> all. If v4.14 is released on sunday let's queue this early for v4.16.

Can you see my reply?
https://lkml.org/lkml/2017/11/3/820

-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-03 22:30 ` [PATCH v6 00/12] gpio: Tight IRQ chip integration Grygorii Strashko
@ 2017-11-06 11:18   ` Thierry Reding
  2017-11-06 23:13     ` Grygorii Strashko
  0 siblings, 1 reply; 25+ messages in thread
From: Thierry Reding @ 2017-11-06 11:18 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 9783 bytes --]

On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
> Hi 
> 
> On 11/02/2017 12:49 PM, Thierry Reding wrote:
> > From: Thierry Reding <treding@nvidia.com>
> > 
> > Hi Linus,
> > 
> > here's the latest series of patches that implement the tighter IRQ chip
> > integration. I've dropped the banked infrastructure for now as per the
> > discussion with Grygorii.
> > 
> > The first couple of patches are mostly preparatory work in order to
> > consolidate all IRQ chip related fields in a new structure and create
> > the base functionality for adding IRQ chips.
> > 
> > After that, I've added the Tegra186 GPIO support patch that makes use of
> > the new tight integration.
> > 
> > Changes in v6:
> > - rebased on latest linux-gpio devel branch
> > - one patch dropped due to rebase
> > 
> > Changes in v5:
> > - dropped the banked infrastructure patches for now (Grygorii)
> > - allocate interrupts on demand, rather than upfront (Grygorii)
> > - split up the first patch further as requested by Grygorii
> > 
> > Not sure what happened in between here. Notes in commit logs indicate
> > that this is actually version 5, but I can't find the cover letter for
> > v3 and v4.
> > 
> > Changes in v2:
> > - rename pins to lines for consistent terminology
> > - rename gpio_irq_chip_banked_handler() to
> >    gpio_irq_chip_banked_chained_handler()
> > 
> 
> Sry, for delayed reply, very sorry.
> 
> Patches 1 - 9, 11 : looks good, so
> Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
> 
> Patch 10 - unfortunately not all my comment were incorporated [1], 
> so below diff on top of patch 10
> which illustrates what i want and also converts gpio-omap to use new infra as
> test for this new infra.
> 
> Pls, take a look
> 
> [1] https://www.spinics.net/lists/linux-tegra/msg31145.html

Most of the changes I had deemed to be material for follow-up patches
since they aren't immediately relevant to the gpio_irq_chip conversion
nor needed by the Tegra186 patch.

However, a couple of the hunks below seem like they should be part of
the initial series.

> -----------><-------------
> From 210fe3ad7a642691a1b7603e441f6980b10ff2b4 Mon Sep 17 00:00:00 2001
> From: Grygorii Strashko <grygorii.strashko@ti.com>
> Date: Fri, 3 Nov 2017 17:24:51 -0500
> Subject: [PATCH] [not for merge] gpiolib: update and test new gpioirq chip
>  infra
> 
> changes in gpiolib:
>  - move set_parent to gpiochip_irq_map() and use parents instead of map for only
>    one parent
>  - add gpio_irq_chip->first_irq for static IRQ allocation
>  - fix nested = true if parent_handler not set
>  - fix gpiochip_irqchip_remove() if parent_handler not set
>  - get of_node from gpiodev
>  - fix lock_key: drivers do not need to set it, but looks a bit overcomplicated
>    as lock_class_key will be created for each gpiochip_add_data() call.
>    Honestly, do not seem better way :(
> 
> GPIO OMAP driver updated to use new gpioirq chip infra and tested on am335x-evm.
> seems it's working - can see irqs from keys.
> 
> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> ---
>  drivers/gpio/gpio-omap.c    | 36 ++++++++++++++--------------
>  drivers/gpio/gpiolib.c      | 58 +++++++++++++++++++--------------------------
>  include/linux/gpio/driver.h | 32 ++++++++++++++++++++++++-
>  3 files changed, 73 insertions(+), 53 deletions(-)
[...]
> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
[...]
> @@ -1642,6 +1644,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
>  			    irq_hw_number_t hwirq)
>  {
>  	struct gpio_chip *chip = d->host_data;
> +	int err = 0;
>  
>  	if (!gpiochip_irqchip_irq_valid(chip, hwirq))
>  		return -ENXIO;
> @@ -1658,6 +1661,12 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
>  		irq_set_nested_thread(irq, 1);
>  	irq_set_noprobe(irq);
>  
> +	if (chip->irq.num_parents == 1)
> +		err = irq_set_parent(irq, chip->irq.parents[0]);
> +	else if (chip->irq.map)
> +		err = irq_set_parent(irq, chip->irq.map[hwirq]);
> +	if (err < 0)
> +		return err;

Yeah, this looks sensible. Both in that this is a slightly better place
to call it and that the handling for num_parents == 1 is necessary, too.

>  	/*
>  	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
>  	 * is passed as default type.
> @@ -1712,30 +1721,18 @@ static void gpiochip_irq_relres(struct irq_data *d)
>  
>  static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>  {
> -	unsigned int irq;
> -	int err;
> -
>  	if (!gpiochip_irqchip_irq_valid(chip, offset))
>  		return -ENXIO;
>  
> -	irq = irq_create_mapping(chip->irq.domain, offset);
> -	if (!irq)
> -		return 0;
> -
> -	if (chip->irq.map) {
> -		err = irq_set_parent(irq, chip->irq.map[offset]);
> -		if (err < 0)
> -			return err;
> -	}
> -
> -	return irq;
> +	return irq_create_mapping(chip->irq.domain, offset);
>  }
>  
>  /**
>   * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
>   * @gpiochip: the GPIO chip to add the IRQ chip to
>   */
> -static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> +static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
> +				    struct lock_class_key *lock_key)
>  {
>  	struct irq_chip *irqchip = gpiochip->irq.chip;
>  	const struct irq_domain_ops *ops;
> @@ -1753,17 +1750,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>  	}
>  
>  	type = gpiochip->irq.default_type;
> -	np = gpiochip->parent->of_node;
> -
> -#ifdef CONFIG_OF_GPIO
> -	/*
> -	 * If the gpiochip has an assigned OF node this takes precedence
> -	 * FIXME: get rid of this and use gpiochip->parent->of_node
> -	 * everywhere
> -	 */
> -	if (gpiochip->of_node)
> -		np = gpiochip->of_node;
> -#endif
> +	/* called from gpiochip_add_data() and is set properly */
> +	np = gpiochip->gpiodev->dev.of_node;

Indeed, looks like we have this twice now.

>  
>  	/*
>  	 * Specifying a default trigger is a terrible idea if DT or ACPI is
> @@ -1789,7 +1777,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>  		ops = &gpiochip_domain_ops;
>  
>  	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
> -						     0, ops, gpiochip);
> +						     gpiochip->irq.first_irq,
> +						     ops, gpiochip);
>  	if (!gpiochip->irq.domain)
>  		return -EINVAL;

This seems backward. You just spent a lot of time getting rid of all
users of first_irq (it's actually the reason why I dropped one of the
patches from the series, since first_irq is no longer used), so why
reintroduce it?

>  
> @@ -1818,9 +1807,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>  		}
>  
>  		gpiochip->irq.nested = false;
> -	} else {
> -		gpiochip->irq.nested = true;
>  	}
> +	/* GPIO driver might not specify parent_handler, but it doesn't mean
> +	 * it's irq_nested, as driver may use request_irq() */

That's certainly how irq_nested is used in gpiolib, though. Interrupts
are considered either cascaded or nested. Maybe this needs clarification
in general?

>  
>  	acpi_gpiochip_request_interrupts(gpiochip);
>  
> @@ -1839,7 +1828,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>  
>  	acpi_gpiochip_free_interrupts(gpiochip);
>  
> -	if (gpiochip->irq.chip) {
> +	if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
>  		struct gpio_irq_chip *irq = &gpiochip->irq;
>  		unsigned int i;
>  

Yeah, this seems like a good idea, though I think this is safe
regardless of irq.parent_handler.

> @@ -1972,7 +1961,8 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>  
>  #else /* CONFIG_GPIOLIB_IRQCHIP */
>  
> -static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> +static inline int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
> +					   struct lock_class_key *lock_key)
>  {
>  	return 0;
>  }
> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> index 51fc7b0..3254996 100644
> --- a/include/linux/gpio/driver.h
> +++ b/include/linux/gpio/driver.h
> @@ -128,6 +128,15 @@ struct gpio_irq_chip {
>  	 * in IRQ domain of the chip.
>  	 */
>  	unsigned long *valid_mask;
> +
> +	/**
> +	 * @first_irq:
> +	 *
> +	 * Required for static irq allocation.
> +	 * if set irq_domain_add_simple() will allocate and map all IRQs
> +	 * during initialization.
> +	 */
> +	unsigned int first_irq;

Again, what was the point of removing all users of this if we need to
add it again?

It seems to me like dynamic allocation should be a prerequisite for
drivers to use this new code, otherwise we'll just end up adding special
cases to this otherwise generic code.

>  };
>  
>  static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
> @@ -312,8 +321,29 @@ struct gpio_chip {
>  extern const char *gpiochip_is_requested(struct gpio_chip *chip,
>  			unsigned offset);
>  
> +extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
> +				 struct lock_class_key *irq_lock_key);
> +#ifdef CONFIG_LOCKDEP
> +/*
> + * Lockdep requires that each irqchip instance be created with a
> + * unique key so as to avoid unnecessary warnings. This upfront
> + * boilerplate static inlines provides such a key for each
> + * unique instance which is created now from inside gpiochip_add_data_key().
> + */
> +static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
> +{
> +	static struct lock_class_key key;
> +
> +	return gpiochip_add_data_key(chip, data, key);
> +}

This looks like a neat improvement, but I think it can be done in a
follow-up to remove the boilerplate in drivers.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-03 23:50   ` Grygorii Strashko
@ 2017-11-06 13:22     ` Linus Walleij
  2017-11-06 14:36       ` Thierry Reding
  0 siblings, 1 reply; 25+ messages in thread
From: Linus Walleij @ 2017-11-06 13:22 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Thierry Reding, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

On Sat, Nov 4, 2017 at 12:50 AM, Grygorii Strashko
<grygorii.strashko@ti.com> wrote:
> On 11/03/2017 05:50 PM, Linus Walleij wrote:

>> I guess I will consider queueing them already for v4.15 if
>> Torvalds churns out another -rc on sunday, I do not
>> doubt that you will finish it as we have discussed with banks and
>> all. If v4.14 is released on sunday let's queue this early for v4.16.
>
> Can you see my reply?
> https://lkml.org/lkml/2017/11/3/820

Yes so I was considering queueing patches 1-9 with your ACK so
Thierry can get his patch stack down and focus on the add-on
stuff at the end of the series.

Thierry, does it sound reasonable?

Linus Walleij

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-06 13:22     ` Linus Walleij
@ 2017-11-06 14:36       ` Thierry Reding
  0 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-06 14:36 UTC (permalink / raw)
  To: Linus Walleij
  Cc: Grygorii Strashko, Jonathan Hunter, linux-gpio, linux-tegra,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1348 bytes --]

On Mon, Nov 06, 2017 at 02:22:22PM +0100, Linus Walleij wrote:
> On Sat, Nov 4, 2017 at 12:50 AM, Grygorii Strashko
> <grygorii.strashko@ti.com> wrote:
> > On 11/03/2017 05:50 PM, Linus Walleij wrote:
> 
> >> I guess I will consider queueing them already for v4.15 if
> >> Torvalds churns out another -rc on sunday, I do not
> >> doubt that you will finish it as we have discussed with banks and
> >> all. If v4.14 is released on sunday let's queue this early for v4.16.
> >
> > Can you see my reply?
> > https://lkml.org/lkml/2017/11/3/820
> 
> Yes so I was considering queueing patches 1-9 with your ACK so
> Thierry can get his patch stack down and focus on the add-on
> stuff at the end of the series.
> 
> Thierry, does it sound reasonable?

Sure. I'd still like to see Tegra186 support go into 4.15 to unblock a
bunch of things. Like I mentioned in my reply to Grygorii earlier, the
bigger part of the changes can be follow-on patches in my opinion since
they become only relevant as other drivers are converted.

I've been running with some changes proposed by Grygorii applied to my
local tree and can send they can all be squashed into patch 10 to at
least address most of Grygorii's comments. Should I send it as follow-
up or do you want me to resend a v7 of 10-12 with those changes squashed
in?

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-06 11:18   ` Thierry Reding
@ 2017-11-06 23:13     ` Grygorii Strashko
  2017-11-07 11:13       ` Thierry Reding
  0 siblings, 1 reply; 25+ messages in thread
From: Grygorii Strashko @ 2017-11-06 23:13 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 11/06/2017 05:18 AM, Thierry Reding wrote:
> On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
>> Hi
>>
>> On 11/02/2017 12:49 PM, Thierry Reding wrote:
>>> From: Thierry Reding <treding@nvidia.com>
>>>
>>> Hi Linus,
>>>
>>> here's the latest series of patches that implement the tighter IRQ chip
>>> integration. I've dropped the banked infrastructure for now as per the
>>> discussion with Grygorii.
>>>
>>> The first couple of patches are mostly preparatory work in order to
>>> consolidate all IRQ chip related fields in a new structure and create
>>> the base functionality for adding IRQ chips.
>>>
>>> After that, I've added the Tegra186 GPIO support patch that makes use of
>>> the new tight integration.
>>>
>>> Changes in v6:
>>> - rebased on latest linux-gpio devel branch
>>> - one patch dropped due to rebase
>>>
>>> Changes in v5:
>>> - dropped the banked infrastructure patches for now (Grygorii)
>>> - allocate interrupts on demand, rather than upfront (Grygorii)
>>> - split up the first patch further as requested by Grygorii
>>>
>>> Not sure what happened in between here. Notes in commit logs indicate
>>> that this is actually version 5, but I can't find the cover letter for
>>> v3 and v4.
>>>
>>> Changes in v2:
>>> - rename pins to lines for consistent terminology
>>> - rename gpio_irq_chip_banked_handler() to
>>>     gpio_irq_chip_banked_chained_handler()
>>>
>>
>> Sry, for delayed reply, very sorry.
>>
>> Patches 1 - 9, 11 : looks good, so
>> Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
>>
>> Patch 10 - unfortunately not all my comment were incorporated [1],
>> so below diff on top of patch 10
>> which illustrates what i want and also converts gpio-omap to use new infra as
>> test for this new infra.
>>
>> Pls, take a look
>>
>> [1] https://www.spinics.net/lists/linux-tegra/msg31145.html
> 
> Most of the changes I had deemed to be material for follow-up patches
> since they aren't immediately relevant to the gpio_irq_chip conversion
> nor needed by the Tegra186 patch.
> 
> However, a couple of the hunks below seem like they should be part of
> the initial series.
> 
>> -----------><-------------
>>  From 210fe3ad7a642691a1b7603e441f6980b10ff2b4 Mon Sep 17 00:00:00 2001
>> From: Grygorii Strashko <grygorii.strashko@ti.com>
>> Date: Fri, 3 Nov 2017 17:24:51 -0500
>> Subject: [PATCH] [not for merge] gpiolib: update and test new gpioirq chip
>>   infra
>>
>> changes in gpiolib:
>>   - move set_parent to gpiochip_irq_map() and use parents instead of map for only
>>     one parent
>>   - add gpio_irq_chip->first_irq for static IRQ allocation
>>   - fix nested = true if parent_handler not set
>>   - fix gpiochip_irqchip_remove() if parent_handler not set
>>   - get of_node from gpiodev
>>   - fix lock_key: drivers do not need to set it, but looks a bit overcomplicated
>>     as lock_class_key will be created for each gpiochip_add_data() call.
>>     Honestly, do not seem better way :(
>>
>> GPIO OMAP driver updated to use new gpioirq chip infra and tested on am335x-evm.
>> seems it's working - can see irqs from keys.
>>
>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>> ---
>>   drivers/gpio/gpio-omap.c    | 36 ++++++++++++++--------------
>>   drivers/gpio/gpiolib.c      | 58 +++++++++++++++++++--------------------------
>>   include/linux/gpio/driver.h | 32 ++++++++++++++++++++++++-
>>   3 files changed, 73 insertions(+), 53 deletions(-)
> [...]
>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> [...]
>> @@ -1642,6 +1644,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
>>   			    irq_hw_number_t hwirq)
>>   {
>>   	struct gpio_chip *chip = d->host_data;
>> +	int err = 0;
>>   
>>   	if (!gpiochip_irqchip_irq_valid(chip, hwirq))
>>   		return -ENXIO;
>> @@ -1658,6 +1661,12 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
>>   		irq_set_nested_thread(irq, 1);
>>   	irq_set_noprobe(irq);
>>   
>> +	if (chip->irq.num_parents == 1)
>> +		err = irq_set_parent(irq, chip->irq.parents[0]);
>> +	else if (chip->irq.map)
>> +		err = irq_set_parent(irq, chip->irq.map[hwirq]);
>> +	if (err < 0)
>> +		return err;
> 
> Yeah, this looks sensible. Both in that this is a slightly better place
> to call it and that the handling for num_parents == 1 is necessary, too.
> 
>>   	/*
>>   	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
>>   	 * is passed as default type.
>> @@ -1712,30 +1721,18 @@ static void gpiochip_irq_relres(struct irq_data *d)
>>   
>>   static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>>   {
>> -	unsigned int irq;
>> -	int err;
>> -
>>   	if (!gpiochip_irqchip_irq_valid(chip, offset))
>>   		return -ENXIO;
>>   
>> -	irq = irq_create_mapping(chip->irq.domain, offset);
>> -	if (!irq)
>> -		return 0;
>> -
>> -	if (chip->irq.map) {
>> -		err = irq_set_parent(irq, chip->irq.map[offset]);
>> -		if (err < 0)
>> -			return err;
>> -	}
>> -
>> -	return irq;
>> +	return irq_create_mapping(chip->irq.domain, offset);
>>   }
>>   
>>   /**
>>    * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
>>    * @gpiochip: the GPIO chip to add the IRQ chip to
>>    */
>> -static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>> +static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
>> +				    struct lock_class_key *lock_key)
>>   {
>>   	struct irq_chip *irqchip = gpiochip->irq.chip;
>>   	const struct irq_domain_ops *ops;
>> @@ -1753,17 +1750,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>   	}
>>   
>>   	type = gpiochip->irq.default_type;
>> -	np = gpiochip->parent->of_node;
>> -
>> -#ifdef CONFIG_OF_GPIO
>> -	/*
>> -	 * If the gpiochip has an assigned OF node this takes precedence
>> -	 * FIXME: get rid of this and use gpiochip->parent->of_node
>> -	 * everywhere
>> -	 */
>> -	if (gpiochip->of_node)
>> -		np = gpiochip->of_node;
>> -#endif
>> +	/* called from gpiochip_add_data() and is set properly */
>> +	np = gpiochip->gpiodev->dev.of_node;
> 
> Indeed, looks like we have this twice now.
> 
>>   
>>   	/*
>>   	 * Specifying a default trigger is a terrible idea if DT or ACPI is
>> @@ -1789,7 +1777,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>   		ops = &gpiochip_domain_ops;
>>   
>>   	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
>> -						     0, ops, gpiochip);
>> +						     gpiochip->irq.first_irq,
>> +						     ops, gpiochip);
>>   	if (!gpiochip->irq.domain)
>>   		return -EINVAL;
> 
> This seems backward. You just spent a lot of time getting rid of all
> users of first_irq (it's actually the reason why I dropped one of the
> patches from the series, since first_irq is no longer used), so why
> reintroduce it?

Yes. It required for HW/drivers not supported (or partially supported)
SPARSE_IRQ. And it's not exactly the same as dropped base_irq.
If SPARSE_IRQ not supported - driver should ensure that proper
 Linux IRQ range allocated (or reserved) and pass first_irq number to the gpiolib
For example, in case of OMAP GPIO this is required for OMAP1 support and
driver has code
  irq_base = devm_irq_alloc_descs(bank->chip.parent, -1, 0, bank->width, 0);

irq_base makes no sense in case of SPARSE_IRQ compatible driver and
therefore was removed from gpiolib to avoid mis-usage - drivers should
maintain it by itself if requred.

> 
>>   
>> @@ -1818,9 +1807,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>   		}
>>   
>>   		gpiochip->irq.nested = false;
>> -	} else {
>> -		gpiochip->irq.nested = true;
>>   	}
>> +	/* GPIO driver might not specify parent_handler, but it doesn't mean
>> +	 * it's irq_nested, as driver may use request_irq() */
> 
> That's certainly how irq_nested is used in gpiolib, though. Interrupts
> are considered either cascaded or nested. Maybe this needs clarification
> in general?

No. Please, take closer look at 
gpiochip_set_nested_irqchip() 
gpiochip_set_cascaded_irqchip()
gpiochip_set_chained_irqchip()
gpiochip_set_nested_irqchip()
 and how they are used.
Also, take a look on OMAP driver - it doesn't install chained handler.

gpiolib now can discover automatically only when child irqs are not nested
(nested here means - threaded nested), therefore different APIs were introduced
gpiochip_set_chained_irqchip()
gpiochip_set_nested_irqchip()

So, with your change:
- nested = false; can be set auto if parent_handler provided
- nested = <set by driver> if no parent_handler provided
because with this patch full GPIO IRQ configuration expected to be done
from inside  gpiochip_add_data().

> 
>>   
>>   	acpi_gpiochip_request_interrupts(gpiochip);
>>   
>> @@ -1839,7 +1828,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>>   
>>   	acpi_gpiochip_free_interrupts(gpiochip);
>>   
>> -	if (gpiochip->irq.chip) {
>> +	if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
>>   		struct gpio_irq_chip *irq = &gpiochip->irq;
>>   		unsigned int i;
>>   
> 
> Yeah, this seems like a good idea, though I think this is safe
> regardless of irq.parent_handler.
> 
>> @@ -1972,7 +1961,8 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>>   
>>   #else /* CONFIG_GPIOLIB_IRQCHIP */
>>   
>> -static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>> +static inline int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
>> +					   struct lock_class_key *lock_key)
>>   {
>>   	return 0;
>>   }
>> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
>> index 51fc7b0..3254996 100644
>> --- a/include/linux/gpio/driver.h
>> +++ b/include/linux/gpio/driver.h
>> @@ -128,6 +128,15 @@ struct gpio_irq_chip {
>>   	 * in IRQ domain of the chip.
>>   	 */
>>   	unsigned long *valid_mask;
>> +
>> +	/**
>> +	 * @first_irq:
>> +	 *
>> +	 * Required for static irq allocation.
>> +	 * if set irq_domain_add_simple() will allocate and map all IRQs
>> +	 * during initialization.
>> +	 */
>> +	unsigned int first_irq;
> 
> Again, what was the point of removing all users of this if we need to
> add it again?
> 
> It seems to me like dynamic allocation should be a prerequisite for
> drivers to use this new code, otherwise we'll just end up adding special
> cases to this otherwise generic code.

The idea, as i see it, is to be able to re-use you change for as much drivers
as possible (as I illustrated for OMAP) and in this case we need support backward
compatibility with non SPARSE_IRQ compatible drivers.

> 
>>   };
>>   
>>   static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
>> @@ -312,8 +321,29 @@ struct gpio_chip {
>>   extern const char *gpiochip_is_requested(struct gpio_chip *chip,
>>   			unsigned offset);
>>   
>> +extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
>> +				 struct  *irq_lock_key);
>> +#ifdef CONFIG_LOCKDEP
>> +/*
>> + * Lockdep requires that each irqchip instance be created with a
>> + * unique key so as to avoid unnecessary warnings. This upfront
>> + * boilerplate static inlines provides such a key for each
>> + * unique instance which is created now from inside gpiochip_add_data_key().
>> + */
>> +static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
>> +{
>> +	static struct lock_class_key key;
>> +
>> +	return gpiochip_add_data_key(chip, data, key);
>> +}
> 
> This looks like a neat improvement, but I think it can be done in a
> follow-up to remove the boilerplate in drivers.

Can't agree here - it better to be considered now. 
Now only two GPIO drivers define lock_class_key:
./drivers/gpio/gpio-bcm-kona.c:static struct lock_class_key gpio_lock_class;
./drivers/gpio/gpio-brcmstb.c:static struct lock_class_key brcmstb_gpio_irq_lock_class;

and these drivers do not use gpioirq framework (your tegra driver will be the third).

So, if proposed changes will be applied all drivers switched to use it will need to define
its own lock_class_key again and it will be step back.

Another question that solution I've proposed may be not ideal :(


-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-06 23:13     ` Grygorii Strashko
@ 2017-11-07 11:13       ` Thierry Reding
  2017-11-07 11:52         ` Thierry Reding
  2017-11-07 17:00         ` Grygorii Strashko
  0 siblings, 2 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-07 11:13 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 14881 bytes --]

On Mon, Nov 06, 2017 at 05:13:33PM -0600, Grygorii Strashko wrote:
> 
> 
> On 11/06/2017 05:18 AM, Thierry Reding wrote:
> > On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
> >> Hi
> >>
> >> On 11/02/2017 12:49 PM, Thierry Reding wrote:
> >>> From: Thierry Reding <treding@nvidia.com>
> >>>
> >>> Hi Linus,
> >>>
> >>> here's the latest series of patches that implement the tighter IRQ chip
> >>> integration. I've dropped the banked infrastructure for now as per the
> >>> discussion with Grygorii.
> >>>
> >>> The first couple of patches are mostly preparatory work in order to
> >>> consolidate all IRQ chip related fields in a new structure and create
> >>> the base functionality for adding IRQ chips.
> >>>
> >>> After that, I've added the Tegra186 GPIO support patch that makes use of
> >>> the new tight integration.
> >>>
> >>> Changes in v6:
> >>> - rebased on latest linux-gpio devel branch
> >>> - one patch dropped due to rebase
> >>>
> >>> Changes in v5:
> >>> - dropped the banked infrastructure patches for now (Grygorii)
> >>> - allocate interrupts on demand, rather than upfront (Grygorii)
> >>> - split up the first patch further as requested by Grygorii
> >>>
> >>> Not sure what happened in between here. Notes in commit logs indicate
> >>> that this is actually version 5, but I can't find the cover letter for
> >>> v3 and v4.
> >>>
> >>> Changes in v2:
> >>> - rename pins to lines for consistent terminology
> >>> - rename gpio_irq_chip_banked_handler() to
> >>>     gpio_irq_chip_banked_chained_handler()
> >>>
> >>
> >> Sry, for delayed reply, very sorry.
> >>
> >> Patches 1 - 9, 11 : looks good, so
> >> Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
> >>
> >> Patch 10 - unfortunately not all my comment were incorporated [1],
> >> so below diff on top of patch 10
> >> which illustrates what i want and also converts gpio-omap to use new infra as
> >> test for this new infra.
> >>
> >> Pls, take a look
> >>
> >> [1] https://www.spinics.net/lists/linux-tegra/msg31145.html
> > 
> > Most of the changes I had deemed to be material for follow-up patches
> > since they aren't immediately relevant to the gpio_irq_chip conversion
> > nor needed by the Tegra186 patch.
> > 
> > However, a couple of the hunks below seem like they should be part of
> > the initial series.
> > 
> >> -----------><-------------
> >>  From 210fe3ad7a642691a1b7603e441f6980b10ff2b4 Mon Sep 17 00:00:00 2001
> >> From: Grygorii Strashko <grygorii.strashko@ti.com>
> >> Date: Fri, 3 Nov 2017 17:24:51 -0500
> >> Subject: [PATCH] [not for merge] gpiolib: update and test new gpioirq chip
> >>   infra
> >>
> >> changes in gpiolib:
> >>   - move set_parent to gpiochip_irq_map() and use parents instead of map for only
> >>     one parent
> >>   - add gpio_irq_chip->first_irq for static IRQ allocation
> >>   - fix nested = true if parent_handler not set
> >>   - fix gpiochip_irqchip_remove() if parent_handler not set
> >>   - get of_node from gpiodev
> >>   - fix lock_key: drivers do not need to set it, but looks a bit overcomplicated
> >>     as lock_class_key will be created for each gpiochip_add_data() call.
> >>     Honestly, do not seem better way :(
> >>
> >> GPIO OMAP driver updated to use new gpioirq chip infra and tested on am335x-evm.
> >> seems it's working - can see irqs from keys.
> >>
> >> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> >> ---
> >>   drivers/gpio/gpio-omap.c    | 36 ++++++++++++++--------------
> >>   drivers/gpio/gpiolib.c      | 58 +++++++++++++++++++--------------------------
> >>   include/linux/gpio/driver.h | 32 ++++++++++++++++++++++++-
> >>   3 files changed, 73 insertions(+), 53 deletions(-)
> > [...]
> >> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> > [...]
> >> @@ -1642,6 +1644,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
> >>   			    irq_hw_number_t hwirq)
> >>   {
> >>   	struct gpio_chip *chip = d->host_data;
> >> +	int err = 0;
> >>   
> >>   	if (!gpiochip_irqchip_irq_valid(chip, hwirq))
> >>   		return -ENXIO;
> >> @@ -1658,6 +1661,12 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
> >>   		irq_set_nested_thread(irq, 1);
> >>   	irq_set_noprobe(irq);
> >>   
> >> +	if (chip->irq.num_parents == 1)
> >> +		err = irq_set_parent(irq, chip->irq.parents[0]);
> >> +	else if (chip->irq.map)
> >> +		err = irq_set_parent(irq, chip->irq.map[hwirq]);
> >> +	if (err < 0)
> >> +		return err;
> > 
> > Yeah, this looks sensible. Both in that this is a slightly better place
> > to call it and that the handling for num_parents == 1 is necessary, too.
> > 
> >>   	/*
> >>   	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
> >>   	 * is passed as default type.
> >> @@ -1712,30 +1721,18 @@ static void gpiochip_irq_relres(struct irq_data *d)
> >>   
> >>   static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
> >>   {
> >> -	unsigned int irq;
> >> -	int err;
> >> -
> >>   	if (!gpiochip_irqchip_irq_valid(chip, offset))
> >>   		return -ENXIO;
> >>   
> >> -	irq = irq_create_mapping(chip->irq.domain, offset);
> >> -	if (!irq)
> >> -		return 0;
> >> -
> >> -	if (chip->irq.map) {
> >> -		err = irq_set_parent(irq, chip->irq.map[offset]);
> >> -		if (err < 0)
> >> -			return err;
> >> -	}
> >> -
> >> -	return irq;
> >> +	return irq_create_mapping(chip->irq.domain, offset);
> >>   }
> >>   
> >>   /**
> >>    * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
> >>    * @gpiochip: the GPIO chip to add the IRQ chip to
> >>    */
> >> -static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >> +static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
> >> +				    struct lock_class_key *lock_key)
> >>   {
> >>   	struct irq_chip *irqchip = gpiochip->irq.chip;
> >>   	const struct irq_domain_ops *ops;
> >> @@ -1753,17 +1750,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >>   	}
> >>   
> >>   	type = gpiochip->irq.default_type;
> >> -	np = gpiochip->parent->of_node;
> >> -
> >> -#ifdef CONFIG_OF_GPIO
> >> -	/*
> >> -	 * If the gpiochip has an assigned OF node this takes precedence
> >> -	 * FIXME: get rid of this and use gpiochip->parent->of_node
> >> -	 * everywhere
> >> -	 */
> >> -	if (gpiochip->of_node)
> >> -		np = gpiochip->of_node;
> >> -#endif
> >> +	/* called from gpiochip_add_data() and is set properly */
> >> +	np = gpiochip->gpiodev->dev.of_node;
> > 
> > Indeed, looks like we have this twice now.
> > 
> >>   
> >>   	/*
> >>   	 * Specifying a default trigger is a terrible idea if DT or ACPI is
> >> @@ -1789,7 +1777,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >>   		ops = &gpiochip_domain_ops;
> >>   
> >>   	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
> >> -						     0, ops, gpiochip);
> >> +						     gpiochip->irq.first_irq,
> >> +						     ops, gpiochip);
> >>   	if (!gpiochip->irq.domain)
> >>   		return -EINVAL;
> > 
> > This seems backward. You just spent a lot of time getting rid of all
> > users of first_irq (it's actually the reason why I dropped one of the
> > patches from the series, since first_irq is no longer used), so why
> > reintroduce it?
> 
> Yes. It required for HW/drivers not supported (or partially supported)
> SPARSE_IRQ. And it's not exactly the same as dropped base_irq.
> If SPARSE_IRQ not supported - driver should ensure that proper
>  Linux IRQ range allocated (or reserved) and pass first_irq number to the gpiolib
> For example, in case of OMAP GPIO this is required for OMAP1 support and
> driver has code
>   irq_base = devm_irq_alloc_descs(bank->chip.parent, -1, 0, bank->width, 0);
> 
> irq_base makes no sense in case of SPARSE_IRQ compatible driver and
> therefore was removed from gpiolib to avoid mis-usage - drivers should
> maintain it by itself if requred.

But this is not something that is currently being used. I understand
that you'll want to add this in order to support fixed IRQ numbers on
OMAP, but I don't see why it would need to be part of this series. It
will simply be dead code until the OMAP patches get merged.

> >> @@ -1818,9 +1807,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >>   		}
> >>   
> >>   		gpiochip->irq.nested = false;
> >> -	} else {
> >> -		gpiochip->irq.nested = true;
> >>   	}
> >> +	/* GPIO driver might not specify parent_handler, but it doesn't mean
> >> +	 * it's irq_nested, as driver may use request_irq() */
> > 
> > That's certainly how irq_nested is used in gpiolib, though. Interrupts
> > are considered either cascaded or nested. Maybe this needs clarification
> > in general?
> 
> No. Please, take closer look at 
> gpiochip_set_nested_irqchip() 
> gpiochip_set_cascaded_irqchip()
> gpiochip_set_chained_irqchip()
> gpiochip_set_nested_irqchip()
>  and how they are used.
> Also, take a look on OMAP driver - it doesn't install chained handler.
> 
> gpiolib now can discover automatically only when child irqs are not nested
> (nested here means - threaded nested), therefore different APIs were introduced
> gpiochip_set_chained_irqchip()
> gpiochip_set_nested_irqchip()
> 
> So, with your change:
> - nested = false; can be set auto if parent_handler provided
> - nested = <set by driver> if no parent_handler provided
> because with this patch full GPIO IRQ configuration expected to be done
> from inside  gpiochip_add_data().

Sorry if I'm being dense. The only user-callable functions currently are
gpiochip_set_chained_irqchip() and gpiochip_set_nested_irqchip(). Both
internally call gpiochip_set_cascaded_irqchip() and the only difference
is that the former passes a parent handler while the latter doesn't. So
this seems to me like exactly the same thing that gpiochip_add_irqchip()
does in my series.

I think there's some ambiguity in how irq_nested is currently being used
because it really means two things: a) not-chained and b) threaded. So I
think what we want is to separate these. For a) I think it's pretty much
solved because we have the parent handler that disambiguates. So instead
of just setting irq.nested = false when a parent handler is available we
should probably also WARN if the driver has set irq.nested = true and
force it to false.

Then, as you suggested, leave the else branch open to allow the driver
to specify whether or not it uses threaded handlers so that
gpiochip_irq_map() and gpiochip_irq_unmap() will know to call
irq_set_nested_thread().

In this case, perhaps it would be better to rename irq.nested to
irq.threaded. Then we no longer need to check/force irq.nested for
chained IRQ chips and instead use only irq.threaded to have interrupts
marked as nested/threaded.

> >>   
> >>   	acpi_gpiochip_request_interrupts(gpiochip);
> >>   
> >> @@ -1839,7 +1828,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
> >>   
> >>   	acpi_gpiochip_free_interrupts(gpiochip);
> >>   
> >> -	if (gpiochip->irq.chip) {
> >> +	if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
> >>   		struct gpio_irq_chip *irq = &gpiochip->irq;
> >>   		unsigned int i;
> >>   
> > 
> > Yeah, this seems like a good idea, though I think this is safe
> > regardless of irq.parent_handler.
> > 
> >> @@ -1972,7 +1961,8 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
> >>   
> >>   #else /* CONFIG_GPIOLIB_IRQCHIP */
> >>   
> >> -static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> >> +static inline int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
> >> +					   struct lock_class_key *lock_key)
> >>   {
> >>   	return 0;
> >>   }
> >> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
> >> index 51fc7b0..3254996 100644
> >> --- a/include/linux/gpio/driver.h
> >> +++ b/include/linux/gpio/driver.h
> >> @@ -128,6 +128,15 @@ struct gpio_irq_chip {
> >>   	 * in IRQ domain of the chip.
> >>   	 */
> >>   	unsigned long *valid_mask;
> >> +
> >> +	/**
> >> +	 * @first_irq:
> >> +	 *
> >> +	 * Required for static irq allocation.
> >> +	 * if set irq_domain_add_simple() will allocate and map all IRQs
> >> +	 * during initialization.
> >> +	 */
> >> +	unsigned int first_irq;
> > 
> > Again, what was the point of removing all users of this if we need to
> > add it again?
> > 
> > It seems to me like dynamic allocation should be a prerequisite for
> > drivers to use this new code, otherwise we'll just end up adding special
> > cases to this otherwise generic code.
> 
> The idea, as i see it, is to be able to re-use you change for as much drivers
> as possible (as I illustrated for OMAP) and in this case we need support backward
> compatibility with non SPARSE_IRQ compatible drivers.

Okay, understood. How about we focus on getting the current series
merged and then we can add this hunk as a preparator patch for the OMAP
conversion series?

> > 
> >>   };
> >>   
> >>   static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
> >> @@ -312,8 +321,29 @@ struct gpio_chip {
> >>   extern const char *gpiochip_is_requested(struct gpio_chip *chip,
> >>   			unsigned offset);
> >>   
> >> +extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
> >> +				 struct  *irq_lock_key);
> >> +#ifdef CONFIG_LOCKDEP
> >> +/*
> >> + * Lockdep requires that each irqchip instance be created with a
> >> + * unique key so as to avoid unnecessary warnings. This upfront
> >> + * boilerplate static inlines provides such a key for each
> >> + * unique instance which is created now from inside gpiochip_add_data_key().
> >> + */
> >> +static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
> >> +{
> >> +	static struct lock_class_key key;
> >> +
> >> +	return gpiochip_add_data_key(chip, data, key);
> >> +}
> > 
> > This looks like a neat improvement, but I think it can be done in a
> > follow-up to remove the boilerplate in drivers.
> 
> Can't agree here - it better to be considered now. 
> Now only two GPIO drivers define lock_class_key:
> ./drivers/gpio/gpio-bcm-kona.c:static struct lock_class_key gpio_lock_class;
> ./drivers/gpio/gpio-brcmstb.c:static struct lock_class_key brcmstb_gpio_irq_lock_class;
> 
> and these drivers do not use gpioirq framework (your tegra driver will be the third).
> 
> So, if proposed changes will be applied all drivers switched to use it will need to define
> its own lock_class_key again and it will be step back.

I think this would be a minor, mostly mechanical refactoring to do as
follow-up. But since you feel very strongly about it, I'll add that into
the series.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-07 11:13       ` Thierry Reding
@ 2017-11-07 11:52         ` Thierry Reding
  2017-11-07 16:49           ` Grygorii Strashko
  2017-11-07 17:00         ` Grygorii Strashko
  1 sibling, 1 reply; 25+ messages in thread
From: Thierry Reding @ 2017-11-07 11:52 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 2343 bytes --]

On Tue, Nov 07, 2017 at 12:13:44PM +0100, Thierry Reding wrote:
> On Mon, Nov 06, 2017 at 05:13:33PM -0600, Grygorii Strashko wrote:
> > On 11/06/2017 05:18 AM, Thierry Reding wrote:
> > > On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
[...]
> > >> @@ -312,8 +321,29 @@ struct gpio_chip {
> > >>   extern const char *gpiochip_is_requested(struct gpio_chip *chip,
> > >>   			unsigned offset);
> > >>   
> > >> +extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
> > >> +				 struct  *irq_lock_key);
> > >> +#ifdef CONFIG_LOCKDEP
> > >> +/*
> > >> + * Lockdep requires that each irqchip instance be created with a
> > >> + * unique key so as to avoid unnecessary warnings. This upfront
> > >> + * boilerplate static inlines provides such a key for each
> > >> + * unique instance which is created now from inside gpiochip_add_data_key().
> > >> + */
> > >> +static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
> > >> +{
> > >> +	static struct lock_class_key key;
> > >> +
> > >> +	return gpiochip_add_data_key(chip, data, key);
> > >> +}
> > > 
> > > This looks like a neat improvement, but I think it can be done in a
> > > follow-up to remove the boilerplate in drivers.
> > 
> > Can't agree here - it better to be considered now. 
> > Now only two GPIO drivers define lock_class_key:
> > ./drivers/gpio/gpio-bcm-kona.c:static struct lock_class_key gpio_lock_class;
> > ./drivers/gpio/gpio-brcmstb.c:static struct lock_class_key brcmstb_gpio_irq_lock_class;
> > 
> > and these drivers do not use gpioirq framework (your tegra driver will be the third).
> > 
> > So, if proposed changes will be applied all drivers switched to use it will need to define
> > its own lock_class_key again and it will be step back.
> 
> I think this would be a minor, mostly mechanical refactoring to do as
> follow-up. But since you feel very strongly about it, I'll add that into
> the series.

After implementing this, I'm having second thoughts. We've got a bunch
of drivers calling gpiochip_add_data() that never register an IRQ chip
but which will each add a struct lock_class_key after this change, and
it will never be used. Now, struct lock_class_key is only 8 bytes big,
so maybe this isn't a big deal, but it still seems like a waste.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-07 11:52         ` Thierry Reding
@ 2017-11-07 16:49           ` Grygorii Strashko
  0 siblings, 0 replies; 25+ messages in thread
From: Grygorii Strashko @ 2017-11-07 16:49 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 11/07/2017 05:52 AM, Thierry Reding wrote:
> On Tue, Nov 07, 2017 at 12:13:44PM +0100, Thierry Reding wrote:
>> On Mon, Nov 06, 2017 at 05:13:33PM -0600, Grygorii Strashko wrote:
>>> On 11/06/2017 05:18 AM, Thierry Reding wrote:
>>>> On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
> [...]
>>>>> @@ -312,8 +321,29 @@ struct gpio_chip {
>>>>>    extern const char *gpiochip_is_requested(struct gpio_chip *chip,
>>>>>    			unsigned offset);
>>>>>    
>>>>> +extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
>>>>> +				 struct  *irq_lock_key);
>>>>> +#ifdef CONFIG_LOCKDEP
>>>>> +/*
>>>>> + * Lockdep requires that each irqchip instance be created with a
>>>>> + * unique key so as to avoid unnecessary warnings. This upfront
>>>>> + * boilerplate static inlines provides such a key for each
>>>>> + * unique instance which is created now from inside gpiochip_add_data_key().
>>>>> + */
>>>>> +static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
>>>>> +{
>>>>> +	static struct lock_class_key key;
>>>>> +
>>>>> +	return gpiochip_add_data_key(chip, data, key);
>>>>> +}
>>>>
>>>> This looks like a neat improvement, but I think it can be done in a
>>>> follow-up to remove the boilerplate in drivers.
>>>
>>> Can't agree here - it better to be considered now.
>>> Now only two GPIO drivers define lock_class_key:
>>> ./drivers/gpio/gpio-bcm-kona.c:static struct lock_class_key gpio_lock_class;
>>> ./drivers/gpio/gpio-brcmstb.c:static struct lock_class_key brcmstb_gpio_irq_lock_class;
>>>
>>> and these drivers do not use gpioirq framework (your tegra driver will be the third).
>>>
>>> So, if proposed changes will be applied all drivers switched to use it will need to define
>>> its own lock_class_key again and it will be step back.
>>
>> I think this would be a minor, mostly mechanical refactoring to do as
>> follow-up. But since you feel very strongly about it, I'll add that into
>> the series.
> 
> After implementing this, I'm having second thoughts. We've got a bunch
> of drivers calling gpiochip_add_data() that never register an IRQ chip
> but which will each add a struct lock_class_key after this change, and
> it will never be used. Now, struct lock_class_key is only 8 bytes big,
> so maybe this isn't a big deal, but it still seems like a waste.

True. And this I've called my approach not ideal, but I do not see other way to do it :(
- that's price to pay for gpioirq chip initialization integration in
gpiochip_add_data() which limits APIs variation used by GPIO drivers. 

Any other opinions, thoughts?

-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-07 11:13       ` Thierry Reding
  2017-11-07 11:52         ` Thierry Reding
@ 2017-11-07 17:00         ` Grygorii Strashko
  2017-11-07 18:19           ` Thierry Reding
  1 sibling, 1 reply; 25+ messages in thread
From: Grygorii Strashko @ 2017-11-07 17:00 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel



On 11/07/2017 05:13 AM, Thierry Reding wrote:
> On Mon, Nov 06, 2017 at 05:13:33PM -0600, Grygorii Strashko wrote:
>>
>>
>> On 11/06/2017 05:18 AM, Thierry Reding wrote:
>>> On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
>>>> Hi
>>>>
>>>> On 11/02/2017 12:49 PM, Thierry Reding wrote:
>>>>> From: Thierry Reding <treding@nvidia.com>
>>>>>
>>>>> Hi Linus,
>>>>>
>>>>> here's the latest series of patches that implement the tighter IRQ chip
>>>>> integration. I've dropped the banked infrastructure for now as per the
>>>>> discussion with Grygorii.
>>>>>
>>>>> The first couple of patches are mostly preparatory work in order to
>>>>> consolidate all IRQ chip related fields in a new structure and create
>>>>> the base functionality for adding IRQ chips.
>>>>>
>>>>> After that, I've added the Tegra186 GPIO support patch that makes use of
>>>>> the new tight integration.
>>>>>
>>>>> Changes in v6:
>>>>> - rebased on latest linux-gpio devel branch
>>>>> - one patch dropped due to rebase
>>>>>
>>>>> Changes in v5:
>>>>> - dropped the banked infrastructure patches for now (Grygorii)
>>>>> - allocate interrupts on demand, rather than upfront (Grygorii)
>>>>> - split up the first patch further as requested by Grygorii
>>>>>
>>>>> Not sure what happened in between here. Notes in commit logs indicate
>>>>> that this is actually version 5, but I can't find the cover letter for
>>>>> v3 and v4.
>>>>>
>>>>> Changes in v2:
>>>>> - rename pins to lines for consistent terminology
>>>>> - rename gpio_irq_chip_banked_handler() to
>>>>>      gpio_irq_chip_banked_chained_handler()
>>>>>
>>>>
>>>> Sry, for delayed reply, very sorry.
>>>>
>>>> Patches 1 - 9, 11 : looks good, so
>>>> Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
>>>>
>>>> Patch 10 - unfortunately not all my comment were incorporated [1],
>>>> so below diff on top of patch 10
>>>> which illustrates what i want and also converts gpio-omap to use new infra as
>>>> test for this new infra.
>>>>
>>>> Pls, take a look
>>>>
>>>> [1] https://www.spinics.net/lists/linux-tegra/msg31145.html
>>>
>>> Most of the changes I had deemed to be material for follow-up patches
>>> since they aren't immediately relevant to the gpio_irq_chip conversion
>>> nor needed by the Tegra186 patch.
>>>
>>> However, a couple of the hunks below seem like they should be part of
>>> the initial series.
>>>
>>>> -----------><-------------
>>>>   From 210fe3ad7a642691a1b7603e441f6980b10ff2b4 Mon Sep 17 00:00:00 2001
>>>> From: Grygorii Strashko <grygorii.strashko@ti.com>
>>>> Date: Fri, 3 Nov 2017 17:24:51 -0500
>>>> Subject: [PATCH] [not for merge] gpiolib: update and test new gpioirq chip
>>>>    infra
>>>>
>>>> changes in gpiolib:
>>>>    - move set_parent to gpiochip_irq_map() and use parents instead of map for only
>>>>      one parent
>>>>    - add gpio_irq_chip->first_irq for static IRQ allocation
>>>>    - fix nested = true if parent_handler not set
>>>>    - fix gpiochip_irqchip_remove() if parent_handler not set
>>>>    - get of_node from gpiodev
>>>>    - fix lock_key: drivers do not need to set it, but looks a bit overcomplicated
>>>>      as lock_class_key will be created for each gpiochip_add_data() call.
>>>>      Honestly, do not seem better way :(
>>>>
>>>> GPIO OMAP driver updated to use new gpioirq chip infra and tested on am335x-evm.
>>>> seems it's working - can see irqs from keys.
>>>>
>>>> Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
>>>> ---
>>>>    drivers/gpio/gpio-omap.c    | 36 ++++++++++++++--------------
>>>>    drivers/gpio/gpiolib.c      | 58 +++++++++++++++++++--------------------------
>>>>    include/linux/gpio/driver.h | 32 ++++++++++++++++++++++++-
>>>>    3 files changed, 73 insertions(+), 53 deletions(-)
>>> [...]
>>>> diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>>> [...]
>>>> @@ -1642,6 +1644,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
>>>>    			    irq_hw_number_t hwirq)
>>>>    {
>>>>    	struct gpio_chip *chip = d->host_data;
>>>> +	int err = 0;
>>>>    
>>>>    	if (!gpiochip_irqchip_irq_valid(chip, hwirq))
>>>>    		return -ENXIO;
>>>> @@ -1658,6 +1661,12 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
>>>>    		irq_set_nested_thread(irq, 1);
>>>>    	irq_set_noprobe(irq);
>>>>    
>>>> +	if (chip->irq.num_parents == 1)
>>>> +		err = irq_set_parent(irq, chip->irq.parents[0]);
>>>> +	else if (chip->irq.map)
>>>> +		err = irq_set_parent(irq, chip->irq.map[hwirq]);
>>>> +	if (err < 0)
>>>> +		return err;
>>>
>>> Yeah, this looks sensible. Both in that this is a slightly better place
>>> to call it and that the handling for num_parents == 1 is necessary, too.
>>>
>>>>    	/*
>>>>    	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
>>>>    	 * is passed as default type.
>>>> @@ -1712,30 +1721,18 @@ static void gpiochip_irq_relres(struct irq_data *d)
>>>>    
>>>>    static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
>>>>    {
>>>> -	unsigned int irq;
>>>> -	int err;
>>>> -
>>>>    	if (!gpiochip_irqchip_irq_valid(chip, offset))
>>>>    		return -ENXIO;
>>>>    
>>>> -	irq = irq_create_mapping(chip->irq.domain, offset);
>>>> -	if (!irq)
>>>> -		return 0;
>>>> -
>>>> -	if (chip->irq.map) {
>>>> -		err = irq_set_parent(irq, chip->irq.map[offset]);
>>>> -		if (err < 0)
>>>> -			return err;
>>>> -	}
>>>> -
>>>> -	return irq;
>>>> +	return irq_create_mapping(chip->irq.domain, offset);
>>>>    }
>>>>    
>>>>    /**
>>>>     * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
>>>>     * @gpiochip: the GPIO chip to add the IRQ chip to
>>>>     */
>>>> -static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>> +static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
>>>> +				    struct lock_class_key *lock_key)
>>>>    {
>>>>    	struct irq_chip *irqchip = gpiochip->irq.chip;
>>>>    	const struct irq_domain_ops *ops;
>>>> @@ -1753,17 +1750,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>>    	}
>>>>    
>>>>    	type = gpiochip->irq.default_type;
>>>> -	np = gpiochip->parent->of_node;
>>>> -
>>>> -#ifdef CONFIG_OF_GPIO
>>>> -	/*
>>>> -	 * If the gpiochip has an assigned OF node this takes precedence
>>>> -	 * FIXME: get rid of this and use gpiochip->parent->of_node
>>>> -	 * everywhere
>>>> -	 */
>>>> -	if (gpiochip->of_node)
>>>> -		np = gpiochip->of_node;
>>>> -#endif
>>>> +	/* called from gpiochip_add_data() and is set properly */
>>>> +	np = gpiochip->gpiodev->dev.of_node;
>>>
>>> Indeed, looks like we have this twice now.
>>>
>>>>    
>>>>    	/*
>>>>    	 * Specifying a default trigger is a terrible idea if DT or ACPI is
>>>> @@ -1789,7 +1777,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>>    		ops = &gpiochip_domain_ops;
>>>>    
>>>>    	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
>>>> -						     0, ops, gpiochip);
>>>> +						     gpiochip->irq.first_irq,
>>>> +						     ops, gpiochip);
>>>>    	if (!gpiochip->irq.domain)
>>>>    		return -EINVAL;
>>>
>>> This seems backward. You just spent a lot of time getting rid of all
>>> users of first_irq (it's actually the reason why I dropped one of the
>>> patches from the series, since first_irq is no longer used), so why
>>> reintroduce it?
>>
>> Yes. It required for HW/drivers not supported (or partially supported)
>> SPARSE_IRQ. And it's not exactly the same as dropped base_irq.
>> If SPARSE_IRQ not supported - driver should ensure that proper
>>   Linux IRQ range allocated (or reserved) and pass first_irq number to the gpiolib
>> For example, in case of OMAP GPIO this is required for OMAP1 support and
>> driver has code
>>    irq_base = devm_irq_alloc_descs(bank->chip.parent, -1, 0, bank->width, 0);
>>
>> irq_base makes no sense in case of SPARSE_IRQ compatible driver and
>> therefore was removed from gpiolib to avoid mis-usage - drivers should
>> maintain it by itself if requred.
> 
> But this is not something that is currently being used. I understand
> that you'll want to add this in order to support fixed IRQ numbers on
> OMAP, but I don't see why it would need to be part of this series. It
> will simply be dead code until the OMAP patches get merged.

My opinion is that if this modification will be merged in gpiolib - 
drivers should be able to use it out of the box.

Any way finial decision is up to Linus.

> 
>>>> @@ -1818,9 +1807,9 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>>    		}
>>>>    
>>>>    		gpiochip->irq.nested = false;
>>>> -	} else {
>>>> -		gpiochip->irq.nested = true;
>>>>    	}
>>>> +	/* GPIO driver might not specify parent_handler, but it doesn't mean
>>>> +	 * it's irq_nested, as driver may use request_irq() */
>>>
>>> That's certainly how irq_nested is used in gpiolib, though. Interrupts
>>> are considered either cascaded or nested. Maybe this needs clarification
>>> in general?
>>
>> No. Please, take closer look at
>> gpiochip_set_nested_irqchip()
>> gpiochip_set_cascaded_irqchip()
>> gpiochip_set_chained_irqchip()
>> gpiochip_set_nested_irqchip()

Sry, above is copy-paste err:
gpiochip_set_chained_irqchip
gpiochip_set_nested_irqchip
gpiochip_irqchip_add
gpiochip_irqchip_add_nested

>>   and how they are used.
>> Also, take a look on OMAP driver - it doesn't install chained handler.
>>
>> gpiolib now can discover automatically only when child irqs are not nested
>> (nested here means - threaded nested), therefore different APIs were introduced
>> gpiochip_set_chained_irqchip()
>> gpiochip_set_nested_irqchip()
>>
>> So, with your change:
>> - nested = false; can be set auto if parent_handler provided
>> - nested = <set by driver> if no parent_handler provided
>> because with this patch full GPIO IRQ configuration expected to be done
>> from inside  gpiochip_add_data().
> 
> Sorry if I'm being dense. The only user-callable functions currently are
> gpiochip_set_chained_irqchip() and gpiochip_set_nested_irqchip(). Both
> internally call gpiochip_set_cascaded_irqchip() and the only difference
> is that the former passes a parent handler while the latter doesn't. So
> this seems to me like exactly the same thing that gpiochip_add_irqchip()
> does in my series.
> 
> I think there's some ambiguity in how irq_nested is currently being used
> because it really means two things: a) not-chained and b) threaded. So I
> think what we want is to separate these. For a) I think it's pretty much
> solved because we have the parent handler that disambiguates. So instead
> of just setting irq.nested = false when a parent handler is available we
> should probably also WARN if the driver has set irq.nested = true and
> force it to false.

good point.

> 
> Then, as you suggested, leave the else branch open to allow the driver
> to specify whether or not it uses threaded handlers so that
> gpiochip_irq_map() and gpiochip_irq_unmap() will know to call
> irq_set_nested_thread().

correct

> 
> In this case, perhaps it would be better to rename irq.nested to
> irq.threaded. Then we no longer need to check/force irq.nested for
> chained IRQ chips and instead use only irq.threaded to have interrupts
> marked as nested/threaded.

agree

> 
>>>>    
>>>>    	acpi_gpiochip_request_interrupts(gpiochip);
>>>>    
>>>> @@ -1839,7 +1828,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
>>>>    
>>>>    	acpi_gpiochip_free_interrupts(gpiochip);
>>>>    
>>>> -	if (gpiochip->irq.chip) {
>>>> +	if (gpiochip->irq.chip && gpiochip->irq.parent_handler) {
>>>>    		struct gpio_irq_chip *irq = &gpiochip->irq;
>>>>    		unsigned int i;
>>>>    
>>>
>>> Yeah, this seems like a good idea, though I think this is safe
>>> regardless of irq.parent_handler.
>>>
>>>> @@ -1972,7 +1961,8 @@ EXPORT_SYMBOL_GPL(gpiochip_irqchip_add_key);
>>>>    
>>>>    #else /* CONFIG_GPIOLIB_IRQCHIP */
>>>>    
>>>> -static inline int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
>>>> +static inline int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
>>>> +					   struct lock_class_key *lock_key)
>>>>    {
>>>>    	return 0;
>>>>    }
>>>> diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
>>>> index 51fc7b0..3254996 100644
>>>> --- a/include/linux/gpio/driver.h
>>>> +++ b/include/linux/gpio/driver.h
>>>> @@ -128,6 +128,15 @@ struct gpio_irq_chip {
>>>>    	 * in IRQ domain of the chip.
>>>>    	 */
>>>>    	unsigned long *valid_mask;
>>>> +
>>>> +	/**
>>>> +	 * @first_irq:
>>>> +	 *
>>>> +	 * Required for static irq allocation.
>>>> +	 * if set irq_domain_add_simple() will allocate and map all IRQs
>>>> +	 * during initialization.
>>>> +	 */
>>>> +	unsigned int first_irq;
>>>
>>> Again, what was the point of removing all users of this if we need to
>>> add it again?
>>>
>>> It seems to me like dynamic allocation should be a prerequisite for
>>> drivers to use this new code, otherwise we'll just end up adding special
>>> cases to this otherwise generic code.
>>
>> The idea, as i see it, is to be able to re-use you change for as much drivers
>> as possible (as I illustrated for OMAP) and in this case we need support backward
>> compatibility with non SPARSE_IRQ compatible drivers.
> 
> Okay, understood. How about we focus on getting the current series
> merged and then we can add this hunk as a preparator patch for the OMAP
> conversion series?

as above -  finial decision is up to Linus.

> 
>>>
>>>>    };
>>>>    
>>>>    static inline struct gpio_irq_chip *to_gpio_irq_chip(struct irq_chip *chip)
>>>> @@ -312,8 +321,29 @@ struct gpio_chip {
>>>>    extern const char *gpiochip_is_requested(struct gpio_chip *chip,
>>>>    			unsigned offset);
>>>>    
>>>> +extern int gpiochip_add_data_key(struct gpio_chip *chip, void *data,
>>>> +				 struct  *irq_lock_key);
>>>> +#ifdef CONFIG_LOCKDEP
>>>> +/*
>>>> + * Lockdep requires that each irqchip instance be created with a
>>>> + * unique key so as to avoid unnecessary warnings. This upfront
>>>> + * boilerplate static inlines provides such a key for each
>>>> + * unique instance which is created now from inside gpiochip_add_data_key().
>>>> + */
>>>> +static inline int gpiochip_add_data(struct gpio_chip *chip, void *data)
>>>> +{
>>>> +	static struct lock_class_key key;
>>>> +
>>>> +	return gpiochip_add_data_key(chip, data, key);
>>>> +}
>>>
>>> This looks like a neat improvement, but I think it can be done in a
>>> follow-up to remove the boilerplate in drivers.
>>
>> Can't agree here - it better to be considered now.
>> Now only two GPIO drivers define lock_class_key:
>> ./drivers/gpio/gpio-bcm-kona.c:static struct lock_class_key gpio_lock_class;
>> ./drivers/gpio/gpio-brcmstb.c:static struct lock_class_key brcmstb_gpio_irq_lock_class;
>>
>> and these drivers do not use gpioirq framework (your tegra driver will be the third).
>>
>> So, if proposed changes will be applied all drivers switched to use it will need to define
>> its own lock_class_key again and it will be step back.
> 
> I think this would be a minor, mostly mechanical refactoring to do as
> follow-up. But since you feel very strongly about it, I'll add that into
> the series.


-- 
regards,
-grygorii

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: [PATCH v6 00/12] gpio: Tight IRQ chip integration
  2017-11-07 17:00         ` Grygorii Strashko
@ 2017-11-07 18:19           ` Thierry Reding
  0 siblings, 0 replies; 25+ messages in thread
From: Thierry Reding @ 2017-11-07 18:19 UTC (permalink / raw)
  To: Grygorii Strashko
  Cc: Linus Walleij, Jonathan Hunter, linux-gpio, linux-tegra, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 9915 bytes --]

On Tue, Nov 07, 2017 at 11:00:41AM -0600, Grygorii Strashko wrote:
> 
> 
> On 11/07/2017 05:13 AM, Thierry Reding wrote:
> > On Mon, Nov 06, 2017 at 05:13:33PM -0600, Grygorii Strashko wrote:
> > > 
> > > 
> > > On 11/06/2017 05:18 AM, Thierry Reding wrote:
> > > > On Fri, Nov 03, 2017 at 05:30:30PM -0500, Grygorii Strashko wrote:
> > > > > Hi
> > > > > 
> > > > > On 11/02/2017 12:49 PM, Thierry Reding wrote:
> > > > > > From: Thierry Reding <treding@nvidia.com>
> > > > > > 
> > > > > > Hi Linus,
> > > > > > 
> > > > > > here's the latest series of patches that implement the tighter IRQ chip
> > > > > > integration. I've dropped the banked infrastructure for now as per the
> > > > > > discussion with Grygorii.
> > > > > > 
> > > > > > The first couple of patches are mostly preparatory work in order to
> > > > > > consolidate all IRQ chip related fields in a new structure and create
> > > > > > the base functionality for adding IRQ chips.
> > > > > > 
> > > > > > After that, I've added the Tegra186 GPIO support patch that makes use of
> > > > > > the new tight integration.
> > > > > > 
> > > > > > Changes in v6:
> > > > > > - rebased on latest linux-gpio devel branch
> > > > > > - one patch dropped due to rebase
> > > > > > 
> > > > > > Changes in v5:
> > > > > > - dropped the banked infrastructure patches for now (Grygorii)
> > > > > > - allocate interrupts on demand, rather than upfront (Grygorii)
> > > > > > - split up the first patch further as requested by Grygorii
> > > > > > 
> > > > > > Not sure what happened in between here. Notes in commit logs indicate
> > > > > > that this is actually version 5, but I can't find the cover letter for
> > > > > > v3 and v4.
> > > > > > 
> > > > > > Changes in v2:
> > > > > > - rename pins to lines for consistent terminology
> > > > > > - rename gpio_irq_chip_banked_handler() to
> > > > > >      gpio_irq_chip_banked_chained_handler()
> > > > > > 
> > > > > 
> > > > > Sry, for delayed reply, very sorry.
> > > > > 
> > > > > Patches 1 - 9, 11 : looks good, so
> > > > > Acked-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > > > > 
> > > > > Patch 10 - unfortunately not all my comment were incorporated [1],
> > > > > so below diff on top of patch 10
> > > > > which illustrates what i want and also converts gpio-omap to use new infra as
> > > > > test for this new infra.
> > > > > 
> > > > > Pls, take a look
> > > > > 
> > > > > [1] https://www.spinics.net/lists/linux-tegra/msg31145.html
> > > > 
> > > > Most of the changes I had deemed to be material for follow-up patches
> > > > since they aren't immediately relevant to the gpio_irq_chip conversion
> > > > nor needed by the Tegra186 patch.
> > > > 
> > > > However, a couple of the hunks below seem like they should be part of
> > > > the initial series.
> > > > 
> > > > > -----------><-------------
> > > > >   From 210fe3ad7a642691a1b7603e441f6980b10ff2b4 Mon Sep 17 00:00:00 2001
> > > > > From: Grygorii Strashko <grygorii.strashko@ti.com>
> > > > > Date: Fri, 3 Nov 2017 17:24:51 -0500
> > > > > Subject: [PATCH] [not for merge] gpiolib: update and test new gpioirq chip
> > > > >    infra
> > > > > 
> > > > > changes in gpiolib:
> > > > >    - move set_parent to gpiochip_irq_map() and use parents instead of map for only
> > > > >      one parent
> > > > >    - add gpio_irq_chip->first_irq for static IRQ allocation
> > > > >    - fix nested = true if parent_handler not set
> > > > >    - fix gpiochip_irqchip_remove() if parent_handler not set
> > > > >    - get of_node from gpiodev
> > > > >    - fix lock_key: drivers do not need to set it, but looks a bit overcomplicated
> > > > >      as lock_class_key will be created for each gpiochip_add_data() call.
> > > > >      Honestly, do not seem better way :(
> > > > > 
> > > > > GPIO OMAP driver updated to use new gpioirq chip infra and tested on am335x-evm.
> > > > > seems it's working - can see irqs from keys.
> > > > > 
> > > > > Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
> > > > > ---
> > > > >    drivers/gpio/gpio-omap.c    | 36 ++++++++++++++--------------
> > > > >    drivers/gpio/gpiolib.c      | 58 +++++++++++++++++++--------------------------
> > > > >    include/linux/gpio/driver.h | 32 ++++++++++++++++++++++++-
> > > > >    3 files changed, 73 insertions(+), 53 deletions(-)
> > > > [...]
> > > > > diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
> > > > [...]
> > > > > @@ -1642,6 +1644,7 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
> > > > >    			    irq_hw_number_t hwirq)
> > > > >    {
> > > > >    	struct gpio_chip *chip = d->host_data;
> > > > > +	int err = 0;
> > > > >    	if (!gpiochip_irqchip_irq_valid(chip, hwirq))
> > > > >    		return -ENXIO;
> > > > > @@ -1658,6 +1661,12 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
> > > > >    		irq_set_nested_thread(irq, 1);
> > > > >    	irq_set_noprobe(irq);
> > > > > +	if (chip->irq.num_parents == 1)
> > > > > +		err = irq_set_parent(irq, chip->irq.parents[0]);
> > > > > +	else if (chip->irq.map)
> > > > > +		err = irq_set_parent(irq, chip->irq.map[hwirq]);
> > > > > +	if (err < 0)
> > > > > +		return err;
> > > > 
> > > > Yeah, this looks sensible. Both in that this is a slightly better place
> > > > to call it and that the handling for num_parents == 1 is necessary, too.
> > > > 
> > > > >    	/*
> > > > >    	 * No set-up of the hardware will happen if IRQ_TYPE_NONE
> > > > >    	 * is passed as default type.
> > > > > @@ -1712,30 +1721,18 @@ static void gpiochip_irq_relres(struct irq_data *d)
> > > > >    static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
> > > > >    {
> > > > > -	unsigned int irq;
> > > > > -	int err;
> > > > > -
> > > > >    	if (!gpiochip_irqchip_irq_valid(chip, offset))
> > > > >    		return -ENXIO;
> > > > > -	irq = irq_create_mapping(chip->irq.domain, offset);
> > > > > -	if (!irq)
> > > > > -		return 0;
> > > > > -
> > > > > -	if (chip->irq.map) {
> > > > > -		err = irq_set_parent(irq, chip->irq.map[offset]);
> > > > > -		if (err < 0)
> > > > > -			return err;
> > > > > -	}
> > > > > -
> > > > > -	return irq;
> > > > > +	return irq_create_mapping(chip->irq.domain, offset);
> > > > >    }
> > > > >    /**
> > > > >     * gpiochip_add_irqchip() - adds an IRQ chip to a GPIO chip
> > > > >     * @gpiochip: the GPIO chip to add the IRQ chip to
> > > > >     */
> > > > > -static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> > > > > +static int gpiochip_add_irqchip_key(struct gpio_chip *gpiochip,
> > > > > +				    struct lock_class_key *lock_key)
> > > > >    {
> > > > >    	struct irq_chip *irqchip = gpiochip->irq.chip;
> > > > >    	const struct irq_domain_ops *ops;
> > > > > @@ -1753,17 +1750,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> > > > >    	}
> > > > >    	type = gpiochip->irq.default_type;
> > > > > -	np = gpiochip->parent->of_node;
> > > > > -
> > > > > -#ifdef CONFIG_OF_GPIO
> > > > > -	/*
> > > > > -	 * If the gpiochip has an assigned OF node this takes precedence
> > > > > -	 * FIXME: get rid of this and use gpiochip->parent->of_node
> > > > > -	 * everywhere
> > > > > -	 */
> > > > > -	if (gpiochip->of_node)
> > > > > -		np = gpiochip->of_node;
> > > > > -#endif
> > > > > +	/* called from gpiochip_add_data() and is set properly */
> > > > > +	np = gpiochip->gpiodev->dev.of_node;
> > > > 
> > > > Indeed, looks like we have this twice now.
> > > > 
> > > > >    	/*
> > > > >    	 * Specifying a default trigger is a terrible idea if DT or ACPI is
> > > > > @@ -1789,7 +1777,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip)
> > > > >    		ops = &gpiochip_domain_ops;
> > > > >    	gpiochip->irq.domain = irq_domain_add_simple(np, gpiochip->ngpio,
> > > > > -						     0, ops, gpiochip);
> > > > > +						     gpiochip->irq.first_irq,
> > > > > +						     ops, gpiochip);
> > > > >    	if (!gpiochip->irq.domain)
> > > > >    		return -EINVAL;
> > > > 
> > > > This seems backward. You just spent a lot of time getting rid of all
> > > > users of first_irq (it's actually the reason why I dropped one of the
> > > > patches from the series, since first_irq is no longer used), so why
> > > > reintroduce it?
> > > 
> > > Yes. It required for HW/drivers not supported (or partially supported)
> > > SPARSE_IRQ. And it's not exactly the same as dropped base_irq.
> > > If SPARSE_IRQ not supported - driver should ensure that proper
> > >   Linux IRQ range allocated (or reserved) and pass first_irq number to the gpiolib
> > > For example, in case of OMAP GPIO this is required for OMAP1 support and
> > > driver has code
> > >    irq_base = devm_irq_alloc_descs(bank->chip.parent, -1, 0, bank->width, 0);
> > > 
> > > irq_base makes no sense in case of SPARSE_IRQ compatible driver and
> > > therefore was removed from gpiolib to avoid mis-usage - drivers should
> > > maintain it by itself if requred.
> > 
> > But this is not something that is currently being used. I understand
> > that you'll want to add this in order to support fixed IRQ numbers on
> > OMAP, but I don't see why it would need to be part of this series. It
> > will simply be dead code until the OMAP patches get merged.
> 
> My opinion is that if this modification will be merged in gpiolib - drivers
> should be able to use it out of the box.
> 
> Any way finial decision is up to Linus.

Alright, I've sent v7 that should address all of the remaining issues.
I've squashed a couple of the fixes you had pointed out into the tight
integration patch and added another three patches on top for the first
IRQ support, nested vs. threaded disambiguation and one for the
automatic lock dep key creation.

Thierry

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2017-11-07 18:19 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-02 17:49 [PATCH v6 00/12] gpio: Tight IRQ chip integration Thierry Reding
2017-11-02 17:49 ` [PATCH v6 01/12] gpio: Introduce struct gpio_irq_chip Thierry Reding
2017-11-02 17:49 ` [PATCH v6 02/12] gpio: Move irqchip into " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 03/12] gpio: Move irqdomain " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 04/12] gpio: Move irq_handler to " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 05/12] gpio: Move irq_default_type " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 06/12] gpio: Move irq_chained_parent " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 07/12] gpio: Move irq_nested into " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 08/12] gpio: Move irq_valid_mask " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 09/12] gpio: Move lock_key " Thierry Reding
2017-11-02 17:49 ` [PATCH v6 10/12] gpio: Implement tighter IRQ chip integration Thierry Reding
2017-11-02 17:49 ` [PATCH v6 11/12] gpio: Export gpiochip_irq_{map,unmap}() Thierry Reding
2017-11-02 17:49 ` [PATCH v6 12/12] gpio: Add Tegra186 support Thierry Reding
2017-11-03 22:30 ` [PATCH v6 00/12] gpio: Tight IRQ chip integration Grygorii Strashko
2017-11-06 11:18   ` Thierry Reding
2017-11-06 23:13     ` Grygorii Strashko
2017-11-07 11:13       ` Thierry Reding
2017-11-07 11:52         ` Thierry Reding
2017-11-07 16:49           ` Grygorii Strashko
2017-11-07 17:00         ` Grygorii Strashko
2017-11-07 18:19           ` Thierry Reding
2017-11-03 22:50 ` Linus Walleij
2017-11-03 23:50   ` Grygorii Strashko
2017-11-06 13:22     ` Linus Walleij
2017-11-06 14:36       ` Thierry Reding

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).