# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1253089841 -3600
# Node ID 72d130772f36284b904da2369410de795237f712
# Parent 0c83979c1b56b297a5109f2c206630af28460337
x86 hvm: suspend platform timer emulation while its IRQ is masked
This patch gets rid of a timer which IRQ is masked from vcpu's timer
list. It reduces the overhead of VM EXIT and context switch of vm.
Also fixes a potential bug.
(1) VCPU#0: mask the IRQ of a timer. (ex. vioapic.redir[2].mask=1)
(2) VCPU#1: pt_timer_fn() is invoked by expiration of the timer.
(3) VCPU#1: pt_update_irq() is called but does nothing by
pt_irq_masked()==1.
(4) VCPU#1: sleep by halt.
(5) VCPU#0: unmask the IRQ of the timer.
After that, no one wakes up the VCPU#1.
IRQ of ISA is masked by:
- PIC's IMR
- IOAPIC's redir[0]
- IOAPIC's redir[N].mask
- LAPIC's LVT0
- LAPIC enabled/disabled
IRQ of LAPIC timer is masked by:
- LAPIC's LVTT
- LAPIC disabled
When above stuffs are changed, the corresponding vcpu is kicked and
suspended timer emulation is resumed.
In addition, a small bug fix in pt_adjust_global_vcpu_target().
Signed-off-by: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
---
xen/arch/x86/hvm/vioapic.c | 6 +++
xen/arch/x86/hvm/vlapic.c | 10 ++++++
xen/arch/x86/hvm/vpic.c | 7 +++-
xen/arch/x86/hvm/vpt.c | 64 ++++++++++++++++++++++++++++++++++++------
xen/include/asm-x86/hvm/vpt.h | 4 +-
5 files changed, 80 insertions(+), 11 deletions(-)
diff -r 0c83979c1b56 -r 72d130772f36 xen/arch/x86/hvm/vioapic.c
--- a/xen/arch/x86/hvm/vioapic.c Wed Sep 16 09:29:17 2009 +0100
+++ b/xen/arch/x86/hvm/vioapic.c Wed Sep 16 09:30:41 2009 +0100
@@ -125,6 +125,7 @@ static void vioapic_write_redirent(
struct domain *d = vioapic_domain(vioapic);
struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq;
union vioapic_redir_entry *pent, ent;
+ int unmasked = 0;
spin_lock(&d->arch.hvm_domain.irq_lock);
@@ -138,10 +139,12 @@ static void vioapic_write_redirent(
}
else
{
+ unmasked = ent.fields.mask;
/* Remote IRR and Delivery Status are read-only. */
ent.bits = ((ent.bits >> 32) << 32) | val;
ent.fields.delivery_status = 0;
ent.fields.remote_irr = pent->fields.remote_irr;
+ unmasked = unmasked && !ent.fields.mask;
}
*pent = ent;
@@ -160,6 +163,9 @@ static void vioapic_write_redirent(
}
spin_unlock(&d->arch.hvm_domain.irq_lock);
+
+ if ( idx == 0 || unmasked )
+ pt_may_unmask_irq(d, NULL);
}
static void vioapic_write_indirect(
diff -r 0c83979c1b56 -r 72d130772f36 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Wed Sep 16 09:29:17 2009 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Wed Sep 16 09:30:41 2009 +0100
@@ -624,7 +624,10 @@ static int vlapic_write(struct vcpu *v,
}
}
else
+ {
vlapic->hw.disabled &= ~VLAPIC_SW_DISABLED;
+ pt_may_unmask_irq(vlapic_domain(vlapic), &vlapic->pt);
+ }
break;
case APIC_ESR:
@@ -654,7 +657,12 @@ static int vlapic_write(struct vcpu *v,
val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
vlapic_set_reg(vlapic, offset, val);
if ( offset == APIC_LVT0 )
+ {
vlapic_adjust_i8259_target(v->domain);
+ pt_may_unmask_irq(v->domain, NULL);
+ }
+ if ( (offset == APIC_LVTT) && !(val & APIC_LVT_MASKED) )
+ pt_may_unmask_irq(NULL, &vlapic->pt);
break;
case APIC_TMICT:
@@ -719,10 +727,12 @@ void vlapic_msr_set(struct vlapic *vlapi
{
vlapic_reset(vlapic);
vlapic->hw.disabled &= ~VLAPIC_HW_DISABLED;
+ pt_may_unmask_irq(vlapic_domain(vlapic), &vlapic->pt);
}
else
{
vlapic->hw.disabled |= VLAPIC_HW_DISABLED;
+ pt_may_unmask_irq(vlapic_domain(vlapic), NULL);
}
}
diff -r 0c83979c1b56 -r 72d130772f36 xen/arch/x86/hvm/vpic.c
--- a/xen/arch/x86/hvm/vpic.c Wed Sep 16 09:29:17 2009 +0100
+++ b/xen/arch/x86/hvm/vpic.c Wed Sep 16 09:30:41 2009 +0100
@@ -178,7 +178,7 @@ static void vpic_ioport_write(
struct hvm_hw_vpic *vpic, uint32_t addr, uint32_t val)
{
int priority, cmd, irq;
- uint8_t mask;
+ uint8_t mask, unmasked = 0;
vpic_lock(vpic);
@@ -190,6 +190,7 @@ static void vpic_ioport_write(
/* Clear edge-sensing logic. */
vpic->irr &= vpic->elcr;
+ unmasked = vpic->imr;
/* No interrupts masked or in service. */
vpic->imr = vpic->isr = 0;
@@ -268,6 +269,7 @@ static void vpic_ioport_write(
{
case 0:
/* OCW1 */
+ unmasked = vpic->imr & (~val);
vpic->imr = val;
break;
case 1:
@@ -295,6 +297,9 @@ static void vpic_ioport_write(
vpic_update_int_output(vpic);
vpic_unlock(vpic);
+
+ if ( unmasked )
+ pt_may_unmask_irq(vpic_domain(vpic), NULL);
}
static uint32_t vpic_ioport_read(struct hvm_hw_vpic *vpic, uint32_t addr)
diff -r 0c83979c1b56 -r 72d130772f36 xen/arch/x86/hvm/vpt.c
--- a/xen/arch/x86/hvm/vpt.c Wed Sep 16 09:29:17 2009 +0100
+++ b/xen/arch/x86/hvm/vpt.c Wed Sep 16 09:30:41 2009 +0100
@@ -216,19 +216,30 @@ void pt_update_irq(struct vcpu *v)
void pt_update_irq(struct vcpu *v)
{
struct list_head *head = &v->arch.hvm_vcpu.tm_list;
- struct periodic_time *pt, *earliest_pt = NULL;
+ struct periodic_time *pt, *temp, *earliest_pt = NULL;
uint64_t max_lag = -1ULL;
int irq, is_lapic;
spin_lock(&v->arch.hvm_vcpu.tm_lock);
- list_for_each_entry ( pt, head, list )
- {
- if ( pt->pending_intr_nr && !pt_irq_masked(pt) &&
- ((pt->last_plt_gtime + pt->period) < max_lag) )
- {
- max_lag = pt->last_plt_gtime + pt->period;
- earliest_pt = pt;
+ list_for_each_entry_safe ( pt, temp, head, list )
+ {
+ if ( pt->pending_intr_nr )
+ {
+ if ( pt_irq_masked(pt) )
+ {
+ /* suspend timer emulation */
+ list_del(&pt->list);
+ pt->on_list = 0;
+ }
+ else
+ {
+ if ( (pt->last_plt_gtime + pt->period) < max_lag )
+ {
+ max_lag = pt->last_plt_gtime + pt->period;
+ earliest_pt = pt;
+ }
+ }
}
}
@@ -412,6 +423,7 @@ void destroy_periodic_time(struct period
if ( pt->on_list )
list_del(&pt->list);
pt->on_list = 0;
+ pt->pending_intr_nr = 0;
pt_unlock(pt);
/*
@@ -451,11 +463,13 @@ static void pt_adjust_vcpu(struct period
void pt_adjust_global_vcpu_target(struct vcpu *v)
{
- struct pl_time *pl_time = &v->domain->arch.hvm_domain.pl_time;
+ struct pl_time *pl_time;
int i;
if ( v == NULL )
return;
+
+ pl_time = &v->domain->arch.hvm_domain.pl_time;
spin_lock(&pl_time->vpit.lock);
pt_adjust_vcpu(&pl_time->vpit.pt0, v);
@@ -470,3 +484,35 @@ void pt_adjust_global_vcpu_target(struct
pt_adjust_vcpu(&pl_time->vhpet.pt[i], v);
spin_unlock(&pl_time->vhpet.lock);
}
+
+
+static void pt_resume(struct periodic_time *pt)
+{
+ if ( pt->vcpu == NULL )
+ return;
+
+ pt_lock(pt);
+ if ( pt->pending_intr_nr && !pt->on_list )
+ {
+ pt->on_list = 1;
+ list_add(&pt->list, &pt->vcpu->arch.hvm_vcpu.tm_list);
+ vcpu_kick(pt->vcpu);
+ }
+ pt_unlock(pt);
+}
+
+void pt_may_unmask_irq(struct domain *d, struct periodic_time *vlapic_pt)
+{
+ int i;
+
+ if ( d )
+ {
+ pt_resume(&d->arch.hvm_domain.pl_time.vpit.pt0);
+ pt_resume(&d->arch.hvm_domain.pl_time.vrtc.pt);
+ for ( i = 0; i < HPET_TIMER_NUM; i++ )
+ pt_resume(&d->arch.hvm_domain.pl_time.vhpet.pt[i]);
+ }
+
+ if ( vlapic_pt )
+ pt_resume(vlapic_pt);
+}
diff -r 0c83979c1b56 -r 72d130772f36 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h Wed Sep 16 09:29:17 2009 +0100
+++ b/xen/include/asm-x86/hvm/vpt.h Wed Sep 16 09:30:41 2009 +0100
@@ -144,8 +144,10 @@ void pt_adjust_global_vcpu_target(struct
#define pt_global_vcpu_target(d) \
((d)->arch.hvm_domain.i8259_target ? : (d)->vcpu ? (d)->vcpu[0] : NULL)
+void pt_may_unmask_irq(struct domain *d, struct periodic_time *vlapic_pt);
+
/* Is given periodic timer active? */
-#define pt_active(pt) ((pt)->on_list)
+#define pt_active(pt) ((pt)->on_list || (pt)->pending_intr_nr)
/*
* Create/destroy a periodic (or one-shot!) timer.
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|