]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/i386/kernel/apic.c
Merge git://git.infradead.org/mtd-2.6
[linux-2.6-omap-h63xx.git] / arch / i386 / kernel / apic.c
index 36825117835d5ede88c4dc992457d064374ad07e..67824f3bb974113aab84b73c79239b1ba0283f30 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/bootmem.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
@@ -64,6 +63,9 @@ static int enable_local_apic __initdata = 0;
 static int local_apic_timer_verify_ok;
 /* Disable local APIC timer from the kernel commandline or via dmi quirk */
 static int local_apic_timer_disabled;
+/* Local APIC timer works in C2 */
+int local_apic_timer_c2_ok;
+EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
 
 /*
  * Debug level, exported for io_apic.c
@@ -126,6 +128,28 @@ static int modern_apic(void)
        return lapic_get_version() >= 0x14;
 }
 
+void apic_wait_icr_idle(void)
+{
+       while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
+               cpu_relax();
+}
+
+unsigned long safe_apic_wait_icr_idle(void)
+{
+       unsigned long send_status;
+       int timeout;
+
+       timeout = 0;
+       do {
+               send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+               if (!send_status)
+                       break;
+               udelay(100);
+       } while (timeout++ < 1000);
+
+       return send_status;
+}
+
 /**
  * enable_NMI_through_LVT0 - enable NMI through local vector table 0
  */
@@ -268,32 +292,6 @@ static void __devinit setup_APIC_timer(void)
        clockevents_register_device(levt);
 }
 
-/*
- * Detect systems with known broken BIOS implementations
- */
-static int __init lapic_check_broken_bios(struct dmi_system_id *d)
-{
-       printk(KERN_NOTICE "%s detected: disabling lapic timer.\n",
-                      d->ident);
-       local_apic_timer_disabled = 1;
-       return 0;
-}
-
-static struct dmi_system_id __initdata broken_bios_dmi_table[] = {
-       {
-               /*
-                * BIOS exports only C1 state, but uses deeper power
-                * modes behind the kernels back.
-                */
-                 .callback = lapic_check_broken_bios,
-                 .ident = "HP nx6325",
-                 .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
-                 },
-        },
-        {}
-};
-
 /*
  * In this functions we calibrate APIC bus clocks to the external timer.
  *
@@ -369,12 +367,12 @@ void __init setup_boot_APIC_clock(void)
        long delta, deltapm;
        int pm_referenced = 0;
 
-       /* Detect know broken systems */
-       dmi_check_system(broken_bios_dmi_table);
+       if (boot_cpu_has(X86_FEATURE_LAPIC_TIMER_BROKEN))
+               local_apic_timer_disabled = 1;
 
        /*
         * The local apic timer can be disabled via the kernel
-        * commandline or from the dmi quirk above. Register the lapic
+        * commandline or from the test above. Register the lapic
         * timer as a dummy clock event source on SMP systems, so the
         * broadcast mechanism is used. On UP systems simply ignore it.
         */
@@ -506,7 +504,8 @@ void __init setup_boot_APIC_clock(void)
                        apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
                else
                        local_apic_timer_verify_ok = 0;
-       }
+       } else
+               local_irq_enable();
 
        if (!local_apic_timer_verify_ok) {
                printk(KERN_WARNING
@@ -1231,6 +1230,13 @@ static int __init parse_disable_lapic_timer(char *arg)
 }
 early_param("nolapic_timer", parse_disable_lapic_timer);
 
+static int __init parse_lapic_timer_c2_ok(char *arg)
+{
+       local_apic_timer_c2_ok = 1;
+       return 0;
+}
+early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
+
 static int __init apic_set_verbosity(char *str)
 {
        if (strcmp("debug", str) == 0)