linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/11] irqdomain: Refactor
@ 2013-06-14 21:07 Grant Likely
  2013-06-14 21:07 ` [PATCH v2 01/11] irqdomain: Relax failure path on setting up mappings Grant Likely
                   ` (10 more replies)
  0 siblings, 11 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:07 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner

I've done a bunch of refactoring work on the irq_domain infrastructure.
Some of these patches I've posted before, and some our brand new. The
goal of this is to greatly simplify how irq_domains work. With this
series, instead of there being multiple different types of irq domains,
each with different mapping rules, instead there is now only one time of
irq_domain that contains both kinds of map; the linear map for irqs
below a certain value, and the radix tree for large & sparse irq
controllers. As you can see from the following diffstat, the result is a
fair bit less code. It should make it easier to understand irqdomains
too.

This is the second posting of this series. I've added a couple more
patches and dropped an unrelated patch to the versatile irq driver.

irqdomain: Relax failure path on setting up mappings
irqdomain: Replace LEGACY mapping with LINEAR
irqdomain: Add a name field
irqdomain: merge linear and tree reverse mappings.
irqdomain: Eliminate revmap type
irqdomain: Clean up aftermath of irq_domain refactoring
irqdomain: Beef up debugfs output
irqdomain: Refactor irq_domain_associate_many()
irqdomain: remove irq_domain_generate_simple()
irqdomain: make irq_linear_revmap() a fast path again
irqdomain: Include hwirq number in /proc/interrupts

 arch/powerpc/platforms/cell/beat_interrupt.c |   2 +-
 arch/powerpc/platforms/powermac/smp.c        |   2 +-
 arch/x86/kernel/devicetree.c                 |   4 +-
 include/linux/irqdomain.h                    | 142 +++++++------
 kernel/irq/generic-chip.c                    |   6 +-
 kernel/irq/irqdomain.c                       | 571 ++++++++++++++++----------------------------------
 kernel/irq/proc.c                            |   2 +
 7 files changed, 261 insertions(+), 468 deletions(-)

I've pushed this series out to my git server at the following branch:

git://git.secretlab.ca/git/linux irqdomain/test

It depends on the tip tree's irq/for-arm branch and also Linus' mainline
(they need to be merged). The branch above includes both.

Cheers,
g.


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

* [PATCH v2 01/11] irqdomain: Relax failure path on setting up mappings
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
@ 2013-06-14 21:07 ` Grant Likely
  2013-06-14 21:07 ` [PATCH v2 02/11] irqdomain: Replace LEGACY mapping with LINEAR Grant Likely
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:07 UTC (permalink / raw)
  To: linux-kernel
  Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely, Paul Mundt

Commit 98aa468e, "irqdomain: Support for static IRQ mapping and
association" introduced an API for directly associating blocks of hwirqs
to linux irqs. However, if any irq in that block failed to map (say if
the mapping functions returns an error because the irq is already
mapped) then the whole thing will fail and roll back. This is probably
too aggressive since there are valid reasons why a mapping may fail.
ie. Firmware may have a particular IRQ marked as unusable.

This patch drops the error path out of irq_domain_associate(). If a
mapping fails, then it is simply skipped. There is no reason to fail the
entire allocation.

v2: Still output an information message on failed mappings and make sure
    attempted mapping gets cleared out of the irq_data structure.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/irq/irqdomain.c | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)

diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 20b677d..61d6d3c 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -464,23 +464,15 @@ int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
 				/*
 				 * If map() returns -EPERM, this interrupt is protected
 				 * by the firmware or some other service and shall not
-				 * be mapped.
-				 *
-				 * Since on some platforms we blindly try to map everything
-				 * we end up with a log full of backtraces.
-				 *
-				 * So instead, we silently fail on -EPERM, it is the
-				 * responsibility of the PIC driver to display a relevant
-				 * message if needed.
+				 * be mapped. Don't bother telling the user about it.
 				 */
 				if (ret != -EPERM) {
-					pr_err("irq-%i==>hwirq-0x%lx mapping failed: %d\n",
-					       virq, hwirq, ret);
-					WARN_ON(1);
+					pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
+					       of_node_full_name(domain->of_node), hwirq, virq, ret);
 				}
 				irq_data->domain = NULL;
 				irq_data->hwirq = 0;
-				goto err_unmap;
+				continue;
 			}
 		}
 
-- 
1.8.1.2


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

* [PATCH v2 02/11] irqdomain: Replace LEGACY mapping with LINEAR
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
  2013-06-14 21:07 ` [PATCH v2 01/11] irqdomain: Relax failure path on setting up mappings Grant Likely
@ 2013-06-14 21:07 ` Grant Likely
  2013-06-14 21:07 ` [PATCH v2 03/11] irqdomain: Add a name field Grant Likely
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:07 UTC (permalink / raw)
  To: linux-kernel
  Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Paul Mundt, Rob Herring

The LEGACY mapping unnecessarily complicates the irqdomain code and
can easily be implemented with a linear mapping.  By ripping it out
and replacing it with the LINEAR mapping the object size of
irqdomain.c shrinks by about 330 bytes (ARMv7) which offsets the
additional allocation required by the linear map.  It also makes it
possible for current LEGACY map users to pre-allocate irq_descs for a
subset of the hwirqs and dynamically allocate the rest as needed.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Rob Herring <rob.herring@calxeda.com>
---
 include/linux/irqdomain.h |  7 ----
 kernel/irq/irqdomain.c    | 84 ++++-------------------------------------------
 2 files changed, 6 insertions(+), 85 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index ba2c708..6f06241 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -95,11 +95,6 @@ struct irq_domain {
 	union {
 		struct {
 			unsigned int size;
-			unsigned int first_irq;
-			irq_hw_number_t first_hwirq;
-		} legacy;
-		struct {
-			unsigned int size;
 			unsigned int *revmap;
 		} linear;
 		struct {
@@ -117,8 +112,6 @@ struct irq_domain {
 	struct irq_domain_chip_generic *gc;
 };
 
-#define IRQ_DOMAIN_MAP_LEGACY 0 /* driver allocated fixed range of irqs.
-				 * ie. legacy 8259, gets irqs 1..15 */
 #define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
 #define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
 #define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 61d6d3c..1ac8cf4 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -82,13 +82,6 @@ void irq_domain_remove(struct irq_domain *domain)
 	mutex_lock(&irq_domain_mutex);
 
 	switch (domain->revmap_type) {
-	case IRQ_DOMAIN_MAP_LEGACY:
-		/*
-		 * Legacy domains don't manage their own irq_desc
-		 * allocations, we expect the caller to handle irq_desc
-		 * freeing on their own.
-		 */
-		break;
 	case IRQ_DOMAIN_MAP_TREE:
 		/*
 		 * radix_tree_delete() takes care of destroying the root
@@ -122,17 +115,6 @@ void irq_domain_remove(struct irq_domain *domain)
 }
 EXPORT_SYMBOL_GPL(irq_domain_remove);
 
-static unsigned int irq_domain_legacy_revmap(struct irq_domain *domain,
-					     irq_hw_number_t hwirq)
-{
-	irq_hw_number_t first_hwirq = domain->revmap_data.legacy.first_hwirq;
-	int size = domain->revmap_data.legacy.size;
-
-	if (WARN_ON(hwirq < first_hwirq || hwirq >= first_hwirq + size))
-		return 0;
-	return hwirq - first_hwirq + domain->revmap_data.legacy.first_irq;
-}
-
 /**
  * irq_domain_add_simple() - Allocate and register a simple irq_domain.
  * @of_node: pointer to interrupt controller's device tree node.
@@ -213,57 +195,17 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 					 void *host_data)
 {
 	struct irq_domain *domain;
-	unsigned int i;
 
-	domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LEGACY, ops, host_data);
+	pr_debug("Setting up legacy domain virq[%i:%i] ==> hwirq[%i:%i]\n",
+		 first_irq, first_irq + size - 1,
+		 (int)first_hwirq, (int)first_hwirq + size -1);
+
+	domain = irq_domain_add_linear(of_node, first_hwirq + size, ops, host_data);
 	if (!domain)
 		return NULL;
 
-	domain->revmap_data.legacy.first_irq = first_irq;
-	domain->revmap_data.legacy.first_hwirq = first_hwirq;
-	domain->revmap_data.legacy.size = size;
-
-	mutex_lock(&irq_domain_mutex);
-	/* Verify that all the irqs are available */
-	for (i = 0; i < size; i++) {
-		int irq = first_irq + i;
-		struct irq_data *irq_data = irq_get_irq_data(irq);
-
-		if (WARN_ON(!irq_data || irq_data->domain)) {
-			mutex_unlock(&irq_domain_mutex);
-			irq_domain_free(domain);
-			return NULL;
-		}
-	}
+	WARN_ON(irq_domain_associate_many(domain, first_irq, first_hwirq, size));
 
-	/* Claim all of the irqs before registering a legacy domain */
-	for (i = 0; i < size; i++) {
-		struct irq_data *irq_data = irq_get_irq_data(first_irq + i);
-		irq_data->hwirq = first_hwirq + i;
-		irq_data->domain = domain;
-	}
-	mutex_unlock(&irq_domain_mutex);
-
-	for (i = 0; i < size; i++) {
-		int irq = first_irq + i;
-		int hwirq = first_hwirq + i;
-
-		/* IRQ0 gets ignored */
-		if (!irq)
-			continue;
-
-		/* Legacy flags are left to default at this point,
-		 * one can then use irq_create_mapping() to
-		 * explicitly change them
-		 */
-		if (ops->map)
-			ops->map(domain, irq, hwirq);
-
-		/* Clear norequest flags */
-		irq_clear_status_flags(irq, IRQ_NOREQUEST);
-	}
-
-	irq_domain_add(domain);
 	return domain;
 }
 EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
@@ -492,10 +434,6 @@ int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
 	}
 
 	return 0;
-
- err_unmap:
-	irq_domain_disassociate_many(domain, irq_base, i);
-	return -EINVAL;
 }
 EXPORT_SYMBOL_GPL(irq_domain_associate_many);
 
@@ -575,10 +513,6 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
 		return virq;
 	}
 
-	/* Get a virtual interrupt number */
-	if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
-		return irq_domain_legacy_revmap(domain, hwirq);
-
 	/* Allocate a virtual interrupt number */
 	hint = hwirq % nr_irqs;
 	if (hint == 0)
@@ -706,10 +640,6 @@ void irq_dispose_mapping(unsigned int virq)
 	if (WARN_ON(domain == NULL))
 		return;
 
-	/* Never unmap legacy interrupts */
-	if (domain->revmap_type == IRQ_DOMAIN_MAP_LEGACY)
-		return;
-
 	irq_domain_disassociate_many(domain, virq, 1);
 	irq_free_desc(virq);
 }
@@ -732,8 +662,6 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 		return 0;
 
 	switch (domain->revmap_type) {
-	case IRQ_DOMAIN_MAP_LEGACY:
-		return irq_domain_legacy_revmap(domain, hwirq);
 	case IRQ_DOMAIN_MAP_LINEAR:
 		return irq_linear_revmap(domain, hwirq);
 	case IRQ_DOMAIN_MAP_TREE:
-- 
1.8.1.2


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

* [PATCH v2 03/11] irqdomain: Add a name field
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
  2013-06-14 21:07 ` [PATCH v2 01/11] irqdomain: Relax failure path on setting up mappings Grant Likely
  2013-06-14 21:07 ` [PATCH v2 02/11] irqdomain: Replace LEGACY mapping with LINEAR Grant Likely
@ 2013-06-14 21:07 ` Grant Likely
  2013-06-14 21:07 ` [PATCH v2 04/11] irqdomain: merge linear and tree reverse mappings Grant Likely
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:07 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

This patch adds a name field to the irq_domain structure to help mere
mortals understand the mappings between irq domains and virqs. It also
converts a number of places that have open-coded some kind of fudging
an irqdomain name to use the new field. This means a more consistent
display of names in irq domain log messages and debugfs output.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 include/linux/irqdomain.h |  1 +
 kernel/irq/generic-chip.c |  1 +
 kernel/irq/irqdomain.c    | 19 ++++++-------------
 3 files changed, 8 insertions(+), 13 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 6f06241..e5e513c 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -89,6 +89,7 @@ struct irq_domain_chip_generic;
  */
 struct irq_domain {
 	struct list_head link;
+	const char *name;
 
 	/* type of reverse mapping_technique */
 	unsigned int revmap_type;
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index 95575d8..ca98cc5 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -305,6 +305,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
 		/* Calc pointer to the next generic chip */
 		tmp += sizeof(*gc) + num_ct * sizeof(struct irq_chip_type);
 	}
+	d->name = name;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 1ac8cf4..b1b5e67 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -410,12 +410,15 @@ int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
 				 */
 				if (ret != -EPERM) {
 					pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
-					       of_node_full_name(domain->of_node), hwirq, virq, ret);
+					       domain->name, hwirq, virq, ret);
 				}
 				irq_data->domain = NULL;
 				irq_data->hwirq = 0;
 				continue;
 			}
+			/* If not already assigned, give the domain the chip's name */
+			if (!domain->name && irq_data->chip)
+				domain->name = irq_data->chip->name;
 		}
 
 		switch (domain->revmap_type) {
@@ -708,8 +711,6 @@ static int virq_debug_show(struct seq_file *m, void *private)
 {
 	unsigned long flags;
 	struct irq_desc *desc;
-	const char *p;
-	static const char none[] = "none";
 	void *data;
 	int i;
 
@@ -731,20 +732,12 @@ static int virq_debug_show(struct seq_file *m, void *private)
 			seq_printf(m, "0x%05lx  ", desc->irq_data.hwirq);
 
 			chip = irq_desc_get_chip(desc);
-			if (chip && chip->name)
-				p = chip->name;
-			else
-				p = none;
-			seq_printf(m, "%-15s  ", p);
+			seq_printf(m, "%-15s  ", (chip && chip->name) ? chip->name : "none");
 
 			data = irq_desc_get_chip_data(desc);
 			seq_printf(m, data ? "0x%p  " : "  %p  ", data);
 
-			if (desc->irq_data.domain)
-				p = of_node_full_name(desc->irq_data.domain->of_node);
-			else
-				p = none;
-			seq_printf(m, "%s\n", p);
+			seq_printf(m, "%s\n", desc->irq_data.domain->name);
 		}
 
 		raw_spin_unlock_irqrestore(&desc->lock, flags);
-- 
1.8.1.2


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

* [PATCH v2 04/11] irqdomain: merge linear and tree reverse mappings.
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (2 preceding siblings ...)
  2013-06-14 21:07 ` [PATCH v2 03/11] irqdomain: Add a name field Grant Likely
@ 2013-06-14 21:07 ` Grant Likely
  2013-06-14 21:08 ` [PATCH v2 05/11] irqdomain: Eliminate revmap type Grant Likely
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:07 UTC (permalink / raw)
  To: linux-kernel
  Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely,
	Paul Mundt, Rob Herring

From: Grant Likely <grant.likely@secretlab.ca>

Keeping them separate makes irq_domain more complex and adds a lot of
code (as proven by the diffstat).  Merging them simplifies the whole
scheme.  This change makes it so both the tree and linear methods can be
used by the same irq_domain instance.  If the hwirq is less than the
->linear_size, then the linear map is used to reverse map the hwirq.
Otherwise the radix tree is used.  The test for which map to use is no
more expensive that the existing code, so the performance of fast path
is preserved.

It also means that complex interrupt controllers can use both the
linear map and a tree in the same domain.  This may be useful for an
interrupt controller with a base set of core irqs and a large number
of GPIOs which might be used as irqs.  The linear map could cover the
core irqs, and the tree used for thas irqs.  The linear map could
cover the core irqs, and the tree used for the gpios.

v2: Drop reorganization of revmap data

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Cc: Paul Mundt <lethal@linux-sh.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Rob Herring <rob.herring@calxeda.com>
---
 include/linux/irqdomain.h |  18 ++++----
 kernel/irq/irqdomain.c    | 107 +++++++++++++---------------------------------
 2 files changed, 39 insertions(+), 86 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index e5e513c..1cbb741 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -75,7 +75,6 @@ struct irq_domain_chip_generic;
  * @link: Element in global irq_domain list.
  * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This
  *               will be one of the IRQ_DOMAIN_MAP_* values.
- * @revmap_data: Revmap method specific data.
  * @ops: pointer to irq_domain methods
  * @host_data: private data pointer for use by owner.  Not touched by irq_domain
  *             core code.
@@ -93,10 +92,9 @@ struct irq_domain {
 
 	/* type of reverse mapping_technique */
 	unsigned int revmap_type;
-	union {
+	struct {
 		struct {
 			unsigned int size;
-			unsigned int *revmap;
 		} linear;
 		struct {
 			unsigned int max_irq;
@@ -111,11 +109,13 @@ struct irq_domain {
 	struct device_node *of_node;
 	/* Optional pointer to generic interrupt chips */
 	struct irq_domain_chip_generic *gc;
+
+	/* Linear reverse map */
+	unsigned int linear_revmap[];
 };
 
 #define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
 #define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
-#define IRQ_DOMAIN_MAP_TREE 3 /* radix tree */
 
 #ifdef CONFIG_IRQ_DOMAIN
 struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
@@ -137,10 +137,6 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
 					 unsigned int max_irq,
 					 const struct irq_domain_ops *ops,
 					 void *host_data);
-struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
-					 const struct irq_domain_ops *ops,
-					 void *host_data);
-
 extern struct irq_domain *irq_find_host(struct device_node *node);
 extern void irq_set_default_host(struct irq_domain *host);
 
@@ -152,6 +148,12 @@ static inline struct irq_domain *irq_domain_add_legacy_isa(
 	return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops,
 				     host_data);
 }
+static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
+					 const struct irq_domain_ops *ops,
+					 void *host_data)
+{
+	return irq_domain_add_linear(of_node, 0, ops, host_data);
+}
 
 extern void irq_domain_remove(struct irq_domain *host);
 
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index b1b5e67..5a1d8ec 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -34,22 +34,24 @@ static struct irq_domain *irq_default_domain;
  * to IRQ domain, or NULL on failure.
  */
 static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
-					   unsigned int revmap_type,
+					   unsigned int revmap_type, int size,
 					   const struct irq_domain_ops *ops,
 					   void *host_data)
 {
 	struct irq_domain *domain;
 
-	domain = kzalloc_node(sizeof(*domain), GFP_KERNEL,
-			      of_node_to_nid(of_node));
+	domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
+			      GFP_KERNEL, of_node_to_nid(of_node));
 	if (WARN_ON(!domain))
 		return NULL;
 
 	/* Fill structure */
+	INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
 	domain->revmap_type = revmap_type;
 	domain->ops = ops;
 	domain->host_data = host_data;
 	domain->of_node = of_node_get(of_node);
+	domain->revmap_data.linear.size = size;
 
 	return domain;
 }
@@ -81,22 +83,12 @@ void irq_domain_remove(struct irq_domain *domain)
 {
 	mutex_lock(&irq_domain_mutex);
 
-	switch (domain->revmap_type) {
-	case IRQ_DOMAIN_MAP_TREE:
-		/*
-		 * radix_tree_delete() takes care of destroying the root
-		 * node when all entries are removed. Shout if there are
-		 * any mappings left.
-		 */
-		WARN_ON(domain->revmap_data.tree.height);
-		break;
-	case IRQ_DOMAIN_MAP_LINEAR:
-		kfree(domain->revmap_data.linear.revmap);
-		domain->revmap_data.linear.size = 0;
-		break;
-	case IRQ_DOMAIN_MAP_NOMAP:
-		break;
-	}
+	/*
+	 * radix_tree_delete() takes care of destroying the root
+	 * node when all entries are removed. Shout if there are
+	 * any mappings left.
+	 */
+	WARN_ON(domain->revmap_data.tree.height);
 
 	list_del(&domain->link);
 
@@ -223,20 +215,11 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
 					 void *host_data)
 {
 	struct irq_domain *domain;
-	unsigned int *revmap;
 
-	revmap = kzalloc_node(sizeof(*revmap) * size, GFP_KERNEL,
-			      of_node_to_nid(of_node));
-	if (WARN_ON(!revmap))
+	domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, size, ops, host_data);
+	if (!domain)
 		return NULL;
 
-	domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, ops, host_data);
-	if (!domain) {
-		kfree(revmap);
-		return NULL;
-	}
-	domain->revmap_data.linear.size = size;
-	domain->revmap_data.linear.revmap = revmap;
 	irq_domain_add(domain);
 	return domain;
 }
@@ -248,7 +231,7 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
 					 void *host_data)
 {
 	struct irq_domain *domain = irq_domain_alloc(of_node,
-					IRQ_DOMAIN_MAP_NOMAP, ops, host_data);
+					IRQ_DOMAIN_MAP_NOMAP, 0, ops, host_data);
 	if (domain) {
 		domain->revmap_data.nomap.max_irq = max_irq ? max_irq : ~0;
 		irq_domain_add(domain);
@@ -258,28 +241,6 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
 EXPORT_SYMBOL_GPL(irq_domain_add_nomap);
 
 /**
- * irq_domain_add_tree()
- * @of_node: pointer to interrupt controller's device tree node.
- * @ops: map/unmap domain callbacks
- *
- * Note: The radix tree will be allocated later during boot automatically
- * (the reverse mapping will use the slow path until that happens).
- */
-struct irq_domain *irq_domain_add_tree(struct device_node *of_node,
-					 const struct irq_domain_ops *ops,
-					 void *host_data)
-{
-	struct irq_domain *domain = irq_domain_alloc(of_node,
-					IRQ_DOMAIN_MAP_TREE, ops, host_data);
-	if (domain) {
-		INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
-		irq_domain_add(domain);
-	}
-	return domain;
-}
-EXPORT_SYMBOL_GPL(irq_domain_add_tree);
-
-/**
  * irq_find_host() - Locates a domain for a given device node
  * @node: device-tree node of the interrupt controller
  */
@@ -359,17 +320,13 @@ static void irq_domain_disassociate_many(struct irq_domain *domain,
 		irq_data->domain = NULL;
 		irq_data->hwirq = 0;
 
-		/* Clear reverse map */
-		switch(domain->revmap_type) {
-		case IRQ_DOMAIN_MAP_LINEAR:
-			if (hwirq < domain->revmap_data.linear.size)
-				domain->revmap_data.linear.revmap[hwirq] = 0;
-			break;
-		case IRQ_DOMAIN_MAP_TREE:
+		/* Clear reverse map for this hwirq */
+		if (hwirq < domain->revmap_data.linear.size) {
+			domain->linear_revmap[hwirq] = 0;
+		} else {
 			mutex_lock(&revmap_trees_mutex);
 			radix_tree_delete(&domain->revmap_data.tree, hwirq);
 			mutex_unlock(&revmap_trees_mutex);
-			break;
 		}
 	}
 }
@@ -421,16 +378,12 @@ int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
 				domain->name = irq_data->chip->name;
 		}
 
-		switch (domain->revmap_type) {
-		case IRQ_DOMAIN_MAP_LINEAR:
-			if (hwirq < domain->revmap_data.linear.size)
-				domain->revmap_data.linear.revmap[hwirq] = virq;
-			break;
-		case IRQ_DOMAIN_MAP_TREE:
+		if (hwirq < domain->revmap_data.linear.size) {
+			domain->linear_revmap[hwirq] = virq;
+		} else {
 			mutex_lock(&revmap_trees_mutex);
 			radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data);
 			mutex_unlock(&revmap_trees_mutex);
-			break;
 		}
 
 		irq_clear_status_flags(virq, IRQ_NOREQUEST);
@@ -667,13 +620,6 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 	switch (domain->revmap_type) {
 	case IRQ_DOMAIN_MAP_LINEAR:
 		return irq_linear_revmap(domain, hwirq);
-	case IRQ_DOMAIN_MAP_TREE:
-		rcu_read_lock();
-		data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
-		rcu_read_unlock();
-		if (data)
-			return data->irq;
-		break;
 	case IRQ_DOMAIN_MAP_NOMAP:
 		data = irq_get_irq_data(hwirq);
 		if (data && (data->domain == domain) && (data->hwirq == hwirq))
@@ -696,13 +642,18 @@ EXPORT_SYMBOL_GPL(irq_find_mapping);
 unsigned int irq_linear_revmap(struct irq_domain *domain,
 			       irq_hw_number_t hwirq)
 {
+	struct irq_data *data;
 	BUG_ON(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR);
 
 	/* Check revmap bounds; complain if exceeded */
-	if (WARN_ON(hwirq >= domain->revmap_data.linear.size))
-		return 0;
+	if (hwirq >= domain->revmap_data.linear.size) {
+		rcu_read_lock();
+		data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
+		rcu_read_unlock();
+		return data ? data->irq : 0;
+	}
 
-	return domain->revmap_data.linear.revmap[hwirq];
+	return domain->linear_revmap[hwirq];
 }
 EXPORT_SYMBOL_GPL(irq_linear_revmap);
 
-- 
1.8.1.2


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

* [PATCH v2 05/11] irqdomain: Eliminate revmap type
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (3 preceding siblings ...)
  2013-06-14 21:07 ` [PATCH v2 04/11] irqdomain: merge linear and tree reverse mappings Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  2013-06-14 21:08 ` [PATCH v2 06/11] irqdomain: Clean up aftermath of irq_domain refactoring Grant Likely
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

The NOMAP irq_domain type is only used by a handful of interrupt
controllers and it unnecessarily complicates the code by adding special
cases on how to look up mappings and different revmap functions are used
for each type which need to validate the correct type is passed to it
before performing the reverse map. Eliminating the revmap_type and
making a single reverse mapping function simplifies the code. It also
shouldn't be any slower than having separate revmap functions because
the type of the revmap needed to be checked anyway.

The linear and tree revmap types were already merged in a previous
patch. This patch rolls the NOMAP or direct mapping behaviour into the
same domain code making is possible for an irq domain to do any mapping
type; linear, tree or direct; and that the mapping will be transparent
to the interrupt controller driver.

With this change, direct mappings will get stored in the linear or tree
mapping for consistency. Reverse mapping from the hwirq to virq will go
through the normal lookup process. However, any controller using a
direct mapping can take advantage of knowing that hwirq==virq for any
mapped interrupts skip doing a revmap lookup when handling IRQs.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 include/linux/irqdomain.h | 48 +++++++++++++++++------------------------
 kernel/irq/generic-chip.c |  5 +----
 kernel/irq/irqdomain.c    | 55 +++++++++++++++++++----------------------------
 3 files changed, 43 insertions(+), 65 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 1cbb741..51ef84a 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -73,50 +73,42 @@ struct irq_domain_chip_generic;
 /**
  * struct irq_domain - Hardware interrupt number translation object
  * @link: Element in global irq_domain list.
- * @revmap_type: Method used for reverse mapping hwirq numbers to linux irq. This
- *               will be one of the IRQ_DOMAIN_MAP_* values.
+ * @name: Name of interrupt domain
  * @ops: pointer to irq_domain methods
  * @host_data: private data pointer for use by owner.  Not touched by irq_domain
  *             core code.
- * @irq_base: Start of irq_desc range assigned to the irq_domain.  The creator
- *            of the irq_domain is responsible for allocating the array of
- *            irq_desc structures.
- * @nr_irq: Number of irqs managed by the irq domain
- * @hwirq_base: Starting number for hwirqs managed by the irq domain
- * @of_node: (optional) Pointer to device tree nodes associated with the
- *           irq_domain.  Used when decoding device tree interrupt specifiers.
+ *
+ * Optional elements
+ * @of_node: Pointer to device tree nodes associated with the irq_domain. Used
+ *           when decoding device tree interrupt specifiers.
+ * @gc: Pointer to a list of generic chips. There is a helper function for
+ *      setting up one or more generic chips for interrupt controllers
+ *      drivers using the generic chip library which uses this pointer.
+ *
+ * Revmap data, used internally by irq_domain
+ * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
+ *                         support direct mapping
+ * @revmap_size: Size of the linear map table @linear_revmap[]
+ * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
+ * @linear_revmap: Linear table of hwirq->virq reverse mappings
  */
 struct irq_domain {
 	struct list_head link;
 	const char *name;
-
-	/* type of reverse mapping_technique */
-	unsigned int revmap_type;
-	struct {
-		struct {
-			unsigned int size;
-		} linear;
-		struct {
-			unsigned int max_irq;
-		} nomap;
-		struct radix_tree_root tree;
-	} revmap_data;
 	const struct irq_domain_ops *ops;
 	void *host_data;
-	irq_hw_number_t inval_irq;
 
-	/* Optional device node pointer */
+	/* Optional data */
 	struct device_node *of_node;
-	/* Optional pointer to generic interrupt chips */
 	struct irq_domain_chip_generic *gc;
 
-	/* Linear reverse map */
+	/* reverse map data. The linear map gets appended to the irq_domain */
+	unsigned int revmap_direct_max_irq;
+	unsigned int revmap_size;
+	struct radix_tree_root revmap_tree;
 	unsigned int linear_revmap[];
 };
 
-#define IRQ_DOMAIN_MAP_NOMAP 1 /* no fast reverse mapping */
-#define IRQ_DOMAIN_MAP_LINEAR 2 /* linear map of interrupts */
-
 #ifdef CONFIG_IRQ_DOMAIN
 struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
 					 unsigned int size,
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index ca98cc5..4b01106 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -270,10 +270,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
 	if (d->gc)
 		return -EBUSY;
 
-	if (d->revmap_type != IRQ_DOMAIN_MAP_LINEAR)
-		return -EINVAL;
-
-	numchips = d->revmap_data.linear.size / irqs_per_chip;
+	numchips = d->revmap_size / irqs_per_chip;
 	if (!numchips)
 		return -EINVAL;
 
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 5a1d8ec..c38be78 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -25,7 +25,6 @@ static struct irq_domain *irq_default_domain;
 /**
  * irq_domain_alloc() - Allocate a new irq_domain data structure
  * @of_node: optional device-tree node of the interrupt controller
- * @revmap_type: type of reverse mapping to use
  * @ops: map/unmap domain callbacks
  * @host_data: Controller private data pointer
  *
@@ -34,7 +33,7 @@ static struct irq_domain *irq_default_domain;
  * to IRQ domain, or NULL on failure.
  */
 static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
-					   unsigned int revmap_type, int size,
+					   int size,
 					   const struct irq_domain_ops *ops,
 					   void *host_data)
 {
@@ -46,12 +45,11 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
 		return NULL;
 
 	/* Fill structure */
-	INIT_RADIX_TREE(&domain->revmap_data.tree, GFP_KERNEL);
-	domain->revmap_type = revmap_type;
+	INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
 	domain->ops = ops;
 	domain->host_data = host_data;
 	domain->of_node = of_node_get(of_node);
-	domain->revmap_data.linear.size = size;
+	domain->revmap_size = size;
 
 	return domain;
 }
@@ -67,8 +65,7 @@ static void irq_domain_add(struct irq_domain *domain)
 	mutex_lock(&irq_domain_mutex);
 	list_add(&domain->link, &irq_domain_list);
 	mutex_unlock(&irq_domain_mutex);
-	pr_debug("Allocated domain of type %d @0x%p\n",
-		 domain->revmap_type, domain);
+	pr_debug("Added domain %s\n", domain->name);
 }
 
 /**
@@ -88,7 +85,7 @@ void irq_domain_remove(struct irq_domain *domain)
 	 * node when all entries are removed. Shout if there are
 	 * any mappings left.
 	 */
-	WARN_ON(domain->revmap_data.tree.height);
+	WARN_ON(domain->revmap_tree.height);
 
 	list_del(&domain->link);
 
@@ -100,8 +97,7 @@ void irq_domain_remove(struct irq_domain *domain)
 
 	mutex_unlock(&irq_domain_mutex);
 
-	pr_debug("Removed domain of type %d @0x%p\n",
-		 domain->revmap_type, domain);
+	pr_debug("Removed domain %s\n", domain->name);
 
 	irq_domain_free(domain);
 }
@@ -216,7 +212,7 @@ struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
 {
 	struct irq_domain *domain;
 
-	domain = irq_domain_alloc(of_node, IRQ_DOMAIN_MAP_LINEAR, size, ops, host_data);
+	domain = irq_domain_alloc(of_node, size, ops, host_data);
 	if (!domain)
 		return NULL;
 
@@ -230,10 +226,9 @@ struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	struct irq_domain *domain = irq_domain_alloc(of_node,
-					IRQ_DOMAIN_MAP_NOMAP, 0, ops, host_data);
+	struct irq_domain *domain = irq_domain_alloc(of_node, 0, ops, host_data);
 	if (domain) {
-		domain->revmap_data.nomap.max_irq = max_irq ? max_irq : ~0;
+		domain->revmap_direct_max_irq = max_irq ? max_irq : ~0;
 		irq_domain_add(domain);
 	}
 	return domain;
@@ -321,11 +316,11 @@ static void irq_domain_disassociate_many(struct irq_domain *domain,
 		irq_data->hwirq = 0;
 
 		/* Clear reverse map for this hwirq */
-		if (hwirq < domain->revmap_data.linear.size) {
+		if (hwirq < domain->revmap_size) {
 			domain->linear_revmap[hwirq] = 0;
 		} else {
 			mutex_lock(&revmap_trees_mutex);
-			radix_tree_delete(&domain->revmap_data.tree, hwirq);
+			radix_tree_delete(&domain->revmap_tree, hwirq);
 			mutex_unlock(&revmap_trees_mutex);
 		}
 	}
@@ -378,11 +373,11 @@ int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
 				domain->name = irq_data->chip->name;
 		}
 
-		if (hwirq < domain->revmap_data.linear.size) {
+		if (hwirq < domain->revmap_size) {
 			domain->linear_revmap[hwirq] = virq;
 		} else {
 			mutex_lock(&revmap_trees_mutex);
-			radix_tree_insert(&domain->revmap_data.tree, hwirq, irq_data);
+			radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
 			mutex_unlock(&revmap_trees_mutex);
 		}
 
@@ -399,7 +394,9 @@ EXPORT_SYMBOL_GPL(irq_domain_associate_many);
  *
  * This routine is used for irq controllers which can choose the hardware
  * interrupt numbers they generate. In such a case it's simplest to use
- * the linux irq as the hardware interrupt number.
+ * the linux irq as the hardware interrupt number. It still uses the linear
+ * or radix tree to store the mapping, but the irq controller can optimize
+ * the revmap path by using the hwirq directly.
  */
 unsigned int irq_create_direct_mapping(struct irq_domain *domain)
 {
@@ -408,17 +405,14 @@ unsigned int irq_create_direct_mapping(struct irq_domain *domain)
 	if (domain == NULL)
 		domain = irq_default_domain;
 
-	if (WARN_ON(!domain || domain->revmap_type != IRQ_DOMAIN_MAP_NOMAP))
-		return 0;
-
 	virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
 	if (!virq) {
 		pr_debug("create_direct virq allocation failed\n");
 		return 0;
 	}
-	if (virq >= domain->revmap_data.nomap.max_irq) {
+	if (virq >= domain->revmap_direct_max_irq) {
 		pr_err("ERROR: no free irqs available below %i maximum\n",
-			domain->revmap_data.nomap.max_irq);
+			domain->revmap_direct_max_irq);
 		irq_free_desc(virq);
 		return 0;
 	}
@@ -617,17 +611,13 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 	if (domain == NULL)
 		return 0;
 
-	switch (domain->revmap_type) {
-	case IRQ_DOMAIN_MAP_LINEAR:
-		return irq_linear_revmap(domain, hwirq);
-	case IRQ_DOMAIN_MAP_NOMAP:
+	if (hwirq < domain->revmap_direct_max_irq) {
 		data = irq_get_irq_data(hwirq);
 		if (data && (data->domain == domain) && (data->hwirq == hwirq))
 			return hwirq;
-		break;
 	}
 
-	return 0;
+	return irq_linear_revmap(domain, hwirq);
 }
 EXPORT_SYMBOL_GPL(irq_find_mapping);
 
@@ -643,12 +633,11 @@ unsigned int irq_linear_revmap(struct irq_domain *domain,
 			       irq_hw_number_t hwirq)
 {
 	struct irq_data *data;
-	BUG_ON(domain->revmap_type != IRQ_DOMAIN_MAP_LINEAR);
 
 	/* Check revmap bounds; complain if exceeded */
-	if (hwirq >= domain->revmap_data.linear.size) {
+	if (hwirq >= domain->revmap_size) {
 		rcu_read_lock();
-		data = radix_tree_lookup(&domain->revmap_data.tree, hwirq);
+		data = radix_tree_lookup(&domain->revmap_tree, hwirq);
 		rcu_read_unlock();
 		return data ? data->irq : 0;
 	}
-- 
1.8.1.2


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

* [PATCH v2 06/11] irqdomain: Clean up aftermath of irq_domain refactoring
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (4 preceding siblings ...)
  2013-06-14 21:08 ` [PATCH v2 05/11] irqdomain: Eliminate revmap type Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  2013-06-14 21:08 ` [PATCH v2 07/11] irqdomain: Beef up debugfs output Grant Likely
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

After refactoring the irqdomain code, there are a number of API
functions that are merely empty wrappers around core code. Drop those
wrappers out of the C file and replace them with static inlines in the
header.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 arch/powerpc/platforms/cell/beat_interrupt.c |   2 +-
 arch/powerpc/platforms/powermac/smp.c        |   2 +-
 include/linux/irqdomain.h                    |  31 +++++--
 kernel/irq/irqdomain.c                       | 127 ++++++++-------------------
 4 files changed, 62 insertions(+), 100 deletions(-)

diff --git a/arch/powerpc/platforms/cell/beat_interrupt.c b/arch/powerpc/platforms/cell/beat_interrupt.c
index 8c6dc42..9e5dfbc 100644
--- a/arch/powerpc/platforms/cell/beat_interrupt.c
+++ b/arch/powerpc/platforms/cell/beat_interrupt.c
@@ -239,7 +239,7 @@ void __init beatic_init_IRQ(void)
 	ppc_md.get_irq = beatic_get_irq;
 
 	/* Allocate an irq host */
-	beatic_host = irq_domain_add_nomap(NULL, 0, &beatic_pic_host_ops, NULL);
+	beatic_host = irq_domain_add_nomap(NULL, ~0, &beatic_pic_host_ops, NULL);
 	BUG_ON(beatic_host == NULL);
 	irq_set_default_host(beatic_host);
 }
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index bdb738a..f921067 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -192,7 +192,7 @@ static int psurge_secondary_ipi_init(void)
 {
 	int rc = -ENOMEM;
 
-	psurge_host = irq_domain_add_nomap(NULL, 0, &psurge_host_ops, NULL);
+	psurge_host = irq_domain_add_nomap(NULL, ~0, &psurge_host_ops, NULL);
 
 	if (psurge_host)
 		psurge_secondary_virq = irq_create_direct_mapping(psurge_host);
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 51ef84a..fd4b26f 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -110,6 +110,10 @@ struct irq_domain {
 };
 
 #ifdef CONFIG_IRQ_DOMAIN
+struct irq_domain *__irq_domain_add(struct device_node *of_node,
+				    int size, int direct_max,
+				    const struct irq_domain_ops *ops,
+				    void *host_data);
 struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
 					 unsigned int size,
 					 unsigned int first_irq,
@@ -121,17 +125,30 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 					 irq_hw_number_t first_hwirq,
 					 const struct irq_domain_ops *ops,
 					 void *host_data);
-struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
+extern struct irq_domain *irq_find_host(struct device_node *node);
+extern void irq_set_default_host(struct irq_domain *host);
+
+/**
+ * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain.
+ * @of_node: pointer to interrupt controller's device tree node.
+ * @size: Number of interrupts in the domain.
+ * @ops: map/unmap domain callbacks
+ * @host_data: Controller private data pointer
+ */
+static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
 					 unsigned int size,
 					 const struct irq_domain_ops *ops,
-					 void *host_data);
-struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
+					 void *host_data)
+{
+	return __irq_domain_add(of_node, size, 0, ops, host_data);
+}
+static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
 					 unsigned int max_irq,
 					 const struct irq_domain_ops *ops,
-					 void *host_data);
-extern struct irq_domain *irq_find_host(struct device_node *node);
-extern void irq_set_default_host(struct irq_domain *host);
-
+					 void *host_data)
+{
+	return __irq_domain_add(of_node, 0, max_irq, ops, host_data);
+}
 static inline struct irq_domain *irq_domain_add_legacy_isa(
 				struct device_node *of_node,
 				const struct irq_domain_ops *ops,
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index c38be78..e0db59e 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -23,8 +23,11 @@ static DEFINE_MUTEX(revmap_trees_mutex);
 static struct irq_domain *irq_default_domain;
 
 /**
- * irq_domain_alloc() - Allocate a new irq_domain data structure
+ * __irq_domain_add() - Allocate a new irq_domain data structure
  * @of_node: optional device-tree node of the interrupt controller
+ * @size: Size of linear map; 0 for radix mapping only
+ * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
+ *              direct mapping
  * @ops: map/unmap domain callbacks
  * @host_data: Controller private data pointer
  *
@@ -32,10 +35,10 @@ static struct irq_domain *irq_default_domain;
  * register allocated irq_domain with irq_domain_register().  Returns pointer
  * to IRQ domain, or NULL on failure.
  */
-static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
-					   int size,
-					   const struct irq_domain_ops *ops,
-					   void *host_data)
+struct irq_domain *__irq_domain_add(struct device_node *of_node,
+				    int size, int direct_max,
+				    const struct irq_domain_ops *ops,
+				    void *host_data)
 {
 	struct irq_domain *domain;
 
@@ -50,23 +53,16 @@ static struct irq_domain *irq_domain_alloc(struct device_node *of_node,
 	domain->host_data = host_data;
 	domain->of_node = of_node_get(of_node);
 	domain->revmap_size = size;
+	domain->revmap_direct_max_irq = direct_max;
 
-	return domain;
-}
-
-static void irq_domain_free(struct irq_domain *domain)
-{
-	of_node_put(domain->of_node);
-	kfree(domain);
-}
-
-static void irq_domain_add(struct irq_domain *domain)
-{
 	mutex_lock(&irq_domain_mutex);
 	list_add(&domain->link, &irq_domain_list);
 	mutex_unlock(&irq_domain_mutex);
+
 	pr_debug("Added domain %s\n", domain->name);
+	return domain;
 }
+EXPORT_SYMBOL_GPL(__irq_domain_add);
 
 /**
  * irq_domain_remove() - Remove an irq domain.
@@ -99,30 +95,28 @@ void irq_domain_remove(struct irq_domain *domain)
 
 	pr_debug("Removed domain %s\n", domain->name);
 
-	irq_domain_free(domain);
+	of_node_put(domain->of_node);
+	kfree(domain);
 }
 EXPORT_SYMBOL_GPL(irq_domain_remove);
 
 /**
- * irq_domain_add_simple() - Allocate and register a simple irq_domain.
+ * irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs
  * @of_node: pointer to interrupt controller's device tree node.
  * @size: total number of irqs in mapping
  * @first_irq: first number of irq block assigned to the domain,
- *	pass zero to assign irqs on-the-fly. This will result in a
- *	linear IRQ domain so it is important to use irq_create_mapping()
- *	for each used IRQ, especially when SPARSE_IRQ is enabled.
+ *	pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
+ *	pre-map all of the irqs in the domain to virqs starting at first_irq.
  * @ops: map/unmap domain callbacks
  * @host_data: Controller private data pointer
  *
- * Allocates a legacy irq_domain if irq_base is positive or a linear
- * domain otherwise. For the legacy domain, IRQ descriptors will also
- * be allocated.
+ * Allocates an irq_domain, and optionally if first_irq is positive then also
+ * allocate irq_descs and map all of the hwirqs to virqs starting at first_irq.
  *
  * This is intended to implement the expected behaviour for most
- * interrupt controllers which is that a linear mapping should
- * normally be used unless the system requires a legacy mapping in
- * order to support supplying interrupt numbers during non-DT
- * registration of devices.
+ * interrupt controllers. If device tree is used, then first_irq will be 0 and
+ * irqs get mapped dynamically on the fly. However, if the controller requires
+ * static virq assignments (non-DT boot) then it will set that up correctly.
  */
 struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
 					 unsigned int size,
@@ -130,33 +124,25 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	if (first_irq > 0) {
-		int irq_base;
+	struct irq_domain *domain;
+
+	domain = __irq_domain_add(of_node, size, 0, ops, host_data);
+	if (!domain)
+		return NULL;
 
+	if (first_irq > 0) {
 		if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
-			/*
-			 * Set the descriptor allocator to search for a
-			 * 1-to-1 mapping, such as irq_alloc_desc_at().
-			 * Use of_node_to_nid() which is defined to
-			 * numa_node_id() on platforms that have no custom
-			 * implementation.
-			 */
-			irq_base = irq_alloc_descs(first_irq, first_irq, size,
-						   of_node_to_nid(of_node));
-			if (irq_base < 0) {
+			/* attempt to allocated irq_descs */
+			int rc = irq_alloc_descs(first_irq, first_irq, size,
+						 of_node_to_nid(of_node));
+			if (rc < 0)
 				pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
 					first_irq);
-				irq_base = first_irq;
-			}
-		} else
-			irq_base = first_irq;
-
-		return irq_domain_add_legacy(of_node, size, irq_base, 0,
-					     ops, host_data);
+		}
+		WARN_ON(irq_domain_associate_many(domain, first_irq, 0, size));
 	}
 
-	/* A linear domain is the default */
-	return irq_domain_add_linear(of_node, size, ops, host_data);
+	return domain;
 }
 EXPORT_SYMBOL_GPL(irq_domain_add_simple);
 
@@ -184,11 +170,7 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 {
 	struct irq_domain *domain;
 
-	pr_debug("Setting up legacy domain virq[%i:%i] ==> hwirq[%i:%i]\n",
-		 first_irq, first_irq + size - 1,
-		 (int)first_hwirq, (int)first_hwirq + size -1);
-
-	domain = irq_domain_add_linear(of_node, first_hwirq + size, ops, host_data);
+	domain = __irq_domain_add(of_node, first_hwirq + size, 0, ops, host_data);
 	if (!domain)
 		return NULL;
 
@@ -199,43 +181,6 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 EXPORT_SYMBOL_GPL(irq_domain_add_legacy);
 
 /**
- * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain.
- * @of_node: pointer to interrupt controller's device tree node.
- * @size: Number of interrupts in the domain.
- * @ops: map/unmap domain callbacks
- * @host_data: Controller private data pointer
- */
-struct irq_domain *irq_domain_add_linear(struct device_node *of_node,
-					 unsigned int size,
-					 const struct irq_domain_ops *ops,
-					 void *host_data)
-{
-	struct irq_domain *domain;
-
-	domain = irq_domain_alloc(of_node, size, ops, host_data);
-	if (!domain)
-		return NULL;
-
-	irq_domain_add(domain);
-	return domain;
-}
-EXPORT_SYMBOL_GPL(irq_domain_add_linear);
-
-struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
-					 unsigned int max_irq,
-					 const struct irq_domain_ops *ops,
-					 void *host_data)
-{
-	struct irq_domain *domain = irq_domain_alloc(of_node, 0, ops, host_data);
-	if (domain) {
-		domain->revmap_direct_max_irq = max_irq ? max_irq : ~0;
-		irq_domain_add(domain);
-	}
-	return domain;
-}
-EXPORT_SYMBOL_GPL(irq_domain_add_nomap);
-
-/**
  * irq_find_host() - Locates a domain for a given device node
  * @node: device-tree node of the interrupt controller
  */
-- 
1.8.1.2


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

* [PATCH v2 07/11] irqdomain: Beef up debugfs output
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (5 preceding siblings ...)
  2013-06-14 21:08 ` [PATCH v2 06/11] irqdomain: Clean up aftermath of irq_domain refactoring Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  2013-06-14 21:08 ` [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many() Grant Likely
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

This patch increases the amount of output produced by the
irq_domain_mapping debugfs file by first listing all of the registered
irq domains at the beginning of the output, and then by including all
mapped IRQs in the output, not just the active ones. It is very useful
when debugging irqdomain issues to be able to see the entire list of
mapped irqs, not just the ones that happen to be connected to devices.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 kernel/irq/irqdomain.c | 35 ++++++++++++++++++++++++++++++-----
 1 file changed, 30 insertions(+), 5 deletions(-)

diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index e0db59e..280b804 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -596,12 +596,29 @@ static int virq_debug_show(struct seq_file *m, void *private)
 {
 	unsigned long flags;
 	struct irq_desc *desc;
-	void *data;
+	struct irq_domain *domain;
+	struct radix_tree_iter iter;
+	void *data, **slot;
 	int i;
 
-	seq_printf(m, "%-5s  %-7s  %-15s  %-*s  %s\n", "irq", "hwirq",
+	seq_printf(m, " %-16s  %-6s  %-10s  %-10s  %s\n",
+		   "name", "mapped", "linear-max", "direct-max", "devtree-node");
+	mutex_lock(&irq_domain_mutex);
+	list_for_each_entry(domain, &irq_domain_list, link) {
+		int count = 0;
+		radix_tree_for_each_slot(slot, &domain->revmap_tree, &iter, 0)
+			count++;
+		seq_printf(m, "%c%-16s  %6u  %10u  %10u  %s\n",
+			   domain == irq_default_domain ? '*' : ' ', domain->name,
+			   domain->revmap_size + count, domain->revmap_size,
+			   domain->revmap_direct_max_irq,
+			   domain->of_node ? of_node_full_name(domain->of_node) : "");
+	}
+	mutex_unlock(&irq_domain_mutex);
+
+	seq_printf(m, "%-5s  %-7s  %-15s  %-*s  %6s  %-14s  %s\n", "irq", "hwirq",
 		      "chip name", (int)(2 * sizeof(void *) + 2), "chip data",
-		      "domain name");
+		      "active", "type", "domain");
 
 	for (i = 1; i < nr_irqs; i++) {
 		desc = irq_to_desc(i);
@@ -609,12 +626,15 @@ static int virq_debug_show(struct seq_file *m, void *private)
 			continue;
 
 		raw_spin_lock_irqsave(&desc->lock, flags);
+		domain = desc->irq_data.domain;
 
-		if (desc->action && desc->action->handler) {
+		if (domain) {
 			struct irq_chip *chip;
+			int hwirq = desc->irq_data.hwirq;
+			bool direct;
 
 			seq_printf(m, "%5d  ", i);
-			seq_printf(m, "0x%05lx  ", desc->irq_data.hwirq);
+			seq_printf(m, "0x%05x  ", hwirq);
 
 			chip = irq_desc_get_chip(desc);
 			seq_printf(m, "%-15s  ", (chip && chip->name) ? chip->name : "none");
@@ -622,6 +642,11 @@ static int virq_debug_show(struct seq_file *m, void *private)
 			data = irq_desc_get_chip_data(desc);
 			seq_printf(m, data ? "0x%p  " : "  %p  ", data);
 
+			seq_printf(m, "   %c    ", (desc->action && desc->action->handler) ? '*' : ' ');
+			direct = (i == hwirq) && (i < domain->revmap_direct_max_irq);
+			seq_printf(m, "%6s%-8s  ",
+				   (hwirq < domain->revmap_size) ? "LINEAR" : "RADIX",
+				   direct ? "(DIRECT)" : "");
 			seq_printf(m, "%s\n", desc->irq_data.domain->name);
 		}
 
-- 
1.8.1.2


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

* [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (6 preceding siblings ...)
  2013-06-14 21:08 ` [PATCH v2 07/11] irqdomain: Beef up debugfs output Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  2013-06-18  1:20   ` Michael Neuling
  2013-06-14 21:08 ` [PATCH v2 09/11] irqdomain: remove irq_domain_generate_simple() Grant Likely
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

Originally, irq_domain_associate_many() was designed to unwind the
mapped irqs on a failure of any individual association. However, that
proved to be a problem with certain IRQ controllers. Some of them only
support a subset of irqs, and will fail when attempting to map a
reserved IRQ. In those cases we want to map as many IRQs as possible, so
instead it is better for irq_domain_associate_many() to make a
best-effort attempt to map irqs, but not fail if any or all of them
don't succeed. If a caller really cares about how many irqs got
associated, then it should instead go back and check that all of the
irqs is cares about were mapped.

The original design open-coded the individual association code into the
body of irq_domain_associate_many(), but with no longer needing to
unwind associations, the code becomes simpler to split out
irq_domain_associate() to contain the bulk of the logic, and
irq_domain_associate_many() to be a simple loop wrapper.

This patch also adds a new error check to the associate path to make
sure it isn't called for an irq larger than the controller can handle,
and adds locking so that the irq_domain_mutex is held while setting up a
new association.

v2: Fixup x86 warning. irq_domain_associate_many() no longer returns an
    error code, but reports errors to the printk log directly. In the
    majority of cases we don't actually want to fail if there is a
    problem, but rather log it and still try to boot the system.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 arch/x86/kernel/devicetree.c |   4 +-
 include/linux/irqdomain.h    |  22 +++--
 kernel/irq/irqdomain.c       | 185 +++++++++++++++++++++----------------------
 3 files changed, 102 insertions(+), 109 deletions(-)

diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
index b158152..4934890 100644
--- a/arch/x86/kernel/devicetree.c
+++ b/arch/x86/kernel/devicetree.c
@@ -364,9 +364,7 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num,
 		 * and assigned so we can keep the 1:1 mapping which the ioapic
 		 * is having.
 		 */
-		ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
-		if (ret)
-			pr_err("Error mapping legacy IRQs: %d\n", ret);
+		irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
 
 		if (num > NR_IRQS_LEGACY) {
 			ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index fd4b26f..f9e8e06 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -103,6 +103,7 @@ struct irq_domain {
 	struct irq_domain_chip_generic *gc;
 
 	/* reverse map data. The linear map gets appended to the irq_domain */
+	irq_hw_number_t hwirq_max;
 	unsigned int revmap_direct_max_irq;
 	unsigned int revmap_size;
 	struct radix_tree_root revmap_tree;
@@ -110,8 +111,8 @@ struct irq_domain {
 };
 
 #ifdef CONFIG_IRQ_DOMAIN
-struct irq_domain *__irq_domain_add(struct device_node *of_node,
-				    int size, int direct_max,
+struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
+				    irq_hw_number_t hwirq_max, int direct_max,
 				    const struct irq_domain_ops *ops,
 				    void *host_data);
 struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
@@ -140,14 +141,14 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(of_node, size, 0, ops, host_data);
+	return __irq_domain_add(of_node, size, size, 0, ops, host_data);
 }
 static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
 					 unsigned int max_irq,
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return __irq_domain_add(of_node, 0, max_irq, ops, host_data);
+	return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data);
 }
 static inline struct irq_domain *irq_domain_add_legacy_isa(
 				struct device_node *of_node,
@@ -166,14 +167,11 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
 
 extern void irq_domain_remove(struct irq_domain *host);
 
-extern int irq_domain_associate_many(struct irq_domain *domain,
-				     unsigned int irq_base,
-				     irq_hw_number_t hwirq_base, int count);
-static inline int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
-					irq_hw_number_t hwirq)
-{
-	return irq_domain_associate_many(domain, irq, hwirq, 1);
-}
+extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
+					irq_hw_number_t hwirq);
+extern void irq_domain_associate_many(struct irq_domain *domain,
+				      unsigned int irq_base,
+				      irq_hw_number_t hwirq_base, int count);
 
 extern unsigned int irq_create_mapping(struct irq_domain *host,
 				       irq_hw_number_t hwirq);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 280b804..80e9249 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -35,8 +35,8 @@ static struct irq_domain *irq_default_domain;
  * register allocated irq_domain with irq_domain_register().  Returns pointer
  * to IRQ domain, or NULL on failure.
  */
-struct irq_domain *__irq_domain_add(struct device_node *of_node,
-				    int size, int direct_max,
+struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
+				    irq_hw_number_t hwirq_max, int direct_max,
 				    const struct irq_domain_ops *ops,
 				    void *host_data)
 {
@@ -52,6 +52,7 @@ struct irq_domain *__irq_domain_add(struct device_node *of_node,
 	domain->ops = ops;
 	domain->host_data = host_data;
 	domain->of_node = of_node_get(of_node);
+	domain->hwirq_max = hwirq_max;
 	domain->revmap_size = size;
 	domain->revmap_direct_max_irq = direct_max;
 
@@ -126,7 +127,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
 {
 	struct irq_domain *domain;
 
-	domain = __irq_domain_add(of_node, size, 0, ops, host_data);
+	domain = __irq_domain_add(of_node, size, size, 0, ops, host_data);
 	if (!domain)
 		return NULL;
 
@@ -139,7 +140,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
 				pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
 					first_irq);
 		}
-		WARN_ON(irq_domain_associate_many(domain, first_irq, 0, size));
+		irq_domain_associate_many(domain, first_irq, 0, size);
 	}
 
 	return domain;
@@ -170,11 +171,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
 {
 	struct irq_domain *domain;
 
-	domain = __irq_domain_add(of_node, first_hwirq + size, 0, ops, host_data);
+	domain = __irq_domain_add(of_node, first_hwirq + size,
+				  first_hwirq + size, 0, ops, host_data);
 	if (!domain)
 		return NULL;
 
-	WARN_ON(irq_domain_associate_many(domain, first_irq, first_hwirq, size));
+	irq_domain_associate_many(domain, first_irq, first_hwirq, size);
 
 	return domain;
 }
@@ -228,109 +230,109 @@ void irq_set_default_host(struct irq_domain *domain)
 }
 EXPORT_SYMBOL_GPL(irq_set_default_host);
 
-static void irq_domain_disassociate_many(struct irq_domain *domain,
-					 unsigned int irq_base, int count)
+static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
 {
-	/*
-	 * disassociate in reverse order;
-	 * not strictly necessary, but nice for unwinding
-	 */
-	while (count--) {
-		int irq = irq_base + count;
-		struct irq_data *irq_data = irq_get_irq_data(irq);
-		irq_hw_number_t hwirq;
+	struct irq_data *irq_data = irq_get_irq_data(irq);
+	irq_hw_number_t hwirq;
 
-		if (WARN_ON(!irq_data || irq_data->domain != domain))
-			continue;
+	if (WARN(!irq_data || irq_data->domain != domain,
+		 "virq%i doesn't exist; cannot disassociate\n", irq))
+		return;
 
-		hwirq = irq_data->hwirq;
-		irq_set_status_flags(irq, IRQ_NOREQUEST);
+	hwirq = irq_data->hwirq;
+	irq_set_status_flags(irq, IRQ_NOREQUEST);
 
-		/* remove chip and handler */
-		irq_set_chip_and_handler(irq, NULL, NULL);
+	/* remove chip and handler */
+	irq_set_chip_and_handler(irq, NULL, NULL);
 
-		/* Make sure it's completed */
-		synchronize_irq(irq);
+	/* Make sure it's completed */
+	synchronize_irq(irq);
 
-		/* Tell the PIC about it */
-		if (domain->ops->unmap)
-			domain->ops->unmap(domain, irq);
-		smp_mb();
+	/* Tell the PIC about it */
+	if (domain->ops->unmap)
+		domain->ops->unmap(domain, irq);
+	smp_mb();
 
-		irq_data->domain = NULL;
-		irq_data->hwirq = 0;
+	irq_data->domain = NULL;
+	irq_data->hwirq = 0;
 
-		/* Clear reverse map for this hwirq */
-		if (hwirq < domain->revmap_size) {
-			domain->linear_revmap[hwirq] = 0;
-		} else {
-			mutex_lock(&revmap_trees_mutex);
-			radix_tree_delete(&domain->revmap_tree, hwirq);
-			mutex_unlock(&revmap_trees_mutex);
-		}
+	/* Clear reverse map for this hwirq */
+	if (hwirq < domain->revmap_size) {
+		domain->linear_revmap[hwirq] = 0;
+	} else {
+		mutex_lock(&revmap_trees_mutex);
+		radix_tree_delete(&domain->revmap_tree, hwirq);
+		mutex_unlock(&revmap_trees_mutex);
 	}
 }
 
-int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
-			      irq_hw_number_t hwirq_base, int count)
+int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
+			 irq_hw_number_t hwirq)
 {
-	unsigned int virq = irq_base;
-	irq_hw_number_t hwirq = hwirq_base;
-	int i, ret;
+	struct irq_data *irq_data = irq_get_irq_data(virq);
+	int ret;
 
-	pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
-		of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
+	if (WARN(hwirq >= domain->hwirq_max,
+		 "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))
+		return -EINVAL;
+	if (WARN(!irq_data, "error: virq%i is not allocated", virq))
+		return -EINVAL;
+	if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
+		return -EINVAL;
 
-	for (i = 0; i < count; i++) {
-		struct irq_data *irq_data = irq_get_irq_data(virq + i);
-
-		if (WARN(!irq_data, "error: irq_desc not allocated; "
-			 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
-			return -EINVAL;
-		if (WARN(irq_data->domain, "error: irq_desc already associated; "
-			 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
-			return -EINVAL;
-	};
-
-	for (i = 0; i < count; i++, virq++, hwirq++) {
-		struct irq_data *irq_data = irq_get_irq_data(virq);
-
-		irq_data->hwirq = hwirq;
-		irq_data->domain = domain;
-		if (domain->ops->map) {
-			ret = domain->ops->map(domain, virq, hwirq);
-			if (ret != 0) {
-				/*
-				 * If map() returns -EPERM, this interrupt is protected
-				 * by the firmware or some other service and shall not
-				 * be mapped. Don't bother telling the user about it.
-				 */
-				if (ret != -EPERM) {
-					pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
-					       domain->name, hwirq, virq, ret);
-				}
-				irq_data->domain = NULL;
-				irq_data->hwirq = 0;
-				continue;
+	mutex_lock(&irq_domain_mutex);
+	irq_data->hwirq = hwirq;
+	irq_data->domain = domain;
+	if (domain->ops->map) {
+		ret = domain->ops->map(domain, virq, hwirq);
+		if (ret != 0) {
+			/*
+			 * If map() returns -EPERM, this interrupt is protected
+			 * by the firmware or some other service and shall not
+			 * be mapped. Don't bother telling the user about it.
+			 */
+			if (ret != -EPERM) {
+				pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
+				       domain->name, hwirq, virq, ret);
 			}
-			/* If not already assigned, give the domain the chip's name */
-			if (!domain->name && irq_data->chip)
-				domain->name = irq_data->chip->name;
+			irq_data->domain = NULL;
+			irq_data->hwirq = 0;
+			mutex_unlock(&irq_domain_mutex);
+			return ret;
 		}
 
-		if (hwirq < domain->revmap_size) {
-			domain->linear_revmap[hwirq] = virq;
-		} else {
-			mutex_lock(&revmap_trees_mutex);
-			radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
-			mutex_unlock(&revmap_trees_mutex);
-		}
+		/* If not already assigned, give the domain the chip's name */
+		if (!domain->name && irq_data->chip)
+			domain->name = irq_data->chip->name;
+	}
 
-		irq_clear_status_flags(virq, IRQ_NOREQUEST);
+	if (hwirq < domain->revmap_size) {
+		domain->linear_revmap[hwirq] = virq;
+	} else {
+		mutex_lock(&revmap_trees_mutex);
+		radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
+		mutex_unlock(&revmap_trees_mutex);
 	}
+	mutex_unlock(&irq_domain_mutex);
+
+	irq_clear_status_flags(virq, IRQ_NOREQUEST);
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(irq_domain_associate);
+
+void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
+			       irq_hw_number_t hwirq_base, int count)
+{
+	int i;
+
+	pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
+		of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
+
+	for (i = 0; i < count; i++) {
+		irq_domain_associate(domain, irq_base + i, hwirq_base + i);
+	}
+}
 EXPORT_SYMBOL_GPL(irq_domain_associate_many);
 
 /**
@@ -460,12 +462,7 @@ int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
 	if (unlikely(ret < 0))
 		return ret;
 
-	ret = irq_domain_associate_many(domain, irq_base, hwirq_base, count);
-	if (unlikely(ret < 0)) {
-		irq_free_descs(irq_base, count);
-		return ret;
-	}
-
+	irq_domain_associate_many(domain, irq_base, hwirq_base, count);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
@@ -535,7 +532,7 @@ void irq_dispose_mapping(unsigned int virq)
 	if (WARN_ON(domain == NULL))
 		return;
 
-	irq_domain_disassociate_many(domain, virq, 1);
+	irq_domain_disassociate(domain, virq);
 	irq_free_desc(virq);
 }
 EXPORT_SYMBOL_GPL(irq_dispose_mapping);
-- 
1.8.1.2


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

* [PATCH v2 09/11] irqdomain: remove irq_domain_generate_simple()
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (7 preceding siblings ...)
  2013-06-14 21:08 ` [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many() Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  2013-06-14 21:08 ` [PATCH v2 10/11] irqdomain: make irq_linear_revmap() a fast path again Grant Likely
  2013-06-14 21:08 ` [PATCH v2 11/11] irqdomain: Include hwirq number in /proc/interrupts Grant Likely
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

Nobody calls it; remove the function

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 include/linux/irqdomain.h |  8 --------
 kernel/irq/irqdomain.c    | 15 ---------------
 2 files changed, 23 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index f9e8e06..fe7c57d 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -205,14 +205,6 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
 			const u32 *intspec, unsigned int intsize,
 			irq_hw_number_t *out_hwirq, unsigned int *out_type);
 
-#if defined(CONFIG_OF_IRQ)
-extern void irq_domain_generate_simple(const struct of_device_id *match,
-					u64 phys_base, unsigned int irq_start);
-#else /* CONFIG_OF_IRQ */
-static inline void irq_domain_generate_simple(const struct of_device_id *match,
-					u64 phys_base, unsigned int irq_start) { }
-#endif /* !CONFIG_OF_IRQ */
-
 #else /* CONFIG_IRQ_DOMAIN */
 static inline void irq_dispose_mapping(unsigned int virq) { }
 #endif /* !CONFIG_IRQ_DOMAIN */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 80e9249..e47b356 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -741,18 +741,3 @@ const struct irq_domain_ops irq_domain_simple_ops = {
 	.xlate = irq_domain_xlate_onetwocell,
 };
 EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
-
-#ifdef CONFIG_OF_IRQ
-void irq_domain_generate_simple(const struct of_device_id *match,
-				u64 phys_base, unsigned int irq_start)
-{
-	struct device_node *node;
-	pr_debug("looking for phys_base=%llx, irq_start=%i\n",
-		(unsigned long long) phys_base, (int) irq_start);
-	node = of_find_matching_node_by_address(NULL, match, phys_base);
-	if (node)
-		irq_domain_add_legacy(node, 32, irq_start, 0,
-				      &irq_domain_simple_ops, NULL);
-}
-EXPORT_SYMBOL_GPL(irq_domain_generate_simple);
-#endif
-- 
1.8.1.2


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

* [PATCH v2 10/11] irqdomain: make irq_linear_revmap() a fast path again
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (8 preceding siblings ...)
  2013-06-14 21:08 ` [PATCH v2 09/11] irqdomain: remove irq_domain_generate_simple() Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  2013-06-14 21:08 ` [PATCH v2 11/11] irqdomain: Include hwirq number in /proc/interrupts Grant Likely
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

Over the years, irq_linear_revmap() gained tests and checks to make sure
callers were using it safely, which while important, also make it less
of a fast path. After the irqdomain refactoring done recently, it is now
possible to make irq_linear_revmap() a fast path again. This patch moves
irq_linear_revmap() to the header file and makes it a static inline so
that interrupt controller drivers using a linear mapping can decode the
virq from a hwirq in just a couple of instructions.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
---
 include/linux/irqdomain.h | 19 ++++++++++++++++---
 kernel/irq/irqdomain.c    | 34 ++++++++--------------------------
 2 files changed, 24 insertions(+), 29 deletions(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index fe7c57d..02f7658 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -176,6 +176,22 @@ extern void irq_domain_associate_many(struct irq_domain *domain,
 extern unsigned int irq_create_mapping(struct irq_domain *host,
 				       irq_hw_number_t hwirq);
 extern void irq_dispose_mapping(unsigned int virq);
+
+/**
+ * irq_linear_revmap() - Find a linux irq from a hw irq number.
+ * @domain: domain owning this hardware interrupt
+ * @hwirq: hardware irq number in that domain space
+ *
+ * This is a fast path alternative to irq_find_mapping() that can be
+ * called directly by irq controller code to save a handful of
+ * instructions. It is always safe to call, but won't find irqs mapped
+ * using the radix tree.
+ */
+static inline unsigned int irq_linear_revmap(struct irq_domain *domain,
+					     irq_hw_number_t hwirq)
+{
+	return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0;
+}
 extern unsigned int irq_find_mapping(struct irq_domain *host,
 				     irq_hw_number_t hwirq);
 extern unsigned int irq_create_direct_mapping(struct irq_domain *host);
@@ -189,9 +205,6 @@ static inline int irq_create_identity_mapping(struct irq_domain *host,
 	return irq_create_strict_mappings(host, hwirq, hwirq, 1);
 }
 
-extern unsigned int irq_linear_revmap(struct irq_domain *host,
-				      irq_hw_number_t hwirq);
-
 extern const struct irq_domain_ops irq_domain_simple_ops;
 
 /* stock xlate functions */
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index e47b356..836a0f7 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -559,35 +559,17 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
 			return hwirq;
 	}
 
-	return irq_linear_revmap(domain, hwirq);
+	/* Check if the hwirq is in the linear revmap. */
+	if (hwirq < domain->revmap_size)
+		return domain->linear_revmap[hwirq];
+
+	rcu_read_lock();
+	data = radix_tree_lookup(&domain->revmap_tree, hwirq);
+	rcu_read_unlock();
+	return data ? data->irq : 0;
 }
 EXPORT_SYMBOL_GPL(irq_find_mapping);
 
-/**
- * irq_linear_revmap() - Find a linux irq from a hw irq number.
- * @domain: domain owning this hardware interrupt
- * @hwirq: hardware irq number in that domain space
- *
- * This is a fast path that can be called directly by irq controller code to
- * save a handful of instructions.
- */
-unsigned int irq_linear_revmap(struct irq_domain *domain,
-			       irq_hw_number_t hwirq)
-{
-	struct irq_data *data;
-
-	/* Check revmap bounds; complain if exceeded */
-	if (hwirq >= domain->revmap_size) {
-		rcu_read_lock();
-		data = radix_tree_lookup(&domain->revmap_tree, hwirq);
-		rcu_read_unlock();
-		return data ? data->irq : 0;
-	}
-
-	return domain->linear_revmap[hwirq];
-}
-EXPORT_SYMBOL_GPL(irq_linear_revmap);
-
 #ifdef CONFIG_IRQ_DOMAIN_DEBUG
 static int virq_debug_show(struct seq_file *m, void *private)
 {
-- 
1.8.1.2


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

* [PATCH v2 11/11] irqdomain: Include hwirq number in /proc/interrupts
  2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
                   ` (9 preceding siblings ...)
  2013-06-14 21:08 ` [PATCH v2 10/11] irqdomain: make irq_linear_revmap() a fast path again Grant Likely
@ 2013-06-14 21:08 ` Grant Likely
  10 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-14 21:08 UTC (permalink / raw)
  To: linux-kernel; +Cc: Benjamin Herrenschmidt, Thomas Gleixner, Grant Likely

From: Grant Likely <grant.likely@secretlab.ca>

Add the hardware interrupt number to the output of /proc/interrupts.
It is often important to have access to the hardware interrupt number because
it identifies exactly how an interrupt signal is wired up to the interrupt
controller.  This is especially important when using irq_domains since irq
numbers get dynamically allocated in that case, and have no relation to the
actual hardware number.

Note: This output is currently conditional on whether or not the irq_domain
pointer is set; however hwirq could still be used without irq_domain.  It
may be worthwhile to always output the hwirq number regardless of the
domain pointer.

Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Tested-by: Olof Johansson <olof@lixom.net>
Cc: Ben Herrenschmidt <benh@kernel.crashing.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
---
 kernel/irq/proc.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 19ed5c4..36f6ee1 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -462,6 +462,8 @@ int show_interrupts(struct seq_file *p, void *v)
 	} else {
 		seq_printf(p, " %8s", "None");
 	}
+	if (desc->irq_data.domain)
+		seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq);
 #ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL
 	seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge");
 #endif
-- 
1.8.1.2


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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-14 21:08 ` [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many() Grant Likely
@ 2013-06-18  1:20   ` Michael Neuling
  2013-06-18  1:25     ` Michael Neuling
  0 siblings, 1 reply; 19+ messages in thread
From: Michael Neuling @ 2013-06-18  1:20 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-kernel, Benjamin Herrenschmidt, Thomas Gleixner,
	linux-next, Linux PPC dev, sfr

Grant,

In next-20130617 we are getting the below crash on POWER7.  Bisecting,
points to this patch (d39046ec72 in next)

Any clues?

Mikey


Using pSeries machine description
Page sizes from device-tree:
base_shift=12: shift=12, sllp=0x0000, avpnm=0x00000000, tlbiel=1, penc=0
base_shift=24: shift=24, sllp=0x0100, avpnm=0x00000001, tlbiel=0, penc=0
base_shift=16: shift=16, sllp=0x0110, avpnm=0x00000000, tlbiel=1, penc=1
base_shift=20: shift=20, sllp=0x0111, avpnm=0x00000000, tlbiel=0, penc=2
base_shift=34: shift=34, sllp=0x0120, avpnm=0x000007ff, tlbiel=0, penc=3
Using 1TB segments
Found initrd at 0xc000000002e60000:0xc000000002e60600
CPU maps initialized for 1 thread per core
Starting Linux PPC64 #48 SMP Tue Jun 18 11:10:17 EST 2013
-----------------------------------------------------
ppc64_pft_size                = 0x0
physicalMemorySize            = 0x80000000
htab_address                  = 0xc00000007fe00000
htab_hash_mask                = 0x3fff
-----------------------------------------------------
Initializing cgroup subsys cpuset
Initializing cgroup subsys cpuacct
Linux version 3.10.0-rc5-14354-gd39046e (mikey@ka1) (gcc version 4.6.0 (GCC) ) #48 SMP Tue Jun 18 11:10:17 EST 2013
[boot]0012 Setup Arch
Zone ranges:
  DMA      [mem 0x00000000-0x7fffffff]
  Normal   empty
Movable zone start for each node
Early memory node ranges
  node   0: [mem 0x00000000-0x7fffffff]
[boot]0015 Setup Done
PERCPU: Embedded 2 pages/cpu @c000000002100000 s88448 r0 d42624 u1048576
Built 1 zonelists in Node order, mobility grouping on.  Total pages: 32740
Policy zone: DMA
Kernel command line: ipr.enabled=0
PID hash table entries: 4096 (order: -1, 32768 bytes)
Sorting __ex_table...
freeing bootmem node 0
Memory: 2061696k/2097152k available (11840k kernel code, 35456k reserved, 1792k data, 1072k bss, 704k init)
SLUB: HWalign=128, Order=0-3, MinObjects=0, CPUs=1, Nodes=256
Hierarchical RCU implementation.
	RCU restricting CPUs from NR_CPUS=2048 to nr_cpu_ids=1.
NR_IRQS:512 nr_irqs:512 16
error: reading the clock failed (-1)
clocksource: timebase mult[86bca1b] shift[23] registered
Console: colour dummy device 80x25
console [tty0] enabled
console [hvc0] enabled
pid_max: default: 32768 minimum: 301
Dentry cache hash table entries: 262144 (order: 5, 2097152 bytes)
Inode-cache hash table entries: 131072 (order: 4, 1048576 bytes)
Mount-cache hash table entries: 4096
Initializing cgroup subsys devices
Initializing cgroup subsys freezer
error: hwirq 0x2 is too large for (null)
------------[ cut here ]------------
WARNING: at /scratch/mikey/src/linux-next/kernel/irq/irqdomain.c:276
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-rc5-14354-gd39046e #48
task: c00000007e500000 ti: c00000007e520000 task.ti: c00000007e520000
NIP: c00000000011433c LR: c000000000114338 CTR: c000000000422310
REGS: c00000007e523780 TRAP: 0700   Not tainted  (3.10.0-rc5-14354-gd39046e)
MSR: 9000000000029032 <SF,HV,EE,ME,IR,DR,RI>  CR: 28000084  XER: 02000000
SOFTE: 1
CFAR: c0000000007b0ab8

GPR00: c000000000114338 c00000007e523a00 c000000000cb9570 0000000000000028 
GPR04: 0000000000000000 0000000000000043 ffffffffffffffff 0000000000000000 
GPR08: 076507200766076f c000000000be3790 0000000000000720 0000000000000000 
GPR12: 0000000028000082 c00000000fe00000 c00000000000be60 0000000000000000 
GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 
GPR20: 0000000000000000 0000000000000000 0000000000000000 c000000000b704b0 
GPR24: c000000000d44a80 c000000000cb9570 0000000000000010 0000000000000002 
GPR28: c00000007e0c0000 0000000000000000 c00000007e0c0000 c00000007e052400 
NIP [c00000000011433c] .irq_domain_associate+0x1ec/0x260
LR [c000000000114338] .irq_domain_associate+0x1e8/0x260
PACATMSCRATCH [9000000032009032]
Call Trace:
[c00000007e523a00] [c000000000114338] .irq_domain_associate+0x1e8/0x260 (unreliable)
[c00000007e523aa0] [c000000000114bf0] .irq_create_mapping+0xa0/0x170
[c00000007e523b30] [c000000000af4574] .xics_smp_probe+0x38/0xa4
[c00000007e523ba0] [c000000000af7af0] .pSeries_smp_probe+0x10/0x68
[c00000007e523c10] [c000000000aed740] .smp_prepare_cpus+0x20c/0x244
[c00000007e523cd0] [c000000000ae44c0] .kernel_init_freeable+0x138/0x328
[c00000007e523db0] [c00000000000be7c] .kernel_init+0x1c/0x120
[c00000007e523e30] [c00000000000a05c] .ret_from_kernel_thread+0x5c/0x80
Instruction dump:
482ca915 60000000 7fa3eb78 4868ea09 60000000 4bffff7c 3c62ffd5 e8bc0010 
7f6407b4 3863c108 4869c731 60000000 <0fe00000> 3ba0ffea 4bffff7c 3c62ffd5 
---[ end trace 31fd0ba7d8756001 ]---
------------[ cut here ]------------
kernel BUG at /scratch/mikey/src/linux-next/arch/powerpc/sysdev/xics/xics-common.c:134!
cpu 0x0: Vector: 700 (Program Check) at [c00000007e5238b0]
    pc: c000000000af4580: .xics_smp_probe+0x44/0xa4
    lr: c000000000af4574: .xics_smp_probe+0x38/0xa4
    sp: c00000007e523b30
   msr: 9000000000029032
  current = 0xc00000007e500000
  paca    = 0xc00000000fe00000	 softe: 0	 irq_happened: 0x01
    pid   = 1, comm = swapper/0
kernel BUG at /scratch/mikey/src/linux-next/arch/powerpc/sysdev/xics/xics-common.c:134!
enter ? for help
[c00000007e523ba0] c000000000af7af0 .pSeries_smp_probe+0x10/0x68
[c00000007e523c10] c000000000aed740 .smp_prepare_cpus+0x20c/0x244
[c00000007e523cd0] c000000000ae44c0 .kernel_init_freeable+0x138/0x328
[c00000007e523db0] c00000000000be7c .kernel_init+0x1c/0x120
[c00000007e523e30] c00000000000a05c .ret_from_kernel_thread+0x5c/0x80
0:mon>  <no input ...>
Oops: Exception in kernel mode, sig: 5 [#1]
SMP NR_CPUS=2048 NUMA pSeries
Modules linked in:
CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W    3.10.0-rc5-14354-gd39046e #48
task: c00000007e500000 ti: c00000007e520000 task.ti: c00000007e520000
NIP: c000000000af4580 LR: c000000000af4574 CTR: 0000000000000002
REGS: c00000007e5238b0 TRAP: 0700   Tainted: G        W     (3.10.0-rc5-14354-gd39046e)
MSR: 9000000000029032 <SF,HV,EE,ME,IR,DR,RI>  CR: 28000084  XER: 02000000
SOFTE: 1
CFAR: c000000000114c1c

GPR00: 0000000000000001 c00000007e523b30 c000000000cb9570 0000000000000000 
GPR04: 0000000000000010 0000000000020000 c00000007e052600 c000000000dcdd10 
GPR08: c000000000b85ac8 fffffffffffeffff 0000000000000001 000000000001ffff 
GPR12: 0000000088000084 c00000000fe00000 c00000000000be60 0000000000000000 
GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 
GPR20: 0000000000000000 0000000000000000 0000000000000000 c000000000b704b0 
GPR24: c000000000d44a80 c000000000cb9570 c000000000cb9570 c000000000b703b0 
GPR28: c000000000b704b0 c000000000d40858 0000000000004000 0000000000000800 
NIP [c000000000af4580] .xics_smp_probe+0x44/0xa4
LR [c000000000af4574] .xics_smp_probe+0x38/0xa4
PACATMSCRATCH [9000000000029032]
Call Trace:
[c00000007e523b30] [c000000000af4574] .xics_smp_probe+0x38/0xa4 (unreliable)
[c00000007e523ba0] [c000000000af7af0] .pSeries_smp_probe+0x10/0x68
[c00000007e523c10] [c000000000aed740] .smp_prepare_cpus+0x20c/0x244
[c00000007e523cd0] [c000000000ae44c0] .kernel_init_freeable+0x138/0x328
[c00000007e523db0] [c00000000000be7c] .kernel_init+0x1c/0x120
[c00000007e523e30] [c00000000000a05c] .ret_from_kernel_thread+0x5c/0x80
Instruction dump:
39290f80 38800002 e86b0010 f8010010 f821ff91 e80a0028 e9290000 f8090008 
4b6205e1 60000000 7c600074 7800d182 <0b000000> 3d22000d 3ce2ffd3 3929fde0 
---[ end trace 31fd0ba7d8756002 ]---



> Originally, irq_domain_associate_many() was designed to unwind the
> mapped irqs on a failure of any individual association. However, that
> proved to be a problem with certain IRQ controllers. Some of them only
> support a subset of irqs, and will fail when attempting to map a
> reserved IRQ. In those cases we want to map as many IRQs as possible, so
> instead it is better for irq_domain_associate_many() to make a
> best-effort attempt to map irqs, but not fail if any or all of them
> don't succeed. If a caller really cares about how many irqs got
> associated, then it should instead go back and check that all of the
> irqs is cares about were mapped.
> 
> The original design open-coded the individual association code into the
> body of irq_domain_associate_many(), but with no longer needing to
> unwind associations, the code becomes simpler to split out
> irq_domain_associate() to contain the bulk of the logic, and
> irq_domain_associate_many() to be a simple loop wrapper.
> 
> This patch also adds a new error check to the associate path to make
> sure it isn't called for an irq larger than the controller can handle,
> and adds locking so that the irq_domain_mutex is held while setting up a
> new association.
> 
> v2: Fixup x86 warning. irq_domain_associate_many() no longer returns an
>     error code, but reports errors to the printk log directly. In the
>     majority of cases we don't actually want to fail if there is a
>     problem, but rather log it and still try to boot the system.
> 
> Signed-off-by: Grant Likely <grant.likely@linaro.org>
> ---
>  arch/x86/kernel/devicetree.c |   4 +-
>  include/linux/irqdomain.h    |  22 +++--
>  kernel/irq/irqdomain.c       | 185 +++++++++++++++++++++----------------------
>  3 files changed, 102 insertions(+), 109 deletions(-)
> 
> diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
> index b158152..4934890 100644
> --- a/arch/x86/kernel/devicetree.c
> +++ b/arch/x86/kernel/devicetree.c
> @@ -364,9 +364,7 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num,
>  		 * and assigned so we can keep the 1:1 mapping which the ioapic
>  		 * is having.
>  		 */
> -		ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
> -		if (ret)
> -			pr_err("Error mapping legacy IRQs: %d\n", ret);
> +		irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
>  
>  		if (num > NR_IRQS_LEGACY) {
>  			ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
> index fd4b26f..f9e8e06 100644
> --- a/include/linux/irqdomain.h
> +++ b/include/linux/irqdomain.h
> @@ -103,6 +103,7 @@ struct irq_domain {
>  	struct irq_domain_chip_generic *gc;
>  
>  	/* reverse map data. The linear map gets appended to the irq_domain */
> +	irq_hw_number_t hwirq_max;
>  	unsigned int revmap_direct_max_irq;
>  	unsigned int revmap_size;
>  	struct radix_tree_root revmap_tree;
> @@ -110,8 +111,8 @@ struct irq_domain {
>  };
>  
>  #ifdef CONFIG_IRQ_DOMAIN
> -struct irq_domain *__irq_domain_add(struct device_node *of_node,
> -				    int size, int direct_max,
> +struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
> +				    irq_hw_number_t hwirq_max, int direct_max,
>  				    const struct irq_domain_ops *ops,
>  				    void *host_data);
>  struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
> @@ -140,14 +141,14 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
>  					 const struct irq_domain_ops *ops,
>  					 void *host_data)
>  {
> -	return __irq_domain_add(of_node, size, 0, ops, host_data);
> +	return __irq_domain_add(of_node, size, size, 0, ops, host_data);
>  }
>  static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
>  					 unsigned int max_irq,
>  					 const struct irq_domain_ops *ops,
>  					 void *host_data)
>  {
> -	return __irq_domain_add(of_node, 0, max_irq, ops, host_data);
> +	return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data);
>  }
>  static inline struct irq_domain *irq_domain_add_legacy_isa(
>  				struct device_node *of_node,
> @@ -166,14 +167,11 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
>  
>  extern void irq_domain_remove(struct irq_domain *host);
>  
> -extern int irq_domain_associate_many(struct irq_domain *domain,
> -				     unsigned int irq_base,
> -				     irq_hw_number_t hwirq_base, int count);
> -static inline int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
> -					irq_hw_number_t hwirq)
> -{
> -	return irq_domain_associate_many(domain, irq, hwirq, 1);
> -}
> +extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
> +					irq_hw_number_t hwirq);
> +extern void irq_domain_associate_many(struct irq_domain *domain,
> +				      unsigned int irq_base,
> +				      irq_hw_number_t hwirq_base, int count);
>  
>  extern unsigned int irq_create_mapping(struct irq_domain *host,
>  				       irq_hw_number_t hwirq);
> diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> index 280b804..80e9249 100644
> --- a/kernel/irq/irqdomain.c
> +++ b/kernel/irq/irqdomain.c
> @@ -35,8 +35,8 @@ static struct irq_domain *irq_default_domain;
>   * register allocated irq_domain with irq_domain_register().  Returns pointer
>   * to IRQ domain, or NULL on failure.
>   */
> -struct irq_domain *__irq_domain_add(struct device_node *of_node,
> -				    int size, int direct_max,
> +struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
> +				    irq_hw_number_t hwirq_max, int direct_max,
>  				    const struct irq_domain_ops *ops,
>  				    void *host_data)
>  {
> @@ -52,6 +52,7 @@ struct irq_domain *__irq_domain_add(struct device_node *of_node,
>  	domain->ops = ops;
>  	domain->host_data = host_data;
>  	domain->of_node = of_node_get(of_node);
> +	domain->hwirq_max = hwirq_max;
>  	domain->revmap_size = size;
>  	domain->revmap_direct_max_irq = direct_max;
>  
> @@ -126,7 +127,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
>  {
>  	struct irq_domain *domain;
>  
> -	domain = __irq_domain_add(of_node, size, 0, ops, host_data);
> +	domain = __irq_domain_add(of_node, size, size, 0, ops, host_data);
>  	if (!domain)
>  		return NULL;
>  
> @@ -139,7 +140,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
>  				pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
>  					first_irq);
>  		}
> -		WARN_ON(irq_domain_associate_many(domain, first_irq, 0, size));
> +		irq_domain_associate_many(domain, first_irq, 0, size);
>  	}
>  
>  	return domain;
> @@ -170,11 +171,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
>  {
>  	struct irq_domain *domain;
>  
> -	domain = __irq_domain_add(of_node, first_hwirq + size, 0, ops, host_data);
> +	domain = __irq_domain_add(of_node, first_hwirq + size,
> +				  first_hwirq + size, 0, ops, host_data);
>  	if (!domain)
>  		return NULL;
>  
> -	WARN_ON(irq_domain_associate_many(domain, first_irq, first_hwirq, size));
> +	irq_domain_associate_many(domain, first_irq, first_hwirq, size);
>  
>  	return domain;
>  }
> @@ -228,109 +230,109 @@ void irq_set_default_host(struct irq_domain *domain)
>  }
>  EXPORT_SYMBOL_GPL(irq_set_default_host);
>  
> -static void irq_domain_disassociate_many(struct irq_domain *domain,
> -					 unsigned int irq_base, int count)
> +static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
>  {
> -	/*
> -	 * disassociate in reverse order;
> -	 * not strictly necessary, but nice for unwinding
> -	 */
> -	while (count--) {
> -		int irq = irq_base + count;
> -		struct irq_data *irq_data = irq_get_irq_data(irq);
> -		irq_hw_number_t hwirq;
> +	struct irq_data *irq_data = irq_get_irq_data(irq);
> +	irq_hw_number_t hwirq;
>  
> -		if (WARN_ON(!irq_data || irq_data->domain != domain))
> -			continue;
> +	if (WARN(!irq_data || irq_data->domain != domain,
> +		 "virq%i doesn't exist; cannot disassociate\n", irq))
> +		return;
>  
> -		hwirq = irq_data->hwirq;
> -		irq_set_status_flags(irq, IRQ_NOREQUEST);
> +	hwirq = irq_data->hwirq;
> +	irq_set_status_flags(irq, IRQ_NOREQUEST);
>  
> -		/* remove chip and handler */
> -		irq_set_chip_and_handler(irq, NULL, NULL);
> +	/* remove chip and handler */
> +	irq_set_chip_and_handler(irq, NULL, NULL);
>  
> -		/* Make sure it's completed */
> -		synchronize_irq(irq);
> +	/* Make sure it's completed */
> +	synchronize_irq(irq);
>  
> -		/* Tell the PIC about it */
> -		if (domain->ops->unmap)
> -			domain->ops->unmap(domain, irq);
> -		smp_mb();
> +	/* Tell the PIC about it */
> +	if (domain->ops->unmap)
> +		domain->ops->unmap(domain, irq);
> +	smp_mb();
>  
> -		irq_data->domain = NULL;
> -		irq_data->hwirq = 0;
> +	irq_data->domain = NULL;
> +	irq_data->hwirq = 0;
>  
> -		/* Clear reverse map for this hwirq */
> -		if (hwirq < domain->revmap_size) {
> -			domain->linear_revmap[hwirq] = 0;
> -		} else {
> -			mutex_lock(&revmap_trees_mutex);
> -			radix_tree_delete(&domain->revmap_tree, hwirq);
> -			mutex_unlock(&revmap_trees_mutex);
> -		}
> +	/* Clear reverse map for this hwirq */
> +	if (hwirq < domain->revmap_size) {
> +		domain->linear_revmap[hwirq] = 0;
> +	} else {
> +		mutex_lock(&revmap_trees_mutex);
> +		radix_tree_delete(&domain->revmap_tree, hwirq);
> +		mutex_unlock(&revmap_trees_mutex);
>  	}
>  }
>  
> -int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
> -			      irq_hw_number_t hwirq_base, int count)
> +int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
> +			 irq_hw_number_t hwirq)
>  {
> -	unsigned int virq = irq_base;
> -	irq_hw_number_t hwirq = hwirq_base;
> -	int i, ret;
> +	struct irq_data *irq_data = irq_get_irq_data(virq);
> +	int ret;
>  
> -	pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
> -		of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
> +	if (WARN(hwirq >= domain->hwirq_max,
> +		 "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))
> +		return -EINVAL;
> +	if (WARN(!irq_data, "error: virq%i is not allocated", virq))
> +		return -EINVAL;
> +	if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
> +		return -EINVAL;
>  
> -	for (i = 0; i < count; i++) {
> -		struct irq_data *irq_data = irq_get_irq_data(virq + i);
> -
> -		if (WARN(!irq_data, "error: irq_desc not allocated; "
> -			 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
> -			return -EINVAL;
> -		if (WARN(irq_data->domain, "error: irq_desc already associated; "
> -			 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
> -			return -EINVAL;
> -	};
> -
> -	for (i = 0; i < count; i++, virq++, hwirq++) {
> -		struct irq_data *irq_data = irq_get_irq_data(virq);
> -
> -		irq_data->hwirq = hwirq;
> -		irq_data->domain = domain;
> -		if (domain->ops->map) {
> -			ret = domain->ops->map(domain, virq, hwirq);
> -			if (ret != 0) {
> -				/*
> -				 * If map() returns -EPERM, this interrupt is protected
> -				 * by the firmware or some other service and shall not
> -				 * be mapped. Don't bother telling the user about it.
> -				 */
> -				if (ret != -EPERM) {
> -					pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
> -					       domain->name, hwirq, virq, ret);
> -				}
> -				irq_data->domain = NULL;
> -				irq_data->hwirq = 0;
> -				continue;
> +	mutex_lock(&irq_domain_mutex);
> +	irq_data->hwirq = hwirq;
> +	irq_data->domain = domain;
> +	if (domain->ops->map) {
> +		ret = domain->ops->map(domain, virq, hwirq);
> +		if (ret != 0) {
> +			/*
> +			 * If map() returns -EPERM, this interrupt is protected
> +			 * by the firmware or some other service and shall not
> +			 * be mapped. Don't bother telling the user about it.
> +			 */
> +			if (ret != -EPERM) {
> +				pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
> +				       domain->name, hwirq, virq, ret);
>  			}
> -			/* If not already assigned, give the domain the chip's name */
> -			if (!domain->name && irq_data->chip)
> -				domain->name = irq_data->chip->name;
> +			irq_data->domain = NULL;
> +			irq_data->hwirq = 0;
> +			mutex_unlock(&irq_domain_mutex);
> +			return ret;
>  		}
>  
> -		if (hwirq < domain->revmap_size) {
> -			domain->linear_revmap[hwirq] = virq;
> -		} else {
> -			mutex_lock(&revmap_trees_mutex);
> -			radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
> -			mutex_unlock(&revmap_trees_mutex);
> -		}
> +		/* If not already assigned, give the domain the chip's name */
> +		if (!domain->name && irq_data->chip)
> +			domain->name = irq_data->chip->name;
> +	}
>  
> -		irq_clear_status_flags(virq, IRQ_NOREQUEST);
> +	if (hwirq < domain->revmap_size) {
> +		domain->linear_revmap[hwirq] = virq;
> +	} else {
> +		mutex_lock(&revmap_trees_mutex);
> +		radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
> +		mutex_unlock(&revmap_trees_mutex);
>  	}
> +	mutex_unlock(&irq_domain_mutex);
> +
> +	irq_clear_status_flags(virq, IRQ_NOREQUEST);
>  
>  	return 0;
>  }
> +EXPORT_SYMBOL_GPL(irq_domain_associate);
> +
> +void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
> +			       irq_hw_number_t hwirq_base, int count)
> +{
> +	int i;
> +
> +	pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
> +		of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
> +
> +	for (i = 0; i < count; i++) {
> +		irq_domain_associate(domain, irq_base + i, hwirq_base + i);
> +	}
> +}
>  EXPORT_SYMBOL_GPL(irq_domain_associate_many);
>  
>  /**
> @@ -460,12 +462,7 @@ int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
>  	if (unlikely(ret < 0))
>  		return ret;
>  
> -	ret = irq_domain_associate_many(domain, irq_base, hwirq_base, count);
> -	if (unlikely(ret < 0)) {
> -		irq_free_descs(irq_base, count);
> -		return ret;
> -	}
> -
> +	irq_domain_associate_many(domain, irq_base, hwirq_base, count);
>  	return 0;
>  }
>  EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
> @@ -535,7 +532,7 @@ void irq_dispose_mapping(unsigned int virq)
>  	if (WARN_ON(domain == NULL))
>  		return;
>  
> -	irq_domain_disassociate_many(domain, virq, 1);
> +	irq_domain_disassociate(domain, virq);
>  	irq_free_desc(virq);
>  }
>  EXPORT_SYMBOL_GPL(irq_dispose_mapping);
> -- 
> 1.8.1.2
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
> 

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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-18  1:20   ` Michael Neuling
@ 2013-06-18  1:25     ` Michael Neuling
  2013-06-18  1:37       ` Stephen Rothwell
  2013-06-18  9:05       ` Grant Likely
  0 siblings, 2 replies; 19+ messages in thread
From: Michael Neuling @ 2013-06-18  1:25 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-kernel, Benjamin Herrenschmidt, Thomas Gleixner,
	linux-next, Linux PPC dev, sfr

Michael Neuling <mikey@neuling.org> wrote:

> Grant,
> 
> In next-20130617 we are getting the below crash on POWER7.  Bisecting,
> points to this patch (d39046ec72 in next)

Also, reverting just d39046ec72 fixes the crash in next-20130617.

Mikey

> 
> Any clues?
> 
> Mikey
> 
> 
> Using pSeries machine description
> Page sizes from device-tree:
> base_shift=12: shift=12, sllp=0x0000, avpnm=0x00000000, tlbiel=1, penc=0
> base_shift=24: shift=24, sllp=0x0100, avpnm=0x00000001, tlbiel=0, penc=0
> base_shift=16: shift=16, sllp=0x0110, avpnm=0x00000000, tlbiel=1, penc=1
> base_shift=20: shift=20, sllp=0x0111, avpnm=0x00000000, tlbiel=0, penc=2
> base_shift=34: shift=34, sllp=0x0120, avpnm=0x000007ff, tlbiel=0, penc=3
> Using 1TB segments
> Found initrd at 0xc000000002e60000:0xc000000002e60600
> CPU maps initialized for 1 thread per core
> Starting Linux PPC64 #48 SMP Tue Jun 18 11:10:17 EST 2013
> -----------------------------------------------------
> ppc64_pft_size                = 0x0
> physicalMemorySize            = 0x80000000
> htab_address                  = 0xc00000007fe00000
> htab_hash_mask                = 0x3fff
> -----------------------------------------------------
> Initializing cgroup subsys cpuset
> Initializing cgroup subsys cpuacct
> Linux version 3.10.0-rc5-14354-gd39046e (mikey@ka1) (gcc version 4.6.0 (GCC) ) #48 SMP Tue Jun 18 11:10:17 EST 2013
> [boot]0012 Setup Arch
> Zone ranges:
>   DMA      [mem 0x00000000-0x7fffffff]
>   Normal   empty
> Movable zone start for each node
> Early memory node ranges
>   node   0: [mem 0x00000000-0x7fffffff]
> [boot]0015 Setup Done
> PERCPU: Embedded 2 pages/cpu @c000000002100000 s88448 r0 d42624 u1048576
> Built 1 zonelists in Node order, mobility grouping on.  Total pages: 32740
> Policy zone: DMA
> Kernel command line: ipr.enabled=0
> PID hash table entries: 4096 (order: -1, 32768 bytes)
> Sorting __ex_table...
> freeing bootmem node 0
> Memory: 2061696k/2097152k available (11840k kernel code, 35456k reserved, 1792k data, 1072k bss, 704k init)
> SLUB: HWalign=128, Order=0-3, MinObjects=0, CPUs=1, Nodes=256
> Hierarchical RCU implementation.
> 	RCU restricting CPUs from NR_CPUS=2048 to nr_cpu_ids=1.
> NR_IRQS:512 nr_irqs:512 16
> error: reading the clock failed (-1)
> clocksource: timebase mult[86bca1b] shift[23] registered
> Console: colour dummy device 80x25
> console [tty0] enabled
> console [hvc0] enabled
> pid_max: default: 32768 minimum: 301
> Dentry cache hash table entries: 262144 (order: 5, 2097152 bytes)
> Inode-cache hash table entries: 131072 (order: 4, 1048576 bytes)
> Mount-cache hash table entries: 4096
> Initializing cgroup subsys devices
> Initializing cgroup subsys freezer
> error: hwirq 0x2 is too large for (null)
> ------------[ cut here ]------------
> WARNING: at /scratch/mikey/src/linux-next/kernel/irq/irqdomain.c:276
> Modules linked in:
> CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-rc5-14354-gd39046e #48
> task: c00000007e500000 ti: c00000007e520000 task.ti: c00000007e520000
> NIP: c00000000011433c LR: c000000000114338 CTR: c000000000422310
> REGS: c00000007e523780 TRAP: 0700   Not tainted  (3.10.0-rc5-14354-gd39046e)
> MSR: 9000000000029032 <SF,HV,EE,ME,IR,DR,RI>  CR: 28000084  XER: 02000000
> SOFTE: 1
> CFAR: c0000000007b0ab8
> 
> GPR00: c000000000114338 c00000007e523a00 c000000000cb9570 0000000000000028 
> GPR04: 0000000000000000 0000000000000043 ffffffffffffffff 0000000000000000 
> GPR08: 076507200766076f c000000000be3790 0000000000000720 0000000000000000 
> GPR12: 0000000028000082 c00000000fe00000 c00000000000be60 0000000000000000 
> GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 
> GPR20: 0000000000000000 0000000000000000 0000000000000000 c000000000b704b0 
> GPR24: c000000000d44a80 c000000000cb9570 0000000000000010 0000000000000002 
> GPR28: c00000007e0c0000 0000000000000000 c00000007e0c0000 c00000007e052400 
> NIP [c00000000011433c] .irq_domain_associate+0x1ec/0x260
> LR [c000000000114338] .irq_domain_associate+0x1e8/0x260
> PACATMSCRATCH [9000000032009032]
> Call Trace:
> [c00000007e523a00] [c000000000114338] .irq_domain_associate+0x1e8/0x260 (unreliable)
> [c00000007e523aa0] [c000000000114bf0] .irq_create_mapping+0xa0/0x170
> [c00000007e523b30] [c000000000af4574] .xics_smp_probe+0x38/0xa4
> [c00000007e523ba0] [c000000000af7af0] .pSeries_smp_probe+0x10/0x68
> [c00000007e523c10] [c000000000aed740] .smp_prepare_cpus+0x20c/0x244
> [c00000007e523cd0] [c000000000ae44c0] .kernel_init_freeable+0x138/0x328
> [c00000007e523db0] [c00000000000be7c] .kernel_init+0x1c/0x120
> [c00000007e523e30] [c00000000000a05c] .ret_from_kernel_thread+0x5c/0x80
> Instruction dump:
> 482ca915 60000000 7fa3eb78 4868ea09 60000000 4bffff7c 3c62ffd5 e8bc0010 
> 7f6407b4 3863c108 4869c731 60000000 <0fe00000> 3ba0ffea 4bffff7c 3c62ffd5 
> ---[ end trace 31fd0ba7d8756001 ]---
> ------------[ cut here ]------------
> kernel BUG at /scratch/mikey/src/linux-next/arch/powerpc/sysdev/xics/xics-common.c:134!
> cpu 0x0: Vector: 700 (Program Check) at [c00000007e5238b0]
>     pc: c000000000af4580: .xics_smp_probe+0x44/0xa4
>     lr: c000000000af4574: .xics_smp_probe+0x38/0xa4
>     sp: c00000007e523b30
>    msr: 9000000000029032
>   current = 0xc00000007e500000
>   paca    = 0xc00000000fe00000	 softe: 0	 irq_happened: 0x01
>     pid   = 1, comm = swapper/0
> kernel BUG at /scratch/mikey/src/linux-next/arch/powerpc/sysdev/xics/xics-common.c:134!
> enter ? for help
> [c00000007e523ba0] c000000000af7af0 .pSeries_smp_probe+0x10/0x68
> [c00000007e523c10] c000000000aed740 .smp_prepare_cpus+0x20c/0x244
> [c00000007e523cd0] c000000000ae44c0 .kernel_init_freeable+0x138/0x328
> [c00000007e523db0] c00000000000be7c .kernel_init+0x1c/0x120
> [c00000007e523e30] c00000000000a05c .ret_from_kernel_thread+0x5c/0x80
> 0:mon>  <no input ...>
> Oops: Exception in kernel mode, sig: 5 [#1]
> SMP NR_CPUS=2048 NUMA pSeries
> Modules linked in:
> CPU: 0 PID: 1 Comm: swapper/0 Tainted: G        W    3.10.0-rc5-14354-gd39046e #48
> task: c00000007e500000 ti: c00000007e520000 task.ti: c00000007e520000
> NIP: c000000000af4580 LR: c000000000af4574 CTR: 0000000000000002
> REGS: c00000007e5238b0 TRAP: 0700   Tainted: G        W     (3.10.0-rc5-14354-gd39046e)
> MSR: 9000000000029032 <SF,HV,EE,ME,IR,DR,RI>  CR: 28000084  XER: 02000000
> SOFTE: 1
> CFAR: c000000000114c1c
> 
> GPR00: 0000000000000001 c00000007e523b30 c000000000cb9570 0000000000000000 
> GPR04: 0000000000000010 0000000000020000 c00000007e052600 c000000000dcdd10 
> GPR08: c000000000b85ac8 fffffffffffeffff 0000000000000001 000000000001ffff 
> GPR12: 0000000088000084 c00000000fe00000 c00000000000be60 0000000000000000 
> GPR16: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 
> GPR20: 0000000000000000 0000000000000000 0000000000000000 c000000000b704b0 
> GPR24: c000000000d44a80 c000000000cb9570 c000000000cb9570 c000000000b703b0 
> GPR28: c000000000b704b0 c000000000d40858 0000000000004000 0000000000000800 
> NIP [c000000000af4580] .xics_smp_probe+0x44/0xa4
> LR [c000000000af4574] .xics_smp_probe+0x38/0xa4
> PACATMSCRATCH [9000000000029032]
> Call Trace:
> [c00000007e523b30] [c000000000af4574] .xics_smp_probe+0x38/0xa4 (unreliable)
> [c00000007e523ba0] [c000000000af7af0] .pSeries_smp_probe+0x10/0x68
> [c00000007e523c10] [c000000000aed740] .smp_prepare_cpus+0x20c/0x244
> [c00000007e523cd0] [c000000000ae44c0] .kernel_init_freeable+0x138/0x328
> [c00000007e523db0] [c00000000000be7c] .kernel_init+0x1c/0x120
> [c00000007e523e30] [c00000000000a05c] .ret_from_kernel_thread+0x5c/0x80
> Instruction dump:
> 39290f80 38800002 e86b0010 f8010010 f821ff91 e80a0028 e9290000 f8090008 
> 4b6205e1 60000000 7c600074 7800d182 <0b000000> 3d22000d 3ce2ffd3 3929fde0 
> ---[ end trace 31fd0ba7d8756002 ]---
> 
> 
> 
> > Originally, irq_domain_associate_many() was designed to unwind the
> > mapped irqs on a failure of any individual association. However, that
> > proved to be a problem with certain IRQ controllers. Some of them only
> > support a subset of irqs, and will fail when attempting to map a
> > reserved IRQ. In those cases we want to map as many IRQs as possible, so
> > instead it is better for irq_domain_associate_many() to make a
> > best-effort attempt to map irqs, but not fail if any or all of them
> > don't succeed. If a caller really cares about how many irqs got
> > associated, then it should instead go back and check that all of the
> > irqs is cares about were mapped.
> > 
> > The original design open-coded the individual association code into the
> > body of irq_domain_associate_many(), but with no longer needing to
> > unwind associations, the code becomes simpler to split out
> > irq_domain_associate() to contain the bulk of the logic, and
> > irq_domain_associate_many() to be a simple loop wrapper.
> > 
> > This patch also adds a new error check to the associate path to make
> > sure it isn't called for an irq larger than the controller can handle,
> > and adds locking so that the irq_domain_mutex is held while setting up a
> > new association.
> > 
> > v2: Fixup x86 warning. irq_domain_associate_many() no longer returns an
> >     error code, but reports errors to the printk log directly. In the
> >     majority of cases we don't actually want to fail if there is a
> >     problem, but rather log it and still try to boot the system.
> > 
> > Signed-off-by: Grant Likely <grant.likely@linaro.org>
> > ---
> >  arch/x86/kernel/devicetree.c |   4 +-
> >  include/linux/irqdomain.h    |  22 +++--
> >  kernel/irq/irqdomain.c       | 185 +++++++++++++++++++++----------------------
> >  3 files changed, 102 insertions(+), 109 deletions(-)
> > 
> > diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
> > index b158152..4934890 100644
> > --- a/arch/x86/kernel/devicetree.c
> > +++ b/arch/x86/kernel/devicetree.c
> > @@ -364,9 +364,7 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num,
> >  		 * and assigned so we can keep the 1:1 mapping which the ioapic
> >  		 * is having.
> >  		 */
> > -		ret = irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
> > -		if (ret)
> > -			pr_err("Error mapping legacy IRQs: %d\n", ret);
> > +		irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY);
> >  
> >  		if (num > NR_IRQS_LEGACY) {
> >  			ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY,
> > diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
> > index fd4b26f..f9e8e06 100644
> > --- a/include/linux/irqdomain.h
> > +++ b/include/linux/irqdomain.h
> > @@ -103,6 +103,7 @@ struct irq_domain {
> >  	struct irq_domain_chip_generic *gc;
> >  
> >  	/* reverse map data. The linear map gets appended to the irq_domain */
> > +	irq_hw_number_t hwirq_max;
> >  	unsigned int revmap_direct_max_irq;
> >  	unsigned int revmap_size;
> >  	struct radix_tree_root revmap_tree;
> > @@ -110,8 +111,8 @@ struct irq_domain {
> >  };
> >  
> >  #ifdef CONFIG_IRQ_DOMAIN
> > -struct irq_domain *__irq_domain_add(struct device_node *of_node,
> > -				    int size, int direct_max,
> > +struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
> > +				    irq_hw_number_t hwirq_max, int direct_max,
> >  				    const struct irq_domain_ops *ops,
> >  				    void *host_data);
> >  struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
> > @@ -140,14 +141,14 @@ static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_no
> >  					 const struct irq_domain_ops *ops,
> >  					 void *host_data)
> >  {
> > -	return __irq_domain_add(of_node, size, 0, ops, host_data);
> > +	return __irq_domain_add(of_node, size, size, 0, ops, host_data);
> >  }
> >  static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node,
> >  					 unsigned int max_irq,
> >  					 const struct irq_domain_ops *ops,
> >  					 void *host_data)
> >  {
> > -	return __irq_domain_add(of_node, 0, max_irq, ops, host_data);
> > +	return __irq_domain_add(of_node, 0, max_irq, max_irq, ops, host_data);
> >  }
> >  static inline struct irq_domain *irq_domain_add_legacy_isa(
> >  				struct device_node *of_node,
> > @@ -166,14 +167,11 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
> >  
> >  extern void irq_domain_remove(struct irq_domain *host);
> >  
> > -extern int irq_domain_associate_many(struct irq_domain *domain,
> > -				     unsigned int irq_base,
> > -				     irq_hw_number_t hwirq_base, int count);
> > -static inline int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
> > -					irq_hw_number_t hwirq)
> > -{
> > -	return irq_domain_associate_many(domain, irq, hwirq, 1);
> > -}
> > +extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq,
> > +					irq_hw_number_t hwirq);
> > +extern void irq_domain_associate_many(struct irq_domain *domain,
> > +				      unsigned int irq_base,
> > +				      irq_hw_number_t hwirq_base, int count);
> >  
> >  extern unsigned int irq_create_mapping(struct irq_domain *host,
> >  				       irq_hw_number_t hwirq);
> > diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
> > index 280b804..80e9249 100644
> > --- a/kernel/irq/irqdomain.c
> > +++ b/kernel/irq/irqdomain.c
> > @@ -35,8 +35,8 @@ static struct irq_domain *irq_default_domain;
> >   * register allocated irq_domain with irq_domain_register().  Returns pointer
> >   * to IRQ domain, or NULL on failure.
> >   */
> > -struct irq_domain *__irq_domain_add(struct device_node *of_node,
> > -				    int size, int direct_max,
> > +struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
> > +				    irq_hw_number_t hwirq_max, int direct_max,
> >  				    const struct irq_domain_ops *ops,
> >  				    void *host_data)
> >  {
> > @@ -52,6 +52,7 @@ struct irq_domain *__irq_domain_add(struct device_node *of_node,
> >  	domain->ops = ops;
> >  	domain->host_data = host_data;
> >  	domain->of_node = of_node_get(of_node);
> > +	domain->hwirq_max = hwirq_max;
> >  	domain->revmap_size = size;
> >  	domain->revmap_direct_max_irq = direct_max;
> >  
> > @@ -126,7 +127,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
> >  {
> >  	struct irq_domain *domain;
> >  
> > -	domain = __irq_domain_add(of_node, size, 0, ops, host_data);
> > +	domain = __irq_domain_add(of_node, size, size, 0, ops, host_data);
> >  	if (!domain)
> >  		return NULL;
> >  
> > @@ -139,7 +140,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
> >  				pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
> >  					first_irq);
> >  		}
> > -		WARN_ON(irq_domain_associate_many(domain, first_irq, 0, size));
> > +		irq_domain_associate_many(domain, first_irq, 0, size);
> >  	}
> >  
> >  	return domain;
> > @@ -170,11 +171,12 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
> >  {
> >  	struct irq_domain *domain;
> >  
> > -	domain = __irq_domain_add(of_node, first_hwirq + size, 0, ops, host_data);
> > +	domain = __irq_domain_add(of_node, first_hwirq + size,
> > +				  first_hwirq + size, 0, ops, host_data);
> >  	if (!domain)
> >  		return NULL;
> >  
> > -	WARN_ON(irq_domain_associate_many(domain, first_irq, first_hwirq, size));
> > +	irq_domain_associate_many(domain, first_irq, first_hwirq, size);
> >  
> >  	return domain;
> >  }
> > @@ -228,109 +230,109 @@ void irq_set_default_host(struct irq_domain *domain)
> >  }
> >  EXPORT_SYMBOL_GPL(irq_set_default_host);
> >  
> > -static void irq_domain_disassociate_many(struct irq_domain *domain,
> > -					 unsigned int irq_base, int count)
> > +static void irq_domain_disassociate(struct irq_domain *domain, unsigned int irq)
> >  {
> > -	/*
> > -	 * disassociate in reverse order;
> > -	 * not strictly necessary, but nice for unwinding
> > -	 */
> > -	while (count--) {
> > -		int irq = irq_base + count;
> > -		struct irq_data *irq_data = irq_get_irq_data(irq);
> > -		irq_hw_number_t hwirq;
> > +	struct irq_data *irq_data = irq_get_irq_data(irq);
> > +	irq_hw_number_t hwirq;
> >  
> > -		if (WARN_ON(!irq_data || irq_data->domain != domain))
> > -			continue;
> > +	if (WARN(!irq_data || irq_data->domain != domain,
> > +		 "virq%i doesn't exist; cannot disassociate\n", irq))
> > +		return;
> >  
> > -		hwirq = irq_data->hwirq;
> > -		irq_set_status_flags(irq, IRQ_NOREQUEST);
> > +	hwirq = irq_data->hwirq;
> > +	irq_set_status_flags(irq, IRQ_NOREQUEST);
> >  
> > -		/* remove chip and handler */
> > -		irq_set_chip_and_handler(irq, NULL, NULL);
> > +	/* remove chip and handler */
> > +	irq_set_chip_and_handler(irq, NULL, NULL);
> >  
> > -		/* Make sure it's completed */
> > -		synchronize_irq(irq);
> > +	/* Make sure it's completed */
> > +	synchronize_irq(irq);
> >  
> > -		/* Tell the PIC about it */
> > -		if (domain->ops->unmap)
> > -			domain->ops->unmap(domain, irq);
> > -		smp_mb();
> > +	/* Tell the PIC about it */
> > +	if (domain->ops->unmap)
> > +		domain->ops->unmap(domain, irq);
> > +	smp_mb();
> >  
> > -		irq_data->domain = NULL;
> > -		irq_data->hwirq = 0;
> > +	irq_data->domain = NULL;
> > +	irq_data->hwirq = 0;
> >  
> > -		/* Clear reverse map for this hwirq */
> > -		if (hwirq < domain->revmap_size) {
> > -			domain->linear_revmap[hwirq] = 0;
> > -		} else {
> > -			mutex_lock(&revmap_trees_mutex);
> > -			radix_tree_delete(&domain->revmap_tree, hwirq);
> > -			mutex_unlock(&revmap_trees_mutex);
> > -		}
> > +	/* Clear reverse map for this hwirq */
> > +	if (hwirq < domain->revmap_size) {
> > +		domain->linear_revmap[hwirq] = 0;
> > +	} else {
> > +		mutex_lock(&revmap_trees_mutex);
> > +		radix_tree_delete(&domain->revmap_tree, hwirq);
> > +		mutex_unlock(&revmap_trees_mutex);
> >  	}
> >  }
> >  
> > -int irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
> > -			      irq_hw_number_t hwirq_base, int count)
> > +int irq_domain_associate(struct irq_domain *domain, unsigned int virq,
> > +			 irq_hw_number_t hwirq)
> >  {
> > -	unsigned int virq = irq_base;
> > -	irq_hw_number_t hwirq = hwirq_base;
> > -	int i, ret;
> > +	struct irq_data *irq_data = irq_get_irq_data(virq);
> > +	int ret;
> >  
> > -	pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
> > -		of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
> > +	if (WARN(hwirq >= domain->hwirq_max,
> > +		 "error: hwirq 0x%x is too large for %s\n", (int)hwirq, domain->name))
> > +		return -EINVAL;
> > +	if (WARN(!irq_data, "error: virq%i is not allocated", virq))
> > +		return -EINVAL;
> > +	if (WARN(irq_data->domain, "error: virq%i is already associated", virq))
> > +		return -EINVAL;
> >  
> > -	for (i = 0; i < count; i++) {
> > -		struct irq_data *irq_data = irq_get_irq_data(virq + i);
> > -
> > -		if (WARN(!irq_data, "error: irq_desc not allocated; "
> > -			 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
> > -			return -EINVAL;
> > -		if (WARN(irq_data->domain, "error: irq_desc already associated; "
> > -			 "irq=%i hwirq=0x%x\n", virq + i, (int)hwirq + i))
> > -			return -EINVAL;
> > -	};
> > -
> > -	for (i = 0; i < count; i++, virq++, hwirq++) {
> > -		struct irq_data *irq_data = irq_get_irq_data(virq);
> > -
> > -		irq_data->hwirq = hwirq;
> > -		irq_data->domain = domain;
> > -		if (domain->ops->map) {
> > -			ret = domain->ops->map(domain, virq, hwirq);
> > -			if (ret != 0) {
> > -				/*
> > -				 * If map() returns -EPERM, this interrupt is protected
> > -				 * by the firmware or some other service and shall not
> > -				 * be mapped. Don't bother telling the user about it.
> > -				 */
> > -				if (ret != -EPERM) {
> > -					pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
> > -					       domain->name, hwirq, virq, ret);
> > -				}
> > -				irq_data->domain = NULL;
> > -				irq_data->hwirq = 0;
> > -				continue;
> > +	mutex_lock(&irq_domain_mutex);
> > +	irq_data->hwirq = hwirq;
> > +	irq_data->domain = domain;
> > +	if (domain->ops->map) {
> > +		ret = domain->ops->map(domain, virq, hwirq);
> > +		if (ret != 0) {
> > +			/*
> > +			 * If map() returns -EPERM, this interrupt is protected
> > +			 * by the firmware or some other service and shall not
> > +			 * be mapped. Don't bother telling the user about it.
> > +			 */
> > +			if (ret != -EPERM) {
> > +				pr_info("%s didn't like hwirq-0x%lx to VIRQ%i mapping (rc=%d)\n",
> > +				       domain->name, hwirq, virq, ret);
> >  			}
> > -			/* If not already assigned, give the domain the chip's name */
> > -			if (!domain->name && irq_data->chip)
> > -				domain->name = irq_data->chip->name;
> > +			irq_data->domain = NULL;
> > +			irq_data->hwirq = 0;
> > +			mutex_unlock(&irq_domain_mutex);
> > +			return ret;
> >  		}
> >  
> > -		if (hwirq < domain->revmap_size) {
> > -			domain->linear_revmap[hwirq] = virq;
> > -		} else {
> > -			mutex_lock(&revmap_trees_mutex);
> > -			radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
> > -			mutex_unlock(&revmap_trees_mutex);
> > -		}
> > +		/* If not already assigned, give the domain the chip's name */
> > +		if (!domain->name && irq_data->chip)
> > +			domain->name = irq_data->chip->name;
> > +	}
> >  
> > -		irq_clear_status_flags(virq, IRQ_NOREQUEST);
> > +	if (hwirq < domain->revmap_size) {
> > +		domain->linear_revmap[hwirq] = virq;
> > +	} else {
> > +		mutex_lock(&revmap_trees_mutex);
> > +		radix_tree_insert(&domain->revmap_tree, hwirq, irq_data);
> > +		mutex_unlock(&revmap_trees_mutex);
> >  	}
> > +	mutex_unlock(&irq_domain_mutex);
> > +
> > +	irq_clear_status_flags(virq, IRQ_NOREQUEST);
> >  
> >  	return 0;
> >  }
> > +EXPORT_SYMBOL_GPL(irq_domain_associate);
> > +
> > +void irq_domain_associate_many(struct irq_domain *domain, unsigned int irq_base,
> > +			       irq_hw_number_t hwirq_base, int count)
> > +{
> > +	int i;
> > +
> > +	pr_debug("%s(%s, irqbase=%i, hwbase=%i, count=%i)\n", __func__,
> > +		of_node_full_name(domain->of_node), irq_base, (int)hwirq_base, count);
> > +
> > +	for (i = 0; i < count; i++) {
> > +		irq_domain_associate(domain, irq_base + i, hwirq_base + i);
> > +	}
> > +}
> >  EXPORT_SYMBOL_GPL(irq_domain_associate_many);
> >  
> >  /**
> > @@ -460,12 +462,7 @@ int irq_create_strict_mappings(struct irq_domain *domain, unsigned int irq_base,
> >  	if (unlikely(ret < 0))
> >  		return ret;
> >  
> > -	ret = irq_domain_associate_many(domain, irq_base, hwirq_base, count);
> > -	if (unlikely(ret < 0)) {
> > -		irq_free_descs(irq_base, count);
> > -		return ret;
> > -	}
> > -
> > +	irq_domain_associate_many(domain, irq_base, hwirq_base, count);
> >  	return 0;
> >  }
> >  EXPORT_SYMBOL_GPL(irq_create_strict_mappings);
> > @@ -535,7 +532,7 @@ void irq_dispose_mapping(unsigned int virq)
> >  	if (WARN_ON(domain == NULL))
> >  		return;
> >  
> > -	irq_domain_disassociate_many(domain, virq, 1);
> > +	irq_domain_disassociate(domain, virq);
> >  	irq_free_desc(virq);
> >  }
> >  EXPORT_SYMBOL_GPL(irq_dispose_mapping);
> > -- 
> > 1.8.1.2
> > 
> > --
> > To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> > the body of a message to majordomo@vger.kernel.org
> > More majordomo info at  http://vger.kernel.org/majordomo-info.html
> > Please read the FAQ at  http://www.tux.org/lkml/
> > 

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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-18  1:25     ` Michael Neuling
@ 2013-06-18  1:37       ` Stephen Rothwell
  2013-06-18  9:05       ` Grant Likely
  1 sibling, 0 replies; 19+ messages in thread
From: Stephen Rothwell @ 2013-06-18  1:37 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Grant Likely, linux-kernel, Benjamin Herrenschmidt,
	Thomas Gleixner, linux-next, Linux PPC dev

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

Hi all,

On Tue, 18 Jun 2013 11:25:34 +1000 Michael Neuling <mikey@neuling.org> wrote:
>
> Michael Neuling <mikey@neuling.org> wrote:
> 
> > In next-20130617 we are getting the below crash on POWER7.  Bisecting,
> > points to this patch (d39046ec72 in next)
> 
> Also, reverting just d39046ec72 fixes the crash in next-20130617.

I will revert that commit in linux-next today.

-- 
Cheers,
Stephen Rothwell                    sfr@canb.auug.org.au

[-- Attachment #2: Type: application/pgp-signature, Size: 836 bytes --]

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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-18  1:25     ` Michael Neuling
  2013-06-18  1:37       ` Stephen Rothwell
@ 2013-06-18  9:05       ` Grant Likely
  2013-06-18  9:46         ` Grant Likely
  1 sibling, 1 reply; 19+ messages in thread
From: Grant Likely @ 2013-06-18  9:05 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Linux Kernel Mailing List, Benjamin Herrenschmidt,
	Thomas Gleixner, linux-next, Linux PPC dev, Stephen Rothwell

On Tue, Jun 18, 2013 at 2:25 AM, Michael Neuling <mikey@neuling.org> wrote:
> Michael Neuling <mikey@neuling.org> wrote:
>
>> Grant,
>>
>> In next-20130617 we are getting the below crash on POWER7.  Bisecting,
>> points to this patch (d39046ec72 in next)
>
> Also, reverting just d39046ec72 fixes the crash in next-20130617.

Odd. Of all the changes in that series, I would not have expected that
one to cause any problems. I'm digging into it now...

g.

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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-18  9:05       ` Grant Likely
@ 2013-06-18  9:46         ` Grant Likely
  2013-06-18 11:04           ` Michael Neuling
  0 siblings, 1 reply; 19+ messages in thread
From: Grant Likely @ 2013-06-18  9:46 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Linux Kernel Mailing List, Benjamin Herrenschmidt,
	Thomas Gleixner, linux-next, Linux PPC dev, Stephen Rothwell

On Tue, 18 Jun 2013 10:05:31 +0100, Grant Likely <grant.likely@linaro.org> wrote:
> On Tue, Jun 18, 2013 at 2:25 AM, Michael Neuling <mikey@neuling.org> wrote:
> > Michael Neuling <mikey@neuling.org> wrote:
> >
> >> Grant,
> >>
> >> In next-20130617 we are getting the below crash on POWER7.  Bisecting,
> >> points to this patch (d39046ec72 in next)
> >
> > Also, reverting just d39046ec72 fixes the crash in next-20130617.
> 
> Odd. Of all the changes in that series, I would not have expected that
> one to cause any problems. I'm digging into it now...

Ugh. I flubbed the commit. Try this patch. It should solve the problem:

>From b7ba09c29ed36eda8e16453646b55faea7f9c25f Mon Sep 17 00:00:00 2001
From: Grant Likely <grant.likely@linaro.org>
Date: Tue, 18 Jun 2013 10:15:19 +0100
Subject: [PATCH] irqdomain: Fix flubbed irq_domain_associate_many refactoring

commit d39046ec72, "irqdomain: Refactor irq_domain_associate_many()" was
missing the following hunk which causes a boot failure on anything using
irq_domain_add_tree() to allocate an irq domain.

Signed-off-by: Grant Likely <grant.likely@linaro.org>
Cc: Michael Neuling <mikey@neuling.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>,
Cc: Thomas Gleixner <tglx@linutronix.de>,
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
---
 include/linux/irqdomain.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index 02f7658..c983ed1 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -162,7 +162,7 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
 					 const struct irq_domain_ops *ops,
 					 void *host_data)
 {
-	return irq_domain_add_linear(of_node, 0, ops, host_data);
+	return __irq_domain_add(of_node, 0, ~0, 0, ops, host_data);
 }
 
 extern void irq_domain_remove(struct irq_domain *host);
-- 
1.8.1.2


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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-18  9:46         ` Grant Likely
@ 2013-06-18 11:04           ` Michael Neuling
  2013-06-18 12:13             ` Grant Likely
  0 siblings, 1 reply; 19+ messages in thread
From: Michael Neuling @ 2013-06-18 11:04 UTC (permalink / raw)
  To: Grant Likely
  Cc: Linux Kernel Mailing List, Benjamin Herrenschmidt,
	Thomas Gleixner, linux-next, Linux PPC dev, Stephen Rothwell

Grant Likely <grant.likely@linaro.org> wrote:

> On Tue, 18 Jun 2013 10:05:31 +0100, Grant Likely <grant.likely@linaro.org> wrote:
> > On Tue, Jun 18, 2013 at 2:25 AM, Michael Neuling <mikey@neuling.org> wrote:
> > > Michael Neuling <mikey@neuling.org> wrote:
> > >
> > >> Grant,
> > >>
> > >> In next-20130617 we are getting the below crash on POWER7.  Bisecting,
> > >> points to this patch (d39046ec72 in next)
> > >
> > > Also, reverting just d39046ec72 fixes the crash in next-20130617.
> > 
> > Odd. Of all the changes in that series, I would not have expected that
> > one to cause any problems. I'm digging into it now...
> 
> Ugh. I flubbed the commit. Try this patch. It should solve the problem:
> 

Yep, it fixes it.  Thanks.

Mikey

> From b7ba09c29ed36eda8e16453646b55faea7f9c25f Mon Sep 17 00:00:00 2001
> From: Grant Likely <grant.likely@linaro.org>
> Date: Tue, 18 Jun 2013 10:15:19 +0100
> Subject: [PATCH] irqdomain: Fix flubbed irq_domain_associate_many refactoring
> 
> commit d39046ec72, "irqdomain: Refactor irq_domain_associate_many()" was
> missing the following hunk which causes a boot failure on anything using
> irq_domain_add_tree() to allocate an irq domain.
> 
> Signed-off-by: Grant Likely <grant.likely@linaro.org>
> Cc: Michael Neuling <mikey@neuling.org>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>,
> Cc: Thomas Gleixner <tglx@linutronix.de>,
> Cc: Stephen Rothwell <sfr@canb.auug.org.au>
> ---
>  include/linux/irqdomain.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
> index 02f7658..c983ed1 100644
> --- a/include/linux/irqdomain.h
> +++ b/include/linux/irqdomain.h
> @@ -162,7 +162,7 @@ static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node
>  					 const struct irq_domain_ops *ops,
>  					 void *host_data)
>  {
> -	return irq_domain_add_linear(of_node, 0, ops, host_data);
> +	return __irq_domain_add(of_node, 0, ~0, 0, ops, host_data);
>  }
>  
>  extern void irq_domain_remove(struct irq_domain *host);
> -- 
> 1.8.1.2
> 

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

* Re: [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many()
  2013-06-18 11:04           ` Michael Neuling
@ 2013-06-18 12:13             ` Grant Likely
  0 siblings, 0 replies; 19+ messages in thread
From: Grant Likely @ 2013-06-18 12:13 UTC (permalink / raw)
  To: Michael Neuling
  Cc: Linux Kernel Mailing List, Benjamin Herrenschmidt,
	Thomas Gleixner, linux-next, Linux PPC dev, Stephen Rothwell

On Tue, Jun 18, 2013 at 12:04 PM, Michael Neuling <mikey@neuling.org> wrote:
> Grant Likely <grant.likely@linaro.org> wrote:
>
>> On Tue, 18 Jun 2013 10:05:31 +0100, Grant Likely <grant.likely@linaro.org> wrote:
>> > On Tue, Jun 18, 2013 at 2:25 AM, Michael Neuling <mikey@neuling.org> wrote:
>> > > Michael Neuling <mikey@neuling.org> wrote:
>> > >
>> > >> Grant,
>> > >>
>> > >> In next-20130617 we are getting the below crash on POWER7.  Bisecting,
>> > >> points to this patch (d39046ec72 in next)
>> > >
>> > > Also, reverting just d39046ec72 fixes the crash in next-20130617.
>> >
>> > Odd. Of all the changes in that series, I would not have expected that
>> > one to cause any problems. I'm digging into it now...
>>
>> Ugh. I flubbed the commit. Try this patch. It should solve the problem:
>>
>
> Yep, it fixes it.  Thanks.

Excellent, thanks for testing.

g.

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

end of thread, other threads:[~2013-06-18 12:14 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-14 21:07 [PATCH v2 00/11] irqdomain: Refactor Grant Likely
2013-06-14 21:07 ` [PATCH v2 01/11] irqdomain: Relax failure path on setting up mappings Grant Likely
2013-06-14 21:07 ` [PATCH v2 02/11] irqdomain: Replace LEGACY mapping with LINEAR Grant Likely
2013-06-14 21:07 ` [PATCH v2 03/11] irqdomain: Add a name field Grant Likely
2013-06-14 21:07 ` [PATCH v2 04/11] irqdomain: merge linear and tree reverse mappings Grant Likely
2013-06-14 21:08 ` [PATCH v2 05/11] irqdomain: Eliminate revmap type Grant Likely
2013-06-14 21:08 ` [PATCH v2 06/11] irqdomain: Clean up aftermath of irq_domain refactoring Grant Likely
2013-06-14 21:08 ` [PATCH v2 07/11] irqdomain: Beef up debugfs output Grant Likely
2013-06-14 21:08 ` [PATCH v2 08/11] irqdomain: Refactor irq_domain_associate_many() Grant Likely
2013-06-18  1:20   ` Michael Neuling
2013-06-18  1:25     ` Michael Neuling
2013-06-18  1:37       ` Stephen Rothwell
2013-06-18  9:05       ` Grant Likely
2013-06-18  9:46         ` Grant Likely
2013-06-18 11:04           ` Michael Neuling
2013-06-18 12:13             ` Grant Likely
2013-06-14 21:08 ` [PATCH v2 09/11] irqdomain: remove irq_domain_generate_simple() Grant Likely
2013-06-14 21:08 ` [PATCH v2 10/11] irqdomain: make irq_linear_revmap() a fast path again Grant Likely
2013-06-14 21:08 ` [PATCH v2 11/11] irqdomain: Include hwirq number in /proc/interrupts Grant Likely

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).