[ACPI] Merge acpi-2.6.12 branch into 2.6.13-rc3
authorLen Brown <len.brown@intel.com>
Fri, 5 Aug 2005 04:31:42 +0000 (00:31 -0400)
committerLen Brown <len.brown@intel.com>
Fri, 5 Aug 2005 04:31:42 +0000 (00:31 -0400)
Signed-off-by: Len Brown <len.brown@intel.com>
1  2 
arch/i386/kernel/acpi/boot.c
arch/ia64/kernel/acpi.c
arch/ia64/kernel/iosapic.c
drivers/acpi/Kconfig
drivers/acpi/pci_irq.c
drivers/acpi/pci_link.c
drivers/char/hpet.c
include/linux/acpi.h

@@@ -29,7 -29,6 +29,7 @@@
  #include <linux/efi.h>
  #include <linux/irq.h>
  #include <linux/module.h>
 +#include <linux/dmi.h>
  
  #include <asm/pgtable.h>
  #include <asm/io_apic.h>
@@@ -159,15 -158,9 +159,15 @@@ char *__acpi_map_table(unsigned long ph
  #endif
  
  #ifdef CONFIG_PCI_MMCONFIG
 -static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
 +/* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
 +struct acpi_table_mcfg_config *pci_mmcfg_config;
 +int pci_mmcfg_config_num;
 +
 +int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
  {
        struct acpi_table_mcfg *mcfg;
 +      unsigned long i;
 +      int config_size;
  
        if (!phys_addr || !size)
                return -EINVAL;
                return -ENODEV;
        }
  
 -      if (mcfg->base_reserved) {
 -              printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
 +      /* how many config structures do we have */
 +      pci_mmcfg_config_num = 0;
 +      i = size - sizeof(struct acpi_table_mcfg);
 +      while (i >= sizeof(struct acpi_table_mcfg_config)) {
 +              ++pci_mmcfg_config_num;
 +              i -= sizeof(struct acpi_table_mcfg_config);
 +      };
 +      if (pci_mmcfg_config_num == 0) {
 +              printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
                return -ENODEV;
        }
  
 -      pci_mmcfg_base_addr = mcfg->base_address;
 +      config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
 +      pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
 +      if (!pci_mmcfg_config) {
 +              printk(KERN_WARNING PREFIX
 +                     "No memory for MCFG config tables\n");
 +              return -ENOMEM;
 +      }
 +
 +      memcpy(pci_mmcfg_config, &mcfg->config, config_size);
 +      for (i = 0; i < pci_mmcfg_config_num; ++i) {
 +              if (mcfg->config[i].base_reserved) {
 +                      printk(KERN_ERR PREFIX
 +                             "MMCONFIG not in low 4GB of memory\n");
 +                      return -ENODEV;
 +              }
 +      }
  
        return 0;
  }
 -#else
 -#define       acpi_parse_mcfg NULL
 -#endif /* !CONFIG_PCI_MMCONFIG */
 +#endif /* CONFIG_PCI_MMCONFIG */
  
  #ifdef CONFIG_X86_LOCAL_APIC
  static int __init
@@@ -484,7 -457,11 +484,11 @@@ int acpi_gsi_to_irq(u32 gsi, unsigned i
        return 0;
  }
  
