From: Rik van Riel <riel@redhat.com> Date: Mon, 13 Apr 2009 12:07:22 -0400 Subject: [xen] x86: misc fixes to the timer code Message-id: 20090413120722.1a2455c1@bree.surriel.com O-Subject: [RHEL 5.4 PATCH 2/5] misc fixes to the timer code (bz 449346) Bugzilla: 449346 RH-Acked-by: Justin M. Forbes <jforbes@redhat.com> RH-Acked-by: Chris Lalancette <clalance@redhat.com> RH-Acked-by: Don Dutile <ddutile@redhat.com> More fixes to the timer infrastructure, required for correct HVM timekeeping. Fixes bug 449346 # HG changeset patch # User Keir Fraser <keir.fraser@citrix.com> # Date 1197470499 0 # Node ID 03551b644e35dbec62d657e6f943faa5dd310409 # Parent 1caed71f2a357533a569a7fdac7bfb06ca2368a7 [HVM] Don't count "missed ticks" on one-shot timers. It's not clear what it would mean, and it leads to division by zero. Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com> xen-unstable changeset: 15943:c0d1825f51899b329495efb2078dd15e0fb3b479 xen-unstable date: Mon Sep 24 13:44:29 2007 +0100 hvm: Fix one-shot timers. Do not disable until the interrupt has been latched by the target VCPU. Signed-off-by: Keir Fraser <keir@xensource.com> xen-unstable changeset: 16125:b4278beaf3549f410a5a6086dbd8af93c495aeac xen-unstable date: Wed Oct 17 13:12:03 2007 +0100 hvm: Fix destroy_periodic_time() to not race destruction of one-shot timers. This bug was tracked down by Dexuan Cui <dexuan.cui@intel.com> Signed-off-by: Keir Fraser <keir.fraser@citrix.com> xen-unstable changeset: 16595:f2f7c92bf1c15206aa7072f6a4e470a132d528e2 xen-unstable date: Wed Dec 12 11:08:21 2007 +0000 diff --git a/arch/x86/hvm/vioapic.c b/arch/x86/hvm/vioapic.c index 3266c39..c86cbfa 100644 --- a/arch/x86/hvm/vioapic.c +++ b/arch/x86/hvm/vioapic.c @@ -311,7 +311,7 @@ static inline int pit_channel0_enabled(void) { PITState *pit = ¤t->domain->arch.hvm_domain.pl_time.vpit; struct periodic_time *pt = &pit->pt[0]; - return pt->enabled; + return pt_active(pt); } static void vioapic_deliver(struct hvm_hw_vioapic *vioapic, int irq) diff --git a/arch/x86/hvm/vlapic.c b/arch/x86/hvm/vlapic.c index 38dd9e9..f4b3b8d 100644 --- a/arch/x86/hvm/vlapic.c +++ b/arch/x86/hvm/vlapic.c @@ -956,15 +956,12 @@ void vlapic_destroy(struct vcpu *v) int is_lvtt(struct vcpu *v, int vector) { - return vcpu_vlapic(v)->pt.enabled && - vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT); + return (pt_active(&vcpu_vlapic(v)->pt) && + (vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT))); } int is_lvtt_enabled(struct vcpu *v) { - if ( unlikely(!vlapic_enabled(vcpu_vlapic(v))) || - !vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT)) - return 0; - - return 1; + return (vlapic_enabled(vcpu_vlapic(v)) && + vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT)); } diff --git a/arch/x86/hvm/vpt.c b/arch/x86/hvm/vpt.c index 4762ef6..18dc6ee 100644 --- a/arch/x86/hvm/vpt.c +++ b/arch/x86/hvm/vpt.c @@ -114,12 +114,13 @@ static void pt_timer_fn(void *data) pt_lock(pt); pt->pending_intr_nr++; - pt->scheduled += pt->period; - - missed_ticks(pt); if ( !pt->one_shot ) + { + pt->scheduled += pt->period; + missed_ticks(pt); set_timer(&pt->timer, pt->scheduled); + } vcpu_kick(pt->vcpu); @@ -204,10 +205,17 @@ void pt_intr_post(struct vcpu *v, int vector, int type) return; } - ASSERT(pt->vcpu == v); - - pt->pending_intr_nr--; - pt->last_plt_gtime += pt->period_cycles; + if ( pt->one_shot ) + { + if ( pt->on_list ) + list_del(&pt->list); + pt->on_list = 0; + } + else + { + pt->pending_intr_nr--; + pt->last_plt_gtime += pt->period_cycles; + } if ( hvm_get_guest_time(v) < pt->last_plt_gtime ) hvm_set_guest_time(v, pt->last_plt_gtime); @@ -260,7 +268,6 @@ void create_periodic_time( spin_lock(&v->arch.hvm_vcpu.tm_lock); - pt->enabled = 1; pt->pending_intr_nr = 0; /* Periodic timer must be at least 0.9ms. */ @@ -282,6 +289,7 @@ void create_periodic_time( pt->cb = cb; pt->priv = data; + pt->on_list = 1; list_add(&pt->list, &v->arch.hvm_vcpu.tm_list); init_timer(&pt->timer, pt_timer_fn, pt, v->processor); @@ -292,12 +300,14 @@ void create_periodic_time( void destroy_periodic_time(struct periodic_time *pt) { - if ( !pt->enabled ) + /* Was this structure previously initialised by create_periodic_time()? */ + if ( pt->vcpu == NULL ) return; pt_lock(pt); - pt->enabled = 0; - list_del(&pt->list); + if ( pt->on_list ) + list_del(&pt->list); + pt->on_list = 0; pt_unlock(pt); /* diff --git a/include/asm-x86/hvm/vpt.h b/include/asm-x86/hvm/vpt.h index acd245a..20e4fbb 100644 --- a/include/asm-x86/hvm/vpt.h +++ b/include/asm-x86/hvm/vpt.h @@ -55,11 +55,11 @@ typedef void time_cb(struct vcpu *v, void *opaque); struct periodic_time { struct list_head list; - char enabled; - char one_shot; /* one shot time */ + bool_t on_list; + bool_t one_shot; u8 irq; struct vcpu *vcpu; /* vcpu timer interrupt delivers to */ - u32 pending_intr_nr; /* the couner for pending timer interrupts */ + u32 pending_intr_nr; /* pending timer interrupts */ u64 period; /* frequency in ns */ u64 period_cycles; /* frequency in cpu cycles */ s_time_t scheduled; /* scheduled timer interrupt */ @@ -122,6 +122,17 @@ void pt_update_irq(struct vcpu *v); void pt_intr_post(struct vcpu *v, int vector, int type); void pt_reset(struct vcpu *v); void pt_migrate(struct vcpu *v); + +/* Is given periodic timer active? */ +#define pt_active(pt) ((pt)->on_list) + +/* + * Create/destroy a periodic (or one-shot!) timer. + * The given periodic timer structure must be initialised with zero bytes or + * have been initialised by a previous invocation of create_periodic_time(). + * Note that, for a given periodic timer, invocations of these functions MUST + * be serialised. + */ void create_periodic_time( struct vcpu *v, struct periodic_time *pt, uint64_t period, uint8_t irq, char one_shot, time_cb *cb, void *data);