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.

---
  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.

Signed-off-by: Eric Auger <eric.au...@linaro.org>
---
 include/kvm/arm_vgic.h | 1 +
 virt/kvm/arm/vgic.c    | 9 +++++++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/kvm/arm_vgic.h b/include/kvm/arm_vgic.h
index 743020f..3da244f 100644
--- a/include/kvm/arm_vgic.h
+++ b/include/kvm/arm_vgic.h
@@ -177,6 +177,7 @@ struct vgic_dist {
        unsigned long           irq_pending_on_cpu;
 
        struct rb_root          irq_phys_map;
+       spinlock_t                      rb_tree_lock;
 #endif
 };
 
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c
index 0007300..195c10c 100644
--- a/virt/kvm/arm/vgic.c
+++ b/virt/kvm/arm/vgic.c
@@ -1517,14 +1517,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 +1561,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 linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to