- unsigned int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)
+ /*
+  * success: return IRQ number (>=0)
+  * failure: return < 0
+  */
+ int acpi_register_gsi(u32 gsi, int edge_level, int active_high_low)
  {
        unsigned int irq;
        unsigned int plat_gsi = gsi;
@@@ -533,22 -510,6 +537,22 @@@ acpi_unmap_lsapic(int cpu
  EXPORT_SYMBOL(acpi_unmap_lsapic);
  #endif /* CONFIG_ACPI_HOTPLUG_CPU */
  
 +int
 +acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
 +{
 +      /* TBD */
 +      return -EINVAL;
 +}
 +EXPORT_SYMBOL(acpi_register_ioapic);
 +
 +int
 +acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
 +{
 +      /* TBD */
 +      return -EINVAL;
 +}
 +EXPORT_SYMBOL(acpi_unregister_ioapic);
 +
  static unsigned long __init
  acpi_scan_rsdp (
        unsigned long           start,
@@@ -858,219 -819,6 +862,219 @@@ acpi_process_madt(void
        return;
  }
  
 +extern int acpi_force;
 +
 +#ifdef __i386__
 +
 +#ifdef        CONFIG_ACPI_PCI
 +static int __init disable_acpi_irq(struct dmi_system_id *d)
 +{
 +      if (!acpi_force) {
 +              printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
 +                     d->ident);
 +              acpi_noirq_set();
 +      }
 +      return 0;
 +}
 +
 +static int __init disable_acpi_pci(struct dmi_system_id *d)
 +{
 +      if (!acpi_force) {
 +              printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
 +                     d->ident);
 +              acpi_disable_pci();
 +      }
 +      return 0;
 +}
 +#endif
 +
 +static int __init dmi_disable_acpi(struct dmi_system_id *d)
 +{
 +      if (!acpi_force) {
 +              printk(KERN_NOTICE "%s detected: acpi off\n",d->ident);
 +              disable_acpi();
 +      } else {
 +              printk(KERN_NOTICE
 +                     "Warning: DMI blacklist says broken, but acpi forced\n");
 +      }
 +      return 0;
 +}
 +
 +/*
 + * Limit ACPI to CPU enumeration for HT
 + */
 +static int __init force_acpi_ht(struct dmi_system_id *d)
 +{
 +      if (!acpi_force) {
 +              printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident);
 +              disable_acpi();
 +              acpi_ht = 1;
 +      } else {
 +              printk(KERN_NOTICE
 +                     "Warning: acpi=force overrules DMI blacklist: acpi=ht\n");
 +      }
 +      return 0;
 +}
 +
 +/*
 + * If your system is blacklisted here, but you find that acpi=force
 + * works for you, please contact acpi-devel@sourceforge.net
 + */
 +static struct dmi_system_id __initdata acpi_dmi_table[] = {
 +      /*
 +       * Boxes that need ACPI disabled
 +       */
 +      {
 +              .callback = dmi_disable_acpi,
 +              .ident = "IBM Thinkpad",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
 +              },
 +      },
 +
 +      /*
 +       * Boxes that need acpi=ht
 +       */
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "FSC Primergy T850",
 +              .matches = {
 +                      DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
 +                      DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "DELL GX240",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "HP VISUALIZE NT Workstation",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
 +                      DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "Compaq Workstation W8000",
 +              .matches = {
 +                      DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
 +                      DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "ASUS P4B266",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 +                      DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "ASUS P2B-DS",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 +                      DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "ASUS CUR-DLS",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 +                      DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "ABIT i440BX-W83977",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "IBM Bladecenter",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "IBM eServer xSeries 360",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "IBM eserver xSeries 330",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
 +              },
 +      },
 +      {
 +              .callback = force_acpi_ht,
 +              .ident = "IBM eserver xSeries 440",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
 +                      DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
 +              },
 +      },
 +
 +#ifdef        CONFIG_ACPI_PCI
 +      /*
 +       * Boxes that need ACPI PCI IRQ routing disabled
 +       */
 +      {
 +              .callback = disable_acpi_irq,
 +              .ident = "ASUS A7V",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
 +                      DMI_MATCH(DMI_BOARD_NAME, "<A7V>"),
 +                      /* newer BIOS, Revision 1011, does work */
 +                      DMI_MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
 +              },
 +      },
 +
 +      /*
 +       * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
 +       */
 +      {       /* _BBN 0 bug */
 +              .callback = disable_acpi_pci,
 +              .ident = "ASUS PR-DLS",
 +              .matches = {
 +                      DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
 +                      DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
 +                      DMI_MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
 +                      DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
 +              },
 +      },
 +      {
 +              .callback = disable_acpi_pci,
 +              .ident = "Acer TravelMate 36x Laptop",
 +              .matches = {
 +                      DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
 +                      DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
 +              },
 +      },
 +#endif
 +      { }
 +};
 +
 +#endif        /* __i386__ */
 +
  /*
   * acpi_boot_table_init() and acpi_boot_init()
   *  called from setup_arch(), always.
@@@ -1099,10 -847,6 +1103,10 @@@ acpi_boot_table_init(void
  {
        int error;
  
 +#ifdef __i386__
 +      dmi_check_system(acpi_dmi_table);
 +#endif
 +
        /*
         * If acpi_disabled, bail out
         * One exception: acpi=ht continues far enough to enumerate LAPICs
         */
        error = acpi_blacklisted();
        if (error) {
 -              extern int acpi_force;
 -
                if (acpi_force) {
                        printk(KERN_WARNING PREFIX "acpi=force override\n");
                } else {
@@@ -1165,6 -911,7 +1169,6 @@@ int __init acpi_boot_init(void
        acpi_process_madt();
  
        acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
 -      acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
  
        return 0;
  }
diff --combined arch/ia64/kernel/acpi.c
@@@ -242,7 -242,9 +242,7 @@@ acpi_parse_iosapic (acpi_table_entry_he
        if (BAD_MADT_ENTRY(iosapic, end))
                return -EINVAL;
  
 -      iosapic_init(iosapic->address, iosapic->global_irq_base);
 -
 -      return 0;
 +      return iosapic_init(iosapic->address, iosapic->global_irq_base);
  }
  
  
@@@ -563,7 -565,11 +563,11 @@@ acpi_numa_arch_fixup (void
  }
  #endif /* CONFIG_ACPI_NUMA */
  
- unsigned int
+ /*
+  * success: return IRQ number (>=0)
+  * failure: return < 0
+  */
+ int
  acpi_register_gsi (u32 gsi, int edge_level, int active_high_low)
  {
        if (has_8259 && gsi < 16)
@@@ -694,10 -700,8 +698,10 @@@ acpi_boot_init (void
                        if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id())
                                node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu];
        }
 -      build_cpu_to_node_map();
  # endif
 +#endif
 +#ifdef CONFIG_ACPI_NUMA
 +      build_cpu_to_node_map();
  #endif
        /* Make boot-up look pretty */
        printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
@@@ -826,7 -830,7 +830,7 @@@ EXPORT_SYMBOL(acpi_unmap_lsapic)
   
  
  #ifdef CONFIG_ACPI_NUMA
 -acpi_status __init
 +acpi_status __devinit
  acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
  {
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        return AE_OK;
  }
  #endif /* CONFIG_NUMA */
 +
 +int
 +acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
 +{
 +      int err;
 +
 +      if ((err = iosapic_init(phys_addr, gsi_base)))
 +              return err;
 +
 +#if CONFIG_ACPI_NUMA
 +      acpi_map_iosapic(handle, 0, NULL, NULL);
 +#endif /* CONFIG_ACPI_NUMA */
 +
 +      return 0;
 +}
 +EXPORT_SYMBOL(acpi_register_ioapic);
 +
 +int
 +acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
 +{
 +      return iosapic_remove(gsi_base);
 +}
 +EXPORT_SYMBOL(acpi_unregister_ioapic);
 +
  #endif /* CONFIG_ACPI_BOOT */
@@@ -129,13 -129,14 +129,13 @@@ static struct iosapic 
        char __iomem    *addr;          /* base address of IOSAPIC */
        unsigned int    gsi_base;       /* first GSI assigned to this IOSAPIC */
        unsigned short  num_rte;        /* number of RTE in this IOSAPIC */
 +      int             rtes_inuse;     /* # of RTEs in use on this IOSAPIC */
  #ifdef CONFIG_NUMA
        unsigned short  node;           /* numa node association via pxm */
  #endif
  } iosapic_lists[NR_IOSAPICS];
  
 -static int num_iosapic;
 -
 -static unsigned char pcat_compat __initdata;  /* 8259 compatibility flag */
 +static unsigned char pcat_compat __devinitdata;       /* 8259 compatibility flag */
  
  static int iosapic_kmalloc_ok;
  static LIST_HEAD(free_rte_list);
