aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/kvm/irq.c13
-rw-r--r--drivers/kvm/irq.h4
-rw-r--r--drivers/kvm/kvm_main.c2
-rw-r--r--drivers/kvm/lapic.c58
-rw-r--r--drivers/kvm/svm.c7
-rw-r--r--drivers/kvm/vmx.c10
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
81void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
82{
83 kvm_inject_apic_timer_irqs(vcpu);
84 /* TODO: PIT, RTC etc. */
85}
86EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
87
88void 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}
93EXPORT_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);
154void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); 154void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
155int kvm_lapic_enabled(struct kvm_vcpu *vcpu); 155int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
156int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); 156int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
157void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
158void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
159void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
160void 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);
283void kvm_vcpu_uninit(struct kvm_vcpu *vcpu) 283void 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 */
834static int __apic_timer_fn(struct kvm_lapic *apic) 838static 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
855static 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
866static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) 863static 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
935void 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
946void 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
938int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu) 956int 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
1363static void kvm_reput_irq(struct vcpu_svm *svm) 1366static 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