]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blobdiff - arch/x86/kernel/apic/io_apic.c
Merge branch 'for-ingo' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[mirror_ubuntu-kernels.git] / arch / x86 / kernel / apic / io_apic.c
index ffd8fdfcbe4c4392b64f43342d38d54676e1c9c9..3c8f9e75d0383a448f467e4d136d1067ab4c7047 100644 (file)
@@ -87,6 +87,9 @@ int nr_ioapic_registers[MAX_IO_APICS];
 struct mpc_ioapic mp_ioapics[MAX_IO_APICS];
 int nr_ioapics;
 
+/* IO APIC gsi routing info */
+struct mp_ioapic_gsi  mp_gsi_routing[MAX_IO_APICS];
+
 /* MP IRQ source entries */
 struct mpc_intsrc mp_irqs[MAX_IRQ_SOURCES];
 
@@ -490,7 +493,8 @@ static void ioapic_mask_entry(int apic, int pin)
  * shared ISA-space IRQs, so we have to support them. We are super
  * fast in the common case, and fast for shared ISA-space IRQs.
  */
-static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+static int
+add_pin_to_irq_node_nopanic(struct irq_cfg *cfg, int node, int apic, int pin)
 {
        struct irq_pin_list **last, *entry;
 
@@ -498,15 +502,27 @@ static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin
        last = &cfg->irq_2_pin;
        for_each_irq_pin(entry, cfg->irq_2_pin) {
                if (entry->apic == apic && entry->pin == pin)
-                       return;
+                       return 0;
                last = &entry->next;
        }
 
        entry = get_one_free_irq_2_pin(node);
+       if (!entry) {
+               printk(KERN_ERR "can not alloc irq_pin_list (%d,%d,%d)\n",
+                               node, apic, pin);
+               return -ENOMEM;
+       }
        entry->apic = apic;
        entry->pin = pin;
 
        *last = entry;
+       return 0;
+}
+
+static void add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
+{
+       if (add_pin_to_irq_node_nopanic(cfg, node, apic, pin))
+               panic("IO-APIC: failed to add irq-pin. Can not proceed\n");
 }
 
 /*
@@ -3723,6 +3739,9 @@ int arch_enable_uv_irq(char *irq_name, unsigned int irq, int cpu, int mmr_blade,
        mmr_pnode = uv_blade_to_pnode(mmr_blade);
        uv_write_global_mmr64(mmr_pnode, mmr_offset, mmr_value);
 
+       if (cfg->move_in_progress)
+               send_cleanup_vector(cfg);
+
        return irq;
 }
 
@@ -3839,7 +3858,11 @@ static int __io_apic_set_pci_routing(struct device *dev, int irq,
         */
        if (irq >= NR_IRQS_LEGACY) {
                cfg = desc->chip_data;
-               add_pin_to_irq_node(cfg, node, ioapic, pin);
+               if (add_pin_to_irq_node_nopanic(cfg, node, ioapic, pin)) {
+                       printk(KERN_INFO "can not add pin %d for irq %d\n",
+                               pin, irq);
+                       return 0;
+               }
        }
 
        setup_IO_APIC_irq(ioapic, pin, irq, desc, trigger, polarity);
@@ -3868,11 +3891,28 @@ int io_apic_set_pci_routing(struct device *dev, int irq,
        return __io_apic_set_pci_routing(dev, irq, irq_attr);
 }
 
-/* --------------------------------------------------------------------------
-                          ACPI-based IOAPIC Configuration
-   -------------------------------------------------------------------------- */
+u8 __init io_apic_unique_id(u8 id)
+{
+#ifdef CONFIG_X86_32
+       if ((boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
+           !APIC_XAPIC(apic_version[boot_cpu_physical_apicid]))
+               return io_apic_get_unique_id(nr_ioapics, id);
+       else
+               return id;
+#else
+       int i;
+       DECLARE_BITMAP(used, 256);
 
-#ifdef CONFIG_ACPI
+       bitmap_zero(used, 256);
+       for (i = 0; i < nr_ioapics; i++) {
+               struct mpc_ioapic *ia = &mp_ioapics[i];
+               __set_bit(ia->apicid, used);
+       }
+       if (!test_bit(id, used))
+               return id;
+       return find_first_zero_bit(used, 256);
+#endif
+}
 
 #ifdef CONFIG_X86_32
 int __init io_apic_get_unique_id(int ioapic, int apic_id)
@@ -3981,8 +4021,6 @@ int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity)
        return 0;
 }
 