@@@ -148,7 -149,7 +148,7 @@@ find_iosapic (unsigned int gsi
  {
        int i;
  
 -      for (i = 0; i < num_iosapic; i++) {
 +      for (i = 0; i < NR_IOSAPICS; i++) {
                if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
                        return i;
        }
@@@ -489,6 -490,8 +489,6 @@@ static int iosapic_find_sharable_vecto
                        }
                }
        }
 -      if (vector < 0)
 -              panic("%s: out of interrupt vectors!\n", __FUNCTION__);
  
        return vector;
  }
@@@ -504,8 -507,6 +504,8 @@@ iosapic_reassign_vector (int vector
  
        if (!list_empty(&iosapic_intr_info[vector].rtes)) {
                new_vector = assign_irq_vector(AUTO_ASSIGN);
 +              if (new_vector < 0)
 +                      panic("%s: out of interrupt vectors!\n", __FUNCTION__);
                printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
                memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
                       sizeof(struct iosapic_intr_info));
@@@ -561,7 -562,7 +561,7 @@@ static inline int vector_is_shared (in
        return (iosapic_intr_info[vector].count > 1);
  }
  
- static void
+ static int
  register_intr (unsigned int gsi, int vector, unsigned char delivery,
               unsigned long polarity, unsigned long trigger)
  {
        index = find_iosapic(gsi);
        if (index < 0) {
                printk(KERN_WARNING "%s: No IOSAPIC for GSI %u\n", __FUNCTION__, gsi);
-               return;
+               return -ENODEV;
        }
  
        iosapic_address = iosapic_lists[index].addr;
                rte = iosapic_alloc_rte();
                if (!rte) {
                        printk(KERN_WARNING "%s: cannot allocate memory\n", __FUNCTION__);
-                       return;
+                       return -ENOMEM;
                }
  
                rte_index = gsi - gsi_base;
                rte->refcnt++;
                list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
                iosapic_intr_info[vector].count++;
 +              iosapic_lists[index].rtes_inuse++;
        }
        else if (vector_is_shared(vector)) {
                struct iosapic_intr_info *info = &iosapic_intr_info[vector];
                if (info->trigger != trigger || info->polarity != polarity) {
                        printk (KERN_WARNING "%s: cannot override the interrupt\n", __FUNCTION__);
-                       return;
+                       return -EINVAL;
                }
        }
  
                               __FUNCTION__, vector, idesc->handler->typename, irq_type->typename);
                idesc->handler = irq_type;
        }
