Merge tag 'iwlwifi-next-for-kalle-2014-12-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / arch / x86 / kernel / apic / io_apic.c
index a6745e7..3f5f604 100644 (file)
 #include <linux/module.h>
 #include <linux/syscore_ops.h>
 #include <linux/irqdomain.h>
-#include <linux/msi.h>
-#include <linux/htirq.h>
 #include <linux/freezer.h>
 #include <linux/kthread.h>
 #include <linux/jiffies.h>     /* time_after() */
 #include <linux/slab.h>
 #include <linux/bootmem.h>
-#include <linux/dmar.h>
-#include <linux/hpet.h>
 
 #include <asm/idle.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/timer.h>
 #include <asm/i8259.h>
-#include <asm/msidef.h>
-#include <asm/hypertransport.h>
 #include <asm/setup.h>
 #include <asm/irq_remapping.h>
-#include <asm/hpet.h>
 #include <asm/hw_irq.h>
 
 #include <asm/apic.h>
 
-#define __apicdebuginit(type) static type __init
-
 #define        for_each_ioapic(idx)            \
        for ((idx) = 0; (idx) < nr_ioapics; (idx)++)
 #define        for_each_ioapic_reverse(idx)    \
@@ -74,7 +65,7 @@
                for_each_pin((idx), (pin))
 
 #define for_each_irq_pin(entry, head) \
-       for (entry = head; entry; entry = entry->next)
+       list_for_each_entry(entry, &head, list)
 
 /*
  *      Is the SiS APIC rmw bug present ?
@@ -83,7 +74,6 @@
 int sis_apic_bug = -1;
 
 static DEFINE_RAW_SPINLOCK(ioapic_lock);
-static DEFINE_RAW_SPINLOCK(vector_lock);
 static DEFINE_MUTEX(ioapic_mutex);
 static unsigned int ioapic_dynirq_base;
 static int ioapic_initialized;
@@ -112,6 +102,7 @@ static struct ioapic {
        struct ioapic_domain_cfg irqdomain_cfg;
        struct irq_domain *irqdomain;
        struct mp_pin_info *pin_info;
+       struct resource *iomem_res;
 } ioapics[MAX_IO_APICS];
 
 #define mpc_ioapic_ver(ioapic_idx)     ioapics[ioapic_idx].mp_config.apicver
@@ -205,8 +196,6 @@ static int __init parse_noapic(char *str)
 }
 early_param("noapic", parse_noapic);
 
-static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node);
-
 /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */
 void mp_save_irq(struct mpc_intsrc *m)
 {
@@ -228,8 +217,8 @@ void mp_save_irq(struct mpc_intsrc *m)
 }
 
 struct irq_pin_list {
+       struct list_head list;
        int apic, pin;
-       struct irq_pin_list *next;
 };
 
 static struct irq_pin_list *alloc_irq_pin_list(int node)
@@ -237,7 +226,26 @@ static struct irq_pin_list *alloc_irq_pin_list(int node)
        return kzalloc_node(sizeof(struct irq_pin_list), GFP_KERNEL, node);
 }
 
-int __init arch_early_irq_init(void)
+static void alloc_ioapic_saved_registers(int idx)
+{
+       size_t size;
+
+       if (ioapics[idx].saved_registers)
+               return;
+
+       size = sizeof(struct IO_APIC_route_entry) * ioapics[idx].nr_registers;
+       ioapics[idx].saved_registers = kzalloc(size, GFP_KERNEL);
+       if (!ioapics[idx].saved_registers)
+               pr_err("IOAPIC %d: suspend/resume impossible!\n", idx);
+}
+
+static void free_ioapic_saved_registers(int idx)
+{
+       kfree(ioapics[idx].saved_registers);
+       ioapics[idx].saved_registers = NULL;
+}
+
+int __init arch_early_ioapic_init(void)
 {
        struct irq_cfg *cfg;
        int i, node = cpu_to_node(0);
@@ -245,13 +253,8 @@ int __init arch_early_irq_init(void)
        if (!nr_legacy_irqs())
                io_apic_irqs = ~0UL;
 
-       for_each_ioapic(i) {
-               ioapics[i].saved_registers =
-                       kzalloc(sizeof(struct IO_APIC_route_entry) *
-                               ioapics[i].nr_registers, GFP_KERNEL);
-               if (!ioapics[i].saved_registers)
-                       pr_err("IOAPIC %d: suspend/resume impossible!\n", i);
-       }
+       for_each_ioapic(i)
+               alloc_ioapic_saved_registers(i);
 
        /*
         * For legacy IRQ's, start with assigning irq0 to irq15 to
@@ -266,61 +269,6 @@ int __init arch_early_irq_init(void)
        return 0;
 }
 
-static inline struct irq_cfg *irq_cfg(unsigned int irq)
-{
-       return irq_get_chip_data(irq);
-}
-
-static struct irq_cfg *alloc_irq_cfg(unsigned int irq, int node)
-{
-       struct irq_cfg *cfg;
-
-       cfg = kzalloc_node(sizeof(*cfg), GFP_KERNEL, node);
-       if (!cfg)
-               return NULL;
-       if (!zalloc_cpumask_var_node(&cfg->domain, GFP_KERNEL, node))
-               goto out_cfg;
-       if (!zalloc_cpumask_var_node(&cfg->old_domain, GFP_KERNEL, node))
-               goto out_domain;
-       return cfg;
-out_domain:
-       free_cpumask_var(cfg->domain);
-out_cfg:
-       kfree(cfg);
-       return NULL;
-}
-
-static void free_irq_cfg(unsigned int at, struct irq_cfg *cfg)
-{
-       if (!cfg)
-               return;
-       irq_set_chip_data(at, NULL);
-       free_cpumask_var(cfg->domain);
-       free_cpumask_var(cfg->old_domain);
-       kfree(cfg);
-}
-
-static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node)
-{
-       int res = irq_alloc_desc_at(at, node);
-       struct irq_cfg *cfg;
-
-       if (res < 0) {
-               if (res != -EEXIST)
-                       return NULL;
-               cfg = irq_cfg(at);
-               if (cfg)
-                       return cfg;
-       }
-
-       cfg = alloc_irq_cfg(at, node);
-       if (cfg)
-               irq_set_chip_data(at, cfg);
-       else
-               irq_free_desc(at);
-       return cfg;
-}
-
 struct io_apic {
        unsigned int index;
        unsigned int unused[3];
@@ -445,15 +393,12 @@ static void ioapic_mask_entry(int apic, int pin)
  */
 static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pin)
 {
-       struct irq_pin_list **last, *entry;
+       struct irq_pin_list *entry;
 
        /* don't allow duplicates */
-       last = &cfg->irq_2_pin;
-       for_each_irq_pin(entry, cfg->irq_2_pin) {
+       for_each_irq_pin(entry, cfg->irq_2_pin)
                if (entry->apic == apic && entry->pin == pin)
                        return 0;
-               last = &entry->next;
-       }
 
        entry = alloc_irq_pin_list(node);
        if (!entry) {
@@ -464,22 +409,19 @@ static int __add_pin_to_irq_node(struct irq_cfg *cfg, int node, int apic, int pi
        entry->apic = apic;
        entry->pin = pin;
 
-       *last = entry;
+       list_add_tail(&entry->list, &cfg->irq_2_pin);
        return 0;
 }
 
 static void __remove_pin_from_irq(struct irq_cfg *cfg, int apic, int pin)
 {
-       struct irq_pin_list **last, *entry;
+       struct irq_pin_list *tmp, *entry;
 
-       last = &cfg->irq_2_pin;
-       for_each_irq_pin(entry, cfg->irq_2_pin)
+       list_for_each_entry_safe(entry, tmp, &cfg->irq_2_pin, list)
                if (entry->apic == apic && entry->pin == pin) {
-                       *last = entry->next;
+                       list_del(&entry->list);
                        kfree(entry);
                        return;
-               } else {
-                       last = &entry->next;
                }
 }
 
@@ -559,7 +501,7 @@ static void mask_ioapic(struct irq_cfg *cfg)
 
 static void mask_ioapic_irq(struct irq_data *data)
 {
-       mask_ioapic(data->chip_data);
+       mask_ioapic(irqd_cfg(data));
 }
 
 static void __unmask_ioapic(struct irq_cfg *cfg)
@@ -578,7 +520,7 @@ static void unmask_ioapic(struct irq_cfg *cfg)
 
 static void unmask_ioapic_irq(struct irq_data *data)
 {
-       unmask_ioapic(data->chip_data);
+       unmask_ioapic(irqd_cfg(data));
 }
 
 /*
@@ -1164,8 +1106,7 @@ void mp_unmap_irq(int irq)
  * Find a specific PCI IRQ entry.
  * Not an __init, possibly needed by modules
  */
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
-                               struct io_apic_irq_attr *irq_attr)
+int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin)
 {
        int irq, i, best_ioapic = -1, best_idx = -1;
 
@@ -1219,195 +1160,11 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin,
                return -1;
 
 out:
-       irq = pin_2_irq(best_idx, best_ioapic, mp_irqs[best_idx].dstirq,
-                       IOAPIC_MAP_ALLOC);
-       if (irq > 0)
-               set_io_apic_irq_attr(irq_attr, best_ioapic,
-                                    mp_irqs[best_idx].dstirq,
-                                    irq_trigger(best_idx),
-                                    irq_polarity(best_idx));
-       return irq;
+       return pin_2_irq(best_idx, best_ioapic, mp_irqs[best_idx].dstirq,
+                        IOAPIC_MAP_ALLOC);
 }
 EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector);
 
