diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 52 |
1 files changed, 39 insertions, 13 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 3855103f71fd..08e8a899e005 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -352,25 +352,46 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) | |||
352 | 352 | ||
353 | static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) | 353 | static inline void apic_clear_irr(int vec, struct kvm_lapic *apic) |
354 | { | 354 | { |
355 | apic->irr_pending = false; | 355 | struct kvm_vcpu *vcpu; |
356 | |||
357 | vcpu = apic->vcpu; | ||
358 | |||
356 | apic_clear_vector(vec, apic->regs + APIC_IRR); | 359 | apic_clear_vector(vec, apic->regs + APIC_IRR); |
357 | if (apic_search_irr(apic) != -1) | 360 | if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) |
358 | apic->irr_pending = true; | 361 | /* try to update RVI */ |
362 | kvm_make_request(KVM_REQ_EVENT, vcpu); | ||
363 | else { | ||
364 | vec = apic_search_irr(apic); | ||
365 | apic->irr_pending = (vec != -1); | ||
366 | } | ||
359 | } | 367 | } |
360 | 368 | ||
361 | static inline void apic_set_isr(int vec, struct kvm_lapic *apic) | 369 | static inline void apic_set_isr(int vec, struct kvm_lapic *apic) |
362 | { | 370 | { |
363 | /* Note that we never get here with APIC virtualization enabled. */ | 371 | struct kvm_vcpu *vcpu; |
372 | |||
373 | if (__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) | ||
374 | return; | ||
375 | |||
376 | vcpu = apic->vcpu; | ||
364 | 377 | ||
365 | if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR)) | ||
366 | ++apic->isr_count; | ||
367 | BUG_ON(apic->isr_count > MAX_APIC_VECTOR); | ||
368 | /* | 378 | /* |
369 | * ISR (in service register) bit is set when injecting an interrupt. | 379 | * With APIC virtualization enabled, all caching is disabled |
370 | * The highest vector is injected. Thus the latest bit set matches | 380 | * because the processor can modify ISR under the hood. Instead |
371 | * the highest bit in ISR. | 381 | * just set SVI. |
372 | */ | 382 | */ |
373 | apic->highest_isr_cache = vec; | 383 | if (unlikely(kvm_apic_vid_enabled(vcpu->kvm))) |
384 | kvm_x86_ops->hwapic_isr_update(vcpu->kvm, vec); | ||
385 | else { | ||
386 | ++apic->isr_count; | ||
387 | BUG_ON(apic->isr_count > MAX_APIC_VECTOR); | ||
388 | /* | ||
389 | * ISR (in service register) bit is set when injecting an interrupt. | ||
390 | * The highest vector is injected. Thus the latest bit set matches | ||
391 | * the highest bit in ISR. | ||
392 | */ | ||
393 | apic->highest_isr_cache = vec; | ||
394 | } | ||
374 | } | 395 | } |
375 | 396 | ||
376 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) | 397 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) |
@@ -1627,11 +1648,16 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) | |||
1627 | int vector = kvm_apic_has_interrupt(vcpu); | 1648 | int vector = kvm_apic_has_interrupt(vcpu); |
1628 | struct kvm_lapic *apic = vcpu->arch.apic; | 1649 | struct kvm_lapic *apic = vcpu->arch.apic; |
1629 | 1650 | ||
1630 | /* Note that we never get here with APIC virtualization enabled. */ | ||
1631 | |||
1632 | if (vector == -1) | 1651 | if (vector == -1) |
1633 | return -1; | 1652 | return -1; |
1634 | 1653 | ||
1654 | /* | ||
1655 | * We get here even with APIC virtualization enabled, if doing | ||
1656 | * nested virtualization and L1 runs with the "acknowledge interrupt | ||
1657 | * on exit" mode. Then we cannot inject the interrupt via RVI, | ||
1658 | * because the process would deliver it through the IDT. | ||
1659 | */ | ||
1660 | |||
1635 | apic_set_isr(vector, apic); | 1661 | apic_set_isr(vector, apic); |
1636 | apic_update_ppr(apic); | 1662 | apic_update_ppr(apic); |
1637 | apic_clear_irr(vector, apic); | 1663 | apic_clear_irr(vector, apic); |