|
@@ -360,6 +360,8 @@ static inline void apic_clear_irr(int vec, struct kvm_lapic *apic)
|
|
|
|
|
|
static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
|
|
|
{
|
|
|
+ /* Note that we never get here with APIC virtualization enabled. */
|
|
|
+
|
|
|
if (!__apic_test_and_set_vector(vec, apic->regs + APIC_ISR))
|
|
|
++apic->isr_count;
|
|
|
BUG_ON(apic->isr_count > MAX_APIC_VECTOR);
|
|
@@ -371,12 +373,48 @@ static inline void apic_set_isr(int vec, struct kvm_lapic *apic)
|
|
|
apic->highest_isr_cache = vec;
|
|
|
}
|
|
|
|
|
|
+static inline int apic_find_highest_isr(struct kvm_lapic *apic)
|
|
|
+{
|
|
|
+ int result;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Note that isr_count is always 1, and highest_isr_cache
|
|
|
+ * is always -1, with APIC virtualization enabled.
|
|
|
+ */
|
|
|
+ if (!apic->isr_count)
|
|
|
+ return -1;
|
|
|
+ if (likely(apic->highest_isr_cache != -1))
|
|
|
+ return apic->highest_isr_cache;
|
|
|
+
|
|
|
+ result = find_highest_vector(apic->regs + APIC_ISR);
|
|
|
+ ASSERT(result == -1 || result >= 16);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
static inline void apic_clear_isr(int vec, struct kvm_lapic *apic)
|
|
|
{
|
|
|
- if (__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
|
|
|
+ struct kvm_vcpu *vcpu;
|
|
|
+ if (!__apic_test_and_clear_vector(vec, apic->regs + APIC_ISR))
|
|
|
+ return;
|
|
|
+
|
|
|
+ vcpu = apic->vcpu;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We do get here for APIC virtualization enabled if the guest
|
|
|
+ * uses the Hyper-V APIC enlightenment. In this case we may need
|
|
|
+ * to trigger a new interrupt delivery by writing the SVI field;
|
|
|
+ * on the other hand isr_count and highest_isr_cache are unused
|
|
|
+ * and must be left alone.
|
|
|
+ */
|
|
|
+ if (unlikely(kvm_apic_vid_enabled(vcpu->kvm)))
|
|
|
+ kvm_x86_ops->hwapic_isr_update(vcpu->kvm,
|
|
|
+ apic_find_highest_isr(apic));
|
|
|
+ else {
|
|
|
--apic->isr_count;
|
|
|
- BUG_ON(apic->isr_count < 0);
|
|
|
- apic->highest_isr_cache = -1;
|
|
|
+ BUG_ON(apic->isr_count < 0);
|
|
|
+ apic->highest_isr_cache = -1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
|
|
@@ -456,22 +494,6 @@ static void pv_eoi_clr_pending(struct kvm_vcpu *vcpu)
|
|
|
__clear_bit(KVM_APIC_PV_EOI_PENDING, &vcpu->arch.apic_attention);
|
|
|
}
|
|
|
|
|
|
-static inline int apic_find_highest_isr(struct kvm_lapic *apic)
|
|
|
-{
|
|
|
- int result;
|
|
|
-
|
|
|
- /* Note that isr_count is always 1 with vid enabled */
|
|
|
- if (!apic->isr_count)
|
|
|
- return -1;
|
|
|
- if (likely(apic->highest_isr_cache != -1))
|
|
|
- return apic->highest_isr_cache;
|
|
|
-
|
|
|
- result = find_highest_vector(apic->regs + APIC_ISR);
|
|
|
- ASSERT(result == -1 || result >= 16);
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr)
|
|
|
{
|
|
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
|
@@ -1605,6 +1627,8 @@ int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
|
|
|
int vector = kvm_apic_has_interrupt(vcpu);
|
|
|
struct kvm_lapic *apic = vcpu->arch.apic;
|
|
|
|
|
|
+ /* Note that we never get here with APIC virtualization enabled. */
|
|
|
+
|
|
|
if (vector == -1)
|
|
|
return -1;
|
|
|
|