Skip to content

Commit

Permalink
x86: Make xen use the paravirt clocksource structs and functions
Browse files Browse the repository at this point in the history
This patch updates the xen guest to use the pvclock structs
and helper functions.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Avi Kivity <avi@qumranet.com>
  • Loading branch information
kraxel authored and avikivity committed Jun 24, 2008
1 parent 7af192c commit 1c7b67f
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 124 deletions.
1 change: 1 addition & 0 deletions arch/x86/xen/Kconfig
Expand Up @@ -5,6 +5,7 @@
config XEN
bool "Xen guest support"
select PARAVIRT
select PARAVIRT_CLOCK
depends on X86_32
depends on X86_CMPXCHG && X86_TSC && !(X86_VISWS || X86_VOYAGER)
help
Expand Down
132 changes: 12 additions & 120 deletions arch/x86/xen/time.c
Expand Up @@ -14,6 +14,7 @@
#include <linux/kernel_stat.h>
#include <linux/math64.h>

#include <asm/pvclock.h>
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>

Expand All @@ -31,17 +32,6 @@

static cycle_t xen_clocksource_read(void);

/* These are perodically updated in shared_info, and then copied here. */
struct shadow_time_info {
u64 tsc_timestamp; /* TSC at last update of time vals. */
u64 system_timestamp; /* Time, in nanosecs, since boot. */
u32 tsc_to_nsec_mul;
int tsc_shift;
u32 version;
};

static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);

/* runstate info updated by Xen */
static DEFINE_PER_CPU(struct vcpu_runstate_info, runstate);

Expand Down Expand Up @@ -211,7 +201,7 @@ unsigned long long xen_sched_clock(void)
unsigned long xen_cpu_khz(void)
{
u64 xen_khz = 1000000ULL << 32;
const struct vcpu_time_info *info =
const struct pvclock_vcpu_time_info *info =
&HYPERVISOR_shared_info->vcpu_info[0].time;

do_div(xen_khz, info->tsc_to_system_mul);
Expand All @@ -223,129 +213,33 @@ unsigned long xen_cpu_khz(void)
return xen_khz;
}

/*
* Reads a consistent set of time-base values from Xen, into a shadow data
* area.
*/
static unsigned get_time_values_from_xen(void)
{
struct vcpu_time_info *src;
struct shadow_time_info *dst;

/* src is shared memory with the hypervisor, so we need to
make sure we get a consistent snapshot, even in the face of
being preempted. */
src = &__get_cpu_var(xen_vcpu)->time;
dst = &__get_cpu_var(shadow_time);

do {
dst->version = src->version;
rmb(); /* fetch version before data */
dst->tsc_timestamp = src->tsc_timestamp;
dst->system_timestamp = src->system_time;
dst->tsc_to_nsec_mul = src->tsc_to_system_mul;
dst->tsc_shift = src->tsc_shift;
rmb(); /* test version after fetching data */
} while ((src->version & 1) | (dst->version ^ src->version));

return dst->version;
}

/*
* Scale a 64-bit delta by scaling and multiplying by a 32-bit fraction,
* yielding a 64-bit result.
*/
static inline u64 scale_delta(u64 delta, u32 mul_frac, int shift)
{
u64 product;
#ifdef __i386__
u32 tmp1, tmp2;
#endif

if (shift < 0)
delta >>= -shift;
else
delta <<= shift;

#ifdef __i386__
__asm__ (
"mul %5 ; "
"mov %4,%%eax ; "
"mov %%edx,%4 ; "
"mul %5 ; "
"xor %5,%5 ; "
"add %4,%%eax ; "
"adc %5,%%edx ; "
: "=A" (product), "=r" (tmp1), "=r" (tmp2)
: "a" ((u32)delta), "1" ((u32)(delta >> 32)), "2" (mul_frac) );
#elif __x86_64__
__asm__ (
"mul %%rdx ; shrd $32,%%rdx,%%rax"
: "=a" (product) : "0" (delta), "d" ((u64)mul_frac) );
#else
#error implement me!
#endif

return product;
}

static u64 get_nsec_offset(struct shadow_time_info *shadow)
{
u64 now, delta;
now = native_read_tsc();
delta = now - shadow->tsc_timestamp;
return scale_delta(delta, shadow->tsc_to_nsec_mul, shadow->tsc_shift);
}

static cycle_t xen_clocksource_read(void)
{
struct shadow_time_info *shadow = &get_cpu_var(shadow_time);
struct pvclock_vcpu_time_info *src;
cycle_t ret;
unsigned version;

do {
version = get_time_values_from_xen();
barrier();
ret = shadow->system_timestamp + get_nsec_offset(shadow);
barrier();
} while (version != __get_cpu_var(xen_vcpu)->time.version);

put_cpu_var(shadow_time);

src = &get_cpu_var(xen_vcpu)->time;
ret = pvclock_clocksource_read(src);
put_cpu_var(xen_vcpu);
return ret;
}

static void xen_read_wallclock(struct timespec *ts)
{
const struct shared_info *s = HYPERVISOR_shared_info;
u32 version;
u64 delta;
struct timespec now;

/* get wallclock at system boot */
do {
version = s->wc_version;
rmb(); /* fetch version before time */
now.tv_sec = s->wc_sec;
now.tv_nsec = s->wc_nsec;
rmb(); /* fetch time before checking version */
} while ((s->wc_version & 1) | (version ^ s->wc_version));
struct shared_info *s = HYPERVISOR_shared_info;
struct pvclock_wall_clock *wall_clock = &(s->wc);
struct pvclock_vcpu_time_info *vcpu_time;

delta = xen_clocksource_read(); /* time since system boot */
delta += now.tv_sec * (u64)NSEC_PER_SEC + now.tv_nsec;

now.tv_nsec = do_div(delta, NSEC_PER_SEC);
now.tv_sec = delta;

set_normalized_timespec(ts, now.tv_sec, now.tv_nsec);
vcpu_time = &get_cpu_var(xen_vcpu)->time;
pvclock_read_wallclock(wall_clock, vcpu_time, ts);
put_cpu_var(xen_vcpu);
}

unsigned long xen_get_wallclock(void)
{
struct timespec ts;

xen_read_wallclock(&ts);

return ts.tv_sec;
}

Expand Down Expand Up @@ -569,8 +463,6 @@ __init void xen_time_init(void)
{
int cpu = smp_processor_id();

get_time_values_from_xen();

clocksource_register(&xen_clocksource);

if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
Expand Down
7 changes: 3 additions & 4 deletions include/xen/interface/xen.h
Expand Up @@ -10,6 +10,7 @@
#define __XEN_PUBLIC_XEN_H__

#include <asm/xen/interface.h>
#include <asm/pvclock-abi.h>

/*
* XEN "SYSTEM CALLS" (a.k.a. HYPERCALLS).
Expand Down Expand Up @@ -336,7 +337,7 @@ struct vcpu_info {
uint8_t evtchn_upcall_mask;
unsigned long evtchn_pending_sel;
struct arch_vcpu_info arch;
struct vcpu_time_info time;
struct pvclock_vcpu_time_info time;
}; /* 64 bytes (x86) */

/*
Expand Down Expand Up @@ -384,9 +385,7 @@ struct shared_info {
* Wallclock time: updated only by control software. Guests should base
* their gettimeofday() syscall on this wallclock-base value.
*/
uint32_t wc_version; /* Version counter: see vcpu_time_info_t. */
uint32_t wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
uint32_t wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
struct pvclock_wall_clock wc;

struct arch_shared_info arch;

Expand Down

0 comments on commit 1c7b67f

Please sign in to comment.