summaryrefslogtreecommitdiffstats
path: root/virt/kvm
diff options
context:
space:
mode:
authorAlexandru Elisei <alexandru.elisei@arm.com>2019-08-07 05:53:20 -0400
committerMarc Zyngier <maz@kernel.org>2019-08-09 03:07:26 -0400
commit16e604a437c89751dc626c9e90cf88ba93c5be64 (patch)
tree66a8b7eca67057f45e431a66d52675c0477e74c5 /virt/kvm
parentc69509c70aa45a8c4954c88c629a64acf4ee4a36 (diff)
KVM: arm/arm64: vgic: Reevaluate level sensitive interrupts on enable
A HW mapped level sensitive interrupt asserted by a device will not be put into the ap_list if it is disabled at the VGIC level. When it is enabled again, it will be inserted into the ap_list and written to a list register on guest entry regardless of the state of the device. We could argue that this can also happen on real hardware, when the command to enable the interrupt reached the GIC before the device had the chance to de-assert the interrupt signal; however, we emulate the distributor and redistributors in software and we can do better than that. Signed-off-by: Alexandru Elisei <alexandru.elisei@arm.com> Signed-off-by: Marc Zyngier <maz@kernel.org>
Diffstat (limited to 'virt/kvm')
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-mmio.c b/virt/kvm/arm/vgic/vgic-mmio.c
index 3ba7278fb533..44efc2ff863f 100644
--- a/virt/kvm/arm/vgic/vgic-mmio.c
+++ b/virt/kvm/arm/vgic/vgic-mmio.c
@@ -113,6 +113,22 @@ void vgic_mmio_write_senable(struct kvm_vcpu *vcpu,
113 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i); 113 struct vgic_irq *irq = vgic_get_irq(vcpu->kvm, vcpu, intid + i);
114 114
115 raw_spin_lock_irqsave(&irq->irq_lock, flags); 115 raw_spin_lock_irqsave(&irq->irq_lock, flags);
116 if (vgic_irq_is_mapped_level(irq)) {
117 bool was_high = irq->line_level;
118
119 /*
120 * We need to update the state of the interrupt because
121 * the guest might have changed the state of the device
122 * while the interrupt was disabled at the VGIC level.
123 */
124 irq->line_level = vgic_get_phys_line_level(irq);
125 /*
126 * Deactivate the physical interrupt so the GIC will let
127 * us know when it is asserted again.
128 */
129 if (!irq->active && was_high && !irq->line_level)
130 vgic_irq_set_phys_active(irq, false);
131 }
116 irq->enabled = true; 132 irq->enabled = true;
117 vgic_queue_irq_unlock(vcpu->kvm, irq, flags); 133 vgic_queue_irq_unlock(vcpu->kvm, irq, flags);
118 134