linux-gpio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Lina Iyer <ilina@codeaurora.org>
To: Linus Walleij <linus.walleij@linaro.org>
Cc: linux-gpio@vger.kernel.org,
	Bartosz Golaszewski <bgolaszewski@baylibre.com>,
	Thomas Gleixner <tglx@linutronix.de>,
	Marc Zyngier <marc.zyngier@arm.com>,
	Jon Hunter <jonathanh@nvidia.com>,
	Sowjanya Komatineni <skomatineni@nvidia.com>,
	Bitan Biswas <bbiswas@nvidia.com>,
	linux-tegra@vger.kernel.org, David Daney <david.daney@cavium.com>,
	Masahiro Yamada <yamada.masahiro@socionext.com>,
	Brian Masney <masneyb@onstation.org>,
	Thierry Reding <treding@nvidia.com>
Subject: Re: [PATCH 1/4 v1] gpio: Add support for hierarchical IRQ domains
Date: Wed, 26 Jun 2019 15:09:00 -0600	[thread overview]
Message-ID: <20190626210900.GA1629@codeaurora.org> (raw)
In-Reply-To: <20190624132531.6184-1-linus.walleij@linaro.org>

Thanks for the patch Linus. I was running into the warning in
gpiochip_set_irq_hooks(), because it was called from two places.
Hopefully, this will fix that as well. I will give it a try.