-#endif /* CONFIG_ACPI */
-
 /*
  * This function currently is only a helper for the i386 smp boot process where
  * we need to reprogram the ioredtbls to cater for the cpus which have come online
@@ -4036,7 +4074,7 @@ void __init setup_ioapic_dest(void)
 
 static struct resource *ioapic_resources;
 
-static struct resource * __init ioapic_setup_resources(void)
+static struct resource * __init ioapic_setup_resources(int nr_ioapics)
 {
        unsigned long n;
        struct resource *res;
@@ -4052,15 +4090,13 @@ static struct resource * __init ioapic_setup_resources(void)
        mem = alloc_bootmem(n);
        res = (void *)mem;
 
-       if (mem != NULL) {
-               mem += sizeof(struct resource) * nr_ioapics;
+       mem += sizeof(struct resource) * nr_ioapics;
 
-               for (i = 0; i < nr_ioapics; i++) {
-                       res[i].name = mem;
-                       res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-                       sprintf(mem,  "IOAPIC %u", i);
-                       mem += IOAPIC_RESOURCE_NAME_SIZE;
-               }
+       for (i = 0; i < nr_ioapics; i++) {
+               res[i].name = mem;
+               res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+               sprintf(mem,  "IOAPIC %u", i);
+               mem += IOAPIC_RESOURCE_NAME_SIZE;
        }
 
        ioapic_resources = res;
@@ -4074,7 +4110,7 @@ void __init ioapic_init_mappings(void)
        struct resource *ioapic_res;
        int i;
 
-       ioapic_res = ioapic_setup_resources();
+       ioapic_res = ioapic_setup_resources(nr_ioapics);
        for (i = 0; i < nr_ioapics; i++) {
                if (smp_found_config) {
                        ioapic_phys = mp_ioapics[i].apicaddr;
@@ -4103,36 +4139,99 @@ fake_ioapic_page:
                            __fix_to_virt(idx), ioapic_phys);
                idx++;
 
-               if (ioapic_res != NULL) {
-                       ioapic_res->start = ioapic_phys;
-                       ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
-                       ioapic_res++;
-               }
+               ioapic_res->start = ioapic_phys;
+               ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
+               ioapic_res++;
        }
 }
 
-static int __init ioapic_insert_resources(void)
+void __init ioapic_insert_resources(void)
 {
        int i;
        struct resource *r = ioapic_resources;
 
        if (!r) {
-               if (nr_ioapics > 0) {
+               if (nr_ioapics > 0)
                        printk(KERN_ERR
                                "IO APIC resources couldn't be allocated.\n");
-                       return -1;
-               }
-               return 0;
+               return;
        }
 
        for (i = 0; i < nr_ioapics; i++) {
                insert_resource(&iomem_resource, r);
                r++;
        }
+}
+
+int mp_find_ioapic(int gsi)
+{
+       int i = 0;
+
+       /* Find the IOAPIC that manages this GSI. */
+       for (i = 0; i < nr_ioapics; i++) {
+               if ((gsi >= mp_gsi_routing[i].gsi_base)
+                   && (gsi <= mp_gsi_routing[i].gsi_end))
+                       return i;
+       }
+
+       printk(KERN_ERR "ERROR: Unable to locate IOAPIC for GSI %d\n", gsi);
+       return -1;
+}
+
+int mp_find_ioapic_pin(int ioapic, int gsi)
+{
+       if (WARN_ON(ioapic == -1))
+               return -1;
+       if (WARN_ON(gsi > mp_gsi_routing[ioapic].gsi_end))
+               return -1;
+
+       return gsi - mp_gsi_routing[ioapic].gsi_base;
+}
 
+static int bad_ioapic(unsigned long address)
+{
+       if (nr_ioapics >= MAX_IO_APICS) {
+               printk(KERN_WARNING "WARING: Max # of I/O APICs (%d) exceeded "
+                      "(found %d), skipping\n", MAX_IO_APICS, nr_ioapics);
+               return 1;
+       }
+       if (!address) {
+               printk(KERN_WARNING "WARNING: Bogus (zero) I/O APIC address"
+                      " found in table, skipping!\n");
+               return 1;
+       }
        return 0;
 }
 
-/* Insert the IO APIC resources after PCI initialization has occured to handle
- * IO APICS that are mapped in on a BAR in PCI space. */
-late_initcall(ioapic_insert_resources);
+void __init mp_register_ioapic(int id, u32 address, u32 gsi_base)
+{
+       int idx = 0;
+
+       if (bad_ioapic(address))
+               return;
+
+       idx = nr_ioapics;
+
+       mp_ioapics[idx].type = MP_IOAPIC;
+       mp_ioapics[idx].flags = MPC_APIC_USABLE;
+       mp_ioapics[idx].apicaddr = address;
+
+       set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
+       mp_ioapics[idx].apicid = io_apic_unique_id(id);
+       mp_ioapics[idx].apicver = io_apic_get_version(idx);
+
+       /*
+        * Build basic GSI lookup table to facilitate gsi->io_apic lookups
+        * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
+        */
+       mp_gsi_routing[idx].gsi_base = gsi_base;
+       mp_gsi_routing[idx].gsi_end = gsi_base +
+           io_apic_get_redir_entries(idx);
+
+       printk(KERN_INFO "IOAPIC[%d]: apic_id %d, version %d, address 0x%x, "
+              "GSI %d-%d\n", idx, mp_ioapics[idx].apicid,
+              mp_ioapics[idx].apicver, mp_ioapics[idx].apicaddr,
+              mp_gsi_routing[idx].gsi_base, mp_gsi_routing[idx].gsi_end);
+
+       nr_ioapics++;
+}