[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC 2/3] x86/hvm/rtc: Inject RTC periodic interupts from the vpt code.
Let the vpt code drive the RTC's timer interrupts directly, as it does for other periodic time sources, and fix up the register state in a vpt callback when the interrupt is injected. This fixes a hang seen on Windows 2003 in no-missed-ticks mode, where when a tick was pending, the early callback from the VPT code would always set REG_C.PF on every VMENTER; meanwhile the guest was in its interrupt handler reading REG_C in a loop and waiting to see it clear. One drawback is that a guest that attempts to suppress RTC periodic interrupts by failing to read REG_C will receive up to 10 spurious interrupts, even in 'strict' mode. However: - since all previous RTC models have had this property (including the current one, since 'no-ack' mode is hard-coded on) we're pretty sure that all guests can handle this; and - we're already playing some other interesting games with this interrupt in the vpt code. One other corner case: a guest that enables the PF timer interrupt, masks the interupt in the APIC and then polls REG_C looking for PF will not see PF getting set. The more likely case of enabling the timers and masking the interrupt with REG_B.PIE is already handled correctly. Signed-off-by: Tim Deegan <tim@xxxxxxx> --- xen/arch/x86/hvm/rtc.c | 25 +++++++++++-------------- xen/arch/x86/hvm/vpt.c | 40 ---------------------------------------- xen/include/asm-x86/hvm/vpt.h | 1 - 3 files changed, 11 insertions(+), 55 deletions(-) diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index cfc1af9..18a4fe8 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -78,29 +78,26 @@ static void rtc_update_irq(RTCState *s) hvm_isa_irq_assert(vrtc_domain(s), RTC_IRQ); } -bool_t rtc_periodic_interrupt(void *opaque) +/* Called by the VPT code after it's injected a PF interrupt for us. + * Fix up the register state to reflect what happened. */ +static void rtc_pf_callback(struct vcpu *v, void *opaque) { RTCState *s = opaque; - bool_t ret; spin_lock(&s->lock); - ret = rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF); - if ( rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_PF) ) - { - s->hw.cmos_data[RTC_REG_C] |= RTC_PF; - rtc_update_irq(s); - } - else if ( ++(s->pt_dead_ticks) >= 10 ) + + if ( !rtc_mode_is(s, no_ack) + && (s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) + && ++(s->pt_dead_ticks) >= 10 ) { /* VM is ignoring its RTC; no point in running the timer */ destroy_periodic_time(&s->pt); s->period = 0; } - if ( !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) ) - ret = 0; - spin_unlock(&s->lock); - return ret; + s->hw.cmos_data[RTC_REG_C] |= RTC_PF|RTC_IRQF; + + spin_unlock(&s->lock); } /* Check whether the REG_C.PF bit should have been set by a tick since @@ -156,7 +153,7 @@ static void rtc_timer_update(RTCState *s) delta = period - ((now - s->start_time) % period); if ( s->hw.cmos_data[RTC_REG_B] & RTC_PIE ) create_periodic_time(v, &s->pt, delta, period, - RTC_IRQ, NULL, s); + RTC_IRQ, rtc_pf_callback, s); else s->check_ticks_since = now; } diff --git a/xen/arch/x86/hvm/vpt.c b/xen/arch/x86/hvm/vpt.c index 1961bda..f7af688 100644 --- a/xen/arch/x86/hvm/vpt.c +++ b/xen/arch/x86/hvm/vpt.c @@ -231,12 +231,9 @@ int pt_update_irq(struct vcpu *v) struct periodic_time *pt, *temp, *earliest_pt; uint64_t max_lag; int irq, is_lapic; - void *pt_priv; - rescan: spin_lock(&v->arch.hvm_vcpu.tm_lock); - rescan_locked: earliest_pt = NULL; max_lag = -1ULL; list_for_each_entry_safe ( pt, temp, head, list ) @@ -270,48 +267,11 @@ int pt_update_irq(struct vcpu *v) earliest_pt->irq_issued = 1; irq = earliest_pt->irq; is_lapic = (earliest_pt->source == PTSRC_lapic); - pt_priv = earliest_pt->priv; spin_unlock(&v->arch.hvm_vcpu.tm_lock); if ( is_lapic ) vlapic_set_irq(vcpu_vlapic(v), irq, 0); - else if ( irq == RTC_IRQ && pt_priv ) - { - if ( !rtc_periodic_interrupt(pt_priv) ) - irq = -1; - - pt_lock(earliest_pt); - - if ( irq < 0 && earliest_pt->pending_intr_nr ) - { - /* - * RTC periodic timer runs without the corresponding interrupt - * being enabled - need to mimic enough of pt_intr_post() to keep - * things going. - */ - earliest_pt->pending_intr_nr = 0; - earliest_pt->irq_issued = 0; - set_timer(&earliest_pt->timer, earliest_pt->scheduled); - } - else if ( irq >= 0 && pt_irq_masked(earliest_pt) ) - { - if ( earliest_pt->on_list ) - { - /* suspend timer emulation */ - list_del(&earliest_pt->list); - earliest_pt->on_list = 0; - } - irq = -1; - } - - /* Avoid dropping the lock if we can. */ - if ( irq < 0 && v == earliest_pt->vcpu ) - goto rescan_locked; - pt_unlock(earliest_pt); - if ( irq < 0 ) - goto rescan; - } else { hvm_isa_irq_deassert(v->domain, irq); diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h index 9f48635..7d62653 100644 --- a/xen/include/asm-x86/hvm/vpt.h +++ b/xen/include/asm-x86/hvm/vpt.h @@ -184,7 +184,6 @@ void rtc_migrate_timers(struct vcpu *v); void rtc_deinit(struct domain *d); void rtc_reset(struct domain *d); void rtc_update_clock(struct domain *d); -bool_t rtc_periodic_interrupt(void *); void pmtimer_init(struct vcpu *v); void pmtimer_deinit(struct domain *d); -- 1.8.5.2 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |