aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Vrabel <david.vrabel@citrix.com>2013-06-27 06:35:48 -0400
committerThomas Gleixner <tglx@linutronix.de>2013-06-28 17:15:07 -0400
commit47433b8c9d7480a3eebd99df38e857ce85a37cee (patch)
treed89d45a5fa0abc84602320d6e19579be73eaad2d
parent5584880e44e49c587059801faa2a9f7d22619c48 (diff)
x86: xen: Sync the CMOS RTC as well as the Xen wallclock
Adjustments to Xen's persistent clock via update_persistent_clock() don't actually persist, as the Xen wallclock is a software only clock and modifications to it do not modify the underlying CMOS RTC. The x86_platform.set_wallclock hook is there to keep the hardware RTC synchronized. On a guest this is pointless. On Dom0 we can use the native implementaion which actually updates the hardware RTC, but we still need to keep the software emulation of RTC for the guests up to date. The subscription to the pvclock_notifier allows us to emulate this easily. The notifier is called at every tick and when the clock was set. Right now we only use that notifier when the clock was set, but due to the fact that it is called periodically from the timekeeping update code, we can utilize it to emulate the NTP driven drift compensation of update_persistant_clock() for the Xen wall (software) clock. Add a 11 minutes periodic update to the pvclock_gtod notifier callback to achieve that. The static variable 'next' which maintains that 11 minutes update cycle is protected by the core code serialization so there is no need to add a Xen specific serialization mechanism. [ tglx: Massaged changelog and added a few comments ] Signed-off-by: David Vrabel <david.vrabel@citrix.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: John Stultz <john.stultz@linaro.org> Cc: <xen-devel@lists.xen.org> Link: http://lkml.kernel.org/r/1372329348-20841-6-git-send-email-david.vrabel@citrix.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/xen/time.c45
1 files changed, 26 insertions, 19 deletions
diff --git a/arch/x86/xen/time.c b/arch/x86/xen/time.c
index 3364850d23e6..7a5671b4fec6 100644
--- a/arch/x86/xen/time.c
+++ b/arch/x86/xen/time.c
@@ -199,37 +199,42 @@ static void xen_get_wallclock(struct timespec *now)
199 199
200static int xen_set_wallclock(const struct timespec *now) 200static int xen_set_wallclock(const struct timespec *now)
201{ 201{
202 struct xen_platform_op op; 202 return -1;
203
204 /* do nothing for domU */
205 if (!xen_initial_domain())
206 return -1;
207
208 op.cmd = XENPF_settime;
209 op.u.settime.secs = now->tv_sec;
210 op.u.settime.nsecs = now->tv_nsec;
211 op.u.settime.system_time = xen_clocksource_read();
212
213 return HYPERVISOR_dom0_op(&op);
214} 203}
215 204
216static int xen_pvclock_gtod_notify(struct notifier_block *nb, unsigned long was_set, 205static int xen_pvclock_gtod_notify(struct notifier_block *nb,
217 void *priv) 206 unsigned long was_set, void *priv)
218{ 207{
219 struct timespec now; 208 /* Protected by the calling core code serialization */
220 struct xen_platform_op op; 209 static struct timespec next_sync;
221 210
222 if (!was_set) 211 struct xen_platform_op op;
223 return NOTIFY_OK; 212 struct timespec now;
224 213
225 now = __current_kernel_time(); 214 now = __current_kernel_time();
226 215
216 /*
217 * We only take the expensive HV call when the clock was set
218 * or when the 11 minutes RTC synchronization time elapsed.
219 */
220 if (!was_set && timespec_compare(&now, &next_sync) < 0)
221 return NOTIFY_OK;
222
227 op.cmd = XENPF_settime; 223 op.cmd = XENPF_settime;
228 op.u.settime.secs = now.tv_sec; 224 op.u.settime.secs = now.tv_sec;
229 op.u.settime.nsecs = now.tv_nsec; 225 op.u.settime.nsecs = now.tv_nsec;
230 op.u.settime.system_time = xen_clocksource_read(); 226 op.u.settime.system_time = xen_clocksource_read();
231 227
232 (void)HYPERVISOR_dom0_op(&op); 228 (void)HYPERVISOR_dom0_op(&op);
229
230 /*
231 * Move the next drift compensation time 11 minutes
232 * ahead. That's emulating the sync_cmos_clock() update for
233 * the hardware RTC.
234 */
235 next_sync = now;
236 next_sync.tv_sec += 11 * 60;
237
233 return NOTIFY_OK; 238 return NOTIFY_OK;
234} 239}
235 240
@@ -513,7 +518,9 @@ void __init xen_init_time_ops(void)
513 518
514 x86_platform.calibrate_tsc = xen_tsc_khz; 519 x86_platform.calibrate_tsc = xen_tsc_khz;
515 x86_platform.get_wallclock = xen_get_wallclock; 520 x86_platform.get_wallclock = xen_get_wallclock;
516 x86_platform.set_wallclock = xen_set_wallclock; 521 /* Dom0 uses the native method to set the hardware RTC. */
522 if (!xen_initial_domain())
523 x86_platform.set_wallclock = xen_set_wallclock;
517} 524}
518 525
519#ifdef CONFIG_XEN_PVHVM 526#ifdef CONFIG_XEN_PVHVM