diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/kvm/irq.c | 13 | ||||
-rw-r--r-- | drivers/kvm/irq.h | 4 | ||||
-rw-r--r-- | drivers/kvm/kvm_main.c | 2 | ||||
-rw-r--r-- | drivers/kvm/lapic.c | 58 | ||||
-rw-r--r-- | drivers/kvm/svm.c | 7 | ||||
-rw-r--r-- | drivers/kvm/vmx.c | 10 |
6 files changed, 69 insertions, 25 deletions
diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c index e09cd65925d6..b88e50115588 100644 --- a/drivers/kvm/irq.c +++ b/drivers/kvm/irq.c | |||
@@ -78,3 +78,16 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | |||
78 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); | 78 | smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0, 0); |
79 | } | 79 | } |
80 | 80 | ||
81 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu) | ||
82 | { | ||
83 | kvm_inject_apic_timer_irqs(vcpu); | ||
84 | /* TODO: PIT, RTC etc. */ | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); | ||
87 | |||
88 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec) | ||
89 | { | ||
90 | kvm_apic_timer_intr_post(vcpu, vec); | ||
91 | /* TODO: PIT, RTC etc. */ | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(kvm_timer_intr_post); | ||
diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h index 07035e8279d4..87baf7e69ea2 100644 --- a/drivers/kvm/irq.h +++ b/drivers/kvm/irq.h | |||
@@ -154,5 +154,9 @@ int kvm_ioapic_init(struct kvm *kvm); | |||
154 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); | 154 | void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); |
155 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); | 155 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); |
156 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); | 156 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); |
157 | void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec); | ||
158 | void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec); | ||
159 | void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); | ||
160 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); | ||
157 | 161 | ||
158 | #endif | 162 | #endif |
diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index d56964a6eb80..8f8bfc9160e3 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c | |||
@@ -283,6 +283,8 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_init); | |||
283 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) | 283 | void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) |
284 | { | 284 | { |
285 | kvm_mmu_destroy(vcpu); | 285 | kvm_mmu_destroy(vcpu); |
286 | if (vcpu->apic) | ||
287 | hrtimer_cancel(&vcpu->apic->timer.dev); | ||
286 | kvm_free_apic(vcpu->apic); | 288 | kvm_free_apic(vcpu->apic); |
287 | free_page((unsigned long)vcpu->pio_data); | 289 | free_page((unsigned long)vcpu->pio_data); |
288 | free_page((unsigned long)vcpu->run); | 290 | free_page((unsigned long)vcpu->run); |
diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c index 68bbbb38edad..490d4939dba7 100644 --- a/drivers/kvm/lapic.c +++ b/drivers/kvm/lapic.c | |||
@@ -313,6 +313,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
313 | int vector, int level, int trig_mode) | 313 | int vector, int level, int trig_mode) |
314 | { | 314 | { |
315 | int result = 0; | 315 | int result = 0; |
316 | int orig_irr; | ||
316 | 317 | ||
317 | switch (delivery_mode) { | 318 | switch (delivery_mode) { |
318 | case APIC_DM_FIXED: | 319 | case APIC_DM_FIXED: |
@@ -321,7 +322,8 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
321 | if (unlikely(!apic_enabled(apic))) | 322 | if (unlikely(!apic_enabled(apic))) |
322 | break; | 323 | break; |
323 | 324 | ||
324 | if (apic_test_and_set_irr(vector, apic) && trig_mode) { | 325 | orig_irr = apic_test_and_set_irr(vector, apic); |
326 | if (orig_irr && trig_mode) { | ||
325 | apic_debug("level trig mode repeatedly for vector %d", | 327 | apic_debug("level trig mode repeatedly for vector %d", |
326 | vector); | 328 | vector); |
327 | break; | 329 | break; |
@@ -335,7 +337,7 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
335 | 337 | ||
336 | kvm_vcpu_kick(apic->vcpu); | 338 | kvm_vcpu_kick(apic->vcpu); |
337 | 339 | ||
338 | result = 1; | 340 | result = (orig_irr == 0); |
339 | break; | 341 | break; |
340 | 342 | ||
341 | case APIC_DM_REMRD: | 343 | case APIC_DM_REMRD: |
@@ -831,38 +833,33 @@ EXPORT_SYMBOL_GPL(kvm_lapic_enabled); | |||
831 | * timer interface | 833 | * timer interface |
832 | *---------------------------------------------------------------------- | 834 | *---------------------------------------------------------------------- |
833 | */ | 835 | */ |
836 | |||
837 | /* TODO: make sure __apic_timer_fn runs in current pCPU */ | ||
834 | static int __apic_timer_fn(struct kvm_lapic *apic) | 838 | static int __apic_timer_fn(struct kvm_lapic *apic) |
835 | { | 839 | { |
836 | u32 vector; | ||
837 | int result = 0; | 840 | int result = 0; |
841 | wait_queue_head_t *q = &apic->vcpu->wq; | ||
838 | 842 | ||
839 | if (unlikely(!apic_enabled(apic) || | ||
840 | !apic_lvt_enabled(apic, APIC_LVTT))) { | ||
841 | apic_debug("%s: time interrupt although apic is down\n", | ||
842 | __FUNCTION__); | ||
843 | return 0; | ||
844 | } | ||
845 | |||
846 | vector = apic_lvt_vector(apic, APIC_LVTT); | ||
847 | apic->timer.last_update = apic->timer.dev.expires; | ||
848 | atomic_inc(&apic->timer.pending); | 843 | atomic_inc(&apic->timer.pending); |
849 | __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); | 844 | if (waitqueue_active(q)) |
850 | 845 | wake_up_interruptible(q); | |
851 | if (apic_lvtt_period(apic)) { | 846 | if (apic_lvtt_period(apic)) { |
852 | u32 offset; | ||
853 | u32 tmict = apic_get_reg(apic, APIC_TMICT); | ||
854 | |||
855 | offset = APIC_BUS_CYCLE_NS * apic->timer.divide_count * tmict; | ||
856 | |||
857 | result = 1; | 847 | result = 1; |
858 | apic->timer.dev.expires = ktime_add_ns( | 848 | apic->timer.dev.expires = ktime_add_ns( |
859 | apic->timer.dev.expires, | 849 | apic->timer.dev.expires, |
860 | apic->timer.period); | 850 | apic->timer.period); |
861 | } | 851 | } |
862 | |||
863 | return result; | 852 | return result; |
864 | } | 853 | } |
865 | 854 | ||
855 | static int __inject_apic_timer_irq(struct kvm_lapic *apic) | ||
856 | { | ||
857 | int vector; | ||
858 | |||
859 | vector = apic_lvt_vector(apic, APIC_LVTT); | ||
860 | return __apic_accept_irq(apic, APIC_DM_FIXED, vector, 1, 0); | ||
861 | } | ||
862 | |||
866 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) | 863 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) |
867 | { | 864 | { |
868 | struct kvm_lapic *apic; | 865 | struct kvm_lapic *apic; |
@@ -935,6 +932,27 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) | |||
935 | return highest_irr; | 932 | return highest_irr; |
936 | } | 933 | } |
937 | 934 | ||
935 | void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) | ||
936 | { | ||
937 | struct kvm_lapic *apic = vcpu->apic; | ||
938 | |||
939 | if (apic && apic_lvt_enabled(apic, APIC_LVTT) && | ||
940 | atomic_read(&apic->timer.pending) > 0) { | ||
941 | if (__inject_apic_timer_irq(apic)) | ||
942 | atomic_dec(&apic->timer.pending); | ||
943 | } | ||
944 | } | ||
945 | |||
946 | void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec) | ||
947 | { | ||
948 | struct kvm_lapic *apic = vcpu->apic; | ||
949 | |||
950 | if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec) | ||
951 | apic->timer.last_update = ktime_add_ns( | ||
952 | apic->timer.last_update, | ||
953 | apic->timer.period); | ||
954 | } | ||
955 | |||
938 | int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) | 956 | int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) |
939 | { | 957 | { |
940 | int vector = kvm_apic_has_interrupt(vcpu); | 958 | int vector = kvm_apic_has_interrupt(vcpu); |
diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index c8cd242f36ff..00119ec41669 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c | |||
@@ -1331,7 +1331,9 @@ static void svm_intr_assist(struct vcpu_svm *svm) | |||
1331 | { | 1331 | { |
1332 | struct vmcb *vmcb = svm->vmcb; | 1332 | struct vmcb *vmcb = svm->vmcb; |
1333 | int intr_vector = -1; | 1333 | int intr_vector = -1; |
1334 | struct kvm_vcpu *vcpu = &svm->vcpu; | ||
1334 | 1335 | ||
1336 | kvm_inject_pending_timer_irqs(vcpu); | ||
1335 | if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && | 1337 | if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && |
1336 | ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { | 1338 | ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { |
1337 | intr_vector = vmcb->control.exit_int_info & | 1339 | intr_vector = vmcb->control.exit_int_info & |
@@ -1344,7 +1346,7 @@ static void svm_intr_assist(struct vcpu_svm *svm) | |||
1344 | if (vmcb->control.int_ctl & V_IRQ_MASK) | 1346 | if (vmcb->control.int_ctl & V_IRQ_MASK) |
1345 | return; | 1347 | return; |
1346 | 1348 | ||
1347 | if (!kvm_cpu_has_interrupt(&svm->vcpu)) | 1349 | if (!kvm_cpu_has_interrupt(vcpu)) |
1348 | return; | 1350 | return; |
1349 | 1351 | ||
1350 | if (!(vmcb->save.rflags & X86_EFLAGS_IF) || | 1352 | if (!(vmcb->save.rflags & X86_EFLAGS_IF) || |
@@ -1356,8 +1358,9 @@ static void svm_intr_assist(struct vcpu_svm *svm) | |||
1356 | return; | 1358 | return; |
1357 | } | 1359 | } |
1358 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ | 1360 | /* Okay, we can deliver the interrupt: grab it and update PIC state. */ |
1359 | intr_vector = kvm_cpu_get_interrupt(&svm->vcpu); | 1361 | intr_vector = kvm_cpu_get_interrupt(vcpu); |
1360 | svm_inject_irq(svm, intr_vector); | 1362 | svm_inject_irq(svm, intr_vector); |
1363 | kvm_timer_intr_post(vcpu, intr_vector); | ||
1361 | } | 1364 | } |
1362 | 1365 | ||
1363 | static void kvm_reput_irq(struct vcpu_svm *svm) | 1366 | static void kvm_reput_irq(struct vcpu_svm *svm) |
diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index 5c2c6e71abf2..eeecadf5da46 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c | |||
@@ -2151,7 +2151,9 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) | |||
2151 | { | 2151 | { |
2152 | u32 idtv_info_field, intr_info_field; | 2152 | u32 idtv_info_field, intr_info_field; |
2153 | int has_ext_irq, interrupt_window_open; | 2153 | int has_ext_irq, interrupt_window_open; |
2154 | int vector; | ||
2154 | 2155 | ||
2156 | kvm_inject_pending_timer_irqs(vcpu); | ||
2155 | update_tpr_threshold(vcpu); | 2157 | update_tpr_threshold(vcpu); |
2156 | 2158 | ||
2157 | has_ext_irq = kvm_cpu_has_interrupt(vcpu); | 2159 | has_ext_irq = kvm_cpu_has_interrupt(vcpu); |
@@ -2183,9 +2185,11 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) | |||
2183 | interrupt_window_open = | 2185 | interrupt_window_open = |
2184 | ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && | 2186 | ((vmcs_readl(GUEST_RFLAGS) & X86_EFLAGS_IF) && |
2185 | (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); | 2187 | (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & 3) == 0); |
2186 | if (interrupt_window_open) | 2188 | if (interrupt_window_open) { |
2187 | vmx_inject_irq(vcpu, kvm_cpu_get_interrupt(vcpu)); | 2189 | vector = kvm_cpu_get_interrupt(vcpu); |
2188 | else | 2190 | vmx_inject_irq(vcpu, vector); |
2191 | kvm_timer_intr_post(vcpu, vector); | ||
2192 | } else | ||
2189 | enable_irq_window(vcpu); | 2193 | enable_irq_window(vcpu); |
2190 | } | 2194 | } |
2191 | 2195 | ||