]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86/kernel/apic.c
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-omap-h63xx.git] / arch / x86 / kernel / apic.c
index d730e8d317275b2ed1ed9bc5005499abb4b330e9..16f94879b52578aba3e689d7a8adcccf59ab8ecb 100644 (file)
@@ -332,11 +332,7 @@ int lapic_get_maxlvt(void)
  */
 
 /* Clock divisor */
-#ifdef CONFG_X86_64
-#define APIC_DIVISOR 1
-#else
 #define APIC_DIVISOR 16
-#endif
 
 /*
  * This function sets up the local APIC timer, with a timeout of
@@ -538,14 +534,51 @@ static void __init lapic_cal_handler(struct clock_event_device *dev)
        }
 }
 
+static int __init calibrate_by_pmtimer(long deltapm, long *delta)
+{
+       const long pm_100ms = PMTMR_TICKS_PER_SEC / 10;
+       const long pm_thresh = pm_100ms / 100;
+       unsigned long mult;
+       u64 res;
+
+#ifndef CONFIG_X86_PM_TIMER
+       return -1;
+#endif
+
+       apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
+
+       /* Check, if the PM timer is available */
+       if (!deltapm)
+               return -1;
+
+       mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, 22);
+
+       if (deltapm > (pm_100ms - pm_thresh) &&
+           deltapm < (pm_100ms + pm_thresh)) {
+               apic_printk(APIC_VERBOSE, "... PM timer result ok\n");
+       } else {
+               res = (((u64)deltapm) *  mult) >> 22;
+               do_div(res, 1000000);
+               printk(KERN_WARNING "APIC calibration not consistent "
+                       "with PM Timer: %ldms instead of 100ms\n",
+                       (long)res);
+               /* Correct the lapic counter value */
+               res = (((u64)(*delta)) * pm_100ms);
+               do_div(res, deltapm);
+               printk(KERN_INFO "APIC delta adjusted to PM-Timer: "
+                       "%lu (%ld)\n", (unsigned long)res, *delta);
+               *delta = (long)res;
+       }
+
+       return 0;
+}
+
 static int __init calibrate_APIC_clock(void)
 {
        struct clock_event_device *levt = &__get_cpu_var(lapic_events);
-       const long pm_100ms = PMTMR_TICKS_PER_SEC/10;
-       const long pm_thresh = pm_100ms/100;
        void (*real_handler)(struct clock_event_device *dev);
        unsigned long deltaj;
-       long delta, deltapm;
+       long delta;
        int pm_referenced = 0;
 
        local_irq_disable();
@@ -555,10 +588,10 @@ static int __init calibrate_APIC_clock(void)
        global_clock_event->event_handler = lapic_cal_handler;
 
        /*
-        * Setup the APIC counter to 1e9. There is no way the lapic
+        * Setup the APIC counter to maximum. There is no way the lapic
         * can underflow in the 100ms detection time frame
         */
-       __setup_APIC_LVTT(1000000000, 0, 0);
+       __setup_APIC_LVTT(0xffffffff, 0, 0);
 
        /* Let the interrupts run */
        local_irq_enable();
@@ -575,36 +608,9 @@ static int __init calibrate_APIC_clock(void)
        delta = lapic_cal_t1 - lapic_cal_t2;
        apic_printk(APIC_VERBOSE, "... lapic delta = %ld\n", delta);
 
-#ifdef CONFIG_X86_PM_TIMER
-       /* Check, if the PM timer is available */
-       deltapm = lapic_cal_pm2 - lapic_cal_pm1;
-       apic_printk(APIC_VERBOSE, "... PM timer delta = %ld\n", deltapm);
-
-       if (deltapm) {
-               unsigned long mult;
-               u64 res;
-
-               mult = clocksource_hz2mult(PMTMR_TICKS_PER_SEC, 22);
-
-               if (deltapm > (pm_100ms - pm_thresh) &&
-                   deltapm < (pm_100ms + pm_thresh)) {
-                       apic_printk(APIC_VERBOSE, "... PM timer result ok\n");
-               } else {
-                       res = (((u64) deltapm) *  mult) >> 22;
-                       do_div(res, 1000000);
-                       printk(KERN_WARNING "APIC calibration not consistent "
-                              "with PM Timer: %ldms instead of 100ms\n",
-                              (long)res);
-                       /* Correct the lapic counter value */
-                       res = (((u64) delta) * pm_100ms);
-                       do_div(res, deltapm);
-                       printk(KERN_INFO "APIC delta adjusted to PM-Timer: "
-                              "%lu (%ld)\n", (unsigned long) res, delta);
-                       delta = (long) res;
-               }
-               pm_referenced = 1;
-       }
-#endif
+       /* we trust the PM based calibration if possible */
+       pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1,
+                                       &delta);
 
        /* Calculate the scaled math multiplication factor */
        lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS,
@@ -646,7 +652,10 @@ static int __init calibrate_APIC_clock(void)
 
        levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
 
-       /* We trust the pm timer based calibration */
+       /*
+        * PM timer calibration failed or not turned on
+        * so lets try APIC timer based calibration
+        */
        if (!pm_referenced) {
                apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
 
@@ -1306,7 +1315,7 @@ void enable_x2apic(void)
        }
 }
 
-void enable_IR_x2apic(void)
+void __init enable_IR_x2apic(void)
 {
 #ifdef CONFIG_INTR_REMAP
        int ret;
@@ -1347,7 +1356,12 @@ void enable_IR_x2apic(void)
 
        local_irq_save(flags);
        mask_8259A();
-       save_mask_IO_APIC_setup();
+
+       ret = save_mask_IO_APIC_setup();
+       if (ret) {
+               printk(KERN_INFO "Saving IO-APIC state failed: %d\n", ret);
+               goto end;
+       }
 
        ret = enable_intr_remapping(1);
 
@@ -1357,14 +1371,15 @@ void enable_IR_x2apic(void)
        }
 
        if (ret)
-               goto end;
+               goto end_restore;
 
        if (!x2apic) {
                x2apic = 1;
                apic_ops = &x2apic_ops;
                enable_x2apic();
        }
-end:
+
+end_restore:
        if (ret)
                /*
                 * IR enabling failed
@@ -1373,6 +1388,7 @@ end:
        else
                reinit_intr_remapped_IO_APIC(x2apic_preenabled);
 
+end:
        unmask_8259A();
        local_irq_restore(flags);