aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kvm/ioapic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kvm/ioapic.c')
-rw-r--r--arch/x86/kvm/ioapic.c34
1 files changed, 25 insertions, 9 deletions
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index bdff437acbcb..4e822ad363f3 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -209,12 +209,12 @@ static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq,
209 209
210 old_irr = ioapic->irr; 210 old_irr = ioapic->irr;
211 ioapic->irr |= mask; 211 ioapic->irr |= mask;
212 if (edge) 212 if (edge) {
213 ioapic->irr_delivered &= ~mask; 213 ioapic->irr_delivered &= ~mask;
214 if ((edge && old_irr == ioapic->irr) || 214 if (old_irr == ioapic->irr) {
215 (!edge && entry.fields.remote_irr)) { 215 ret = 0;
216 ret = 0; 216 goto out;
217 goto out; 217 }
218 } 218 }
219 219
220 ret = ioapic_service(ioapic, irq, line_status); 220 ret = ioapic_service(ioapic, irq, line_status);
@@ -257,8 +257,7 @@ void kvm_ioapic_scan_entry(struct kvm_vcpu *vcpu, ulong *ioapic_handled_vectors)
257 index == RTC_GSI) { 257 index == RTC_GSI) {
258 if (kvm_apic_match_dest(vcpu, NULL, 0, 258 if (kvm_apic_match_dest(vcpu, NULL, 0,
259 e->fields.dest_id, e->fields.dest_mode) || 259 e->fields.dest_id, e->fields.dest_mode) ||
260 (e->fields.trig_mode == IOAPIC_EDGE_TRIG && 260 kvm_apic_pending_eoi(vcpu, e->fields.vector))
261 kvm_apic_pending_eoi(vcpu, e->fields.vector)))
262 __set_bit(e->fields.vector, 261 __set_bit(e->fields.vector,
263 ioapic_handled_vectors); 262 ioapic_handled_vectors);
264 } 263 }
@@ -277,6 +276,7 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
277{ 276{
278 unsigned index; 277 unsigned index;
279 bool mask_before, mask_after; 278 bool mask_before, mask_after;
279 int old_remote_irr, old_delivery_status;
280 union kvm_ioapic_redirect_entry *e; 280 union kvm_ioapic_redirect_entry *e;
281 281
282 switch (ioapic->ioregsel) { 282 switch (ioapic->ioregsel) {
@@ -299,14 +299,28 @@ static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
299 return; 299 return;
300 e = &ioapic->redirtbl[index]; 300 e = &ioapic->redirtbl[index];
301 mask_before = e->fields.mask; 301 mask_before = e->fields.mask;
302 /* Preserve read-only fields */
303 old_remote_irr = e->fields.remote_irr;
304 old_delivery_status = e->fields.delivery_status;
302 if (ioapic->ioregsel & 1) { 305 if (ioapic->ioregsel & 1) {
303 e->bits &= 0xffffffff; 306 e->bits &= 0xffffffff;
304 e->bits |= (u64) val << 32; 307 e->bits |= (u64) val << 32;
305 } else { 308 } else {
306 e->bits &= ~0xffffffffULL; 309 e->bits &= ~0xffffffffULL;
307 e->bits |= (u32) val; 310 e->bits |= (u32) val;
308 e->fields.remote_irr = 0;
309 } 311 }
312 e->fields.remote_irr = old_remote_irr;
313 e->fields.delivery_status = old_delivery_status;
314
315 /*
316 * Some OSes (Linux, Xen) assume that Remote IRR bit will
317 * be cleared by IOAPIC hardware when the entry is configured
318 * as edge-triggered. This behavior is used to simulate an
319 * explicit EOI on IOAPICs that don't have the EOI register.
320 */
321 if (e->fields.trig_mode == IOAPIC_EDGE_TRIG)
322 e->fields.remote_irr = 0;
323
310 mask_after = e->fields.mask; 324 mask_after = e->fields.mask;
311 if (mask_before != mask_after) 325 if (mask_before != mask_after)
312 kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after); 326 kvm_fire_mask_notifiers(ioapic->kvm, KVM_IRQCHIP_IOAPIC, index, mask_after);
@@ -324,7 +338,9 @@ static int ioapic_service(struct kvm_ioapic *ioapic, int irq, bool line_status)
324 struct kvm_lapic_irq irqe; 338 struct kvm_lapic_irq irqe;
325 int ret; 339 int ret;
326 340
327 if (entry->fields.mask) 341 if (entry->fields.mask ||
342 (entry->fields.trig_mode == IOAPIC_LEVEL_TRIG &&
343 entry->fields.remote_irr))
328 return -1; 344 return -1;
329 345
330 ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " 346 ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "