diff options
author | Gleb Natapov <gleb@redhat.com> | 2009-03-05 09:35:04 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:27 -0400 |
commit | 58c2dde17d6eb6c8c0566e52d184aa16755d890f (patch) | |
tree | a968731cbce73932decd63e00be313cebfd2f57f | |
parent | e1035715ef8d3171e29f9c6aee6f40d57b3fead5 (diff) |
KVM: APIC: get rid of deliver_bitmask
Deliver interrupt during destination matching loop.
Signed-off-by: Gleb Natapov <gleb@redhat.com>
Acked-by: Xiantao Zhang <xiantao.zhang@intel.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | arch/ia64/kvm/kvm-ia64.c | 33 | ||||
-rw-r--r-- | arch/ia64/kvm/lapic.h | 4 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 59 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 3 | ||||
-rw-r--r-- | include/linux/kvm_types.h | 10 | ||||
-rw-r--r-- | virt/kvm/ioapic.c | 57 | ||||
-rw-r--r-- | virt/kvm/ioapic.h | 6 | ||||
-rw-r--r-- | virt/kvm/irq_comm.c | 71 |
8 files changed, 108 insertions, 135 deletions
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index 1887a93a2bd5..acf43ec42704 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -283,6 +283,18 @@ static int handle_sal_call(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) | |||
283 | 283 | ||
284 | } | 284 | } |
285 | 285 | ||
286 | static int __apic_accept_irq(struct kvm_vcpu *vcpu, uint64_t vector) | ||
287 | { | ||
288 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
289 | |||
290 | if (!test_and_set_bit(vector, &vpd->irr[0])) { | ||
291 | vcpu->arch.irq_new_pending = 1; | ||
292 | kvm_vcpu_kick(vcpu); | ||
293 | return 1; | ||
294 | } | ||
295 | return 0; | ||
296 | } | ||
297 | |||
286 | /* | 298 | /* |
287 | * offset: address offset to IPI space. | 299 | * offset: address offset to IPI space. |
288 | * value: deliver value. | 300 | * value: deliver value. |
@@ -292,20 +304,20 @@ static void vcpu_deliver_ipi(struct kvm_vcpu *vcpu, uint64_t dm, | |||
292 | { | 304 | { |
293 | switch (dm) { | 305 | switch (dm) { |
294 | case SAPIC_FIXED: | 306 | case SAPIC_FIXED: |
295 | kvm_apic_set_irq(vcpu, vector, dm, 0); | ||
296 | break; | 307 | break; |
297 | case SAPIC_NMI: | 308 | case SAPIC_NMI: |
298 | kvm_apic_set_irq(vcpu, 2, dm, 0); | 309 | vector = 2; |
299 | break; | 310 | break; |
300 | case SAPIC_EXTINT: | 311 | case SAPIC_EXTINT: |
301 | kvm_apic_set_irq(vcpu, 0, dm, 0); | 312 | vector = 0; |
302 | break; | 313 | break; |
303 | case SAPIC_INIT: | 314 | case SAPIC_INIT: |
304 | case SAPIC_PMI: | 315 | case SAPIC_PMI: |
305 | default: | 316 | default: |
306 | printk(KERN_ERR"kvm: Unimplemented Deliver reserved IPI!\n"); | 317 | printk(KERN_ERR"kvm: Unimplemented Deliver reserved IPI!\n"); |
307 | break; | 318 | return; |
308 | } | 319 | } |
320 | __apic_accept_irq(vcpu, vector); | ||
309 | } | 321 | } |
310 | 322 | ||
311 | static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id, | 323 | static struct kvm_vcpu *lid_to_vcpu(struct kvm *kvm, unsigned long id, |
@@ -1813,17 +1825,9 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu) | |||
1813 | put_cpu(); | 1825 | put_cpu(); |
1814 | } | 1826 | } |
1815 | 1827 | ||
1816 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig) | 1828 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq) |
1817 | { | 1829 | { |
1818 | 1830 | return __apic_accept_irq(vcpu, irq->vector); | |
1819 | struct vpd *vpd = to_host(vcpu->kvm, vcpu->arch.vpd); | ||
1820 | |||
1821 | if (!test_and_set_bit(vec, &vpd->irr[0])) { | ||
1822 | vcpu->arch.irq_new_pending = 1; | ||
1823 | kvm_vcpu_kick(vcpu); | ||
1824 | return 1; | ||
1825 | } | ||
1826 | return 0; | ||
1827 | } | 1831 | } |
1828 | 1832 | ||
1829 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) | 1833 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest) |
@@ -1844,6 +1848,7 @@ int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2) | |||
1844 | int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | 1848 | int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, |
1845 | int short_hand, int dest, int dest_mode) | 1849 | int short_hand, int dest, int dest_mode) |
1846 | { | 1850 | { |
1851 | struct kvm_lapic *target = vcpu->arch.apic; | ||
1847 | return (dest_mode == 0) ? | 1852 | return (dest_mode == 0) ? |
1848 | kvm_apic_match_physical_addr(target, dest) : | 1853 | kvm_apic_match_physical_addr(target, dest) : |
1849 | kvm_apic_match_logical_addr(target, dest); | 1854 | kvm_apic_match_logical_addr(target, dest); |
diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h index e42109e6ca47..ee541cebcd78 100644 --- a/arch/ia64/kvm/lapic.h +++ b/arch/ia64/kvm/lapic.h | |||
@@ -23,7 +23,7 @@ int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); | |||
23 | int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, | 23 | int kvm_apic_match_dest(struct kvm_vcpu *vcpu, struct kvm_lapic *source, |
24 | int short_hand, int dest, int dest_mode); | 24 | int short_hand, int dest, int dest_mode); |
25 | int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); | 25 | int kvm_apic_compare_prio(struct kvm_vcpu *vcpu1, struct kvm_vcpu *vcpu2); |
26 | bool kvm_apic_present(struct kvm_vcpu *vcpu); | 26 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); |
27 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig); | 27 | #define kvm_apic_present(x) (true) |
28 | 28 | ||
29 | #endif | 29 | #endif |
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 814466f455d9..dd934d27040f 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -199,27 +199,12 @@ EXPORT_SYMBOL_GPL(kvm_lapic_find_highest_irr); | |||
199 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, | 199 | static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, |
200 | int vector, int level, int trig_mode); | 200 | int vector, int level, int trig_mode); |
201 | 201 | ||
202 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig) | 202 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq) |
203 | { | 203 | { |
204 | struct kvm_lapic *apic = vcpu->arch.apic; | 204 | struct kvm_lapic *apic = vcpu->arch.apic; |
205 | int lapic_dmode; | ||
206 | 205 | ||
207 | switch (dmode) { | 206 | return __apic_accept_irq(apic, irq->delivery_mode, irq->vector, |
208 | case IOAPIC_LOWEST_PRIORITY: | 207 | irq->level, irq->trig_mode); |
209 | lapic_dmode = APIC_DM_LOWEST; | ||
210 | break; | ||
211 | case IOAPIC_FIXED: | ||
212 | lapic_dmode = APIC_DM_FIXED; | ||
213 | break; | ||
214 | case IOAPIC_NMI: | ||
215 | lapic_dmode = APIC_DM_NMI; | ||
216 | break; | ||
217 | default: | ||
218 | printk(KERN_DEBUG"Ignoring delivery mode %d\n", dmode); | ||
219 | return 0; | ||
220 | break; | ||
221 | } | ||
222 | return __apic_accept_irq(apic, lapic_dmode, vec, 1, trig); | ||
223 | } | 208 | } |
224 | 209 | ||
225 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) | 210 | static inline int apic_find_highest_isr(struct kvm_lapic *apic) |
@@ -447,36 +432,24 @@ static void apic_send_ipi(struct kvm_lapic *apic) | |||
447 | { | 432 | { |
448 | u32 icr_low = apic_get_reg(apic, APIC_ICR); | 433 | u32 icr_low = apic_get_reg(apic, APIC_ICR); |
449 | u32 icr_high = apic_get_reg(apic, APIC_ICR2); | 434 | u32 icr_high = apic_get_reg(apic, APIC_ICR2); |
435 | struct kvm_lapic_irq irq; | ||
450 | 436 | ||
451 | unsigned int dest = GET_APIC_DEST_FIELD(icr_high); | 437 | irq.vector = icr_low & APIC_VECTOR_MASK; |
452 | unsigned int short_hand = icr_low & APIC_SHORT_MASK; | 438 | irq.delivery_mode = icr_low & APIC_MODE_MASK; |
453 | unsigned int trig_mode = icr_low & APIC_INT_LEVELTRIG; | 439 | irq.dest_mode = icr_low & APIC_DEST_MASK; |
454 | unsigned int level = icr_low & APIC_INT_ASSERT; | 440 | irq.level = icr_low & APIC_INT_ASSERT; |
455 | unsigned int dest_mode = icr_low & APIC_DEST_MASK; | 441 | irq.trig_mode = icr_low & APIC_INT_LEVELTRIG; |
456 | unsigned int delivery_mode = icr_low & APIC_MODE_MASK; | 442 | irq.shorthand = icr_low & APIC_SHORT_MASK; |
457 | unsigned int vector = icr_low & APIC_VECTOR_MASK; | 443 | irq.dest_id = GET_APIC_DEST_FIELD(icr_high); |
458 | |||
459 | DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS); | ||
460 | int i; | ||
461 | 444 | ||
462 | apic_debug("icr_high 0x%x, icr_low 0x%x, " | 445 | apic_debug("icr_high 0x%x, icr_low 0x%x, " |
463 | "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " | 446 | "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, " |
464 | "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", | 447 | "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n", |
465 | icr_high, icr_low, short_hand, dest, | 448 | icr_high, icr_low, irq.shorthand, irq.dest, |
466 | trig_mode, level, dest_mode, delivery_mode, vector); | 449 | irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode, |
467 | 450 | irq.vector); | |
468 | kvm_get_intr_delivery_bitmask(apic->vcpu->kvm, apic, dest, dest_mode, | 451 | |
469 | delivery_mode == APIC_DM_LOWEST, short_hand, | 452 | kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq); |
470 | deliver_bitmask); | ||
471 | |||
472 | while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS)) | ||
473 | < KVM_MAX_VCPUS) { | ||
474 | struct kvm_vcpu *vcpu = apic->vcpu->kvm->vcpus[i]; | ||
475 | __clear_bit(i, deliver_bitmask); | ||
476 | if (vcpu) | ||
477 | __apic_accept_irq(vcpu->arch.apic, delivery_mode, | ||
478 | vector, level, trig_mode); | ||
479 | } | ||
480 | } | 453 | } |
481 | 454 | ||
482 | static u32 apic_get_tmcct(struct kvm_lapic *apic) | 455 | static u32 apic_get_tmcct(struct kvm_lapic *apic) |
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index b66dc14a9698..a587f8349c46 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -31,14 +31,13 @@ u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu); | |||
31 | 31 | ||
32 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); | 32 | int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest); |
33 | int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); | 33 | int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda); |
34 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 dmode, u8 trig); | 34 | int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct kvm_lapic_irq *irq); |
35 | 35 | ||
36 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); | 36 | u64 kvm_get_apic_base(struct kvm_vcpu *vcpu); |
37 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); | 37 | void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data); |
38 | void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); | 38 | void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu); |
39 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); | 39 | int kvm_lapic_enabled(struct kvm_vcpu *vcpu); |
40 | bool kvm_apic_present(struct kvm_vcpu *vcpu); | 40 | bool kvm_apic_present(struct kvm_vcpu *vcpu); |
41 | bool kvm_lapic_present(struct kvm_vcpu *vcpu); | ||
42 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); | 41 | int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu); |
43 | 42 | ||
44 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); | 43 | void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr); |
diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h index b84aca3c4ad1..fb46efbeabec 100644 --- a/include/linux/kvm_types.h +++ b/include/linux/kvm_types.h | |||
@@ -57,4 +57,14 @@ union kvm_ioapic_redirect_entry { | |||
57 | } fields; | 57 | } fields; |
58 | }; | 58 | }; |
59 | 59 | ||
60 | struct kvm_lapic_irq { | ||
61 | u32 vector; | ||
62 | u32 delivery_mode; | ||
63 | u32 dest_mode; | ||
64 | u32 level; | ||
65 | u32 trig_mode; | ||
66 | u32 shorthand; | ||
67 | u32 dest_id; | ||
68 | }; | ||
69 | |||
60 | #endif /* __KVM_TYPES_H__ */ | 70 | #endif /* __KVM_TYPES_H__ */ |
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 43969bbf127f..1eddae94bab3 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -142,58 +142,33 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) | |||
142 | } | 142 | } |
143 | } | 143 | } |
144 | 144 | ||
145 | int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e) | ||
146 | { | ||
147 | DECLARE_BITMAP(deliver_bitmask, KVM_MAX_VCPUS); | ||
148 | int i, r = -1; | ||
149 | |||
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); | ||
154 | |||
155 | if (find_first_bit(deliver_bitmask, KVM_MAX_VCPUS) >= KVM_MAX_VCPUS) { | ||
156 | ioapic_debug("no target on destination\n"); | ||
157 | return r; | ||
158 | } | ||
159 | |||
160 | while ((i = find_first_bit(deliver_bitmask, KVM_MAX_VCPUS)) | ||
161 | < KVM_MAX_VCPUS) { | ||
162 | struct kvm_vcpu *vcpu = kvm->vcpus[i]; | ||
163 | __clear_bit(i, deliver_bitmask); | ||
164 | if (vcpu) { | ||
165 | if (r < 0) | ||
166 | r = 0; | ||
167 | r += kvm_apic_set_irq(vcpu, e->fields.vector, | ||
168 | e->fields.delivery_mode, | ||
169 | e->fields.trig_mode); | ||
170 | } else | ||
171 | ioapic_debug("null destination vcpu: " | ||
172 | "mask=%x vector=%x delivery_mode=%x\n", | ||
173 | e->fields.deliver_bitmask, | ||
174 | e->fields.vector, e->fields.delivery_mode); | ||
175 | } | ||
176 | return r; | ||
177 | } | ||
178 | |||
179 | static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) | 145 | static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) |
180 | { | 146 | { |
181 | union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq]; | 147 | union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq]; |
148 | struct kvm_lapic_irq irqe; | ||
182 | 149 | ||
183 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " | 150 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " |
184 | "vector=%x trig_mode=%x\n", | 151 | "vector=%x trig_mode=%x\n", |
185 | entry.fields.dest, entry.fields.dest_mode, | 152 | entry->fields.dest, entry->fields.dest_mode, |
186 | entry.fields.delivery_mode, entry.fields.vector, | 153 | entry->fields.delivery_mode, entry->fields.vector, |
187 | entry.fields.trig_mode); | 154 | entry->fields.trig_mode); |
155 | |||
156 | irqe.dest_id = entry->fields.dest_id; | ||
157 | irqe.vector = entry->fields.vector; | ||
158 | irqe.dest_mode = entry->fields.dest_mode; | ||
159 | irqe.trig_mode = entry->fields.trig_mode; | ||
160 | irqe.delivery_mode = entry->fields.delivery_mode << 8; | ||
161 | irqe.level = 1; | ||
162 | irqe.shorthand = 0; | ||
188 | 163 | ||
189 | #ifdef CONFIG_X86 | 164 | #ifdef CONFIG_X86 |
190 | /* Always delivery PIT interrupt to vcpu 0 */ | 165 | /* Always delivery PIT interrupt to vcpu 0 */ |
191 | if (irq == 0) { | 166 | if (irq == 0) { |
192 | entry.fields.dest_mode = 0; /* Physical mode. */ | 167 | irqe.dest_mode = 0; /* Physical mode. */ |
193 | entry.fields.dest_id = ioapic->kvm->vcpus[0]->vcpu_id; | 168 | irqe.dest_id = ioapic->kvm->vcpus[0]->vcpu_id; |
194 | } | 169 | } |
195 | #endif | 170 | #endif |
196 | return ioapic_deliver_entry(ioapic->kvm, &entry); | 171 | return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe); |
197 | } | 172 | } |
198 | 173 | ||
199 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) | 174 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) |
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h index e7bc92d895ff..7080b713c160 100644 --- a/virt/kvm/ioapic.h +++ b/virt/kvm/ioapic.h | |||
@@ -71,8 +71,6 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode); | |||
71 | int kvm_ioapic_init(struct kvm *kvm); | 71 | int kvm_ioapic_init(struct kvm *kvm); |
72 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); | 72 | int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level); |
73 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic); | 73 | void kvm_ioapic_reset(struct kvm_ioapic *ioapic); |
74 | void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src, | 74 | int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, |
75 | int dest_id, int dest_mode, bool low_prio, int short_hand, | 75 | struct kvm_lapic_irq *irq); |
76 | unsigned long *deliver_bitmask); | ||
77 | int ioapic_deliver_entry(struct kvm *kvm, union kvm_ioapic_redirect_entry *e); | ||
78 | #endif | 76 | #endif |
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index f5e059b67cd4..4fa1f604b425 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
@@ -22,6 +22,9 @@ | |||
22 | #include <linux/kvm_host.h> | 22 | #include <linux/kvm_host.h> |
23 | 23 | ||
24 | #include <asm/msidef.h> | 24 | #include <asm/msidef.h> |
25 | #ifdef CONFIG_IA64 | ||
26 | #include <asm/iosapic.h> | ||
27 | #endif | ||
25 | 28 | ||
26 | #include "irq.h" | 29 | #include "irq.h" |
27 | 30 | ||
@@ -43,61 +46,71 @@ 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); | 46 | return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level); |
44 | } | 47 | } |
45 | 48 | ||
46 | void kvm_get_intr_delivery_bitmask(struct kvm *kvm, struct kvm_lapic *src, | 49 | inline static bool kvm_is_dm_lowest_prio(struct kvm_lapic_irq *irq) |
47 | int dest_id, int dest_mode, bool low_prio, int short_hand, | ||
48 | unsigned long *deliver_bitmask) | ||
49 | { | 50 | { |
50 | int i, lowest = -1; | 51 | #ifdef CONFIG_IA64 |
51 | struct kvm_vcpu *vcpu; | 52 | return irq->delivery_mode == |
53 | (IOSAPIC_LOWEST_PRIORITY << IOSAPIC_DELIVERY_SHIFT); | ||
54 | #else | ||
55 | return irq->delivery_mode == APIC_DM_LOWEST; | ||
56 | #endif | ||
57 | } | ||
52 | 58 | ||
53 | if (dest_mode == 0 && dest_id == 0xff && low_prio) | 59 | int kvm_irq_delivery_to_apic(struct kvm *kvm, struct kvm_lapic *src, |
60 | struct kvm_lapic_irq *irq) | ||
61 | { | ||
62 | int i, r = -1; | ||
63 | struct kvm_vcpu *vcpu, *lowest = NULL; | ||
64 | |||
65 | if (irq->dest_mode == 0 && irq->dest_id == 0xff && | ||
66 | kvm_is_dm_lowest_prio(irq)) | ||
54 | printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); | 67 | printk(KERN_INFO "kvm: apic: phys broadcast and lowest prio\n"); |
55 | 68 | ||
56 | bitmap_zero(deliver_bitmask, KVM_MAX_VCPUS); | ||
57 | for (i = 0; i < KVM_MAX_VCPUS; i++) { | 69 | for (i = 0; i < KVM_MAX_VCPUS; i++) { |
58 | vcpu = kvm->vcpus[i]; | 70 | vcpu = kvm->vcpus[i]; |
59 | 71 | ||
60 | if (!vcpu || !kvm_apic_present(vcpu)) | 72 | if (!vcpu || !kvm_apic_present(vcpu)) |
61 | continue; | 73 | continue; |
62 | 74 | ||
63 | if (!kvm_apic_match_dest(vcpu, src, short_hand, dest_id, | 75 | if (!kvm_apic_match_dest(vcpu, src, irq->shorthand, |
64 | dest_mode)) | 76 | irq->dest_id, irq->dest_mode)) |
65 | continue; | 77 | continue; |
66 | 78 | ||
67 | if (!low_prio) { | 79 | if (!kvm_is_dm_lowest_prio(irq)) { |
68 | __set_bit(i, deliver_bitmask); | 80 | if (r < 0) |
81 | r = 0; | ||
82 | r += kvm_apic_set_irq(vcpu, irq); | ||
69 | } else { | 83 | } else { |
70 | if (lowest < 0) | 84 | if (!lowest) |
71 | lowest = i; | 85 | lowest = vcpu; |
72 | if (kvm_apic_compare_prio(vcpu, kvm->vcpus[lowest]) < 0) | 86 | else if (kvm_apic_compare_prio(vcpu, lowest) < 0) |
73 | lowest = i; | 87 | lowest = vcpu; |
74 | } | 88 | } |
75 | } | 89 | } |
76 | 90 | ||
77 | if (lowest != -1) | 91 | if (lowest) |
78 | __set_bit(lowest, deliver_bitmask); | 92 | r = kvm_apic_set_irq(lowest, irq); |
93 | |||
94 | return r; | ||
79 | } | 95 | } |
80 | 96 | ||
81 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | 97 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, |
82 | struct kvm *kvm, int level) | 98 | struct kvm *kvm, int level) |
83 | { | 99 | { |
84 | union kvm_ioapic_redirect_entry entry; | 100 | struct kvm_lapic_irq irq; |
85 | 101 | ||
86 | entry.bits = 0; | 102 | irq.dest_id = (e->msi.address_lo & |
87 | entry.fields.dest_id = (e->msi.address_lo & | ||
88 | MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; | 103 | MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; |
89 | entry.fields.vector = (e->msi.data & | 104 | irq.vector = (e->msi.data & |
90 | MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; | 105 | MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; |
91 | entry.fields.dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, | 106 | irq.dest_mode = (1 << MSI_ADDR_DEST_MODE_SHIFT) & e->msi.address_lo; |
92 | (unsigned long *)&e->msi.address_lo); | 107 | irq.trig_mode = (1 << MSI_DATA_TRIGGER_SHIFT) & e->msi.data; |
93 | entry.fields.trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, | 108 | irq.delivery_mode = e->msi.data & 0x700; |
94 | (unsigned long *)&e->msi.data); | 109 | irq.level = 1; |
95 | entry.fields.delivery_mode = test_bit( | 110 | irq.shorthand = 0; |
96 | MSI_DATA_DELIVERY_MODE_SHIFT, | ||
97 | (unsigned long *)&e->msi.data); | ||
98 | 111 | ||
99 | /* TODO Deal with RH bit of MSI message address */ | 112 | /* TODO Deal with RH bit of MSI message address */ |
100 | return ioapic_deliver_entry(kvm, &entry); | 113 | return kvm_irq_delivery_to_apic(kvm, NULL, &irq); |
101 | } | 114 | } |
102 | 115 | ||
103 | /* This should be called with the kvm->lock mutex held | 116 | /* This should be called with the kvm->lock mutex held |