diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2011-02-22 15:07:44 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2011-02-23 16:27:54 -0500 |
commit | bcc7c1244fcfd852b9f4590935491057e1cab9dd (patch) | |
tree | 4b68fc51466e8b42f343d6f26db0f1200d595c50 /arch/x86/kernel/devicetree.c | |
parent | 9079b35364e75ce6b968a179f861d2f819f33e61 (diff) |
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>
Diffstat (limited to 'arch/x86/kernel/devicetree.c')
-rw-r--r-- | arch/x86/kernel/devicetree.c | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 0bc83bfa4ead..2d65897a39d0 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c | |||
@@ -320,3 +320,107 @@ void __init x86_dtb_get_config(unsigned int unused) | |||
320 | dtb_setup_hpet(); | 320 | dtb_setup_hpet(); |
321 | dtb_apic_setup(); | 321 | dtb_apic_setup(); |
322 | } | 322 | } |
323 | |||
324 | #ifdef CONFIG_X86_IO_APIC | ||
325 | |||
326 | struct of_ioapic_type { | ||
327 | u32 out_type; | ||
328 | u32 trigger; | ||
329 | u32 polarity; | ||
330 | }; | ||
331 | |||
332 | static struct of_ioapic_type of_ioapic_type[] = | ||
333 | { | ||
334 | { | ||
335 | .out_type = IRQ_TYPE_EDGE_RISING, | ||
336 | .trigger = IOAPIC_EDGE, | ||
337 | .polarity = 1, | ||
338 | }, | ||
339 | { | ||
340 | .out_type = IRQ_TYPE_LEVEL_LOW, | ||
341 | .trigger = IOAPIC_LEVEL, | ||
342 | .polarity = 0, | ||
343 | }, | ||
344 | { | ||
345 | .out_type = IRQ_TYPE_LEVEL_HIGH, | ||
346 | .trigger = IOAPIC_LEVEL, | ||
347 | .polarity = 1, | ||
348 | }, | ||
349 | { | ||
350 | .out_type = IRQ_TYPE_EDGE_FALLING, | ||
351 | .trigger = IOAPIC_EDGE, | ||
352 | .polarity = 0, | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static int ioapic_xlate(struct irq_domain *id, const u32 *intspec, u32 intsize, | ||
357 | u32 *out_hwirq, u32 *out_type) | ||
358 | { | ||
359 | struct io_apic_irq_attr attr; | ||
360 | struct of_ioapic_type *it; | ||
361 | u32 line, idx, type; | ||
362 | |||
363 | if (intsize < 2) | ||
364 | return -EINVAL; | ||
365 | |||
366 | line = *intspec; | ||
367 | idx = (u32) id->priv; | ||
368 | *out_hwirq = line + mp_gsi_routing[idx].gsi_base; | ||
369 | |||
370 | intspec++; | ||
371 | type = *intspec; | ||
372 | |||
373 | if (type >= ARRAY_SIZE(of_ioapic_type)) | ||
374 | return -EINVAL; | ||
375 | |||
376 | it = of_ioapic_type + type; | ||
377 | *out_type = it->out_type; | ||
378 | |||
379 | set_io_apic_irq_attr(&attr, idx, line, it->trigger, it->polarity); | ||
380 | |||
381 | return io_apic_setup_irq_pin(*out_hwirq, cpu_to_node(0), &attr); | ||
382 | } | ||
383 | |||
384 | static void __init ioapic_add_ofnode(struct device_node *np) | ||
385 | { | ||
386 | struct resource r; | ||
387 | int i, ret; | ||
388 | |||
389 | ret = of_address_to_resource(np, 0, &r); | ||
390 | if (ret) { | ||
391 | printk(KERN_ERR "Failed to obtain address for %s\n", | ||
392 | np->full_name); | ||
393 | return; | ||
394 | } | ||
395 | |||
396 | for (i = 0; i < nr_ioapics; i++) { | ||
397 | if (r.start == mp_ioapics[i].apicaddr) { | ||
398 | struct irq_domain *id; | ||
399 | |||
400 | id = kzalloc(sizeof(*id), GFP_KERNEL); | ||
401 | BUG_ON(!id); | ||
402 | id->controller = np; | ||
403 | id->xlate = ioapic_xlate; | ||
404 | id->priv = (void *)i; | ||
405 | add_interrupt_host(id); | ||
406 | return; | ||
407 | } | ||
408 | } | ||
409 | printk(KERN_ERR "IOxAPIC at %s is not registered.\n", np->full_name); | ||
410 | } | ||
411 | |||
412 | void __init x86_add_irq_domains(void) | ||
413 | { | ||
414 | struct device_node *dp; | ||
415 | |||
416 | if (!initial_boot_params) | ||
417 | return; | ||
418 | |||
419 | for_each_node_with_property(dp, "interrupt-controller") { | ||
420 | if (of_device_is_compatible(dp, "intel,ce4100-ioapic")) | ||
421 | ioapic_add_ofnode(dp); | ||
422 | } | ||
423 | } | ||
424 | #else | ||
425 | void __init x86_add_irq_domains(void) { } | ||
426 | #endif | ||