blob: 3bbd377e1657040fad9526495a1a7ca6c04a5f2a [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>
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070014#include <linux/kernel_stat.h>
Jeremy Fitzhardingef595ec92008-06-12 10:47:56 +020015#include <linux/math64.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090016#include <linux/gfp.h>
Konrad Rzeszutek Wilkc9d76a22013-06-04 17:09:36 -040017#include <linux/slab.h>
David Vrabel55848802013-06-27 11:35:47 +010018#include <linux/pvclock_gtod.h>
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070019
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020020#include <asm/pvclock.h>
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070021#include <asm/xen/hypervisor.h>
22#include <asm/xen/hypercall.h>
23
24#include <xen/events.h>
Stefano Stabellini409771d2010-05-14 12:48:19 +010025#include <xen/features.h>
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070026#include <xen/interface/xen.h>
27#include <xen/interface/vcpu.h>
28
29#include "xen-ops.h"
30
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070031/* Xen may fire a timer up to this many ns early */
32#define TIMER_SLOP 100000
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070033#define NS_PER_TICK (1000000000LL / HZ)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070034
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070035/* snapshots of runstate info */
Tejun Heoc6e22f92009-10-29 22:34:13 +090036static DEFINE_PER_CPU(struct vcpu_runstate_info, xen_runstate_snapshot);
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070037
Laszlo Ersek0b0c0022011-10-18 22:42:59 +020038/* unused ns of stolen time */
Tejun Heoc6e22f92009-10-29 22:34:13 +090039static DEFINE_PER_CPU(u64, xen_residual_stolen);
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070040
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070041static void do_stolen_accounting(void)
42{
43 struct vcpu_runstate_info state;
44 struct vcpu_runstate_info *snap;
Laszlo Ersek0b0c0022011-10-18 22:42:59 +020045 s64 runnable, offline, stolen;
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070046 cputime_t ticks;
47
Stefano Stabellini4ccefbe2015-11-05 15:15:07 +000048 xen_get_runstate_snapshot(&state);
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070049
50 WARN_ON(state.state != RUNSTATE_running);
51
Christoph Lameter89cbc762014-08-17 12:30:40 -050052 snap = this_cpu_ptr(&xen_runstate_snapshot);
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070053
54 /* work out how much time the VCPU has not been runn*ing* */
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070055 runnable = state.time[RUNSTATE_runnable] - snap->time[RUNSTATE_runnable];
56 offline = state.time[RUNSTATE_offline] - snap->time[RUNSTATE_offline];
57
58 *snap = state;
59
60 /* Add the appropriate number of ticks of stolen time,
Martin Schwidefsky79741dd2008-12-31 15:11:38 +010061 including any left-overs from last time. */
Christoph Lameter780f36d2010-12-06 11:16:29 -060062 stolen = runnable + offline + __this_cpu_read(xen_residual_stolen);
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070063
64 if (stolen < 0)
65 stolen = 0;
66
Jeremy Fitzhardingef595ec92008-06-12 10:47:56 +020067 ticks = iter_div_u64_rem(stolen, NS_PER_TICK, &stolen);
Christoph Lameter780f36d2010-12-06 11:16:29 -060068 __this_cpu_write(xen_residual_stolen, stolen);
Martin Schwidefsky79741dd2008-12-31 15:11:38 +010069 account_steal_ticks(ticks);
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -070070}
71
Alok Katariae93ef942008-07-01 11:43:36 -070072/* Get the TSC speed from Xen */
Stefano Stabellini409771d2010-05-14 12:48:19 +010073static unsigned long xen_tsc_khz(void)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070074{
Glauber Costa3807f342008-07-28 11:47:52 -030075 struct pvclock_vcpu_time_info *info =
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070076 &HYPERVISOR_shared_info->vcpu_info[0].time;
77
Glauber Costa3807f342008-07-28 11:47:52 -030078 return pvclock_tsc_khz(info);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070079}
80
Jeremy Fitzhardingeee7686b2008-08-21 13:17:56 -070081cycle_t xen_clocksource_read(void)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070082{
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020083 struct pvclock_vcpu_time_info *src;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070084 cycle_t ret;
85
Jeremy Fitzhardingef1c39622011-08-24 09:54:24 -070086 preempt_disable_notrace();
Boris Ostrovsky3251f202014-10-16 17:02:15 -040087 src = &__this_cpu_read(xen_vcpu)->time;
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +020088 ret = pvclock_clocksource_read(src);
Jeremy Fitzhardingef1c39622011-08-24 09:54:24 -070089 preempt_enable_notrace();
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070090 return ret;
91}
92
Magnus Damm8e196082009-04-21 12:24:00 -070093static cycle_t xen_clocksource_get_cycles(struct clocksource *cs)
94{
95 return xen_clocksource_read();
96}
97
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -070098static void xen_read_wallclock(struct timespec *ts)
99{
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +0200100 struct shared_info *s = HYPERVISOR_shared_info;
101 struct pvclock_wall_clock *wall_clock = &(s->wc);
102 struct pvclock_vcpu_time_info *vcpu_time;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700103
Gerd Hoffmann1c7b67f2008-06-03 16:17:30 +0200104 vcpu_time = &get_cpu_var(xen_vcpu)->time;
105 pvclock_read_wallclock(wall_clock, vcpu_time, ts);
106 put_cpu_var(xen_vcpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700107}
108
David Vrabel35651842013-05-13 18:56:06 +0100109static void xen_get_wallclock(struct timespec *now)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700110{
David Vrabel35651842013-05-13 18:56:06 +0100111 xen_read_wallclock(now);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700112}
113
David Vrabel35651842013-05-13 18:56:06 +0100114static int xen_set_wallclock(const struct timespec *now)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700115{
David Vrabel47433b82013-06-27 11:35:48 +0100116 return -1;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700117}
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700118
David Vrabel47433b82013-06-27 11:35:48 +0100119static int xen_pvclock_gtod_notify(struct notifier_block *nb,
120 unsigned long was_set, void *priv)
David Vrabel55848802013-06-27 11:35:47 +0100121{
David Vrabel47433b82013-06-27 11:35:48 +0100122 /* Protected by the calling core code serialization */
123 static struct timespec next_sync;
David Vrabel55848802013-06-27 11:35:47 +0100124
David Vrabel47433b82013-06-27 11:35:48 +0100125 struct xen_platform_op op;
126 struct timespec now;
David Vrabel55848802013-06-27 11:35:47 +0100127
128 now = __current_kernel_time();
129
David Vrabel47433b82013-06-27 11:35:48 +0100130 /*
131 * We only take the expensive HV call when the clock was set
132 * or when the 11 minutes RTC synchronization time elapsed.
133 */
134 if (!was_set && timespec_compare(&now, &next_sync) < 0)
135 return NOTIFY_OK;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700136
Stefano Stabellinif3d60272015-11-23 10:38:12 +0000137 op.cmd = XENPF_settime32;
138 op.u.settime32.secs = now.tv_sec;
139 op.u.settime32.nsecs = now.tv_nsec;
140 op.u.settime32.system_time = xen_clocksource_read();
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700141
Stefano Stabellinicfafae92015-11-23 10:36:12 +0000142 (void)HYPERVISOR_platform_op(&op);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700143
David Vrabel47433b82013-06-27 11:35:48 +0100144 /*
145 * Move the next drift compensation time 11 minutes
146 * ahead. That's emulating the sync_cmos_clock() update for
147 * the hardware RTC.
148 */
149 next_sync = now;
150 next_sync.tv_sec += 11 * 60;
151
David Vrabel55848802013-06-27 11:35:47 +0100152 return NOTIFY_OK;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700153}
154
David Vrabel55848802013-06-27 11:35:47 +0100155static struct notifier_block xen_pvclock_gtod_notifier = {
156 .notifier_call = xen_pvclock_gtod_notify,
157};
158
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700159static struct clocksource xen_clocksource __read_mostly = {
160 .name = "xen",
161 .rating = 400,
162 .read = xen_clocksource_get_cycles,
163 .mask = ~0,
164 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
165};
166
167/*
168 Xen clockevent implementation
169
170 Xen has two clockevent implementations:
171
172 The old timer_op one works with all released versions of Xen prior
173 to version 3.0.4. This version of the hypervisor provides a
174 single-shot timer with nanosecond resolution. However, sharing the
175 same event channel is a 100Hz tick which is delivered while the
176 vcpu is running. We don't care about or use this tick, but it will
177 cause the core time code to think the timer fired too soon, and
178 will end up resetting it each time. It could be filtered, but
179 doing so has complications when the ktime clocksource is not yet
180 the xen clocksource (ie, at boot time).
181
182 The new vcpu_op-based timer interface allows the tick timer period
183 to be changed or turned off. The tick timer is not useful as a
184 periodic timer because events are only delivered to running vcpus.
185 The one-shot timer can report when a timeout is in the past, so
186 set_next_event is capable of returning -ETIME when appropriate.
187 This interface is used when available.
188*/
189
190
191/*
192 Get a hypervisor absolute time. In theory we could maintain an
193 offset between the kernel's time and the hypervisor's time, and
194 apply that to a kernel's absolute timeout. Unfortunately the
195 hypervisor and kernel times can drift even if the kernel is using
196 the Xen clocksource, because ntp can warp the kernel's clocksource.
197*/
198static s64 get_abs_timeout(unsigned long delta)
199{
200 return xen_clocksource_read() + delta;
201}
202
Viresh Kumar955381d2015-07-16 16:28:48 +0530203static int xen_timerop_shutdown(struct clock_event_device *evt)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700204{
Viresh Kumar955381d2015-07-16 16:28:48 +0530205 /* cancel timeout */
206 HYPERVISOR_set_timer_op(0);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700207
Viresh Kumar955381d2015-07-16 16:28:48 +0530208 return 0;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700209}
210
211static int xen_timerop_set_next_event(unsigned long delta,
212 struct clock_event_device *evt)
213{
Viresh Kumar955381d2015-07-16 16:28:48 +0530214 WARN_ON(!clockevent_state_oneshot(evt));
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700215
216 if (HYPERVISOR_set_timer_op(get_abs_timeout(delta)) < 0)
217 BUG();
218
219 /* We may have missed the deadline, but there's no real way of
220 knowing for sure. If the event was in the past, then we'll
221 get an immediate interrupt. */
222
223 return 0;
224}
225
226static const struct clock_event_device xen_timerop_clockevent = {
Viresh Kumar955381d2015-07-16 16:28:48 +0530227 .name = "xen",
228 .features = CLOCK_EVT_FEAT_ONESHOT,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700229
Viresh Kumar955381d2015-07-16 16:28:48 +0530230 .max_delta_ns = 0xffffffff,
231 .min_delta_ns = TIMER_SLOP,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700232
Viresh Kumar955381d2015-07-16 16:28:48 +0530233 .mult = 1,
234 .shift = 0,
235 .rating = 500,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700236
Viresh Kumar955381d2015-07-16 16:28:48 +0530237 .set_state_shutdown = xen_timerop_shutdown,
238 .set_next_event = xen_timerop_set_next_event,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700239};
240
Viresh Kumar955381d2015-07-16 16:28:48 +0530241static int xen_vcpuop_shutdown(struct clock_event_device *evt)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700242{
243 int cpu = smp_processor_id();
244
Viresh Kumar955381d2015-07-16 16:28:48 +0530245 if (HYPERVISOR_vcpu_op(VCPUOP_stop_singleshot_timer, cpu, NULL) ||
246 HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
247 BUG();
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700248
Viresh Kumar955381d2015-07-16 16:28:48 +0530249 return 0;
250}
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700251
Viresh Kumar955381d2015-07-16 16:28:48 +0530252static int xen_vcpuop_set_oneshot(struct clock_event_device *evt)
253{
254 int cpu = smp_processor_id();
255
256 if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
257 BUG();
258
259 return 0;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700260}
261
262static int xen_vcpuop_set_next_event(unsigned long delta,
263 struct clock_event_device *evt)
264{
265 int cpu = smp_processor_id();
266 struct vcpu_set_singleshot_timer single;
267 int ret;
268
Viresh Kumar955381d2015-07-16 16:28:48 +0530269 WARN_ON(!clockevent_state_oneshot(evt));
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700270
271 single.timeout_abs_ns = get_abs_timeout(delta);
272 single.flags = VCPU_SSHOTTMR_future;
273
274 ret = HYPERVISOR_vcpu_op(VCPUOP_set_singleshot_timer, cpu, &single);
275
276 BUG_ON(ret != 0 && ret != -ETIME);
277
278 return ret;
279}
280
281static const struct clock_event_device xen_vcpuop_clockevent = {
282 .name = "xen",
283 .features = CLOCK_EVT_FEAT_ONESHOT,
284
285 .max_delta_ns = 0xffffffff,
286 .min_delta_ns = TIMER_SLOP,
287
288 .mult = 1,
289 .shift = 0,
290 .rating = 500,
291
Viresh Kumar955381d2015-07-16 16:28:48 +0530292 .set_state_shutdown = xen_vcpuop_shutdown,
293 .set_state_oneshot = xen_vcpuop_set_oneshot,
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700294 .set_next_event = xen_vcpuop_set_next_event,
295};
296
297static const struct clock_event_device *xen_clockevent =
298 &xen_timerop_clockevent;
Konrad Rzeszutek Wilk31620a12013-06-04 17:06:36 -0400299
300struct xen_clock_event_device {
301 struct clock_event_device evt;
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100302 char name[16];
Konrad Rzeszutek Wilk31620a12013-06-04 17:06:36 -0400303};
304static DEFINE_PER_CPU(struct xen_clock_event_device, xen_clock_events) = { .evt.irq = -1 };
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700305
306static irqreturn_t xen_timer_interrupt(int irq, void *dev_id)
307{
Christoph Lameter89cbc762014-08-17 12:30:40 -0500308 struct clock_event_device *evt = this_cpu_ptr(&xen_clock_events.evt);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700309 irqreturn_t ret;
310
311 ret = IRQ_NONE;
312 if (evt->event_handler) {
313 evt->event_handler(evt);
314 ret = IRQ_HANDLED;
315 }
316
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -0700317 do_stolen_accounting();
318
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700319 return ret;
320}
321
Konrad Rzeszutek Wilk09e99da2013-06-04 17:13:29 -0400322void xen_teardown_timer(int cpu)
323{
324 struct clock_event_device *evt;
325 BUG_ON(cpu == 0);
326 evt = &per_cpu(xen_clock_events, cpu).evt;
327
328 if (evt->irq >= 0) {
329 unbind_from_irqhandler(evt->irq, NULL);
330 evt->irq = -1;
Konrad Rzeszutek Wilk09e99da2013-06-04 17:13:29 -0400331 }
332}
333
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700334void xen_setup_timer(int cpu)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700335{
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100336 struct xen_clock_event_device *xevt = &per_cpu(xen_clock_events, cpu);
337 struct clock_event_device *evt = &xevt->evt;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700338 int irq;
339
Konrad Rzeszutek Wilkef35a4e2013-04-08 21:05:15 -0400340 WARN(evt->irq >= 0, "IRQ%d for CPU%d is already allocated\n", evt->irq, cpu);
Konrad Rzeszutek Wilk09e99da2013-06-04 17:13:29 -0400341 if (evt->irq >= 0)
342 xen_teardown_timer(cpu);
Konrad Rzeszutek Wilkef35a4e2013-04-08 21:05:15 -0400343
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700344 printk(KERN_INFO "installing Xen timer for CPU %d\n", cpu);
345
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100346 snprintf(xevt->name, sizeof(xevt->name), "timer%d", cpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700347
348 irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
Michael Opdenacker9d71cee2013-09-07 08:46:49 +0200349 IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER|
David Vrabel8d5999d2014-08-07 17:06:06 +0100350 IRQF_FORCE_RESUME|IRQF_EARLY_RESUME,
Vitaly Kuznetsov7be07722015-01-05 16:27:51 +0100351 xevt->name, NULL);
David Vrabel8785c672013-09-23 12:52:21 +0100352 (void)xen_set_irq_priority(irq, XEN_IRQ_PRIORITY_MAX);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700353
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700354 memcpy(evt, xen_clockevent, sizeof(*evt));
355
Rusty Russell320ab2b2008-12-13 21:20:26 +1030356 evt->cpumask = cpumask_of(cpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700357 evt->irq = irq;
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700358}
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -0700359
Alex Nixond68d82a2008-08-22 11:52:15 +0100360
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700361void xen_setup_cpu_clockevents(void)
362{
Christoph Lameter89cbc762014-08-17 12:30:40 -0500363 clockevents_register_device(this_cpu_ptr(&xen_clock_events.evt));
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700364}
365
Jeremy Fitzhardinged07af1f2008-05-31 01:33:03 +0100366void xen_timer_resume(void)
367{
368 int cpu;
369
Jeremy Fitzhardingee7a3481c2010-10-25 16:53:46 -0700370 pvclock_resume();
371
Jeremy Fitzhardinged07af1f2008-05-31 01:33:03 +0100372 if (xen_clockevent != &xen_vcpuop_clockevent)
373 return;
374
375 for_each_online_cpu(cpu) {
376 if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL))
377 BUG();
378 }
379}
380
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200381static const struct pv_time_ops xen_time_ops __initconst = {
Jeremy Fitzhardingeca50a5f2010-08-04 14:49:16 -0700382 .sched_clock = xen_clocksource_read,
Stefano Stabellini409771d2010-05-14 12:48:19 +0100383};
384
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200385static void __init xen_time_init(void)
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700386{
387 int cpu = smp_processor_id();
John Stultzc4507252010-03-11 14:04:47 -0800388 struct timespec tp;
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700389
Palik, Imre94dd85f2015-01-13 09:14:22 +0100390 /* As Dom0 is never moved, no penalty on using TSC there */
391 if (xen_initial_domain())
392 xen_clocksource.rating = 275;
393
John Stultzb01cc1b2010-04-26 19:03:05 -0700394 clocksource_register_hz(&xen_clocksource, NSEC_PER_SEC);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700395
396 if (HYPERVISOR_vcpu_op(VCPUOP_stop_periodic_timer, cpu, NULL) == 0) {
Jeremy Fitzhardingef91a8b42007-07-17 18:37:05 -0700397 /* Successfully turned off 100Hz tick, so we have the
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700398 vcpuop-based timer interface */
399 printk(KERN_DEBUG "Xen: using vcpuop timer interface\n");
400 xen_clockevent = &xen_vcpuop_clockevent;
401 }
402
403 /* Set initial system time with full resolution */
John Stultzc4507252010-03-11 14:04:47 -0800404 xen_read_wallclock(&tp);
405 do_settimeofday(&tp);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700406
Andi Kleen404ee5b2008-01-30 13:33:20 +0100407 setup_force_cpu_cap(X86_FEATURE_TSC);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700408
Ian Campbellbe012922009-11-21 08:35:55 +0800409 xen_setup_runstate_info(cpu);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700410 xen_setup_timer(cpu);
Jeremy Fitzhardingef87e4ca2007-07-17 18:37:06 -0700411 xen_setup_cpu_clockevents();
David Vrabel55848802013-06-27 11:35:47 +0100412
413 if (xen_initial_domain())
414 pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
Jeremy Fitzhardinge15c84732007-07-17 18:37:05 -0700415}
Stefano Stabellini409771d2010-05-14 12:48:19 +0100416
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200417void __init xen_init_time_ops(void)
Stefano Stabellini409771d2010-05-14 12:48:19 +0100418{
419 pv_time_ops = xen_time_ops;
420
421 x86_init.timers.timer_init = xen_time_init;
422 x86_init.timers.setup_percpu_clockev = x86_init_noop;
423 x86_cpuinit.setup_percpu_clockev = x86_init_noop;
424
425 x86_platform.calibrate_tsc = xen_tsc_khz;
426 x86_platform.get_wallclock = xen_get_wallclock;
David Vrabel47433b82013-06-27 11:35:48 +0100427 /* Dom0 uses the native method to set the hardware RTC. */
428 if (!xen_initial_domain())
429 x86_platform.set_wallclock = xen_set_wallclock;
Stefano Stabellini409771d2010-05-14 12:48:19 +0100430}
431
Stefano Stabellinica65f9f2010-07-29 14:37:48 +0100432#ifdef CONFIG_XEN_PVHVM
Stefano Stabellini409771d2010-05-14 12:48:19 +0100433static void xen_hvm_setup_cpu_clockevents(void)
434{
435 int cpu = smp_processor_id();
436 xen_setup_runstate_info(cpu);
Konrad Rzeszutek Wilk7918c922013-04-16 15:18:00 -0400437 /*
438 * xen_setup_timer(cpu) - snprintf is bad in atomic context. Hence
439 * doing it xen_hvm_cpu_notify (which gets called by smp_init during
440 * early bootup and also during CPU hotplug events).
441 */
Stefano Stabellini409771d2010-05-14 12:48:19 +0100442 xen_setup_cpu_clockevents();
443}
444
Daniel Kiperfb6ce5d2011-05-04 20:18:45 +0200445void __init xen_hvm_init_time_ops(void)
Stefano Stabellini409771d2010-05-14 12:48:19 +0100446{
447 /* vector callback is needed otherwise we cannot receive interrupts
Stefano Stabellini31e7e932010-10-01 17:35:46 +0100448 * on cpu > 0 and at this point we don't know how many cpus are
449 * available */
450 if (!xen_have_vector_callback)
Stefano Stabellini409771d2010-05-14 12:48:19 +0100451 return;
452 if (!xen_feature(XENFEAT_hvm_safe_pvclock)) {
453 printk(KERN_INFO "Xen doesn't support pvclock on HVM,"
454 "disable pv timer\n");
455 return;
456 }
457
458 pv_time_ops = xen_time_ops;
459 x86_init.timers.setup_percpu_clockev = xen_time_init;
460 x86_cpuinit.setup_percpu_clockev = xen_hvm_setup_cpu_clockevents;
461
462 x86_platform.calibrate_tsc = xen_tsc_khz;
463 x86_platform.get_wallclock = xen_get_wallclock;
464 x86_platform.set_wallclock = xen_set_wallclock;
465}
Stefano Stabellinica65f9f2010-07-29 14:37:48 +0100466#endif