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
|