x86: ioapic: Add OF bindings for IO_APIC

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>
This commit is contained in:
Sebastian Andrzej Siewior 2011-02-22 21:07:44 +01:00 committed by Thomas Gleixner
parent 9079b35364
commit bcc7c1244f
3 changed files with 112 additions and 0 deletions

View 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

View 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

View 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,