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] x86 hvm: freeze PIT/LAPIC timer emulation while its

To: xen-devel@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-devel] [PATCH] x86 hvm: freeze PIT/LAPIC timer emulation while its IRQ is masked
From: Kouya Shimura <kouya@xxxxxxxxxxxxxx>
Date: Thu, 10 Sep 2009 14:47:22 +0900
Delivery-date: Wed, 09 Sep 2009 22:48:03 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
Hi,

I've found that modern windows OS never use the PIT timer,
and neither cpu#0's LAPIC timer after boot.
Despite that, xen emulates them busily. It's inefficient.

Note: this patch ignores the IRQ mask of legacy i8259 since
rombios frequently modifies it.

Thanks,
Kouya

Signed-off-by: Kouya Shimura <kouya@xxxxxxxxxxxxxx>

diff -r d2a32e24fe50 xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Wed Sep 09 16:39:41 2009 +0100
+++ b/xen/arch/x86/hvm/i8254.c  Thu Sep 10 09:55:29 2009 +0900
@@ -421,6 +421,8 @@ static int pit_load(struct domain *d, hv
 
     spin_unlock(&pit->lock);
 
+    pt_freeze_pit_timer_if_irqmasked(d);
+
     return 0;
 }
 
diff -r d2a32e24fe50 xen/arch/x86/hvm/vioapic.c
--- a/xen/arch/x86/hvm/vioapic.c        Wed Sep 09 16:39:41 2009 +0100
+++ b/xen/arch/x86/hvm/vioapic.c        Thu Sep 10 09:55:29 2009 +0900
@@ -158,6 +158,9 @@ static void vioapic_write_redirent(
         pent->fields.remote_irr = 1;
         vioapic_deliver(vioapic, idx);
     }
+
+    if ( idx == hvm_isa_irq_to_gsi(0) && !top_word )
+        pt_freeze_pit_timer_if_irqmasked(d);
 
     spin_unlock(&d->arch.hvm_domain.irq_lock);
 }
diff -r d2a32e24fe50 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Wed Sep 09 16:39:41 2009 +0100
+++ b/xen/arch/x86/hvm/vlapic.c Thu Sep 10 09:55:29 2009 +0900
@@ -655,6 +655,8 @@ static int vlapic_write(struct vcpu *v, 
         vlapic_set_reg(vlapic, offset, val);
         if ( offset == APIC_LVT0 )
             vlapic_adjust_i8259_target(v->domain);
+        if ( offset == APIC_LVTT )
+            pt_freeze_lapic_timer_if_irqmasked(&vlapic->pt);
         break;
 
     case APIC_TMICT:
@@ -770,10 +772,13 @@ void vlapic_adjust_i8259_target(struct d
     v = d->vcpu ? d->vcpu[0] : NULL;
 
  found:
-    if ( d->arch.hvm_domain.i8259_target == v )
-        return;
-    d->arch.hvm_domain.i8259_target = v;
-    pt_adjust_global_vcpu_target(v);
+    if ( d->arch.hvm_domain.i8259_target != v )
+    {
+        d->arch.hvm_domain.i8259_target = v;
+        pt_adjust_global_vcpu_target(v);
+    }
+
+    pt_freeze_pit_timer_if_irqmasked(d);
 }
 
 int vlapic_has_pending_irq(struct vcpu *v)
@@ -934,6 +939,7 @@ static int lapic_load_regs(struct domain
 
     vlapic_adjust_i8259_target(d);
     lapic_rearm(s);
+    pt_freeze_lapic_timer_if_irqmasked(&s->pt);
     return 0;
 }
 
diff -r d2a32e24fe50 xen/arch/x86/hvm/vpt.c
--- a/xen/arch/x86/hvm/vpt.c    Wed Sep 09 16:39:41 2009 +0100
+++ b/xen/arch/x86/hvm/vpt.c    Thu Sep 10 09:55:29 2009 +0900
@@ -211,6 +211,10 @@ static void pt_timer_fn(void *data)
         pt_process_missed_ticks(pt);
         set_timer(&pt->timer, pt->scheduled);
     }
+    else
+    {
+        pt->frozen_by_irqmask = 0;
+    }
 
     if ( !pt_irq_masked(pt) )
         vcpu_kick(pt->vcpu);
@@ -394,6 +398,7 @@ void create_periodic_time(
 
     pt->on_list = 1;
     list_add(&pt->list, &v->arch.hvm_vcpu.tm_list);
+    pt->frozen_by_irqmask = 0;
 
     init_timer(&pt->timer, pt_timer_fn, pt, v->processor);
     set_timer(&pt->timer, pt->scheduled);
@@ -411,6 +416,7 @@ void destroy_periodic_time(struct period
     if ( pt->on_list )
         list_del(&pt->list);
     pt->on_list = 0;
+    pt->frozen_by_irqmask = 0;
     pt_unlock(pt);
 
     /*
@@ -469,3 +475,75 @@ 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_freeze_timer(struct periodic_time *pt)
+{
+    struct vcpu *v = NULL;
+
+    pt_lock(pt);
+    if ( pt->on_list )
+    {
+        v = pt->vcpu;
+        pt->frozen_by_irqmask = 1;
+        pt->on_list = 0;
+        list_del(&pt->list);
+        stop_timer(&pt->timer);
+    }
+    pt_unlock(pt);
+
+    if ( v )
+        gdprintk(XENLOG_INFO, "vcpu%d freeze %s timer(irq=%d)\n", v->vcpu_id,
+                 pt->source == PTSRC_lapic ? "LAPIC" : "ISA", pt->irq);
+}
+
+static void pt_thaw_timer(struct periodic_time *pt)
+{
+    struct vcpu *v = NULL;
+
+    pt_lock(pt);
+    if ( !pt->on_list && pt->frozen_by_irqmask )
+    {
+        v = pt->vcpu;
+        pt->on_list = 1;
+        list_add(&pt->list, &v->arch.hvm_vcpu.tm_list);
+        migrate_timer(&pt->timer, v->processor);
+        /*
+         * It may set the past time, however, TIMER_SOFTIRQ is raised
+         * and pt_timer_fn() will reset the timer appropriately.
+         */
+        set_timer(&pt->timer, pt->scheduled);
+    }
+    pt->frozen_by_irqmask = 0;
+    pt_unlock(pt);
+
+    if ( v )
+        gdprintk(XENLOG_INFO, "vcpu%d thaw %s timer(irq=%d)\n", v->vcpu_id,
+                 pt->source == PTSRC_lapic ? "LAPIC" : "ISA", pt->irq);
+}
+
+void pt_freeze_pit_timer_if_irqmasked(struct domain *d)
+{
+    struct periodic_time *pt = &d->arch.hvm_domain.pl_time.vpit.pt0;
+    unsigned int gsi = hvm_isa_irq_to_gsi(pt->irq);
+
+    if ( pt->vcpu == NULL )
+        return;
+
+    if ( !vlapic_accept_pic_intr(pt->vcpu) &&
+         domain_vioapic(d)->redirtbl[gsi].fields.mask )
+        pt_freeze_timer(pt);
+    else
+        pt_thaw_timer(pt);
+}
+
+void pt_freeze_lapic_timer_if_irqmasked(struct periodic_time *pt)
+{
+    if ( pt->vcpu == NULL )
+        return;
+
+    if (vlapic_get_reg(vcpu_vlapic(pt->vcpu), APIC_LVTT) & APIC_LVT_MASKED)
+        pt_freeze_timer(pt);
+    else
+        pt_thaw_timer(pt);
+}
diff -r d2a32e24fe50 xen/include/asm-x86/hvm/vpt.h
--- a/xen/include/asm-x86/hvm/vpt.h     Wed Sep 09 16:39:41 2009 +0100
+++ b/xen/include/asm-x86/hvm/vpt.h     Thu Sep 10 09:55:29 2009 +0900
@@ -44,6 +44,7 @@ struct periodic_time {
     bool_t do_not_freeze;
     bool_t irq_issued;
     bool_t warned_timeout_too_short;
+    bool_t frozen_by_irqmask;
 #define PTSRC_isa    1 /* ISA time source */
 #define PTSRC_lapic  2 /* LAPIC time source */
     u8 source;                  /* PTSRC_ */
@@ -145,7 +146,10 @@ void pt_adjust_global_vcpu_target(struct
     ((d)->arch.hvm_domain.i8259_target ? : (d)->vcpu ? (d)->vcpu[0] : NULL)
 
 /* Is given periodic timer active? */
-#define pt_active(pt) ((pt)->on_list)
+#define pt_active(pt) ((pt)->on_list || (pt)->frozen_by_irqmask)
+
+void pt_freeze_pit_timer_if_irqmasked(struct domain *d);
+void pt_freeze_lapic_timer_if_irqmasked(struct periodic_time *pt);
 
 /*
  * Create/destroy a periodic (or one-shot!) timer.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel