diff options
| author | David Vrabel <david.vrabel@citrix.com> | 2013-05-13 18:56:06 +0100 | 
|---|---|---|
| committer | John Stultz <john.stultz@linaro.org> | 2013-05-28 14:00:59 -0700 | 
| commit | 3565184ed0c1ea46bea5b792da5f72a83c43e49b (patch) | |
| tree | 4846a589a6aa295634ef585e5637872f15c19993 /arch/x86 | |
| parent | 0a0a7e66fa269de78975ea8d4e825a66d92b8d70 (diff) | |
| download | linux-3565184ed0c1ea46bea5b792da5f72a83c43e49b.tar.bz2 | |
x86: Increase precision of x86_platform.get/set_wallclock()
All the virtualized platforms (KVM, lguest and Xen) have persistent
wallclocks that have more than one second of precision.
read_persistent_wallclock() and update_persistent_wallclock() allow
for nanosecond precision but their implementation on x86 with
x86_platform.get/set_wallclock() only allows for one second precision.
This means guests may see a wallclock time that is off by up to 1
second.
Make set_wallclock() and get_wallclock() take a struct timespec
parameter (which allows for nanosecond precision) so KVM and Xen
guests may start with a more accurate wallclock time and a Xen dom0
can maintain a more accurate wallclock for guests.
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'arch/x86')
| -rw-r--r-- | arch/x86/include/asm/mc146818rtc.h | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/x86_init.h | 6 | ||||
| -rw-r--r-- | arch/x86/kernel/kvmclock.c | 9 | ||||
| -rw-r--r-- | arch/x86/kernel/rtc.c | 17 | ||||
| -rw-r--r-- | arch/x86/lguest/boot.c | 4 | ||||
| -rw-r--r-- | arch/x86/platform/efi/efi.c | 10 | ||||
| -rw-r--r-- | arch/x86/xen/time.c | 19 | 
7 files changed, 30 insertions, 39 deletions
| diff --git a/arch/x86/include/asm/mc146818rtc.h b/arch/x86/include/asm/mc146818rtc.h index d354fb781c57..a55c7efcc4ed 100644 --- a/arch/x86/include/asm/mc146818rtc.h +++ b/arch/x86/include/asm/mc146818rtc.h @@ -95,8 +95,8 @@ static inline unsigned char current_lock_cmos_reg(void)  unsigned char rtc_cmos_read(unsigned char addr);  void rtc_cmos_write(unsigned char val, unsigned char addr); -extern int mach_set_rtc_mmss(unsigned long nowtime); -extern unsigned long mach_get_cmos_time(void); +extern int mach_set_rtc_mmss(const struct timespec *now); +extern void mach_get_cmos_time(struct timespec *now);  #define RTC_IRQ 8 diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h index d8d99222b36a..828a1565ba57 100644 --- a/arch/x86/include/asm/x86_init.h +++ b/arch/x86/include/asm/x86_init.h @@ -142,6 +142,8 @@ struct x86_cpuinit_ops {  	void (*fixup_cpu_id)(struct cpuinfo_x86 *c, int node);  }; +struct timespec; +  /**   * struct x86_platform_ops - platform specific runtime functions   * @calibrate_tsc:		calibrate TSC @@ -156,8 +158,8 @@ struct x86_cpuinit_ops {   */  struct x86_platform_ops {  	unsigned long (*calibrate_tsc)(void); -	unsigned long (*get_wallclock)(void); -	int (*set_wallclock)(unsigned long nowtime); +	void (*get_wallclock)(struct timespec *ts); +	int (*set_wallclock)(const struct timespec *ts);  	void (*iommu_shutdown)(void);  	bool (*is_untracked_pat_range)(u64 start, u64 end);  	void (*nmi_init)(void); diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index d2c381280e3c..0db81ab511cc 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -48,10 +48,9 @@ static struct pvclock_wall_clock wall_clock;   * have elapsed since the hypervisor wrote the data. So we try to account for   * that with system time   */ -static unsigned long kvm_get_wallclock(void) +static void kvm_get_wallclock(struct timespec *now)  {  	struct pvclock_vcpu_time_info *vcpu_time; -	struct timespec ts;  	int low, high;  	int cpu; @@ -64,14 +63,12 @@ static unsigned long kvm_get_wallclock(void)  	cpu = smp_processor_id();  	vcpu_time = &hv_clock[cpu].pvti; -	pvclock_read_wallclock(&wall_clock, vcpu_time, &ts); +	pvclock_read_wallclock(&wall_clock, vcpu_time, now);  	preempt_enable(); - -	return ts.tv_sec;  } -static int kvm_set_wallclock(unsigned long now) +static int kvm_set_wallclock(const struct timespec *now)  {  	return -1;  } diff --git a/arch/x86/kernel/rtc.c b/arch/x86/kernel/rtc.c index 198eb201ed3b..0aa29394ed6f 100644 --- a/arch/x86/kernel/rtc.c +++ b/arch/x86/kernel/rtc.c @@ -38,8 +38,9 @@ EXPORT_SYMBOL(rtc_lock);   * jump to the next second precisely 500 ms later. Check the Motorola   * MC146818A or Dallas DS12887 data sheet for details.   */ -int mach_set_rtc_mmss(unsigned long nowtime) +int mach_set_rtc_mmss(const struct timespec *now)  { +	unsigned long nowtime = now->tv_sec;  	struct rtc_time tm;  	int retval = 0; @@ -58,7 +59,7 @@ int mach_set_rtc_mmss(unsigned long nowtime)  	return retval;  } -unsigned long mach_get_cmos_time(void) +void mach_get_cmos_time(struct timespec *now)  {  	unsigned int status, year, mon, day, hour, min, sec, century = 0;  	unsigned long flags; @@ -107,7 +108,8 @@ unsigned long mach_get_cmos_time(void)  	} else  		year += CMOS_YEARS_OFFS; -	return mktime(year, mon, day, hour, min, sec); +	now->tv_sec = mktime(year, mon, day, hour, min, sec); +	now->tv_nsec = 0;  }  /* Routines for accessing the CMOS RAM/RTC. */ @@ -135,18 +137,13 @@ EXPORT_SYMBOL(rtc_cmos_write);  int update_persistent_clock(struct timespec now)  { -	return x86_platform.set_wallclock(now.tv_sec); +	return x86_platform.set_wallclock(&now);  }  /* not static: needed by APM */  void read_persistent_clock(struct timespec *ts)  { -	unsigned long retval; - -	retval = x86_platform.get_wallclock(); - -	ts->tv_sec = retval; -	ts->tv_nsec = 0; +	x86_platform.get_wallclock(ts);  } diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 7114c63f047d..8424d5adcfa2 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c @@ -882,9 +882,9 @@ int lguest_setup_irq(unsigned int irq)   * It would be far better for everyone if the Guest had its own clock, but   * until then the Host gives us the time on every interrupt.   */ -static unsigned long lguest_get_wallclock(void) +static void lguest_get_wallclock(struct timespec *now)  { -	return lguest_data.time.tv_sec; +	*now = lguest_data.time;  }  /* diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 55856b2310d3..dd3b82530145 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -352,8 +352,9 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,  	return status;  } -int efi_set_rtc_mmss(unsigned long nowtime) +int efi_set_rtc_mmss(const struct timespec *now)  { +	unsigned long nowtime = now->tv_sec;  	efi_status_t 	status;  	efi_time_t 	eft;  	efi_time_cap_t 	cap; @@ -388,7 +389,7 @@ int efi_set_rtc_mmss(unsigned long nowtime)  	return 0;  } -unsigned long efi_get_time(void) +void efi_get_time(struct timespec *now)  {  	efi_status_t status;  	efi_time_t eft; @@ -398,8 +399,9 @@ unsigned long efi_get_time(void)  	if (status != EFI_SUCCESS)  		pr_err("Oops: efitime: can't read time!\n"); -	return mktime(eft.year, eft.month, eft.day, eft.hour, -		      eft.minute, eft.second); +	now->tv_sec = mktime(eft.year, eft.month, eft.day, eft.hour, +			     eft.minute, eft.second); +	now->tv_nsec = 0;  }  /* diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c index 3d88bfdf9e1c..a1947ac2da82 100644 --- a/arch/x86/xen/time.c +++ b/arch/x86/xen/time.c @@ -191,32 +191,25 @@ static void xen_read_wallclock(struct timespec *ts)  	put_cpu_var(xen_vcpu);  } -static unsigned long xen_get_wallclock(void) +static void xen_get_wallclock(struct timespec *now)  { -	struct timespec ts; - -	xen_read_wallclock(&ts); -	return ts.tv_sec; +	xen_read_wallclock(now);  } -static int xen_set_wallclock(unsigned long now) +static int xen_set_wallclock(const struct timespec *now)  {  	struct xen_platform_op op; -	int rc;  	/* do nothing for domU */  	if (!xen_initial_domain())  		return -1;  	op.cmd = XENPF_settime; -	op.u.settime.secs = now; -	op.u.settime.nsecs = 0; +	op.u.settime.secs = now->tv_sec; +	op.u.settime.nsecs = now->tv_nsec;  	op.u.settime.system_time = xen_clocksource_read(); -	rc = HYPERVISOR_dom0_op(&op); -	WARN(rc != 0, "XENPF_settime failed: now=%ld\n", now); - -	return rc; +	return HYPERVISOR_dom0_op(&op);  }  static struct clocksource xen_clocksource __read_mostly = { |