@@ -484,6 +484,7 @@ void pit_init(struct domain *d, unsigned long cpu_khz)
{
register_portio_handler(d, PIT_BASE, 4, handle_pit_io);
register_portio_handler(d, 0x61, 1, handle_speaker_io);
+ init_periodic_timer(&pit->pt0);
}
pit_reset(d);
@@ -739,12 +739,18 @@ static void hpet_set(HPETState *h)
void hpet_init(struct domain *d)
{
+ HPETState *h = domain_vhpet(d);
+ unsigned int i;
+
if ( !has_vhpet(d) )
return;
- hpet_set(domain_vhpet(d));
+ hpet_set(h);
register_mmio_handler(d, &hpet_mmio_ops);
d->arch.hvm.params[HVM_PARAM_HPET_ENABLED] = 1;
+
+ for ( i = 0; i < HPET_TIMER_NUM; i++ )
+ init_periodic_timer(&h->pt[i]);
}
void hpet_deinit(struct domain *d)
@@ -665,8 +665,6 @@ int hvm_domain_initialise(struct domain *d)
/* need link to containing domain */
d->arch.hvm.pl_time->domain = d;
- rwlock_init(&d->arch.hvm.pl_time->pt_migrate);
-
/* Set the default IO Bitmap. */
if ( is_hardware_domain(d) )
{
@@ -846,6 +846,7 @@ void rtc_init(struct domain *d)
init_timer(&s->update_timer, rtc_update_timer, s, smp_processor_id());
init_timer(&s->update_timer2, rtc_update_timer2, s, smp_processor_id());
init_timer(&s->alarm_timer, rtc_alarm_cb, s, smp_processor_id());
+ init_periodic_timer(&s->pt);
register_portio_handler(d, RTC_PORT(0), 2, handle_rtc_io);
@@ -1642,6 +1642,7 @@ int vlapic_init(struct vcpu *v)
return 0;
}
+ init_periodic_timer(&vlapic->pt);
vlapic->pt.source = PTSRC_lapic;
if (vlapic->regs_page == NULL)
@@ -126,23 +126,6 @@ static int pt_irq_masked(struct periodic_time *pt)
return 1;
}
-static void pt_lock(struct periodic_time *pt)
-{
- /*
- * We cannot use pt_vcpu_lock here, because we need to acquire the
- * per-domain lock first and then (re-)fetch the value of pt->vcpu, or
- * else we might be using a stale value of pt->vcpu.
- */
- read_lock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate);
- spin_lock(&pt->vcpu->arch.hvm.tm_lock);
-}
-
-static void pt_unlock(struct periodic_time *pt)
-{
- spin_unlock(&pt->vcpu->arch.hvm.tm_lock);
- read_unlock(&pt->vcpu->domain->arch.hvm.pl_time->pt_migrate);
-}
-
static void pt_process_missed_ticks(struct periodic_time *pt)
{
s_time_t missed_ticks, now = NOW();
@@ -224,7 +207,7 @@ static void pt_timer_fn(void *data)
void *cb_priv;
unsigned int irq;
- pt_lock(pt);
+ spin_lock(&pt->lock);
v = pt->vcpu;
irq = pt->irq;
@@ -240,7 +223,7 @@ static void pt_timer_fn(void *data)
cb_priv = pt->priv;
}
- pt_unlock(pt);
+ spin_unlock(&pt->lock);
if ( cb )
cb(v, cb_priv);
@@ -257,7 +240,7 @@ static void eoi_callback(unsigned int unused, void *data)
time_cb *cb = NULL;
void *cb_priv;
- pt_lock(pt);
+ spin_lock(&pt->lock);
pt_irq_fired(pt->vcpu, pt);
if ( pt->pending_intr_nr )
@@ -272,7 +255,7 @@ static void eoi_callback(unsigned int unused, void *data)
}
}
- pt_unlock(pt);
+ spin_unlock(&pt->lock);
if ( cb != NULL )
cb(v, cb_priv);
@@ -320,6 +303,11 @@ static bool inject_interrupt(struct periodic_time *pt)
return true;
}
+void init_periodic_timer(struct periodic_time *pt)
+{
+ spin_lock_init(&pt->lock);
+}
+
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, bool level)
@@ -336,7 +324,7 @@ void create_periodic_time(
destroy_periodic_time(pt);
- write_lock(&v->domain->arch.hvm.pl_time->pt_migrate);
+ spin_lock(&pt->lock);
pt->pending_intr_nr = 0;
pt->masked = false;
@@ -400,18 +388,21 @@ void create_periodic_time(
init_timer(&pt->timer, pt_timer_fn, pt, v->processor);
set_timer(&pt->timer, pt->scheduled);
- write_unlock(&v->domain->arch.hvm.pl_time->pt_migrate);
+ spin_unlock(&pt->lock);
}
void destroy_periodic_time(struct periodic_time *pt)
{
unsigned int gsi;
+ spin_lock(&pt->lock);
/* Was this structure previously initialised by create_periodic_time()? */
if ( pt->vcpu == NULL )
+ {
+ spin_unlock(&pt->lock);
return;
+ }
- pt_lock(pt);
pt->pending_intr_nr = 0;
pt->masked = false;
@@ -425,7 +416,7 @@ void destroy_periodic_time(struct periodic_time *pt)
hvm_gsi_unregister_callback(pt->vcpu->domain, gsi, &pt->eoi_cb);
break;
}
- pt_unlock(pt);
+ spin_unlock(&pt->lock);
/*
* pt_timer_fn() can run until this kill_timer() returns. We must do this
@@ -440,10 +431,13 @@ static void pt_resume(struct periodic_time *pt)
time_cb *cb = NULL;
void *cb_priv;
+ spin_lock(&pt->lock);
if ( pt->vcpu == NULL )
+ {
+ spin_unlock(&pt->lock);
return;
+ }
- pt_lock(pt);
if ( pt->pending_intr_nr && pt->masked && inject_interrupt(pt) )
{
pt->pending_intr_nr--;
@@ -452,7 +446,7 @@ static void pt_resume(struct periodic_time *pt)
v = pt->vcpu;
pt->masked = false;
}
- pt_unlock(pt);
+ spin_unlock(&pt->lock);
if ( cb )
cb(v, cb_priv);
@@ -49,6 +49,7 @@ struct periodic_time {
time_cb *cb;
void *priv; /* point back to platform time source */
struct hvm_gsi_eoi_callback eoi_cb; /* EOI callback registration data */
+ spinlock_t lock;
};
@@ -127,13 +128,6 @@ struct pl_time { /* platform time */
struct RTCState vrtc;
struct HPETState vhpet;
struct PMTState vpmt;
- /*
- * rwlock to prevent periodic_time vCPU migration. Take the lock in read
- * mode in order to prevent the vcpu field of periodic_time from changing.
- * Lock must be taken in write mode when changes to the vcpu field are
- * performed, as it allows exclusive access to all the timers of a domain.
- */
- rwlock_t pt_migrate;
/* guest_time = Xen sys time + stime_offset */
int64_t stime_offset;
/* Ensures monotonicity in appropriate timer modes. */
@@ -168,6 +162,7 @@ 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, bool level);
void destroy_periodic_time(struct periodic_time *pt);
+void init_periodic_timer(struct periodic_time *pt);
int pv_pit_handler(int port, int data, int write);
void pit_reset(struct domain *d);
Introduce a per virtual timer lock that replaces the existing per-vCPU and per-domain vPT locks. Since virtual timers are no longer assigned or migrated between vCPUs the locking can be simplified to a in-structure spinlock that protects all the fields. This requires introducing a helper to initialize the spinlock, and that could be used to initialize other virtual timer fields in the future. Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> --- Changes since v1: - New in his version. --- xen/arch/x86/emul-i8254.c | 1 + xen/arch/x86/hvm/hpet.c | 8 +++++- xen/arch/x86/hvm/hvm.c | 2 -- xen/arch/x86/hvm/rtc.c | 1 + xen/arch/x86/hvm/vlapic.c | 1 + xen/arch/x86/hvm/vpt.c | 48 +++++++++++++++-------------------- xen/include/asm-x86/hvm/vpt.h | 9 ++----- 7 files changed, 33 insertions(+), 37 deletions(-)