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 a531f65..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>
@@ -43,6 +44,7 @@
 #include <asm/io.h>
 #include <asm/mpspec.h>
 #include <asm/smp.h>
+#include <asm/i8259.h>
 
 #include "sleep.h" /* To include x86_acpi_suspend_lowlevel */
 static int __initdata acpi_force = 0;
@@ -93,44 +95,7 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = {
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
 };
 
-static unsigned int gsi_to_irq(unsigned int gsi)
-{
-       unsigned int irq = gsi + NR_IRQS_LEGACY;
-       unsigned int i;
-
-       for (i = 0; i < NR_IRQS_LEGACY; i++) {
-               if (isa_irq_to_gsi[i] == gsi) {
-                       return i;
-               }
-       }
-
-       /* Provide an identity mapping of gsi == irq
-        * except on truly weird platforms that have
-        * non isa irqs in the first 16 gsis.
-        */
-       if (gsi >= NR_IRQS_LEGACY)
-               irq = gsi;
-       else
-               irq = gsi_top + gsi;
-
-       return irq;
-}
-
-static u32 irq_to_gsi(int irq)
-{
-       unsigned int gsi;
-
-       if (irq < NR_IRQS_LEGACY)
-               gsi = isa_irq_to_gsi[irq];
-       else if (irq < gsi_top)
-               gsi = irq;
-       else if (irq < (gsi_top + NR_IRQS_LEGACY))
-               gsi = irq - gsi_top;
-       else
-               gsi = 0xffffffff;
-
-       return gsi;
-}
+#define        ACPI_INVALID_GSI                INT_MIN
 
 /*
  * This is just a simple wrapper around early_ioremap(),
@@ -341,11 +306,145 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e
 #endif                         /*CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_IO_APIC
+#define MP_ISA_BUS             0
+
+static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger,
+                                         u32 gsi)
+{
+       int ioapic;
+       int pin;
+       struct mpc_intsrc mp_irq;
+
+       /*
+        * Convert 'gsi' to 'ioapic.pin'.
+        */
+       ioapic = mp_find_ioapic(gsi);
+       if (ioapic < 0)
+               return;
+       pin = mp_find_ioapic_pin(ioapic, gsi);
+
+       /*
+        * TBD: This check is for faulty timer entries, where the override
+        *      erroneously sets the trigger to level, resulting in a HUGE
+        *      increase of timer interrupts!
+        */
+       if ((bus_irq == 0) && (trigger == 3))
+               trigger = 1;
+
+       mp_irq.type = MP_INTSRC;
+       mp_irq.irqtype = mp_INT;
+       mp_irq.irqflag = (trigger << 2) | polarity;
+       mp_irq.srcbus = MP_ISA_BUS;
+       mp_irq.srcbusirq = bus_irq;     /* IRQ */
+       mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
+       mp_irq.dstirq = pin;    /* INTIN# */
+
+       mp_save_irq(&mp_irq);
+
+       /*
+        * Reset default identity mapping if gsi is also an legacy IRQ,
+        * otherwise there will be more than one entry with the same GSI
+        * and acpi_isa_irq_to_gsi() may give wrong result.
+        */
+       if (gsi < nr_legacy_irqs() && isa_irq_to_gsi[gsi] == gsi)
+               isa_irq_to_gsi[gsi] = ACPI_INVALID_GSI;
+       isa_irq_to_gsi[bus_irq] = gsi;
+}
+
+static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
+                       int polarity)
+{
+#ifdef CONFIG_X86_MPPARSE
+       struct mpc_intsrc mp_irq;
+       struct pci_dev *pdev;
+       unsigned char number;
+       unsigned int devfn;
+       int ioapic;
+       u8 pin;
+
+       if (!acpi_ioapic)
+               return 0;
+       if (!dev || !dev_is_pci(dev))
+               return 0;
+
+       pdev = to_pci_dev(dev);
+       number = pdev->bus->number;
+       devfn = pdev->devfn;
+       pin = pdev->pin;
+       /* print the entry should happen on mptable identically */
+       mp_irq.type = MP_INTSRC;
+       mp_irq.irqtype = mp_INT;
+       mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
+                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
+       mp_irq.srcbus = number;
+       mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
+       ioapic = mp_find_ioapic(gsi);
+       mp_irq.dstapic = mpc_ioapic_id(ioapic);
+       mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);
+
+       mp_save_irq(&mp_irq);
+#endif
+       return 0;
+}
+
+static int mp_register_gsi(struct device *dev, u32 gsi, int trigger,
+                          int polarity)
+{
+       int irq, node;
+
+       if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
+               return gsi;
+
+       /* Don't set up the ACPI SCI because it's already set up */
+       if (acpi_gbl_FADT.sci_interrupt == 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;
+       }
+
+       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);
+
+       return irq;
+}
+
+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;
 