On Mon, Jun 24 2019 at 07:29 -0600, Linus Walleij wrote:
>Hierarchical IRQ domains can be used to stack different IRQ
>controllers on top of each other.
>
>Bring hierarchical IRQ domains into the GPIOLIB core with the
>following basic idea:
>
>Drivers that need their interrupts handled hierarchically
>specify a callback to translate the child hardware IRQ and
>IRQ type for each GPIO offset to a parent hardware IRQ and
>parent hardware IRQ type.
>
>Users have to pass the callback, fwnode, and parent irqdomain
>before calling gpiochip_irqchip_add().
>
>We use the new method of just filling in the struct
>gpio_irq_chip before adding the gpiochip for all hierarchical
>irqchips of this type.
>
>The code path for device tree is pretty straight-forward,
>while the code path for old boardfiles or anything else will
>be more convoluted requireing upfront allocation of the
>interrupts when adding the chip.
>
>One specific use-case where this can be useful is if a power
>management controller has top-level controls for wakeup
>interrupts. In such cases, the power management controller can
>be a parent to other interrupt controllers and program
>additional registers when an IRQ has its wake capability
>enabled or disabled.
>
>The hierarchical irqchip helper code will only be available
>when IRQ_DOMAIN_HIERARCHY is selected to GPIO chips using
>this should select or depend on that symbol. When using
>hierarchical IRQs, the parent interrupt controller must
>also be hierarchical all the way up to the top interrupt
>controller wireing directly into the CPU, so on systems
>that do not have this we can get rid of all the extra
>code for supporting hierarchical irqs.
>
>Cc: Thomas Gleixner <tglx@linutronix.de>
>Cc: Marc Zyngier <marc.zyngier@arm.com>
>Cc: Lina Iyer <ilina@codeaurora.org>
>Cc: Jon Hunter <jonathanh@nvidia.com>
>Cc: Sowjanya Komatineni <skomatineni@nvidia.com>
>Cc: Bitan Biswas <bbiswas@nvidia.com>
>Cc: linux-tegra@vger.kernel.org
>Cc: David Daney <david.daney@cavium.com>
>Cc: Masahiro Yamada <yamada.masahiro@socionext.com>
>Cc: Brian Masney <masneyb@onstation.org>
>Signed-off-by: Thierry Reding <treding@nvidia.com>
>Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
>---
>ChangeLog RFC->v1:
>- Tested on real hardware
>- Incorporate Thierry's idea to have a translation callback.
>  He was right about this approach, I was wrong in insisting
>  on IRQ maps.
>---
> Documentation/driver-api/gpio/driver.rst | 120 ++++++++--
> drivers/gpio/gpiolib.c                   | 285 ++++++++++++++++++++++-
> include/linux/gpio/driver.h              |  46 ++++
> 3 files changed, 426 insertions(+), 25 deletions(-)
>
>diff --git a/Documentation/driver-api/gpio/driver.rst b/Documentation/driver-api/gpio/driver.rst
>index 1ce7fcd0f989..3099c7fbefdb 100644
>--- a/Documentation/driver-api/gpio/driver.rst
>+++ b/Documentation/driver-api/gpio/driver.rst
>@@ -259,7 +259,7 @@ most often cascaded off a parent interrupt controller, and in some special
> cases the GPIO logic is melded with a SoC's primary interrupt controller.
>
> The IRQ portions of the GPIO block are implemented using an irq_chip, using
>-the header <linux/irq.h>. So basically such a driver is utilizing two sub-
>+the header <linux/irq.h>. So this combined driver is utilizing two sub-
> systems simultaneously: gpio and irq.
>
> It is legal for any IRQ consumer to request an IRQ from any irqchip even if it
>@@ -391,14 +391,108 @@ Infrastructure helpers for GPIO irqchips
> ----------------------------------------
>
> To help out in handling the set-up and management of GPIO irqchips and the
>-associated irqdomain and resource allocation callbacks, the gpiolib has
>-some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
>-symbol:
>-
>-- gpiochip_irqchip_add(): adds a chained cascaded irqchip to a gpiochip. It
>-  will pass the struct gpio_chip* for the chip to all IRQ callbacks, so the
>-  callbacks need to embed the gpio_chip in its state container and obtain a
>-  pointer to the container using container_of().
>+associated irqdomain and resource allocation callbacks. These are activated
>+by selecting the Kconfig symbol GPIOLIB_IRQCHIP. If the symbol
>+IRQ_DOMAIN_HIERARCHY is also selected, hierarchical helpers will also be
>+provided. A big portion of overhead code will be managed by gpiolib,
>+under the assumption that your interrupts are 1-to-1-mapped to the
>+GPIO line index:
>+
>+  GPIO line offset   Hardware IRQ
>+  0                  0
>+  1                  1
>+  2                  2
>+  ...                ...
>+  ngpio-1            ngpio-1
>+
>+If some GPIO lines do not have corresponding IRQs, the bitmask valid_mask
>+and the flag need_valid_mask in gpio_irq_chip can be used to mask off some
>+lines as invalid for associating with IRQs.
>+
>+The preferred way to set up the helpers is to fill in the
>+struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
>+If you do this, the additional irq_chip will be set up by gpiolib at the
>+same time as setting up the rest of the GPIO functionality. The following
>+is a typical example of a cascaded interrupt handler using gpio_irq_chip:
>+
>+  /* Typical state container with dynamic irqchip */
>+  struct my_gpio {
>+      struct gpio_chip gc;
>+      struct irq_chip irq;
>+  };
>+
>+  int irq; /* from platform etc */
>+  struct my_gpio *g;
>+  struct gpio_irq_chip *girq
>+
>+  /* Set up the irqchip dynamically */
>+  g->irq.name = "my_gpio_irq";
>+  g->irq.irq_ack = my_gpio_ack_irq;
>+  g->irq.irq_mask = my_gpio_mask_irq;
>+  g->irq.irq_unmask = my_gpio_unmask_irq;
>+  g->irq.irq_set_type = my_gpio_set_irq_type;
>+
>+  /* Get a pointer to the gpio_irq_chip */
>+  girq = &g->gc.irq;
>+  girq->chip = &g->irq;
>+  girq->parent_handler = ftgpio_gpio_irq_handler;
>+  girq->num_parents = 1;
>+  girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
>+                               GFP_KERNEL);
Could this be folded into the gpiolib?

