Merge branch 'linus' into perfcounters/core
[safe/jmp/linux-2.6] / arch / x86 / kernel / apic / apic.c
index c6bd771..e9021a9 100644 (file)
@@ -34,7 +34,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 
-#include <asm/arch_hooks.h>
+#include <asm/perf_counter.h>
 #include <asm/pgalloc.h>
 #include <asm/atomic.h>
 #include <asm/mpspec.h>
@@ -47,6 +47,7 @@
 #include <asm/idle.h>
 #include <asm/mtrr.h>
 #include <asm/smp.h>
+#include <asm/mce.h>
 
 unsigned int num_processors;
 
@@ -431,6 +432,12 @@ static void __cpuinit setup_APIC_timer(void)
 {
        struct clock_event_device *levt = &__get_cpu_var(lapic_events);
 
+       if (cpu_has(&current_cpu_data, X86_FEATURE_ARAT)) {
+               lapic_clockevent.features &= ~CLOCK_EVT_FEAT_C3STOP;
+               /* Make LAPIC timer preferrable over percpu HPET */
+               lapic_clockevent.rating = 150;
+       }
+
        memcpy(levt, &lapic_clockevent, sizeof(*levt));
        levt->cpumask = cpumask_of(smp_processor_id());
 
@@ -755,6 +762,8 @@ static void local_apic_timer_interrupt(void)
        inc_irq_stat(apic_timer_irqs);
 
        evt->event_handler(evt);
+
+       perf_counter_unthrottle();
 }
 
 /*
@@ -809,7 +818,7 @@ void clear_local_APIC(void)
        u32 v;
 
        /* APIC hasn't been mapped yet */
-       if (!apic_phys)
+       if (!x2apic && !apic_phys)
                return;
 
        maxlvt = lapic_get_maxlvt();
@@ -843,6 +852,14 @@ void clear_local_APIC(void)
                apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
        }
 #endif
+#ifdef CONFIG_X86_MCE_INTEL
+       if (maxlvt >= 6) {
+               v = apic_read(APIC_LVTCMCI);
+               if (!(v & APIC_LVT_MASKED))
+                       apic_write(APIC_LVTCMCI, v | APIC_LVT_MASKED);
+       }
+#endif
+
        /*
         * Clean APIC state for other OSs:
         */
@@ -1119,6 +1136,7 @@ void __cpuinit setup_local_APIC(void)
                apic_write(APIC_ESR, 0);
        }
 #endif
+       perf_counters_lapic_init(0);
 
        preempt_disable();
 
@@ -1242,6 +1260,12 @@ void __cpuinit setup_local_APIC(void)
        apic_write(APIC_LVT1, value);
 
        preempt_enable();
+
+#ifdef CONFIG_X86_MCE_INTEL
+       /* Recheck CMCI information after local APIC is up on CPU #0 */
+       if (smp_processor_id() == 0)
+               cmci_recheck();
+#endif
 }
 
 void __cpuinit end_local_APIC_setup(void)
@@ -1290,6 +1314,7 @@ void __init enable_IR_x2apic(void)
 #ifdef CONFIG_INTR_REMAP
        int ret;
        unsigned long flags;
+       struct IO_APIC_route_entry **ioapic_entries = NULL;
 
        if (!cpu_has_x2apic)
                return;
@@ -1320,16 +1345,23 @@ void __init enable_IR_x2apic(void)
                return;
        }
 
-       local_irq_save(flags);
-       mask_8259A();
+       ioapic_entries = alloc_ioapic_entries();
+       if (!ioapic_entries) {
+               pr_info("Allocate ioapic_entries failed: %d\n", ret);
+               goto end;
+       }
 
-       ret = save_mask_IO_APIC_setup();
+       ret = save_IO_APIC_setup(ioapic_entries);
        if (ret) {
                pr_info("Saving IO-APIC state failed: %d\n", ret);
                goto end;
        }
 
