WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-devel

[Xen-devel] [PATCH 2/2] x86 hvm: suspend platform timer emulation while

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
<Prev in Thread] Current Thread [Next in Thread>