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

[Xen-devel] [PATCH] x86 hvm: freeze PIT/LAPIC timer emulation while its IRQ is masked



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

 


Rackspace

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