-void lock_vector_lock(void)
-{
-       /* Used to the online set of cpus does not change
-        * during assign_irq_vector.
-        */
-       raw_spin_lock(&vector_lock);
-}
-
-void unlock_vector_lock(void)
-{
-       raw_spin_unlock(&vector_lock);
-}
-
-static int
-__assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
-{
-       /*
-        * NOTE! The local APIC isn't very good at handling
-        * multiple interrupts at the same interrupt level.
-        * As the interrupt level is determined by taking the
-        * vector number and shifting that right by 4, we
-        * want to spread these out a bit so that they don't
-        * all fall in the same interrupt level.
-        *
-        * Also, we've got to be careful not to trash gate
-        * 0x80, because int 0x80 is hm, kind of importantish. ;)
-        */
-       static int current_vector = FIRST_EXTERNAL_VECTOR + VECTOR_OFFSET_START;
-       static int current_offset = VECTOR_OFFSET_START % 16;
-       int cpu, err;
-       cpumask_var_t tmp_mask;
-
-       if (cfg->move_in_progress)
-               return -EBUSY;
-
-       if (!alloc_cpumask_var(&tmp_mask, GFP_ATOMIC))
-               return -ENOMEM;
-
-       /* Only try and allocate irqs on cpus that are present */
-       err = -ENOSPC;
-       cpumask_clear(cfg->old_domain);
-       cpu = cpumask_first_and(mask, cpu_online_mask);
-       while (cpu < nr_cpu_ids) {
-               int new_cpu, vector, offset;
-
-               apic->vector_allocation_domain(cpu, tmp_mask, mask);
-
-               if (cpumask_subset(tmp_mask, cfg->domain)) {
-                       err = 0;
-                       if (cpumask_equal(tmp_mask, cfg->domain))
-                               break;
-                       /*
-                        * New cpumask using the vector is a proper subset of
-                        * the current in use mask. So cleanup the vector
-                        * allocation for the members that are not used anymore.
-                        */
-                       cpumask_andnot(cfg->old_domain, cfg->domain, tmp_mask);
-                       cfg->move_in_progress =
-                          cpumask_intersects(cfg->old_domain, cpu_online_mask);
-                       cpumask_and(cfg->domain, cfg->domain, tmp_mask);
-                       break;
-               }
-
-               vector = current_vector;
-               offset = current_offset;
-next:
-               vector += 16;
-               if (vector >= first_system_vector) {
-                       offset = (offset + 1) % 16;
-                       vector = FIRST_EXTERNAL_VECTOR + offset;
-               }
-
-               if (unlikely(current_vector == vector)) {
-                       cpumask_or(cfg->old_domain, cfg->old_domain, tmp_mask);
-                       cpumask_andnot(tmp_mask, mask, cfg->old_domain);
-                       cpu = cpumask_first_and(tmp_mask, cpu_online_mask);
-                       continue;
-               }
-
-               if (test_bit(vector, used_vectors))
-                       goto next;
-
-               for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask) {
-                       if (per_cpu(vector_irq, new_cpu)[vector] > VECTOR_UNDEFINED)
-                               goto next;
-               }
-               /* Found one! */
-               current_vector = vector;
-               current_offset = offset;
-               if (cfg->vector) {
-                       cpumask_copy(cfg->old_domain, cfg->domain);
-                       cfg->move_in_progress =
-                          cpumask_intersects(cfg->old_domain, cpu_online_mask);
-               }
-               for_each_cpu_and(new_cpu, tmp_mask, cpu_online_mask)
-                       per_cpu(vector_irq, new_cpu)[vector] = irq;
-               cfg->vector = vector;
-               cpumask_copy(cfg->domain, tmp_mask);
-               err = 0;
-               break;
-       }
-       free_cpumask_var(tmp_mask);
-       return err;
-}
-
-int assign_irq_vector(int irq, struct irq_cfg *cfg, const struct cpumask *mask)
-{
-       int err;
-       unsigned long flags;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       err = __assign_irq_vector(irq, cfg, mask);
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-       return err;
-}
-
-static void __clear_irq_vector(int irq, struct irq_cfg *cfg)
-{
-       int cpu, vector;
-
-       BUG_ON(!cfg->vector);
-
-       vector = cfg->vector;
-       for_each_cpu_and(cpu, cfg->domain, cpu_online_mask)
-               per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
-
-       cfg->vector = 0;
-       cpumask_clear(cfg->domain);
-
-       if (likely(!cfg->move_in_progress))
-               return;
-       for_each_cpu_and(cpu, cfg->old_domain, cpu_online_mask) {
-               for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
-                       if (per_cpu(vector_irq, cpu)[vector] != irq)
-                               continue;
-                       per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
-                       break;
-               }
-       }
-       cfg->move_in_progress = 0;
-}
-
-void __setup_vector_irq(int cpu)
-{
-       /* Initialize vector_irq on a new cpu */
-       int irq, vector;
-       struct irq_cfg *cfg;
-
-       /*
-        * vector_lock will make sure that we don't run into irq vector
-        * assignments that might be happening on another cpu in parallel,
-        * while we setup our initial vector to irq mappings.
-        */
-       raw_spin_lock(&vector_lock);
-       /* Mark the inuse vectors */
-       for_each_active_irq(irq) {
-               cfg = irq_cfg(irq);
-               if (!cfg)
-                       continue;
-
-               if (!cpumask_test_cpu(cpu, cfg->domain))
-                       continue;
-               vector = cfg->vector;
-               per_cpu(vector_irq, cpu)[vector] = irq;
-       }
-       /* Mark the free vectors */
-       for (vector = 0; vector < NR_VECTORS; ++vector) {
-               irq = per_cpu(vector_irq, cpu)[vector];
-               if (irq <= VECTOR_UNDEFINED)
-                       continue;
-
-               cfg = irq_cfg(irq);
-               if (!cpumask_test_cpu(cpu, cfg->domain))
-                       per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
-       }
-       raw_spin_unlock(&vector_lock);
-}
-
 static struct irq_chip ioapic_chip;
 
 #ifdef CONFIG_X86_32
@@ -1496,7 +1253,7 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
                                         &dest)) {
                pr_warn("Failed to obtain apicid for ioapic %d, pin %d\n",
                        mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
-               __clear_irq_vector(irq, cfg);
+               clear_irq_vector(irq, cfg);
 
                return;
        }
@@ -1510,7 +1267,7 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg,
        if (x86_io_apic_ops.setup_entry(irq, &entry, dest, cfg->vector, attr)) {
                pr_warn("Failed to setup ioapic entry for ioapic  %d, pin %d\n",
                        mpc_ioapic_id(attr->ioapic), attr->ioapic_pin);
-               __clear_irq_vector(irq, cfg);
+               clear_irq_vector(irq, cfg);
 
                return;
        }
@@ -1641,7 +1398,7 @@ void ioapic_zap_locks(void)
        raw_spin_lock_init(&ioapic_lock);
 }
 
-__apicdebuginit(void) print_IO_APIC(int ioapic_idx)
+static void __init print_IO_APIC(int ioapic_idx)
 {
        union IO_APIC_reg_00 reg_00;
        union IO_APIC_reg_01 reg_01;
@@ -1698,7 +1455,7 @@ __apicdebuginit(void) print_IO_APIC(int ioapic_idx)
        x86_io_apic_ops.print_entries(ioapic_idx, reg_01.bits.entries);
 }
 
-__apicdebuginit(void) print_IO_APICs(void)
+void __init print_IO_APICs(void)
 {
        int ioapic_idx;
        struct irq_cfg *cfg;
@@ -1731,8 +1488,7 @@ __apicdebuginit(void) print_IO_APICs(void)
                cfg = irq_cfg(irq);
                if (!cfg)
                        continue;
-               entry = cfg->irq_2_pin;
-               if (!entry)
+               if (list_empty(&cfg->irq_2_pin))
                        continue;
                printk(KERN_DEBUG "IRQ%d ", irq);
                for_each_irq_pin(entry, cfg->irq_2_pin)
@@ -1743,205 +1499,6 @@ __apicdebuginit(void) print_IO_APICs(void)
        printk(KERN_INFO ".................................... done.\n");
 }
 
-__apicdebuginit(void) print_APIC_field(int base)
-{
-       int i;
-
-       printk(KERN_DEBUG);
-
-       for (i = 0; i < 8; i++)
-               pr_cont("%08x", apic_read(base + i*0x10));
-
-       pr_cont("\n");
-}
-
-__apicdebuginit(void) print_local_APIC(void *dummy)
-{
-       unsigned int i, v, ver, maxlvt;
-       u64 icr;
-
-       printk(KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
-               smp_processor_id(), hard_smp_processor_id());
-       v = apic_read(APIC_ID);
-       printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, read_apic_id());
-       v = apic_read(APIC_LVR);
-       printk(KERN_INFO "... APIC VERSION: %08x\n", v);
-       ver = GET_APIC_VERSION(v);
-       maxlvt = lapic_get_maxlvt();
-
-       v = apic_read(APIC_TASKPRI);
-       printk(KERN_DEBUG "... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
-
-       if (APIC_INTEGRATED(ver)) {                     /* !82489DX */
-               if (!APIC_XAPIC(ver)) {
-                       v = apic_read(APIC_ARBPRI);
-                       printk(KERN_DEBUG "... APIC ARBPRI: %08x (%02x)\n", v,
-                              v & APIC_ARBPRI_MASK);
-               }
-               v = apic_read(APIC_PROCPRI);
-               printk(KERN_DEBUG "... APIC PROCPRI: %08x\n", v);
-       }
-
-       /*
-        * Remote read supported only in the 82489DX and local APIC for
-        * Pentium processors.
-        */
-       if (!APIC_INTEGRATED(ver) || maxlvt == 3) {
-               v = apic_read(APIC_RRR);
-               printk(KERN_DEBUG "... APIC RRR: %08x\n", v);
-       }
-
-       v = apic_read(APIC_LDR);
-       printk(KERN_DEBUG "... APIC LDR: %08x\n", v);
-       if (!x2apic_enabled()) {
-               v = apic_read(APIC_DFR);
-               printk(KERN_DEBUG "... APIC DFR: %08x\n", v);
-       }
-       v = apic_read(APIC_SPIV);
-       printk(KERN_DEBUG "... APIC SPIV: %08x\n", v);
-
-       printk(KERN_DEBUG "... APIC ISR field:\n");
-       print_APIC_field(APIC_ISR);
-       printk(KERN_DEBUG "... APIC TMR field:\n");
-       print_APIC_field(APIC_TMR);
-       printk(KERN_DEBUG "... APIC IRR field:\n");
-       print_APIC_field(APIC_IRR);
-
-       if (APIC_INTEGRATED(ver)) {             /* !82489DX */
-               if (maxlvt > 3)         /* Due to the Pentium erratum 3AP. */
-                       apic_write(APIC_ESR, 0);
-
-               v = apic_read(APIC_ESR);
-               printk(KERN_DEBUG "... APIC ESR: %08x\n", v);
-       }
-
-       icr = apic_icr_read();
-       printk(KERN_DEBUG "... APIC ICR: %08x\n", (u32)icr);
-       printk(KERN_DEBUG "... APIC ICR2: %08x\n", (u32)(icr >> 32));
-
-       v = apic_read(APIC_LVTT);
-       printk(KERN_DEBUG "... APIC LVTT: %08x\n", v);
-
-       if (maxlvt > 3) {                       /* PC is LVT#4. */
-               v = apic_read(APIC_LVTPC);
-               printk(KERN_DEBUG "... APIC LVTPC: %08x\n", v);
-       }
-       v = apic_read(APIC_LVT0);
-       printk(KERN_DEBUG "... APIC LVT0: %08x\n", v);
-       v = apic_read(APIC_LVT1);
-       printk(KERN_DEBUG "... APIC LVT1: %08x\n", v);
-
-       if (maxlvt > 2) {                       /* ERR is LVT#3. */
-               v = apic_read(APIC_LVTERR);
-               printk(KERN_DEBUG "... APIC LVTERR: %08x\n", v);
-       }
-
-       v = apic_read(APIC_TMICT);
-       printk(KERN_DEBUG "... APIC TMICT: %08x\n", v);
-       v = apic_read(APIC_TMCCT);
-       printk(KERN_DEBUG "... APIC TMCCT: %08x\n", v);
-       v = apic_read(APIC_TDCR);
-       printk(KERN_DEBUG "... APIC TDCR: %08x\n", v);
-
-       if (boot_cpu_has(X86_FEATURE_EXTAPIC)) {
-               v = apic_read(APIC_EFEAT);
-               maxlvt = (v >> 16) & 0xff;
-               printk(KERN_DEBUG "... APIC EFEAT: %08x\n", v);
-               v = apic_read(APIC_ECTRL);
-               printk(KERN_DEBUG "... APIC ECTRL: %08x\n", v);
-               for (i = 0; i < maxlvt; i++) {
-                       v = apic_read(APIC_EILVTn(i));
-                       printk(KERN_DEBUG "... APIC EILVT%d: %08x\n", i, v);
-               }
-       }
-       pr_cont("\n");
-}
-
-__apicdebuginit(void) print_local_APICs(int maxcpu)
-{
-       int cpu;
-
-       if (!maxcpu)
-               return;
-
-       preempt_disable();
-       for_each_online_cpu(cpu) {
-               if (cpu >= maxcpu)
-                       break;
-               smp_call_function_single(cpu, print_local_APIC, NULL, 1);
-       }
-       preempt_enable();
-}
-
-__apicdebuginit(void) print_PIC(void)
-{
-       unsigned int v;
-       unsigned long flags;
-
-       if (!nr_legacy_irqs())
-               return;
-
-       printk(KERN_DEBUG "\nprinting PIC contents\n");
-
-       raw_spin_lock_irqsave(&i8259A_lock, flags);
-
-       v = inb(0xa1) << 8 | inb(0x21);
-       printk(KERN_DEBUG "... PIC  IMR: %04x\n", v);
-
-       v = inb(0xa0) << 8 | inb(0x20);
-       printk(KERN_DEBUG "... PIC  IRR: %04x\n", v);
-
-       outb(0x0b,0xa0);
-       outb(0x0b,0x20);
-       v = inb(0xa0) << 8 | inb(0x20);
-       outb(0x0a,0xa0);
-       outb(0x0a,0x20);
-
-       raw_spin_unlock_irqrestore(&i8259A_lock, flags);
-
-       printk(KERN_DEBUG "... PIC  ISR: %04x\n", v);
-
-       v = inb(0x4d1) << 8 | inb(0x4d0);
-       printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
-}
-
-static int __initdata show_lapic = 1;
-static __init int setup_show_lapic(char *arg)
-{
-       int num = -1;
-
-       if (strcmp(arg, "all") == 0) {
-               show_lapic = CONFIG_NR_CPUS;
-       } else {
-               get_option(&arg, &num);
-               if (num >= 0)
-                       show_lapic = num;
-       }
-
-       return 1;
-}
-__setup("show_lapic=", setup_show_lapic);
-
-__apicdebuginit(int) print_ICs(void)
-{
-       if (apic_verbosity == APIC_QUIET)
-               return 0;
-
-       print_PIC();
-
-       /* don't print out if apic is not there */
-       if (!cpu_has_apic && !apic_from_smp_config())
-               return 0;
-
-       print_local_APICs(show_lapic);
-       print_IO_APICs();
-
-       return 0;
-}
-
-late_initcall(print_ICs);
-
-
 /* Where if anywhere is the i8259 connect in external int mode */
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
 
