lkml.org 
[lkml]   [2011]   [Feb]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 09/11] x86/ioapic: Add OF bindings for IO-APIC
    Date
    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.

    Cc: devicetree-discuss@lists.ozlabs.org
    Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
    ---
    arch/x86/include/asm/io_apic.h | 7 +++
    arch/x86/include/asm/prom.h | 2 +
    arch/x86/kernel/apic/io_apic.c | 99 ++++++++++++++++++++++++++++++++++++++++
    arch/x86/kernel/devicetree.c | 13 +++++
    arch/x86/kernel/irqinit.c | 6 ++
    5 files changed, 127 insertions(+), 0 deletions(-)

    diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h
    index f327d38..fe88a73 100644
    --- a/arch/x86/include/asm/io_apic.h
    +++ b/arch/x86/include/asm/io_apic.h
    @@ -177,6 +177,13 @@ struct mp_ioapic_gsi{
    u32 gsi_base;
    u32 gsi_end;
    };
    +#ifdef CONFIG_OF
    +struct mp_of_ioapic {
    + struct device_node *node;
    +};
    +extern struct mp_of_ioapic mp_of_ioapic[MAX_IO_APICS];
    +void __init ioapic_add_ofnode(struct device_node *np);
    +#endif
    extern struct mp_ioapic_gsi mp_gsi_routing[];
    extern u32 gsi_top;
    int mp_find_ioapic(u32 gsi);
    diff --git a/arch/x86/include/asm/prom.h b/arch/x86/include/asm/prom.h
    index 3e441b3..98b9a73 100644
    --- a/arch/x86/include/asm/prom.h
    +++ b/arch/x86/include/asm/prom.h
    @@ -26,6 +26,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);
    @@ -43,6 +44,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
    diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
    index ca9e2a3..c172452 100644
    --- a/arch/x86/kernel/apic/io_apic.c
    +++ b/arch/x86/kernel/apic/io_apic.c
    @@ -43,6 +43,7 @@
    #include <linux/bootmem.h>
    #include <linux/dmar.h>
    #include <linux/hpet.h>
    +#include <linux/of_address.h>

    #include <asm/idle.h>
    #include <asm/io.h>
    @@ -60,6 +61,7 @@
    #include <asm/irq_remapping.h>
    #include <asm/hpet.h>
    #include <asm/hw_irq.h>
    +#include <asm/irq_controller.h>

    #include <asm/apic.h>

    @@ -88,6 +90,10 @@ int nr_ioapics;
    /* IO APIC gsi routing info */
    struct mp_ioapic_gsi mp_gsi_routing[MAX_IO_APICS];

    +#ifdef CONFIG_OF
    +/* OF -> IO APIC lookup */
    +struct mp_of_ioapic mp_of_ioapic[MAX_IO_APICS];
    +#endif
    /* The one past the highest gsi number used */
    u32 gsi_top;

    @@ -4083,6 +4089,99 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
    nr_ioapics++;
    }

    +#ifdef CONFIG_OF
    +static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize,
    + u32 *out_hwirq, u32 *out_type)
    +{
    + u32 line;
    + u32 idx;
    + u32 type;
    + u32 trigger;
    + u32 polarity;
    + struct irq_cfg *cfg;
    + struct irq_desc *desc;
    +
    + if (intsize < 1)
    + return -EINVAL;
    +
    + line = *intspec;
    + idx = (u32) id->priv;
    + *out_hwirq = line + mp_gsi_routing[idx].gsi_base;
    + if (intsize > 1) {
    + intspec++;
    + type = *intspec;
    + switch (type) {
    + case 0:
    + *out_type = IRQ_TYPE_EDGE_RISING;
    + trigger = IOAPIC_EDGE;
    + polarity = 1;
    + break;
    + case 1:
    + *out_type = IRQ_TYPE_LEVEL_LOW;
    + trigger = IOAPIC_LEVEL;
    + polarity = 0;
    + break;
    + case 2:
    + *out_type = IRQ_TYPE_LEVEL_HIGH;
    + trigger = IOAPIC_LEVEL;
    + polarity = 1;
    + break;
    + case 3:
    + *out_type = IRQ_TYPE_EDGE_FALLING;
    + trigger = IOAPIC_EDGE;
    + polarity = 0;
    + break;
    + default:
    + *out_type = IRQ_TYPE_NONE;
    + trigger = IOAPIC_AUTO;
    + polarity = 0;
    + break;
    + };
    + } else {
    + *out_type = IRQ_TYPE_NONE;
    + trigger = IOAPIC_AUTO;
    + polarity = 0;
    + }
    + /* And now tell the IO APIC to make the line ready */
    + desc = irq_to_desc_alloc_node(*out_hwirq, 0);
    + cfg = irq_cfg(*out_hwirq);
    + add_pin_to_irq_node(cfg, 0, idx, line);
    + /* make it edge by default, settype will update it */
    + setup_ioapic_irq(idx, line, *out_hwirq, cfg, trigger, polarity);
    + return 0;
    +}
    +
    +void __init ioapic_add_ofnode(struct device_node *np)
    +{
    + int i;
    + int ret;
    + struct resource r;
    +
    + 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;
    +
    + mp_of_ioapic[i].node = np;
    + 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);
    +}
    +#endif
    +
    /* Enable IOAPIC early just for system timer */
    void __init pre_init_apic_IRQ0(void)
    {
    diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c
    index 179833f..62d0072 100644
    --- a/arch/x86/kernel/devicetree.c
    +++ b/arch/x86/kernel/devicetree.c
    @@ -322,3 +322,16 @@ void __init x86_dtb_get_config(unsigned int unused)
    dtb_setup_hpet();
    dtb_apic_setup();
    }
    +
    +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);
    + }
    +}
    diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
    index 4cadf86..9f76f89 100644
    --- a/arch/x86/kernel/irqinit.c
    +++ b/arch/x86/kernel/irqinit.c
    @@ -119,6 +119,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,
    * then this configuration will likely be static after the boot. If
    --
    1.7.4


    \
     
     \ /
      Last update: 2011-02-22 21:11    [W:0.030 / U:2.160 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site