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 | ||
