]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86_64/kernel/io_apic.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davej/agpgart
[linux-2.6-omap-h63xx.git] / arch / x86_64 / kernel / io_apic.c
index e55028fba942dc3b9a69e7b82d82d4537b277094..b000017e4b5da80f336588e321982217599cf848 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/acpi.h>
 #include <linux/sysdev.h>
 #include <linux/msi.h>
+#include <linux/htirq.h>
 #ifdef CONFIG_ACPI
 #include <acpi/acpi_bus.h>
 #endif
@@ -46,7 +47,7 @@
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
 
-static int assign_irq_vector(int irq, cpumask_t mask);
+static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result);
 
 #define __apicdebuginit  __init
 
@@ -56,7 +57,7 @@ static int no_timer_check;
 
 static int disable_timer_pin_1 __initdata;
 
-int timer_over_8254 __initdata = 0;
+int timer_over_8254 __initdata = 1;
 
 /* Where if anywhere is the i8259 connect in external int mode */
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
@@ -173,12 +174,10 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
 
        cpus_and(mask, tmp, CPU_MASK_ALL);
 
-       vector = assign_irq_vector(irq, mask);
+       vector = assign_irq_vector(irq, mask, &tmp);
        if (vector < 0)
                return;
 
-       cpus_clear(tmp);
-       cpu_set(vector >> 8, tmp);
        dest = cpu_mask_to_apicid(tmp);
 
        /*
@@ -187,7 +186,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
        dest = SET_APIC_LOGICAL_ID(dest);
 
        spin_lock_irqsave(&ioapic_lock, flags);
-       __target_IO_APIC_irq(irq, dest, vector & 0xff);
+       __target_IO_APIC_irq(irq, dest, vector);
        set_native_irq_info(irq, mask);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 }
@@ -562,9 +561,45 @@ static inline int IO_APIC_irq_trigger(int irq)
 }
 
 /* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-unsigned int irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_EXTERNAL_VECTOR, 0 };
+static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = {
+       [0] = FIRST_EXTERNAL_VECTOR + 0,
+       [1] = FIRST_EXTERNAL_VECTOR + 1,
+       [2] = FIRST_EXTERNAL_VECTOR + 2,
+       [3] = FIRST_EXTERNAL_VECTOR + 3,
+       [4] = FIRST_EXTERNAL_VECTOR + 4,
+       [5] = FIRST_EXTERNAL_VECTOR + 5,
+       [6] = FIRST_EXTERNAL_VECTOR + 6,
+       [7] = FIRST_EXTERNAL_VECTOR + 7,
+       [8] = FIRST_EXTERNAL_VECTOR + 8,
+       [9] = FIRST_EXTERNAL_VECTOR + 9,
+       [10] = FIRST_EXTERNAL_VECTOR + 10,
+       [11] = FIRST_EXTERNAL_VECTOR + 11,
+       [12] = FIRST_EXTERNAL_VECTOR + 12,
+       [13] = FIRST_EXTERNAL_VECTOR + 13,
+       [14] = FIRST_EXTERNAL_VECTOR + 14,
+       [15] = FIRST_EXTERNAL_VECTOR + 15,
+};
+
+static cpumask_t irq_domain[NR_IRQ_VECTORS] __read_mostly = {
+       [0] = CPU_MASK_ALL,
+       [1] = CPU_MASK_ALL,
+       [2] = CPU_MASK_ALL,
+       [3] = CPU_MASK_ALL,
+       [4] = CPU_MASK_ALL,
+       [5] = CPU_MASK_ALL,
+       [6] = CPU_MASK_ALL,
+       [7] = CPU_MASK_ALL,
+       [8] = CPU_MASK_ALL,
+       [9] = CPU_MASK_ALL,
+       [10] = CPU_MASK_ALL,
+       [11] = CPU_MASK_ALL,
+       [12] = CPU_MASK_ALL,
+       [13] = CPU_MASK_ALL,
+       [14] = CPU_MASK_ALL,
+       [15] = CPU_MASK_ALL,
+};
 
-static int __assign_irq_vector(int irq, cpumask_t mask)
+static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
 {
        /*
         * NOTE! The local APIC isn't very good at handling
@@ -586,16 +621,24 @@ static int __assign_irq_vector(int irq, cpumask_t mask)
 
        BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
 
-       if (IO_APIC_VECTOR(irq) > 0)
-               old_vector = IO_APIC_VECTOR(irq);
-       if ((old_vector > 0) && cpu_isset(old_vector >> 8, mask)) {
-               return old_vector;
+       if (irq_vector[irq] > 0)
+               old_vector = irq_vector[irq];
+       if (old_vector > 0) {
+               cpus_and(*result, irq_domain[irq], mask);
+               if (!cpus_empty(*result))
+                       return old_vector;
        }
 
        for_each_cpu_mask(cpu, mask) {
+               cpumask_t domain;
+               int first, new_cpu;
                int vector, offset;
-               vector = pos[cpu].vector;
-               offset = pos[cpu].offset;
+
+               domain = vector_allocation_domain(cpu);
+               first = first_cpu(domain);
+
+               vector = pos[first].vector;
+               offset = pos[first].offset;
 next:
                vector += 8;
                if (vector >= FIRST_SYSTEM_VECTOR) {
@@ -603,35 +646,40 @@ next:
                        offset = (offset + 1) % 8;
                        vector = FIRST_DEVICE_VECTOR + offset;
                }
-               if (unlikely(pos[cpu].vector == vector))
+               if (unlikely(pos[first].vector == vector))
                        continue;
                if (vector == IA32_SYSCALL_VECTOR)
                        goto next;
-               if (per_cpu(vector_irq, cpu)[vector] != -1)
-                       goto next;
+               for_each_cpu_mask(new_cpu, domain)
+                       if (per_cpu(vector_irq, new_cpu)[vector] != -1)
+                               goto next;
                /* Found one! */
