aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/hpet.c
diff options
context:
space:
mode:
authorkaf24@localhost.localdomain <kaf24@localhost.localdomain>2006-12-29 14:12:55 +0000
committerkaf24@localhost.localdomain <kaf24@localhost.localdomain>2006-12-29 14:12:55 +0000
commit7467f810fc99ee2a61f7423b55900bfa4452c0b5 (patch)
treedf4c71bf80bc966b2accdb548ae61fd46147cfdb /xen/arch/x86/hvm/hpet.c
parentbcef756eb4389e6c86abfeb99255303c0b9c5bee (diff)
downloadxen-7467f810fc99ee2a61f7423b55900bfa4452c0b5.tar.gz
xen-7467f810fc99ee2a61f7423b55900bfa4452c0b5.tar.bz2
xen-7467f810fc99ee2a61f7423b55900bfa4452c0b5.zip
[HVM] Fix HPET timer to support 8-byte accesses, erroneous updates
to read-only bits, etc. Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/arch/x86/hvm/hpet.c')
-rw-r--r--xen/arch/x86/hvm/hpet.c434
1 files changed, 150 insertions, 284 deletions
diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c
index 536b698f17..68cb5e5544 100644
--- a/xen/arch/x86/hvm/hpet.c
+++ b/xen/arch/x86/hvm/hpet.c
@@ -1,6 +1,7 @@
/*
- * hpet.c: emulating HPET in Xen
+ * hpet.c: HPET emulation for HVM guests.
* Copyright (c) 2006, Intel Corporation.
+ * Copyright (c) 2006, Keir Fraser <keir@xensource.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -42,19 +43,7 @@
#define HPET_T2_CFG 0x140
#define HPET_T2_CMP 0x148
#define HPET_T2_ROUTE 0x150
-#define HPET_T3_CFG 0x158 /* not supported now*/
-
-#define HPET_REV 0x01ULL
-#define HPET_NUMBER 0x200ULL /* 3 timers */
-#define HPET_COUNTER_SIZE_CAP 0x2000ULL
-#define HPET_LEG_RT_CAP 0x8000ULL
-#define HPET_VENDOR_8086 0x80860000ULL
-
-/* 64bit main counter; 3 timers supported now;
- LegacyReplacemen Route supported. */
-#define HPET_CAP_ID_REG \
- (HPET_REV | HPET_NUMBER | HPET_COUNTER_SIZE_CAP | \
- HPET_LEG_RT_CAP | HPET_VENDOR_8086)
+#define HPET_T3_CFG 0x160
#define HPET_CFG_ENABLE 0x001
#define HPET_CFG_LEGACY 0x002
@@ -65,6 +54,7 @@
#define HPET_TN_PERIODIC_CAP 0x010
#define HPET_TN_SETVAL 0x040
#define HPET_TN_32BIT 0x100
+#define HPET_TN_SIZE_CAP 0x200
#define HPET_TN_INT_ROUTE_MASK 0x3e00
#define HPET_TN_INT_ROUTE_SHIFT 9
#define HPET_TN_INT_ROUTE_CAP_SHIFT 32
@@ -77,16 +67,11 @@
#define HPET_TN_INT_ROUTE_CAP_MASK (0xffffffffULL \
<< HPET_TN_INT_ROUTE_CAP_SHIFT)
-#define HPET_TIMER_CMP32_DEFAULT 0xffffffffULL
-#define HPET_TIMER_CMP64_DEFAULT 0xffffffffffffffffULL
-#define HPET_TN_SIZE_CAP (1 << 5)
-
#define hpet_tick_to_ns(h, tick) ((s_time_t)(tick)*S_TO_NS/h->tsc_freq)
#define timer_config(h, n) (h->hpet.timers[n].config)
#define timer_enabled(h, n) (timer_config(h, n) & HPET_TN_ENABLE)
#define timer_is_periodic(h, n) (timer_config(h, n) & HPET_TN_PERIODIC)
#define timer_is_32bit(h, n) (timer_config(h, n) & HPET_TN_32BIT)
-#define timer_period_cap(h, n) (timer_config(h, n) & HPET_TN_PERIODIC_CAP)
#define hpet_enabled(h) (h->hpet.config & HPET_CFG_ENABLE)
#define timer_level(h, n) (timer_config(h, n) & HPET_TN_INT_TYPE_LEVEL)
@@ -97,72 +82,26 @@
((timer_config(h, n) & HPET_TN_INT_ROUTE_CAP_MASK) \
>> HPET_TN_INT_ROUTE_CAP_SHIFT)
-#define hpet_time_after(a, b) ((int32_t)(b) -(int32_t)(a) < 0)
-#define hpet_time_after64(a, b) ((int64_t)(b) -(int64_t)(a) < 0)
+#define hpet_time_after(a, b) ((int32_t)(b) - (int32_t)(a) < 0)
+#define hpet_time_after64(a, b) ((int64_t)(b) - (int64_t)(a) < 0)
-static inline uint32_t hpet_read32(HPETState *h, unsigned long addr)
+static inline uint64_t hpet_read64(HPETState *h, unsigned long addr)
{
- unsigned long p = ((unsigned long)&h->hpet) + addr;
- return *((uint32_t*)p);
-}
-
-static inline void hpet_write32(HPETState *h, unsigned long addr, uint32_t val)
-{
- unsigned long p = ((unsigned long)&h->hpet) + addr;
- *((uint32_t*)p) = val;
+ uint64_t *p = (uint64_t *)(((unsigned long)&h->hpet) + addr);
+ return (addr >= HPET_T3_CFG) ? 0 : *p;
}
static int hpet_check_access_length(unsigned long addr, unsigned long len)
{
- if ( (len != 4) && (len != 8) )
- {
- gdprintk(XENLOG_ERR, "HPET: access with len=%lu\n", len);
- goto fail;
- }
-
- if ( addr & (len-1) )
- {
- gdprintk(XENLOG_ERR, "HPET: access across register boundary\n");
- goto fail;
- }
-
- return 0;
-
- fail:
- domain_crash(current->domain);
- return -EINVAL;
-}
-
-static int hpet_check_access_offset(unsigned long addr)
-{
- if ( addr >= HPET_T3_CFG )
- {
- gdprintk(XENLOG_ERR, "HPET: only 3 timers supported now\n");
- goto fail;
- }
-
- if ( (addr == HPET_T0_ROUTE) || (addr == HPET_T0_ROUTE+4) ||
- (addr == HPET_T1_ROUTE) || (addr == HPET_T1_ROUTE+4) ||
- (addr == HPET_T2_ROUTE) || (addr == HPET_T2_ROUTE+4) )
+ if ( (addr & (len - 1)) || (len > 8) )
{
- gdprintk(XENLOG_ERR, "HPET: FSB interrupt route not supported now\n");
- goto fail;
+ gdprintk(XENLOG_ERR, "HPET: access across register boundary: "
+ "%lx %lx\n", addr, len);
+ domain_crash(current->domain);
+ return -EINVAL;
}
return 0;
-
- fail:
- domain_crash(current->domain);
- return -EINVAL;
-}
-
-static void hpet_level_triggered_interrupt_not_supported(void)
-{
- /* It's hard to support level triggered interrupt in HPET. */
- /* Now we haven't found any OS uses this kind of interrupt of HPET. */
- gdprintk(XENLOG_ERR,
- "HPET: level triggered interrupt not supported now\n");
- domain_crash(current->domain);
}
static uint64_t hpet_update_maincounter(HPETState *h)
@@ -177,104 +116,68 @@ static unsigned long hpet_read(
struct vcpu *v, unsigned long addr, unsigned long length)
{
HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
- uint64_t mc, result;
+ unsigned long result;
+ uint64_t val;
addr &= HPET_MMAP_SIZE-1;
if ( hpet_check_access_length(addr, length) != 0 )
- goto fail;
+ return ~0UL;
- if ( length == 8 )
- {
- /* TODO: no OS is found to use length=8 now.
- * Windows 2000/XP/2003 doesn't use HPET; all of Linux
- * and 32bit/64bit Vista use 4-byte-length access.
- * Besides, section 2.4.7 of HPET spec gives a note saying
- * 64bit read may be inaccurate in some platforms. */
- gdprintk(XENLOG_ERR, "HPET: hpet_read with len=8 not implementated\n");
- domain_crash(v->domain);
- goto fail;
- }
+ val = hpet_read64(h, addr & ~7);
+ if ( (addr & ~7) == HPET_COUNTER )
+ val = hpet_update_maincounter(h);
- switch ( addr )
- {
- case HPET_COUNTER:
- mc = hpet_update_maincounter(h);
- result = mc & 0xffffffffU;
- break;
- case HPET_COUNTER + 4:
- mc = hpet_update_maincounter(h);
- result = (mc >> 32);
- break;
- case HPET_T0_CMP:
- result = hpet_read32(h, addr);
- break;
- case HPET_T0_CMP + 4:
- result = timer_is_32bit(h, 0) ? 0 : hpet_read32(h, addr);
- break;
- default:
- if ( hpet_check_access_offset(addr) != 0 )
- goto fail;
- result = hpet_read32(h, addr);
- break;
- }
+ result = val;
+ if ( length != 8 )
+ result = (val >> ((addr & 7) * 8)) & ((1UL << (length * 8)) - 1);
return result;
-
- fail:
- return ~0UL;
}
static void hpet_stop_timer(HPETState *h, unsigned int tn)
{
- ASSERT( tn < HPET_TIMER_NUM );
+ ASSERT(tn < HPET_TIMER_NUM);
stop_timer(&h->timers[tn]);
}
static void hpet_set_timer(HPETState *h, unsigned int tn)
{
- uint64_t tn_cmp;
- uint32_t cur_tick;
+ uint64_t tn_cmp, cur_tick;
ASSERT(tn < HPET_TIMER_NUM);
if ( !hpet_enabled(h) || !timer_enabled(h, tn) )
return;
- switch ( tn )
+ if ( (tn == 0) && (h->hpet.config & HPET_CFG_LEGACY) )
{
- case 0:
- if ( !(h->hpet.config & HPET_CFG_LEGACY) )
- {
- gdprintk(XENLOG_INFO,
- "HPET: LegacyReplacementRoute not set for timer0\n");
- }
- else
- {
- /* HPET specification requires PIT shouldn't generate
- * interrupts if LegacyReplacementRoute is set for timer0 */
- PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
- pit_stop_channel0_irq(pit);
- }
- if ( timer_is_32bit(h, 0) )
- h->t0_period = hpet_tick_to_ns(h, (uint32_t)h->t0_initial_cnt);
- else
- h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt);
- h->t0_period = hpet_tick_to_ns(h, h->t0_initial_cnt);
- set_timer(&h->timers[0], NOW() + h->t0_period);
- break;
- case 1:
- case 2: /* only support 32bit timer1 & timer 2 now */
- tn_cmp = h->hpet.timers[tn].c64 & 0xffffffffULL;
- cur_tick = hpet_update_maincounter(h);
- if ( tn_cmp > cur_tick )
- set_timer(&h->timers[tn], NOW() +
- hpet_tick_to_ns(h, tn_cmp-cur_tick));
- else /* handle the overflow case */
- set_timer(&h->timers[tn], NOW() +
- hpet_tick_to_ns(h, 0xffffffff-cur_tick+tn_cmp));
- break;
+ /* HPET specification requires PIT shouldn't generate
+ * interrupts if LegacyReplacementRoute is set for timer0 */
+ PITState *pit = &h->vcpu->domain->arch.hvm_domain.pl_time.vpit;
+ pit_stop_channel0_irq(pit);
+ }
+
+ tn_cmp = h->hpet.timers[tn].cmp;
+ cur_tick = hpet_update_maincounter(h);
+ if ( timer_is_32bit(h, tn) )
+ {
+ tn_cmp = (uint32_t)tn_cmp;
+ cur_tick = (uint32_t)cur_tick;
}
+
+ if ( (int64_t)(tn_cmp - cur_tick) > 0 )
+ set_timer(&h->timers[tn], NOW() +
+ hpet_tick_to_ns(h, tn_cmp-cur_tick));
+ else
+ set_timer(&h->timers[tn], NOW());
+}
+
+static uint64_t hpet_fixup_reg(uint64_t new, uint64_t old, uint64_t mask)
+{
+ new &= mask;
+ new |= old & ~mask;
+ return new;
}
static void hpet_write(
@@ -282,7 +185,7 @@ static void hpet_write(
unsigned long length, unsigned long val)
{
HPETState *h = &v->domain->arch.hvm_domain.pl_time.vhpet;
- unsigned long old_val;
+ uint64_t old_val, new_val;
int tn, i;
addr &= HPET_MMAP_SIZE-1;
@@ -290,106 +193,93 @@ static void hpet_write(
if ( hpet_check_access_length(addr, length) != 0 )
return;
- if ( length == 8 )
- {
- gdprintk(XENLOG_ERR, "HPET: hpet_write with len=8 not implemented\n");
- domain_crash(v->domain);
- return;
- }
+ old_val = hpet_read64(h, addr & ~7);
+ if ( (addr & ~7) == HPET_COUNTER )
+ old_val = hpet_update_maincounter(h);
+
+ new_val = val;
+ if ( length != 8 )
+ new_val = hpet_fixup_reg(
+ new_val << (addr & 7) * 8, old_val,
+ ((1ULL << (length*8)) - 1) << ((addr & 7) * 8));
- switch ( addr )
+ switch ( addr & ~7 )
{
- case HPET_ID:
- case HPET_ID + 4:
- gdprintk(XENLOG_WARNING,
- "HPET: Capabilities and ID register is readonly\n");
- break;
- case HPET_CFG:
- old_val = h->hpet.config;
- h->hpet.config = val;
+ case HPET_CFG:
+ h->hpet.config = hpet_fixup_reg(new_val, old_val, 0x3);
- if ( !(old_val & HPET_CFG_ENABLE) && (val & HPET_CFG_ENABLE) )
+ if ( !(old_val & HPET_CFG_ENABLE) && (new_val & HPET_CFG_ENABLE) )
{
- /* enable main counter & interrupt generating */
+ /* Enable main counter and interrupt generation. */
h->mc_offset = h->hpet.mc64 - hvm_get_guest_time(h->vcpu);
for ( i = 0; i < HPET_TIMER_NUM; i++ )
hpet_set_timer(h, i);
}
- else if ( (old_val & HPET_CFG_ENABLE) && !(val & HPET_CFG_ENABLE) )
+ else if ( (old_val & HPET_CFG_ENABLE) && !(new_val & HPET_CFG_ENABLE) )
{
- /* halt main counter & disable interrupt generating */
+ /* Halt main counter and disable interrupt generation. */
h->hpet.mc64 = h->mc_offset + hvm_get_guest_time(h->vcpu);
for ( i = 0; i < HPET_TIMER_NUM; i++ )
hpet_stop_timer(h, i);
}
break;
- case HPET_STATUS:
- hpet_level_triggered_interrupt_not_supported();
- break;
+
case HPET_COUNTER:
- case HPET_COUNTER + 4:
if ( hpet_enabled(h) )
gdprintk(XENLOG_WARNING,
"HPET: writing main counter but it's not halted!\n");
- hpet_write32(h, addr, val);
+ h->hpet.mc64 = new_val;
break;
- default:
- if ( hpet_check_access_offset(addr) != 0 )
- break;
- if ( (addr < HPET_T0_CFG) || (addr >= HPET_T2_ROUTE) )
+ case HPET_T0_CFG:
+ case HPET_T1_CFG:
+ case HPET_T2_CFG:
+ tn = (addr - HPET_T0_CFG) >> 5;
+
+ h->hpet.timers[tn].config = hpet_fixup_reg(new_val, old_val, 0x3f4e);
+
+ if ( timer_level(h, tn) )
{
- gdprintk(XENLOG_WARNING,
- "HPET: writing reserved addr=0x%lx, ignored\n", addr);
+ gdprintk(XENLOG_ERR,
+ "HPET: level triggered interrupt not supported now\n");
+ domain_crash(current->domain);
break;
}
- tn = (addr - HPET_T0_CFG) / 0x20;
- if ( (addr == HPET_T0_CMP + 0x20*tn) ||
- (addr == HPET_T0_CMP + 0x20*tn+4) )
- {
- hpet_write32(h, addr, val);
- if ( addr == HPET_T0_CMP )
- *((uint32_t*)&(h->t0_initial_cnt)) = val;
- else if ( addr == HPET_T0_CMP + 4 )
- *(((uint32_t*)&(h->t0_initial_cnt))+1) = val;
- if( hpet_enabled(h) && timer_enabled(h, tn) )
- hpet_set_timer(h, tn);
- }
- else /* HPET_Tn_CFG or HPET_Tn_CFG+4 */
- {
- if ( addr == (HPET_T0_CFG + 0x20*tn + 4) )
- {
- gdprintk(XENLOG_WARNING,
- "HPET: Timer%d_CFG[63..32] is readonly\n", tn);
- }
- else
- {
- old_val = timer_config(h, tn);
- if( (old_val & HPET_TN_CFG_BITS_READONLY_OR_RESERVED) !=
- (val & HPET_TN_CFG_BITS_READONLY_OR_RESERVED) )
- {
- gdprintk(XENLOG_ERR,
- "HPET: TN_CFG writing incorrect value\n");
- domain_crash(v->domain);
- break;
- }
- hpet_write32(h, addr, val);
-
- if ( timer_level(h, tn) )
- {
- hpet_level_triggered_interrupt_not_supported();
- break;
- }
-
- if ( !(old_val & HPET_TN_ENABLE) &&
- (val & HPET_TN_ENABLE) )
- hpet_set_timer(h, tn);
- else if ( (old_val & HPET_TN_ENABLE) &&
- !(val & HPET_TN_ENABLE) )
- hpet_stop_timer(h, tn);
- }
- }
+ if ( new_val & HPET_TN_32BIT )
+ h->hpet.timers[tn].cmp = (uint32_t)h->hpet.timers[tn].cmp;
+
+ if ( !(old_val & HPET_TN_ENABLE) && (new_val & HPET_TN_ENABLE) )
+ hpet_set_timer(h, tn);
+ else if ( (old_val & HPET_TN_ENABLE) && !(new_val & HPET_TN_ENABLE) )
+ hpet_stop_timer(h, tn);
+ break;
+
+ case HPET_T0_CMP:
+ case HPET_T1_CMP:
+ case HPET_T2_CMP:
+ tn = (addr - HPET_T0_CMP) >> 5;
+ if ( timer_is_32bit(h, tn) )
+ new_val = (uint32_t)new_val;
+ if ( !timer_is_periodic(h, tn) ||
+ (h->hpet.timers[tn].config & HPET_TN_SETVAL) )
+ h->hpet.timers[tn].cmp = new_val;
+ else
+ h->period[tn] = new_val;
+ h->hpet.timers[tn].config &= ~HPET_TN_SETVAL;
+ if ( hpet_enabled(h) && timer_enabled(h, tn) )
+ hpet_set_timer(h, tn);
+ break;
+
+ case HPET_T0_ROUTE:
+ case HPET_T1_ROUTE:
+ case HPET_T2_ROUTE:
+ tn = (addr - HPET_T0_ROUTE) >> 5;
+ h->hpet.timers[tn].hpet_fsb[0] = new_val;
+ break;
+
+ default:
+ /* Ignore writes to unsupported and reserved registers. */
break;
}
}
@@ -402,26 +292,27 @@ static int hpet_range(struct vcpu *v, unsigned long addr)
struct hvm_mmio_handler hpet_mmio_handler = {
.check_handler = hpet_range,
- .read_handler = hpet_read,
+ .read_handler = hpet_read,
.write_handler = hpet_write
};
-static void hpet_set_irq(struct domain *d, int hpet_tn)
-{
- /* if LegacyReplacementRoute bit is set, HPET specification requires
- timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
- timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
- int isa_irq = (hpet_tn == 0) ? 0 : 8;
- hvm_isa_irq_deassert(d, isa_irq);
- hvm_isa_irq_assert(d, isa_irq);
-}
-
static void hpet_route_interrupt(HPETState *h, unsigned int tn)
{
unsigned int tn_int_route = timer_int_route(h, tn);
struct domain *d = h->vcpu->domain;
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
+ if ( (tn <= 1) && (h->hpet.config & HPET_CFG_LEGACY) )
+ {
+ /* if LegacyReplacementRoute bit is set, HPET specification requires
+ timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
+ timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC. */
+ int isa_irq = (tn == 0) ? 0 : 8;
+ hvm_isa_irq_deassert(d, isa_irq);
+ hvm_isa_irq_assert(d, isa_irq);
+ return;
+ }
+
if ( !(timer_int_route_cap(h, tn) & (1U << tn_int_route)) )
{
gdprintk(XENLOG_ERR,
@@ -444,45 +335,24 @@ static void hpet_timer_fn(void *opaque)
if ( !hpet_enabled(h) || !timer_enabled(h, tn) )
return;
-
- if ( timer_level(h, tn) )
- {
- hpet_level_triggered_interrupt_not_supported();
- return;
- }
- switch ( tn )
+ hpet_route_interrupt(h, tn);
+
+ if ( timer_is_periodic(h, tn) && (h->period[tn] != 0) )
{
- case 0:
- case 1:
- if ( h->hpet.config & HPET_CFG_LEGACY )
- hpet_set_irq(h->vcpu->domain, tn);
- else
- hpet_route_interrupt(h, tn);
-
- if ( (tn == 0) && timer_is_periodic(h, tn) )
- {
- uint64_t mc = hpet_update_maincounter(h);
- if ( timer_is_32bit(h, 0) )
- {
- while ( hpet_time_after(mc, h->hpet.timers[0].c32) )
- h->hpet.timers[0].c32 += h->t0_initial_cnt;
- }
- else
- {
- while ( hpet_time_after64(mc, h->hpet.timers[0].c64) )
- h->hpet.timers[0].c64 += h->t0_initial_cnt;
- }
- set_timer(&h->timers[tn], NOW() + h->t0_period);
- }
- break;
- case 2:
- hpet_route_interrupt(h, tn);
- break;
- default:
- gdprintk(XENLOG_WARNING,
- "HPET: timer%u is not supported now\n", tn);
- break;
+ uint64_t mc = hpet_update_maincounter(h);
+ if ( timer_is_32bit(h, tn) )
+ {
+ while ( hpet_time_after(mc, h->hpet.timers[tn].cmp) )
+ h->hpet.timers[tn].cmp = (uint32_t)(
+ h->hpet.timers[tn].cmp + h->period[tn]);
+ }
+ else
+ {
+ while ( hpet_time_after64(mc, h->hpet.timers[tn].cmp) )
+ h->hpet.timers[tn].cmp += h->period[tn];
+ }
+ set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, h->period[tn]));
}
vcpu_kick(h->vcpu);
@@ -506,23 +376,19 @@ void hpet_init(struct vcpu *v)
h->vcpu = v;
h->tsc_freq = ticks_per_sec(v);
- h->hpet.capability = HPET_CAP_ID_REG;
+
+ /* 64-bit main counter; 3 timers supported; LegacyReplacementRoute. */
+ h->hpet.capability = 0x8086A201ULL;
/* This is the number of femptoseconds per HPET tick. */
- /* Here we define HPET's frequency as tsc's. */
+ /* Here we define HPET's frequency to be the same as the TSC's. */
h->hpet.capability |= ((S_TO_FS/h->tsc_freq) << 32);
- h->hpet.timers[0].config = HPET_TN_INT_ROUTE_CAP |
- HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
- h->hpet.timers[0].c64 = HPET_TIMER_CMP64_DEFAULT;
-
- h->hpet.timers[1].config = HPET_TN_INT_ROUTE_CAP;
- h->hpet.timers[1].c32 = HPET_TIMER_CMP32_DEFAULT;
- h->hpet.timers[2].config = HPET_TN_INT_ROUTE_CAP;
- h->hpet.timers[2].c32 = HPET_TIMER_CMP32_DEFAULT;
-
for ( i = 0; i < HPET_TIMER_NUM; i++ )
{
+ h->hpet.timers[i].config =
+ HPET_TN_INT_ROUTE_CAP | HPET_TN_SIZE_CAP | HPET_TN_PERIODIC_CAP;
+ h->hpet.timers[i].cmp = ~0ULL;
h->timer_fn_info[i].hs = h;
h->timer_fn_info[i].tn = i;
init_timer(&h->timers[i], hpet_timer_fn, &h->timer_fn_info[i],