diff options
Diffstat (limited to 'drivers/kvm/lapic.c')
-rw-r--r-- | drivers/kvm/lapic.c | 58 |
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 */ | ||
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); |