-               pos[cpu].vector = vector;
-               pos[cpu].offset = offset;
+               for_each_cpu_mask(new_cpu, domain) {
+                       pos[new_cpu].vector = vector;
+                       pos[new_cpu].offset = offset;
+               }
                if (old_vector >= 0) {
-                       int old_cpu = old_vector >> 8;
-                       old_vector &= 0xff;
-                       per_cpu(vector_irq, old_cpu)[old_vector] = -1;
+                       int old_cpu;
+                       for_each_cpu_mask(old_cpu, irq_domain[irq])
+                               per_cpu(vector_irq, old_cpu)[old_vector] = -1;
                }
-               per_cpu(vector_irq, cpu)[vector] = irq;
-               vector |= cpu << 8;
-               IO_APIC_VECTOR(irq) = vector;
+               for_each_cpu_mask(new_cpu, domain)
+                       per_cpu(vector_irq, new_cpu)[vector] = irq;
+               irq_vector[irq] = vector;
+               irq_domain[irq] = domain;
+               cpus_and(*result, domain, mask);
                return vector;
        }
        return -ENOSPC;
 }
 
-static int assign_irq_vector(int irq, cpumask_t mask)
+static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
 {
        int vector;
        unsigned long flags;
 
        spin_lock_irqsave(&vector_lock, flags);
-       vector = __assign_irq_vector(irq, mask);
+       vector = __assign_irq_vector(irq, mask, result);
        spin_unlock_irqrestore(&vector_lock, flags);
        return vector;
 }
@@ -648,11 +696,11 @@ static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               set_irq_chip_and_handler(irq, &ioapic_chip,
-                                        handle_fasteoi_irq);
+               set_irq_chip_and_handler_name(irq, &ioapic_chip,
+                                             handle_fasteoi_irq, "fasteoi");
        else
-               set_irq_chip_and_handler(irq, &ioapic_chip,
-                                        handle_edge_irq);
+               set_irq_chip_and_handler_name(irq, &ioapic_chip,
+                                             handle_edge_irq, "edge");
 }
 
 static void __init setup_IO_APIC_irqs(void)
