Skip to content

Commit a0c9a82

Browse files
mstsirkinmatosatti
authored andcommitted
KVM: dont clear TMR on EOI
Intel spec says that TMR needs to be set/cleared when IRR is set, but kvm also clears it on EOI. I did some tests on a real (AMD based) system, and I see same TMR values both before and after EOI, so I think it's a minor bug in kvm. This patch fixes TMR to be set/cleared on IRR set only as per spec. And now that we don't clear TMR, we can save an atomic read of TMR on EOI that's not propagated to ioapic, by checking whether ioapic needs a specific vector first and calculating the mode afterwards. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
1 parent e597175 commit a0c9a82

File tree

3 files changed

+21
-9
lines changed

3 files changed

+21
-9
lines changed

arch/x86/kvm/lapic.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ static inline int apic_test_and_clear_vector(int vec, void *bitmap)
9292
return test_and_clear_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
9393
}
9494

95+
static inline int apic_test_vector(int vec, void *bitmap)
96+
{
97+
return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
98+
}
99+
95100
static inline void apic_set_vector(int vec, void *bitmap)
96101
{
97102
set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec));
@@ -480,7 +485,6 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2)
480485
static void apic_set_eoi(struct kvm_lapic *apic)
481486
{
482487
int vector = apic_find_highest_isr(apic);
483-
int trigger_mode;
484488
/*
485489
* Not every write EOI will has corresponding ISR,
486490
* one example is when Kernel check timer on setup_IO_APIC
@@ -491,12 +495,15 @@ static void apic_set_eoi(struct kvm_lapic *apic)
491495
apic_clear_vector(vector, apic->regs + APIC_ISR);
492496
apic_update_ppr(apic);
493497

494-
if (apic_test_and_clear_vector(vector, apic->regs + APIC_TMR))
495-
trigger_mode = IOAPIC_LEVEL_TRIG;
496-
else
497-
trigger_mode = IOAPIC_EDGE_TRIG;
498-
if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
498+
if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI) &&
499+
kvm_ioapic_handles_vector(apic->vcpu->kvm, vector)) {
500+
int trigger_mode;
501+
if (apic_test_vector(vector, apic->regs + APIC_TMR))
502+
trigger_mode = IOAPIC_LEVEL_TRIG;
503+
else
504+
trigger_mode = IOAPIC_EDGE_TRIG;
499505
kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
506+
}
500507
kvm_make_request(KVM_REQ_EVENT, apic->vcpu);
501508
}
502509

virt/kvm/ioapic.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,17 @@ static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,
254254
}
255255
}
256256

257+
bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector)
258+
{
259+
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
260+
smp_rmb();
261+
return test_bit(vector, ioapic->handled_vectors);
262+
}
263+
257264
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)
258265
{
259266
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
260267

261-
smp_rmb();
262-
if (!test_bit(vector, ioapic->handled_vectors))
263-
return;
264268
spin_lock(&ioapic->lock);
265269
__kvm_ioapic_update_eoi(ioapic, vector, trigger_mode);
266270
spin_unlock(&ioapic->lock);

virt/kvm/ioapic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
7171
int short_hand, int dest, int dest_mode);
7272
int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2);
7373
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
74+
bool kvm_ioapic_handles_vector(struct kvm *kvm, int vector);
7475
int kvm_ioapic_init(struct kvm *kvm);
7576
void kvm_ioapic_destroy(struct kvm *kvm);
7677
int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);

0 commit comments

Comments
 (0)