+       return 0;
  }
  
  static unsigned int
@@@ -710,7 -711,7 +711,7 @@@ in
  iosapic_register_intr (unsigned int gsi,
                       unsigned long polarity, unsigned long trigger)
  {
-       int vector, mask = 1;
+       int vector, mask = 1, err;
        unsigned int dest;
        unsigned long flags;
        struct iosapic_rte_info *rte;
@@@ -734,11 -735,11 +735,11 @@@ again
        spin_unlock_irqrestore(&iosapic_lock, flags);
  
        /* If vector is running out, we try to find a sharable vector */
-       vector = assign_irq_vector(AUTO_ASSIGN);
+       vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
        if (vector < 0) {
                vector = iosapic_find_sharable_vector(trigger, polarity);
-               if (vector < 0)
-                       panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+               if (vector < 0)
+                       Return -ENOSPC;
        }
  
        spin_lock_irqsave(&irq_descp(vector)->lock, flags);
                }
  
                dest = get_target_cpu(gsi, vector);
-               register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
+               err = register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY,
                              polarity, trigger);
+               if (err < 0) {
+                       spin_unlock(&iosapic_lock);
+                       spin_unlock_irqrestore(&irq_descp(vector)->lock, flags);
+                       return err;
+               }
  
                /*
                 * If the vector is shared and already unmasked for
@@@ -781,7 -787,7 +787,7 @@@ voi
  iosapic_unregister_intr (unsigned int gsi)
  {
        unsigned long flags;
 -      int irq, vector;
 +      int irq, vector, index;
        irq_desc_t *idesc;
        u32 low32;
        unsigned long trigger, polarity;
                list_del(&rte->rte_list);
                iosapic_intr_info[vector].count--;
                iosapic_free_rte(rte);
 +              index = find_iosapic(gsi);
 +              iosapic_lists[index].rtes_inuse--;
 +              WARN_ON(iosapic_lists[index].rtes_inuse < 0);
  
                trigger  = iosapic_intr_info[vector].trigger;
                polarity = iosapic_intr_info[vector].polarity;
@@@ -887,8 -890,6 +893,8 @@@ iosapic_register_platform_intr (u32 int
                break;
              case ACPI_INTERRUPT_INIT:
                vector = assign_irq_vector(AUTO_ASSIGN);
 +              if (vector < 0)
 +                      panic("%s: out of interrupt vectors!\n", __FUNCTION__);
                delivery = IOSAPIC_INIT;
                break;
              case ACPI_INTERRUPT_CPEI:
@@@ -960,86 -961,30 +966,86 @@@ iosapic_system_init (int system_pcat_co
        }
  }
  
 -void __init
 +static inline int
 +iosapic_alloc (void)
 +{
 +      int index;
 +
 +      for (index = 0; index < NR_IOSAPICS; index++)
 +              if (!iosapic_lists[index].addr)
 +                      return index;
 +
 +      printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
 +      return -1;
 +}
 +
 +static inline void
 +iosapic_free (int index)
 +{
 +      memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
 +}
 +
 +static inline int
 +iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
 +{
 +      int index;
 +      unsigned int gsi_end, base, end;
 +
 +      /* check gsi range */
 +      gsi_end = gsi_base + ((ver >> 16) & 0xff);
 +      for (index = 0; index < NR_IOSAPICS; index++) {
 +              if (!iosapic_lists[index].addr)
 +                      continue;
 +
 +              base = iosapic_lists[index].gsi_base;
 +              end  = base + iosapic_lists[index].num_rte - 1;
 +
 +              if (gsi_base < base && gsi_end < base)
 +                      continue;/* OK */
 +
 +              if (gsi_base > end && gsi_end > end)
 +                      continue; /* OK */
 +
 +              return -EBUSY;
 +      }
 +      return 0;
 +}
 +
 +int __devinit
  iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
  {
 -      int num_rte;
 +      int num_rte, err, index;
        unsigned int isa_irq, ver;
        char __iomem *addr;
 +      unsigned long flags;
  
 -      addr = ioremap(phys_addr, 0);
 -      ver = iosapic_version(addr);
 +      spin_lock_irqsave(&iosapic_lock, flags);
 +      {
 +              addr = ioremap(phys_addr, 0);
 +              ver = iosapic_version(addr);
  
 -      /*
 -       * The MAX_REDIR register holds the highest input pin
 -       * number (starting from 0).
 -       * We add 1 so that we can use it for number of pins (= RTEs)
 -       */
 -      num_rte = ((ver >> 16) & 0xff) + 1;
 +              if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
 +                      iounmap(addr);
 +                      spin_unlock_irqrestore(&iosapic_lock, flags);
 +                      return err;
 +              }
 +
 +              /*
 +               * The MAX_REDIR register holds the highest input pin
 +               * number (starting from 0).
 +               * We add 1 so that we can use it for number of pins (= RTEs)
 +               */
 +              num_rte = ((ver >> 16) & 0xff) + 1;
  
 -      iosapic_lists[num_iosapic].addr = addr;
 -      iosapic_lists[num_iosapic].gsi_base = gsi_base;
 -      iosapic_lists[num_iosapic].num_rte = num_rte;
 +              index = iosapic_alloc();
 +              iosapic_lists[index].addr = addr;
 +              iosapic_lists[index].gsi_base = gsi_base;
 +              iosapic_lists[index].num_rte = num_rte;
  #ifdef CONFIG_NUMA
 -      iosapic_lists[num_iosapic].node = MAX_NUMNODES;
 +              iosapic_lists[index].node = MAX_NUMNODES;
  #endif
 -      num_iosapic++;
 +      }
 +      spin_unlock_irqrestore(&iosapic_lock, flags);
  
        if ((gsi_base == 0) && pcat_compat) {
                /*
                for (isa_irq = 0; isa_irq < 16; ++isa_irq)
                        iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
        }
 +      return 0;
 +}
 +
 +#ifdef CONFIG_HOTPLUG
 +int
 +iosapic_remove (unsigned int gsi_base)
 +{
 +      int index, err = 0;
 +      unsigned long flags;
 +
 +      spin_lock_irqsave(&iosapic_lock, flags);
 +      {
 +              index = find_iosapic(gsi_base);
 +              if (index < 0) {
 +                      printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
 +                             __FUNCTION__, gsi_base);
 +                      goto out;
 +              }
 +
 +              if (iosapic_lists[index].rtes_inuse) {
 +                      err = -EBUSY;
 +                      printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
 +                             __FUNCTION__, gsi_base);
 +                      goto out;
 +              }
 +
 +              iounmap(iosapic_lists[index].addr);
 +              iosapic_free(index);
 +      }
 + out:
 +      spin_unlock_irqrestore(&iosapic_lock, flags);
 +      return err;
  }
 +#endif /* CONFIG_HOTPLUG */
  
  #ifdef CONFIG_NUMA
 -void __init
 +void __devinit
  map_iosapic_to_node(unsigned int gsi_base, int node)
  {
        int index;
diff --combined drivers/acpi/Kconfig
@@@ -55,8 -55,8 +55,8 @@@ if ACPI_INTERPRETE
  
  config ACPI_SLEEP
        bool "Sleep States (EXPERIMENTAL)"
 -      depends on X86
 -      depends on EXPERIMENTAL
 +      depends on X86 && (!SMP || SUSPEND_SMP)
 +      depends on EXPERIMENTAL && PM
        default y
        ---help---
          This option adds support for ACPI suspend states. 
@@@ -154,12 -154,10 +154,10 @@@ config ACPI_PROCESSO
          support it.
  
  config ACPI_HOTPLUG_CPU
-       bool "Processor Hotplug (EXPERIMENTAL)"
-       depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
+       bool
+       depends on ACPI_PROCESSOR && HOTPLUG_CPU
        select ACPI_CONTAINER
-       default n
-        ---help---
-        Select this option if your platform support physical CPU hotplug.
+       default y
  
  config ACPI_THERMAL
        tristate "Thermal Zone"
diff --combined drivers/acpi/pci_irq.c
@@@ -424,6 -424,7 +424,7 @@@ acpi_pci_irq_enable 
        int                     edge_level = ACPI_LEVEL_SENSITIVE;
        int                     active_high_low = ACPI_ACTIVE_LOW;
        char                    *link = NULL;
+       int                     rc;
  
        ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
  
                printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
                        pci_name(dev), ('A' + pin));
                /* Interrupt Line values above 0xF are forbidden */
 -              if (dev->irq >= 0 && (dev->irq <= 0xF)) {
 +              if (dev->irq > 0 && (dev->irq <= 0xF)) {
                        printk(" - using IRQ %d\n", dev->irq);
 +                      acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
                        return_VALUE(0);
                }
                else {
                }
        }
  
-       dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
+       rc = acpi_register_gsi(irq, edge_level, active_high_low);
+       if (rc < 0) {
+               printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: failed "
+                      "to register GSI\n", pci_name(dev), ('A' + pin));
+               return_VALUE(rc);
+       }
+       dev->irq = rc;
  
        printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
                pci_name(dev), 'A' + pin);