@@ -2244,26 +1801,12 @@ static unsigned int startup_ioapic_irq(struct irq_data *data)
                if (legacy_pic->irq_pending(irq))
                        was_pending = 1;
        }
-       __unmask_ioapic(data->chip_data);
+       __unmask_ioapic(irqd_cfg(data));
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
 
        return was_pending;
 }
 
-static int ioapic_retrigger_irq(struct irq_data *data)
-{
-       struct irq_cfg *cfg = data->chip_data;
-       unsigned long flags;
-       int cpu;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       cpu = cpumask_first_and(cfg->domain, cpu_online_mask);
-       apic->send_IPI_mask(cpumask_of(cpu), cfg->vector);
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-
-       return 1;
-}
-
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -2273,113 +1816,6 @@ static int ioapic_retrigger_irq(struct irq_data *data)
  * races.
  */
 
-#ifdef CONFIG_SMP
-void send_cleanup_vector(struct irq_cfg *cfg)
-{
-       cpumask_var_t cleanup_mask;
-
-       if (unlikely(!alloc_cpumask_var(&cleanup_mask, GFP_ATOMIC))) {
-               unsigned int i;
-               for_each_cpu_and(i, cfg->old_domain, cpu_online_mask)
-                       apic->send_IPI_mask(cpumask_of(i), IRQ_MOVE_CLEANUP_VECTOR);
-       } else {
-               cpumask_and(cleanup_mask, cfg->old_domain, cpu_online_mask);
-               apic->send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
-               free_cpumask_var(cleanup_mask);
-       }
-       cfg->move_in_progress = 0;
-}
-
-asmlinkage __visible void smp_irq_move_cleanup_interrupt(void)
-{
-       unsigned vector, me;
-
-       ack_APIC_irq();
-       irq_enter();
-       exit_idle();
-
-       me = smp_processor_id();
-       for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
-               int irq;
-               unsigned int irr;
-               struct irq_desc *desc;
-               struct irq_cfg *cfg;
-               irq = __this_cpu_read(vector_irq[vector]);
-
-               if (irq <= VECTOR_UNDEFINED)
-                       continue;
-
-               desc = irq_to_desc(irq);
-               if (!desc)
-                       continue;
-
-               cfg = irq_cfg(irq);
-               if (!cfg)
-                       continue;
-
-               raw_spin_lock(&desc->lock);
-
-               /*
-                * Check if the irq migration is in progress. If so, we
-                * haven't received the cleanup request yet for this irq.
-                */
-               if (cfg->move_in_progress)
-                       goto unlock;
-
-               if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
-                       goto unlock;
-
-               irr = apic_read(APIC_IRR + (vector / 32 * 0x10));
-               /*
-                * Check if the vector that needs to be cleanedup is
-                * registered at the cpu's IRR. If so, then this is not
-                * the best time to clean it up. Lets clean it up in the
-                * next attempt by sending another IRQ_MOVE_CLEANUP_VECTOR
-                * to myself.
-                */
-               if (irr  & (1 << (vector % 32))) {
-                       apic->send_IPI_self(IRQ_MOVE_CLEANUP_VECTOR);
-                       goto unlock;
-               }
-               __this_cpu_write(vector_irq[vector], VECTOR_UNDEFINED);
-unlock:
-               raw_spin_unlock(&desc->lock);
-       }
-
-       irq_exit();
-}
-
-static void __irq_complete_move(struct irq_cfg *cfg, unsigned vector)
-{
-       unsigned me;
-
-       if (likely(!cfg->move_in_progress))
-               return;
-
-       me = smp_processor_id();
-
-       if (vector == cfg->vector && cpumask_test_cpu(me, cfg->domain))
-               send_cleanup_vector(cfg);
-}
-
-static void irq_complete_move(struct irq_cfg *cfg)
-{
-       __irq_complete_move(cfg, ~get_irq_regs()->orig_ax);
-}
-
-void irq_force_complete_move(int irq)
-{
-       struct irq_cfg *cfg = irq_cfg(irq);
-
-       if (!cfg)
-               return;
-
-       __irq_complete_move(cfg, cfg->vector);
-}
-#else
-static inline void irq_complete_move(struct irq_cfg *cfg) { }
-#endif
-
 static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq_cfg *cfg)
 {
        int apic, pin;
@@ -2400,71 +1836,29 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, struct irq
        }
 }
 