>+  if (!girq->parents)
>+      return -ENOMEM;
>+  girq->default_type = IRQ_TYPE_NONE;
>+  girq->handler = handle_bad_irq;
>+  girq->parents[0] = irq;
>+
>+  return devm_gpiochip_add_data(dev, &g->gc, g);
>+
>+The helper support using hierarchical interrupt controllers as well.
>+In this case the typical set-up will look like this:
>+
>+  /* Typical state container with dynamic irqchip */
>+  struct my_gpio {
>+      struct gpio_chip gc;
>+      struct irq_chip irq;
>+      struct fwnode_handle *fwnode;
>+  };
>+
>+  int irq; /* from platform etc */
>+  struct my_gpio *g;
>+  struct gpio_irq_chip *girq
>+
>+  /* Set up the irqchip dynamically */
>+  g->irq.name = "my_gpio_irq";
>+  g->irq.irq_ack = my_gpio_ack_irq;
>+  g->irq.irq_mask = my_gpio_mask_irq;
>+  g->irq.irq_unmask = my_gpio_unmask_irq;
>+  g->irq.irq_set_type = my_gpio_set_irq_type;
>+
>+  /* Get a pointer to the gpio_irq_chip */
>+  girq = &g->gc.irq;
>+  girq->chip = &g->irq;
>+  girq->default_type = IRQ_TYPE_NONE;
>+  girq->handler = handle_bad_irq;
>+  girq->fwnode = g->fwnode;
>+  girq->parent_domain = parent;
>+  girq->child_to_parent_hwirq = my_gpio_child_to_parent_hwirq;
>+
Should be the necessary, if the driver implements it's own .alloc?

