diff options
Diffstat (limited to 'virt')
-rw-r--r-- | virt/kvm/ioapic.c | 91 | ||||
-rw-r--r-- | virt/kvm/irq_comm.c | 95 |
2 files changed, 92 insertions, 94 deletions
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 812801317e36..883fd0dc9b78 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c | |||
@@ -203,79 +203,56 @@ u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, | |||
203 | 203 | ||
204 | static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) | 204 | static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) |
205 | { | 205 | { |
206 | u8 dest = ioapic->redirtbl[irq].fields.dest_id; | 206 | union kvm_ioapic_redirect_entry entry = ioapic->redirtbl[irq]; |
207 | u8 dest_mode = ioapic->redirtbl[irq].fields.dest_mode; | 207 | unsigned long deliver_bitmask; |
208 | u8 delivery_mode = ioapic->redirtbl[irq].fields.delivery_mode; | ||
209 | u8 vector = ioapic->redirtbl[irq].fields.vector; | ||
210 | u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; | ||
211 | u32 deliver_bitmask; | ||
212 | struct kvm_vcpu *vcpu; | 208 | struct kvm_vcpu *vcpu; |
213 | int vcpu_id, r = -1; | 209 | int vcpu_id, r = -1; |
214 | 210 | ||
215 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " | 211 | ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " |
216 | "vector=%x trig_mode=%x\n", | 212 | "vector=%x trig_mode=%x\n", |
217 | dest, dest_mode, delivery_mode, vector, trig_mode); | 213 | entry.fields.dest, entry.fields.dest_mode, |
214 | entry.fields.delivery_mode, entry.fields.vector, | ||
215 | entry.fields.trig_mode); | ||
218 | 216 | ||
219 | deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, dest, | 217 | kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask); |
220 | dest_mode); | ||
221 | if (!deliver_bitmask) { | 218 | if (!deliver_bitmask) { |
222 | ioapic_debug("no target on destination\n"); | 219 | ioapic_debug("no target on destination\n"); |
223 | return 0; | 220 | return 0; |
224 | } | 221 | } |
225 | 222 | ||
226 | switch (delivery_mode) { | 223 | /* Always delivery PIT interrupt to vcpu 0 */ |
227 | case IOAPIC_LOWEST_PRIORITY: | ||
228 | vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, | ||
229 | deliver_bitmask); | ||
230 | #ifdef CONFIG_X86 | 224 | #ifdef CONFIG_X86 |
231 | if (irq == 0) | 225 | if (irq == 0) |
232 | vcpu = ioapic->kvm->vcpus[0]; | 226 | deliver_bitmask = 1; |
233 | #endif | 227 | #endif |
234 | if (vcpu != NULL) | 228 | |
235 | r = ioapic_inj_irq(ioapic, vcpu, vector, | 229 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { |
236 | trig_mode, delivery_mode); | 230 | if (!(deliver_bitmask & (1 << vcpu_id))) |
237 | else | 231 | continue; |
238 | ioapic_debug("null lowest prio vcpu: " | 232 | deliver_bitmask &= ~(1 << vcpu_id); |
239 | "mask=%x vector=%x delivery_mode=%x\n", | 233 | vcpu = ioapic->kvm->vcpus[vcpu_id]; |
240 | deliver_bitmask, vector, IOAPIC_LOWEST_PRIORITY); | 234 | if (vcpu) { |
241 | break; | 235 | if (entry.fields.delivery_mode == |
242 | case IOAPIC_FIXED: | 236 | IOAPIC_LOWEST_PRIORITY || |
243 | #ifdef CONFIG_X86 | 237 | entry.fields.delivery_mode == IOAPIC_FIXED) { |
244 | if (irq == 0) | ||
245 | deliver_bitmask = 1; | ||
246 | #endif | ||
247 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { | ||
248 | if (!(deliver_bitmask & (1 << vcpu_id))) | ||
249 | continue; | ||
250 | deliver_bitmask &= ~(1 << vcpu_id); | ||
251 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | ||
252 | if (vcpu) { | ||
253 | if (r < 0) | 238 | if (r < 0) |
254 | r = 0; | 239 | r = 0; |
255 | r += ioapic_inj_irq(ioapic, vcpu, vector, | 240 | r += ioapic_inj_irq(ioapic, vcpu, |
256 | trig_mode, delivery_mode); | 241 | entry.fields.vector, |
257 | } | 242 | entry.fields.trig_mode, |
258 | } | 243 | entry.fields.delivery_mode); |
259 | break; | 244 | } else if (entry.fields.delivery_mode == IOAPIC_NMI) { |
260 | case IOAPIC_NMI: | ||
261 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { | ||
262 | if (!(deliver_bitmask & (1 << vcpu_id))) | ||
263 | continue; | ||
264 | deliver_bitmask &= ~(1 << vcpu_id); | ||
265 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | ||
266 | if (vcpu) { | ||
267 | ioapic_inj_nmi(vcpu); | ||
268 | r = 1; | 245 | r = 1; |
269 | } | 246 | ioapic_inj_nmi(vcpu); |
270 | else | 247 | } else |
271 | ioapic_debug("NMI to vcpu %d failed\n", | 248 | ioapic_debug("unsupported delivery mode %x!\n", |
272 | vcpu->vcpu_id); | 249 | entry.fields.delivery_mode); |
273 | } | 250 | } else |
274 | break; | 251 | ioapic_debug("null destination vcpu: " |
275 | default: | 252 | "mask=%x vector=%x delivery_mode=%x\n", |
276 | printk(KERN_WARNING "Unsupported delivery mode %d\n", | 253 | entry.fields.deliver_bitmask, |
277 | delivery_mode); | 254 | entry.fields.vector, |
278 | break; | 255 | entry.fields.delivery_mode); |
279 | } | 256 | } |
280 | return r; | 257 | return r; |
281 | } | 258 | } |
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c index 864ac5483baa..aec7a0d93a3f 100644 --- a/virt/kvm/irq_comm.c +++ b/virt/kvm/irq_comm.c | |||
@@ -43,53 +43,74 @@ 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 | ||
46 | void kvm_get_intr_delivery_bitmask(struct kvm_ioapic *ioapic, | ||
47 | union kvm_ioapic_redirect_entry *entry, | ||
48 | unsigned long *deliver_bitmask) | ||
49 | { | ||
50 | struct kvm_vcpu *vcpu; | ||
51 | |||
52 | *deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, | ||
53 | entry->fields.dest_id, entry->fields.dest_mode); | ||
54 | switch (entry->fields.delivery_mode) { | ||
55 | case IOAPIC_LOWEST_PRIORITY: | ||
56 | vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, | ||
57 | entry->fields.vector, *deliver_bitmask); | ||
58 | *deliver_bitmask = 1 << vcpu->vcpu_id; | ||
59 | break; | ||
60 | case IOAPIC_FIXED: | ||
61 | case IOAPIC_NMI: | ||
62 | break; | ||
63 | default: | ||
64 | if (printk_ratelimit()) | ||
65 | printk(KERN_INFO "kvm: unsupported delivery mode %d\n", | ||
66 | entry->fields.delivery_mode); | ||
67 | *deliver_bitmask = 0; | ||
68 | } | ||
69 | } | ||
70 | |||
46 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, | 71 | static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, |
47 | struct kvm *kvm, int level) | 72 | struct kvm *kvm, int level) |
48 | { | 73 | { |
49 | int vcpu_id, r = -1; | 74 | int vcpu_id, r = -1; |
50 | struct kvm_vcpu *vcpu; | 75 | struct kvm_vcpu *vcpu; |
51 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); | 76 | struct kvm_ioapic *ioapic = ioapic_irqchip(kvm); |
52 | int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK) | 77 | union kvm_ioapic_redirect_entry entry; |
53 | >> MSI_ADDR_DEST_ID_SHIFT; | 78 | unsigned long deliver_bitmask; |
54 | int vector = (e->msi.data & MSI_DATA_VECTOR_MASK) | ||
55 | >> MSI_DATA_VECTOR_SHIFT; | ||
56 | int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, | ||
57 | (unsigned long *)&e->msi.address_lo); | ||
58 | int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, | ||
59 | (unsigned long *)&e->msi.data); | ||
60 | int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT, | ||
61 | (unsigned long *)&e->msi.data); | ||
62 | u32 deliver_bitmask; | ||
63 | 79 | ||
64 | BUG_ON(!ioapic); | 80 | BUG_ON(!ioapic); |
65 | 81 | ||
66 | deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic, | 82 | entry.bits = 0; |
67 | dest_id, dest_mode); | 83 | entry.fields.dest_id = (e->msi.address_lo & |
68 | /* IOAPIC delivery mode value is the same as MSI here */ | 84 | MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; |
69 | switch (delivery_mode) { | 85 | entry.fields.vector = (e->msi.data & |
70 | case IOAPIC_LOWEST_PRIORITY: | 86 | MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; |
71 | vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector, | 87 | entry.fields.dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT, |
72 | deliver_bitmask); | 88 | (unsigned long *)&e->msi.address_lo); |
73 | if (vcpu != NULL) | 89 | entry.fields.trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT, |
74 | r = kvm_apic_set_irq(vcpu, vector, trig_mode); | 90 | (unsigned long *)&e->msi.data); |
75 | else | 91 | entry.fields.delivery_mode = test_bit( |
76 | printk(KERN_INFO "kvm: null lowest priority vcpu!\n"); | 92 | MSI_DATA_DELIVERY_MODE_SHIFT, |
77 | break; | 93 | (unsigned long *)&e->msi.data); |
78 | case IOAPIC_FIXED: | 94 | |
79 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { | 95 | /* TODO Deal with RH bit of MSI message address */ |
80 | if (!(deliver_bitmask & (1 << vcpu_id))) | 96 | |
81 | continue; | 97 | kvm_get_intr_delivery_bitmask(ioapic, &entry, &deliver_bitmask); |
82 | deliver_bitmask &= ~(1 << vcpu_id); | 98 | |
83 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | 99 | if (!deliver_bitmask) { |
84 | if (vcpu) { | 100 | printk(KERN_WARNING "kvm: no destination for MSI delivery!"); |
85 | if (r < 0) | 101 | return -1; |
86 | r = 0; | 102 | } |
87 | r += kvm_apic_set_irq(vcpu, vector, trig_mode); | 103 | for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) { |
88 | } | 104 | if (!(deliver_bitmask & (1 << vcpu_id))) |
105 | continue; | ||
106 | deliver_bitmask &= ~(1 << vcpu_id); | ||
107 | vcpu = ioapic->kvm->vcpus[vcpu_id]; | ||
108 | if (vcpu) { | ||
109 | if (r < 0) | ||
110 | r = 0; | ||
111 | r += kvm_apic_set_irq(vcpu, entry.fields.vector, | ||
112 | entry.fields.trig_mode); | ||
89 | } | 113 | } |
90 | break; | ||
91 | default: | ||
92 | break; | ||
93 | } | 114 | } |
94 | return r; | 115 | return r; |
95 | } | 116 | } |