In addition to consolidating the or1k-pic with other interrupt
controllers, this makes OpenRISC less tied to its on-cpu
interrupt controller.

All or1k-pic specific parts are moved out of irq.c and into
drivers/irqchip/irq-or1k-pic.c

In that transition, a couple of changes have been done:
- The wrongly handled or1k_pic_mask_ack() for the non-or1200
  case have been fixed.
- The warnings for the non-or1200 case have been removed.
- A hook for registering a handle_arch_irq function have been
  added.

Signed-off-by: Stefan Kristiansson <stefan.kristians...@saunalahti.fi>
---
Changes in v2:
 - Move or1k-pic related code into irq-or1k-pic
 - Add documentation for device tree bindings
---
 .../interrupt-controller/opencores,or1k-pic.txt    |  16 +++
 arch/openrisc/Kconfig                              |   1 +
 arch/openrisc/include/asm/irq.h                    |   3 +
 arch/openrisc/kernel/irq.c                         | 146 ++-------------------
 drivers/irqchip/Kconfig                            |   4 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-or1k-pic.c                     | 135 +++++++++++++++++++
 7 files changed, 173 insertions(+), 133 deletions(-)
 create mode 100644 
Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt
 create mode 100644 drivers/irqchip/irq-or1k-pic.c

diff --git 
a/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt 
b/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt
new file mode 100644
index 0000000..1da0b78
--- /dev/null
+++ 
b/Documentation/devicetree/bindings/interrupt-controller/opencores,or1k-pic.txt
@@ -0,0 +1,16 @@
+OpenRISC 1000 Programmable Interrupt Controller
+
+Required properties:
+
+- compatible : should be "opencores,o1k-pic"
+- interrupt-controller : Identifies the node as an interrupt controller
+- #interrupt-cells : Specifies the number of cells needed to encode an
+  interrupt source. The value shall be 1.
+
+Example:
+
+intc: interrupt-controller {
+       compatible = "opencores,or1k-pic";
+       interrupt-controller;
+       #interrupt-cells = <1>;
+};
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 2ca7b91..8120fe2 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -23,6 +23,7 @@ config OPENRISC
        select GENERIC_STRNLEN_USER
        select MODULES_USE_ELF_RELA
        select HAVE_DEBUG_STACKOVERFLOW
+       select OR1K_PIC
 
 config MMU
        def_bool y
diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h
index eb612b1..b84634c 100644
--- a/arch/openrisc/include/asm/irq.h
+++ b/arch/openrisc/include/asm/irq.h
@@ -24,4 +24,7 @@
 
 #define NO_IRQ         (-1)
 
+void handle_IRQ(unsigned int, struct pt_regs *);
+extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
+
 #endif /* __ASM_OPENRISC_IRQ_H__ */
diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c
index 8ec77bc..967eb14 100644
--- a/arch/openrisc/kernel/irq.c
+++ b/arch/openrisc/kernel/irq.c
@@ -16,11 +16,10 @@
 
 #include <linux/interrupt.h>
 #include <linux/init.h>
-#include <linux/of.h>
 #include <linux/ftrace.h>
 #include <linux/irq.h>
+#include <linux/irqchip.h>
 #include <linux/export.h>
-#include <linux/irqdomain.h>
 #include <linux/irqflags.h>
 
 /* read interrupt enabled status */
@@ -37,150 +36,31 @@ void arch_local_irq_restore(unsigned long flags)
 }
 EXPORT_SYMBOL(arch_local_irq_restore);
 
-
-/* OR1K PIC implementation */
-
-/* We're a couple of cycles faster than the generic implementations with
- * these 'fast' versions.
- */
-
-static void or1k_pic_mask(struct irq_data *data)
-{
-       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
-}
-
-static void or1k_pic_unmask(struct irq_data *data)
-{
-       mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
-}
-
-static void or1k_pic_ack(struct irq_data *data)
-{
-       /* EDGE-triggered interrupts need to be ack'ed in order to clear
-        * the latch.
-        * LEVEL-triggered interrupts do not need to be ack'ed; however,
-        * ack'ing the interrupt has no ill-effect and is quicker than
-        * trying to figure out what type it is...
-        */
-
-       /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the
-        * interrupt, but the OR1200 does this backwards and requires a 0
-        * to be written...
-        */
-
-#ifdef CONFIG_OR1K_1200
-       /* There are two oddities with the OR1200 PIC implementation:
-        * i)  LEVEL-triggered interrupts are latched and need to be cleared
-        * ii) the interrupt latch is cleared by writing a 0 to the bit,
-        *     as opposed to a 1 as mandated by the spec
-        */
-
-       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
-#else
-       WARN(1, "Interrupt handling possibly broken\n");
-       mtspr(SPR_PICSR, (1UL << data->hwirq));
-#endif
-}
-
-static void or1k_pic_mask_ack(struct irq_data *data)
-{
-       /* Comments for pic_ack apply here, too */
-
-#ifdef CONFIG_OR1K_1200
-       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
-       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
-#else
-       WARN(1, "Interrupt handling possibly broken\n");
-       mtspr(SPR_PICMR, (1UL << data->hwirq));
-       mtspr(SPR_PICSR, (1UL << data->hwirq));
-#endif
-}
-
-#if 0
-static int or1k_pic_set_type(struct irq_data *data, unsigned int flow_type)
-{
-       /* There's nothing to do in the PIC configuration when changing
-        * flow type.  Level and edge-triggered interrupts are both
-        * supported, but it's PIC-implementation specific which type
-        * is handled. */
-
-       return irq_setup_alt_chip(data, flow_type);
-}
-#endif
-
-static struct irq_chip or1k_dev = {
-       .name = "or1k-PIC",
-       .irq_unmask = or1k_pic_unmask,
-       .irq_mask = or1k_pic_mask,
-       .irq_ack = or1k_pic_ack,
-       .irq_mask_ack = or1k_pic_mask_ack,
-};
-
-static struct irq_domain *root_domain;
-
-static inline int pic_get_irq(int first)
-{
-       int hwirq;
-
-       hwirq = ffs(mfspr(SPR_PICSR) >> first);
-       if (!hwirq)
-               return NO_IRQ;
-       else
-               hwirq = hwirq + first -1;
-
-       return irq_find_mapping(root_domain, hwirq);
-}
-
-
-static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+void __init init_IRQ(void)
 {
-       irq_set_chip_and_handler_name(irq, &or1k_dev,
-                                     handle_level_irq, "level");
-       irq_set_status_flags(irq, IRQ_LEVEL | IRQ_NOPROBE);
-
-       return 0;
+       irqchip_init();
 }
 
-static const struct irq_domain_ops or1k_irq_domain_ops = {
-       .xlate = irq_domain_xlate_onecell,
-       .map = or1k_map,
-};
-
-/*
- * This sets up the IRQ domain for the PIC built in to the OpenRISC
- * 1000 CPU.  This is the "root" domain as these are the interrupts
- * that directly trigger an exception in the CPU.
- */
-static void __init or1k_irq_init(void)
-{
-       struct device_node *intc = NULL;
-
-       /* The interrupt controller device node is mandatory */
-       intc = of_find_compatible_node(NULL, NULL, "opencores,or1k-pic");
-       BUG_ON(!intc);
-
-       /* Disable all interrupts until explicitly requested */
-       mtspr(SPR_PICMR, (0UL));
-
-       root_domain = irq_domain_add_linear(intc, 32,
-                                           &or1k_irq_domain_ops, NULL);
-}
+static void (*handle_arch_irq)(struct pt_regs *);
 
-void __init init_IRQ(void)
+void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
 {
-       or1k_irq_init();
+       handle_arch_irq = handle_irq;
 }
 
-void __irq_entry do_IRQ(struct pt_regs *regs)
+void handle_IRQ(unsigned int irq, struct pt_regs *regs)
 {
-       int irq = -1;
        struct pt_regs *old_regs = set_irq_regs(regs);
 
        irq_enter();
 
-       while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
-               generic_handle_irq(irq);
+       generic_handle_irq(irq);
 
        irq_exit();
        set_irq_regs(old_regs);
 }
+
+void __irq_entry do_IRQ(struct pt_regs *regs)
+{
+       handle_arch_irq(regs);
+}
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 3792a1a..f657872 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -61,3 +61,7 @@ config VERSATILE_FPGA_IRQ_NR
        int
        default 4
        depends on VERSATILE_FPGA_IRQ
+
+config OR1K_PIC
+       bool
+       select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index c60b901..1ae2c103 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -22,3 +22,4 @@ obj-$(CONFIG_RENESAS_IRQC)            += irq-renesas-irqc.o
 obj-$(CONFIG_VERSATILE_FPGA_IRQ)       += irq-versatile-fpga.o
 obj-$(CONFIG_ARCH_VT8500)              += irq-vt8500.o
 obj-$(CONFIG_TB10X_IRQC)               += irq-tb10x.o
