Pull asus into release branch
[pandora-kernel.git] / arch / x86_64 / kernel / apic.c
index 135ff25..bd3e45d 100644 (file)
@@ -37,6 +37,7 @@
 #include <asm/idle.h>
 #include <asm/proto.h>
 #include <asm/timex.h>
+#include <asm/hpet.h>
 #include <asm/apic.h>
 
 int apic_mapped;
@@ -46,6 +47,11 @@ int apic_calibrate_pmtmr __initdata;
 
 int disable_apic_timer __initdata;
 
+/* Local APIC timer works in C2? */
+int local_apic_timer_c2_ok;
+EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
+
+static struct resource *ioapic_resources;
 static struct resource lapic_resource = {
        .name = "Local APIC",
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
@@ -139,7 +145,6 @@ void clear_local_APIC(void)
                apic_write(APIC_LVTERR, APIC_LVT_MASKED);
        if (maxlvt >= 4)
                apic_write(APIC_LVTPC, APIC_LVT_MASKED);
-       v = GET_APIC_VERSION(apic_read(APIC_LVR));
        apic_write(APIC_ESR, 0);
        apic_read(APIC_ESR);
 }
@@ -458,23 +463,30 @@ static struct {
 static int lapic_suspend(struct sys_device *dev, pm_message_t state)
 {
        unsigned long flags;
+       int maxlvt;
 
        if (!apic_pm_state.active)
                return 0;
 
+       maxlvt = get_maxlvt();
+
        apic_pm_state.apic_id = apic_read(APIC_ID);
        apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI);
        apic_pm_state.apic_ldr = apic_read(APIC_LDR);
        apic_pm_state.apic_dfr = apic_read(APIC_DFR);
        apic_pm_state.apic_spiv = apic_read(APIC_SPIV);
        apic_pm_state.apic_lvtt = apic_read(APIC_LVTT);
-       apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
+       if (maxlvt >= 4)
+               apic_pm_state.apic_lvtpc = apic_read(APIC_LVTPC);
        apic_pm_state.apic_lvt0 = apic_read(APIC_LVT0);
        apic_pm_state.apic_lvt1 = apic_read(APIC_LVT1);
        apic_pm_state.apic_lvterr = apic_read(APIC_LVTERR);
        apic_pm_state.apic_tmict = apic_read(APIC_TMICT);
        apic_pm_state.apic_tdcr = apic_read(APIC_TDCR);
-       apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
+#ifdef CONFIG_X86_MCE_INTEL
+       if (maxlvt >= 5)
+               apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR);
+#endif
        local_irq_save(flags);
        disable_local_APIC();
        local_irq_restore(flags);
@@ -485,10 +497,13 @@ static int lapic_resume(struct sys_device *dev)
 {
        unsigned int l, h;
        unsigned long flags;
+       int maxlvt;
 
        if (!apic_pm_state.active)
                return 0;
 
+       maxlvt = get_maxlvt();
+
        local_irq_save(flags);
        rdmsr(MSR_IA32_APICBASE, l, h);
        l &= ~MSR_IA32_APICBASE_BASE;
@@ -502,8 +517,12 @@ static int lapic_resume(struct sys_device *dev)
        apic_write(APIC_SPIV, apic_pm_state.apic_spiv);
        apic_write(APIC_LVT0, apic_pm_state.apic_lvt0);
        apic_write(APIC_LVT1, apic_pm_state.apic_lvt1);
-       apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
-       apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
+#ifdef CONFIG_X86_MCE_INTEL
+       if (maxlvt >= 5)
+               apic_write(APIC_LVTTHMR, apic_pm_state.apic_thmr);
+#endif
+       if (maxlvt >= 4)
+               apic_write(APIC_LVTPC, apic_pm_state.apic_lvtpc);
        apic_write(APIC_LVTT, apic_pm_state.apic_lvtt);
        apic_write(APIC_TDCR, apic_pm_state.apic_tdcr);
        apic_write(APIC_TMICT, apic_pm_state.apic_tmict);
@@ -606,23 +625,47 @@ static struct resource * __init ioapic_setup_resources(void)
        n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
        n *= nr_ioapics;
 
-       res = alloc_bootmem(n);
+       mem = alloc_bootmem(n);
+       res = (void *)mem;
 
-       if (!res)
-               return NULL;
+       if (mem != NULL) {
+               memset(mem, 0, n);
+               mem += sizeof(struct resource) * nr_ioapics;
 
-       memset(res, 0, n);
-       mem = (void *)&res[nr_ioapics];
+               for (i = 0; i < nr_ioapics; i++) {
+                       res[i].name = mem;
+                       res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
+                       sprintf(mem,  "IOAPIC %u", i);
+                       mem += IOAPIC_RESOURCE_NAME_SIZE;
+               }
+       }
+
+       ioapic_resources = res;
+
+       return res;
+}
+
+static int __init ioapic_insert_resources(void)
+{
+       int i;
+       struct resource *r = ioapic_resources;
+
+       if (!r) {
+               printk("IO APIC resources could be not be allocated.\n");
+               return -1;
+       }
 
        for (i = 0; i < nr_ioapics; i++) {
-               res[i].name = mem;
-               res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
-               snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
-               mem += IOAPIC_RESOURCE_NAME_SIZE;
+               insert_resource(&iomem_resource, r);
+               r++;
        }
 
-       return res;
+       return 0;
 }
+
+/* Insert the IO APIC resources after PCI initialization has occured to handle
+ * IO APICS that are mapped in on a BAR in PCI space. */
+late_initcall(ioapic_insert_resources);
 #endif
 
 void __init init_apic_mappings(void)
@@ -673,10 +716,9 @@ void __init init_apic_mappings(void)
                                        __fix_to_virt(idx), ioapic_phys);
                        idx++;
 
-                       if (ioapic_res) {
+                       if (ioapic_res != NULL) {
                                ioapic_res->start = ioapic_phys;
                                ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
-                               insert_resource(&iomem_resource, ioapic_res);
                                ioapic_res++;
                        }
                }
@@ -698,10 +740,9 @@ void __init init_apic_mappings(void)
 
 static void __setup_APIC_LVTT(unsigned int clocks)
 {
-       unsigned int lvtt_value, tmp_value, ver;
+       unsigned int lvtt_value, tmp_value;
        int cpu = smp_processor_id();
 
-       ver = GET_APIC_VERSION(apic_read(APIC_LVR));
        lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
 
        if (cpu_isset(cpu, timer_interrupt_broadcast_ipi_mask))
@@ -727,7 +768,7 @@ static void setup_APIC_timer(unsigned int clocks)
        local_irq_save(flags);
 
        /* wait for irq slice */
-       if (vxtime.hpet_address && hpet_use_timer) {
+       if (hpet_address && hpet_use_timer) {
                int trigger = hpet_readl(HPET_T0_CMP);
                while (hpet_readl(HPET_COUNTER) >= trigger)
                        /* do nothing */ ;
@@ -749,7 +790,7 @@ static void setup_APIC_timer(unsigned int clocks)
        /* Turn off PIT interrupt if we use APIC timer as main timer.
           Only works with the PM timer right now
           TBD fix it for HPET too. */
-       if (vxtime.mode == VXTIME_PMTMR &&
+       if ((pmtmr_ioport != 0) &&
                smp_processor_id() == boot_cpu_id &&
                apic_runs_main_timer == 1 &&
                !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
@@ -893,9 +934,17 @@ EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
 
 void smp_send_timer_broadcast_ipi(void)
 {
+       int cpu = smp_processor_id();
        cpumask_t mask;
 
        cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
+
+       if (cpu_isset(cpu, mask)) {
+               cpu_clear(cpu, mask);
+               add_pda(apic_timer_irqs, 1);
+               smp_local_timer_interrupt();
+       }
+
        if (!cpus_empty(mask)) {
                send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
        }
@@ -939,14 +988,14 @@ void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
  * value into /proc/profile.
  */
 
-void smp_local_timer_interrupt(struct pt_regs *regs)
+void smp_local_timer_interrupt(void)
 {
-       profile_tick(CPU_PROFILING, regs);
+       profile_tick(CPU_PROFILING);
 #ifdef CONFIG_SMP
-       update_process_times(user_mode(regs));
+       update_process_times(user_mode(get_irq_regs()));
 #endif
        if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
-               main_timer_handler(regs);
+               main_timer_handler();
        /*
         * We take the 'long' return path, and there every subsystem
         * grabs the appropriate locks (kernel lock/ irq lock).
@@ -969,6 +1018,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
  */
 void smp_apic_timer_interrupt(struct pt_regs *regs)
 {
+       struct pt_regs *old_regs = set_irq_regs(regs);
+
        /*
         * the NMI deadlock-detector uses this.
         */
@@ -986,8 +1037,9 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
         */
        exit_idle();
        irq_enter();
-       smp_local_timer_interrupt(regs);
+       smp_local_timer_interrupt();
        irq_exit();
+       set_irq_regs(old_regs);
 }
 
 /*
@@ -1152,6 +1204,13 @@ static __init int setup_nolapic(char *str)
 } 
 early_param("nolapic", setup_nolapic);
 
+static int __init parse_lapic_timer_c2_ok(char *arg)
+{
+       local_apic_timer_c2_ok = 1;
+       return 0;
+}
+early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
+
 static __init int setup_noapictimer(char *str) 
 { 
        if (str[0] != ' ' && str[0] != 0)