-/*
- * Either sets data->affinity to a valid value, and returns
- * ->cpu_mask_to_apicid of that in dest_id, or returns -1 and
- * leaves data->affinity untouched.
- */
-int __ioapic_set_affinity(struct irq_data *data, const struct cpumask *mask,
-                         unsigned int *dest_id)
+int native_ioapic_set_affinity(struct irq_data *data,
+                              const struct cpumask *mask,
+                              bool force)
 {
-       struct irq_cfg *cfg = data->chip_data;
-       unsigned int irq = data->irq;
-       int err;
-
-       if (!config_enabled(CONFIG_SMP))
-               return -EPERM;
-
-       if (!cpumask_intersects(mask, cpu_online_mask))
-               return -EINVAL;
-
-       err = assign_irq_vector(irq, cfg, mask);
-       if (err)
-               return err;
-
-       err = apic->cpu_mask_to_apicid_and(mask, cfg->domain, dest_id);
-       if (err) {
-               if (assign_irq_vector(irq, cfg, data->affinity))
-                       pr_err("Failed to recover vector for irq %d\n", irq);
-               return err;
-       }
-
-       cpumask_copy(data->affinity, mask);
-
-       return 0;
-}
-
-
-int native_ioapic_set_affinity(struct irq_data *data,
-                              const struct cpumask *mask,
-                              bool force)
-{
-       unsigned int dest, irq = data->irq;
-       unsigned long flags;
-       int ret;
+       unsigned int dest, irq = data->irq;
+       unsigned long flags;
+       int ret;
 
        if (!config_enabled(CONFIG_SMP))
                return -EPERM;
 
        raw_spin_lock_irqsave(&ioapic_lock, flags);
-       ret = __ioapic_set_affinity(data, mask, &dest);
+       ret = apic_set_affinity(data, mask, &dest);
        if (!ret) {
                /* Only the high 8 bits are valid. */
                dest = SET_APIC_LOGICAL_ID(dest);
-               __target_IO_APIC_irq(irq, dest, data->chip_data);
+               __target_IO_APIC_irq(irq, dest, irqd_cfg(data));
                ret = IRQ_SET_MASK_OK_NOCOPY;
        }
        raw_spin_unlock_irqrestore(&ioapic_lock, flags);
        return ret;
 }
 
-static void ack_apic_edge(struct irq_data *data)
-{
-       irq_complete_move(data->chip_data);
-       irq_move_irq(data);
-       ack_APIC_irq();
-}
-
 atomic_t irq_mis_count;
 
 #ifdef CONFIG_GENERIC_PENDING_IRQ
@@ -2547,9 +1941,9 @@ static inline void ioapic_irqd_unmask(struct irq_data *data,
 }
 #endif
 
-static void ack_apic_level(struct irq_data *data)
+static void ack_ioapic_level(struct irq_data *data)
 {
-       struct irq_cfg *cfg = data->chip_data;
+       struct irq_cfg *cfg = irqd_cfg(data);
        int i, irq = data->irq;
        unsigned long v;
        bool masked;
@@ -2619,10 +2013,10 @@ static struct irq_chip ioapic_chip __read_mostly = {
        .irq_startup            = startup_ioapic_irq,
        .irq_mask               = mask_ioapic_irq,
        .irq_unmask             = unmask_ioapic_irq,
-       .irq_ack                = ack_apic_edge,
-       .irq_eoi                = ack_apic_level,
+       .irq_ack                = apic_ack_edge,
+       .irq_eoi                = ack_ioapic_level,
        .irq_set_affinity       = native_ioapic_set_affinity,
-       .irq_retrigger          = ioapic_retrigger_irq,
+       .irq_retrigger          = apic_retrigger_irq,
        .flags                  = IRQCHIP_SKIP_SET_WAKE,
 };
 
@@ -2965,6 +2359,16 @@ static int mp_irqdomain_create(int ioapic)
        return 0;
 }
 
