aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEddie Dong <eddie.dong@intel.com>2007-09-03 09:56:58 -0400
committerAvi Kivity <avi@qumranet.com>2007-10-13 04:18:26 -0400
commit1b9778dae71dc64d3678d766c0f1fbed79c80f9f (patch)
tree3196bbfe474119a849f35aefddb5e0922205850f /drivers
parent6e5d865c0b9679b00b5e5f0754c9fc2b6b9894d6 (diff)
KVM: Keep track of missed timer irq injections
APIC timer IRQ is set every time when a certain period expires at host time, but the guest may be descheduled at that time and thus the irq be overwritten by later fire. This patch keep track of firing irq numbers and decrease only when the IRQ is injected to guest or buffered in APIC. Signed-off-by: Yaozu (Eddie) Dong <Eddie.Dong@intel.com> Signed-off-by: Qing He <qing.he@intel.com> Signed-off-by: Avi Kivity <avi@qumranet.com>
Diffstat (limited to 'drivers')
-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