+obj-$(CONFIG_OR1K_PIC)                 += irq-or1k-pic.o
diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c
new file mode 100644
index 0000000..989c055
--- /dev/null
+++ b/drivers/irqchip/irq-or1k-pic.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010-2011 Jonas Bonn <jo...@southpole.se>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#include "irqchip.h"
+
+/* OR1K PIC implementation */
+
+/* We're a couple of cycles faster than the generic implementations with
+ * these 'fast' versions.
+ */
+
+static void or1k_pic_mask(struct irq_data *data)
+{
+       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
+}
+
+static void or1k_pic_unmask(struct irq_data *data)
+{
+       mtspr(SPR_PICMR, mfspr(SPR_PICMR) | (1UL << data->hwirq));
+}
+
+static void or1k_pic_ack(struct irq_data *data)
+{
+       /* EDGE-triggered interrupts need to be ack'ed in order to clear
+        * the latch.
+        * LEVEL-triggered interrupts do not need to be ack'ed; however,
+        * ack'ing the interrupt has no ill-effect and is quicker than
+        * trying to figure out what type it is...
+        */
+
+       /* The OpenRISC 1000 spec says to write a 1 to the bit to ack the
+        * interrupt, but the OR1200 does this backwards and requires a 0
+        * to be written...
+        */
+
+#ifdef CONFIG_OR1K_1200
+       /* There are two oddities with the OR1200 PIC implementation:
+        * i)  LEVEL-triggered interrupts are latched and need to be cleared
+        * ii) the interrupt latch is cleared by writing a 0 to the bit,
+        *     as opposed to a 1 as mandated by the spec
+        */
+
+       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
+#else
+       mtspr(SPR_PICSR, (1UL << data->hwirq));
+#endif
+}
+
+static void or1k_pic_mask_ack(struct irq_data *data)
+{
+       mtspr(SPR_PICMR, mfspr(SPR_PICMR) & ~(1UL << data->hwirq));
+
+       /* Comments for pic_ack apply here, too */
+#ifdef CONFIG_OR1K_1200
+       mtspr(SPR_PICSR, mfspr(SPR_PICSR) & ~(1UL << data->hwirq));
+#else
+       mtspr(SPR_PICSR, (1UL << data->hwirq));
+#endif
+}
+
+static struct irq_chip or1k_dev = {
+       .name = "or1k-PIC",
+       .irq_unmask = or1k_pic_unmask,
+       .irq_mask = or1k_pic_mask,
+       .irq_ack = or1k_pic_ack,
+       .irq_mask_ack = or1k_pic_mask_ack,
+};
+
+static struct irq_domain *root_domain;
+
+static inline int pic_get_irq(int first)
+{
+       int hwirq;
+
+       hwirq = ffs(mfspr(SPR_PICSR) >> first);
+       if (!hwirq)
+               return NO_IRQ;
+       else
+               hwirq = hwirq + first -1;
+
+       return irq_find_mapping(root_domain, hwirq);
+}
+
+static void or1k_pic_handle_irq(struct pt_regs *regs)
+{
+       int irq = -1;
+
+       while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
+               handle_IRQ(irq, regs);
+}
+
+static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
+{
+       irq_set_chip_and_handler_name(irq, &or1k_dev,
+                                     handle_level_irq, "level");
+       irq_set_status_flags(irq, IRQ_LEVEL | IRQ_NOPROBE);
+
+       return 0;
+}
+
+static const struct irq_domain_ops or1k_irq_domain_ops = {
+       .xlate = irq_domain_xlate_onecell,
+       .map = or1k_map,
+};
+
+/*
+ * This sets up the IRQ domain for the PIC built in to the OpenRISC
+ * 1000 CPU.  This is the "root" domain as these are the interrupts
+ * that directly trigger an exception in the CPU.
+ */
+static int __init
+or1k_irq_init(struct device_node *intc,  struct device_node *parent)
+{
+       /* Disable all interrupts until explicitly requested */
+       mtspr(SPR_PICMR, (0UL));
+
+       root_domain = irq_domain_add_linear(intc, 32,
+                                           &or1k_irq_domain_ops, NULL);
+
+       set_handle_irq(or1k_pic_handle_irq);
+
+       return 0;
+}
+IRQCHIP_DECLARE(or1k_pic, "opencores,or1k-pic", or1k_irq_init);
-- 
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to