diff --combined drivers/acpi/pci_link.c
@@@ -786,33 -786,14 +786,32 @@@ end
        return_VALUE(result);
  }
  
 -static int irqrouter_suspend(struct sys_device *dev, pm_message_t state)
 +static int
 +acpi_pci_link_resume(
 +      struct acpi_pci_link *link)
 +{
 +      ACPI_FUNCTION_TRACE("acpi_pci_link_resume");
 +
 +      if (link->refcnt && link->irq.active && link->irq.initialized)
 +              return_VALUE(acpi_pci_link_set(link, link->irq.active));
 +      else
 +              return_VALUE(0);
 +}
 +
 +/*
 + * FIXME: this is a workaround to avoid nasty warning.  It will be removed
 + * after every device calls pci_disable_device in .resume.
 + */
 +int acpi_in_resume;
 +static int
- irqrouter_resume(
-       struct sys_device *dev)
++irqrouter_resume(struct sys_device *dev)
  {
        struct list_head        *node = NULL;
        struct acpi_pci_link    *link = NULL;
 -      int                     ret = 0;
  
 -      ACPI_FUNCTION_TRACE("irqrouter_suspend");
 +      ACPI_FUNCTION_TRACE("irqrouter_resume");
  
 +      acpi_in_resume = 1;
        list_for_each(node, &acpi_link.entries) {
                link = list_entry(node, struct acpi_pci_link, node);
                if (!link) {
                                "Invalid link context\n"));
                        continue;
                }
 -              if (link->irq.initialized && link->refcnt != 0
 -                      /* We ignore legacy IDE device irq */
 -                      && link->irq.active != 14 && link->irq.active !=15) {
 -                      printk(KERN_WARNING PREFIX
 -                              "%d drivers with interrupt %d neglected to call"
 -                              " pci_disable_device at .suspend\n",
 -                              link->refcnt,
 -                              link->irq.active);
 -                      printk(KERN_WARNING PREFIX
 -                              "Fix the driver, or rmmod before suspend\n");
 -                      link->refcnt = 0;
 -                      ret = -EINVAL;
 -              }
 +              acpi_pci_link_resume(link);
        }
 -      return_VALUE(ret);
 +      acpi_in_resume = 0;
 +      return_VALUE(0);
  }
  
  