>+  return devm_gpiochip_add_data(dev, &g->gc, g);
>+
>+As you can see pretty similar, but you do not supply a parent handler for
>+the IRQ, instead a parent irqdomain, an fwnode for the hardware and
>+a funcion .child_to_parent_hwirq() that has the purpose of looking up
>+the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
>+As always it is good to look at examples in the kernel tree for advice
>+on how to find the required pieces.
>+
>+The old way of adding irqchips to gpiochips after registration is also still
>+available but we try to move away from this:
>+
>+- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a
>+  gpiochip. It will pass the struct gpio_chip* for the chip to all IRQ
>+  callbacks, so the callbacks need to embed the gpio_chip in its state
>+  container and obtain a pointer to the container using container_of().
>   (See Documentation/driver-model/design-patterns.txt)
>
> - gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
>@@ -406,10 +500,10 @@ symbol:
>   cascaded irq has to be handled by a threaded interrupt handler.
>   Apart from that it works exactly like the chained irqchip.
>
>-- gpiochip_set_chained_irqchip(): sets up a chained cascaded irq handler for a
>-  gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
>-  data. Notice that we pass is as the handler data, since the irqchip data is
>-  likely used by the parent irqchip.
>+- DEPRECATED: gpiochip_set_chained_irqchip(): sets up a chained cascaded irq
>+  handler for a gpio_chip from a parent IRQ and passes the struct gpio_chip*
>+  as handler data. Notice that we pass is as the handler data, since the
>+  irqchip data is likely used by the parent irqchip.
>
> - gpiochip_set_nested_irqchip(): sets up a nested cascaded irq handler for a
>   gpio_chip from a parent IRQ. As the parent IRQ has usually been
>diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
>index e013d417a936..af72ffa02963 100644
>--- a/drivers/gpio/gpiolib.c
>+++ b/drivers/gpio/gpiolib.c
>@@ -1718,6 +1718,240 @@ void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
> }
> EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
>
>+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
>+
>+/**
>+ * gpiochip_set_hierarchical_irqchip() - connects a hierarchical irqchip
>+ * to a gpiochip
>+ * @gc: the gpiochip to set the irqchip hierarchical handler to
>+ * @irqchip: the irqchip to handle this level of the hierarchy, the interrupt
>+ * will then percolate up to the parent
>+ */
>+static void gpiochip_set_hierarchical_irqchip(struct gpio_chip *gc,
>+					      struct irq_chip *irqchip)
>+{
>+	/* DT will deal with mapping each IRQ as we go along */
>+	if (is_of_node(gc->irq.fwnode))
>+		return;
>+
>+	/*
>+	 * This is for legacy and boardfile "irqchip" fwnodes: allocate
>+	 * irqs upfront instead of dynamically since we don't have the
>+	 * dynamic type of allocation that hardware description languages
>+	 * provide. Once all GPIO drivers using board files are gone from
>+	 * the kernel we can delete this code, but for a transitional period
>+	 * it is necessary to keep this around.
>+	 */
>+	if (is_fwnode_irqchip(gc->irq.fwnode)) {
>+		int i;
>+		int ret;
>+
>+		for (i = 0; i < gc->ngpio; i++) {
>+			struct irq_fwspec fwspec;
>+			unsigned int parent_hwirq;
>+			unsigned int parent_type;
>+			struct gpio_irq_chip *girq = &gc->irq;
>+
>+			/*
>+			 * We call the child to parent translation function
>+			 * only to check if the child IRQ is valid or not.
>+			 * Just pick the rising edge type here as that is what
>+			 * we likely need to support.
>+			 */
>+			ret = girq->child_to_parent_hwirq(gc, i,
>+							  IRQ_TYPE_EDGE_RISING,
>+							  &parent_hwirq,
>+							  &parent_type);
>+			if (ret) {
>+				chip_err(gc, "skip set-up on hwirq %d\n",
>+					 i);
>+				continue;
>+			}
>+
>+			fwspec.fwnode = gc->irq.fwnode;
>+			/* This is the hwirq for the GPIO line side of things */
>+			fwspec.param[0] = i;
>+			/* Just pick something */
>+			fwspec.param[1] = IRQ_TYPE_EDGE_RISING;
>+			fwspec.param_count = 2;
>+			ret = __irq_domain_alloc_irqs(gc->irq.domain,
>+						      /* just pick something */
>+						      -1,
>+						      1,
>+						      NUMA_NO_NODE,
>+						      &fwspec,
>+						      false,
>+						      NULL);
>+			if (ret < 0) {
>+				chip_err(gc,
>+					 "can not allocate irq for GPIO line %d parent hwirq %d in hierarchy domain: %d\n",
>+					 i, parent_hwirq,
>+					 ret);
>+			}
>+		}
>+	}
>+
>+	chip_err(gc, "%s unknown fwnode type proceed anyway\n", __func__);
>+
>+	return;
>+}
>+
>+static int gpiochip_hierarchy_irq_domain_translate(struct irq_domain *d,
>+						   struct irq_fwspec *fwspec,
>+						   unsigned long *hwirq,
>+						   unsigned int *type)
>+{
>+	/* We support standard DT translation */
>+	if (is_of_node(fwspec->fwnode) && fwspec->param_count == 2) {
>+		return irq_domain_translate_twocell(d, fwspec, hwirq, type);
>+	}
>+
>+	/* This is for board files and others not using DT */
>+	if (is_fwnode_irqchip(fwspec->fwnode)) {
>+		int ret;
>+
>+		ret = irq_domain_translate_twocell(d, fwspec, hwirq, type);
>+		if (ret)
>+			return ret;
>+		WARN_ON(*type == IRQ_TYPE_NONE);
>+		return 0;
>+	}
>+	return -EINVAL;
>+}
>+
>+static int gpiochip_hierarchy_irq_domain_alloc(struct irq_domain *d,
>+					       unsigned int irq,
>+					       unsigned int nr_irqs,
>+					       void *data)
>+{
>+	struct gpio_chip *gc = d->host_data;
>+	irq_hw_number_t hwirq;
>+	unsigned int type = IRQ_TYPE_NONE;
>+	struct irq_fwspec *fwspec = data;
>+	int ret;
>+	int i;
>+
>+	chip_info(gc, "called %s\n", __func__);
>+
>+	ret = gpiochip_hierarchy_irq_domain_translate(d, fwspec, &hwirq, &type);
>+	if (ret)
>+		return ret;
>+
>+	chip_info(gc, "allocate IRQ %d..%d, hwirq %lu..%lu\n",
>+		  irq, irq + nr_irqs - 1,
>+		  hwirq, hwirq + nr_irqs - 1);
>+
>+	for (i = 0; i < nr_irqs; i++) {
>+		struct irq_fwspec parent_fwspec;
>+		unsigned int parent_hwirq;
>+		unsigned int parent_type;
>+		struct gpio_irq_chip *girq = &gc->irq;
>+
>+		ret = girq->child_to_parent_hwirq(gc, hwirq, type,
>+						  &parent_hwirq, &parent_type);
>+		if (ret) {
>+			chip_err(gc, "can't look up hwirq %lu\n", hwirq);
>+			return ret;
>+		}
>+		chip_info(gc, "found parent hwirq %u\n", parent_hwirq);
>+
>+		/*
>+		 * We set handle_bad_irq because the .set_type() should
>+		 * always be invoked and set the right type of handler.
>+		 */
>+		irq_domain_set_info(d,
>+				    irq + i,
>+				    hwirq + i,
>+				    gc->irq.chip,
>+				    gc,
>+				    handle_bad_irq,
>+				    NULL, NULL);
>+		irq_set_probe(irq + i);
>+
>+		/*
>+		 * Create a IRQ fwspec to send up to the parent irqdomain:
>+		 * specify the hwirq we address on the parent and tie it
>+		 * all together up the chain.
>+		 */
>+		parent_fwspec.fwnode = d->parent->fwnode;
>+		parent_fwspec.param_count = 2;
>+		parent_fwspec.param[0] = parent_hwirq;
>+		/* This parent only handles asserted level IRQs */
>+		parent_fwspec.param[1] = parent_type;
>+		chip_info(gc, "alloc_irqs_parent for %d parent hwirq %d\n",
>+			  irq + i, parent_hwirq);
>+		ret = irq_domain_alloc_irqs_parent(d, irq + i, 1,
>+						   &parent_fwspec);
>+		if (ret)
>+			chip_err(gc,
>+				 "failed to allocate parent hwirq %d for hwirq %lu\n",
>+				 parent_hwirq, hwirq);
>+	}
>+
>+	return 0;
>+}
>+
>+static const struct irq_domain_ops gpiochip_hierarchy_domain_ops = {
>+	.activate = gpiochip_irq_domain_activate,
>+	.deactivate = gpiochip_irq_domain_deactivate,
>+	.translate = gpiochip_hierarchy_irq_domain_translate,
>+	.alloc = gpiochip_hierarchy_irq_domain_alloc,
>+	.free = irq_domain_free_irqs_common,
>+};
>+
>+static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
>+{
>+	if (!gc->irq.parent_domain) {
>+		chip_err(gc, "missing parent irqdomain\n");
>+		return -EINVAL;
>+	}
>+
>+	if (!gc->irq.parent_domain ||
>+	    !gc->irq.child_to_parent_hwirq ||
This should probably be validated if the .ops have not been set.

>+	    !gc->irq.fwnode) {
>+		chip_err(gc, "missing irqdomain vital data\n");
>+		return -EINVAL;
>+	}
>+
>+	gc->irq.domain = irq_domain_create_hierarchy(
>+		gc->irq.parent_domain,
>+		IRQ_DOMAIN_FLAG_HIERARCHY,
>+		gc->ngpio,
>+		gc->irq.fwnode,
>+		&gpiochip_hierarchy_domain_ops,
>+		gc);
>+
>+	if (!gc->irq.domain) {
>+		chip_err(gc, "failed to add hierarchical domain\n");
>+		return -EINVAL;
>+	}
>+
>+	gpiochip_set_hierarchical_irqchip(gc, gc->irq.chip);
>+
>+	chip_info(gc, "set up hierarchical irqdomain\n");
>+
>+	return 0;
>+}
>+
>+static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
>+{
>+	return !!gc->irq.parent_domain;
>+}
>+
>+#else
>+
>+static int gpiochip_hierarchy_add_domain(struct gpio_chip *gc)
>+{
>+	return -EINVAL;
>+}
>+
>+static bool gpiochip_hierarchy_is_hierarchical(struct gpio_chip *gc)
>+{
>+	return false;
>+}
>+
>+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
>+
> /**
>  * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
>  * @d: the irqdomain used by this irqchip
>@@ -1786,6 +2020,11 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
> 	.xlate	= irq_domain_xlate_twocell,
> };
>
>+/*
>+ * TODO: move these activate/deactivate in under the hierarchicial
>+ * irqchip implementation as static once SPMI and SSBI (all external
>+ * users) are phased over.
>+ */
> /**
>  * gpiochip_irq_domain_activate() - Lock a GPIO to be used as an IRQ
>  * @domain: The IRQ domain used by this IRQ chip
>@@ -1825,10 +2064,23 @@ EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
>
> static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
> {
>+	struct irq_domain *domain = chip->irq.domain;
>+
> 	if (!gpiochip_irqchip_irq_valid(chip, offset))
> 		return -ENXIO;
>
>-	return irq_create_mapping(chip->irq.domain, offset);
>+	if (irq_domain_is_hierarchy(domain)) {
>+		struct irq_fwspec spec;
>+
>+		spec.fwnode = domain->fwnode;
>+		spec.param_count = 2;
>+		spec.param[0] = offset;
>+		spec.param[1] = IRQ_TYPE_NONE;
>+
>+		return irq_create_fwspec_mapping(&spec);
>+	}
>+
>+	return irq_create_mapping(domain, offset);
> }
>
> static int gpiochip_irq_reqres(struct irq_data *d)
>@@ -1905,7 +2157,7 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
> 				struct lock_class_key *request_key)
> {
> 	struct irq_chip *irqchip = gpiochip->irq.chip;
>-	const struct irq_domain_ops *ops;
>+	const struct irq_domain_ops *ops = NULL;
> 	struct device_node *np;
> 	unsigned int type;
> 	unsigned int i;
>@@ -1941,16 +2193,25 @@ static int gpiochip_add_irqchip(struct gpio_chip *gpiochip,
> 	gpiochip->irq.lock_key = lock_key;
> 	gpiochip->irq.request_key = request_key;
>
>-	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,
>-						     gpiochip->irq.first,
>-						     ops, gpiochip);
>-	if (!gpiochip->irq.domain)
>-		return -EINVAL;
>+	/* If a parent irqdomain is provided, let's build a hierarchy */
>+	if (gpiochip_hierarchy_is_hierarchical(gpiochip)) {
>+		int ret = gpiochip_hierarchy_add_domain(gpiochip);
>+		if (ret)
>+			return ret;
>+	} else {
>+		/* Some drivers provide custom irqdomain ops */
>+		if (gpiochip->irq.domain_ops)
>+			ops = gpiochip->irq.domain_ops;
>+
>+		if (!ops)
>+			ops = &gpiochip_domain_ops;
>+		gpiochip->irq.domain = irq_domain_add_simple(np,
>+			gpiochip->ngpio,
>+			gpiochip->irq.first,
>+			ops, gpiochip);
>+		if (!gpiochip->irq.domain)
>+			return -EINVAL;
>+	}
>
> 	if (gpiochip->irq.parent_handler) {
> 		void *data = gpiochip->irq.parent_handler_data ?: gpiochip;
>diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h
>index a1d273c96016..e32d02cb2d08 100644
>--- a/include/linux/gpio/driver.h
>+++ b/include/linux/gpio/driver.h
>@@ -22,6 +22,9 @@ enum gpiod_flags;
> #ifdef CONFIG_GPIOLIB
>
> #ifdef CONFIG_GPIOLIB_IRQCHIP
>+
>+struct gpio_chip;
>+
> /**
>  * struct gpio_irq_chip - GPIO interrupt controller
>  */
>@@ -48,6 +51,49 @@ struct gpio_irq_chip {
> 	 */
> 	const struct irq_domain_ops *domain_ops;
>
>+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
>+	/**
>+	 * @fwnode:
>+	 *
>+	 * Firmware node corresponding to this gpiochip/irqchip, necessary
>+	 * for hierarchical irqdomain support.
>+	 */
>+	struct fwnode_handle *fwnode;
>+
>+	/**
>+	 * @parent_domain:
>+	 *
>+	 * If non-NULL, will be set as the parent of this GPIO interrupt
>+	 * controller's IRQ domain to establish a hierarchical interrupt
>+	 * domain. The presence of this will activate the hierarchical
>+	 * interrupt support.
>+	 */
>+	struct irq_domain *parent_domain;
>+
>+	/**
>+	 * @child_to_parent_hwirq:
>+	 *
>+	 * This callback translates a child hardware IRQ offset to a parent
>+	 * hardware IRQ offset on a hierarchical interrupt chip. The child
>+	 * hardware IRQs correspond to the GPIO index 0..ngpio-1 (see the
>+	 * ngpio field of struct gpio_chip) and the corresponding parent
>+	 * hardware IRQ and type (such as IRQ_TYPE_*) shall be returned by
>+	 * the driver. The driver can calculate this from an offset or using
>+	 * a lookup table or whatever method is best for this chip. Return
>+	 * 0 on successful translation in the driver.
>+	 *
>+	 * If some ranges of hardware IRQs do not have a corresponding parent
>+	 * HWIRQ, return -EINVAL, but also make sure to fill in @valid_mask and
>+	 * @need_valid_mask to make these GPIO lines unavailable for
>+	 * translation.
>+	 */
>+	int (*child_to_parent_hwirq)(struct gpio_chip *chip,
>+				     unsigned int child_hwirq,
>+				     unsigned int child_type,
>+				     unsigned int *parent_hwirq,
>+				     unsigned int *parent_type);
Would irq_fwspec(s) be better than passing all these arguments around?

Thanks,
Lina

>+#endif
>+
> 	/**
> 	 * @handler:
> 	 *
>--
>2.21.0
>

  parent reply	other threads:[~2019-06-26 21:09 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-24 13:25 [PATCH 1/4 v1] gpio: Add support for hierarchical IRQ domains Linus Walleij
2019-06-24 13:25 ` [PATCH 2/4 v1] gpio: ixp4xx: Convert to hieararchical GPIOLIB_IRQCHIP Linus Walleij
2019-06-24 13:25 ` [PATCH 3/4 v1] RFT: gpio: thunderx: Switch to GPIOLIB_IRQCHIP Linus Walleij
2019-06-24 13:25 ` [PATCH 4/4 v1] RFT: gpio: uniphier: " Linus Walleij
2019-07-18 11:09   ` Masahiro Yamada
2019-08-08 11:57     ` Linus Walleij
2019-06-26 21:09 ` Lina Iyer [this message]
2019-06-28  9:14   ` [PATCH 1/4 v1] gpio: Add support for hierarchical IRQ domains Linus Walleij
2019-06-28 15:58     ` Lina Iyer
2019-07-03  6:33       ` Linus Walleij
2019-06-27 20:44 ` Lina Iyer
2019-06-28 10:43 ` Brian Masney
2019-06-28 11:11   ` Linus Walleij
2019-07-03  9:22 ` Brian Masney
2019-07-03 12:39   ` Linus Walleij
2019-07-07  1:46 ` Brian Masney
2019-07-07  8:09   ` Linus Walleij
2019-07-09  2:37 ` Brian Masney
2019-07-18 11:12 ` Masahiro Yamada
2019-08-07 14:43   ` Linus Walleij
2019-08-07 15:00     ` Marc Zyngier

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190626210900.GA1629@codeaurora.org \
    --to=ilina@codeaurora.org \
    --cc=bbiswas@nvidia.com \
    --cc=bgolaszewski@baylibre.com \
    --cc=david.daney@cavium.com \
    --cc=jonathanh@nvidia.com \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-tegra@vger.kernel.org \
    --cc=marc.zyngier@arm.com \
    --cc=masneyb@onstation.org \
    --cc=skomatineni@nvidia.com \
    --cc=tglx@linutronix.de \
    --cc=treding@nvidia.com \
    --cc=yamada.masahiro@socionext.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).