[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 5/6] vpt: add support for level interrupts
Level trigger interrupts will be asserted regardless of whether the interrupt is masked, and thus the callback will also be executed. Add a new 'level' parameter to create_periodic_time in order to create level triggered timers. Note that none of the current users of vpt are switched to use level triggered interrupts yet. Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> --- Cc: Jan Beulich <jbeulich@xxxxxxxx> Cc: Andrew Cooper <andrew.cooper3@xxxxxxxxxx> --- xen/arch/x86/hvm/hpet.c | 2 +- xen/arch/x86/hvm/i8254.c | 4 ++-- xen/arch/x86/hvm/rtc.c | 2 +- xen/arch/x86/hvm/vlapic.c | 8 +++---- xen/arch/x86/hvm/vpt.c | 45 ++++++++++++++++++++++++++++------- xen/include/asm-x86/hvm/vpt.h | 3 ++- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c index f7ef4f7514..72209350ba 100644 --- a/xen/arch/x86/hvm/hpet.c +++ b/xen/arch/x86/hvm/hpet.c @@ -302,7 +302,7 @@ static void hpet_set_timer(HPETState *h, unsigned int tn, 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); + irq, NULL, NULL, false); } static inline uint64_t hpet_fixup_reg( diff --git a/xen/arch/x86/hvm/i8254.c b/xen/arch/x86/hvm/i8254.c index 992f08dd6c..b8ec56f8d3 100644 --- a/xen/arch/x86/hvm/i8254.c +++ b/xen/arch/x86/hvm/i8254.c @@ -191,14 +191,14 @@ static void pit_load_count(PITState *pit, int channel, int val) /* Periodic timer. */ TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, period); create_periodic_time(v, &pit->pt0, period, period, 0, pit_time_fired, - &pit->count_load_time[channel]); + &pit->count_load_time[channel], false); break; case 1: case 4: /* One-shot timer. */ TRACE_2D(TRC_HVM_EMUL_PIT_START_TIMER, period, 0); create_periodic_time(v, &pit->pt0, period, 0, 0, pit_time_fired, - &pit->count_load_time[channel]); + &pit->count_load_time[channel], false); break; default: TRACE_0D(TRC_HVM_EMUL_PIT_STOP_TIMER); diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index cb75b99ed1..96921bb5b5 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -156,7 +156,7 @@ static void rtc_timer_update(RTCState *s) { TRACE_2D(TRC_HVM_EMUL_RTC_START_TIMER, delta, period); create_periodic_time(v, &s->pt, delta, period, - RTC_IRQ, rtc_pf_callback, s); + RTC_IRQ, rtc_pf_callback, s, false); } else s->check_ticks_since = now; diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index 1b9f00a0e4..d2ac4b8625 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -762,7 +762,7 @@ static void vlapic_update_timer(struct vlapic *vlapic, uint32_t lvtt, create_periodic_time(current, &vlapic->pt, delta, is_periodic ? period : 0, vlapic->pt.irq, is_periodic ? vlapic_pt_cb : NULL, - &vlapic->timer_last_update); + &vlapic->timer_last_update, false); vlapic->timer_last_update = vlapic->pt.last_plt_gtime; if ( !tmict_updated ) @@ -1166,7 +1166,7 @@ void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value) TRC_PAR_LONG(0LL), vlapic->pt.irq); create_periodic_time(v, &vlapic->pt, delta, 0, vlapic->pt.irq, vlapic_tdt_pt_cb, - &vlapic->timer_last_update); + &vlapic->timer_last_update, false); vlapic->timer_last_update = vlapic->pt.last_plt_gtime; } else @@ -1180,7 +1180,7 @@ void vlapic_tdt_msr_set(struct vlapic *vlapic, uint64_t value) TRC_PAR_LONG(0LL), vlapic->pt.irq); create_periodic_time(v, &vlapic->pt, 0, 0, vlapic->pt.irq, vlapic_tdt_pt_cb, - &vlapic->timer_last_update); + &vlapic->timer_last_update, false); vlapic->timer_last_update = vlapic->pt.last_plt_gtime; } else @@ -1431,7 +1431,7 @@ static void lapic_rearm(struct vlapic *s) vlapic_lvtt_period(s) ? period : 0, s->pt.irq, vlapic_lvtt_period(s) ? vlapic_pt_cb : NULL, - &s->timer_last_update); + &s->timer_last_update, false); s->timer_last_update = s->pt.last_plt_gtime; } diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c index 2565f7237e..e98bc41b1c 100644 --- a/xen/arch/x86/hvm/vpt.c +++ b/xen/arch/x86/hvm/vpt.c @@ -306,6 +306,7 @@ int pt_update_irq(struct vcpu *v) struct periodic_time *pt, *temp, *earliest_pt; uint64_t max_lag; int irq, pt_vector = -1; + bool level; spin_lock(&v->arch.hvm_vcpu.tm_lock); @@ -316,7 +317,9 @@ int pt_update_irq(struct vcpu *v) if ( pt->pending_intr_nr ) { /* RTC code takes care of disabling the timer itself. */ - if ( (pt->irq != RTC_IRQ || !pt->priv) && pt_irq_masked(pt) ) + if ( (pt->irq != RTC_IRQ || !pt->priv) && pt_irq_masked(pt) && + /* Level interrupts should be asserted even if masked. */ + !pt->level ) { /* suspend timer emulation */ list_del(&pt->list); @@ -341,6 +344,7 @@ int pt_update_irq(struct vcpu *v) earliest_pt->irq_issued = 1; irq = earliest_pt->irq; + level = earliest_pt->level; spin_unlock(&v->arch.hvm_vcpu.tm_lock); @@ -374,13 +378,36 @@ int pt_update_irq(struct vcpu *v) 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, false); + pt_vector = hvm_ioapic_assert(v->domain, irq, level); if ( pt_vector < 0 || !vlapic_test_irq(vcpu_vlapic(v), pt_vector) ) + { pt_vector = -1; + if ( level ) + { + /* + * Level interrupts are asserted even if the interrupt is + * masked, so also execute the callback associated with the + * timer. + */ + time_cb *cb = NULL; + void *cb_priv; + + spin_lock(&v->arch.hvm_vcpu.tm_lock); + /* Make sure the timer is still on the list. */ + list_for_each_entry ( pt, &v->arch.hvm_vcpu.tm_list, list ) + if ( pt == earliest_pt ) + { + pt_irq_fired(v, pt); + cb = pt->cb; + cb_priv = pt->priv; + break; + } + spin_unlock(&v->arch.hvm_vcpu.tm_lock); + + if ( cb != NULL ) + cb(v, cb_priv); + } + } break; } @@ -447,12 +474,13 @@ void pt_migrate(struct vcpu *v) void create_periodic_time( struct vcpu *v, struct periodic_time *pt, uint64_t delta, - uint64_t period, uint8_t irq, time_cb *cb, void *data) + uint64_t period, uint8_t irq, time_cb *cb, void *data, bool level) { if ( !pt->source || (irq >= NR_ISAIRQS && pt->source == PTSRC_isa) || (irq >= hvm_domain_irq(v->domain)->nr_gsis && - pt->source == PTSRC_ioapic) ) + pt->source == PTSRC_ioapic) || + (level && pt->source != PTSRC_ioapic) ) { ASSERT_UNREACHABLE(); return; @@ -480,6 +508,7 @@ void create_periodic_time( pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu); pt->irq = irq; pt->one_shot = !period; + pt->level = level; pt->scheduled = NOW() + delta; if ( !pt->one_shot ) diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h index f693c0bcf1..61c26ed8b2 100644 --- a/xen/include/asm-x86/hvm/vpt.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -42,6 +42,7 @@ struct periodic_time { bool do_not_freeze; bool irq_issued; bool warned_timeout_too_short; + bool level; #define PTSRC_isa 1 /* ISA time source */ #define PTSRC_lapic 2 /* LAPIC time source */ #define PTSRC_ioapic 3 /* IOAPIC time source */ @@ -169,7 +170,7 @@ void pt_may_unmask_irq(struct domain *d, struct periodic_time *vlapic_pt); */ void create_periodic_time( struct vcpu *v, struct periodic_time *pt, uint64_t delta, - uint64_t period, uint8_t irq, time_cb *cb, void *data); + uint64_t period, uint8_t irq, time_cb *cb, void *data, bool level); void destroy_periodic_time(struct periodic_time *pt); int pv_pit_handler(int port, int data, int write); -- 2.17.1 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |