diff options
Diffstat (limited to 'arch/x86/kvm/lapic.c')
-rw-r--r-- | arch/x86/kvm/lapic.c | 141 |
1 files changed, 67 insertions, 74 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index a8e9369f41c5..e29883c604ff 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -94,6 +94,14 @@ static inline int apic_test_vector(int vec, void *bitmap) | |||
94 | return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | 94 | return test_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); |
95 | } | 95 | } |
96 | 96 | ||
97 | bool kvm_apic_pending_eoi(struct kvm_vcpu *vcpu, int vector) | ||
98 | { | ||
99 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
100 | |||
101 | return apic_test_vector(vector, apic->regs + APIC_ISR) || | ||
102 | apic_test_vector(vector, apic->regs + APIC_IRR); | ||
103 | } | ||
104 | |||
97 | static inline void apic_set_vector(int vec, void *bitmap) | 105 | static inline void apic_set_vector(int vec, void *bitmap) |
98 | { | 106 | { |
99 | set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); | 107 | set_bit(VEC_POS(vec), (bitmap) + REG_POS(vec)); |
@@ -145,53 +153,6 @@ static inline int kvm_apic_id(struct kvm_lapic *apic) | |||
145 | return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; | 153 | return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff; |
146 | } | 154 | } |
147 | 155 | ||
148 | void kvm_calculate_eoi_exitmap(struct kvm_vcpu *vcpu, | ||
149 | struct kvm_lapic_irq *irq, | ||
150 | u64 *eoi_exit_bitmap) | ||
151 | { | ||
152 | struct kvm_lapic **dst; | ||
153 | struct kvm_apic_map *map; | ||
154 | unsigned long bitmap = 1; | ||
155 | int i; | ||
156 | |||
157 | rcu_read_lock(); | ||
158 | map = rcu_dereference(vcpu->kvm->arch.apic_map); | ||
159 | |||
160 | if (unlikely(!map)) { | ||
161 | __set_bit(irq->vector, (unsigned long *)eoi_exit_bitmap); | ||
162 | goto out; | ||
163 | } | ||
164 | |||
165 | if (irq->dest_mode == 0) { /* physical mode */ | ||
166 | if (irq->delivery_mode == APIC_DM_LOWEST || | ||
167 | irq->dest_id == 0xff) { | ||
168 | __set_bit(irq->vector, | ||
169 | (unsigned long *)eoi_exit_bitmap); | ||
170 | goto out; | ||
171 | } | ||
172 | dst = &map->phys_map[irq->dest_id & 0xff]; | ||
173 | } else { | ||
174 | u32 mda = irq->dest_id << (32 - map->ldr_bits); | ||
175 | |||
176 | dst = map->logical_map[apic_cluster_id(map, mda)]; | ||
177 | |||
178 | bitmap = apic_logical_id(map, mda); | ||
179 | } | ||
180 | |||
181 | for_each_set_bit(i, &bitmap, 16) { | ||
182 | if (!dst[i]) | ||
183 | continue; | ||
184 | if (dst[i]->vcpu == vcpu) { | ||
185 | __set_bit(irq->vector, | ||
186 | (unsigned long *)eoi_exit_bitmap); | ||
187 | break; | ||
188 | } | ||
189 | } | ||
190 | |||
191 | out: | ||
192 | rcu_read_unlock(); | ||
193 | } | ||
194 | |||
195 | static void recalculate_apic_map(struct kvm *kvm) | 156 | static void recalculate_apic_map(struct kvm *kvm) |
196 | { | 157 | { |
197 | struct kvm_apic_map *new, *old = NULL; | 158 | struct kvm_apic_map *new, *old = NULL; |
@@ -256,7 +217,7 @@ out: | |||
256 | if (old) | 217 | if (old) |
257 | kfree_rcu(old, rcu); | 218 | kfree_rcu(old, rcu); |
258 | 219 | ||
259 | kvm_ioapic_make_eoibitmap_request(kvm); | 220 | kvm_vcpu_request_scan_ioapic(kvm); |
260 | } | 221 | } |
261 | 222 | ||
262 | static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id) | 223 | static inline void kvm_apic_set_id(struct kvm_lapic *apic, u8 id) |
@@ -357,6 +318,19 @@ static u8 count_vectors(void *bitmap) | |||
357 | return count; | 318 | return count; |
358 | } | 319 | } |
359 | 320 | ||
321 | void kvm_apic_update_irr(struct kvm_vcpu *vcpu, u32 *pir) | ||
322 | { | ||
323 | u32 i, pir_val; | ||
324 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
325 | |||
326 | for (i = 0; i <= 7; i++) { | ||
327 | pir_val = xchg(&pir[i], 0); | ||
328 | if (pir_val) | ||
329 | *((u32 *)(apic->regs + APIC_IRR + i * 0x10)) |= pir_val; | ||
330 | } | ||
331 | } | ||
332 | EXPORT_SYMBOL_GPL(kvm_apic_update_irr); | ||
333 | |||
360 | static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) | 334 | static inline int apic_test_and_set_irr(int vec, struct kvm_lapic *apic) |
361 | { | 335 | { |
362 | apic->irr_pending = true; | 336 | apic->irr_pending = true; |
@@ -379,6 +353,7 @@ static inline int apic_find_highest_irr(struct kvm_lapic *apic) | |||
379 | if (!apic->irr_pending) | 353 | if (!apic->irr_pending) |
380 | return -1; | 354 | return -1; |
381 | 355 | ||
356 | kvm_x86_ops->sync_pir_to_irr(apic->vcpu); | ||
382 | result = apic_search_irr(apic); | 357 | result = apic_search_irr(apic); |
383 | ASSERT(result == -1 || result >= 16); | 358 | ASSERT(result == -1 || result >= 16); |
384 | 359 | ||
@@ -431,14 +406,16 @@ int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu) | |||
431 | } | 406 | } |
432 | 407 | ||
433 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | 408 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, |
434 | int vector, int level, int trig_mode); | 409 | int vector, int level, int trig_mode, |
410 | unsigned long *dest_map); | ||
435 | 411 | ||
436 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq) | 412 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq, |
413 | unsigned long *dest_map) | ||
437 | { | 414 | { |
438 | struct kvm_lapic *apic = vcpu->arch.apic; | 415 | struct kvm_lapic *apic = vcpu->arch.apic; |
439 | 416 | ||
440 | return __apic_accept_irq(apic, irq->delivery_mode, irq->vector, | 417 | return __apic_accept_irq(apic, irq->delivery_mode, irq->vector, |
441 | irq->level, irq->trig_mode); | 418 | irq->level, irq->trig_mode, dest_map); |
442 | } | 419 | } |
443 | 420 | ||
444 | static int pv_eoi_put_user(struct kvm_vcpu *vcpu, u8 val) | 421 | static int pv_eoi_put_user(struct kvm_vcpu *vcpu, u8 val) |
@@ -505,6 +482,15 @@ static inline int apic_find_highest_isr(struct kvm_lapic *apic) | |||
505 | return result; | 482 | return result; |
506 | } | 483 | } |
507 | 484 | ||
485 | void kvm_apic_update_tmr(struct kvm_vcpu *vcpu, u32 *tmr) | ||
486 | { | ||
487 | struct kvm_lapic *apic = vcpu->arch.apic; | ||
488 | int i; | ||
489 | |||
490 | for (i = 0; i < 8; i++) | ||
491 | apic_set_reg(apic, APIC_TMR + 0x10 * i, tmr[i]); | ||
492 | } | ||
493 | |||
508 | static void apic_update_ppr(struct kvm_lapic *apic) | 494 | static void apic_update_ppr(struct kvm_lapic *apic) |
509 | { | 495 | { |
510 | u32 tpr, isrv, ppr, old_ppr; | 496 | u32 tpr, isrv, ppr, old_ppr; |
@@ -611,7 +597,7 @@ int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | |||
611 | } | 597 | } |
612 | 598 | ||
613 | bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, | 599 | bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, |
614 | struct kvm_lapic_irq *irq, int *r) | 600 | struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map) |
615 | { | 601 | { |
616 | struct kvm_apic_map *map; | 602 | struct kvm_apic_map *map; |
617 | unsigned long bitmap = 1; | 603 | unsigned long bitmap = 1; |
@@ -622,7 +608,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, | |||
622 | *r = -1; | 608 | *r = -1; |
623 | 609 | ||
624 | if (irq->shorthand == APIC_DEST_SELF) { | 610 | if (irq->shorthand == APIC_DEST_SELF) { |
625 | *r = kvm_apic_set_irq(src->vcpu, irq); | 611 | *r = kvm_apic_set_irq(src->vcpu, irq, dest_map); |
626 | return true; | 612 | return true; |
627 | } | 613 | } |
628 | 614 | ||
@@ -667,7 +653,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src, | |||
667 | continue; | 653 | continue; |
668 | if (*r < 0) | 654 | if (*r < 0) |
669 | *r = 0; | 655 | *r = 0; |
670 | *r += kvm_apic_set_irq(dst[i]->vcpu, irq); | 656 | *r += kvm_apic_set_irq(dst[i]->vcpu, irq, dest_map); |
671 | } | 657 | } |
672 | 658 | ||
673 | ret = true; | 659 | ret = true; |
@@ -681,7 +667,8 @@ out: | |||
681 | * Return 1 if successfully added and 0 if discarded. | 667 | * Return 1 if successfully added and 0 if discarded. |
682 | */ | 668 | */ |
683 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | 669 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, |
684 | int vector, int level, int trig_mode) | 670 | int vector, int level, int trig_mode, |
671 | unsigned long *dest_map) | ||
685 | { | 672 | { |
686 | int result = 0; | 673 | int result = 0; |
687 | struct kvm_vcpu *vcpu = apic->vcpu; | 674 | struct kvm_vcpu *vcpu = apic->vcpu; |
@@ -694,24 +681,28 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | |||
694 | if (unlikely(!apic_enabled(apic))) | 681 | if (unlikely(!apic_enabled(apic))) |
695 | break; | 682 | break; |
696 | 683 | ||
697 | if (trig_mode) { | 684 | if (dest_map) |
698 | apic_debug("level trig mode for vector %d", vector); | 685 | __set_bit(vcpu->vcpu_id, dest_map); |
699 | apic_set_vector(vector, apic->regs + APIC_TMR); | ||
700 | } else | ||
701 | apic_clear_vector(vector, apic->regs + APIC_TMR); | ||
702 | 686 | ||
703 | result = !apic_test_and_set_irr(vector, apic); | 687 | if (kvm_x86_ops->deliver_posted_interrupt) { |
704 | trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode, | 688 | result = 1; |
705 | trig_mode, vector, !result); | 689 | kvm_x86_ops->deliver_posted_interrupt(vcpu, vector); |
706 | if (!result) { | 690 | } else { |
707 | if (trig_mode) | 691 | result = !apic_test_and_set_irr(vector, apic); |
708 | apic_debug("level trig mode repeatedly for " | ||
709 | "vector %d", vector); | ||
710 | break; | ||
711 | } | ||
712 | 692 | ||
713 | kvm_make_request(KVM_REQ_EVENT, vcpu); | 693 | if (!result) { |
714 | kvm_vcpu_kick(vcpu); | 694 | if (trig_mode) |
695 | apic_debug("level trig mode repeatedly " | ||
696 | "for vector %d", vector); | ||
697 | goto out; | ||
698 | } | ||
699 | |||
700 | kvm_make_request(KVM_REQ_EVENT, vcpu); | ||
701 | kvm_vcpu_kick(vcpu); | ||
702 | } | ||
703 | out: | ||
704 | trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode, | ||
705 | trig_mode, vector, !result); | ||
715 | break; | 706 | break; |
716 | 707 | ||
717 | case APIC_DM_REMRD: | 708 | case APIC_DM_REMRD: |
@@ -786,7 +777,7 @@ static void kvm_ioapic_send_eoi(struct kvm_lapic *apic, int vector) | |||
786 | trigger_mode = IOAPIC_LEVEL_TRIG; | 777 | trigger_mode = IOAPIC_LEVEL_TRIG; |
787 | else | 778 | else |
788 | trigger_mode = IOAPIC_EDGE_TRIG; | 779 | trigger_mode = IOAPIC_EDGE_TRIG; |
789 | kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode); | 780 | kvm_ioapic_update_eoi(apic->vcpu, vector, trigger_mode); |
790 | } | 781 | } |
791 | } | 782 | } |
792 | 783 | ||
@@ -852,7 +843,7 @@ static void apic_send_ipi(struct kvm_lapic *apic) | |||
852 | irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, | 843 | irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, |
853 | irq.vector); | 844 | irq.vector); |
854 | 845 | ||
855 | kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); | 846 | kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq, NULL); |
856 | } | 847 | } |
857 | 848 | ||
858 | static u32 apic_get_tmcct(struct kvm_lapic *apic) | 849 | static u32 apic_get_tmcct(struct kvm_lapic *apic) |
@@ -1488,7 +1479,8 @@ int kvm_apic_local_deliver(struct kvm_lapic *apic, int lvt_type) | |||
1488 | vector = reg & APIC_VECTOR_MASK; | 1479 | vector = reg & APIC_VECTOR_MASK; |
1489 | mode = reg & APIC_MODE_MASK; | 1480 | mode = reg & APIC_MODE_MASK; |
1490 | trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; | 1481 | trig_mode = reg & APIC_LVT_LEVEL_TRIGGER; |
1491 | return __apic_accept_irq(apic, mode, vector, 1, trig_mode); | 1482 | return __apic_accept_irq(apic, mode, vector, 1, trig_mode, |
1483 | NULL); | ||
1492 | } | 1484 | } |
1493 | return 0; | 1485 | return 0; |
1494 | } | 1486 | } |
@@ -1658,6 +1650,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu, | |||
1658 | apic->highest_isr_cache = -1; | 1650 | apic->highest_isr_cache = -1; |
1659 | kvm_x86_ops->hwapic_isr_update(vcpu->kvm, apic_find_highest_isr(apic)); | 1651 | kvm_x86_ops->hwapic_isr_update(vcpu->kvm, apic_find_highest_isr(apic)); |
1660 | kvm_make_request(KVM_REQ_EVENT, vcpu); | 1652 | kvm_make_request(KVM_REQ_EVENT, vcpu); |
1653 | kvm_rtc_eoi_tracking_restore_one(vcpu); | ||
1661 | } | 1654 | } |
1662 | 1655 | ||
1663 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) | 1656 | void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) |