Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6
[pandora-kernel.git] / arch / x86_64 / kernel / io_apic.c
index 0de3ea9..c768d8a 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/mach_apic.h>
 #include <asm/acpi.h>
 #include <asm/dma.h>
+#include <asm/nmi.h>
 
 #define __apicdebuginit  __init
 
@@ -56,6 +57,7 @@ int timer_over_8254 __initdata = 0;
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
 
 static DEFINE_SPINLOCK(ioapic_lock);
+static DEFINE_SPINLOCK(vector_lock);
 
 /*
  * # of IRQ routing registers
@@ -271,6 +273,18 @@ __setup("enable_8254_timer", setup_enable_8254_timer);
 #include <linux/pci_ids.h>
 #include <linux/pci.h>
 
+
+#ifdef CONFIG_ACPI
+
+static int nvidia_hpet_detected __initdata;
+
+static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+{
+       nvidia_hpet_detected = 1;
+       return 0;
+}
+#endif
+
 /* Temporary Hack. Nvidia and VIA boards currently only work with IO-APIC
    off. Check for an Nvidia or VIA PCI bridge and turn it off.
    Use pci direct infrastructure because this runs before the PCI subsystem. 
@@ -305,7 +319,7 @@ void __init check_ioapic(void)
                                vendor &= 0xffff;
                                switch (vendor) { 
                                case PCI_VENDOR_ID_VIA:
-#ifdef CONFIG_GART_IOMMU
+#ifdef CONFIG_IOMMU
                                        if ((end_pfn > MAX_DMA32_PFN ||
                                             force_iommu) &&
                                            !iommu_aperture_allowed) {
@@ -317,11 +331,19 @@ void __init check_ioapic(void)
                                        return;
                                case PCI_VENDOR_ID_NVIDIA:
 #ifdef CONFIG_ACPI
-                                       /* All timer overrides on Nvidia
-                                          seem to be wrong. Skip them. */
-                                       acpi_skip_timer_override = 1;
-                                       printk(KERN_INFO 
-            "Nvidia board detected. Ignoring ACPI timer override.\n");
+                                       /*
+                                        * All timer overrides on Nvidia are
+                                        * wrong unless HPET is enabled.
+                                        */
+                                       nvidia_hpet_detected = 0;
+                                       acpi_table_parse(ACPI_HPET,
+                                                       nvidia_hpet_check);
+                                       if (nvidia_hpet_detected == 0) {
+                                               acpi_skip_timer_override = 1;
+                                               printk(KERN_INFO "Nvidia board "
+                                                   "detected. Ignoring ACPI "
+                                                   "timer override.\n");
+                                       }
 #endif
                                        /* RED-PEN skip them on mptables too? */
                                        return;
@@ -814,10 +836,17 @@ u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
 int assign_irq_vector(int irq)
 {
        static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
+       unsigned long flags;
+       int vector;
 
        BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
-       if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0)
+
+       spin_lock_irqsave(&vector_lock, flags);
+
+       if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
+               spin_unlock_irqrestore(&vector_lock, flags);
                return IO_APIC_VECTOR(irq);
+       }
 next:
        current_vector += 8;
        if (current_vector == IA32_SYSCALL_VECTOR)
@@ -829,11 +858,14 @@ next:
                current_vector = FIRST_DEVICE_VECTOR + offset;
        }
 
-       vector_irq[current_vector] = irq;
+       vector = current_vector;
+       vector_irq[vector] = irq;
        if (irq != AUTO_ASSIGN)
-               IO_APIC_VECTOR(irq) = current_vector;
+               IO_APIC_VECTOR(irq) = vector;
+
+       spin_unlock_irqrestore(&vector_lock, flags);
 
-       return current_vector;
+       return vector;
 }
 
 extern void (*interrupt[NR_IRQS])(void);
@@ -846,21 +878,14 @@ static struct hw_interrupt_type ioapic_edge_type;
 
 static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-       if (use_pci_vector() && !platform_legacy_irq(irq)) {
-               if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-                               trigger == IOAPIC_LEVEL)
-                       irq_desc[vector].handler = &ioapic_level_type;
-               else
-                       irq_desc[vector].handler = &ioapic_edge_type;
-               set_intr_gate(vector, interrupt[vector]);
-       } else  {
-               if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
-                               trigger == IOAPIC_LEVEL)
-                       irq_desc[irq].handler = &ioapic_level_type;
-               else
-                       irq_desc[irq].handler = &ioapic_edge_type;
-               set_intr_gate(vector, interrupt[irq]);
-       }
+       unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+
+       if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
+                       trigger == IOAPIC_LEVEL)
+               irq_desc[idx].handler = &ioapic_level_type;
+       else
+               irq_desc[idx].handler = &ioapic_edge_type;
+       set_intr_gate(vector, interrupt[idx]);
 }
 
 static void __init setup_IO_APIC_irqs(void)