-       ret = enable_intr_remapping(1);
+       local_irq_save(flags);
+       mask_IO_APIC_setup(ioapic_entries);
+       mask_8259A();
+
+       ret = enable_intr_remapping(EIM_32BIT_APIC_ID);
 
        if (ret && x2apic_preenabled) {
                local_irq_restore(flags);
@@ -1349,14 +1381,14 @@ end_restore:
                /*
                 * IR enabling failed
                 */
-               restore_IO_APIC_setup();
+               restore_IO_APIC_setup(ioapic_entries);
        else
-               reinit_intr_remapped_IO_APIC(x2apic_preenabled);
+               reinit_intr_remapped_IO_APIC(x2apic_preenabled, ioapic_entries);
 
-end:
        unmask_8259A();
        local_irq_restore(flags);
 
+end:
        if (!ret) {
                if (!x2apic_preenabled)
                        pr_info("Enabled x2apic and interrupt-remapping\n");
@@ -1364,6 +1396,8 @@ end:
                        pr_info("Enabled Interrupt-remapping\n");
        } else
                pr_err("Failed to enable Interrupt-remapping and x2apic\n");
+       if (ioapic_entries)
+               free_ioapic_entries(ioapic_entries);
 #else
        if (!cpu_has_x2apic)
                return;
@@ -1509,12 +1543,10 @@ void __init early_init_lapic_mapping(void)
  */
 void __init init_apic_mappings(void)
 {
-#ifdef CONFIG_X86_X2APIC
        if (x2apic) {
                boot_cpu_physical_apicid = read_apic_id();
                return;
        }
-#endif
 
        /*
         * If no local APIC can be found then set up a fake all
@@ -1941,6 +1973,10 @@ static int lapic_suspend(struct sys_device *dev, pm_message_t state)
 
        local_irq_save(flags);
        disable_local_APIC();
+#ifdef CONFIG_INTR_REMAP
+       if (intr_remapping_enabled)
+               disable_intr_remapping();
+#endif
        local_irq_restore(flags);
        return 0;
 }
@@ -1951,19 +1987,42 @@ static int lapic_resume(struct sys_device *dev)
        unsigned long flags;
        int maxlvt;
 
+#ifdef CONFIG_INTR_REMAP
+       int ret;
+       struct IO_APIC_route_entry **ioapic_entries = NULL;
+
        if (!apic_pm_state.active)
                return 0;
 
-       maxlvt = lapic_get_maxlvt();
-
        local_irq_save(flags);
+       if (x2apic) {
+               ioapic_entries = alloc_ioapic_entries();
+               if (!ioapic_entries) {
+                       WARN(1, "Alloc ioapic_entries in lapic resume failed.");
+                       return -ENOMEM;
+               }
 
-#ifdef CONFIG_X86_X2APIC
+               ret = save_IO_APIC_setup(ioapic_entries);
+               if (ret) {
+                       WARN(1, "Saving IO-APIC state failed: %d\n", ret);
+                       free_ioapic_entries(ioapic_entries);
+                       return ret;
+               }
+
+               mask_IO_APIC_setup(ioapic_entries);
+               mask_8259A();
+               enable_x2apic();
+       }
+#else
+       if (!apic_pm_state.active)
+               return 0;
+
+       local_irq_save(flags);
        if (x2apic)
                enable_x2apic();
-       else
 #endif
-       {
+
+       else {
                /*
                 * Make sure the APICBASE points to the right address
                 *
@@ -1976,6 +2035,7 @@ static int lapic_resume(struct sys_device *dev)
                wrmsr(MSR_IA32_APICBASE, l, h);
        }
 
+       maxlvt = lapic_get_maxlvt();
        apic_write(APIC_LVTERR, ERROR_APIC_VECTOR | APIC_LVT_MASKED);
        apic_write(APIC_ID, apic_pm_state.apic_id);
        apic_write(APIC_DFR, apic_pm_state.apic_dfr);
@@ -1999,8 +2059,20 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_ESR, 0);
        apic_read(APIC_ESR);
 
+#ifdef CONFIG_INTR_REMAP
+       if (intr_remapping_enabled)
+               reenable_intr_remapping(EIM_32BIT_APIC_ID);
+
+       if (x2apic) {
+               unmask_8259A();
+               restore_IO_APIC_setup(ioapic_entries);
+               free_ioapic_entries(ioapic_entries);
+       }
+#endif
+
        local_irq_restore(flags);
 
+
        return 0;
 }
 
@@ -2038,7 +2110,9 @@ static int __init init_lapic_sysfs(void)
                error = sysdev_register(&device_lapic);
        return error;
 }
-device_initcall(init_lapic_sysfs);
+
+/* local apic needs to resume before other devices access its registers. */
+core_initcall(init_lapic_sysfs);
 
 #else  /* CONFIG_PM */