hpet_get_comparator(h, tn, guest_time);
}
+static void hpet_timer_fired(struct vcpu *v, void *data)
+{
+ unsigned int tn = (unsigned long)data;
+ HPETState *h = vcpu_vhpet(v);
+
+ write_lock(&h->lock);
+ if ( __test_and_set_bit(tn, &h->hpet.isr) )
+ ASSERT_UNREACHABLE();
+ write_unlock(&h->lock);
+}
+
/* the number of HPET tick that stands for
* 1/(2^10) second, namely, 0.9765625 milliseconds */
#define HPET_TINY_TIME_SPAN ((h->stime_freq >> 10) / STIME_PER_HPET_TICK)
pit_stop_channel0_irq(&vhpet_domain(h)->arch.vpit);
}
- if ( !timer_enabled(h, tn) )
+ if ( !timer_enabled(h, tn) ||
+ (timer_level(h, tn) && test_bit(tn, &h->hpet.isr)) )
return;
if ( !timer_int_route_valid(h, tn) )
* timer we also need the period which may be different because time may
* have elapsed between the time the comparator was written and the timer
* being enabled (now).
+ *
+ * NB: set periodic timers as oneshot if interrupt type is set to level
+ * because the user must ack the interrupt (by writing 1 to the interrupt
+ * status register) before another interrupt can be delivered.
*/
- oneshot = !timer_is_periodic(h, tn);
+ oneshot = !timer_is_periodic(h, tn) || timer_level(h, tn);
TRACE_2_LONG_4D(TRC_HVM_EMUL_HPET_START_TIMER, tn, irq,
TRC_PAR_LONG(hpet_tick_to_ns(h, diff)),
TRC_PAR_LONG(oneshot ? 0LL :
create_periodic_time(vhpet_vcpu(h), &h->pt[tn],
hpet_tick_to_ns(h, diff),
oneshot ? 0 : hpet_tick_to_ns(h, h->hpet.period[tn]),
- irq, NULL, NULL, false);
+ irq, timer_level(h, tn) ? hpet_timer_fired : NULL,
+ (void *)(unsigned long)tn, timer_level(h, tn));
}
static inline uint64_t hpet_fixup_reg(
HPETState *h = vcpu_vhpet(v);
uint64_t old_val, new_val;
uint64_t guest_time;
- int tn, i;
+ unsigned int tn, i;
/* Acculumate a bit mask of timers whos state is changed by this write. */
unsigned long start_timers = 0;
}
break;
+ case HPET_STATUS:
+ /* write 1 to clear. */
+ while ( new_val )
+ {
+ bool active;
+
+ i = find_first_set_bit(new_val);
+ if ( i >= HPET_TIMER_NUM )
+ break;
+ __clear_bit(i, &new_val);
+ active = __test_and_clear_bit(i, &h->hpet.isr);
+ if ( active )
+ {
+ hvm_ioapic_deassert(v->domain, timer_int_route(h, i));
+ if ( hpet_enabled(h) && timer_enabled(h, i) &&
+ timer_level(h, i) && timer_is_periodic(h, i) )
+ set_start_timer(i);
+ }
+ }
+ break;
+
case HPET_COUNTER:
h->hpet.mc64 = new_val;
if ( hpet_enabled(h) )
timer_sanitize_int_route(h, tn);
- if ( timer_level(h, tn) )
- {
- gdprintk(XENLOG_ERR,
- "HPET: level triggered interrupt not supported now\n");
- domain_crash(current->domain);
- break;
- }
-
if ( new_val & HPET_TN_32BIT )
{
h->hpet.timers[tn].cmp = (uint32_t)h->hpet.timers[tn].cmp;