ia64/xen-unstable

view xen/include/asm-x86/hvm/vpt.h @ 18702:71c15dfaa12b

Port HPET device model to vpt timer subsystem

The current hpet implementation runs a one-shot xen timer for each
hpet timer whenever the main counter is enabled regardless of whether
or not the individual hpet timers are enabled. When the timer fires,
if it is enabled the interrupt is routed to the guest. If the hpet
timer is periodic, a new one-shot timer is set, for NOW()+period.
There are a number of problems with this the most significant is guest
time drift. Windows does not read the hardware clock to verify time,
it depends on timer interrupts firing at the expected interval. The
existing implementation queues a new one-shot timer each time it fires
and does not allow for a difference between NOW() and the time the
timer was expected to fire, causing drift. Also there is
no allowance for lost ticks. This modification changes HPET to use the
Virtual Platform Timer (VPT) and, for periodic timers, to use periodic
timers. The VPT ensures an interrupt is delivered to the guest for
each period that elapses, plus, its use of xen periodic timers ensures
no drift.

Signed-off-by: Peter Johnston <peter.johnston@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 22 12:04:32 2008 +0100 (2008-10-22)
parents 978ffdd19c0f
children 82bbce59b65d
line source
1 /*
2 * vpt.h: Virtual Platform Timer definitions
3 *
4 * Copyright (c) 2004, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 */
20 #ifndef __ASM_X86_HVM_VPT_H__
21 #define __ASM_X86_HVM_VPT_H__
23 #include <xen/config.h>
24 #include <xen/init.h>
25 #include <xen/lib.h>
26 #include <xen/time.h>
27 #include <xen/errno.h>
28 #include <xen/time.h>
29 #include <xen/timer.h>
30 #include <xen/list.h>
31 #include <asm/hvm/vpic.h>
32 #include <asm/hvm/irq.h>
33 #include <public/hvm/save.h>
35 /*
36 * Abstract layer of periodic time, one short time.
37 */
38 typedef void time_cb(struct vcpu *v, void *opaque);
40 struct periodic_time {
41 struct list_head list;
42 bool_t on_list;
43 bool_t one_shot;
44 bool_t do_not_freeze;
45 bool_t irq_issued;
46 bool_t warned_timeout_too_short;
47 #define PTSRC_isa 1 /* ISA time source */
48 #define PTSRC_lapic 2 /* LAPIC time source */
49 u8 source; /* PTSRC_ */
50 u8 irq;
51 struct vcpu *vcpu; /* vcpu timer interrupt delivers to */
52 u32 pending_intr_nr; /* pending timer interrupts */
53 u64 period; /* frequency in ns */
54 u64 period_cycles; /* frequency in cpu cycles */
55 s_time_t scheduled; /* scheduled timer interrupt */
56 u64 last_plt_gtime; /* platform time when last IRQ is injected */
57 struct timer timer; /* ac_timer */
58 time_cb *cb;
59 void *priv; /* point back to platform time source */
60 };
63 #define PIT_FREQ 1193182
64 #define PIT_BASE 0x40
66 typedef struct PITState {
67 /* Hardware state */
68 struct hvm_hw_pit hw;
69 /* Last time the counters read zero, for calcuating counter reads */
70 int64_t count_load_time[3];
71 /* Channel 0 IRQ handling. */
72 struct periodic_time pt0;
73 spinlock_t lock;
74 } PITState;
76 struct hpet_registers {
77 /* Memory-mapped, software visible registers */
78 uint64_t capability; /* capabilities */
79 uint64_t config; /* configuration */
80 uint64_t isr; /* interrupt status reg */
81 uint64_t mc64; /* main counter */
82 struct { /* timers */
83 uint64_t config; /* configuration/cap */
84 uint64_t cmp; /* comparator */
85 uint64_t fsb; /* FSB route, not supported now */
86 } timers[HPET_TIMER_NUM];
88 /* Hidden register state */
89 uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
90 uint64_t comparator64[HPET_TIMER_NUM]; /* 64 bit running comparator */
91 };
93 typedef struct HPETState {
94 struct hpet_registers hpet;
95 struct vcpu *vcpu;
96 uint64_t stime_freq;
97 uint64_t hpet_to_ns_scale; /* hpet ticks to ns (multiplied by 2^10) */
98 uint64_t hpet_to_ns_limit; /* max hpet ticks convertable to ns */
99 uint64_t mc_offset;
100 struct periodic_time pt[HPET_TIMER_NUM];
101 spinlock_t lock;
102 } HPETState;
104 typedef struct RTCState {
105 /* Hardware state */
106 struct hvm_hw_rtc hw;
107 /* RTC's idea of the current time */
108 struct tm current_tm;
109 /* second update */
110 int64_t next_second_time;
111 struct timer second_timer;
112 struct timer second_timer2;
113 struct periodic_time pt;
114 spinlock_t lock;
115 } RTCState;
117 #define FREQUENCE_PMTIMER 3579545 /* Timer should run at 3.579545 MHz */
118 typedef struct PMTState {
119 struct hvm_hw_pmtimer pm; /* 32bit timer value */
120 struct vcpu *vcpu; /* Keeps sync with this vcpu's guest-time */
121 uint64_t last_gtime; /* Last (guest) time we updated the timer */
122 uint64_t scale; /* Multiplier to get from tsc to timer ticks */
123 struct timer timer; /* To make sure we send SCIs */
124 spinlock_t lock;
125 } PMTState;
127 struct pl_time { /* platform time */
128 struct PITState vpit;
129 struct RTCState vrtc;
130 struct HPETState vhpet;
131 struct PMTState vpmt;
132 /* guest_time = Xen sys time + stime_offset */
133 int64_t stime_offset;
134 /* Ensures monotonicity in appropriate timer modes. */
135 uint64_t last_guest_time;
136 spinlock_t pl_time_lock;
137 };
139 #define ticks_per_sec(v) (v->domain->arch.hvm_domain.tsc_frequency)
141 void pt_save_timer(struct vcpu *v);
142 void pt_restore_timer(struct vcpu *v);
143 void pt_update_irq(struct vcpu *v);
144 void pt_intr_post(struct vcpu *v, struct hvm_intack intack);
145 void pt_reset(struct vcpu *v);
146 void pt_migrate(struct vcpu *v);
148 /* Is given periodic timer active? */
149 #define pt_active(pt) ((pt)->on_list)
151 /*
152 * Create/destroy a periodic (or one-shot!) timer.
153 * The given periodic timer structure must be initialised with zero bytes,
154 * except for the 'source' field which must be initialised with the
155 * correct PTSRC_ value. The initialised timer structure can then be passed
156 * to {create,destroy}_periodic_time() any number of times and in any order.
157 * Note that, for a given periodic timer, invocations of these functions MUST
158 * be serialised.
159 */
160 void create_periodic_time(
161 struct vcpu *v, struct periodic_time *pt, uint64_t delta,
162 uint64_t period, uint8_t irq, time_cb *cb, void *data);
163 void destroy_periodic_time(struct periodic_time *pt);
165 int pv_pit_handler(int port, int data, int write);
166 void pit_reset(struct domain *d);
168 void pit_init(struct vcpu *v, unsigned long cpu_khz);
169 void pit_stop_channel0_irq(PITState * pit);
170 void pit_deinit(struct domain *d);
171 void rtc_init(struct domain *d);
172 void rtc_migrate_timers(struct vcpu *v);
173 void rtc_deinit(struct domain *d);
174 void rtc_reset(struct domain *d);
175 void rtc_update_clock(struct domain *d);
177 void pmtimer_init(struct vcpu *v);
178 void pmtimer_deinit(struct domain *d);
179 void pmtimer_reset(struct domain *d);
181 void hpet_init(struct vcpu *v);
182 void hpet_deinit(struct domain *d);
183 void hpet_reset(struct domain *d);
185 #endif /* __ASM_X86_HVM_VPT_H__ */