Fix multiple injection of level sensitive forwarded IRQs.
With current code, the second injection fails since the state bitmaps
are not reset (process_maintenance is not called anymore).
New implementation consists in fully bypassing the vgic state
management for forwarded IRQ (checks are ignored in
vgic_update_irq_pending). This obviously assumes the forwarded IRQ is
injected from kernel side.

Signed-off-by: Eric Auger <eric.au...@linaro.org>

---

It was attempted to reset the states in __kvm_vgic_sync_hwstate, checking
the emptied LR of forwarded IRQ. However surprisingly this solution does
not seem to work. Some times, a new forwarded IRQ injection is observed
while the LR of the previous instance was not observed as empty.

v1 -> v2:
- fix vgic state bypass in vgic_queue_hwirq
---
 virt/kvm/arm/vgic.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 0007300..8ef495b 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1259,7 +1259,9 @@ static bool vgic_queue_sgi(struct kvm_vcpu *vcpu, int irq)
 
 static bool vgic_queue_hwirq(struct kvm_vcpu *vcpu, int irq)
 {
-       if (vgic_irq_is_queued(vcpu, irq))
+       bool is_forwarded =  (vgic_get_phys_irq(vcpu, irq) > 0);
+
+       if (vgic_irq_is_queued(vcpu, irq) && !is_forwarded)
                return true; /* level interrupt, already queued */
 
        if (vgic_queue_irq(vcpu, 0, irq)) {
@@ -1517,14 +1519,18 @@ static bool vgic_update_irq_pending(struct kvm *kvm, 
int cpuid,
        int edge_triggered, level_triggered;
        int enabled;
        bool ret = true;
+       bool is_forwarded;
 
        spin_lock(&dist->lock);
 
        vcpu = kvm_get_vcpu(kvm, cpuid);
+       is_forwarded = (vgic_get_phys_irq(vcpu, irq_num) > 0);
+
        edge_triggered = vgic_irq_is_edge(vcpu, irq_num);
        level_triggered = !edge_triggered;
 
-       if (!vgic_validate_injection(vcpu, irq_num, level)) {
+       if (!is_forwarded &&
+               !vgic_validate_injection(vcpu, irq_num, level)) {
                ret = false;
                goto out;
        }
@@ -1557,7 +1563,8 @@ static bool vgic_update_irq_pending(struct kvm *kvm, int 
cpuid,
                goto out;
        }
 
-       if (level_triggered && vgic_irq_is_queued(vcpu, irq_num)) {
+       if (!is_forwarded &&
+               level_triggered && vgic_irq_is_queued(vcpu, irq_num)) {
                /*
                 * Level interrupt in progress, will be picked up
                 * when EOId.
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to