]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/io_apic_32.c
x86: make 32bit to use irq_2_pin in irq_cfg
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / io_apic_32.c
index 923be1f4a6d0d0d36c9a75e244fb995c4c1e6944..59d2e8a273e31ac8452a3e5df25659f71bf8d54b 100644 (file)
 #include <asm/nmi.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
+#include <asm/setup.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
 
+#define __apicdebuginit(type) static type __init
+
 int (*ioapic_renumber_irq)(int ioapic, int irq);
 atomic_t irq_mis_count;
 
@@ -67,6 +70,7 @@ int timer_through_8259 __initdata;
  */
 int sis_apic_bug = -1;
 
+int first_free_entry;
 /*
  * # of IRQ routing registers
  */
@@ -90,12 +94,180 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES);
 
 static int disable_timer_pin_1 __initdata;
 
+struct irq_cfg;
+struct irq_pin_list;
+struct irq_cfg {
+       unsigned int irq;
+       struct irq_cfg *next;
+       struct irq_pin_list *irq_2_pin;
+       u8 vector;
+};
+
+
+/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
+static struct irq_cfg irq_cfg_legacy[] __initdata = {
+       [0]  = { .irq =  0, .vector = IRQ0_VECTOR,  },
+       [1]  = { .irq =  1, .vector = IRQ1_VECTOR,  },
+       [2]  = { .irq =  2, .vector = IRQ2_VECTOR,  },
+       [3]  = { .irq =  3, .vector = IRQ3_VECTOR,  },
+       [4]  = { .irq =  4, .vector = IRQ4_VECTOR,  },
+       [5]  = { .irq =  5, .vector = IRQ5_VECTOR,  },
+       [6]  = { .irq =  6, .vector = IRQ6_VECTOR,  },
+       [7]  = { .irq =  7, .vector = IRQ7_VECTOR,  },
+       [8]  = { .irq =  8, .vector = IRQ8_VECTOR,  },
+       [9]  = { .irq =  9, .vector = IRQ9_VECTOR,  },
+       [10] = { .irq = 10, .vector = IRQ10_VECTOR, },
+       [11] = { .irq = 11, .vector = IRQ11_VECTOR, },
+       [12] = { .irq = 12, .vector = IRQ12_VECTOR, },
+       [13] = { .irq = 13, .vector = IRQ13_VECTOR, },
+       [14] = { .irq = 14, .vector = IRQ14_VECTOR, },
+       [15] = { .irq = 15, .vector = IRQ15_VECTOR, },
+};
+
+static struct irq_cfg irq_cfg_init = { .irq =  -1U, };
+/* need to be biger than size of irq_cfg_legacy */
+static int nr_irq_cfg = 32;
+
+static int __init parse_nr_irq_cfg(char *arg)
+{
+       if (arg) {
+               nr_irq_cfg = simple_strtoul(arg, NULL, 0);
+               if (nr_irq_cfg < 32)
+                       nr_irq_cfg = 32;
+       }
+       return 0;
+}
+
+early_param("nr_irq_cfg", parse_nr_irq_cfg);
+
+static void init_one_irq_cfg(struct irq_cfg *cfg)
+{
+       memcpy(cfg, &irq_cfg_init, sizeof(struct irq_cfg));
+}
+
+static struct irq_cfg *irq_cfgx;
+static struct irq_cfg *irq_cfgx_free;
+static void __init init_work(void *data)
+{
+       struct dyn_array *da = data;
+       struct irq_cfg *cfg;
+       int legacy_count;
+       int i;
+
+       cfg = *da->name;
+
+       memcpy(cfg, irq_cfg_legacy, sizeof(irq_cfg_legacy));
+
+       legacy_count = sizeof(irq_cfg_legacy)/sizeof(irq_cfg_legacy[0]);
+       for (i = legacy_count; i < *da->nr; i++)
+               init_one_irq_cfg(&cfg[i]);
+
+       for (i = 1; i < *da->nr; i++)
+               cfg[i-1].next = &cfg[i];
+
+       irq_cfgx_free = &irq_cfgx[legacy_count];
+       irq_cfgx[legacy_count - 1].next = NULL;
+}
+
+#define for_each_irq_cfg(cfg)           \
+       for (cfg = irq_cfgx; cfg; cfg = cfg->next)
+
+DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irq_cfg, PAGE_SIZE, init_work);
+
+static struct irq_cfg *irq_cfg(unsigned int irq)
+{
+       struct irq_cfg *cfg;
+
+       cfg = irq_cfgx;
+       while (cfg) {
+               if (cfg->irq == irq)
+                       return cfg;
+
+               cfg = cfg->next;
+       }
+
+       return NULL;
+}
+
+static struct irq_cfg *irq_cfg_alloc(unsigned int irq)
+{
+       struct irq_cfg *cfg, *cfg_pri;
+       int i;
+       int count = 0;
+
+       cfg_pri = cfg = irq_cfgx;
+       while (cfg) {
+               if (cfg->irq == irq)
+                       return cfg;
+
+               cfg_pri = cfg;
+               cfg = cfg->next;
+               count++;
+       }
+
+       if (!irq_cfgx_free) {
+               unsigned long phys;
+               unsigned long total_bytes;
+               /*
+                *  we run out of pre-allocate ones, allocate more
+                */
+               printk(KERN_DEBUG "try to get more irq_cfg %d\n", nr_irq_cfg);
+
+               total_bytes = sizeof(struct irq_cfg) * nr_irq_cfg;
+               if (after_bootmem)
+                       cfg = kzalloc(total_bytes, GFP_ATOMIC);
+               else
+                       cfg = __alloc_bootmem_nopanic(total_bytes, PAGE_SIZE, 0);
+
+               if (!cfg)
+                       panic("please boot with nr_irq_cfg= %d\n", count * 2);
+
+               phys = __pa(cfg);
+               printk(KERN_DEBUG "irq_irq ==> [%#lx - %#lx]\n", phys, phys + total_bytes);
+
+               for (i = 0; i < nr_irq_cfg; i++)
+                       init_one_irq_cfg(&cfg[i]);
+
+               for (i = 1; i < nr_irq_cfg; i++)
+                       cfg[i-1].next = &cfg[i];
+
+               irq_cfgx_free = cfg;
+       }
+
+       cfg = irq_cfgx_free;
+       irq_cfgx_free = irq_cfgx_free->next;
+       cfg->next = NULL;
+       if (cfg_pri)
+               cfg_pri->next = cfg;
+       else
+               irq_cfgx = cfg;
+       cfg->irq = irq;
+       printk(KERN_DEBUG "found new irq_cfg for irq %d\n", cfg->irq);
+
+#ifdef CONFIG_HAVE_SPARSE_IRQ_DEBUG
+       {
+               /* dump the results */
+               struct irq_cfg *cfg;
+               unsigned long phys;
+               unsigned long bytes = sizeof(struct irq_cfg);
+
+               printk(KERN_DEBUG "=========================== %d\n", irq);
+               printk(KERN_DEBUG "irq_cfg dump after get that for %d\n", irq);
+               for_each_irq_cfg(cfg) {
+                       phys = __pa(cfg);
+                       printk(KERN_DEBUG "irq_cfg %d ==> [%#lx - %#lx]\n", cfg->irq, phys, phys + bytes);
+               }
+               printk(KERN_DEBUG "===========================\n");
+       }
+#endif
+       return cfg;
+}
+
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
  */
