Merge branch 'linus' into perfcounters/core
[safe/jmp/linux-2.6] / arch / x86 / kernel / apic / apic.c
index 699f8cf..fb504f8 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/smp.h>
 #include <linux/mm.h>
 
+#include <asm/perf_counter.h>
 #include <asm/pgalloc.h>
 #include <asm/atomic.h>
 #include <asm/mpspec.h>
@@ -755,6 +756,8 @@ static void local_apic_timer_interrupt(void)
        inc_irq_stat(apic_timer_irqs);
 
        evt->event_handler(evt);
+
+       perf_counter_unthrottle();
 }
 
 /*
@@ -1127,6 +1130,7 @@ void __cpuinit setup_local_APIC(void)
                apic_write(APIC_ESR, 0);
        }
 #endif
+       perf_counters_lapic_init(0);
 
        preempt_disable();
 
@@ -1304,6 +1308,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;
@@ -1334,16 +1339,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);
@@ -1363,14 +1375,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");
@@ -1378,6 +1390,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;
@@ -1953,6 +1967,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;
 }
@@ -1963,15 +1981,41 @@ 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;
+               }
 
+               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();
+#endif
+
        else {
                /*
                 * Make sure the APICBASE points to the right address
@@ -1985,6 +2029,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);
@@ -2008,8 +2053,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;
 }
 
@@ -2047,7 +2104,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 */