blob: c31006f0f37f053c537cabb6ac073892d995c6cf [file] [log] [blame]
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -07001/*
2 * Xen time implementation.
3 *
4 * This is implemented in terms of a clocksource driver which uses
5 * the hypervisor clock as a nanosecond timebase, and a clockevent
6 * driver which uses the hypervisor's timer mechanism.
7 *
8 * Jeremy Fitzhardinge <jeremy@xensource.com>, XenSource Inc, 2007
9 */
10#include <linux/kernel.h>
11#include <linux/interrupt.h>
12#include <linux/clocksource.h>
13#include <linux/clockchips.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090014#include <linux/gfp.h>
Konrad Rzeszutek Wilkc9d76a22013-06-04 17:09:36 -040015#include <linux/slab.h>
David Vrabel55848802013-06-27 11:35:47 +010016#include <linux/pvclock_gtod.h>
Stefano Stabellini76096862015-11-23 10:42:12 +000017#include <linux/timekeeper_internal.h>
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070018
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020019#include <asm/pvclock.h>
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070020#include <asm/xen/hypervisor.h>
21#include <asm/xen/hypercall.h>
22
23#include <xen/events.h>
Stefano Stabellini409771d2010-05-14 12:48:19 +010024#include <xen/features.h>
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070025#include <xen/interface/xen.h>
26#include <xen/interface/vcpu.h>
27
28#include "xen-ops.h"
29
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070030/* Xen may fire a timer up to this many ns early */
31#define TIMER_SLOP 100000
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070032
Alok Katariae93ef942008-07-01 11:43:36 -070033/* Get the TSC speed from Xen */
Stefano Stabellini409771d2010-05-14 12:48:19 +010034static unsigned long xen_tsc_khz(void)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070035{
Glauber Costa3807f342008-07-28 11:47:52 -030036 struct pvclock_vcpu_time_info *info =
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070037 &HYPERVISOR_shared_info->vcpu_info[0].time;
38
Glauber Costa3807f342008-07-28 11:47:52 -030039 return pvclock_tsc_khz(info);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070040}
41
Jeremy Fitzhardingeee7686b2008-08-21 13:17:56 -070042cycle_t xen_clocksource_read(void)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070043{
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020044 struct pvclock_vcpu_time_info *src;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070045 cycle_t ret;
46
Jeremy Fitzhardingef1c39622011-08-24 09:54:24 -070047 preempt_disable_notrace();
Boris Ostrovsky3251f202014-10-16 17:02:15 -040048 src = &__this_cpu_read(xen_vcpu)->time;
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020049 ret = pvclock_clocksource_read(src);
Jeremy Fitzhardingef1c39622011-08-24 09:54:24 -070050 preempt_enable_notrace();
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070051 return ret;
52}
53
Magnus Damm8e196082009-04-21 12:24:00 -070054static cycle_t xen_clocksource_get_cycles(struct clocksource *cs)
55{
56 return xen_clocksource_read();
57}
58
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070059static void xen_read_wallclock(struct timespec *ts)
60{
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020061 struct shared_info *s = HYPERVISOR_shared_info;
62 struct pvclock_wall_clock *wall_clock = &(s->wc);
63 struct pvclock_vcpu_time_info *vcpu_time;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070064
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020065 vcpu_time = &get_cpu_var(xen_vcpu)->time;
66 pvclock_read_wallclock(wall_clock, vcpu_time, ts);
67 put_cpu_var(xen_vcpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070068}
69
David Vrabel35651842013-05-13 18:56:06 +010070static void xen_get_wallclock(struct timespec *now)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070071{
David Vrabel35651842013-05-13 18:56:06 +010072 xen_read_wallclock(now);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070073}
74
David Vrabel35651842013-05-13 18:56:06 +010075static int xen_set_wallclock(const struct timespec *now)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070076{
David Vrabel47433b82013-06-27 11:35:48 +010077 return -1;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070078}
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070079
David Vrabel47433b82013-06-27 11:35:48 +010080static int xen_pvclock_gtod_notify(struct notifier_block *nb,
81 unsigned long was_set, void *priv)
David Vrabel55848802013-06-27 11:35:47 +010082{
David Vrabel47433b82013-06-27 11:35:48 +010083 /* Protected by the calling core code serialization */
Stefano Stabellini187b26a2015-11-24 14:53:02 +000084 static struct timespec64 next_sync;
David Vrabel55848802013-06-27 11:35:47 +010085
David Vrabel47433b82013-06-27 11:35:48 +010086 struct xen_platform_op op;
Stefano Stabellini76096862015-11-23 10:42:12 +000087 struct timespec64 now;
88 struct timekeeper *tk = priv;
89 static bool settime64_supported = true;
90 int ret;
David Vrabel55848802013-06-27 11:35:47 +010091
Stefano Stabellini76096862015-11-23 10:42:12 +000092 now.tv_sec = tk->xtime_sec;
93 now.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
David Vrabel55848802013-06-27 11:35:47 +010094
David Vrabel47433b82013-06-27 11:35:48 +010095 /*
96 * We only take the expensive HV call when the clock was set
97 * or when the 11 minutes RTC synchronization time elapsed.
98 */
Stefano Stabellini187b26a2015-11-24 14:53:02 +000099 if (!was_set && timespec64_compare(&now, &next_sync) < 0)
David Vrabel47433b82013-06-27 11:35:48 +0100100 return NOTIFY_OK;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700101
Stefano Stabellini76096862015-11-23 10:42:12 +0000102again:
103 if (settime64_supported) {
104 op.cmd = XENPF_settime64;
105 op.u.settime64.mbz = 0;
106 op.u.settime64.secs = now.tv_sec;
107 op.u.settime64.nsecs = now.tv_nsec;
108 op.u.settime64.system_time = xen_clocksource_read();
109 } else {
110 op.cmd = XENPF_settime32;
111 op.u.settime32.secs = now.tv_sec;
112 op.u.settime32.nsecs = now.tv_nsec;
113 op.u.settime32.system_time = xen_clocksource_read();
114 }
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700115
Stefano Stabellini76096862015-11-23 10:42:12 +0000116 ret = HYPERVISOR_platform_op(&op);
117
118 if (ret == -ENOSYS && settime64_supported) {
119 settime64_supported = false;
120 goto again;
121 }
122 if (ret < 0)
123 return NOTIFY_BAD;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700124
David Vrabel47433b82013-06-27 11:35:48 +0100125 /*
126 * Move the next drift compensation time 11 minutes
127 * ahead. That's emulating the sync_cmos_clock() update for
128 * the hardware RTC.
129 */
130 next_sync = now;
131 next_sync.tv_sec += 11 * 60;
132
David Vrabel55848802013-06-27 11:35:47 +0100133 return NOTIFY_OK;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700134}
135
David Vrabel55848802013-06-27 11:35:47 +0100136static struct notifier_block xen_pvclock_gtod_notifier = {
137 .notifier_call = xen_pvclock_gtod_notify,
138};
139
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700140static struct clocksource xen_clocksource __read_mostly = {
141 .name = "xen",
142 .rating = 400,
143 .read = xen_clocksource_get_cycles,
144 .mask = ~0,
145 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
146};
147
148/*
149 Xen clockevent implementation
150
151 Xen has two clockevent implementations:
152
153 The old timer_op one works with all released versions of Xen prior
154 to version 3.0.4. This version of the hypervisor provides a
155 single-shot timer with nanosecond resolution. However, sharing the
156 same event channel is a 100Hz tick which is delivered while the
157 vcpu is running. We don't care about or use this tick, but it will
158 cause the core time code to think the timer fired too soon, and
159 will end up resetting it each time. It could be filtered, but
160 doing so has complications when the ktime clocksource is not yet
161 the xen clocksource (ie, at boot time).
162
163 The new vcpu_op-based timer interface allows the tick timer period
164 to be changed or turned off. The tick timer is not useful as a
165 periodic timer because events are only delivered to running vcpus.
166 The one-shot timer can report when a timeout is in the past, so
167 set_next_event is capable of returning -ETIME when appropriate.
168 This interface is used when available.
169*/
170
171
172/*
173 Get a hypervisor absolute time. In theory we could maintain an
174 offset between the kernel's time and the hypervisor's time, and
175 apply that to a kernel's absolute timeout. Unfortunately the
176 hypervisor and kernel times can drift even if the kernel is using
177 the Xen clocksource, because ntp can warp the kernel's clocksource.
178*/
179static s64 get_abs_timeout(unsigned long delta)
180{
181 return xen_clocksource_read() + delta;
182}
183
Viresh Kumar955381d2015-07-16 16:28:48 +0530184static int xen_timerop_shutdown(struct clock_event_device *evt)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700185{
Viresh Kumar955381d2015-07-16 16:28:48 +0530186 /* cancel timeout */
187 HYPERVISOR_set_timer_op(0);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700188
Viresh Kumar955381d2015-07-16 16:28:48 +0530189 return 0;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700190}
191
192static int xen_timerop_set_next_event(unsigned long delta,
193 struct clock_event_device *evt)
194{
Viresh Kumar955381d2015-07-16 16:28:48 +0530195 WARN_ON(!clockevent_state_oneshot(evt));
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700196
197 if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
198 BUG();
199
200 /* We may have missed the deadline, but there's no real way of
201 knowing for sure. If the event was in the past, then we'll
202 get an immediate interrupt. */
203
204 return 0;
205}
206
207static const struct clock_event_device xen_timerop_clockevent = {
Viresh Kumar955381d2015-07-16 16:28:48 +0530208 .name = "xen",
209 .features = CLOCK_EVT_FEAT_ONESHOT,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700210
Viresh Kumar955381d2015-07-16 16:28:48 +0530211 .max_delta_ns = 0xffffffff,
212 .min_delta_ns = TIMER_SLOP,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700213
Viresh Kumar955381d2015-07-16 16:28:48 +0530214 .mult = 1,
215 .shift = 0,
216 .rating = 500,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700217
Viresh Kumar955381d2015-07-16 16:28:48 +0530218 .set_state_shutdown = xen_timerop_shutdown,
219 .set_next_event = xen_timerop_set_next_event,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700220};
221
Viresh Kumar955381d2015-07-16 16:28:48 +0530222static int xen_vcpuop_shutdown(struct clock_event_device *evt)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700223{
224 int cpu = smp_processor_id();
225
Viresh Kumar955381d2015-07-16 16:28:48 +0530226 if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
227 HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
228 BUG();
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700229
Viresh Kumar955381d2015-07-16 16:28:48 +0530230 return 0;
231}
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700232
Viresh Kumar955381d2015-07-16 16:28:48 +0530233static int xen_vcpuop_set_oneshot(struct clock_event_device *evt)
234{
235 int cpu = smp_processor_id();
236
237 if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
238 BUG();
239
240 return 0;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700241}
242
243static int xen_vcpuop_set_next_event(unsigned long delta,
244 struct clock_event_device *evt)
245{
246 int cpu = smp_processor_id();
247 struct vcpu_set_singleshot_timer single;
248 int ret;
249
Viresh Kumar955381d2015-07-16 16:28:48 +0530250 WARN_ON(!clockevent_state_oneshot(evt));
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700251
252 single.timeout_abs_ns = get_abs_timeout(delta);
Stefano Stabellinic06b6d72016-04-15 18:23:00 -0700253 /* Get an event anyway, even if the timeout is already expired */
254 single.flags = 0;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700255
256 ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
Stefano Stabellinic06b6d72016-04-15 18:23:00 -0700257 BUG_ON(ret != 0);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700258
259 return ret;
260}
261
262static const struct clock_event_device xen_vcpuop_clockevent = {
263 .name = "xen",
264 .features = CLOCK_EVT_FEAT_ONESHOT,
265
266 .max_delta_ns = 0xffffffff,
267 .min_delta_ns = TIMER_SLOP,
268
269 .mult = 1,
270 .shift = 0,
271 .rating = 500,
272
Viresh Kumar955381d2015-07-16 16:28:48 +0530273 .set_state_shutdown = xen_vcpuop_shutdown,
274 .set_state_oneshot = xen_vcpuop_set_oneshot,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700275 .set_next_event = xen_vcpuop_set_next_event,
276};
277
278static const struct clock_event_device *xen_clockevent =
279 &xen_timerop_clockevent;
Konrad Rzeszutek Wilk31620a12013-06-04 17:06:36 -0400280
281struct xen_clock_event_device {
282 struct clock_event_device evt;
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100283 char name[16];
Konrad Rzeszutek Wilk31620a12013-06-04 17:06:36 -0400284};
285static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt.irq = -1 };
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700286
287static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
288{
Christoph Lameter89cbc762014-08-17 12:30:40 -0500289 struct clock_event_device *evt = this_cpu_ptr(&xen_clock_events.evt);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700290 irqreturn_t ret;
291
292 ret = IRQ_NONE;
293 if (evt->event_handler) {
294 evt->event_handler(evt);
295 ret = IRQ_HANDLED;
296 }
297
298 return ret;
299}
300
Konrad Rzeszutek Wilk09e99da2013-06-04 17:13:29 -0400301void xen_teardown_timer(int cpu)
302{
303 struct clock_event_device *evt;
304 BUG_ON(cpu == 0);
305 evt = &per_cpu(xen_clock_events, cpu).evt;
306
307 if (evt->irq >= 0) {
308 unbind_from_irqhandler(evt->irq, NULL);
309 evt->irq = -1;
Konrad Rzeszutek Wilk09e99da2013-06-04 17:13:29 -0400310 }
311}
312
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700313void xen_setup_timer(int cpu)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700314{
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100315 struct xen_clock_event_device *xevt = &per_cpu(xen_clock_events, cpu);
316 struct clock_event_device *evt = &xevt->evt;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700317 int irq;
318
Konrad Rzeszutek Wilkef35a4e2013-04-08 21:05:15 -0400319 WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
Konrad Rzeszutek Wilk09e99da2013-06-04 17:13:29 -0400320 if (evt->irq >= 0)
321 xen_teardown_timer(cpu);
Konrad Rzeszutek Wilkef35a4e2013-04-08 21:05:15 -0400322
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700323 printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
324
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100325 snprintf(xevt->name, sizeof(xevt->name), "timer%d", cpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700326
327 irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
Michael Opdenacker9d71cee2013-09-07 08:46:49 +0200328 IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER|
David Vrabel8d5999d2014-08-07 17:06:06 +0100329 IRQF_FORCE_RESUME|IRQF_EARLY_RESUME,
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100330 xevt->name, NULL);
David Vrabel8785c672013-09-23 12:52:21 +0100331 (void)xen_set_irq_priority(irq, XEN_IRQ_PRIORITY_MAX);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700332
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700333 memcpy(evt, xen_clockevent, sizeof(*evt));
334
Rusty Russell320ab2b2008-12-13 21:20:26 +1030335 evt->cpumask = cpumask_of(cpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700336 evt->irq = irq;
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700337}
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -0700338
Alex Nixond68d82a2008-08-22 11:52:15 +0100339
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700340void xen_setup_cpu_clockevents(void)
341{
Christoph Lameter89cbc762014-08-17 12:30:40 -0500342 clockevents_register_device(this_cpu_ptr(&xen_clock_events.evt));
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700343}
344
Jeremy Fitzhardinged07af1f2008-05-31 01:33:03 +0100345void xen_timer_resume(void)
346{
347 int cpu;
348
Jeremy Fitzhardingee7a3481c2010-10-25 16:53:46 -0700349 pvclock_resume();
350
Jeremy Fitzhardinged07af1f2008-05-31 01:33:03 +0100351 if (xen_clockevent != &xen_vcpuop_clockevent)
352 return;
353
354 for_each_online_cpu(cpu) {
355 if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
356 BUG();
357 }
358}
359
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200360static const struct pv_time_ops xen_time_ops __initconst = {
Jeremy Fitzhardingeca50a5f2010-08-04 14:49:16 -0700361 .sched_clock = xen_clocksource_read,
Stefano Stabellini409771d2010-05-14 12:48:19 +0100362};
363
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200364static void __init xen_time_init(void)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700365{
366 int cpu = smp_processor_id();
John Stultzc4507252010-03-11 14:04:47 -0800367 struct timespec tp;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700368
Palik, Imre94dd85f2015-01-13 09:14:22 +0100369 /* As Dom0 is never moved, no penalty on using TSC there */
370 if (xen_initial_domain())
371 xen_clocksource.rating = 275;
372
John Stultzb01cc1b2010-04-26 19:03:05 -0700373 clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700374
375 if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -0700376 /* Successfully turned off 100Hz tick, so we have the
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700377 vcpuop-based timer interface */
378 printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
379 xen_clockevent = &xen_vcpuop_clockevent;
380 }
381
382 /* Set initial system time with full resolution */
John Stultzc4507252010-03-11 14:04:47 -0800383 xen_read_wallclock(&tp);
384 do_settimeofday(&tp);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700385
Andi Kleen404ee5b2008-01-30 13:33:20 +0100386 setup_force_cpu_cap(X86_FEATURE_TSC);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700387
Ian Campbellbe012922009-11-21 08:35:55 +0800388 xen_setup_runstate_info(cpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700389 xen_setup_timer(cpu);
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700390 xen_setup_cpu_clockevents();
David Vrabel55848802013-06-27 11:35:47 +0100391
Juergen Grossecb23dc2016-05-20 09:26:48 +0200392 xen_time_setup_guest();
393
David Vrabel55848802013-06-27 11:35:47 +0100394 if (xen_initial_domain())
395 pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700396}
Stefano Stabellini409771d2010-05-14 12:48:19 +0100397
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200398void __init xen_init_time_ops(void)
Stefano Stabellini409771d2010-05-14 12:48:19 +0100399{
400 pv_time_ops = xen_time_ops;
401
402 x86_init.timers.timer_init = xen_time_init;
403 x86_init.timers.setup_percpu_clockev = x86_init_noop;
404 x86_cpuinit.setup_percpu_clockev = x86_init_noop;
405
406 x86_platform.calibrate_tsc = xen_tsc_khz;
407 x86_platform.get_wallclock = xen_get_wallclock;
David Vrabel47433b82013-06-27 11:35:48 +0100408 /* Dom0 uses the native method to set the hardware RTC. */
409 if (!xen_initial_domain())
410 x86_platform.set_wallclock = xen_set_wallclock;
Stefano Stabellini409771d2010-05-14 12:48:19 +0100411}
412
Stefano Stabellinica65f9f2010-07-29 14:37:48 +0100413#ifdef CONFIG_XEN_PVHVM
Stefano Stabellini409771d2010-05-14 12:48:19 +0100414static void xen_hvm_setup_cpu_clockevents(void)
415{
416 int cpu = smp_processor_id();
417 xen_setup_runstate_info(cpu);
Konrad Rzeszutek Wilk7918c922013-04-16 15:18:00 -0400418 /*
419 * xen_setup_timer(cpu) - snprintf is bad in atomic context. Hence
420 * doing it xen_hvm_cpu_notify (which gets called by smp_init during
421 * early bootup and also during CPU hotplug events).
422 */
Stefano Stabellini409771d2010-05-14 12:48:19 +0100423 xen_setup_cpu_clockevents();
424}
425
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200426void __init xen_hvm_init_time_ops(void)
Stefano Stabellini409771d2010-05-14 12:48:19 +0100427{
428 /* vector callback is needed otherwise we cannot receive interrupts
Stefano Stabellini31e7e932010-10-01 17:35:46 +0100429 * on cpu > 0 and at this point we don't know how many cpus are
430 * available */
431 if (!xen_have_vector_callback)
Stefano Stabellini409771d2010-05-14 12:48:19 +0100432 return;
433 if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
434 printk(KERN_INFO "Xen doesn't support pvclock on HVM,"
435 "disable pv timer\n");
436 return;
437 }
438
439 pv_time_ops = xen_time_ops;
440 x86_init.timers.setup_percpu_clockev = xen_time_init;
441 x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents;
442
443 x86_platform.calibrate_tsc = xen_tsc_khz;
444 x86_platform.get_wallclock = xen_get_wallclock;
445 x86_platform.set_wallclock = xen_set_wallclock;
446}
Stefano Stabellinica65f9f2010-07-29 14:37:48 +0100447#endif