# HG changeset patch
# User kaf24@xxxxxxxxxxxxxxxxxxxx
# Node ID 217fb2d1f364176571396fb7b4bf89222927631e
# Parent 7931f14bd447465bfdf2a458f70ccac55edcad03
More time-interface fixes.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
diff -r 7931f14bd447 -r 217fb2d1f364
linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c
--- a/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Sat Aug 6 09:54:57 2005
+++ b/linux-2.6-xen-sparse/arch/xen/i386/kernel/time.c Sat Aug 6 15:24:22 2005
@@ -115,7 +115,8 @@
u32 version;
};
static DEFINE_PER_CPU(struct shadow_time_info, shadow_time);
-static struct timeval shadow_tv;
+static struct timespec shadow_tv;
+static u32 shadow_tv_version;
/* Keep track of last time we did processing/updating of jiffies and xtime. */
static u64 processed_system_time; /* System time (ns) at last processing. */
@@ -123,18 +124,6 @@
#define NS_PER_TICK (1000000000ULL/HZ)
-#define HANDLE_USEC_UNDERFLOW(_tv) do { \
- while ((_tv).tv_usec < 0) { \
- (_tv).tv_usec += USEC_PER_SEC; \
- (_tv).tv_sec--; \
- } \
-} while (0)
-#define HANDLE_USEC_OVERFLOW(_tv) do { \
- while ((_tv).tv_usec >= USEC_PER_SEC) { \
- (_tv).tv_usec -= USEC_PER_SEC; \
- (_tv).tv_sec++; \
- } \
-} while (0)
static inline void __normalize_time(time_t *sec, s64 *nsec)
{
while (*nsec >= NSEC_PER_SEC) {
@@ -231,14 +220,16 @@
shared_info_t *s = HYPERVISOR_shared_info;
long wtm_nsec, xtime_nsec;
time_t wtm_sec, xtime_sec;
- u64 tmp, usec;
-
- if ((shadow_tv.tv_sec == s->wc_sec) &&
- (shadow_tv.tv_usec == s->wc_usec))
- return;
-
- shadow_tv.tv_sec = s->wc_sec;
- shadow_tv.tv_usec = s->wc_usec;
+ u64 tmp, nsec;
+
+ do {
+ shadow_tv_version = s->wc_version;
+ rmb();
+ shadow_tv.tv_sec = s->wc_sec;
+ shadow_tv.tv_nsec = s->wc_nsec;
+ rmb();
+ }
+ while ((s->wc_version & 1) | (shadow_tv_version ^ s->wc_version));
if (INDEPENDENT_WALLCLOCK())
return;
@@ -247,15 +238,14 @@
return;
/* Adjust wall-clock time base based on wall_jiffies ticks. */
- usec = processed_system_time;
- do_div(usec, 1000);
- usec += (u64)shadow_tv.tv_sec * 1000000ULL;
- usec += (u64)shadow_tv.tv_usec;
- usec -= (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ);
+ nsec = processed_system_time;
+ nsec += (u64)shadow_tv.tv_sec * 1000000000ULL;
+ nsec += (u64)shadow_tv.tv_nsec;
+ nsec -= (jiffies - wall_jiffies) * (u64)(NSEC_PER_SEC / HZ);
/* Split wallclock base into seconds and nanoseconds. */
- tmp = usec;
- xtime_nsec = do_div(tmp, 1000000) * 1000ULL;
+ tmp = nsec;
+ xtime_nsec = do_div(tmp, 1000000000);
xtime_sec = (time_t)tmp;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - xtime_sec);
@@ -279,7 +269,7 @@
dst = &per_cpu(shadow_time, smp_processor_id());
do {
- dst->version = src->time_version2;
+ dst->version = src->version;
rmb();
dst->tsc_timestamp = src->tsc_timestamp;
dst->system_timestamp = src->system_time;
@@ -287,7 +277,7 @@
dst->tsc_shift = src->tsc_shift;
rmb();
}
- while (dst->version != src->time_version1);
+ while ((src->version & 1) | (dst->version ^ src->version));
dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
}
@@ -300,7 +290,7 @@
src = &HYPERVISOR_shared_info->vcpu_time[cpu];
dst = &per_cpu(shadow_time, cpu);
- return (dst->version == src->time_version2);
+ return (dst->version == src->version);
}
/*
@@ -469,7 +459,7 @@
dom0_op_t op;
op.cmd = DOM0_SETTIME;
op.u.settime.secs = xentime.tv_sec;
- op.u.settime.usecs = xentime.tv_nsec / NSEC_PER_USEC;
+ op.u.settime.nsecs = xentime.tv_nsec;
op.u.settime.system_time = shadow->system_timestamp;
write_sequnlock_irq(&xtime_lock);
HYPERVISOR_dom0_op(&op);
@@ -574,7 +564,7 @@
}
while (!time_values_up_to_date(cpu));
- if (unlikely(delta < 0) || unlikely(delta_cpu < 0)) {
+ if (unlikely(delta < (s64)-1000000) || unlikely(delta_cpu < 0)) {
printk("Timer ISR/%d: Time went backwards: "
"delta=%lld cpu_delta=%lld shadow=%lld "
"off=%lld processed=%lld cpu_processed=%lld\n",
@@ -603,7 +593,8 @@
profile_tick(CPU_PROFILING, regs);
}
- update_wallclock();
+ if (unlikely(shadow_tv_version != HYPERVISOR_shared_info->wc_version))
+ update_wallclock();
}
/*
@@ -792,8 +783,6 @@
#endif
get_time_values_from_xen();
update_wallclock();
- xtime.tv_sec = shadow_tv.tv_sec;
- xtime.tv_nsec = shadow_tv.tv_usec * NSEC_PER_USEC;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
processed_system_time = per_cpu(shadow_time, 0).system_timestamp;
diff -r 7931f14bd447 -r 217fb2d1f364 xen/arch/ia64/xentime.c
--- a/xen/arch/ia64/xentime.c Sat Aug 6 09:54:57 2005
+++ b/xen/arch/ia64/xentime.c Sat Aug 6 15:24:22 2005
@@ -48,7 +48,7 @@
static s_time_t stime_irq = 0x0; /* System time at last 'time
update' */
unsigned long itc_scale;
unsigned long itc_at_irq;
-static unsigned long wc_sec, wc_usec; /* UTC time at last 'time update'. */
+static unsigned long wc_sec, wc_nsec; /* UTC time at last 'time update'. */
//static rwlock_t time_lock = RW_LOCK_UNLOCKED;
static irqreturn_t vmx_timer_interrupt (int irq, void *dev_id, struct pt_regs
*regs);
@@ -103,25 +103,22 @@
}
/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
-void do_settime(unsigned long secs, unsigned long usecs, u64 system_time_base)
+void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
{
#ifdef CONFIG_VTI
- s64 delta;
- long _usecs = (long)usecs;
+ u64 _nsecs;
write_lock_irq(&xtime_lock);
- delta = (s64)(stime_irq - system_time_base);
-
- _usecs += (long)(delta/1000);
- while ( _usecs >= 1000000 )
+ _nsecs = (u64)nsecs + (s64)(stime_irq - system_time_base);
+ while ( _nsecs >= 1000000000 )
{
- _usecs -= 1000000;
+ _nsecs -= 1000000000;
secs++;
}
wc_sec = secs;
- wc_usec = _usecs;
+ wc_nsec = (unsigned long)_nsecs;
write_unlock_irq(&xtime_lock);
@@ -290,13 +287,13 @@
/* Wallclock time starts as the initial RTC time. */
efi_gettimeofday(&tm);
wc_sec = tm.tv_sec;
- wc_usec = tm.tv_nsec/1000;
+ wc_nsec = tm.tv_nsec;
printk("Time init:\n");
printk(".... System Time: %ldns\n", NOW());
printk(".... scale: %16lX\n", itc_scale);
- printk(".... Wall Clock: %lds %ldus\n", wc_sec, wc_usec);
+ printk(".... Wall Clock: %lds %ldus\n", wc_sec, wc_nsec/1000);
return 0;
}
@@ -338,10 +335,10 @@
(*(unsigned long *)&jiffies_64)++;
/* Update wall time. */
- wc_usec += 1000000/HZ;
- if ( wc_usec >= 1000000 )
+ wc_nsec += 1000000000/HZ;
+ if ( wc_nsec >= 1000000000 )
{
- wc_usec -= 1000000;
+ wc_nsec -= 1000000000;
wc_sec++;
}
diff -r 7931f14bd447 -r 217fb2d1f364 xen/arch/x86/domain.c
--- a/xen/arch/x86/domain.c Sat Aug 6 09:54:57 2005
+++ b/xen/arch/x86/domain.c Sat Aug 6 15:24:22 2005
@@ -279,6 +279,8 @@
shadow_lock_init(d);
INIT_LIST_HEAD(&d->arch.free_shadow_frames);
+
+ init_domain_time(d);
}
void arch_do_boot_vcpu(struct vcpu *v)
diff -r 7931f14bd447 -r 217fb2d1f364 xen/arch/x86/time.c
--- a/xen/arch/x86/time.c Sat Aug 6 09:54:57 2005
+++ b/xen/arch/x86/time.c Sat Aug 6 15:24:22 2005
@@ -43,7 +43,7 @@
spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
int timer_ack = 0;
unsigned long volatile jiffies;
-static unsigned long wc_sec, wc_usec; /* UTC time at last 'time update'. */
+static u32 wc_sec, wc_nsec; /* UTC time at last 'time update'. */
struct time_scale {
int shift;
@@ -630,25 +630,32 @@
return now;
}
+static inline void version_update_begin(u32 *version)
+{
+ /* Explicitly OR with 1 just in case version number gets out of sync. */
+ *version = (*version + 1) | 1;
+ wmb();
+}
+
+static inline void version_update_end(u32 *version)
+{
+ wmb();
+ (*version)++;
+}
+
static inline void __update_dom_time(struct vcpu *v)
{
struct cpu_time *t = &cpu_time[smp_processor_id()];
struct vcpu_time_info *u = &v->domain->shared_info->vcpu_time[v->vcpu_id];
- u->time_version1++;
- wmb();
+ version_update_begin(&u->version);
u->tsc_timestamp = t->local_tsc_stamp;
u->system_time = t->stime_local_stamp;
u->tsc_to_system_mul = t->tsc_scale.mul_frac;
u->tsc_shift = (s8)t->tsc_scale.shift;
- wmb();
- u->time_version2++;
-
- /* Should only do this during do_settime(). */
- v->domain->shared_info->wc_sec = wc_sec;
- v->domain->shared_info->wc_usec = wc_usec;
+ version_update_end(&u->version);
}
void update_dom_time(struct vcpu *v)
@@ -659,21 +666,39 @@
}
/* Set clock to <secs,usecs> after 00:00:00 UTC, 1 January, 1970. */
-void do_settime(unsigned long secs, unsigned long usecs, u64 system_time_base)
-{
- u64 x, base_usecs;
- u32 y;
-
- base_usecs = system_time_base;
- do_div(base_usecs, 1000);
-
- x = (secs * 1000000ULL) + (u64)usecs + base_usecs;
- y = do_div(x, 1000000);
-
- wc_sec = (unsigned long)x;
- wc_usec = (unsigned long)y;
-
- __update_dom_time(current);
+void do_settime(unsigned long secs, unsigned long nsecs, u64 system_time_base)
+{
+ u64 x;
+ u32 y, _wc_sec, _wc_nsec;
+ struct domain *d;
+ shared_info_t *s;
+
+ x = (secs * 1000000000ULL) + (u64)nsecs + system_time_base;
+ y = do_div(x, 1000000000);
+
+ wc_sec = _wc_sec = (u32)x;
+ wc_nsec = _wc_nsec = (u32)y;
+
+ read_lock(&domlist_lock);
+
+ for_each_domain ( d )
+ {
+ s = d->shared_info;
+ version_update_begin(&s->wc_version);
+ s->wc_sec = _wc_sec;
+ s->wc_nsec = _wc_nsec;
+ version_update_end(&s->wc_version);
+ }
+
+ read_unlock(&domlist_lock);
+}
+
+void init_domain_time(struct domain *d)
+{
+ version_update_begin(&d->shared_info->wc_version);
+ d->shared_info->wc_sec = wc_sec;
+ d->shared_info->wc_nsec = wc_nsec;
+ version_update_end(&d->shared_info->wc_version);
}
static void local_time_calibration(void *unused)
diff -r 7931f14bd447 -r 217fb2d1f364 xen/common/dom0_ops.c
--- a/xen/common/dom0_ops.c Sat Aug 6 09:54:57 2005
+++ b/xen/common/dom0_ops.c Sat Aug 6 15:24:22 2005
@@ -475,7 +475,7 @@
case DOM0_SETTIME:
{
do_settime(op->u.settime.secs,
- op->u.settime.usecs,
+ op->u.settime.nsecs,
op->u.settime.system_time);
ret = 0;
}
diff -r 7931f14bd447 -r 217fb2d1f364 xen/include/asm-x86/time.h
--- a/xen/include/asm-x86/time.h Sat Aug 6 09:54:57 2005
+++ b/xen/include/asm-x86/time.h Sat Aug 6 15:24:22 2005
@@ -7,4 +7,7 @@
extern void calibrate_tsc_bp(void);
extern void calibrate_tsc_ap(void);
+struct domain;
+extern void init_domain_time(struct domain *d);
+
#endif /* __X86_TIME_H__ */
diff -r 7931f14bd447 -r 217fb2d1f364 xen/include/public/dom0_ops.h
--- a/xen/include/public/dom0_ops.h Sat Aug 6 09:54:57 2005
+++ b/xen/include/public/dom0_ops.h Sat Aug 6 15:24:22 2005
@@ -131,14 +131,14 @@
} dom0_debug_t;
/*
- * Set clock such that it would read <secs,usecs> after 00:00:00 UTC,
+ * Set clock such that it would read <secs,nsecs> after 00:00:00 UTC,
* 1 January, 1970 if the current system time was <system_time>.
*/
#define DOM0_SETTIME 17
typedef struct {
/* IN variables. */
u32 secs;
- u32 usecs;
+ u32 nsecs;
u64 system_time;
} dom0_settime_t;
diff -r 7931f14bd447 -r 217fb2d1f364 xen/include/public/xen.h
--- a/xen/include/public/xen.h Sat Aug 6 09:54:57 2005
+++ b/xen/include/public/xen.h Sat Aug 6 15:24:22 2005
@@ -331,14 +331,15 @@
typedef struct vcpu_time_info {
/*
- * The following values are updated periodically (and not necessarily
- * atomically!). The guest OS detects this because 'time_version1' is
- * incremented just before updating these values, and 'time_version2' is
- * incremented immediately after. See the Xen-specific Linux code for an
- * example of how to read these values safely (arch/xen/kernel/time.c).
+ * Updates to the following values are preceded and followed by an
+ * increment of 'version'. The guest can therefore detect updates by
+ * looking for changes to 'version'. If the least-significant bit of
+ * the version number is set then an update is in progress and the guest
+ * must wait to read a consistent set of values.
+ * The correct way to interact with the version number is similar to
+ * Linux's seqlock: see the implementations of read_seqbegin/read_seqretry.
*/
- u32 time_version1;
- u32 time_version2;
+ u32 version;
u64 tsc_timestamp; /* TSC at last update of time vals. */
u64 system_time; /* Time, in nanosecs, since boot. */
/*
@@ -400,8 +401,9 @@
* Wallclock time: updated only by control software. Guests should base
* their gettimeofday() syscall on this wallclock-base value.
*/
- u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
- u32 wc_usec; /* Usecs 00:00:00 UTC, Jan 1, 1970. */
+ u32 wc_version; /* Version counter: see vcpu_time_info_t. */
+ u32 wc_sec; /* Secs 00:00:00 UTC, Jan 1, 1970. */
+ u32 wc_nsec; /* Nsecs 00:00:00 UTC, Jan 1, 1970. */
arch_shared_info_t arch;
diff -r 7931f14bd447 -r 217fb2d1f364 xen/include/xen/time.h
--- a/xen/include/xen/time.h Sat Aug 6 09:54:57 2005
+++ b/xen/include/xen/time.h Sat Aug 6 15:24:22 2005
@@ -57,7 +57,7 @@
extern void update_dom_time(struct vcpu *v);
extern void do_settime(
- unsigned long secs, unsigned long usecs, u64 system_time_base);
+ unsigned long secs, unsigned long nsecs, u64 system_time_base);
#endif /* __XEN_TIME_H__ */
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|