aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/kvm/lapic.c
diff options
context:
space:
mode:
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);