[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC v2 2/3] x86/hvm/rtc: Inject RTC periodic interupts from the vpt code.
From: Tim Deegan <tim@xxxxxxx> 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 1455bc6..7a37ebb 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) 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); s->period = period; } else 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.7.10.4 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |