All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] ARM: vic: device tree binding
@ 2011-09-27 12:16 ` Jamie Iles
  0 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 12:16 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

This adds a device tree binding for the VIC based on the of_irq_init()
support.

Cc: Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
---
 Documentation/devicetree/bindings/arm/vic.txt |   29 ++++++
 arch/arm/common/vic.c                         |  121 ++++++++++++++++++++-----
 arch/arm/include/asm/hardware/vic.h           |   13 +++-
 3 files changed, 137 insertions(+), 26 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/vic.txt

diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
new file mode 100644
index 0000000..266716b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/vic.txt
@@ -0,0 +1,29 @@
+* ARM Vectored Interrupt Controller
+
+One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
+system for interrupt routing.  For multiple controllers they can either be
+nested or have the outputs wire-OR'd together.
+
+Required properties:
+
+- compatible : should be one of
+	"arm,pl190-vic"
+	"arm,pl192-vic"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
+  the VIC has no configuration options for interrupt sources.  The cell is a u32
+  and defines the interrupt number.
+- reg : The register bank for the VIC.
+
+Optional properties:
+
+- interrupts : Interrupt source for parent controllers if the VIC is nested.
+
+Example:
+
+	vic0: interrupt-controller@60000 {
+		compatible = "arm,pl192-vic";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0x60000 0x1000>;
+	};
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 7aa4262..3658579 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -22,6 +22,10 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/syscore_ops.h>
 #include <linux/device.h>
 #include <linux/amba/bus.h>
@@ -29,7 +33,6 @@
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
 
-#ifdef CONFIG_PM
 /**
  * struct vic_device - VIC PM device
  * @irq: The IRQ number for the base of the VIC.
@@ -50,13 +53,15 @@ struct vic_device {
 	u32		int_enable;
 	u32		soft_int;
 	u32		protect;
+#ifdef CONFIG_IRQ_DOMAIN
+	struct irq_domain domain;
+#endif /* CONFIG_IRQ_DOMAIN */
 };
 
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
 static int vic_id;
-#endif /* CONFIG_PM */
 
 /**
  * vic_init2 - common initialisation code
@@ -156,9 +161,10 @@ static int __init vic_pm_init(void)
 	return 0;
 }
 late_initcall(vic_pm_init);
+#endif /* CONFIG_PM */
 
 /**
- * vic_pm_register - Register a VIC for later power management control
+ * vic_register - Register a VIC.
  * @base: The base address of the VIC.
  * @irq: The base IRQ for the VIC.
  * @resume_sources: bitmask of interrupts allowed for resume sources.
@@ -166,24 +172,28 @@ late_initcall(vic_pm_init);
  * Register the VIC with the system device tree so that it can be notified
  * of suspend and resume requests and ensure that the correct actions are
  * taken to re-instate the settings on resume.
+ *
+ * We return the VIC so that it can be used for IRQ domain operations for
+ * device tree translation.
  */
-static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
+static struct vic_device * __init
+vic_register(void __iomem *base, unsigned int irq, u32 resume_sources)
 {
 	struct vic_device *v;
 
-	if (vic_id >= ARRAY_SIZE(vic_devices))
+	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
-	else {
-		v = &vic_devices[vic_id];
-		v->base = base;
-		v->resume_sources = resume_sources;
-		v->irq = irq;
-		vic_id++;
+		return NULL;
 	}
+
+	v = &vic_devices[vic_id];
+	v->base = base;
+	v->resume_sources = resume_sources;
+	v->irq = irq;
+	vic_id++;
+
+	return v;
 }
-#else
-static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
-#endif /* CONFIG_PM */
 
 static void vic_ack_irq(struct irq_data *d)
 {
@@ -331,15 +341,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 	vic_set_irq_sources(base, irq_start, vic_sources);
 }
 
-/**
- * vic_init - initialise a vectored interrupt controller
- * @base: iomem base address
- * @irq_start: starting interrupt number, must be muliple of 32
- * @vic_sources: bitmask of interrupt sources to allow
- * @resume_sources: bitmask of interrupt sources to allow for resume
- */
-void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources, u32 resume_sources)
+static struct vic_device * __init
+__vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	   u32 resume_sources)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -357,7 +361,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
 		vic_init_st(base, irq_start, vic_sources);
-		return;
+		return NULL;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
 		/* fall through */
@@ -375,5 +379,72 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
 
 	vic_set_irq_sources(base, irq_start, vic_sources);
 
-	vic_pm_register(base, irq_start, resume_sources);
+	return vic_register(base, irq_start, resume_sources);
 }
+
+/**
+ * vic_init - initialise a vectored interrupt controller
+ * @base: iomem base address
+ * @irq_start: starting interrupt number, must be muliple of 32
+ * @vic_sources: bitmask of interrupt sources to allow
+ * @resume_sources: bitmask of interrupt sources to allow for resume
+ */
+void __init vic_init(void __iomem *base, unsigned int irq_start,
+		     u32 vic_sources, u32 resume_sources)
+{
+	__vic_init(base, irq_start, vic_sources, resume_sources);
+}
+
+#ifdef CONFIG_OF
+static int
+vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
+			    const u32 *intspec, unsigned int intsize,
+			    unsigned long *out_hwirq, unsigned int *out_type)
+{
+	if (d->of_node != np)
+		return -EINVAL;
+	if (intsize < 1)
+		return -EINVAL;
+
+	*out_hwirq = intspec[0];
+	*out_type = IRQ_TYPE_NONE;
+
+	return 0;
+}
+
+static const struct irq_domain_ops vic_irq_domain_ops = {
+	.dt_translate = vic_irq_domain_dt_translate,
+};
+
+int __init vic_of_init(struct device_node *node, struct device_node *parent)
+{
+	void __iomem *regs = of_iomap(node, 0);
+	struct vic_device *vic;
+	int irq_base;
+
+	if (WARN_ON(!regs))
+		return -EIO;
+
+	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
+	if (WARN_ON(irq_base < 0))
+		goto out_unmap;
+
+	vic = __vic_init(regs, irq_base, ~0, ~0);
+	if (WARN_ON(!vic))
+		goto out_unmap;
+
+	vic->domain.irq_base = irq_base;
+	vic->domain.nr_irq = 32;
+	vic->domain.of_node = of_node_get(node);
+	vic->domain.ops = &vic_irq_domain_ops;
+	irq_domain_add(&vic->domain);
+
+	return 0;
+
+out_unmap:
+	iounmap(regs);
+
+	return -EIO;
+}
+
+#endif /* CONFIG OF */
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
index 5d72550..df1d895 100644
--- a/arch/arm/include/asm/hardware/vic.h
+++ b/arch/arm/include/asm/hardware/vic.h
@@ -41,7 +41,18 @@
 #define VIC_PL192_VECT_ADDR		0xF00
 
 #ifndef __ASSEMBLY__
+struct device_node;
 void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
-#endif
+
+#ifdef CONFIG_OF
+int vic_of_init(struct device_node *node, struct device_node *parent);
+#else /* CONFIG_OF */
+static inline int vic_of_init(struct device_node *node,
+			      struct device_node *parent)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_OF */
+#endif /* __ASSEMBLY__ */
 
 #endif
-- 
1.7.4.1

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

* [PATCH 1/2] ARM: vic: device tree binding
@ 2011-09-27 12:16 ` Jamie Iles
  0 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

This adds a device tree binding for the VIC based on the of_irq_init()
support.

Cc: Rob Herring <robherring2@gmail.com>
Signed-off-by: Jamie Iles <jamie@jamieiles.com>
---
 Documentation/devicetree/bindings/arm/vic.txt |   29 ++++++
 arch/arm/common/vic.c                         |  121 ++++++++++++++++++++-----
 arch/arm/include/asm/hardware/vic.h           |   13 +++-
 3 files changed, 137 insertions(+), 26 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/arm/vic.txt

diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
new file mode 100644
index 0000000..266716b
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/vic.txt
@@ -0,0 +1,29 @@
+* ARM Vectored Interrupt Controller
+
+One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
+system for interrupt routing.  For multiple controllers they can either be
+nested or have the outputs wire-OR'd together.
+
+Required properties:
+
+- compatible : should be one of
+	"arm,pl190-vic"
+	"arm,pl192-vic"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
+  the VIC has no configuration options for interrupt sources.  The cell is a u32
+  and defines the interrupt number.
+- reg : The register bank for the VIC.
+
+Optional properties:
+
+- interrupts : Interrupt source for parent controllers if the VIC is nested.
+
+Example:
+
+	vic0: interrupt-controller at 60000 {
+		compatible = "arm,pl192-vic";
+		interrupt-controller;
+		#interrupt-cells = <1>;
+		reg = <0x60000 0x1000>;
+	};
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 7aa4262..3658579 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -22,6 +22,10 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/io.h>
+#include <linux/irqdomain.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
 #include <linux/syscore_ops.h>
 #include <linux/device.h>
 #include <linux/amba/bus.h>
@@ -29,7 +33,6 @@
 #include <asm/mach/irq.h>
 #include <asm/hardware/vic.h>
 
-#ifdef CONFIG_PM
 /**
  * struct vic_device - VIC PM device
  * @irq: The IRQ number for the base of the VIC.
@@ -50,13 +53,15 @@ struct vic_device {
 	u32		int_enable;
 	u32		soft_int;
 	u32		protect;
+#ifdef CONFIG_IRQ_DOMAIN
+	struct irq_domain domain;
+#endif /* CONFIG_IRQ_DOMAIN */
 };
 
 /* we cannot allocate memory when VICs are initially registered */
 static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
 static int vic_id;
-#endif /* CONFIG_PM */
 
 /**
  * vic_init2 - common initialisation code
@@ -156,9 +161,10 @@ static int __init vic_pm_init(void)
 	return 0;
 }
 late_initcall(vic_pm_init);
+#endif /* CONFIG_PM */
 
 /**
- * vic_pm_register - Register a VIC for later power management control
+ * vic_register - Register a VIC.
  * @base: The base address of the VIC.
  * @irq: The base IRQ for the VIC.
  * @resume_sources: bitmask of interrupts allowed for resume sources.
@@ -166,24 +172,28 @@ late_initcall(vic_pm_init);
  * Register the VIC with the system device tree so that it can be notified
  * of suspend and resume requests and ensure that the correct actions are
  * taken to re-instate the settings on resume.
+ *
+ * We return the VIC so that it can be used for IRQ domain operations for
+ * device tree translation.
  */
-static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
+static struct vic_device * __init
+vic_register(void __iomem *base, unsigned int irq, u32 resume_sources)
 {
 	struct vic_device *v;
 
-	if (vic_id >= ARRAY_SIZE(vic_devices))
+	if (vic_id >= ARRAY_SIZE(vic_devices)) {
 		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
-	else {
-		v = &vic_devices[vic_id];
-		v->base = base;
-		v->resume_sources = resume_sources;
-		v->irq = irq;
-		vic_id++;
+		return NULL;
 	}
+
+	v = &vic_devices[vic_id];
+	v->base = base;
+	v->resume_sources = resume_sources;
+	v->irq = irq;
+	vic_id++;
+
+	return v;
 }
-#else
-static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
-#endif /* CONFIG_PM */
 
 static void vic_ack_irq(struct irq_data *d)
 {
@@ -331,15 +341,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
 	vic_set_irq_sources(base, irq_start, vic_sources);
 }
 
-/**
- * vic_init - initialise a vectored interrupt controller
- * @base: iomem base address
- * @irq_start: starting interrupt number, must be muliple of 32
- * @vic_sources: bitmask of interrupt sources to allow
- * @resume_sources: bitmask of interrupt sources to allow for resume
- */
-void __init vic_init(void __iomem *base, unsigned int irq_start,
-		     u32 vic_sources, u32 resume_sources)
+static struct vic_device * __init
+__vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
+	   u32 resume_sources)
 {
 	unsigned int i;
 	u32 cellid = 0;
@@ -357,7 +361,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
 	switch(vendor) {
 	case AMBA_VENDOR_ST:
 		vic_init_st(base, irq_start, vic_sources);
-		return;
+		return NULL;
 	default:
 		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
 		/* fall through */
@@ -375,5 +379,72 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
 
 	vic_set_irq_sources(base, irq_start, vic_sources);
 
-	vic_pm_register(base, irq_start, resume_sources);
+	return vic_register(base, irq_start, resume_sources);
 }
+
+/**
+ * vic_init - initialise a vectored interrupt controller
+ * @base: iomem base address
+ * @irq_start: starting interrupt number, must be muliple of 32
+ * @vic_sources: bitmask of interrupt sources to allow
+ * @resume_sources: bitmask of interrupt sources to allow for resume
+ */
+void __init vic_init(void __iomem *base, unsigned int irq_start,
+		     u32 vic_sources, u32 resume_sources)
+{
+	__vic_init(base, irq_start, vic_sources, resume_sources);
+}
+
+#ifdef CONFIG_OF
+static int
+vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
+			    const u32 *intspec, unsigned int intsize,
+			    unsigned long *out_hwirq, unsigned int *out_type)
+{
+	if (d->of_node != np)
+		return -EINVAL;
+	if (intsize < 1)
+		return -EINVAL;
+
+	*out_hwirq = intspec[0];
+	*out_type = IRQ_TYPE_NONE;
+
+	return 0;
+}
+
+static const struct irq_domain_ops vic_irq_domain_ops = {
+	.dt_translate = vic_irq_domain_dt_translate,
+};
+
+int __init vic_of_init(struct device_node *node, struct device_node *parent)
+{
+	void __iomem *regs = of_iomap(node, 0);
+	struct vic_device *vic;
+	int irq_base;
+
+	if (WARN_ON(!regs))
+		return -EIO;
+
+	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
+	if (WARN_ON(irq_base < 0))
+		goto out_unmap;
+
+	vic = __vic_init(regs, irq_base, ~0, ~0);
+	if (WARN_ON(!vic))
+		goto out_unmap;
+
+	vic->domain.irq_base = irq_base;
+	vic->domain.nr_irq = 32;
+	vic->domain.of_node = of_node_get(node);
+	vic->domain.ops = &vic_irq_domain_ops;
+	irq_domain_add(&vic->domain);
+
+	return 0;
+
+out_unmap:
+	iounmap(regs);
+
+	return -EIO;
+}
+
+#endif /* CONFIG OF */
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
index 5d72550..df1d895 100644
--- a/arch/arm/include/asm/hardware/vic.h
+++ b/arch/arm/include/asm/hardware/vic.h
@@ -41,7 +41,18 @@
 #define VIC_PL192_VECT_ADDR		0xF00
 
 #ifndef __ASSEMBLY__
+struct device_node;
 void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
-#endif
+
+#ifdef CONFIG_OF
+int vic_of_init(struct device_node *node, struct device_node *parent);
+#else /* CONFIG_OF */
+static inline int vic_of_init(struct device_node *node,
+			      struct device_node *parent)
+{
+	return -ENOSYS;
+}
+#endif /* CONFIG_OF */
+#endif /* __ASSEMBLY__ */
 
 #endif
-- 
1.7.4.1

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

* [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
  2011-09-27 12:16 ` Jamie Iles
@ 2011-09-27 12:16     ` Jamie Iles
  -1 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 12:16 UTC (permalink / raw)
  To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ

Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
platforms.  This only works for platforms with CONFIG_OF=y as we can
determine which controllers are the primary controllers (no parent).

Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
---
 arch/arm/common/vic.c               |   48 +++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/hardware/vic.h |    1 +
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 3658579..e9b72d3 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -63,6 +63,22 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
 static int vic_id;
 
+#if defined(CONFIG_OF) && defined(CONFIG_MULTI_IRQ_HANDLER)
+/*
+ * The root VIC's.  We keep track of these so that we can do the IRQ demuxing
+ * as we can have more than one root VIC.
+ */
+static struct vic_device *vic_root_devices[CONFIG_ARM_VIC_NR];
+static int nr_root_vics;
+
+static void vic_register_root_controller(struct vic_device *vic)
+{
+	vic_root_devices[nr_root_vics++] = vic;
+}
+#else /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
+static inline void vic_register_root_controller(struct vic_device *vic) {}
+#endif /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
+
 /**
  * vic_init2 - common initialisation code
  * @base: Base of the VIC.
@@ -439,6 +455,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	vic->domain.ops = &vic_irq_domain_ops;
 	irq_domain_add(&vic->domain);
 
+	if (!parent)
+		vic_register_root_controller(vic);
+
 	return 0;
 
 out_unmap:
@@ -447,4 +466,33 @@ out_unmap:
 	return -EIO;
 }
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+static void vic_single_handle_irq(struct vic_device *vic, struct pt_regs *regs)
+{
+	u32 stat, irq;
+	bool handled = false;
+
+	while (!handled) {
+		stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
+		if (!stat)
+			break;
+
+		while (stat) {
+			irq = fls(stat) - 1;
+			handle_IRQ(irq + vic->irq, regs);
+			stat &= ~(1 << irq);
+			handled = true;
+		}
+	}
+}
+
+asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < nr_root_vics; ++i)
+		vic_single_handle_irq(vic_root_devices[i], regs);
+}
+#endif /* CONFIG_MULTI_IRQ_HANDLER */
+
 #endif /* CONFIG OF */
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
index df1d895..451788c 100644
--- a/arch/arm/include/asm/hardware/vic.h
+++ b/arch/arm/include/asm/hardware/vic.h
@@ -53,6 +53,7 @@ static inline int vic_of_init(struct device_node *node,
 	return -ENOSYS;
 }
 #endif /* CONFIG_OF */
+void vic_handle_irq(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 #endif
-- 
1.7.4.1

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

* [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
@ 2011-09-27 12:16     ` Jamie Iles
  0 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 12:16 UTC (permalink / raw)
  To: linux-arm-kernel

Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
platforms.  This only works for platforms with CONFIG_OF=y as we can
determine which controllers are the primary controllers (no parent).

Signed-off-by: Jamie Iles <jamie@jamieiles.com>
---
 arch/arm/common/vic.c               |   48 +++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/hardware/vic.h |    1 +
 2 files changed, 49 insertions(+), 0 deletions(-)

diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index 3658579..e9b72d3 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -63,6 +63,22 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
 
 static int vic_id;
 
+#if defined(CONFIG_OF) && defined(CONFIG_MULTI_IRQ_HANDLER)
+/*
+ * The root VIC's.  We keep track of these so that we can do the IRQ demuxing
+ * as we can have more than one root VIC.
+ */
+static struct vic_device *vic_root_devices[CONFIG_ARM_VIC_NR];
+static int nr_root_vics;
+
+static void vic_register_root_controller(struct vic_device *vic)
+{
+	vic_root_devices[nr_root_vics++] = vic;
+}
+#else /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
+static inline void vic_register_root_controller(struct vic_device *vic) {}
+#endif /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
+
 /**
  * vic_init2 - common initialisation code
  * @base: Base of the VIC.
@@ -439,6 +455,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
 	vic->domain.ops = &vic_irq_domain_ops;
 	irq_domain_add(&vic->domain);
 
+	if (!parent)
+		vic_register_root_controller(vic);
+
 	return 0;
 
 out_unmap:
@@ -447,4 +466,33 @@ out_unmap:
 	return -EIO;
 }
 
+#ifdef CONFIG_MULTI_IRQ_HANDLER
+static void vic_single_handle_irq(struct vic_device *vic, struct pt_regs *regs)
+{
+	u32 stat, irq;
+	bool handled = false;
+
+	while (!handled) {
+		stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
+		if (!stat)
+			break;
+
+		while (stat) {
+			irq = fls(stat) - 1;
+			handle_IRQ(irq + vic->irq, regs);
+			stat &= ~(1 << irq);
+			handled = true;
+		}
+	}
+}
+
+asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
+{
+	int i;
+
+	for (i = 0; i < nr_root_vics; ++i)
+		vic_single_handle_irq(vic_root_devices[i], regs);
+}
+#endif /* CONFIG_MULTI_IRQ_HANDLER */
+
 #endif /* CONFIG OF */
diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
index df1d895..451788c 100644
--- a/arch/arm/include/asm/hardware/vic.h
+++ b/arch/arm/include/asm/hardware/vic.h
@@ -53,6 +53,7 @@ static inline int vic_of_init(struct device_node *node,
 	return -ENOSYS;
 }
 #endif /* CONFIG_OF */
+void vic_handle_irq(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 #endif
-- 
1.7.4.1

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

* Re: [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
  2011-09-27 12:16     ` Jamie Iles
@ 2011-09-27 13:25         ` Rob Herring
  -1 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2011-09-27 13:25 UTC (permalink / raw)
  To: Jamie Iles
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 09/27/2011 07:16 AM, Jamie Iles wrote:
> Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
> platforms.  This only works for platforms with CONFIG_OF=y as we can
> determine which controllers are the primary controllers (no parent).

That's probably not an acceptable limitation. I guess this is hard-wired
into entry-macro.S files currently? Perhaps adding an "is_root" flag to
vic_init would fix it for non-DT.

Rob

> 
> Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
> ---
>  arch/arm/common/vic.c               |   48 +++++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/hardware/vic.h |    1 +
>  2 files changed, 49 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 3658579..e9b72d3 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -63,6 +63,22 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
>  
> +#if defined(CONFIG_OF) && defined(CONFIG_MULTI_IRQ_HANDLER)
> +/*
> + * The root VIC's.  We keep track of these so that we can do the IRQ demuxing
> + * as we can have more than one root VIC.
> + */
> +static struct vic_device *vic_root_devices[CONFIG_ARM_VIC_NR];
> +static int nr_root_vics;
> +
> +static void vic_register_root_controller(struct vic_device *vic)
> +{
> +	vic_root_devices[nr_root_vics++] = vic;
> +}
> +#else /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +static inline void vic_register_root_controller(struct vic_device *vic) {}
> +#endif /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +
>  /**
>   * vic_init2 - common initialisation code
>   * @base: Base of the VIC.
> @@ -439,6 +455,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
>  	vic->domain.ops = &vic_irq_domain_ops;
>  	irq_domain_add(&vic->domain);
>  
> +	if (!parent)
> +		vic_register_root_controller(vic);
> +
>  	return 0;
>  
>  out_unmap:
> @@ -447,4 +466,33 @@ out_unmap:
>  	return -EIO;
>  }
>  
> +#ifdef CONFIG_MULTI_IRQ_HANDLER
> +static void vic_single_handle_irq(struct vic_device *vic, struct pt_regs *regs)
> +{
> +	u32 stat, irq;
> +	bool handled = false;
> +
> +	while (!handled) {
> +		stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
> +		if (!stat)
> +			break;
> +
> +		while (stat) {
> +			irq = fls(stat) - 1;
> +			handle_IRQ(irq + vic->irq, regs);
> +			stat &= ~(1 << irq);
> +			handled = true;
> +		}
> +	}
> +}
> +
> +asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
> +{
> +	int i;
> +
> +	for (i = 0; i < nr_root_vics; ++i)
> +		vic_single_handle_irq(vic_root_devices[i], regs);
> +}
> +#endif /* CONFIG_MULTI_IRQ_HANDLER */
> +
>  #endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index df1d895..451788c 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -53,6 +53,7 @@ static inline int vic_of_init(struct device_node *node,
>  	return -ENOSYS;
>  }
>  #endif /* CONFIG_OF */
> +void vic_handle_irq(struct pt_regs *regs);
>  #endif /* __ASSEMBLY__ */
>  
>  #endif

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

* [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
@ 2011-09-27 13:25         ` Rob Herring
  0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2011-09-27 13:25 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/27/2011 07:16 AM, Jamie Iles wrote:
> Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
> platforms.  This only works for platforms with CONFIG_OF=y as we can
> determine which controllers are the primary controllers (no parent).

That's probably not an acceptable limitation. I guess this is hard-wired
into entry-macro.S files currently? Perhaps adding an "is_root" flag to
vic_init would fix it for non-DT.

Rob

> 
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> ---
>  arch/arm/common/vic.c               |   48 +++++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/hardware/vic.h |    1 +
>  2 files changed, 49 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 3658579..e9b72d3 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -63,6 +63,22 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
>  
> +#if defined(CONFIG_OF) && defined(CONFIG_MULTI_IRQ_HANDLER)
> +/*
> + * The root VIC's.  We keep track of these so that we can do the IRQ demuxing
> + * as we can have more than one root VIC.
> + */
> +static struct vic_device *vic_root_devices[CONFIG_ARM_VIC_NR];
> +static int nr_root_vics;
> +
> +static void vic_register_root_controller(struct vic_device *vic)
> +{
> +	vic_root_devices[nr_root_vics++] = vic;
> +}
> +#else /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +static inline void vic_register_root_controller(struct vic_device *vic) {}
> +#endif /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +
>  /**
>   * vic_init2 - common initialisation code
>   * @base: Base of the VIC.
> @@ -439,6 +455,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
>  	vic->domain.ops = &vic_irq_domain_ops;
>  	irq_domain_add(&vic->domain);
>  
> +	if (!parent)
> +		vic_register_root_controller(vic);
> +
>  	return 0;
>  
>  out_unmap:
> @@ -447,4 +466,33 @@ out_unmap:
>  	return -EIO;
>  }
>  
> +#ifdef CONFIG_MULTI_IRQ_HANDLER
> +static void vic_single_handle_irq(struct vic_device *vic, struct pt_regs *regs)
> +{
> +	u32 stat, irq;
> +	bool handled = false;
> +
> +	while (!handled) {
> +		stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
> +		if (!stat)
> +			break;
> +
> +		while (stat) {
> +			irq = fls(stat) - 1;
> +			handle_IRQ(irq + vic->irq, regs);
> +			stat &= ~(1 << irq);
> +			handled = true;
> +		}
> +	}
> +}
> +
> +asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
> +{
> +	int i;
> +
> +	for (i = 0; i < nr_root_vics; ++i)
> +		vic_single_handle_irq(vic_root_devices[i], regs);
> +}
> +#endif /* CONFIG_MULTI_IRQ_HANDLER */
> +
>  #endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index df1d895..451788c 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -53,6 +53,7 @@ static inline int vic_of_init(struct device_node *node,
>  	return -ENOSYS;
>  }
>  #endif /* CONFIG_OF */
> +void vic_handle_irq(struct pt_regs *regs);
>  #endif /* __ASSEMBLY__ */
>  
>  #endif

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

* Re: [PATCH 1/2] ARM: vic: device tree binding
  2011-09-27 12:16 ` Jamie Iles
@ 2011-09-27 13:30     ` Rob Herring
  -1 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2011-09-27 13:30 UTC (permalink / raw)
  To: Jamie Iles
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On 09/27/2011 07:16 AM, Jamie Iles wrote:
> This adds a device tree binding for the VIC based on the of_irq_init()
> support.
> 
> Cc: Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/arm/vic.txt |   29 ++++++
>  arch/arm/common/vic.c                         |  121 ++++++++++++++++++++-----
>  arch/arm/include/asm/hardware/vic.h           |   13 +++-
>  3 files changed, 137 insertions(+), 26 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/vic.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
> new file mode 100644
> index 0000000..266716b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/vic.txt
> @@ -0,0 +1,29 @@
> +* ARM Vectored Interrupt Controller
> +
> +One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
> +system for interrupt routing.  For multiple controllers they can either be
> +nested or have the outputs wire-OR'd together.
> +
> +Required properties:
> +
> +- compatible : should be one of
> +	"arm,pl190-vic"
> +	"arm,pl192-vic"
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
> +  the VIC has no configuration options for interrupt sources.  The cell is a u32
> +  and defines the interrupt number.
> +- reg : The register bank for the VIC.
> +
> +Optional properties:
> +
> +- interrupts : Interrupt source for parent controllers if the VIC is nested.
> +
> +Example:
> +
> +	vic0: interrupt-controller@60000 {
> +		compatible = "arm,pl192-vic";
> +		interrupt-controller;
> +		#interrupt-cells = <1>;
> +		reg = <0x60000 0x1000>;
> +	};
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 7aa4262..3658579 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -22,6 +22,10 @@
>  #include <linux/init.h>
>  #include <linux/list.h>
>  #include <linux/io.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
>  #include <linux/syscore_ops.h>
>  #include <linux/device.h>
>  #include <linux/amba/bus.h>
> @@ -29,7 +33,6 @@
>  #include <asm/mach/irq.h>
>  #include <asm/hardware/vic.h>
>  
> -#ifdef CONFIG_PM
>  /**
>   * struct vic_device - VIC PM device
>   * @irq: The IRQ number for the base of the VIC.
> @@ -50,13 +53,15 @@ struct vic_device {
>  	u32		int_enable;
>  	u32		soft_int;
>  	u32		protect;
> +#ifdef CONFIG_IRQ_DOMAIN
> +	struct irq_domain domain;
> +#endif /* CONFIG_IRQ_DOMAIN */
>  };
>  
>  /* we cannot allocate memory when VICs are initially registered */
>  static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
> -#endif /* CONFIG_PM */
>  
>  /**
>   * vic_init2 - common initialisation code
> @@ -156,9 +161,10 @@ static int __init vic_pm_init(void)
>  	return 0;
>  }
>  late_initcall(vic_pm_init);
> +#endif /* CONFIG_PM */
>  
>  /**
> - * vic_pm_register - Register a VIC for later power management control
> + * vic_register - Register a VIC.
>   * @base: The base address of the VIC.
>   * @irq: The base IRQ for the VIC.
>   * @resume_sources: bitmask of interrupts allowed for resume sources.
> @@ -166,24 +172,28 @@ late_initcall(vic_pm_init);
>   * Register the VIC with the system device tree so that it can be notified
>   * of suspend and resume requests and ensure that the correct actions are
>   * taken to re-instate the settings on resume.
> + *
> + * We return the VIC so that it can be used for IRQ domain operations for
> + * device tree translation.
>   */
> -static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
> +static struct vic_device * __init
> +vic_register(void __iomem *base, unsigned int irq, u32 resume_sources)
>  {
>  	struct vic_device *v;
>  
> -	if (vic_id >= ARRAY_SIZE(vic_devices))
> +	if (vic_id >= ARRAY_SIZE(vic_devices)) {
>  		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
> -	else {
> -		v = &vic_devices[vic_id];
> -		v->base = base;
> -		v->resume_sources = resume_sources;
> -		v->irq = irq;
> -		vic_id++;
> +		return NULL;
>  	}
> +
> +	v = &vic_devices[vic_id];
> +	v->base = base;
> +	v->resume_sources = resume_sources;
> +	v->irq = irq;
> +	vic_id++;
> +
> +	return v;
>  }
> -#else
> -static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
> -#endif /* CONFIG_PM */
>  
>  static void vic_ack_irq(struct irq_data *d)
>  {
> @@ -331,15 +341,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  }
>  
> -/**
> - * vic_init - initialise a vectored interrupt controller
> - * @base: iomem base address
> - * @irq_start: starting interrupt number, must be muliple of 32
> - * @vic_sources: bitmask of interrupt sources to allow
> - * @resume_sources: bitmask of interrupt sources to allow for resume
> - */
> -void __init vic_init(void __iomem *base, unsigned int irq_start,
> -		     u32 vic_sources, u32 resume_sources)
> +static struct vic_device * __init
> +__vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
> +	   u32 resume_sources)
>  {
>  	unsigned int i;
>  	u32 cellid = 0;
> @@ -357,7 +361,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  	switch(vendor) {
>  	case AMBA_VENDOR_ST:
>  		vic_init_st(base, irq_start, vic_sources);
> -		return;
> +		return NULL;
>  	default:
>  		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
>  		/* fall through */
> @@ -375,5 +379,72 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  
> -	vic_pm_register(base, irq_start, resume_sources);
> +	return vic_register(base, irq_start, resume_sources);
>  }
> +
> +/**
> + * vic_init - initialise a vectored interrupt controller
> + * @base: iomem base address
> + * @irq_start: starting interrupt number, must be muliple of 32
> + * @vic_sources: bitmask of interrupt sources to allow
> + * @resume_sources: bitmask of interrupt sources to allow for resume
> + */
> +void __init vic_init(void __iomem *base, unsigned int irq_start,
> +		     u32 vic_sources, u32 resume_sources)
> +{
> +	__vic_init(base, irq_start, vic_sources, resume_sources);
> +}
> +
> +#ifdef CONFIG_OF
> +static int
> +vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
> +			    const u32 *intspec, unsigned int intsize,
> +			    unsigned long *out_hwirq, unsigned int *out_type)
> +{
> +	if (d->of_node != np)
> +		return -EINVAL;
> +	if (intsize < 1)
> +		return -EINVAL;
> +
> +	*out_hwirq = intspec[0];
> +	*out_type = IRQ_TYPE_NONE;
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops vic_irq_domain_ops = {
> +	.dt_translate = vic_irq_domain_dt_translate,
> +};

You should be able to use the simple ops here. You'll need this patch if
you don't already have it:

https://lkml.org/lkml/2011/9/14/189

> +
> +int __init vic_of_init(struct device_node *node, struct device_node *parent)
> +{
> +	void __iomem *regs = of_iomap(node, 0);
> +	struct vic_device *vic;
> +	int irq_base;
> +
> +	if (WARN_ON(!regs))
> +		return -EIO;
> +
> +	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
> +	if (WARN_ON(irq_base < 0))
> +		goto out_unmap;
> +
> +	vic = __vic_init(regs, irq_base, ~0, ~0);
> +	if (WARN_ON(!vic))
> +		goto out_unmap;
> +
> +	vic->domain.irq_base = irq_base;
> +	vic->domain.nr_irq = 32;
> +	vic->domain.of_node = of_node_get(node);
> +	vic->domain.ops = &vic_irq_domain_ops;
> +	irq_domain_add(&vic->domain);
> +
> +	return 0;
> +
> +out_unmap:
> +	iounmap(regs);
> +
> +	return -EIO;
> +}
> +
> +#endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index 5d72550..df1d895 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -41,7 +41,18 @@
>  #define VIC_PL192_VECT_ADDR		0xF00
>  
>  #ifndef __ASSEMBLY__
> +struct device_node;
>  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
> -#endif
> +
> +#ifdef CONFIG_OF
> +int vic_of_init(struct device_node *node, struct device_node *parent);
> +#else /* CONFIG_OF */
> +static inline int vic_of_init(struct device_node *node,
> +			      struct device_node *parent)
> +{
> +	return -ENOSYS;

I'm doing ENODEV here for gic. We should be consistent. Which is right?

Rob

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

* [PATCH 1/2] ARM: vic: device tree binding
@ 2011-09-27 13:30     ` Rob Herring
  0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2011-09-27 13:30 UTC (permalink / raw)
  To: linux-arm-kernel

On 09/27/2011 07:16 AM, Jamie Iles wrote:
> This adds a device tree binding for the VIC based on the of_irq_init()
> support.
> 
> Cc: Rob Herring <robherring2@gmail.com>
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> ---
>  Documentation/devicetree/bindings/arm/vic.txt |   29 ++++++
>  arch/arm/common/vic.c                         |  121 ++++++++++++++++++++-----
>  arch/arm/include/asm/hardware/vic.h           |   13 +++-
>  3 files changed, 137 insertions(+), 26 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/vic.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
> new file mode 100644
> index 0000000..266716b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/vic.txt
> @@ -0,0 +1,29 @@
> +* ARM Vectored Interrupt Controller
> +
> +One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
> +system for interrupt routing.  For multiple controllers they can either be
> +nested or have the outputs wire-OR'd together.
> +
> +Required properties:
> +
> +- compatible : should be one of
> +	"arm,pl190-vic"
> +	"arm,pl192-vic"
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
> +  the VIC has no configuration options for interrupt sources.  The cell is a u32
> +  and defines the interrupt number.
> +- reg : The register bank for the VIC.
> +
> +Optional properties:
> +
> +- interrupts : Interrupt source for parent controllers if the VIC is nested.
> +
> +Example:
> +
> +	vic0: interrupt-controller at 60000 {
> +		compatible = "arm,pl192-vic";
> +		interrupt-controller;
> +		#interrupt-cells = <1>;
> +		reg = <0x60000 0x1000>;
> +	};
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 7aa4262..3658579 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -22,6 +22,10 @@
>  #include <linux/init.h>
>  #include <linux/list.h>
>  #include <linux/io.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
>  #include <linux/syscore_ops.h>
>  #include <linux/device.h>
>  #include <linux/amba/bus.h>
> @@ -29,7 +33,6 @@
>  #include <asm/mach/irq.h>
>  #include <asm/hardware/vic.h>
>  
> -#ifdef CONFIG_PM
>  /**
>   * struct vic_device - VIC PM device
>   * @irq: The IRQ number for the base of the VIC.
> @@ -50,13 +53,15 @@ struct vic_device {
>  	u32		int_enable;
>  	u32		soft_int;
>  	u32		protect;
> +#ifdef CONFIG_IRQ_DOMAIN
> +	struct irq_domain domain;
> +#endif /* CONFIG_IRQ_DOMAIN */
>  };
>  
>  /* we cannot allocate memory when VICs are initially registered */
>  static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
> -#endif /* CONFIG_PM */
>  
>  /**
>   * vic_init2 - common initialisation code
> @@ -156,9 +161,10 @@ static int __init vic_pm_init(void)
>  	return 0;
>  }
>  late_initcall(vic_pm_init);
> +#endif /* CONFIG_PM */
>  
>  /**
> - * vic_pm_register - Register a VIC for later power management control
> + * vic_register - Register a VIC.
>   * @base: The base address of the VIC.
>   * @irq: The base IRQ for the VIC.
>   * @resume_sources: bitmask of interrupts allowed for resume sources.
> @@ -166,24 +172,28 @@ late_initcall(vic_pm_init);
>   * Register the VIC with the system device tree so that it can be notified
>   * of suspend and resume requests and ensure that the correct actions are
>   * taken to re-instate the settings on resume.
> + *
> + * We return the VIC so that it can be used for IRQ domain operations for
> + * device tree translation.
>   */
> -static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
> +static struct vic_device * __init
> +vic_register(void __iomem *base, unsigned int irq, u32 resume_sources)
>  {
>  	struct vic_device *v;
>  
> -	if (vic_id >= ARRAY_SIZE(vic_devices))
> +	if (vic_id >= ARRAY_SIZE(vic_devices)) {
>  		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
> -	else {
> -		v = &vic_devices[vic_id];
> -		v->base = base;
> -		v->resume_sources = resume_sources;
> -		v->irq = irq;
> -		vic_id++;
> +		return NULL;
>  	}
> +
> +	v = &vic_devices[vic_id];
> +	v->base = base;
> +	v->resume_sources = resume_sources;
> +	v->irq = irq;
> +	vic_id++;
> +
> +	return v;
>  }
> -#else
> -static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
> -#endif /* CONFIG_PM */
>  
>  static void vic_ack_irq(struct irq_data *d)
>  {
> @@ -331,15 +341,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  }
>  
> -/**
> - * vic_init - initialise a vectored interrupt controller
> - * @base: iomem base address
> - * @irq_start: starting interrupt number, must be muliple of 32
> - * @vic_sources: bitmask of interrupt sources to allow
> - * @resume_sources: bitmask of interrupt sources to allow for resume
> - */
> -void __init vic_init(void __iomem *base, unsigned int irq_start,
> -		     u32 vic_sources, u32 resume_sources)
> +static struct vic_device * __init
> +__vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,
> +	   u32 resume_sources)
>  {
>  	unsigned int i;
>  	u32 cellid = 0;
> @@ -357,7 +361,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  	switch(vendor) {
>  	case AMBA_VENDOR_ST:
>  		vic_init_st(base, irq_start, vic_sources);
> -		return;
> +		return NULL;
>  	default:
>  		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
>  		/* fall through */
> @@ -375,5 +379,72 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  
> -	vic_pm_register(base, irq_start, resume_sources);
> +	return vic_register(base, irq_start, resume_sources);
>  }
> +
> +/**
> + * vic_init - initialise a vectored interrupt controller
> + * @base: iomem base address
> + * @irq_start: starting interrupt number, must be muliple of 32
> + * @vic_sources: bitmask of interrupt sources to allow
> + * @resume_sources: bitmask of interrupt sources to allow for resume
> + */
> +void __init vic_init(void __iomem *base, unsigned int irq_start,
> +		     u32 vic_sources, u32 resume_sources)
> +{
> +	__vic_init(base, irq_start, vic_sources, resume_sources);
> +}
> +
> +#ifdef CONFIG_OF
> +static int
> +vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
> +			    const u32 *intspec, unsigned int intsize,
> +			    unsigned long *out_hwirq, unsigned int *out_type)
> +{
> +	if (d->of_node != np)
> +		return -EINVAL;
> +	if (intsize < 1)
> +		return -EINVAL;
> +
> +	*out_hwirq = intspec[0];
> +	*out_type = IRQ_TYPE_NONE;
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops vic_irq_domain_ops = {
> +	.dt_translate = vic_irq_domain_dt_translate,
> +};

You should be able to use the simple ops here. You'll need this patch if
you don't already have it:

https://lkml.org/lkml/2011/9/14/189

> +
> +int __init vic_of_init(struct device_node *node, struct device_node *parent)
> +{
> +	void __iomem *regs = of_iomap(node, 0);
> +	struct vic_device *vic;
> +	int irq_base;
> +
> +	if (WARN_ON(!regs))
> +		return -EIO;
> +
> +	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
> +	if (WARN_ON(irq_base < 0))
> +		goto out_unmap;
> +
> +	vic = __vic_init(regs, irq_base, ~0, ~0);
> +	if (WARN_ON(!vic))
> +		goto out_unmap;
> +
> +	vic->domain.irq_base = irq_base;
> +	vic->domain.nr_irq = 32;
> +	vic->domain.of_node = of_node_get(node);
> +	vic->domain.ops = &vic_irq_domain_ops;
> +	irq_domain_add(&vic->domain);
> +
> +	return 0;
> +
> +out_unmap:
> +	iounmap(regs);
> +
> +	return -EIO;
> +}
> +
> +#endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index 5d72550..df1d895 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -41,7 +41,18 @@
>  #define VIC_PL192_VECT_ADDR		0xF00
>  
>  #ifndef __ASSEMBLY__
> +struct device_node;
>  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
> -#endif
> +
> +#ifdef CONFIG_OF
> +int vic_of_init(struct device_node *node, struct device_node *parent);
> +#else /* CONFIG_OF */
> +static inline int vic_of_init(struct device_node *node,
> +			      struct device_node *parent)
> +{
> +	return -ENOSYS;

I'm doing ENODEV here for gic. We should be consistent. Which is right?

Rob

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

* Re: [PATCH 1/2] ARM: vic: device tree binding
  2011-09-27 13:30     ` Rob Herring
@ 2011-09-27 13:38         ` Jamie Iles
  -1 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 13:38 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

Hi Rob,

On Tue, Sep 27, 2011 at 08:30:43AM -0500, Rob Herring wrote:
> On 09/27/2011 07:16 AM, Jamie Iles wrote:
[...]
> > +#ifdef CONFIG_OF
> > +static int
> > +vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
> > +			    const u32 *intspec, unsigned int intsize,
> > +			    unsigned long *out_hwirq, unsigned int *out_type)
> > +{
> > +	if (d->of_node != np)
> > +		return -EINVAL;
> > +	if (intsize < 1)
> > +		return -EINVAL;
> > +
> > +	*out_hwirq = intspec[0];
> > +	*out_type = IRQ_TYPE_NONE;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct irq_domain_ops vic_irq_domain_ops = {
> > +	.dt_translate = vic_irq_domain_dt_translate,
> > +};
> 
> You should be able to use the simple ops here. You'll need this patch if
> you don't already have it:
> 
> https://lkml.org/lkml/2011/9/14/189

I didn't use the simple ops because I thought it would be better to only 
accept one interrupt cell, but I got it wrong and should have had:

	if (intsize != 1)
		return -EINVAL;

The simple ops would work but I'm not sure what would be best.  Any 
preference?

> > +
> > +int __init vic_of_init(struct device_node *node, struct device_node *parent)
> > +{
> > +	void __iomem *regs = of_iomap(node, 0);
> > +	struct vic_device *vic;
> > +	int irq_base;
> > +
> > +	if (WARN_ON(!regs))
> > +		return -EIO;
> > +
> > +	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
> > +	if (WARN_ON(irq_base < 0))
> > +		goto out_unmap;
> > +
> > +	vic = __vic_init(regs, irq_base, ~0, ~0);
> > +	if (WARN_ON(!vic))
> > +		goto out_unmap;
> > +
> > +	vic->domain.irq_base = irq_base;
> > +	vic->domain.nr_irq = 32;
> > +	vic->domain.of_node = of_node_get(node);
> > +	vic->domain.ops = &vic_irq_domain_ops;
> > +	irq_domain_add(&vic->domain);
> > +
> > +	return 0;
> > +
> > +out_unmap:
> > +	iounmap(regs);
> > +
> > +	return -EIO;
> > +}
> > +
> > +#endif /* CONFIG OF */
> > diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> > index 5d72550..df1d895 100644
> > --- a/arch/arm/include/asm/hardware/vic.h
> > +++ b/arch/arm/include/asm/hardware/vic.h
> > @@ -41,7 +41,18 @@
> >  #define VIC_PL192_VECT_ADDR		0xF00
> >  
> >  #ifndef __ASSEMBLY__
> > +struct device_node;
> >  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
> > -#endif
> > +
> > +#ifdef CONFIG_OF
> > +int vic_of_init(struct device_node *node, struct device_node *parent);
> > +#else /* CONFIG_OF */
> > +static inline int vic_of_init(struct device_node *node,
> > +			      struct device_node *parent)
> > +{
> > +	return -ENOSYS;
> 
> I'm doing ENODEV here for gic. We should be consistent. Which is right?

I see -ENOSYS for lots of these in include/linux, but I'm not sure it 
matters a great deal.  I'll change it to -ENODEV for the next version.

Jamie

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

* [PATCH 1/2] ARM: vic: device tree binding
@ 2011-09-27 13:38         ` Jamie Iles
  0 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 13:38 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Rob,

On Tue, Sep 27, 2011 at 08:30:43AM -0500, Rob Herring wrote:
> On 09/27/2011 07:16 AM, Jamie Iles wrote:
[...]
> > +#ifdef CONFIG_OF
> > +static int
> > +vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
> > +			    const u32 *intspec, unsigned int intsize,
> > +			    unsigned long *out_hwirq, unsigned int *out_type)
> > +{
> > +	if (d->of_node != np)
> > +		return -EINVAL;
> > +	if (intsize < 1)
> > +		return -EINVAL;
> > +
> > +	*out_hwirq = intspec[0];
> > +	*out_type = IRQ_TYPE_NONE;
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct irq_domain_ops vic_irq_domain_ops = {
> > +	.dt_translate = vic_irq_domain_dt_translate,
> > +};
> 
> You should be able to use the simple ops here. You'll need this patch if
> you don't already have it:
> 
> https://lkml.org/lkml/2011/9/14/189

I didn't use the simple ops because I thought it would be better to only 
accept one interrupt cell, but I got it wrong and should have had:

	if (intsize != 1)
		return -EINVAL;

The simple ops would work but I'm not sure what would be best.  Any 
preference?

> > +
> > +int __init vic_of_init(struct device_node *node, struct device_node *parent)
> > +{
> > +	void __iomem *regs = of_iomap(node, 0);
> > +	struct vic_device *vic;
> > +	int irq_base;
> > +
> > +	if (WARN_ON(!regs))
> > +		return -EIO;
> > +
> > +	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
> > +	if (WARN_ON(irq_base < 0))
> > +		goto out_unmap;
> > +
> > +	vic = __vic_init(regs, irq_base, ~0, ~0);
> > +	if (WARN_ON(!vic))
> > +		goto out_unmap;
> > +
> > +	vic->domain.irq_base = irq_base;
> > +	vic->domain.nr_irq = 32;
> > +	vic->domain.of_node = of_node_get(node);
> > +	vic->domain.ops = &vic_irq_domain_ops;
> > +	irq_domain_add(&vic->domain);
> > +
> > +	return 0;
> > +
> > +out_unmap:
> > +	iounmap(regs);
> > +
> > +	return -EIO;
> > +}
> > +
> > +#endif /* CONFIG OF */
> > diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> > index 5d72550..df1d895 100644
> > --- a/arch/arm/include/asm/hardware/vic.h
> > +++ b/arch/arm/include/asm/hardware/vic.h
> > @@ -41,7 +41,18 @@
> >  #define VIC_PL192_VECT_ADDR		0xF00
> >  
> >  #ifndef __ASSEMBLY__
> > +struct device_node;
> >  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
> > -#endif
> > +
> > +#ifdef CONFIG_OF
> > +int vic_of_init(struct device_node *node, struct device_node *parent);
> > +#else /* CONFIG_OF */
> > +static inline int vic_of_init(struct device_node *node,
> > +			      struct device_node *parent)
> > +{
> > +	return -ENOSYS;
> 
> I'm doing ENODEV here for gic. We should be consistent. Which is right?

I see -ENOSYS for lots of these in include/linux, but I'm not sure it 
matters a great deal.  I'll change it to -ENODEV for the next version.

Jamie

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

* Re: [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
  2011-09-27 13:25         ` Rob Herring
@ 2011-09-27 13:58             ` Jamie Iles
  -1 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 13:58 UTC (permalink / raw)
  To: Rob Herring
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Sep 27, 2011 at 08:25:30AM -0500, Rob Herring wrote:
> On 09/27/2011 07:16 AM, Jamie Iles wrote:
> > Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
> > platforms.  This only works for platforms with CONFIG_OF=y as we can
> > determine which controllers are the primary controllers (no parent).
> 
> That's probably not an acceptable limitation. I guess this is hard-wired
> into entry-macro.S files currently? Perhaps adding an "is_root" flag to
> vic_init would fix it for non-DT.

OK.  Looking at all of the other users of the common vic code, I can't 
find an instance where the vic isn't the top level controller.  So I 
think that restriction can be removed and in the device tree probing 
issue a WARN() if parent != NULL.  Does that work for you?

Jamie

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

* [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
@ 2011-09-27 13:58             ` Jamie Iles
  0 siblings, 0 replies; 16+ messages in thread
From: Jamie Iles @ 2011-09-27 13:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 27, 2011 at 08:25:30AM -0500, Rob Herring wrote:
> On 09/27/2011 07:16 AM, Jamie Iles wrote:
> > Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
> > platforms.  This only works for platforms with CONFIG_OF=y as we can
> > determine which controllers are the primary controllers (no parent).
> 
> That's probably not an acceptable limitation. I guess this is hard-wired
> into entry-macro.S files currently? Perhaps adding an "is_root" flag to
> vic_init would fix it for non-DT.

OK.  Looking at all of the other users of the common vic code, I can't 
find an instance where the vic isn't the top level controller.  So I 
think that restriction can be removed and in the device tree probing 
issue a WARN() if parent != NULL.  Does that work for you?

Jamie

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

* Re: [PATCH 1/2] ARM: vic: device tree binding
  2011-09-27 12:16 ` Jamie Iles
@ 2011-09-27 21:00     ` Grant Likely
  -1 siblings, 0 replies; 16+ messages in thread
From: Grant Likely @ 2011-09-27 21:00 UTC (permalink / raw)
  To: Jamie Iles
  Cc: devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r

On Tue, Sep 27, 2011 at 01:16:41PM +0100, Jamie Iles wrote:
> This adds a device tree binding for the VIC based on the of_irq_init()
> support.
> 
> Cc: Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Signed-off-by: Jamie Iles <jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
> ---
>  Documentation/devicetree/bindings/arm/vic.txt |   29 ++++++
>  arch/arm/common/vic.c                         |  121 ++++++++++++++++++++-----
>  arch/arm/include/asm/hardware/vic.h           |   13 +++-
>  3 files changed, 137 insertions(+), 26 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/vic.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
> new file mode 100644
> index 0000000..266716b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/vic.txt
> @@ -0,0 +1,29 @@
> +* ARM Vectored Interrupt Controller
> +
> +One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
> +system for interrupt routing.  For multiple controllers they can either be
> +nested or have the outputs wire-OR'd together.
> +
> +Required properties:
> +
> +- compatible : should be one of
> +	"arm,pl190-vic"
> +	"arm,pl192-vic"
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
> +  the VIC has no configuration options for interrupt sources.  The cell is a u32
> +  and defines the interrupt number.
> +- reg : The register bank for the VIC.
> +
> +Optional properties:
> +
> +- interrupts : Interrupt source for parent controllers if the VIC is nested.
> +
> +Example:
> +
> +	vic0: interrupt-controller@60000 {
> +		compatible = "arm,pl192-vic";
> +		interrupt-controller;
> +		#interrupt-cells = <1>;
> +		reg = <0x60000 0x1000>;
> +	};
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 7aa4262..3658579 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -22,6 +22,10 @@
>  #include <linux/init.h>
>  #include <linux/list.h>
>  #include <linux/io.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
>  #include <linux/syscore_ops.h>
>  #include <linux/device.h>
>  #include <linux/amba/bus.h>
> @@ -29,7 +33,6 @@
>  #include <asm/mach/irq.h>
>  #include <asm/hardware/vic.h>
>  
> -#ifdef CONFIG_PM

Interesting that this #ifdef is being removed, but no mention of it in
the commit text.  It helps with review is some of the implementation
details are described.

>  /**
>   * struct vic_device - VIC PM device
>   * @irq: The IRQ number for the base of the VIC.
> @@ -50,13 +53,15 @@ struct vic_device {
>  	u32		int_enable;
>  	u32		soft_int;
>  	u32		protect;
> +#ifdef CONFIG_IRQ_DOMAIN
> +	struct irq_domain domain;
> +#endif /* CONFIG_IRQ_DOMAIN */
>  };
>  
>  /* we cannot allocate memory when VICs are initially registered */
>  static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
> -#endif /* CONFIG_PM */
>  
>  /**
>   * vic_init2 - common initialisation code
> @@ -156,9 +161,10 @@ static int __init vic_pm_init(void)
>  	return 0;
>  }
>  late_initcall(vic_pm_init);
> +#endif /* CONFIG_PM */
>  
>  /**
> - * vic_pm_register - Register a VIC for later power management control
> + * vic_register - Register a VIC.

Nit: kerneldoc format is:

/**
 * function_name() - description
 *
 
>   * @base: The base address of the VIC.
>   * @irq: The base IRQ for the VIC.
>   * @resume_sources: bitmask of interrupts allowed for resume sources.
> @@ -166,24 +172,28 @@ late_initcall(vic_pm_init);
>   * Register the VIC with the system device tree so that it can be notified
>   * of suspend and resume requests and ensure that the correct actions are
>   * taken to re-instate the settings on resume.
> + *
> + * We return the VIC so that it can be used for IRQ domain operations for
> + * device tree translation.
>   */
> -static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
> +static struct vic_device * __init
> +vic_register(void __iomem *base, unsigned int irq, u32 resume_sources)

Nit: Linebreaks should be restricted to the argument list.  That way
grepping for the function name tells you both what the annotations &
return value is, and that there are more arguments than can be seen
because you don't see closing parentheses.

>  {
>  	struct vic_device *v;
>  
> -	if (vic_id >= ARRAY_SIZE(vic_devices))
> +	if (vic_id >= ARRAY_SIZE(vic_devices)) {
>  		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
> -	else {
> -		v = &vic_devices[vic_id];
> -		v->base = base;
> -		v->resume_sources = resume_sources;
> -		v->irq = irq;
> -		vic_id++;
> +		return NULL;
>  	}
> +
> +	v = &vic_devices[vic_id];
> +	v->base = base;
> +	v->resume_sources = resume_sources;
> +	v->irq = irq;
> +	vic_id++;
> +
> +	return v;
>  }
> -#else
> -static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
> -#endif /* CONFIG_PM */
>  
>  static void vic_ack_irq(struct irq_data *d)
>  {
> @@ -331,15 +341,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  }
>  
> -/**
> - * vic_init - initialise a vectored interrupt controller
> - * @base: iomem base address
> - * @irq_start: starting interrupt number, must be muliple of 32
> - * @vic_sources: bitmask of interrupt sources to allow
> - * @resume_sources: bitmask of interrupt sources to allow for resume
> - */
> -void __init vic_init(void __iomem *base, unsigned int irq_start,
> -		     u32 vic_sources, u32 resume_sources)
> +static struct vic_device * __init
> +__vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,

Ditto here.

> +	   u32 resume_sources)
>  {
>  	unsigned int i;
>  	u32 cellid = 0;
> @@ -357,7 +361,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  	switch(vendor) {
>  	case AMBA_VENDOR_ST:
>  		vic_init_st(base, irq_start, vic_sources);
> -		return;
> +		return NULL;
>  	default:
>  		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
>  		/* fall through */
> @@ -375,5 +379,72 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  
> -	vic_pm_register(base, irq_start, resume_sources);
> +	return vic_register(base, irq_start, resume_sources);
>  }
> +
> +/**
> + * vic_init - initialise a vectored interrupt controller
> + * @base: iomem base address
> + * @irq_start: starting interrupt number, must be muliple of 32
> + * @vic_sources: bitmask of interrupt sources to allow
> + * @resume_sources: bitmask of interrupt sources to allow for resume
> + */
> +void __init vic_init(void __iomem *base, unsigned int irq_start,
> +		     u32 vic_sources, u32 resume_sources)
> +{
> +	__vic_init(base, irq_start, vic_sources, resume_sources);
> +}
> +
> +#ifdef CONFIG_OF
> +static int
> +vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
> +			    const u32 *intspec, unsigned int intsize,
> +			    unsigned long *out_hwirq, unsigned int *out_type)
> +{
> +	if (d->of_node != np)
> +		return -EINVAL;
> +	if (intsize < 1)
> +		return -EINVAL;
> +
> +	*out_hwirq = intspec[0];
> +	*out_type = IRQ_TYPE_NONE;
> +
> +	return 0;
> +}

It matches the simple binding.  Just use
irq_domain_simple_dt_translate() directly.

> +
> +static const struct irq_domain_ops vic_irq_domain_ops = {
> +	.dt_translate = vic_irq_domain_dt_translate,
> +};
> +
> +int __init vic_of_init(struct device_node *node, struct device_node *parent)
> +{
> +	void __iomem *regs = of_iomap(node, 0);
> +	struct vic_device *vic;
> +	int irq_base;
> +
> +	if (WARN_ON(!regs))
> +		return -EIO;
> +
> +	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
> +	if (WARN_ON(irq_base < 0))
> +		goto out_unmap;
> +
> +	vic = __vic_init(regs, irq_base, ~0, ~0);
> +	if (WARN_ON(!vic))
> +		goto out_unmap;
> +
> +	vic->domain.irq_base = irq_base;
> +	vic->domain.nr_irq = 32;
> +	vic->domain.of_node = of_node_get(node);
> +	vic->domain.ops = &vic_irq_domain_ops;
> +	irq_domain_add(&vic->domain);
> +
> +	return 0;
> +
> +out_unmap:

Nit: putting a single space before the label makes 'diff' behave
better.

> +	iounmap(regs);
> +
> +	return -EIO;
> +}
> +
> +#endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index 5d72550..df1d895 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -41,7 +41,18 @@
>  #define VIC_PL192_VECT_ADDR		0xF00
>  
>  #ifndef __ASSEMBLY__
> +struct device_node;
>  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
> -#endif
> +
> +#ifdef CONFIG_OF
> +int vic_of_init(struct device_node *node, struct device_node *parent);
> +#else /* CONFIG_OF */
> +static inline int vic_of_init(struct device_node *node,
> +			      struct device_node *parent)
> +{
> +	return -ENOSYS;
> +}
> +#endif /* CONFIG_OF */

Will this ever be referenced when !CONFIG_OF?  It shouldn't be.

Otherwise looks good.
g.

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

* [PATCH 1/2] ARM: vic: device tree binding
@ 2011-09-27 21:00     ` Grant Likely
  0 siblings, 0 replies; 16+ messages in thread
From: Grant Likely @ 2011-09-27 21:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 27, 2011 at 01:16:41PM +0100, Jamie Iles wrote:
> This adds a device tree binding for the VIC based on the of_irq_init()
> support.
> 
> Cc: Rob Herring <robherring2@gmail.com>
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> ---
>  Documentation/devicetree/bindings/arm/vic.txt |   29 ++++++
>  arch/arm/common/vic.c                         |  121 ++++++++++++++++++++-----
>  arch/arm/include/asm/hardware/vic.h           |   13 +++-
>  3 files changed, 137 insertions(+), 26 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/arm/vic.txt
> 
> diff --git a/Documentation/devicetree/bindings/arm/vic.txt b/Documentation/devicetree/bindings/arm/vic.txt
> new file mode 100644
> index 0000000..266716b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/arm/vic.txt
> @@ -0,0 +1,29 @@
> +* ARM Vectored Interrupt Controller
> +
> +One or more Vectored Interrupt Controllers (VIC's) can be connected in an ARM
> +system for interrupt routing.  For multiple controllers they can either be
> +nested or have the outputs wire-OR'd together.
> +
> +Required properties:
> +
> +- compatible : should be one of
> +	"arm,pl190-vic"
> +	"arm,pl192-vic"
> +- interrupt-controller : Identifies the node as an interrupt controller
> +- #interrupt-cells : The number of cells to define the interrupts.  Must be 1 as
> +  the VIC has no configuration options for interrupt sources.  The cell is a u32
> +  and defines the interrupt number.
> +- reg : The register bank for the VIC.
> +
> +Optional properties:
> +
> +- interrupts : Interrupt source for parent controllers if the VIC is nested.
> +
> +Example:
> +
> +	vic0: interrupt-controller at 60000 {
> +		compatible = "arm,pl192-vic";
> +		interrupt-controller;
> +		#interrupt-cells = <1>;
> +		reg = <0x60000 0x1000>;
> +	};
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 7aa4262..3658579 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -22,6 +22,10 @@
>  #include <linux/init.h>
>  #include <linux/list.h>
>  #include <linux/io.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
>  #include <linux/syscore_ops.h>
>  #include <linux/device.h>
>  #include <linux/amba/bus.h>
> @@ -29,7 +33,6 @@
>  #include <asm/mach/irq.h>
>  #include <asm/hardware/vic.h>
>  
> -#ifdef CONFIG_PM

Interesting that this #ifdef is being removed, but no mention of it in
the commit text.  It helps with review is some of the implementation
details are described.

>  /**
>   * struct vic_device - VIC PM device
>   * @irq: The IRQ number for the base of the VIC.
> @@ -50,13 +53,15 @@ struct vic_device {
>  	u32		int_enable;
>  	u32		soft_int;
>  	u32		protect;
> +#ifdef CONFIG_IRQ_DOMAIN
> +	struct irq_domain domain;
> +#endif /* CONFIG_IRQ_DOMAIN */
>  };
>  
>  /* we cannot allocate memory when VICs are initially registered */
>  static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
> -#endif /* CONFIG_PM */
>  
>  /**
>   * vic_init2 - common initialisation code
> @@ -156,9 +161,10 @@ static int __init vic_pm_init(void)
>  	return 0;
>  }
>  late_initcall(vic_pm_init);
> +#endif /* CONFIG_PM */
>  
>  /**
> - * vic_pm_register - Register a VIC for later power management control
> + * vic_register - Register a VIC.

Nit: kerneldoc format is:

/**
 * function_name() - description
 *
 
>   * @base: The base address of the VIC.
>   * @irq: The base IRQ for the VIC.
>   * @resume_sources: bitmask of interrupts allowed for resume sources.
> @@ -166,24 +172,28 @@ late_initcall(vic_pm_init);
>   * Register the VIC with the system device tree so that it can be notified
>   * of suspend and resume requests and ensure that the correct actions are
>   * taken to re-instate the settings on resume.
> + *
> + * We return the VIC so that it can be used for IRQ domain operations for
> + * device tree translation.
>   */
> -static void __init vic_pm_register(void __iomem *base, unsigned int irq, u32 resume_sources)
> +static struct vic_device * __init
> +vic_register(void __iomem *base, unsigned int irq, u32 resume_sources)

Nit: Linebreaks should be restricted to the argument list.  That way
grepping for the function name tells you both what the annotations &
return value is, and that there are more arguments than can be seen
because you don't see closing parentheses.

>  {
>  	struct vic_device *v;
>  
> -	if (vic_id >= ARRAY_SIZE(vic_devices))
> +	if (vic_id >= ARRAY_SIZE(vic_devices)) {
>  		printk(KERN_ERR "%s: too few VICs, increase CONFIG_ARM_VIC_NR\n", __func__);
> -	else {
> -		v = &vic_devices[vic_id];
> -		v->base = base;
> -		v->resume_sources = resume_sources;
> -		v->irq = irq;
> -		vic_id++;
> +		return NULL;
>  	}
> +
> +	v = &vic_devices[vic_id];
> +	v->base = base;
> +	v->resume_sources = resume_sources;
> +	v->irq = irq;
> +	vic_id++;
> +
> +	return v;
>  }
> -#else
> -static inline void vic_pm_register(void __iomem *base, unsigned int irq, u32 arg1) { }
> -#endif /* CONFIG_PM */
>  
>  static void vic_ack_irq(struct irq_data *d)
>  {
> @@ -331,15 +341,9 @@ static void __init vic_init_st(void __iomem *base, unsigned int irq_start,
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  }
>  
> -/**
> - * vic_init - initialise a vectored interrupt controller
> - * @base: iomem base address
> - * @irq_start: starting interrupt number, must be muliple of 32
> - * @vic_sources: bitmask of interrupt sources to allow
> - * @resume_sources: bitmask of interrupt sources to allow for resume
> - */
> -void __init vic_init(void __iomem *base, unsigned int irq_start,
> -		     u32 vic_sources, u32 resume_sources)
> +static struct vic_device * __init
> +__vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources,

Ditto here.

> +	   u32 resume_sources)
>  {
>  	unsigned int i;
>  	u32 cellid = 0;
> @@ -357,7 +361,7 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  	switch(vendor) {
>  	case AMBA_VENDOR_ST:
>  		vic_init_st(base, irq_start, vic_sources);
> -		return;
> +		return NULL;
>  	default:
>  		printk(KERN_WARNING "VIC: unknown vendor, continuing anyways\n");
>  		/* fall through */
> @@ -375,5 +379,72 @@ void __init vic_init(void __iomem *base, unsigned int irq_start,
>  
>  	vic_set_irq_sources(base, irq_start, vic_sources);
>  
> -	vic_pm_register(base, irq_start, resume_sources);
> +	return vic_register(base, irq_start, resume_sources);
>  }
> +
> +/**
> + * vic_init - initialise a vectored interrupt controller
> + * @base: iomem base address
> + * @irq_start: starting interrupt number, must be muliple of 32
> + * @vic_sources: bitmask of interrupt sources to allow
> + * @resume_sources: bitmask of interrupt sources to allow for resume
> + */
> +void __init vic_init(void __iomem *base, unsigned int irq_start,
> +		     u32 vic_sources, u32 resume_sources)
> +{
> +	__vic_init(base, irq_start, vic_sources, resume_sources);
> +}
> +
> +#ifdef CONFIG_OF
> +static int
> +vic_irq_domain_dt_translate(struct irq_domain *d, struct device_node *np,
> +			    const u32 *intspec, unsigned int intsize,
> +			    unsigned long *out_hwirq, unsigned int *out_type)
> +{
> +	if (d->of_node != np)
> +		return -EINVAL;
> +	if (intsize < 1)
> +		return -EINVAL;
> +
> +	*out_hwirq = intspec[0];
> +	*out_type = IRQ_TYPE_NONE;
> +
> +	return 0;
> +}

It matches the simple binding.  Just use
irq_domain_simple_dt_translate() directly.

> +
> +static const struct irq_domain_ops vic_irq_domain_ops = {
> +	.dt_translate = vic_irq_domain_dt_translate,
> +};
> +
> +int __init vic_of_init(struct device_node *node, struct device_node *parent)
> +{
> +	void __iomem *regs = of_iomap(node, 0);
> +	struct vic_device *vic;
> +	int irq_base;
> +
> +	if (WARN_ON(!regs))
> +		return -EIO;
> +
> +	irq_base = irq_alloc_descs(-1, 0, 32, numa_node_id());
> +	if (WARN_ON(irq_base < 0))
> +		goto out_unmap;
> +
> +	vic = __vic_init(regs, irq_base, ~0, ~0);
> +	if (WARN_ON(!vic))
> +		goto out_unmap;
> +
> +	vic->domain.irq_base = irq_base;
> +	vic->domain.nr_irq = 32;
> +	vic->domain.of_node = of_node_get(node);
> +	vic->domain.ops = &vic_irq_domain_ops;
> +	irq_domain_add(&vic->domain);
> +
> +	return 0;
> +
> +out_unmap:

Nit: putting a single space before the label makes 'diff' behave
better.

> +	iounmap(regs);
> +
> +	return -EIO;
> +}
> +
> +#endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index 5d72550..df1d895 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -41,7 +41,18 @@
>  #define VIC_PL192_VECT_ADDR		0xF00
>  
>  #ifndef __ASSEMBLY__
> +struct device_node;
>  void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources);
> -#endif
> +
> +#ifdef CONFIG_OF
> +int vic_of_init(struct device_node *node, struct device_node *parent);
> +#else /* CONFIG_OF */
> +static inline int vic_of_init(struct device_node *node,
> +			      struct device_node *parent)
> +{
> +	return -ENOSYS;
> +}
> +#endif /* CONFIG_OF */

Will this ever be referenced when !CONFIG_OF?  It shouldn't be.

Otherwise looks good.
g.

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

* Re: [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
  2011-09-27 12:16     ` Jamie Iles
@ 2011-09-27 21:05       ` Grant Likely
  -1 siblings, 0 replies; 16+ messages in thread
From: Grant Likely @ 2011-09-27 21:05 UTC (permalink / raw)
  To: Jamie Iles; +Cc: devicetree-discuss, linux-arm-kernel

On Tue, Sep 27, 2011 at 01:16:42PM +0100, Jamie Iles wrote:
> Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
> platforms.  This only works for platforms with CONFIG_OF=y as we can
> determine which controllers are the primary controllers (no parent).
> 
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> ---
>  arch/arm/common/vic.c               |   48 +++++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/hardware/vic.h |    1 +
>  2 files changed, 49 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 3658579..e9b72d3 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -63,6 +63,22 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
>  
> +#if defined(CONFIG_OF) && defined(CONFIG_MULTI_IRQ_HANDLER)
> +/*
> + * The root VIC's.  We keep track of these so that we can do the IRQ demuxing
> + * as we can have more than one root VIC.
> + */
> +static struct vic_device *vic_root_devices[CONFIG_ARM_VIC_NR];
> +static int nr_root_vics;
> +
> +static void vic_register_root_controller(struct vic_device *vic)
> +{
> +	vic_root_devices[nr_root_vics++] = vic;
> +}
> +#else /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +static inline void vic_register_root_controller(struct vic_device *vic) {}
> +#endif /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +
>  /**
>   * vic_init2 - common initialisation code
>   * @base: Base of the VIC.
> @@ -439,6 +455,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
>  	vic->domain.ops = &vic_irq_domain_ops;
>  	irq_domain_add(&vic->domain);
>  
> +	if (!parent)
> +		vic_register_root_controller(vic);
> +
>  	return 0;
>  
>  out_unmap:
> @@ -447,4 +466,33 @@ out_unmap:
>  	return -EIO;
>  }
>  
> +#ifdef CONFIG_MULTI_IRQ_HANDLER
> +static void vic_single_handle_irq(struct vic_device *vic, struct pt_regs *regs)
> +{
> +	u32 stat, irq;
> +	bool handled = false;
> +
> +	while (!handled) {
> +		stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
> +		if (!stat)
> +			break;
> +
> +		while (stat) {
> +			irq = fls(stat) - 1;
> +			handle_IRQ(irq + vic->irq, regs);

This is the other reason for irq_domain.  Should use
irq_domain_to_irq() here instead of irq + vic->irq.  (similar to that,
this driver can also be converted to use (struct irq_data*)->hwirq
instead of the ((struct irq_data*)->irq & 32) that it currently uses.
hwirq was added when irq_domains were added.

> +			stat &= ~(1 << irq);
> +			handled = true;
> +		}
> +	}
> +}
> +
> +asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
> +{
> +	int i;
> +
> +	for (i = 0; i < nr_root_vics; ++i)
> +		vic_single_handle_irq(vic_root_devices[i], regs);
> +}
> +#endif /* CONFIG_MULTI_IRQ_HANDLER */
> +
>  #endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index df1d895..451788c 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -53,6 +53,7 @@ static inline int vic_of_init(struct device_node *node,
>  	return -ENOSYS;
>  }
>  #endif /* CONFIG_OF */
> +void vic_handle_irq(struct pt_regs *regs);
>  #endif /* __ASSEMBLY__ */
>  
>  #endif
> -- 
> 1.7.4.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler
@ 2011-09-27 21:05       ` Grant Likely
  0 siblings, 0 replies; 16+ messages in thread
From: Grant Likely @ 2011-09-27 21:05 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Sep 27, 2011 at 01:16:42PM +0100, Jamie Iles wrote:
> Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER
> platforms.  This only works for platforms with CONFIG_OF=y as we can
> determine which controllers are the primary controllers (no parent).
> 
> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
> ---
>  arch/arm/common/vic.c               |   48 +++++++++++++++++++++++++++++++++++
>  arch/arm/include/asm/hardware/vic.h |    1 +
>  2 files changed, 49 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
> index 3658579..e9b72d3 100644
> --- a/arch/arm/common/vic.c
> +++ b/arch/arm/common/vic.c
> @@ -63,6 +63,22 @@ static struct vic_device vic_devices[CONFIG_ARM_VIC_NR];
>  
>  static int vic_id;
>  
> +#if defined(CONFIG_OF) && defined(CONFIG_MULTI_IRQ_HANDLER)
> +/*
> + * The root VIC's.  We keep track of these so that we can do the IRQ demuxing
> + * as we can have more than one root VIC.
> + */
> +static struct vic_device *vic_root_devices[CONFIG_ARM_VIC_NR];
> +static int nr_root_vics;
> +
> +static void vic_register_root_controller(struct vic_device *vic)
> +{
> +	vic_root_devices[nr_root_vics++] = vic;
> +}
> +#else /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +static inline void vic_register_root_controller(struct vic_device *vic) {}
> +#endif /* CONFIG_OF && CONFIG_MULTI_IRQ_HANDLER */
> +
>  /**
>   * vic_init2 - common initialisation code
>   * @base: Base of the VIC.
> @@ -439,6 +455,9 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
>  	vic->domain.ops = &vic_irq_domain_ops;
>  	irq_domain_add(&vic->domain);
>  
> +	if (!parent)
> +		vic_register_root_controller(vic);
> +
>  	return 0;
>  
>  out_unmap:
> @@ -447,4 +466,33 @@ out_unmap:
>  	return -EIO;
>  }
>  
> +#ifdef CONFIG_MULTI_IRQ_HANDLER
> +static void vic_single_handle_irq(struct vic_device *vic, struct pt_regs *regs)
> +{
> +	u32 stat, irq;
> +	bool handled = false;
> +
> +	while (!handled) {
> +		stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
> +		if (!stat)
> +			break;
> +
> +		while (stat) {
> +			irq = fls(stat) - 1;
> +			handle_IRQ(irq + vic->irq, regs);

This is the other reason for irq_domain.  Should use
irq_domain_to_irq() here instead of irq + vic->irq.  (similar to that,
this driver can also be converted to use (struct irq_data*)->hwirq
instead of the ((struct irq_data*)->irq & 32) that it currently uses.
hwirq was added when irq_domains were added.

> +			stat &= ~(1 << irq);
> +			handled = true;
> +		}
> +	}
> +}
> +
> +asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
> +{
> +	int i;
> +
> +	for (i = 0; i < nr_root_vics; ++i)
> +		vic_single_handle_irq(vic_root_devices[i], regs);
> +}
> +#endif /* CONFIG_MULTI_IRQ_HANDLER */
> +
>  #endif /* CONFIG OF */
> diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h
> index df1d895..451788c 100644
> --- a/arch/arm/include/asm/hardware/vic.h
> +++ b/arch/arm/include/asm/hardware/vic.h
> @@ -53,6 +53,7 @@ static inline int vic_of_init(struct device_node *node,
>  	return -ENOSYS;
>  }
>  #endif /* CONFIG_OF */
> +void vic_handle_irq(struct pt_regs *regs);
>  #endif /* __ASSEMBLY__ */
>  
>  #endif
> -- 
> 1.7.4.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, other threads:[~2011-09-27 21:05 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-27 12:16 [PATCH 1/2] ARM: vic: device tree binding Jamie Iles
2011-09-27 12:16 ` Jamie Iles
     [not found] ` <1317125802-14386-1-git-send-email-jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
2011-09-27 12:16   ` [PATCH 2/2] ARM: vic: MULTI_IRQ_HANDLER handler Jamie Iles
2011-09-27 12:16     ` Jamie Iles
     [not found]     ` <1317125802-14386-2-git-send-email-jamie-wmLquQDDieKakBO8gow8eQ@public.gmane.org>
2011-09-27 13:25       ` Rob Herring
2011-09-27 13:25         ` Rob Herring
     [not found]         ` <4E81CECA.6050306-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2011-09-27 13:58           ` Jamie Iles
2011-09-27 13:58             ` Jamie Iles
2011-09-27 21:05     ` Grant Likely
2011-09-27 21:05       ` Grant Likely
2011-09-27 13:30   ` [PATCH 1/2] ARM: vic: device tree binding Rob Herring
2011-09-27 13:30     ` Rob Herring
     [not found]     ` <4E81D003.4040501-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2011-09-27 13:38       ` Jamie Iles
2011-09-27 13:38         ` Jamie Iles
2011-09-27 21:00   ` Grant Likely
2011-09-27 21:00     ` Grant Likely

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.