Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / arch / x86 / kernel / acpi / boot.c
index 9965afb..b436fc7 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/dmi.h>
 #include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/slab.h>
 #include <linux/bootmem.h>
 #include <linux/ioport.h>
@@ -75,10 +76,6 @@ int acpi_fix_pin2_polarity __initdata;
 static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 #endif
 
-#ifndef __HAVE_ARCH_CMPXCHG
-#warning ACPI uses CMPXCHG, i486 and later hardware
-#endif
-
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
@@ -100,17 +97,6 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = {
 
 #define        ACPI_INVALID_GSI                INT_MIN
 
-static int map_gsi_to_irq(unsigned int gsi)
-{
-       int i;
-
-       for (i = 0; i < nr_legacy_irqs(); i++)
-               if (isa_irq_to_gsi[i] == gsi)
-                       return i;
-
-       return mp_map_gsi_to_irq(gsi);
-}
-
 /*
  * This is just a simple wrapper around early_ioremap(),
  * with sanity checks for phys == 0 and size == 0.
@@ -404,11 +390,7 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
 static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
                           int polarity)
 {
-       int irq;
-       int ioapic;
-       int ioapic_pin;
-       struct io_apic_irq_attr irq_attr;
-       int ret;
+       int irq, node;
 
        if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
                return gsi;
@@ -417,43 +399,52 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
        if (acpi_gbl_FADT.sci_interrupt == gsi)
                return gsi;
 
-       irq = map_gsi_to_irq(gsi);
-       if (irq < 0)
-               return ACPI_INVALID_GSI;
-
-       ioapic = mp_find_ioapic(gsi);
-       if (ioapic < 0) {
-               printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
-               return gsi;
+       trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1;
+       polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1;
+       node = dev ? dev_to_node(dev) : NUMA_NO_NODE;
+       if (mp_set_gsi_attr(gsi, trigger, polarity, node)) {
+               pr_warn("Failed to set pin attr for GSI%d\n", gsi);
+               return -1;
        }
 
-       ioapic_pin = mp_find_ioapic_pin(ioapic, gsi);
-
-       if (ioapic_pin > MP_MAX_IOAPIC_PIN) {
-               printk(KERN_ERR "Invalid reference to IOAPIC pin "
-                      "%d-%d\n", mpc_ioapic_id(ioapic),
-                      ioapic_pin);
-               return gsi;
-       }
+       irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC);
+       if (irq < 0)
+               return irq;
 
        if (enable_update_mptable)
                mp_config_acpi_gsi(dev, gsi, trigger, polarity);
 
-       set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
-                            trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
-                            polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
-       ret = io_apic_set_pci_routing(dev, irq, &irq_attr);
-       if (ret < 0)
-               gsi = ACPI_INVALID_GSI;
+       return irq;
+}
 
-       return gsi;
+static void mp_unregister_gsi(u32 gsi)
+{
+       int irq;
+
+       if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
+               return;
+
+       if (acpi_gbl_FADT.sci_interrupt == gsi)
+               return;
+
+       irq = mp_map_gsi_to_irq(gsi, 0);
+       if (irq > 0)
+               mp_unmap_irq(irq);
 }
 
+static struct irq_domain_ops acpi_irqdomain_ops = {
+       .map = mp_irqdomain_map,
+       .unmap = mp_irqdomain_unmap,
+};
 
 static int __init
 acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
 {
        struct acpi_madt_io_apic *ioapic = NULL;
+       struct ioapic_domain_cfg cfg = {
+               .type = IOAPIC_DOMAIN_DYNAMIC,
+               .ops = &acpi_irqdomain_ops,
+       };
 
        ioapic = (struct acpi_madt_io_apic *)header;
 
@@ -462,8 +453,12 @@ acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
 
        acpi_table_print_madt_entry(header);
 
-       mp_register_ioapic(ioapic->id,
-                          ioapic->address, ioapic->global_irq_base);
+       /* Statically assign IRQ numbers for IOAPICs hosting legacy IRQs */
+       if (ioapic->global_irq_base < nr_legacy_irqs())
+               cfg.type = IOAPIC_DOMAIN_LEGACY;
+
+       mp_register_ioapic(ioapic->id, ioapic->address, ioapic->global_irq_base,
+                          &cfg);
 
        return 0;
 }
@@ -609,13 +604,9 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
 
 int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
 {
-       int irq = map_gsi_to_irq(gsi);
+       int irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
 
        if (irq >= 0) {
-#ifdef CONFIG_X86_IO_APIC
-               if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
-                       setup_IO_APIC_irq_extra(gsi);
-#endif
                *irqp = irq;
                return 0;
        }
@@ -652,15 +643,25 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
 static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi,
                                    int trigger, int polarity)
 {
+       int irq = gsi;
+
 #ifdef CONFIG_X86_IO_APIC
-       gsi = mp_register_gsi(dev, gsi, trigger, polarity);
+       irq = mp_register_gsi(dev, gsi, trigger, polarity);
 #endif
 
-       return gsi;
+       return irq;
+}
+
+static void acpi_unregister_gsi_ioapic(u32 gsi)
+{
+#ifdef CONFIG_X86_IO_APIC
+       mp_unregister_gsi(gsi);
+#endif
 }
 
 int (*__acpi_register_gsi)(struct device *dev, u32 gsi,
                           int trigger, int polarity) = acpi_register_gsi_pic;
+void (*__acpi_unregister_gsi)(u32 gsi) = NULL;
 
 #ifdef CONFIG_ACPI_SLEEP
 int (*acpi_suspend_lowlevel)(void) = x86_acpi_suspend_lowlevel;
@@ -674,18 +675,14 @@ int (*acpi_suspend_lowlevel)(void);
  */
 int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
 {
-       unsigned int plat_gsi;
-
-       plat_gsi = __acpi_register_gsi(dev, gsi, trigger, polarity);
-       if (plat_gsi != ACPI_INVALID_GSI)
-               return map_gsi_to_irq(plat_gsi);
-
-       return -1;
+       return __acpi_register_gsi(dev, gsi, trigger, polarity);
 }
 EXPORT_SYMBOL_GPL(acpi_register_gsi);
 
 void acpi_unregister_gsi(u32 gsi)
 {
+       if (__acpi_unregister_gsi)
+               __acpi_unregister_gsi(gsi);
 }
 EXPORT_SYMBOL_GPL(acpi_unregister_gsi);
 
@@ -693,6 +690,7 @@ static void __init acpi_set_irq_model_ioapic(void)
 {
        acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC;
        __acpi_register_gsi = acpi_register_gsi_ioapic;
+       __acpi_unregister_gsi = acpi_unregister_gsi_ioapic;
        acpi_ioapic = 1;
 }