+static void ioapic_destroy_irqdomain(int idx)
+{
+       if (ioapics[idx].irqdomain) {
+               irq_domain_remove(ioapics[idx].irqdomain);
+               ioapics[idx].irqdomain = NULL;
+       }
+       kfree(ioapics[idx].pin_info);
+       ioapics[idx].pin_info = NULL;
+}
+
 void __init setup_IO_APIC(void)
 {
        int ioapic;
@@ -3044,399 +2448,6 @@ static int __init ioapic_init_ops(void)
 
 device_initcall(ioapic_init_ops);
 
-/*
- * Dynamic irq allocate and deallocation. Should be replaced by irq domains!
- */
-int arch_setup_hwirq(unsigned int irq, int node)
-{
-       struct irq_cfg *cfg;
-       unsigned long flags;
-       int ret;
-
-       cfg = alloc_irq_cfg(irq, node);
-       if (!cfg)
-               return -ENOMEM;
-
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       ret = __assign_irq_vector(irq, cfg, apic->target_cpus());
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-
-       if (!ret)
-               irq_set_chip_data(irq, cfg);
-       else
-               free_irq_cfg(irq, cfg);
-       return ret;
-}
-
-void arch_teardown_hwirq(unsigned int irq)
-{
-       struct irq_cfg *cfg = irq_cfg(irq);
-       unsigned long flags;
-
-       free_remapped_irq(irq);
-       raw_spin_lock_irqsave(&vector_lock, flags);
-       __clear_irq_vector(irq, cfg);
-       raw_spin_unlock_irqrestore(&vector_lock, flags);
-       free_irq_cfg(irq, cfg);
-}
-
-/*
- * MSI message composition
- */
-void native_compose_msi_msg(struct pci_dev *pdev,
-                           unsigned int irq, unsigned int dest,
-                           struct msi_msg *msg, u8 hpet_id)
-{
-       struct irq_cfg *cfg = irq_cfg(irq);
-
-       msg->address_hi = MSI_ADDR_BASE_HI;
-
-       if (x2apic_enabled())
-               msg->address_hi |= MSI_ADDR_EXT_DEST_ID(dest);
-
-       msg->address_lo =
-               MSI_ADDR_BASE_LO |
-               ((apic->irq_dest_mode == 0) ?
-                       MSI_ADDR_DEST_MODE_PHYSICAL:
-                       MSI_ADDR_DEST_MODE_LOGICAL) |
-               ((apic->irq_delivery_mode != dest_LowestPrio) ?
-                       MSI_ADDR_REDIRECTION_CPU:
-                       MSI_ADDR_REDIRECTION_LOWPRI) |
-               MSI_ADDR_DEST_ID(dest);
-
-       msg->data =
-               MSI_DATA_TRIGGER_EDGE |
-               MSI_DATA_LEVEL_ASSERT |
-               ((apic->irq_delivery_mode != dest_LowestPrio) ?
-                       MSI_DATA_DELIVERY_FIXED:
-                       MSI_DATA_DELIVERY_LOWPRI) |
-               MSI_DATA_VECTOR(cfg->vector);
-}
-
-#ifdef CONFIG_PCI_MSI
-static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
-                          struct msi_msg *msg, u8 hpet_id)
-{
-       struct irq_cfg *cfg;
-       int err;
-       unsigned dest;
-
-       if (disable_apic)
-               return -ENXIO;
-
-       cfg = irq_cfg(irq);
-       err = assign_irq_vector(irq, cfg, apic->target_cpus());
-       if (err)
-               return err;
-
-       err = apic->cpu_mask_to_apicid_and(cfg->domain,
-                                          apic->target_cpus(), &dest);
-       if (err)
-               return err;
-
-       x86_msi.compose_msi_msg(pdev, irq, dest, msg, hpet_id);
-
-       return 0;
-}
-
-static int
-msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
-{
-       struct irq_cfg *cfg = data->chip_data;
-       struct msi_msg msg;
-       unsigned int dest;
-       int ret;
-
-       ret = __ioapic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
-
-       __get_cached_msi_msg(data->msi_desc, &msg);
-
-       msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(cfg->vector);
-       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
-
-       __pci_write_msi_msg(data->msi_desc, &msg);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-/*
- * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI or MSI-X Capability Structure.
- */
-static struct irq_chip msi_chip = {
-       .name                   = "PCI-MSI",
-       .irq_unmask             = pci_msi_unmask_irq,
-       .irq_mask               = pci_msi_mask_irq,
-       .irq_ack                = ack_apic_edge,
-       .irq_set_affinity       = msi_set_affinity,
-       .irq_retrigger          = ioapic_retrigger_irq,
-       .flags                  = IRQCHIP_SKIP_SET_WAKE,
-};
-
-int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
-                 unsigned int irq_base, unsigned int irq_offset)
-{
-       struct irq_chip *chip = &msi_chip;
-       struct msi_msg msg;
-       unsigned int irq = irq_base + irq_offset;
-       int ret;
-
-       ret = msi_compose_msg(dev, irq, &msg, -1);
-       if (ret < 0)
-               return ret;
-
-       irq_set_msi_desc_off(irq_base, irq_offset, msidesc);
-
-       /*
-        * MSI-X message is written per-IRQ, the offset is always 0.
-        * MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
-        */
-       if (!irq_offset)
-               pci_write_msi_msg(irq, &msg);
-
-       setup_remapped_irq(irq, irq_cfg(irq), chip);
-
-       irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
-
-       dev_printk(KERN_DEBUG, &dev->dev, "irq %d for MSI/MSI-X\n", irq);
-
-       return 0;
-}
-
-int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
-{
-       struct msi_desc *msidesc;
-       unsigned int irq;
-       int node, ret;
-
-       /* Multiple MSI vectors only supported with interrupt remapping */
-       if (type == PCI_CAP_ID_MSI && nvec > 1)
-               return 1;
-
-       node = dev_to_node(&dev->dev);
-
-       list_for_each_entry(msidesc, &dev->msi_list, list) {
-               irq = irq_alloc_hwirq(node);
-               if (!irq)
-                       return -ENOSPC;
-
-               ret = setup_msi_irq(dev, msidesc, irq, 0);
-               if (ret < 0) {
-                       irq_free_hwirq(irq);
-                       return ret;
-               }
-
-       }
-       return 0;
-}
-
-void native_teardown_msi_irq(unsigned int irq)
-{
-       irq_free_hwirq(irq);
-}
-
-#ifdef CONFIG_DMAR_TABLE
-static int
-dmar_msi_set_affinity(struct irq_data *data, const struct cpumask *mask,
-                     bool force)
-{
-       struct irq_cfg *cfg = data->chip_data;
-       unsigned int dest, irq = data->irq;
-       struct msi_msg msg;
-       int ret;
-
-       ret = __ioapic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
-
-       dmar_msi_read(irq, &msg);
-
-       msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(cfg->vector);
-       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
-       msg.address_hi = MSI_ADDR_BASE_HI | MSI_ADDR_EXT_DEST_ID(dest);
-
-       dmar_msi_write(irq, &msg);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-static struct irq_chip dmar_msi_type = {
-       .name                   = "DMAR_MSI",
-       .irq_unmask             = dmar_msi_unmask,
-       .irq_mask               = dmar_msi_mask,
-       .irq_ack                = ack_apic_edge,
-       .irq_set_affinity       = dmar_msi_set_affinity,
-       .irq_retrigger          = ioapic_retrigger_irq,
-       .flags                  = IRQCHIP_SKIP_SET_WAKE,
-};
-
-int arch_setup_dmar_msi(unsigned int irq)
-{
-       int ret;
-       struct msi_msg msg;
-
-       ret = msi_compose_msg(NULL, irq, &msg, -1);
-       if (ret < 0)
-               return ret;
-       dmar_msi_write(irq, &msg);
-       irq_set_chip_and_handler_name(irq, &dmar_msi_type, handle_edge_irq,
-                                     "edge");
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_HPET_TIMER
-
-static int hpet_msi_set_affinity(struct irq_data *data,
-                                const struct cpumask *mask, bool force)
-{
-       struct irq_cfg *cfg = data->chip_data;
-       struct msi_msg msg;
-       unsigned int dest;
-       int ret;
-
-       ret = __ioapic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
-
-       hpet_msi_read(data->handler_data, &msg);
-
-       msg.data &= ~MSI_DATA_VECTOR_MASK;
-       msg.data |= MSI_DATA_VECTOR(cfg->vector);
-       msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
-       msg.address_lo |= MSI_ADDR_DEST_ID(dest);
-
-       hpet_msi_write(data->handler_data, &msg);
-
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-static struct irq_chip hpet_msi_type = {
-       .name = "HPET_MSI",
-       .irq_unmask = hpet_msi_unmask,
-       .irq_mask = hpet_msi_mask,
-       .irq_ack = ack_apic_edge,
-       .irq_set_affinity = hpet_msi_set_affinity,
-       .irq_retrigger = ioapic_retrigger_irq,
-       .flags = IRQCHIP_SKIP_SET_WAKE,
-};
-
-int default_setup_hpet_msi(unsigned int irq, unsigned int id)
-{
-       struct irq_chip *chip = &hpet_msi_type;
-       struct msi_msg msg;
-       int ret;
-
-       ret = msi_compose_msg(NULL, irq, &msg, id);
-       if (ret < 0)
-               return ret;
-
-       hpet_msi_write(irq_get_handler_data(irq), &msg);
-       irq_set_status_flags(irq, IRQ_MOVE_PCNTXT);
-       setup_remapped_irq(irq, irq_cfg(irq), chip);
-
-       irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge");
-       return 0;
-}
-#endif
-
-#endif /* CONFIG_PCI_MSI */
-/*
- * Hypertransport interrupt support
- */
-#ifdef CONFIG_HT_IRQ
-
-static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
-{
-       struct ht_irq_msg msg;
-       fetch_ht_irq_msg(irq, &msg);
-
-       msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
-       msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
-
-       msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
-       msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
-
-       write_ht_irq_msg(irq, &msg);
-}
-
-static int
-ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
-{
-       struct irq_cfg *cfg = data->chip_data;
-       unsigned int dest;
-       int ret;
-
-       ret = __ioapic_set_affinity(data, mask, &dest);
-       if (ret)
-               return ret;
-
-       target_ht_irq(data->irq, dest, cfg->vector);
-       return IRQ_SET_MASK_OK_NOCOPY;
-}
-
-static struct irq_chip ht_irq_chip = {
-       .name                   = "PCI-HT",
-       .irq_mask               = mask_ht_irq,
-       .irq_unmask             = unmask_ht_irq,
-       .irq_ack                = ack_apic_edge,
-       .irq_set_affinity       = ht_set_affinity,
-       .irq_retrigger          = ioapic_retrigger_irq,
-       .flags                  = IRQCHIP_SKIP_SET_WAKE,
-};
-
-int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
-{
-       struct irq_cfg *cfg;
-       struct ht_irq_msg msg;
-       unsigned dest;
-       int err;
-
-       if (disable_apic)
-               return -ENXIO;
-
-       cfg = irq_cfg(irq);
-       err = assign_irq_vector(irq, cfg, apic->target_cpus());
-       if (err)
-               return err;
-
-       err = apic->cpu_mask_to_apicid_and(cfg->domain,
-                                          apic->target_cpus(), &dest);
-       if (err)
-               return err;
-
-       msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
-
-       msg.address_lo =
-               HT_IRQ_LOW_BASE |
-               HT_IRQ_LOW_DEST_ID(dest) |
-               HT_IRQ_LOW_VECTOR(cfg->vector) |
-               ((apic->irq_dest_mode == 0) ?
-                       HT_IRQ_LOW_DM_PHYSICAL :
-                       HT_IRQ_LOW_DM_LOGICAL) |
-               HT_IRQ_LOW_RQEOI_EDGE |
-               ((apic->irq_delivery_mode != dest_LowestPrio) ?
-                       HT_IRQ_LOW_MT_FIXED :
-                       HT_IRQ_LOW_MT_ARBITRATED) |
-               HT_IRQ_LOW_IRQ_MASKED;
-
-       write_ht_irq_msg(irq, &msg);
-
-       irq_set_chip_and_handler_name(irq, &ht_irq_chip,
-                                     handle_edge_irq, "edge");
-
-       dev_printk(KERN_DEBUG, &dev->dev, "irq %d for HT\n", irq);
-
-       return 0;
-}
-#endif /* CONFIG_HT_IRQ */
-
 static int
 io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
 {
@@ -3451,7 +2462,7 @@ io_apic_setup_irq_pin(unsigned int irq, int node, struct io_apic_irq_attr *attr)
        return ret;
 }
 
-static int __init io_apic_get_redir_entries(int ioapic)
+static int io_apic_get_redir_entries(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
        unsigned long flags;
@@ -3476,28 +2487,8 @@ unsigned int arch_dynirq_lower_bound(unsigned int from)
        return ioapic_initialized ? ioapic_dynirq_base : gsi_top;
 }
 
-int __init arch_probe_nr_irqs(void)
-{
-       int nr;
-
-       if (nr_irqs > (NR_VECTORS * nr_cpu_ids))
-               nr_irqs = NR_VECTORS * nr_cpu_ids;
-
-       nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids;
-#if defined(CONFIG_PCI_MSI) || defined(CONFIG_HT_IRQ)
-       /*
-        * for MSI and HT dyn irq
-        */
-       nr += gsi_top * 16;
-#endif
-       if (nr < nr_irqs)
-               nr_irqs = nr;
-
-       return 0;
-}
-
 #ifdef CONFIG_X86_32
-static int __init io_apic_get_unique_id(int ioapic, int apic_id)
+static int io_apic_get_unique_id(int ioapic, int apic_id)
 {
        union IO_APIC_reg_00 reg_00;
        static physid_mask_t apic_id_map = PHYSID_MASK_NONE;
@@ -3572,30 +2563,63 @@ static int __init io_apic_get_unique_id(int ioapic, int apic_id)
        return apic_id;
 }
 
-static u8 __init io_apic_unique_id(u8 id)
+static u8 io_apic_unique_id(int idx, u8 id)
 {
        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);
+               return io_apic_get_unique_id(idx, id);
        else
                return id;
 }
 #else
-static u8 __init io_apic_unique_id(u8 id)
+static u8 io_apic_unique_id(int idx, u8 id)
 {
-       int i;
+       union IO_APIC_reg_00 reg_00;
        DECLARE_BITMAP(used, 256);
+       unsigned long flags;
+       u8 new_id;
+       int i;
 
        bitmap_zero(used, 256);
        for_each_ioapic(i)
                __set_bit(mpc_ioapic_id(i), used);
+
+       /* Hand out the requested id if available */
        if (!test_bit(id, used))
                return id;
-       return find_first_zero_bit(used, 256);
+
+       /*
+        * Read the current id from the ioapic and keep it if
+        * available.
+        */
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
+       reg_00.raw = io_apic_read(idx, 0);
+       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+       new_id = reg_00.bits.ID;
+       if (!test_bit(new_id, used)) {
+               apic_printk(APIC_VERBOSE, KERN_INFO
+                       "IOAPIC[%d]: Using reg apic_id %d instead of %d\n",
+                        idx, new_id, id);
+               return new_id;
+       }
+
+       /*
+        * Get the next free id and write it to the ioapic.
+        */
+       new_id = find_first_zero_bit(used, 256);
+       reg_00.bits.ID = new_id;
+       raw_spin_lock_irqsave(&ioapic_lock, flags);
+       io_apic_write(idx, 0, reg_00.raw);
+       reg_00.raw = io_apic_read(idx, 0);
+       raw_spin_unlock_irqrestore(&ioapic_lock, flags);
+       /* Sanity check */
+       BUG_ON(reg_00.bits.ID != new_id);
+
+       return new_id;
 }
 #endif
 
-static int __init io_apic_get_version(int ioapic)
+static int io_apic_get_version(int ioapic)
 {
        union IO_APIC_reg_01    reg_01;
        unsigned long flags;
@@ -3702,6 +2726,7 @@ static struct resource * __init ioapic_setup_resources(void)
                snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
                mem += IOAPIC_RESOURCE_NAME_SIZE;
                num++;
+               ioapics[i].iomem_res = res;
        }
 
        ioapic_resources = res;
@@ -3799,21 +2824,7 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi)
        return gsi - gsi_cfg->gsi_base;
 }
 