@@ -354,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;
 }
@@ -378,11 +481,6 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger,
        if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
                polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
 
-       /*
-        * mp_config_acpi_legacy_irqs() already setup IRQs < 16
-        * If GSI is < 16, this will update its flags,
-        * else it will create a new mp_irqs[] entry.
-        */
        mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
 
        /*
@@ -504,25 +602,28 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
        outb(new >> 8, 0x4d1);
 }
 
-int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
+int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp)
 {
-       *irq = gsi_to_irq(gsi);
+       int irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK);
 
-#ifdef CONFIG_X86_IO_APIC
-       if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
-               setup_IO_APIC_irq_extra(gsi);
-#endif
+       if (irq >= 0) {
+               *irqp = irq;
+               return 0;
+       }
 
-       return 0;
+       return -1;
 }
 EXPORT_SYMBOL_GPL(acpi_gsi_to_irq);
 
 int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
 {
-       if (isa_irq >= 16)
-               return -1;
-       *gsi = irq_to_gsi(isa_irq);
-       return 0;
+       if (isa_irq < nr_legacy_irqs() &&
+           isa_irq_to_gsi[isa_irq] != ACPI_INVALID_GSI) {
+               *gsi = isa_irq_to_gsi[isa_irq];
+               return 0;
+       }
+
+       return -1;
 }
 
 static int acpi_register_gsi_pic(struct device *dev, u32 gsi,
@@ -542,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;
@@ -564,32 +675,22 @@ int (*acpi_suspend_lowlevel)(void);
  */
 int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
 {
-       unsigned int irq;
-       unsigned int plat_gsi = gsi;
-
-       plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity);
-       irq = gsi_to_irq(plat_gsi);
-
-       return irq;
+       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);
 
-void __init acpi_set_irq_model_pic(void)
-{
-       acpi_irq_model = ACPI_IRQ_MODEL_PIC;
-       __acpi_register_gsi = acpi_register_gsi_pic;
-       acpi_ioapic = 0;
-}
-
-void __init acpi_set_irq_model_ioapic(void)
+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;
 }
 
@@ -825,9 +926,8 @@ static int __init early_acpi_parse_madt_lapic_addr_ovr(void)
         * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
         */
 
-       count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
-                                 acpi_parse_lapic_addr_ovr, 0);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
+                                     acpi_parse_lapic_addr_ovr, 0);
        if (count < 0) {
                printk(KERN_ERR PREFIX
                       "Error parsing LAPIC address override entry\n");
@@ -852,9 +952,8 @@ static int __init acpi_parse_madt_lapic_entries(void)
         * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
         */
 
-       count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
-                                 acpi_parse_lapic_addr_ovr, 0);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
+                                     acpi_parse_lapic_addr_ovr, 0);
        if (count < 0) {
                printk(KERN_ERR PREFIX
                       "Error parsing LAPIC address override entry\n");
@@ -882,11 +981,10 @@ static int __init acpi_parse_madt_lapic_entries(void)
                return count;
        }
 
