diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN))
? (uint32_t)diff : 0;
+ destroy_periodic_time(&h->pt[tn]);
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. */
irq = (tn == 0) ? 0 : 8;
+ h->pt[tn].source = PTSRC_isa;
+ }
else
+ {
irq = timer_int_route(h, tn);
+ h->pt[tn].source = PTSRC_ioapic;
+ }
/*
* diff is the time from now when the timer should fire, for a periodic
static int pt_irq_masked(struct periodic_time *pt)
{
struct vcpu *v = pt->vcpu;
- unsigned int gsi, isa_irq;
- uint8_t pic_imr;
+ unsigned int gsi = pt->irq;
- if ( pt->source == PTSRC_lapic )
+ switch ( pt->source )
+ {
+ case PTSRC_lapic:
{
struct vlapic *vlapic = vcpu_vlapic(v);
+
return (!vlapic_enabled(vlapic) ||
(vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_MASKED));
}
- isa_irq = pt->irq;
- gsi = hvm_isa_irq_to_gsi(isa_irq);
- pic_imr = v->domain->arch.hvm_domain.vpic[isa_irq >> 3].imr;
+ case PTSRC_isa:
+ {
+ uint8_t pic_imr = v->domain->arch.hvm_domain.vpic[pt->irq >> 3].imr;
- return (((pic_imr & (1 << (isa_irq & 7))) || !vlapic_accept_pic_intr(v)) &&
- domain_vioapic(v->domain)->redirtbl[gsi].fields.mask);
+ /* Check if the interrupt is unmasked in the PIC. */
+ if ( !(pic_imr & (1 << (pt->irq & 7))) && vlapic_accept_pic_intr(v) )
+ return 0;
+
+ gsi = hvm_isa_irq_to_gsi(pt->irq);
+ }
+
+ /* Fallthrough to check if the interrupt is masked on the IO APIC. */
+ case PTSRC_ioapic:
+ return domain_vioapic(v->domain)->redirtbl[gsi].fields.mask;
+ }
+
+ ASSERT_UNREACHABLE();
+ return 1;
}
static void pt_lock(struct periodic_time *pt)
struct list_head *head = &v->arch.hvm_vcpu.tm_list;
struct periodic_time *pt, *temp, *earliest_pt;
uint64_t max_lag;
- int irq, is_lapic;
+ int irq, pt_vector = -1;
spin_lock(&v->arch.hvm_vcpu.tm_lock);
earliest_pt->irq_issued = 1;
irq = earliest_pt->irq;
- is_lapic = (earliest_pt->source == PTSRC_lapic);
spin_unlock(&v->arch.hvm_vcpu.tm_lock);
- if ( is_lapic )
- vlapic_set_irq(vcpu_vlapic(v), irq, 0);
- else
+ switch ( earliest_pt->source )
{
+ case PTSRC_lapic:
+ /*
+ * If periodic timer interrupt is handled by lapic, its vector in
+ * IRR is returned and used to set eoi_exit_bitmap for virtual
+ * interrupt delivery case. Otherwise return -1 to do nothing.
+ */
+ vlapic_set_irq(vcpu_vlapic(v), irq, 0);
+ pt_vector = irq;
+ break;
+
+ case PTSRC_isa:
hvm_isa_irq_deassert(v->domain, irq);
hvm_isa_irq_assert(v->domain, irq);
+
+ if ( platform_legacy_irq(irq) && vlapic_accept_pic_intr(v) &&
+ v->domain->arch.hvm_domain.vpic[irq >> 3].int_output )
+ return -1;
+
+ pt_vector = pt_irq_vector(earliest_pt, hvm_intsrc_lapic);
+ break;
+
+ case PTSRC_ioapic:
+ /*
+ * NB: At the moment IO-APIC routed interrupts generated by vpt devices
+ * (HPET) are edge-triggered.
+ */
+ pt_vector = hvm_ioapic_assert(v->domain, irq, 0);
+ break;
}
- /*
- * If periodic timer interrut is handled by lapic, its vector in
- * IRR is returned and used to set eoi_exit_bitmap for virtual
- * interrupt delivery case. Otherwise return -1 to do nothing.
- */
- if ( !is_lapic &&
- platform_legacy_irq(irq) && vlapic_accept_pic_intr(v) &&
- (&v->domain->arch.hvm_domain)->vpic[irq >> 3].int_output )
- return -1;
- else
- return pt_irq_vector(earliest_pt, hvm_intsrc_lapic);
+ return pt_vector;
}
static struct periodic_time *is_pt_irq(
struct vcpu *v, struct periodic_time *pt, uint64_t delta,
uint64_t period, uint8_t irq, time_cb *cb, void *data)
{
- ASSERT(pt->source != 0);
+ if ( !pt->source ||
+ (pt->irq >= NR_ISAIRQS && pt->source == PTSRC_isa) ||
+ (pt->irq >= VIOAPIC_NUM_PINS && pt->source == PTSRC_ioapic) )
+ {
+ ASSERT_UNREACHABLE();
+ return;
+ }
destroy_periodic_time(pt);
{
int on_list;
- ASSERT(pt->source == PTSRC_isa);
+ ASSERT(pt->source == PTSRC_isa || pt->source == PTSRC_ioapic);
if ( pt->vcpu == NULL )
return;