-static __init int bad_ioapic(unsigned long address)
-{
-       if (nr_ioapics >= MAX_IO_APICS) {
-               pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
-                       MAX_IO_APICS, nr_ioapics);
-               return 1;
-       }
-       if (!address) {
-               pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n");
-               return 1;
-       }
-       return 0;
-}
-
-static __init int bad_ioapic_register(int idx)
+static int bad_ioapic_register(int idx)
 {
        union IO_APIC_reg_00 reg_00;
        union IO_APIC_reg_01 reg_01;
@@ -3832,32 +2843,61 @@ static __init int bad_ioapic_register(int idx)
        return 0;
 }
 
-void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
-                              struct ioapic_domain_cfg *cfg)
+static int find_free_ioapic_entry(void)
 {
-       int idx = 0;
-       int entries;
+       int idx;
+
+       for (idx = 0; idx < MAX_IO_APICS; idx++)
+               if (ioapics[idx].nr_registers == 0)
+                       return idx;
+
+       return MAX_IO_APICS;
+}
+
+/**
+ * mp_register_ioapic - Register an IOAPIC device
+ * @id:                hardware IOAPIC ID
+ * @address:   physical address of IOAPIC register area
+ * @gsi_base:  base of GSI associated with the IOAPIC
+ * @cfg:       configuration information for the IOAPIC
+ */
+int mp_register_ioapic(int id, u32 address, u32 gsi_base,
+                      struct ioapic_domain_cfg *cfg)
+{
+       bool hotplug = !!ioapic_initialized;
        struct mp_ioapic_gsi *gsi_cfg;
+       int idx, ioapic, entries;
+       u32 gsi_end;
 
-       if (bad_ioapic(address))
-               return;
+       if (!address) {
+               pr_warn("Bogus (zero) I/O APIC address found, skipping!\n");
+               return -EINVAL;
+       }
+       for_each_ioapic(ioapic)
+               if (ioapics[ioapic].mp_config.apicaddr == address) {
+                       pr_warn("address 0x%x conflicts with IOAPIC%d\n",
+                               address, ioapic);
+                       return -EEXIST;
+               }
 
-       idx = nr_ioapics;
+       idx = find_free_ioapic_entry();
+       if (idx >= MAX_IO_APICS) {
+               pr_warn("Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
+                       MAX_IO_APICS, idx);
+               return -ENOSPC;
+       }
 
        ioapics[idx].mp_config.type = MP_IOAPIC;
        ioapics[idx].mp_config.flags = MPC_APIC_USABLE;
        ioapics[idx].mp_config.apicaddr = address;
-       ioapics[idx].irqdomain = NULL;
-       ioapics[idx].irqdomain_cfg = *cfg;
 
        set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
-
        if (bad_ioapic_register(idx)) {
                clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
-               return;
+               return -ENODEV;
        }
 
-       ioapics[idx].mp_config.apicid = io_apic_unique_id(id);
+       ioapics[idx].mp_config.apicid = io_apic_unique_id(idx, id);
        ioapics[idx].mp_config.apicver = io_apic_get_version(idx);
 
        /*
@@ -3865,24 +2905,112 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base,
         * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
         */
        entries = io_apic_get_redir_entries(idx);
+       gsi_end = gsi_base + entries - 1;
+       for_each_ioapic(ioapic) {
+               gsi_cfg = mp_ioapic_gsi_routing(ioapic);
+               if ((gsi_base >= gsi_cfg->gsi_base &&
+                    gsi_base <= gsi_cfg->gsi_end) ||
+                   (gsi_end >= gsi_cfg->gsi_base &&
+                    gsi_end <= gsi_cfg->gsi_end)) {
+                       pr_warn("GSI range [%u-%u] for new IOAPIC conflicts with GSI[%u-%u]\n",
+                               gsi_base, gsi_end,
+                               gsi_cfg->gsi_base, gsi_cfg->gsi_end);
+                       clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+                       return -ENOSPC;
+               }
+       }
        gsi_cfg = mp_ioapic_gsi_routing(idx);
        gsi_cfg->gsi_base = gsi_base;
-       gsi_cfg->gsi_end = gsi_base + entries - 1;
+       gsi_cfg->gsi_end = gsi_end;
+
+       ioapics[idx].irqdomain = NULL;
+       ioapics[idx].irqdomain_cfg = *cfg;
 
        /*
-        * The number of IO-APIC IRQ registers (== #pins):
+        * If mp_register_ioapic() is called during early boot stage when
+        * walking ACPI/SFI/DT tables, it's too early to create irqdomain,
+        * we are still using bootmem allocator. So delay it to setup_IO_APIC().
         */
-       ioapics[idx].nr_registers = entries;
+       if (hotplug) {
+               if (mp_irqdomain_create(idx)) {
+                       clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
+                       return -ENOMEM;
+               }
+               alloc_ioapic_saved_registers(idx);
+       }
 
        if (gsi_cfg->gsi_end >= gsi_top)
                gsi_top = gsi_cfg->gsi_end + 1;
+       if (nr_ioapics <= idx)
+               nr_ioapics = idx + 1;
+
+       /* Set nr_registers to mark entry present */
+       ioapics[idx].nr_registers = entries;
 
        pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n",
                idx, mpc_ioapic_id(idx),
                mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
                gsi_cfg->gsi_base, gsi_cfg->gsi_end);
 
