[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 2/2] 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>

# HG changeset patch
# User Kouya Shimura <kouya@xxxxxxxxxxxxxx>
# Date 1253080328 -32400
# Node ID b62a5e4c6125e62fd5fd1e28f7ae1c8a093b689d
# Parent  58ef1439ca982cdd2f7e4698ce9bdba1f4b38853
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>

diff -r 58ef1439ca98 -r b62a5e4c6125 xen/arch/x86/hvm/vioapic.c
--- a/xen/arch/x86/hvm/vioapic.c        Tue Sep 15 10:08:12 2009 +0100
+++ b/xen/arch/x86/hvm/vioapic.c        Wed Sep 16 14:52:08 2009 +0900
@@ -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 58ef1439ca98 -r b62a5e4c6125 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Tue Sep 15 10:08:12 2009 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Wed Sep 16 14:52:08 2009 +0900
@@ -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 58ef1439ca98 -r b62a5e4c6125 xen/arch/x86/hvm/vpic.c
--- a/xen/arch/x86/hvm/vpic.c   Tue Sep 15 10:08:12 2009 +0100
+++ b/xen/arch/x86/hvm/vpic.c   Wed Sep 16 14:52:08 2009 +0900
@@ -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 58ef1439ca98 -r b62a5e4c6125 xen/arch/x86/hvm/vpt.c
--- a/xen/arch/x86/hvm/vpt.c    Tue Sep 15 10:08:12 2009 +0100
+++ b/xen/arch/x86/hvm/vpt.c    Wed Sep 16 14:52:08 2009 +0900
@@ -221,19 +221,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 )
+    list_for_each_entry_safe ( pt, temp, head, list )
     {
-        if ( pt->pending_intr_nr && !pt_irq_masked(pt) &&
-             ((pt->last_plt_gtime + pt->period) < max_lag) )
+        if ( pt->pending_intr_nr )
         {
-            max_lag = pt->last_plt_gtime + pt->period;
-            earliest_pt = pt;
+            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;
+                }
+            }
         }
     }
 
@@ -411,6 +422,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);
 
     /*
@@ -450,11 +462,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);
@@ -469,3 +483,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 58ef1439ca98 -r b62a5e4c6125 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Tue Sep 15 10:08:12 2009 +0100
+++ b/xen/include/asm-x86/hvm/vpt.h     Wed Sep 16 14:52:08 2009 +0900
@@ -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-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.