-#define MAX_PLUS_SHARED_IRQS NR_IRQS
-#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
+int pin_map_size;
 
 /*
  * This is performance-critical, we want to do it O(1)
@@ -104,9 +276,66 @@ static int disable_timer_pin_1 __initdata;
  * between pins and IRQs.
  */
 
-static struct irq_pin_list {
-       int apic, pin, next;
-} irq_2_pin[PIN_MAP_SIZE];
+struct irq_pin_list {
+       int apic, pin;
+       struct irq_pin_list *next;
+};
+
+static struct irq_pin_list *irq_2_pin_head;
+/* fill one page ? */
+static int nr_irq_2_pin = 0x100;
+static struct irq_pin_list *irq_2_pin_ptr;
+static void __init irq_2_pin_init_work(void *data)
+{
+       struct dyn_array *da = data;
+       struct irq_pin_list *pin;
+       int i;
+
+       pin = *da->name;
+
+       for (i = 1; i < *da->nr; i++)
+               pin[i-1].next = &pin[i];
+
+       irq_2_pin_ptr = &pin[0];
+}
+DEFINE_DYN_ARRAY(irq_2_pin_head, sizeof(struct irq_pin_list), nr_irq_2_pin, PAGE_SIZE, irq_2_pin_init_work);
+
+static struct irq_pin_list *get_one_free_irq_2_pin(void)
+{
+       struct irq_pin_list *pin;
+       int i;
+
+       pin = irq_2_pin_ptr;
+
+       if (pin) {
+               irq_2_pin_ptr = pin->next;
+               pin->next = NULL;
+               return pin;
+       }
+
+       /*
+        *  we run out of pre-allocate ones, allocate more
+        */
+       printk(KERN_DEBUG "try to get more irq_2_pin %d\n", nr_irq_2_pin);
+
+       if (after_bootmem)
+               pin = kzalloc(sizeof(struct irq_pin_list)*nr_irq_2_pin,
+                                GFP_ATOMIC);
+       else
+               pin = __alloc_bootmem_nopanic(sizeof(struct irq_pin_list) *
+                               nr_irq_2_pin, PAGE_SIZE, 0);
+
+       if (!pin)
+               panic("can not get more irq_2_pin\n");
+
+       for (i = 1; i < nr_irq_2_pin; i++)
+               pin[i-1].next = &pin[i];
+
+       irq_2_pin_ptr = pin->next;
+       pin->next = NULL;
+
+       return pin;
+}
 
 struct io_apic {
        unsigned int index;
@@ -210,20 +439,34 @@ static void ioapic_mask_entry(int apic, int pin)
  */
 static void add_pin_to_irq(unsigned int irq, int apic, int pin)
 {
-       static int first_free_entry = NR_IRQS;
-       struct irq_pin_list *entry = irq_2_pin + irq;
+       struct irq_cfg *cfg;
+       struct irq_pin_list *entry;
+
+       /* first time to refer irq_cfg, so with new */
+       cfg = irq_cfg_alloc(irq);
+       entry = cfg->irq_2_pin;
+       if (!entry) {
+               entry = get_one_free_irq_2_pin();
+               cfg->irq_2_pin = entry;
+               entry->apic = apic;
+               entry->pin = pin;
+               printk(KERN_DEBUG " 0 add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin);
+               return;
+       }
 
-       while (entry->next)
-               entry = irq_2_pin + entry->next;
+       while (entry->next) {
+               /* not again, please */
+               if (entry->apic == apic && entry->pin == pin)
+                       return;
 
-       if (entry->pin != -1) {
-               entry->next = first_free_entry;
-               entry = irq_2_pin + entry->next;
-               if (++first_free_entry >= PIN_MAP_SIZE)
-                       panic("io_apic.c: whoops");
+               entry = entry->next;
        }
+
+       entry->next = get_one_free_irq_2_pin();
+       entry = entry->next;
        entry->apic = apic;
        entry->pin = pin;
+       printk(KERN_DEBUG " x add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin);
 }
 
 /*
@@ -233,35 +476,45 @@ static void __init replace_pin_at_irq(unsigned int irq,
                                      int oldapic, int oldpin,
                                      int newapic, int newpin)
 {
-       struct irq_pin_list *entry = irq_2_pin + irq;
+       struct irq_cfg *cfg = irq_cfg(irq);
+       struct irq_pin_list *entry = cfg->irq_2_pin;
+       int replaced = 0;
 
-       while (1) {
+       while (entry) {
                if (entry->apic == oldapic && entry->pin == oldpin) {
                        entry->apic = newapic;
                        entry->pin = newpin;
-               }
-               if (!entry->next)
+                       replaced = 1;
+                       /* every one is different, right? */
                        break;
-               entry = irq_2_pin + entry->next;
+               }
+               entry = entry->next;
        }
+
+       /* why? call replace before add? */
+       if (!replaced)
+               add_pin_to_irq(irq, newapic, newpin);
 }
 
 static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable)
 {
-       struct irq_pin_list *entry = irq_2_pin + irq;
+       struct irq_cfg *cfg;
+       struct irq_pin_list *entry;
        unsigned int pin, reg;
 
+       cfg = irq_cfg(irq);
+       entry = cfg->irq_2_pin;
        for (;;) {
-               pin = entry->pin;
-               if (pin == -1)
+               if (!entry)
                        break;
+               pin = entry->pin;
                reg = io_apic_read(entry->apic, 0x10 + pin*2);
                reg &= ~disable;
                reg |= enable;
                io_apic_modify(entry->apic, 0x10 + pin*2, reg);
                if (!entry->next)
                        break;
-               entry = irq_2_pin + entry->next;
+               entry = entry->next;
        }
 }
 
@@ -336,11 +589,17 @@ static void clear_IO_APIC(void)
 #ifdef CONFIG_SMP
 static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
 {
+       struct irq_cfg *cfg;
        unsigned long flags;
        int pin;
-       struct irq_pin_list *entry = irq_2_pin + irq;
+       struct irq_pin_list *entry;
        unsigned int apicid_value;
        cpumask_t tmp;
+       struct irq_desc *desc;
+
+
+       cfg = irq_cfg(irq);
+       entry = cfg->irq_2_pin;
 
        cpus_and(tmp, cpumask, cpu_online_map);
        if (cpus_empty(tmp))
@@ -353,394 +612,19 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
        apicid_value = apicid_value << 24;
        spin_lock_irqsave(&ioapic_lock, flags);
        for (;;) {
-               pin = entry->pin;
-               if (pin == -1)
+               if (!entry)
                        break;
+               pin = entry->pin;
                io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value);
                if (!entry->next)
                        break;
-               entry = irq_2_pin + entry->next;
+               entry = entry->next;
        }
-       irq_desc[irq].affinity = cpumask;
+       desc = irq_to_desc(irq);
+       desc->affinity = cpumask;
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
 
-#if defined(CONFIG_IRQBALANCE)
-# include <asm/processor.h>    /* kernel_thread() */
-# include <linux/kernel_stat.h>        /* kstat */
-# include <linux/slab.h>               /* kmalloc() */
-# include <linux/timer.h>
-
-#define IRQBALANCE_CHECK_ARCH -999
-#define MAX_BALANCED_IRQ_INTERVAL      (5*HZ)
-#define MIN_BALANCED_IRQ_INTERVAL      (HZ/2)
-#define BALANCED_IRQ_MORE_DELTA                (HZ/10)
-#define BALANCED_IRQ_LESS_DELTA                (HZ)
-
-static int irqbalance_disabled __read_mostly = IRQBALANCE_CHECK_ARCH;
-static int physical_balance __read_mostly;
-static long balanced_irq_interval __read_mostly = MAX_BALANCED_IRQ_INTERVAL;
-
-static struct irq_cpu_info {
-       unsigned long *last_irq;
-       unsigned long *irq_delta;
-       unsigned long irq;
-} irq_cpu_data[NR_CPUS];
-
-#define CPU_IRQ(cpu)           (irq_cpu_data[cpu].irq)
-#define LAST_CPU_IRQ(cpu, irq)   (irq_cpu_data[cpu].last_irq[irq])
-#define IRQ_DELTA(cpu, irq)    (irq_cpu_data[cpu].irq_delta[irq])
-
-#define IDLE_ENOUGH(cpu,now) \
-       (idle_cpu(cpu) && ((now) - per_cpu(irq_stat, (cpu)).idle_timestamp > 1))
-
-#define IRQ_ALLOWED(cpu, allowed_mask) cpu_isset(cpu, allowed_mask)
-
-#define CPU_TO_PACKAGEINDEX(i) (first_cpu(per_cpu(cpu_sibling_map, i)))
-
-static cpumask_t balance_irq_affinity[NR_IRQS] = {
-       [0 ... NR_IRQS-1] = CPU_MASK_ALL
-};
-
-void set_balance_irq_affinity(unsigned int irq, cpumask_t mask)
-{
-       balance_irq_affinity[irq] = mask;
-}
-
-static unsigned long move(int curr_cpu, cpumask_t allowed_mask,
-                       unsigned long now, int direction)
-{
-       int search_idle = 1;
-       int cpu = curr_cpu;
-
-       goto inside;
-
-       do {
-               if (unlikely(cpu == curr_cpu))
-                       search_idle = 0;
-inside:
-               if (direction == 1) {
-                       cpu++;
-                       if (cpu >= NR_CPUS)
-                               cpu = 0;
-               } else {
-                       cpu--;
-                       if (cpu == -1)
-                               cpu = NR_CPUS-1;
-               }
-       } while (!cpu_online(cpu) || !IRQ_ALLOWED(cpu, allowed_mask) ||
-                       (search_idle && !IDLE_ENOUGH(cpu, now)));
-
-       return cpu;
-}
-
-static inline void balance_irq(int cpu, int irq)
-{
-       unsigned long now = jiffies;
-       cpumask_t allowed_mask;
-       unsigned int new_cpu;
-
-       if (irqbalance_disabled)
-               return;
-
-       cpus_and(allowed_mask, cpu_online_map, balance_irq_affinity[irq]);
-       new_cpu = move(cpu, allowed_mask, now, 1);
-       if (cpu != new_cpu)
-               set_pending_irq(irq, cpumask_of_cpu(new_cpu));
-}
-
-static inline void rotate_irqs_among_cpus(unsigned long useful_load_threshold)
-{
-       int i, j;
-
-       for_each_online_cpu(i) {
-               for (j = 0; j < NR_IRQS; j++) {
-                       if (!irq_desc[j].action)
-                               continue;
-                       /* Is it a significant load ?  */
-                       if (IRQ_DELTA(CPU_TO_PACKAGEINDEX(i), j) <
-                                               useful_load_threshold)
-                               continue;
-                       balance_irq(i, j);
-               }
-       }
-       balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
-               balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
-       return;
-}
-
-static void do_irq_balance(void)
-{
-       int i, j;
-       unsigned long max_cpu_irq = 0, min_cpu_irq = (~0);
-       unsigned long move_this_load = 0;
-       int max_loaded = 0, min_loaded = 0;
-       int load;
-       unsigned long useful_load_threshold = balanced_irq_interval + 10;
-       int selected_irq;
-       int tmp_loaded, first_attempt = 1;
-       unsigned long tmp_cpu_irq;
-       unsigned long imbalance = 0;
-       cpumask_t allowed_mask, target_cpu_mask, tmp;
-
-       for_each_possible_cpu(i) {
-               int package_index;
-               CPU_IRQ(i) = 0;
-               if (!cpu_online(i))
-                       continue;
-               package_index = CPU_TO_PACKAGEINDEX(i);
-               for (j = 0; j < NR_IRQS; j++) {
-                       unsigned long value_now, delta;
-                       /* Is this an active IRQ or balancing disabled ? */
-                       if (!irq_desc[j].action || irq_balancing_disabled(j))
-                               continue;
-                       if (package_index == i)
-                               IRQ_DELTA(package_index, j) = 0;
-                       /* Determine the total count per processor per IRQ */
-                       value_now = (unsigned long) kstat_cpu(i).irqs[j];
-
-                       /* Determine the activity per processor per IRQ */
-                       delta = value_now - LAST_CPU_IRQ(i, j);
-
-                       /* Update last_cpu_irq[][] for the next time */
-                       LAST_CPU_IRQ(i, j) = value_now;
-
-                       /* Ignore IRQs whose rate is less than the clock */
-                       if (delta < useful_load_threshold)
-                               continue;
-                       /* update the load for the processor or package total */
-                       IRQ_DELTA(package_index, j) += delta;
-
-                       /* Keep track of the higher numbered sibling as well */
-                       if (i != package_index)
-                               CPU_IRQ(i) += delta;
-                       /*
-                        * We have sibling A and sibling B in the package
-                        *
-                        * cpu_irq[A] = load for cpu A + load for cpu B
-                        * cpu_irq[B] = load for cpu B
-                        */
-                       CPU_IRQ(package_index) += delta;
-               }
-       }
-       /* Find the least loaded processor package */
-       for_each_online_cpu(i) {
-               if (i != CPU_TO_PACKAGEINDEX(i))
-                       continue;
-               if (min_cpu_irq > CPU_IRQ(i)) {
-                       min_cpu_irq = CPU_IRQ(i);
-                       min_loaded = i;
-               }
-       }
-       max_cpu_irq = ULONG_MAX;
-
-tryanothercpu:
-       /*
-        * Look for heaviest loaded processor.
-        * We may come back to get the next heaviest loaded processor.
-        * Skip processors with trivial loads.
-        */
-       tmp_cpu_irq = 0;
-       tmp_loaded = -1;
-       for_each_online_cpu(i) {
-               if (i != CPU_TO_PACKAGEINDEX(i))
-                       continue;
-               if (max_cpu_irq <= CPU_IRQ(i))
-                       continue;
-               if (tmp_cpu_irq < CPU_IRQ(i)) {
-                       tmp_cpu_irq = CPU_IRQ(i);
-                       tmp_loaded = i;
-               }
-       }
-
-       if (tmp_loaded == -1) {
-        /*
-         * In the case of small number of heavy interrupt sources,
-         * loading some of the cpus too much. We use Ingo's original
-         * approach to rotate them around.
-         */
-               if (!first_attempt && imbalance >= useful_load_threshold) {
-                       rotate_irqs_among_cpus(useful_load_threshold);
-                       return;
-               }
-               goto not_worth_the_effort;
-       }
-
-       first_attempt = 0;              /* heaviest search */
-       max_cpu_irq = tmp_cpu_irq;      /* load */
-       max_loaded = tmp_loaded;        /* processor */
-       imbalance = (max_cpu_irq - min_cpu_irq) / 2;
-
-       /*
-        * if imbalance is less than approx 10% of max load, then
-        * observe diminishing returns action. - quit
-        */
-       if (imbalance < (max_cpu_irq >> 3))
-               goto not_worth_the_effort;
-
-tryanotherirq:
-       /* if we select an IRQ to move that can't go where we want, then
-        * see if there is another one to try.
-        */
-       move_this_load = 0;
-       selected_irq = -1;
-       for (j = 0; j < NR_IRQS; j++) {
-               /* Is this an active IRQ? */
-               if (!irq_desc[j].action)
-                       continue;
-               if (imbalance <= IRQ_DELTA(max_loaded, j))
-                       continue;
-               /* Try to find the IRQ that is closest to the imbalance
-                * without going over.
-                */
-               if (move_this_load < IRQ_DELTA(max_loaded, j)) {
-                       move_this_load = IRQ_DELTA(max_loaded, j);
-                       selected_irq = j;
-               }
-       }
-       if (selected_irq == -1)
-               goto tryanothercpu;
-
-       imbalance = move_this_load;
-
-       /* For physical_balance case, we accumulated both load
-        * values in the one of the siblings cpu_irq[],
-        * to use the same code for physical and logical processors
-        * as much as possible.
-        *
-        * NOTE: the cpu_irq[] array holds the sum of the load for
-        * sibling A and sibling B in the slot for the lowest numbered
-        * sibling (A), _AND_ the load for sibling B in the slot for
-        * the higher numbered sibling.
-        *
-        * We seek the least loaded sibling by making the comparison
-        * (A+B)/2 vs B
-        */
-       load = CPU_IRQ(min_loaded) >> 1;
-       for_each_cpu_mask(j, per_cpu(cpu_sibling_map, min_loaded)) {
-               if (load > CPU_IRQ(j)) {
-                       /* This won't change cpu_sibling_map[min_loaded] */
-                       load = CPU_IRQ(j);
-                       min_loaded = j;
-               }
-       }
-
-       cpus_and(allowed_mask,
-               cpu_online_map,
-               balance_irq_affinity[selected_irq]);
-       target_cpu_mask = cpumask_of_cpu(min_loaded);
-       cpus_and(tmp, target_cpu_mask, allowed_mask);
-
-       if (!cpus_empty(tmp)) {
-               /* mark for change destination */
-               set_pending_irq(selected_irq, cpumask_of_cpu(min_loaded));
-
-               /* Since we made a change, come back sooner to
-                * check for more variation.
-                */
-               balanced_irq_interval = max((long)MIN_BALANCED_IRQ_INTERVAL,
-                       balanced_irq_interval - BALANCED_IRQ_LESS_DELTA);
-               return;
-       }
-       goto tryanotherirq;
-
-not_worth_the_effort:
-       /*
-        * if we did not find an IRQ to move, then adjust the time interval
-        * upward
-        */
-       balanced_irq_interval = min((long)MAX_BALANCED_IRQ_INTERVAL,
-               balanced_irq_interval + BALANCED_IRQ_MORE_DELTA);
-       return;
-}
-
-static int balanced_irq(void *unused)
-{
-       int i;
-       unsigned long prev_balance_time = jiffies;
-       long time_remaining = balanced_irq_interval;
-
-       /* push everything to CPU 0 to give us a starting point.  */
-       for (i = 0 ; i < NR_IRQS ; i++) {
-               irq_desc[i].pending_mask = cpumask_of_cpu(0);
-               set_pending_irq(i, cpumask_of_cpu(0));
-       }
-
-       set_freezable();
-       for ( ; ; ) {
-               time_remaining = schedule_timeout_interruptible(time_remaining);
-               try_to_freeze();
-               if (time_after(jiffies,
-                               prev_balance_time+balanced_irq_interval)) {
-                       preempt_disable();
-                       do_irq_balance();
-                       prev_balance_time = jiffies;
-                       time_remaining = balanced_irq_interval;
-                       preempt_enable();
-               }
-       }
-       return 0;
-}
-
-static int __init balanced_irq_init(void)
-{
-       int i;
-       struct cpuinfo_x86 *c;
-       cpumask_t tmp;
-
-       cpus_shift_right(tmp, cpu_online_map, 2);
-       c = &boot_cpu_data;
-       /* When not overwritten by the command line ask subarchitecture. */
-       if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH)
-               irqbalance_disabled = NO_BALANCE_IRQ;
-       if (irqbalance_disabled)
-               return 0;
-
-        /* disable irqbalance completely if there is only one processor online */
-       if (num_online_cpus() < 2) {
-               irqbalance_disabled = 1;
-               return 0;
-       }
-       /*
-        * Enable physical balance only if more than 1 physical processor
-        * is present
-        */
-       if (smp_num_siblings > 1 && !cpus_empty(tmp))
-               physical_balance = 1;
-
-       for_each_online_cpu(i) {
-               irq_cpu_data[i].irq_delta = kzalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
-               irq_cpu_data[i].last_irq = kzalloc(sizeof(unsigned long) * NR_IRQS, GFP_KERNEL);
-               if (irq_cpu_data[i].irq_delta == NULL || irq_cpu_data[i].last_irq == NULL) {
-                       printk(KERN_ERR "balanced_irq_init: out of memory");
-                       goto failed;
-               }
-       }
-
-       printk(KERN_INFO "Starting balanced_irq\n");
-       if (!IS_ERR(kthread_run(balanced_irq, NULL, "kirqd")))
-               return 0;
-       printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
-failed:
-       for_each_possible_cpu(i) {
-               kfree(irq_cpu_data[i].irq_delta);
-               irq_cpu_data[i].irq_delta = NULL;
-               kfree(irq_cpu_data[i].last_irq);
-               irq_cpu_data[i].last_irq = NULL;
-       }
-       return 0;
-}
-
-int __devinit irqbalance_disable(char *str)
-{
-       irqbalance_disabled = 1;
-       return 1;
-}
-
-__setup("noirqbalance", irqbalance_disable);
-
-late_initcall(balanced_irq_init);
-#endif /* CONFIG_IRQBALANCE */
 #endif /* CONFIG_SMP */
 
 #ifndef CONFIG_SMP
