Merge branch 'for-ingo' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
authorIngo Molnar <mingo@elte.hu>
Sat, 29 Aug 2009 07:30:41 +0000 (09:30 +0200)
committerIngo Molnar <mingo@elte.hu>
Sat, 29 Aug 2009 07:31:47 +0000 (09:31 +0200)
Merge reason: the SFI (Simple Firmware Interface) feature in the ACPI
              tree needs this cleanup, pull it into the APIC branch as
      well so that there's no interactions.

Signed-off-by: Ingo Molnar <mingo@elte.hu>
1  2 
arch/x86/kernel/acpi/boot.c
arch/x86/kernel/apic/es7000_32.c
arch/x86/kernel/apic/io_apic.c

index ce31c1af854f2a5a68f2eb7f2477ca2e01873776,7e62d1eb8e3035bb5d82c6c2f59371971446f1cf..67e929b89875bea8c06c5b8c454a43332862eb46
@@@ -833,106 -833,6 +833,6 @@@ static int __init acpi_parse_madt_lapic
  extern int es7000_plat;
  #endif
  
- static struct {
-       int gsi_base;
-       int gsi_end;
- } mp_ioapic_routing[MAX_IO_APICS];
- 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_ioapic_routing[i].gsi_base)
-                   && (gsi <= mp_ioapic_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_ioapic_routing[ioapic].gsi_end))
-               return -1;
-       return gsi - mp_ioapic_routing[ioapic].gsi_base;
- }
- static u8 __init uniq_ioapic_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);
-       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
- }
- static int bad_ioapic(unsigned long address)
- {
-       if (nr_ioapics >= MAX_IO_APICS) {
-               printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
-                      "(found %d)\n", MAX_IO_APICS, nr_ioapics);
-               panic("Recompile kernel with bigger MAX_IO_APICS!\n");
-       }
-       if (!address) {
-               printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
-                      " found in table, skipping!\n");
-               return 1;
-       }
-       return 0;
- }
- 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 = uniq_ioapic_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_ioapic_routing[idx].gsi_base = gsi_base;
-       mp_ioapic_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_ioapic_routing[idx].gsi_base, mp_ioapic_routing[idx].gsi_end);
-       nr_ioapics++;
- }
  int __init acpi_probe_gsi(void)
  {
        int idx;
  
        max_gsi = 0;
        for (idx = 0; idx < nr_ioapics; idx++) {
-               gsi = mp_ioapic_routing[idx].gsi_end;
+               gsi = mp_gsi_routing[idx].gsi_end;
  
                if (gsi > max_gsi)
                        max_gsi = gsi;
@@@ -1179,8 -1079,9 +1079,8 @@@ static int __init acpi_parse_madt_ioapi
         * If MPS is present, it will handle them,
         * otherwise the system will stay in PIC mode
         */
 -      if (acpi_disabled || acpi_noirq) {
 +      if (acpi_disabled || acpi_noirq)
                return -ENODEV;
 -      }
  
        if (!cpu_has_apic)
                return -ENODEV;
index 420f95da7bf6e4a931a30e7556e5243fa2ea0013,8952a5890281cc363094cc2f67fed1159e6d7674..89174f847b49effb88961e01c6e526f3809ae690
@@@ -167,7 -167,7 +167,7 @@@ static int es7000_apic_is_cluster(void
  {
        /* MPENTIUMIII */
        if (boot_cpu_data.x86 == 6 &&
 -          (boot_cpu_data.x86_model >= 7 || boot_cpu_data.x86_model <= 11))
 +          (boot_cpu_data.x86_model >= 7 && boot_cpu_data.x86_model <= 11))
                return 1;
  
        return 0;
@@@ -652,7 -652,8 +652,8 @@@ static int es7000_mps_oem_check_cluster
        return ret && es7000_apic_is_cluster();
  }
  
- struct apic apic_es7000_cluster = {
+ /* We've been warned by a false positive warning.Use __refdata to keep calm. */
+ struct apic __refdata apic_es7000_cluster = {
  
        .name                           = "es7000",
        .probe                          = probe_es7000,
index d836b4d347e60d0587220b5349153770090b4bd8,a8c0232b38933c209670b03cd3aa90768f095a87..3c8f9e75d0383a448f467e4d136d1067ab4c7047
@@@ -66,8 -66,6 +66,8 @@@
  #include <asm/apic.h>
  
  #define __apicdebuginit(type) static type __init
 +#define for_each_irq_pin(entry, head) \
 +      for (entry = head; entry; entry = entry->next)
  
  /*
   *      Is the SiS APIC rmw bug present ?
@@@ -87,6 -85,9 +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];
  
@@@ -118,6 -119,15 +121,6 @@@ static int __init parse_noapic(char *st
  }
  early_param("noapic", parse_noapic);
  
 -struct irq_pin_list;
 -
 -/*
 - * This is performance-critical, we want to do it O(1)
 - *
 - * the indexing order of this array favors 1:1 mappings
 - * between pins and IRQs.
 - */
 -
  struct irq_pin_list {
        int apic, pin;
        struct irq_pin_list *next;
@@@ -132,11 -142,6 +135,11 @@@ static struct irq_pin_list *get_one_fre
        return pin;
  }
  
 +/*
 + * This is performance-critical, we want to do it O(1)
 + *
 + * Most irqs are mapped 1:1 with pins.
 + */
  struct irq_cfg {
        struct irq_pin_list *irq_2_pin;
        cpumask_var_t domain;
@@@ -412,10 -417,13 +415,10 @@@ static bool io_apic_level_ack_pending(s
        unsigned long flags;
  
        spin_lock_irqsave(&ioapic_lock, flags);
 -      entry = cfg->irq_2_pin;
 -      for (;;) {
 +      for_each_irq_pin(entry, cfg->irq_2_pin) {
                unsigned int reg;
                int pin;
  
 -              if (!entry)
 -                      break;
                pin = entry->pin;
                reg = io_apic_read(entry->apic, 0x10 + pin*2);
                /* Is the remote IRR bit set? */
                        spin_unlock_irqrestore(&ioapic_lock, flags);
                        return true;
                }
 -              if (!entry->next)
 -                      break;
 -              entry = entry->next;
        }
        spin_unlock_irqrestore(&ioapic_lock, flags);
  
@@@ -490,68 -501,72 +493,68 @@@ static void ioapic_mask_entry(int apic
   * 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 *entry;
 -
 -      entry = cfg->irq_2_pin;
 -      if (!entry) {
 -              entry = get_one_free_irq_2_pin(node);
 -              if (!entry) {
 -                      printk(KERN_ERR "can not alloc irq_2_pin to add %d - %d\n",
 -                                      apic, pin);
 -                      return;
 -              }
 -              cfg->irq_2_pin = entry;
 -              entry->apic = apic;
 -              entry->pin = pin;
 -              return;
 -      }
 +      struct irq_pin_list **last, *entry;
  
 -      while (entry->next) {
 -              /* not again, please */
 +      /* don't allow duplicates */
 +      last = &cfg->irq_2_pin;
 +      for_each_irq_pin(entry, cfg->irq_2_pin) {
                if (entry->apic == apic && entry->pin == pin)
 -                      return;
 -
 -              entry = entry->next;
 +                      return 0;
 +              last = &entry->next;
        }
  
 -      entry->next = get_one_free_irq_2_pin(node);
 -      entry = 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");
  }
  
  /*
   * Reroute an IRQ to a different pin.
   */
  static void __init replace_pin_at_irq_node(struct irq_cfg *cfg, int node,
 -                                    int oldapic, int oldpin,
 -                                    int newapic, int newpin)
 +                                         int oldapic, int oldpin,
 +                                         int newapic, int newpin)
  {
 -      struct irq_pin_list *entry = cfg->irq_2_pin;
 -      int replaced = 0;
 +      struct irq_pin_list *entry;
  
 -      while (entry) {
 +      for_each_irq_pin(entry, cfg->irq_2_pin) {
                if (entry->apic == oldapic && entry->pin == oldpin) {
                        entry->apic = newapic;
                        entry->pin = newpin;
 -                      replaced = 1;
                        /* every one is different, right? */
 -                      break;
 +                      return;
                }
 -              entry = entry->next;
        }
  
 -      /* why? call replace before add? */
 -      if (!replaced)
 -              add_pin_to_irq_node(cfg, node, newapic, newpin);
 +      /* old apic/pin didn't exist, so just add new ones */
 +      add_pin_to_irq_node(cfg, node, newapic, newpin);
  }
  
 -static inline void io_apic_modify_irq(struct irq_cfg *cfg,
 -                              int mask_and, int mask_or,
 -                              void (*final)(struct irq_pin_list *entry))
 +static void io_apic_modify_irq(struct irq_cfg *cfg,
 +                             int mask_and, int mask_or,
 +                             void (*final)(struct irq_pin_list *entry))
  {
        int pin;
        struct irq_pin_list *entry;
  
 -      for (entry = cfg->irq_2_pin; entry != NULL; entry = entry->next) {
 +      for_each_irq_pin(entry, cfg->irq_2_pin) {
                unsigned int reg;
                pin = entry->pin;
                reg = io_apic_read(entry->apic, 0x10 + pin * 2);
@@@ -568,6 -583,7 +571,6 @@@ static void __unmask_IO_APIC_irq(struc
        io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED, 0, NULL);
  }
  
 -#ifdef CONFIG_X86_64
  static void io_apic_sync(struct irq_pin_list *entry)
  {
        /*
@@@ -583,6 -599,11 +586,6 @@@ static void __mask_IO_APIC_irq(struct i
  {
        io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, &io_apic_sync);
  }
 -#else /* CONFIG_X86_32 */
 -static void __mask_IO_APIC_irq(struct irq_cfg *cfg)
 -{
 -      io_apic_modify_irq(cfg, ~0, IO_APIC_REDIR_MASKED, NULL);
 -}
  
  static void __mask_and_edge_IO_APIC_irq(struct irq_cfg *cfg)
  {
@@@ -595,6 -616,7 +598,6 @@@ static void __unmask_and_level_IO_APIC_
        io_apic_modify_irq(cfg, ~IO_APIC_REDIR_MASKED,
                        IO_APIC_REDIR_LEVEL_TRIGGER, NULL);
  }
 -#endif /* CONFIG_X86_32 */
  
  static void mask_IO_APIC_irq_desc(struct irq_desc *desc)
  {
@@@ -1683,8 -1705,12 +1686,8 @@@ __apicdebuginit(void) print_IO_APIC(voi
                if (!entry)
                        continue;
                printk(KERN_DEBUG "IRQ%d ", irq);
 -              for (;;) {
 +              for_each_irq_pin(entry, cfg->irq_2_pin)
                        printk("-> %d:%d", entry->apic, entry->pin);
 -                      if (!entry->next)
 -                              break;
 -                      entry = entry->next;
 -              }
                printk("\n");
        }
  
@@@ -2188,6 -2214,7 +2191,6 @@@ static unsigned int startup_ioapic_irq(
        return was_pending;
  }
  
 -#ifdef CONFIG_X86_64
  static int ioapic_retrigger_irq(unsigned int irq)
  {
  
  
        return 1;
  }
 -#else
 -static int ioapic_retrigger_irq(unsigned int irq)
 -{
 -      apic->send_IPI_self(irq_cfg(irq)->vector);
 -
 -      return 1;
 -}
 -#endif
  
  /*
   * Level and edge triggered IO-APIC interrupts need different handling,
@@@ -2237,9 -2272,13 +2240,9 @@@ static void __target_IO_APIC_irq(unsign
        struct irq_pin_list *entry;
        u8 vector = cfg->vector;
  
 -      entry = cfg->irq_2_pin;
 -      for (;;) {
 +      for_each_irq_pin(entry, cfg->irq_2_pin) {
                unsigned int reg;
  
 -              if (!entry)
 -                      break;
 -
                apic = entry->apic;
                pin = entry->pin;
                /*
                reg &= ~IO_APIC_REDIR_VECTOR_MASK;
                reg |= vector;
                io_apic_modify(apic, 0x10 + pin*2, reg);
 -              if (!entry->next)
 -                      break;
 -              entry = entry->next;
        }
  }
  
@@@ -2476,8 -2518,11 +2479,8 @@@ atomic_t irq_mis_count
  static void ack_apic_level(unsigned int irq)
  {
        struct irq_desc *desc = irq_to_desc(irq);
 -
 -#ifdef CONFIG_X86_32
        unsigned long v;
        int i;
 -#endif
        struct irq_cfg *cfg;
        int do_unmask_irq = 0;
  
        }
  #endif
  
 -#ifdef CONFIG_X86_32
        /*
 -      * It appears there is an erratum which affects at least version 0x11
 -      * of I/O APIC (that's the 82093AA and cores integrated into various
 -      * chipsets).  Under certain conditions a level-triggered interrupt is
 -      * erroneously delivered as edge-triggered one but the respective IRR
 -      * bit gets set nevertheless.  As a result the I/O unit expects an EOI
 -      * message but it will never arrive and further interrupts are blocked
 -      * from the source.  The exact reason is so far unknown, but the
 -      * phenomenon was observed when two consecutive interrupt requests
 -      * from a given source get delivered to the same CPU and the source is
 -      * temporarily disabled in between.
 -      *
 -      * A workaround is to simulate an EOI message manually.  We achieve it
 -      * by setting the trigger mode to edge and then to level when the edge
 -      * trigger mode gets detected in the TMR of a local APIC for a
 -      * level-triggered interrupt.  We mask the source for the time of the
 -      * operation to prevent an edge-triggered interrupt escaping meanwhile.
 -      * The idea is from Manfred Spraul.  --macro
 -      */
 +       * It appears there is an erratum which affects at least version 0x11
 +       * of I/O APIC (that's the 82093AA and cores integrated into various
 +       * chipsets).  Under certain conditions a level-triggered interrupt is
 +       * erroneously delivered as edge-triggered one but the respective IRR
 +       * bit gets set nevertheless.  As a result the I/O unit expects an EOI
 +       * message but it will never arrive and further interrupts are blocked
 +       * from the source.  The exact reason is so far unknown, but the
 +       * phenomenon was observed when two consecutive interrupt requests
 +       * from a given source get delivered to the same CPU and the source is
 +       * temporarily disabled in between.
 +       *
 +       * A workaround is to simulate an EOI message manually.  We achieve it
 +       * by setting the trigger mode to edge and then to level when the edge
 +       * trigger mode gets detected in the TMR of a local APIC for a
 +       * level-triggered interrupt.  We mask the source for the time of the
 +       * operation to prevent an edge-triggered interrupt escaping meanwhile.
 +       * The idea is from Manfred Spraul.  --macro
 +       */
        cfg = desc->chip_data;
        i = cfg->vector;
 -
        v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 -#endif
  
        /*
         * We must acknowledge the irq before we move it or the acknowledge will
                unmask_IO_APIC_irq_desc(desc);
        }
  
 -#ifdef CONFIG_X86_32
 +      /* Tail end of version 0x11 I/O APIC bug workaround */
        if (!(v & (1 << (i & 0x1f)))) {
                atomic_inc(&irq_mis_count);
                spin_lock(&ioapic_lock);
                __unmask_and_level_IO_APIC_irq(cfg);
                spin_unlock(&ioapic_lock);
        }
 -#endif
  }
  
  #ifdef CONFIG_INTR_REMAP
  static void __eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg)
  {
 -      int apic, pin;
        struct irq_pin_list *entry;
  
 -      entry = cfg->irq_2_pin;
 -      for (;;) {
 -
 -              if (!entry)
 -                      break;
 -
 -              apic = entry->apic;
 -              pin = entry->pin;
 -              io_apic_eoi(apic, pin);
 -              entry = entry->next;
 -      }
 +      for_each_irq_pin(entry, cfg->irq_2_pin)
 +              io_apic_eoi(entry->apic, entry->pin);
  }
  
  static void
@@@ -3185,7 -3244,8 +3188,7 @@@ void destroy_irq(unsigned int irq
        cfg = desc->chip_data;
        dynamic_irq_cleanup(irq);
        /* connect back irq_cfg */
 -      if (desc)
 -              desc->chip_data = cfg;
 +      desc->chip_data = cfg;
  
        free_irte(irq);
        spin_lock_irqsave(&vector_lock, flags);
@@@ -3736,6 -3796,9 +3739,9 @@@ int arch_enable_uv_irq(char *irq_name, 
        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;
  }
  
@@@ -3852,11 -3915,7 +3858,11 @@@ static int __io_apic_set_pci_routing(st
         */
        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);
@@@ -3885,11 -3944,28 +3891,28 @@@ int io_apic_set_pci_routing(struct devi
        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)
@@@ -3998,8 -4074,6 +4021,6 @@@ int acpi_get_override_irq(int bus_irq, 
        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
@@@ -4053,7 -4127,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;
        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;
@@@ -4089,7 -4165,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;
@@@ -4118,34 -4194,101 +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++;
+ }