-       nr_ioapics++;
+       return 0;
+}
+
+int mp_unregister_ioapic(u32 gsi_base)
+{
+       int ioapic, pin;
+       int found = 0;
+       struct mp_pin_info *pin_info;
+
+       for_each_ioapic(ioapic)
+               if (ioapics[ioapic].gsi_config.gsi_base == gsi_base) {
+                       found = 1;
+                       break;
+               }
+       if (!found) {
+               pr_warn("can't find IOAPIC for GSI %d\n", gsi_base);
+               return -ENODEV;
+       }
+
+       for_each_pin(ioapic, pin) {
+               pin_info = mp_pin_info(ioapic, pin);
+               if (pin_info->count) {
+                       pr_warn("pin%d on IOAPIC%d is still in use.\n",
+                               pin, ioapic);
+                       return -EBUSY;
+               }
+       }
+
+       /* Mark entry not present */
+       ioapics[ioapic].nr_registers  = 0;
+       ioapic_destroy_irqdomain(ioapic);
+       free_ioapic_saved_registers(ioapic);
+       if (ioapics[ioapic].iomem_res)
+               release_resource(ioapics[ioapic].iomem_res);
+       clear_fixmap(FIX_IO_APIC_BASE_0 + ioapic);
+       memset(&ioapics[ioapic], 0, sizeof(ioapics[ioapic]));
+
+       return 0;
+}
+
+int mp_ioapic_registered(u32 gsi_base)
+{
+       int ioapic;
+
+       for_each_ioapic(ioapic)
+               if (ioapics[ioapic].gsi_config.gsi_base == gsi_base)
+                       return 1;
+
+       return 0;
+}
+
+static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
+                                       int ioapic, int ioapic_pin,
+                                       int trigger, int polarity)
+{
+       irq_attr->ioapic        = ioapic;
+       irq_attr->ioapic_pin    = ioapic_pin;
+       irq_attr->trigger       = trigger;
+       irq_attr->polarity      = polarity;
 }
 
 int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
@@ -3931,7 +3059,7 @@ void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq)
 
        ioapic_mask_entry(ioapic, pin);
        __remove_pin_from_irq(cfg, ioapic, pin);
-       WARN_ON(cfg->irq_2_pin != NULL);
+       WARN_ON(!list_empty(&cfg->irq_2_pin));
        arch_teardown_hwirq(virq);
 }
 
@@ -3964,18 +3092,6 @@ int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
        return ret;
 }
 
-bool mp_should_keep_irq(struct device *dev)
-{
-       if (dev->power.is_prepared)
-               return true;
-#ifdef CONFIG_PM
-       if (dev->power.runtime_status == RPM_SUSPENDING)
-               return true;
-#endif
-
-       return false;
-}
-
 /* Enable IOAPIC early just for system timer */
 void __init pre_init_apic_IRQ0(void)
 {