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

Commit 33e4c686 authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity
Browse files

KVM: Optimize searching for highest IRR



Most of the time IRR is empty, so instead of scanning the whole IRR on
each VM entry keep a variable that tells us if IRR is not empty. IRR
will have to be scanned twice on each IRQ delivery, but this is much
more rare than VM entry.

Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 6edf14d8
Loading
Loading
Loading
Loading
+21 −3
Original line number Original line Diff line number Diff line
@@ -165,29 +165,46 @@ static int find_highest_vector(void *bitmap)


static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic)
{
{
	apic->irr_pending = true;
	return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
	return apic_test_and_set_vector(vec, apic->regs + APIC_IRR);
}
}


static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
static inline int apic_search_irr(struct kvm_lapic *apic)
{
{
	apic_clear_vector(vec, apic->regs + APIC_IRR);
	return find_highest_vector(apic->regs + APIC_IRR);
}
}


static inline int apic_find_highest_irr(struct kvm_lapic *apic)
static inline int apic_find_highest_irr(struct kvm_lapic *apic)
{
{
	int result;
	int result;


	result = find_highest_vector(apic->regs + APIC_IRR);
	if (!apic->irr_pending)
		return -1;

	result = apic_search_irr(apic);
	ASSERT(result == -1 || result >= 16);
	ASSERT(result == -1 || result >= 16);


	return result;
	return result;
}
}


static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
{
	apic->irr_pending = false;
	apic_clear_vector(vec, apic->regs + APIC_IRR);
	if (apic_search_irr(apic) != -1)
		apic->irr_pending = true;
}

int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
{
{
	struct kvm_lapic *apic = vcpu->arch.apic;
	struct kvm_lapic *apic = vcpu->arch.apic;
	int highest_irr;
	int highest_irr;


	/* This may race with setting of irr in __apic_accept_irq() and
	 * value returned may be wrong, but kvm_vcpu_kick() in __apic_accept_irq
	 * will cause vmexit immediately and the value will be recalculated
	 * on the next vmentry.
	 */
	if (!apic)
	if (!apic)
		return 0;
		return 0;
	highest_irr = apic_find_highest_irr(apic);
	highest_irr = apic_find_highest_irr(apic);
@@ -843,6 +860,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
		apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
		apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
		apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
		apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
	}
	}
	apic->irr_pending = false;
	update_divide_count(apic);
	update_divide_count(apic);
	atomic_set(&apic->lapic_timer.pending, 0);
	atomic_set(&apic->lapic_timer.pending, 0);
	if (kvm_vcpu_is_bsp(vcpu))
	if (kvm_vcpu_is_bsp(vcpu))
+1 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@ struct kvm_lapic {
	struct kvm_timer lapic_timer;
	struct kvm_timer lapic_timer;
	u32 divide_count;
	u32 divide_count;
	struct kvm_vcpu *vcpu;
	struct kvm_vcpu *vcpu;
	bool irr_pending;
	struct page *regs_page;
	struct page *regs_page;
	void *regs;
	void *regs;
	gpa_t vapic_addr;
	gpa_t vapic_addr;