@@@ -938,7 -930,7 +937,7 @@@ __setup("acpi_irq_balance", acpi_irq_ba
  /* FIXME: we will remove this interface after all drivers call pci_disable_device */
  static struct sysdev_class irqrouter_sysdev_class = {
          set_kset_name("irqrouter"),
 -        .suspend = irqrouter_suspend,
 +        .resume = irqrouter_resume,
  };
  
  
diff --combined drivers/char/hpet.c
@@@ -834,7 -834,7 +834,7 @@@ int hpet_alloc(struct hpet_data *hdp
        printk("\n");
  
        ns = hpetp->hp_period;  /* femptoseconds, 10^-15 */
 -      do_div(ns, 1000000);    /* convert to nanoseconds, 10^-9 */
 +      ns /= 1000000;          /* convert to nanoseconds, 10^-9 */
        printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n",
                hpetp->hp_which, ns, hpetp->hp_ntimer,
                cap & HPET_COUNTER_SIZE_MASK ? 64 : 32);
@@@ -906,11 -906,15 +906,15 @@@ static acpi_status hpet_resources(struc
                if (irqp->number_of_interrupts > 0) {
                        hdp->hd_nirqs = irqp->number_of_interrupts;
  
-                       for (i = 0; i < hdp->hd_nirqs; i++)
-                               hdp->hd_irq[i] =
+                       for (i = 0; i < hdp->hd_nirqs; i++) {
+                               int rc =
                                    acpi_register_gsi(irqp->interrupts[i],
                                                      irqp->edge_level,
                                                      irqp->active_high_low);
+                               if (rc < 0)
+                                       return AE_ERROR;
+                               hdp->hd_irq[i] = rc;
+                       }
                }
        }
  
diff --combined include/linux/acpi.h
@@@ -345,19 -345,11 +345,19 @@@ struct acpi_table_ecdt 
  
  /* PCI MMCONFIG */
  
 +/* Defined in PCI Firmware Specification 3.0 */
 +struct acpi_table_mcfg_config {
 +      u32                             base_address;
 +      u32                             base_reserved;
 +      u16                             pci_segment_group_number;
 +      u8                              start_bus_number;
 +      u8                              end_bus_number;
 +      u8                              reserved[4];
 +} __attribute__ ((packed));
  struct acpi_table_mcfg {
        struct acpi_table_header        header;
        u8                              reserved[8];
 -      u32                             base_address;
 -      u32                             base_reserved;
 +      struct acpi_table_mcfg_config   config[0];
  } __attribute__ ((packed));
  
  /* Table Handlers */
@@@ -402,7 -394,6 +402,7 @@@ int acpi_table_parse (enum acpi_table_i
  int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
  int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
  int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
 +int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size);
  void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
  void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
  void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
@@@ -419,13 -410,9 +419,13 @@@ int acpi_map_lsapic(acpi_handle handle
  int acpi_unmap_lsapic(int cpu);
  #endif /* CONFIG_ACPI_HOTPLUG_CPU */
  
 +int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
 +int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
 +
  extern int acpi_mp_config;
  
 -extern u32 pci_mmcfg_base_addr;
 +extern struct acpi_table_mcfg_config *pci_mmcfg_config;
 +extern int pci_mmcfg_config_num;
  
  extern int sbf_port ;
  
  
  #define acpi_mp_config        0
  
- static inline int acpi_boot_init(void)
- {
-       return 0;
- }
- static inline int acpi_boot_table_init(void)
- {
-       return 0;
- }
  #endif        /*!CONFIG_ACPI_BOOT*/
  
unsigned int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low);
+ int acpi_register_gsi (u32 gsi, int edge_level, int active_high_low);
  int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
  
  /*
@@@ -549,5 -526,17 +539,17 @@@ static inline int acpi_get_pxm(acpi_han
  
  extern int pnpacpi_disabled;
  
+ #else /* CONFIG_ACPI */
+ static inline int acpi_boot_init(void)
+ {
+       return 0;
+ }
+ static inline int acpi_boot_table_init(void)
+ {
+       return 0;
+ }
  #endif        /* CONFIG_ACPI */
  #endif        /*_LINUX_ACPI_H*/