@@ -1164,18 +1048,18 @@ static inline int IO_APIC_irq_trigger(int irq)
        return 0;
 }
 
-/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
 
 static int __assign_irq_vector(int irq)
 {
        static int current_vector = FIRST_DEVICE_VECTOR, current_offset;
        int vector, offset;
+       struct irq_cfg *cfg;
 
-       BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+       BUG_ON((unsigned)irq >= nr_irqs);
 
-       if (irq_vector[irq] > 0)
-               return irq_vector[irq];
+       cfg = irq_cfg(irq);
+       if (cfg->vector > 0)
+               return cfg->vector;
 
        vector = current_vector;
        offset = current_offset;
@@ -1192,7 +1076,7 @@ next:
 
        current_vector = vector;
        current_offset = offset;
-       irq_vector[irq] = vector;
+       cfg->vector = vector;
 
        return vector;
 }
@@ -1217,13 +1101,16 @@ static struct irq_chip ioapic_chip;
 
 static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
            trigger == IOAPIC_LEVEL) {
-               irq_desc[irq].status |= IRQ_LEVEL;
+               desc->status |= IRQ_LEVEL;
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                         handle_fasteoi_irq, "fasteoi");
        } else {
-               irq_desc[irq].status &= ~IRQ_LEVEL;
+               desc->status &= ~IRQ_LEVEL;
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                         handle_edge_irq, "edge");
        }
