Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 40487c68 authored by Qing He's avatar Qing He Committed by Avi Kivity
Browse files

KVM: deliver PIC interrupt only to vcpu0



This patch changes the PIC interrupts delivery. Now it is only delivered
to vcpu0 when either condition is met (on vcpu0):
  1. local APIC is hardware disabled
  2. LVT0 is unmasked and configured to delivery mode ExtInt

It fixes the 2x faster wall clock on x86_64 and SMP i386 Linux guests

Signed-off-by: default avatarEddie (Yaozu) Dong <eddie.dong@intel.com>
Signed-off-by: default avatarQing He <qing.he@intel.com>
Signed-off-by: default avatarAvi Kivity <avi@qumranet.com>
parent 5cd4f6fd
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -33,8 +33,11 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
	struct kvm_pic *s;

	if (kvm_apic_has_interrupt(v) == -1) {	/* LAPIC */
		if (kvm_apic_accept_pic_intr(v)) {
			s = pic_irqchip(v->kvm);	/* PIC */
			return s->output;
		} else
			return 0;
	}
	return 1;
}
@@ -50,10 +53,12 @@ int kvm_cpu_get_interrupt(struct kvm_vcpu *v)

	vector = kvm_get_apic_interrupt(v);	/* APIC */
	if (vector == -1) {
		if (kvm_apic_accept_pic_intr(v)) {
			s = pic_irqchip(v->kvm);
			s->output = 0;		/* PIC */
			vector = kvm_pic_read_irq(s);
		}
	}
	return vector;
}
EXPORT_SYMBOL_GPL(kvm_cpu_get_interrupt);
+1 −0
Original line number Diff line number Diff line
@@ -135,6 +135,7 @@ do { \

void kvm_vcpu_kick(struct kvm_vcpu *vcpu);
int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu);
int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu);
int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu);
int kvm_create_lapic(struct kvm_vcpu *vcpu);
void kvm_free_apic(struct kvm_lapic *apic);
+17 −0
Original line number Diff line number Diff line
@@ -788,6 +788,8 @@ static void lapic_reset(struct kvm_vcpu *vcpu)

	for (i = 0; i < APIC_LVT_NUM; i++)
		apic_set_reg(apic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
	apic_set_reg(apic, APIC_LVT0,
		     SET_APIC_DELIVERY_MODE(0, APIC_MODE_EXTINT));

	apic_set_reg(apic, APIC_DFR, 0xffffffffU);
	apic_set_reg(apic, APIC_SPIV, 0xff);
@@ -932,6 +934,21 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)
	return highest_irr;
}

int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu)
{
	u32 lvt0 = apic_get_reg(vcpu->apic, APIC_LVT0);
	int r = 0;

	if (vcpu->vcpu_id == 0) {
		if (!apic_hw_enabled(vcpu->apic))
			r = 1;
		if ((lvt0 & APIC_LVT_MASKED) == 0 &&
		    GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
			r = 1;
	}
	return r;
}

void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
{
	struct kvm_lapic *apic = vcpu->apic;