-       x2count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI,
-                                 acpi_parse_x2apic_nmi, 0);
-       count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
+       x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI,
+                                       acpi_parse_x2apic_nmi, 0);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI,
+                                     acpi_parse_lapic_nmi, 0);
        if (count < 0 || x2count < 0) {
                printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
                /* TBD: Cleanup to allow fallback to MPS */
@@ -897,44 +995,7 @@ static int __init acpi_parse_madt_lapic_entries(void)
 #endif                         /* CONFIG_X86_LOCAL_APIC */
 
 #ifdef CONFIG_X86_IO_APIC
-#define MP_ISA_BUS             0
-
-void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
-{
-       int ioapic;
-       int pin;
-       struct mpc_intsrc mp_irq;
-
-       /*
-        * Convert 'gsi' to 'ioapic.pin'.
-        */
-       ioapic = mp_find_ioapic(gsi);
-       if (ioapic < 0)
-               return;
-       pin = mp_find_ioapic_pin(ioapic, gsi);
-
-       /*
-        * TBD: This check is for faulty timer entries, where the override
-        *      erroneously sets the trigger to level, resulting in a HUGE
-        *      increase of timer interrupts!
-        */
-       if ((bus_irq == 0) && (trigger == 3))
-               trigger = 1;
-
-       mp_irq.type = MP_INTSRC;
-       mp_irq.irqtype = mp_INT;
-       mp_irq.irqflag = (trigger << 2) | polarity;
-       mp_irq.srcbus = MP_ISA_BUS;
-       mp_irq.srcbusirq = bus_irq;     /* IRQ */
-       mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */
-       mp_irq.dstirq = pin;    /* INTIN# */
-
-       mp_save_irq(&mp_irq);
-
-       isa_irq_to_gsi[bus_irq] = gsi;
-}
-
-void __init mp_config_acpi_legacy_irqs(void)
+static void __init mp_config_acpi_legacy_irqs(void)
 {
        int i;
        struct mpc_intsrc mp_irq;
@@ -952,7 +1013,7 @@ void __init mp_config_acpi_legacy_irqs(void)
         * Use the default configuration for the IRQs 0-15.  Unless
         * overridden by (MADT) interrupt source override entries.
         */
-       for (i = 0; i < 16; i++) {
+       for (i = 0; i < nr_legacy_irqs(); i++) {
                int ioapic, pin;
                unsigned int dstapic;
                int idx;
@@ -1000,84 +1061,6 @@ void __init mp_config_acpi_legacy_irqs(void)
        }
 }
 
-static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger,
-                       int polarity)
-{
-#ifdef CONFIG_X86_MPPARSE
-       struct mpc_intsrc mp_irq;
-       struct pci_dev *pdev;
-       unsigned char number;
-       unsigned int devfn;
-       int ioapic;
-       u8 pin;
-
-       if (!acpi_ioapic)
-               return 0;
-       if (!dev || !dev_is_pci(dev))
-               return 0;
-
-       pdev = to_pci_dev(dev);
-       number = pdev->bus->number;
-       devfn = pdev->devfn;
-       pin = pdev->pin;
-       /* print the entry should happen on mptable identically */
-       mp_irq.type = MP_INTSRC;
-       mp_irq.irqtype = mp_INT;
-       mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) |
-                               (polarity == ACPI_ACTIVE_HIGH ? 1 : 3);
-       mp_irq.srcbus = number;
-       mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3);
-       ioapic = mp_find_ioapic(gsi);
-       mp_irq.dstapic = mpc_ioapic_id(ioapic);
-       mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi);
-
-       mp_save_irq(&mp_irq);
-#endif
-       return 0;
-}
-
-int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
-{
-       int ioapic;
-       int ioapic_pin;
-       struct io_apic_irq_attr irq_attr;
-       int ret;
-
-       if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
-               return gsi;
-
-       /* Don't set up the ACPI SCI because it's already set up */
-       if (acpi_gbl_FADT.sci_interrupt == gsi)
-               return gsi;
-
-       ioapic = mp_find_ioapic(gsi);
-       if (ioapic < 0) {
-               printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi);
-               return gsi;
-       }
-
-       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;
-       }
-
-       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, gsi_to_irq(gsi), &irq_attr);
-       if (ret < 0)
-               gsi = INT_MIN;
-
-       return gsi;
-}
-
 /*
  * Parse IOAPIC related entries in MADT
  * returns 0 on success, < 0 on error
@@ -1107,9 +1090,8 @@ static int __init acpi_parse_madt_ioapic_entries(void)
                return -ENODEV;
        }
 
-       count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
-                                 MAX_IO_APICS);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
+                                     MAX_IO_APICS);
        if (!count) {
                printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
                return -ENODEV;
@@ -1118,9 +1100,8 @@ static int __init acpi_parse_madt_ioapic_entries(void)
                return count;
        }
 
-       count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
-                                 nr_irqs);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE,
+                                     acpi_parse_int_src_ovr, nr_irqs);
        if (count < 0) {
                printk(KERN_ERR PREFIX
                       "Error parsing interrupt source overrides entry\n");
@@ -1139,9 +1120,8 @@ static int __init acpi_parse_madt_ioapic_entries(void)
        /* Fill in identity legacy mappings where no override */
        mp_config_acpi_legacy_irqs();
 
-       count =
-           acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
-                                 nr_irqs);
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE,
+                                     acpi_parse_nmi_src, nr_irqs);
        if (count < 0) {
                printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
                /* TBD: Cleanup to allow fallback to MPS */