@@ -703,14 +751,12 @@ static void __init setup_IO_APIC_irqs(void)
 
                if (IO_APIC_IRQ(irq)) {
                        cpumask_t mask;
-                       vector = assign_irq_vector(irq, TARGET_CPUS);
+                       vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
                        if (vector < 0)
                                continue;
 
-                       cpus_clear(mask);
-                       cpu_set(vector >> 8, mask);
                        entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
-                       entry.vector = vector & 0xff;
+                       entry.vector = vector;
 
                        ioapic_register_intr(irq, vector, IOAPIC_AUTO);
                        if (!apic && (irq < 16))
@@ -760,7 +806,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       set_irq_chip_and_handler(0, &ioapic_chip, handle_edge_irq);
+       set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
 
        /*
         * Add it to the IO-APIC irq-routing table:
@@ -1209,12 +1255,15 @@ static int ioapic_retrigger_irq(unsigned int irq)
 {
        cpumask_t mask;
        unsigned vector;
+       unsigned long flags;
 
+       spin_lock_irqsave(&vector_lock, flags);
        vector = irq_vector[irq];
        cpus_clear(mask);
-       cpu_set(vector >> 8, mask);
+       cpu_set(first_cpu(irq_domain[irq]), mask);
 
-       send_IPI_mask(mask, vector & 0xff);
+       send_IPI_mask(mask, vector);
+       spin_unlock_irqrestore(&vector_lock, flags);
 
        return 1;
 }
@@ -1288,7 +1337,7 @@ static inline void init_IO_APIC_traps(void)
         */
        for (irq = 0; irq < NR_IRQS ; irq++) {
                int tmp = irq;
-               if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
+               if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
                        /*
                         * Hmm.. We don't have an entry for this,
                         * so default to an old-fashioned 8259
@@ -1429,12 +1478,13 @@ static inline void check_timer(void)
 {
        int apic1, pin1, apic2, pin2;
        int vector;
+       cpumask_t mask;
 
        /*
         * get/set the timer IRQ vector:
         */
        disable_8259A_irq(0);
-       vector = assign_irq_vector(0, TARGET_CPUS);
+       vector = assign_irq_vector(0, TARGET_CPUS, &mask);
 
        /*
         * Subtle, code in do_timer_interrupt() expects an AEOI
@@ -1666,6 +1716,7 @@ int create_irq(void)
        int new;
        int vector = 0;
        unsigned long flags;
+       cpumask_t mask;
 
        irq = -ENOSPC;
        spin_lock_irqsave(&vector_lock, flags);
@@ -1674,7 +1725,7 @@ int create_irq(void)
                        continue;
                if (irq_vector[new] != 0)
                        continue;
-               vector = __assign_irq_vector(new, TARGET_CPUS);
+               vector = __assign_irq_vector(new, TARGET_CPUS, &mask);
                if (likely(vector > 0))
                        irq = new;
                break;
@@ -1706,13 +1757,10 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_ms
 {
        int vector;
        unsigned dest;
+       cpumask_t tmp;
 
-       vector = assign_irq_vector(irq, TARGET_CPUS);
+       vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
        if (vector >= 0) {
-               cpumask_t tmp;
-
-               cpus_clear(tmp);
-               cpu_set(vector >> 8, tmp);
                dest = cpu_mask_to_apicid(tmp);
 
                msg->address_hi = MSI_ADDR_BASE_HI;
@@ -1751,12 +1799,10 @@ static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
 
        cpus_and(mask, tmp, CPU_MASK_ALL);
 
-       vector = assign_irq_vector(irq, mask);
+       vector = assign_irq_vector(irq, mask, &tmp);
        if (vector < 0)
                return;
 
-       cpus_clear(tmp);
-       cpu_set(vector >> 8, tmp);
        dest = cpu_mask_to_apicid(tmp);
 
        read_msi_msg(irq, &msg);
@@ -1796,7 +1842,7 @@ int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
 
        write_msi_msg(irq, &msg);
 
-       set_irq_chip_and_handler(irq, &msi_chip, handle_edge_irq);
+       set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
        return 0;
 }
@@ -1843,12 +1889,10 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
 
        cpus_and(mask, tmp, CPU_MASK_ALL);
 
-       vector = assign_irq_vector(irq, mask);
+       vector = assign_irq_vector(irq, mask, &tmp);
        if (vector < 0)
                return;
 
-       cpus_clear(tmp);
-       cpu_set(vector >> 8, tmp);
        dest = cpu_mask_to_apicid(tmp);
 
        target_ht_irq(irq, dest, vector & 0xff);
@@ -1856,7 +1900,7 @@ static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
 }
 #endif
 
-static struct hw_interrupt_type ht_irq_chip = {
+static struct irq_chip ht_irq_chip = {
        .name           = "PCI-HT",
        .mask           = mask_ht_irq,
        .unmask         = unmask_ht_irq,
@@ -1870,15 +1914,13 @@ static struct hw_interrupt_type ht_irq_chip = {
 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
 {
        int vector;
+       cpumask_t tmp;
 
-       vector = assign_irq_vector(irq, TARGET_CPUS);
+       vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
        if (vector >= 0) {
                u32 low, high;
                unsigned dest;
-               cpumask_t tmp;
 
-               cpus_clear(tmp);
-               cpu_set(vector >> 8, tmp);
                dest = cpu_mask_to_apicid(tmp);
 
                high =  HT_IRQ_HIGH_DEST_ID(dest);
@@ -1897,7 +1939,8 @@ int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
                write_ht_irq_low(irq, low);
                write_ht_irq_high(irq, high);
 
-               set_irq_chip_and_handler(irq, &ht_irq_chip, handle_edge_irq);
+               set_irq_chip_and_handler_name(irq, &ht_irq_chip,
+                                             handle_edge_irq, "edge");
        }
        return vector;
 }
@@ -1944,13 +1987,10 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
                add_pin_to_irq(irq, ioapic, pin);
 
 
-       vector = assign_irq_vector(irq, TARGET_CPUS);
+       vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
        if (vector < 0)
                return vector;
 
-       cpus_clear(mask);
-       cpu_set(vector >> 8, mask);
-
        /*
         * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
         * Note that we mask (disable) IRQs now -- these get enabled when the