aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGleb Natapov <gleb@redhat.com>2009-03-05 09:34:54 -0500
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:27 -0400
commit343f94fe4d16ec898da77720c03da9e09f8523d2 (patch)
treefa0180a8446a90000086593b9fa8d4d81708ddd8
parenta53c17d21c46a752f5ac6695376481bc27865b04 (diff)
KVM: consolidate ioapic/ipi interrupt delivery logic
Use kvm_apic_match_dest() in kvm_get_intr_delivery_bitmask() instead of duplicating the same code. Use kvm_get_intr_delivery_bitmask() in apic_send_ipi() to figure out ipi destination instead of reimplementing the logic. Signed-off-by: Gleb Natapov <gleb@redhat.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--arch/ia64/kvm/kvm-ia64.c8
-rw-r--r--arch/ia64/kvm/lapic.h3
-rw-r--r--arch/x86/kvm/lapic.c69
-rw-r--r--arch/x86/kvm/lapic.h2
-rw-r--r--include/linux/kvm_host.h5
-rw-r--r--virt/kvm/ioapic.c5
-rw-r--r--virt/kvm/ioapic.h10
-rw-r--r--virt/kvm/irq_comm.c74
8 files changed, 70 insertions, 106 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 99d6d174d932..8eea9cba7b7c 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -1852,6 +1852,14 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
1852 return lvcpu; 1852 return lvcpu;
1853} 1853}
1854 1854
1855int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
1856 int short_hand, int dest, int dest_mode)
1857{
1858 return (dest_mode == 0) ?
1859 kvm_apic_match_physical_addr(target, dest) :
1860 kvm_apic_match_logical_addr(target, dest);
1861}
1862
1855static int find_highest_bits(int *dat) 1863static int find_highest_bits(int *dat)
1856{ 1864{
1857 u32 bits, bitnum; 1865 u32 bits, bitnum;
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
index cbcfaa6195c7..31602e7338d7 100644
--- a/arch/ia64/kvm/lapic.h
+++ b/arch/ia64/kvm/lapic.h
@@ -20,6 +20,9 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu);
20 20
21int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); 21int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
22int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); 22int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
23int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
24 int short_hand, int dest, int dest_mode);
25bool kvm_apic_present(struct kvm_vcpu *vcpu);
23int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig); 26int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig);
24 27
25#endif 28#endif
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index a42f968a23e1..998862a3c267 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -260,7 +260,7 @@ static void apic_set_tpr(struct kvm_lapic *apic, u32 tpr)
260 260
261int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) 261int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest)
262{ 262{
263 return kvm_apic_id(apic) == dest; 263 return dest == 0xff || kvm_apic_id(apic) == dest;
264} 264}
265 265
266int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda) 266int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
@@ -289,37 +289,34 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda)
289 return result; 289 return result;
290} 290}
291 291
292static int apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, 292int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
293 int short_hand, int dest, int dest_mode) 293 int short_hand, int dest, int dest_mode)
294{ 294{
295 int result = 0; 295 int result = 0;
296 struct kvm_lapic *target = vcpu->arch.apic; 296 struct kvm_lapic *target = vcpu->arch.apic;
297 297
298 apic_debug("target %p, source %p, dest 0x%x, " 298 apic_debug("target %p, source %p, dest 0x%x, "
299 "dest_mode 0x%x, short_hand 0x%x", 299 "dest_mode 0x%x, short_hand 0x%x\n",
300 target, source, dest, dest_mode, short_hand); 300 target, source, dest, dest_mode, short_hand);
301 301
302 ASSERT(!target); 302 ASSERT(!target);
303 switch (short_hand) { 303 switch (short_hand) {
304 case APIC_DEST_NOSHORT: 304 case APIC_DEST_NOSHORT:
305 if (dest_mode == 0) { 305 if (dest_mode == 0)
306 /* Physical mode. */ 306 /* Physical mode. */
307 if ((dest == 0xFF) || (dest == kvm_apic_id(target))) 307 result = kvm_apic_match_physical_addr(target, dest);
308 result = 1; 308 else
309 } else
310 /* Logical mode. */ 309 /* Logical mode. */
311 result = kvm_apic_match_logical_addr(target, dest); 310 result = kvm_apic_match_logical_addr(target, dest);
312 break; 311 break;
313 case APIC_DEST_SELF: 312 case APIC_DEST_SELF:
314 if (target == source) 313 result = (target == source);
315 result = 1;
316 break; 314 break;
317 case APIC_DEST_ALLINC: 315 case APIC_DEST_ALLINC:
318 result = 1; 316 result = 1;
319 break; 317 break;
320 case APIC_DEST_ALLBUT: 318 case APIC_DEST_ALLBUT:
321 if (target != source) 319 result = (target != source);
322 result = 1;
323 break; 320 break;
324 default: 321 default:
325 printk(KERN_WARNING "Bad dest shorthand value %x\n", 322 printk(KERN_WARNING "Bad dest shorthand value %x\n",
@@ -492,38 +489,26 @@ static void apic_send_ipi(struct kvm_lapic *apic)
492 unsigned int delivery_mode = icr_low & APIC_MODE_MASK; 489 unsigned int delivery_mode = icr_low & APIC_MODE_MASK;
493 unsigned int vector = icr_low & APIC_VECTOR_MASK; 490 unsigned int vector = icr_low & APIC_VECTOR_MASK;
494 491
495 struct kvm_vcpu *target; 492 DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
496 struct kvm_vcpu *vcpu;
497 DECLARE_BITMAP(lpr_map, KVM_MAX_VCPUS);
498 int i; 493 int i;
499 494
500 bitmap_zero(lpr_map, KVM_MAX_VCPUS);
501 apic_debug("icr_high 0x%x, icr_low 0x%x, " 495 apic_debug("icr_high 0x%x, icr_low 0x%x, "
502 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " 496 "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
503 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", 497 "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
504 icr_high, icr_low, short_hand, dest, 498 icr_high, icr_low, short_hand, dest,
505 trig_mode, level, dest_mode, delivery_mode, vector); 499 trig_mode, level, dest_mode, delivery_mode, vector);
506 500
507 for (i = 0; i < KVM_MAX_VCPUS; i++) { 501 kvm_get_intr_delivery_bitmask(apic->vcpu->kvm, apic, dest, dest_mode,
508 vcpu = apic->vcpu->kvm->vcpus[i]; 502 delivery_mode == APIC_DM_LOWEST, short_hand,
509 if (!vcpu) 503 deliver_bitmask);
510 continue; 504
511 505 while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS))
512 if (vcpu->arch.apic && 506 < KVM_MAX_VCPUS) {
513 apic_match_dest(vcpu, apic, short_hand, dest, dest_mode)) { 507 struct kvm_vcpu *vcpu = apic->vcpu->kvm->vcpus[i];
514 if (delivery_mode == APIC_DM_LOWEST) 508 __clear_bit(i, deliver_bitmask);
515 __set_bit(vcpu->vcpu_id, lpr_map); 509 if (vcpu)
516 else 510 __apic_accept_irq(vcpu->arch.apic, delivery_mode,
517 __apic_accept_irq(vcpu->arch.apic, delivery_mode, 511 vector, level, trig_mode);
518 vector, level, trig_mode);
519 }
520 }
521
522 if (delivery_mode == APIC_DM_LOWEST) {
523 target = kvm_get_lowest_prio_vcpu(vcpu->kvm, vector, lpr_map);
524 if (target != NULL)
525 __apic_accept_irq(target->arch.apic, delivery_mode,
526 vector, level, trig_mode);
527 } 512 }
528} 513}
529 514
@@ -930,16 +915,14 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu)
930} 915}
931EXPORT_SYMBOL_GPL(kvm_lapic_reset); 916EXPORT_SYMBOL_GPL(kvm_lapic_reset);
932 917
933int kvm_lapic_enabled(struct kvm_vcpu *vcpu) 918bool kvm_apic_present(struct kvm_vcpu *vcpu)
934{ 919{
935 struct kvm_lapic *apic = vcpu->arch.apic; 920 return vcpu->arch.apic && apic_hw_enabled(vcpu->arch.apic);
936 int ret = 0; 921}
937
938 if (!apic)
939 return 0;
940 ret = apic_enabled(apic);
941 922
942 return ret; 923int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
924{
925 return kvm_apic_present(vcpu) && apic_sw_enabled(vcpu->arch.apic);
943} 926}
944EXPORT_SYMBOL_GPL(kvm_lapic_enabled); 927EXPORT_SYMBOL_GPL(kvm_lapic_enabled);
945 928
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 1b0e3c03cb34..b66dc14a9698 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -37,6 +37,8 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
37void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); 37void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
38void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); 38void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
39int kvm_lapic_enabled(struct kvm_vcpu *vcpu); 39int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
40bool kvm_apic_present(struct kvm_vcpu *vcpu);
41bool kvm_lapic_present(struct kvm_vcpu *vcpu);
40int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); 42int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
41 43
42void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); 44void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ec9d078b1e8e..fb60f31c4fb3 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -363,11 +363,6 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
363 struct kvm_irq_mask_notifier *kimn); 363 struct kvm_irq_mask_notifier *kimn);
364void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask); 364void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
365 365
366#ifdef __KVM_HAVE_IOAPIC
367void kvm_get_intr_delivery_bitmask(struct kvm *kvm,
368 union kvm_ioapic_redirect_entry *entry,
369 unsigned long *deliver_bitmask);
370#endif
371int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level); 366int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
372void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin); 367void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
373void kvm_register_irq_ack_notifier(struct kvm *kvm, 368void kvm_register_irq_ack_notifier(struct kvm *kvm,
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index b71c0442cecf..43969bbf127f 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -147,7 +147,10 @@ int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e)
147 DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS); 147 DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS);
148 int i, r = -1; 148 int i, r = -1;
149 149
150 kvm_get_intr_delivery_bitmask(kvm, e, deliver_bitmask); 150 kvm_get_intr_delivery_bitmask(kvm, NULL, e->fields.dest_id,
151 e->fields.dest_mode,
152 e->fields.delivery_mode == IOAPIC_LOWEST_PRIORITY,
153 0, deliver_bitmask);
151 154
152 if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) { 155 if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) {
153 ioapic_debug("no target on destination\n"); 156 ioapic_debug("no target on destination\n");
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index bedeea59cc1c..d996c7abc466 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -65,13 +65,15 @@ static inline struct kvm_ioapic *ioapic_irqchip(struct kvm *kvm)
65} 65}
66 66
67struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, 67struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
68 unsigned long *bitmap); 68 unsigned long *bitmap);
69int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source,
70 int short_hand, int dest, int dest_mode);
69void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode); 71void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
70int kvm_ioapic_init(struct kvm *kvm); 72int kvm_ioapic_init(struct kvm *kvm);
71int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); 73int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
72void kvm_ioapic_reset(struct kvm_ioapic *ioapic); 74void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
73void kvm_get_intr_delivery_bitmask(struct kvm *kvm, 75void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
74 union kvm_ioapic_redirect_entry *entry, 76 int dest_id, int dest_mode, bool low_prio, int short_hand,
75 unsigned long *deliver_bitmask); 77 unsigned long *deliver_bitmask);
76int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e); 78int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e);
77#endif 79#endif
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 35397a569b24..e43701c0a5c4 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -43,67 +43,35 @@ static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
43 return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); 43 return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
44} 44}
45 45
46void kvm_get_intr_delivery_bitmask(struct kvm *kvm, 46void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src,
47 union kvm_ioapic_redirect_entry *entry, 47 int dest_id, int dest_mode, bool low_prio, int short_hand,
48 unsigned long *deliver_bitmask) 48 unsigned long *deliver_bitmask)
49{ 49{
50 int i; 50 int i;
51 struct kvm_vcpu *vcpu; 51 struct kvm_vcpu *vcpu;
52 52
53 if (dest_mode == 0 && dest_id == 0xff && low_prio)
54 printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n");
55
53 bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS); 56 bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
57 for (i = 0; i < KVM_MAX_VCPUS; i++) {
58 vcpu = kvm->vcpus[i];
54 59
55 if (entry->fields.dest_mode == 0) { /* Physical mode. */ 60 if (!vcpu || !kvm_apic_present(vcpu))
56 if (entry->fields.dest_id == 0xFF) { /* Broadcast. */ 61 continue;
57 for (i = 0; i < KVM_MAX_VCPUS; ++i)
58 if (kvm->vcpus[i] && kvm->vcpus[i]->arch.apic)
59 __set_bit(i, deliver_bitmask);
60 /* Lowest priority shouldn't combine with broadcast */
61 if (entry->fields.delivery_mode ==
62 IOAPIC_LOWEST_PRIORITY && printk_ratelimit())
63 printk(KERN_INFO "kvm: apic: phys broadcast "
64 "and lowest prio\n");
65 return;
66 }
67 for (i = 0; i < KVM_MAX_VCPUS; ++i) {
68 vcpu = kvm->vcpus[i];
69 if (!vcpu)
70 continue;
71 if (kvm_apic_match_physical_addr(vcpu->arch.apic,
72 entry->fields.dest_id)) {
73 if (vcpu->arch.apic)
74 __set_bit(i, deliver_bitmask);
75 break;
76 }
77 }
78 } else if (entry->fields.dest_id != 0) /* Logical mode, MDA non-zero. */
79 for (i = 0; i < KVM_MAX_VCPUS; ++i) {
80 vcpu = kvm->vcpus[i];
81 if (!vcpu)
82 continue;
83 if (vcpu->arch.apic &&
84 kvm_apic_match_logical_addr(vcpu->arch.apic,
85 entry->fields.dest_id))
86 __set_bit(i, deliver_bitmask);
87 }
88 62
89 switch (entry->fields.delivery_mode) { 63 if (!kvm_apic_match_dest(vcpu, src, short_hand, dest_id,
90 case IOAPIC_LOWEST_PRIORITY: 64 dest_mode))
91 /* Select one in deliver_bitmask */ 65 continue;
92 vcpu = kvm_get_lowest_prio_vcpu(kvm, 66
93 entry->fields.vector, deliver_bitmask); 67 __set_bit(i, deliver_bitmask);
94 bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS); 68 }
95 if (!vcpu) 69
96 return; 70 if (low_prio) {
97 __set_bit(vcpu->vcpu_id, deliver_bitmask); 71 vcpu = kvm_get_lowest_prio_vcpu(kvm, 0, deliver_bitmask);
98 break;
99 case IOAPIC_FIXED:
100 case IOAPIC_NMI:
101 break;
102 default:
103 if (printk_ratelimit())
104 printk(KERN_INFO "kvm: unsupported delivery mode %d\n",
105 entry->fields.delivery_mode);
106 bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS); 72 bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS);
73 if (vcpu)
74 __set_bit(vcpu->vcpu_id, deliver_bitmask);
107 } 75 }
108} 76}
109 77