Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[safe/jmp/linux-2.6] / arch / x86 / xen / time.c
index 41e2175..b3c6c59 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/clockchips.h>
 #include <linux/kernel_stat.h>
 #include <linux/math64.h>
+#include <linux/gfp.h>
 
 #include <asm/pvclock.h>
 #include <asm/xen/hypervisor.h>
 #define TIMER_SLOP     100000
 #define NS_PER_TICK    (1000000000LL / HZ)
 
-static cycle_t xen_clocksource_read(void);
-
 /* runstate info updated by Xen */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate);
 
 /* snapshots of runstate info */
-static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate_snapshot);
+static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
 
 /* unused ns of stolen and blocked time */
-static DEFINE_PER_CPU(u64, residual_stolen);
-static DEFINE_PER_CPU(u64, residual_blocked);
+static DEFINE_PER_CPU(u64, xen_residual_stolen);
+static DEFINE_PER_CPU(u64, xen_residual_blocked);
 
 /* return an consistent snapshot of 64-bit time/counter value */
 static u64 get64(const u64 *p)
@@ -81,7 +80,7 @@ static void get_runstate_snapshot(struct vcpu_runstate_info *res)
 
        BUG_ON(preemptible());
 
-       state = &__get_cpu_var(runstate);
+       state = &__get_cpu_var(xen_runstate);
 
        /*
         * The runstate info is always updated by the hypervisor on
@@ -99,14 +98,14 @@ static void get_runstate_snapshot(struct vcpu_runstate_info *res)
 /* return true when a vcpu could run but has no real cpu to run on */
 bool xen_vcpu_stolen(int vcpu)
 {
-       return per_cpu(runstate, vcpu).state == RUNSTATE_runnable;
+       return per_cpu(xen_runstate, vcpu).state == RUNSTATE_runnable;
 }
 
-static void setup_runstate_info(int cpu)
+void xen_setup_runstate_info(int cpu)
 {
        struct vcpu_register_runstate_memory_area area;
 
-       area.addr.v = &per_cpu(runstate, cpu);
+       area.addr.v = &per_cpu(xen_runstate, cpu);
 
        if (HYPERVISOR_vcpu_op(VCPUOP_register_runstate_memory_area,
                               cpu, &area))
@@ -124,7 +123,7 @@ static void do_stolen_accounting(void)
 
        WARN_ON(state.state != RUNSTATE_running);
 
-       snap = &__get_cpu_var(runstate_snapshot);
+       snap = &__get_cpu_var(xen_runstate_snapshot);
 
        /* work out how much time the VCPU has not been runn*ing*  */
        blocked = state.time[RUNSTATE_blocked] - snap->time[RUNSTATE_blocked];
@@ -134,28 +133,26 @@ static void do_stolen_accounting(void)
        *snap = state;
 
        /* Add the appropriate number of ticks of stolen time,
-          including any left-overs from last time.  Passing NULL to
-          account_steal_time accounts the time as stolen. */
-       stolen = runnable + offline + __get_cpu_var(residual_stolen);
+          including any left-overs from last time. */
+       stolen = runnable + offline + __get_cpu_var(xen_residual_stolen);
 
        if (stolen < 0)
                stolen = 0;
 
        ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
-       __get_cpu_var(residual_stolen) = stolen;
-       account_steal_time(NULL, ticks);
+       __get_cpu_var(xen_residual_stolen) = stolen;
+       account_steal_ticks(ticks);
 
        /* Add the appropriate number of ticks of blocked time,
-          including any left-overs from last time.  Passing idle to
-          account_steal_time accounts the time as idle/wait. */
-       blocked += __get_cpu_var(residual_blocked);
+          including any left-overs from last time. */
+       blocked += __get_cpu_var(xen_residual_blocked);
 
        if (blocked < 0)
                blocked = 0;
 
        ticks = iter_div_u64_rem(blocked, NS_PER_TICK, &blocked);
-       __get_cpu_var(residual_blocked) = blocked;
-       account_steal_time(idle_task(smp_processor_id()), ticks);
+       __get_cpu_var(xen_residual_blocked) = blocked;
+       account_idle_ticks(ticks);
 }
 
 /*
@@ -197,23 +194,16 @@ unsigned long long xen_sched_clock(void)
 }
 
 
-/* Get the CPU speed from Xen */
-unsigned long xen_cpu_khz(void)
+/* Get the TSC speed from Xen */
+unsigned long xen_tsc_khz(void)
 {
-       u64 xen_khz = 1000000ULL << 32;
-       const struct pvclock_vcpu_time_info *info =
+       struct pvclock_vcpu_time_info *info =
                &HYPERVISOR_shared_info->vcpu_info[0].time;
 
-       do_div(xen_khz, info->tsc_to_system_mul);
-       if (info->tsc_shift < 0)
-               xen_khz <<= -info->tsc_shift;
-       else
-               xen_khz >>= info->tsc_shift;
-
-       return xen_khz;
+       return pvclock_tsc_khz(info);
 }
 
