ia64/xen-unstable

view xen/arch/x86/hvm/hpet.c @ 18703:6f74549ac4c5

x86, hvm: Allow 100us periodic virtual timers

Adjust vpt and hpet minimum period (for timers) from 900us to 100us to
be able to pass Windows 2008 compatibility tests.

Signed-off-by: Peter Johnston <peter.johnston@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Oct 22 12:08:16 2008 +0100 (2008-10-22)
parents 71c15dfaa12b
children
line source
1 /*
2 * hpet.c: HPET emulation for HVM guests.
3 * Copyright (c) 2006, Intel Corporation.
4 * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
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 #include <asm/hvm/vpt.h>
21 #include <asm/hvm/io.h>
22 #include <asm/hvm/support.h>
23 #include <asm/current.h>
24 #include <xen/sched.h>
25 #include <xen/event.h>
27 #define HPET_BASE_ADDRESS 0xfed00000ULL
28 #define HPET_MMAP_SIZE 1024
29 #define S_TO_NS 1000000000ULL /* 1s = 10^9 ns */
30 #define S_TO_FS 1000000000000000ULL /* 1s = 10^15 fs */
32 /* Frequency_of_Xen_systeme_time / frequency_of_HPET = 16 */
33 #define STIME_PER_HPET_TICK 16
34 #define guest_time_hpet(v) (hvm_get_guest_time(v) / STIME_PER_HPET_TICK)
36 #define HPET_ID 0x000
37 #define HPET_PERIOD 0x004
38 #define HPET_CFG 0x010
39 #define HPET_STATUS 0x020
40 #define HPET_COUNTER 0x0f0
41 #define HPET_T0_CFG 0x100
42 #define HPET_T0_CMP 0x108
43 #define HPET_T0_ROUTE 0x110
44 #define HPET_T1_CFG 0x120
45 #define HPET_T1_CMP 0x128
46 #define HPET_T1_ROUTE 0x130
47 #define HPET_T2_CFG 0x140
48 #define HPET_T2_CMP 0x148
49 #define HPET_T2_ROUTE 0x150
50 #define HPET_T3_CFG 0x160
52 #define HPET_CFG_ENABLE 0x001
53 #define HPET_CFG_LEGACY 0x002
55 #define HPET_TN_INT_TYPE_LEVEL 0x002
56 #define HPET_TN_ENABLE 0x004
57 #define HPET_TN_PERIODIC 0x008
58 #define HPET_TN_PERIODIC_CAP 0x010
59 #define HPET_TN_SIZE_CAP 0x020
60 #define HPET_TN_SETVAL 0x040
61 #define HPET_TN_32BIT 0x100
62 #define HPET_TN_INT_ROUTE_MASK 0x3e00
63 #define HPET_TN_INT_ROUTE_SHIFT 9
64 #define HPET_TN_INT_ROUTE_CAP_SHIFT 32
65 #define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
67 /* can be routed to IOAPIC.redirect_table[23..20] */
68 #define HPET_TN_INT_ROUTE_CAP (0x00f00000ULL \
69 << HPET_TN_INT_ROUTE_CAP_SHIFT)
71 #define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \
72 << HPET_TN_INT_ROUTE_CAP_SHIFT)
74 #define hpet_tick_to_ns(h, tick) \
75 ((s_time_t)((((tick) > (h)->hpet_to_ns_limit) ? \
76 ~0ULL : (tick) * (h)->hpet_to_ns_scale) >> 10))
78 #define timer_config(h, n) (h->hpet.timers[n].config)
79 #define timer_enabled(h, n) (timer_config(h, n) & HPET_TN_ENABLE)
80 #define timer_is_periodic(h, n) (timer_config(h, n) & HPET_TN_PERIODIC)
81 #define timer_is_32bit(h, n) (timer_config(h, n) & HPET_TN_32BIT)
82 #define hpet_enabled(h) (h->hpet.config & HPET_CFG_ENABLE)
83 #define timer_level(h, n) (timer_config(h, n) & HPET_TN_INT_TYPE_LEVEL)
85 #define timer_int_route(h, n) \
86 ((timer_config(h, n) & HPET_TN_INT_ROUTE_MASK) >> HPET_TN_INT_ROUTE_SHIFT)
88 #define timer_int_route_cap(h, n) \
89 ((timer_config(h, n) & HPET_TN_INT_ROUTE_CAP_MASK) \
90 >> HPET_TN_INT_ROUTE_CAP_SHIFT)
92 static inline uint64_t hpet_read_maincounter(HPETState *h)
93 {
94 ASSERT(spin_is_locked(&h->lock));
96 if ( hpet_enabled(h) )
97 return guest_time_hpet(h->vcpu) + h->mc_offset;
98 else
99 return h->hpet.mc64;
100 }
102 static uint64_t hpet_get_comparator(HPETState *h, unsigned int tn)
103 {
104 uint64_t comparator;
105 uint64_t elapsed;
107 comparator = h->hpet.comparator64[tn];
108 if ( timer_is_periodic(h, tn) )
109 {
110 /* update comparator by number of periods elapsed since last update */
111 uint64_t period = h->hpet.period[tn];
112 if (period)
113 {
114 elapsed = hpet_read_maincounter(h) + period - 1 - comparator;
115 comparator += (elapsed / period) * period;
116 h->hpet.comparator64[tn] = comparator;
117 }
118 }
120 /* truncate if timer is in 32 bit mode */
121 if ( timer_is_32bit(h, tn) )
122 comparator = (uint32_t)comparator;
123 h->hpet.timers[tn].cmp = comparator;
124 return comparator;
125 }
126 static inline uint64_t hpet_read64(HPETState *h, unsigned long addr)
127 {
128 addr &= ~7;
130 switch ( addr )
131 {
132 case HPET_ID:
133 return h->hpet.capability;
134 case HPET_CFG:
135 return h->hpet.config;
136 case HPET_STATUS:
137 return h->hpet.isr;
138 case HPET_COUNTER:
139 return hpet_read_maincounter(h);
140 case HPET_T0_CFG:
141 case HPET_T1_CFG:
142 case HPET_T2_CFG:
143 return h->hpet.timers[(addr - HPET_T0_CFG) >> 5].config;
144 case HPET_T0_CMP:
145 case HPET_T1_CMP:
146 case HPET_T2_CMP:
147 return hpet_get_comparator(h, (addr - HPET_T0_CMP) >> 5);
148 case HPET_T0_ROUTE:
149 case HPET_T1_ROUTE:
150 case HPET_T2_ROUTE:
151 return h->hpet.timers[(addr - HPET_T0_ROUTE) >> 5].fsb;
152 }
154 return 0;
155 }
157 static inline int hpet_check_access_length(
158 unsigned long addr, unsigned long len)
159 {
160 if ( (addr & (len - 1)) || (len > 8) )
161 {
162 /*
163 * According to ICH9 specification, unaligned accesses may result
164 * in unexpected behaviour or master abort, but should not crash/hang.
165 * Hence we read all-ones, drop writes, and log a warning.
166 */
167 gdprintk(XENLOG_WARNING, "HPET: access across register boundary: "
168 "%lx %lx\n", addr, len);
169 return -EINVAL;
170 }
172 return 0;
173 }
175 static int hpet_read(
176 struct vcpu *v, unsigned long addr, unsigned long length,
177 unsigned long *pval)
178 {
179 HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
180 unsigned long result;
181 uint64_t val;
183 addr &= HPET_MMAP_SIZE-1;
185 if ( hpet_check_access_length(addr, length) != 0 )
186 {
187 result = ~0ul;
188 goto out;
189 }
191 spin_lock(&h->lock);
193 val = hpet_read64(h, addr);
195 result = val;
196 if ( length != 8 )
197 result = (val >> ((addr & 7) * 8)) & ((1ULL << (length * 8)) - 1);
199 spin_unlock(&h->lock);
201 out:
202 *pval = result;
203 return X86EMUL_OKAY;
204 }
206 static void hpet_stop_timer(HPETState *h, unsigned int tn)
207 {
208 ASSERT(tn < HPET_TIMER_NUM);
209 ASSERT(spin_is_locked(&h->lock));
210 destroy_periodic_time(&h->pt[tn]);
211 /* read the comparator to get it updated so a read while stopped will
212 * return the expected value. */
213 hpet_get_comparator(h, tn);
214 }
216 /* the number of HPET tick that stands for
217 * 1/(2^10) second, namely, 0.9765625 milliseconds */
218 #define HPET_TINY_TIME_SPAN ((h->stime_freq >> 10) / STIME_PER_HPET_TICK)
220 static void hpet_set_timer(HPETState *h, unsigned int tn)
221 {
222 uint64_t tn_cmp, cur_tick, diff;
223 unsigned int irq;
224 unsigned int oneshot;
226 ASSERT(tn < HPET_TIMER_NUM);
227 ASSERT(spin_is_locked(&h->lock));
229 if ( (tn == 0) && (h->hpet.config & HPET_CFG_LEGACY) )
230 {
231 /* HPET specification requires PIT shouldn't generate
232 * interrupts if LegacyReplacementRoute is set for timer0 */
233 PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
234 pit_stop_channel0_irq(pit);
235 }
237 if ( !timer_enabled(h, tn) )
238 return;
240 tn_cmp = hpet_get_comparator(h, tn);
241 cur_tick = hpet_read_maincounter(h);
242 if ( timer_is_32bit(h, tn) )
243 {
244 tn_cmp = (uint32_t)tn_cmp;
245 cur_tick = (uint32_t)cur_tick;
246 }
248 diff = tn_cmp - cur_tick;
250 /*
251 * Detect time values set in the past. This is hard to do for 32-bit
252 * comparators as the timer does not have to be set that far in the future
253 * for the counter difference to wrap a 32-bit signed integer. We fudge
254 * by looking for a 'small' time value in the past.
255 */
256 if ( (int64_t)diff < 0 )
257 diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN))
258 ? (uint32_t)diff : 0;
260 if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) )
261 /* if LegacyReplacementRoute bit is set, HPET specification requires
262 timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
263 timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
264 irq = (tn == 0) ? 0 : 8;
265 else
266 irq = timer_int_route(h, tn);
268 /*
269 * diff is the time from now when the timer should fire, for a periodic
270 * timer we also need the period which may be different because time may
271 * have elapsed between the time the comparator was written and the timer
272 * being enabled (now).
273 */
274 oneshot = !timer_is_periodic(h, tn);
275 create_periodic_time(h->vcpu, &h->pt[tn],
276 hpet_tick_to_ns(h, diff),
277 oneshot ? 0 : hpet_tick_to_ns(h, h->hpet.period[tn]),
278 irq, NULL, NULL);
279 }
281 static inline uint64_t hpet_fixup_reg(
282 uint64_t new, uint64_t old, uint64_t mask)
283 {
284 new &= mask;
285 new |= old & ~mask;
286 return new;
287 }
289 static int hpet_write(
290 struct vcpu *v, unsigned long addr,
291 unsigned long length, unsigned long val)
292 {
293 HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
294 uint64_t old_val, new_val;
295 int tn, i;
297 /* Acculumate a bit mask of timers whos state is changed by this write. */
298 unsigned long start_timers = 0;
299 unsigned long stop_timers = 0;
300 #define set_stop_timer(n) (__set_bit((n), &stop_timers))
301 #define set_start_timer(n) (__set_bit((n), &start_timers))
302 #define set_restart_timer(n) (set_stop_timer(n),set_start_timer(n))
304 addr &= HPET_MMAP_SIZE-1;
306 if ( hpet_check_access_length(addr, length) != 0 )
307 goto out;
309 spin_lock(&h->lock);
311 old_val = hpet_read64(h, addr);
312 new_val = val;
313 if ( length != 8 )
314 new_val = hpet_fixup_reg(
315 new_val << (addr & 7) * 8, old_val,
316 ((1ULL << (length*8)) - 1) << ((addr & 7) * 8));
318 switch ( addr & ~7 )
319 {
320 case HPET_CFG:
321 h->hpet.config = hpet_fixup_reg(new_val, old_val, 0x3);
323 if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) )
324 {
325 /* Enable main counter and interrupt generation. */
326 h->mc_offset = h->hpet.mc64 - guest_time_hpet(h->vcpu);
327 for ( i = 0; i < HPET_TIMER_NUM; i++ )
328 {
329 h->hpet.comparator64[i] =
330 h->hpet.timers[i].config & HPET_TN_32BIT ?
331 (uint32_t)h->hpet.timers[i].cmp :
332 h->hpet.timers[i].cmp;
333 if ( timer_enabled(h, i) )
334 set_start_timer(i);
335 }
336 }
337 else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) )
338 {
339 /* Halt main counter and disable interrupt generation. */
340 h->hpet.mc64 = h->mc_offset + guest_time_hpet(h->vcpu);
341 for ( i = 0; i < HPET_TIMER_NUM; i++ )
342 if ( timer_enabled(h, i) )
343 set_stop_timer(i);
344 }
345 break;
347 case HPET_COUNTER:
348 h->hpet.mc64 = new_val;
349 if ( hpet_enabled(h) )
350 {
351 gdprintk(XENLOG_WARNING,
352 "HPET: writing main counter but it's not halted!\n");
353 for ( i = 0; i < HPET_TIMER_NUM; i++ )
354 if ( timer_enabled(h, i) )
355 set_restart_timer(i);
356 }
357 break;
359 case HPET_T0_CFG:
360 case HPET_T1_CFG:
361 case HPET_T2_CFG:
362 tn = (addr - HPET_T0_CFG) >> 5;
364 h->hpet.timers[tn].config = hpet_fixup_reg(new_val, old_val, 0x3f4e);
366 if ( timer_level(h, tn) )
367 {
368 gdprintk(XENLOG_ERR,
369 "HPET: level triggered interrupt not supported now\n");
370 domain_crash(current->domain);
371 break;
372 }
374 if ( new_val & HPET_TN_32BIT )
375 {
376 h->hpet.timers[tn].cmp = (uint32_t)h->hpet.timers[tn].cmp;
377 h->hpet.period[tn] = (uint32_t)h->hpet.period[tn];
378 }
379 if ( hpet_enabled(h) )
380 {
381 if ( new_val & HPET_TN_ENABLE )
382 {
383 if ( (new_val ^ old_val) & HPET_TN_PERIODIC )
384 /* timer is enabled but switching mode to/from periodic/
385 * one-shot, stop and restart the vpt timer to get it in
386 * the right mode. */
387 set_restart_timer(tn);
388 else if ( (new_val & HPET_TN_32BIT) &&
389 !(old_val & HPET_TN_32BIT) )
390 /* switching from 64 bit to 32 bit mode could cause timer
391 * next fire time, or period, to change. */
392 set_restart_timer(tn);
393 else if ( !(old_val & HPET_TN_ENABLE) )
394 /* transition from timer disabled to timer enabled. */
395 set_start_timer(tn);
396 }
397 else if ( old_val & HPET_TN_ENABLE )
398 /* transition from timer enabled to timer disabled. */
399 set_stop_timer(tn);
400 }
401 break;
403 case HPET_T0_CMP:
404 case HPET_T1_CMP:
405 case HPET_T2_CMP:
406 tn = (addr - HPET_T0_CMP) >> 5;
407 if ( timer_is_32bit(h, tn) )
408 new_val = (uint32_t)new_val;
409 h->hpet.timers[tn].cmp = new_val;
410 if ( h->hpet.timers[tn].config & HPET_TN_SETVAL )
411 /*
412 * When SETVAL is one, software is able to "directly set a periodic
413 * timer's accumulator." That is, set the comparator without
414 * adjusting the period. Much the same as just setting the
415 * comparator on an enabled one-shot timer.
416 *
417 * This configuration bit clears when the comparator is written.
418 */
419 h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;
420 else if ( timer_is_periodic(h, tn) )
421 {
422 /*
423 * Clamp period to reasonable min/max values:
424 * - minimum is 100us, same as timers controlled by vpt.c
425 * - maximum is to prevent overflow in time_after() calculations
426 */
427 if ( hpet_tick_to_ns(h, new_val) < MICROSECS(100) )
428 new_val = (MICROSECS(100) << 10) / h->hpet_to_ns_scale;
429 new_val &= (timer_is_32bit(h, tn) ? ~0u : ~0ull) >> 1;
430 h->hpet.period[tn] = new_val;
431 }
432 h->hpet.comparator64[tn] = new_val;
433 if ( hpet_enabled(h) && timer_enabled(h, tn) )
434 set_restart_timer(tn);
435 break;
437 case HPET_T0_ROUTE:
438 case HPET_T1_ROUTE:
439 case HPET_T2_ROUTE:
440 tn = (addr - HPET_T0_ROUTE) >> 5;
441 h->hpet.timers[tn].fsb = new_val;
442 break;
444 default:
445 /* Ignore writes to unsupported and reserved registers. */
446 break;
447 }
449 /* stop/start timers whos state was changed by this write. */
450 while (stop_timers)
451 {
452 i = find_first_set_bit(stop_timers);
453 __clear_bit(i, &stop_timers);
454 hpet_stop_timer(h, i);
455 }
457 while (start_timers)
458 {
459 i = find_first_set_bit(start_timers);
460 __clear_bit(i, &start_timers);
461 hpet_set_timer(h, i);
462 }
464 #undef set_stop_timer
465 #undef set_start_timer
466 #undef set_restart_timer
468 spin_unlock(&h->lock);
470 out:
471 return X86EMUL_OKAY;
472 }
474 static int hpet_range(struct vcpu *v, unsigned long addr)
475 {
476 return (v->domain->arch.hvm_domain.params[HVM_PARAM_HPET_ENABLED] &&
477 (addr >= HPET_BASE_ADDRESS) &&
478 (addr < (HPET_BASE_ADDRESS + HPET_MMAP_SIZE)));
479 }
481 struct hvm_mmio_handler hpet_mmio_handler = {
482 .check_handler = hpet_range,
483 .read_handler = hpet_read,
484 .write_handler = hpet_write
485 };
488 static int hpet_save(struct domain *d, hvm_domain_context_t *h)
489 {
490 HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet;
491 int rc;
493 spin_lock(&hp->lock);
495 /* Write the proper value into the main counter */
496 hp->hpet.mc64 = hp->mc_offset + guest_time_hpet(hp->vcpu);
498 /* Save the HPET registers */
499 rc = _hvm_init_entry(h, HVM_SAVE_CODE(HPET), 0, HVM_SAVE_LENGTH(HPET));
500 if ( rc == 0 )
501 {
502 struct hvm_hw_hpet *rec = (struct hvm_hw_hpet *)&h->data[h->cur];
503 h->cur += HVM_SAVE_LENGTH(HPET);
504 memset(rec, 0, HVM_SAVE_LENGTH(HPET));
505 #define C(x) rec->x = hp->hpet.x
506 C(capability);
507 C(config);
508 C(isr);
509 C(mc64);
510 C(timers[0].config);
511 C(timers[0].fsb);
512 C(timers[1].config);
513 C(timers[1].fsb);
514 C(timers[2].config);
515 C(timers[2].fsb);
516 C(period[0]);
517 C(period[1]);
518 C(period[2]);
519 #undef C
520 /* save the 64 bit comparator in the 64 bit timer[n].cmp field
521 * regardless of whether or not the timer is in 32 bit mode. */
522 rec->timers[0].cmp = hp->hpet.comparator64[0];
523 rec->timers[1].cmp = hp->hpet.comparator64[1];
524 rec->timers[2].cmp = hp->hpet.comparator64[2];
525 }
527 spin_unlock(&hp->lock);
529 return rc;
530 }
532 static int hpet_load(struct domain *d, hvm_domain_context_t *h)
533 {
534 HPETState *hp = &d->arch.hvm_domain.pl_time.vhpet;
535 struct hvm_hw_hpet *rec;
536 uint64_t cmp;
537 int i;
539 spin_lock(&hp->lock);
541 /* Reload the HPET registers */
542 if ( _hvm_check_entry(h, HVM_SAVE_CODE(HPET), HVM_SAVE_LENGTH(HPET)) )
543 {
544 spin_unlock(&hp->lock);
545 return -EINVAL;
546 }
548 rec = (struct hvm_hw_hpet *)&h->data[h->cur];
549 h->cur += HVM_SAVE_LENGTH(HPET);
551 #define C(x) hp->hpet.x = rec->x
552 C(capability);
553 C(config);
554 C(isr);
555 C(mc64);
556 /* The following define will generate a compiler error if HPET_TIMER_NUM
557 * changes. This indicates an incompatability with previous saved state. */
558 #define HPET_TIMER_NUM 3
559 for ( i = 0; i < HPET_TIMER_NUM; i++ )
560 {
561 C(timers[i].config);
562 C(timers[i].fsb);
563 C(period[i]);
564 /* restore the hidden 64 bit comparator and truncate the timer's
565 * visible comparator field if in 32 bit mode. */
566 cmp = rec->timers[i].cmp;
567 hp->hpet.comparator64[i] = cmp;
568 if ( timer_is_32bit(hp, i) )
569 cmp = (uint32_t)cmp;
570 hp->hpet.timers[i].cmp = cmp;
571 }
572 #undef C
574 /* Recalculate the offset between the main counter and guest time */
575 hp->mc_offset = hp->hpet.mc64 - guest_time_hpet(hp->vcpu);
577 /* restart all timers */
579 if ( hpet_enabled(hp) )
580 for ( i = 0; i < HPET_TIMER_NUM; i++ )
581 if ( timer_enabled(hp, i) )
582 hpet_set_timer(hp, i);
584 spin_unlock(&hp->lock);
586 return 0;
587 }
589 HVM_REGISTER_SAVE_RESTORE(HPET, hpet_save, hpet_load, 1, HVMSR_PER_DOM);
591 void hpet_init(struct vcpu *v)
592 {
593 HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
594 int i;
596 memset(h, 0, sizeof(HPETState));
598 spin_lock_init(&h->lock);
600 h->vcpu = v;
601 h->stime_freq = S_TO_NS;
603 h->hpet_to_ns_scale = ((S_TO_NS * STIME_PER_HPET_TICK) << 10) / h->stime_freq;
604 h->hpet_to_ns_limit = ~0ULL / h->hpet_to_ns_scale;
606 /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
607 h->hpet.capability = 0x8086A201ULL;
609 /* This is the number of femptoseconds per HPET tick. */
610 /* Here we define HPET's frequency to be 1/16 of Xen system time */
611 h->hpet.capability |= ((S_TO_FS*STIME_PER_HPET_TICK/h->stime_freq) << 32);
613 for ( i = 0; i < HPET_TIMER_NUM; i++ )
614 {
615 h->hpet.timers[i].config =
616 HPET_TN_INT_ROUTE_CAP | HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
617 h->hpet.timers[i].cmp = ~0ULL;
618 h->pt[i].source = PTSRC_isa;
619 }
620 }
622 void hpet_deinit(struct domain *d)
623 {
624 int i;
625 HPETState *h = &d->arch.hvm_domain.pl_time.vhpet;
627 spin_lock(&h->lock);
629 if ( hpet_enabled(h) )
630 for ( i = 0; i < HPET_TIMER_NUM; i++ )
631 if ( timer_enabled(h, i) )
632 hpet_stop_timer(h, i);
634 spin_unlock(&h->lock);
635 }
637 void hpet_reset(struct domain *d)
638 {
639 hpet_deinit(d);
640 hpet_init(d->vcpu[0]);
641 }