@@ -1341,7 +1228,8 @@ static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
        ioapic_write_entry(apic, pin, entry);
 }
 
-void __init print_IO_APIC(void)
+
+__apicdebuginit(void) print_IO_APIC(void)
 {
        int apic, i;
        union IO_APIC_reg_00 reg_00;
@@ -1349,6 +1237,7 @@ void __init print_IO_APIC(void)
        union IO_APIC_reg_02 reg_02;
        union IO_APIC_reg_03 reg_03;
        unsigned long flags;
+       struct irq_cfg *cfg;
 
        if (apic_verbosity == APIC_QUIET)
                return;
@@ -1437,16 +1326,16 @@ void __init print_IO_APIC(void)
        }
        }
        printk(KERN_DEBUG "IRQ to pin mappings:\n");
-       for (i = 0; i < NR_IRQS; i++) {
-               struct irq_pin_list *entry = irq_2_pin + i;
-               if (entry->pin < 0)
+       for_each_irq_cfg(cfg) {
+               struct irq_pin_list *entry = cfg->irq_2_pin;
+               if (!entry)
                        continue;
                printk(KERN_DEBUG "IRQ%d ", i);
                for (;;) {
                        printk("-> %d:%d", entry->apic, entry->pin);
                        if (!entry->next)
                                break;
-                       entry = irq_2_pin + entry->next;
+                       entry = entry->next;
                }
                printk("\n");
        }
@@ -1456,9 +1345,7 @@ void __init print_IO_APIC(void)
        return;
 }
 
