Merge branch 'dev' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
[pandora-kernel.git] / arch / x86 / kernel / apic / apic.c
index 52fa563..f98d84c 100644 (file)
@@ -186,7 +186,7 @@ static struct resource lapic_resource = {
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
-static unsigned int calibration_result;
+unsigned int lapic_timer_frequency = 0;
 
 static void apic_pm_activate(void);
 
@@ -454,7 +454,7 @@ static void lapic_timer_setup(enum clock_event_mode mode,
        switch (mode) {
        case CLOCK_EVT_MODE_PERIODIC:
        case CLOCK_EVT_MODE_ONESHOT:
-               __setup_APIC_LVTT(calibration_result,
+               __setup_APIC_LVTT(lapic_timer_frequency,
                                  mode != CLOCK_EVT_MODE_PERIODIC, 1);
                break;
        case CLOCK_EVT_MODE_UNUSED:
@@ -638,6 +638,25 @@ static int __init calibrate_APIC_clock(void)
        long delta, deltatsc;
        int pm_referenced = 0;
 
+       /**
+        * check if lapic timer has already been calibrated by platform
+        * specific routine, such as tsc calibration code. if so, we just fill
+        * in the clockevent structure and return.
+        */
+
+       if (lapic_timer_frequency) {
+               apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
+                               lapic_timer_frequency);
+               lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
+                                       TICK_NSEC, lapic_clockevent.shift);
+               lapic_clockevent.max_delta_ns =
+                       clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
+               lapic_clockevent.min_delta_ns =
+                       clockevent_delta2ns(0xF, &lapic_clockevent);
+               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
+               return 0;
+       }
+
        local_irq_disable();
 
        /* Replace the global interrupt handler */
@@ -679,12 +698,12 @@ static int __init calibrate_APIC_clock(void)
        lapic_clockevent.min_delta_ns =
                clockevent_delta2ns(0xF, &lapic_clockevent);
 
-       calibration_result = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
+       lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
 
        apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
        apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
        apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
-                   calibration_result);
+                   lapic_timer_frequency);
 
        if (cpu_has_tsc) {
                apic_printk(APIC_VERBOSE, "..... CPU clock speed is "
@@ -695,13 +714,13 @@ static int __init calibrate_APIC_clock(void)
 
        apic_printk(APIC_VERBOSE, "..... host bus clock speed is "
                    "%u.%04u MHz.\n",
-                   calibration_result / (1000000 / HZ),
-                   calibration_result % (1000000 / HZ));
+                   lapic_timer_frequency / (1000000 / HZ),
+                   lapic_timer_frequency % (1000000 / HZ));
 
        /*
         * Do a sanity check on the APIC calibration result
         */
-       if (calibration_result < (1000000 / HZ)) {
+       if (lapic_timer_frequency < (1000000 / HZ)) {
                local_irq_enable();
                pr_warning("APIC frequency too slow, disabling apic timer\n");
                return -1;
@@ -1437,27 +1456,21 @@ void enable_x2apic(void)
 
 int __init enable_IR(void)
 {
-#ifdef CONFIG_INTR_REMAP
+#ifdef CONFIG_IRQ_REMAP
        if (!intr_remapping_supported()) {
                pr_debug("intr-remapping not supported\n");
-               return 0;
+               return -1;
        }
 
        if (!x2apic_preenabled && skip_ioapic_setup) {
                pr_info("Skipped enabling intr-remap because of skipping "
                        "io-apic setup\n");
-               return 0;
+               return -1;
        }
 
-       if (enable_intr_remapping(x2apic_supported()))
-               return 0;
-
-       pr_info("Enabled Interrupt-remapping\n");
-
-       return 1;
-
+       return enable_intr_remapping();
 #endif
-       return 0;
+       return -1;
 }
 
 void __init enable_IR_x2apic(void)
@@ -1481,11 +1494,11 @@ void __init enable_IR_x2apic(void)
        mask_ioapic_entries();
 
        if (dmar_table_init_ret)
-               ret = 0;
+               ret = -1;
        else
                ret = enable_IR();
 
-       if (!ret) {
+       if (ret < 0) {
                /* IR is required if there is APIC ID > 255 even when running
                 * under KVM
                 */
@@ -1499,6 +1512,9 @@ void __init enable_IR_x2apic(void)
                x2apic_force_phys();
        }
 
+       if (ret == IRQ_REMAP_XAPIC_MODE)
+               goto nox2apic;
+
        x2apic_enabled = 1;
 
        if (x2apic_supported() && !x2apic_mode) {
@@ -1508,19 +1524,21 @@ void __init enable_IR_x2apic(void)
        }
 
 nox2apic:
-       if (!ret) /* IR enabling failed */
+       if (ret < 0) /* IR enabling failed */
                restore_ioapic_entries();
        legacy_pic->restore_mask();
        local_irq_restore(flags);
 
 out:
-       if (x2apic_enabled)
+       if (x2apic_enabled || !x2apic_supported())
                return;
 
        if (x2apic_preenabled)
                panic("x2apic: enabled by BIOS but kernel init failed.");
-       else if (cpu_has_x2apic)
-               pr_info("Not enabling x2apic, Intr-remapping init failed.\n");
+       else if (ret == IRQ_REMAP_XAPIC_MODE)
+               pr_info("x2apic not enabled, IRQ remapping is in xapic mode\n");
+       else if (ret < 0)
+               pr_info("x2apic not enabled, IRQ remapping init failed\n");
 }
 
 #ifdef CONFIG_X86_64