]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/io_apic.c
Merge branch 'irq-fixes-for-linus-4' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / io_apic.c
index a1a2e070f31afc8446c2c7186925f76daf043d55..74917658b004aea2eb08dca5c5c9ba8a775eb81e 100644 (file)
@@ -141,6 +141,9 @@ struct irq_cfg {
        unsigned move_cleanup_count;
        u8 vector;
        u8 move_in_progress : 1;
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+       u8 move_desc_pending : 1;
+#endif
 };
 
 /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
@@ -167,7 +170,7 @@ static struct irq_cfg irq_cfgx[NR_IRQS] = {
        [15] = { .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, },
 };
 
-void __init arch_early_irq_init(void)
+int __init arch_early_irq_init(void)
 {
        struct irq_cfg *cfg;
        struct irq_desc *desc;
@@ -181,6 +184,8 @@ void __init arch_early_irq_init(void)
                desc = irq_to_desc(i);
                desc->chip_data = &cfg[i];
        }
+
+       return 0;
 }
 
 #ifdef CONFIG_SPARSE_IRQ
@@ -209,7 +214,7 @@ static struct irq_cfg *get_one_free_irq_cfg(int cpu)
        return cfg;
 }
 
-void arch_init_chip_data(struct irq_desc *desc, int cpu)
+int arch_init_chip_data(struct irq_desc *desc, int cpu)
 {
        struct irq_cfg *cfg;
 
@@ -221,8 +226,125 @@ void arch_init_chip_data(struct irq_desc *desc, int cpu)
                        BUG_ON(1);
                }
        }
+
+       return 0;
+}
+
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+
+static void
+init_copy_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg, int cpu)
+{
+       struct irq_pin_list *old_entry, *head, *tail, *entry;
+
+       cfg->irq_2_pin = NULL;
+       old_entry = old_cfg->irq_2_pin;
+       if (!old_entry)
+               return;
+
+       entry = get_one_free_irq_2_pin(cpu);
+       if (!entry)
+               return;
+
+       entry->apic     = old_entry->apic;
+       entry->pin      = old_entry->pin;
+       head            = entry;
+       tail            = entry;
+       old_entry       = old_entry->next;
+       while (old_entry) {
+               entry = get_one_free_irq_2_pin(cpu);
+               if (!entry) {
+                       entry = head;
+                       while (entry) {
+                               head = entry->next;
+                               kfree(entry);
+                               entry = head;
+                       }
+                       /* still use the old one */
+                       return;
+               }
+               entry->apic     = old_entry->apic;
+               entry->pin      = old_entry->pin;
+               tail->next      = entry;
+               tail            = entry;
+               old_entry       = old_entry->next;
+       }
+
+       tail->next = NULL;
+       cfg->irq_2_pin = head;
 }
 