-#if 0
-
-static void print_APIC_bitfield(int base)
+__apicdebuginit(void) print_APIC_bitfield(int base)
 {
        unsigned int v;
        int i, j;
@@ -1479,7 +1366,7 @@ static void print_APIC_bitfield(int base)
        }
 }
 
-void /*__init*/ print_local_APIC(void *dummy)
+__apicdebuginit(void) print_local_APIC(void *dummy)
 {
        unsigned int v, ver, maxlvt;
        u64 icr;
@@ -1563,12 +1450,12 @@ void /*__init*/ print_local_APIC(void *dummy)
        printk("\n");
 }
 
-void print_all_local_APICs(void)
+__apicdebuginit(void) print_all_local_APICs(void)
 {
        on_each_cpu(print_local_APIC, NULL, 1);
 }
 
-void /*__init*/ print_PIC(void)
+__apicdebuginit(void) print_PIC(void)
 {
        unsigned int v;
        unsigned long flags;
@@ -1600,7 +1487,17 @@ void /*__init*/ print_PIC(void)
        printk(KERN_DEBUG "... PIC ELCR: %04x\n", v);
 }
 
-#endif  /*  0  */
+__apicdebuginit(int) print_all_ICs(void)
+{
+       print_PIC();
+       print_all_local_APICs();
+       print_IO_APIC();
+
+       return 0;
+}
+
+fs_initcall(print_all_ICs);
+
 
 static void __init enable_IO_APIC(void)
 {
@@ -1609,10 +1506,6 @@ static void __init enable_IO_APIC(void)
        int i, apic;
        unsigned long flags;
 
-       for (i = 0; i < PIN_MAP_SIZE; i++) {
-               irq_2_pin[i].pin = -1;
-               irq_2_pin[i].next = 0;
-       }
        if (!pirqs_enabled)
                for (i = 0; i < MAX_PIRQS; i++)
                        pirq_entries[i] = -1;
@@ -1724,10 +1617,8 @@ static void __init setup_ioapic_ids_from_mpc(void)
        unsigned char old_id;
        unsigned long flags;
 
-#ifdef CONFIG_X86_NUMAQ
-       if (found_numaq)
+       if (x86_quirks->setup_ioapic_ids && x86_quirks->setup_ioapic_ids())
                return;
-#endif
 
        /*
         * Don't check I/O APIC IDs for xAPIC systems.  They have
@@ -1944,7 +1835,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq)
  * operation to prevent an edge-triggered interrupt escaping meanwhile.
  * The idea is from Manfred Spraul.  --macro
  */
-       i = irq_vector[irq];
+       i = irq_cfg(irq)->vector;
 
        v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
 
@@ -1961,7 +1852,7 @@ static void ack_ioapic_quirk_irq(unsigned int irq)
 
 static int ioapic_retrigger_irq(unsigned int irq)
 {
-       send_IPI_self(irq_vector[irq]);
+       send_IPI_self(irq_cfg(irq)->vector);
 
        return 1;
 }
@@ -1983,6 +1874,8 @@ static struct irq_chip ioapic_chip __read_mostly = {
 static inline void init_IO_APIC_traps(void)
 {
        int irq;
+       struct irq_desc *desc;
+       struct irq_cfg *cfg;
 
        /*
         * NOTE! The local APIC isn't very good at handling
@@ -1995,8 +1888,9 @@ static inline void init_IO_APIC_traps(void)
         * Also, we've got to be careful not to trash gate
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
-       for (irq = 0; irq < NR_IRQS ; irq++) {
-               if (IO_APIC_IRQ(irq) && !irq_vector[irq]) {
+       for_each_irq_cfg(cfg) {
+               irq = cfg->irq;
+               if (IO_APIC_IRQ(irq) && !cfg->vector) {
                        /*
                         * Hmm.. We don't have an entry for this,
                         * so default to an old-fashioned 8259
@@ -2004,9 +1898,11 @@ static inline void init_IO_APIC_traps(void)
                         */
                        if (irq < 16)
                                make_8259A_irq(irq);
-                       else
+                       else {
+                               desc = irq_to_desc(irq);
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].chip = &no_irq_chip;
+                               desc->chip = &no_irq_chip;
+                       }
                }
        }
 }
