x86: ioapic: Add OF bindings for IO_APIC
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Tue, 22 Feb 2011 20:07:44 +0000 (21:07 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Wed, 23 Feb 2011 21:27:54 +0000 (22:27 +0100)
ioapic_xlate provides a translation from the information in device tree
to ioapic related informations. This includes
- obtaining hw irq which is the vector number "=> pin number + gsi"
- obtaining type (level/edge/..)
- programming this information into ioapic

ioapic_add_ofnode adds an irq_domain based on informations from the device
tree. This information (irq_domain) is required in order to map a device to
its proper interrupt controller.

[ tglx: Adapted to the io_apic changes, which let us move that whole code
   to devicetree.c ]

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Cc: sodaville@linutronix.de
Cc: devicetree-discuss@lists.ozlabs.org
LKML-Reference: <1298405266-1624-10-git-send-email-bigeasy@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
arch/x86/include/asm/prom.h
arch/x86/kernel/devicetree.c
arch/x86/kernel/irqinit.c

index 8fcd519a44dcfc953b6b544a63afd91fc874b9c6..ae50131ad76659c0e0961f851b48a54e6135533e 100644 (file)
@@ -27,6 +27,7 @@
 extern int of_ioapic;
 extern u64 initial_dtb;
 extern void add_dtb(u64 data);
+extern void x86_add_irq_domains(void);
 void x86_dtb_find_config(void);
 void x86_dtb_get_config(unsigned int unused);
 void add_interrupt_host(struct irq_domain *ih);
@@ -44,6 +45,7 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
 
 #else
 static inline void add_dtb(u64 data) { }
+static inline void x86_add_irq_domains(void) { }
 static inline void x86_of_pci_init(void) { }
 #define x86_dtb_find_config x86_init_noop
 #define x86_dtb_get_config x86_init_uint_noop
index 0bc83bfa4ead6fa222fd4a48f38c542ac1150f02..2d65897a39d03c62c3dc88da84cc219921788106 100644 (file)
@@ -320,3 +320,107 @@ void __init x86_dtb_get_config(unsigned int unused)
        dtb_setup_hpet();
        dtb_apic_setup();
 }
+
+#ifdef CONFIG_X86_IO_APIC
+
+struct of_ioapic_type {
+       u32 out_type;
+       u32 trigger;
+       u32 polarity;
+};
+
+static struct of_ioapic_type of_ioapic_type[] =
+{
+       {
+               .out_type       = IRQ_TYPE_EDGE_RISING,
+               .trigger        = IOAPIC_EDGE,
+               .polarity       = 1,
+       },
+       {
+               .out_type       = IRQ_TYPE_LEVEL_LOW,
+               .trigger        = IOAPIC_LEVEL,
+               .polarity       = 0,
+       },
+       {
+               .out_type       = IRQ_TYPE_LEVEL_HIGH,
+               .trigger        = IOAPIC_LEVEL,
+               .polarity       = 1,
+       },
+       {
+               .out_type       = IRQ_TYPE_EDGE_FALLING,
+               .trigger        = IOAPIC_EDGE,
+               .polarity       = 0,
+       },
+};
+
+static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
+                       u32 *out_hwirq, u32 *out_type)
+{
+       struct io_apic_irq_attr attr;
+       struct of_ioapic_type *it;
+       u32 line, idx, type;
+
+       if (intsize < 2)
+               return -EINVAL;
+
+       line = *intspec;
+       idx = (u32) id->priv;
+       *out_hwirq = line + mp_gsi_routing[idx].gsi_base;
+
+       intspec++;
+       type = *intspec;
+
+       if (type >= ARRAY_SIZE(of_ioapic_type))
+               return -EINVAL;
+
+       it = of_ioapic_type + type;
+       *out_type = it->out_type;
+
+       set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity);
+
+       return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr);
+}
+
+static void __init ioapic_add_ofnode(struct device_node *np)
+{
+       struct resource r;
+       int i, ret;
+
+       ret = of_address_to_resource(np, 0, &r);
+       if (ret) {
+               printk(KERN_ERR "Failed to obtain address for %s\n",
+                               np->full_name);
+               return;
+       }
+
+       for (i = 0; i < nr_ioapics; i++) {
+               if (r.start == mp_ioapics[i].apicaddr) {
+                       struct irq_domain *id;
+
+                       id = kzalloc(sizeof(*id), GFP_KERNEL);
+                       BUG_ON(!id);
+                       id->controller = np;
+                       id->xlate = ioapic_xlate;
+                       id->priv = (void *)i;
+                       add_interrupt_host(id);
+                       return;
+               }
+       }
+       printk(KERN_ERR "IOxAPIC at %s is not registered.\n", np->full_name);
+}
+
+void __init x86_add_irq_domains(void)
+{
+       struct device_node *dp;
+
+       if (!initial_boot_params)
+               return;
+
+       for_each_node_with_property(dp, "interrupt-controller") {
+               if (of_device_is_compatible(dp, "intel,ce4100-ioapic"))
+                       ioapic_add_ofnode(dp);
+       }
+}
+#else
+void __init x86_add_irq_domains(void) { }
+#endif
index 4cadf8688dbd013286ea6e1fd9f7166e28baa495..9f76f89f43a4248cb8d7511d195fa5678a6849cc 100644 (file)
@@ -118,6 +118,12 @@ void __init init_IRQ(void)
 {
        int i;
 
+       /*
+        * We probably need a better place for this, but it works for
+        * now ...
+        */
+       x86_add_irq_domains();
+
        /*
         * On cpu 0, Assign IRQ0_VECTOR..IRQ15_VECTOR's to IRQ 0..15.
         * If these IRQ's are handled by legacy interrupt-controllers like PIC,