[PATCH] i386: trust the PM-Timer calibration of the local APIC timer
[powerpc.git] / arch / i386 / kernel / apic.c
index 9655c23..5cff797 100644 (file)
@@ -38,7 +38,6 @@
 #include <asm/hpet.h>
 #include <asm/i8253.h>
 #include <asm/nmi.h>
-#include <asm/idle.h>
 
 #include <mach_apic.h>
 #include <mach_apicdef.h>
@@ -339,6 +338,7 @@ void __init setup_boot_APIC_clock(void)
        void (*real_handler)(struct clock_event_device *dev);
        unsigned long deltaj;
        long delta, deltapm;
+       int pm_referenced = 0;
 
        apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
                    "calibrating APIC timer ...\n");
@@ -358,7 +358,8 @@ void __init setup_boot_APIC_clock(void)
        /* Let the interrupts run */
        local_irq_enable();
 
-       while(lapic_cal_loops <= LAPIC_CAL_LOOPS);
+       while (lapic_cal_loops <= LAPIC_CAL_LOOPS)
+               cpu_relax();
 
        local_irq_disable();
 
@@ -395,6 +396,7 @@ void __init setup_boot_APIC_clock(void)
                               "%lu (%ld)\n", (unsigned long) res, delta);
                        delta = (long) res;
                }
+               pm_referenced = 1;
        }
 
        /* Calculate the scaled math multiplication factor */
@@ -424,68 +426,41 @@ void __init setup_boot_APIC_clock(void)
                    calibration_result / (1000000 / HZ),
                    calibration_result % (1000000 / HZ));
 
-
-       apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
-
-       /*
-        * Setup the apic timer manually
-        */
        local_apic_timer_verify_ok = 1;
-       levt->event_handler = lapic_cal_handler;
-       lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
-       lapic_cal_loops = -1;
 
-       /* Let the interrupts run */
-       local_irq_enable();
+       /* We trust the pm timer based calibration */
+       if (!pm_referenced) {
+               apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
 
-       while(lapic_cal_loops <= LAPIC_CAL_LOOPS);
+               /*
+                * Setup the apic timer manually
+                */
+               levt->event_handler = lapic_cal_handler;
+               lapic_timer_setup(CLOCK_EVT_MODE_PERIODIC, levt);
+               lapic_cal_loops = -1;
 
-       local_irq_disable();
+               /* Let the interrupts run */
+               local_irq_enable();
 
-       /* Stop the lapic timer */
-       lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
+               while(lapic_cal_loops <= LAPIC_CAL_LOOPS)
+                       cpu_relax();
 
-       local_irq_enable();
+               local_irq_disable();
 
-       /* Jiffies delta */
-       deltaj = lapic_cal_j2 - lapic_cal_j1;
-       apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
+               /* Stop the lapic timer */
+               lapic_timer_setup(CLOCK_EVT_MODE_SHUTDOWN, levt);
 
-       /* Check, if the PM timer is available */
-       deltapm = lapic_cal_pm2 - lapic_cal_pm1;
-       apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
+               local_irq_enable();
 
-       local_apic_timer_verify_ok = 0;
+               /* Jiffies delta */
+               deltaj = lapic_cal_j2 - lapic_cal_j1;
+               apic_printk(APIC_VERBOSE, "... jiffies delta = %lu\n", deltaj);
 
-       if (deltapm) {
-               if (deltapm > (pm_100ms - pm_thresh) &&
-                   deltapm < (pm_100ms + pm_thresh)) {
-                       apic_printk(APIC_VERBOSE, "... PM timer result ok\n");
-                       /* Check, if the jiffies result is consistent */
-                       if (deltaj < LAPIC_CAL_LOOPS-2 ||
-                           deltaj > LAPIC_CAL_LOOPS+2) {
-                               /*
-                                * Not sure, what we can do about this one.
-                                * When high resultion timers are active
-                                * and the lapic timer does not stop in C3
-                                * we are fine. Otherwise more trouble might
-                                * be waiting. -- tglx
-                                */
-                               printk(KERN_WARNING "Global event device %s "
-                                      "has wrong frequency "
-                                      "(%lu ticks instead of %d)\n",
-                                      global_clock_event->name, deltaj,
-                                      LAPIC_CAL_LOOPS);
-                       }
-                       local_apic_timer_verify_ok = 1;
-               }
-       } else {
                /* Check, if the jiffies result is consistent */
-               if (deltaj >= LAPIC_CAL_LOOPS-2 &&
-                   deltaj <= LAPIC_CAL_LOOPS+2) {
+               if (deltaj >= LAPIC_CAL_LOOPS-2 && deltaj <= LAPIC_CAL_LOOPS+2)
                        apic_printk(APIC_VERBOSE, "... jiffies result ok\n");
-                       local_apic_timer_verify_ok = 1;
-               }
+               else
+                       local_apic_timer_verify_ok = 0;
        }
 
        if (!local_apic_timer_verify_ok) {
@@ -494,8 +469,15 @@ void __init setup_boot_APIC_clock(void)
                /* No broadcast on UP ! */
                if (num_possible_cpus() == 1)
                        return;
-       } else
-               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+       } else {
+               /*
+                * If nmi_watchdog is set to IO_APIC, we need the
+                * PIT/HPET going.  Otherwise register lapic as a dummy
+                * device.
+                */
+               if (nmi_watchdog != NMI_IO_APIC)
+                       lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+       }
 
        /* Setup the lapic or request the broadcast */
        setup_APIC_timer();
@@ -561,7 +543,6 @@ void fastcall smp_apic_timer_interrupt(struct pt_regs *regs)
         * Besides, if we don't timer interrupts ignore the global
         * interrupt lock, which is the WrongThing (tm) to do.
         */
-       exit_idle();
        irq_enter();
        local_apic_timer_interrupt();
        irq_exit();
@@ -1221,7 +1202,6 @@ void smp_spurious_interrupt(struct pt_regs *regs)
 {
        unsigned long v;
 
-       exit_idle();
        irq_enter();
        /*
         * Check if this really is a spurious interrupt and ACK it
@@ -1245,7 +1225,6 @@ void smp_error_interrupt(struct pt_regs *regs)
 {
        unsigned long v, v1;
 
-       exit_idle();
        irq_enter();
        /* First tickle the hardware, only then report what went on. -- REW */
        v = apic_read(APIC_ESR);