+static void free_irq_2_pin(struct irq_cfg *old_cfg, struct irq_cfg *cfg)
+{
+       struct irq_pin_list *entry, *next;
+
+       if (old_cfg->irq_2_pin == cfg->irq_2_pin)
+               return;
+
+       entry = old_cfg->irq_2_pin;
+
+       while (entry) {
+               next = entry->next;
+               kfree(entry);
+               entry = next;
+       }
+       old_cfg->irq_2_pin = NULL;
+}
+
+void arch_init_copy_chip_data(struct irq_desc *old_desc,
+                                struct irq_desc *desc, int cpu)
+{
+       struct irq_cfg *cfg;
+       struct irq_cfg *old_cfg;
+
+       cfg = get_one_free_irq_cfg(cpu);
+
+       if (!cfg)
+               return;
+
+       desc->chip_data = cfg;
+
+       old_cfg = old_desc->chip_data;
+
+       memcpy(cfg, old_cfg, sizeof(struct irq_cfg));
+
+       init_copy_irq_2_pin(old_cfg, cfg, cpu);
+}
+
+static void free_irq_cfg(struct irq_cfg *old_cfg)
+{
+       kfree(old_cfg);
+}
+
+void arch_free_chip_data(struct irq_desc *old_desc, struct irq_desc *desc)
+{
+       struct irq_cfg *old_cfg, *cfg;
+
+       old_cfg = old_desc->chip_data;
+       cfg = desc->chip_data;
+
+       if (old_cfg == cfg)
+               return;
+
+       if (old_cfg) {
+               free_irq_2_pin(old_cfg, cfg);
+               free_irq_cfg(old_cfg);
+               old_desc->chip_data = NULL;
+       }
+}
+
+static void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
+{
+       struct irq_cfg *cfg = desc->chip_data;
+
+       if (!cfg->move_in_progress) {
+               /* it means that domain is not changed */
+               if (!cpus_intersects(desc->affinity, mask))
+                       cfg->move_desc_pending = 1;
+       }
+}
+#endif
+
 #else
 static struct irq_cfg *irq_cfg(unsigned int irq)
 {
@@ -231,9 +353,11 @@ static struct irq_cfg *irq_cfg(unsigned int irq)
 
 #endif
 
+#ifndef CONFIG_NUMA_MIGRATE_IRQ_DESC
 static inline void set_extra_move_desc(struct irq_desc *desc, cpumask_t mask)
 {
 }
+#endif
 
 struct io_apic {
        unsigned int index;
@@ -1225,8 +1349,6 @@ void __setup_vector_irq(int cpu)
 
        /* Mark the inuse vectors */
        for_each_irq_desc(irq, desc) {
-               if (!desc)
-                       continue;
                cfg = desc->chip_data;
                if (!cpu_isset(cpu, cfg->domain))
                        continue;
@@ -1610,8 +1732,6 @@ __apicdebuginit(void) print_IO_APIC(void)
        for_each_irq_desc(irq, desc) {
                struct irq_pin_list *entry;
 
-               if (!desc)
-                       continue;
                cfg = desc->chip_data;
                entry = cfg->irq_2_pin;
                if (!entry)
@@ -2258,9 +2378,6 @@ static void ir_irq_migration(struct work_struct *work)
        struct irq_desc *desc;
 
        for_each_irq_desc(irq, desc) {
-               if (!desc)
-                       continue;
-
                if (desc->status & IRQ_MOVE_PENDING) {
                        unsigned long flags;
 
@@ -2303,10 +2420,9 @@ static void set_ir_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
 asmlinkage void smp_irq_move_cleanup_interrupt(void)
 {
        unsigned vector, me;
+
        ack_APIC_irq();
-#ifdef CONFIG_X86_64
        exit_idle();
-#endif
        irq_enter();
 
        me = smp_processor_id();
@@ -2346,14 +2462,34 @@ static void irq_complete_move(struct irq_desc **descp)
        struct irq_cfg *cfg = desc->chip_data;
        unsigned vector, me;
 
-       if (likely(!cfg->move_in_progress))
+       if (likely(!cfg->move_in_progress)) {
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+               if (likely(!cfg->move_desc_pending))
+                       return;
+
+               /* domain has not changed, but affinity did */
+               me = smp_processor_id();
+               if (cpu_isset(me, desc->affinity)) {
+                       *descp = desc = move_irq_desc(desc, me);
+                       /* get the new one */
+                       cfg = desc->chip_data;
+                       cfg->move_desc_pending = 0;
+               }
+#endif
                return;
+       }
 
        vector = ~get_irq_regs()->orig_ax;
        me = smp_processor_id();
        if ((vector == cfg->vector) && cpu_isset(me, cfg->domain)) {
                cpumask_t cleanup_mask;
 
+#ifdef CONFIG_NUMA_MIGRATE_IRQ_DESC
+               *descp = desc = move_irq_desc(desc, me);
+               /* get the new one */
+               cfg = desc->chip_data;
+#endif
+
                cpus_and(cleanup_mask, cfg->old_domain, cpu_online_map);
                cfg->move_cleanup_count = cpus_weight(cleanup_mask);
                send_IPI_mask(cleanup_mask, IRQ_MOVE_CLEANUP_VECTOR);
@@ -2531,9 +2667,6 @@ static inline void init_IO_APIC_traps(void)
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        for_each_irq_desc(irq, desc) {
-               if (!desc)
-                       continue;
-
                cfg = desc->chip_data;
                if (IO_APIC_IRQ(irq) && cfg && !cfg->vector) {
                        /*