-static cycle_t xen_clocksource_read(void)
+cycle_t xen_clocksource_read(void)
 {
         struct pvclock_vcpu_time_info *src;
        cycle_t ret;
@@ -224,6 +214,11 @@ static cycle_t xen_clocksource_read(void)
        return ret;
 }
 
+static cycle_t xen_clocksource_get_cycles(struct clocksource *cs)
+{
+       return xen_clocksource_read();
+}
+
 static void xen_read_wallclock(struct timespec *ts)
 {
        struct shared_info *s = HYPERVISOR_shared_info;
@@ -252,7 +247,7 @@ int xen_set_wallclock(unsigned long now)
 static struct clocksource xen_clocksource __read_mostly = {
        .name = "xen",
        .rating = 400,
-       .read = xen_clocksource_read,
+       .read = xen_clocksource_get_cycles,
        .mask = ~0,
        .mult = 1<<XEN_SHIFT,           /* time directly in nanoseconds */
        .shift = XEN_SHIFT,
@@ -440,16 +435,22 @@ void xen_setup_timer(int cpu)
                name = "<timer kasprintf failed>";
 
        irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
-                                     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
+                                     IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER,
                                      name, NULL);
 
        evt = &per_cpu(xen_clock_events, cpu);
        memcpy(evt, xen_clockevent, sizeof(*evt));
 
-       evt->cpumask = cpumask_of_cpu(cpu);
+       evt->cpumask = cpumask_of(cpu);
        evt->irq = irq;
+}
 
-       setup_runstate_info(cpu);
+void xen_teardown_timer(int cpu)
+{
+       struct clock_event_device *evt;
+       BUG_ON(cpu == 0);
+       evt = &per_cpu(xen_clock_events, cpu);
+       unbind_from_irqhandler(evt->irq, NULL);
 }
 
 void xen_setup_cpu_clockevents(void)
@@ -459,9 +460,23 @@ void xen_setup_cpu_clockevents(void)
        clockevents_register_device(&__get_cpu_var(xen_clock_events));
 }
 
+void xen_timer_resume(void)
+{
+       int cpu;
+
+       if (xen_clockevent != &xen_vcpuop_clockevent)
+               return;
+
+       for_each_online_cpu(cpu) {
+               if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
+                       BUG();
+       }
+}
+
 __init void xen_time_init(void)
 {
        int cpu = smp_processor_id();
+       struct timespec tp;
 
        clocksource_register(&xen_clocksource);
 
@@ -473,12 +488,12 @@ __init void xen_time_init(void)
        }
 
        /* Set initial system time with full resolution */
-       xen_read_wallclock(&xtime);
-       set_normalized_timespec(&wall_to_monotonic,
-                               -xtime.tv_sec, -xtime.tv_nsec);
+       xen_read_wallclock(&tp);
+       do_settimeofday(&tp);
 
        setup_force_cpu_cap(X86_FEATURE_TSC);
 
+       xen_setup_runstate_info(cpu);
        xen_setup_timer(cpu);
        xen_setup_cpu_clockevents();
 }