On 01/28/2013 02:12 PM, Florian Fainelli wrote:
Le 28/01/2013 22:59, John Crispin a écrit :
From: Gabor Juhos <juhosg@xxxxxxxxxxx>
Adds an irqdomain wrapper for the cpu irq controller that can be
passed inside
the of_device_id to of_irq_init().
A device_node inside a dts file would look as such.
cpuintc: cpuintc@0 {
#address-cells = <0>;
#interrupt-cells = <1>;
interrupt-controller;
compatible = "mti,cpu-intc";
Is it necessary to use the word 'intc'? What does that mean? Perhaps
"mti,cpu-interrupt-controller"?
};
Please use this as an actual device tree documentation binding.
Yes, bindings should be documented in Documentation/devicetree/bindings/mips
Just to satisfy my curiosity, Which drivers are using (or will be using)
these mapping facilities? The timer and performance counters already
work, so it isn't needed for them. What will use this.
David Daney
Signed-off-by: Gabor Juhos <juhosg@xxxxxxxxxxx>
Signed-off-by: John Crispin <blogic@xxxxxxxxxxx>
---
arch/mips/include/asm/irq_cpu.h | 6 ++++++
arch/mips/kernel/irq_cpu.c | 42
+++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/arch/mips/include/asm/irq_cpu.h
b/arch/mips/include/asm/irq_cpu.h
index ef6a07c..3f11fdb 100644
--- a/arch/mips/include/asm/irq_cpu.h
+++ b/arch/mips/include/asm/irq_cpu.h
@@ -17,4 +17,10 @@ extern void mips_cpu_irq_init(void);
extern void rm7k_cpu_irq_init(void);
extern void rm9k_cpu_irq_init(void);
+#ifdef CONFIG_IRQ_DOMAIN
+struct device_node;
+extern int mips_cpu_intc_init(struct device_node *of_node,
+ struct device_node *parent);
+#endif
+
#endif /* _ASM_IRQ_CPU_H */
diff --git a/arch/mips/kernel/irq_cpu.c b/arch/mips/kernel/irq_cpu.c
index 972263b..49bc9ca 100644
--- a/arch/mips/kernel/irq_cpu.c
+++ b/arch/mips/kernel/irq_cpu.c
@@ -31,6 +31,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <asm/irq_cpu.h>
#include <asm/mipsregs.h>
@@ -113,3 +114,44 @@ void __init mips_cpu_irq_init(void)
irq_set_chip_and_handler(i, &mips_cpu_irq_controller,
handle_percpu_irq);
}
+
+#ifdef CONFIG_IRQ_DOMAIN
+static int mips_cpu_intc_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hw)
+{
+ static struct irq_chip *chip;
+
+ if (hw < 2 && cpu_has_mipsmt) {
+ /* Software interrupts are used for MT/CMT IPI */
+ chip = &mips_mt_cpu_irq_controller;
+ } else {
+ chip = &mips_cpu_irq_controller;
+ }
+
+ irq_set_chip_and_handler(irq, chip, handle_percpu_irq);
+
+ return 0;
+}
+
+static const struct irq_domain_ops mips_cpu_intc_irq_domain_ops = {
+ .map = mips_cpu_intc_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+int __init mips_cpu_intc_init(struct device_node *of_node,
+ struct device_node *parent)
+{
+ struct irq_domain *domain;
+
+ /* Mask interrupts. */
+ clear_c0_status(ST0_IM);
+ clear_c0_cause(CAUSEF_IP);
+
+ domain = irq_domain_add_legacy(of_node, 8, MIPS_CPU_IRQ_BASE, 0,
+ &mips_cpu_intc_irq_domain_ops, NULL);
+ if (!domain)
+ panic("Failed to add irqdomain for MIPS CPU\n");
+
+ return 0;
+}
+#endif /* CONFIG_IRQ_DOMAIN */