aboutsummaryrefslogtreecommitdiffstats
path: root/virt/kvm
diff options
context:
space:
mode:
authorMarc Zyngier <marc.zyngier@arm.com>2019-04-02 01:36:23 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2019-04-02 21:18:43 -0400
commit96085b949672dca19773495813b577eb3bedf06e (patch)
tree6976d070504820315cb794fda1f23e386ff9591b /virt/kvm
parent8fa76162487143d202db20ce84e12061b671a058 (diff)
KVM: arm/arm64: vgic-v3: Retire pending interrupts on disabling LPIs
When disabling LPIs (for example on reset) at the redistributor level, it is expected that LPIs that was pending in the CPU interface are eventually retired. Currently, this is not what is happening, and these LPIs will stay in the ap_list, eventually being acknowledged by the vcpu (which didn't quite expect this behaviour). The fix is thus to retire these LPIs from the list of pending interrupts as we disable LPIs. Reported-by: Heyi Guo <guoheyi@huawei.com> Tested-by: Heyi Guo <guoheyi@huawei.com> Fixes: 0e4e82f154e3 ("KVM: arm64: vgic-its: Enable ITS emulation as a virtual MSI controller") Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Diffstat (limited to 'virt/kvm')
-rw-r--r--virt/kvm/arm/vgic/vgic-mmio-v3.c3
-rw-r--r--virt/kvm/arm/vgic/vgic.c21
-rw-r--r--virt/kvm/arm/vgic/vgic.h1
3 files changed, 25 insertions, 0 deletions
diff --git a/virt/kvm/arm/vgic/vgic-mmio-v3.c b/virt/kvm/arm/vgic/vgic-mmio-v3.c
index 4a12322bf7df..9f4843fe9cda 100644
--- a/virt/kvm/arm/vgic/vgic-mmio-v3.c
+++ b/virt/kvm/arm/vgic/vgic-mmio-v3.c
@@ -200,6 +200,9 @@ static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
200 200
201 vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS; 201 vgic_cpu->lpis_enabled = val & GICR_CTLR_ENABLE_LPIS;
202 202
203 if (was_enabled && !vgic_cpu->lpis_enabled)
204 vgic_flush_pending_lpis(vcpu);
205
203 if (!was_enabled && vgic_cpu->lpis_enabled) 206 if (!was_enabled && vgic_cpu->lpis_enabled)
204 vgic_enable_lpis(vcpu); 207 vgic_enable_lpis(vcpu);
205} 208}
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 3af69f2a3866..191deccf60bf 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -151,6 +151,27 @@ void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
151 kfree(irq); 151 kfree(irq);
152} 152}
153 153
154void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu)
155{
156 struct vgic_cpu *vgic_cpu = &vcpu->arch.vgic_cpu;
157 struct vgic_irq *irq, *tmp;
158 unsigned long flags;
159
160 raw_spin_lock_irqsave(&vgic_cpu->ap_list_lock, flags);
161
162 list_for_each_entry_safe(irq, tmp, &vgic_cpu->ap_list_head, ap_list) {
163 if (irq->intid >= VGIC_MIN_LPI) {
164 raw_spin_lock(&irq->irq_lock);
165 list_del(&irq->ap_list);
166 irq->vcpu = NULL;
167 raw_spin_unlock(&irq->irq_lock);
168 vgic_put_irq(vcpu->kvm, irq);
169 }
170 }
171
172 raw_spin_unlock_irqrestore(&vgic_cpu->ap_list_lock, flags);
173}
174
154void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending) 175void vgic_irq_set_phys_pending(struct vgic_irq *irq, bool pending)
155{ 176{
156 WARN_ON(irq_set_irqchip_state(irq->host_irq, 177 WARN_ON(irq_set_irqchip_state(irq->host_irq,
diff --git a/virt/kvm/arm/vgic/vgic.h b/virt/kvm/arm/vgic/vgic.h
index a90024718ca4..abeeffabc456 100644
--- a/virt/kvm/arm/vgic/vgic.h
+++ b/virt/kvm/arm/vgic/vgic.h
@@ -238,6 +238,7 @@ void vgic_v3_put(struct kvm_vcpu *vcpu);
238bool vgic_has_its(struct kvm *kvm); 238bool vgic_has_its(struct kvm *kvm);
239int kvm_vgic_register_its_device(void); 239int kvm_vgic_register_its_device(void);
240void vgic_enable_lpis(struct kvm_vcpu *vcpu); 240void vgic_enable_lpis(struct kvm_vcpu *vcpu);
241void vgic_flush_pending_lpis(struct kvm_vcpu *vcpu);
241int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi); 242int vgic_its_inject_msi(struct kvm *kvm, struct kvm_msi *msi);
242int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr); 243int vgic_v3_has_attr_regs(struct kvm_device *dev, struct kvm_device_attr *attr);
243int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write, 244int vgic_v3_dist_uaccess(struct kvm_vcpu *vcpu, bool is_write,