aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/lapic.c
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/kvm/lapic.c
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/kvm/lapic.c')
-rw-r--r--drivers/kvm/lapic.c58
1 files changed, 38 insertions, 20 deletions
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);