@@ -2045,7 +1941,10 @@ static struct irq_chip lapic_chip __read_mostly = {
 
 static void lapic_register_intr(int irq, int vector)
 {
-       irq_desc[irq].status &= ~IRQ_LEVEL;
+       struct irq_desc *desc;
+
+       desc = irq_to_desc(irq);
+       desc->status &= ~IRQ_LEVEL;
        set_irq_chip_and_handler_name(irq, &lapic_chip, handle_edge_irq,
                                      "edge");
        set_intr_gate(vector, interrupt[irq]);
@@ -2328,8 +2227,6 @@ void __init setup_IO_APIC(void)
        setup_IO_APIC_irqs();
        init_IO_APIC_traps();
        check_timer();
-       if (!acpi_ioapic)
-               print_IO_APIC();
 }
 
 /*
@@ -2438,14 +2335,18 @@ int create_irq(void)
        /* Allocate an unused irq */
        int irq, new, vector = 0;
        unsigned long flags;
+       struct irq_cfg *cfg_new;
 
        irq = -ENOSPC;
        spin_lock_irqsave(&vector_lock, flags);
-       for (new = (NR_IRQS - 1); new >= 0; new--) {
+       for (new = (nr_irqs - 1); new >= 0; new--) {
                if (platform_legacy_irq(new))
                        continue;
-               if (irq_vector[new] != 0)
+               cfg_new = irq_cfg(new);
+               if (cfg_new && cfg_new->vector != 0)
                        continue;
+               if (!cfg_new)
+                       cfg_new = irq_cfg_alloc(new);
                vector = __assign_irq_vector(new);
                if (likely(vector > 0))
                        irq = new;
@@ -2467,8 +2368,8 @@ void destroy_irq(unsigned int irq)
        dynamic_irq_cleanup(irq);
 
        spin_lock_irqsave(&vector_lock, flags);
-       clear_bit(irq_vector[irq], used_vectors);
-       irq_vector[irq] = 0;
+       clear_bit(irq_cfg(irq)->vector, used_vectors);
+       irq_cfg(irq)->vector = 0;
        spin_unlock_irqrestore(&vector_lock, flags);
 }
 
@@ -2514,6 +2415,7 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
        unsigned int dest;
        cpumask_t tmp;
        int vector;
+       struct irq_desc *desc;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
@@ -2533,7 +2435,8 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);
 
        write_msi_msg(irq, &msg);
-       irq_desc[irq].affinity = mask;
+       desc = irq_to_desc(irq);
+       desc->affinity = mask;
 }
 #endif /* CONFIG_SMP */
 
@@ -2607,6 +2510,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
 {
        unsigned int dest;
        cpumask_t tmp;
+       struct irq_desc *desc;
 
        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
@@ -2617,7 +2521,8 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
        dest = cpu_mask_to_apicid(mask);
 
        target_ht_irq(irq, dest);
-       irq_desc[irq].affinity = mask;
+       desc = irq_to_desc(irq);
+       desc->affinity = mask;
 }
 #endif